staging: android: ion: Remove crufty cache support
[linux-2.6-microblaze.git] / drivers / staging / android / ion / ion-ioctl.c
1 /*
2  *
3  * Copyright (C) 2011 Google, Inc.
4  *
5  * This software is licensed under the terms of the GNU General Public
6  * License version 2, as published by the Free Software Foundation, and
7  * may be copied, distributed, and modified under those terms.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  */
15
16 #include <linux/kernel.h>
17 #include <linux/file.h>
18 #include <linux/fs.h>
19 #include <linux/uaccess.h>
20
21 #include "ion.h"
22 #include "ion_priv.h"
23 #include "compat_ion.h"
24
25 union ion_ioctl_arg {
26         struct ion_fd_data fd;
27         struct ion_allocation_data allocation;
28         struct ion_handle_data handle;
29         struct ion_custom_data custom;
30         struct ion_heap_query query;
31 };
32
33 static int validate_ioctl_arg(unsigned int cmd, union ion_ioctl_arg *arg)
34 {
35         int ret = 0;
36
37         switch (cmd) {
38         case ION_IOC_HEAP_QUERY:
39                 ret = arg->query.reserved0 != 0;
40                 ret |= arg->query.reserved1 != 0;
41                 ret |= arg->query.reserved2 != 0;
42                 break;
43         default:
44                 break;
45         }
46
47         return ret ? -EINVAL : 0;
48 }
49
50 /* fix up the cases where the ioctl direction bits are incorrect */
51 static unsigned int ion_ioctl_dir(unsigned int cmd)
52 {
53         switch (cmd) {
54         case ION_IOC_FREE:
55         case ION_IOC_CUSTOM:
56                 return _IOC_WRITE;
57         default:
58                 return _IOC_DIR(cmd);
59         }
60 }
61
62 long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
63 {
64         struct ion_client *client = filp->private_data;
65         struct ion_device *dev = client->dev;
66         struct ion_handle *cleanup_handle = NULL;
67         int ret = 0;
68         unsigned int dir;
69         union ion_ioctl_arg data;
70
71         dir = ion_ioctl_dir(cmd);
72
73         if (_IOC_SIZE(cmd) > sizeof(data))
74                 return -EINVAL;
75
76         /*
77          * The copy_from_user is unconditional here for both read and write
78          * to do the validate. If there is no write for the ioctl, the
79          * buffer is cleared
80          */
81         if (copy_from_user(&data, (void __user *)arg, _IOC_SIZE(cmd)))
82                 return -EFAULT;
83
84         ret = validate_ioctl_arg(cmd, &data);
85         if (WARN_ON_ONCE(ret))
86                 return ret;
87
88         if (!(dir & _IOC_WRITE))
89                 memset(&data, 0, sizeof(data));
90
91         switch (cmd) {
92         case ION_IOC_ALLOC:
93         {
94                 struct ion_handle *handle;
95
96                 handle = ion_alloc(client, data.allocation.len,
97                                                 data.allocation.heap_id_mask,
98                                                 data.allocation.flags);
99                 if (IS_ERR(handle))
100                         return PTR_ERR(handle);
101
102                 data.allocation.handle = handle->id;
103
104                 cleanup_handle = handle;
105                 break;
106         }
107         case ION_IOC_FREE:
108         {
109                 struct ion_handle *handle;
110
111                 mutex_lock(&client->lock);
112                 handle = ion_handle_get_by_id_nolock(client,
113                                                      data.handle.handle);
114                 if (IS_ERR(handle)) {
115                         mutex_unlock(&client->lock);
116                         return PTR_ERR(handle);
117                 }
118                 ion_free_nolock(client, handle);
119                 ion_handle_put_nolock(handle);
120                 mutex_unlock(&client->lock);
121                 break;
122         }
123         case ION_IOC_SHARE:
124         case ION_IOC_MAP:
125         {
126                 struct ion_handle *handle;
127
128                 handle = ion_handle_get_by_id(client, data.handle.handle);
129                 if (IS_ERR(handle))
130                         return PTR_ERR(handle);
131                 data.fd.fd = ion_share_dma_buf_fd(client, handle);
132                 ion_handle_put(handle);
133                 if (data.fd.fd < 0)
134                         ret = data.fd.fd;
135                 break;
136         }
137         case ION_IOC_IMPORT:
138         {
139                 struct ion_handle *handle;
140
141                 handle = ion_import_dma_buf_fd(client, data.fd.fd);
142                 if (IS_ERR(handle))
143                         ret = PTR_ERR(handle);
144                 else
145                         data.handle.handle = handle->id;
146                 break;
147         }
148         case ION_IOC_CUSTOM:
149         {
150                 if (!dev->custom_ioctl)
151                         return -ENOTTY;
152                 ret = dev->custom_ioctl(client, data.custom.cmd,
153                                                 data.custom.arg);
154                 break;
155         }
156         case ION_IOC_HEAP_QUERY:
157                 ret = ion_query_heaps(client, &data.query);
158                 break;
159         default:
160                 return -ENOTTY;
161         }
162
163         if (dir & _IOC_READ) {
164                 if (copy_to_user((void __user *)arg, &data, _IOC_SIZE(cmd))) {
165                         if (cleanup_handle)
166                                 ion_free(client, cleanup_handle);
167                         return -EFAULT;
168                 }
169         }
170         return ret;
171 }