1 /* arch/arm/mach-msm/smd_rpcrouter_device.c
3 * Copyright (C) 2007 Google, Inc.
4 * Copyright (c) 2007-2009 QUALCOMM Incorporated.
5 * Author: San Mehat <san@android.com>
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.
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.
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>
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>
33 #include <asm/uaccess.h>
34 #include <asm/byteorder.h>
36 #include "smd_rpcrouter.h"
38 #define SAFETY_MEM_SIZE 65536
40 /* Next minor # available for a remote server */
41 static int next_minor = 1;
43 struct class *msm_rpcrouter_class;
44 dev_t msm_rpcrouter_devno;
46 static struct cdev rpcrouter_cdev;
47 static struct device *rpcrouter_device;
49 static int rpcrouter_open(struct inode *inode, struct file *filp)
52 struct msm_rpc_endpoint *ept;
54 rc = nonseekable_open(inode, filp);
58 ept = msm_rpcrouter_create_local_endpoint(inode->i_rdev);
62 filp->private_data = ept;
66 static int rpcrouter_release(struct inode *inode, struct file *filp)
68 struct msm_rpc_endpoint *ept;
69 ept = (struct msm_rpc_endpoint *) filp->private_data;
71 return msm_rpcrouter_destroy_local_endpoint(ept);
74 static ssize_t rpcrouter_read(struct file *filp, char __user *buf,
75 size_t count, loff_t *ppos)
77 struct msm_rpc_endpoint *ept;
78 struct rr_fragment *frag, *next;
81 ept = (struct msm_rpc_endpoint *) filp->private_data;
83 rc = __msm_rpc_read(ept, &frag, count, -1);
89 while (frag != NULL) {
90 if (copy_to_user(buf, frag->data, frag->length)) {
92 "rpcrouter: could not copy all read data to user!\n");
104 static ssize_t rpcrouter_write(struct file *filp, const char __user *buf,
105 size_t count, loff_t *ppos)
107 struct msm_rpc_endpoint *ept;
111 ept = (struct msm_rpc_endpoint *) filp->private_data;
113 /* A check for safety, this seems non-standard */
114 if (count > SAFETY_MEM_SIZE)
117 k_buffer = kmalloc(count, GFP_KERNEL);
121 if (copy_from_user(k_buffer, buf, count)) {
126 rc = msm_rpc_write(ept, k_buffer, count);
136 static unsigned int rpcrouter_poll(struct file *filp,
137 struct poll_table_struct *wait)
139 struct msm_rpc_endpoint *ept;
141 ept = (struct msm_rpc_endpoint *) filp->private_data;
143 /* If there's data already in the read queue, return POLLIN.
144 * Else, wait for the requested amount of time, and check again.
147 if (!list_empty(&ept->read_q))
151 poll_wait(filp, &ept->wait_q, wait);
152 if (!list_empty(&ept->read_q))
159 static long rpcrouter_ioctl(struct file *filp, unsigned int cmd,
162 struct msm_rpc_endpoint *ept;
163 struct rpcrouter_ioctl_server_args server_args;
167 ept = (struct msm_rpc_endpoint *) filp->private_data;
170 case RPC_ROUTER_IOCTL_GET_VERSION:
171 n = RPC_ROUTER_VERSION_V1;
172 rc = put_user(n, (unsigned int *) arg);
175 case RPC_ROUTER_IOCTL_GET_MTU:
176 /* the pacmark word reduces the actual payload
177 * possible per message
179 n = RPCROUTER_MSGSIZE_MAX - sizeof(uint32_t);
180 rc = put_user(n, (unsigned int *) arg);
183 case RPC_ROUTER_IOCTL_REGISTER_SERVER:
184 rc = copy_from_user(&server_args, (void *) arg,
185 sizeof(server_args));
188 msm_rpc_register_server(ept,
193 case RPC_ROUTER_IOCTL_UNREGISTER_SERVER:
194 rc = copy_from_user(&server_args, (void *) arg,
195 sizeof(server_args));
199 msm_rpc_unregister_server(ept,
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);
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,
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,
237 int msm_rpcrouter_create_server_cdev(struct rr_server *server)
242 if (next_minor == RPCROUTER_MAX_REMOTE_SERVERS) {
244 "rpcrouter: Minor numbers exhausted - Increase "
245 "RPCROUTER_MAX_REMOTE_SERVERS\n");
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.
256 if ((server->vers & RPC_VERSION_MODE_MASK))
257 dev_vers = server->vers;
259 dev_vers = server->vers & RPC_VERSION_MAJOR_MASK;
261 dev_vers = server->vers;
264 server->device_number =
265 MKDEV(MAJOR(msm_rpcrouter_devno), next_minor++);
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)) {
273 "rpcrouter: Unable to create device (%ld)\n",
274 PTR_ERR(server->device));
275 return PTR_ERR(server->device);;
278 cdev_init(&server->cdev, &rpcrouter_server_fops);
279 server->cdev.owner = THIS_MODULE;
281 rc = cdev_add(&server->cdev, server->device_number, 1);
284 "rpcrouter: Unable to add chrdev (%d)\n", rc);
285 device_destroy(msm_rpcrouter_class, server->device_number);
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
295 int msm_rpcrouter_create_server_pdev(struct rr_server *server)
297 sprintf(server->pdev_name, "rs%.8x:%.8x",
299 #if CONFIG_MSM_AMSS_VERSION >= 6350
300 (server->vers & RPC_VERSION_MODE_MASK) ? server->vers :
301 (server->vers & RPC_VERSION_MAJOR_MASK));
306 server->p_device.base.id = -1;
307 server->p_device.base.name = server->pdev_name;
309 server->p_device.prog = server->prog;
310 server->p_device.vers = server->vers;
312 platform_device_register(&server->p_device.base);
316 int msm_rpcrouter_init_devices(void)
321 /* Create the device nodes */
322 msm_rpcrouter_class = class_create(THIS_MODULE, "oncrpc");
323 if (IS_ERR(msm_rpcrouter_class)) {
326 "rpcrouter: failed to create oncrpc class\n");
330 rc = alloc_chrdev_region(&msm_rpcrouter_devno, 0,
331 RPCROUTER_MAX_REMOTE_SERVERS + 1,
335 "rpcrouter: Failed to alloc chardev region (%d)\n", rc);
336 goto fail_destroy_class;
339 major = MAJOR(msm_rpcrouter_devno);
340 rpcrouter_device = device_create(msm_rpcrouter_class, NULL,
341 msm_rpcrouter_devno, NULL, "%.8x:%d",
343 if (IS_ERR(rpcrouter_device)) {
345 goto fail_unregister_cdev_region;
348 cdev_init(&rpcrouter_cdev, &rpcrouter_router_fops);
349 rpcrouter_cdev.owner = THIS_MODULE;
351 rc = cdev_add(&rpcrouter_cdev, msm_rpcrouter_devno, 1);
353 goto 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);
363 class_destroy(msm_rpcrouter_class);
368 void msm_rpcrouter_exit_devices(void)
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);