blob: 7a0fb8e16e27508d6b16baf8196f7575ae3b7b9f [file] [log] [blame]
Fabien Chouteau71adf112010-04-08 09:31:15 +02001
2 Linux USB HID gadget driver
3
4Introduction
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
14Configuration
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 */
25static 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
66static 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
Andrzej Pietrasiewicz21a94762014-11-06 11:12:03 +010077Configuration 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
Fabien Chouteau71adf112010-04-08 09:31:15 +020084Send 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
Tobias Klauser6e7be1a2011-06-22 10:33:02 +020091 gadget driver. To use, point it at a hidg device and set the
92 device type (keyboard / mouse / joystick) - E.G.:
Fabien Chouteau71adf112010-04-08 09:31:15 +020093
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
Tobias Klauser6e7be1a2011-06-22 10:33:02 +0200107 --caps-lock and hit return. A report is then sent by the
Fabien Chouteau71adf112010-04-08 09:31:15 +0200108 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
121Sample 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
137struct options {
138 const char *opt;
139 unsigned char val;
140};
141
142static 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
154static 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
188int 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
234static struct options mmod[] = {
235 {.opt = "--b1", .val = 0x01},
236 {.opt = "--b2", .val = 0x02},
237 {.opt = "--b3", .val = 0x04},
238 {.opt = NULL}
239};
240
241int 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
279static 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
292int 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
331void 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
363int 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}