About Kernel Documentation Linux Kernel Contact Linux Resources Linux Blog

Documentation / usb / gadget_hid.txt




Custom Search

Based on kernel version 4.1. Page generated on 2015-06-28 12:14 EST.

1	
2			     Linux USB HID gadget driver
3	
4	Introduction
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	
14	Configuration
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 */
25	static 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	
66	static 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	
77	Configuration 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	
84	Send 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	
121	Sample 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	
137	struct options {
138		const char    *opt;
139		unsigned char val;
140	};
141	
142	static 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	
154	static 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	
188	int 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	
234	static struct options mmod[] = {
235		{.opt = "--b1", .val = 0x01},
236		{.opt = "--b2", .val = 0x02},
237		{.opt = "--b3", .val = 0x04},
238		{.opt = NULL}
239	};
240	
241	int 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	
279	static 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	
292	int 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	
331	void 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	
363	int 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	}
Hide Line Numbers
About Kernel Documentation Linux Kernel Contact Linux Resources Linux Blog

Information is copyright its respective author. All material is available from the Linux Kernel Source distributed under a GPL License. This page is provided as a free service by mjmwired.net.