diff options
author | Petri Gynther <pgynther@google.com> | 2014-03-24 16:50:01 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2014-04-01 12:27:33 -0400 |
commit | 4522643aa9630be17238edf1b4c0b690c5dd7f5d (patch) | |
tree | 4476b31d4cab4643baeaf0877e21da51f69c7ad2 /drivers/hid/uhid.c | |
parent | c3d77fab51f40821de91a744e4b514e9e4e76a7c (diff) |
HID: uhid: Add UHID_CREATE2 + UHID_INPUT2
UHID_CREATE2:
HID report descriptor data (rd_data) is an array in struct uhid_create2_req,
instead of a pointer. Enables use from languages that don't support pointers,
e.g. Python.
UHID_INPUT2:
Data array is the last field of struct uhid_input2_req. Enables userspace to
write only the required bytes to kernel (ev.type + ev.u.input2.size + the part
of the data array that matters), instead of the entire struct uhid_input2_req.
Note:
UHID_CREATE2 increases the total size of struct uhid_event slightly, thus
increasing the size of messages that are queued for userspace. However, this
won't affect the userspace processing of these events.
[Jiri Kosina <jkosina@suse.cz>: adjust to hid_get_raw_report() and
hid_output_raw_report() API changes]
Signed-off-by: Petri Gynther <pgynther@google.com>
Reviewed-by: David Herrmann <dh.herrmann@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/uhid.c')
-rw-r--r-- | drivers/hid/uhid.c | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c index 7ed79be2686a..0d078c32db4f 100644 --- a/drivers/hid/uhid.c +++ b/drivers/hid/uhid.c | |||
@@ -428,6 +428,67 @@ err_free: | |||
428 | return ret; | 428 | return ret; |
429 | } | 429 | } |
430 | 430 | ||
431 | static int uhid_dev_create2(struct uhid_device *uhid, | ||
432 | const struct uhid_event *ev) | ||
433 | { | ||
434 | struct hid_device *hid; | ||
435 | int ret; | ||
436 | |||
437 | if (uhid->running) | ||
438 | return -EALREADY; | ||
439 | |||
440 | uhid->rd_size = ev->u.create2.rd_size; | ||
441 | if (uhid->rd_size <= 0 || uhid->rd_size > HID_MAX_DESCRIPTOR_SIZE) | ||
442 | return -EINVAL; | ||
443 | |||
444 | uhid->rd_data = kmalloc(uhid->rd_size, GFP_KERNEL); | ||
445 | if (!uhid->rd_data) | ||
446 | return -ENOMEM; | ||
447 | |||
448 | memcpy(uhid->rd_data, ev->u.create2.rd_data, uhid->rd_size); | ||
449 | |||
450 | hid = hid_allocate_device(); | ||
451 | if (IS_ERR(hid)) { | ||
452 | ret = PTR_ERR(hid); | ||
453 | goto err_free; | ||
454 | } | ||
455 | |||
456 | strncpy(hid->name, ev->u.create2.name, 127); | ||
457 | hid->name[127] = 0; | ||
458 | strncpy(hid->phys, ev->u.create2.phys, 63); | ||
459 | hid->phys[63] = 0; | ||
460 | strncpy(hid->uniq, ev->u.create2.uniq, 63); | ||
461 | hid->uniq[63] = 0; | ||
462 | |||
463 | hid->ll_driver = &uhid_hid_driver; | ||
464 | hid->bus = ev->u.create2.bus; | ||
465 | hid->vendor = ev->u.create2.vendor; | ||
466 | hid->product = ev->u.create2.product; | ||
467 | hid->version = ev->u.create2.version; | ||
468 | hid->country = ev->u.create2.country; | ||
469 | hid->driver_data = uhid; | ||
470 | hid->dev.parent = uhid_misc.this_device; | ||
471 | |||
472 | uhid->hid = hid; | ||
473 | uhid->running = true; | ||
474 | |||
475 | ret = hid_add_device(hid); | ||
476 | if (ret) { | ||
477 | hid_err(hid, "Cannot register HID device\n"); | ||
478 | goto err_hid; | ||
479 | } | ||
480 | |||
481 | return 0; | ||
482 | |||
483 | err_hid: | ||
484 | hid_destroy_device(hid); | ||
485 | uhid->hid = NULL; | ||
486 | uhid->running = false; | ||
487 | err_free: | ||
488 | kfree(uhid->rd_data); | ||
489 | return ret; | ||
490 | } | ||
491 | |||
431 | static int uhid_dev_destroy(struct uhid_device *uhid) | 492 | static int uhid_dev_destroy(struct uhid_device *uhid) |
432 | { | 493 | { |
433 | if (!uhid->running) | 494 | if (!uhid->running) |
@@ -456,6 +517,17 @@ static int uhid_dev_input(struct uhid_device *uhid, struct uhid_event *ev) | |||
456 | return 0; | 517 | return 0; |
457 | } | 518 | } |
458 | 519 | ||
520 | static int uhid_dev_input2(struct uhid_device *uhid, struct uhid_event *ev) | ||
521 | { | ||
522 | if (!uhid->running) | ||
523 | return -EINVAL; | ||
524 | |||
525 | hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input2.data, | ||
526 | min_t(size_t, ev->u.input2.size, UHID_DATA_MAX), 0); | ||
527 | |||
528 | return 0; | ||
529 | } | ||
530 | |||
459 | static int uhid_dev_feature_answer(struct uhid_device *uhid, | 531 | static int uhid_dev_feature_answer(struct uhid_device *uhid, |
460 | struct uhid_event *ev) | 532 | struct uhid_event *ev) |
461 | { | 533 | { |
@@ -592,12 +664,18 @@ static ssize_t uhid_char_write(struct file *file, const char __user *buffer, | |||
592 | case UHID_CREATE: | 664 | case UHID_CREATE: |
593 | ret = uhid_dev_create(uhid, &uhid->input_buf); | 665 | ret = uhid_dev_create(uhid, &uhid->input_buf); |
594 | break; | 666 | break; |
667 | case UHID_CREATE2: | ||
668 | ret = uhid_dev_create2(uhid, &uhid->input_buf); | ||
669 | break; | ||
595 | case UHID_DESTROY: | 670 | case UHID_DESTROY: |
596 | ret = uhid_dev_destroy(uhid); | 671 | ret = uhid_dev_destroy(uhid); |
597 | break; | 672 | break; |
598 | case UHID_INPUT: | 673 | case UHID_INPUT: |
599 | ret = uhid_dev_input(uhid, &uhid->input_buf); | 674 | ret = uhid_dev_input(uhid, &uhid->input_buf); |
600 | break; | 675 | break; |
676 | case UHID_INPUT2: | ||
677 | ret = uhid_dev_input2(uhid, &uhid->input_buf); | ||
678 | break; | ||
601 | case UHID_FEATURE_ANSWER: | 679 | case UHID_FEATURE_ANSWER: |
602 | ret = uhid_dev_feature_answer(uhid, &uhid->input_buf); | 680 | ret = uhid_dev_feature_answer(uhid, &uhid->input_buf); |
603 | break; | 681 | break; |