Add usbhidctl(1) a program for manipulating USB HID devices.

This commit is contained in:
augustss 1998-07-13 11:14:03 +00:00
parent 6b7023e319
commit 8f894bc08b
7 changed files with 1083 additions and 2 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.82 1998/05/25 20:06:39 tv Exp $
# $NetBSD: Makefile,v 1.83 1998/07/13 11:14:03 augustss Exp $
# from: @(#)Makefile 8.3 (Berkeley) 1/7/94
.include <bsd.own.mk> # for EXPORTABLE_SYSTEM definition
@ -21,7 +21,7 @@ SUBDIR= apply apropos asa at audioctl banner basename bdes \
showmount skey skeyinfo skeyinit soelim split \
su systat tail talk tcopy tee tftp time \
tip tn3270 touch tput tr true tset tsort tty ul \
uname unexpand unifdef uniq units unvis users \
uname unexpand unifdef uniq units unvis usbhidctl users \
uudecode uuencode vacation vgrind vi vis vmstat w \
wall wc what whatis whereis which who whois window \
write xargs xinstall xlint xstr yacc yes ypcat \

View File

@ -0,0 +1,9 @@
# $NetBSD: Makefile,v 1.1 1998/07/13 11:14:03 augustss Exp $
PROG= usbhidctl
SRCS= usbhid.c hidsubr.c
FILES= usb_hid_usages
FILESDIR=/usr/share/misc
.include <bsd.prog.mk>
.include <bsd.subdir.mk>

506
usr.bin/usbhidctl/hidsubr.c Normal file
View File

