~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/Documentation/usb/gadget_hid.rst

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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   }

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php