9p: Optimize TCREATE by eliminating a redundant fid clone.
[pandora-kernel.git] / drivers / staging / dream / smd / smd_rpcrouter_device.c
1 /* arch/arm/mach-msm/smd_rpcrouter_device.c
2  *
3  * Copyright (C) 2007 Google, Inc.
4  * Copyright (c) 2007-2009 QUALCOMM Incorporated.
5  * Author: San Mehat <san@android.com>
6  *
7  * This software is licensed under the terms of the GNU General Public
8  * License version 2, as published by the Free Software Foundation, and
9  * may be copied, distributed, and modified under those terms.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  */
17 #include <linux/module.h>
18 #include <linux/kernel.h>
19 #include <linux/string.h>
20 #include <linux/errno.h>
21 #include <linux/cdev.h>
22 #include <linux/init.h>
23 #include <linux/device.h>
24 #include <linux/types.h>
25 #include <linux/delay.h>
26 #include <linux/fs.h>
27 #include <linux/err.h>
28 #include <linux/sched.h>
29 #include <linux/poll.h>
30 #include <linux/platform_device.h>
31 #include <linux/msm_rpcrouter.h>
32 #include <linux/slab.h>
33
34 #include <asm/uaccess.h>
35 #include <asm/byteorder.h>
36
37 #include "smd_rpcrouter.h"
38
39 #define SAFETY_MEM_SIZE 65536
40
41 /* Next minor # available for a remote server */
42 static int next_minor = 1;
43
44 struct class *msm_rpcrouter_class;
45 dev_t msm_rpcrouter_devno;
46
47 static struct cdev rpcrouter_cdev;
48 static struct device *rpcrouter_device;
49
50 static int rpcrouter_open(struct inode *inode, struct file *filp)
51 {
52         int rc;
53         struct msm_rpc_endpoint *ept;
54
55         rc = nonseekable_open(inode, filp);
56         if (rc < 0)
57                 return rc;
58
59         ept = msm_rpcrouter_create_local_endpoint(inode->i_rdev);
60         if (!ept)
61                 return -ENOMEM;
62
63         filp->private_data = ept;
64         return 0;
65 }
66
67 static int rpcrouter_release(struct inode *inode, struct file *filp)
68 {
69         struct msm_rpc_endpoint *ept;
70         ept = (struct msm_rpc_endpoint *) filp->private_data;
71
72         return msm_rpcrouter_destroy_local_endpoint(ept);
73 }
74
75 static ssize_t rpcrouter_read(struct file *filp, char __user *buf,
76                               size_t count, loff_t *ppos)
77 {
78         struct msm_rpc_endpoint *ept;
79         struct rr_fragment *frag, *next;
80         int rc;
81
82         ept = (struct msm_rpc_endpoint *) filp->private_data;
83
84         rc = __msm_rpc_read(ept, &frag, count, -1);
85         if (rc < 0)
86                 return rc;
87
88         count = rc;
89
90         while (frag != NULL) {
91                 if (copy_to_user(buf, frag->data, frag->length)) {
92                         printk(KERN_ERR
93                                "rpcrouter: could not copy all read data to user!\n");
94                         rc = -EFAULT;
95                 }
96                 buf += frag->length;
97                 next = frag->next;
98                 kfree(frag);
99                 frag = next;
100         }
101
102         return rc;
103 }
104
105 static ssize_t rpcrouter_write(struct file *filp, const char __user *buf,
106                                 size_t count, loff_t *ppos)
107 {
108         struct msm_rpc_endpoint *ept;
109         int rc = 0;
110         void *k_buffer;
111
112         ept = (struct msm_rpc_endpoint *) filp->private_data;
113
114         /* A check for safety, this seems non-standard */
115         if (count > SAFETY_MEM_SIZE)
116                 return -EINVAL;
117
118         k_buffer = kmalloc(count, GFP_KERNEL);
119         if (!k_buffer)
120                 return -ENOMEM;
121
122         if (copy_from_user(k_buffer, buf, count)) {
123                 rc = -EFAULT;
124                 goto write_out_free;
125         }
126
127         rc = msm_rpc_write(ept, k_buffer, count);
128         if (rc < 0)
129                 goto write_out_free;
130
131         rc = count;
132 write_out_free:
133         kfree(k_buffer);
134         return rc;
135 }
136
137 static unsigned int rpcrouter_poll(struct file *filp,
138                                    struct poll_table_struct *wait)
139 {
140         struct msm_rpc_endpoint *ept;
141         unsigned mask = 0;
142         ept = (struct msm_rpc_endpoint *) filp->private_data;
143
144         /* If there's data already in the read queue, return POLLIN.
145          * Else, wait for the requested amount of time, and check again.
146          */
147
148         if (!list_empty(&ept->read_q))
149                 mask |= POLLIN;
150
151         if (!mask) {
152                 poll_wait(filp, &ept->wait_q, wait);
153                 if (!list_empty(&ept->read_q))
154                         mask |= POLLIN;
155         }
156
157         return mask;
158 }
159
160 static long rpcrouter_ioctl(struct file *filp, unsigned int cmd,
161                             unsigned long arg)
162 {
163         struct msm_rpc_endpoint *ept;
164         struct rpcrouter_ioctl_server_args server_args;
165         int rc = 0;
166         uint32_t n;
167
168         ept = (struct msm_rpc_endpoint *) filp->private_data;
169         switch (cmd) {
170
171         case RPC_ROUTER_IOCTL_GET_VERSION:
172                 n = RPC_ROUTER_VERSION_V1;
173                 rc = put_user(n, (unsigned int *) arg);
174                 break;
175
176         case RPC_ROUTER_IOCTL_GET_MTU:
177                 /* the pacmark word reduces the actual payload
178                  * possible per message
179                  */
180                 n = RPCROUTER_MSGSIZE_MAX - sizeof(uint32_t);
181                 rc = put_user(n, (unsigned int *) arg);
182                 break;
183
184         case RPC_ROUTER_IOCTL_REGISTER_SERVER:
185                 rc = copy_from_user(&server_args, (void *) arg,
186                                     sizeof(server_args));
187                 if (rc < 0)
188                         break;
189                 msm_rpc_register_server(ept,
190                                         server_args.prog,
191                                         server_args.vers);
192                 break;
193
194         case RPC_ROUTER_IOCTL_UNREGISTER_SERVER:
195                 rc = copy_from_user(&server_args, (void *) arg,
196                                     sizeof(server_args));
197                 if (rc < 0)
198                         break;
199
200                 msm_rpc_unregister_server(ept,
201                                           server_args.prog,
202                                           server_args.vers);
203                 break;
204
205         case RPC_ROUTER_IOCTL_GET_MINOR_VERSION:
206                 n = MSM_RPC_GET_MINOR(msm_rpc_get_vers(ept));
207                 rc = put_user(n, (unsigned int *)arg);
208                 break;
209
210         default:
211                 rc = -EINVAL;
212                 break;
213         }
214
215         return rc;
216 }
217
218 static struct file_operations rpcrouter_server_fops = {
219         .owner   = THIS_MODULE,
220         .open    = rpcrouter_open,
221         .release = rpcrouter_release,
222         .read    = rpcrouter_read,
223         .write   = rpcrouter_write,
224         .poll    = rpcrouter_poll,
225         .unlocked_ioctl  = rpcrouter_ioctl,
226 };
227
228 static struct file_operations rpcrouter_router_fops = {
229         .owner   = THIS_MODULE,
230         .open    = rpcrouter_open,
231         .release = rpcrouter_release,
232         .read    = rpcrouter_read,
233         .write   = rpcrouter_write,
234         .poll    = rpcrouter_poll,
235         .unlocked_ioctl = rpcrouter_ioctl,
236 };
237
238 int msm_rpcrouter_create_server_cdev(struct rr_server *server)
239 {
240         int rc;
241         uint32_t dev_vers;
242
243         if (next_minor == RPCROUTER_MAX_REMOTE_SERVERS) {
244                 printk(KERN_ERR
245                        "rpcrouter: Minor numbers exhausted - Increase "
246                        "RPCROUTER_MAX_REMOTE_SERVERS\n");
247                 return -ENOBUFS;
248         }
249
250 #if CONFIG_MSM_AMSS_VERSION >= 6350
251         /* Servers with bit 31 set are remote msm servers with hashkey version.
252          * Servers with bit 31 not set are remote msm servers with
253          * backwards compatible version type in which case the minor number
254          * (lower 16 bits) is set to zero.
255          *
256          */
257         if ((server->vers & RPC_VERSION_MODE_MASK))
258                 dev_vers = server->vers;
259         else
260                 dev_vers = server->vers & RPC_VERSION_MAJOR_MASK;
261 #else
262         dev_vers = server->vers;
263 #endif
264
265         server->device_number =
266                 MKDEV(MAJOR(msm_rpcrouter_devno), next_minor++);
267
268         server->device =
269                 device_create(msm_rpcrouter_class, rpcrouter_device,
270                               server->device_number, NULL, "%.8x:%.8x",
271                               server->prog, dev_vers);
272         if (IS_ERR(server->device)) {
273                 printk(KERN_ERR
274                        "rpcrouter: Unable to create device (%ld)\n",
275                        PTR_ERR(server->device));
276                 return PTR_ERR(server->device);;
277         }
278
279         cdev_init(&server->cdev, &rpcrouter_server_fops);
280         server->cdev.owner = THIS_MODULE;
281
282         rc = cdev_add(&server->cdev, server->device_number, 1);
283         if (rc < 0) {
284                 printk(KERN_ERR
285                        "rpcrouter: Unable to add chrdev (%d)\n", rc);
286                 device_destroy(msm_rpcrouter_class, server->device_number);
287                 return rc;
288         }
289         return 0;
290 }
291
292 /* for backward compatible version type (31st bit cleared)
293  * clearing minor number (lower 16 bits) in device name
294  * is neccessary for driver binding
295  */
296 int msm_rpcrouter_create_server_pdev(struct rr_server *server)
297 {
298         sprintf(server->pdev_name, "rs%.8x:%.8x",
299                 server->prog,
300 #if CONFIG_MSM_AMSS_VERSION >= 6350
301                 (server->vers & RPC_VERSION_MODE_MASK) ? server->vers :
302                 (server->vers & RPC_VERSION_MAJOR_MASK));
303 #else
304                 server->vers);
305 #endif
306
307         server->p_device.base.id = -1;
308         server->p_device.base.name = server->pdev_name;
309
310         server->p_device.prog = server->prog;
311         server->p_device.vers = server->vers;
312
313         platform_device_register(&server->p_device.base);
314         return 0;
315 }
316
317 int msm_rpcrouter_init_devices(void)
318 {
319         int rc;
320         int major;
321
322         /* Create the device nodes */
323         msm_rpcrouter_class = class_create(THIS_MODULE, "oncrpc");
324         if (IS_ERR(msm_rpcrouter_class)) {
325                 rc = -ENOMEM;
326                 printk(KERN_ERR
327                        "rpcrouter: failed to create oncrpc class\n");
328                 goto fail;
329         }
330
331         rc = alloc_chrdev_region(&msm_rpcrouter_devno, 0,
332                                  RPCROUTER_MAX_REMOTE_SERVERS + 1,
333                                  "oncrpc");
334         if (rc < 0) {
335                 printk(KERN_ERR
336                        "rpcrouter: Failed to alloc chardev region (%d)\n", rc);
337                 goto fail_destroy_class;
338         }
339
340         major = MAJOR(msm_rpcrouter_devno);
341         rpcrouter_device = device_create(msm_rpcrouter_class, NULL,
342                                          msm_rpcrouter_devno, NULL, "%.8x:%d",
343                                          0, 0);
344         if (IS_ERR(rpcrouter_device)) {
345                 rc = -ENOMEM;
346                 goto fail_unregister_cdev_region;
347         }
348
349         cdev_init(&rpcrouter_cdev, &rpcrouter_router_fops);
350         rpcrouter_cdev.owner = THIS_MODULE;
351
352         rc = cdev_add(&rpcrouter_cdev, msm_rpcrouter_devno, 1);
353         if (rc < 0)
354                 goto fail_destroy_device;
355
356         return 0;
357
358 fail_destroy_device:
359         device_destroy(msm_rpcrouter_class, msm_rpcrouter_devno);
360 fail_unregister_cdev_region:
361         unregister_chrdev_region(msm_rpcrouter_devno,
362                                  RPCROUTER_MAX_REMOTE_SERVERS + 1);
363 fail_destroy_class:
364         class_destroy(msm_rpcrouter_class);
365 fail:
366         return rc;
367 }
368
369 void msm_rpcrouter_exit_devices(void)
370 {
371         cdev_del(&rpcrouter_cdev);
372         device_destroy(msm_rpcrouter_class, msm_rpcrouter_devno);
373         unregister_chrdev_region(msm_rpcrouter_devno,
374                                  RPCROUTER_MAX_REMOTE_SERVERS + 1);
375         class_destroy(msm_rpcrouter_class);
376 }
377