tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

USB autoconf rework, updated patches



Here are the patches again, updated for -current after the last
device_t etc cleanups.

All drivers which don't attach to the whole device but to
interfaces use a "udev" helper device now, so a kernel
config file should include:
udev* at uhub? port ?
uhidev* at udev?
etc -- the kernel config(8) program will complain where
necessary.

I hope that this framework will make loadable USB
drivers more straightforward, and that it will allow
to access single interfaces of a multifunction device
to be accessed by the generic "ugen" driver.

Please review and comment.

best regards
Matthias





-------------------------------------------------------------------
-------------------------------------------------------------------
Forschungszentrum Juelich GmbH
52425 Juelich

Sitz der Gesellschaft: Juelich
Eingetragen im Handelsregister des Amtsgerichts Dueren Nr. HR B 3498
Vorsitzende des Aufsichtsrats: MinDir'in Baerbel Brumme-Bothe
Geschaeftsfuehrung: Prof. Dr. Achim Bachem (Vorsitzender),
Dr. Ulrich Krafft (stellv. Vorsitzender), Prof. Dr. Harald Bolt,
Dr. Sebastian M. Schmidt
-------------------------------------------------------------------
-------------------------------------------------------------------
#
#
# add_file "sys/dev/usb/udev.c"
#  content [23147124ea5b88485292bd5b1cc2f78850e76ed2]
# 
# add_file "sys/dev/usb/udev_ugen.c"
#  content [6d9db30d8029c4610d4e201e8f6953a208aab6f4]
# 
# add_file "sys/dev/usb/udevvar.h"
#  content [74d091553b93202dd54c25e08fc7c3a827a6d9ed]
# 
# add_file "sys/dev/usb/usbfunction.h"
#  content [2bd3396fefb32af2b2dec61f26237f8ecef48c05]
# 
# add_file "sys/dev/usb/usbiadreg.h"
#  content [9bf158738f9406942171989748462e30ca213ae4]
# 
# patch "sys/dev/usb/files.usb"
#  from [27a8673fba807146c4a3084b06ca2ecb34a34a5b]
#    to [2655b0ffc9f928e4d090e67a8b79f2c70998ca10]
# 
# patch "sys/dev/usb/uaudio.c"
#  from [5abb92f27d812ca7874ece4b315a30fba814f05f]
#    to [bb1a24d95a6da0476ebaec20db49714deb060e43]
# 
# patch "sys/dev/usb/ugen.c"
#  from [886fadd3c361883d19a0f9eaa47bf36459447da8]
#    to [cc9fc12f9de117bc531e196d4f7413cc6340c041]
# 
# patch "sys/dev/usb/uhub.c"
#  from [abf3f4739bd6526ebaaff9a74f30930463409368]
#    to [3a52f88cc8b7762f0a563b90813cd6d2c0ba9699]
# 
# patch "sys/dev/usb/usb.c"
#  from [baec30d7b668d7cf3bbd524c02dfb3cbf419c4a7]
#    to [7f1eec27c3342ca4ae28105ca8ccf80238b97ade]
# 
# patch "sys/dev/usb/usb.h"
#  from [572dc8d893c531cf62045994fcde0d59b80935c7]
#    to [9fc7925ca6786f49e560b52787e6069152d32d59]
# 
# patch "sys/dev/usb/usb_subr.c"
#  from [1fa1e08204f9bee75e9c9c02cde89c00af1f234f]
#    to [5185dec78577f35c713201070097a20f32ef636f]
# 
# patch "sys/dev/usb/usbdi.h"
#  from [be5af7b140f06fc59cf93bac23beb29b4375bb22]
#    to [5895a90b548c10073af09eb416eda0788ceb5bd0]
# 
# patch "sys/dev/usb/usbdivar.h"
#  from [6b9a9d672cd3d7efddc7fba805ba08420ea69f75]
#    to [72189560a2de33ba34088cb2a540f66c3fed2127]
#
============================================================
--- sys/dev/usb/udev.c  23147124ea5b88485292bd5b1cc2f78850e76ed2
+++ sys/dev/usb/udev.c  23147124ea5b88485292bd5b1cc2f78850e76ed2
@@ -0,0 +1,455 @@
+/* $NetBSD$ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+
+#include <sys/device.h>
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdi_util.h>
+#include <sys/bus.h>
+#include <dev/usb/usbdivar.h>
+#include <dev/usb/usbiadreg.h>
+#include <dev/usb/usbfunction.h>
+#include <dev/usb/udevvar.h>
+
+static int udev_match(device_t, struct cfdata *, void *);
+static void udev_attach(device_t, device_t, void *);
+static int udev_detach(device_t, int);
+static void udev_childdetached(device_t, device_t);
+static int ucmp_ifprint(void *, const char *);
+static int ucmp_fifprint(void *, const char *);
+
+CFATTACH_DECL2_NEW(udev, sizeof(struct udev_softc),
+                  udev_match, udev_attach, udev_detach,
+                  NULL,
+                  NULL, udev_childdetached);
+
+static int
+udev_match(device_t parent, struct cfdata *match, void *aux)
+{
+       /* struct usb_attach_arg *uaa = aux; */
+
+       /* match all at a priority lower than device specific drivers */
+       return 1;
+}
+
+/*
+ * The historical way of attaching drivers which attach to an interface.
+ * This does not handle drivers well which access multiple interfaces.
+ * Needs to be kept until all drivers are converted.
+ */
+static void
+udev_compat_attachinterfaces(struct udev_softc *sc)
+{
+       usbd_device_handle dev = sc->sc_udev;
+       usb_device_descriptor_t *dd = &dev->ddesc;
+       struct usbif_attach_arg uiaa;
+       int locs[USBIFIFCF_NLOCS];
+       int i;
+       device_t dv;
+
+       KASSERT(sc->sc_configlock);
+
+       uiaa.device = dev;
+       uiaa.port = sc->sc_port;
+       uiaa.vendor = UGETW(dd->idVendor);
+       uiaa.product = UGETW(dd->idProduct);
+       uiaa.release = UGETW(dd->bcdDevice);
+       uiaa.configno = dev->cdesc->bConfigurationValue;
+       uiaa.nifaces = sc->sc_nifaces;
+       uiaa.ifaces = sc->sc_ifaces;
+       locs[USBIFIFCF_PORT] = uiaa.port;
+       locs[USBIFIFCF_VENDOR] = uiaa.vendor;
+       locs[USBIFIFCF_PRODUCT] = uiaa.product;
+       locs[USBIFIFCF_RELEASE] = uiaa.release;
+       locs[USBIFIFCF_CONFIGURATION] = uiaa.configno;
+
+       for (i = 0; i < sc->sc_nifaces; i++) {
+               if (sc->sc_subdevs[i])
+                       continue; /* interface already claimed */
+               uiaa.iface = sc->sc_ifaces[i];
+               uiaa.class = sc->sc_ifaces[i]->idesc->bInterfaceClass;
+               uiaa.subclass = sc->sc_ifaces[i]->idesc->bInterfaceSubClass;
+               uiaa.proto = sc->sc_ifaces[i]->idesc->bInterfaceProtocol;
+               /* ifaceno should be i, else we have a strange device */
+               uiaa.ifaceno = sc->sc_ifaces[i]->idesc->bInterfaceNumber;
+               locs[USBIFIFCF_INTERFACE] = uiaa.ifaceno;
+               dv = config_found_sm_loc(sc->sc_dev, "usbifif", locs, &uiaa,
+                                        ucmp_ifprint, config_stdsubmatch);
+               if (dv) {
+                       sc->sc_subdevs[i] = dv;
+                       sc->sc_nifaces_claimed++;
+               }
+       }
+}
+
+static int
+ucmp_ifprint(void *aux, const char *pnp)
+{
+       struct usbif_attach_arg *uaa = aux;
+
+       if (pnp)
+               return (QUIET);
+       aprint_normal(" configuration %d interface %d",
+                     uaa->configno, uaa->ifaceno);
+       return (UNCONF);
+}
+
+static void
+udev_attachinterfaces(struct udev_softc *sc)
+{
+       usbd_device_handle dev = sc->sc_udev;
+       struct usbfunction_attach_args ufaa;
+       int locs[USBFIFCF_NLOCS];
+       int i;
+       device_t dv;
+
+       KASSERT(sc->sc_configlock);
+
+       ufaa.device = dev;
+       ufaa.type = USBF_INTERFACE;
+
+       for (i = 0; i < sc->sc_nifaces; i++) {
+               if (sc->sc_subdevs[i])
+                       continue; /* interface already claimed */
+               ufaa.ifaces = &sc->sc_ifaces[i];
+               ufaa.nifaces = 1;
+               ufaa.class = sc->sc_ifaces[i]->idesc->bInterfaceClass;
+               ufaa.subclass = sc->sc_ifaces[i]->idesc->bInterfaceSubClass;
+               ufaa.proto = sc->sc_ifaces[i]->idesc->bInterfaceProtocol;
+               /* ifaceno should be i, else we have a strange device */
+               ufaa.ifaceno = sc->sc_ifaces[i]->idesc->bInterfaceNumber;
+               locs[USBFIFCF_INTERFACE] = ufaa.ifaceno;
+               dv = config_found_sm_loc(sc->sc_dev, "usbfif", locs, &ufaa,
+                                        ucmp_fifprint, config_stdsubmatch);
+               if (dv) {
+                       sc->sc_subdevs[i] = dv;
+                       sc->sc_nifaces_claimed++;
+               }
+       }
+}
+
+/*
+ * attach by IADs
+ */
+static void
+udev_scaniads(struct udev_softc *sc)
+{
+       usbd_device_handle dev = sc->sc_udev;
+       usbd_desc_iter_t di;
+       const usb_descriptor_t *d;
+       const usb_interface_association_descriptor_t *iad;
+       struct usbfunction_attach_args ufaa;
+       usbd_interface_handle *ifs;
+       int ifbusy, i;
+       int locs[USBFIFCF_NLOCS];
+       device_t dv;
+
+       KASSERT(sc->sc_configlock);
+
+       usb_desc_iter_init(dev, &di);
+       while ((d = usb_desc_iter_next(&di))) {
+               if (d->bDescriptorType != UDESC_INTERFACE_ASSOCIATION)
+                       continue;
+               iad = (const usb_interface_association_descriptor_t *)d;
+
+               if (iad->bFirstInterface + iad->bInterfaceCount
+                   > sc->sc_nifaces) {
+                       printf("%s: invalid iad\n", device_xname(sc->sc_dev));
+                       return;
+               }
+
+               ifbusy = 0;
+               for (i = 0; i < iad->bInterfaceCount; i++) {
+                       if (sc->sc_subdevs[iad->bFirstInterface + i]) {
+                               ifbusy++;
+                               break;
+                       }
+               }
+               if (ifbusy)
+                       continue;
+
+               ifs = malloc(iad->bInterfaceCount
+                            * sizeof(usbd_interface_handle *),
+                            M_USBDEV, M_NOWAIT);
+               if (!ifs)
+                       return;
+               for (i = 0; i < iad->bInterfaceCount; i++)
+                       ifs[i] = sc->sc_ifaces[iad->bFirstInterface + i];
+               ufaa.ifaces = ifs;
+               ufaa.nifaces = iad->bInterfaceCount;
+               ufaa.class = iad->bFunctionClass;
+               ufaa.subclass = iad->bFunctionSubClass;
+               ufaa.proto = iad->bFunctionProtocol;
+               ufaa.device = dev;
+               ufaa.ifaceno = iad->bFirstInterface;
+               ufaa.type = USBF_IAD;
+               locs[USBFIFCF_INTERFACE] = ufaa.ifaceno;
+               dv = config_found_sm_loc(sc->sc_dev, "usbfif", locs, &ufaa,
+                                        ucmp_fifprint, config_stdsubmatch);
+               if (dv) {
+                       for (i = 0; i < iad->bInterfaceCount; i++)
+                               sc->sc_subdevs[iad->bFirstInterface + i] = dv;
+                       sc->sc_nifaces_claimed += iad->bInterfaceCount;
+               }
+               free(ifs, M_USBDEV);
+       }
+}
+
+/*
+ * handle audio devices without IADs: look for multiple audio interfaces
+ * (need at least one control and one streaming interface)
+ */
+static void
+udev_scanaudio(struct udev_softc *sc)
+{
+       usbd_device_handle dev = sc->sc_udev;
+       struct usbfunction_attach_args ufaa;
+       usbd_interface_handle *ifs;
+       int *ifacenrs;
+       int locs[USBFIFCF_NLOCS];
+       int naudioif, i, j;
+       device_t dv;
+
+       KASSERT(sc->sc_configlock);
+
+       naudioif = 0;
+       for (i = 0; i < sc->sc_nifaces; i++) {
+               if (sc->sc_subdevs[i])
+                       continue; /* interface already claimed */
+               if (sc->sc_ifaces[i]->idesc->bInterfaceClass == UICLASS_AUDIO)
+                       naudioif++;
+       }
+       if (naudioif < 2)
+               return;
+
+       ifs = malloc(naudioif * sizeof(usbd_interface_handle *),
+                    M_USBDEV, M_NOWAIT);
+       if (!ifs)
+               return;
+       ifacenrs = malloc(naudioif * sizeof(int), M_USBDEV, M_NOWAIT);
+       if (!ifacenrs) {
+               free(ifs, M_USBDEV);
+               return;
+       }
+       j = 0;
+       for (i = 0; i < sc->sc_nifaces; i++) {
+               if (sc->sc_subdevs[i])
+                       continue; /* interface already claimed */
+               if (sc->sc_ifaces[i]->idesc->bInterfaceClass == UICLASS_AUDIO) {
+                       ifs[j] = sc->sc_ifaces[i];
+                       ifacenrs[j] = i;
+                       j++;
+                       if (j == naudioif)
+                               break;
+               }
+       }
+       if (j != naudioif) {
+               printf("udev_scanaudio: lost interface\n");
+               free(ifs, M_USBDEV);
+               return;
+       }
+
+       ufaa.device = dev;
+       ufaa.type = USBF_LEGACYAUDIO;
+       ufaa.class = UICLASS_AUDIO;
+       ufaa.subclass = 0;
+       ufaa.proto = 0;
+       ufaa.ifaces = ifs;
+       ufaa.nifaces = naudioif;
+       ufaa.ifaceno = ifacenrs[0];
+       locs[USBFIFCF_INTERFACE] = ufaa.ifaceno;
+       dv = config_found_sm_loc(sc->sc_dev, "usbfif", locs, &ufaa,
+                                ucmp_fifprint, config_stdsubmatch);
+       if (dv) {
+               for (i = 0; i < naudioif; i++)
+                       sc->sc_subdevs[ifacenrs[i]] = dv;
+               sc->sc_nifaces_claimed += naudioif;
+       }
+       free(ifs, M_USBDEV);
+       free(ifacenrs, M_USBDEV);
+}
+
+
+static int
+ucmp_fifprint(void *aux, const char *pnp)
+{
+       struct usbfunction_attach_args *uaa = aux;
+
+       if (pnp) {
+               if (uaa->type == USBF_IAD)
+                       aprint_normal("IAD device (class=%d) at %s",
+                                     uaa->class, pnp);
+               else if (uaa->type == USBF_LEGACYAUDIO)
+                       aprint_normal("legacy audio device at %s", pnp);
+               else
+                       return (QUIET);
+       }
+       aprint_normal(" interface %d", uaa->ifaceno);
+       return (UNCONF);
+}
+
+static int
+udev_setconfig(struct udev_softc *sc, int configidx)
+{
+       usbd_device_handle dev = sc->sc_udev;
+       usbd_status err;
+       int nifaces, i;
+
+       if (sc->sc_configlock) {
+               if (configidx == dev->cdesc->iConfiguration)
+                       return 0;
+               else
+                       return EAGAIN;
+       }
+       sc->sc_configlock = 1;
+       KASSERT(sc->sc_nifaces_claimed == 0);
+
+       err = usbd_set_config_index(dev, configidx, 1);
+       if (err) {
+               printf("set config failed\n");
+               sc->sc_configlock = 0;
+               return EIO;
+       }
+
+       nifaces = dev->cdesc->bNumInterface;
+       sc->sc_ifaces = malloc(nifaces * sizeof(usbd_interface_handle),
+                              M_USBDEV, M_NOWAIT);
+       if (!sc->sc_ifaces) {
+               sc->sc_configlock = 0;
+               return ENOMEM;
+       }
+       for (i = 0; i < nifaces; i++)
+               sc->sc_ifaces[i] = &dev->ifaces[i];
+       sc->sc_nifaces = nifaces;
+
+       sc->sc_subdevs = malloc(nifaces * sizeof(device_t),
+                               M_USBDEV, M_NOWAIT | M_ZERO);
+       if (!sc->sc_subdevs) {
+               free(sc->sc_ifaces, M_USBDEV);
+               sc->sc_ifaces = 0;
+               sc->sc_configlock = 0;
+               return ENOMEM;
+       }
+
+       return 0;
+}
+
+static void
+udev_freeconfig(struct udev_softc *sc)
+{
+
+       KASSERT(sc->sc_nifaces_claimed == 0);
+       KASSERT(sc->sc_configlock);
+       KASSERT(sc->sc_subdevs && sc->sc_ifaces);
+
+       free(sc->sc_ifaces, M_USBDEV);
+       sc->sc_ifaces = 0;
+       free(sc->sc_subdevs, M_USBDEV);
+       sc->sc_subdevs = 0;
+
+       sc->sc_configlock = 0;
+}
+
+static void
+udev_attach(device_t parent, device_t self, void *aux)
+{
+       struct udev_softc *sc = device_private(self);
+       struct usb_attach_arg *uaa = aux;
+       char *devinfop;
+       int res, confi;
+       usbd_device_handle dev = uaa->device;
+       usb_device_descriptor_t *dd = &dev->ddesc;
+
+       sc->sc_dev = self;
+       sc->sc_udev = uaa->device;
+       sc->sc_port = uaa->port;
+
+       devinfop = usbd_devinfo_alloc(sc->sc_udev, 0);
+       printf(": %s\n", devinfop);
+       usbd_devinfo_free(devinfop);
+
+       if (!pmf_device_register(self, NULL, NULL))
+               aprint_error_dev(self, "couldn't establish power handler\n");
+
+       if ((uaa->class == UDCLASS_MISC) &&
+           (uaa->subclass == UDSUBCLASS_COMMON) &&
+           (uaa->proto == UDPROTO_IAD)) {
+               res = udev_setconfig(sc, 0);
+               if (!res) {
+                       udev_scaniads(sc);
+                       if (!sc->sc_nifaces_claimed)
+                               udev_freeconfig(sc);
+               }
+       }
+
+       for (confi = 0; confi < dd->bNumConfigurations; confi++) {
+               res = udev_setconfig(sc, confi);
+               if (res) {
+                       /*
+                        * should catch the case that devices were attached
+                        * with other configurations
+                        */
+                       continue;
+               }
+
+               udev_scanaudio(sc);
+               udev_attachinterfaces(sc);
+               udev_compat_attachinterfaces(sc);
+
+               if (sc->sc_nifaces_claimed != 0) {
+                       /*
+                        * no point in trying other configs, we are not allowed
+                        * to switch anyway
+                        */
+                       break;
+               } else
+                       udev_freeconfig(sc);
+       }
+
+       KASSERT(sc->sc_configlock == (sc->sc_nifaces_claimed != 0));
+
+       udev_ugen_attachcheck(sc);
+}
+
+static int
+udev_detach(device_t self, int flags)
+{
+       struct udev_softc *sc = device_private(self);
+       int res;
+
+       res = config_detach_children(self, flags);
+       if (res)
+               return res;
+
+       KASSERT(sc->sc_nifaces_claimed == 0);
+       KASSERT(!sc->sc_configlock);
+       KASSERT(!sc->sc_subdevs && !sc->sc_ifaces);
+       return 0;
+}
+
+static void
+udev_childdetached(device_t self, device_t dev)
+{
+       struct udev_softc *sc = device_private(self);
+       int i;
+
+       udev_ugen_detachcheck(sc, dev);
+
+       if (sc->sc_configlock) {
+               for (i = 0; i < sc->sc_nifaces; i++) {
+                       if (sc->sc_subdevs[i] == dev) {
+                               sc->sc_subdevs[i] = 0;
+                               sc->sc_nifaces_claimed--;
+                       }
+               }
+               if (!sc->sc_nifaces_claimed)
+                       udev_freeconfig(sc);
+       }
+
+#if 0 /* XXX allow interfaces now free, check not dying */
+       udev_ugen_attachcheck(sc);
+#endif
+}
============================================================
--- sys/dev/usb/udev_ugen.c     6d9db30d8029c4610d4e201e8f6953a208aab6f4
+++ sys/dev/usb/udev_ugen.c     6d9db30d8029c4610d4e201e8f6953a208aab6f4
@@ -0,0 +1,55 @@
+/* $NetBSD$ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <sys/bus.h>
+#include <dev/usb/usbdivar.h>
+#include <dev/usb/udevvar.h>
+
+/*
+ * XXX compatibility for now: only attach if no interface claimed,
+ * and keep attach args from usbdevif
+ */
+
+static int
+ugen_print(void *aux, const char *pnp)
+{
+
+       return (UNCONF);
+}
+
+void
+udev_ugen_attachcheck(struct udev_softc *sc)
+{
+       usbd_device_handle udev;
+       usb_device_descriptor_t *dd;
+       struct usb_attach_arg uaa;
+
+       if (sc->sc_ugendev || sc->sc_nifaces_claimed)
+               return;
+
+       udev = sc->sc_udev;
+       dd = &udev->ddesc;
+       uaa.device = udev;
+       uaa.port = sc->sc_port;
+       uaa.vendor = UGETW(dd->idVendor);
+       uaa.product = UGETW(dd->idProduct);
+       uaa.release = UGETW(dd->bcdDevice);
+       uaa.class = dd->bDeviceClass;
+       uaa.subclass = dd->bDeviceSubClass;
+       uaa.proto = dd->bDeviceProtocol;
+
+       sc->sc_ugendev = config_found_sm_loc(sc->sc_dev, "usbgenif", NULL,
+                               &uaa, ugen_print, NULL);
+}
+
+void
+udev_ugen_detachcheck(struct udev_softc *sc, device_t child)
+{
+
+       if (child == sc->sc_ugendev)
+               sc->sc_ugendev = 0;
+}
============================================================
--- sys/dev/usb/udevvar.h       74d091553b93202dd54c25e08fc7c3a827a6d9ed
+++ sys/dev/usb/udevvar.h       74d091553b93202dd54c25e08fc7c3a827a6d9ed
@@ -0,0 +1,19 @@
+/* $NetBSD$ */
+
+struct udev_softc {
+       device_t sc_dev;
+       usbd_device_handle sc_udev;
+       int sc_port; /* XXX only for historical attach arg */
+
+       int sc_configlock; /* set config disallowed */
+
+       int sc_nifaces; /* array length for following two */
+       usbd_interface_handle *sc_ifaces;
+       device_t *sc_subdevs; /* owner per interface */
+       int sc_nifaces_claimed;
+
+       device_t sc_ugendev;
+};
+
+void udev_ugen_attachcheck(struct udev_softc *);
+void udev_ugen_detachcheck(struct udev_softc *, device_t);
============================================================
--- sys/dev/usb/usbfunction.h   2bd3396fefb32af2b2dec61f26237f8ecef48c05
+++ sys/dev/usb/usbfunction.h   2bd3396fefb32af2b2dec61f26237f8ecef48c05
@@ -0,0 +1,15 @@
+
+struct usbfunction_attach_args {
+       usbd_device_handle device;
+       int type;
+#define USBF_INTERFACE 1 /* just a single interface */
+#define USBF_IAD 2 /* interface group described by an IAD */
+#define USBF_LEGACYAUDIO 3 /* group of audio interfaces */
+#define USBF_CDC 4 /* CDC UFC (not implemented yet) */
+
+       int class, subclass, proto;
+
+       usbd_interface_handle *ifaces;
+       int nifaces;
+       int ifaceno; /* first one, as locator */
+};
============================================================
--- sys/dev/usb/usbiadreg.h     9bf158738f9406942171989748462e30ca213ae4
+++ sys/dev/usb/usbiadreg.h     9bf158738f9406942171989748462e30ca213ae4
@@ -0,0 +1,14 @@
+/* $NetBSD$ */
+
+typedef struct {
+       uByte           bLength;
+       uByte           bDescriptorType;
+       uByte           bFirstInterface;
+       uByte           bInterfaceCount;
+       uByte           bFunctionClass;
+       uByte           bFunctionSubClass;
+       uByte           bFunctionProtocol;
+       uByte           iFunction;
+} UPACKED usb_interface_association_descriptor_t;
+
+#define UDESC_INTERFACE_ASSOCIATION 11
============================================================
--- sys/dev/usb/files.usb       27a8673fba807146c4a3084b06ca2ecb34a34a5b
+++ sys/dev/usb/files.usb       2655b0ffc9f928e4d090e67a8b79f2c70998ca10
@@ -10,6 +10,8 @@ define        usbifif { [port = -1], [configura
                   [vendor = -1], [product = -1], [release = -1] }
 define usbifif { [port = -1], [configuration = -1], [interface = -1],
                  [vendor = -1], [product = -1], [release = -1] }
+define usbfif { [interface = -1] }
+define usbgenif { }
 
 device usb: usbdevif
 attach usb at usbus
@@ -21,10 +23,15 @@ file        dev/usb/usb_quirks.c            usb
 file   dev/usb/usb_quirks.c            usb
 
 # Hub driver
-device uhub: usbdevif, usbifif
+device uhub: usbdevif
 attach uhub at usbdevif
 file   dev/usb/uhub.c                  usb
 
+device udev: usbfif, usbifif, usbgenif
+attach udev at usbdevif
+file   dev/usb/udev.c                  udev
+file   dev/usb/udev_ugen.c             udev
+
 # Modem and com serial port "bus"
 define ucombus {[ portno = -1 ]}
 
@@ -34,7 +41,7 @@ device        uaudio: audiobus, auconv, mulaw, 
 
 # Audio devices
 device uaudio: audiobus, auconv, mulaw, aurateconv
-attach uaudio at usbifif
+attach uaudio at usbfif
 file   dev/usb/uaudio.c                uaudio
 
 # MIDI devices
@@ -52,8 +59,8 @@ device        ugen
 # Generic devices
 defflag UGEN_BULK_RA_WB
 device ugen
-attach ugen at usbdevif
-file   dev/usb/ugen.c                  ugen                    needs-flag
+attach ugen at usbgenif
+file   dev/usb/ugen.c                  ugen
 
 
 # HID
============================================================
--- sys/dev/usb/uaudio.c        5abb92f27d812ca7874ece4b315a30fba814f05f
+++ sys/dev/usb/uaudio.c        bb1a24d95a6da0476ebaec20db49714deb060e43
@@ -70,6 +70,7 @@ __KERNEL_RCSID(0, "$NetBSD: uaudio.c,v 1
 #include <dev/usb/usbdi.h>
 #include <dev/usb/usbdi_util.h>
 #include <dev/usb/usb_quirks.h>
+#include <dev/usb/usbfunction.h>
 
 #include <dev/usb/uaudioreg.h>
 
@@ -162,7 +163,6 @@ struct uaudio_softc {
        USBBASEDEVICE   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;
@@ -224,9 +224,9 @@ Static usbd_status uaudio_identify_ac
 #endif
 
 Static usbd_status uaudio_identify_ac
-       (struct uaudio_softc *, const usb_config_descriptor_t *);
+       (struct uaudio_softc *, const usb_config_descriptor_t *, int);
 Static usbd_status uaudio_identify_as
-       (struct uaudio_softc *, const usb_config_descriptor_t *);
+       (struct uaudio_softc *, const usb_config_descriptor_t *, int);
 Static usbd_status uaudio_process_as
        (struct uaudio_softc *, const char *, int *, int,
         const usb_interface_descriptor_t *);
@@ -272,7 +272,8 @@ Static usbd_status uaudio_identify
 Static struct terminal_list *uaudio_io_terminaltype
        (int, struct io_terminal *, int);
 Static usbd_status uaudio_identify
-       (struct uaudio_softc *, const usb_config_descriptor_t *);
+       (struct uaudio_softc *, const usb_config_descriptor_t *,
+        usbd_interface_handle *, int);
 
 Static int     uaudio_signext(int, int);
 Static int     uaudio_value2bsd(struct mixerctl *, int);
@@ -376,11 +377,9 @@ USB_MATCH(uaudio)
 
 USB_MATCH(uaudio)
 {
-       USB_IFMATCH_START(uaudio, uaa);
+       struct usbfunction_attach_args *uaa = aux;
 
-       /* Trigger on the control interface. */
        if (uaa->class != UICLASS_AUDIO ||
-           uaa->subclass != UISUBCLASS_AUDIOCONTROL ||
            (usbd_get_quirks(uaa->device)->uq_flags & UQ_BAD_AUDIO))
                return UMATCH_NONE;
 
@@ -389,7 +388,8 @@ USB_ATTACH(uaudio)
 
 USB_ATTACH(uaudio)
 {
-       USB_IFATTACH_START(uaudio, sc, uaa);
+       struct uaudio_softc *sc = (struct uaudio_softc *)self;
+       struct usbfunction_attach_args *uaa = aux;
        usb_interface_descriptor_t *id;
        usb_config_descriptor_t *cdesc;
        char *devinfop;
@@ -409,14 +409,13 @@ USB_ATTACH(uaudio)
                USB_ATTACH_ERROR_RETURN;
        }
 
-       err = uaudio_identify(sc, cdesc);
+       err = uaudio_identify(sc, cdesc, uaa->ifaces, uaa->nifaces);
        if (err) {
                printf("%s: audio descriptors make no sense, error=%d\n",
                       USBDEVNAME(sc->sc_dev), err);
                USB_ATTACH_ERROR_RETURN;
        }
 
-       sc->sc_ac_ifaceh = uaa->iface;
        /* Pick up the AS interface. */
        for (i = 0; i < uaa->nifaces; i++) {
                if (uaa->ifaces[i] == NULL)
@@ -543,7 +542,7 @@ Static const usb_interface_descriptor_t 
 }
 
 Static const usb_interface_descriptor_t *
-uaudio_find_iface(const char *tbuf, int size, int *offsp, int subtype)
+uaudio_find_iface(const char *tbuf, int size, int *offsp, int number)
 {
        const usb_interface_descriptor_t *d;
 
@@ -552,7 +551,7 @@ uaudio_find_iface(const char *tbuf, int 
                *offsp += d->bLength;
                if (d->bDescriptorType == UDESC_INTERFACE &&
                    d->bInterfaceClass == UICLASS_AUDIO &&
-                   d->bInterfaceSubClass == subtype)
+                   d->bInterfaceNumber == number)
                        return d;
        }
        return NULL;
@@ -1487,14 +1486,29 @@ Static usbd_status
 }
 
 Static usbd_status
-uaudio_identify(struct uaudio_softc *sc, const usb_config_descriptor_t *cdesc)
+uaudio_identify(struct uaudio_softc *sc, const usb_config_descriptor_t *cdesc,
+               usbd_interface_handle *ifaces, int nifaces)
 {
+       int i;
+       usb_interface_descriptor_t *d;
        usbd_status err;
 
-       err = uaudio_identify_ac(sc, cdesc);
-       if (err)
-               return err;
-       return uaudio_identify_as(sc, cdesc);
+       for (i = 0; i < nifaces; i++) {
+               d = usbd_get_interface_descriptor(ifaces[i]);
+               if (d->bInterfaceSubClass == UISUBCLASS_AUDIOCONTROL) {
+                       err = uaudio_identify_ac(sc, cdesc,
+                                                d->bInterfaceNumber);
+                       if (err)
+                               return err;
+               }
+       }
+       for (i = 0; i < nifaces; i++) {
+               d = usbd_get_interface_descriptor(ifaces[i]);
+               if (d->bInterfaceSubClass == UISUBCLASS_AUDIOSTREAM)
+                       return uaudio_identify_as(sc, cdesc,
+                                                 d->bInterfaceNumber);
+       }
+       return USBD_INVAL;
 }
 
 Static void
@@ -1737,7 +1751,8 @@ uaudio_identify_as(struct uaudio_softc *
 
 Static usbd_status
 uaudio_identify_as(struct uaudio_softc *sc,
-                  const usb_config_descriptor_t *cdesc)
+                  const usb_config_descriptor_t *cdesc,
+                  int ifaceno)
 {
        const usb_interface_descriptor_t *id;
        const char *tbuf;
@@ -1751,7 +1766,7 @@ uaudio_identify_as(struct uaudio_softc *
 
        /* Locate the AudioStreaming interface descriptor. */
        offs = 0;
-       id = uaudio_find_iface(tbuf, size, &offs, UISUBCLASS_AUDIOSTREAM);
+       id = uaudio_find_iface(tbuf, size, &offs, ifaceno);
        if (id == NULL)
                return USBD_INVAL;
 
@@ -1777,7 +1792,7 @@ uaudio_identify_as(struct uaudio_softc *
                               USBDEVNAME(sc->sc_dev), id->bNumEndpoints);
                        break;
                }
-               id = uaudio_find_iface(tbuf, size, 
&offs,UISUBCLASS_AUDIOSTREAM);
+               id = uaudio_find_iface(tbuf, size, &offs, ifaceno);
                if (id == NULL)
                        break;
        }
@@ -1839,7 +1854,9 @@ Static usbd_status
 }
 
 Static usbd_status
-uaudio_identify_ac(struct uaudio_softc *sc, const usb_config_descriptor_t 
*cdesc)
+uaudio_identify_ac(struct uaudio_softc *sc,
+                  const usb_config_descriptor_t *cdesc,
+                  int ifaceno)
 {
        struct io_terminal* iot;
        const usb_interface_descriptor_t *id;
@@ -1855,7 +1872,7 @@ uaudio_identify_ac(struct uaudio_softc *
 
        /* Locate the AudioControl interface descriptor. */
        offs = 0;
-       id = uaudio_find_iface(tbuf, size, &offs, UISUBCLASS_AUDIOCONTROL);
+       id = uaudio_find_iface(tbuf, size, &offs, ifaceno);
        if (id == NULL)
                return USBD_INVAL;
        if (offs + sizeof *acdp > size)
============================================================
--- sys/dev/usb/ugen.c  886fadd3c361883d19a0f9eaa47bf36459447da8
+++ sys/dev/usb/ugen.c  cc9fc12f9de117bc531e196d4f7413cc6340c041
@@ -214,14 +214,8 @@ USB_MATCH(ugen)
 
 USB_MATCH(ugen)
 {
-       USB_MATCH_START(ugen, uaa);
 
-       if (match->cf_flags & 1)
-               return (UMATCH_HIGHEST);
-       else if (uaa->usegeneric)
-               return (UMATCH_GENERIC);
-       else
-               return (UMATCH_NONE);
+       return 1;
 }
 
 USB_ATTACH(ugen)
============================================================
--- sys/dev/usb/uhub.c  abf3f4739bd6526ebaaff9a74f30930463409368
+++ sys/dev/usb/uhub.c  3a52f88cc8b7762f0a563b90813cd6d2c0ba9699
@@ -542,7 +542,7 @@ uhub_activate(device_ptr_t self, enum de
        struct uhub_softc *sc = (struct uhub_softc *)self;
        struct usbd_hub *hub = sc->sc_hub->hub;
        usbd_device_handle dev;
-       int nports, port, i;
+       int nports, port;
 
        switch (act) {
        case DVACT_ACTIVATE:
@@ -554,10 +554,8 @@ uhub_activate(device_ptr_t self, enum de
                nports = hub->hubdesc.bNbrPorts;
                for(port = 0; port < nports; port++) {
                        dev = hub->ports[port].device;
-                       if (dev != NULL && dev->subdevs != NULL) {
-                               for (i = 0; dev->subdevs[i] != NULL; i++)
-                                       config_deactivate(dev->subdevs[i]);
-                       }
+                       if (dev != NULL && dev->subdev)
+                               config_deactivate(dev->subdev);
                }
                break;
        }
@@ -620,7 +618,6 @@ uhub_childdet(device_t self, device_t ch
        usbd_device_handle dev;
        int nports;
        int port;
-       int i;
 
        if (!devhub->hub)
                /* should never happen; children are only created after init */
@@ -629,14 +626,10 @@ uhub_childdet(device_t self, device_t ch
        nports = devhub->hub->hubdesc.bNbrPorts;
        for (port = 0; port < nports; port++) {
                dev = devhub->hub->ports[port].device;
-               if (dev == NULL || dev->subdevs == NULL)
+               if (dev == NULL || dev->subdev != child)
                        continue;
-               for (i = 0; dev->subdevs[i]; i++) {
-                       if (dev->subdevs[i] == child) {
-                               dev->subdevs[i] = NULL;
-                               return;
-                       }
-               }
+               dev->subdev = NULL;
+               return;
        }
        KASSERT(false);
 }
============================================================
--- sys/dev/usb/usb.c   baec30d7b668d7cf3bbd524c02dfb3cbf419c4a7
+++ sys/dev/usb/usb.c   7f1eec27c3342ca4ae28105ca8ccf80238b97ade
@@ -901,7 +901,7 @@ usb_activate(device_t self, enum devact 
 {
        struct usb_softc *sc = device_private(self);
        usbd_device_handle dev = sc->sc_port.device;
-       int i, rv = 0;
+       int rv = 0;
 
        switch (act) {
        case DVACT_ACTIVATE:
@@ -909,10 +909,8 @@ usb_activate(device_t self, enum devact 
 
        case DVACT_DEACTIVATE:
                sc->sc_dying = 1;
-               if (dev != NULL && dev->cdesc != NULL && dev->subdevs != NULL) {
-                       for (i = 0; dev->subdevs[i]; i++)
-                               rv |= config_deactivate(dev->subdevs[i]);
-               }
+               if (dev != NULL && dev->cdesc != NULL && dev->subdev)
+                       rv = config_deactivate(dev->subdev);
                break;
        }
        return (rv);
@@ -921,22 +919,13 @@ usb_childdet(device_t self, device_t chi
 void
 usb_childdet(device_t self, device_t child)
 {
-       int i, last = -1;
        struct usb_softc *sc = device_private(self);
        struct usbd_device *dev;
 
-       if ((dev = sc->sc_port.device) == NULL || dev->subdevs == NULL)
-               return;
-
-       for (i = 0; dev->subdevs[i] != NULL; i++)
-               last = i;
-
-       for (i = 0; dev->subdevs[i] != NULL; i++) {
-               if (dev->subdevs[i] == child) {
-                       dev->subdevs[i] = dev->subdevs[last];
-                       dev->subdevs[last] = NULL;
-               }
-       }
+       KASSERT(sc->sc_port.device);
+       dev = sc->sc_port.device;
+       KASSERT(dev->subdev);
+       dev->subdev = NULL;
 }
 
 int
============================================================
--- sys/dev/usb/usb.h   572dc8d893c531cf62045994fcde0d59b80935c7
+++ sys/dev/usb/usb.h   9fc7925ca6786f49e560b52787e6069152d32d59
@@ -400,6 +400,9 @@ typedef struct {
 #define UDCLASS_WIRELESS       0xe0
 #define  UDSUBCLASS_RF         0x01
 #define   UDPROTO_BLUETOOTH    0x01
+#define UDCLASS_MISC           0xef
+#define  UDSUBCLASS_COMMON     0x02
+#define   UDPROTO_IAD          0x01
 #define UDCLASS_VENDOR         0xff
 
 /* Interface class codes */
============================================================
--- sys/dev/usb/usb_subr.c      1fa1e08204f9bee75e9c9c02cde89c00af1f234f
+++ sys/dev/usb/usb_subr.c      5185dec78577f35c713201070097a20f32ef636f
@@ -794,29 +794,9 @@ usbd_probe_and_attach(device_ptr_t paren
                      int port, int addr)
 {
        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;
 
-#if defined(__FreeBSD__)
-       /*
-        * XXX uaa is a static var. Not a problem as it _should_ be used only
-        * during probe and attach. Should be changed however.
-        */
-       device_t bdev;
-       bdev = device_add_child(parent, NULL, -1, &uaa);
-       if (!bdev) {
-           printf("%s: Device creation failed\n", USBDEVNAME(dev->bus->bdev));
-           return (USBD_INVAL);
-       }
-       device_quiet(bdev);
-#endif
-
        uaa.device = dev;
-       uaa.usegeneric = 0;
        uaa.port = port;
        uaa.vendor = UGETW(dd->idVendor);
        uaa.product = UGETW(dd->idProduct);
@@ -827,134 +807,9 @@ usbd_probe_and_attach(device_ptr_t paren
 
        /* First try with device specific drivers. */
        DPRINTF(("usbd_probe_and_attach: trying device specific drivers\n"));
-       dv = USB_DO_ATTACH(dev, bdev, parent, &uaa, usbd_print, usbd_submatch);
-       if (dv) {
-               dev->subdevs = malloc(2 * sizeof dv, M_USB, M_NOWAIT);
-               if (dev->subdevs == NULL)
-                       return (USBD_NOMEM);
-               dev->subdevs[0] = dv;
-               dev->subdevs[1] = 0;
-               return (USBD_NORMAL_COMPLETION);
-       }
-
-       DPRINTF(("usbd_probe_and_attach: no device specific driver found\n"));
-
-       uiaa.device = dev;
-       uiaa.port = port;
-       uiaa.vendor = UGETW(dd->idVendor);
-       uiaa.product = UGETW(dd->idProduct);
-       uiaa.release = UGETW(dd->bcdDevice);
-
-       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));
-               err = usbd_set_config_index(dev, confi, 1);
-               if (err) {
-#ifdef USB_DEBUG
-                       DPRINTF(("%s: port %d, set config at addr %d failed, "
-                                "error=%s\n", USBDEVPTRNAME(parent), port,
-                                addr, usbd_errstr(err)));
-#else
-                       printf("%s: port %d, set config at addr %d failed\n",
-                              USBDEVPTRNAME(parent), port, addr);
-#endif
-#if defined(__FreeBSD__)
-                       device_delete_child(parent, bdev);
-#endif
-
-                       return (err);
-               }
-               nifaces = dev->cdesc->bNumInterface;
-               uiaa.configno = dev->cdesc->bConfigurationValue;
-               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+1) * sizeof dv, M_USB,M_NOWAIT);
-               if (dev->subdevs == NULL) {
-                       free(ifaces, M_USB);
-nomem:
-#if defined(__FreeBSD__)
-                       device_delete_child(parent, bdev);
-#endif
-                       return (USBD_NOMEM);
-               }
-
-               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;
-                       dv = USB_DO_IFATTACH(dev, bdev, parent, &uiaa, 
usbd_ifprint,
-                                            usbd_ifsubmatch);
-                       if (dv != NULL) {
-                               dev->subdevs[found++] = dv;
-                               dev->subdevs[found] = 0;
-                               ifaces[i] = 0; /* consumed */
-
-#if defined(__FreeBSD__)
-                               /* create another child for the next iface */
-                               bdev = device_add_child(parent, NULL, -1,&uaa);
-                               if (!bdev) {
-                                       printf("%s: Device creation failed\n",
-                                       USBDEVNAME(dev->bus->bdev));
-                                       free(ifaces, M_USB);
-                                       return (USBD_NORMAL_COMPLETION);
-                               }
-                               device_quiet(bdev);
-#endif
-                       }
-               }
-               if (found != 0) {
-#if defined(__FreeBSD__)
-                       /* remove the last created child again; it is unused */
-                       device_delete_child(parent, bdev);
-#endif
-                       free(ifaces, M_USB);
-                       return (USBD_NORMAL_COMPLETION);
-               }
-               free(ifaces, M_USB);
-               free(dev->subdevs, M_USB);
-               dev->subdevs = 0;
-       }
-       /* No interfaces were attached in any of the configurations. */
-
-       if (dd->bNumConfigurations > 1) /* don't change if only 1 config */
-               usbd_set_config_index(dev, 0, 0);
-
-       DPRINTF(("usbd_probe_and_attach: no interface drivers found\n"));
-
-       /* Finally try the generic driver. */
-       uaa.usegeneric = 1;
-       dv = USB_DO_ATTACH(dev, bdev, parent, &uaa, usbd_print, usbd_submatch);
-       if (dv != NULL) {
-               dev->subdevs = malloc(2 * sizeof dv, M_USB, M_NOWAIT);
-               if (dev->subdevs == 0)
-                       return (USBD_NOMEM);
-               dev->subdevs[0] = dv;
-               dev->subdevs[1] = 0;
-               return (USBD_NORMAL_COMPLETION);
-       }
-
-       /*
-        * The generic attach failed, but leave the device as it is.
-        * We just did not find any drivers, that's all.  The device is
-        * fully operational and not harming anyone.
-        */
-       DPRINTF(("usbd_probe_and_attach: generic attach failed\n"));
-#if defined(__FreeBSD__)
-       device_delete_child(parent, bdev);
-#endif
+       dev->subdev = USB_DO_ATTACH(dev, bdev, parent, &uaa,
+                                   usbd_print, usbd_submatch);
+       
        return (USBD_NORMAL_COMPLETION);
 }
 
@@ -1181,16 +1036,8 @@ usbd_print(void *aux, const char *pnp)
        struct usb_attach_arg *uaa = aux;
 
        DPRINTFN(15, ("usbd_print dev=%p\n", uaa->device));
-       if (pnp) {
-#define USB_DEVINFO 1024
-               char *devinfo;
-               if (!uaa->usegeneric)
-                       return (QUIET);
-               devinfo = malloc(USB_DEVINFO, M_TEMP, M_WAITOK);
-               usbd_devinfo(uaa->device, 1, devinfo, USB_DEVINFO);
-               aprint_normal("%s, %s", devinfo, pnp);
-               free(devinfo, M_TEMP);
-       }
+       if (pnp)
+               return (QUIET);
        if (uaa->port != 0)
                aprint_normal(" port %d", uaa->port);
 #if 0
@@ -1343,13 +1190,11 @@ usbd_fill_deviceinfo(usbd_device_handle 
        di->udi_power = dev->self_powered ? 0 : dev->power;
        di->udi_speed = dev->speed;
 
-       if (dev->subdevs != NULL) {
-               for (i = 0; dev->subdevs[i] &&
-                            i < USB_MAX_DEVNAMES; i++) {
-                       strncpy(di->udi_devnames[i], 
USBDEVPTRNAME(dev->subdevs[i]),
-                               USB_MAX_DEVNAMELEN);
-                       di->udi_devnames[i][USB_MAX_DEVNAMELEN-1] = '\0';
-                }
+       if (dev->subdev) {
+               strncpy(di->udi_devnames[0], USBDEVPTRNAME(dev->subdev),
+                       USB_MAX_DEVNAMELEN);
+               di->udi_devnames[0][USB_MAX_DEVNAMELEN-1] = '\0';
+               i = 1;
         } else {
                 i = 0;
         }
@@ -1406,13 +1251,11 @@ usbd_fill_deviceinfo_old(usbd_device_han
        di->udi_power = dev->self_powered ? 0 : dev->power;
        di->udi_speed = dev->speed;
 
-       if (dev->subdevs != NULL) {
-               for (i = 0; dev->subdevs[i] &&
-                            i < USB_MAX_DEVNAMES; i++) {
-                       strncpy(di->udi_devnames[i], 
USBDEVPTRNAME(dev->subdevs[i]),
-                               USB_MAX_DEVNAMELEN);
-                       di->udi_devnames[i][USB_MAX_DEVNAMELEN-1] = '\0';
-               }
+       if (dev->subdev) {
+               strncpy(di->udi_devnames[0], USBDEVPTRNAME(dev->subdev),
+                       USB_MAX_DEVNAMELEN);
+               di->udi_devnames[0][USB_MAX_DEVNAMELEN-1] = '\0';
+               i = 1;
        } else {
                i = 0;
        }
@@ -1462,8 +1305,6 @@ usb_free_device(usbd_device_handle dev)
        }
        if (dev->cdesc != NULL)
                free(dev->cdesc, M_USB);
-       if (dev->subdevs != NULL)
-               free(dev->subdevs, M_USB);
        free(dev, M_USB);
 }
 
@@ -1489,7 +1330,6 @@ usb_disconnect_port(struct usbd_port *up
 {
        usbd_device_handle dev = up->device;
        char *hubname = USBDEVPTRNAME(parent);
-       int i;
 
        DPRINTFN(3,("uhub_disconnect: up=%p dev=%p port=%d\n",
                    up, dev, up->portno));
@@ -1501,16 +1341,14 @@ usb_disconnect_port(struct usbd_port *up
        }
 #endif
 
-       if (dev->subdevs != NULL) {
-               DPRINTFN(3,("usb_disconnect_port: disconnect subdevs\n"));
-               for (i = 0; dev->subdevs[i]; i++) {
-                       printf("%s: at %s", USBDEVPTRNAME(dev->subdevs[i]),
-                              hubname);
-                       if (up->portno != 0)
-                               printf(" port %d", up->portno);
-                       printf(" (addr %d) disconnected\n", dev->address);
-                       config_detach(dev->subdevs[i], DETACH_FORCE);
-               }
+       if (dev->subdev) {
+               DPRINTFN(3,("usb_disconnect_port: disconnect subdev\n"));
+               printf("%s: at %s", USBDEVPTRNAME(dev->subdev), hubname);
+               if (up->portno != 0)
+                       printf(" port %d", up->portno);
+               printf(" (addr %d) disconnected\n", dev->address);
+               config_detach(dev->subdev, DETACH_FORCE);
+               dev->subdev = 0;
        }
 
        usbd_add_dev_event(USB_EVENT_DEVICE_DETACH, dev);
============================================================
--- sys/dev/usb/usbdi.h be5af7b140f06fc59cf93bac23beb29b4375bb22
+++ sys/dev/usb/usbdi.h 5895a90b548c10073af09eb416eda0788ceb5bd0
@@ -235,7 +235,6 @@ struct usb_attach_arg {
        int                     release;
        usbd_device_handle      device; /* current device */
        int                     class, subclass, proto;
-       int                     usegeneric;
 };
 
 struct usbif_attach_arg {
============================================================
--- sys/dev/usb/usbdivar.h      6b9a9d672cd3d7efddc7fba805ba08420ea69f75
+++ sys/dev/usb/usbdivar.h      72189560a2de33ba34088cb2a540f66c3fed2127
@@ -154,7 +154,7 @@ struct usbd_device {
        usb_config_descriptor_t *cdesc;        /* full config descr */
        const struct usbd_quirks     *quirks;  /* device quirks, always set */
        struct usbd_hub        *hub;           /* only if this is a hub */
-       device_t               *subdevs;       /* sub-devices, 0 terminated */
+       device_t                subdev;        /* sub-device */
 };
 
 struct usbd_interface {


Home | Main Index | Thread Index | Old Index