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