@ -0,0 +1,506 @@
/* $NetBSD: hidsubr.c,v 1.1 1998/07/13 11:14:04 augustss Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
* All rights reserved.
*
* Author: Lennart Augustsson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <err.h>
#include <ctype.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbhid.h>
#include "hidsubr.h"
#define MAXUSAGE 100
struct hid_data {
u_char *start;
u_char *end;
u_char *p;
struct hid_item cur;
u_int32_t usages[MAXUSAGE];
int nusage;
int minset;
int multi;
int multimax;
int kindset;
};
static int min(int x, int y) { return x < y ? x : y; }
static void
hid_clear_local(struct hid_item *c)
{
c->usage = 0;
c->usage_minimum = 0;
c->usage_maximum = 0;
c->designator_index = 0;
c->designator_minimum = 0;
c->designator_maximum = 0;
c->string_index = 0;
c->string_minimum = 0;
c->string_maximum = 0;
c->set_delimiter = 0;
}
struct hid_data *
hid_start_parse(u_char *d, int len, int kindset)
{
struct hid_data *s;
s = malloc(sizeof *s);
memset(s, 0, sizeof *s);
s->start = s->p = d;
s->end = d + len;
s->kindset = kindset;
return (s);
}
void
hid_end_parse(struct hid_data *s)
{
while (s->cur.next) {
struct hid_item *hi = s->cur.next->next;
free(s->cur.next);
s->cur.next = hi;
}
free(s);
}
int
hid_get_item(struct hid_data *s, struct hid_item *h)
{
struct hid_item *c = &s->cur;
int bTag = 0, bType = 0, bSize;
u_char *data;
int32_t dval;
u_char *p;
struct hid_item *hi;
int i;
top:
if (s->multimax) {
if (s->multi < s->multimax) {
c->usage = s->usages[min(s->multi, s->nusage-1)];
s->multi++;
*h = *c;
c->pos += c->report_size;
h->next = 0;
return (1);
} else {
c->report_count = s->multimax;
s->multimax = 0;
s->nusage = 0;
hid_clear_local(c);
}
}
for (;;) {
p = s->p;
if (p >= s->end)
return (0);
bSize = *p++;
if (bSize == 0xfe) {
/* long item */
bSize = *p++;
bSize |= *p++ << 8;
bTag = *p++;
data = p;
p += bSize;
} else {
/* short item */
bTag = bSize >> 4;
bType = (bSize >> 2) & 3;
bSize &= 3;
if (bSize == 3) bSize = 4;
data = p;
p += bSize;
}
s->p = p;
switch(bSize) {
case 0:
dval = 0;
break;
case 1:
dval = (int8_t)*data++;
break;
case 2:
dval = *data++;
dval |= *data++ << 8;
dval = (int16_t)dval;
break;
case 4:
dval = *data++;
dval |= *data++ << 8;
dval |= *data++ << 16;
dval |= *data++ << 24;
break;
default:
printf("BAD LENGTH %d\n", bSize);
continue;
}
switch (bType) {
case 0: /* Main */
switch (bTag) {
case 8: /* Input */
if (!(s->kindset & (1 << hid_input)))
continue;
c->kind = hid_input;
c->flags = dval;
ret:
if (c->flags & HIO_VARIABLE) {
s->multimax = c->report_count;
s->multi = 0;
c->report_count = 1;
if (s->minset) {
for (i = c->usage_minimum;
i <= c->usage_maximum;
i++) {
s->usages[s->nusage] = i;
if (s->nusage < MAXUSAGE-1)
s->nusage++;
}
s->minset = 0;
}
goto top;
} else {
if (s->minset)
c->usage = c->usage_minimum;
*h = *c;
h->next = 0;
c->pos += c->report_size * c->report_count;
hid_clear_local(c);
s->minset = 0;
return (1);
}
case 9: /* Output */
if (!(s->kindset & (1 << hid_output)))
continue;
c->kind = hid_output;
c->flags = dval;
goto ret;
case 10: /* Collection */
c->kind = hid_collection;
c->collection = dval;
c->collevel++;
*h = *c;
hid_clear_local(c);
s->nusage = 0;
return (1);
case 11: /* Feature */
if (!(s->kindset & (1 << hid_feature)))
continue;
c->kind = hid_feature;
c->flags = dval;
goto ret;
case 12: /* End collection */
c->kind = hid_endcollection;
c->collevel--;
*h = *c;
hid_clear_local(c);
s->nusage = 0;
return (1);
default:
printf("Main bTag=%d\n", bTag);
break;
}
break;
case 1: /* Global */
switch (bTag) {
case 0:
c->_usage_page = dval << 16;
break;
case 1:
c->logical_minimum = dval;
break;
case 2:
c->logical_maximum = dval;
break;
case 3:
c->physical_maximum = dval;
break;
case 4:
c->physical_maximum = dval;
break;
case 5:
c->unit_exponent = dval;
break;
case 6:
c->unit = dval;
break;
case 7:
c->report_size = dval;
break;
case 8:
c->report_ID = dval;
break;
case 9:
c->report_count = dval;
break;
case 10: /* Push */
hi = malloc(sizeof *hi);
*hi = s->cur;
c->next = hi;
break;
case 11: /* Pop */
hi = c->next;
s->cur = *hi;
free(hi);
break;
default:
printf("Global bTag=%d\n", bTag);
break;
}
break;
case 2: /* Local */
switch (bTag) {
case 0:
if (bSize == 1)
dval = c->_usage_page | (dval&0xff);
else if (bSize == 2)
dval = c->_usage_page | (dval&0xffff);
c->usage = dval;
if (s->nusage < MAXUSAGE)
s->usages[s->nusage++] = dval;
/* else XXX */
break;
case 1:
s->minset = 1;
if (bSize == 1)
dval = c->_usage_page | (dval&0xff);
else if (bSize == 2)
dval = c->_usage_page | (dval&0xffff);
c->usage_minimum = dval;
break;
case 2:
if (bSize == 1)
dval = c->_usage_page | (dval&0xff);
else if (bSize == 2)
dval = c->_usage_page | (dval&0xffff);
c->usage_maximum = dval;
break;
case 3:
c->designator_index = dval;
break;
case 4:
c->designator_minimum = dval;
break;
case 5:
c->designator_maximum = dval;
break;
case 7:
c->string_index = dval;
break;
case 8:
c->string_minimum = dval;
break;
case 9:
c->string_maximum = dval;
break;
case 10:
c->set_delimiter = dval;
break;
default:
printf("Local bTag=%d\n", bTag);
break;
}
break;
default:
printf("default bType=%d\n", bType);
break;
}
}
}
int
hid_report_size(u_char *buf, int len, enum hid_kind k)
{
struct hid_data *d;
struct hid_item h;
int size, id;
id = 0;
memset(&h, 0, sizeof h);
for (d = hid_start_parse(buf, len, 1<<k); hid_get_item(d, &h); )
if (h.report_ID != 0)
id = 8;
hid_end_parse(d);
size = h.pos + id;
return ((size + 7) / 8);
}
struct usage_in_page {
char *name;
int usage;
};
struct usage_page {
char *name;
int usage;
struct usage_in_page *page_contents;
int pagesize, pagesizemax;
} *pages;
int npages, npagesmax;
void
dump_hid_table(void)
{
int i, j;
for (i = 0; i < npages; i++) {
printf("%d\t%s\n", pages[i].usage, pages[i].name);
for (j = 0; j < pages[i].pagesize; j++) {
printf("\t%d\t%s\n", pages[i].page_contents[j].usage,
pages[i].page_contents[j].name);
}
}
}
void
init_hid(char *hidname)
{
FILE *f;
char line[100], name[100], *p, *n;
int no;
int lineno;
struct usage_page *curpage = 0;
f = fopen(hidname, "r");
if (f == NULL)
err(1, "%s", hidname);
for (lineno = 1; ; lineno++) {
if (fgets(line, sizeof line, f) == NULL)
break;
if (line[0] == '#' || line[0] == '\n')
continue;
if (sscanf(line, " 0x%x %[^\n]", &no, name) != 2 &&
sscanf(line, " %d %[^\n]", &no, name) != 2)
errx(1, "file %s, line %d, syntax error\n",
hidname, lineno);
for (p = name; *p; p++)
if (isspace(*p) || *p == '.')
*p = '_';
n = strdup(name);
if (!n)
err(1, "strdup");
if (isspace(line[0])) {
if (!curpage)
errx(1, "file %s, line %d, syntax error\n",
hidname, lineno);
if (curpage->pagesize >= curpage->pagesizemax) {
curpage->pagesizemax += 10;
curpage->page_contents =
realloc(curpage->page_contents,
curpage->pagesizemax *
sizeof (struct usage_in_page));
if (!curpage->page_contents)
err(1, "realloc");
}
curpage->page_contents[curpage->pagesize].name = n;
curpage->page_contents[curpage->pagesize].usage = no;
curpage->pagesize++;
} else {
if (npages >= npagesmax) {
if (pages == 0) {
npagesmax = 5;
pages = malloc(npagesmax *
sizeof (struct usage_page));
} else {
npagesmax += 5;
pages = realloc(pages,
npagesmax *
sizeof (struct usage_page));
}
if (!pages)
err(1, "alloc");
}
curpage = &pages[npages++];
curpage->name = n;
curpage->usage = no;
curpage->pagesize = 0;
curpage->pagesizemax = 10;
curpage->page_contents =
malloc(curpage->pagesizemax *
sizeof (struct usage_in_page));
if (!curpage->page_contents)
err(1, "malloc");
}
}
fclose(f);
/*dump_hid_table();*/
}
char *
usage_page(int i)
{
static char b[10];
int k;
if (!pages)
errx(1, "no hid table\n");
for (k = 0; k < npages; k++)
if (pages[k].usage == i)
return pages[k].name;
sprintf(b, "x%x", i);
return b;
}
char *
usage_in_page(unsigned int u)
{
int page = HID_PAGE(u);
int i = HID_USAGE(u);
static char b[10];
int j, k;
for (k = 0; k < npages; k++)
if (pages[k].usage == page)
break;
if (k >= npages)
goto bad;
for (j = 0; j < pages[k].pagesize; j++)
if (pages[k].page_contents[j].usage == i)
return pages[k].page_contents[j].name;
bad:
sprintf(b, "x%x", i);
return b;
}

