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>
32 #include <linux/slab.h>
34 #include <asm/uaccess.h>
35 #include <asm/byteorder.h>
37 #include "smd_rpcrouter.h"
39 #define SAFETY_MEM_SIZE 65536
41 /* Next minor # available for a remote server */
42 static int next_minor
= 1;
44 struct class *msm_rpcrouter_class
;
45 dev_t msm_rpcrouter_devno
;
47 static struct cdev rpcrouter_cdev
;
48 static struct device
*rpcrouter_device
;
50 static int rpcrouter_open(struct inode
*inode
, struct file
*filp
)
53 struct msm_rpc_endpoint
*ept
;
55 rc
= nonseekable_open(inode
, filp
);
59 ept
= msm_rpcrouter_create_local_endpoint(inode
->i_rdev
);
63 filp
->private_data
= ept
;
67 static int rpcrouter_release(struct inode
*inode
, struct file
*filp
)
69 struct msm_rpc_endpoint
*ept
;
70 ept
= (struct msm_rpc_endpoint
*) filp
->private_data
;
72 return msm_rpcrouter_destroy_local_endpoint(ept
);
75 static ssize_t
rpcrouter_read(struct file
*filp
, char __user
*buf
,
76 size_t count
, loff_t
*ppos
)
78 struct msm_rpc_endpoint
*ept
;
79 struct rr_fragment
*frag
, *next
;
82 ept
= (struct msm_rpc_endpoint
*) filp
->private_data
;
84 rc
= __msm_rpc_read(ept
, &frag
, count
, -1);
90 while (frag
!= NULL
) {
91 if (copy_to_user(buf
, frag
->data
, frag
->length
)) {
93 "rpcrouter: could not copy all read data to user!\n");
105 static ssize_t
rpcrouter_write(struct file
*filp
, const char __user
*buf
,
106 size_t count
, loff_t
*ppos
)
108 struct msm_rpc_endpoint
*ept
;
112 ept
= (struct msm_rpc_endpoint
*) filp
->private_data
;
114 /* A check for safety, this seems non-standard */
115 if (count
> SAFETY_MEM_SIZE
)
118 k_buffer
= kmalloc(count
, GFP_KERNEL
);
122 if (copy_from_user(k_buffer
, buf
, count
)) {
127 rc
= msm_rpc_write(ept
, k_buffer
, count
);
137 static unsigned int rpcrouter_poll(struct file
*filp
,
138 struct poll_table_struct
*wait
)
140 struct msm_rpc_endpoint
*ept
;
142 ept
= (struct msm_rpc_endpoint
*) filp
->private_data
;
144 /* If there's data already in the read queue, return POLLIN.
145 * Else, wait for the requested amount of time, and check again.
148 if (!list_empty(&ept
->read_q
))
152 poll_wait(filp
, &ept
->wait_q
, wait
);
153 if (!list_empty(&ept
->read_q
))
160 static long rpcrouter_ioctl(struct file
*filp
, unsigned int cmd
,
163 struct msm_rpc_endpoint
*ept
;
164 struct rpcrouter_ioctl_server_args server_args
;
168 ept
= (struct msm_rpc_endpoint
*) filp
->private_data
;
171 case RPC_ROUTER_IOCTL_GET_VERSION
:
172 n
= RPC_ROUTER_VERSION_V1
;
173 rc
= put_user(n
, (unsigned int *) arg
);
176 case RPC_ROUTER_IOCTL_GET_MTU
:
177 /* the pacmark word reduces the actual payload
178 * possible per message
180 n
= RPCROUTER_MSGSIZE_MAX
- sizeof(uint32_t);
181 rc
= put_user(n
, (unsigned int *) arg
);
184 case RPC_ROUTER_IOCTL_REGISTER_SERVER
:
185 rc
= copy_from_user(&server_args
, (void *) arg
,
186 sizeof(server_args
));
189 msm_rpc_register_server(ept
,
194 case RPC_ROUTER_IOCTL_UNREGISTER_SERVER
:
195 rc
= copy_from_user(&server_args
, (void *) arg
,
196 sizeof(server_args
));
200 msm_rpc_unregister_server(ept
,
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
);
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
,
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
,
238 int msm_rpcrouter_create_server_cdev(struct rr_server
*server
)
243 if (next_minor
== RPCROUTER_MAX_REMOTE_SERVERS
) {
245 "rpcrouter: Minor numbers exhausted - Increase "
246 "RPCROUTER_MAX_REMOTE_SERVERS\n");
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.
257 if ((server
->vers
& RPC_VERSION_MODE_MASK
))
258 dev_vers
= server
->vers
;
260 dev_vers
= server
->vers
& RPC_VERSION_MAJOR_MASK
;
262 dev_vers
= server
->vers
;
265 server
->device_number
=
266 MKDEV(MAJOR(msm_rpcrouter_devno
), next_minor
++);
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
)) {
274 "rpcrouter: Unable to create device (%ld)\n",
275 PTR_ERR(server
->device
));
276 return PTR_ERR(server
->device
);;
279 cdev_init(&server
->cdev
, &rpcrouter_server_fops
);
280 server
->cdev
.owner
= THIS_MODULE
;
282 rc
= cdev_add(&server
->cdev
, server
->device_number
, 1);
285 "rpcrouter: Unable to add chrdev (%d)\n", rc
);
286 device_destroy(msm_rpcrouter_class
, server
->device_number
);
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
296 int msm_rpcrouter_create_server_pdev(struct rr_server
*server
)
298 sprintf(server
->pdev_name
, "rs%.8x:%.8x",
300 #if CONFIG_MSM_AMSS_VERSION >= 6350
301 (server
->vers
& RPC_VERSION_MODE_MASK
) ? server
->vers
:
302 (server
->vers
& RPC_VERSION_MAJOR_MASK
));
307 server
->p_device
.base
.id
= -1;
308 server
->p_device
.base
.name
= server
->pdev_name
;
310 server
->p_device
.prog
= server
->prog
;
311 server
->p_device
.vers
= server
->vers
;
313 platform_device_register(&server
->p_device
.base
);
317 int msm_rpcrouter_init_devices(void)
322 /* Create the device nodes */
323 msm_rpcrouter_class
= class_create(THIS_MODULE
, "oncrpc");
324 if (IS_ERR(msm_rpcrouter_class
)) {
327 "rpcrouter: failed to create oncrpc class\n");
331 rc
= alloc_chrdev_region(&msm_rpcrouter_devno
, 0,
332 RPCROUTER_MAX_REMOTE_SERVERS
+ 1,
336 "rpcrouter: Failed to alloc chardev region (%d)\n", rc
);
337 goto fail_destroy_class
;
340 major
= MAJOR(msm_rpcrouter_devno
);
341 rpcrouter_device
= device_create(msm_rpcrouter_class
, NULL
,
342 msm_rpcrouter_devno
, NULL
, "%.8x:%d",
344 if (IS_ERR(rpcrouter_device
)) {
346 goto fail_unregister_cdev_region
;
349 cdev_init(&rpcrouter_cdev
, &rpcrouter_router_fops
);
350 rpcrouter_cdev
.owner
= THIS_MODULE
;
352 rc
= cdev_add(&rpcrouter_cdev
, msm_rpcrouter_devno
, 1);
354 goto 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);
364 class_destroy(msm_rpcrouter_class
);
369 void msm_rpcrouter_exit_devices(void)
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
);