MFprojects/hid:

- Fix usbhidctl and usbhidaction to handle HID devices with multiple
report ids, such as multimedia keyboards.
 - Add collection type and report id to the `usbhidctl -r` output. They
are important for proper device understanding and debugging.
 - Fix usbhidaction tool to properly handle items having report_count
more then 1.

Approved by:	re (kib)
MFC after:	2 weeks
This commit is contained in:
Alexander Motin 2011-07-30 13:22:44 +00:00
parent c86c3aa3d9
commit 1bee2ec756
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=224511
3 changed files with 69 additions and 25 deletions

View file

@ -322,6 +322,8 @@ hid_get_item(hid_data_t s, hid_item_t *h)
* one and one item:
*/
c->report_count = 1;
c->usage_minimum = 0;
c->usage_maximum = 0;
} else {
s->ncount = 1;
}
@ -512,13 +514,14 @@ hid_report_size(report_desc_t r, enum hid_kind k, int id)
uint32_t temp;
uint32_t hpos;
uint32_t lpos;
int report_id = 0;
hpos = 0;
lpos = 0xFFFFFFFF;
memset(&h, 0, sizeof h);
for (d = hid_start_parse(r, 1 << k, id); hid_get_item(d, &h); ) {
if (h.report_ID == id && h.kind == k) {
if ((h.report_ID == id || id < 0) && h.kind == k) {
/* compute minimum */
if (lpos > h.pos)
lpos = h.pos;
@ -527,6 +530,8 @@ hid_report_size(report_desc_t r, enum hid_kind k, int id)
/* compute maximum */
if (hpos < temp)
hpos = temp;
if (h.report_ID != 0)
report_id = 1;
}
}
hid_end_parse(d);
@ -537,11 +542,8 @@ hid_report_size(report_desc_t r, enum hid_kind k, int id)
else
temp = hpos - lpos;
if (id)
temp += 8;
/* return length in bytes rounded up */
return ((temp + 7) / 8);
return ((temp + 7) / 8 + report_id);
}
int

View file

