blob: 2276850218157a65e400cdffdd9e3598d56097d2 [file] [log] [blame]
/*
* drivers/staging/android/ion/compat_ion.c
*
* Copyright (C) 2013 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/compat.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include "ion.h"
#include "compat_ion.h"
/* See drivers/staging/android/uapi/ion.h for the definition of these structs */
struct compat_ion_allocation_data {
compat_size_t len;
compat_uint_t heap_id_mask;
compat_uint_t flags;
compat_uint_t fd;
compat_int_t unused;
};
struct compat_ion_custom_data {
compat_int_t share_fd;
compat_uint_t cmd;
compat_ulong_t arg;
};
struct compat_ion_berlin_data {
compat_uint_t cmd;
compat_uint_t offset;
compat_ulong_t addr;
compat_size_t len;
};
#define COMPAT_ION_IOC_CUSTOM _IOWR(ION_IOC_MAGIC, 6, \
struct compat_ion_custom_data)
static int compat_get_ion_custom_data(
struct compat_ion_custom_data __user *data32,
struct ion_custom_data __user *data)
{
compat_int_t i;
compat_uint_t u;
compat_ulong_t ul;
int err;
err = get_user(i, &data32->share_fd);
err |= put_user(i, &data->share_fd);
err |= get_user(u, &data32->cmd);
err |= put_user(u, &data->cmd);
err |= get_user(ul, &data32->arg);
err |= put_user(ul, &data->arg);
return err;
};
static int compat_get_ion_berlin_data(
struct compat_ion_berlin_data __user *data32,
struct ion_berlin_data __user *data)
{
compat_size_t s;
compat_uint_t u;
compat_ulong_t ul;
int err;
err = get_user(u, &data32->cmd);
err |= put_user(u, &data->cmd);
err |= get_user(u, &data32->offset);
err |= put_user(u, &data->offset);
err |= get_user(ul, &data32->addr);
err |= put_user(ul, &data->addr);
err |= get_user(s, &data32->len);
err |= put_user(s, &data->len);
return err;
}
static int compat_put_ion_berlin_data(
struct compat_ion_berlin_data __user *data32,
struct ion_berlin_data __user *data)
{
compat_size_t s;
compat_uint_t u;
compat_ulong_t ul;
int err;
err = get_user(u, &data->cmd);
err |= put_user(u, &data32->cmd);
err |= get_user(u, &data->offset);
err |= put_user(u, &data32->offset);
err |= get_user(ul, &data->addr);
err |= put_user(ul, &data32->addr);
err |= get_user(s, &data->len);
err |= put_user(s, &data32->len);
return err;
}
long compat_ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
long ret;
if (!filp->f_op->unlocked_ioctl)
return -ENOTTY;
switch (cmd) {
case COMPAT_ION_IOC_CUSTOM:
{
struct compat_ion_custom_data __user *data32;
struct ion_custom_data __user *data;
struct compat_ion_berlin_data __user *data32_berlin;
struct ion_berlin_data __user *data_berlin;
compat_ulong_t berlin_arg;
int err;
int cmd;
data32 = compat_ptr(arg);
data = compat_alloc_user_space(sizeof(*data) +
sizeof(*data_berlin));
if (!data)
return -EFAULT;
data_berlin = (struct ion_berlin_data *)(
(void __user *)data + sizeof(*data));
err = compat_get_ion_custom_data(data32, data);
if (err)
return err;
get_user(cmd, &data->cmd);
get_user(data32_berlin,
(struct compat_ion_berlin_data **)&data->arg);
err = compat_get_ion_berlin_data(data32_berlin, data_berlin);
if (err)
return err;
berlin_arg = (compat_ulong_t) ((unsigned long)data_berlin);
put_user(berlin_arg, &data->arg);
ret = filp->f_op->unlocked_ioctl(filp, ION_IOC_CUSTOM,
(unsigned long)data);
err = compat_put_ion_berlin_data(data32_berlin, data_berlin);
return ret ? ret : err;
}
case ION_IOC_ALLOC:
case ION_IOC_HEAP_QUERY:
return filp->f_op->unlocked_ioctl(filp, cmd,
(unsigned long)compat_ptr(arg));
default:
return -ENOIOCTLCMD;
}
}