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"); }
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); } }
int main (int argc, char **argv) { char *device_file; int fd = -1; int report_id; report_desc_t report_desc; struct hid_data *data; hid_item_t item; boolean is_keyboard = FALSE; boolean is_keypad = FALSE; boolean is_mouse = FALSE; boolean is_joystick = FALSE; if (! hfp_init(argc, argv)) goto end; device_file = getenv("HAL_PROP_HIDDEV_DEVICE"); if (! device_file) goto end; fd = open(device_file, O_RDONLY); if (fd < 0) goto end; /* give a meaningful process title for ps(1) */ setproctitle("%s", device_file); #ifdef HAVE_LIBUSB20 report_id = hid_get_report_id(fd); if (report_id == -1) #else if (ioctl(fd, USB_GET_REPORT_ID, &report_id) < 0) #endif goto end; hid_init(NULL); report_desc = hid_get_report_desc(fd); if (! report_desc) goto end; for (data = hid_start_parse(report_desc, ~0, report_id); hid_get_item(data, &item);) if (item.kind == hid_collection) { if (item.collection == HID_COLLECTION_APPLICATION) { const char *page; char *full_page; int i; page = hid_usage_page(HID_PAGE(item.usage)); full_page = hfp_strdup_printf("%s Page", page); for (i = 0; full_page[i] != 0; i++) if (full_page[i] == '_') full_page[i] = ' '; libhal_device_property_strlist_append(hfp_ctx, hfp_udi, "hiddev.application_pages", full_page, &hfp_error); hfp_free(full_page); } switch (item.usage) { case HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE): is_mouse = TRUE; break; case HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_JOYSTICK): case HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_GAME_PAD): is_joystick = TRUE; break; case HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD): is_keyboard = TRUE; break; case HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYPAD): is_keypad = TRUE; break; } } hid_end_parse(data); hid_dispose_report_desc(report_desc); if (is_keyboard || is_mouse || is_joystick || is_keypad) { libhal_device_add_capability(hfp_ctx, hfp_udi, "input", &hfp_error); libhal_device_set_property_string(hfp_ctx, hfp_udi, "info.category", "input", &hfp_error); libhal_device_set_property_string(hfp_ctx, hfp_udi, "input.device", device_file, &hfp_error); } if (is_keyboard) libhal_device_add_capability(hfp_ctx, hfp_udi, "input.keyboard", &hfp_error); if (is_keypad) libhal_device_add_capability(hfp_ctx, hfp_udi, "input.keypad", &hfp_error); if (is_keyboard || is_keypad) libhal_device_add_capability(hfp_ctx, hfp_udi, "input.keys", &hfp_error); if (is_mouse) libhal_device_add_capability(hfp_ctx, hfp_udi, "input.mouse", &hfp_error); if (is_joystick) libhal_device_add_capability(hfp_ctx, hfp_udi, "input.joystick", &hfp_error); end: return 0; }
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); }