About Kernel Documentation Linux Kernel Contact Linux Resources Linux Blog

Documentation / usb / gadget_hid.txt




Custom Search

Based on kernel version 3.16. Page generated on 2014-08-06 21:41 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	Send and receive HID reports
78	
79		HID reports can be sent/received using read/write on the
80		/dev/hidgX character devices. See below for an example program
81		to do this.
82	
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.:
86	
87			# hid_gadget_test /dev/hidg0 keyboard
88	
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.
93	
94		For example type: g i s t r --left-shift
95	
96		Hit return and the corresponding report will be sent by the
97		HID gadget.
98	
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.
103	
104			--caps-lock
105			recv report:2
106	
107		With this command:
108	
109			# hid_gadget_test /dev/hidg1 mouse
110	
111		You can test the mouse emulation. Values are two signed numbers.
112	
113	
114	Sample code
115	
116	/* hid_gadget_test */
117	
118	#include <pthread.h>
119	#include <string.h>
120	#include <stdio.h>
121	#include <ctype.h>
122	#include <fcntl.h>
123	#include <errno.h>
124	#include <stdio.h>
125	#include <stdlib.h>
126	#include <unistd.h>
127	
128	#define BUF_LEN 512
129	
130	struct options {
131		const char    *opt;
132		unsigned char val;
133	};
134	
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},
144		{.opt = NULL}
145	};
146	
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},
178		{.opt = NULL}
179	};
180	
181	int keyboard_fill_report(char report[8], char buf[BUF_LEN], int *hold)
182	{
183		char *tok = strtok(buf, " ");
184		int key = 0;
185		int i = 0;
186	
187		for (; tok != NULL; tok = strtok(NULL, " ")) {
188	
189			if (strcmp(tok, "--quit") == 0)
190				return -1;
191	
192			if (strcmp(tok, "--hold") == 0) {
193				*hold = 1;
194				continue;
195			}
196	
197			if (key < 6) {
198				for (i = 0; kval[i].opt != NULL; i++)
199					if (strcmp(tok, kval[i].opt) == 0) {
200						report[2 + key++] = kval[i].val;
201						break;
202					}
203				if (kval[i].opt != NULL)
204					continue;
205			}
206	
207			if (key < 6)
208				if (islower(tok[0])) {
209					report[2 + key++] = (tok[0] - ('a' - 0x04));
210					continue;
211				}
212	
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;
216					break;
217				}
218			if (kmod[i].opt != NULL)
219				continue;
220	
221			if (key < 6)
222				fprintf(stderr, "unknown option: %s\n", tok);
223		}
224		return 8;
225	}
226	
227	static struct options mmod[] = {
228		{.opt = "--b1", .val = 0x01},
229		{.opt = "--b2", .val = 0x02},
230		{.opt = "--b3", .val = 0x04},
231		{.opt = NULL}
232	};
233	
234	int mouse_fill_report(char report[8], char buf[BUF_LEN], int *hold)
235	{
236		char *tok = strtok(buf, " ");
237		int mvt = 0;
238		int i = 0;
239		for (; tok != NULL; tok = strtok(NULL, " ")) {
240	
241			if (strcmp(tok, "--quit") == 0)
242				return -1;
243	
244			if (strcmp(tok, "--hold") == 0) {
245				*hold = 1;
246				continue;
247			}
248	
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;
252					break;
253				}
254			if (mmod[i].opt != NULL)
255				continue;
256	
257			if (!(tok[0] == '-' && tok[1] == '-') && mvt < 2) {
258				errno = 0;
259				report[1 + mvt++] = (char)strtol(tok, NULL, 0);
260				if (errno != 0) {
261					fprintf(stderr, "Bad value:'%s'\n", tok);
262					report[1 + mvt--] = 0;
263				}
264				continue;
265			}
266	
267			fprintf(stderr, "unknown option: %s\n", tok);
268		}
269		return 3;
270	}
271	
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},
282		{.opt = NULL}
283	};
284	
285	int joystick_fill_report(char report[8], char buf[BUF_LEN], int *hold)
286	{
287		char *tok = strtok(buf, " ");
288		int mvt = 0;
289		int i = 0;
290	
291		*hold = 1;
292	
293		/* set default hat position: neutral */
294		report[3] = 0x04;
295	
296		for (; tok != NULL; tok = strtok(NULL, " ")) {
297	
298			if (strcmp(tok, "--quit") == 0)
299				return -1;
300	
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;
304					break;
305				}
306			if (jmod[i].opt != NULL)
307				continue;
308	
309			if (!(tok[0] == '-' && tok[1] == '-') && mvt < 3) {
310				errno = 0;
311				report[mvt++] = (char)strtol(tok, NULL, 0);
312				if (errno != 0) {
313					fprintf(stderr, "Bad value:'%s'\n", tok);
314					report[mvt--] = 0;
315				}
316				continue;
317			}
318	
319			fprintf(stderr, "unknown option: %s\n", tok);
320		}
321		return 4;
322	}
323	
324	void print_options(char c)
325	{
326		int i = 0;
327	
328		if (c == 'k') {
329			printf("	keyboard options:\n"
330			       "		--hold\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"
334			       "		[a-z] or\n");
335			for (i = 0; kval[i].opt != NULL; i++)
336				printf("\t\t%-8s%s", kval[i].opt, i % 2 ? "\n" : "");
337			printf("\n");
338		} else if (c == 'm') {
339			printf("	mouse options:\n"
340			       "		--hold\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");
346		} else {
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");
353		}
354	}
355	
356	int main(int argc, const char *argv[])
357	{
358		const char *filename = NULL;
359		int fd = 0;
360		char buf[BUF_LEN];
361		int cmd_len;
362		char report[8];
363		int to_send = 8;
364		int hold = 0;
365		fd_set rfds;
366		int retval, i;
367	
368		if (argc < 3) {
369			fprintf(stderr, "Usage: %s devname mouse|keyboard|joystick\n",
370				argv[0]);
371			return 1;
372		}
373	
374		if (argv[2][0] != 'k' && argv[2][0] != 'm' && argv[2][0] != 'j')
375		  return 2;
376	
377		filename = argv[1];
378	
379		if ((fd = open(filename, O_RDWR, 0666)) == -1) {
380			perror(filename);
381			return 3;
382		}
383	
384		print_options(argv[2][0]);
385	
386		while (42) {
387	
388			FD_ZERO(&rfds);
389			FD_SET(STDIN_FILENO, &rfds);
390			FD_SET(fd, &rfds);
391	
392			retval = select(fd + 1, &rfds, NULL, NULL, NULL);
393			if (retval == -1 && errno == EINTR)
394				continue;
395			if (retval < 0) {
396				perror("select()");
397				return 4;
398			}
399	
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]);
405				printf("\n");
406			}
407	
408			if (FD_ISSET(STDIN_FILENO, &rfds)) {
409				memset(report, 0x0, sizeof(report));
410				cmd_len = read(STDIN_FILENO, buf, BUF_LEN - 1);
411	
412				if (cmd_len == 0)
413					break;
414	
415				buf[cmd_len - 1] = '\0';
416				hold = 0;
417	
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);
423				else
424					to_send = joystick_fill_report(report, buf, &hold);
425	
426				if (to_send == -1)
427					break;
428	
429				if (write(fd, report, to_send) != to_send) {
430					perror(filename);
431					return 5;
432				}
433				if (!hold) {
434					memset(report, 0x0, sizeof(report));
435					if (write(fd, report, to_send) != to_send) {
436						perror(filename);
437						return 6;
438					}
439				}
440			}
441		}
442	
443		close(fd);
444		return 0;
445	}
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.