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