linux/Documentation/usb/gadget_hid.rst
<<
>>
Prefs
   1===========================
   2Linux USB HID gadget driver
   3===========================
   4
   5Introduction
   6============
   7
   8The HID Gadget driver provides emulation of USB Human Interface
   9Devices (HID). The basic HID handling is done in the kernel,
  10and HID reports can be sent/received through I/O on the
  11/dev/hidgX character devices.
  12
  13For more details about HID, see the developer page on
  14https://www.usb.org/developers/hidpage/
  15
  16Configuration
  17=============
  18
  19g_hid is a platform driver, so to use it you need to add
  20struct platform_device(s) to your platform code defining the
  21HID function descriptors you want to use - E.G. something
  22like::
  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
  77You can add as many HID functions as you want, only limited by
  78the amount of interrupt endpoints your gadget driver supports.
  79
  80Configuration with configfs
  81===========================
  82
  83Instead of adding fake platform devices and drivers in order to pass
  84some data to the kernel, if HID is a part of a gadget composed with
  85configfs the hidg_func_descriptor.report_desc is passed to the kernel
  86by writing the appropriate stream of bytes to a configfs attribute.
  87
  88Send and receive HID reports
  89============================
  90
  91HID reports can be sent/received using read/write on the
  92/dev/hidgX character devices. See below for an example program
  93to do this.
  94
  95hid_gadget_test is a small interactive program to test the HID
  96gadget driver. To use, point it at a hidg device and set the
  97device type (keyboard / mouse / joystick) - E.G.::
  98
  99        # hid_gadget_test /dev/hidg0 keyboard
 100
 101You are now in the prompt of hid_gadget_test. You can type any
 102combination of options and values. Available options and
 103values are listed at program start. In keyboard mode you can
 104send up to six values.
 105
 106For example type: g i s t r --left-shift
 107
 108Hit return and the corresponding report will be sent by the
 109HID gadget.
 110
 111Another interesting example is the caps lock test. Type
 112--caps-lock and hit return. A report is then sent by the
 113gadget and you should receive the host answer, corresponding
 114to the caps lock LED status::
 115
 116        --caps-lock
 117        recv report:2
 118
 119With this command::
 120
 121        # hid_gadget_test /dev/hidg1 mouse
 122
 123You can test the mouse emulation. Values are two signed numbers.
 124
 125
 126Sample 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  }
 458