cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

gadget_hid.rst (11838B)


      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  }