109d308a8SNick Hibma /* $NetBSD: usbhid.c,v 1.14 2000/07/03 02:51:37 matt Exp $ */ 209d308a8SNick Hibma /* $FreeBSD$ */ 309d308a8SNick Hibma 41de7b4b8SPedro F. Giffuni /*- 5b61a5730SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 61de7b4b8SPedro F. Giffuni * 709d308a8SNick Hibma * Copyright (c) 1998 The NetBSD Foundation, Inc. 809d308a8SNick Hibma * All rights reserved. 909d308a8SNick Hibma * 1009d308a8SNick Hibma * This code is derived from software contributed to The NetBSD Foundation 1109d308a8SNick Hibma * by Lennart Augustsson (augustss@netbsd.org). 1209d308a8SNick Hibma * 1309d308a8SNick Hibma * Redistribution and use in source and binary forms, with or without 1409d308a8SNick Hibma * modification, are permitted provided that the following conditions 1509d308a8SNick Hibma * are met: 1609d308a8SNick Hibma * 1. Redistributions of source code must retain the above copyright 1709d308a8SNick Hibma * notice, this list of conditions and the following disclaimer. 1809d308a8SNick Hibma * 2. Redistributions in binary form must reproduce the above copyright 1909d308a8SNick Hibma * notice, this list of conditions and the following disclaimer in the 2009d308a8SNick Hibma * documentation and/or other materials provided with the distribution. 2109d308a8SNick Hibma * 2209d308a8SNick Hibma * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 2309d308a8SNick Hibma * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 2409d308a8SNick Hibma * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2509d308a8SNick Hibma * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 2609d308a8SNick Hibma * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2709d308a8SNick Hibma * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2809d308a8SNick Hibma * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2909d308a8SNick Hibma * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 3009d308a8SNick Hibma * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3109d308a8SNick Hibma * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3209d308a8SNick Hibma * POSSIBILITY OF SUCH DAMAGE. 3309d308a8SNick Hibma */ 3409d308a8SNick Hibma 3509d308a8SNick Hibma #include <stdio.h> 3609d308a8SNick Hibma #include <stdlib.h> 3709d308a8SNick Hibma #include <string.h> 3809d308a8SNick Hibma #include <sys/types.h> 3909d308a8SNick Hibma #include <fcntl.h> 4009d308a8SNick Hibma #include <unistd.h> 4109d308a8SNick Hibma #include <err.h> 4209d308a8SNick Hibma #include <ctype.h> 4309d308a8SNick Hibma #include <errno.h> 44cf0e07e5SMatthew N. Dodd #include <usbhid.h> 45bf41796cSAndrew Thompson #include <dev/usb/usbhid.h> 4609d308a8SNick Hibma 4769c5bce6SEd Schouten static struct variable { 487778ab7eSAlexander Motin char *name; 497778ab7eSAlexander Motin int instance; 507778ab7eSAlexander Motin int val; 517778ab7eSAlexander Motin struct hid_item h; 527778ab7eSAlexander Motin struct variable *next; 537778ab7eSAlexander Motin } *vars; 547778ab7eSAlexander Motin 5569c5bce6SEd Schouten static int verbose = 0; 5669c5bce6SEd Schouten static int noname = 0; 5769c5bce6SEd Schouten static int hexdump = 0; 5869c5bce6SEd Schouten static int wflag = 0; 5969c5bce6SEd Schouten static int zflag = 0; 6009d308a8SNick Hibma 617778ab7eSAlexander Motin static void usage(void); 627778ab7eSAlexander Motin static void dumpitem(const char *label, struct hid_item *h); 637778ab7eSAlexander Motin static void dumpitems(report_desc_t r); 647778ab7eSAlexander Motin static void prdata(u_char *buf, struct hid_item *h); 657778ab7eSAlexander Motin static void dumpdata(int f, report_desc_t r, int loop); 667778ab7eSAlexander Motin static void writedata(int f, report_desc_t r); 6709d308a8SNick Hibma 687778ab7eSAlexander Motin static void 697778ab7eSAlexander Motin parceargs(report_desc_t r, int all, int nnames, char **names) 7009d308a8SNick Hibma { 717778ab7eSAlexander Motin struct hid_data *d; 727778ab7eSAlexander Motin struct hid_item h; 737778ab7eSAlexander Motin char colls[1000]; 747778ab7eSAlexander Motin char hname[1000], *tmp1, *tmp2; 757778ab7eSAlexander Motin struct variable *var, **pnext; 767778ab7eSAlexander Motin int i, instance, cp, t; 7709d308a8SNick Hibma 787778ab7eSAlexander Motin pnext = &vars; 797778ab7eSAlexander Motin if (all) { 807778ab7eSAlexander Motin if (wflag) 817778ab7eSAlexander Motin errx(1, "Must not specify -w to read variables"); 827778ab7eSAlexander Motin cp = 0; 837778ab7eSAlexander Motin for (d = hid_start_parse(r, 847778ab7eSAlexander Motin 1<<hid_input | 1<<hid_output | 1<<hid_feature, -1); 857778ab7eSAlexander Motin hid_get_item(d, &h); ) { 867778ab7eSAlexander Motin if (h.kind == hid_collection) { 877778ab7eSAlexander Motin cp += sprintf(&colls[cp], "%s%s:%s", 887778ab7eSAlexander Motin cp != 0 ? "." : "", 897778ab7eSAlexander Motin hid_usage_page(HID_PAGE(h.usage)), 907778ab7eSAlexander Motin hid_usage_in_page(h.usage)); 917778ab7eSAlexander Motin } else if (h.kind == hid_endcollection) { 927778ab7eSAlexander Motin tmp1 = strrchr(colls, '.'); 937778ab7eSAlexander Motin if (tmp1 != NULL) { 947778ab7eSAlexander Motin cp -= strlen(tmp1); 957778ab7eSAlexander Motin tmp1[0] = 0; 967778ab7eSAlexander Motin } else { 977778ab7eSAlexander Motin cp = 0; 987778ab7eSAlexander Motin colls[0] = 0; 997778ab7eSAlexander Motin } 1007778ab7eSAlexander Motin } 1017778ab7eSAlexander Motin if ((h.kind != hid_input && h.kind != hid_output && 1027778ab7eSAlexander Motin h.kind != hid_feature) || (h.flags & HIO_CONST)) 1037778ab7eSAlexander Motin continue; 1047778ab7eSAlexander Motin var = malloc(sizeof(*var)); 1057778ab7eSAlexander Motin memset(var, 0, sizeof(*var)); 1067778ab7eSAlexander Motin asprintf(&var->name, "%s%s%s:%s", 1077778ab7eSAlexander Motin colls, colls[0] != 0 ? "." : "", 1087778ab7eSAlexander Motin hid_usage_page(HID_PAGE(h.usage)), 1097778ab7eSAlexander Motin hid_usage_in_page(h.usage)); 1107778ab7eSAlexander Motin var->h = h; 1117778ab7eSAlexander Motin *pnext = var; 1127778ab7eSAlexander Motin pnext = &var->next; 1137778ab7eSAlexander Motin } 1147778ab7eSAlexander Motin hid_end_parse(d); 1157778ab7eSAlexander Motin return; 1167778ab7eSAlexander Motin } 1177778ab7eSAlexander Motin for (i = 0; i < nnames; i++) { 1187778ab7eSAlexander Motin var = malloc(sizeof(*var)); 1197778ab7eSAlexander Motin memset(var, 0, sizeof(*var)); 1207778ab7eSAlexander Motin tmp1 = tmp2 = strdup(names[i]); 1217778ab7eSAlexander Motin strsep(&tmp2, "="); 1227778ab7eSAlexander Motin var->name = strsep(&tmp1, "#"); 1237778ab7eSAlexander Motin if (tmp1 != NULL) 1247778ab7eSAlexander Motin var->instance = atoi(tmp1); 1257778ab7eSAlexander Motin if (tmp2 != NULL) { 1267778ab7eSAlexander Motin if (!wflag) 1277778ab7eSAlexander Motin errx(1, "Must specify -w to write variables"); 1287778ab7eSAlexander Motin var->val = atoi(tmp2); 1297778ab7eSAlexander Motin } else 1307778ab7eSAlexander Motin if (wflag) 1317778ab7eSAlexander Motin errx(1, "Must not specify -w to read variables"); 1327778ab7eSAlexander Motin *pnext = var; 1337778ab7eSAlexander Motin pnext = &var->next; 1347778ab7eSAlexander Motin 1357778ab7eSAlexander Motin instance = 0; 1367778ab7eSAlexander Motin cp = 0; 1377778ab7eSAlexander Motin for (d = hid_start_parse(r, 1387778ab7eSAlexander Motin 1<<hid_input | 1<<hid_output | 1<<hid_feature, -1); 1397778ab7eSAlexander Motin hid_get_item(d, &h); ) { 1407778ab7eSAlexander Motin if (h.kind == hid_collection) { 1417778ab7eSAlexander Motin cp += sprintf(&colls[cp], "%s%s:%s", 1427778ab7eSAlexander Motin cp != 0 ? "." : "", 1437778ab7eSAlexander Motin hid_usage_page(HID_PAGE(h.usage)), 1447778ab7eSAlexander Motin hid_usage_in_page(h.usage)); 1457778ab7eSAlexander Motin } else if (h.kind == hid_endcollection) { 1467778ab7eSAlexander Motin tmp1 = strrchr(colls, '.'); 1477778ab7eSAlexander Motin if (tmp1 != NULL) { 1487778ab7eSAlexander Motin cp -= strlen(tmp1); 1497778ab7eSAlexander Motin tmp1[0] = 0; 1507778ab7eSAlexander Motin } else { 1517778ab7eSAlexander Motin cp = 0; 1527778ab7eSAlexander Motin colls[0] = 0; 1537778ab7eSAlexander Motin } 1547778ab7eSAlexander Motin } 1557778ab7eSAlexander Motin if ((h.kind != hid_input && h.kind != hid_output && 1567778ab7eSAlexander Motin h.kind != hid_feature) || (h.flags & HIO_CONST)) 1577778ab7eSAlexander Motin continue; 1587778ab7eSAlexander Motin snprintf(hname, sizeof(hname), "%s%s%s:%s", 1597778ab7eSAlexander Motin colls, colls[0] != 0 ? "." : "", 1607778ab7eSAlexander Motin hid_usage_page(HID_PAGE(h.usage)), 1617778ab7eSAlexander Motin hid_usage_in_page(h.usage)); 1627778ab7eSAlexander Motin t = strlen(hname) - strlen(var->name); 1637778ab7eSAlexander Motin if (t > 0) { 1647778ab7eSAlexander Motin if (strcmp(hname + t, var->name) != 0) 1657778ab7eSAlexander Motin continue; 1667778ab7eSAlexander Motin if (hname[t - 1] != '.') 1677778ab7eSAlexander Motin continue; 1687778ab7eSAlexander Motin } else if (strcmp(hname, var->name) != 0) 1697778ab7eSAlexander Motin continue; 1707778ab7eSAlexander Motin if (var->instance != instance++) 1717778ab7eSAlexander Motin continue; 1727778ab7eSAlexander Motin var->h = h; 1737778ab7eSAlexander Motin break; 1747778ab7eSAlexander Motin } 1757778ab7eSAlexander Motin hid_end_parse(d); 1767778ab7eSAlexander Motin if (var->h.usage == 0) 1777778ab7eSAlexander Motin errx(1, "Unknown item '%s'", var->name); 1787778ab7eSAlexander Motin } 17909d308a8SNick Hibma } 18009d308a8SNick Hibma 1817778ab7eSAlexander Motin static void 18209d308a8SNick Hibma usage(void) 18309d308a8SNick Hibma { 18409d308a8SNick Hibma 1859a2a66f1SGreg Lehey fprintf(stderr, 1869a2a66f1SGreg Lehey "usage: %s -f device " 187e39e854eSAlexander Motin "[-l] [-n] [-r] [-t tablefile] [-v] [-x] [-z] name ...\n", 1881946089bSXin LI getprogname()); 1899a2a66f1SGreg Lehey fprintf(stderr, 1909a2a66f1SGreg Lehey " %s -f device " 191e39e854eSAlexander Motin "[-l] [-n] [-r] [-t tablefile] [-v] [-x] [-z] -a\n", 1921946089bSXin LI getprogname()); 1937778ab7eSAlexander Motin fprintf(stderr, 1947778ab7eSAlexander Motin " %s -f device " 1957778ab7eSAlexander Motin "[-t tablefile] [-v] [-z] -w name=value\n", 1967778ab7eSAlexander Motin getprogname()); 19709d308a8SNick Hibma exit(1); 19809d308a8SNick Hibma } 19909d308a8SNick Hibma 2007778ab7eSAlexander Motin static void 2011a27f4f2SMark Murray dumpitem(const char *label, struct hid_item *h) 20209d308a8SNick Hibma { 20309d308a8SNick Hibma if ((h->flags & HIO_CONST) && !verbose) 20409d308a8SNick Hibma return; 2055c1d9710SHans Petter Selasky printf("%s rid=%d pos=%d size=%d count=%d page=%s usage=%s%s%s", label, 2065c1d9710SHans Petter Selasky h->report_ID, h->pos, h->report_size, h->report_count, 20709d308a8SNick Hibma hid_usage_page(HID_PAGE(h->usage)), 20809d308a8SNick Hibma hid_usage_in_page(h->usage), 2091bee2ec7SAlexander Motin h->flags & HIO_CONST ? " Const" : "", 2101bee2ec7SAlexander Motin h->flags & HIO_VARIABLE ? "" : " Array"); 21109d308a8SNick Hibma printf(", logical range %d..%d", 21209d308a8SNick Hibma h->logical_minimum, h->logical_maximum); 21309d308a8SNick Hibma if (h->physical_minimum != h->physical_maximum) 21409d308a8SNick Hibma printf(", physical range %d..%d", 21509d308a8SNick Hibma h->physical_minimum, h->physical_maximum); 21609d308a8SNick Hibma if (h->unit) 21709d308a8SNick Hibma printf(", unit=0x%02x exp=%d", h->unit, h->unit_exponent); 21809d308a8SNick Hibma printf("\n"); 21909d308a8SNick Hibma } 22009d308a8SNick Hibma 2211bee2ec7SAlexander Motin static const char * 2221bee2ec7SAlexander Motin hid_collection_type(int32_t type) 2231bee2ec7SAlexander Motin { 2241bee2ec7SAlexander Motin static char num[8]; 2251bee2ec7SAlexander Motin 2261bee2ec7SAlexander Motin switch (type) { 2271bee2ec7SAlexander Motin case 0: return ("Physical"); 2281bee2ec7SAlexander Motin case 1: return ("Application"); 2291bee2ec7SAlexander Motin case 2: return ("Logical"); 2301bee2ec7SAlexander Motin case 3: return ("Report"); 2311bee2ec7SAlexander Motin case 4: return ("Named_Array"); 2321bee2ec7SAlexander Motin case 5: return ("Usage_Switch"); 2331bee2ec7SAlexander Motin case 6: return ("Usage_Modifier"); 2341bee2ec7SAlexander Motin } 2351bee2ec7SAlexander Motin snprintf(num, sizeof(num), "0x%02x", type); 2361bee2ec7SAlexander Motin return (num); 2371bee2ec7SAlexander Motin } 2381bee2ec7SAlexander Motin 2397778ab7eSAlexander Motin static void 24009d308a8SNick Hibma dumpitems(report_desc_t r) 24109d308a8SNick Hibma { 24209d308a8SNick Hibma struct hid_data *d; 24309d308a8SNick Hibma struct hid_item h; 2441d10fe50SNick Hibma int size; 24509d308a8SNick Hibma 2461bee2ec7SAlexander Motin for (d = hid_start_parse(r, ~0, -1); hid_get_item(d, &h); ) { 24709d308a8SNick Hibma switch (h.kind) { 24809d308a8SNick Hibma case hid_collection: 2491bee2ec7SAlexander Motin printf("Collection type=%s page=%s usage=%s\n", 2501bee2ec7SAlexander Motin hid_collection_type(h.collection), 25109d308a8SNick Hibma hid_usage_page(HID_PAGE(h.usage)), 25209d308a8SNick Hibma hid_usage_in_page(h.usage)); 25309d308a8SNick Hibma break; 25409d308a8SNick Hibma case hid_endcollection: 25509d308a8SNick Hibma printf("End collection\n"); 25609d308a8SNick Hibma break; 25709d308a8SNick Hibma case hid_input: 25809d308a8SNick Hibma dumpitem("Input ", &h); 25909d308a8SNick Hibma break; 26009d308a8SNick Hibma case hid_output: 26109d308a8SNick Hibma dumpitem("Output ", &h); 26209d308a8SNick Hibma break; 26309d308a8SNick Hibma case hid_feature: 26409d308a8SNick Hibma dumpitem("Feature", &h); 26509d308a8SNick Hibma break; 26609d308a8SNick Hibma } 26709d308a8SNick Hibma } 26809d308a8SNick Hibma hid_end_parse(d); 2691bee2ec7SAlexander Motin size = hid_report_size(r, hid_input, -1); 2701a2cdef4SNick Hibma printf("Total input size %d bytes\n", size); 27109d308a8SNick Hibma 2721bee2ec7SAlexander Motin size = hid_report_size(r, hid_output, -1); 2731d10fe50SNick Hibma printf("Total output size %d bytes\n", size); 27409d308a8SNick Hibma 2751bee2ec7SAlexander Motin size = hid_report_size(r, hid_feature, -1); 2761d10fe50SNick Hibma printf("Total feature size %d bytes\n", size); 27709d308a8SNick Hibma } 27809d308a8SNick Hibma 2797778ab7eSAlexander Motin static void 28009d308a8SNick Hibma prdata(u_char *buf, struct hid_item *h) 28109d308a8SNick Hibma { 28209d308a8SNick Hibma u_int data; 28309d308a8SNick Hibma int i, pos; 28409d308a8SNick Hibma 28509d308a8SNick Hibma pos = h->pos; 28609d308a8SNick Hibma for (i = 0; i < h->report_count; i++) { 28709d308a8SNick Hibma data = hid_get_data(buf, h); 2881bee2ec7SAlexander Motin if (i > 0) 2891bee2ec7SAlexander Motin printf(" "); 29009d308a8SNick Hibma if (h->logical_minimum < 0) 29109d308a8SNick Hibma printf("%d", (int)data); 29209d308a8SNick Hibma else 29309d308a8SNick Hibma printf("%u", data); 2949a2a66f1SGreg Lehey if (hexdump) 2959a2a66f1SGreg Lehey printf(" [0x%x]", data); 2961bee2ec7SAlexander Motin h->pos += h->report_size; 29709d308a8SNick Hibma } 2981bee2ec7SAlexander Motin h->pos = pos; 29909d308a8SNick Hibma } 30009d308a8SNick Hibma 3017778ab7eSAlexander Motin static void 30209d308a8SNick Hibma dumpdata(int f, report_desc_t rd, int loop) 30309d308a8SNick Hibma { 3047778ab7eSAlexander Motin struct variable *var; 3057778ab7eSAlexander Motin int dlen, havedata, i, match, r, rid, use_rid; 30609d308a8SNick Hibma u_char *dbuf; 3077778ab7eSAlexander Motin enum hid_kind kind; 30809d308a8SNick Hibma 309e39e854eSAlexander Motin kind = zflag ? 3 : 0; 3107778ab7eSAlexander Motin rid = -1; 3117778ab7eSAlexander Motin use_rid = !!hid_get_report_id(f); 31209d308a8SNick Hibma do { 3137778ab7eSAlexander Motin if (kind < 3) { 3147778ab7eSAlexander Motin if (++rid >= 256) { 3157778ab7eSAlexander Motin rid = 0; 3167778ab7eSAlexander Motin kind++; 31709d308a8SNick Hibma } 3187778ab7eSAlexander Motin if (kind >= 3) 3197778ab7eSAlexander Motin rid = -1; 3207778ab7eSAlexander Motin for (var = vars; var; var = var->next) { 3217778ab7eSAlexander Motin if (rid == var->h.report_ID && 3227778ab7eSAlexander Motin kind == var->h.kind) 3237778ab7eSAlexander Motin break; 3247778ab7eSAlexander Motin } 3257778ab7eSAlexander Motin if (var == NULL) 3261bee2ec7SAlexander Motin continue; 3277778ab7eSAlexander Motin } 3287778ab7eSAlexander Motin dlen = hid_report_size(rd, kind < 3 ? kind : hid_input, rid); 3297778ab7eSAlexander Motin if (dlen <= 0) 3307778ab7eSAlexander Motin continue; 3317778ab7eSAlexander Motin dbuf = malloc(dlen); 3327778ab7eSAlexander Motin memset(dbuf, 0, dlen); 3337778ab7eSAlexander Motin if (kind < 3) { 3347778ab7eSAlexander Motin dbuf[0] = rid; 3357778ab7eSAlexander Motin r = hid_get_report(f, kind, dbuf, dlen); 3367778ab7eSAlexander Motin if (r < 0) 3377778ab7eSAlexander Motin warn("hid_get_report(rid %d)", rid); 3387778ab7eSAlexander Motin havedata = !r && (rid == 0 || dbuf[0] == rid); 3397778ab7eSAlexander Motin if (rid != 0) 3407778ab7eSAlexander Motin dbuf[0] = rid; 3417778ab7eSAlexander Motin } else { 3427778ab7eSAlexander Motin r = read(f, dbuf, dlen); 3437778ab7eSAlexander Motin if (r < 1) 3447778ab7eSAlexander Motin err(1, "read error"); 3457778ab7eSAlexander Motin havedata = 1; 3467778ab7eSAlexander Motin } 3477778ab7eSAlexander Motin if (verbose) { 3487778ab7eSAlexander Motin printf("Got %s report %d (%d bytes):", 3497778ab7eSAlexander Motin kind == hid_output ? "output" : 3507778ab7eSAlexander Motin kind == hid_feature ? "feature" : "input", 3517778ab7eSAlexander Motin use_rid ? dbuf[0] : 0, dlen); 3527778ab7eSAlexander Motin if (havedata) { 3537778ab7eSAlexander Motin for (i = 0; i < dlen; i++) 3547778ab7eSAlexander Motin printf(" %02x", dbuf[i]); 3557778ab7eSAlexander Motin } 3567778ab7eSAlexander Motin printf("\n"); 3577778ab7eSAlexander Motin } 3587778ab7eSAlexander Motin match = 0; 3597778ab7eSAlexander Motin for (var = vars; var; var = var->next) { 3607778ab7eSAlexander Motin if ((kind < 3 ? kind : hid_input) != var->h.kind) 3617778ab7eSAlexander Motin continue; 3627778ab7eSAlexander Motin if (var->h.report_ID != 0 && 3637778ab7eSAlexander Motin dbuf[0] != var->h.report_ID) 3647778ab7eSAlexander Motin continue; 3657778ab7eSAlexander Motin match = 1; 36609d308a8SNick Hibma if (!noname) 3677778ab7eSAlexander Motin printf("%s=", var->name); 3687778ab7eSAlexander Motin if (havedata) 3697778ab7eSAlexander Motin prdata(dbuf, &var->h); 37009d308a8SNick Hibma printf("\n"); 37109d308a8SNick Hibma } 3727778ab7eSAlexander Motin if (match) 37309d308a8SNick Hibma printf("\n"); 37409d308a8SNick Hibma free(dbuf); 3757778ab7eSAlexander Motin } while (loop || kind < 3); 3767778ab7eSAlexander Motin } 3777778ab7eSAlexander Motin 3787778ab7eSAlexander Motin static void 3797778ab7eSAlexander Motin writedata(int f, report_desc_t rd) 3807778ab7eSAlexander Motin { 3817778ab7eSAlexander Motin struct variable *var; 3827778ab7eSAlexander Motin int dlen, i, r, rid; 3837778ab7eSAlexander Motin u_char *dbuf; 3847778ab7eSAlexander Motin enum hid_kind kind; 3857778ab7eSAlexander Motin 3867778ab7eSAlexander Motin kind = 0; 3877778ab7eSAlexander Motin rid = 0; 3887778ab7eSAlexander Motin for (kind = 0; kind < 3; kind ++) { 3897778ab7eSAlexander Motin for (rid = 0; rid < 256; rid ++) { 3907778ab7eSAlexander Motin for (var = vars; var; var = var->next) { 3917778ab7eSAlexander Motin if (rid == var->h.report_ID && kind == var->h.kind) 3927778ab7eSAlexander Motin break; 3937778ab7eSAlexander Motin } 3947778ab7eSAlexander Motin if (var == NULL) 3957778ab7eSAlexander Motin continue; 3967778ab7eSAlexander Motin dlen = hid_report_size(rd, kind, rid); 3977778ab7eSAlexander Motin if (dlen <= 0) 3987778ab7eSAlexander Motin continue; 3997778ab7eSAlexander Motin dbuf = malloc(dlen); 4007778ab7eSAlexander Motin memset(dbuf, 0, dlen); 4017778ab7eSAlexander Motin dbuf[0] = rid; 4027778ab7eSAlexander Motin if (!zflag && hid_get_report(f, kind, dbuf, dlen) == 0) { 4037778ab7eSAlexander Motin if (verbose) { 4047778ab7eSAlexander Motin printf("Got %s report %d (%d bytes):", 4057778ab7eSAlexander Motin kind == hid_input ? "input" : 4067778ab7eSAlexander Motin kind == hid_output ? "output" : "feature", 4077778ab7eSAlexander Motin rid, dlen); 4087778ab7eSAlexander Motin for (i = 0; i < dlen; i++) 4097778ab7eSAlexander Motin printf(" %02x", dbuf[i]); 4107778ab7eSAlexander Motin printf("\n"); 4117778ab7eSAlexander Motin } 4127778ab7eSAlexander Motin } else if (!zflag) { 4137778ab7eSAlexander Motin warn("hid_get_report(rid %d)", rid); 4147778ab7eSAlexander Motin if (verbose) { 4157778ab7eSAlexander Motin printf("Can't get %s report %d (%d bytes). " 4167778ab7eSAlexander Motin "Will be initialized with zeros.\n", 4177778ab7eSAlexander Motin kind == hid_input ? "input" : 4187778ab7eSAlexander Motin kind == hid_output ? "output" : "feature", 4197778ab7eSAlexander Motin rid, dlen); 4207778ab7eSAlexander Motin } 4217778ab7eSAlexander Motin } 4227778ab7eSAlexander Motin for (var = vars; var; var = var->next) { 4237778ab7eSAlexander Motin if (rid != var->h.report_ID || kind != var->h.kind) 4247778ab7eSAlexander Motin continue; 4257778ab7eSAlexander Motin hid_set_data(dbuf, &var->h, var->val); 4267778ab7eSAlexander Motin } 4277778ab7eSAlexander Motin if (verbose) { 4287778ab7eSAlexander Motin printf("Setting %s report %d (%d bytes):", 4297778ab7eSAlexander Motin kind == hid_output ? "output" : 4307778ab7eSAlexander Motin kind == hid_feature ? "feature" : "input", 4317778ab7eSAlexander Motin rid, dlen); 4327778ab7eSAlexander Motin for (i = 0; i < dlen; i++) 4337778ab7eSAlexander Motin printf(" %02x", dbuf[i]); 4347778ab7eSAlexander Motin printf("\n"); 4357778ab7eSAlexander Motin } 4367778ab7eSAlexander Motin r = hid_set_report(f, kind, dbuf, dlen); 4377778ab7eSAlexander Motin if (r != 0) 4387778ab7eSAlexander Motin warn("hid_set_report(rid %d)", rid); 4397778ab7eSAlexander Motin free(dbuf); 4407778ab7eSAlexander Motin } 4417778ab7eSAlexander Motin } 44209d308a8SNick Hibma } 44309d308a8SNick Hibma 44409d308a8SNick Hibma int 44509d308a8SNick Hibma main(int argc, char **argv) 44609d308a8SNick Hibma { 44709d308a8SNick Hibma report_desc_t r; 4487778ab7eSAlexander Motin char *table = 0; 4497778ab7eSAlexander Motin char devnam[100], *dev = NULL; 4507778ab7eSAlexander Motin int f; 4517778ab7eSAlexander Motin int all = 0; 45209d308a8SNick Hibma int ch; 45309d308a8SNick Hibma int repdump = 0; 45409d308a8SNick Hibma int loop = 0; 45509d308a8SNick Hibma 4567778ab7eSAlexander Motin while ((ch = getopt(argc, argv, "af:lnrt:vwxz")) != -1) { 45709d308a8SNick Hibma switch(ch) { 45809d308a8SNick Hibma case 'a': 45909d308a8SNick Hibma all++; 46009d308a8SNick Hibma break; 46109d308a8SNick Hibma case 'f': 46209d308a8SNick Hibma dev = optarg; 46309d308a8SNick Hibma break; 46409d308a8SNick Hibma case 'l': 46509d308a8SNick Hibma loop ^= 1; 46609d308a8SNick Hibma break; 46709d308a8SNick Hibma case 'n': 46809d308a8SNick Hibma noname++; 46909d308a8SNick Hibma break; 47009d308a8SNick Hibma case 'r': 47109d308a8SNick Hibma repdump++; 47209d308a8SNick Hibma break; 47309d308a8SNick Hibma case 't': 47409d308a8SNick Hibma table = optarg; 47509d308a8SNick Hibma break; 47609d308a8SNick Hibma case 'v': 47709d308a8SNick Hibma verbose++; 47809d308a8SNick Hibma break; 4797778ab7eSAlexander Motin case 'w': 4807778ab7eSAlexander Motin wflag = 1; 4817778ab7eSAlexander Motin break; 4829a2a66f1SGreg Lehey case 'x': 483eb29cfddSGreg Lehey hexdump = 1; 4849a2a66f1SGreg Lehey break; 4857778ab7eSAlexander Motin case 'z': 4867778ab7eSAlexander Motin zflag = 1; 4877778ab7eSAlexander Motin break; 48809d308a8SNick Hibma case '?': 48909d308a8SNick Hibma default: 49009d308a8SNick Hibma usage(); 49109d308a8SNick Hibma } 49209d308a8SNick Hibma } 49309d308a8SNick Hibma argc -= optind; 49409d308a8SNick Hibma argv += optind; 4957778ab7eSAlexander Motin if (dev == NULL) 49609d308a8SNick Hibma usage(); 49709d308a8SNick Hibma 4987778ab7eSAlexander Motin if (argc == 0 && !all && !repdump) 49909d308a8SNick Hibma usage(); 50009d308a8SNick Hibma 50109d308a8SNick Hibma if (dev[0] != '/') { 50209d308a8SNick Hibma if (isdigit(dev[0])) 5031a27f4f2SMark Murray snprintf(devnam, sizeof(devnam), "/dev/uhid%s", dev); 50409d308a8SNick Hibma else 5051a27f4f2SMark Murray snprintf(devnam, sizeof(devnam), "/dev/%s", dev); 5061a27f4f2SMark Murray dev = devnam; 50709d308a8SNick Hibma } 50809d308a8SNick Hibma 50909d308a8SNick Hibma hid_init(table); 51009d308a8SNick Hibma 51109d308a8SNick Hibma f = open(dev, O_RDWR); 51209d308a8SNick Hibma if (f < 0) 51309d308a8SNick Hibma err(1, "%s", dev); 51409d308a8SNick Hibma 51509d308a8SNick Hibma r = hid_get_report_desc(f); 51609d308a8SNick Hibma if (r == 0) 51709d308a8SNick Hibma errx(1, "USB_GET_REPORT_DESC"); 51809d308a8SNick Hibma 51909d308a8SNick Hibma if (repdump) { 52009d308a8SNick Hibma printf("Report descriptor:\n"); 52109d308a8SNick Hibma dumpitems(r); 52209d308a8SNick Hibma } 5237778ab7eSAlexander Motin if (argc != 0 || all) { 5247778ab7eSAlexander Motin parceargs(r, all, argc, argv); 5257778ab7eSAlexander Motin if (wflag) 5267778ab7eSAlexander Motin writedata(f, r); 5277778ab7eSAlexander Motin else 52809d308a8SNick Hibma dumpdata(f, r, loop); 5297778ab7eSAlexander Motin } 53009d308a8SNick Hibma 53109d308a8SNick Hibma hid_dispose_report_desc(r); 53209d308a8SNick Hibma exit(0); 53309d308a8SNick Hibma } 534