Back to home page

OSCL-LXR

 
 

    


0001 ===========================
0002 Linux USB HID gadget driver
0003 ===========================
0004 
0005 Introduction
0006 ============
0007 
0008 The HID Gadget driver provides emulation of USB Human Interface
0009 Devices (HID). The basic HID handling is done in the kernel,
0010 and HID reports can be sent/received through I/O on the
0011 /dev/hidgX character devices.
0012 
0013 For more details about HID, see the developer page on
0014 https://www.usb.org/developers/hidpage/
0015 
0016 Configuration
0017 =============
0018 
0019 g_hid is a platform driver, so to use it you need to add
0020 struct platform_device(s) to your platform code defining the
0021 HID function descriptors you want to use - E.G. something
0022 like::
0023 
0024   #include <linux/platform_device.h>
0025   #include <linux/usb/g_hid.h>
0026 
0027   /* hid descriptor for a keyboard */
0028   static struct hidg_func_descriptor my_hid_data = {
0029         .subclass               = 0, /* No subclass */
0030         .protocol               = 1, /* Keyboard */
0031         .report_length          = 8,
0032         .report_desc_length     = 63,
0033         .report_desc            = {
0034                 0x05, 0x01,     /* USAGE_PAGE (Generic Desktop)           */
0035                 0x09, 0x06,     /* USAGE (Keyboard)                       */
0036                 0xa1, 0x01,     /* COLLECTION (Application)               */
0037                 0x05, 0x07,     /*   USAGE_PAGE (Keyboard)                */
0038                 0x19, 0xe0,     /*   USAGE_MINIMUM (Keyboard LeftControl) */
0039                 0x29, 0xe7,     /*   USAGE_MAXIMUM (Keyboard Right GUI)   */
0040                 0x15, 0x00,     /*   LOGICAL_MINIMUM (0)                  */
0041                 0x25, 0x01,     /*   LOGICAL_MAXIMUM (1)                  */
0042                 0x75, 0x01,     /*   REPORT_SIZE (1)                      */
0043                 0x95, 0x08,     /*   REPORT_COUNT (8)                     */
0044                 0x81, 0x02,     /*   INPUT (Data,Var,Abs)                 */
0045                 0x95, 0x01,     /*   REPORT_COUNT (1)                     */
0046                 0x75, 0x08,     /*   REPORT_SIZE (8)                      */
0047                 0x81, 0x03,     /*   INPUT (Cnst,Var,Abs)                 */
0048                 0x95, 0x05,     /*   REPORT_COUNT (5)                     */
0049                 0x75, 0x01,     /*   REPORT_SIZE (1)                      */
0050                 0x05, 0x08,     /*   USAGE_PAGE (LEDs)                    */
0051                 0x19, 0x01,     /*   USAGE_MINIMUM (Num Lock)             */
0052                 0x29, 0x05,     /*   USAGE_MAXIMUM (Kana)                 */
0053                 0x91, 0x02,     /*   OUTPUT (Data,Var,Abs)                */
0054                 0x95, 0x01,     /*   REPORT_COUNT (1)                     */
0055                 0x75, 0x03,     /*   REPORT_SIZE (3)                      */
0056                 0x91, 0x03,     /*   OUTPUT (Cnst,Var,Abs)                */
0057                 0x95, 0x06,     /*   REPORT_COUNT (6)                     */
0058                 0x75, 0x08,     /*   REPORT_SIZE (8)                      */
0059                 0x15, 0x00,     /*   LOGICAL_MINIMUM (0)                  */
0060                 0x25, 0x65,     /*   LOGICAL_MAXIMUM (101)                */
0061                 0x05, 0x07,     /*   USAGE_PAGE (Keyboard)                */
0062                 0x19, 0x00,     /*   USAGE_MINIMUM (Reserved)             */
0063                 0x29, 0x65,     /*   USAGE_MAXIMUM (Keyboard Application) */
0064                 0x81, 0x00,     /*   INPUT (Data,Ary,Abs)                 */
0065                 0xc0            /* END_COLLECTION                         */
0066         }
0067   };
0068 
0069   static struct platform_device my_hid = {
0070         .name                   = "hidg",
0071         .id                     = 0,
0072         .num_resources          = 0,
0073         .resource               = 0,
0074         .dev.platform_data      = &my_hid_data,
0075   };
0076 
0077 You can add as many HID functions as you want, only limited by
0078 the amount of interrupt endpoints your gadget driver supports.
0079 
0080 Configuration with configfs
0081 ===========================
0082 
0083 Instead of adding fake platform devices and drivers in order to pass
0084 some data to the kernel, if HID is a part of a gadget composed with
0085 configfs the hidg_func_descriptor.report_desc is passed to the kernel
0086 by writing the appropriate stream of bytes to a configfs attribute.
0087 
0088 Send and receive HID reports
0089 ============================
0090 
0091 HID reports can be sent/received using read/write on the
0092 /dev/hidgX character devices. See below for an example program
0093 to do this.
0094 
0095 hid_gadget_test is a small interactive program to test the HID
0096 gadget driver. To use, point it at a hidg device and set the
0097 device type (keyboard / mouse / joystick) - E.G.::
0098 
0099         # hid_gadget_test /dev/hidg0 keyboard
0100 
0101 You are now in the prompt of hid_gadget_test. You can type any
0102 combination of options and values. Available options and
0103 values are listed at program start. In keyboard mode you can
0104 send up to six values.
0105 
0106 For example type: g i s t r --left-shift
0107 
0108 Hit return and the corresponding report will be sent by the
0109 HID gadget.
0110 
0111 Another interesting example is the caps lock test. Type
0112 --caps-lock and hit return. A report is then sent by the
0113 gadget and you should receive the host answer, corresponding
0114 to the caps lock LED status::
0115 
0116         --caps-lock
0117         recv report:2
0118 
0119 With this command::
0120 
0121         # hid_gadget_test /dev/hidg1 mouse
0122 
0123 You can test the mouse emulation. Values are two signed numbers.
0124 
0125 
0126 Sample code::
0127 
0128     /* hid_gadget_test */
0129 
0130     #include <pthread.h>
0131     #include <string.h>
0132     #include <stdio.h>
0133     #include <ctype.h>
0134     #include <fcntl.h>
0135     #include <errno.h>
0136     #include <stdio.h>
0137     #include <stdlib.h>
0138     #include <unistd.h>
0139 
0140     #define BUF_LEN 512
0141 
0142     struct options {
0143         const char    *opt;
0144         unsigned char val;
0145   };
0146 
0147   static struct options kmod[] = {
0148         {.opt = "--left-ctrl",          .val = 0x01},
0149         {.opt = "--right-ctrl",         .val = 0x10},
0150         {.opt = "--left-shift",         .val = 0x02},
0151         {.opt = "--right-shift",        .val = 0x20},
0152         {.opt = "--left-alt",           .val = 0x04},
0153         {.opt = "--right-alt",          .val = 0x40},
0154         {.opt = "--left-meta",          .val = 0x08},
0155         {.opt = "--right-meta",         .val = 0x80},
0156         {.opt = NULL}
0157   };
0158 
0159   static struct options kval[] = {
0160         {.opt = "--return",     .val = 0x28},
0161         {.opt = "--esc",        .val = 0x29},
0162         {.opt = "--bckspc",     .val = 0x2a},
0163         {.opt = "--tab",        .val = 0x2b},
0164         {.opt = "--spacebar",   .val = 0x2c},
0165         {.opt = "--caps-lock",  .val = 0x39},
0166         {.opt = "--f1",         .val = 0x3a},
0167         {.opt = "--f2",         .val = 0x3b},
0168         {.opt = "--f3",         .val = 0x3c},
0169         {.opt = "--f4",         .val = 0x3d},
0170         {.opt = "--f5",         .val = 0x3e},
0171         {.opt = "--f6",         .val = 0x3f},
0172         {.opt = "--f7",         .val = 0x40},
0173         {.opt = "--f8",         .val = 0x41},
0174         {.opt = "--f9",         .val = 0x42},
0175         {.opt = "--f10",        .val = 0x43},
0176         {.opt = "--f11",        .val = 0x44},
0177         {.opt = "--f12",        .val = 0x45},
0178         {.opt = "--insert",     .val = 0x49},
0179         {.opt = "--home",       .val = 0x4a},
0180         {.opt = "--pageup",     .val = 0x4b},
0181         {.opt = "--del",        .val = 0x4c},
0182         {.opt = "--end",        .val = 0x4d},
0183         {.opt = "--pagedown",   .val = 0x4e},
0184         {.opt = "--right",      .val = 0x4f},
0185         {.opt = "--left",       .val = 0x50},
0186         {.opt = "--down",       .val = 0x51},
0187         {.opt = "--kp-enter",   .val = 0x58},
0188         {.opt = "--up",         .val = 0x52},
0189         {.opt = "--num-lock",   .val = 0x53},
0190         {.opt = NULL}
0191   };
0192 
0193   int keyboard_fill_report(char report[8], char buf[BUF_LEN], int *hold)
0194   {
0195         char *tok = strtok(buf, " ");
0196         int key = 0;
0197         int i = 0;
0198 
0199         for (; tok != NULL; tok = strtok(NULL, " ")) {
0200 
0201                 if (strcmp(tok, "--quit") == 0)
0202                         return -1;
0203 
0204                 if (strcmp(tok, "--hold") == 0) {
0205                         *hold = 1;
0206                         continue;
0207                 }
0208 
0209                 if (key < 6) {
0210                         for (i = 0; kval[i].opt != NULL; i++)
0211                                 if (strcmp(tok, kval[i].opt) == 0) {
0212                                         report[2 + key++] = kval[i].val;
0213                                         break;
0214                                 }
0215                         if (kval[i].opt != NULL)
0216                                 continue;
0217                 }
0218 
0219                 if (key < 6)
0220                         if (islower(tok[0])) {
0221                                 report[2 + key++] = (tok[0] - ('a' - 0x04));
0222                                 continue;
0223                         }
0224 
0225                 for (i = 0; kmod[i].opt != NULL; i++)
0226                         if (strcmp(tok, kmod[i].opt) == 0) {
0227                                 report[0] = report[0] | kmod[i].val;
0228                                 break;
0229                         }
0230                 if (kmod[i].opt != NULL)
0231                         continue;
0232 
0233                 if (key < 6)
0234                         fprintf(stderr, "unknown option: %s\n", tok);
0235         }
0236         return 8;
0237   }
0238 
0239   static struct options mmod[] = {
0240         {.opt = "--b1", .val = 0x01},
0241         {.opt = "--b2", .val = 0x02},
0242         {.opt = "--b3", .val = 0x04},
0243         {.opt = NULL}
0244   };
0245 
0246   int mouse_fill_report(char report[8], char buf[BUF_LEN], int *hold)
0247   {
0248         char *tok = strtok(buf, " ");
0249         int mvt = 0;
0250         int i = 0;
0251         for (; tok != NULL; tok = strtok(NULL, " ")) {
0252 
0253                 if (strcmp(tok, "--quit") == 0)
0254                         return -1;
0255 
0256                 if (strcmp(tok, "--hold") == 0) {
0257                         *hold = 1;
0258                         continue;
0259                 }
0260 
0261                 for (i = 0; mmod[i].opt != NULL; i++)
0262                         if (strcmp(tok, mmod[i].opt) == 0) {
0263                                 report[0] = report[0] | mmod[i].val;
0264                                 break;
0265                         }
0266                 if (mmod[i].opt != NULL)
0267                         continue;
0268 
0269                 if (!(tok[0] == '-' && tok[1] == '-') && mvt < 2) {
0270                         errno = 0;
0271                         report[1 + mvt++] = (char)strtol(tok, NULL, 0);
0272                         if (errno != 0) {
0273                                 fprintf(stderr, "Bad value:'%s'\n", tok);
0274                                 report[1 + mvt--] = 0;
0275                         }
0276                         continue;
0277                 }
0278 
0279                 fprintf(stderr, "unknown option: %s\n", tok);
0280         }
0281         return 3;
0282   }
0283 
0284   static struct options jmod[] = {
0285         {.opt = "--b1",         .val = 0x10},
0286         {.opt = "--b2",         .val = 0x20},
0287         {.opt = "--b3",         .val = 0x40},
0288         {.opt = "--b4",         .val = 0x80},
0289         {.opt = "--hat1",       .val = 0x00},
0290         {.opt = "--hat2",       .val = 0x01},
0291         {.opt = "--hat3",       .val = 0x02},
0292         {.opt = "--hat4",       .val = 0x03},
0293         {.opt = "--hatneutral", .val = 0x04},
0294         {.opt = NULL}
0295   };
0296 
0297   int joystick_fill_report(char report[8], char buf[BUF_LEN], int *hold)
0298   {
0299         char *tok = strtok(buf, " ");
0300         int mvt = 0;
0301         int i = 0;
0302 
0303         *hold = 1;
0304 
0305         /* set default hat position: neutral */
0306         report[3] = 0x04;
0307 
0308         for (; tok != NULL; tok = strtok(NULL, " ")) {
0309 
0310                 if (strcmp(tok, "--quit") == 0)
0311                         return -1;
0312 
0313                 for (i = 0; jmod[i].opt != NULL; i++)
0314                         if (strcmp(tok, jmod[i].opt) == 0) {
0315                                 report[3] = (report[3] & 0xF0) | jmod[i].val;
0316                                 break;
0317                         }
0318                 if (jmod[i].opt != NULL)
0319                         continue;
0320 
0321                 if (!(tok[0] == '-' && tok[1] == '-') && mvt < 3) {
0322                         errno = 0;
0323                         report[mvt++] = (char)strtol(tok, NULL, 0);
0324                         if (errno != 0) {
0325                                 fprintf(stderr, "Bad value:'%s'\n", tok);
0326                                 report[mvt--] = 0;
0327                         }
0328                         continue;
0329                 }
0330 
0331                 fprintf(stderr, "unknown option: %s\n", tok);
0332         }
0333         return 4;
0334   }
0335 
0336   void print_options(char c)
0337   {
0338         int i = 0;
0339 
0340         if (c == 'k') {
0341                 printf("        keyboard options:\n"
0342                        "                --hold\n");
0343                 for (i = 0; kmod[i].opt != NULL; i++)
0344                         printf("\t\t%s\n", kmod[i].opt);
0345                 printf("\n      keyboard values:\n"
0346                        "                [a-z] or\n");
0347                 for (i = 0; kval[i].opt != NULL; i++)
0348                         printf("\t\t%-8s%s", kval[i].opt, i % 2 ? "\n" : "");
0349                 printf("\n");
0350         } else if (c == 'm') {
0351                 printf("        mouse options:\n"
0352                        "                --hold\n");
0353                 for (i = 0; mmod[i].opt != NULL; i++)
0354                         printf("\t\t%s\n", mmod[i].opt);
0355                 printf("\n      mouse values:\n"
0356                        "                Two signed numbers\n"
0357                        "--quit to close\n");
0358         } else {
0359                 printf("        joystick options:\n");
0360                 for (i = 0; jmod[i].opt != NULL; i++)
0361                         printf("\t\t%s\n", jmod[i].opt);
0362                 printf("\n      joystick values:\n"
0363                        "                three signed numbers\n"
0364                        "--quit to close\n");
0365         }
0366   }
0367 
0368   int main(int argc, const char *argv[])
0369   {
0370         const char *filename = NULL;
0371         int fd = 0;
0372         char buf[BUF_LEN];
0373         int cmd_len;
0374         char report[8];
0375         int to_send = 8;
0376         int hold = 0;
0377         fd_set rfds;
0378         int retval, i;
0379 
0380         if (argc < 3) {
0381                 fprintf(stderr, "Usage: %s devname mouse|keyboard|joystick\n",
0382                         argv[0]);
0383                 return 1;
0384         }
0385 
0386         if (argv[2][0] != 'k' && argv[2][0] != 'm' && argv[2][0] != 'j')
0387           return 2;
0388 
0389         filename = argv[1];
0390 
0391         if ((fd = open(filename, O_RDWR, 0666)) == -1) {
0392                 perror(filename);
0393                 return 3;
0394         }
0395 
0396         print_options(argv[2][0]);
0397 
0398         while (42) {
0399 
0400                 FD_ZERO(&rfds);
0401                 FD_SET(STDIN_FILENO, &rfds);
0402                 FD_SET(fd, &rfds);
0403 
0404                 retval = select(fd + 1, &rfds, NULL, NULL, NULL);
0405                 if (retval == -1 && errno == EINTR)
0406                         continue;
0407                 if (retval < 0) {
0408                         perror("select()");
0409                         return 4;
0410                 }
0411 
0412                 if (FD_ISSET(fd, &rfds)) {
0413                         cmd_len = read(fd, buf, BUF_LEN - 1);
0414                         printf("recv report:");
0415                         for (i = 0; i < cmd_len; i++)
0416                                 printf(" %02x", buf[i]);
0417                         printf("\n");
0418                 }
0419 
0420                 if (FD_ISSET(STDIN_FILENO, &rfds)) {
0421                         memset(report, 0x0, sizeof(report));
0422                         cmd_len = read(STDIN_FILENO, buf, BUF_LEN - 1);
0423 
0424                         if (cmd_len == 0)
0425                                 break;
0426 
0427                         buf[cmd_len - 1] = '\0';
0428                         hold = 0;
0429 
0430                         memset(report, 0x0, sizeof(report));
0431                         if (argv[2][0] == 'k')
0432                                 to_send = keyboard_fill_report(report, buf, &hold);
0433                         else if (argv[2][0] == 'm')
0434                                 to_send = mouse_fill_report(report, buf, &hold);
0435                         else
0436                                 to_send = joystick_fill_report(report, buf, &hold);
0437 
0438                         if (to_send == -1)
0439                                 break;
0440 
0441                         if (write(fd, report, to_send) != to_send) {
0442                                 perror(filename);
0443                                 return 5;
0444                         }
0445                         if (!hold) {
0446                                 memset(report, 0x0, sizeof(report));
0447                                 if (write(fd, report, to_send) != to_send) {
0448                                         perror(filename);
0449                                         return 6;
0450                                 }
0451                         }
0452                 }
0453         }
0454 
0455         close(fd);
0456         return 0;
0457   }