Commit f5e4e7fdd57691d5308cf854dd0dbcfd58799e9a

Authored by David Herrmann
Committed by Jiri Kosina
1 parent 58c59bc997

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>

Showing 1 changed file with 103 additions and 20 deletions Side-by-side Diff

samples/uhid/uhid-example.c
1 1 /*
2 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 6 * The code may be used by anyone for any purpose,
7 7 * and can serve as a starting point for developing
8 8 * applications using uhid.
9 9 */
10 10  
11   -/* UHID Example
  11 +/*
  12 + * UHID Example
12 13 * This example emulates a basic 3 buttons mouse with wheel over UHID. Run this
13 14 * program as root and then use the following keys to control the mouse:
14 15 * q: Quit the application
... ... @@ -22,6 +23,11 @@
22 23 * r: Move wheel up
23 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 31 * If uhid is not available as /dev/uhid, then you can pass a different path as
26 32 * first argument.
27 33 * If <linux/uhid.h> is not installed in /usr, then compile this with:
28 34  
... ... @@ -41,11 +47,12 @@
41 47 #include <unistd.h>
42 48 #include <linux/uhid.h>
43 49  
44   -/* HID Report Desciptor
45   - * We emulate a basic 3 button mouse with wheel. This is the report-descriptor
46   - * as the kernel will parse it:
  50 +/*
  51 + * HID Report Desciptor
  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 56 * Field(0)
50 57 * Physical(GenericDesktop.Pointer)
51 58 * Application(GenericDesktop.Mouse)
... ... @@ -72,6 +79,19 @@
72 79 * Report Count(3)
73 80 * Report Offset(8)
74 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 96 * This is the mapping that we expect:
77 97 * Button.0001 ---> Key.LeftBtn
78 98  
... ... @@ -80,19 +100,59 @@
80 100 * GenericDesktop.X ---> Relative.X
81 101 * GenericDesktop.Y ---> Relative.Y
82 102 * GenericDesktop.Wheel ---> Relative.Wheel
  103 + * LED.NumLock ---> LED.NumLock
  104 + * LED.CapsLock ---> LED.CapsLock
  105 + * LED.ScrollLock ---> LED.ScrollLock
83 106 *
84 107 * This information can be verified by reading /sys/kernel/debug/hid/<dev>/rdesc
85 108 * This file should print the same information as showed above.
86 109 */
87 110  
88 111 static unsigned char rdesc[] = {
89   - 0x05, 0x01, 0x09, 0x02, 0xa1, 0x01, 0x09, 0x01,
90   - 0xa1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03,
91   - 0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01,
92   - 0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81, 0x01,
93   - 0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x09, 0x38,
94   - 0x15, 0x80, 0x25, 0x7f, 0x75, 0x08, 0x95, 0x03,
95   - 0x81, 0x06, 0xc0, 0xc0,
  112 + 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
  113 + 0x09, 0x02, /* USAGE (Mouse) */
  114 + 0xa1, 0x01, /* COLLECTION (Application) */
  115 + 0x09, 0x01, /* USAGE (Pointer) */
  116 + 0xa1, 0x00, /* COLLECTION (Physical) */
  117 + 0x85, 0x01, /* REPORT_ID (1) */
  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 158 static int uhid_write(int fd, const struct uhid_event *ev)
... ... @@ -140,6 +200,27 @@
140 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 224 static int event(int fd)
144 225 {
145 226 struct uhid_event ev;
... ... @@ -174,6 +255,7 @@
174 255 break;
175 256 case UHID_OUTPUT:
176 257 fprintf(stderr, "UHID_OUTPUT from uhid-dev\n");
  258 + handle_output(&ev);
177 259 break;
178 260 case UHID_OUTPUT_EV:
179 261 fprintf(stderr, "UHID_OUTPUT_EV from uhid-dev\n");
180 262  
181 263  
182 264  
183 265  
184 266  
... ... @@ -198,18 +280,19 @@
198 280  
199 281 memset(&ev, 0, sizeof(ev));
200 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 286 if (btn1_down)
204   - ev.u.input.data[0] |= 0x1;
  287 + ev.u.input.data[1] |= 0x1;
205 288 if (btn2_down)
206   - ev.u.input.data[0] |= 0x2;
  289 + ev.u.input.data[1] |= 0x2;
207 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;
211   - ev.u.input.data[2] = abs_ver;
212   - ev.u.input.data[3] = wheel;
  293 + ev.u.input.data[2] = abs_hor;
  294 + ev.u.input.data[3] = abs_ver;
  295 + ev.u.input.data[4] = wheel;
213 296  
214 297 return uhid_write(fd, &ev);
215 298 }