@ -92,12 +92,12 @@ main(int argc, char **argv)
char buf[100];
char devnamebuf[PATH_MAX];
struct command *cmd;
int reportid;
int reportid = -1;
demon = 1;
ignore = 0;
dieearly = 0;
while ((ch = getopt(argc, argv, "c:def:ip:t:v")) != -1) {
while ((ch = getopt(argc, argv, "c:def:ip:r:t:v")) != -1) {
switch(ch) {
case 'c':
conf = optarg;
@ -117,6 +117,9 @@ main(int argc, char **argv)
case 'p':
pidfile = optarg;
break;
case 'r':
reportid = atoi(optarg);
break;
case 't':
table = optarg;
break;
@ -146,14 +149,13 @@ main(int argc, char **argv)
fd = open(dev, O_RDWR);
if (fd < 0)
err(1, "%s", dev);
reportid = hid_get_report_id(fd);
repd = hid_get_report_desc(fd);
if (repd == NULL)
err(1, "hid_get_report_desc() failed");
commands = parse_conf(conf, repd, reportid, ignore);
sz = (size_t)hid_report_size(repd, hid_input, reportid);
sz = (size_t)hid_report_size(repd, hid_input, -1);
if (verbose)
printf("report size %zu\n", sz);
@ -198,7 +200,23 @@ main(int argc, char **argv)
}
#endif
for (cmd = commands; cmd; cmd = cmd->next) {
val = hid_get_data(buf, &cmd->item);
if (cmd->item.report_ID != 0 &&
buf[0] != cmd->item.report_ID)
continue;
if (cmd->item.flags & HIO_VARIABLE)
val = hid_get_data(buf, &cmd->item);
else {
uint32_t pos = cmd->item.pos;
for (i = 0; i < cmd->item.report_count; i++) {
val = hid_get_data(buf, &cmd->item);
if (val == cmd->value)
break;
cmd->item.pos += cmd->item.report_size;
}
cmd->item.pos = pos;
val = (i < cmd->item.report_count) ?
cmd->value : -1;
}
if (cmd->value != val && cmd->anyvalue == 0)
goto next;
if ((cmd->debounce == 0) ||

View file

@ -46,7 +46,6 @@ int verbose = 0;
int all = 0;
int noname = 0;
int hexdump = 0;
static int reportid;
char **names;
int nnames;
@ -101,11 +100,12 @@ dumpitem(const char *label, struct hid_item *h)
{
if ((h->flags & HIO_CONST) && !verbose)
return;
printf("%s size=%d count=%d page=%s usage=%s%s", label,
h->report_size, h->report_count,
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_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)
@ -116,6 +116,24 @@ dumpitem(const char *label, struct hid_item *h)
printf("\n");
}
static const char *
hid_collection_type(int32_t type)
{
static char num[8];
switch (type) {
case 0: return ("Physical");
case 1: return ("Application");
case 2: return ("Logical");
case 3: return ("Report");
case 4: return ("Named_Array");
case 5: return ("Usage_Switch");
case 6: return ("Usage_Modifier");
}
snprintf(num, sizeof(num), "0x%02x", type);
return (num);
}
void
dumpitems(report_desc_t r)
{
@ -123,10 +141,11 @@ dumpitems(report_desc_t r)
struct hid_item h;
int size;
for (d = hid_start_parse(r, ~0, reportid); hid_get_item(d, &h); ) {
for (d = hid_start_parse(r, ~0, -1); hid_get_item(d, &h); ) {
switch (h.kind) {
case hid_collection:
printf("Collection page=%s usage=%s\n",
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;
@ -145,13 +164,13 @@ dumpitems(report_desc_t r)
}
}
hid_end_parse(d);
size = hid_report_size(r, hid_input, 0);
size = hid_report_size(r, hid_input, -1);
printf("Total input size %d bytes\n", size);
size = hid_report_size(r, hid_output, 0);
size = hid_report_size(r, hid_output, -1);
printf("Total output size %d bytes\n", size);
size = hid_report_size(r, hid_feature, 0);
size = hid_report_size(r, hid_feature, -1);
printf("Total feature size %d bytes\n", size);
}
@ -180,14 +199,17 @@ prdata(u_char *buf, struct hid_item *h)
pos = h->pos;
for (i = 0; i < h->report_count; i++) {
data = hid_get_data(buf, h);
if (i > 0)
printf(" ");
if (h->logical_minimum < 0)
printf("%d", (int)data);
else
printf("%u", data);
if (hexdump)
printf(" [0x%x]", data);
pos += h->report_size;
h->pos += h->report_size;
}
h->pos = pos;
}
void
@ -202,7 +224,7 @@ dumpdata(int f, report_desc_t rd, int loop)
char namebuf[10000], *namep;
hids = 0;
for (d = hid_start_parse(rd, 1<<hid_input, reportid);
for (d = hid_start_parse(rd, 1<<hid_input, -1);
hid_get_item(d, &h); ) {
if (h.kind == hid_collection)
colls[++sp] = h.usage;
@ -217,7 +239,7 @@ dumpdata(int f, report_desc_t rd, int loop)
}
hid_end_parse(d);
rev(&hids);
dlen = hid_report_size(rd, hid_input, 0);
dlen = hid_report_size(rd, hid_input, -1);
dbuf = malloc(dlen);
if (!loop)
if (hid_set_immed(f, 1) < 0) {
@ -228,10 +250,12 @@ dumpdata(int f, report_desc_t rd, int loop)
}
do {
r = read(f, dbuf, dlen);
if (r != dlen) {
err(1, "bad read %d != %d", r, 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)),
@ -242,7 +266,7 @@ dumpdata(int f, report_desc_t rd, int loop)
if (all || gotname(namebuf)) {
if (!noname)
printf("%s=", namebuf);
prdata(dbuf + (reportid != 0), n);
prdata(dbuf, n);
printf("\n");
}
}