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