summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authordrochner <drochner@NetBSD.org>2008-07-28 15:22:01 +0000
committerdrochner <drochner@NetBSD.org>2008-07-28 15:22:01 +0000
commit6a47db887e26dfed1935dcef7f48449aa005e2be (patch)
tree9fa7821d8c4c7973cc39013ae3783c3dd109d5b0 /sys/dev
parent6b623b615a0dc1c8904d680bc22e14dafe6497eb (diff)
-in usbd_probe_and_attach(), split out the code for per-device and
per-interface attachment into individual functions, to ease maintainance and allow easier plugin of new attachment functions -keep a counter of USB interfaces in use on a device, and try to keep track of interfaces claimed by drivers behind the framework's back
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/usb/uhub.c7
-rw-r--r--sys/dev/usb/usb_subr.c157
-rw-r--r--sys/dev/usb/usbdivar.h3
3 files changed, 92 insertions, 75 deletions
diff --git a/sys/dev/usb/uhub.c b/sys/dev/usb/uhub.c
index 250231297db..8a7bdae0722 100644
--- a/sys/dev/usb/uhub.c
+++ b/sys/dev/usb/uhub.c
@@ -1,4 +1,4 @@
-/* $NetBSD: uhub.c,v 1.101 2008/06/16 10:37:54 drochner Exp $ */
+/* $NetBSD: uhub.c,v 1.102 2008/07/28 15:22:01 drochner Exp $ */
/* $FreeBSD: src/sys/dev/usb/uhub.c,v 1.18 1999/11/17 22:33:43 n_hibma Exp $ */
/*
@@ -36,7 +36,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uhub.c,v 1.101 2008/06/16 10:37:54 drochner Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uhub.c,v 1.102 2008/07/28 15:22:01 drochner Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -645,11 +645,10 @@ uhub_childdet(device_t self, device_t child)
for (i = 0; i < dev->subdevlen; i++) {
if (dev->subdevs[i] == child) {
dev->subdevs[i] = NULL;
- return;
+ dev->nifaces_claimed--;
}
}
}
- KASSERT(false);
}
diff --git a/sys/dev/usb/usb_subr.c b/sys/dev/usb/usb_subr.c
index 527e64fc344..50c2d461d66 100644
--- a/sys/dev/usb/usb_subr.c
+++ b/sys/dev/usb/usb_subr.c
@@ -1,4 +1,4 @@
-/* $NetBSD: usb_subr.c,v 1.159 2008/06/22 21:31:51 jmcneill Exp $ */
+/* $NetBSD: usb_subr.c,v 1.160 2008/07/28 15:22:01 drochner Exp $ */
/* $FreeBSD: src/sys/dev/usb/usb_subr.c,v 1.18 1999/11/17 22:33:47 n_hibma Exp $ */
/*
@@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: usb_subr.c,v 1.159 2008/06/22 21:31:51 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: usb_subr.c,v 1.160 2008/07/28 15:22:01 drochner Exp $");
#include "opt_compat_netbsd.h"
#include "opt_usbverbose.h"
@@ -793,22 +793,17 @@ usbd_attach_roothub(device_t parent, usbd_device_handle dev)
return (USBD_NORMAL_COMPLETION);
}
-usbd_status
-usbd_probe_and_attach(device_ptr_t parent, usbd_device_handle dev,
- int port, int addr)
+static usbd_status
+usbd_attachwholedevice(device_t parent, usbd_device_handle dev, int port,
+ int usegeneric)
{
struct usb_attach_arg uaa;
- struct usbif_attach_arg uiaa;
usb_device_descriptor_t *dd = &dev->ddesc;
- int found, i, confi, nifaces;
- usbd_status err;
- device_ptr_t dv;
- usbd_interface_handle *ifaces;
+ device_t dv;
int dlocs[USBDEVIFCF_NLOCS];
- int ilocs[USBIFIFCF_NLOCS];
uaa.device = dev;
- uaa.usegeneric = 0;
+ uaa.usegeneric = usegeneric;
uaa.port = port;
uaa.vendor = UGETW(dd->idVendor);
uaa.product = UGETW(dd->idProduct);
@@ -825,35 +820,96 @@ usbd_probe_and_attach(device_ptr_t parent, usbd_device_handle dev,
dlocs[USBDEVIFCF_CONFIGURATION] = -1;
dlocs[USBDEVIFCF_INTERFACE] = -1;
- /* First try with device specific drivers. */
- DPRINTF(("usbd_probe_and_attach: trying device specific drivers\n"));
dv = config_found_sm_loc(parent, "usbdevif", dlocs, &uaa, usbd_print,
- config_stdsubmatch);
+ config_stdsubmatch);
if (dv) {
dev->subdevs = malloc(sizeof dv, M_USB, M_NOWAIT);
if (dev->subdevs == NULL)
return (USBD_NOMEM);
dev->subdevs[0] = dv;
dev->subdevlen = 1;
- return (USBD_NORMAL_COMPLETION);
+ dev->nifaces_claimed = 1; /* XXX */
}
+ return (USBD_NORMAL_COMPLETION);
+}
- DPRINTF(("usbd_probe_and_attach: no device specific driver found\n"));
+static usbd_status
+usbd_attachinterfaces(device_t parent, usbd_device_handle dev, int port)
+{
+ struct usbif_attach_arg uiaa;
+ usb_device_descriptor_t *dd = &dev->ddesc;
+ int nifaces;
+ usbd_interface_handle *ifaces;
+ int i, j;
+ device_t dv;
+ int ilocs[USBIFIFCF_NLOCS];
+
+ nifaces = dev->cdesc->bNumInterface;
+ ifaces = malloc(nifaces * sizeof(*ifaces), M_USB, M_NOWAIT|M_ZERO);
+ if (!ifaces)
+ return (USBD_NOMEM);
+ for (i = 0; i < nifaces; i++)
+ if (!dev->subdevs[i])
+ ifaces[i] = &dev->ifaces[i];
uiaa.device = dev;
uiaa.port = port;
uiaa.vendor = UGETW(dd->idVendor);
uiaa.product = UGETW(dd->idProduct);
uiaa.release = UGETW(dd->bcdDevice);
-
+ uiaa.configno = dev->cdesc->bConfigurationValue;
+ uiaa.ifaces = ifaces;
+ uiaa.nifaces = nifaces;
ilocs[USBIFIFCF_PORT] = uiaa.port;
ilocs[USBIFIFCF_VENDOR] = uiaa.vendor;
ilocs[USBIFIFCF_PRODUCT] = uiaa.product;
ilocs[USBIFIFCF_RELEASE] = uiaa.release;
+ ilocs[USBIFIFCF_CONFIGURATION] = uiaa.configno;
+
+ for (i = 0; i < nifaces; i++) {
+ if (!ifaces[i])
+ continue; /* interface already claimed */
+ uiaa.iface = ifaces[i];
+ uiaa.class = ifaces[i]->idesc->bInterfaceClass;
+ uiaa.subclass = ifaces[i]->idesc->bInterfaceSubClass;
+ uiaa.proto = ifaces[i]->idesc->bInterfaceProtocol;
+ uiaa.ifaceno = ifaces[i]->idesc->bInterfaceNumber;
+ ilocs[USBIFIFCF_INTERFACE] = uiaa.ifaceno;
+ dv = config_found_sm_loc(parent, "usbifif", ilocs, &uiaa,
+ usbd_ifprint, config_stdsubmatch);
+ if (!dv)
+ continue;
+ ifaces[i] = 0; /* claim */
+ /* account for ifaces claimed by the driver behind our back */
+ for (j = 0; j < nifaces; j++) {
+ if (!ifaces[j] && !dev->subdevs[j]) {
+ dev->subdevs[j] = dv;
+ dev->nifaces_claimed++;
+ }
+ }
+ }
+
+ free(ifaces, M_USB);
+ return (USBD_NORMAL_COMPLETION);
+}
+
+usbd_status
+usbd_probe_and_attach(device_ptr_t parent, usbd_device_handle dev,
+ int port, int addr)
+{
+ usb_device_descriptor_t *dd = &dev->ddesc;
+ int confi, nifaces;
+ usbd_status err;
+
+ /* First try with device specific drivers. */
+ DPRINTF(("usbd_probe_and_attach: trying device specific drivers\n"));
+ err = usbd_attachwholedevice(parent, dev, port, 0);
+ if (dev->nifaces_claimed || err)
+ return (err);
+ DPRINTF(("usbd_probe_and_attach: no device specific driver found\n"));
DPRINTF(("usbd_probe_and_attach: looping over %d configurations\n",
dd->bNumConfigurations));
- /* Next try with interface drivers. */
for (confi = 0; confi < dd->bNumConfigurations; confi++) {
DPRINTFN(1,("usbd_probe_and_attach: trying config idx=%d\n",
confi));
@@ -870,51 +926,21 @@ usbd_probe_and_attach(device_ptr_t parent, usbd_device_handle dev,
return (err);
}
nifaces = dev->cdesc->bNumInterface;
- uiaa.configno = dev->cdesc->bConfigurationValue;
- ilocs[USBIFIFCF_CONFIGURATION] = uiaa.configno;
-
- ifaces = malloc(nifaces * sizeof(*ifaces), M_USB, M_NOWAIT);
- if (ifaces == NULL)
- goto nomem;
- for (i = 0; i < nifaces; i++)
- ifaces[i] = &dev->ifaces[i];
- uiaa.ifaces = ifaces;
- uiaa.nifaces = nifaces;
- dev->subdevs = malloc(nifaces * sizeof dv, M_USB,
+ dev->subdevs = malloc(nifaces * sizeof(device_t), M_USB,
M_NOWAIT|M_ZERO);
- if (dev->subdevs == NULL) {
- free(ifaces, M_USB);
-nomem:
+ if (dev->subdevs == NULL)
return (USBD_NOMEM);
- }
dev->subdevlen = nifaces;
- found = 0;
- for (i = 0; i < nifaces; i++) {
- if (ifaces[i] == NULL)
- continue; /* interface already claimed */
- uiaa.iface = ifaces[i];
- uiaa.class = ifaces[i]->idesc->bInterfaceClass;
- uiaa.subclass = ifaces[i]->idesc->bInterfaceSubClass;
- uiaa.proto = ifaces[i]->idesc->bInterfaceProtocol;
- uiaa.ifaceno = ifaces[i]->idesc->bInterfaceNumber;
- ilocs[USBIFIFCF_INTERFACE] = uiaa.ifaceno;
- dv = config_found_sm_loc(parent, "usbifif", ilocs, &uiaa,
- usbd_ifprint, config_stdsubmatch);
- if (dv != NULL) {
- found++;
- dev->subdevs[i] = dv;
- ifaces[i] = 0; /* consumed */
- }
- }
- if (found != 0) {
- free(ifaces, M_USB);
- return (USBD_NORMAL_COMPLETION);
+ err = usbd_attachinterfaces(parent, dev, port);
+
+ if (!dev->nifaces_claimed) {
+ free(dev->subdevs, M_USB);
+ dev->subdevs = 0;
+ dev->subdevlen = 0;
}
- free(ifaces, M_USB);
- free(dev->subdevs, M_USB);
- dev->subdevs = 0;
- dev->subdevlen = 0;
+ if (dev->nifaces_claimed || err)
+ return (err);
}
/* No interfaces were attached in any of the configurations. */
@@ -924,17 +950,7 @@ nomem:
DPRINTF(("usbd_probe_and_attach: no interface drivers found\n"));
/* Finally try the generic driver. */
- uaa.usegeneric = 1;
- dv = config_found_sm_loc(parent, "usbdevif", dlocs, &uaa, usbd_print,
- config_stdsubmatch);
- if (dv != NULL) {
- dev->subdevs = malloc(sizeof dv, M_USB, M_NOWAIT);
- if (dev->subdevs == 0)
- return (USBD_NOMEM);
- dev->subdevs[0] = dv;
- dev->subdevlen = 1;
- return (USBD_NORMAL_COMPLETION);
- }
+ err = usbd_attachwholedevice(parent, dev, port, 1);
/*
* The generic attach failed, but leave the device as it is.
@@ -1432,6 +1448,7 @@ usb_disconnect_port(struct usbd_port *up, device_ptr_t parent)
printf(" (addr %d) disconnected\n", dev->address);
config_detach(dev->subdevs[i], DETACH_FORCE);
}
+ KASSERT(!dev->nifaces_claimed);
}
usbd_add_dev_event(USB_EVENT_DEVICE_DETACH, dev);
diff --git a/sys/dev/usb/usbdivar.h b/sys/dev/usb/usbdivar.h
index 99e6cad6ebe..67d797db9db 100644
--- a/sys/dev/usb/usbdivar.h
+++ b/sys/dev/usb/usbdivar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: usbdivar.h,v 1.86 2008/05/26 18:00:33 drochner Exp $ */
+/* $NetBSD: usbdivar.h,v 1.87 2008/07/28 15:22:01 drochner Exp $ */
/* $FreeBSD: src/sys/dev/usb/usbdivar.h,v 1.11 1999/11/17 22:33:51 n_hibma Exp $ */
/*
@@ -143,6 +143,7 @@ struct usbd_device {
struct usbd_hub *hub; /* only if this is a hub */
int subdevlen; /* array length of following */
device_t *subdevs; /* sub-devices */
+ int nifaces_claimed; /* number of ifaces in use */
};
struct usbd_interface {