MAINTAINERS: add Mediatek SoC mailing list
[linux/fpc-iii.git] / Documentation / usb / gadget_hid.txt
blob7a0fb8e16e27508d6b16baf8196f7575ae3b7b9f
2                      Linux USB HID gadget driver
4 Introduction
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.
11         For more details about HID, see the developer page on
12         http://www.usb.org/developers/hidpage/
14 Configuration
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:
21 #include <linux/platform_device.h>
22 #include <linux/usb/g_hid.h>
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         }
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,
74         You can add as many HID functions as you want, only limited by
75         the amount of interrupt endpoints your gadget driver supports.
77 Configuration with configfs
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.
84 Send and receive HID reports
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.
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.:
94                 # hid_gadget_test /dev/hidg0 keyboard
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.
101         For example type: g i s t r --left-shift
103         Hit return and the corresponding report will be sent by the
104         HID gadget.
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.
111                 --caps-lock
112                 recv report:2
114         With this command:
116                 # hid_gadget_test /dev/hidg1 mouse
118         You can test the mouse emulation. Values are two signed numbers.
121 Sample code
123 /* hid_gadget_test */
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>
135 #define BUF_LEN 512
137 struct options {
138         const char    *opt;
139         unsigned char val;
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}
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}
188 int keyboard_fill_report(char report[8], char buf[BUF_LEN], int *hold)
190         char *tok = strtok(buf, " ");
191         int key = 0;
192         int i = 0;
194         for (; tok != NULL; tok = strtok(NULL, " ")) {
196                 if (strcmp(tok, "--quit") == 0)
197                         return -1;
199                 if (strcmp(tok, "--hold") == 0) {
200                         *hold = 1;
201                         continue;
202                 }
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                 }
214                 if (key < 6)
215                         if (islower(tok[0])) {
216                                 report[2 + key++] = (tok[0] - ('a' - 0x04));
217                                 continue;
218                         }
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;
228                 if (key < 6)
229                         fprintf(stderr, "unknown option: %s\n", tok);
230         }
231         return 8;
234 static struct options mmod[] = {
235         {.opt = "--b1", .val = 0x01},
236         {.opt = "--b2", .val = 0x02},
237         {.opt = "--b3", .val = 0x04},
238         {.opt = NULL}
241 int mouse_fill_report(char report[8], char buf[BUF_LEN], int *hold)
243         char *tok = strtok(buf, " ");
244         int mvt = 0;
245         int i = 0;
246         for (; tok != NULL; tok = strtok(NULL, " ")) {
248                 if (strcmp(tok, "--quit") == 0)
249                         return -1;
251                 if (strcmp(tok, "--hold") == 0) {
252                         *hold = 1;
253                         continue;
254                 }
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;
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                 }
274                 fprintf(stderr, "unknown option: %s\n", tok);
275         }
276         return 3;
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}
292 int joystick_fill_report(char report[8], char buf[BUF_LEN], int *hold)
294         char *tok = strtok(buf, " ");
295         int mvt = 0;
296         int i = 0;
298         *hold = 1;
300         /* set default hat position: neutral */
301         report[3] = 0x04;
303         for (; tok != NULL; tok = strtok(NULL, " ")) {
305                 if (strcmp(tok, "--quit") == 0)
306                         return -1;
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;
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                 }
326                 fprintf(stderr, "unknown option: %s\n", tok);
327         }
328         return 4;
331 void print_options(char c)
333         int i = 0;
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         }
363 int main(int argc, const char *argv[])
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;
375         if (argc < 3) {
376                 fprintf(stderr, "Usage: %s devname mouse|keyboard|joystick\n",
377                         argv[0]);
378                 return 1;
379         }
381         if (argv[2][0] != 'k' && argv[2][0] != 'm' && argv[2][0] != 'j')
382           return 2;
384         filename = argv[1];
386         if ((fd = open(filename, O_RDWR, 0666)) == -1) {
387                 perror(filename);
388                 return 3;
389         }
391         print_options(argv[2][0]);
393         while (42) {
395                 FD_ZERO(&rfds);
396                 FD_SET(STDIN_FILENO, &rfds);
397                 FD_SET(fd, &rfds);
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                 }
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                 }
415                 if (FD_ISSET(STDIN_FILENO, &rfds)) {
416                         memset(report, 0x0, sizeof(report));
417                         cmd_len = read(STDIN_FILENO, buf, BUF_LEN - 1);
419                         if (cmd_len == 0)
420                                 break;
422                         buf[cmd_len - 1] = '\0';
423                         hold = 0;
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);
433                         if (to_send == -1)
434                                 break;
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         }
450         close(fd);
451         return 0;