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 }