Linux 6.13-rc3
[linux.git] / Documentation / usb / gadget_hid.rst
blobe623416de4f1bae24ed12ae0f7fe0463b291ab5b
1 ===========================
2 Linux USB HID gadget driver
3 ===========================
5 Introduction
6 ============
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.
13 For more details about HID, see the developer page on
14 https://www.usb.org/developers/hidpage/
16 Configuration
17 =============
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::
24   #include <linux/platform_device.h>
25   #include <linux/usb/g_hid.h>
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   };
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   };
77 You can add as many HID functions as you want, only limited by
78 the amount of interrupt endpoints your gadget driver supports.
80 Configuration with configfs
81 ===========================
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.
88 Send and receive HID reports
89 ============================
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.
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.::
99         # hid_gadget_test /dev/hidg0 keyboard
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.
106 For example type: g i s t r --left-shift
108 Hit return and the corresponding report will be sent by the
109 HID gadget.
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::
116         --caps-lock
117         recv report:2
119 With this command::
121         # hid_gadget_test /dev/hidg1 mouse
123 You can test the mouse emulation. Values are two signed numbers.
126 Sample code::
128     /* hid_gadget_test */
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>
140     #define BUF_LEN 512
142     struct options {
143         const char    *opt;
144         unsigned char val;
145   };
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   };
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   };
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;
199         for (; tok != NULL; tok = strtok(NULL, " ")) {
201                 if (strcmp(tok, "--quit") == 0)
202                         return -1;
204                 if (strcmp(tok, "--hold") == 0) {
205                         *hold = 1;
206                         continue;
207                 }
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                 }
219                 if (key < 6)
220                         if (islower(tok[0])) {
221                                 report[2 + key++] = (tok[0] - ('a' - 0x04));
222                                 continue;
223                         }
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;
233                 if (key < 6)
234                         fprintf(stderr, "unknown option: %s\n", tok);
235         }
236         return 8;
237   }
239   static struct options mmod[] = {
240         {.opt = "--b1", .val = 0x01},
241         {.opt = "--b2", .val = 0x02},
242         {.opt = "--b3", .val = 0x04},
243         {.opt = NULL}
244   };
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, " ")) {
253                 if (strcmp(tok, "--quit") == 0)
254                         return -1;
256                 if (strcmp(tok, "--hold") == 0) {
257                         *hold = 1;
258                         continue;
259                 }
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;
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                 }
279                 fprintf(stderr, "unknown option: %s\n", tok);
280         }
281         return 3;
282   }
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   };
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;
303         *hold = 1;
305         /* set default hat position: neutral */
306         report[3] = 0x04;
308         for (; tok != NULL; tok = strtok(NULL, " ")) {
310                 if (strcmp(tok, "--quit") == 0)
311                         return -1;
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;
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                 }
331                 fprintf(stderr, "unknown option: %s\n", tok);
332         }
333         return 4;
334   }
336   void print_options(char c)
337   {
338         int i = 0;
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   }
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;
380         if (argc < 3) {
381                 fprintf(stderr, "Usage: %s devname mouse|keyboard|joystick\n",
382                         argv[0]);
383                 return 1;
384         }
386         if (argv[2][0] != 'k' && argv[2][0] != 'm' && argv[2][0] != 'j')
387           return 2;
389         filename = argv[1];
391         if ((fd = open(filename, O_RDWR, 0666)) == -1) {
392                 perror(filename);
393                 return 3;
394         }
396         print_options(argv[2][0]);
398         while (42) {
400                 FD_ZERO(&rfds);
401                 FD_SET(STDIN_FILENO, &rfds);
402                 FD_SET(fd, &rfds);
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                 }
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                 }
420                 if (FD_ISSET(STDIN_FILENO, &rfds)) {
421                         memset(report, 0x0, sizeof(report));
422                         cmd_len = read(STDIN_FILENO, buf, BUF_LEN - 1);
424                         if (cmd_len == 0)
425                                 break;
427                         buf[cmd_len - 1] = '\0';
428                         hold = 0;
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);
438                         if (to_send == -1)
439                                 break;
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         }
455         close(fd);
456         return 0;
457   }