]> git.ipfire.org Git - people/arne_f/kernel.git/blame - drivers/staging/dream/smd/smd_rpcrouter_device.c
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[people/arne_f/kernel.git] / drivers / staging / dream / smd / smd_rpcrouter_device.c
CommitLineData
7bf06dac
BS
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>
5a0e3ad6 32#include <linux/slab.h>
7bf06dac
BS
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 */
42static int next_minor = 1;
43
44struct class *msm_rpcrouter_class;
45dev_t msm_rpcrouter_devno;
46
47static struct cdev rpcrouter_cdev;
48static struct device *rpcrouter_device;
49
50static 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
67static 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
75static 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
105static 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;
132write_out_free:
133 kfree(k_buffer);
134 return rc;
135}
136
137static 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
160static 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
218static 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
228static 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
238int 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 */
296int 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
317int 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
358fail_destroy_device:
359 device_destroy(msm_rpcrouter_class, msm_rpcrouter_devno);
360fail_unregister_cdev_region:
361 unregister_chrdev_region(msm_rpcrouter_devno,
362 RPCROUTER_MAX_REMOTE_SERVERS + 1);
363fail_destroy_class:
364 class_destroy(msm_rpcrouter_class);
365fail:
366 return rc;
367}
368
369void 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