2 Linux USB HID gadget driver
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.
11 For more details about HID, see the developer page on
12 http://www.usb.org/developers/hidpage/
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
21 #include <linux/platform_device.h>
22 #include <linux/usb/g_hid.h>
24 /* hid descriptor for a keyboard */
25 static struct hidg_func_descriptor my_hid_data = {
26 .subclass = 0, /* No subclass */
27 .protocol = 1, /* Keyboard */
29 .report_desc_length = 63,
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 */
66 static struct platform_device my_hid = {
71 .dev.platform_data = &my_hid_data,
74 You can add as many HID functions as you want, only limited by
75 the amount of interrupt endpoints your gadget driver supports.
77 Send and receive HID reports
79 HID reports can be sent/received using read/write on the
80 /dev/hidgX character devices. See below for an example program
83 hid_gadget_test is a small interactive program to test the HID
84 gadget driver. To use, point it at a hidg device and set the
85 device type (keyboard / mouse / joystick) - E.G.:
87 # hid_gadget_test /dev/hidg0 keyboard
89 You are now in the prompt of hid_gadget_test. You can type any
90 combination of options and values. Available options and
91 values are listed at program start. In keyboard mode you can
92 send up to six values.
94 For example type: g i s t r --left-shift
96 Hit return and the corresponding report will be sent by the
99 Another interesting example is the caps lock test. Type
100 --caps-lock and hit return. A report is then sent by the
101 gadget and you should receive the host answer, corresponding
102 to the caps lock LED status.
109 # hid_gadget_test /dev/hidg1 mouse
111 You can test the mouse emulation. Values are two signed numbers.
116 /* hid_gadget_test */
135 static struct options kmod[] = {
136 {.opt = "--left-ctrl", .val = 0x01},
137 {.opt = "--right-ctrl", .val = 0x10},
138 {.opt = "--left-shift", .val = 0x02},
139 {.opt = "--right-shift", .val = 0x20},
140 {.opt = "--left-alt", .val = 0x04},
141 {.opt = "--right-alt", .val = 0x40},
142 {.opt = "--left-meta", .val = 0x08},
143 {.opt = "--right-meta", .val = 0x80},
147 static struct options kval[] = {
148 {.opt = "--return", .val = 0x28},
149 {.opt = "--esc", .val = 0x29},
150 {.opt = "--bckspc", .val = 0x2a},
151 {.opt = "--tab", .val = 0x2b},
152 {.opt = "--spacebar", .val = 0x2c},
153 {.opt = "--caps-lock", .val = 0x39},
154 {.opt = "--f1", .val = 0x3a},
155 {.opt = "--f2", .val = 0x3b},
156 {.opt = "--f3", .val = 0x3c},
157 {.opt = "--f4", .val = 0x3d},
158 {.opt = "--f5", .val = 0x3e},
159 {.opt = "--f6", .val = 0x3f},
160 {.opt = "--f7", .val = 0x40},
161 {.opt = "--f8", .val = 0x41},
162 {.opt = "--f9", .val = 0x42},
163 {.opt = "--f10", .val = 0x43},
164 {.opt = "--f11", .val = 0x44},
165 {.opt = "--f12", .val = 0x45},
166 {.opt = "--insert", .val = 0x49},
167 {.opt = "--home", .val = 0x4a},
168 {.opt = "--pageup", .val = 0x4b},
169 {.opt = "--del", .val = 0x4c},
170 {.opt = "--end", .val = 0x4d},
171 {.opt = "--pagedown", .val = 0x4e},
172 {.opt = "--right", .val = 0x4f},
173 {.opt = "--left", .val = 0x50},
174 {.opt = "--down", .val = 0x51},
175 {.opt = "--kp-enter", .val = 0x58},
176 {.opt = "--up", .val = 0x52},
177 {.opt = "--num-lock", .val = 0x53},
181 int keyboard_fill_report(char report[8], char buf[BUF_LEN], int *hold)
183 char *tok = strtok(buf, " ");
187 for (; tok != NULL; tok = strtok(NULL, " ")) {
189 if (strcmp(tok, "--quit") == 0)
192 if (strcmp(tok, "--hold") == 0) {
198 for (i = 0; kval[i].opt != NULL; i++)
199 if (strcmp(tok, kval[i].opt) == 0) {
200 report[2 + key++] = kval[i].val;
203 if (kval[i].opt != NULL)
208 if (islower(tok[0])) {
209 report[2 + key++] = (tok[0] - ('a' - 0x04));
213 for (i = 0; kmod[i].opt != NULL; i++)
214 if (strcmp(tok, kmod[i].opt) == 0) {
215 report[0] = report[0] | kmod[i].val;
218 if (kmod[i].opt != NULL)
222 fprintf(stderr, "unknown option: %s\n", tok);
227 static struct options mmod[] = {
228 {.opt = "--b1", .val = 0x01},
229 {.opt = "--b2", .val = 0x02},
230 {.opt = "--b3", .val = 0x04},
234 int mouse_fill_report(char report[8], char buf[BUF_LEN], int *hold)
236 char *tok = strtok(buf, " ");
239 for (; tok != NULL; tok = strtok(NULL, " ")) {
241 if (strcmp(tok, "--quit") == 0)
244 if (strcmp(tok, "--hold") == 0) {
249 for (i = 0; mmod[i].opt != NULL; i++)
250 if (strcmp(tok, mmod[i].opt) == 0) {
251 report[0] = report[0] | mmod[i].val;
254 if (mmod[i].opt != NULL)
257 if (!(tok[0] == '-' && tok[1] == '-') && mvt < 2) {
259 report[1 + mvt++] = (char)strtol(tok, NULL, 0);
261 fprintf(stderr, "Bad value:'%s'\n", tok);
262 report[1 + mvt--] = 0;
267 fprintf(stderr, "unknown option: %s\n", tok);
272 static struct options jmod[] = {
273 {.opt = "--b1", .val = 0x10},
274 {.opt = "--b2", .val = 0x20},
275 {.opt = "--b3", .val = 0x40},
276 {.opt = "--b4", .val = 0x80},
277 {.opt = "--hat1", .val = 0x00},
278 {.opt = "--hat2", .val = 0x01},
279 {.opt = "--hat3", .val = 0x02},
280 {.opt = "--hat4", .val = 0x03},
281 {.opt = "--hatneutral", .val = 0x04},
285 int joystick_fill_report(char report[8], char buf[BUF_LEN], int *hold)
287 char *tok = strtok(buf, " ");
293 /* set default hat position: neutral */
296 for (; tok != NULL; tok = strtok(NULL, " ")) {
298 if (strcmp(tok, "--quit") == 0)
301 for (i = 0; jmod[i].opt != NULL; i++)
302 if (strcmp(tok, jmod[i].opt) == 0) {
303 report[3] = (report[3] & 0xF0) | jmod[i].val;
306 if (jmod[i].opt != NULL)
309 if (!(tok[0] == '-' && tok[1] == '-') && mvt < 3) {
311 report[mvt++] = (char)strtol(tok, NULL, 0);
313 fprintf(stderr, "Bad value:'%s'\n", tok);
319 fprintf(stderr, "unknown option: %s\n", tok);
324 void print_options(char c)
329 printf(" keyboard options:\n"
331 for (i = 0; kmod[i].opt != NULL; i++)
332 printf("\t\t%s\n", kmod[i].opt);
333 printf("\n keyboard values:\n"
335 for (i = 0; kval[i].opt != NULL; i++)
336 printf("\t\t%-8s%s", kval[i].opt, i % 2 ? "\n" : "");
338 } else if (c == 'm') {
339 printf(" mouse options:\n"
341 for (i = 0; mmod[i].opt != NULL; i++)
342 printf("\t\t%s\n", mmod[i].opt);
343 printf("\n mouse values:\n"
344 " Two signed numbers\n"
345 "--quit to close\n");
347 printf(" joystick options:\n");
348 for (i = 0; jmod[i].opt != NULL; i++)
349 printf("\t\t%s\n", jmod[i].opt);
350 printf("\n joystick values:\n"
351 " three signed numbers\n"
352 "--quit to close\n");
356 int main(int argc, const char *argv[])
358 const char *filename = NULL;
369 fprintf(stderr, "Usage: %s devname mouse|keyboard|joystick\n",
374 if (argv[2][0] != 'k' && argv[2][0] != 'm' && argv[2][0] != 'j')
379 if ((fd = open(filename, O_RDWR, 0666)) == -1) {
384 print_options(argv[2][0]);
389 FD_SET(STDIN_FILENO, &rfds);
392 retval = select(fd + 1, &rfds, NULL, NULL, NULL);
393 if (retval == -1 && errno == EINTR)
400 if (FD_ISSET(fd, &rfds)) {
401 cmd_len = read(fd, buf, BUF_LEN - 1);
402 printf("recv report:");
403 for (i = 0; i < cmd_len; i++)
404 printf(" %02x", buf[i]);
408 if (FD_ISSET(STDIN_FILENO, &rfds)) {
409 memset(report, 0x0, sizeof(report));
410 cmd_len = read(STDIN_FILENO, buf, BUF_LEN - 1);
415 buf[cmd_len - 1] = '\0';
418 memset(report, 0x0, sizeof(report));
419 if (argv[2][0] == 'k')
420 to_send = keyboard_fill_report(report, buf, &hold);
421 else if (argv[2][0] == 'm')
422 to_send = mouse_fill_report(report, buf, &hold);
424 to_send = joystick_fill_report(report, buf, &hold);
429 if (write(fd, report, to_send) != to_send) {
434 memset(report, 0x0, sizeof(report));
435 if (write(fd, report, to_send) != to_send) {