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