View File

@ -0,0 +1,86 @@
/* $NetBSD: hidsubr.h,v 1.1 1998/07/13 11:14:04 augustss Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
* All rights reserved.
*
* Author: Lennart Augustsson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
enum hid_kind {
hid_input, hid_output, hid_feature, hid_collection, hid_endcollection
};
struct hid_item {
/* Global */
int32_t _usage_page;
int32_t logical_minimum;
int32_t logical_maximum;
int32_t physical_minimum;
int32_t physical_maximum;
int32_t unit_exponent;
int32_t unit;
int32_t report_size;
int32_t report_ID;
int32_t report_count;
/* Local */
u_int32_t usage;
int32_t usage_minimum;
int32_t usage_maximum;
int32_t designator_index;
int32_t designator_minimum;
int32_t designator_maximum;
int32_t string_index;
int32_t string_minimum;
int32_t string_maximum;
int32_t set_delimiter;
/* Misc */
int32_t collection;
int collevel;
enum hid_kind kind;
u_int32_t flags;
/* Absolute data position (bits) */
u_int32_t pos;
/* */
struct hid_item *next;
};
#define HID_PAGE(u) ((u) >> 16)
#define HID_USAGE(u) ((u) & 0xffff)
struct hid_data *hid_start_parse(u_char *d, int len, int kindset);
void hid_end_parse(struct hid_data *s);
int hid_get_item(struct hid_data *s, struct hid_item *h);
int hid_report_size(u_char *buf, int len, enum hid_kind k);
char *usage_page(int i);
char *usage_in_page(unsigned int u);
void init_hid(char *file);
void dump_hid_table(void);

