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