summaryrefslogtreecommitdiff
path: root/sys/dev/usb
diff options
context:
space:
mode:
authorJacob Meuser <jakemsr@cvs.openbsd.org>2011-01-16 22:35:30 +0000
committerJacob Meuser <jakemsr@cvs.openbsd.org>2011-01-16 22:35:30 +0000
commitbf7dd43b0ff651c5b7ba593bceb215dc29ad45d7 (patch)
tree45e6e943d25ebc8148bddd5d6a8250fbb43a6d85 /sys/dev/usb
parent3ea785dfac3b842c38d5b36eb3a32b8af8086460 (diff)
* instead of NULLing pointers to interface descriptors in the uaa, mark
interfaces as being claimed in the usbd_device's copy of the interface descriptors * allow ugen(4) to be attached if there are unused interfaces in a configuration that has had drivers attached * make ugen(4) aware that it may be sharing a device with (an)other driver(s), and if so: * do not let ugen(4) change the configuration * do not let ugen(4) access the already claimed interfaces discussed with deraadt and miod
Diffstat (limited to 'sys/dev/usb')
-rw-r--r--sys/dev/usb/if_cdce.c6
-rw-r--r--sys/dev/usb/if_urndis.c6
-rw-r--r--sys/dev/usb/uaudio.c8
-rw-r--r--sys/dev/usb/ugen.c42
-rw-r--r--sys/dev/usb/umodem.c6
-rw-r--r--sys/dev/usb/usb_subr.c57
-rw-r--r--sys/dev/usb/usbdi.c20
-rw-r--r--sys/dev/usb/usbdi.h6
-rw-r--r--sys/dev/usb/usbdivar.h4
-rw-r--r--sys/dev/usb/uvideo.c28
10 files changed, 122 insertions, 61 deletions
diff --git a/sys/dev/usb/if_cdce.c b/sys/dev/usb/if_cdce.c
index cb91ba3e0b9..2e91ec8c0bb 100644
--- a/sys/dev/usb/if_cdce.c
+++ b/sys/dev/usb/if_cdce.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_cdce.c,v 1.47 2010/10/27 17:51:11 jakemsr Exp $ */
+/* $OpenBSD: if_cdce.c,v 1.48 2011/01/16 22:35:29 jakemsr Exp $ */
/*
* Copyright (c) 1997, 1998, 1999, 2000-2003 Bill Paul <wpaul@windriver.com>
@@ -224,12 +224,12 @@ cdce_attach(struct device *parent, struct device *self, void *aux)
DPRINTF(("cdce_attach: union interface: ctl=%d, data=%d\n",
ctl_ifcno, data_ifcno));
for (i = 0; i < uaa->nifaces; i++) {
- if (uaa->ifaces[i] == NULL)
+ if (usbd_iface_claimed(sc->cdce_udev, i))
continue;
id = usbd_get_interface_descriptor(uaa->ifaces[i]);
if (id != NULL && id->bInterfaceNumber == data_ifcno) {
sc->cdce_data_iface = uaa->ifaces[i];
- uaa->ifaces[i] = NULL;
+ usbd_claim_iface(sc->cdce_udev, i);
}
}
}
diff --git a/sys/dev/usb/if_urndis.c b/sys/dev/usb/if_urndis.c
index 29f9dd597b0..71a3a093593 100644
--- a/sys/dev/usb/if_urndis.c
+++ b/sys/dev/usb/if_urndis.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_urndis.c,v 1.27 2010/10/27 17:51:11 jakemsr Exp $ */
+/* $OpenBSD: if_urndis.c,v 1.28 2011/01/16 22:35:29 jakemsr Exp $ */
/*
* Copyright (c) 2010 Jonathan Armani <armani@openbsd.org>
@@ -1389,12 +1389,12 @@ urndis_attach(struct device *parent, struct device *self, void *aux)
DPRINTF(("urndis_attach: union interface: ctl %u, data %u\n",
if_ctl, if_data));
for (i = 0; i < uaa->nifaces; i++) {
- if (uaa->ifaces[i] == NULL)
+ if (usbd_iface_claimed(sc->sc_udev, i))
continue;
id = usbd_get_interface_descriptor(uaa->ifaces[i]);
if (id && id->bInterfaceNumber == if_data) {
sc->sc_iface_data = uaa->ifaces[i];
- uaa->ifaces[i] = NULL;
+ usbd_claim_iface(sc->sc_udev, i);
}
}
}
diff --git a/sys/dev/usb/uaudio.c b/sys/dev/usb/uaudio.c
index f91aaa1d57a..7a357bec7b0 100644
--- a/sys/dev/usb/uaudio.c
+++ b/sys/dev/usb/uaudio.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uaudio.c,v 1.89 2010/08/18 22:54:58 jakemsr Exp $ */
+/* $OpenBSD: uaudio.c,v 1.90 2011/01/16 22:35:29 jakemsr Exp $ */
/* $NetBSD: uaudio.c,v 1.90 2004/10/29 17:12:53 kent Exp $ */
/*
@@ -210,7 +210,6 @@ struct uaudio_softc {
struct device sc_dev; /* base device */
usbd_device_handle sc_udev; /* USB device */
int sc_ac_iface; /* Audio Control interface */
- usbd_interface_handle sc_ac_ifaceh;
struct chan sc_playchan; /* play channel */
struct chan sc_recchan; /* record channel */
int sc_nullalt;
@@ -520,10 +519,9 @@ uaudio_attach(struct device *parent, struct device *self, void *aux)
return;
}
- sc->sc_ac_ifaceh = uaa->iface;
/* Pick up the AS interface. */
for (i = 0; i < uaa->nifaces; i++) {
- if (uaa->ifaces[i] == NULL)
+ if (usbd_iface_claimed(sc->sc_udev, i))
continue;
id = usbd_get_interface_descriptor(uaa->ifaces[i]);
if (id == NULL)
@@ -537,7 +535,7 @@ uaudio_attach(struct device *parent, struct device *self, void *aux)
}
}
if (found)
- uaa->ifaces[i] = NULL;
+ usbd_claim_iface(sc->sc_udev, i);
}
for (j = 0; j < sc->sc_nalts; j++) {
diff --git a/sys/dev/usb/ugen.c b/sys/dev/usb/ugen.c
index 457b77cd894..8261bbe9c2d 100644
--- a/sys/dev/usb/ugen.c
+++ b/sys/dev/usb/ugen.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ugen.c,v 1.62 2010/09/24 08:33:59 yuo Exp $ */
+/* $OpenBSD: ugen.c,v 1.63 2011/01/16 22:35:29 jakemsr Exp $ */
/* $NetBSD: ugen.c,v 1.63 2002/11/26 18:49:48 christos Exp $ */
/* $FreeBSD: src/sys/dev/usb/ugen.c,v 1.26 1999/11/17 22:33:41 n_hibma Exp $ */
@@ -103,6 +103,7 @@ struct ugen_softc {
int sc_refcnt;
u_char sc_dying;
+ u_char sc_secondary;
};
void ugenintr(usbd_xfer_handle xfer, usbd_private_handle addr,
@@ -166,13 +167,18 @@ ugen_attach(struct device *parent, struct device *self, void *aux)
sc->sc_udev = udev = uaa->device;
- /* First set configuration index 0, the default one for ugen. */
- err = usbd_set_config_index(udev, 0, 0);
- if (err) {
- printf("%s: setting configuration index 0 failed\n",
- sc->sc_dev.dv_xname);
- sc->sc_dying = 1;
- return;
+ if (usbd_get_devcnt(udev) > 0)
+ sc->sc_secondary = 1;
+
+ if (!sc->sc_secondary) {
+ /* First set configuration index 0, the default one for ugen. */
+ err = usbd_set_config_index(udev, 0, 0);
+ if (err) {
+ printf("%s: setting configuration index 0 failed\n",
+ sc->sc_dev.dv_xname);
+ sc->sc_dying = 1;
+ return;
+ }
}
conf = usbd_get_config_descriptor(udev)->bConfigurationValue;
@@ -220,9 +226,15 @@ ugen_set_config(struct ugen_softc *sc, int configno)
/* Avoid setting the current value. */
cdesc = usbd_get_config_descriptor(dev);
if (!cdesc || cdesc->bConfigurationValue != configno) {
- err = usbd_set_config_no(dev, configno, 1);
- if (err)
- return (err);
+ if (sc->sc_secondary) {
+ printf("%s: secondary, not changing config to %d\n",
+ __func__, configno);
+ return (USBD_IN_USE);
+ } else {
+ err = usbd_set_config_no(dev, configno, 1);
+ if (err)
+ return (err);
+ }
}
err = usbd_interface_count(dev, &niface);
@@ -231,6 +243,11 @@ ugen_set_config(struct ugen_softc *sc, int configno)
memset(sc->sc_endpoints, 0, sizeof sc->sc_endpoints);
for (ifaceno = 0; ifaceno < niface; ifaceno++) {
DPRINTFN(1,("ugen_set_config: ifaceno %d\n", ifaceno));
+ if (usbd_iface_claimed(sc->sc_udev, ifaceno)) {
+ DPRINTF(("%s: iface %d not available\n", __func__,
+ ifaceno));
+ continue;
+ }
err = usbd_device2interface_handle(dev, ifaceno, &iface);
if (err)
return (err);
@@ -897,7 +914,8 @@ ugen_set_interface(struct ugen_softc *sc, int ifaceidx, int altno)
err = usbd_interface_count(sc->sc_udev, &niface);
if (err)
return (err);
- if (ifaceidx < 0 || ifaceidx >= niface)
+ if (ifaceidx < 0 || ifaceidx >= niface ||
+ usbd_iface_claimed(sc->sc_udev, ifaceidx))
return (USBD_INVAL);
err = usbd_device2interface_handle(sc->sc_udev, ifaceidx, &iface);
diff --git a/sys/dev/usb/umodem.c b/sys/dev/usb/umodem.c
index 4b55568eff1..cab12b62537 100644
--- a/sys/dev/usb/umodem.c
+++ b/sys/dev/usb/umodem.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: umodem.c,v 1.39 2010/12/02 01:37:45 jakemsr Exp $ */
+/* $OpenBSD: umodem.c,v 1.40 2011/01/16 22:35:29 jakemsr Exp $ */
/* $NetBSD: umodem.c,v 1.45 2002/09/23 05:51:23 simonb Exp $ */
/*
@@ -280,12 +280,12 @@ umodem_attach(struct device *parent, struct device *self, void *aux)
/* Get the data interface too. */
for (i = 0; i < uaa->nifaces; i++) {
- if (uaa->ifaces[i] != NULL) {
+ if (!usbd_iface_claimed(sc->sc_udev, i)) {
id = usbd_get_interface_descriptor(uaa->ifaces[i]);
if (id != NULL &&
id->bInterfaceNumber == data_iface_no) {
sc->sc_data_iface = uaa->ifaces[i];
- uaa->ifaces[i] = NULL;
+ usbd_claim_iface(sc->sc_udev, i);
}
}
}
diff --git a/sys/dev/usb/usb_subr.c b/sys/dev/usb/usb_subr.c
index 498c579b4db..b46b0649a6a 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.78 2011/01/15 23:58:43 jakemsr Exp $ */
+/* $OpenBSD: usb_subr.c,v 1.79 2011/01/16 22:35:29 jakemsr 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 $ */
@@ -777,7 +777,7 @@ usbd_set_config_index(usbd_device_handle dev, int index, int msg)
/* Allocate and fill interface data. */
nifc = cdp->bNumInterface;
dev->ifaces = malloc(nifc * sizeof(struct usbd_interface),
- M_USB, M_NOWAIT);
+ M_USB, M_NOWAIT | M_ZERO);
if (dev->ifaces == NULL) {
err = USBD_NOMEM;
goto bad;
@@ -859,14 +859,13 @@ usbd_getnewaddr(usbd_bus_handle bus)
return (-1);
}
-
usbd_status
usbd_probe_and_attach(struct device *parent, usbd_device_handle dev, int port,
int addr)
{
struct usb_attach_arg uaa;
usb_device_descriptor_t *dd = &dev->ddesc;
- int found, i, confi, nifaces, len;
+ int i, confi, nifaces, len;
usbd_status err;
struct device *dv;
usbd_interface_handle *ifaces;
@@ -895,8 +894,8 @@ usbd_probe_and_attach(struct device *parent, usbd_device_handle dev, int port,
err = USBD_NOMEM;
goto fail;
}
- dev->subdevs[0] = dv;
- dev->subdevs[1] = 0;
+ dev->subdevs[dev->ndevs++] = dv;
+ dev->subdevs[dev->ndevs] = 0;
err = USBD_NORMAL_COMPLETION;
goto fail;
}
@@ -934,7 +933,9 @@ usbd_probe_and_attach(struct device *parent, usbd_device_handle dev, int port,
ifaces[i] = &dev->ifaces[i];
uaa.ifaces = ifaces;
uaa.nifaces = nifaces;
- len = (nifaces+1) * sizeof dv;
+
+ /* add 1 for possible ugen and 1 for NULL terminator */
+ len = (nifaces + 2) * sizeof dv;
dev->subdevs = malloc(len, M_USB, M_NOWAIT | M_ZERO);
if (dev->subdevs == NULL) {
free(ifaces, M_USB);
@@ -942,25 +943,31 @@ usbd_probe_and_attach(struct device *parent, usbd_device_handle dev, int port,
goto fail;
}
- found = 0;
for (i = 0; i < nifaces; i++) {
- if (ifaces[i] == NULL)
- continue; /* interface already claimed */
+ if (usbd_iface_claimed(dev, i))
+ continue;
uaa.iface = ifaces[i];
uaa.ifaceno = ifaces[i]->idesc->bInterfaceNumber;
dv = config_found_sm(parent, &uaa, usbd_print,
usbd_submatch);
-
if (dv != NULL) {
- dev->subdevs[found++] = dv;
- ifaces[i] = NULL; /* consumed */
+ dev->subdevs[dev->ndevs++] = dv;
+ usbd_claim_iface(dev, i);
}
}
free(ifaces, M_USB);
- if (found != 0) {
- err = USBD_NORMAL_COMPLETION;
- goto fail;
+
+ if (dev->ndevs > 0) {
+ for (i = 0; i < nifaces; i++) {
+ if (!usbd_iface_claimed(dev, i))
+ break;
+ }
+ if (i < nifaces)
+ goto generic;
+ else
+ goto fail;
}
+
free(dev->subdevs, M_USB);
dev->subdevs = 0;
}
@@ -971,20 +978,24 @@ usbd_probe_and_attach(struct device *parent, usbd_device_handle dev, int port,
DPRINTF(("usbd_probe_and_attach: no interface drivers found\n"));
+generic:
/* Finally try the generic driver. */
uaa.iface = NULL;
uaa.usegeneric = 1;
- uaa.configno = UHUB_UNK_CONFIGURATION;
+ uaa.configno = dev->ndevs == 0 ? UHUB_UNK_CONFIGURATION :
+ dev->cdesc->bConfigurationValue;
uaa.ifaceno = UHUB_UNK_INTERFACE;
dv = config_found_sm(parent, &uaa, usbd_print, usbd_submatch);
if (dv != NULL) {
- dev->subdevs = malloc(2 * sizeof dv, M_USB, M_NOWAIT);
- if (dev->subdevs == 0) {
- err = USBD_NOMEM;
- goto fail;
+ if (dev->ndevs == 0) {
+ dev->subdevs = malloc(2 * sizeof dv, M_USB, M_NOWAIT);
+ if (dev->subdevs == NULL) {
+ err = USBD_NOMEM;
+ goto fail;
+ }
}
- dev->subdevs[0] = dv;
- dev->subdevs[1] = 0;
+ dev->subdevs[dev->ndevs++] = dv;
+ dev->subdevs[dev->ndevs] = 0;
err = USBD_NORMAL_COMPLETION;
goto fail;
}
diff --git a/sys/dev/usb/usbdi.c b/sys/dev/usb/usbdi.c
index 78e80e7c882..d0f90c25f9d 100644
--- a/sys/dev/usb/usbdi.c
+++ b/sys/dev/usb/usbdi.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: usbdi.c,v 1.42 2010/12/30 05:10:35 jakemsr Exp $ */
+/* $OpenBSD: usbdi.c,v 1.43 2011/01/16 22:35:29 jakemsr Exp $ */
/* $NetBSD: usbdi.c,v 1.103 2002/09/27 15:37:38 provos Exp $ */
/* $FreeBSD: src/sys/dev/usb/usbdi.c,v 1.28 1999/11/17 22:33:49 n_hibma Exp $ */
@@ -117,6 +117,24 @@ usbd_ref_wait(usbd_device_handle dev)
tsleep(&dev->ref_cnt, PWAIT, "usbref", hz * 60);
}
+int
+usbd_get_devcnt(usbd_device_handle dev)
+{
+ return (dev->ndevs);
+}
+
+void
+usbd_claim_iface(usbd_device_handle dev, int ifaceidx)
+{
+ dev->ifaces[ifaceidx].claimed = 1;
+}
+
+int
+usbd_iface_claimed(usbd_device_handle dev, int ifaceidx)
+{
+ return (dev->ifaces[ifaceidx].claimed);
+}
+
static __inline int
usbd_xfer_isread(usbd_xfer_handle xfer)
{
diff --git a/sys/dev/usb/usbdi.h b/sys/dev/usb/usbdi.h
index c7bc9a4c09e..0dd722f33ff 100644
--- a/sys/dev/usb/usbdi.h
+++ b/sys/dev/usb/usbdi.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: usbdi.h,v 1.37 2010/12/30 05:10:35 jakemsr Exp $ */
+/* $OpenBSD: usbdi.h,v 1.38 2011/01/16 22:35:29 jakemsr Exp $ */
/* $NetBSD: usbdi.h,v 1.62 2002/07/11 21:14:35 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/usbdi.h,v 1.18 1999/11/17 22:33:49 n_hibma Exp $ */
@@ -165,6 +165,10 @@ usbd_status usbd_reload_device_desc(usbd_device_handle);
int usbd_ratecheck(struct timeval *last);
+int usbd_get_devcnt(usbd_device_handle);
+void usbd_claim_iface(usbd_device_handle, int);
+int usbd_iface_claimed(usbd_device_handle, int);
+
int usbd_is_dying(usbd_device_handle);
void usbd_deactivate(usbd_device_handle);
diff --git a/sys/dev/usb/usbdivar.h b/sys/dev/usb/usbdivar.h
index f53369945ad..52d6ade7563 100644
--- a/sys/dev/usb/usbdivar.h
+++ b/sys/dev/usb/usbdivar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: usbdivar.h,v 1.41 2010/12/30 05:10:35 jakemsr Exp $ */
+/* $OpenBSD: usbdivar.h,v 1.42 2011/01/16 22:35:29 jakemsr 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 $ */
@@ -147,6 +147,7 @@ struct usbd_device {
const struct usbd_quirks *quirks; /* device quirks, always set */
struct usbd_hub *hub; /* only if this is a hub */
struct device **subdevs; /* sub-devices, 0 terminated */
+ int ndevs; /* # of subdevs */
};
struct usbd_interface {
@@ -157,6 +158,7 @@ struct usbd_interface {
struct usbd_endpoint *endpoints;
void *priv;
LIST_HEAD(, usbd_pipe) pipes;
+ u_int8_t claimed;
};
struct usbd_pipe {
diff --git a/sys/dev/usb/uvideo.c b/sys/dev/usb/uvideo.c
index 72a28548294..f0f85b5aba8 100644
--- a/sys/dev/usb/uvideo.c
+++ b/sys/dev/usb/uvideo.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uvideo.c,v 1.147 2010/11/24 19:53:07 jakemsr Exp $ */
+/* $OpenBSD: uvideo.c,v 1.148 2011/01/16 22:35:29 jakemsr Exp $ */
/*
* Copyright (c) 2008 Robert Nagy <robert@openbsd.org>
@@ -468,13 +468,24 @@ uvideo_attach(struct device *parent, struct device *self, void *aux)
{
struct uvideo_softc *sc = (struct uvideo_softc *)self;
struct usb_attach_arg *uaa = aux;
+ usb_interface_descriptor_t *id;
+ int i;
sc->sc_udev = uaa->device;
sc->sc_nifaces = uaa->nifaces;
- sc->sc_ifaces = malloc(uaa->nifaces * sizeof(usbd_interface_handle),
- M_USB, M_WAITOK);
- bcopy(uaa->ifaces, sc->sc_ifaces,
- uaa->nifaces * sizeof(usbd_interface_handle));
+ /*
+ * Claim all video interfaces. Interfaces must be claimed during
+ * attach, during attach hooks is too late.
+ */
+ for (i = 0; i < sc->sc_nifaces; i++) {
+ if (usbd_iface_claimed(sc->sc_udev, i))
+ continue;
+ id = usbd_get_interface_descriptor(&sc->sc_udev->ifaces[i]);
+ if (id == NULL)
+ continue;
+ if (id->bInterfaceClass == UICLASS_VIDEO)
+ usbd_claim_iface(sc->sc_udev, i);
+ }
/* maybe the device has quirks */
sc->sc_quirk = uvideo_lookup(uaa->vendor, uaa->product);
@@ -557,8 +568,6 @@ uvideo_detach(struct device *self, int flags)
struct uvideo_softc *sc = (struct uvideo_softc *)self;
int rv = 0;
- free(sc->sc_ifaces, M_USB);
-
/* Wait for outstanding requests to complete */
usbd_delay_ms(sc->sc_udev, UVIDEO_NFRAMES_MAX);
@@ -837,12 +846,13 @@ uvideo_vs_parse_desc(struct uvideo_softc *sc, usb_config_descriptor_t *cdesc)
for (i = 0; i < sc->sc_desc_vc_header.fix->bInCollection; i++) {
iface = sc->sc_desc_vc_header.baInterfaceNr[i];
- id = usbd_get_interface_descriptor(sc->sc_ifaces[iface]);
+ id = usbd_get_interface_descriptor(&sc->sc_udev->ifaces[iface]);
if (id == NULL) {
printf("%s: can't get VS interface %d!\n",
DEVNAME(sc), iface);
return (USBD_INVAL);
}
+ usbd_claim_iface(sc->sc_udev, iface);
numalts = usbd_get_no_alts(cdesc, id->bInterfaceNumber);
@@ -1197,7 +1207,7 @@ uvideo_vs_parse_desc_alt(struct uvideo_softc *sc, int vs_nr, int iface, int numa
/* save endpoint with largest bandwidth */
if (UGETW(ed->wMaxPacketSize) > vs->psize) {
- vs->ifaceh = sc->sc_ifaces[iface];
+ vs->ifaceh = &sc->sc_udev->ifaces[iface];
vs->endpoint = ed->bEndpointAddress;
vs->numalts = numalts;
vs->curalt = id->bAlternateSetting;