]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blob - Documentation/usb/gadget_hid.rst
Merge tag 'zynqmp-soc-for-v5.9-v2' of https://github.com/Xilinx/linux-xlnx into arm...
[mirror_ubuntu-hirsute-kernel.git] / Documentation / usb / gadget_hid.rst
1 ===========================
2 Linux USB HID gadget driver
3 ===========================
4
5 Introduction
6 ============
7
8 The HID Gadget driver provides emulation of USB Human Interface
9 Devices (HID). The basic HID handling is done in the kernel,
10 and HID reports can be sent/received through I/O on the
11 /dev/hidgX character devices.
12
13 For more details about HID, see the developer page on
14 https://www.usb.org/developers/hidpage/
15
16 Configuration
17 =============
18
19 g_hid is a platform driver, so to use it you need to add
20 struct platform_device(s) to your platform code defining the
21 HID function descriptors you want to use - E.G. something
22 like::
23
24 #include <linux/platform_device.h>
25 #include <linux/usb/g_hid.h>
26
27 /* hid descriptor for a keyboard */
28 static struct hidg_func_descriptor my_hid_data = {
29 .subclass = 0, /* No subclass */
30 .protocol = 1, /* Keyboard */
31 .report_length = 8,
32 .report_desc_length = 63,
33 .report_desc = {
34 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
35 0x09, 0x06, /* USAGE (Keyboard) */
36 0xa1, 0x01, /* COLLECTION (Application) */
37 0x05, 0x07, /* USAGE_PAGE (Keyboard) */
38 0x19, 0xe0, /* USAGE_MINIMUM (Keyboard LeftControl) */
39 0x29, 0xe7, /* USAGE_MAXIMUM (Keyboard Right GUI) */
40 0x15, 0x00, /* LOGICAL_MINIMUM (0) */
41 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
42 0x75, 0x01, /* REPORT_SIZE (1) */
43 0x95, 0x08, /* REPORT_COUNT (8) */
44 0x81, 0x02, /* INPUT (Data,Var,Abs) */
45 0x95, 0x01, /* REPORT_COUNT (1) */
46 0x75, 0x08, /* REPORT_SIZE (8) */
47 0x81, 0x03, /* INPUT (Cnst,Var,Abs) */
48 0x95, 0x05, /* REPORT_COUNT (5) */
49 0x75, 0x01, /* REPORT_SIZE (1) */
50 0x05, 0x08, /* USAGE_PAGE (LEDs) */
51 0x19, 0x01, /* USAGE_MINIMUM (Num Lock) */
52 0x29, 0x05, /* USAGE_MAXIMUM (Kana) */
53 0x91, 0x02, /* OUTPUT (Data,Var,Abs) */
54 0x95, 0x01, /* REPORT_COUNT (1) */
55 0x75, 0x03, /* REPORT_SIZE (3) */
56 0x91, 0x03, /* OUTPUT (Cnst,Var,Abs) */
57 0x95, 0x06, /* REPORT_COUNT (6) */
58 0x75, 0x08, /* REPORT_SIZE (8) */
59 0x15, 0x00, /* LOGICAL_MINIMUM (0) */
60 0x25, 0x65, /* LOGICAL_MAXIMUM (101) */
61 0x05, 0x07, /* USAGE_PAGE (Keyboard) */
62 0x19, 0x00, /* USAGE_MINIMUM (Reserved) */
63 0x29, 0x65, /* USAGE_MAXIMUM (Keyboard Application) */
64 0x81, 0x00, /* INPUT (Data,Ary,Abs) */
65 0xc0 /* END_COLLECTION */
66 }
67 };
68
69 static struct platform_device my_hid = {
70 .name = "hidg",
71 .id = 0,
72 .num_resources = 0,
73 .resource = 0,
74 .dev.platform_data = &my_hid_data,
75 };
76
77 You can add as many HID functions as you want, only limited by
78 the amount of interrupt endpoints your gadget driver supports.
79
80 Configuration with configfs
81 ===========================
82
83 Instead of adding fake platform devices and drivers in order to pass
84 some data to the kernel, if HID is a part of a gadget composed with
85 configfs the hidg_func_descriptor.report_desc is passed to the kernel
86 by writing the appropriate stream of bytes to a configfs attribute.
87
88 Send and receive HID reports
89 ============================
90
91 HID reports can be sent/received using read/write on the
92 /dev/hidgX character devices. See below for an example program
93 to do this.
94
95 hid_gadget_test is a small interactive program to test the HID
96 gadget driver. To use, point it at a hidg device and set the
97 device type (keyboard / mouse / joystick) - E.G.::
98
99 # hid_gadget_test /dev/hidg0 keyboard
100
101 You are now in the prompt of hid_gadget_test. You can type any
102 combination of options and values. Available options and
103 values are listed at program start. In keyboard mode you can
104 send up to six values.
105
106 For example type: g i s t r --left-shift
107
108 Hit return and the corresponding report will be sent by the
109 HID gadget.
110
111 Another interesting example is the caps lock test. Type
112 --caps-lock and hit return. A report is then sent by the
113 gadget and you should receive the host answer, corresponding
114 to the caps lock LED status::
115
116 --caps-lock
117 recv report:2
118
119 With this command::
120
121 # hid_gadget_test /dev/hidg1 mouse
122
123 You can test the mouse emulation. Values are two signed numbers.
124
125
126 Sample code::
127
128 /* hid_gadget_test */
129
130 #include <pthread.h>
131 #include <string.h>
132 #include <stdio.h>
133 #include <ctype.h>
134 #include <fcntl.h>
135 #include <errno.h>
136 #include <stdio.h>
137 #include <stdlib.h>
138 #include <unistd.h>
139
140 #define BUF_LEN 512
141
142 struct options {
143 const char *opt;
144 unsigned char val;
145 };
146
147 static struct options kmod[] = {
148 {.opt = "--left-ctrl", .val = 0x01},
149 {.opt = "--right-ctrl", .val = 0x10},
150 {.opt = "--left-shift", .val = 0x02},
151 {.opt = "--right-shift", .val = 0x20},
152 {.opt = "--left-alt", .val = 0x04},
153 {.opt = "--right-alt", .val = 0x40},
154 {.opt = "--left-meta", .val = 0x08},
155 {.opt = "--right-meta", .val = 0x80},
156 {.opt = NULL}
157 };
158
159 static struct options kval[] = {
160 {.opt = "--return", .val = 0x28},
161 {.opt = "--esc", .val = 0x29},
162 {.opt = "--bckspc", .val = 0x2a},
163 {.opt = "--tab", .val = 0x2b},
164 {.opt = "--spacebar", .val = 0x2c},
165 {.opt = "--caps-lock", .val = 0x39},
166 {.opt = "--f1", .val = 0x3a},
167 {.opt = "--f2", .val = 0x3b},
168 {.opt = "--f3", .val = 0x3c},
169 {.opt = "--f4", .val = 0x3d},
170 {.opt = "--f5", .val = 0x3e},
171 {.opt = "--f6", .val = 0x3f},
172 {.opt = "--f7", .val = 0x40},
173 {.opt = "--f8", .val = 0x41},
174 {.opt = "--f9", .val = 0x42},
175 {.opt = "--f10", .val = 0x43},
176 {.opt = "--f11", .val = 0x44},
177 {.opt = "--f12", .val = 0x45},
178 {.opt = "--insert", .val = 0x49},
179 {.opt = "--home", .val = 0x4a},
180 {.opt = "--pageup", .val = 0x4b},
181 {.opt = "--del", .val = 0x4c},
182 {.opt = "--end", .val = 0x4d},
183 {.opt = "--pagedown", .val = 0x4e},
184 {.opt = "--right", .val = 0x4f},
185 {.opt = "--left", .val = 0x50},
186 {.opt = "--down", .val = 0x51},
187 {.opt = "--kp-enter", .val = 0x58},
188 {.opt = "--up", .val = 0x52},
189 {.opt = "--num-lock", .val = 0x53},
190 {.opt = NULL}
191 };
192
193 int keyboard_fill_report(char report[8], char buf[BUF_LEN], int *hold)
194 {
195 char *tok = strtok(buf, " ");
196 int key = 0;
197 int i = 0;
198
199 for (; tok != NULL; tok = strtok(NULL, " ")) {
200
201 if (strcmp(tok, "--quit") == 0)
202 return -1;
203
204 if (strcmp(tok, "--hold") == 0) {
205 *hold = 1;
206 continue;
207 }
208
209 if (key < 6) {
210 for (i = 0; kval[i].opt != NULL; i++)
211 if (strcmp(tok, kval[i].opt) == 0) {
212 report[2 + key++] = kval[i].val;
213 break;
214 }
215 if (kval[i].opt != NULL)
216 continue;
217 }
218
219 if (key < 6)
220 if (islower(tok[0])) {
221 report[2 + key++] = (tok[0] - ('a' - 0x04));
222 continue;
223 }
224
225 for (i = 0; kmod[i].opt != NULL; i++)
226 if (strcmp(tok, kmod[i].opt) == 0) {
227 report[0] = report[0] | kmod[i].val;
228 break;
229 }
230 if (kmod[i].opt != NULL)
231 continue;
232
233 if (key < 6)
234 fprintf(stderr, "unknown option: %s\n", tok);
235 }
236 return 8;
237 }
238
239 static struct options mmod[] = {
240 {.opt = "--b1", .val = 0x01},
241 {.opt = "--b2", .val = 0x02},
242 {.opt = "--b3", .val = 0x04},
243 {.opt = NULL}
244 };
245
246 int mouse_fill_report(char report[8], char buf[BUF_LEN], int *hold)
247 {
248 char *tok = strtok(buf, " ");
249 int mvt = 0;
250 int i = 0;
251 for (; tok != NULL; tok = strtok(NULL, " ")) {
252
253 if (strcmp(tok, "--quit") == 0)
254 return -1;
255
256 if (strcmp(tok, "--hold") == 0) {
257 *hold = 1;
258 continue;
259 }
260
261 for (i = 0; mmod[i].opt != NULL; i++)
262 if (strcmp(tok, mmod[i].opt) == 0) {
263 report[0] = report[0] | mmod[i].val;
264 break;
265 }
266 if (mmod[i].opt != NULL)
267 continue;
268
269 if (!(tok[0] == '-' && tok[1] == '-') && mvt < 2) {
270 errno = 0;
271 report[1 + mvt++] = (char)strtol(tok, NULL, 0);
272 if (errno != 0) {
273 fprintf(stderr, "Bad value:'%s'\n", tok);
274 report[1 + mvt--] = 0;
275 }
276 continue;
277 }
278
279 fprintf(stderr, "unknown option: %s\n", tok);
280 }
281 return 3;
282 }
283
284 static struct options jmod[] = {
285 {.opt = "--b1", .val = 0x10},
286 {.opt = "--b2", .val = 0x20},
287 {.opt = "--b3", .val = 0x40},
288 {.opt = "--b4", .val = 0x80},
289 {.opt = "--hat1", .val = 0x00},
290 {.opt = "--hat2", .val = 0x01},
291 {.opt = "--hat3", .val = 0x02},
292 {.opt = "--hat4", .val = 0x03},
293 {.opt = "--hatneutral", .val = 0x04},
294 {.opt = NULL}
295 };
296
297 int joystick_fill_report(char report[8], char buf[BUF_LEN], int *hold)
298 {
299 char *tok = strtok(buf, " ");
300 int mvt = 0;
301 int i = 0;
302
303 *hold = 1;
304
305 /* set default hat position: neutral */
306 report[3] = 0x04;
307
308 for (; tok != NULL; tok = strtok(NULL, " ")) {
309
310 if (strcmp(tok, "--quit") == 0)
311 return -1;
312
313 for (i = 0; jmod[i].opt != NULL; i++)
314 if (strcmp(tok, jmod[i].opt) == 0) {
315 report[3] = (report[3] & 0xF0) | jmod[i].val;
316 break;
317 }
318 if (jmod[i].opt != NULL)
319 continue;
320
321 if (!(tok[0] == '-' && tok[1] == '-') && mvt < 3) {
322 errno = 0;
323 report[mvt++] = (char)strtol(tok, NULL, 0);
324 if (errno != 0) {
325 fprintf(stderr, "Bad value:'%s'\n", tok);
326 report[mvt--] = 0;
327 }
328 continue;
329 }
330
331 fprintf(stderr, "unknown option: %s\n", tok);
332 }
333 return 4;
334 }
335
336 void print_options(char c)
337 {
338 int i = 0;
339
340 if (c == 'k') {
341 printf(" keyboard options:\n"
342 " --hold\n");
343 for (i = 0; kmod[i].opt != NULL; i++)
344 printf("\t\t%s\n", kmod[i].opt);
345 printf("\n keyboard values:\n"
346 " [a-z] or\n");
347 for (i = 0; kval[i].opt != NULL; i++)
348 printf("\t\t%-8s%s", kval[i].opt, i % 2 ? "\n" : "");
349 printf("\n");
350 } else if (c == 'm') {
351 printf(" mouse options:\n"
352 " --hold\n");
353 for (i = 0; mmod[i].opt != NULL; i++)
354 printf("\t\t%s\n", mmod[i].opt);
355 printf("\n mouse values:\n"
356 " Two signed numbers\n"
357 "--quit to close\n");
358 } else {
359 printf(" joystick options:\n");
360 for (i = 0; jmod[i].opt != NULL; i++)
361 printf("\t\t%s\n", jmod[i].opt);
362 printf("\n joystick values:\n"
363 " three signed numbers\n"
364 "--quit to close\n");
365 }
366 }
367
368 int main(int argc, const char *argv[])
369 {
370 const char *filename = NULL;
371 int fd = 0;
372 char buf[BUF_LEN];
373 int cmd_len;
374 char report[8];
375 int to_send = 8;
376 int hold = 0;
377 fd_set rfds;
378 int retval, i;
379
380 if (argc < 3) {
381 fprintf(stderr, "Usage: %s devname mouse|keyboard|joystick\n",
382 argv[0]);
383 return 1;
384 }
385
386 if (argv[2][0] != 'k' && argv[2][0] != 'm' && argv[2][0] != 'j')
387 return 2;
388
389 filename = argv[1];
390
391 if ((fd = open(filename, O_RDWR, 0666)) == -1) {
392 perror(filename);
393 return 3;
394 }
395
396 print_options(argv[2][0]);
397
398 while (42) {
399
400 FD_ZERO(&rfds);
401 FD_SET(STDIN_FILENO, &rfds);
402 FD_SET(fd, &rfds);
403
404 retval = select(fd + 1, &rfds, NULL, NULL, NULL);
405 if (retval == -1 && errno == EINTR)
406 continue;
407 if (retval < 0) {
408 perror("select()");
409 return 4;
410 }
411
412 if (FD_ISSET(fd, &rfds)) {
413 cmd_len = read(fd, buf, BUF_LEN - 1);
414 printf("recv report:");
415 for (i = 0; i < cmd_len; i++)
416 printf(" %02x", buf[i]);
417 printf("\n");
418 }
419
420 if (FD_ISSET(STDIN_FILENO, &rfds)) {
421 memset(report, 0x0, sizeof(report));
422 cmd_len = read(STDIN_FILENO, buf, BUF_LEN - 1);
423
424 if (cmd_len == 0)
425 break;
426
427 buf[cmd_len - 1] = '\0';
428 hold = 0;
429
430 memset(report, 0x0, sizeof(report));
431 if (argv[2][0] == 'k')
432 to_send = keyboard_fill_report(report, buf, &hold);
433 else if (argv[2][0] == 'm')
434 to_send = mouse_fill_report(report, buf, &hold);
435 else
436 to_send = joystick_fill_report(report, buf, &hold);
437
438 if (to_send == -1)
439 break;
440
441 if (write(fd, report, to_send) != to_send) {
442 perror(filename);
443 return 5;
444 }
445 if (!hold) {
446 memset(report, 0x0, sizeof(report));
447 if (write(fd, report, to_send) != to_send) {
448 perror(filename);
449 return 6;
450 }
451 }
452 }
453 }
454
455 close(fd);
456 return 0;
457 }