1
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
77Configuration 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
84Send 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
91	gadget driver. To use, point it at a hidg device and set the
92	device type (keyboard / mouse / joystick) - E.G.:
93
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
107	--caps-lock and hit return. A report is then sent by the
108	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}
453