Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-or-later
2 : : /*
3 : : * Copyright (c) 2001 Paul Stewart
4 : : * Copyright (c) 2001 Vojtech Pavlik
5 : : *
6 : : * HID char devices, giving access to raw HID device events.
7 : : */
8 : :
9 : : /*
10 : : *
11 : : * Should you need to contact me, the author, you can do so either by
12 : : * e-mail - mail your message to Paul Stewart <stewart@wetlogic.net>
13 : : */
14 : :
15 : : #include <linux/poll.h>
16 : : #include <linux/slab.h>
17 : : #include <linux/sched/signal.h>
18 : : #include <linux/module.h>
19 : : #include <linux/init.h>
20 : : #include <linux/input.h>
21 : : #include <linux/usb.h>
22 : : #include <linux/hid.h>
23 : : #include <linux/hiddev.h>
24 : : #include <linux/compat.h>
25 : : #include <linux/vmalloc.h>
26 : : #include <linux/nospec.h>
27 : : #include "usbhid.h"
28 : :
29 : : #ifdef CONFIG_USB_DYNAMIC_MINORS
30 : : #define HIDDEV_MINOR_BASE 0
31 : : #define HIDDEV_MINORS 256
32 : : #else
33 : : #define HIDDEV_MINOR_BASE 96
34 : : #define HIDDEV_MINORS 16
35 : : #endif
36 : : #define HIDDEV_BUFFER_SIZE 2048
37 : :
38 : : struct hiddev_list {
39 : : struct hiddev_usage_ref buffer[HIDDEV_BUFFER_SIZE];
40 : : int head;
41 : : int tail;
42 : : unsigned flags;
43 : : struct fasync_struct *fasync;
44 : : struct hiddev *hiddev;
45 : : struct list_head node;
46 : : struct mutex thread_lock;
47 : : };
48 : :
49 : : /*
50 : : * Find a report, given the report's type and ID. The ID can be specified
51 : : * indirectly by REPORT_ID_FIRST (which returns the first report of the given
52 : : * type) or by (REPORT_ID_NEXT | old_id), which returns the next report of the
53 : : * given type which follows old_id.
54 : : */
55 : : static struct hid_report *
56 : : hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo)
57 : : {
58 : : unsigned int flags = rinfo->report_id & ~HID_REPORT_ID_MASK;
59 : : unsigned int rid = rinfo->report_id & HID_REPORT_ID_MASK;
60 : : struct hid_report_enum *report_enum;
61 : : struct hid_report *report;
62 : : struct list_head *list;
63 : :
64 : : if (rinfo->report_type < HID_REPORT_TYPE_MIN ||
65 : : rinfo->report_type > HID_REPORT_TYPE_MAX)
66 : : return NULL;
67 : :
68 : : report_enum = hid->report_enum +
69 : : (rinfo->report_type - HID_REPORT_TYPE_MIN);
70 : :
71 : : switch (flags) {
72 : : case 0: /* Nothing to do -- report_id is already set correctly */
73 : : break;
74 : :
75 : : case HID_REPORT_ID_FIRST:
76 : : if (list_empty(&report_enum->report_list))
77 : : return NULL;
78 : :
79 : : list = report_enum->report_list.next;
80 : : report = list_entry(list, struct hid_report, list);
81 : : rinfo->report_id = report->id;
82 : : break;
83 : :
84 : : case HID_REPORT_ID_NEXT:
85 : : report = report_enum->report_id_hash[rid];
86 : : if (!report)
87 : : return NULL;
88 : :
89 : : list = report->list.next;
90 : : if (list == &report_enum->report_list)
91 : : return NULL;
92 : :
93 : : report = list_entry(list, struct hid_report, list);
94 : : rinfo->report_id = report->id;
95 : : break;
96 : :
97 : : default:
98 : : return NULL;
99 : : }
100 : :
101 : : return report_enum->report_id_hash[rinfo->report_id];
102 : : }
103 : :
104 : : /*
105 : : * Perform an exhaustive search of the report table for a usage, given its
106 : : * type and usage id.
107 : : */
108 : : static struct hid_field *
109 : 0 : hiddev_lookup_usage(struct hid_device *hid, struct hiddev_usage_ref *uref)
110 : : {
111 : 0 : int i, j;
112 : 0 : struct hid_report *report;
113 : 0 : struct hid_report_enum *report_enum;
114 : 0 : struct hid_field *field;
115 : :
116 [ # # ]: 0 : if (uref->report_type < HID_REPORT_TYPE_MIN ||
117 : : uref->report_type > HID_REPORT_TYPE_MAX)
118 : : return NULL;
119 : :
120 : 0 : report_enum = hid->report_enum +
121 : 0 : (uref->report_type - HID_REPORT_TYPE_MIN);
122 : :
123 [ # # ]: 0 : list_for_each_entry(report, &report_enum->report_list, list) {
124 [ # # ]: 0 : for (i = 0; i < report->maxfield; i++) {
125 : 0 : field = report->field[i];
126 [ # # ]: 0 : for (j = 0; j < field->maxusage; j++) {
127 [ # # ]: 0 : if (field->usage[j].hid == uref->usage_code) {
128 : 0 : uref->report_id = report->id;
129 : 0 : uref->field_index = i;
130 : 0 : uref->usage_index = j;
131 : 0 : return field;
132 : : }
133 : : }
134 : : }
135 : : }
136 : :
137 : : return NULL;
138 : : }
139 : :
140 : : static void hiddev_send_event(struct hid_device *hid,
141 : : struct hiddev_usage_ref *uref)
142 : : {
143 : : struct hiddev *hiddev = hid->hiddev;
144 : : struct hiddev_list *list;
145 : : unsigned long flags;
146 : :
147 : : spin_lock_irqsave(&hiddev->list_lock, flags);
148 : : list_for_each_entry(list, &hiddev->list, node) {
149 : : if (uref->field_index != HID_FIELD_INDEX_NONE ||
150 : : (list->flags & HIDDEV_FLAG_REPORT) != 0) {
151 : : list->buffer[list->head] = *uref;
152 : : list->head = (list->head + 1) &
153 : : (HIDDEV_BUFFER_SIZE - 1);
154 : : kill_fasync(&list->fasync, SIGIO, POLL_IN);
155 : : }
156 : : }
157 : : spin_unlock_irqrestore(&hiddev->list_lock, flags);
158 : :
159 : : wake_up_interruptible(&hiddev->wait);
160 : : }
161 : :
162 : : /*
163 : : * This is where hid.c calls into hiddev to pass an event that occurred over
164 : : * the interrupt pipe
165 : : */
166 : 0 : void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
167 : : struct hid_usage *usage, __s32 value)
168 : : {
169 : 0 : unsigned type = field->report_type;
170 : 0 : struct hiddev_usage_ref uref;
171 : :
172 : 0 : uref.report_type =
173 [ # # # # : 0 : (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT :
# # ]
174 : : ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT :
175 : : ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE : 0));
176 : 0 : uref.report_id = field->report->id;
177 : 0 : uref.field_index = field->index;
178 : 0 : uref.usage_index = (usage - field->usage);
179 : 0 : uref.usage_code = usage->hid;
180 : 0 : uref.value = value;
181 : :
182 : 0 : hiddev_send_event(hid, &uref);
183 : 0 : }
184 : : EXPORT_SYMBOL_GPL(hiddev_hid_event);
185 : :
186 : 0 : void hiddev_report_event(struct hid_device *hid, struct hid_report *report)
187 : : {
188 : 0 : unsigned type = report->type;
189 : 0 : struct hiddev_usage_ref uref;
190 : :
191 : 0 : memset(&uref, 0, sizeof(uref));
192 : 0 : uref.report_type =
193 [ # # # # : 0 : (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT :
# # ]
194 : : ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT :
195 : : ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE : 0));
196 : 0 : uref.report_id = report->id;
197 : 0 : uref.field_index = HID_FIELD_INDEX_NONE;
198 : :
199 : 0 : hiddev_send_event(hid, &uref);
200 : 0 : }
201 : :
202 : : /*
203 : : * fasync file op
204 : : */
205 : 0 : static int hiddev_fasync(int fd, struct file *file, int on)
206 : : {
207 : 0 : struct hiddev_list *list = file->private_data;
208 : :
209 : 0 : return fasync_helper(fd, file, on, &list->fasync);
210 : : }
211 : :
212 : :
213 : : /*
214 : : * release file op
215 : : */
216 : 0 : static int hiddev_release(struct inode * inode, struct file * file)
217 : : {
218 : 0 : struct hiddev_list *list = file->private_data;
219 : 0 : unsigned long flags;
220 : :
221 : 0 : spin_lock_irqsave(&list->hiddev->list_lock, flags);
222 : 0 : list_del(&list->node);
223 : 0 : spin_unlock_irqrestore(&list->hiddev->list_lock, flags);
224 : :
225 : 0 : mutex_lock(&list->hiddev->existancelock);
226 [ # # ]: 0 : if (!--list->hiddev->open) {
227 [ # # ]: 0 : if (list->hiddev->exist) {
228 : 0 : hid_hw_close(list->hiddev->hid);
229 [ # # ]: 0 : hid_hw_power(list->hiddev->hid, PM_HINT_NORMAL);
230 : : } else {
231 : 0 : mutex_unlock(&list->hiddev->existancelock);
232 : 0 : kfree(list->hiddev);
233 : 0 : vfree(list);
234 : 0 : return 0;
235 : : }
236 : : }
237 : :
238 : 0 : mutex_unlock(&list->hiddev->existancelock);
239 : 0 : vfree(list);
240 : :
241 : 0 : return 0;
242 : : }
243 : :
244 : : static int __hiddev_open(struct hiddev *hiddev, struct file *file)
245 : : {
246 : : struct hiddev_list *list;
247 : : int error;
248 : :
249 : : lockdep_assert_held(&hiddev->existancelock);
250 : :
251 : : list = vzalloc(sizeof(*list));
252 : : if (!list)
253 : : return -ENOMEM;
254 : :
255 : : mutex_init(&list->thread_lock);
256 : : list->hiddev = hiddev;
257 : :
258 : : if (!hiddev->open++) {
259 : : error = hid_hw_power(hiddev->hid, PM_HINT_FULLON);
260 : : if (error < 0)
261 : : goto err_drop_count;
262 : :
263 : : error = hid_hw_open(hiddev->hid);
264 : : if (error < 0)
265 : : goto err_normal_power;
266 : : }
267 : :
268 : : spin_lock_irq(&hiddev->list_lock);
269 : : list_add_tail(&list->node, &hiddev->list);
270 : : spin_unlock_irq(&hiddev->list_lock);
271 : :
272 : : file->private_data = list;
273 : :
274 : : return 0;
275 : :
276 : : err_normal_power:
277 : : hid_hw_power(hiddev->hid, PM_HINT_NORMAL);
278 : : err_drop_count:
279 : : hiddev->open--;
280 : : vfree(list);
281 : : return error;
282 : : }
283 : :
284 : : /*
285 : : * open file op
286 : : */
287 : 0 : static int hiddev_open(struct inode *inode, struct file *file)
288 : : {
289 : 0 : struct usb_interface *intf;
290 : 0 : struct hid_device *hid;
291 : 0 : struct hiddev *hiddev;
292 : 0 : int res;
293 : :
294 : 0 : intf = usbhid_find_interface(iminor(inode));
295 [ # # ]: 0 : if (!intf)
296 : : return -ENODEV;
297 : :
298 : 0 : hid = usb_get_intfdata(intf);
299 : 0 : hiddev = hid->hiddev;
300 : :
301 : 0 : mutex_lock(&hiddev->existancelock);
302 [ # # ]: 0 : res = hiddev->exist ? __hiddev_open(hiddev, file) : -ENODEV;
303 : 0 : mutex_unlock(&hiddev->existancelock);
304 : :
305 : 0 : return res;
306 : : }
307 : :
308 : : /*
309 : : * "write" file op
310 : : */
311 : 0 : static ssize_t hiddev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
312 : : {
313 : 0 : return -EINVAL;
314 : : }
315 : :
316 : : /*
317 : : * "read" file op
318 : : */
319 : 0 : static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
320 : : {
321 [ # # ]: 0 : DEFINE_WAIT(wait);
322 : 0 : struct hiddev_list *list = file->private_data;
323 : 0 : int event_size;
324 : 0 : int retval;
325 : :
326 [ # # ]: 0 : event_size = ((list->flags & HIDDEV_FLAG_UREF) != 0) ?
327 : : sizeof(struct hiddev_usage_ref) : sizeof(struct hiddev_event);
328 : :
329 [ # # ]: 0 : if (count < event_size)
330 : : return 0;
331 : :
332 : : /* lock against other threads */
333 : 0 : retval = mutex_lock_interruptible(&list->thread_lock);
334 [ # # ]: 0 : if (retval)
335 : : return -ERESTARTSYS;
336 : :
337 [ # # ]: 0 : while (retval == 0) {
338 [ # # ]: 0 : if (list->head == list->tail) {
339 : 0 : prepare_to_wait(&list->hiddev->wait, &wait, TASK_INTERRUPTIBLE);
340 : :
341 : 0 : while (list->head == list->tail) {
342 [ # # ]: 0 : if (signal_pending(current)) {
343 : : retval = -ERESTARTSYS;
344 : : break;
345 : : }
346 [ # # ]: 0 : if (!list->hiddev->exist) {
347 : : retval = -EIO;
348 : : break;
349 : : }
350 [ # # ]: 0 : if (file->f_flags & O_NONBLOCK) {
351 : : retval = -EAGAIN;
352 : : break;
353 : : }
354 : :
355 : : /* let O_NONBLOCK tasks run */
356 : 0 : mutex_unlock(&list->thread_lock);
357 : 0 : schedule();
358 [ # # ]: 0 : if (mutex_lock_interruptible(&list->thread_lock)) {
359 : 0 : finish_wait(&list->hiddev->wait, &wait);
360 : 0 : return -EINTR;
361 : : }
362 [ # # ]: 0 : set_current_state(TASK_INTERRUPTIBLE);
363 : : }
364 : 0 : finish_wait(&list->hiddev->wait, &wait);
365 : :
366 : : }
367 : :
368 [ # # ]: 0 : if (retval) {
369 : 0 : mutex_unlock(&list->thread_lock);
370 : 0 : return retval;
371 : : }
372 : :
373 : :
374 [ # # ]: 0 : while (list->head != list->tail &&
375 [ # # ]: 0 : retval + event_size <= count) {
376 [ # # ]: 0 : if ((list->flags & HIDDEV_FLAG_UREF) == 0) {
377 [ # # ]: 0 : if (list->buffer[list->tail].field_index != HID_FIELD_INDEX_NONE) {
378 : 0 : struct hiddev_event event;
379 : :
380 : 0 : event.hid = list->buffer[list->tail].usage_code;
381 : 0 : event.value = list->buffer[list->tail].value;
382 [ # # ]: 0 : if (copy_to_user(buffer + retval, &event, sizeof(struct hiddev_event))) {
383 : 0 : mutex_unlock(&list->thread_lock);
384 : 0 : return -EFAULT;
385 : : }
386 : 0 : retval += sizeof(struct hiddev_event);
387 : : }
388 : : } else {
389 [ # # ]: 0 : if (list->buffer[list->tail].field_index != HID_FIELD_INDEX_NONE ||
390 [ # # ]: 0 : (list->flags & HIDDEV_FLAG_REPORT) != 0) {
391 : :
392 [ # # # # ]: 0 : if (copy_to_user(buffer + retval, list->buffer + list->tail, sizeof(struct hiddev_usage_ref))) {
393 : 0 : mutex_unlock(&list->thread_lock);
394 : 0 : return -EFAULT;
395 : : }
396 : 0 : retval += sizeof(struct hiddev_usage_ref);
397 : : }
398 : : }
399 : 0 : list->tail = (list->tail + 1) & (HIDDEV_BUFFER_SIZE - 1);
400 : : }
401 : :
402 : : }
403 : 0 : mutex_unlock(&list->thread_lock);
404 : :
405 : 0 : return retval;
406 : : }
407 : :
408 : : /*
409 : : * "poll" file op
410 : : * No kernel lock - fine
411 : : */
412 : 0 : static __poll_t hiddev_poll(struct file *file, poll_table *wait)
413 : : {
414 : 0 : struct hiddev_list *list = file->private_data;
415 : :
416 [ # # ]: 0 : poll_wait(file, &list->hiddev->wait, wait);
417 [ # # ]: 0 : if (list->head != list->tail)
418 : : return EPOLLIN | EPOLLRDNORM | EPOLLOUT;
419 [ # # ]: 0 : if (!list->hiddev->exist)
420 : 0 : return EPOLLERR | EPOLLHUP;
421 : : return 0;
422 : : }
423 : :
424 : : /*
425 : : * "ioctl" file op
426 : : */
427 : : static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd, void __user *user_arg)
428 : : {
429 : : struct hid_device *hid = hiddev->hid;
430 : : struct hiddev_report_info rinfo;
431 : : struct hiddev_usage_ref_multi *uref_multi = NULL;
432 : : struct hiddev_usage_ref *uref;
433 : : struct hid_report *report;
434 : : struct hid_field *field;
435 : : int i;
436 : :
437 : : uref_multi = kmalloc(sizeof(struct hiddev_usage_ref_multi), GFP_KERNEL);
438 : : if (!uref_multi)
439 : : return -ENOMEM;
440 : : uref = &uref_multi->uref;
441 : : if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
442 : : if (copy_from_user(uref_multi, user_arg,
443 : : sizeof(*uref_multi)))
444 : : goto fault;
445 : : } else {
446 : : if (copy_from_user(uref, user_arg, sizeof(*uref)))
447 : : goto fault;
448 : : }
449 : :
450 : : switch (cmd) {
451 : : case HIDIOCGUCODE:
452 : : rinfo.report_type = uref->report_type;
453 : : rinfo.report_id = uref->report_id;
454 : : if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
455 : : goto inval;
456 : :
457 : : if (uref->field_index >= report->maxfield)
458 : : goto inval;
459 : : uref->field_index = array_index_nospec(uref->field_index,
460 : : report->maxfield);
461 : :
462 : : field = report->field[uref->field_index];
463 : : if (uref->usage_index >= field->maxusage)
464 : : goto inval;
465 : : uref->usage_index = array_index_nospec(uref->usage_index,
466 : : field->maxusage);
467 : :
468 : : uref->usage_code = field->usage[uref->usage_index].hid;
469 : :
470 : : if (copy_to_user(user_arg, uref, sizeof(*uref)))
471 : : goto fault;
472 : :
473 : : goto goodreturn;
474 : :
475 : : default:
476 : : if (cmd != HIDIOCGUSAGE &&
477 : : cmd != HIDIOCGUSAGES &&
478 : : uref->report_type == HID_REPORT_TYPE_INPUT)
479 : : goto inval;
480 : :
481 : : if (uref->report_id == HID_REPORT_ID_UNKNOWN) {
482 : : field = hiddev_lookup_usage(hid, uref);
483 : : if (field == NULL)
484 : : goto inval;
485 : : } else {
486 : : rinfo.report_type = uref->report_type;
487 : : rinfo.report_id = uref->report_id;
488 : : if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
489 : : goto inval;
490 : :
491 : : if (uref->field_index >= report->maxfield)
492 : : goto inval;
493 : : uref->field_index = array_index_nospec(uref->field_index,
494 : : report->maxfield);
495 : :
496 : : field = report->field[uref->field_index];
497 : :
498 : : if (cmd == HIDIOCGCOLLECTIONINDEX) {
499 : : if (uref->usage_index >= field->maxusage)
500 : : goto inval;
501 : : uref->usage_index =
502 : : array_index_nospec(uref->usage_index,
503 : : field->maxusage);
504 : : } else if (uref->usage_index >= field->report_count)
505 : : goto inval;
506 : : }
507 : :
508 : : if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
509 : : if (uref_multi->num_values > HID_MAX_MULTI_USAGES ||
510 : : uref->usage_index + uref_multi->num_values >
511 : : field->report_count)
512 : : goto inval;
513 : :
514 : : uref->usage_index =
515 : : array_index_nospec(uref->usage_index,
516 : : field->report_count -
517 : : uref_multi->num_values);
518 : : }
519 : :
520 : : switch (cmd) {
521 : : case HIDIOCGUSAGE:
522 : : uref->value = field->value[uref->usage_index];
523 : : if (copy_to_user(user_arg, uref, sizeof(*uref)))
524 : : goto fault;
525 : : goto goodreturn;
526 : :
527 : : case HIDIOCSUSAGE:
528 : : field->value[uref->usage_index] = uref->value;
529 : : goto goodreturn;
530 : :
531 : : case HIDIOCGCOLLECTIONINDEX:
532 : : i = field->usage[uref->usage_index].collection_index;
533 : : kfree(uref_multi);
534 : : return i;
535 : : case HIDIOCGUSAGES:
536 : : for (i = 0; i < uref_multi->num_values; i++)
537 : : uref_multi->values[i] =
538 : : field->value[uref->usage_index + i];
539 : : if (copy_to_user(user_arg, uref_multi,
540 : : sizeof(*uref_multi)))
541 : : goto fault;
542 : : goto goodreturn;
543 : : case HIDIOCSUSAGES:
544 : : for (i = 0; i < uref_multi->num_values; i++)
545 : : field->value[uref->usage_index + i] =
546 : : uref_multi->values[i];
547 : : goto goodreturn;
548 : : }
549 : :
550 : : goodreturn:
551 : : kfree(uref_multi);
552 : : return 0;
553 : : fault:
554 : : kfree(uref_multi);
555 : : return -EFAULT;
556 : : inval:
557 : : kfree(uref_multi);
558 : : return -EINVAL;
559 : : }
560 : : }
561 : :
562 : : static noinline int hiddev_ioctl_string(struct hiddev *hiddev, unsigned int cmd, void __user *user_arg)
563 : : {
564 : : struct hid_device *hid = hiddev->hid;
565 : : struct usb_device *dev = hid_to_usb_dev(hid);
566 : : int idx, len;
567 : : char *buf;
568 : :
569 : : if (get_user(idx, (int __user *)user_arg))
570 : : return -EFAULT;
571 : :
572 : : if ((buf = kmalloc(HID_STRING_SIZE, GFP_KERNEL)) == NULL)
573 : : return -ENOMEM;
574 : :
575 : : if ((len = usb_string(dev, idx, buf, HID_STRING_SIZE-1)) < 0) {
576 : : kfree(buf);
577 : : return -EINVAL;
578 : : }
579 : :
580 : : if (copy_to_user(user_arg+sizeof(int), buf, len+1)) {
581 : : kfree(buf);
582 : : return -EFAULT;
583 : : }
584 : :
585 : : kfree(buf);
586 : :
587 : : return len;
588 : : }
589 : :
590 : 0 : static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
591 : : {
592 : 0 : struct hiddev_list *list = file->private_data;
593 : 0 : struct hiddev *hiddev = list->hiddev;
594 : 0 : struct hid_device *hid;
595 : 0 : struct hiddev_collection_info cinfo;
596 : 0 : struct hiddev_report_info rinfo;
597 : 0 : struct hiddev_field_info finfo;
598 : 0 : struct hiddev_devinfo dinfo;
599 : 0 : struct hid_report *report;
600 : 0 : struct hid_field *field;
601 : 0 : void __user *user_arg = (void __user *)arg;
602 : 0 : int i, r = -EINVAL;
603 : :
604 : : /* Called without BKL by compat methods so no BKL taken */
605 : :
606 : 0 : mutex_lock(&hiddev->existancelock);
607 [ # # ]: 0 : if (!hiddev->exist) {
608 : 0 : r = -ENODEV;
609 : 0 : goto ret_unlock;
610 : : }
611 : :
612 : 0 : hid = hiddev->hid;
613 : :
614 [ # # # # : 0 : switch (cmd) {
# # # # #
# # # #
# ]
615 : :
616 : : case HIDIOCGVERSION:
617 : 0 : r = put_user(HID_VERSION, (int __user *)arg) ?
618 [ # # ]: 0 : -EFAULT : 0;
619 : : break;
620 : :
621 : 0 : case HIDIOCAPPLICATION:
622 [ # # ]: 0 : if (arg >= hid->maxapplication)
623 : : break;
624 : :
625 [ # # ]: 0 : for (i = 0; i < hid->maxcollection; i++)
626 [ # # ]: 0 : if (hid->collection[i].type ==
627 [ # # ]: 0 : HID_COLLECTION_APPLICATION && arg-- == 0)
628 : : break;
629 : :
630 [ # # ]: 0 : if (i < hid->maxcollection)
631 : 0 : r = hid->collection[i].usage;
632 : : break;
633 : :
634 : 0 : case HIDIOCGDEVINFO:
635 : : {
636 : 0 : struct usb_device *dev = hid_to_usb_dev(hid);
637 : 0 : struct usbhid_device *usbhid = hid->driver_data;
638 : :
639 : 0 : memset(&dinfo, 0, sizeof(dinfo));
640 : :
641 : 0 : dinfo.bustype = BUS_USB;
642 : 0 : dinfo.busnum = dev->bus->busnum;
643 : 0 : dinfo.devnum = dev->devnum;
644 : 0 : dinfo.ifnum = usbhid->ifnum;
645 : 0 : dinfo.vendor = le16_to_cpu(dev->descriptor.idVendor);
646 : 0 : dinfo.product = le16_to_cpu(dev->descriptor.idProduct);
647 : 0 : dinfo.version = le16_to_cpu(dev->descriptor.bcdDevice);
648 : 0 : dinfo.num_applications = hid->maxapplication;
649 : :
650 : 0 : r = copy_to_user(user_arg, &dinfo, sizeof(dinfo)) ?
651 [ # # ]: 0 : -EFAULT : 0;
652 : : break;
653 : : }
654 : :
655 : : case HIDIOCGFLAG:
656 : 0 : r = put_user(list->flags, (int __user *)arg) ?
657 [ # # ]: 0 : -EFAULT : 0;
658 : : break;
659 : :
660 : : case HIDIOCSFLAG:
661 : : {
662 : 0 : int newflags;
663 : :
664 [ # # ]: 0 : if (get_user(newflags, (int __user *)arg)) {
665 : : r = -EFAULT;
666 : : break;
667 : : }
668 : :
669 [ # # ]: 0 : if ((newflags & ~HIDDEV_FLAGS) != 0 ||
670 [ # # ]: 0 : ((newflags & HIDDEV_FLAG_REPORT) != 0 &&
671 : : (newflags & HIDDEV_FLAG_UREF) == 0))
672 : : break;
673 : :
674 : 0 : list->flags = newflags;
675 : :
676 : 0 : r = 0;
677 : 0 : break;
678 : : }
679 : :
680 : 0 : case HIDIOCGSTRING:
681 : 0 : r = hiddev_ioctl_string(hiddev, cmd, user_arg);
682 : 0 : break;
683 : :
684 : 0 : case HIDIOCINITREPORT:
685 : 0 : usbhid_init_reports(hid);
686 : 0 : hiddev->initialized = true;
687 : 0 : r = 0;
688 : 0 : break;
689 : :
690 : : case HIDIOCGREPORT:
691 [ # # ]: 0 : if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) {
692 : : r = -EFAULT;
693 : : break;
694 : : }
695 : :
696 [ # # ]: 0 : if (rinfo.report_type == HID_REPORT_TYPE_OUTPUT)
697 : : break;
698 : :
699 : 0 : report = hiddev_lookup_report(hid, &rinfo);
700 [ # # ]: 0 : if (report == NULL)
701 : : break;
702 : :
703 : 0 : hid_hw_request(hid, report, HID_REQ_GET_REPORT);
704 [ # # ]: 0 : hid_hw_wait(hid);
705 : :
706 : : r = 0;
707 : : break;
708 : :
709 : : case HIDIOCSREPORT:
710 [ # # ]: 0 : if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) {
711 : : r = -EFAULT;
712 : : break;
713 : : }
714 : :
715 [ # # ]: 0 : if (rinfo.report_type == HID_REPORT_TYPE_INPUT)
716 : : break;
717 : :
718 : 0 : report = hiddev_lookup_report(hid, &rinfo);
719 [ # # ]: 0 : if (report == NULL)
720 : : break;
721 : :
722 : 0 : hid_hw_request(hid, report, HID_REQ_SET_REPORT);
723 [ # # ]: 0 : hid_hw_wait(hid);
724 : :
725 : : r = 0;
726 : : break;
727 : :
728 : : case HIDIOCGREPORTINFO:
729 [ # # ]: 0 : if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) {
730 : : r = -EFAULT;
731 : : break;
732 : : }
733 : :
734 : 0 : report = hiddev_lookup_report(hid, &rinfo);
735 [ # # ]: 0 : if (report == NULL)
736 : : break;
737 : :
738 : 0 : rinfo.num_fields = report->maxfield;
739 : :
740 : 0 : r = copy_to_user(user_arg, &rinfo, sizeof(rinfo)) ?
741 [ # # ]: 0 : -EFAULT : 0;
742 : : break;
743 : :
744 : : case HIDIOCGFIELDINFO:
745 [ # # ]: 0 : if (copy_from_user(&finfo, user_arg, sizeof(finfo))) {
746 : : r = -EFAULT;
747 : : break;
748 : : }
749 : :
750 : 0 : rinfo.report_type = finfo.report_type;
751 : 0 : rinfo.report_id = finfo.report_id;
752 : :
753 : 0 : report = hiddev_lookup_report(hid, &rinfo);
754 [ # # ]: 0 : if (report == NULL)
755 : : break;
756 : :
757 [ # # ]: 0 : if (finfo.field_index >= report->maxfield)
758 : : break;
759 : 0 : finfo.field_index = array_index_nospec(finfo.field_index,
760 : : report->maxfield);
761 : :
762 : 0 : field = report->field[finfo.field_index];
763 : 0 : memset(&finfo, 0, sizeof(finfo));
764 : 0 : finfo.report_type = rinfo.report_type;
765 : 0 : finfo.report_id = rinfo.report_id;
766 : 0 : finfo.field_index = field->report_count - 1;
767 : 0 : finfo.maxusage = field->maxusage;
768 : 0 : finfo.flags = field->flags;
769 : 0 : finfo.physical = field->physical;
770 : 0 : finfo.logical = field->logical;
771 : 0 : finfo.application = field->application;
772 : 0 : finfo.logical_minimum = field->logical_minimum;
773 : 0 : finfo.logical_maximum = field->logical_maximum;
774 : 0 : finfo.physical_minimum = field->physical_minimum;
775 : 0 : finfo.physical_maximum = field->physical_maximum;
776 : 0 : finfo.unit_exponent = field->unit_exponent;
777 : 0 : finfo.unit = field->unit;
778 : :
779 : 0 : r = copy_to_user(user_arg, &finfo, sizeof(finfo)) ?
780 [ # # ]: 0 : -EFAULT : 0;
781 : : break;
782 : :
783 : 0 : case HIDIOCGUCODE:
784 : : /* fall through */
785 : : case HIDIOCGUSAGE:
786 : : case HIDIOCSUSAGE:
787 : : case HIDIOCGUSAGES:
788 : : case HIDIOCSUSAGES:
789 : : case HIDIOCGCOLLECTIONINDEX:
790 [ # # ]: 0 : if (!hiddev->initialized) {
791 : 0 : usbhid_init_reports(hid);
792 : 0 : hiddev->initialized = true;
793 : : }
794 : 0 : r = hiddev_ioctl_usage(hiddev, cmd, user_arg);
795 : 0 : break;
796 : :
797 : : case HIDIOCGCOLLECTIONINFO:
798 [ # # ]: 0 : if (copy_from_user(&cinfo, user_arg, sizeof(cinfo))) {
799 : : r = -EFAULT;
800 : : break;
801 : : }
802 : :
803 [ # # ]: 0 : if (cinfo.index >= hid->maxcollection)
804 : : break;
805 : 0 : cinfo.index = array_index_nospec(cinfo.index,
806 : : hid->maxcollection);
807 : :
808 : 0 : cinfo.type = hid->collection[cinfo.index].type;
809 : 0 : cinfo.usage = hid->collection[cinfo.index].usage;
810 : 0 : cinfo.level = hid->collection[cinfo.index].level;
811 : :
812 : 0 : r = copy_to_user(user_arg, &cinfo, sizeof(cinfo)) ?
813 [ # # ]: 0 : -EFAULT : 0;
814 : : break;
815 : :
816 : 0 : default:
817 [ # # # # ]: 0 : if (_IOC_TYPE(cmd) != 'H' || _IOC_DIR(cmd) != _IOC_READ)
818 : : break;
819 : :
820 [ # # ]: 0 : if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGNAME(0))) {
821 : 0 : int len = strlen(hid->name) + 1;
822 [ # # ]: 0 : if (len > _IOC_SIZE(cmd))
823 : 0 : len = _IOC_SIZE(cmd);
824 [ # # ]: 0 : r = copy_to_user(user_arg, hid->name, len) ?
825 [ # # ]: 0 : -EFAULT : len;
826 : : break;
827 : : }
828 : :
829 [ # # ]: 0 : if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGPHYS(0))) {
830 : 0 : int len = strlen(hid->phys) + 1;
831 [ # # ]: 0 : if (len > _IOC_SIZE(cmd))
832 : 0 : len = _IOC_SIZE(cmd);
833 [ # # ]: 0 : r = copy_to_user(user_arg, hid->phys, len) ?
834 [ # # ]: 0 : -EFAULT : len;
835 : : break;
836 : : }
837 : : }
838 : :
839 : 0 : ret_unlock:
840 : 0 : mutex_unlock(&hiddev->existancelock);
841 : 0 : return r;
842 : : }
843 : :
844 : : static const struct file_operations hiddev_fops = {
845 : : .owner = THIS_MODULE,
846 : : .read = hiddev_read,
847 : : .write = hiddev_write,
848 : : .poll = hiddev_poll,
849 : : .open = hiddev_open,
850 : : .release = hiddev_release,
851 : : .unlocked_ioctl = hiddev_ioctl,
852 : : .fasync = hiddev_fasync,
853 : : .compat_ioctl = compat_ptr_ioctl,
854 : : .llseek = noop_llseek,
855 : : };
856 : :
857 : 0 : static char *hiddev_devnode(struct device *dev, umode_t *mode)
858 : : {
859 [ # # ]: 0 : return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev));
860 : : }
861 : :
862 : : static struct usb_class_driver hiddev_class = {
863 : : .name = "hiddev%d",
864 : : .devnode = hiddev_devnode,
865 : : .fops = &hiddev_fops,
866 : : .minor_base = HIDDEV_MINOR_BASE,
867 : : };
868 : :
869 : : /*
870 : : * This is where hid.c calls us to connect a hid device to the hiddev driver
871 : : */
872 : 0 : int hiddev_connect(struct hid_device *hid, unsigned int force)
873 : : {
874 : 0 : struct hiddev *hiddev;
875 : 0 : struct usbhid_device *usbhid = hid->driver_data;
876 : 0 : int retval;
877 : :
878 [ # # ]: 0 : if (!force) {
879 : : unsigned int i;
880 [ # # ]: 0 : for (i = 0; i < hid->maxcollection; i++)
881 [ # # ]: 0 : if (hid->collection[i].type ==
882 : 0 : HID_COLLECTION_APPLICATION &&
883 [ # # # # : 0 : !IS_INPUT_APPLICATION(hid->collection[i].usage))
# # # # ]
884 : : break;
885 : :
886 [ # # ]: 0 : if (i == hid->maxcollection)
887 : : return -1;
888 : : }
889 : :
890 [ # # ]: 0 : if (!(hiddev = kzalloc(sizeof(struct hiddev), GFP_KERNEL)))
891 : : return -1;
892 : :
893 : 0 : init_waitqueue_head(&hiddev->wait);
894 : 0 : INIT_LIST_HEAD(&hiddev->list);
895 : 0 : spin_lock_init(&hiddev->list_lock);
896 : 0 : mutex_init(&hiddev->existancelock);
897 : 0 : hid->hiddev = hiddev;
898 : 0 : hiddev->hid = hid;
899 : 0 : hiddev->exist = 1;
900 : 0 : retval = usb_register_dev(usbhid->intf, &hiddev_class);
901 [ # # ]: 0 : if (retval) {
902 : 0 : hid_err(hid, "Not able to get a minor for this device\n");
903 : 0 : hid->hiddev = NULL;
904 : 0 : kfree(hiddev);
905 : 0 : return -1;
906 : : }
907 : :
908 : : /*
909 : : * If HID_QUIRK_NO_INIT_REPORTS is set, make sure we don't initialize
910 : : * the reports.
911 : : */
912 : 0 : hiddev->initialized = hid->quirks & HID_QUIRK_NO_INIT_REPORTS;
913 : :
914 : 0 : hiddev->minor = usbhid->intf->minor;
915 : :
916 : 0 : return 0;
917 : : }
918 : :
919 : : /*
920 : : * This is where hid.c calls us to disconnect a hiddev device from the
921 : : * corresponding hid device (usually because the usb device has disconnected)
922 : : */
923 : : static struct usb_class_driver hiddev_class;
924 : 0 : void hiddev_disconnect(struct hid_device *hid)
925 : : {
926 : 0 : struct hiddev *hiddev = hid->hiddev;
927 : 0 : struct usbhid_device *usbhid = hid->driver_data;
928 : :
929 : 0 : usb_deregister_dev(usbhid->intf, &hiddev_class);
930 : :
931 : 0 : mutex_lock(&hiddev->existancelock);
932 : 0 : hiddev->exist = 0;
933 : :
934 [ # # ]: 0 : if (hiddev->open) {
935 : 0 : hid_hw_close(hiddev->hid);
936 : 0 : wake_up_interruptible(&hiddev->wait);
937 : 0 : mutex_unlock(&hiddev->existancelock);
938 : : } else {
939 : 0 : mutex_unlock(&hiddev->existancelock);
940 : 0 : kfree(hiddev);
941 : : }
942 : 0 : }
|