gadget_hid.rst (11838B)
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 }