View File

@ -0,0 +1,92 @@
#
# USB HID usage table
# Syntax:
# * lines that do not start with a white space give the number and name of
# a usage page.
# * lines that start with a white space give the number and name of
# a usage with the last given page.
#
1 Generic Desktop Controls
0x01 Pointer
0x02 Mouse
0x04 Joystick
0x05 Game Pad
0x06 Keyboard
0x07 Keyboard
0x30 X
0x31 Y
0x32 Z
0x35 Rz
0x36 Slider
0x38 Wheel
0x39 Hat switch
2 Simulation Controls
3 VR Controls
4 Sport Controls
5 Game Controls
7 Keyboard/Keypad
8 LEDs
0x01 Num Lock
0x02 Caps Lock
0x03 Scroll Lock
0x04 Compose
9 Button
1 Button 1
2 Button 2
3 Button 3
4 Button 4
5 Button 5
6 Button 6
7 Button 7
8 Button 8
9 Button 9
10 Button 10
11 Button 11
12 Button 12
13 Button 13
14 Button 14
15 Button 15
16 Button 16
17 Button 17
18 Button 18
19 Button 19
20 Button 20
21 Button 21
22 Button 22
23 Button 23
24 Button 24
25 Button 25
26 Button 26
27 Button 27
28 Button 28
29 Button 29
30 Button 30
31 Button 31
32 Button 32
33 Button 33
34 Button 34
35 Button 35
36 Button 36
37 Button 37
38 Button 38
39 Button 39
40 Button 40
41 Button 41
42 Button 42
43 Button 43
44 Button 44
45 Button 45
46 Button 46
47 Button 47
48 Button 48
49 Button 49
50 Button 50
10 Ordinal
11 Telephony
12 Consumer
0x01 Consumer Control
0xe5 Bass Boost
0xe9 Volume Increment
0xea Volume Decrement
13 Digitizer

308
usr.bin/usbhidctl/usbhid.c Normal file
View File

