diff options
-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 | } |