]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - Documentation/usb/gadget_hid.txt
Merge branches 'upstream-fixes' and 'magicmouse' into for-linus
[karo-tx-linux.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 Send and receive HID reports
78
79         HID reports can be sent/received using read/write on the
80         /dev/hidgX character devices. See below for an example program
81         to do this.
82
83         hid_gadget_test is a small interactive program to test the HID
84         gadget driver. To use, point it at a hidg device and set the
85         device type (keyboard / mouse / joystick) - E.G.:
86
87                 # hid_gadget_test /dev/hidg0 keyboard
88
89         You are now in the prompt of hid_gadget_test. You can type any
90         combination of options and values. Available options and
91         values are listed at program start. In keyboard mode you can
92         send up to six values.
93
94         For example type: g i s t r --left-shift
95
96         Hit return and the corresponding report will be sent by the
97         HID gadget.
98
99         Another interesting example is the caps lock test. Type
100         --caps-lock and hit return. A report is then sent by the
101         gadget and you should receive the host answer, corresponding
102         to the caps lock LED status.
103
104                 --caps-lock
105                 recv report:2
106
107         With this command:
108
109                 # hid_gadget_test /dev/hidg1 mouse
110
111         You can test the mouse emulation. Values are two signed numbers.
112
113
114 Sample code
115
116 /* hid_gadget_test */
117
118 #include <pthread.h>
119 #include <string.h>
120 #include <stdio.h>
121 #include <ctype.h>
122 #include <fcntl.h>
123 #include <errno.h>
124 #include <stdio.h>
125 #include <stdlib.h>
126 #include <unistd.h>
127
128 #define BUF_LEN 512
129
130 struct options {
131         const char    *opt;
132         unsigned char val;
133 };
134
135 static struct options kmod[] = {
136         {.opt = "--left-ctrl",          .val = 0x01},
137         {.opt = "--right-ctrl",         .val = 0x10},
138         {.opt = "--left-shift",         .val = 0x02},
139         {.opt = "--right-shift",        .val = 0x20},
140         {.opt = "--left-alt",           .val = 0x04},
141         {.opt = "--right-alt",          .val = 0x40},
142         {.opt = "--left-meta",          .val = 0x08},
143         {.opt = "--right-meta",         .val = 0x80},
144         {.opt = NULL}
145 };
146
147 static struct options kval[] = {
148         {.opt = "--return",     .val = 0x28},
149         {.opt = "--esc",        .val = 0x29},
150         {.opt = "--bckspc",     .val = 0x2a},
151         {.opt = "--tab",        .val = 0x2b},
152         {.opt = "--spacebar",   .val = 0x2c},
153         {.opt = "--caps-lock",  .val = 0x39},
154         {.opt = "--f1",         .val = 0x3a},
155         {.opt = "--f2",         .val = 0x3b},
156         {.opt = "--f3",         .val = 0x3c},
157         {.opt = "--f4",         .val = 0x3d},
158         {.opt = "--f5",         .val = 0x3e},
159         {.opt = "--f6",         .val = 0x3f},
160         {.opt = "--f7",         .val = 0x40},
161         {.opt = "--f8",         .val = 0x41},
162         {.opt = "--f9",         .val = 0x42},
163         {.opt = "--f10",        .val = 0x43},
164         {.opt = "--f11",        .val = 0x44},
165         {.opt = "--f12",        .val = 0x45},
166         {.opt = "--insert",     .val = 0x49},
167         {.opt = "--home",       .val = 0x4a},
168         {.opt = "--pageup",     .val = 0x4b},
169         {.opt = "--del",        .val = 0x4c},
170         {.opt = "--end",        .val = 0x4d},
171         {.opt = "--pagedown",   .val = 0x4e},
172         {.opt = "--right",      .val = 0x4f},
173         {.opt = "--left",       .val = 0x50},
174         {.opt = "--down",       .val = 0x51},
175         {.opt = "--kp-enter",   .val = 0x58},
176         {.opt = "--up",         .val = 0x52},
177         {.opt = "--num-lock",   .val = 0x53},
178         {.opt = NULL}
179 };
180
181 int keyboard_fill_report(char report[8], char buf[BUF_LEN], int *hold)
182 {
183         char *tok = strtok(buf, " ");
184         int key = 0;
185         int i = 0;
186
187         for (; tok != NULL; tok = strtok(NULL, " ")) {
188
189                 if (strcmp(tok, "--quit") == 0)
190                         return -1;
191
192                 if (strcmp(tok, "--hold") == 0) {
193                         *hold = 1;
194                         continue;
195                 }
196
197                 if (key < 6) {
198                         for (i = 0; kval[i].opt != NULL; i++)
199                                 if (strcmp(tok, kval[i].opt) == 0) {
200                                         report[2 + key++] = kval[i].val;
201                                         break;
202                                 }
203                         if (kval[i].opt != NULL)
204                                 continue;
205                 }
206
207                 if (key < 6)
208                         if (islower(tok[0])) {
209                                 report[2 + key++] = (tok[0] - ('a' - 0x04));
210                                 continue;
211                         }
212
213                 for (i = 0; kmod[i].opt != NULL; i++)
214                         if (strcmp(tok, kmod[i].opt) == 0) {
215                                 report[0] = report[0] | kmod[i].val;
216                                 break;
217                         }
218                 if (kmod[i].opt != NULL)
219                         continue;
220
221                 if (key < 6)
222                         fprintf(stderr, "unknown option: %s\n", tok);
223         }
224         return 8;
225 }
226
227 static struct options mmod[] = {
228         {.opt = "--b1", .val = 0x01},
229         {.opt = "--b2", .val = 0x02},
230         {.opt = "--b3", .val = 0x04},
231         {.opt = NULL}
232 };
233
234 int mouse_fill_report(char report[8], char buf[BUF_LEN], int *hold)
235 {
236         char *tok = strtok(buf, " ");
237         int mvt = 0;
238         int i = 0;
239         for (; tok != NULL; tok = strtok(NULL, " ")) {
240
241                 if (strcmp(tok, "--quit") == 0)
242                         return -1;
243
244                 if (strcmp(tok, "--hold") == 0) {
245                         *hold = 1;
246                         continue;
247                 }
248
249                 for (i = 0; mmod[i].opt != NULL; i++)
250                         if (strcmp(tok, mmod[i].opt) == 0) {
251                                 report[0] = report[0] | mmod[i].val;
252                                 break;
253                         }
254                 if (mmod[i].opt != NULL)
255                         continue;
256
257                 if (!(tok[0] == '-' && tok[1] == '-') && mvt < 2) {
258                         errno = 0;
259                         report[1 + mvt++] = (char)strtol(tok, NULL, 0);
260                         if (errno != 0) {
261                                 fprintf(stderr, "Bad value:'%s'\n", tok);
262                                 report[1 + mvt--] = 0;
263                         }
264                         continue;
265                 }
266
267                 fprintf(stderr, "unknown option: %s\n", tok);
268         }
269         return 3;
270 }
271
272 static struct options jmod[] = {
273         {.opt = "--b1",         .val = 0x10},
274         {.opt = "--b2",         .val = 0x20},
275         {.opt = "--b3",         .val = 0x40},
276         {.opt = "--b4",         .val = 0x80},
277         {.opt = "--hat1",       .val = 0x00},
278         {.opt = "--hat2",       .val = 0x01},
279         {.opt = "--hat3",       .val = 0x02},
280         {.opt = "--hat4",       .val = 0x03},
281         {.opt = "--hatneutral", .val = 0x04},
282         {.opt = NULL}
283 };
284
285 int joystick_fill_report(char report[8], char buf[BUF_LEN], int *hold)
286 {
287         char *tok = strtok(buf, " ");
288         int mvt = 0;
289         int i = 0;
290
291         *hold = 1;
292
293         /* set default hat position: neutral */
294         report[3] = 0x04;
295
296         for (; tok != NULL; tok = strtok(NULL, " ")) {
297
298                 if (strcmp(tok, "--quit") == 0)
299                         return -1;
300
301                 for (i = 0; jmod[i].opt != NULL; i++)
302                         if (strcmp(tok, jmod[i].opt) == 0) {
303                                 report[3] = (report[3] & 0xF0) | jmod[i].val;
304                                 break;
305                         }
306                 if (jmod[i].opt != NULL)
307                         continue;
308
309                 if (!(tok[0] == '-' && tok[1] == '-') && mvt < 3) {
310                         errno = 0;
311                         report[mvt++] = (char)strtol(tok, NULL, 0);
312                         if (errno != 0) {
313                                 fprintf(stderr, "Bad value:'%s'\n", tok);
314                                 report[mvt--] = 0;
315                         }
316                         continue;
317                 }
318
319                 fprintf(stderr, "unknown option: %s\n", tok);
320         }
321         return 4;
322 }
323
324 void print_options(char c)
325 {
326         int i = 0;
327
328         if (c == 'k') {
329                 printf("        keyboard options:\n"
330                        "                --hold\n");
331                 for (i = 0; kmod[i].opt != NULL; i++)
332                         printf("\t\t%s\n", kmod[i].opt);
333                 printf("\n      keyboard values:\n"
334                        "                [a-z] or\n");
335                 for (i = 0; kval[i].opt != NULL; i++)
336                         printf("\t\t%-8s%s", kval[i].opt, i % 2 ? "\n" : "");
337                 printf("\n");
338         } else if (c == 'm') {
339                 printf("        mouse options:\n"
340                        "                --hold\n");
341                 for (i = 0; mmod[i].opt != NULL; i++)
342                         printf("\t\t%s\n", mmod[i].opt);
343                 printf("\n      mouse values:\n"
344                        "                Two signed numbers\n"
345                        "--quit to close\n");
346         } else {
347                 printf("        joystick options:\n");
348                 for (i = 0; jmod[i].opt != NULL; i++)
349                         printf("\t\t%s\n", jmod[i].opt);
350                 printf("\n      joystick values:\n"
351                        "                three signed numbers\n"
352                        "--quit to close\n");
353         }
354 }
355
356 int main(int argc, const char *argv[])
357 {
358         const char *filename = NULL;
359         int fd = 0;
360         char buf[BUF_LEN];
361         int cmd_len;
362         char report[8];
363         int to_send = 8;
364         int hold = 0;
365         fd_set rfds;
366         int retval, i;
367
368         if (argc < 3) {
369                 fprintf(stderr, "Usage: %s devname mouse|keyboard|joystick\n",
370                         argv[0]);
371                 return 1;
372         }
373
374         if (argv[2][0] != 'k' && argv[2][0] != 'm' && argv[2][0] != 'j')
375           return 2;
376
377         filename = argv[1];
378
379         if ((fd = open(filename, O_RDWR, 0666)) == -1) {
380                 perror(filename);
381                 return 3;
382         }
383
384         print_options(argv[2][0]);
385
386         while (42) {
387
388                 FD_ZERO(&rfds);
389                 FD_SET(STDIN_FILENO, &rfds);
390                 FD_SET(fd, &rfds);
391
392                 retval = select(fd + 1, &rfds, NULL, NULL, NULL);
393                 if (retval == -1 && errno == EINTR)
394                         continue;
395                 if (retval < 0) {
396                         perror("select()");
397                         return 4;
398                 }
399
400                 if (FD_ISSET(fd, &rfds)) {
401                         cmd_len = read(fd, buf, BUF_LEN - 1);
402                         printf("recv report:");
403                         for (i = 0; i < cmd_len; i++)
404                                 printf(" %02x", buf[i]);
405                         printf("\n");
406                 }
407
408                 if (FD_ISSET(STDIN_FILENO, &rfds)) {
409                         memset(report, 0x0, sizeof(report));
410                         cmd_len = read(STDIN_FILENO, buf, BUF_LEN - 1);
411
412                         if (cmd_len == 0)
413                                 break;
414
415                         buf[cmd_len - 1] = '\0';
416                         hold = 0;
417
418                         memset(report, 0x0, sizeof(report));
419                         if (argv[2][0] == 'k')
420                                 to_send = keyboard_fill_report(report, buf, &hold);
421                         else if (argv[2][0] == 'm')
422                                 to_send = mouse_fill_report(report, buf, &hold);
423                         else
424                                 to_send = joystick_fill_report(report, buf, &hold);
425
426                         if (to_send == -1)
427                                 break;
428
429                         if (write(fd, report, to_send) != to_send) {
430                                 perror(filename);
431                                 return 5;
432                         }
433                         if (!hold) {
434                                 memset(report, 0x0, sizeof(report));
435                                 if (write(fd, report, to_send) != to_send) {
436                                         perror(filename);
437                                         return 6;
438                                 }
439                         }
440                 }
441         }
442
443         close(fd);
444         return 0;
445 }