1/*
2 * drivers/staging/android/ion/compat_ion.c
3 *
4 * Copyright (C) 2013 Google, Inc.
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#include <linux/compat.h>
18#include <linux/fs.h>
19#include <linux/uaccess.h>
20
21#include "ion.h"
22#include "compat_ion.h"
23
24/* See drivers/staging/android/uapi/ion.h for the definition of these structs */
25struct compat_ion_allocation_data {
26	compat_size_t len;
27	compat_size_t align;
28	compat_uint_t heap_id_mask;
29	compat_uint_t flags;
30	compat_int_t handle;
31};
32
33struct compat_ion_custom_data {
34	compat_uint_t cmd;
35	compat_ulong_t arg;
36};
37
38struct compat_ion_handle_data {
39	compat_int_t handle;
40};
41
42#define COMPAT_ION_IOC_ALLOC	_IOWR(ION_IOC_MAGIC, 0, \
43				      struct compat_ion_allocation_data)
44#define COMPAT_ION_IOC_FREE	_IOWR(ION_IOC_MAGIC, 1, \
45				      struct compat_ion_handle_data)
46#define COMPAT_ION_IOC_CUSTOM	_IOWR(ION_IOC_MAGIC, 6, \
47				      struct compat_ion_custom_data)
48
49static int compat_get_ion_allocation_data(
50			struct compat_ion_allocation_data __user *data32,
51			struct ion_allocation_data __user *data)
52{
53	compat_size_t s;
54	compat_uint_t u;
55	compat_int_t i;
56	int err;
57
58	err = get_user(s, &data32->len);
59	err |= put_user(s, &data->len);
60	err |= get_user(s, &data32->align);
61	err |= put_user(s, &data->align);
62	err |= get_user(u, &data32->heap_id_mask);
63	err |= put_user(u, &data->heap_id_mask);
64	err |= get_user(u, &data32->flags);
65	err |= put_user(u, &data->flags);
66	err |= get_user(i, &data32->handle);
67	err |= put_user(i, &data->handle);
68
69	return err;
70}
71
72static int compat_get_ion_handle_data(
73			struct compat_ion_handle_data __user *data32,
74			struct ion_handle_data __user *data)
75{
76	compat_int_t i;
77	int err;
78
79	err = get_user(i, &data32->handle);
80	err |= put_user(i, &data->handle);
81
82	return err;
83}
84
85static int compat_put_ion_allocation_data(
86			struct compat_ion_allocation_data __user *data32,
87			struct ion_allocation_data __user *data)
88{
89	compat_size_t s;
90	compat_uint_t u;
91	compat_int_t i;
92	int err;
93
94	err = get_user(s, &data->len);
95	err |= put_user(s, &data32->len);
96	err |= get_user(s, &data->align);
97	err |= put_user(s, &data32->align);
98	err |= get_user(u, &data->heap_id_mask);
99	err |= put_user(u, &data32->heap_id_mask);
100	err |= get_user(u, &data->flags);
101	err |= put_user(u, &data32->flags);
102	err |= get_user(i, &data->handle);
103	err |= put_user(i, &data32->handle);
104
105	return err;
106}
107
108static int compat_get_ion_custom_data(
109			struct compat_ion_custom_data __user *data32,
110			struct ion_custom_data __user *data)
111{
112	compat_uint_t cmd;
113	compat_ulong_t arg;
114	int err;
115
116	err = get_user(cmd, &data32->cmd);
117	err |= put_user(cmd, &data->cmd);
118	err |= get_user(arg, &data32->arg);
119	err |= put_user(arg, &data->arg);
120
121	return err;
122};
123
124long compat_ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
125{
126	long ret;
127
128	if (!filp->f_op->unlocked_ioctl)
129		return -ENOTTY;
130
131	switch (cmd) {
132	case COMPAT_ION_IOC_ALLOC:
133	{
134		struct compat_ion_allocation_data __user *data32;
135		struct ion_allocation_data __user *data;
136		int err;
137
138		data32 = compat_ptr(arg);
139		data = compat_alloc_user_space(sizeof(*data));
140		if (data == NULL)
141			return -EFAULT;
142
143		err = compat_get_ion_allocation_data(data32, data);
144		if (err)
145			return err;
146		ret = filp->f_op->unlocked_ioctl(filp, ION_IOC_ALLOC,
147							(unsigned long)data);
148		err = compat_put_ion_allocation_data(data32, data);
149		return ret ? ret : err;
150	}
151	case COMPAT_ION_IOC_FREE:
152	{
153		struct compat_ion_handle_data __user *data32;
154		struct ion_handle_data __user *data;
155		int err;
156
157		data32 = compat_ptr(arg);
158		data = compat_alloc_user_space(sizeof(*data));
159		if (data == NULL)
160			return -EFAULT;
161
162		err = compat_get_ion_handle_data(data32, data);
163		if (err)
164			return err;
165
166		return filp->f_op->unlocked_ioctl(filp, ION_IOC_FREE,
167							(unsigned long)data);
168	}
169	case COMPAT_ION_IOC_CUSTOM: {
170		struct compat_ion_custom_data __user *data32;
171		struct ion_custom_data __user *data;
172		int err;
173
174		data32 = compat_ptr(arg);
175		data = compat_alloc_user_space(sizeof(*data));
176		if (data == NULL)
177			return -EFAULT;
178
179		err = compat_get_ion_custom_data(data32, data);
180		if (err)
181			return err;
182
183		return filp->f_op->unlocked_ioctl(filp, ION_IOC_CUSTOM,
184							(unsigned long)data);
185	}
186	case ION_IOC_SHARE:
187	case ION_IOC_MAP:
188	case ION_IOC_IMPORT:
189	case ION_IOC_SYNC:
190		return filp->f_op->unlocked_ioctl(filp, cmd,
191						(unsigned long)compat_ptr(arg));
192	default:
193		return -ENOIOCTLCMD;
194	}
195}
196