GNU Linux-libre 6.6.34-gnu
[releases.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   }