tech-kern archive

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

Re: use of an intermediate device to handle USB interfaces



plunky%rya-online.net@localhost said:
> ugen0 at udev0         - last interface we have no driver for 

OK, I've renamed that and also moved ugen to udev.
And removed the "usbifif" attribute from uhub which
means that drivers attaching to a USB interface must
be a child of "udev" now. This requires all kernel config
files to be changed.

ugen still only attaches only if no other driver took any of
the device's interfaces. This can be changed later, but
first the bookkeeping of used and unused interfaces needs
to be ensured. This means that drivers using multiple interfaces
should be converted to the "usbfif" attachment which passes
the list of interfaces explicitely. I've done this for the
uaudio driver in a minimalistic way -- the list of interfaces
comes either from an IAD or just by collecting all interfaces
of the "audio" class within a device.
For the "CDC" (communication: ethernet/modem etc) class devices
something similar is needed -- I don't have access to any
device of that sort, so some help would be appreciated.

So with these patches there is no added functionality
compared to the existing one, but also no significant
loss. (Afaict only the config file flag to force use of ugen
fell behind.)

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 [75399ad45fa82468807774e7f5d9f32111be1c07]
#    to [836fdca512c4546780ffd1bfdf051f7f49256275]
# 
# patch "sys/dev/usb/ugen.c"
#  from [886fadd3c361883d19a0f9eaa47bf36459447da8]
#    to [cc9fc12f9de117bc531e196d4f7413cc6340c041]
# 
# patch "sys/dev/usb/uhub.c"
#  from [e975b149cfb82b268d68dd770b4cb5ac092f0bf6]
#    to [303b99f25ecf6566d8bc862832e9732f5745cb22]
# 
# patch "sys/dev/usb/usb.c"
#  from [1c550756be6c67ce8ac15fb60efa2f929ba42e4c]
#    to [721abf3d2b7f1699d0359649ccdc581c3823c067]
# 
# patch "sys/dev/usb/usb.h"
#  from [572dc8d893c531cf62045994fcde0d59b80935c7]
#    to [9fc7925ca6786f49e560b52787e6069152d32d59]
# 
# patch "sys/dev/usb/usb_subr.c"
#  from [f832062e7e3cd9a34aa72b7f32df984d6c25bac6]
#    to [fad7833005c5e9ea6b0c116f1379225ca149808a]
# 
# patch "sys/dev/usb/usbdi.h"
#  from [be5af7b140f06fc59cf93bac23beb29b4375bb22]
#    to [5895a90b548c10073af09eb416eda0788ceb5bd0]
# 
# patch "sys/dev/usb/usbdivar.h"
#  from [776d9d7ae7e5f55abfcf5015bec2fe0cf6a96537]
#    to [35c8ecae8497c98dcc1c657bb1d16377512b6931]
#
============================================================
--- 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        75399ad45fa82468807774e7f5d9f32111be1c07
+++ sys/dev/usb/uaudio.c        836fdca512c4546780ffd1bfdf051f7f49256275
@@ -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);
@@ -366,11 +367,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;
 
@@ -379,7 +378,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;
@@ -399,14 +399,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)
@@ -525,7 +524,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;
 
@@ -534,7 +533,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;
@@ -1469,14 +1468,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
@@ -1719,7 +1733,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;
@@ -1733,7 +1748,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;
 
@@ -1759,7 +1774,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;
        }
@@ -1821,7 +1836,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;
@@ -1837,7 +1854,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  e975b149cfb82b268d68dd770b4cb5ac092f0bf6
+++ sys/dev/usb/uhub.c  303b99f25ecf6566d8bc862832e9732f5745cb22
@@ -557,7 +557,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:
@@ -569,10 +569,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;
        }
============================================================
--- sys/dev/usb/usb.c   1c550756be6c67ce8ac15fb60efa2f929ba42e4c
+++ sys/dev/usb/usb.c   721abf3d2b7f1699d0359649ccdc581c3823c067
@@ -892,7 +892,7 @@ usb_activate(device_ptr_t self, enum dev
 {
        struct usb_softc *sc = (struct usb_softc *)self;
        usbd_device_handle dev = sc->sc_port.device;
-       int i, rv = 0;
+       int rv = 0;
 
        switch (act) {
        case DVACT_ACTIVATE:
@@ -900,10 +900,8 @@ usb_activate(device_ptr_t self, enum dev
 
        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);
============================================================
--- 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      f832062e7e3cd9a34aa72b7f32df984d6c25bac6
+++ sys/dev/usb/usb_subr.c      fad7833005c5e9ea6b0c116f1379225ca149808a
@@ -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,17 +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);
-                       dev->subdevs[i] = 0;
-               }
+       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      776d9d7ae7e5f55abfcf5015bec2fe0cf6a96537
+++ sys/dev/usb/usbdivar.h      35c8ecae8497c98dcc1c657bb1d16377512b6931
@@ -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_ptr_t           *subdevs;       /* sub-devices, 0 terminated */
+       device_t                subdev;        /* sub-device */
 };
 
 struct usbd_interface {


Home | Main Index | Thread Index | Old Index