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 }
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.