1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
41static int next_minor = 1;
42
43struct class *msm_rpcrouter_class;
44dev_t msm_rpcrouter_devno;
45
46static struct cdev rpcrouter_cdev;
47static struct device *rpcrouter_device;
48
49static 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
66static 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
74static 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
104static 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
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;
131write_out_free:
132 kfree(k_buffer);
133 return rc;
134}
135
136static 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
144
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
159static 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
177
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
217static 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
227static 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
237int 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
251
252
253
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
292
293
294
295int 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
316int msm_rpcrouter_init_devices(void)
317{
318 int rc;
319 int major;
320
321
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
357fail_destroy_device:
358 device_destroy(msm_rpcrouter_class, msm_rpcrouter_devno);
359fail_unregister_cdev_region:
360 unregister_chrdev_region(msm_rpcrouter_devno,
361 RPCROUTER_MAX_REMOTE_SERVERS + 1);
362fail_destroy_class:
363 class_destroy(msm_rpcrouter_class);
364fail:
365 return rc;
366}
367
368void 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
377