blob: c05b544cf588a11cb218aaa3a594170abcc67be8 [file] [log] [blame]
David Herrmann1ccd7a22012-06-10 15:16:13 +02001/*
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>
Dmitry Torokhovbefde022013-02-18 11:26:11 +010014#include <linux/compat.h>
David Herrmann1ccd7a22012-06-10 15:16:13 +020015#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"
David Herrmannace3d862012-06-10 15:16:14 +020029#define UHID_BUFSIZE 32
30
31struct uhid_device {
David Herrmannd937ae52012-06-10 15:16:16 +020032 struct mutex devlock;
David Herrmannd365c6c2012-06-10 15:16:18 +020033 bool running;
34
35 __u8 *rd_data;
36 uint rd_size;
37
David Herrmannace3d862012-06-10 15:16:14 +020038 struct hid_device *hid;
David Herrmann6664ef72012-06-10 15:16:17 +020039 struct uhid_event input_buf;
David Herrmannace3d862012-06-10 15:16:14 +020040
41 wait_queue_head_t waitq;
42 spinlock_t qlock;
43 __u8 head;
44 __u8 tail;
45 struct uhid_event *outq[UHID_BUFSIZE];
David Herrmannfcfcf0d2012-06-10 15:16:25 +020046
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;
David Herrmannace3d862012-06-10 15:16:14 +020052};
David Herrmann1ccd7a22012-06-10 15:16:13 +020053
54static struct miscdevice uhid_misc;
55
David Herrmannace3d862012-06-10 15:16:14 +020056static 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
David Herrmannd365c6c2012-06-10 15:16:18 +020090static int uhid_hid_start(struct hid_device *hid)
91{
David Herrmannec4b7de2012-06-10 15:16:21 +020092 struct uhid_device *uhid = hid->driver_data;
93
94 return uhid_queue_event(uhid, UHID_START);
David Herrmannd365c6c2012-06-10 15:16:18 +020095}
96
97static void uhid_hid_stop(struct hid_device *hid)
98{
David Herrmannec4b7de2012-06-10 15:16:21 +020099 struct uhid_device *uhid = hid->driver_data;
100
101 hid->claimed = 0;
102 uhid_queue_event(uhid, UHID_STOP);
David Herrmannd365c6c2012-06-10 15:16:18 +0200103}
104
105static int uhid_hid_open(struct hid_device *hid)
106{
David Herrmanne7191472012-06-10 15:16:22 +0200107 struct uhid_device *uhid = hid->driver_data;
108
109 return uhid_queue_event(uhid, UHID_OPEN);
David Herrmannd365c6c2012-06-10 15:16:18 +0200110}
111
112static void uhid_hid_close(struct hid_device *hid)
113{
David Herrmanne7191472012-06-10 15:16:22 +0200114 struct uhid_device *uhid = hid->driver_data;
115
116 uhid_queue_event(uhid, UHID_CLOSE);
David Herrmannd365c6c2012-06-10 15:16:18 +0200117}
118
David Herrmannd365c6c2012-06-10 15:16:18 +0200119static int uhid_hid_parse(struct hid_device *hid)
120{
David Herrmann037c0612012-06-10 15:16:20 +0200121 struct uhid_device *uhid = hid->driver_data;
122
123 return hid_parse_report(hid, uhid->rd_data, uhid->rd_size);
David Herrmannd365c6c2012-06-10 15:16:18 +0200124}
125
Jiri Kosina289a7162014-02-17 14:49:34 +0100126static int uhid_hid_get_raw(struct hid_device *hid, unsigned char rnum,
127 __u8 *buf, size_t count, unsigned char rtype)
128{
129 struct uhid_device *uhid = hid->driver_data;
130 __u8 report_type;
131 struct uhid_event *ev;
132 unsigned long flags;
133 int ret;
134 size_t uninitialized_var(len);
135 struct uhid_feature_answer_req *req;
136
137 if (!uhid->running)
138 return -EIO;
139
140 switch (rtype) {
141 case HID_FEATURE_REPORT:
142 report_type = UHID_FEATURE_REPORT;
143 break;
144 case HID_OUTPUT_REPORT:
145 report_type = UHID_OUTPUT_REPORT;
146 break;
147 case HID_INPUT_REPORT:
148 report_type = UHID_INPUT_REPORT;
149 break;
150 default:
151 return -EINVAL;
152 }
153
154 ret = mutex_lock_interruptible(&uhid->report_lock);
155 if (ret)
156 return ret;
157
158 ev = kzalloc(sizeof(*ev), GFP_KERNEL);
159 if (!ev) {
160 ret = -ENOMEM;
161 goto unlock;
162 }
163
164 spin_lock_irqsave(&uhid->qlock, flags);
165 ev->type = UHID_FEATURE;
166 ev->u.feature.id = atomic_inc_return(&uhid->report_id);
167 ev->u.feature.rnum = rnum;
168 ev->u.feature.rtype = report_type;
169
170 atomic_set(&uhid->report_done, 0);
171 uhid_queue(uhid, ev);
172 spin_unlock_irqrestore(&uhid->qlock, flags);
173
174 ret = wait_event_interruptible_timeout(uhid->report_wait,
David Herrmann0e0d7522014-07-29 17:14:15 +0200175 atomic_read(&uhid->report_done) || !uhid->running,
176 5 * HZ);
Jiri Kosina289a7162014-02-17 14:49:34 +0100177
Jiri Kosina289a7162014-02-17 14:49:34 +0100178 if (!ret || !uhid->running) {
179 ret = -EIO;
180 } else if (ret < 0) {
181 ret = -ERESTARTSYS;
182 } else {
183 spin_lock_irqsave(&uhid->qlock, flags);
184 req = &uhid->report_buf.u.feature_answer;
185
186 if (req->err) {
187 ret = -EIO;
188 } else {
189 ret = 0;
190 len = min(count,
191 min_t(size_t, req->size, UHID_DATA_MAX));
192 memcpy(buf, req->data, len);
193 }
194
195 spin_unlock_irqrestore(&uhid->qlock, flags);
196 }
197
198 atomic_set(&uhid->report_done, 1);
199
200unlock:
201 mutex_unlock(&uhid->report_lock);
202 return ret ? ret : len;
203}
204
David Herrmannd365c6c2012-06-10 15:16:18 +0200205static int uhid_hid_output_raw(struct hid_device *hid, __u8 *buf, size_t count,
206 unsigned char report_type)
207{
David Herrmann3b3baa82012-06-10 15:16:24 +0200208 struct uhid_device *uhid = hid->driver_data;
209 __u8 rtype;
210 unsigned long flags;
211 struct uhid_event *ev;
212
213 switch (report_type) {
214 case HID_FEATURE_REPORT:
215 rtype = UHID_FEATURE_REPORT;
216 break;
217 case HID_OUTPUT_REPORT:
218 rtype = UHID_OUTPUT_REPORT;
219 break;
220 default:
221 return -EINVAL;
222 }
223
224 if (count < 1 || count > UHID_DATA_MAX)
225 return -EINVAL;
226
227 ev = kzalloc(sizeof(*ev), GFP_KERNEL);
228 if (!ev)
229 return -ENOMEM;
230
231 ev->type = UHID_OUTPUT;
232 ev->u.output.size = count;
233 ev->u.output.rtype = rtype;
234 memcpy(ev->u.output.data, buf, count);
235
236 spin_lock_irqsave(&uhid->qlock, flags);
237 uhid_queue(uhid, ev);
238 spin_unlock_irqrestore(&uhid->qlock, flags);
239
240 return count;
David Herrmannd365c6c2012-06-10 15:16:18 +0200241}
242
Frank Praznik596cfdd2014-01-22 13:49:43 -0500243static int uhid_hid_output_report(struct hid_device *hid, __u8 *buf,
244 size_t count)
245{
Benjamin Tissoires41abfb32014-02-10 12:58:46 -0500246 return uhid_hid_output_raw(hid, buf, count, HID_OUTPUT_REPORT);
Frank Praznik596cfdd2014-01-22 13:49:43 -0500247}
248
Benjamin Tissoires706daef2014-02-10 12:58:47 -0500249static int uhid_raw_request(struct hid_device *hid, unsigned char reportnum,
250 __u8 *buf, size_t len, unsigned char rtype,
251 int reqtype)
252{
253 switch (reqtype) {
254 case HID_REQ_GET_REPORT:
255 return uhid_hid_get_raw(hid, reportnum, buf, len, rtype);
256 case HID_REQ_SET_REPORT:
257 /* TODO: implement proper SET_REPORT functionality */
258 return -ENOSYS;
259 default:
260 return -EIO;
261 }
262}
263
David Herrmannd365c6c2012-06-10 15:16:18 +0200264static struct hid_ll_driver uhid_hid_driver = {
265 .start = uhid_hid_start,
266 .stop = uhid_hid_stop,
267 .open = uhid_hid_open,
268 .close = uhid_hid_close,
David Herrmannd365c6c2012-06-10 15:16:18 +0200269 .parse = uhid_hid_parse,
Frank Praznik596cfdd2014-01-22 13:49:43 -0500270 .output_report = uhid_hid_output_report,
Benjamin Tissoires706daef2014-02-10 12:58:47 -0500271 .raw_request = uhid_raw_request,
David Herrmannd365c6c2012-06-10 15:16:18 +0200272};
273
Dmitry Torokhovbefde022013-02-18 11:26:11 +0100274#ifdef CONFIG_COMPAT
275
276/* Apparently we haven't stepped on these rakes enough times yet. */
277struct uhid_create_req_compat {
278 __u8 name[128];
279 __u8 phys[64];
280 __u8 uniq[64];
281
282 compat_uptr_t rd_data;
283 __u16 rd_size;
284
285 __u16 bus;
286 __u32 vendor;
287 __u32 product;
288 __u32 version;
289 __u32 country;
290} __attribute__((__packed__));
291
292static int uhid_event_from_user(const char __user *buffer, size_t len,
293 struct uhid_event *event)
294{
295 if (is_compat_task()) {
296 u32 type;
297
298 if (get_user(type, buffer))
299 return -EFAULT;
300
301 if (type == UHID_CREATE) {
302 /*
303 * This is our messed up request with compat pointer.
304 * It is largish (more than 256 bytes) so we better
305 * allocate it from the heap.
306 */
307 struct uhid_create_req_compat *compat;
308
David Herrmann80897aa2013-11-26 13:58:18 +0100309 compat = kzalloc(sizeof(*compat), GFP_KERNEL);
Dmitry Torokhovbefde022013-02-18 11:26:11 +0100310 if (!compat)
311 return -ENOMEM;
312
313 buffer += sizeof(type);
314 len -= sizeof(type);
315 if (copy_from_user(compat, buffer,
316 min(len, sizeof(*compat)))) {
317 kfree(compat);
318 return -EFAULT;
319 }
320
321 /* Shuffle the data over to proper structure */
322 event->type = type;
323
324 memcpy(event->u.create.name, compat->name,
325 sizeof(compat->name));
326 memcpy(event->u.create.phys, compat->phys,
327 sizeof(compat->phys));
328 memcpy(event->u.create.uniq, compat->uniq,
329 sizeof(compat->uniq));
330
331 event->u.create.rd_data = compat_ptr(compat->rd_data);
332 event->u.create.rd_size = compat->rd_size;
333
334 event->u.create.bus = compat->bus;
335 event->u.create.vendor = compat->vendor;
336 event->u.create.product = compat->product;
337 event->u.create.version = compat->version;
338 event->u.create.country = compat->country;
339
340 kfree(compat);
341 return 0;
342 }
343 /* All others can be copied directly */
344 }
345
346 if (copy_from_user(event, buffer, min(len, sizeof(*event))))
347 return -EFAULT;
348
349 return 0;
350}
351#else
352static int uhid_event_from_user(const char __user *buffer, size_t len,
353 struct uhid_event *event)
354{
355 if (copy_from_user(event, buffer, min(len, sizeof(*event))))
356 return -EFAULT;
357
358 return 0;
359}
360#endif
361
Petri Gynther45226432014-03-24 13:50:01 -0700362static int uhid_dev_create2(struct uhid_device *uhid,
363 const struct uhid_event *ev)
364{
365 struct hid_device *hid;
366 int ret;
367
368 if (uhid->running)
369 return -EALREADY;
370
371 uhid->rd_size = ev->u.create2.rd_size;
372 if (uhid->rd_size <= 0 || uhid->rd_size > HID_MAX_DESCRIPTOR_SIZE)
373 return -EINVAL;
374
Benoit Taine662d4ce2014-05-26 17:21:25 +0200375 uhid->rd_data = kmemdup(ev->u.create2.rd_data, uhid->rd_size,
376 GFP_KERNEL);
Petri Gynther45226432014-03-24 13:50:01 -0700377 if (!uhid->rd_data)
378 return -ENOMEM;
379
Petri Gynther45226432014-03-24 13:50:01 -0700380 hid = hid_allocate_device();
381 if (IS_ERR(hid)) {
382 ret = PTR_ERR(hid);
383 goto err_free;
384 }
385
386 strncpy(hid->name, ev->u.create2.name, 127);
387 hid->name[127] = 0;
388 strncpy(hid->phys, ev->u.create2.phys, 63);
389 hid->phys[63] = 0;
390 strncpy(hid->uniq, ev->u.create2.uniq, 63);
391 hid->uniq[63] = 0;
392
393 hid->ll_driver = &uhid_hid_driver;
394 hid->bus = ev->u.create2.bus;
395 hid->vendor = ev->u.create2.vendor;
396 hid->product = ev->u.create2.product;
397 hid->version = ev->u.create2.version;
398 hid->country = ev->u.create2.country;
399 hid->driver_data = uhid;
400 hid->dev.parent = uhid_misc.this_device;
401
402 uhid->hid = hid;
403 uhid->running = true;
404
405 ret = hid_add_device(hid);
406 if (ret) {
407 hid_err(hid, "Cannot register HID device\n");
408 goto err_hid;
409 }
410
411 return 0;
412
413err_hid:
414 hid_destroy_device(hid);
415 uhid->hid = NULL;
416 uhid->running = false;
417err_free:
418 kfree(uhid->rd_data);
419 return ret;
420}
421
David Herrmann56c47752014-07-29 17:14:16 +0200422static int uhid_dev_create(struct uhid_device *uhid,
423 struct uhid_event *ev)
424{
425 struct uhid_create_req orig;
426
427 orig = ev->u.create;
428
429 if (orig.rd_size <= 0 || orig.rd_size > HID_MAX_DESCRIPTOR_SIZE)
430 return -EINVAL;
431 if (copy_from_user(&ev->u.create2.rd_data, orig.rd_data, orig.rd_size))
432 return -EFAULT;
433
434 memcpy(ev->u.create2.name, orig.name, sizeof(orig.name));
435 memcpy(ev->u.create2.phys, orig.phys, sizeof(orig.phys));
436 memcpy(ev->u.create2.uniq, orig.uniq, sizeof(orig.uniq));
437 ev->u.create2.rd_size = orig.rd_size;
438 ev->u.create2.bus = orig.bus;
439 ev->u.create2.vendor = orig.vendor;
440 ev->u.create2.product = orig.product;
441 ev->u.create2.version = orig.version;
442 ev->u.create2.country = orig.country;
443
444 return uhid_dev_create2(uhid, ev);
445}
446
David Herrmannd365c6c2012-06-10 15:16:18 +0200447static int uhid_dev_destroy(struct uhid_device *uhid)
448{
449 if (!uhid->running)
450 return -EINVAL;
451
452 uhid->running = false;
David Herrmannfcfcf0d2012-06-10 15:16:25 +0200453 wake_up_interruptible(&uhid->report_wait);
David Herrmannd365c6c2012-06-10 15:16:18 +0200454
455 hid_destroy_device(uhid->hid);
456 kfree(uhid->rd_data);
457
458 return 0;
459}
460
David Herrmann5e87a362012-06-10 15:16:19 +0200461static int uhid_dev_input(struct uhid_device *uhid, struct uhid_event *ev)
462{
463 if (!uhid->running)
464 return -EINVAL;
465
466 hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input.data,
467 min_t(size_t, ev->u.input.size, UHID_DATA_MAX), 0);
468
469 return 0;
470}
471
Petri Gynther45226432014-03-24 13:50:01 -0700472static int uhid_dev_input2(struct uhid_device *uhid, struct uhid_event *ev)
473{
474 if (!uhid->running)
475 return -EINVAL;
476
477 hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input2.data,
478 min_t(size_t, ev->u.input2.size, UHID_DATA_MAX), 0);
479
480 return 0;
481}
482
David Herrmannfcfcf0d2012-06-10 15:16:25 +0200483static int uhid_dev_feature_answer(struct uhid_device *uhid,
484 struct uhid_event *ev)
485{
486 unsigned long flags;
487
488 if (!uhid->running)
489 return -EINVAL;
490
491 spin_lock_irqsave(&uhid->qlock, flags);
492
493 /* id for old report; drop it silently */
494 if (atomic_read(&uhid->report_id) != ev->u.feature_answer.id)
495 goto unlock;
496 if (atomic_read(&uhid->report_done))
497 goto unlock;
498
499 memcpy(&uhid->report_buf, ev, sizeof(*ev));
500 atomic_set(&uhid->report_done, 1);
501 wake_up_interruptible(&uhid->report_wait);
502
503unlock:
504 spin_unlock_irqrestore(&uhid->qlock, flags);
505 return 0;
506}
507
David Herrmann1ccd7a22012-06-10 15:16:13 +0200508static int uhid_char_open(struct inode *inode, struct file *file)
509{
David Herrmannace3d862012-06-10 15:16:14 +0200510 struct uhid_device *uhid;
511
512 uhid = kzalloc(sizeof(*uhid), GFP_KERNEL);
513 if (!uhid)
514 return -ENOMEM;
515
David Herrmannd937ae52012-06-10 15:16:16 +0200516 mutex_init(&uhid->devlock);
David Herrmannfcfcf0d2012-06-10 15:16:25 +0200517 mutex_init(&uhid->report_lock);
David Herrmannace3d862012-06-10 15:16:14 +0200518 spin_lock_init(&uhid->qlock);
519 init_waitqueue_head(&uhid->waitq);
David Herrmannfcfcf0d2012-06-10 15:16:25 +0200520 init_waitqueue_head(&uhid->report_wait);
David Herrmannd365c6c2012-06-10 15:16:18 +0200521 uhid->running = false;
David Herrmannfcfcf0d2012-06-10 15:16:25 +0200522 atomic_set(&uhid->report_done, 1);
David Herrmannace3d862012-06-10 15:16:14 +0200523
524 file->private_data = uhid;
525 nonseekable_open(inode, file);
526
David Herrmann1ccd7a22012-06-10 15:16:13 +0200527 return 0;
528}
529
530static int uhid_char_release(struct inode *inode, struct file *file)
531{
David Herrmannace3d862012-06-10 15:16:14 +0200532 struct uhid_device *uhid = file->private_data;
533 unsigned int i;
534
David Herrmannd365c6c2012-06-10 15:16:18 +0200535 uhid_dev_destroy(uhid);
536
David Herrmannace3d862012-06-10 15:16:14 +0200537 for (i = 0; i < UHID_BUFSIZE; ++i)
538 kfree(uhid->outq[i]);
539
540 kfree(uhid);
541
David Herrmann1ccd7a22012-06-10 15:16:13 +0200542 return 0;
543}
544
545static ssize_t uhid_char_read(struct file *file, char __user *buffer,
546 size_t count, loff_t *ppos)
547{
David Herrmannd937ae52012-06-10 15:16:16 +0200548 struct uhid_device *uhid = file->private_data;
549 int ret;
550 unsigned long flags;
551 size_t len;
552
553 /* they need at least the "type" member of uhid_event */
554 if (count < sizeof(__u32))
555 return -EINVAL;
556
557try_again:
558 if (file->f_flags & O_NONBLOCK) {
559 if (uhid->head == uhid->tail)
560 return -EAGAIN;
561 } else {
562 ret = wait_event_interruptible(uhid->waitq,
563 uhid->head != uhid->tail);
564 if (ret)
565 return ret;
566 }
567
568 ret = mutex_lock_interruptible(&uhid->devlock);
569 if (ret)
570 return ret;
571
572 if (uhid->head == uhid->tail) {
573 mutex_unlock(&uhid->devlock);
574 goto try_again;
575 } else {
576 len = min(count, sizeof(**uhid->outq));
Vinicius Costa Gomesadefb692012-07-14 18:59:25 -0300577 if (copy_to_user(buffer, uhid->outq[uhid->tail], len)) {
David Herrmannd937ae52012-06-10 15:16:16 +0200578 ret = -EFAULT;
579 } else {
580 kfree(uhid->outq[uhid->tail]);
581 uhid->outq[uhid->tail] = NULL;
582
583 spin_lock_irqsave(&uhid->qlock, flags);
584 uhid->tail = (uhid->tail + 1) % UHID_BUFSIZE;
585 spin_unlock_irqrestore(&uhid->qlock, flags);
586 }
587 }
588
589 mutex_unlock(&uhid->devlock);
590 return ret ? ret : len;
David Herrmann1ccd7a22012-06-10 15:16:13 +0200591}
592
593static ssize_t uhid_char_write(struct file *file, const char __user *buffer,
594 size_t count, loff_t *ppos)
595{
David Herrmann6664ef72012-06-10 15:16:17 +0200596 struct uhid_device *uhid = file->private_data;
597 int ret;
598 size_t len;
599
600 /* we need at least the "type" member of uhid_event */
601 if (count < sizeof(__u32))
602 return -EINVAL;
603
604 ret = mutex_lock_interruptible(&uhid->devlock);
605 if (ret)
606 return ret;
607
608 memset(&uhid->input_buf, 0, sizeof(uhid->input_buf));
609 len = min(count, sizeof(uhid->input_buf));
Dmitry Torokhovbefde022013-02-18 11:26:11 +0100610
611 ret = uhid_event_from_user(buffer, len, &uhid->input_buf);
612 if (ret)
David Herrmann6664ef72012-06-10 15:16:17 +0200613 goto unlock;
David Herrmann6664ef72012-06-10 15:16:17 +0200614
615 switch (uhid->input_buf.type) {
David Herrmannd365c6c2012-06-10 15:16:18 +0200616 case UHID_CREATE:
617 ret = uhid_dev_create(uhid, &uhid->input_buf);
618 break;
Petri Gynther45226432014-03-24 13:50:01 -0700619 case UHID_CREATE2:
620 ret = uhid_dev_create2(uhid, &uhid->input_buf);
621 break;
David Herrmannd365c6c2012-06-10 15:16:18 +0200622 case UHID_DESTROY:
623 ret = uhid_dev_destroy(uhid);
624 break;
David Herrmann5e87a362012-06-10 15:16:19 +0200625 case UHID_INPUT:
626 ret = uhid_dev_input(uhid, &uhid->input_buf);
627 break;
Petri Gynther45226432014-03-24 13:50:01 -0700628 case UHID_INPUT2:
629 ret = uhid_dev_input2(uhid, &uhid->input_buf);
630 break;
David Herrmannfcfcf0d2012-06-10 15:16:25 +0200631 case UHID_FEATURE_ANSWER:
632 ret = uhid_dev_feature_answer(uhid, &uhid->input_buf);
633 break;
David Herrmann6664ef72012-06-10 15:16:17 +0200634 default:
635 ret = -EOPNOTSUPP;
636 }
637
638unlock:
639 mutex_unlock(&uhid->devlock);
640
641 /* return "count" not "len" to not confuse the caller */
642 return ret ? ret : count;
David Herrmann1ccd7a22012-06-10 15:16:13 +0200643}
644
645static unsigned int uhid_char_poll(struct file *file, poll_table *wait)
646{
David Herrmann1f9dec12012-06-10 15:16:15 +0200647 struct uhid_device *uhid = file->private_data;
648
649 poll_wait(file, &uhid->waitq, wait);
650
651 if (uhid->head != uhid->tail)
652 return POLLIN | POLLRDNORM;
653
David Herrmann1ccd7a22012-06-10 15:16:13 +0200654 return 0;
655}
656
657static const struct file_operations uhid_fops = {
658 .owner = THIS_MODULE,
659 .open = uhid_char_open,
660 .release = uhid_char_release,
661 .read = uhid_char_read,
662 .write = uhid_char_write,
663 .poll = uhid_char_poll,
664 .llseek = no_llseek,
665};
666
667static struct miscdevice uhid_misc = {
668 .fops = &uhid_fops,
David Herrmann19872d22013-09-09 18:33:54 +0200669 .minor = UHID_MINOR,
David Herrmann1ccd7a22012-06-10 15:16:13 +0200670 .name = UHID_NAME,
671};
672
673static int __init uhid_init(void)
674{
675 return misc_register(&uhid_misc);
676}
677
678static void __exit uhid_exit(void)
679{
680 misc_deregister(&uhid_misc);
681}
682
683module_init(uhid_init);
684module_exit(uhid_exit);
685MODULE_LICENSE("GPL");
686MODULE_AUTHOR("David Herrmann <dh.herrmann@gmail.com>");
687MODULE_DESCRIPTION("User-space I/O driver support for HID subsystem");
David Herrmann19872d22013-09-09 18:33:54 +0200688MODULE_ALIAS_MISCDEV(UHID_MINOR);
Marcel Holtmann60cbd532013-09-01 11:02:46 -0700689MODULE_ALIAS("devname:" UHID_NAME);