summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorPatrick Wildt <patrick@cvs.openbsd.org>2016-05-18 18:28:59 +0000
committerPatrick Wildt <patrick@cvs.openbsd.org>2016-05-18 18:28:59 +0000
commit6a41f6b80c0bc216e5da434fa5ae352a150b441c (patch)
treec46b5acce3af6b11e4999bcd9ffd50fa2730c99e /sys
parent0dfa9bec1380dab46bbe5ac5af47c96e047c14ab (diff)
Cache vendor, product and serial info for each usb device. This allows
ioctl(USB_DEVICEINFO) not to issue any further requests to gather information. Thus reducing stress on connected usb devices. This fixes an issue where usbdevs called in a loop causes a USB mass storage device to halt operation. Adapted from a similar commit in NetBSD. ok mpi@
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/usb/usb.c4
-rw-r--r--sys/dev/usb/usb_subr.c50
-rw-r--r--sys/dev/usb/usbdivar.h7
3 files changed, 54 insertions, 7 deletions
diff --git a/sys/dev/usb/usb.c b/sys/dev/usb/usb.c
index 732ecfdbb27..e0d7992571c 100644
--- a/sys/dev/usb/usb.c
+++ b/sys/dev/usb/usb.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: usb.c,v 1.110 2016/03/03 18:13:24 stefan Exp $ */
+/* $OpenBSD: usb.c,v 1.111 2016/05/18 18:28:58 patrick Exp $ */
/* $NetBSD: usb.c,v 1.77 2003/01/01 00:10:26 thorpej Exp $ */
/*
@@ -520,7 +520,7 @@ usb_fill_di_task(void *arg)
if (dev == NULL)
return;
- usbd_fill_deviceinfo(dev, di, 1);
+ usbd_fill_deviceinfo(dev, di, 0);
}
void
diff --git a/sys/dev/usb/usb_subr.c b/sys/dev/usb/usb_subr.c
index a255793ebae..bfd4e591b55 100644
--- a/sys/dev/usb/usb_subr.c
+++ b/sys/dev/usb/usb_subr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: usb_subr.c,v 1.120 2016/03/03 18:13:24 stefan Exp $ */
+/* $OpenBSD: usb_subr.c,v 1.121 2016/05/18 18:28:58 patrick Exp $ */
/* $NetBSD: usb_subr.c,v 1.103 2003/01/10 11:19:13 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/usb_subr.c,v 1.18 1999/11/17 22:33:47 n_hibma Exp $ */
@@ -63,6 +63,7 @@ usbd_status usbd_set_config(struct usbd_device *, int);
void usbd_devinfo(struct usbd_device *, int, char *, size_t);
void usbd_devinfo_vp(struct usbd_device *, char *, size_t,
char *, size_t, int);
+void usbd_get_device_string(struct usbd_device *, uByte, char **);
char *usbd_get_string(struct usbd_device *, int, char *, size_t);
int usbd_getnewaddr(struct usbd_bus *);
int usbd_print(void *, const char *);
@@ -212,6 +213,28 @@ usbd_trim_spaces(char *p)
}
void
+usbd_get_device_string(struct usbd_device *dev, uByte index, char **buf)
+{
+ char *b = malloc(USB_MAX_STRING_LEN, M_USB, M_NOWAIT);
+ if (b != NULL) {
+ usbd_get_string(dev, index, b, USB_MAX_STRING_LEN);
+ usbd_trim_spaces(b);
+ }
+ *buf = b;
+}
+
+void
+usbd_get_device_strings(struct usbd_device *dev)
+{
+ usbd_get_device_string(dev, dev->ddesc.iManufacturer,
+ &dev->vendor);
+ usbd_get_device_string(dev, dev->ddesc.iProduct,
+ &dev->product);
+ usbd_get_device_string(dev, dev->ddesc.iSerialNumber,
+ &dev->serial);
+}
+
+void
usbd_devinfo_vp(struct usbd_device *dev, char *v, size_t vl,
char *p, size_t pl, int usedev)
{
@@ -232,6 +255,11 @@ usbd_devinfo_vp(struct usbd_device *dev, char *v, size_t vl,
usbd_trim_spaces(vendor);
product = usbd_get_string(dev, udd->iProduct, p, pl);
usbd_trim_spaces(product);
+ } else {
+ if (dev->vendor != NULL)
+ vendor = dev->vendor;
+ if (dev->product != NULL)
+ product = dev->product;
}
#ifdef USBVERBOSE
if (vendor == NULL || product == NULL) {
@@ -294,7 +322,7 @@ usbd_devinfo(struct usbd_device *dev, int showclass, char *base, size_t len)
char *cp = base;
int bcdDevice, bcdUSB;
- usbd_devinfo_vp(dev, vendor, sizeof vendor, product, sizeof product, 1);
+ usbd_devinfo_vp(dev, vendor, sizeof vendor, product, sizeof product, 0);
snprintf(cp, len, "\"%s %s\"", vendor, product);
cp += strlen(cp);
if (showclass) {
@@ -1188,6 +1216,8 @@ usbd_new_device(struct device *parent, struct usbd_bus *bus, int depth,
DPRINTF(("usbd_new_device: new dev (addr %d), dev=%p, parent=%p\n",
addr, dev, parent));
+ usbd_get_device_strings(dev);
+
err = usbd_probe_and_attach(parent, dev, port, addr);
if (err) {
usb_free_device(dev);
@@ -1304,8 +1334,13 @@ usbd_fill_deviceinfo(struct usbd_device *dev, struct usb_device_info *di,
di->udi_nports = 0;
bzero(di->udi_serial, sizeof(di->udi_serial));
- usbd_get_string(dev, dev->ddesc.iSerialNumber, di->udi_serial,
- sizeof(di->udi_serial));
+ if (!usedev && dev->serial != NULL) {
+ strlcpy(di->udi_serial, dev->serial,
+ sizeof(di->udi_serial));
+ } else {
+ usbd_get_string(dev, dev->ddesc.iSerialNumber,
+ di->udi_serial, sizeof(di->udi_serial));
+ }
}
/* Retrieve a complete descriptor for a certain device and index. */
@@ -1368,6 +1403,13 @@ usb_free_device(struct usbd_device *dev)
free(dev->subdevs, M_USB, 0);
dev->bus->devices[dev->address] = NULL;
+ if (dev->vendor != NULL)
+ free(dev->vendor, M_USB, USB_MAX_STRING_LEN);
+ if (dev->product != NULL)
+ free(dev->product, M_USB, USB_MAX_STRING_LEN);
+ if (dev->serial != NULL)
+ free(dev->serial, M_USB, USB_MAX_STRING_LEN);
+
free(dev, M_USB, 0);
}
diff --git a/sys/dev/usb/usbdivar.h b/sys/dev/usb/usbdivar.h
index 3a7bac3c48c..59c42f0dcda 100644
--- a/sys/dev/usb/usbdivar.h
+++ b/sys/dev/usb/usbdivar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: usbdivar.h,v 1.69 2014/12/21 12:04:01 mpi Exp $ */
+/* $OpenBSD: usbdivar.h,v 1.70 2016/05/18 18:28:58 patrick Exp $ */
/* $NetBSD: usbdivar.h,v 1.70 2002/07/11 21:14:36 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/usbdivar.h,v 1.11 1999/11/17 22:33:51 n_hibma Exp $ */
@@ -150,6 +150,10 @@ struct usbd_device {
struct usbd_hub *hub; /* only if this is a hub */
struct device **subdevs; /* sub-devices, 0 terminated */
int ndevs; /* # of subdevs */
+
+ char *serial; /* serial number, can be NULL */
+ char *vendor; /* vendor string, can be NULL */
+ char *product; /* product string, can be NULL */
};
struct usbd_interface {
@@ -229,6 +233,7 @@ void usbd_dump_pipe(struct usbd_pipe *);
/* Routines from usb_subr.c */
int usbctlprint(void *, const char *);
+void usbd_get_device_strings(struct usbd_device *);
void usb_delay_ms(struct usbd_bus *, u_int);
usbd_status usbd_port_disown_to_1_1(struct usbd_device *, int);
int usbd_reset_port(struct usbd_device *, int);