@ -0,0 +1,308 @@
/* $NetBSD: usbhid.c,v 1.1 1998/07/13 11:14:04 augustss Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
* All rights reserved.
*
* Author: Lennart Augustsson
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <err.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbhid.h>
#include "hidsubr.h"
#define HIDTABLE "/usr/share/misc/usb_hid_usages"
#define USBDEV "/dev/uhid0"
int verbose = 0;
void prbits(int bits, char **strs, int n);
void usage(void);
void dumpitems(u_char *buf, int len);
void rev(struct hid_item **p);
u_long getdata(u_char *buf, int hpos, int hsize, int sign);
void prdata(u_char *buf, struct hid_item *h);
void dumpdata(int f, u_char *buf, int len, int loop);
void
prbits(int bits, char **strs, int n)
{
int i;
for(i = 0; i < n; i++, bits >>= 1)
if (strs[i*2])
printf("%s%s", i == 0 ? "" : ", ", strs[i*2 + (bits&1)]);
}
void
usage(void)
{
extern char *__progname;
fprintf(stderr, "Usage: %s -f device [-l] [-n] [-r] [-t tablefile] [-v]\n", __progname);
exit(1);
}
void
dumpitems(u_char *buf, int len)
{
struct hid_data *d;
struct hid_item h;
for (d = hid_start_parse(buf, len, ~0); hid_get_item(d, &h); ) {
switch (h.kind) {
case hid_collection:
printf("Collection page=%s usage=%s\n",
usage_page(HID_PAGE(h.usage)),
usage_in_page(h.usage));
break;
case hid_endcollection:
printf("End collection\n");
break;
case hid_input:
printf("Input size=%d count=%d page=%s usage=%s%s\n",
h.report_size, h.report_count,
usage_page(HID_PAGE(h.usage)),
usage_in_page(h.usage),
h.flags & HIO_CONST ? " Const" : "");
break;
case hid_output:
printf("Output size=%d count=%d page=%s usage=%s%s\n",
h.report_size, h.report_count,
usage_page(HID_PAGE(h.usage)),
usage_in_page(h.usage),
h.flags & HIO_CONST ? " Const" : "");
break;
case hid_feature:
printf("Feature size=%d count=%d page=%s usage=%s%s\n",
h.report_size, h.report_count,
usage_page(HID_PAGE(h.usage)),
usage_in_page(h.usage),
h.flags & HIO_CONST ? " Const" : "");
break;
}
}
hid_end_parse(d);
printf("Total input size %d bytes\n",
hid_report_size(buf, len, hid_input));
printf("Total output size %d bytes\n",
hid_report_size(buf, len, hid_output));
printf("Total feature size %d bytes\n",
hid_report_size(buf, len, hid_feature));
}
void
rev(struct hid_item **p)
{
struct hid_item *cur, *prev, *next;
prev = 0;
cur = *p;
while(cur != 0) {
next = cur->next;
cur->next = prev;
prev = cur;
cur = next;
}
*p = prev;
}
u_long
getdata(u_char *buf, int hpos, int hsize, int sign)
{
u_long data;
int i, size, s;
data = 0;
/*printf("hpos=%d hsize=%d bytes=%d\n", hpos, hsize, (hsize+14)/8);*/
s = hpos/8;
for (i = hpos; i < hpos+hsize; i += 8) {
/*printf("data=%x i=%d buf[i/8]=%x %x ndata=%x\n",data, i, buf[i/8], buf[i/8] << (i/8)*8, data | buf[i/8] << (i/8)*8);*/
data |= buf[i / 8] << (i/8-s)*8;
}
data >>= (hpos % 8);
data &= (1 << hsize) - 1;
size = 32 - hsize;
if (sign) {
/* Need to sign extend */
data = ((long)data << size) >> size;
}
return data;
}
void
prdata(u_char *buf, struct hid_item *h)
{
u_long data;
int i, pos;
/*for(i =0; i < 8; i++)printf(" %02x", buf[i]); */
pos = h->pos;
for (i = 0; i < h->report_count; i++) {
data = getdata(buf, pos, h->report_size,
h->logical_minimum < 0);
if (h->logical_minimum < 0)
printf("%ld", (long)data);
else
printf("%lu", data);
pos += h->report_size;
}
}
void
dumpdata(int f, u_char *buf, int len, int loop)
{
struct hid_data *d;
struct hid_item h, *hids, *n;
int r, dlen;
u_char *dbuf;
static int one = 1;
u_int32_t colls[100];
int sp = 0;
hids = 0;
for (d = hid_start_parse(buf, len, 1<<hid_input);
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;
/*printf("pos=%d %d\n", h.pos, h.report_size);*/
h.next = hids;
h.collection = colls[sp];
hids = malloc(sizeof *hids);
*hids = h;
}
hid_end_parse(d);
rev(&hids);
dlen = hid_report_size(buf, len, hid_input);
dbuf = malloc(dlen);
if (!loop)
if (ioctl(f, USB_SET_IMMED, &one) < 0)
err(1, "USB_SET_IMMED");
do {
r = read(f, dbuf, dlen);
if (r != dlen) {
err(1, "bad read %d != %d", r, dlen);
}
for (n = hids; n; n = n->next) {
printf("%s.%s.",
usage_page(HID_PAGE(n->collection)),
usage_in_page(n->collection));
printf("%s.%s=",
usage_page(HID_PAGE(n->usage)),
usage_in_page(n->usage));
prdata(dbuf, n);
if (verbose)
printf(" [%d - %d]",
n->logical_minimum, n->logical_maximum);
printf("\n");
}
if (loop)
printf("\n");
} while (loop);
free(dbuf);
}
int
main(int argc, char **argv)
{
int f, r;
char *dev = 0;
int ch;
extern char *optarg;
extern int optind;
struct usb_ctl_report_desc rep;
int repdump = 0;
int loop = 0;
int nothing = 0;
char *table = HIDTABLE;
while ((ch = getopt(argc, argv, "f:lnrt:v")) != -1) {
switch(ch) {
case 'f':
dev = optarg;
break;
case 'l':
loop ^= 1;
break;
case 'n':
nothing++;
break;
case 'r':
repdump++;
break;
case 't':
table = optarg;
break;
case 'v':
verbose++;
break;
case '?':
default:
usage();
}
}
argc -= optind;
argv += optind;
if (argc != 0 || dev == 0)
usage();
init_hid(table);
f = open(dev, O_RDWR);
if (f < 0)
err(1, "%s", dev);
rep.size = 0;
r = ioctl(f, USB_GET_REPORT_DESC, &rep);
if (r)
errx(1, "USB_GET_REPORT_DESC");
if (repdump) {
printf("Report descriptor\n");
dumpitems(rep.data, rep.size);
}
if (!nothing)
dumpdata(f, rep.data, rep.size, loop);
exit(0);
}

