• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  }
458