diff options
| author | David Herrmann <dh.herrmann@gmail.com> | 2013-09-01 17:45:18 -0400 |
|---|---|---|
| committer | Jiri Kosina <jkosina@suse.cz> | 2013-09-04 05:35:14 -0400 |
| commit | f5e4e7fdd57691d5308cf854dd0dbcfd58799e9a (patch) | |
| tree | 959b6a8c272d2e9dccd4f7c33b2607f3a033592c /samples | |
| parent | 58c59bc997d86593f0bea41845885917cf304d22 (diff) | |
HID: uhid: improve uhid example client
This extends the uhid example client. It properly documents the built-in
report-descriptor an adds explicit report-numbers.
Furthermore, LED output reports are added to utilize the new UHID output
reports of the kernel. Support for 3 basic LEDs is added and a small
report-parser to print debug messages if output reports were received.
To test this, simply write the EV_LED+LED_CAPSL+1 event to the evdev
device-node of the uhid-device and the kernel will forward it to your uhid
client.
Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'samples')
| -rw-r--r-- | samples/uhid/uhid-example.c | 123 |
1 files changed, 103 insertions, 20 deletions
diff --git a/samples/uhid/uhid-example.c b/samples/uhid/uhid-example.c index 03ce3c059a5e..7d58a4b8d324 100644 --- a/samples/uhid/uhid-example.c +++ b/samples/uhid/uhid-example.c | |||
| @@ -1,14 +1,15 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * UHID Example | 2 | * UHID Example |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com> | 4 | * Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.com> |
| 5 | * | 5 | * |
| 6 | * The code may be used by anyone for any purpose, | 6 | * The code may be used by anyone for any purpose, |
| 7 | * and can serve as a starting point for developing | 7 | * and can serve as a starting point for developing |
| 8 | * applications using uhid. | 8 | * applications using uhid. |
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | /* UHID Example | 11 | /* |
| 12 | * UHID Example | ||
| 12 | * This example emulates a basic 3 buttons mouse with wheel over UHID. Run this | 13 | * This example emulates a basic 3 buttons mouse with wheel over UHID. Run this |
| 13 | * program as root and then use the following keys to control the mouse: | 14 | * program as root and then use the following keys to control the mouse: |
| 14 | * q: Quit the application | 15 | * q: Quit the application |
| @@ -22,6 +23,11 @@ | |||
| 22 | * r: Move wheel up | 23 | * r: Move wheel up |
| 23 | * f: Move wheel down | 24 | * f: Move wheel down |
| 24 | * | 25 | * |
| 26 | * Additionally to 3 button mouse, 3 keyboard LEDs are also supported (LED_NUML, | ||
| 27 | * LED_CAPSL and LED_SCROLLL). The device doesn't generate any related keyboard | ||
| 28 | * events, though. You need to manually write the EV_LED/LED_XY/1 activation | ||
| 29 | * input event to the evdev device to see it being sent to this device. | ||
| 30 | * | ||
| 25 | * If uhid is not available as /dev/uhid, then you can pass a different path as | 31 | * If uhid is not available as /dev/uhid, then you can pass a different path as |
| 26 | * first argument. | 32 | * first argument. |
| 27 | * If <linux/uhid.h> is not installed in /usr, then compile this with: | 33 | * If <linux/uhid.h> is not installed in /usr, then compile this with: |
| @@ -41,11 +47,12 @@ | |||
| 41 | #include <unistd.h> | 47 | #include <unistd.h> |
| 42 | #include <linux/uhid.h> | 48 | #include <linux/uhid.h> |
| 43 | 49 | ||
| 44 | /* HID Report Desciptor | 50 | /* |
| 45 | * We emulate a basic 3 button mouse with wheel. This is the report-descriptor | 51 | * HID Report Desciptor |
| 46 | * as the kernel will parse it: | 52 | * We emulate a basic 3 button mouse with wheel and 3 keyboard LEDs. This is |
| 53 | * the report-descriptor as the kernel will parse it: | ||
| 47 | * | 54 | * |
| 48 | * INPUT[INPUT] | 55 | * INPUT(1)[INPUT] |
| 49 | * Field(0) | 56 | * Field(0) |
| 50 | * Physical(GenericDesktop.Pointer) | 57 | * Physical(GenericDesktop.Pointer) |
| 51 | * Application(GenericDesktop.Mouse) | 58 | * Application(GenericDesktop.Mouse) |
| @@ -72,6 +79,19 @@ | |||
| 72 | * Report Count(3) | 79 | * Report Count(3) |
| 73 | * Report Offset(8) | 80 | * Report Offset(8) |
| 74 | * Flags( Variable Relative ) | 81 | * Flags( Variable Relative ) |
| 82 | * OUTPUT(2)[OUTPUT] | ||
| 83 | * Field(0) | ||
| 84 | * Application(GenericDesktop.Keyboard) | ||
| 85 | * Usage(3) | ||
| 86 | * LED.NumLock | ||
| 87 | * LED.CapsLock | ||
| 88 | * LED.ScrollLock | ||
| 89 | * Logical Minimum(0) | ||
| 90 | * Logical Maximum(1) | ||
| 91 | * Report Size(1) | ||
| 92 | * Report Count(3) | ||
| 93 | * Report Offset(0) | ||
| 94 | * Flags( Variable Absolute ) | ||
| 75 | * | 95 | * |
| 76 | * This is the mapping that we expect: | 96 | * This is the mapping that we expect: |
| 77 | * Button.0001 ---> Key.LeftBtn | 97 | * Button.0001 ---> Key.LeftBtn |
| @@ -80,19 +100,59 @@ | |||
| 80 | * GenericDesktop.X ---> Relative.X | 100 | * GenericDesktop.X ---> Relative.X |
| 81 | * GenericDesktop.Y ---> Relative.Y | 101 | * GenericDesktop.Y ---> Relative.Y |
| 82 | * GenericDesktop.Wheel ---> Relative.Wheel | 102 | * GenericDesktop.Wheel ---> Relative.Wheel |
| 103 | * LED.NumLock ---> LED.NumLock | ||
| 104 | * LED.CapsLock ---> LED.CapsLock | ||
| 105 | * LED.ScrollLock ---> LED.ScrollLock | ||
| 83 | * | 106 | * |
| 84 | * This information can be verified by reading /sys/kernel/debug/hid/<dev>/rdesc | 107 | * This information can be verified by reading /sys/kernel/debug/hid/<dev>/rdesc |
| 85 | * This file should print the same information as showed above. | 108 | * This file should print the same information as showed above. |
| 86 | */ | 109 | */ |
| 87 | 110 | ||
| 88 | static unsigned char rdesc[] = { | 111 | static unsigned char rdesc[] = { |
| 89 | 0x05, 0x01, 0x09, 0x02, 0xa1, 0x01, 0x09, 0x01, | 112 | 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ |
| 90 | 0xa1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03, | 113 | 0x09, 0x02, /* USAGE (Mouse) */ |
| 91 | 0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01, | 114 | 0xa1, 0x01, /* COLLECTION (Application) */ |
| 92 | 0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81, 0x01, | 115 | 0x09, 0x01, /* USAGE (Pointer) */ |
| 93 | 0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x09, 0x38, | 116 | 0xa1, 0x00, /* COLLECTION (Physical) */ |
| 94 | 0x15, 0x80, 0x25, 0x7f, 0x75, 0x08, 0x95, 0x03, | 117 | 0x85, 0x01, /* REPORT_ID (1) */ |
| 95 | 0x81, 0x06, 0xc0, 0xc0, | 118 | 0x05, 0x09, /* USAGE_PAGE (Button) */ |
| 119 | 0x19, 0x01, /* USAGE_MINIMUM (Button 1) */ | ||
| 120 | 0x29, 0x03, /* USAGE_MAXIMUM (Button 3) */ | ||
| 121 | 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ | ||
| 122 | 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ | ||
| 123 | 0x95, 0x03, /* REPORT_COUNT (3) */ | ||
| 124 | 0x75, 0x01, /* REPORT_SIZE (1) */ | ||
| 125 | 0x81, 0x02, /* INPUT (Data,Var,Abs) */ | ||
| 126 | 0x95, 0x01, /* REPORT_COUNT (1) */ | ||
| 127 | 0x75, 0x05, /* REPORT_SIZE (5) */ | ||
| 128 | 0x81, 0x01, /* INPUT (Cnst,Var,Abs) */ | ||
| 129 | 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ | ||
| 130 | 0x09, 0x30, /* USAGE (X) */ | ||
| 131 | 0x09, 0x31, /* USAGE (Y) */ | ||
| 132 | 0x09, 0x38, /* USAGE (WHEEL) */ | ||
| 133 | 0x15, 0x81, /* LOGICAL_MINIMUM (-127) */ | ||
| 134 | 0x25, 0x7f, /* LOGICAL_MAXIMUM (127) */ | ||
| 135 | 0x75, 0x08, /* REPORT_SIZE (8) */ | ||
| 136 | 0x95, 0x03, /* REPORT_COUNT (3) */ | ||
| 137 | 0x81, 0x06, /* INPUT (Data,Var,Rel) */ | ||
| 138 | 0xc0, /* END_COLLECTION */ | ||
| 139 | 0xc0, /* END_COLLECTION */ | ||
| 140 | 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ | ||
| 141 | 0x09, 0x06, /* USAGE (Keyboard) */ | ||
| 142 | 0xa1, 0x01, /* COLLECTION (Application) */ | ||
| 143 | 0x85, 0x02, /* REPORT_ID (2) */ | ||
| 144 | 0x05, 0x08, /* USAGE_PAGE (Led) */ | ||
| 145 | 0x19, 0x01, /* USAGE_MINIMUM (1) */ | ||
| 146 | 0x29, 0x03, /* USAGE_MAXIMUM (3) */ | ||
| 147 | 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ | ||
| 148 | 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ | ||
| 149 | 0x95, 0x03, /* REPORT_COUNT (3) */ | ||
| 150 | 0x75, 0x01, /* REPORT_SIZE (1) */ | ||
| 151 | 0x91, 0x02, /* Output (Data,Var,Abs) */ | ||
| 152 | 0x95, 0x01, /* REPORT_COUNT (1) */ | ||
| 153 | 0x75, 0x05, /* REPORT_SIZE (5) */ | ||
| 154 | 0x91, 0x01, /* Output (Cnst,Var,Abs) */ | ||
| 155 | 0xc0, /* END_COLLECTION */ | ||
| 96 | }; | 156 | }; |
| 97 | 157 | ||
| 98 | static int uhid_write(int fd, const struct uhid_event *ev) | 158 | static int uhid_write(int fd, const struct uhid_event *ev) |
| @@ -140,6 +200,27 @@ static void destroy(int fd) | |||
| 140 | uhid_write(fd, &ev); | 200 | uhid_write(fd, &ev); |
| 141 | } | 201 | } |
| 142 | 202 | ||
| 203 | /* This parses raw output reports sent by the kernel to the device. A normal | ||
| 204 | * uhid program shouldn't do this but instead just forward the raw report. | ||
| 205 | * However, for ducomentational purposes, we try to detect LED events here and | ||
| 206 | * print debug messages for it. */ | ||
| 207 | static void handle_output(struct uhid_event *ev) | ||
| 208 | { | ||
| 209 | /* LED messages are adverised via OUTPUT reports; ignore the rest */ | ||
| 210 | if (ev->u.output.rtype != UHID_OUTPUT_REPORT) | ||
| 211 | return; | ||
| 212 | /* LED reports have length 2 bytes */ | ||
| 213 | if (ev->u.output.size != 2) | ||
| 214 | return; | ||
| 215 | /* first byte is report-id which is 0x02 for LEDs in our rdesc */ | ||
| 216 | if (ev->u.output.data[0] != 0x2) | ||
| 217 | return; | ||
| 218 | |||
| 219 | /* print flags payload */ | ||
| 220 | fprintf(stderr, "LED output report received with flags %x\n", | ||
| 221 | ev->u.output.data[1]); | ||
| 222 | } | ||
| 223 | |||
| 143 | static int event(int fd) | 224 | static int event(int fd) |
| 144 | { | 225 | { |
| 145 | struct uhid_event ev; | 226 | struct uhid_event ev; |
| @@ -174,6 +255,7 @@ static int event(int fd) | |||
| 174 | break; | 255 | break; |
| 175 | case UHID_OUTPUT: | 256 | case UHID_OUTPUT: |
| 176 | fprintf(stderr, "UHID_OUTPUT from uhid-dev\n"); | 257 | fprintf(stderr, "UHID_OUTPUT from uhid-dev\n"); |
| 258 | handle_output(&ev); | ||
| 177 | break; | 259 | break; |
| 178 | case UHID_OUTPUT_EV: | 260 | case UHID_OUTPUT_EV: |
| 179 | fprintf(stderr, "UHID_OUTPUT_EV from uhid-dev\n"); | 261 | fprintf(stderr, "UHID_OUTPUT_EV from uhid-dev\n"); |
| @@ -198,18 +280,19 @@ static int send_event(int fd) | |||
| 198 | 280 | ||
| 199 | memset(&ev, 0, sizeof(ev)); | 281 | memset(&ev, 0, sizeof(ev)); |
| 200 | ev.type = UHID_INPUT; | 282 | ev.type = UHID_INPUT; |
| 201 | ev.u.input.size = 4; | 283 | ev.u.input.size = 5; |
| 202 | 284 | ||
| 285 | ev.u.input.data[0] = 0x1; | ||
| 203 | if (btn1_down) | 286 | if (btn1_down) |
| 204 | ev.u.input.data[0] |= 0x1; | 287 | ev.u.input.data[1] |= 0x1; |
| 205 | if (btn2_down) | 288 | if (btn2_down) |
| 206 | ev.u.input.data[0] |= 0x2; | 289 | ev.u.input.data[1] |= 0x2; |
| 207 | if (btn3_down) | 290 | if (btn3_down) |
| 208 | ev.u.input.data[0] |= 0x4; | 291 | ev.u.input.data[1] |= 0x4; |
| 209 | 292 | ||
| 210 | ev.u.input.data[1] = abs_hor; | 293 | ev.u.input.data[2] = abs_hor; |
| 211 | ev.u.input.data[2] = abs_ver; | 294 | ev.u.input.data[3] = abs_ver; |
| 212 | ev.u.input.data[3] = wheel; | 295 | ev.u.input.data[4] = wheel; |
| 213 | 296 | ||
| 214 | return uhid_write(fd, &ev); | 297 | return uhid_write(fd, &ev); |
| 215 | } | 298 | } |
