compat_ion.c revision c3a2fe03148f13b119c7bf0427a0526bdb288a92
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
38static int compat_get_ion_allocation_data(
39			struct compat_ion_allocation_data __user *data32,
40			struct ion_allocation_data __user *data)
41{
42	compat_size_t s;
43	compat_uint_t u;
44	compat_int_t i;
45	int err;
46
47	err = get_user(s, &data32->len);
48	err |= put_user(s, &data->len);
49	err |= get_user(s, &data32->align);
50	err |= put_user(s, &data->align);
51	err |= get_user(u, &data32->heap_id_mask);
52	err |= put_user(u, &data->heap_id_mask);
53	err |= get_user(u, &data32->flags);
54	err |= put_user(u, &data->flags);
55	err |= get_user(i, &data32->handle);
56	err |= put_user(i, &data->handle);
57
58	return err;
59}
60
61static int compat_put_ion_allocation_data(
62			struct compat_ion_allocation_data __user *data32,
63			struct ion_allocation_data __user *data)
64{
65	compat_size_t s;
66	compat_uint_t u;
67	compat_int_t i;
68	int err;
69
70	err = get_user(s, &data->len);
71	err |= put_user(s, &data32->len);
72	err |= get_user(s, &data->align);
73	err |= put_user(s, &data32->align);
74	err |= get_user(u, &data->heap_id_mask);
75	err |= put_user(u, &data32->heap_id_mask);
76	err |= get_user(u, &data->flags);
77	err |= put_user(u, &data32->flags);
78	err |= get_user(i, &data->handle);
79	err |= put_user(i, &data32->handle);
80
81	return err;
82}
83
84static int compat_get_ion_custom_data(
85			struct compat_ion_custom_data __user *data32,
86			struct ion_custom_data __user *data)
87{
88        compat_uint_t cmd;
89        compat_ulong_t arg;
90	int err;
91
92	err = get_user(cmd, &data32->cmd);
93	err |= put_user(cmd, &data->cmd);
94	err |= get_user(arg, &data32->arg);
95	err |= put_user(arg, &data->arg);
96
97	return err;
98};
99
100long compat_ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
101{
102	long ret;
103
104	if (!filp->f_op || !filp->f_op->unlocked_ioctl)
105		return -ENOTTY;
106
107	switch (cmd) {
108	case ION_IOC_ALLOC:
109	{
110		struct compat_ion_allocation_data __user *data32;
111		struct ion_allocation_data __user *data;
112		int err;
113
114		data32 = compat_ptr(arg);
115		data = compat_alloc_user_space(sizeof(*data));
116		if (data == NULL)
117			return -EFAULT;
118
119		err = compat_get_ion_allocation_data(data32, data);
120		if (err)
121			return err;
122
123		ret = filp->f_op->unlocked_ioctl(filp, cmd,
124							(unsigned long)data);
125		err = compat_put_ion_allocation_data(data32, data);
126		return ret ? ret : err;
127	}
128	case ION_IOC_FREE:
129	{
130		struct compat_ion_allocation_data __user *data32;
131		struct ion_allocation_data __user *data;
132		int err;
133
134		data32 = compat_ptr(arg);
135		data = compat_alloc_user_space(sizeof(*data));
136		if (data == NULL)
137			return -EFAULT;
138
139		err = compat_get_ion_allocation_data(data32, data);
140		if (err)
141			return err;
142
143		return filp->f_op->unlocked_ioctl(filp, cmd,
144							(unsigned long)data);
145	}
146	case ION_IOC_CUSTOM: {
147		struct compat_ion_custom_data __user *data32;
148		struct ion_custom_data __user *data;
149		int err;
150
151		data32 = compat_ptr(arg);
152		data = compat_alloc_user_space(sizeof(*data));
153		if (data == NULL)
154			return -EFAULT;
155
156		err = compat_get_ion_custom_data(data32, data);
157		if (err)
158			return err;
159
160		return filp->f_op->unlocked_ioctl(filp, cmd,
161							(unsigned long)data);
162	}
163	case ION_IOC_SHARE:
164	case ION_IOC_MAP:
165	case ION_IOC_IMPORT:
166	case ION_IOC_SYNC:
167		return filp->f_op->unlocked_ioctl(filp, cmd,
168						(unsigned long)compat_ptr(arg));
169	default:
170		return -ENOIOCTLCMD;
171	}
172}
173