summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornate <nate@openbsd.org>2002-05-10 00:09:17 +0000
committernate <nate@openbsd.org>2002-05-10 00:09:17 +0000
commit7517eab27d5826c1a463a3cd45d021e17e9bb423 (patch)
treec8ffa8a4d8a2766dab08a2b30c66addee732307f
parentprototype open_socket() (diff)
downloadwireguard-openbsd-7517eab27d5826c1a463a3cd45d021e17e9bb423.tar.xz
wireguard-openbsd-7517eab27d5826c1a463a3cd45d021e17e9bb423.zip
Update usb userland stuff to reflect hid changes in the kernel.
This adds the new program usbhidaction which can be used to assign actions to events that occur on a uhid device. For example, you can now make the volume buttons on some newer keyboards actually do something.
-rw-r--r--lib/libusbhid/data.c4
-rw-r--r--lib/libusbhid/descr.c4
-rw-r--r--lib/libusbhid/parse.c147
-rw-r--r--lib/libusbhid/usage.c13
-rw-r--r--lib/libusbhid/usbhid.336
-rw-r--r--lib/libusbhid/usbhid.h16
-rw-r--r--lib/libusbhid/usbvar.h4
-rw-r--r--usr.bin/usbhidaction/Makefile10
-rw-r--r--usr.bin/usbhidaction/usbhidaction.1137
-rw-r--r--usr.bin/usbhidaction/usbhidaction.c439
-rw-r--r--usr.bin/usbhidctl/usbhid.c447
-rw-r--r--usr.bin/usbhidctl/usbhidctl.199
-rw-r--r--usr.sbin/usbdevs/usbdevs.813
-rw-r--r--usr.sbin/usbdevs/usbdevs.c45
14 files changed, 1148 insertions, 266 deletions
diff --git a/lib/libusbhid/data.c b/lib/libusbhid/data.c
index 57571967fe4..371fd99dfee 100644
--- a/lib/libusbhid/data.c
+++ b/lib/libusbhid/data.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: data.c,v 1.1 2001/12/30 07:04:38 pvalchev Exp $ */
-/* $NetBSD: data.c,v 1.8 2000/04/02 11:10:53 augustss Exp $ */
+/* $OpenBSD: data.c,v 1.2 2002/05/10 00:09:17 nate Exp $ */
+/* $NetBSD: data.c,v 1.1 2001/12/28 17:45:26 augustss Exp $ */
/*
* Copyright (c) 1999 Lennart Augustsson <augustss@netbsd.org>
diff --git a/lib/libusbhid/descr.c b/lib/libusbhid/descr.c
index 7366784338b..35095a406c6 100644
--- a/lib/libusbhid/descr.c
+++ b/lib/libusbhid/descr.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: descr.c,v 1.2 2002/05/02 20:12:07 nate Exp $ */
-/* $NetBSD: descr.c,v 1.9 2000/09/24 02:13:24 augustss Exp $ */
+/* $OpenBSD: descr.c,v 1.3 2002/05/10 00:09:17 nate Exp $ */
+/* $NetBSD: descr.c,v 1.2 2002/02/20 20:31:07 christos Exp $ */
/*
* Copyright (c) 1999 Lennart Augustsson <augustss@netbsd.org>
diff --git a/lib/libusbhid/parse.c b/lib/libusbhid/parse.c
index 737812254b1..4bc72344a5a 100644
--- a/lib/libusbhid/parse.c
+++ b/lib/libusbhid/parse.c
@@ -1,8 +1,8 @@
-/* $OpenBSD: parse.c,v 1.1 2001/12/30 07:04:38 pvalchev Exp $ */
-/* $NetBSD: parse.c,v 1.11 2000/09/24 02:19:54 augustss Exp $ */
+/* $OpenBSD: parse.c,v 1.2 2002/05/10 00:09:17 nate Exp $ */
+/* $NetBSD: parse.c,v 1.2 2001/12/29 20:44:22 augustss Exp $ */
/*
- * Copyright (c) 1999 Lennart Augustsson <augustss@netbsd.org>
+ * Copyright (c) 1999, 2001 Lennart Augustsson <augustss@netbsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -46,18 +46,30 @@ struct hid_data {
unsigned int usages[MAXUSAGE];
int nusage;
int minset;
+ int logminsize;
int multi;
int multimax;
int kindset;
+ int reportid;
- /* Absolute data position (bits) for input/output/feature.
- Assumes that hid_input, hid_output and hid_feature have
- values 0, 1 and 2. */
- unsigned int kindpos[3];
+ /*
+ * The start of collection item has no report ID set, so save
+ * it until we know the ID.
+ */
+ hid_item_t savedcoll;
+ u_char hassavedcoll;
+ /*
+ * Absolute data position (bits) for input/output/feature.
+ * Assumes that hid_input, hid_output and hid_feature have
+ * values 0, 1 and 2.
+ */
+ unsigned int kindpos[3];
};
static int min(int x, int y) { return x < y ? x : y; }
+static int hid_get_item_raw(hid_data_t s, hid_item_t *h);
+
static void
hid_clear_local(hid_item_t *c)
{
@@ -72,17 +84,21 @@ hid_clear_local(hid_item_t *c)
c->string_minimum = 0;
c->string_maximum = 0;
c->set_delimiter = 0;
+ c->report_size = 0;
}
hid_data_t
-hid_start_parse(report_desc_t d, int kindset)
+hid_start_parse(report_desc_t d, int kindset, int id)
{
- struct hid_data *s = malloc(sizeof *s);
+ struct hid_data *s;
+ s = malloc(sizeof *s);
memset(s, 0, sizeof *s);
s->start = s->p = d->data;
s->end = d->data + d->size;
s->kindset = kindset;
+ s->reportid = id;
+ s->hassavedcoll = 0;
return (s);
}
@@ -101,12 +117,38 @@ hid_end_parse(hid_data_t s)
int
hid_get_item(hid_data_t s, hid_item_t *h)
{
+ int r;
+
+ for (;;) {
+ r = hid_get_item_raw(s, h);
+ if (r <= 0)
+ break;
+ if (h->report_ID == s->reportid || s->reportid == -1)
+ break;
+ }
+ return (r);
+}
+
+#define REPORT_SAVED_COLL \
+ do { \
+ if (s->hassavedcoll) { \
+ *h = s->savedcoll; \
+ h->report_ID = c->report_ID; \
+ s->hassavedcoll = 0; \
+ return (1); \
+ } \
+ } while(/*LINTED*/ 0)
+
+static int
+hid_get_item_raw(hid_data_t s, hid_item_t *h)
+{
hid_item_t *c;
unsigned int bTag = 0, bType = 0, bSize;
unsigned char *data;
int dval;
unsigned char *p;
hid_item_t *hi;
+ hid_item_t nc;
int i;
hid_kind_t retkind;
@@ -114,13 +156,21 @@ hid_get_item(hid_data_t s, hid_item_t *h)
top:
if (s->multimax) {
+ REPORT_SAVED_COLL;
+ if (c->logical_minimum >= c->logical_maximum) {
+ if (s->logminsize == 1)
+ c->logical_minimum =(int8_t)c->logical_minimum;
+ else if (s->logminsize == 2)
+ c->logical_minimum =(int16_t)c->logical_minimum;
+ }
if (s->multi < s->multimax) {
c->usage = s->usages[min(s->multi, s->nusage-1)];
s->multi++;
*h = *c;
-
- /* 'multimax' is only non-zero if the current
- item kind is input/output/feature */
+ /*
+ * 'multimax' is only non-zero if the current
+ * item kind is input/output/feature
+ */
h->pos = s->kindpos[c->kind];
s->kindpos[c->kind] += c->report_size;
h->next = 0;
@@ -163,12 +213,12 @@ hid_get_item(hid_data_t s, hid_item_t *h)
dval = 0;
break;
case 1:
- dval = (int8_t)*data++;
+ dval = /*(int8_t)*/*data++;
break;
case 2:
dval = *data++;
dval |= *data++ << 8;
- dval = (int16_t)dval;
+ dval = /*(int16_t)*/dval;
break;
case 4:
dval = *data++;
@@ -205,6 +255,8 @@ hid_get_item(hid_data_t s, hid_item_t *h)
if (s->nusage < MAXUSAGE-1)
s->nusage++;
}
+ c->usage_minimum = 0;
+ c->usage_maximum = 0;
s->minset = 0;
}
goto top;
@@ -214,7 +266,8 @@ hid_get_item(hid_data_t s, hid_item_t *h)
*h = *c;
h->next = 0;
h->pos = s->kindpos[c->kind];
- s->kindpos[c->kind] += c->report_size * c->report_count;
+ s->kindpos[c->kind] +=
+ c->report_size * c->report_count;
hid_clear_local(c);
s->minset = 0;
return (1);
@@ -226,15 +279,25 @@ hid_get_item(hid_data_t s, hid_item_t *h)
c->kind = hid_collection;
c->collection = dval;
c->collevel++;
- *h = *c;
+ nc = *c;
hid_clear_local(c);
- c->report_ID = NO_REPORT_ID;
+ /*c->report_ID = NO_REPORT_ID;*/
s->nusage = 0;
- return (1);
+ if (s->hassavedcoll) {
+ *h = s->savedcoll;
+ h->report_ID = nc.report_ID;
+ s->savedcoll = nc;
+ return (1);
+ } else {
+ s->hassavedcoll = 1;
+ s->savedcoll = nc;
+ }
+ break;
case 11: /* Feature */
retkind = hid_feature;
goto ret;
case 12: /* End collection */
+ REPORT_SAVED_COLL;
c->kind = hid_endcollection;
c->collevel--;
*h = *c;
@@ -244,6 +307,7 @@ hid_get_item(hid_data_t s, hid_item_t *h)
default:
return (-2);
}
+ break;
case 1: /* Global */
switch (bTag) {
@@ -252,6 +316,7 @@ hid_get_item(hid_data_t s, hid_item_t *h)
break;
case 1:
c->logical_minimum = dval;
+ s->logminsize = bSize;
break;
case 2:
c->logical_maximum = dval;
@@ -273,6 +338,9 @@ hid_get_item(hid_data_t s, hid_item_t *h)
break;
case 8:
c->report_ID = dval;
+ s->kindpos[hid_input] =
+ s->kindpos[hid_output] =
+ s->kindpos[hid_feature] = 0;
break;
case 9:
c->report_count = dval;
@@ -294,29 +362,17 @@ hid_get_item(hid_data_t s, hid_item_t *h)
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;
+ c->usage = c->_usage_page | dval;
if (s->nusage < MAXUSAGE)
- s->usages[s->nusage++] = dval;
+ s->usages[s->nusage++] = c->usage;
/* 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;
+ c->usage_minimum = c->_usage_page | 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;
+ c->usage_maximum = c->_usage_page | dval;
break;
case 3:
c->designator_index = dval;
@@ -350,35 +406,30 @@ hid_get_item(hid_data_t s, hid_item_t *h)
}
int
-hid_report_size(report_desc_t r, enum hid_kind k, int *idp)
+hid_report_size(report_desc_t r, enum hid_kind k, int id)
{
struct hid_data *d;
hid_item_t h;
- int size, id;
+ int size;
- id = 0;
- if (idp)
- *idp = 0;
memset(&h, 0, sizeof h);
- for (d = hid_start_parse(r, 1<<k); hid_get_item(d, &h); ) {
- if (h.report_ID != NO_REPORT_ID) {
- if (idp)
- *idp = h.report_ID;
- id = 8;
+ size = 0;
+ for (d = hid_start_parse(r, 1<<k, id); hid_get_item(d, &h); ) {
+ if (h.report_ID == id && h.kind == k) {
+ size = d->kindpos[k];
}
}
-
- size = d->kindpos[k] + id;
hid_end_parse(d);
return ((size + 7) / 8);
}
int
-hid_locate(report_desc_t desc, unsigned int u, enum hid_kind k, hid_item_t *h)
+hid_locate(report_desc_t desc, unsigned int u, enum hid_kind k,
+ hid_item_t *h, int id)
{
hid_data_t d;
- for (d = hid_start_parse(desc, 1<<k); hid_get_item(d, h); ) {
+ for (d = hid_start_parse(desc, 1<<k, id); hid_get_item(d, h); ) {
if (h->kind == k && !(h->flags & HIO_CONST) && h->usage == u) {
hid_end_parse(d);
return (1);
diff --git a/lib/libusbhid/usage.c b/lib/libusbhid/usage.c
index fb36769d243..e5122c1745e 100644
--- a/lib/libusbhid/usage.c
+++ b/lib/libusbhid/usage.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: usage.c,v 1.1 2001/12/30 07:04:38 pvalchev Exp $ */
-/* $NetBSD: usage.c,v 1.11 2001/01/09 15:59:47 augustss Exp $ */
+/* $OpenBSD: usage.c,v 1.2 2002/05/10 00:09:17 nate Exp $ */
+/* $NetBSD: usage.c,v 1.1 2001/12/28 17:45:27 augustss Exp $ */
/*
* Copyright (c) 1999 Lennart Augustsson <augustss@netbsd.org>
@@ -163,7 +163,7 @@ hid_usage_page(int i)
for (k = 0; k < npages; k++)
if (pages[k].usage == i)
return pages[k].name;
- snprintf(b, sizeof b, "0x%04x", i);
+ sprintf(b, "0x%04x", i);
return b;
}
@@ -183,7 +183,7 @@ hid_usage_in_page(unsigned int u)
for (j = 0; j < pages[k].pagesize; j++) {
us = pages[k].page_contents[j].usage;
if (us == -1) {
- snprintf(b, sizeof b, "%s %d",
+ snprintf(b, sizeof b, "%s %d",
pages[k].page_contents[j].name, i);
return b;
}
@@ -191,7 +191,7 @@ hid_usage_in_page(unsigned int u)
return pages[k].page_contents[j].name;
}
bad:
- snprintf(b, sizeof b, "0x%04x", i);
+ sprintf(b, "0x%04x", i);
return b;
}
@@ -213,10 +213,11 @@ hid_parse_usage_page(const char *name)
int
hid_parse_usage_in_page(const char *name)
{
- const char *sep = strchr(name, ':');
+ const char *sep;
int k, j;
unsigned int l;
+ sep = strchr(name, ':');
if (sep == NULL)
return -1;
l = sep - name;
diff --git a/lib/libusbhid/usbhid.3 b/lib/libusbhid/usbhid.3
index 066d3a8da34..5d2c042a1dd 100644
--- a/lib/libusbhid/usbhid.3
+++ b/lib/libusbhid/usbhid.3
@@ -1,7 +1,7 @@
-.\" $OpenBSD: usbhid.3,v 1.3 2002/05/01 08:03:30 mpech Exp $
-.\" $NetBSD: usb.3,v 1.14 2001/04/09 12:09:49 wiz Exp $
+.\" $OpenBSD: usbhid.3,v 1.4 2002/05/10 00:09:17 nate Exp $
+.\" $NetBSD: usbhid.3,v 1.5 2002/02/07 07:00:52 ross Exp $
.\"
-.\" Copyright (c) 1999 Lennart Augustsson <augustss@netbsd.org>
+.\" Copyright (c) 1999, 2001 Lennart Augustsson <augustss@netbsd.org>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd May 11, 1999
+.Dd December 29, 2001
.Dt USBHID 3
.Os
.Sh NAME
@@ -45,7 +45,7 @@
.Nm hid_set_data
.Nd USB HID access routines
.Sh SYNOPSIS
-.Fd #include <usbhid.h>
+.Fd #include \*[Lt]usbhid.h\*[Gt]
.Ft report_desc_t
.Fn hid_get_report_desc "int file"
.Ft report_desc_t
@@ -53,15 +53,15 @@
.Ft void
.Fn hid_dispose_report_desc "report_desc_t d"
.Ft hid_data_t
-.Fn hid_start_parse "report_desc_t d" "int kindset"
+.Fn hid_start_parse "report_desc_t d" "int kindset" "int id"
.Ft void
.Fn hid_end_parse "hid_data_t s"
.Ft int
.Fn hid_get_item "hid_data_t s" "hid_item_t *h"
.Ft int
-.Fn hid_report_size "report_desc_t d" "hid_kind_t k" "int *idp"
+.Fn hid_report_size "report_desc_t d" "hid_kind_t k" "int id"
.Ft int
-.Fn hid_locate "report_desc_t d" "u_int usage" "hid_kind_t k" "hid_item_t *h"
+.Fn hid_locate "report_desc_t d" "u_int usage" "hid_kind_t k" "hid_item_t *h" "int id"
.Ft char *
.Fn hid_usage_page "int i"
.Ft char *
@@ -115,11 +115,13 @@ To parse the report descriptor the
function should be called with a report descriptor and a set that
describes which items that are interesting.
The set is obtained by or-ing together values
-.Fa "(1 << k)"
+.Fa "(1 \*[Lt]\*[Lt] k)"
where
.Fa k
is an item of type
.Fa hid_kind_t .
+The report id (if present) is given by
+.Fa id .
The function returns
.Fa NULL
if the initialization fails, otherwise an opaque value to be used
@@ -140,7 +142,7 @@ will be filled with the relevant data for the item.
The definition of
.Fa hid_item_t
can be found in
-.Pa <usbhid.h>
+.Pa \*[Lt]usbhid.h\*[Gt]
and the meaning of the components in the USB HID documentation.
.Pp
Data should be read/written to the device in the size of
@@ -148,9 +150,8 @@ the report.
The size of a report (of a certain kind) can be computed by the
.Fn hid_report_size
function.
-If the report is prefixed by an ID byte it is stored at
-.Fa idp ,
-otherwise it will contain 0.
+If the report is prefixed by an ID byte it is given by
+.Fa id .
.Pp
To locate a single item the
.Fn hid_locate
@@ -192,18 +193,15 @@ function extracts the value of the item.
Conversely
.Fn hid_set_data
can be used to put data into a report (which must be zeroed first).
-.Sh EXAMPLES
-Not yet.
.Sh FILES
.Pa /usr/share/misc/usb_hid_usages
The default HID usage table.
-.Sh BUGS
-This man page is woefully incomplete.
+.\" .Sh EXAMPLES
.Sh SEE ALSO
The
.Tn USB
specifications can be found at:
-.Dv http://www.usb.org/developers/docs.html
+.Dv http://www.usb.org/developers/docs.html .
.Pp
.Xr uhid 4 ,
.Xr usb 4
@@ -212,3 +210,5 @@ The
.Nm
library first appeared in
.Ox 3.0 .
+.Sh BUGS
+This man page is woefully incomplete.
diff --git a/lib/libusbhid/usbhid.h b/lib/libusbhid/usbhid.h
index 57c0b83bde9..7172ca5fac8 100644
--- a/lib/libusbhid/usbhid.h
+++ b/lib/libusbhid/usbhid.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: usbhid.h,v 1.1 2001/12/30 07:04:38 pvalchev Exp $ */
+/* $OpenBSD: usbhid.h,v 1.2 2002/05/10 00:09:17 nate Exp $ */
/* $NetBSD: usbhid.h,v 1.1 2001/12/28 17:45:27 augustss Exp $ */
/*
@@ -32,8 +32,12 @@ typedef struct report_desc *report_desc_t;
typedef struct hid_data *hid_data_t;
typedef enum hid_kind {
- hid_input, hid_output, hid_feature, hid_collection, hid_endcollection
-}hid_kind_t;
+ hid_input = 0,
+ hid_output = 1,
+ hid_feature = 2,
+ hid_collection,
+ hid_endcollection
+} hid_kind_t;
typedef struct hid_item {
/* Global */
@@ -79,11 +83,11 @@ report_desc_t hid_use_report_desc(unsigned char *data, unsigned int size);
void hid_dispose_report_desc(report_desc_t);
/* Parsing of a HID report descriptor, parse.c: */
-hid_data_t hid_start_parse(report_desc_t d, int kindset);
+hid_data_t hid_start_parse(report_desc_t d, int kindset, int id);
void hid_end_parse(hid_data_t s);
int hid_get_item(hid_data_t s, hid_item_t *h);
-int hid_report_size(report_desc_t d, enum hid_kind k, int *idp);
-int hid_locate(report_desc_t d, unsigned int usage, enum hid_kind k, hid_item_t *h);
+int hid_report_size(report_desc_t d, enum hid_kind k, int id);
+int hid_locate(report_desc_t d, unsigned int usage, enum hid_kind k, hid_item_t *h, int id);
/* Conversion to/from usage names, usage.c: */
const char *hid_usage_page(int i);
diff --git a/lib/libusbhid/usbvar.h b/lib/libusbhid/usbvar.h
index ef23a3d3bfa..224423ea99f 100644
--- a/lib/libusbhid/usbvar.h
+++ b/lib/libusbhid/usbvar.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: usbvar.h,v 1.1 2001/12/30 07:04:38 pvalchev Exp $ */
-/* $NetBSD: usbvar.h,v 1.2 1999/05/11 21:15:46 augustss Exp $ */
+/* $OpenBSD: usbvar.h,v 1.2 2002/05/10 00:09:17 nate Exp $ */
+/* $NetBSD: usbvar.h,v 1.1 2001/12/28 17:45:27 augustss Exp $ */
/*
* Copyright (c) 1999 Lennart Augustsson <augustss@netbsd.org>
diff --git a/usr.bin/usbhidaction/Makefile b/usr.bin/usbhidaction/Makefile
new file mode 100644
index 00000000000..1ce2fe8b7ad
--- /dev/null
+++ b/usr.bin/usbhidaction/Makefile
@@ -0,0 +1,10 @@
+# $OpenBSD: Makefile,v 1.1 2002/05/10 00:09:17 nate Exp $
+# $NetBSD: Makefile,v 1.4 2002/02/02 16:54:26 veego Exp $
+
+PROG= usbhidaction
+SRCS= usbhidaction.c
+
+LDADD+= -lusbhid -lutil
+DPADD+= ${LIBUSBHID} ${LIBUTIL}
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/usbhidaction/usbhidaction.1 b/usr.bin/usbhidaction/usbhidaction.1
new file mode 100644
index 00000000000..9f075b80b13
--- /dev/null
+++ b/usr.bin/usbhidaction/usbhidaction.1
@@ -0,0 +1,137 @@
+.\" $OpenBSD: usbhidaction.1,v 1.1 2002/05/10 00:09:17 nate Exp $
+.\" $NetBSD: usbhidaction.1,v 1.6 2002/01/18 14:38:59 augustss Exp $
+.\"
+.\" Copyright (c) 2000 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Lennart Augustsson (lennart@augustsson.net).
+.\"
+.\" 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 December 29, 2000
+.Dt USBHIDACTION 1
+.Os
+.Sh NAME
+.Nm usbhidaction
+.Nd perform actions according to USB HID controls
+.Sh SYNOPSIS
+.Nm
+.Fl c Ar config-file
+.Op Fl d
+.Op Fl i
+.Fl f Ar device
+.Op Fl v
+.Ar arg ...
+.Sh DESCRIPTION
+.Nm
+can be used to execute commands when certain values appear on HID controls.
+The normal operation for this program is to read the configuration file
+and then become a daemon and execute commands as the HID items specify.
+If a read from the HID device fails the program dies; this will make it
+die when the USB device is unplugged.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl c Ar config-file
+Specify a path name for the config file.
+.It Fl d
+Toggle the daemon flag.
+.It Fl i
+Ignore HID items in the config file that does not exist in the device.
+.It Fl f Ar device
+Specify a path name for the device to operate on. If
+.Ar device
+is numeric, it is taken to be the USB HID device number. If it is a relative
+path, it is taken to be the name of the device under
+.Pa /dev .
+An absolute path is taken to be the literal device pathname.
+.It Fl v
+Be verbose, and do not become a daemon.
+.El
+.Pp
+The config file will be re-read if the process gets a HUP signal.
+.Sh CONFIGURATION
+The configuration file has a very simple format. Each line describes an
+action; if a line begins with a whitespace it is considered a continuation
+of the previous line. Lines beginning with `#' are considered as comments.
+.Pp
+Each line has three parts: a name of a USB HID item, a value for that item,
+and an action. There must be whitespace between the parts.
+.Pp
+The item names are similar to those used by
+.Xr usbhidctl 1 ,
+but each part must be prefixed by its page name.
+.Pp
+The value is simply a numeric value. When the item reports this value
+the action will be performed.
+If the value is `*' it will match any value.
+.Pp
+The action is a normal command that is executed with
+.Xr system 3 .
+Before it is executed some substitution will occur:
+`$n' will be replaced by the nth argument on the
+command line, `$V' will be replaced by the numeric value
+of the HID item, `$N' will be replaced by the name
+of the control, and `$H' will be replaced by the name
+of the HID device.
+.Sh FILES
+.Pa /usr/share/misc/usb_hid_usages
+The HID usage table.
+.Sh EXAMPLES
+The following configuration file can be used to control a pair
+of Philips USB speakers with the HID controls on the speakers.
+.Bd -literal -offset indent
+# Configuration for various Philips USB speakers
+Consumer:Consumer_Control.Consumer:Volume_Up 1
+ mixerctl -f $1 -n -w fea8-i7-master++
+Consumer:Consumer_Control.Consumer:Volume_Down 1
+ mixerctl -f $1 -n -w fea8-i7-master--
+Consumer:Consumer_Control.Consumer:Mute 1
+ mixerctl -f $1 -n -w fea8-i7-mute++
+Consumer:Consumer_Control.Consumer:Channel_Top.Microsoft:Base_Up 1
+ mixerctl -f $1 -n -w fea8-i7-bass++
+Consumer:Consumer_Control.Consumer:Channel_Top.Microsoft:Base_Down 1
+ mixerctl -f $1 -n -w fea8-i7-bass--
+.Ed
+.Pp
+A sample invocation using this configuration would be
+.Bd -literal -offset indent
+usbhidaction -f /dev/uhid1 -c conf /dev/mixer1
+.Ed
+.Sh SEE ALSO
+.Xr usbhidctl 1 ,
+.Xr usbhid 3 ,
+.Xr uhid 4 ,
+.Xr usb 4
+.Sh HISTORY
+The
+.Nm
+command first appeared in
+.Ox 3.2 .
diff --git a/usr.bin/usbhidaction/usbhidaction.c b/usr.bin/usbhidaction/usbhidaction.c
new file mode 100644
index 00000000000..7b218f5e49f
--- /dev/null
+++ b/usr.bin/usbhidaction/usbhidaction.c
@@ -0,0 +1,439 @@
+/* $OpenBSD: usbhidaction.c,v 1.1 2002/05/10 00:09:17 nate Exp $ */
+/* $NetBSD: usbhidaction.c,v 1.7 2002/01/18 14:38:59 augustss Exp $ */
+
+/*
+ * Copyright (c) 2000, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson <lennart@augustsson.net>.
+ *
+ * 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 <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <dev/usb/usb.h>
+#include <dev/usb/usbhid.h>
+#include <usbhid.h>
+#include <util.h>
+#include <syslog.h>
+#include <signal.h>
+
+int verbose = 0;
+int isdemon = 0;
+int reparse = 1;
+
+struct command {
+ struct command *next;
+ int line;
+
+ struct hid_item item;
+ int value;
+ char anyvalue;
+ char *name;
+ char *action;
+};
+struct command *commands;
+
+#define SIZE 4000
+
+void usage(void);
+struct command *parse_conf(const char *, report_desc_t, int, int);
+void docmd(struct command *, int, const char *, int, char **);
+void freecommands(struct command *);
+
+static void
+sighup(int sig)
+{
+ reparse = 1;
+}
+
+int
+main(int argc, char **argv)
+{
+ const char *conf = NULL;
+ const char *dev = NULL;
+ int fd, ch, sz, n, val, i;
+ int demon, ignore;
+ report_desc_t repd;
+ char buf[100];
+ char devnamebuf[PATH_MAX];
+ struct command *cmd;
+ int reportid;
+
+ demon = 1;
+ ignore = 0;
+ while ((ch = getopt(argc, argv, "c:df:iv")) != -1) {
+ switch(ch) {
+ case 'c':
+ conf = optarg;
+ break;
+ case 'd':
+ demon ^= 1;
+ break;
+ case 'i':
+ ignore++;
+ break;
+ case 'f':
+ dev = optarg;
+ break;
+ case 'v':
+ demon = 0;
+ verbose++;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (conf == NULL || dev == NULL)
+ usage();
+
+ hid_init(NULL);
+
+ if (dev[0] != '/') {
+ snprintf(devnamebuf, sizeof(devnamebuf), "/dev/%s%s",
+ isdigit(dev[0]) ? "uhid" : "", dev);
+ dev = devnamebuf;
+ }
+
+ fd = open(dev, O_RDWR);
+ if (fd < 0)
+ err(1, "%s", dev);
+ if (ioctl(fd, USB_GET_REPORT_ID, &reportid) < 0)
+ reportid = -1;
+ repd = hid_get_report_desc(fd);
+ if (repd == NULL)
+ err(1, "hid_get_report_desc() failed\n");
+
+ commands = parse_conf(conf, repd, reportid, ignore);
+
+ sz = hid_report_size(repd, hid_input, reportid);
+
+ if (verbose)
+ printf("report size %d\n", sz);
+ if (sz > sizeof buf)
+ errx(1, "report too large");
+
+ (void)signal(SIGHUP, sighup);
+
+ if (demon) {
+ if (daemon(0, 0) < 0)
+ err(1, "daemon()");
+ pidfile(NULL);
+ isdemon = 1;
+ }
+
+ for(;;) {
+ n = read(fd, buf, sz);
+ if (verbose > 2) {
+ printf("read %d bytes:", n);
+ for (i = 0; i < n; i++)
+ printf(" %02x", buf[i]);
+ printf("\n");
+ }
+ if (n < 0) {
+ if (verbose)
+ err(1, "read");
+ else
+ exit(1);
+ }
+#if 0
+ if (n != sz) {
+ err(2, "read size");
+ }
+#endif
+ for (cmd = commands; cmd; cmd = cmd->next) {
+ val = hid_get_data(buf, &cmd->item);
+ if (cmd->value == val || cmd->anyvalue)
+ docmd(cmd, val, dev, argc, argv);
+ }
+ if (reparse) {
+ struct command *cmds =
+ parse_conf(conf, repd, reportid, ignore);
+ if (cmds) {
+ freecommands(commands);
+ commands = cmds;
+ }
+ reparse = 0;
+ }
+ }
+
+ exit(0);
+}
+
+void
+usage(void)
+{
+ extern char *__progname;
+
+ fprintf(stderr, "Usage: %s -c config_file [-d] -f hid_dev "
+ "[-i] [-v]\n", __progname);
+ exit(1);
+}
+
+static int
+peek(FILE *f)
+{
+ int c;
+
+ c = getc(f);
+ if (c != EOF)
+ ungetc(c, f);
+ return c;
+}
+
+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], action[SIZE];
+ char usage[SIZE], coll[SIZE];
+ struct command *cmd, *cmds;
+ struct hid_data *d;
+ struct hid_item h;
+ int u, lo, hi, range;
+
+
+ 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 %[^\n]", name, value, action) != 3) {
+ 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);
+ }
+ }
+
+ 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\n",
+ conf, line, value);
+ freecommands(cmds);
+ return (NULL);
+ } else {
+ errx(1, "config file `%s', line %d, "
+ "bad value: %s\n",
+ conf, line, value);
+ }
+ }
+ }
+
+ coll[0] = 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++) {
+ snprintf(usage, sizeof usage, "%s:%s",
+ hid_usage_page(HID_PAGE(u)),
+ hid_usage_in_page(u));
+ if (verbose > 2)
+ printf("usage %s\n", usage);
+ if (!strcasecmp(usage, name))
+ goto foundhid;
+ if (coll[0]) {
+ snprintf(usage, sizeof usage,
+ "%s.%s:%s", coll+1,
+ hid_usage_page(HID_PAGE(u)),
+ hid_usage_in_page(u));
+ if (verbose > 2)
+ printf("usage %s\n",
+ usage);
+ if (!strcasecmp(usage, name))
+ 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'\n", 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->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);
+}
+
+void
+docmd(struct command *cmd, int value, const char *hid, int argc, char **argv)
+{
+ char cmdbuf[SIZE], *p, *q;
+ size_t len;
+ int n, r;
+
+ for (p = cmd->action, q = cmdbuf; *p && q < &cmdbuf[SIZE-1]; ) {
+ if (*p == '$') {
+ p++;
+ len = &cmdbuf[SIZE-1] - q;
+ if (isdigit(*p)) {
+ n = strtol(p, &p, 10) - 1;
+ if (n >= 0 && n < argc) {
+ strncpy(q, argv[n], len);
+ q += strlen(q);
+ }
+ } else if (*p == 'V') {
+ p++;
+ snprintf(q, len, "%d", value);
+ q += strlen(q);
+ } else if (*p == 'N') {
+ p++;
+ strncpy(q, cmd->name, len);
+ q += strlen(q);
+ } else if (*p == 'H') {
+ p++;
+ strncpy(q, hid, len);
+ q += strlen(q);
+ } else if (*p) {
+ *q++ = *p++;
+ }
+ } else {
+ *q++ = *p++;
+ }
+ }
+ *q = 0;
+
+ if (verbose)
+ printf("system '%s'\n", cmdbuf);
+ r = system(cmdbuf);
+ if (verbose > 1 && r)
+ printf("return code = 0x%x\n", r);
+}
+
+void
+freecommands(struct command *cmd)
+{
+ struct command *next;
+
+ while (cmd) {
+ next = cmd->next;
+ free(cmd);
+ cmd = next;
+ }
+}
diff --git a/usr.bin/usbhidctl/usbhid.c b/usr.bin/usbhidctl/usbhid.c
index 1751eb8d1ea..83dd7f7abf7 100644
--- a/usr.bin/usbhidctl/usbhid.c
+++ b/usr.bin/usbhidctl/usbhid.c
@@ -1,8 +1,8 @@
-/* $OpenBSD: usbhid.c,v 1.3 2002/05/02 20:12:07 nate Exp $ */
-/* $NetBSD: usbhid.c,v 1.17 2001/03/28 03:17:42 simonb Exp $ */
+/* $OpenBSD: usbhid.c,v 1.4 2002/05/10 00:09:17 nate Exp $ */
+/* $NetBSD: usbhid.c,v 1.22 2002/02/20 20:30:42 christos Exp $ */
/*
- * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@@ -53,14 +53,18 @@
#include <unistd.h>
#include <usbhid.h>
+/*
+ * Zero if not in a verbose mode. Greater levels of verbosity
+ * are indicated by values larger than one.
+ */
+unsigned int verbose;
+
/* Parser tokens */
#define DELIM_USAGE '.'
#define DELIM_PAGE ':'
#define DELIM_SET '='
-/* Zero if not in a verbose mode. Greater levels of verbosity are
- indicated by values larger than one. */
-static unsigned int verbose;
+static int reportid;
struct Susbvar {
/* Variable name, not NUL terminated */
@@ -77,6 +81,7 @@ struct Susbvar {
#define MATCH_SHOWPAGENAME (1 << 5)
#define MATCH_SHOWNUMERIC (1 << 6)
#define MATCH_WRITABLE (1 << 7)
+#define MATCH_SHOWVALUES (1 << 8)
unsigned int mflags;
/* Workspace for hidmatch() */
@@ -108,11 +113,183 @@ static struct {
#define REPORT_MAXVAL 2
};
+/*
+ * Extract 16-bit unsigned usage ID from a numeric string. Returns -1
+ * if string failed to parse correctly.
+ */
+static int
+strtousage(const char *nptr, size_t nlen)
+{
+ char *endptr;
+ long result;
+ char numstr[16];
+
+ if (nlen >= sizeof(numstr) || !isdigit((unsigned char)*nptr))
+ return -1;
+
+ /*
+ * We use strtol() here, but unfortunately strtol() requires a
+ * NUL terminated string - which we don't have - at least not
+ * officially.
+ */
+ memcpy(numstr, nptr, nlen);
+ numstr[nlen] = '\0';
+
+ result = strtol(numstr, &endptr, 0);
+
+ if (result < 0 || result > 0xffff || endptr != &numstr[nlen])
+ return -1;
+
+ return result;
+}
+
+struct usagedata {
+ char const *page_name;
+ char const *usage_name;
+ size_t page_len;
+ size_t usage_len;
+ int isfinal;
+ u_int32_t usage_id;
+};
+
+/*
+ * Test a rule against the current usage data. Returns -1 on no
+ * match, 0 on partial match and 1 on complete match.
+ */
+static int
+hidtestrule(struct Susbvar *var, struct usagedata *cache)
+{
+ char const *varname;
+ ssize_t matchindex, pagesplit;
+ size_t strind, varlen;
+ int numusage;
+ u_int32_t usage_id;
+
+ matchindex = var->matchindex;
+ varname = var->variable;
+ varlen = var->varlen;
+
+ usage_id = cache->usage_id;
+
+ /*
+ * Parse the current variable name, locating the end of the
+ * current 'usage', and possibly where the usage page name
+ * ends.
+ */
+ pagesplit = -1;
+ for (strind = matchindex; strind < varlen; strind++) {
+ if (varname[strind] == DELIM_USAGE)
+ break;
+ if (varname[strind] == DELIM_PAGE)
+ pagesplit = strind;
+ }
+
+ if (cache->isfinal && strind != varlen)
+ /*
+ * Variable name is too long (hit delimiter instead of
+ * end-of-variable).
+ */
+ return -1;
+
+ if (pagesplit >= 0) {
+ /*
+ * Page name was specified, determine whether it was
+ * symbolic or numeric.
+ */
+ char const *strstart;
+ int numpage;
+
+ strstart = &varname[matchindex];
+
+ numpage = strtousage(strstart, pagesplit - matchindex);
+
+ if (numpage >= 0) {
+ /* Valid numeric */
+
+ if (numpage != HID_PAGE(usage_id))
+ /* Numeric didn't match page ID */
+ return -1;
+ } else {
+ /* Not a valid numeric */
+
+ /*
+ * Load and cache the page name if and only if
+ * it hasn't already been loaded (it's a
+ * fairly expensive operation).
+ */
+ if (cache->page_name == NULL) {
+ cache->page_name = hid_usage_page(HID_PAGE(usage_id));
+ cache->page_len = strlen(cache->page_name);
+ }
+
+ /*
+ * Compare specified page name to actual page
+ * name.
+ */
+ if (cache->page_len !=
+ (size_t)(pagesplit - matchindex) ||
+ memcmp(cache->page_name,
+ &varname[matchindex],
+ cache->page_len) != 0)
+ /* Mismatch, page name wrong */
+ return -1;
+ }
+
+ /* Page matches, discard page name */
+ matchindex = pagesplit + 1;
+ }
+
+ numusage = strtousage(&varname[matchindex], strind - matchindex);
+
+ if (numusage >= 0) {
+ /* Valid numeric */
+
+ if (numusage != HID_USAGE(usage_id))
+ /* Numeric didn't match usage ID */
+ return -1;
+ } else {
+ /* Not a valid numeric */
+
+ /* Load and cache the usage name */
+ if (cache->usage_name == NULL) {
+ cache->usage_name = hid_usage_in_page(usage_id);
+ cache->usage_len = strlen(cache->usage_name);
+ }
+
+ /*
+ * Compare specified usage name to actual usage name
+ */
+ if (cache->usage_len != (size_t)(strind - matchindex) ||
+ memcmp(cache->usage_name, &varname[matchindex],
+ cache->usage_len) != 0)
+ /* Mismatch, usage name wrong */
+ return -1;
+ }
+
+ if (cache->isfinal)
+ /* Match */
+ return 1;
+
+ /*
+ * Partial match: Move index past this usage string +
+ * delimiter
+ */
+ var->matchindex = strind + 1;
+
+ return 0;
+}
+
+/*
+ * hidmatch() determines whether the item specified in 'item', and
+ * nested within a heirarchy of collections specified in 'collist'
+ * matches any of the rules in the list 'varlist'. Returns the
+ * matching rule on success, or NULL on no match.
+ */
static struct Susbvar*
hidmatch(u_int32_t const *collist, size_t collen, struct hid_item *item,
struct Susbvar *varlist, size_t vlsize)
{
- size_t vlind, colind, vlactive;
+ size_t colind, vlactive, vlind;
int iscollection;
/*
@@ -161,96 +338,52 @@ hidmatch(u_int32_t const *collist, size_t collen, struct hid_item *item,
}
}
+ /*
+ * Loop through each usage in the collection list, including
+ * the 'item' itself on the final iteration. For each usage,
+ * test which variables named in the rule list are still
+ * applicable - if any.
+ */
for (colind = 0; vlactive > 0 && colind <= collen; colind++) {
- char const *usage_name, *page_name;
- size_t usage_len, page_len;
- int final;
- u_int32_t usage_id;
-
- final = (colind == collen);
+ struct usagedata cache;
- if (final)
- usage_id = item->usage;
+ cache.isfinal = (colind == collen);
+ if (cache.isfinal)
+ cache.usage_id = item->usage;
else
- usage_id = collist[colind];
+ cache.usage_id = collist[colind];
- usage_name = hid_usage_in_page(usage_id);
- usage_len = strlen(usage_name);
-
- page_name = NULL;
+ cache.usage_name = NULL;
+ cache.page_name = NULL;
+ /*
+ * Loop through each rule, testing whether the rule is
+ * still applicable or not. For each rule,
+ * 'matchindex' retains the current match state as an
+ * index into the variable name string, or -1 if this
+ * rule has been proven not to match.
+ */
for (vlind = 0; vlind < vlsize; vlind++) {
- ssize_t matchindex, pagesplit;
- size_t varlen, strind;
- char const *varname;
struct Susbvar *var;
+ int matchres;
var = &varlist[vlind];
- matchindex = var->matchindex;
- varname = var->variable;
- varlen = var->varlen;
-
- if (matchindex < 0)
+ if (var->matchindex < 0)
/* Mismatch at a previous level */
continue;
- pagesplit = -1;
- for (strind = matchindex; strind < varlen; strind++) {
- if (varname[strind] == DELIM_USAGE)
- break;
- if (varname[strind] == DELIM_PAGE)
- pagesplit = strind;
- }
+ matchres = hidtestrule(var, &cache);
- if (final && strind != varlen) {
- /*
- * Variable name is too long (hit
- * delimiter instead of
- * end-of-variable)
- */
- var->matchindex = -1;
- vlactive--;
- continue;
- }
-
- if (pagesplit >= 0) {
- if (page_name == NULL) {
- page_name = hid_usage_page(HID_PAGE(usage_id));
- page_len = strlen(page_name);
- }
- if (page_len !=
- (size_t)(pagesplit - matchindex) ||
- memcmp(page_name, &varname[matchindex],
- page_len) != 0) {
- /* Mismatch, page name wrong */
- var->matchindex = -1;
- vlactive--;
- continue;
- }
-
- /* Page matches, discard page name */
- matchindex = pagesplit + 1;
- }
-
- if (usage_len != strind - matchindex ||
- memcmp(usage_name, &varname[matchindex],
- usage_len) != 0) {
- /* Mismatch, usage name wrong */
+ if (matchres < 0) {
+ /* Bad match */
var->matchindex = -1;
vlactive--;
continue;
- }
-
- if (final)
- /* Match */
+ } else if (matchres > 0) {
+ /* Complete match */
return var;
-
- /*
- * Partial match: Move index past this usage
- * string + delimiter
- */
- var->matchindex = matchindex + usage_len + 1;
+ }
}
}
@@ -262,8 +395,7 @@ allocreport(struct Sreport *report, report_desc_t rd, int repindex)
{
int reptsize;
- reptsize = hid_report_size(rd, reptoparam[repindex].hid_kind,
- &report->report_id);
+ reptsize = hid_report_size(rd, reptoparam[repindex].hid_kind, reportid);
if (reptsize < 0)
errx(1, "Negative report size");
report->size = reptsize;
@@ -302,7 +434,8 @@ getreport(struct Sreport *report, int hidfd, report_desc_t rd, int repindex)
report->buffer->ucr_report = reptoparam[repindex].uhid_report;
if (ioctl(hidfd, USB_GET_REPORT, report->buffer) < 0)
- err(1, "USB_GET_REPORT");
+ err(1, "USB_GET_REPORT (probably not supported by "
+ "device)");
}
}
@@ -335,19 +468,30 @@ varop_display(struct hid_item *item, struct Susbvar *var,
u_int32_t const *collist, size_t collen, u_char *buf)
{
size_t colitem;
-
- for (colitem = 0; colitem < collen; colitem++) {
+ int val, i;
+
+ for (i = 0; i < item->report_count; i++) {
+ for (colitem = 0; colitem < collen; colitem++) {
+ if (var->mflags & MATCH_SHOWPAGENAME)
+ printf("%s:",
+ hid_usage_page(HID_PAGE(collist[colitem])));
+ printf("%s.", hid_usage_in_page(collist[colitem]));
+ }
if (var->mflags & MATCH_SHOWPAGENAME)
- printf("%s:",
- hid_usage_page(HID_PAGE(collist[colitem])));
- printf("%s.", hid_usage_in_page(collist[colitem]));
+ printf("%s:", hid_usage_page(HID_PAGE(item->usage)));
+ val = hid_get_data(buf, item);
+ item->pos += item->report_size;
+ if (item->usage_minimum != 0 || item->usage_maximum != 0) {
+ val += item->usage_minimum;
+ printf("%s=1", hid_usage_in_page(val));
+ } else {
+ printf("%s=%d%s", hid_usage_in_page(item->usage),
+ val, item->flags & HIO_CONST ? " (const)" : "");
+ }
+ if (item->report_count > 1)
+ printf(" [%d]", i);
+ printf("\n");
}
-
- if (var->mflags & MATCH_SHOWPAGENAME)
- printf("%s:", hid_usage_page(HID_PAGE(item->usage)));
- printf("%s=%d%s\n", hid_usage_in_page(item->usage),
- hid_get_data(buf, item),
- (item->flags & HIO_CONST) ? " (const)" : "");
return 0;
}
@@ -362,12 +506,8 @@ varop_modify(struct hid_item *item, struct Susbvar *var,
hid_set_data(buf, item, dataval);
- if (verbose >= 1)
- /*
- * Allow displaying of set value in verbose mode.
- * This isn't particularly useful though, so don't
- * bother documenting it.
- */
+ if (var->mflags & MATCH_SHOWVALUES)
+ /* Display set value */
varop_display(item, var, collist, collen, buf);
return 1;
@@ -376,14 +516,28 @@ varop_modify(struct hid_item *item, struct Susbvar *var,
static void
reportitem(char const *label, struct hid_item const *item, unsigned int mflags)
{
- printf("%s size=%d count=%d page=%s usage=%s%s", label,
+ int isconst = item->flags & HIO_CONST,
+ isvar = item->flags & HIO_VARIABLE;
+ printf("%s size=%d count=%d%s%s page=%s", label,
item->report_size, item->report_count,
- hid_usage_page(HID_PAGE(item->usage)),
- hid_usage_in_page(item->usage),
- item->flags & HIO_CONST ? " Const" : "");
- if (mflags & MATCH_SHOWNUMERIC)
- printf(" (%u/0x%x)",
- HID_PAGE(item->usage), HID_USAGE(item->usage));
+ isconst ? " Const" : "",
+ !isvar && !isconst ? " Array" : "",
+ hid_usage_page(HID_PAGE(item->usage)));
+ if (item->usage_minimum != 0 || item->usage_maximum != 0) {
+ printf(" usage=%s..%s", hid_usage_in_page(item->usage_minimum),
+ hid_usage_in_page(item->usage_maximum));
+ if (mflags & MATCH_SHOWNUMERIC)
+ printf(" (%u:0x%x..%u:0x%x)",
+ HID_PAGE(item->usage_minimum),
+ HID_USAGE(item->usage_minimum),
+ HID_PAGE(item->usage_maximum),
+ HID_USAGE(item->usage_maximum));
+ } else {
+ printf(" usage=%s", hid_usage_in_page(item->usage));
+ if (mflags & MATCH_SHOWNUMERIC)
+ printf(" (%u:0x%x)",
+ HID_PAGE(item->usage), HID_USAGE(item->usage));
+ }
printf(", logical range %d..%d",
item->logical_minimum, item->logical_maximum);
if (item->physical_minimum != item->physical_maximum)
@@ -402,9 +556,14 @@ varop_report(struct hid_item *item, struct Susbvar *var,
{
switch (item->kind) {
case hid_collection:
- printf("Collection page=%s usage=%s\n",
+ printf("Collection page=%s usage=%s",
hid_usage_page(HID_PAGE(item->usage)),
hid_usage_in_page(item->usage));
+ if (var->mflags & MATCH_SHOWNUMERIC)
+ printf(" (%u:0x%x)\n",
+ HID_PAGE(item->usage), HID_USAGE(item->usage));
+ else
+ printf("\n");
break;
case hid_endcollection:
printf("End collection\n");
@@ -426,13 +585,12 @@ varop_report(struct hid_item *item, struct Susbvar *var,
static void
devloop(int hidfd, report_desc_t rd, struct Susbvar *varlist, size_t vlsize)
{
+ u_char *dbuf;
struct hid_data *hdata;
+ size_t collind, dlen;
struct hid_item hitem;
u_int32_t colls[128];
struct Sreport inreport;
- size_t dlen;
- u_char *dbuf;
- size_t collind;
allocreport(&inreport, rd, REPORT_INPUT);
@@ -446,12 +604,14 @@ devloop(int hidfd, report_desc_t rd, struct Susbvar *varlist, size_t vlsize)
ssize_t readlen;
readlen = read(hidfd, dbuf, dlen);
- if (readlen < 0 || dlen != (size_t)readlen)
- err(1, "bad read %ld != %ld",
- (long)readlen, (long)dlen);
+ if (readlen < 0)
+ err(1, "Device read error");
+ if (dlen != (size_t)readlen)
+ errx(1, "Unexpected response length: %lu != %lu",
+ (unsigned long)readlen, (unsigned long)dlen);
collind = 0;
- hdata = hid_start_parse(rd, 1 << hid_input);
+ hdata = hid_start_parse(rd, 1 << hid_input, reportid);
if (hdata == NULL)
errx(1, "Failed to start parser");
@@ -476,6 +636,9 @@ devloop(int hidfd, report_desc_t rd, struct Susbvar *varlist, size_t vlsize)
errx(1, "Unexpected non-input item returned");
}
+ if (reportid != -1 && hitem.report_ID != reportid)
+ continue;
+
matchvar = hidmatch(colls, collind, &hitem,
varlist, vlsize);
@@ -495,10 +658,9 @@ devshow(int hidfd, report_desc_t rd, struct Susbvar *varlist, size_t vlsize,
int kindset)
{
struct hid_data *hdata;
+ size_t collind, repind, vlind;
struct hid_item hitem;
u_int32_t colls[128];
- size_t collind, repind, vlind;
-
struct Sreport reports[REPORT_MAXVAL + 1];
@@ -509,9 +671,7 @@ devshow(int hidfd, report_desc_t rd, struct Susbvar *varlist, size_t vlsize,
}
collind = 0;
- hdata = hid_start_parse(rd, kindset |
- (1 << hid_collection) |
- (1 << hid_endcollection));
+ hdata = hid_start_parse(rd, kindset, reportid);
if (hdata == NULL)
errx(1, "Failed to start parser");
@@ -519,6 +679,9 @@ devshow(int hidfd, report_desc_t rd, struct Susbvar *varlist, size_t vlsize,
struct Susbvar *matchvar;
int repindex;
+ if (verbose > 3)
+ printf("item: kind=%d repid=%d usage=0x%x\n",
+ hitem.kind, hitem.report_ID, hitem.usage);
repindex = -1;
switch (hitem.kind) {
case hid_collection:
@@ -542,6 +705,9 @@ devshow(int hidfd, report_desc_t rd, struct Susbvar *varlist, size_t vlsize,
break;
}
+ if (reportid != -1 && hitem.report_ID != reportid)
+ continue;
+
matchvar = hidmatch(colls, collind, &hitem, varlist, vlsize);
if (matchvar != NULL) {
@@ -609,13 +775,13 @@ usage(void)
int
main(int argc, char **argv)
{
- int hidfd;
- report_desc_t repdesc;
- char devnamebuf[PATH_MAX];
char const *dev;
- int ch, wflag, aflag, nflag, rflag, lflag;
- size_t varnum;
char const *table;
+ size_t varnum;
+ int aflag, lflag, nflag, rflag, wflag;
+ int ch, hidfd;
+ report_desc_t repdesc;
+ char devnamebuf[PATH_MAX];
struct Susbvar variables[128];
wflag = aflag = nflag = verbose = rflag = lflag = 0;
@@ -698,6 +864,14 @@ main(int argc, char **argv)
if (!wflag)
errx(2, "Must specify -w to set variables");
svar->mflags |= MATCH_WRITABLE;
+ if (verbose >= 1)
+ /*
+ * Allow displaying of set value in
+ * verbose mode. This isn't
+ * particularly useful though, so
+ * don't bother documenting it.
+ */
+ svar->mflags |= MATCH_SHOWVALUES;
svar->varlen = valuesep - name;
svar->value = valuesep + 1;
svar->opfunc = varop_modify;
@@ -770,6 +944,10 @@ main(int argc, char **argv)
if (hidfd < 0)
err(1, "%s", dev);
+ if (ioctl(hidfd, USB_GET_REPORT_ID, &reportid) < 0)
+ reportid = -1;
+ if (verbose > 1)
+ printf("report ID=%d\n", reportid);
repdesc = hid_get_report_desc(hidfd);
if (repdesc == 0)
errx(1, "USB_GET_REPORT_DESC");
@@ -788,31 +966,18 @@ main(int argc, char **argv)
1 << hid_output |
1 << hid_feature);
-#if 0
- {
- size_t repindex;
- for (repindex = 0;
- repindex < (sizeof(reptoparam) / sizeof(*reptoparam));
- repindex++)
- devshow(hidfd, repdesc, variables, varnum,
- 1 << reptoparam[repindex].hid_kind);
- }
-#endif
-
if (rflag) {
/* Report mode trailer */
size_t repindex;
for (repindex = 0;
repindex < (sizeof(reptoparam) / sizeof(*reptoparam));
repindex++) {
- int report_id, size;
+ int size;
size = hid_report_size(repdesc,
reptoparam[repindex].hid_kind,
- &report_id);
- size -= report_id != 0;
- printf("Total %7s size %s%d bytes\n",
- reptoparam[repindex].name,
- report_id && size ? "1+" : "", size);
+ reportid);
+ printf("Total %7s size %d bytes\n",
+ reptoparam[repindex].name, size);
}
}
diff --git a/usr.bin/usbhidctl/usbhidctl.1 b/usr.bin/usbhidctl/usbhidctl.1
index b7b2ec48efa..87f92e51a1a 100644
--- a/usr.bin/usbhidctl/usbhidctl.1
+++ b/usr.bin/usbhidctl/usbhidctl.1
@@ -1,7 +1,7 @@
-.\" $OpenBSD: usbhidctl.1,v 1.3 2001/12/30 07:24:07 pvalchev Exp $
-.\" $NetBSD: usbhidctl.1,v 1.10 2000/09/24 02:27:12 augustss Exp $
+.\" $OpenBSD: usbhidctl.1,v 1.4 2002/05/10 00:09:17 nate Exp $
+.\" $NetBSD: usbhidctl.1,v 1.14 2001/12/28 17:49:32 augustss Exp $
.\"
-.\" Copyright (c) 2000 The NetBSD Foundation, Inc.
+.\" Copyright (c) 2001 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
@@ -70,8 +70,8 @@
.Op Ar item=value ...
.Sh DESCRIPTION
.Nm
-can be used to dump or modify the state of a USB HID (Human Interface Device).
-If a list of items is present on the command line, then
+can be used to output or modify the state of a USB HID (Human Interface
+Device). If a list of items is present on the command line, then
.Nm
prints the current value of those items for the specified device. If the
.Fl w
@@ -83,6 +83,7 @@ The options are as follows:
.Bl -tag -width Ds
.It Fl a
Show all items and their current values.
+This option fails if the device does not support the GET_REPORT command.
.It Fl f Ar device
Specify a path name for the device to operate on. If
.Ar device
@@ -94,9 +95,10 @@ An absolute path is taken to be the literal device pathname.
Loop and dump the device data every time it changes. Only 'input' items are
displayed in this mode.
.It Fl n
-Suppress printing of the item name when querying specific item values.
+Suppress printing of the item name when querying specific items. Only output
+the current value.
.It Fl r
-Dump the report descriptor.
+Dump the USB HID report descriptor.
.It Fl t Ar table
Specify a path name for the HID usage table file.
.It Fl v
@@ -108,18 +110,91 @@ option.
.Sh FILES
.Pa /usr/share/misc/usb_hid_usages
The default HID usage table.
+.Sh SYNTAX
+.Nm
+parses the names of items specified on the command line against the human
+interface items reported by the USB device. Each human interface item is
+mapped from its native form to a human readable name, using the HID usage
+table file. Command line items are compared with the generated item names,
+and the USB HID device is operated on when a match is found.
+.Pp
+Each human interface item is named by the
+.Qq page
+it appears in, the
+.Qq usage
+within that page, and the list of
+.Qq collections
+containing the item. Each collection in turn is also identified by page, and
+the usage within that page.
+.Pp
+On the
+.Nm
+command line the page name is separated from the usage name with the character
+.Cm So : Sc .
+The collections are separated by the character
+.Cm So . Sc .
+.Pp
+As an alternative notation in items on the command line, the native numeric
+value for the page name or usage can be used instead of the full human
+readable page name or usage name. Numeric values can be specified in decimal,
+octal or hexadecimal.
+.Sh EXAMPLES
+On a standard USB mouse the item
+.Dl Generic_Desktop:Mouse.Generic_Desktop:Pointer.Button:Button_2
+reflects the current status of button 2. The
+.Qq button 2
+item is encapsulated within two collections, the
+.Qq Mouse
+collection in the
+.Qq Generic Desktop
+page, and the
+.Qq Pointer
+collection in the
+.Qq Generic Desktop
+page. The item itself is the usage
+.Qq Button_2
+in the
+.Qq Button
+page.
+.Pp
+An item can generally be named by omitting one or more of the page names. For
+example the
+.Qq button 2
+item would usually just be referred to on the command line as:
+.Dl usbhidctl -f /dev/mouse Mouse.Pointer.Button_2
+.Pp
+Items can also be named by referring to parts of the item name with the
+numeric representation of the native HID usage identifiers. This is most
+useful when items are missing from the HID usage table. The page identifier
+for the
+.Qq Generic Desktop
+page is 1, and the usage identifier for the usage
+.Qq Button_2
+is 2, so the following can be used to refer to the
+.Qq button 2
+item:
+.Dl usbhidctl -f /dev/mouse 1:Mouse.1:Pointer.Button:2
+.Pp
+Devices with human interface outputs can be manipulated with the
+.Fl w
+option. For example, some USB mice have a Light Emitting Diode under software
+control as usage 2 under page 0xffff, in the
+.Qq Mouse
+collection. The following can be used to switch this LED off:
+.Dl usbhidctl -f /dev/mouse -w Mouse.0xffff:2=0
.Sh SEE ALSO
+.Xr usbhidaction 1 ,
.Xr usbhid 3 ,
.Xr uhid 4 ,
.Xr usb 4
-.Sh AUTHOR
-David Sainty <David.Sainty@dtsp.co.nz>
.Sh HISTORY
The
.Nm
command first appeared in
.Ox 3.0 .
+.Sh AUTHORS
+.An David Sainty Aq David.Sainty@dtsp.co.nz
.Sh BUGS
-Some USB HID devices report multiple items with exactly the same description.
-The current naming scheme does not provide the means to specify which of the
-identically named items you are referring to.
+Some USB HID devices report multiple items with exactly the same usage
+identifiers. The current naming scheme does not provide the means to specify
+which of a set of identically named items you are referring to.
diff --git a/usr.sbin/usbdevs/usbdevs.8 b/usr.sbin/usbdevs/usbdevs.8
index a9397e35704..b36206ff508 100644
--- a/usr.sbin/usbdevs/usbdevs.8
+++ b/usr.sbin/usbdevs/usbdevs.8
@@ -1,5 +1,5 @@
-.\" $OpenBSD: usbdevs.8,v 1.5 2001/09/17 17:29:56 mickey Exp $
-.\" $NetBSD: usbdevs.8,v 1.4 1999/04/13 20:50:49 augustss Exp $
+.\" $OpenBSD: usbdevs.8,v 1.6 2002/05/10 00:09:17 nate Exp $
+.\" $NetBSD: usbdevs.8,v 1.5 2000/10/15 12:44:11 bjh21 Exp $
.\"
.\" Copyright (c) 1999 The NetBSD Foundation, Inc.
.\" All rights reserved.
@@ -35,17 +35,18 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd August 14, 2001
+.Dd October 15, 2000
.Dt USBDEVS 8
.Os
.Sh NAME
.Nm usbdevs
.Nd show USB devices connected to the system
.Sh SYNOPSIS
-.Nm usbdevs
-.Op Fl dv
+.Nm
.Op Fl a Ar addr
+.Op Fl d
.Op Fl f Ar dev
+.Op Fl v
.Sh DESCRIPTION
.Nm
prints a listing of all USB devices connected to the system
@@ -53,7 +54,7 @@ with some information about each device.
The indentation of each line indicates its distance from the root.
.Pp
The options are as follows:
-.Bl -tag -width Ds
+.Bl -tag -width Fl
.It Fl a Ar addr
Only print information about the device at the given address.
.It Fl d
diff --git a/usr.sbin/usbdevs/usbdevs.c b/usr.sbin/usbdevs/usbdevs.c
index 8a07c829b4f..a22f1576e4f 100644
--- a/usr.sbin/usbdevs/usbdevs.c
+++ b/usr.sbin/usbdevs/usbdevs.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: usbdevs.c,v 1.4 2002/05/02 20:12:07 nate Exp $ */
-/* $NetBSD: usbdevs.c,v 1.11 1999/09/08 02:39:36 augustss Exp $ */
+/* $OpenBSD: usbdevs.c,v 1.5 2002/05/10 00:09:17 nate Exp $ */
+/* $NetBSD: usbdevs.c,v 1.19 2002/02/21 00:34:31 christos Exp $ */
/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -49,8 +49,8 @@
#define USBDEV "/dev/usb"
-int verbose;
-int showdevs;
+int verbose = 0;
+int showdevs = 0;
void usage(void);
void usbdev(int f, int a, int rec);
@@ -72,10 +72,7 @@ char done[USB_MAX_DEVICES];
int indent;
void
-usbdev(f, a, rec)
- int f;
- int a;
- int rec;
+usbdev(int f, int a, int rec)
{
struct usb_device_info di;
int e, p, i;
@@ -90,8 +87,17 @@ usbdev(f, a, rec)
printf("addr %d: ", a);
done[a] = 1;
if (verbose) {
+#ifdef notyet
+ switch (di.udi_speed) {
+ case USB_SPEED_LOW: printf("low speed, "); break;
+ case USB_SPEED_FULL: printf("full speed, "); break;
+ case USB_SPEED_HIGH: printf("high speed, "); break;
+ default: break;
+ }
+#endif
if (di.udi_lowspeed)
printf("low speed, ");
+
if (di.udi_power)
printf("power %d mA, ", di.udi_power);
else
@@ -109,10 +115,10 @@ usbdev(f, a, rec)
printf("%s, %s", di.udi_product, di.udi_vendor);
printf("\n");
if (showdevs) {
- for (i = 0; i< USB_MAX_DEVNAMES; i++)
+ for (i = 0; i < USB_MAX_DEVNAMES; i++)
if (di.udi_devnames[i][0])
- printf("%*s %s\n", indent, "",
- di.udi_devnames[i]);
+ printf("%*s %s\n", indent, "",
+ di.udi_devnames[i]);
}
if (!rec)
return;
@@ -143,8 +149,7 @@ usbdev(f, a, rec)
}
void
-usbdump(f)
- int f;
+usbdump(int f)
{
int a;
@@ -155,10 +160,7 @@ usbdump(f)
}
void
-dumpone(name, f, addr)
- char *name;
- int f;
- int addr;
+dumpone(char *name, int f, int addr)
{
if (verbose)
printf("Controller %s:\n", name);
@@ -171,14 +173,10 @@ dumpone(name, f, addr)
}
int
-main(argc, argv)
- int argc;
- char **argv;
+main(int argc, char **argv)
{
int ch, i, f;
char buf[50];
- extern int optind;
- extern char *optarg;
char *dev = 0;
int addr = 0;
int ncont;
@@ -220,7 +218,8 @@ main(argc, argv)
ncont++;
}
if (verbose && ncont == 0)
- printf("%s: no USB controllers found\n", __progname);
+ printf("%s: no USB controllers found\n",
+ __progname);
} else {
f = open(dev, O_RDONLY);
if (f >= 0)