View File

@ -0,0 +1,80 @@
.\" $NetBSD: usbhidctl.1,v 1.1 1998/07/13 11:14:04 augustss Exp $
.\" Copyright (c) 1998 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" Author: Lennart Augustsson
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by the NetBSD
.\" Foundation, Inc. and its contributors.
.\" 4. Neither the name of The NetBSD Foundation nor the names of its
.\" contributors may be used to endorse or promote products derived
.\" from this software without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd July 12, 1998
.Dt USBHIDCTL 1
.Os
.Sh NAME
.Nm usbhidctl
.Nd manipulate USB HID devices
.Sh SYNOPSIS
.Nm
.Op Fl f Ar device
.Op Fl l
.Op Fl n
.Op Fl r
.Op Fl t Ar table
.Op Fl v
.Sh DESCRIPTION
.Nm
can be used to dump the state of a USB HID (Human Interface Device).
.Pp
The options are as follows:
.Bl -tag -width Ds
.It Fl f Ar device
Specify a path name for device to operate on.
.It Fl l
Loop and dump the device data every time it changes.
.It Fl n
Do not dump any data.
.It Fl r
Dump the report descriptor.
.It Fl t Ar table
Specify a path name for the HID usage table file.
.It Fl v
Be verbose.
.El
.Sh FILES
.Pa /usr/share/misc/usb_hid_usages
The default HID usage table.
.Sh BUGS
The HID usage table is very incomplete.
.Sh SEE ALSO
.Xr usb 4 ,
.Xr uhid 4
.Sh HISTORY
The
.Nm
command appeared in
.Nx 1.4 .