Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[sfrench/cifs-2.6.git] / drivers / staging / android / ion / compat_ion.c
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 */
25 struct 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
33 struct compat_ion_custom_data {
34         compat_uint_t cmd;
35         compat_ulong_t arg;
36 };
37
38 struct 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
49 static 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
72 static 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
85 static 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
108 static 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
124 long 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 }