Hi everyone,
This is a preliminary patch that adds descriptor dumping support
to usbdevs(8). I have attempted to keep any unnecessary changes to
a minimum. I will do some cleanup work incrementally on top of
this patch.
I've tested this on a single machine running -current so more testing
would be nice.
Let me know what you think and I will rework my patch.
Cheers,
Dimitris
Index: usr.sbin/usbdevs/usbdevs.8
===================================================================
RCS file: /cvs/src/usr.sbin/usbdevs/usbdevs.8,v
retrieving revision 1.9
diff -u -p -r1.9 usbdevs.8
--- usr.sbin/usbdevs/usbdevs.8 26 Jun 2008 05:42:21 -0000 1.9
+++ usr.sbin/usbdevs/usbdevs.8 13 Apr 2015 13:57:27 -0000
@@ -54,7 +54,13 @@ Show the device drivers associated with
.It Fl f Ar dev
Only print information for the given USB controller.
.It Fl v
-Be verbose.
+Verbose mode. Causes
+.Nm
+to display detailed information about the devices present.
+Multiple
+.Fl v
+options increase verbosity. At level 1 or above the device
+and configuration descriptors will be shown.
.El
.Sh FILES
.Bl -tag -width Pa
Index: usr.sbin/usbdevs/usbdevs.c
===================================================================
RCS file: /cvs/src/usr.sbin/usbdevs/usbdevs.c,v
retrieving revision 1.24
diff -u -p -r1.24 usbdevs.c
--- usr.sbin/usbdevs/usbdevs.c 31 Mar 2015 13:38:27 -0000 1.24
+++ usr.sbin/usbdevs/usbdevs.c 13 Apr 2015 13:57:27 -0000
@@ -50,6 +50,14 @@ int verbose = 0;
int showdevs = 0;
void usage(void);
+int getddesc(int, int, int, struct usb_device_ddesc *);
+int getcdesc(int, int, int, struct usb_device_cdesc *);
+int getfdesc(int, int, int, int, struct usb_device_fdesc *);
+void dumpedesc(usb_endpoint_descriptor_t *);
+void dumpidesc(usb_interface_descriptor_t *);
+void dumpcdesc(usb_config_descriptor_t *);
+void dumpddesc(usb_device_descriptor_t *);
+void dumpdesc(int, int, int);
void usbdev(int f, int a, int rec);
void usbdump(int f);
void dumpone(char *name, int f, int addr);
@@ -67,6 +75,236 @@ usage(void)
char done[USB_MAX_DEVICES];
int indent;
+int
+getddesc(int f, int b, int a, struct usb_device_ddesc *ddesc)
+{
+ int r;
+
+ ddesc->udd_bus = b;
+ ddesc->udd_addr = a;
+ r = ioctl(f, USB_DEVICE_GET_DDESC, ddesc);
+ if (r) {
+ if (errno != ENXIO)
+ warn("USB_DEVICE_GET_DDESC");
+ return -1;
+ }
+ return 0;
+}
+
+int
+getcdesc(int f, int b, int a, struct usb_device_cdesc *cdesc)
+{
+ int r;
+
+ cdesc->udc_bus = b;
+ cdesc->udc_addr = a;
+ cdesc->udc_config_index = USB_CURRENT_CONFIG_INDEX;
+ r = ioctl(f, USB_DEVICE_GET_CDESC, cdesc);
+ if (r) {
+ if (errno != ENXIO)
+ warn("USB_DEVICE_GET_CDESC");
+ return -1;
+ }
+ return 0;
+}
+
+int
+getfdesc(int f, int b, int a, int l, struct usb_device_fdesc *fdesc)
+{
+ int r;
+
+ fdesc->udf_bus = b;
+ fdesc->udf_addr = a;
+ fdesc->udf_config_index = USB_CURRENT_CONFIG_INDEX;
+ fdesc->udf_size = l;
+ fdesc->udf_data = malloc(l);
+ if (!fdesc->udf_data)
+ err(1, "malloc");
+ r = ioctl(f, USB_DEVICE_GET_FDESC, fdesc);
+ if (r) {
+ if (errno != ENXIO)
+ warn("USB_DEVICE_GET_FDESC");
+ free(fdesc->udf_data);
+ return -1;
+ }
+ return 0;
+}
+
+void
+dumpedesc(usb_endpoint_descriptor_t *ed)
+{
+ char *xfertype, *synchtype;
+
+ printf("%*sEndpoint Descriptor:\n", indent, "");
+ indent++;
+ printf("%*sbLength: %d\n", indent, "", ed->bLength);
+ printf("%*sbDescriptorType: %d\n", indent, "", ed->bDescriptorType);
+ printf("%*sbEndpointAddress: %#x EP %d %s\n", indent, "",
ed->bEndpointAddress,
+ UE_GET_ADDR(ed->bEndpointAddress),
+ UE_GET_DIR(ed->bEndpointAddress) ? "in" : "out");
+ printf("%*sbmAttributes: %#x\n", indent, "", ed->bmAttributes);
+
+ switch (UE_GET_XFERTYPE(ed->bmAttributes)) {
+ case UE_CONTROL:
+ xfertype = "Control";
+ break;
+ case UE_ISOCHRONOUS:
+ xfertype = "Isochronous";
+ break;
+ case UE_BULK:
+ xfertype = "Bulk";
+ break;
+ case UE_INTERRUPT:
+ xfertype = "Interrupt";
+ break;
+ default:
+ xfertype = "Unknown";
+ break;
+ }
+
+ switch (UE_GET_ISO_TYPE(ed->bmAttributes)) {
+ case UE_ISO_ASYNC:
+ synchtype = "Asynchronous";
+ break;
+ case UE_ISO_ADAPT:
+ synchtype = "Adaptive";
+ break;
+ case UE_ISO_SYNC:
+ synchtype = "Synchronous";
+ break;
+ default:
+ synchtype = "No Synchronization";
+ break;
+ }
+
+ indent++;
+ printf("%*sTransfer type: %s\n", indent, "", xfertype);
+ printf("%*sSynch type: %s\n", indent, "", synchtype);
+ indent--;
+
+ printf("%*swMaxPacketSize: %#x\n", indent, "",
UGETW(ed->wMaxPacketSize));
+ printf("%*sbInterval: %d\n", indent, "", ed->bInterval);
+ indent--;
+}
+
+void
+dumpidesc(usb_interface_descriptor_t *ifd)
+{
+ printf("%*sInterface Descriptor:\n", indent, "");
+ indent++;
+ printf("%*sbLength: %d\n", indent, "", ifd->bLength);
+ printf("%*sbDescriptorType: %d\n", indent, "", ifd->bDescriptorType);
+ printf("%*sbInterfaceNumber: %d\n", indent, "", ifd->bInterfaceNumber);
+ printf("%*sbAlternateSetting: %d\n", indent, "",
ifd->bAlternateSetting);
+ printf("%*sbNumEndpoints: %d\n", indent, "", ifd->bNumEndpoints);
+ printf("%*sbInterfaceClass: %d\n", indent, "", ifd->bInterfaceClass);
+ printf("%*sbInterfaceSubClass: %d\n", indent, "",
ifd->bInterfaceSubClass);
+ printf("%*sbInterfaceProtocol: %d\n", indent, "",
ifd->bInterfaceProtocol);
+ printf("%*siInterface: %d\n", indent, "", ifd->iInterface);
+ indent--;
+}
+
+void
+dumpcdesc(usb_config_descriptor_t *cd)
+{
+ printf("%*sConfiguration Descriptor:\n", indent, "");
+ indent++;
+ printf("%*sbLength: %d\n", indent, "", cd->bLength);
+ printf("%*sbDescriptorType: %d\n", indent, "", cd->bDescriptorType);
+ printf("%*swTotalLength: %d\n", indent, "", UGETW(cd->wTotalLength));
+ printf("%*sbNumInterface: %d\n", indent, "", cd->bNumInterface);
+ printf("%*sbConfigurationValue: %d\n", indent, "",
cd->bConfigurationValue);
+ printf("%*siConfiguration: %d\n", indent, "", cd->iConfiguration);
+ printf("%*sbmAttributes: %#x\n", indent, "", cd->bmAttributes);
+ indent++;
+ if (cd->bmAttributes & UC_BUS_POWERED)
+ printf("%*sBus Powered\n", indent, "");
+ else if (cd->bmAttributes & UC_SELF_POWERED)
+ printf("%*sSelf Powered\n", indent, "");
+ else if (cd->bmAttributes & UC_REMOTE_WAKEUP)
+ printf("%*sRemove Wakeup\n", indent, "");
+ indent--;
+ printf("%*sbMaxPower: %dmA\n", indent, "", cd->bMaxPower * 2);
+ indent--;
+}
+
+void
+dumpddesc(usb_device_descriptor_t *dd)
+{
+ printf("%*sDevice Descriptor:\n", indent, "");
+ indent++;
+ printf("%*sbLength: %d\n", indent, "", dd->bLength);
+ printf("%*sbDescriptorType: %d\n", indent, "", dd->bDescriptorType);
+ printf("%*sbcdUSB: %#x\n", indent, "", UGETW(dd->bcdUSB));
+ printf("%*sbDeviceClass: %d\n", indent, "", dd->bDeviceClass);
+ printf("%*sbDeviceSubClass: %d\n", indent, "", dd->bDeviceSubClass);
+ printf("%*sbDeviceProtocol: %d\n", indent, "", dd->bDeviceProtocol);
+ printf("%*sbMaxPacketSize: %#x\n", indent, "", dd->bMaxPacketSize);
+ printf("%*sidVendor: %#x\n", indent, "", UGETW(dd->idVendor));
+ printf("%*sidProduct: %#x\n", indent, "", UGETW(dd->idProduct));
+ printf("%*sbcdDevice: %#x\n", indent, "", UGETW(dd->bcdDevice));
+ printf("%*siManufacturer: %d\n", indent, "", dd->iManufacturer);
+ printf("%*siProduct: %d\n", indent, "", dd->iProduct);
+ printf("%*siSerialNumber: %d\n", indent, "", dd->iSerialNumber);
+ printf("%*sbNumConfigurations: %d\n", indent, "",
dd->bNumConfigurations);
+ indent--;
+}
+
+void
+dumpdesc(int f, int b, int a)
+{
+ struct usb_device_ddesc ddesc;
+ struct usb_device_cdesc cdesc;
+ struct usb_device_fdesc fdesc;
+ char *p;
+ int i, j, k, r;
+
+ r = getddesc(f, b, a, &ddesc);
+ if (r < 0)
+ return;
+
+ r = getcdesc(f, b, a, &cdesc);
+ if (r < 0)
+ return;
+
+ r = getfdesc(f, b, a, UGETW(cdesc.udc_desc.wTotalLength), &fdesc);
+ if (r < 0)
+ return;
+
+ indent++;
+ dumpddesc(&ddesc.udd_desc);
+ p = fdesc.udf_data;
+ for (i = 0; i < ddesc.udd_desc.bNumConfigurations; i++) {
+ usb_config_descriptor_t *cd;
+
+ cd = (usb_config_descriptor_t *)p;
+ p += cd->bLength;
+ indent++;
+ dumpcdesc(cd);
+ for (j = 0; j < cd->bNumInterface; j++) {
+ usb_interface_descriptor_t *ifd;
+
+ ifd = (usb_interface_descriptor_t *)p;
+ p += ifd->bLength;
+ indent++;
+ dumpidesc(ifd);
+ for (k = 0; k < ifd->bNumEndpoints; k++) {
+ usb_endpoint_descriptor_t *ed;
+
+ ed = (usb_endpoint_descriptor_t *)p;
+ p += ed->bLength;
+ indent++;
+ dumpedesc(ed);
+ indent--;
+ }
+ indent--;
+ }
+ indent--;
+ }
+ indent--;
+ free(fdesc.udf_data);
+}
+
void
usbdev(int f, int a, int rec)
{
@@ -122,9 +360,11 @@ usbdev(int f, int a, int rec)
if (showdevs) {
for (i = 0; i < USB_MAX_DEVNAMES; i++)
if (di.udi_devnames[i][0])
- printf("%*s %s\n", indent, "",
+ printf("%*s %s\n", indent, "",
di.udi_devnames[i]);
}
+ if (verbose > 1)
+ dumpdesc(f, di.udi_bus, di.udi_addr);
if (!rec)
return;
for (p = 0; p < di.udi_nports && p < nitems(di.udi_ports); p++) {
@@ -201,7 +441,7 @@ main(int argc, char **argv)
dev = optarg;
break;
case 'v':
- verbose = 1;
+ verbose++;
break;
default:
usage();