static void hid_dump_descriptor(report_desc_t r) { struct hid_data *d = NULL; struct hid_item h; for (d = hid_start_parse(r, ~0, -1); hid_get_item(d, &h); ) { switch (h.kind) { case hid_collection: fprintf(stdout, "Collection page=%s usage=%s\n", hid_usage_page(HID_PAGE(h.usage)), hid_usage_in_page(h.usage)); break; case hid_endcollection: fprintf(stdout, "End collection\n"); break; case hid_input: hid_dump_item("Input ", &h); break; case hid_output: hid_dump_item("Output ", &h); break; case hid_feature: hid_dump_item("Feature", &h); break; } } hid_end_parse(d); }
static void dumpitem(const char *label, struct hid_item *h) { if ((h->flags & HIO_CONST) && !verbose) return; printf("%s rid=%d size=%d count=%d page=%s usage=%s%s%s", label, h->report_ID, h->report_size, h->report_count, hid_usage_page(HID_PAGE(h->usage)), hid_usage_in_page(h->usage), h->flags & HIO_CONST ? " Const" : "", h->flags & HIO_VARIABLE ? "" : " Array"); printf(", logical range %d..%d", h->logical_minimum, h->logical_maximum); if (h->physical_minimum != h->physical_maximum) printf(", physical range %d..%d", h->physical_minimum, h->physical_maximum); if (h->unit) printf(", unit=0x%02x exp=%d", h->unit, h->unit_exponent); printf("\n"); }
static void dumpitems(report_desc_t r) { struct hid_data *d; struct hid_item h; int size; for (d = hid_start_parse(r, ~0, -1); hid_get_item(d, &h); ) { switch (h.kind) { case hid_collection: printf("Collection type=%s page=%s usage=%s\n", hid_collection_type(h.collection), hid_usage_page(HID_PAGE(h.usage)), hid_usage_in_page(h.usage)); break; case hid_endcollection: printf("End collection\n"); break; case hid_input: dumpitem("Input ", &h); break; case hid_output: dumpitem("Output ", &h); break; case hid_feature: dumpitem("Feature", &h); break; } } hid_end_parse(d); size = hid_report_size(r, hid_input, -1); printf("Total input size %d bytes\n", size); size = hid_report_size(r, hid_output, -1); printf("Total output size %d bytes\n", size); size = hid_report_size(r, hid_feature, -1); printf("Total feature size %d bytes\n", size); }
static void hid_dump_item(char const *label, struct hid_item *h) { if ((h->flags & HIO_CONST) && !verbose) return; fprintf(stdout, "%s id=%u size=%u count=%u page=%s usage=%s%s%s%s%s%s%s%s%s%s", label, (uint8_t) h->report_ID, h->report_size, h->report_count, hid_usage_page(HID_PAGE(h->usage)), hid_usage_in_page(h->usage), h->flags & HIO_CONST ? " Const" : "", h->flags & HIO_VARIABLE ? " Variable" : "", h->flags & HIO_RELATIVE ? " Relative" : "", h->flags & HIO_WRAP ? " Wrap" : "", h->flags & HIO_NONLINEAR ? " NonLinear" : "", h->flags & HIO_NOPREF ? " NoPref" : "", h->flags & HIO_NULLSTATE ? " NullState" : "", h->flags & HIO_VOLATILE ? " Volatile" : "", h->flags & HIO_BUFBYTES ? " BufBytes" : ""); fprintf(stdout, ", logical range %d..%d", h->logical_minimum, h->logical_maximum); if (h->physical_minimum != h->physical_maximum) fprintf(stdout, ", physical range %d..%d", h->physical_minimum, h->physical_maximum); if (h->unit) fprintf(stdout, ", unit=0x%02x exp=%d", h->unit, h->unit_exponent); fprintf(stdout, "\n"); }
int SDL_SYS_JoystickOpen(SDL_Joystick *joy) { char *path = joynames[joy->index]; struct joystick_hwdata *hw; struct hid_item hitem; struct hid_data *hdata; struct report *rep; int fd; int i; fd = open(path, O_RDONLY); if (fd == -1) { SDL_SetError("%s: %s", path, strerror(errno)); return (-1); } hw = (struct joystick_hwdata *)SDL_malloc(sizeof(struct joystick_hwdata)); if (hw == NULL) { SDL_OutOfMemory(); close(fd); return (-1); } joy->hwdata = hw; hw->fd = fd; hw->path = strdup(path); hw->x = 0; hw->y = 0; hw->xmin = 0xffff; hw->ymin = 0xffff; hw->xmax = 0; hw->ymax = 0; if (! SDL_strncmp(path, "/dev/joy", 8)) { hw->type = BSDJOY_JOY; joy->naxes = 2; joy->nbuttons = 2; joy->nhats = 0; joy->nballs = 0; joydevnames[joy->index] = strdup("Gameport joystick"); goto usbend; } else { hw->type = BSDJOY_UHID; } { int ax; for (ax = 0; ax < JOYAXE_count; ax++) hw->axis_map[ax] = -1; } hw->repdesc = hid_get_report_desc(fd); if (hw->repdesc == NULL) { SDL_SetError("%s: USB_GET_REPORT_DESC: %s", hw->path, strerror(errno)); goto usberr; } #if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063) rep->rid = hid_get_report_id(fd); if (rep->rid < 0) { #else rep = &hw->inreport; if (ioctl(fd, USB_GET_REPORT_ID, &rep->rid) < 0) { #endif rep->rid = -1; /* XXX */ } if (report_alloc(rep, hw->repdesc, REPORT_INPUT) < 0) { goto usberr; } if (rep->size <= 0) { SDL_SetError("%s: Input report descriptor has invalid length", hw->path); goto usberr; } #if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_kernel_version >= 500111) hdata = hid_start_parse(hw->repdesc, 1 << hid_input, rep->rid); #else hdata = hid_start_parse(hw->repdesc, 1 << hid_input); #endif if (hdata == NULL) { SDL_SetError("%s: Cannot start HID parser", hw->path); goto usberr; } joy->naxes = 0; joy->nbuttons = 0; joy->nhats = 0; joy->nballs = 0; for (i=0; i<JOYAXE_count; i++) hw->axis_map[i] = -1; while (hid_get_item(hdata, &hitem) > 0) { char *sp; const char *s; switch (hitem.kind) { case hid_collection: switch (HID_PAGE(hitem.usage)) { case HUP_GENERIC_DESKTOP: switch (HID_USAGE(hitem.usage)) { case HUG_JOYSTICK: case HUG_GAME_PAD: s = hid_usage_in_page(hitem.usage); sp = SDL_malloc(SDL_strlen(s) + 5); SDL_snprintf(sp, SDL_strlen(s) + 5, "%s (%d)", s, joy->index); joydevnames[joy->index] = sp; } } break; case hid_input: switch (HID_PAGE(hitem.usage)) { case HUP_GENERIC_DESKTOP: { unsigned usage = HID_USAGE(hitem.usage); int joyaxe = usage_to_joyaxe(usage); if (joyaxe >= 0) { hw->axis_map[joyaxe] = 1; } else if (usage == HUG_HAT_SWITCH) { joy->nhats++; } break; } case HUP_BUTTON: joy->nbuttons++; break; default: break; } break; default: break; } } hid_end_parse(hdata); for (i=0; i<JOYAXE_count; i++) if (hw->axis_map[i] > 0) hw->axis_map[i] = joy->naxes++; usbend: /* The poll blocks the event thread. */ fcntl(fd, F_SETFL, O_NONBLOCK); return (0); usberr: close(hw->fd); SDL_free(hw->path); SDL_free(hw); return (-1); } void SDL_SYS_JoystickUpdate(SDL_Joystick *joy) { struct hid_item hitem; struct hid_data *hdata; struct report *rep; int nbutton, naxe = -1; Sint32 v; #if defined(__FREEBSD__) || SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H struct joystick gameport; if (joy->hwdata->type == BSDJOY_JOY) { if (read(joy->hwdata->fd, &gameport, sizeof gameport) != sizeof gameport) return; if (abs(joy->hwdata->x - gameport.x) > 8) { joy->hwdata->x = gameport.x; if (joy->hwdata->x < joy->hwdata->xmin) { joy->hwdata->xmin = joy->hwdata->x; } if (joy->hwdata->x > joy->hwdata->xmax) { joy->hwdata->xmax = joy->hwdata->x; } if (joy->hwdata->xmin == joy->hwdata->xmax) { joy->hwdata->xmin--; joy->hwdata->xmax++; } v = (Sint32)joy->hwdata->x; v -= (joy->hwdata->xmax + joy->hwdata->xmin + 1)/2; v *= 32768/((joy->hwdata->xmax - joy->hwdata->xmin + 1)/2); SDL_PrivateJoystickAxis(joy, 0, v); } if (abs(joy->hwdata->y - gameport.y) > 8) { joy->hwdata->y = gameport.y; if (joy->hwdata->y < joy->hwdata->ymin) { joy->hwdata->ymin = joy->hwdata->y; } if (joy->hwdata->y > joy->hwdata->ymax) { joy->hwdata->ymax = joy->hwdata->y; } if (joy->hwdata->ymin == joy->hwdata->ymax) { joy->hwdata->ymin--; joy->hwdata->ymax++; } v = (Sint32)joy->hwdata->y; v -= (joy->hwdata->ymax + joy->hwdata->ymin + 1)/2; v *= 32768/((joy->hwdata->ymax - joy->hwdata->ymin + 1)/2); SDL_PrivateJoystickAxis(joy, 1, v); } if (gameport.b1 != joy->buttons[0]) { SDL_PrivateJoystickButton(joy, 0, gameport.b1); } if (gameport.b2 != joy->buttons[1]) { SDL_PrivateJoystickButton(joy, 1, gameport.b2); } return; } #endif /* defined(__FREEBSD__) || SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H */ rep = &joy->hwdata->inreport; if (read(joy->hwdata->fd, REP_BUF_DATA(rep), rep->size) != rep->size) { return; } #if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_kernel_version >= 500111) hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input, rep->rid); #else hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input); #endif if (hdata == NULL) { fprintf(stderr, "%s: Cannot start HID parser\n", joy->hwdata->path); return; } for (nbutton = 0; hid_get_item(hdata, &hitem) > 0;) { switch (hitem.kind) { case hid_input: switch (HID_PAGE(hitem.usage)) { case HUP_GENERIC_DESKTOP: { unsigned usage = HID_USAGE(hitem.usage); int joyaxe = usage_to_joyaxe(usage); if (joyaxe >= 0) { naxe = joy->hwdata->axis_map[joyaxe]; /* scaleaxe */ v = (Sint32)hid_get_data(REP_BUF_DATA(rep), &hitem); v -= (hitem.logical_maximum + hitem.logical_minimum + 1)/2; v *= 32768/((hitem.logical_maximum - hitem.logical_minimum + 1)/2); if (v != joy->axes[naxe]) { SDL_PrivateJoystickAxis(joy, naxe, v); } } else if (usage == HUG_HAT_SWITCH) { v = (Sint32)hid_get_data(REP_BUF_DATA(rep), &hitem); SDL_PrivateJoystickHat(joy, 0, hatval_to_sdl(v)-hitem.logical_minimum); } break; } case HUP_BUTTON: v = (Sint32)hid_get_data(REP_BUF_DATA(rep), &hitem); if (joy->buttons[nbutton] != v) { SDL_PrivateJoystickButton(joy, nbutton, v); } nbutton++; break; default: continue; } break; default: break; } } hid_end_parse(hdata); return; } /* Function to close a joystick after use */ void SDL_SYS_JoystickClose(SDL_Joystick *joy) { if (SDL_strncmp(joy->hwdata->path, "/dev/joy", 8)) { report_free(&joy->hwdata->inreport); hid_dispose_report_desc(joy->hwdata->repdesc); } close(joy->hwdata->fd); SDL_free(joy->hwdata->path); SDL_free(joy->hwdata); return; } void SDL_SYS_JoystickQuit(void) { int i; for (i = 0; i < MAX_JOYS; i++) { if (joynames[i] != NULL) SDL_free(joynames[i]); if (joydevnames[i] != NULL) SDL_free(joydevnames[i]); } return; }
int SDL_SYS_JoystickOpen(SDL_Joystick *joy) { char *path = joynames[joy->index]; struct joystick_hwdata *hw; struct hid_item hitem; struct hid_data *hdata; struct report *rep; int fd; int i; fd = open(path, O_RDONLY); if (fd == -1) { SDL_SetError("%s: %s", path, strerror(errno)); return (-1); } hw = (struct joystick_hwdata *)SDL_malloc(sizeof(struct joystick_hwdata)); if (hw == NULL) { SDL_OutOfMemory(); close(fd); return (-1); } joy->hwdata = hw; hw->fd = fd; hw->path = strdup(path); hw->x = 0; hw->y = 0; hw->xmin = 0xffff; hw->ymin = 0xffff; hw->xmax = 0; hw->ymax = 0; if (! SDL_strncmp(path, "/dev/joy", 8)) { hw->type = BSDJOY_JOY; joy->naxes = 2; joy->nbuttons = 2; joy->nhats = 0; joy->nballs = 0; joydevnames[joy->index] = strdup("Gameport joystick"); goto usbend; } else { hw->type = BSDJOY_UHID; } { int ax; for (ax = 0; ax < JOYAXE_count; ax++) hw->axis_map[ax] = -1; } hw->repdesc = hid_get_report_desc(fd); if (hw->repdesc == NULL) { SDL_SetError("%s: USB_GET_REPORT_DESC: %s", hw->path, strerror(errno)); goto usberr; } rep = &hw->inreport; if (ioctl(fd, USB_GET_REPORT_ID, &rep->rid) < 0) { rep->rid = -1; /* XXX */ } if (report_alloc(rep, hw->repdesc, REPORT_INPUT) < 0) { goto usberr; } if (rep->size <= 0) { SDL_SetError("%s: Input report descriptor has invalid length", hw->path); goto usberr; } #if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_version >= 500111) hdata = hid_start_parse(hw->repdesc, 1 << hid_input, rep->rid); #else hdata = hid_start_parse(hw->repdesc, 1 << hid_input); #endif if (hdata == NULL) { SDL_SetError("%s: Cannot start HID parser", hw->path); goto usberr; } joy->naxes = 0; joy->nbuttons = 0; joy->nhats = 0; joy->nballs = 0; for (i=0; i<JOYAXE_count; i++) hw->axis_map[i] = -1; while (hid_get_item(hdata, &hitem) > 0) { char *sp; const char *s; switch (hitem.kind) { case hid_collection: switch (HID_PAGE(hitem.usage)) { case HUP_GENERIC_DESKTOP: switch (HID_USAGE(hitem.usage)) { case HUG_JOYSTICK: case HUG_GAME_PAD: s = hid_usage_in_page(hitem.usage); sp = SDL_malloc(SDL_strlen(s) + 5); SDL_snprintf(sp, SDL_strlen(s) + 5, "%s (%d)", s, joy->index); joydevnames[joy->index] = sp; } } break; case hid_input: switch (HID_PAGE(hitem.usage)) { case HUP_GENERIC_DESKTOP: { unsigned usage = HID_USAGE(hitem.usage); int joyaxe = usage_to_joyaxe(usage); if (joyaxe >= 0) { hw->axis_map[joyaxe] = 1; } else if (usage == HUG_HAT_SWITCH) { joy->nhats++; } break; } case HUP_BUTTON: joy->nbuttons++; break; default: break; } break; default: break; } } hid_end_parse(hdata); for (i=0; i<JOYAXE_count; i++) if (hw->axis_map[i] > 0) hw->axis_map[i] = joy->naxes++; usbend: /* The poll blocks the event thread. */ fcntl(fd, F_SETFL, O_NONBLOCK); return (0); usberr: close(hw->fd); SDL_free(hw->path); SDL_free(hw); return (-1); }
struct command * parse_conf(const char *conf, report_desc_t repd, int reportid, int ignore) { FILE *f; char *p; int line; char buf[SIZE], name[SIZE], value[SIZE], debounce[SIZE], action[SIZE]; char usbuf[SIZE], coll[SIZE], *tmp; struct command *cmd, *cmds; struct hid_data *d; struct hid_item h; int inst, cinst, u, lo, hi, range, t; f = fopen(conf, "r"); if (f == NULL) err(1, "%s", conf); cmds = NULL; for (line = 1; ; line++) { if (fgets(buf, sizeof buf, f) == NULL) break; if (buf[0] == '#' || buf[0] == '\n') continue; p = strchr(buf, '\n'); while (p && isspace(peek(f))) { if (fgets(p, sizeof buf - strlen(buf), f) == NULL) break; p = strchr(buf, '\n'); } if (p) *p = 0; if (sscanf(buf, "%s %s %s %[^\n]", name, value, debounce, action) != 4) { if (isdemon) { syslog(LOG_WARNING, "config file `%s', line %d" ", syntax error: %s", conf, line, buf); freecommands(cmds); return (NULL); } else { errx(1, "config file `%s', line %d," ", syntax error: %s", conf, line, buf); } } tmp = strchr(name, '#'); if (tmp != NULL) { *tmp = 0; inst = atoi(tmp + 1); } else inst = 0; cmd = malloc(sizeof *cmd); if (cmd == NULL) err(1, "malloc failed"); cmd->next = cmds; cmds = cmd; cmd->line = line; if (strcmp(value, "*") == 0) { cmd->anyvalue = 1; } else { cmd->anyvalue = 0; if (sscanf(value, "%d", &cmd->value) != 1) { if (isdemon) { syslog(LOG_WARNING, "config file `%s', line %d, " "bad value: %s (should be * or a number)\n", conf, line, value); freecommands(cmds); return (NULL); } else { errx(1, "config file `%s', line %d, " "bad value: %s (should be * or a number)\n", conf, line, value); } } } if (sscanf(debounce, "%d", &cmd->debounce) != 1) { if (isdemon) { syslog(LOG_WARNING, "config file `%s', line %d, " "bad value: %s (should be a number >= 0)\n", conf, line, debounce); freecommands(cmds); return (NULL); } else { errx(1, "config file `%s', line %d, " "bad value: %s (should be a number >= 0)\n", conf, line, debounce); } } coll[0] = 0; cinst = 0; for (d = hid_start_parse(repd, 1 << hid_input, reportid); hid_get_item(d, &h); ) { if (verbose > 2) printf("kind=%d usage=%x\n", h.kind, h.usage); if (h.flags & HIO_CONST) continue; switch (h.kind) { case hid_input: if (h.usage_minimum != 0 || h.usage_maximum != 0) { lo = h.usage_minimum; hi = h.usage_maximum; range = 1; } else { lo = h.usage; hi = h.usage; range = 0; } for (u = lo; u <= hi; u++) { if (coll[0]) { snprintf(usbuf, sizeof usbuf, "%s.%s:%s", coll+1, hid_usage_page(HID_PAGE(u)), hid_usage_in_page(u)); } else { snprintf(usbuf, sizeof usbuf, "%s:%s", hid_usage_page(HID_PAGE(u)), hid_usage_in_page(u)); } if (verbose > 2) printf("usage %s\n", usbuf); t = strlen(usbuf) - strlen(name); if (t > 0) { if (strcmp(usbuf + t, name)) continue; if (usbuf[t - 1] != '.') continue; } else if (strcmp(usbuf, name)) continue; if (inst == cinst++) goto foundhid; } break; case hid_collection: snprintf(coll + strlen(coll), sizeof coll - strlen(coll), ".%s:%s", hid_usage_page(HID_PAGE(h.usage)), hid_usage_in_page(h.usage)); break; case hid_endcollection: if (coll[0]) *strrchr(coll, '.') = 0; break; default: break; } } if (ignore) { if (verbose) warnx("ignore item '%s'", name); continue; } if (isdemon) { syslog(LOG_WARNING, "config file `%s', line %d, HID " "item not found: `%s'\n", conf, line, name); freecommands(cmds); return (NULL); } else { errx(1, "config file `%s', line %d, HID item " "not found: `%s'\n", conf, line, name); } foundhid: hid_end_parse(d); cmd->lastseen = -1; cmd->lastused = -1; cmd->item = h; cmd->name = strdup(name); cmd->action = strdup(action); if (range) { if (cmd->value == 1) cmd->value = u - lo; else cmd->value = -1; } if (verbose) printf("PARSE:%d %s, %d, '%s'\n", cmd->line, name, cmd->value, cmd->action); } fclose(f); return (cmds); }
static void parceargs(report_desc_t r, int all, int nnames, char **names) { struct hid_data *d; struct hid_item h; char colls[1000]; char hname[1000], *tmp1, *tmp2; struct variable *var, **pnext; int i, instance, cp, t; pnext = &vars; if (all) { if (wflag) errx(1, "Must not specify -w to read variables"); cp = 0; for (d = hid_start_parse(r, 1<<hid_input | 1<<hid_output | 1<<hid_feature, -1); hid_get_item(d, &h); ) { if (h.kind == hid_collection) { cp += sprintf(&colls[cp], "%s%s:%s", cp != 0 ? "." : "", hid_usage_page(HID_PAGE(h.usage)), hid_usage_in_page(h.usage)); } else if (h.kind == hid_endcollection) { tmp1 = strrchr(colls, '.'); if (tmp1 != NULL) { cp -= strlen(tmp1); tmp1[0] = 0; } else { cp = 0; colls[0] = 0; } } if ((h.kind != hid_input && h.kind != hid_output && h.kind != hid_feature) || (h.flags & HIO_CONST)) continue; var = malloc(sizeof(*var)); memset(var, 0, sizeof(*var)); asprintf(&var->name, "%s%s%s:%s", colls, colls[0] != 0 ? "." : "", hid_usage_page(HID_PAGE(h.usage)), hid_usage_in_page(h.usage)); var->h = h; *pnext = var; pnext = &var->next; } hid_end_parse(d); return; } for (i = 0; i < nnames; i++) { var = malloc(sizeof(*var)); memset(var, 0, sizeof(*var)); tmp1 = tmp2 = strdup(names[i]); strsep(&tmp2, "="); var->name = strsep(&tmp1, "#"); if (tmp1 != NULL) var->instance = atoi(tmp1); if (tmp2 != NULL) { if (!wflag) errx(1, "Must specify -w to write variables"); var->val = atoi(tmp2); } else if (wflag) errx(1, "Must not specify -w to read variables"); *pnext = var; pnext = &var->next; instance = 0; cp = 0; for (d = hid_start_parse(r, 1<<hid_input | 1<<hid_output | 1<<hid_feature, -1); hid_get_item(d, &h); ) { if (h.kind == hid_collection) { cp += sprintf(&colls[cp], "%s%s:%s", cp != 0 ? "." : "", hid_usage_page(HID_PAGE(h.usage)), hid_usage_in_page(h.usage)); } else if (h.kind == hid_endcollection) { tmp1 = strrchr(colls, '.'); if (tmp1 != NULL) { cp -= strlen(tmp1); tmp1[0] = 0; } else { cp = 0; colls[0] = 0; } } if ((h.kind != hid_input && h.kind != hid_output && h.kind != hid_feature) || (h.flags & HIO_CONST)) continue; snprintf(hname, sizeof(hname), "%s%s%s:%s", colls, colls[0] != 0 ? "." : "", hid_usage_page(HID_PAGE(h.usage)), hid_usage_in_page(h.usage)); t = strlen(hname) - strlen(var->name); if (t > 0) { if (strcmp(hname + t, var->name) != 0) continue; if (hname[t - 1] != '.') continue; } else if (strcmp(hname, var->name) != 0) continue; if (var->instance != instance++) continue; var->h = h; break; } hid_end_parse(d); if (var->h.usage == 0) errx(1, "Unknown item '%s'", var->name); } }
void dumpdata(int f, report_desc_t rd, int loop) { struct hid_data *d; struct hid_item h, *hids, *n; int r, dlen; u_char *dbuf; u_int32_t colls[100]; int sp = 0; char namebuf[10000], *namep; hids = 0; for (d = hid_start_parse(rd, 1<<hid_input, -1); hid_get_item(d, &h); ) { if (h.kind == hid_collection) colls[++sp] = h.usage; else if (h.kind == hid_endcollection) --sp; if (h.kind != hid_input || (h.flags & HIO_CONST)) continue; h.next = hids; h.collection = colls[sp]; hids = malloc(sizeof *hids); *hids = h; } hid_end_parse(d); rev(&hids); dlen = hid_report_size(rd, hid_input, -1); dbuf = malloc(dlen); if (!loop) if (hid_set_immed(f, 1) < 0) { if (errno == EOPNOTSUPP) warnx("device does not support immediate mode, only changes reported."); else err(1, "USB_SET_IMMED"); } do { r = read(f, dbuf, dlen); if (r < 1) { err(1, "read error"); } for (n = hids; n; n = n->next) { if (n->report_ID != 0 && dbuf[0] != n->report_ID) continue; namep = namebuf; namep += sprintf(namep, "%s:%s.", hid_usage_page(HID_PAGE(n->collection)), hid_usage_in_page(n->collection)); namep += sprintf(namep, "%s:%s", hid_usage_page(HID_PAGE(n->usage)), hid_usage_in_page(n->usage)); if (all || gotname(namebuf)) { if (!noname) printf("%s=", namebuf); prdata(dbuf, n); printf("\n"); } } if (loop) printf("\n"); } while (loop); free(dbuf); }