1ecefae6dSMauro Carvalho Chehab=========================== 2ecefae6dSMauro Carvalho ChehabLinux USB HID gadget driver 3ecefae6dSMauro Carvalho Chehab=========================== 4ecefae6dSMauro Carvalho Chehab 5ecefae6dSMauro Carvalho ChehabIntroduction 6ecefae6dSMauro Carvalho Chehab============ 7ecefae6dSMauro Carvalho Chehab 8ecefae6dSMauro Carvalho ChehabThe HID Gadget driver provides emulation of USB Human Interface 9ecefae6dSMauro Carvalho ChehabDevices (HID). The basic HID handling is done in the kernel, 10ecefae6dSMauro Carvalho Chehaband HID reports can be sent/received through I/O on the 11ecefae6dSMauro Carvalho Chehab/dev/hidgX character devices. 12ecefae6dSMauro Carvalho Chehab 13ecefae6dSMauro Carvalho ChehabFor more details about HID, see the developer page on 14*ffeb1e9eSAlexander A. Klimovhttps://www.usb.org/developers/hidpage/ 15ecefae6dSMauro Carvalho Chehab 16ecefae6dSMauro Carvalho ChehabConfiguration 17ecefae6dSMauro Carvalho Chehab============= 18ecefae6dSMauro Carvalho Chehab 19ecefae6dSMauro Carvalho Chehabg_hid is a platform driver, so to use it you need to add 20ecefae6dSMauro Carvalho Chehabstruct platform_device(s) to your platform code defining the 21ecefae6dSMauro Carvalho ChehabHID function descriptors you want to use - E.G. something 22ecefae6dSMauro Carvalho Chehablike:: 23ecefae6dSMauro Carvalho Chehab 24ecefae6dSMauro Carvalho Chehab #include <linux/platform_device.h> 25ecefae6dSMauro Carvalho Chehab #include <linux/usb/g_hid.h> 26ecefae6dSMauro Carvalho Chehab 27ecefae6dSMauro Carvalho Chehab /* hid descriptor for a keyboard */ 28ecefae6dSMauro Carvalho Chehab static struct hidg_func_descriptor my_hid_data = { 29ecefae6dSMauro Carvalho Chehab .subclass = 0, /* No subclass */ 30ecefae6dSMauro Carvalho Chehab .protocol = 1, /* Keyboard */ 31ecefae6dSMauro Carvalho Chehab .report_length = 8, 32ecefae6dSMauro Carvalho Chehab .report_desc_length = 63, 33ecefae6dSMauro Carvalho Chehab .report_desc = { 34ecefae6dSMauro Carvalho Chehab 0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */ 35ecefae6dSMauro Carvalho Chehab 0x09, 0x06, /* USAGE (Keyboard) */ 36ecefae6dSMauro Carvalho Chehab 0xa1, 0x01, /* COLLECTION (Application) */ 37ecefae6dSMauro Carvalho Chehab 0x05, 0x07, /* USAGE_PAGE (Keyboard) */ 38ecefae6dSMauro Carvalho Chehab 0x19, 0xe0, /* USAGE_MINIMUM (Keyboard LeftControl) */ 39ecefae6dSMauro Carvalho Chehab 0x29, 0xe7, /* USAGE_MAXIMUM (Keyboard Right GUI) */ 40ecefae6dSMauro Carvalho Chehab 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ 41ecefae6dSMauro Carvalho Chehab 0x25, 0x01, /* LOGICAL_MAXIMUM (1) */ 42ecefae6dSMauro Carvalho Chehab 0x75, 0x01, /* REPORT_SIZE (1) */ 43ecefae6dSMauro Carvalho Chehab 0x95, 0x08, /* REPORT_COUNT (8) */ 44ecefae6dSMauro Carvalho Chehab 0x81, 0x02, /* INPUT (Data,Var,Abs) */ 45ecefae6dSMauro Carvalho Chehab 0x95, 0x01, /* REPORT_COUNT (1) */ 46ecefae6dSMauro Carvalho Chehab 0x75, 0x08, /* REPORT_SIZE (8) */ 47ecefae6dSMauro Carvalho Chehab 0x81, 0x03, /* INPUT (Cnst,Var,Abs) */ 48ecefae6dSMauro Carvalho Chehab 0x95, 0x05, /* REPORT_COUNT (5) */ 49ecefae6dSMauro Carvalho Chehab 0x75, 0x01, /* REPORT_SIZE (1) */ 50ecefae6dSMauro Carvalho Chehab 0x05, 0x08, /* USAGE_PAGE (LEDs) */ 51ecefae6dSMauro Carvalho Chehab 0x19, 0x01, /* USAGE_MINIMUM (Num Lock) */ 52ecefae6dSMauro Carvalho Chehab 0x29, 0x05, /* USAGE_MAXIMUM (Kana) */ 53ecefae6dSMauro Carvalho Chehab 0x91, 0x02, /* OUTPUT (Data,Var,Abs) */ 54ecefae6dSMauro Carvalho Chehab 0x95, 0x01, /* REPORT_COUNT (1) */ 55ecefae6dSMauro Carvalho Chehab 0x75, 0x03, /* REPORT_SIZE (3) */ 56ecefae6dSMauro Carvalho Chehab 0x91, 0x03, /* OUTPUT (Cnst,Var,Abs) */ 57ecefae6dSMauro Carvalho Chehab 0x95, 0x06, /* REPORT_COUNT (6) */ 58ecefae6dSMauro Carvalho Chehab 0x75, 0x08, /* REPORT_SIZE (8) */ 59ecefae6dSMauro Carvalho Chehab 0x15, 0x00, /* LOGICAL_MINIMUM (0) */ 60ecefae6dSMauro Carvalho Chehab 0x25, 0x65, /* LOGICAL_MAXIMUM (101) */ 61ecefae6dSMauro Carvalho Chehab 0x05, 0x07, /* USAGE_PAGE (Keyboard) */ 62ecefae6dSMauro Carvalho Chehab 0x19, 0x00, /* USAGE_MINIMUM (Reserved) */ 63ecefae6dSMauro Carvalho Chehab 0x29, 0x65, /* USAGE_MAXIMUM (Keyboard Application) */ 64ecefae6dSMauro Carvalho Chehab 0x81, 0x00, /* INPUT (Data,Ary,Abs) */ 65ecefae6dSMauro Carvalho Chehab 0xc0 /* END_COLLECTION */ 66ecefae6dSMauro Carvalho Chehab } 67ecefae6dSMauro Carvalho Chehab }; 68ecefae6dSMauro Carvalho Chehab 69ecefae6dSMauro Carvalho Chehab static struct platform_device my_hid = { 70ecefae6dSMauro Carvalho Chehab .name = "hidg", 71ecefae6dSMauro Carvalho Chehab .id = 0, 72ecefae6dSMauro Carvalho Chehab .num_resources = 0, 73ecefae6dSMauro Carvalho Chehab .resource = 0, 74ecefae6dSMauro Carvalho Chehab .dev.platform_data = &my_hid_data, 75ecefae6dSMauro Carvalho Chehab }; 76ecefae6dSMauro Carvalho Chehab 77ecefae6dSMauro Carvalho ChehabYou can add as many HID functions as you want, only limited by 78ecefae6dSMauro Carvalho Chehabthe amount of interrupt endpoints your gadget driver supports. 79ecefae6dSMauro Carvalho Chehab 80ecefae6dSMauro Carvalho ChehabConfiguration with configfs 81ecefae6dSMauro Carvalho Chehab=========================== 82ecefae6dSMauro Carvalho Chehab 83ecefae6dSMauro Carvalho ChehabInstead of adding fake platform devices and drivers in order to pass 84ecefae6dSMauro Carvalho Chehabsome data to the kernel, if HID is a part of a gadget composed with 85ecefae6dSMauro Carvalho Chehabconfigfs the hidg_func_descriptor.report_desc is passed to the kernel 86ecefae6dSMauro Carvalho Chehabby writing the appropriate stream of bytes to a configfs attribute. 87ecefae6dSMauro Carvalho Chehab 88ecefae6dSMauro Carvalho ChehabSend and receive HID reports 89ecefae6dSMauro Carvalho Chehab============================ 90ecefae6dSMauro Carvalho Chehab 91ecefae6dSMauro Carvalho ChehabHID reports can be sent/received using read/write on the 92ecefae6dSMauro Carvalho Chehab/dev/hidgX character devices. See below for an example program 93ecefae6dSMauro Carvalho Chehabto do this. 94ecefae6dSMauro Carvalho Chehab 95ecefae6dSMauro Carvalho Chehabhid_gadget_test is a small interactive program to test the HID 96ecefae6dSMauro Carvalho Chehabgadget driver. To use, point it at a hidg device and set the 97ecefae6dSMauro Carvalho Chehabdevice type (keyboard / mouse / joystick) - E.G.:: 98ecefae6dSMauro Carvalho Chehab 99ecefae6dSMauro Carvalho Chehab # hid_gadget_test /dev/hidg0 keyboard 100ecefae6dSMauro Carvalho Chehab 101ecefae6dSMauro Carvalho ChehabYou are now in the prompt of hid_gadget_test. You can type any 102ecefae6dSMauro Carvalho Chehabcombination of options and values. Available options and 103ecefae6dSMauro Carvalho Chehabvalues are listed at program start. In keyboard mode you can 104ecefae6dSMauro Carvalho Chehabsend up to six values. 105ecefae6dSMauro Carvalho Chehab 106ecefae6dSMauro Carvalho ChehabFor example type: g i s t r --left-shift 107ecefae6dSMauro Carvalho Chehab 108ecefae6dSMauro Carvalho ChehabHit return and the corresponding report will be sent by the 109ecefae6dSMauro Carvalho ChehabHID gadget. 110ecefae6dSMauro Carvalho Chehab 111ecefae6dSMauro Carvalho ChehabAnother interesting example is the caps lock test. Type 112ecefae6dSMauro Carvalho Chehab--caps-lock and hit return. A report is then sent by the 113ecefae6dSMauro Carvalho Chehabgadget and you should receive the host answer, corresponding 114ecefae6dSMauro Carvalho Chehabto the caps lock LED status:: 115ecefae6dSMauro Carvalho Chehab 116ecefae6dSMauro Carvalho Chehab --caps-lock 117ecefae6dSMauro Carvalho Chehab recv report:2 118ecefae6dSMauro Carvalho Chehab 119ecefae6dSMauro Carvalho ChehabWith this command:: 120ecefae6dSMauro Carvalho Chehab 121ecefae6dSMauro Carvalho Chehab # hid_gadget_test /dev/hidg1 mouse 122ecefae6dSMauro Carvalho Chehab 123ecefae6dSMauro Carvalho ChehabYou can test the mouse emulation. Values are two signed numbers. 124ecefae6dSMauro Carvalho Chehab 125ecefae6dSMauro Carvalho Chehab 126ecefae6dSMauro Carvalho ChehabSample code:: 127ecefae6dSMauro Carvalho Chehab 128ecefae6dSMauro Carvalho Chehab /* hid_gadget_test */ 129ecefae6dSMauro Carvalho Chehab 130ecefae6dSMauro Carvalho Chehab #include <pthread.h> 131ecefae6dSMauro Carvalho Chehab #include <string.h> 132ecefae6dSMauro Carvalho Chehab #include <stdio.h> 133ecefae6dSMauro Carvalho Chehab #include <ctype.h> 134ecefae6dSMauro Carvalho Chehab #include <fcntl.h> 135ecefae6dSMauro Carvalho Chehab #include <errno.h> 136ecefae6dSMauro Carvalho Chehab #include <stdio.h> 137ecefae6dSMauro Carvalho Chehab #include <stdlib.h> 138ecefae6dSMauro Carvalho Chehab #include <unistd.h> 139ecefae6dSMauro Carvalho Chehab 140ecefae6dSMauro Carvalho Chehab #define BUF_LEN 512 141ecefae6dSMauro Carvalho Chehab 142ecefae6dSMauro Carvalho Chehab struct options { 143ecefae6dSMauro Carvalho Chehab const char *opt; 144ecefae6dSMauro Carvalho Chehab unsigned char val; 145ecefae6dSMauro Carvalho Chehab }; 146ecefae6dSMauro Carvalho Chehab 147ecefae6dSMauro Carvalho Chehab static struct options kmod[] = { 148ecefae6dSMauro Carvalho Chehab {.opt = "--left-ctrl", .val = 0x01}, 149ecefae6dSMauro Carvalho Chehab {.opt = "--right-ctrl", .val = 0x10}, 150ecefae6dSMauro Carvalho Chehab {.opt = "--left-shift", .val = 0x02}, 151ecefae6dSMauro Carvalho Chehab {.opt = "--right-shift", .val = 0x20}, 152ecefae6dSMauro Carvalho Chehab {.opt = "--left-alt", .val = 0x04}, 153ecefae6dSMauro Carvalho Chehab {.opt = "--right-alt", .val = 0x40}, 154ecefae6dSMauro Carvalho Chehab {.opt = "--left-meta", .val = 0x08}, 155ecefae6dSMauro Carvalho Chehab {.opt = "--right-meta", .val = 0x80}, 156ecefae6dSMauro Carvalho Chehab {.opt = NULL} 157ecefae6dSMauro Carvalho Chehab }; 158ecefae6dSMauro Carvalho Chehab 159ecefae6dSMauro Carvalho Chehab static struct options kval[] = { 160ecefae6dSMauro Carvalho Chehab {.opt = "--return", .val = 0x28}, 161ecefae6dSMauro Carvalho Chehab {.opt = "--esc", .val = 0x29}, 162ecefae6dSMauro Carvalho Chehab {.opt = "--bckspc", .val = 0x2a}, 163ecefae6dSMauro Carvalho Chehab {.opt = "--tab", .val = 0x2b}, 164ecefae6dSMauro Carvalho Chehab {.opt = "--spacebar", .val = 0x2c}, 165ecefae6dSMauro Carvalho Chehab {.opt = "--caps-lock", .val = 0x39}, 166ecefae6dSMauro Carvalho Chehab {.opt = "--f1", .val = 0x3a}, 167ecefae6dSMauro Carvalho Chehab {.opt = "--f2", .val = 0x3b}, 168ecefae6dSMauro Carvalho Chehab {.opt = "--f3", .val = 0x3c}, 169ecefae6dSMauro Carvalho Chehab {.opt = "--f4", .val = 0x3d}, 170ecefae6dSMauro Carvalho Chehab {.opt = "--f5", .val = 0x3e}, 171ecefae6dSMauro Carvalho Chehab {.opt = "--f6", .val = 0x3f}, 172ecefae6dSMauro Carvalho Chehab {.opt = "--f7", .val = 0x40}, 173ecefae6dSMauro Carvalho Chehab {.opt = "--f8", .val = 0x41}, 174ecefae6dSMauro Carvalho Chehab {.opt = "--f9", .val = 0x42}, 175ecefae6dSMauro Carvalho Chehab {.opt = "--f10", .val = 0x43}, 176ecefae6dSMauro Carvalho Chehab {.opt = "--f11", .val = 0x44}, 177ecefae6dSMauro Carvalho Chehab {.opt = "--f12", .val = 0x45}, 178ecefae6dSMauro Carvalho Chehab {.opt = "--insert", .val = 0x49}, 179ecefae6dSMauro Carvalho Chehab {.opt = "--home", .val = 0x4a}, 180ecefae6dSMauro Carvalho Chehab {.opt = "--pageup", .val = 0x4b}, 181ecefae6dSMauro Carvalho Chehab {.opt = "--del", .val = 0x4c}, 182ecefae6dSMauro Carvalho Chehab {.opt = "--end", .val = 0x4d}, 183ecefae6dSMauro Carvalho Chehab {.opt = "--pagedown", .val = 0x4e}, 184ecefae6dSMauro Carvalho Chehab {.opt = "--right", .val = 0x4f}, 185ecefae6dSMauro Carvalho Chehab {.opt = "--left", .val = 0x50}, 186ecefae6dSMauro Carvalho Chehab {.opt = "--down", .val = 0x51}, 187ecefae6dSMauro Carvalho Chehab {.opt = "--kp-enter", .val = 0x58}, 188ecefae6dSMauro Carvalho Chehab {.opt = "--up", .val = 0x52}, 189ecefae6dSMauro Carvalho Chehab {.opt = "--num-lock", .val = 0x53}, 190ecefae6dSMauro Carvalho Chehab {.opt = NULL} 191ecefae6dSMauro Carvalho Chehab }; 192ecefae6dSMauro Carvalho Chehab 193ecefae6dSMauro Carvalho Chehab int keyboard_fill_report(char report[8], char buf[BUF_LEN], int *hold) 194ecefae6dSMauro Carvalho Chehab { 195ecefae6dSMauro Carvalho Chehab char *tok = strtok(buf, " "); 196ecefae6dSMauro Carvalho Chehab int key = 0; 197ecefae6dSMauro Carvalho Chehab int i = 0; 198ecefae6dSMauro Carvalho Chehab 199ecefae6dSMauro Carvalho Chehab for (; tok != NULL; tok = strtok(NULL, " ")) { 200ecefae6dSMauro Carvalho Chehab 201ecefae6dSMauro Carvalho Chehab if (strcmp(tok, "--quit") == 0) 202ecefae6dSMauro Carvalho Chehab return -1; 203ecefae6dSMauro Carvalho Chehab 204ecefae6dSMauro Carvalho Chehab if (strcmp(tok, "--hold") == 0) { 205ecefae6dSMauro Carvalho Chehab *hold = 1; 206ecefae6dSMauro Carvalho Chehab continue; 207ecefae6dSMauro Carvalho Chehab } 208ecefae6dSMauro Carvalho Chehab 209ecefae6dSMauro Carvalho Chehab if (key < 6) { 210ecefae6dSMauro Carvalho Chehab for (i = 0; kval[i].opt != NULL; i++) 211ecefae6dSMauro Carvalho Chehab if (strcmp(tok, kval[i].opt) == 0) { 212ecefae6dSMauro Carvalho Chehab report[2 + key++] = kval[i].val; 213ecefae6dSMauro Carvalho Chehab break; 214ecefae6dSMauro Carvalho Chehab } 215ecefae6dSMauro Carvalho Chehab if (kval[i].opt != NULL) 216ecefae6dSMauro Carvalho Chehab continue; 217ecefae6dSMauro Carvalho Chehab } 218ecefae6dSMauro Carvalho Chehab 219ecefae6dSMauro Carvalho Chehab if (key < 6) 220ecefae6dSMauro Carvalho Chehab if (islower(tok[0])) { 221ecefae6dSMauro Carvalho Chehab report[2 + key++] = (tok[0] - ('a' - 0x04)); 222ecefae6dSMauro Carvalho Chehab continue; 223ecefae6dSMauro Carvalho Chehab } 224ecefae6dSMauro Carvalho Chehab 225ecefae6dSMauro Carvalho Chehab for (i = 0; kmod[i].opt != NULL; i++) 226ecefae6dSMauro Carvalho Chehab if (strcmp(tok, kmod[i].opt) == 0) { 227ecefae6dSMauro Carvalho Chehab report[0] = report[0] | kmod[i].val; 228ecefae6dSMauro Carvalho Chehab break; 229ecefae6dSMauro Carvalho Chehab } 230ecefae6dSMauro Carvalho Chehab if (kmod[i].opt != NULL) 231ecefae6dSMauro Carvalho Chehab continue; 232ecefae6dSMauro Carvalho Chehab 233ecefae6dSMauro Carvalho Chehab if (key < 6) 234ecefae6dSMauro Carvalho Chehab fprintf(stderr, "unknown option: %s\n", tok); 235ecefae6dSMauro Carvalho Chehab } 236ecefae6dSMauro Carvalho Chehab return 8; 237ecefae6dSMauro Carvalho Chehab } 238ecefae6dSMauro Carvalho Chehab 239ecefae6dSMauro Carvalho Chehab static struct options mmod[] = { 240ecefae6dSMauro Carvalho Chehab {.opt = "--b1", .val = 0x01}, 241ecefae6dSMauro Carvalho Chehab {.opt = "--b2", .val = 0x02}, 242ecefae6dSMauro Carvalho Chehab {.opt = "--b3", .val = 0x04}, 243ecefae6dSMauro Carvalho Chehab {.opt = NULL} 244ecefae6dSMauro Carvalho Chehab }; 245ecefae6dSMauro Carvalho Chehab 246ecefae6dSMauro Carvalho Chehab int mouse_fill_report(char report[8], char buf[BUF_LEN], int *hold) 247ecefae6dSMauro Carvalho Chehab { 248ecefae6dSMauro Carvalho Chehab char *tok = strtok(buf, " "); 249ecefae6dSMauro Carvalho Chehab int mvt = 0; 250ecefae6dSMauro Carvalho Chehab int i = 0; 251ecefae6dSMauro Carvalho Chehab for (; tok != NULL; tok = strtok(NULL, " ")) { 252ecefae6dSMauro Carvalho Chehab 253ecefae6dSMauro Carvalho Chehab if (strcmp(tok, "--quit") == 0) 254ecefae6dSMauro Carvalho Chehab return -1; 255ecefae6dSMauro Carvalho Chehab 256ecefae6dSMauro Carvalho Chehab if (strcmp(tok, "--hold") == 0) { 257ecefae6dSMauro Carvalho Chehab *hold = 1; 258ecefae6dSMauro Carvalho Chehab continue; 259ecefae6dSMauro Carvalho Chehab } 260ecefae6dSMauro Carvalho Chehab 261ecefae6dSMauro Carvalho Chehab for (i = 0; mmod[i].opt != NULL; i++) 262ecefae6dSMauro Carvalho Chehab if (strcmp(tok, mmod[i].opt) == 0) { 263ecefae6dSMauro Carvalho Chehab report[0] = report[0] | mmod[i].val; 264ecefae6dSMauro Carvalho Chehab break; 265ecefae6dSMauro Carvalho Chehab } 266ecefae6dSMauro Carvalho Chehab if (mmod[i].opt != NULL) 267ecefae6dSMauro Carvalho Chehab continue; 268ecefae6dSMauro Carvalho Chehab 269ecefae6dSMauro Carvalho Chehab if (!(tok[0] == '-' && tok[1] == '-') && mvt < 2) { 270ecefae6dSMauro Carvalho Chehab errno = 0; 271ecefae6dSMauro Carvalho Chehab report[1 + mvt++] = (char)strtol(tok, NULL, 0); 272ecefae6dSMauro Carvalho Chehab if (errno != 0) { 273ecefae6dSMauro Carvalho Chehab fprintf(stderr, "Bad value:'%s'\n", tok); 274ecefae6dSMauro Carvalho Chehab report[1 + mvt--] = 0; 275ecefae6dSMauro Carvalho Chehab } 276ecefae6dSMauro Carvalho Chehab continue; 277ecefae6dSMauro Carvalho Chehab } 278ecefae6dSMauro Carvalho Chehab 279ecefae6dSMauro Carvalho Chehab fprintf(stderr, "unknown option: %s\n", tok); 280ecefae6dSMauro Carvalho Chehab } 281ecefae6dSMauro Carvalho Chehab return 3; 282ecefae6dSMauro Carvalho Chehab } 283ecefae6dSMauro Carvalho Chehab 284ecefae6dSMauro Carvalho Chehab static struct options jmod[] = { 285ecefae6dSMauro Carvalho Chehab {.opt = "--b1", .val = 0x10}, 286ecefae6dSMauro Carvalho Chehab {.opt = "--b2", .val = 0x20}, 287ecefae6dSMauro Carvalho Chehab {.opt = "--b3", .val = 0x40}, 288ecefae6dSMauro Carvalho Chehab {.opt = "--b4", .val = 0x80}, 289ecefae6dSMauro Carvalho Chehab {.opt = "--hat1", .val = 0x00}, 290ecefae6dSMauro Carvalho Chehab {.opt = "--hat2", .val = 0x01}, 291ecefae6dSMauro Carvalho Chehab {.opt = "--hat3", .val = 0x02}, 292ecefae6dSMauro Carvalho Chehab {.opt = "--hat4", .val = 0x03}, 293ecefae6dSMauro Carvalho Chehab {.opt = "--hatneutral", .val = 0x04}, 294ecefae6dSMauro Carvalho Chehab {.opt = NULL} 295ecefae6dSMauro Carvalho Chehab }; 296ecefae6dSMauro Carvalho Chehab 297ecefae6dSMauro Carvalho Chehab int joystick_fill_report(char report[8], char buf[BUF_LEN], int *hold) 298ecefae6dSMauro Carvalho Chehab { 299ecefae6dSMauro Carvalho Chehab char *tok = strtok(buf, " "); 300ecefae6dSMauro Carvalho Chehab int mvt = 0; 301ecefae6dSMauro Carvalho Chehab int i = 0; 302ecefae6dSMauro Carvalho Chehab 303ecefae6dSMauro Carvalho Chehab *hold = 1; 304ecefae6dSMauro Carvalho Chehab 305ecefae6dSMauro Carvalho Chehab /* set default hat position: neutral */ 306ecefae6dSMauro Carvalho Chehab report[3] = 0x04; 307ecefae6dSMauro Carvalho Chehab 308ecefae6dSMauro Carvalho Chehab for (; tok != NULL; tok = strtok(NULL, " ")) { 309ecefae6dSMauro Carvalho Chehab 310ecefae6dSMauro Carvalho Chehab if (strcmp(tok, "--quit") == 0) 311ecefae6dSMauro Carvalho Chehab return -1; 312ecefae6dSMauro Carvalho Chehab 313ecefae6dSMauro Carvalho Chehab for (i = 0; jmod[i].opt != NULL; i++) 314ecefae6dSMauro Carvalho Chehab if (strcmp(tok, jmod[i].opt) == 0) { 315ecefae6dSMauro Carvalho Chehab report[3] = (report[3] & 0xF0) | jmod[i].val; 316ecefae6dSMauro Carvalho Chehab break; 317ecefae6dSMauro Carvalho Chehab } 318ecefae6dSMauro Carvalho Chehab if (jmod[i].opt != NULL) 319ecefae6dSMauro Carvalho Chehab continue; 320ecefae6dSMauro Carvalho Chehab 321ecefae6dSMauro Carvalho Chehab if (!(tok[0] == '-' && tok[1] == '-') && mvt < 3) { 322ecefae6dSMauro Carvalho Chehab errno = 0; 323ecefae6dSMauro Carvalho Chehab report[mvt++] = (char)strtol(tok, NULL, 0); 324ecefae6dSMauro Carvalho Chehab if (errno != 0) { 325ecefae6dSMauro Carvalho Chehab fprintf(stderr, "Bad value:'%s'\n", tok); 326ecefae6dSMauro Carvalho Chehab report[mvt--] = 0; 327ecefae6dSMauro Carvalho Chehab } 328ecefae6dSMauro Carvalho Chehab continue; 329ecefae6dSMauro Carvalho Chehab } 330ecefae6dSMauro Carvalho Chehab 331ecefae6dSMauro Carvalho Chehab fprintf(stderr, "unknown option: %s\n", tok); 332ecefae6dSMauro Carvalho Chehab } 333ecefae6dSMauro Carvalho Chehab return 4; 334ecefae6dSMauro Carvalho Chehab } 335ecefae6dSMauro Carvalho Chehab 336ecefae6dSMauro Carvalho Chehab void print_options(char c) 337ecefae6dSMauro Carvalho Chehab { 338ecefae6dSMauro Carvalho Chehab int i = 0; 339ecefae6dSMauro Carvalho Chehab 340ecefae6dSMauro Carvalho Chehab if (c == 'k') { 341ecefae6dSMauro Carvalho Chehab printf(" keyboard options:\n" 342ecefae6dSMauro Carvalho Chehab " --hold\n"); 343ecefae6dSMauro Carvalho Chehab for (i = 0; kmod[i].opt != NULL; i++) 344ecefae6dSMauro Carvalho Chehab printf("\t\t%s\n", kmod[i].opt); 345ecefae6dSMauro Carvalho Chehab printf("\n keyboard values:\n" 346ecefae6dSMauro Carvalho Chehab " [a-z] or\n"); 347ecefae6dSMauro Carvalho Chehab for (i = 0; kval[i].opt != NULL; i++) 348ecefae6dSMauro Carvalho Chehab printf("\t\t%-8s%s", kval[i].opt, i % 2 ? "\n" : ""); 349ecefae6dSMauro Carvalho Chehab printf("\n"); 350ecefae6dSMauro Carvalho Chehab } else if (c == 'm') { 351ecefae6dSMauro Carvalho Chehab printf(" mouse options:\n" 352ecefae6dSMauro Carvalho Chehab " --hold\n"); 353ecefae6dSMauro Carvalho Chehab for (i = 0; mmod[i].opt != NULL; i++) 354ecefae6dSMauro Carvalho Chehab printf("\t\t%s\n", mmod[i].opt); 355ecefae6dSMauro Carvalho Chehab printf("\n mouse values:\n" 356ecefae6dSMauro Carvalho Chehab " Two signed numbers\n" 357ecefae6dSMauro Carvalho Chehab "--quit to close\n"); 358ecefae6dSMauro Carvalho Chehab } else { 359ecefae6dSMauro Carvalho Chehab printf(" joystick options:\n"); 360ecefae6dSMauro Carvalho Chehab for (i = 0; jmod[i].opt != NULL; i++) 361ecefae6dSMauro Carvalho Chehab printf("\t\t%s\n", jmod[i].opt); 362ecefae6dSMauro Carvalho Chehab printf("\n joystick values:\n" 363ecefae6dSMauro Carvalho Chehab " three signed numbers\n" 364ecefae6dSMauro Carvalho Chehab "--quit to close\n"); 365ecefae6dSMauro Carvalho Chehab } 366ecefae6dSMauro Carvalho Chehab } 367ecefae6dSMauro Carvalho Chehab 368ecefae6dSMauro Carvalho Chehab int main(int argc, const char *argv[]) 369ecefae6dSMauro Carvalho Chehab { 370ecefae6dSMauro Carvalho Chehab const char *filename = NULL; 371ecefae6dSMauro Carvalho Chehab int fd = 0; 372ecefae6dSMauro Carvalho Chehab char buf[BUF_LEN]; 373ecefae6dSMauro Carvalho Chehab int cmd_len; 374ecefae6dSMauro Carvalho Chehab char report[8]; 375ecefae6dSMauro Carvalho Chehab int to_send = 8; 376ecefae6dSMauro Carvalho Chehab int hold = 0; 377ecefae6dSMauro Carvalho Chehab fd_set rfds; 378ecefae6dSMauro Carvalho Chehab int retval, i; 379ecefae6dSMauro Carvalho Chehab 380ecefae6dSMauro Carvalho Chehab if (argc < 3) { 381ecefae6dSMauro Carvalho Chehab fprintf(stderr, "Usage: %s devname mouse|keyboard|joystick\n", 382ecefae6dSMauro Carvalho Chehab argv[0]); 383ecefae6dSMauro Carvalho Chehab return 1; 384ecefae6dSMauro Carvalho Chehab } 385ecefae6dSMauro Carvalho Chehab 386ecefae6dSMauro Carvalho Chehab if (argv[2][0] != 'k' && argv[2][0] != 'm' && argv[2][0] != 'j') 387ecefae6dSMauro Carvalho Chehab return 2; 388ecefae6dSMauro Carvalho Chehab 389ecefae6dSMauro Carvalho Chehab filename = argv[1]; 390ecefae6dSMauro Carvalho Chehab 391ecefae6dSMauro Carvalho Chehab if ((fd = open(filename, O_RDWR, 0666)) == -1) { 392ecefae6dSMauro Carvalho Chehab perror(filename); 393ecefae6dSMauro Carvalho Chehab return 3; 394ecefae6dSMauro Carvalho Chehab } 395ecefae6dSMauro Carvalho Chehab 396ecefae6dSMauro Carvalho Chehab print_options(argv[2][0]); 397ecefae6dSMauro Carvalho Chehab 398ecefae6dSMauro Carvalho Chehab while (42) { 399ecefae6dSMauro Carvalho Chehab 400ecefae6dSMauro Carvalho Chehab FD_ZERO(&rfds); 401ecefae6dSMauro Carvalho Chehab FD_SET(STDIN_FILENO, &rfds); 402ecefae6dSMauro Carvalho Chehab FD_SET(fd, &rfds); 403ecefae6dSMauro Carvalho Chehab 404ecefae6dSMauro Carvalho Chehab retval = select(fd + 1, &rfds, NULL, NULL, NULL); 405ecefae6dSMauro Carvalho Chehab if (retval == -1 && errno == EINTR) 406ecefae6dSMauro Carvalho Chehab continue; 407ecefae6dSMauro Carvalho Chehab if (retval < 0) { 408ecefae6dSMauro Carvalho Chehab perror("select()"); 409ecefae6dSMauro Carvalho Chehab return 4; 410ecefae6dSMauro Carvalho Chehab } 411ecefae6dSMauro Carvalho Chehab 412ecefae6dSMauro Carvalho Chehab if (FD_ISSET(fd, &rfds)) { 413ecefae6dSMauro Carvalho Chehab cmd_len = read(fd, buf, BUF_LEN - 1); 414ecefae6dSMauro Carvalho Chehab printf("recv report:"); 415ecefae6dSMauro Carvalho Chehab for (i = 0; i < cmd_len; i++) 416ecefae6dSMauro Carvalho Chehab printf(" %02x", buf[i]); 417ecefae6dSMauro Carvalho Chehab printf("\n"); 418ecefae6dSMauro Carvalho Chehab } 419ecefae6dSMauro Carvalho Chehab 420ecefae6dSMauro Carvalho Chehab if (FD_ISSET(STDIN_FILENO, &rfds)) { 421ecefae6dSMauro Carvalho Chehab memset(report, 0x0, sizeof(report)); 422ecefae6dSMauro Carvalho Chehab cmd_len = read(STDIN_FILENO, buf, BUF_LEN - 1); 423ecefae6dSMauro Carvalho Chehab 424ecefae6dSMauro Carvalho Chehab if (cmd_len == 0) 425ecefae6dSMauro Carvalho Chehab break; 426ecefae6dSMauro Carvalho Chehab 427ecefae6dSMauro Carvalho Chehab buf[cmd_len - 1] = '\0'; 428ecefae6dSMauro Carvalho Chehab hold = 0; 429ecefae6dSMauro Carvalho Chehab 430ecefae6dSMauro Carvalho Chehab memset(report, 0x0, sizeof(report)); 431ecefae6dSMauro Carvalho Chehab if (argv[2][0] == 'k') 432ecefae6dSMauro Carvalho Chehab to_send = keyboard_fill_report(report, buf, &hold); 433ecefae6dSMauro Carvalho Chehab else if (argv[2][0] == 'm') 434ecefae6dSMauro Carvalho Chehab to_send = mouse_fill_report(report, buf, &hold); 435ecefae6dSMauro Carvalho Chehab else 436ecefae6dSMauro Carvalho Chehab to_send = joystick_fill_report(report, buf, &hold); 437ecefae6dSMauro Carvalho Chehab 438ecefae6dSMauro Carvalho Chehab if (to_send == -1) 439ecefae6dSMauro Carvalho Chehab break; 440ecefae6dSMauro Carvalho Chehab 441ecefae6dSMauro Carvalho Chehab if (write(fd, report, to_send) != to_send) { 442ecefae6dSMauro Carvalho Chehab perror(filename); 443ecefae6dSMauro Carvalho Chehab return 5; 444ecefae6dSMauro Carvalho Chehab } 445ecefae6dSMauro Carvalho Chehab if (!hold) { 446ecefae6dSMauro Carvalho Chehab memset(report, 0x0, sizeof(report)); 447ecefae6dSMauro Carvalho Chehab if (write(fd, report, to_send) != to_send) { 448ecefae6dSMauro Carvalho Chehab perror(filename); 449ecefae6dSMauro Carvalho Chehab return 6; 450ecefae6dSMauro Carvalho Chehab } 451ecefae6dSMauro Carvalho Chehab } 452ecefae6dSMauro Carvalho Chehab } 453ecefae6dSMauro Carvalho Chehab } 454ecefae6dSMauro Carvalho Chehab 455ecefae6dSMauro Carvalho Chehab close(fd); 456ecefae6dSMauro Carvalho Chehab return 0; 457ecefae6dSMauro Carvalho Chehab } 458