summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Binkert <nate@cvs.openbsd.org>2002-05-10 00:09:18 +0000
committerNathan Binkert <nate@cvs.openbsd.org>2002-05-10 00:09:18 +0000
commita82d07519e6786b844ed49d488f67672db78daa2 (patch)
tree9ed579bb5297f1a9a77613ce6171eb968d7bf508
parent0dd51d96675add74c11132637e3499fceb185340 (diff)
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)