linux/Documentation/usb/gadget_hid.txt
<<
1/spa 1spa class="lxr_search"> ="+search" method="post" onsubmit="return do_search(this);"> "> Search 1/spa ="ajax+*" method="post" onsubmit="return false;"> 1input typ hidden" nam ajax_lookup" id ajax_lookup" on> ">
. .11/a> . .21/a> Linux USB HID gadget driver . .31/a> . .41/a>Introduc > . .51/a> . .61/a> The HID Gadget driver provides emula > of USB Huma Interface . .71/a> Devices (HID). The basic HID handling is done itithe kernel, . .81/a> and HID reports ca be sent/receivedithrough I/O otithe . .91/a> /dev/hidgX charac er devices. . vala> . 111/a> For more details about HID, seeithe developer page > . 121/a> http://www.usb.org/developers/hidpage/ala> . 131/a> . 141/a>Configura > . 151/a> . 161/a> g_hid is a pla form driver, so to use it you needito add . 171/a> struc pla form_device(s)ito your pla form code defining the . 181/a> HID func > descriptors you want to use - E.G. something . 191/a> like: . 2vala> . 211/a>#include <linux/pla form_device.h> . 221/a>#include <linux/usb/g_hid.h> . 231/a> . 241/a>/* hid descriptor for a keyboard */ . 251/a>sta c struc hidg_func_descriptor my_hid_data = { . 261/a> .subclass = 0, /* No subclass */ . 271/a> .protocol = 1, /* Keyboard */ . 281/a> .report_length = 8, . 291/a> .report_desc_length = 63, . 301/a> .report_desc = { . 311/a> 0x05, 0x01, /* USAGE_PAGE (Gener c Desktop) */ . 321/a> 0x09, 0x06, /* USAGE (Keyboard) */ . 331/a> 0xa1, 0x01, /* COLLECTION (Applica > ) */ . 341/a> 0x05, 0x07, /* USAGE_PAGE (Keyboard) */ . 351/a> 0x19, 0xe0, /* USAGE_MINIMUM (Keyboard LeftControl) */ . 361/a> 0x29, 0xe7, /* USAGE_MAXIMUM (Keyboard Right GUI) */ . 371/a> 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ . 381/a> 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ . 391/a> 0x75, 0x01, /* REPORT_SIZE (1) */ . 401/a> 0x95, 0x08, /* REPORT_COUNT (8) */ . 411/a> 0x81, 0x02, /* INPUT (Data,Var,Abs) */ . 421/a> 0x95, 0x01, /* REPORT_COUNT (1) */ . 431/a> 0x75, 0x08, /* REPORT_SIZE (8) */ . 441/a> 0x81, 0x03, /* INPUT (Cnst,Var,Abs) */ . 451/a> 0x95, 0x05, /* REPORT_COUNT (5) */ . 461/a> 0x75, 0x01, /* REPORT_SIZE (1) */ . 471/a> 0x05, 0x08, /* USAGE_PAGE (LEDs) */ . 481/a> 0x19, 0x01, /* USAGE_MINIMUM (Num Lock) */ . 491/a> 0x29, 0x05, /* USAGE_MAXIMUM (Kana) */ . 501/a> 0x91, 0x02, /* OUTPUT (Data,Var,Abs) */ . 511/a> 0x95, 0x01, /* REPORT_COUNT (1) */ . 521/a> 0x75, 0x03, /* REPORT_SIZE (3) */ . 531/a> 0x91, 0x03, /* OUTPUT (Cnst,Var,Abs) */ . 541/a> 0x95, 0x06, /* REPORT_COUNT (6) */ . 551/a> 0x75, 0x08, /* REPORT_SIZE (8) */ . 561/a> 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ . 571/a> 0x25, 0x65, /* LOGICAL_MAXIMUM (101) */ . 581/a> 0x05, 0x07, /* USAGE_PAGE (Keyboard) */ . 591/a> 0x19, 0x00, /* USAGE_MINIMUM (Reserved) */ . 601/a> 0x29, 0x65, /* USAGE_MAXIMUM (Keyboard Applica > ) */ . 611/a> 0x81, 0x00, /* INPUT (Data,Ary,Abs) */ . 621/a> 0xc0 /* END_COLLECTION */ . 631/a> } . 641/a>}; . 651/a> . 661/a>sta c struc pla form_device my_hid = { . 671/a> .nam = "hidg", . 681/a> .id = 0, . 691/a> .num_resources = 0, . 701/a> .resource = 0, . 711/a> .dev.pla form_data = &my_hid_data, . 721/a>}; . 731/a> . 741/a> You ca add as many HID func > s as you want, only limited by . 751/a> the amount of interrupt endpoints your gadget driver supports. . 761/a> . 771/a>Send and receive HID reports . 781/a> . 791/a> HID reports ca be sent/receivediusing read/write otithe . 801/a> /dev/hidgX charac er devices. See below for an example program . 811/a> to do this. . 821/a> . 831/a> hid_gadget_test is a small interac ve program to test the HID . 841/a> gadget driver. To use, point it at a hidg device and setithe . 851/a> device typ (keyboard / mouse / joys ck) - E.G.: . 861/a> . 871/a> # hid_gadget_test /dev/hidg0 keyboard . 881/a> . 891/a> You are now itithe prompt of hid_gadget_test. You ca typ any . 901/a> combina > of > s and on> s. Available > s and . 911/a> on> s are listed at program start. In keyboard mode you ca . 921/a> send up to six on> s. . 931/a> . 941/a> For example typ : g i s t r --left-shift . 951/a> . 961/a> Hit return andithe corresponding report will be sent byithe . 971/a> HID gadget. . 981/a> . 991/a> Another interesting example is the caps lock test. Typ .1001/a> --caps-lock andihit return. A report is then sent byithe .1011/a> gadget andiyou should receive the host answer, corresponding .1021/a> to the caps lock LED status. .1031/a> .1041/a> --caps-lock .1051/a> recv report:2 .1061/a> .1071/a> With this command: .1081/a> .1091/a> # hid_gadget_test /dev/hidg1 mouse .1 vala> .1111/a> You ca test the mouse emula > . Vn> s are two signed numbers. .1121/a> .1131/a> .1141/a>Sample code .1151/a> .1161/a>/* hid_gadget_test */ .1171/a> .1181/a>#include <pthread.h> .1191/a>#include <string.h> .12vala>#include <stdio.h> .1211/a>#include <ctyp .h> .1221/a>#include <fcntl.h> .1231/a>#include <errno.h> .1241/a>#include <stdio.h> .1251/a>#include <stdlib.h> .1261/a>#include <unistd.h> .1271/a> .1281/a>#define BUF_LEN 512 .1291/a> .1301/a>struc > s { .1311/a> c> st char * ; .1321/a> unsigned char val; .1331/a>}; .1341/a> .1351/a>sta c struc > s kmod[] = { .1361/a> {. = "--left-ctrl", .val = 0x01}, .1371/a> {. = "--right-ctrl", .val = 0x10}, .1381/a> {. = "--left-shift", .val = 0x02}, .1391/a> {. = "--right-shift", .val = 0x20}, .1401/a> {. = "--left-alt", .val = 0x04}, .1411/a> {. = "--right-alt", .val = 0x40}, .1421/a> {. = "--left-meta", .val = 0x08}, .1431/a> {. = "--right-meta", .val = 0x80}, .1441/a> {. = NULL} .1451/a>}; .1461/a> .1471/a>sta c struc > s kval[] = { .1481/a> {. = "--return", .val = 0x28}, .1491/a> {. = "--esc", .val = 0x29}, .1501/a> {. = "--bckspc", .val = 0x2a}, .1511/a> {. = "--tab", .val = 0x2b}, .1521/a> {. = "--spacebar", .val = 0x2c}, .1531/a> {. = "--caps-lock", .val = 0x39}, .1541/a> {. = "--f1", .val = 0x3a}, .1551/a> {. = "--f2", .val = 0x3b}, .1561/a> {. = "--f3", .val = 0x3c}, .1571/a> {. = "--f4", .val = 0x3d}, .1581/a> {. = "--f5", .val = 0x3e}, .1591/a> {. = "--f6", .val = 0x3f}, .1601/a> {. = "--f7", .val = 0x40}, .1611/a> {. = "--f8", .val = 0x41}, .1621/a> {. = "--f9", .val = 0x42}, .1631/a> {. = "--f10", .val = 0x43}, .1641/a> {. = "--f11", .val = 0x44}, .1651/a> {. = "--f12", .val = 0x45}, .1661/a> {. = "--insert", .val = 0x49}, .1671/a> {. = "--home", .val = 0x4a}, .1681/a> {. = "--pageup", .val = 0x4b}, .1691/a> {. = "--del", .val = 0x4c}, .1701/a> {. = "--end", .val = 0x4d}, .1711/a> {. = "--pagedown", .val = 0x4e}, .1721/a> {. = "--right", .val = 0x4f}, .1731/a> {. = "--left", .val = 0x50}, .1741/a> {. = "--down", .val = 0x51}, .1751/a> {. = "--kp-enter", .val = 0x58}, .1761/a> {. = "--up", .val = 0x52}, .1771/a> {. = "--num-lock", .val = 0x53}, .1781/a> {. = NULL} .1791/a>}; .18vala> .1811/a>int keyboard_fill_report(char report[8], char buf[BUF_LEN], int *hold) .1821/a>{ .1831/a> char *tok = strtok(buf, " "); .1841/a> int key = 0; .1851/a> int i = 0; .1861/a> .1871/a> for (; tok != NULL; tok = strtok(NULL, " ")) { .1881/a> .1891/a> if (strcmp(tok, "--quit") == 0) .1901/a> return -1; .1911/a> .1921/a> if (strcmp(tok, "--hold") == 0) { .1931/a> *hold = 1; .1941/a> continue; .1951/a> } .1961/a> .1971/a> if (key < 6) { .1981/a> for (i = 0; kval[i]. != NULL; i++) .1991/a> if (strcmp(tok, kval[i]. ) == 0) { .2001/a> report[2 + key++] = kval[i].val; .2011/a> break; .2021/a> } .2031/a> if (kval[i]. != NULL) .2041/a> continue; .2051/a> } .2061/a> .2071/a> if (key < 6) .2081/a> if (islower(tok[0])) { .2091/a> report[2 + key++] = (tok[0] - ('a' - 0x04)); .2101/a> continue; .2111/a> } .2121/a> .2131/a> for (i = 0; kmod[i]. != NULL; i++) .2141/a> if (strcmp(tok, kmod[i]. ) == 0) { .2151/a> report[0] = report[0] | kmod[i].val; .2161/a> break; .2171/a> } .2181/a> if (kmod[i]. != NULL) .2191/a> continue; .22vala> .2211/a> if (key < 6) .2221/a> fprintf(stderr, "unknown > : %s\n", tok); .2231/a> } .2241/a> return 8; .2251/a>} .2261/a> .2271/a>sta c struc > s mmod[] = { .2281/a> {. = "--b1", .val = 0x01}, .2291/a> {. = "--b2", .val = 0x02}, .2301/a> {. = "--b3", .val = 0x04}, .2311/a> {. = NULL} .2321/a>}; .2331/a> .2341/a>int mouse_fill_report(char report[8], char buf[BUF_LEN], int *hold) .2351/a>{ .2361/a> char *tok = strtok(buf, " "); .2371/a> int mvt = 0; .2381/a> int i = 0; .2391/a> for (; tok != NULL; tok = strtok(NULL, " ")) { .24vala> .2411/a> if (strcmp(tok, "--quit") == 0) .2421/a> return -1; .2431/a> .2441/a> if (strcmp(tok, "--hold") == 0) { .2451/a> *hold = 1; .2461/a> continue; .2471/a> } .2481/a> .2491/a> for (i = 0; mmod[i]. != NULL; i++) .2501/a> if (strcmp(tok, mmod[i]. ) == 0) { .2511/a> report[0] = report[0] | mmod[i].val; .2521/a> break; .2531/a> } .2541/a> if (mmod[i]. != NULL) .2551/a> continue; .2561/a> .2571/a> if (!(tok[0] == '-' && tok[1] == '-') && mvt < 2) { .2581/a> errno = 0; .2591/a> report[1 + mvt++] = (char)strtol(tok, NULL, 0); .2601/a> if (errno != 0) { .2611/a> fprintf(stderr, "Bad on> :'%s'\n", tok); .2621/a> report[1 + mvt--] = 0; .2631/a> } .2641/a> continue; .2651/a> } .2661/a> .2671/a> fprintf(stderr, "unknown > : %s\n", tok); .2681/a> } .2691/a> return 3; .2701/a>} .2711/a> .2721/a>sta c struc > s jmod[] = { .2731/a> {. = "--b1", .val = 0x10}, .2741/a> {. = "--b2", .val = 0x20}, .2751/a> {. = "--b3", .val = 0x40}, .2761/a> {. = "--b4", .val = 0x80}, .2771/a> {. = "--hat1", .val = 0x00}, .2781/a> {. = "--hat2", .val = 0x01}, .2791/a> {. = "--hat3", .val = 0x02}, .2801/a> {. = "--hat4", .val = 0x03}, .2811/a> {. = "--hatneutral", .val = 0x04}, .2821/a> {. = NULL} .2831/a>}; .2841/a> .2851/a>int joys ck_fill_report(char report[8], char buf[BUF_LEN], int *hold) .2861/a>{ .2871/a> char *tok = strtok(buf, " "); .2881/a> int mvt = 0; .2891/a> int i = 0; .29vala> .2911/a> *hold = 1; .2921/a> .2931/a> /* setidefault hat posi > : neutral */ .2941/a> report[3] = 0x04; .2951/a> .2961/a> for (; tok != NULL; tok = strtok(NULL, " ")) { .2971/a> .2981/a> if (strcmp(tok, "--quit") == 0) .2991/a> return -1; .30vala> .3011/a> for (i = 0; jmod[i]. != NULL; i++) .3021/a> if (strcmp(tok, jmod[i]. ) == 0) { .3031/a> report[3] = (report[3] & 0xF0) | jmod[i].val; .3041/a> break; .3051/a> } .3061/a> if (jmod[i]. != NULL) .3071/a> continue; .3081/a> .3091/a> if (!(tok[0] == '-' && tok[1] == '-') && mvt < 3) { .3101/a> errno = 0; .3111/a> report[mvt++] = (char)strtol(tok, NULL, 0); .3121/a> if (errno != 0) { .3131/a> fprintf(stderr, "Bad on> :'%s'\n", tok); .3141/a> report[mvt--] = 0; .3151/a> } .3161/a> continue; .3171/a> } .3181/a> .3191/a> fprintf(stderr, "unknown > : %s\n", tok); .3201/a> } .3211/a> return 4; .3221/a>} .3231/a> .3241/a>void print_ > s(char c) .3251/a>{ .3261/a> int i = 0; .3271/a> .3281/a> if (c == 'k') { .3291/a> printf(" keyboard > s:\n" .3301/a> " --hold\n"); .3311/a> for (i = 0; kmod[i]. != NULL; i++) .3321/a> printf("\t\t%s\n", kmod[i]. ); .3331/a> printf("\n keyboard on> s:\n" .3341/a> " [a-z] or\n"); .3351/a> for (i = 0; kval[i]. != NULL; i++) .3361/a> printf("\t\t%-8s%s", kval[i]. , i % 2 ? "\n" : ""); .3371/a> printf("\n"); .3381/a> } else if (c == 'm') { .3391/a> printf(" mouse > s:\n" .3401/a> " --hold\n"); .3411/a> for (i = 0; mmod[i]. != NULL; i++) .3421/a> printf("\t\t%s\n", mmod[i]. ); .3431/a> printf("\n mouse on> s:\n" .3441/a> " Two signed numbers\n" .3451/a> "--quit to close\n"); .3461/a> } else { .3471/a> printf(" joys ck > s:\n"); .3481/a> for (i = 0; jmod[i]. != NULL; i++) .3491/a> printf("\t\t%s\n", jmod[i]. ); .3501/a> printf("\n joys ck on> s:\n" .3511/a> " three signed numbers\n" .3521/a> "--quit to close\n"); .3531/a> } .3541/a>} .3551/a> .3561/a>int main(int argc, c> st char *argv[]) .3571/a>{ .3581/a> c> st char *filenam = NULL; .3591/a> int fd = 0; .3601/a> char buf[BUF_LEN]; .3611/a> int cmd_len; .3621/a> char report[8]; .3631/a> int to_send = 8; .3641/a> int hold = 0; .3651/a> fd_setirfds; .3661/a> int reton>, i; .3671/a> .3681/a> if (argc < 3) { .3691/a> fprintf(stderr, "Usage: %s devnam mouse|keyboard|joys ck\n", .3701/a> argv[0]); .3711/a> return 1; .3721/a> } .3731/a> .3741/a> if (argv[2][0] != 'k' && argv[2][0] != 'm' && argv[2][0] != 'j') .3751/a> return 2; .3761/a> .3771/a> filenam = argv[1]; .3781/a> .3791/a> if ((fd = open(filenam , O_RDWR, 0666)) == -1) { .3801/a> perror(filenam ); .3811/a> return 3; .3821/a> } .3831/a> .3841/a> print_ > s(argv[2][0]); .3851/a> .3861/a> while (42) { .3871/a> .3881/a> FD_ZERO(&rfds); .3891/a> FD_SET(STDIN_FILENO, &rfds); .3901/a> FD_SET(fd, &rfds); .3911/a> .3921/a> reton> = select(fd + 1, &rfds, NULL, NULL, NULL); .3931/a> if (reton> == -1 && errno == EINTR) .3941/a> continue; .3951/a> if (reton> < 0) { .3961/a> perror("select()"); .3971/a> return 4; .3981/a> } .3991/a> .4001/a> if (FD_ISSET(fd, &rfds)) { .4011/a> cmd_len = read(fd, buf, BUF_LEN - 1); .4021/a> printf("recv report:"); .4031/a> for (i = 0; i < cmd_len; i++) .4041/a> printf(" %02x", buf[i]); .4051/a> printf("\n"); .4061/a> } .4071/a> .4081/a> if (FD_ISSET(STDIN_FILENO, &rfds)) { .4091/a> memset(report, 0x0, sizeof(report)); .4101/a> cmd_len = read(STDIN_FILENO, buf, BUF_LEN - 1); .4111/a> .4121/a> if (cmd_len == 0) .4131/a> break; .4141/a> .4151/a> buf[cmd_len - 1] = '\0'; .4161/a> hold = 0; .4171/a> .4181/a> memset(report, 0x0, sizeof(report)); .4191/a> if (argv[2][0] == 'k') .4201/a> to_send = keyboard_fill_report(report, buf, &hold); .4211/a> else if (argv[2][0] == 'm') .4221/a> to_send = mouse_fill_report(report, buf, &hold); .4231/a> else .4241/a> to_send = joys ck_fill_report(report, buf, &hold); .4251/a> .4261/a> if (to_send == -1) .4271/a> break; .4281/a> .4291/a> if (write(fd, report, to_send) != to_send) { .4301/a> perror(filenam ); .4311/a> return 5; .4321/a> } .4331/a> if (!hold) { .4341/a> memset(report, 0x0, sizeof(report)); .4351/a> if (write(fd, report, to_send) != to_send) { .4361/a> perror(filenam ); .4371/a> return 6; .4381/a> } .4391/a> } .4401/a> } .4411/a> } .4421/a> .4431/a> close(fd); .4441/a> return 0; .4451/a>} .4461/a>
lxr.linux.no kindly hosted by Redpill Linpro AS1/a>, provider of Linux c> sulting and era > s services since.1995.