HID: uhid: remove uhid_hid_get_raw()
[deliverable/linux.git] / drivers / hid / uhid.c
CommitLineData
1ccd7a2a
DH
1/*
2 * User-space I/O driver support for HID subsystem
3 * Copyright (c) 2012 David Herrmann
4 */
5
6/*
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 */
12
13#include <linux/atomic.h>
befde022 14#include <linux/compat.h>
1ccd7a2a
DH
15#include <linux/device.h>
16#include <linux/fs.h>
17#include <linux/hid.h>
18#include <linux/input.h>
19#include <linux/miscdevice.h>
20#include <linux/module.h>
21#include <linux/mutex.h>
22#include <linux/poll.h>
23#include <linux/sched.h>
24#include <linux/spinlock.h>
25#include <linux/uhid.h>
26#include <linux/wait.h>
27
28#define UHID_NAME "uhid"
ace3d861
DH
29#define UHID_BUFSIZE 32
30
31struct uhid_device {
d937ae5f 32 struct mutex devlock;
d365c6cf
DH
33 bool running;
34
35 __u8 *rd_data;
36 uint rd_size;
37
ace3d861 38 struct hid_device *hid;
6664ef72 39 struct uhid_event input_buf;
ace3d861
DH
40
41 wait_queue_head_t waitq;
42 spinlock_t qlock;
43 __u8 head;
44 __u8 tail;
45 struct uhid_event *outq[UHID_BUFSIZE];
fcfcf0de
DH
46
47 struct mutex report_lock;
48 wait_queue_head_t report_wait;
49 atomic_t report_done;
50 atomic_t report_id;
51 struct uhid_event report_buf;
ace3d861 52};
1ccd7a2a
DH
53
54static struct miscdevice uhid_misc;
55
ace3d861
DH
56static void uhid_queue(struct uhid_device *uhid, struct uhid_event *ev)
57{
58 __u8 newhead;
59
60 newhead = (uhid->head + 1) % UHID_BUFSIZE;
61
62 if (newhead != uhid->tail) {
63 uhid->outq[uhid->head] = ev;
64 uhid->head = newhead;
65 wake_up_interruptible(&uhid->waitq);
66 } else {
67 hid_warn(uhid->hid, "Output queue is full\n");
68 kfree(ev);
69 }
70}
71
72static int uhid_queue_event(struct uhid_device *uhid, __u32 event)
73{
74 unsigned long flags;
75 struct uhid_event *ev;
76
77 ev = kzalloc(sizeof(*ev), GFP_KERNEL);
78 if (!ev)
79 return -ENOMEM;
80
81 ev->type = event;
82
83 spin_lock_irqsave(&uhid->qlock, flags);
84 uhid_queue(uhid, ev);
85 spin_unlock_irqrestore(&uhid->qlock, flags);
86
87 return 0;
88}
89
d365c6cf
DH
90static int uhid_hid_start(struct hid_device *hid)
91{
ec4b7dea
DH
92 struct uhid_device *uhid = hid->driver_data;
93
94 return uhid_queue_event(uhid, UHID_START);
d365c6cf
DH
95}
96
97static void uhid_hid_stop(struct hid_device *hid)
98{
ec4b7dea
DH
99 struct uhid_device *uhid = hid->driver_data;
100
101 hid->claimed = 0;
102 uhid_queue_event(uhid, UHID_STOP);
d365c6cf
DH
103}
104
105static int uhid_hid_open(struct hid_device *hid)
106{
e7191474
DH
107 struct uhid_device *uhid = hid->driver_data;
108
109 return uhid_queue_event(uhid, UHID_OPEN);
d365c6cf
DH
110}
111
112static void uhid_hid_close(struct hid_device *hid)
113{
e7191474
DH
114 struct uhid_device *uhid = hid->driver_data;
115
116 uhid_queue_event(uhid, UHID_CLOSE);
d365c6cf
DH
117}
118
d365c6cf
DH
119static int uhid_hid_parse(struct hid_device *hid)
120{
037c061b
DH
121 struct uhid_device *uhid = hid->driver_data;
122
123 return hid_parse_report(hid, uhid->rd_data, uhid->rd_size);
d365c6cf
DH
124}
125
d365c6cf
DH
126static int uhid_hid_output_raw(struct hid_device *hid, __u8 *buf, size_t count,
127 unsigned char report_type)
128{
3b3baa82
DH
129 struct uhid_device *uhid = hid->driver_data;
130 __u8 rtype;
131 unsigned long flags;
132 struct uhid_event *ev;
133
134 switch (report_type) {
135 case HID_FEATURE_REPORT:
136 rtype = UHID_FEATURE_REPORT;
137 break;
138 case HID_OUTPUT_REPORT:
139 rtype = UHID_OUTPUT_REPORT;
140 break;
141 default:
142 return -EINVAL;
143 }
144
145 if (count < 1 || count > UHID_DATA_MAX)
146 return -EINVAL;
147
148 ev = kzalloc(sizeof(*ev), GFP_KERNEL);
149 if (!ev)
150 return -ENOMEM;
151
152 ev->type = UHID_OUTPUT;
153 ev->u.output.size = count;
154 ev->u.output.rtype = rtype;
155 memcpy(ev->u.output.data, buf, count);
156
157 spin_lock_irqsave(&uhid->qlock, flags);
158 uhid_queue(uhid, ev);
159 spin_unlock_irqrestore(&uhid->qlock, flags);
160
161 return count;
d365c6cf
DH
162}
163
596cfdd8
FP
164static int uhid_hid_output_report(struct hid_device *hid, __u8 *buf,
165 size_t count)
166{
167 struct uhid_device *uhid = hid->driver_data;
168 unsigned long flags;
169 struct uhid_event *ev;
170
171 if (count < 1 || count > UHID_DATA_MAX)
172 return -EINVAL;
173
174 ev = kzalloc(sizeof(*ev), GFP_KERNEL);
175 if (!ev)
176 return -ENOMEM;
177
178 ev->type = UHID_OUTPUT;
179 ev->u.output.size = count;
180 ev->u.output.rtype = UHID_OUTPUT_REPORT;
181 memcpy(ev->u.output.data, buf, count);
182
183 spin_lock_irqsave(&uhid->qlock, flags);
184 uhid_queue(uhid, ev);
185 spin_unlock_irqrestore(&uhid->qlock, flags);
186
187 return count;
188}
189
d365c6cf
DH
190static struct hid_ll_driver uhid_hid_driver = {
191 .start = uhid_hid_start,
192 .stop = uhid_hid_stop,
193 .open = uhid_hid_open,
194 .close = uhid_hid_close,
d365c6cf 195 .parse = uhid_hid_parse,
596cfdd8 196 .output_report = uhid_hid_output_report,
d365c6cf
DH
197};
198
befde022
DT
199#ifdef CONFIG_COMPAT
200
201/* Apparently we haven't stepped on these rakes enough times yet. */
202struct uhid_create_req_compat {
203 __u8 name[128];
204 __u8 phys[64];
205 __u8 uniq[64];
206
207 compat_uptr_t rd_data;
208 __u16 rd_size;
209
210 __u16 bus;
211 __u32 vendor;
212 __u32 product;
213 __u32 version;
214 __u32 country;
215} __attribute__((__packed__));
216
217static int uhid_event_from_user(const char __user *buffer, size_t len,
218 struct uhid_event *event)
219{
220 if (is_compat_task()) {
221 u32 type;
222
223 if (get_user(type, buffer))
224 return -EFAULT;
225
226 if (type == UHID_CREATE) {
227 /*
228 * This is our messed up request with compat pointer.
229 * It is largish (more than 256 bytes) so we better
230 * allocate it from the heap.
231 */
232 struct uhid_create_req_compat *compat;
233
80897aa7 234 compat = kzalloc(sizeof(*compat), GFP_KERNEL);
befde022
DT
235 if (!compat)
236 return -ENOMEM;
237
238 buffer += sizeof(type);
239 len -= sizeof(type);
240 if (copy_from_user(compat, buffer,
241 min(len, sizeof(*compat)))) {
242 kfree(compat);
243 return -EFAULT;
244 }
245
246 /* Shuffle the data over to proper structure */
247 event->type = type;
248
249 memcpy(event->u.create.name, compat->name,
250 sizeof(compat->name));
251 memcpy(event->u.create.phys, compat->phys,
252 sizeof(compat->phys));
253 memcpy(event->u.create.uniq, compat->uniq,
254 sizeof(compat->uniq));
255
256 event->u.create.rd_data = compat_ptr(compat->rd_data);
257 event->u.create.rd_size = compat->rd_size;
258
259 event->u.create.bus = compat->bus;
260 event->u.create.vendor = compat->vendor;
261 event->u.create.product = compat->product;
262 event->u.create.version = compat->version;
263 event->u.create.country = compat->country;
264
265 kfree(compat);
266 return 0;
267 }
268 /* All others can be copied directly */
269 }
270
271 if (copy_from_user(event, buffer, min(len, sizeof(*event))))
272 return -EFAULT;
273
274 return 0;
275}
276#else
277static int uhid_event_from_user(const char __user *buffer, size_t len,
278 struct uhid_event *event)
279{
280 if (copy_from_user(event, buffer, min(len, sizeof(*event))))
281 return -EFAULT;
282
283 return 0;
284}
285#endif
286
d365c6cf
DH
287static int uhid_dev_create(struct uhid_device *uhid,
288 const struct uhid_event *ev)
289{
290 struct hid_device *hid;
291 int ret;
292
293 if (uhid->running)
294 return -EALREADY;
295
296 uhid->rd_size = ev->u.create.rd_size;
297 if (uhid->rd_size <= 0 || uhid->rd_size > HID_MAX_DESCRIPTOR_SIZE)
298 return -EINVAL;
299
300 uhid->rd_data = kmalloc(uhid->rd_size, GFP_KERNEL);
301 if (!uhid->rd_data)
302 return -ENOMEM;
303
304 if (copy_from_user(uhid->rd_data, ev->u.create.rd_data,
305 uhid->rd_size)) {
306 ret = -EFAULT;
307 goto err_free;
308 }
309
310 hid = hid_allocate_device();
311 if (IS_ERR(hid)) {
312 ret = PTR_ERR(hid);
313 goto err_free;
314 }
315
316 strncpy(hid->name, ev->u.create.name, 127);
317 hid->name[127] = 0;
318 strncpy(hid->phys, ev->u.create.phys, 63);
319 hid->phys[63] = 0;
320 strncpy(hid->uniq, ev->u.create.uniq, 63);
321 hid->uniq[63] = 0;
322
323 hid->ll_driver = &uhid_hid_driver;
d365c6cf
DH
324 hid->hid_output_raw_report = uhid_hid_output_raw;
325 hid->bus = ev->u.create.bus;
326 hid->vendor = ev->u.create.vendor;
327 hid->product = ev->u.create.product;
328 hid->version = ev->u.create.version;
329 hid->country = ev->u.create.country;
330 hid->driver_data = uhid;
331 hid->dev.parent = uhid_misc.this_device;
332
333 uhid->hid = hid;
334 uhid->running = true;
335
336 ret = hid_add_device(hid);
337 if (ret) {
338 hid_err(hid, "Cannot register HID device\n");
339 goto err_hid;
340 }
341
342 return 0;
343
344err_hid:
345 hid_destroy_device(hid);
346 uhid->hid = NULL;
347 uhid->running = false;
348err_free:
349 kfree(uhid->rd_data);
350 return ret;
351}
352
353static int uhid_dev_destroy(struct uhid_device *uhid)
354{
355 if (!uhid->running)
356 return -EINVAL;
357
fcfcf0de 358 /* clear "running" before setting "report_done" */
d365c6cf 359 uhid->running = false;
fcfcf0de
DH
360 smp_wmb();
361 atomic_set(&uhid->report_done, 1);
362 wake_up_interruptible(&uhid->report_wait);
d365c6cf
DH
363
364 hid_destroy_device(uhid->hid);
365 kfree(uhid->rd_data);
366
367 return 0;
368}
369
5e87a36a
DH
370static int uhid_dev_input(struct uhid_device *uhid, struct uhid_event *ev)
371{
372 if (!uhid->running)
373 return -EINVAL;
374
375 hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input.data,
376 min_t(size_t, ev->u.input.size, UHID_DATA_MAX), 0);
377
378 return 0;
379}
380
fcfcf0de
DH
381static int uhid_dev_feature_answer(struct uhid_device *uhid,
382 struct uhid_event *ev)
383{
384 unsigned long flags;
385
386 if (!uhid->running)
387 return -EINVAL;
388
389 spin_lock_irqsave(&uhid->qlock, flags);
390
391 /* id for old report; drop it silently */
392 if (atomic_read(&uhid->report_id) != ev->u.feature_answer.id)
393 goto unlock;
394 if (atomic_read(&uhid->report_done))
395 goto unlock;
396
397 memcpy(&uhid->report_buf, ev, sizeof(*ev));
398 atomic_set(&uhid->report_done, 1);
399 wake_up_interruptible(&uhid->report_wait);
400
401unlock:
402 spin_unlock_irqrestore(&uhid->qlock, flags);
403 return 0;
404}
405
1ccd7a2a
DH
406static int uhid_char_open(struct inode *inode, struct file *file)
407{
ace3d861
DH
408 struct uhid_device *uhid;
409
410 uhid = kzalloc(sizeof(*uhid), GFP_KERNEL);
411 if (!uhid)
412 return -ENOMEM;
413
d937ae5f 414 mutex_init(&uhid->devlock);
fcfcf0de 415 mutex_init(&uhid->report_lock);
ace3d861
DH
416 spin_lock_init(&uhid->qlock);
417 init_waitqueue_head(&uhid->waitq);
fcfcf0de 418 init_waitqueue_head(&uhid->report_wait);
d365c6cf 419 uhid->running = false;
fcfcf0de 420 atomic_set(&uhid->report_done, 1);
ace3d861
DH
421
422 file->private_data = uhid;
423 nonseekable_open(inode, file);
424
1ccd7a2a
DH
425 return 0;
426}
427
428static int uhid_char_release(struct inode *inode, struct file *file)
429{
ace3d861
DH
430 struct uhid_device *uhid = file->private_data;
431 unsigned int i;
432
d365c6cf
DH
433 uhid_dev_destroy(uhid);
434
ace3d861
DH
435 for (i = 0; i < UHID_BUFSIZE; ++i)
436 kfree(uhid->outq[i]);
437
438 kfree(uhid);
439
1ccd7a2a
DH
440 return 0;
441}
442
443static ssize_t uhid_char_read(struct file *file, char __user *buffer,
444 size_t count, loff_t *ppos)
445{
d937ae5f
DH
446 struct uhid_device *uhid = file->private_data;
447 int ret;
448 unsigned long flags;
449 size_t len;
450
451 /* they need at least the "type" member of uhid_event */
452 if (count < sizeof(__u32))
453 return -EINVAL;
454
455try_again:
456 if (file->f_flags & O_NONBLOCK) {
457 if (uhid->head == uhid->tail)
458 return -EAGAIN;
459 } else {
460 ret = wait_event_interruptible(uhid->waitq,
461 uhid->head != uhid->tail);
462 if (ret)
463 return ret;
464 }
465
466 ret = mutex_lock_interruptible(&uhid->devlock);
467 if (ret)
468 return ret;
469
470 if (uhid->head == uhid->tail) {
471 mutex_unlock(&uhid->devlock);
472 goto try_again;
473 } else {
474 len = min(count, sizeof(**uhid->outq));
adefb69b 475 if (copy_to_user(buffer, uhid->outq[uhid->tail], len)) {
d937ae5f
DH
476 ret = -EFAULT;
477 } else {
478 kfree(uhid->outq[uhid->tail]);
479 uhid->outq[uhid->tail] = NULL;
480
481 spin_lock_irqsave(&uhid->qlock, flags);
482 uhid->tail = (uhid->tail + 1) % UHID_BUFSIZE;
483 spin_unlock_irqrestore(&uhid->qlock, flags);
484 }
485 }
486
487 mutex_unlock(&uhid->devlock);
488 return ret ? ret : len;
1ccd7a2a
DH
489}
490
491static ssize_t uhid_char_write(struct file *file, const char __user *buffer,
492 size_t count, loff_t *ppos)
493{
6664ef72
DH
494 struct uhid_device *uhid = file->private_data;
495 int ret;
496 size_t len;
497
498 /* we need at least the "type" member of uhid_event */
499 if (count < sizeof(__u32))
500 return -EINVAL;
501
502 ret = mutex_lock_interruptible(&uhid->devlock);
503 if (ret)
504 return ret;
505
506 memset(&uhid->input_buf, 0, sizeof(uhid->input_buf));
507 len = min(count, sizeof(uhid->input_buf));
befde022
DT
508
509 ret = uhid_event_from_user(buffer, len, &uhid->input_buf);
510 if (ret)
6664ef72 511 goto unlock;
6664ef72
DH
512
513 switch (uhid->input_buf.type) {
d365c6cf
DH
514 case UHID_CREATE:
515 ret = uhid_dev_create(uhid, &uhid->input_buf);
516 break;
517 case UHID_DESTROY:
518 ret = uhid_dev_destroy(uhid);
519 break;
5e87a36a
DH
520 case UHID_INPUT:
521 ret = uhid_dev_input(uhid, &uhid->input_buf);
522 break;
fcfcf0de
DH
523 case UHID_FEATURE_ANSWER:
524 ret = uhid_dev_feature_answer(uhid, &uhid->input_buf);
525 break;
6664ef72
DH
526 default:
527 ret = -EOPNOTSUPP;
528 }
529
530unlock:
531 mutex_unlock(&uhid->devlock);
532
533 /* return "count" not "len" to not confuse the caller */
534 return ret ? ret : count;
1ccd7a2a
DH
535}
536
537static unsigned int uhid_char_poll(struct file *file, poll_table *wait)
538{
1f9dec1e
DH
539 struct uhid_device *uhid = file->private_data;
540
541 poll_wait(file, &uhid->waitq, wait);
542
543 if (uhid->head != uhid->tail)
544 return POLLIN | POLLRDNORM;
545
1ccd7a2a
DH
546 return 0;
547}
548
549static const struct file_operations uhid_fops = {
550 .owner = THIS_MODULE,
551 .open = uhid_char_open,
552 .release = uhid_char_release,
553 .read = uhid_char_read,
554 .write = uhid_char_write,
555 .poll = uhid_char_poll,
556 .llseek = no_llseek,
557};
558
559static struct miscdevice uhid_misc = {
560 .fops = &uhid_fops,
19872d20 561 .minor = UHID_MINOR,
1ccd7a2a
DH
562 .name = UHID_NAME,
563};
564
565static int __init uhid_init(void)
566{
567 return misc_register(&uhid_misc);
568}
569
570static void __exit uhid_exit(void)
571{
572 misc_deregister(&uhid_misc);
573}
574
575module_init(uhid_init);
576module_exit(uhid_exit);
577MODULE_LICENSE("GPL");
578MODULE_AUTHOR("David Herrmann <dh.herrmann@gmail.com>");
579MODULE_DESCRIPTION("User-space I/O driver support for HID subsystem");
19872d20 580MODULE_ALIAS_MISCDEV(UHID_MINOR);
60cbd53e 581MODULE_ALIAS("devname:" UHID_NAME);
This page took 0.199271 seconds and 5 git commands to generate.