aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPetri Gynther <pgynther@google.com>2014-03-24 16:50:01 -0400
committerJiri Kosina <jkosina@suse.cz>2014-04-01 12:27:33 -0400
commit4522643aa9630be17238edf1b4c0b690c5dd7f5d (patch)
tree4476b31d4cab4643baeaf0877e21da51f69c7ad2
parentc3d77fab51f40821de91a744e4b514e9e4e76a7c (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>
-rw-r--r--Documentation/hid/uhid.txt11
-rw-r--r--drivers/hid/uhid.c78
-rw-r--r--include/uapi/linux/uhid.h23
3 files changed, 112 insertions, 0 deletions
diff --git a/Documentation/hid/uhid.txt b/Documentation/hid/uhid.txt
index dc35a2b75eee..ee6593608c8e 100644
--- a/Documentation/hid/uhid.txt
+++ b/Documentation/hid/uhid.txt
@@ -93,6 +93,11 @@ the request was handled successfully.
93 event to the kernel. The payload is of type struct uhid_create_req and 93 event to the kernel. The payload is of type struct uhid_create_req and
94 contains information about your device. You can start I/O now. 94 contains information about your device. You can start I/O now.
95 95
96 UHID_CREATE2:
97 Same as UHID_CREATE, but the HID report descriptor data (rd_data) is an array
98 inside struct uhid_create2_req, instead of a pointer to a separate array.
99 Enables use from languages that don't support pointers, e.g. Python.
100
96 UHID_DESTROY: 101 UHID_DESTROY:
97 This destroys the internal HID device. No further I/O will be accepted. There 102 This destroys the internal HID device. No further I/O will be accepted. There
98 may still be pending messages that you can receive with read() but no further 103 may still be pending messages that you can receive with read() but no further
@@ -105,6 +110,12 @@ the request was handled successfully.
105 contains a data-payload. This is the raw data that you read from your device. 110 contains a data-payload. This is the raw data that you read from your device.
106 The kernel will parse the HID reports and react on it. 111 The kernel will parse the HID reports and react on it.
107 112
113 UHID_INPUT2:
114 Same as UHID_INPUT, but the data array is the last field of uhid_input2_req.
115 Enables userspace to write only the required bytes to kernel (ev.type +
116 ev.u.input2.size + the part of the data array that matters), instead of
117 the entire struct uhid_input2_req.
118
108 UHID_FEATURE_ANSWER: 119 UHID_FEATURE_ANSWER:
109 If you receive a UHID_FEATURE request you must answer with this request. You 120 If you receive a UHID_FEATURE request you must answer with this request. You
110 must copy the "id" field from the request into the answer. Set the "err" field 121 must copy the "id" field from the request into the answer. Set the "err" field
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
431static 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
483err_hid:
484 hid_destroy_device(hid);
485 uhid->hid = NULL;
486 uhid->running = false;
487err_free:
488 kfree(uhid->rd_data);
489 return ret;
490}
491
431static int uhid_dev_destroy(struct uhid_device *uhid) 492static 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
520static 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
459static int uhid_dev_feature_answer(struct uhid_device *uhid, 531static 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;
diff --git a/include/uapi/linux/uhid.h b/include/uapi/linux/uhid.h
index 414b74be4da1..1e3b09c191cd 100644
--- a/include/uapi/linux/uhid.h
+++ b/include/uapi/linux/uhid.h
@@ -21,6 +21,7 @@
21 21
22#include <linux/input.h> 22#include <linux/input.h>
23#include <linux/types.h> 23#include <linux/types.h>
24#include <linux/hid.h>
24 25
25enum uhid_event_type { 26enum uhid_event_type {
26 UHID_CREATE, 27 UHID_CREATE,
@@ -34,6 +35,8 @@ enum uhid_event_type {
34 UHID_INPUT, 35 UHID_INPUT,
35 UHID_FEATURE, 36 UHID_FEATURE,
36 UHID_FEATURE_ANSWER, 37 UHID_FEATURE_ANSWER,
38 UHID_CREATE2,
39 UHID_INPUT2,
37}; 40};
38 41
39struct uhid_create_req { 42struct uhid_create_req {
@@ -50,6 +53,19 @@ struct uhid_create_req {
50 __u32 country; 53 __u32 country;
51} __attribute__((__packed__)); 54} __attribute__((__packed__));
52 55
56struct uhid_create2_req {
57 __u8 name[128];
58 __u8 phys[64];
59 __u8 uniq[64];
60 __u16 rd_size;
61 __u16 bus;
62 __u32 vendor;
63 __u32 product;
64 __u32 version;
65 __u32 country;
66 __u8 rd_data[HID_MAX_DESCRIPTOR_SIZE];
67} __attribute__((__packed__));
68
53#define UHID_DATA_MAX 4096 69#define UHID_DATA_MAX 4096
54 70
55enum uhid_report_type { 71enum uhid_report_type {
@@ -63,6 +79,11 @@ struct uhid_input_req {
63 __u16 size; 79 __u16 size;
64} __attribute__((__packed__)); 80} __attribute__((__packed__));
65 81
82struct uhid_input2_req {
83 __u16 size;
84 __u8 data[UHID_DATA_MAX];
85} __attribute__((__packed__));
86
66struct uhid_output_req { 87struct uhid_output_req {
67 __u8 data[UHID_DATA_MAX]; 88 __u8 data[UHID_DATA_MAX];
68 __u16 size; 89 __u16 size;
@@ -100,6 +121,8 @@ struct uhid_event {
100 struct uhid_output_ev_req output_ev; 121 struct uhid_output_ev_req output_ev;
101 struct uhid_feature_req feature; 122 struct uhid_feature_req feature;
102 struct uhid_feature_answer_req feature_answer; 123 struct uhid_feature_answer_req feature_answer;
124 struct uhid_create2_req create2;
125 struct uhid_input2_req input2;
103 } u; 126 } u;
104} __attribute__((__packed__)); 127} __attribute__((__packed__));
105 128