Home | History | Annotate | Line # | Download | only in usb
uhub.c revision 1.85.8.3
      1  1.85.8.3     itohy /*	$NetBSD: uhub.c,v 1.85.8.3 2007/06/21 15:21:40 itohy Exp $	*/
      2       1.1  augustss 
      3  1.85.8.1     itohy /*-
      4      1.74   mycroft  * Copyright (c) 1998, 2004 The NetBSD Foundation, Inc.
      5       1.1  augustss  * All rights reserved.
      6       1.1  augustss  *
      7       1.6  augustss  * This code is derived from software contributed to The NetBSD Foundation
      8      1.44  augustss  * by Lennart Augustsson (lennart (at) augustsson.net) at
      9       1.6  augustss  * Carlstedt Research & Technology.
     10       1.1  augustss  *
     11       1.1  augustss  * Redistribution and use in source and binary forms, with or without
     12       1.1  augustss  * modification, are permitted provided that the following conditions
     13       1.1  augustss  * are met:
     14       1.1  augustss  * 1. Redistributions of source code must retain the above copyright
     15       1.1  augustss  *    notice, this list of conditions and the following disclaimer.
     16       1.1  augustss  * 2. Redistributions in binary form must reproduce the above copyright
     17       1.1  augustss  *    notice, this list of conditions and the following disclaimer in the
     18       1.1  augustss  *    documentation and/or other materials provided with the distribution.
     19       1.1  augustss  * 3. All advertising materials mentioning features or use of this software
     20       1.1  augustss  *    must display the following acknowledgement:
     21       1.1  augustss  *        This product includes software developed by the NetBSD
     22       1.1  augustss  *        Foundation, Inc. and its contributors.
     23       1.1  augustss  * 4. Neither the name of The NetBSD Foundation nor the names of its
     24       1.1  augustss  *    contributors may be used to endorse or promote products derived
     25       1.1  augustss  *    from this software without specific prior written permission.
     26       1.1  augustss  *
     27       1.1  augustss  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     28       1.1  augustss  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     29       1.1  augustss  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     30       1.1  augustss  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     31       1.1  augustss  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     32       1.1  augustss  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     33       1.1  augustss  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     34       1.1  augustss  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     35       1.1  augustss  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     36       1.1  augustss  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     37       1.1  augustss  * POSSIBILITY OF SUCH DAMAGE.
     38      1.15  augustss  */
     39      1.15  augustss 
     40      1.15  augustss /*
     41      1.64    ichiro  * USB spec: http://www.usb.org/developers/docs/usbspec.zip
     42       1.1  augustss  */
     43      1.53     lukem 
     44      1.53     lukem #include <sys/cdefs.h>
     45  1.85.8.3     itohy __KERNEL_RCSID(0, "$NetBSD: uhub.c,v 1.85.8.3 2007/06/21 15:21:40 itohy Exp $");
     46  1.85.8.1     itohy /* __FBSDID("$FreeBSD: src/sys/dev/usb/uhub.c,v 1.74 2007/02/03 21:11:11 flz Exp $"); */
     47       1.1  augustss 
     48       1.1  augustss #include <sys/param.h>
     49       1.1  augustss #include <sys/systm.h>
     50       1.1  augustss #include <sys/kernel.h>
     51       1.1  augustss #include <sys/malloc.h>
     52      1.20  augustss #if defined(__NetBSD__) || defined(__OpenBSD__)
     53       1.1  augustss #include <sys/device.h>
     54      1.34  augustss #include <sys/proc.h>
     55      1.11  augustss #elif defined(__FreeBSD__)
     56      1.11  augustss #include <sys/module.h>
     57      1.11  augustss #include <sys/bus.h>
     58  1.85.8.1     itohy #include <sys/lock.h>
     59  1.85.8.1     itohy #include <sys/mutex.h>
     60  1.85.8.1     itohy #include <sys/sysctl.h>
     61      1.11  augustss #endif
     62      1.28  augustss 
     63      1.28  augustss #include <machine/bus.h>
     64       1.1  augustss 
     65       1.1  augustss #include <dev/usb/usb.h>
     66       1.1  augustss #include <dev/usb/usbdi.h>
     67       1.1  augustss #include <dev/usb/usbdi_util.h>
     68       1.1  augustss #include <dev/usb/usbdivar.h>
     69       1.1  augustss 
     70      1.32  augustss #ifdef UHUB_DEBUG
     71  1.85.8.1     itohy #define DPRINTF(x)	if (uhubdebug) printf x
     72  1.85.8.1     itohy #define DPRINTFN(n,x)	if (uhubdebug > (n)) printf x
     73      1.63   dsainty int	uhubdebug = 0;
     74  1.85.8.1     itohy #if defined(__FreeBSD__)
     75  1.85.8.1     itohy SYSCTL_NODE(_hw_usb, OID_AUTO, uhub, CTLFLAG_RW, 0, "USB uhub");
     76  1.85.8.1     itohy SYSCTL_INT(_hw_usb_uhub, OID_AUTO, debug, CTLFLAG_RW,
     77  1.85.8.1     itohy 	   &uhubdebug, 0, "uhub debug level");
     78  1.85.8.1     itohy #endif
     79       1.1  augustss #else
     80       1.1  augustss #define DPRINTF(x)
     81       1.1  augustss #define DPRINTFN(n,x)
     82       1.1  augustss #endif
     83       1.1  augustss 
     84       1.1  augustss struct uhub_softc {
     85      1.26  augustss 	USBBASEDEVICE		sc_dev;		/* base device */
     86      1.11  augustss 	usbd_device_handle	sc_hub;		/* USB device */
     87  1.85.8.2     itohy 	int			sc_proto;	/* device protocol */
     88      1.11  augustss 	usbd_pipe_handle	sc_ipipe;	/* interrupt pipe */
     89  1.85.8.3     itohy 
     90  1.85.8.3     itohy 	/* XXX second buffer needed because we can't suspend pipes yet */
     91  1.85.8.3     itohy 	u_int8_t		*sc_statusbuf;
     92      1.84  drochner 	u_int8_t		*sc_status;
     93  1.85.8.3     itohy 	size_t			sc_statuslen;
     94  1.85.8.3     itohy 	int			sc_explorepending;
     95  1.85.8.3     itohy 
     96      1.11  augustss 	u_char			sc_running;
     97       1.1  augustss };
     98  1.85.8.3     itohy 
     99  1.85.8.2     itohy #define UHUB_IS_HIGH_SPEED(sc) ((sc)->sc_proto != UDPROTO_FSHUB)
    100  1.85.8.2     itohy #define UHUB_IS_SINGLE_TT(sc) ((sc)->sc_proto == UDPROTO_HSHUBSTT)
    101       1.1  augustss 
    102  1.85.8.3     itohy #define PORTSTAT_ISSET(sc, port) \
    103  1.85.8.3     itohy 	((sc)->sc_status[(port) / 8] & (1 << ((port) % 8)))
    104  1.85.8.3     itohy 
    105      1.45  augustss Static usbd_status uhub_explore(usbd_device_handle hub);
    106      1.45  augustss Static void uhub_intr(usbd_xfer_handle, usbd_private_handle,usbd_status);
    107       1.1  augustss 
    108      1.32  augustss #if defined(__FreeBSD__)
    109  1.85.8.1     itohy Static bus_child_location_str_t uhub_child_location_str;
    110  1.85.8.1     itohy Static bus_child_pnpinfo_str_t uhub_child_pnpinfo_str;
    111      1.32  augustss #endif
    112      1.32  augustss 
    113      1.58  augustss /*
    114      1.32  augustss  * We need two attachment points:
    115      1.32  augustss  * hub to usb and hub to hub
    116      1.32  augustss  * Every other driver only connects to hubs
    117      1.32  augustss  */
    118       1.1  augustss 
    119      1.20  augustss #if defined(__NetBSD__) || defined(__OpenBSD__)
    120      1.34  augustss USB_DECLARE_DRIVER(uhub);
    121      1.32  augustss #elif defined(__FreeBSD__)
    122      1.34  augustss USB_DECLARE_DRIVER_INIT(uhub,
    123  1.85.8.1     itohy 	DEVMETHOD(bus_child_pnpinfo_str, uhub_child_pnpinfo_str),
    124  1.85.8.1     itohy 	DEVMETHOD(bus_child_location_str, uhub_child_location_str),
    125  1.85.8.1     itohy 	DEVMETHOD(bus_driver_added, bus_generic_driver_added),
    126  1.85.8.1     itohy 	DEVMETHOD(device_suspend, bus_generic_suspend),
    127  1.85.8.1     itohy 	DEVMETHOD(device_resume, bus_generic_resume),
    128  1.85.8.1     itohy 	DEVMETHOD(device_shutdown, bus_generic_shutdown)
    129  1.85.8.1     itohy 	);
    130      1.58  augustss 
    131      1.32  augustss /* Create the driver instance for the hub connected to usb case. */
    132      1.32  augustss devclass_t uhubroot_devclass;
    133      1.32  augustss 
    134      1.41  augustss Static device_method_t uhubroot_methods[] = {
    135  1.85.8.1     itohy 	DEVMETHOD(bus_child_location_str, uhub_child_location_str),
    136  1.85.8.1     itohy 	DEVMETHOD(bus_child_pnpinfo_str, uhub_child_pnpinfo_str),
    137  1.85.8.1     itohy 	DEVMETHOD(bus_driver_added, bus_generic_driver_added),
    138  1.85.8.1     itohy 
    139      1.32  augustss 	DEVMETHOD(device_probe, uhub_match),
    140      1.32  augustss 	DEVMETHOD(device_attach, uhub_attach),
    141  1.85.8.1     itohy 	DEVMETHOD(device_detach, uhub_detach),
    142  1.85.8.1     itohy 	DEVMETHOD(device_suspend, bus_generic_suspend),
    143  1.85.8.1     itohy 	DEVMETHOD(device_resume, bus_generic_resume),
    144  1.85.8.1     itohy 	DEVMETHOD(device_shutdown, bus_generic_shutdown),
    145      1.32  augustss 	{0,0}
    146      1.32  augustss };
    147      1.32  augustss 
    148      1.41  augustss Static	driver_t uhubroot_driver = {
    149      1.32  augustss 	"uhub",
    150      1.32  augustss 	uhubroot_methods,
    151      1.32  augustss 	sizeof(struct uhub_softc)
    152      1.32  augustss };
    153      1.11  augustss #endif
    154       1.1  augustss 
    155      1.11  augustss USB_MATCH(uhub)
    156       1.1  augustss {
    157      1.11  augustss 	USB_MATCH_START(uhub, uaa);
    158  1.85.8.2     itohy #ifndef USB_USE_IFATTACH
    159       1.1  augustss 	usb_device_descriptor_t *dd = usbd_get_device_descriptor(uaa->device);
    160  1.85.8.2     itohy #endif /* USB_USE_IFATTACH */
    161      1.58  augustss 
    162  1.85.8.3     itohy 	DPRINTFN(5,("uhub_match, uaa=%p\n", uaa));
    163      1.58  augustss 	/*
    164       1.1  augustss 	 * The subclass for hubs seems to be 0 for some and 1 for others,
    165       1.1  augustss 	 * so we just ignore the subclass.
    166       1.1  augustss 	 */
    167  1.85.8.2     itohy #ifndef USB_USE_IFATTACH
    168      1.40  augustss 	if (uaa->iface == NULL && dd->bDeviceClass == UDCLASS_HUB)
    169  1.85.8.2     itohy #else
    170  1.85.8.2     itohy 	if (uaa->class == UDCLASS_HUB)
    171  1.85.8.2     itohy #endif /* USB_USE_IFATTACH */
    172       1.1  augustss 		return (UMATCH_DEVCLASS_DEVSUBCLASS);
    173       1.1  augustss 	return (UMATCH_NONE);
    174       1.1  augustss }
    175       1.1  augustss 
    176      1.11  augustss USB_ATTACH(uhub)
    177       1.1  augustss {
    178      1.11  augustss 	USB_ATTACH_START(uhub, sc, uaa);
    179       1.1  augustss 	usbd_device_handle dev = uaa->device;
    180  1.85.8.1     itohy 	char *devinfo;
    181      1.33  augustss 	usbd_status err;
    182      1.70  augustss 	struct usbd_hub *hub = NULL;
    183       1.1  augustss 	usb_device_request_t req;
    184       1.1  augustss 	usb_hub_descriptor_t hubdesc;
    185      1.42  augustss 	int p, port, nports, nremov, pwrdly;
    186       1.1  augustss 	usbd_interface_handle iface;
    187       1.1  augustss 	usb_endpoint_descriptor_t *ed;
    188      1.70  augustss 	struct usbd_tt *tts = NULL;
    189      1.58  augustss 
    190       1.1  augustss 	DPRINTFN(1,("uhub_attach\n"));
    191       1.1  augustss 	sc->sc_hub = dev;
    192  1.85.8.2     itohy #ifndef USB_USE_IFATTACH
    193  1.85.8.2     itohy 	sc->sc_proto = sc->sc_hub->ddesc.bDeviceProtocol;
    194  1.85.8.2     itohy #else
    195  1.85.8.2     itohy 	sc->sc_proto = uaa->proto;
    196  1.85.8.2     itohy #endif /* USB_USE_IFATTACH */
    197      1.76  augustss 
    198  1.85.8.1     itohy 	devinfo = usbd_devinfo_alloc(dev, 1);
    199      1.11  augustss 	USB_ATTACH_SETUP;
    200  1.85.8.1     itohy 	printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo);
    201  1.85.8.1     itohy 	usbd_devinfo_free(devinfo);
    202       1.1  augustss 
    203      1.75  augustss 	if (dev->depth > 0 && UHUB_IS_HIGH_SPEED(sc)) {
    204      1.70  augustss 		printf("%s: %s transaction translator%s\n",
    205      1.73     perry 		       USBDEVNAME(sc->sc_dev),
    206      1.70  augustss 		       UHUB_IS_SINGLE_TT(sc) ? "single" : "multiple",
    207      1.70  augustss 		       UHUB_IS_SINGLE_TT(sc) ? "" : "s");
    208      1.69  augustss 	}
    209      1.69  augustss 
    210      1.33  augustss 	err = usbd_set_config_index(dev, 0, 1);
    211      1.33  augustss 	if (err) {
    212      1.21  augustss 		DPRINTF(("%s: configuration failed, error=%s\n",
    213      1.33  augustss 			 USBDEVNAME(sc->sc_dev), usbd_errstr(err)));
    214      1.11  augustss 		USB_ATTACH_ERROR_RETURN;
    215       1.1  augustss 	}
    216       1.1  augustss 
    217       1.1  augustss 	if (dev->depth > USB_HUB_MAX_DEPTH) {
    218       1.1  augustss 		printf("%s: hub depth (%d) exceeded, hub ignored\n",
    219      1.11  augustss 		       USBDEVNAME(sc->sc_dev), USB_HUB_MAX_DEPTH);
    220      1.11  augustss 		USB_ATTACH_ERROR_RETURN;
    221       1.1  augustss 	}
    222       1.1  augustss 
    223       1.1  augustss 	/* Get hub descriptor. */
    224       1.1  augustss 	req.bmRequestType = UT_READ_CLASS_DEVICE;
    225       1.1  augustss 	req.bRequest = UR_GET_DESCRIPTOR;
    226  1.85.8.1     itohy 	USETW2(req.wValue, (dev->address > 1 ? UDESC_HUB : 0), 0);
    227       1.1  augustss 	USETW(req.wIndex, 0);
    228       1.1  augustss 	USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE);
    229       1.1  augustss 	DPRINTFN(1,("usb_init_hub: getting hub descriptor\n"));
    230      1.33  augustss 	err = usbd_do_request(dev, &req, &hubdesc);
    231      1.11  augustss 	nports = hubdesc.bNbrPorts;
    232      1.33  augustss 	if (!err && nports > 7) {
    233      1.11  augustss 		USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE + (nports+1) / 8);
    234      1.33  augustss 		err = usbd_do_request(dev, &req, &hubdesc);
    235      1.11  augustss 	}
    236      1.33  augustss 	if (err) {
    237      1.21  augustss 		DPRINTF(("%s: getting hub descriptor failed, error=%s\n",
    238      1.33  augustss 			 USBDEVNAME(sc->sc_dev), usbd_errstr(err)));
    239      1.11  augustss 		USB_ATTACH_ERROR_RETURN;
    240       1.1  augustss 	}
    241       1.1  augustss 
    242      1.11  augustss 	for (nremov = 0, port = 1; port <= nports; port++)
    243      1.11  augustss 		if (!UHD_NOT_REMOV(&hubdesc, port))
    244      1.11  augustss 			nremov++;
    245      1.11  augustss 	printf("%s: %d port%s with %d removable, %s powered\n",
    246      1.11  augustss 	       USBDEVNAME(sc->sc_dev), nports, nports != 1 ? "s" : "",
    247      1.11  augustss 	       nremov, dev->self_powered ? "self" : "bus");
    248      1.11  augustss 
    249      1.70  augustss 	if (nports == 0) {
    250      1.70  augustss 		printf("%s: no ports, hub ignored\n", USBDEVNAME(sc->sc_dev));
    251      1.70  augustss 		goto bad;
    252      1.70  augustss 	}
    253      1.70  augustss 
    254       1.1  augustss 	hub = malloc(sizeof(*hub) + (nports-1) * sizeof(struct usbd_port),
    255      1.18  augustss 		     M_USBDEV, M_NOWAIT);
    256      1.33  augustss 	if (hub == NULL)
    257      1.11  augustss 		USB_ATTACH_ERROR_RETURN;
    258       1.1  augustss 	dev->hub = hub;
    259      1.11  augustss 	dev->hub->hubsoftc = sc;
    260       1.1  augustss 	hub->explore = uhub_explore;
    261       1.1  augustss 	hub->hubdesc = hubdesc;
    262      1.58  augustss 
    263  1.85.8.1     itohy #if 0	/* This chack is disabled since the spec is unclear. */
    264  1.85.8.1     itohy 	DPRINTFN(1,("usbhub_init_hub: selfpowered=%d, parent=%p, "
    265  1.85.8.1     itohy 		    "parent->selfpowered=%d\n",
    266  1.85.8.1     itohy 		 dev->self_powered, dev->powersrc->parent,
    267  1.85.8.1     itohy 		 dev->powersrc->parent ?
    268  1.85.8.1     itohy 		 dev->powersrc->parent->self_powered : 0));
    269  1.85.8.1     itohy 
    270  1.85.8.1     itohy 	if (!dev->self_powered && dev->powersrc->parent != NULL &&
    271  1.85.8.1     itohy 	    !dev->powersrc->parent->self_powered) {
    272  1.85.8.1     itohy 		printf("%s: bus powered hub connected to bus powered hub, "
    273  1.85.8.1     itohy 		       "ignored\n", USBDEVNAME(sc->sc_dev));
    274  1.85.8.1     itohy 		goto bad;
    275  1.85.8.1     itohy 	}
    276  1.85.8.1     itohy #endif
    277  1.85.8.1     itohy 
    278       1.1  augustss 	/* Set up interrupt pipe. */
    279      1.33  augustss 	err = usbd_device2interface_handle(dev, 0, &iface);
    280      1.33  augustss 	if (err) {
    281      1.11  augustss 		printf("%s: no interface handle\n", USBDEVNAME(sc->sc_dev));
    282      1.18  augustss 		goto bad;
    283       1.1  augustss 	}
    284      1.83  drochner 
    285      1.83  drochner 	if (UHUB_IS_HIGH_SPEED(sc) && !UHUB_IS_SINGLE_TT(sc)) {
    286      1.83  drochner 		err = usbd_set_interface(iface, 1);
    287      1.83  drochner 		if (err)
    288      1.83  drochner 			printf("%s: can't enable multiple TTs\n",
    289      1.83  drochner 			       USBDEVNAME(sc->sc_dev));
    290      1.83  drochner 	}
    291      1.83  drochner 
    292       1.1  augustss 	ed = usbd_interface2endpoint_descriptor(iface, 0);
    293      1.33  augustss 	if (ed == NULL) {
    294      1.11  augustss 		printf("%s: no endpoint descriptor\n", USBDEVNAME(sc->sc_dev));
    295      1.18  augustss 		goto bad;
    296       1.1  augustss 	}
    297       1.1  augustss 	if ((ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) {
    298      1.11  augustss 		printf("%s: bad interrupt endpoint\n", USBDEVNAME(sc->sc_dev));
    299      1.18  augustss 		goto bad;
    300       1.1  augustss 	}
    301       1.1  augustss 
    302  1.85.8.3     itohy 	sc->sc_statuslen = (nports + 1 + 7) / 8;
    303  1.85.8.3     itohy 	sc->sc_statusbuf = malloc(sc->sc_statuslen, M_USBDEV, M_NOWAIT);
    304  1.85.8.3     itohy 	if (!sc->sc_statusbuf)
    305  1.85.8.3     itohy 		goto bad;
    306  1.85.8.3     itohy 	sc->sc_status = malloc(sc->sc_statuslen, M_USBDEV, M_NOWAIT);
    307      1.84  drochner 	if (!sc->sc_status)
    308      1.84  drochner 		goto bad;
    309      1.84  drochner 
    310  1.85.8.3     itohy 	/* force initial scan */
    311  1.85.8.3     itohy 	memset(sc->sc_status, 0xff, sc->sc_statuslen);
    312  1.85.8.3     itohy 	sc->sc_explorepending = 1;
    313  1.85.8.3     itohy 
    314      1.33  augustss 	err = usbd_open_pipe_intr(iface, ed->bEndpointAddress,
    315  1.85.8.3     itohy 		  USBD_SHORT_XFER_OK, &sc->sc_ipipe, sc, sc->sc_statusbuf,
    316  1.85.8.3     itohy 		  sc->sc_statuslen, uhub_intr, USBD_DEFAULT_INTERVAL);
    317      1.33  augustss 	if (err) {
    318      1.58  augustss 		printf("%s: cannot open interrupt pipe\n",
    319      1.11  augustss 		       USBDEVNAME(sc->sc_dev));
    320      1.18  augustss 		goto bad;
    321       1.1  augustss 	}
    322       1.1  augustss 
    323      1.11  augustss 	/* Wait with power off for a while. */
    324      1.13  augustss 	usbd_delay_ms(dev, USB_POWER_DOWN_TIME);
    325      1.11  augustss 
    326      1.37  augustss 	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, dev, USBDEV(sc->sc_dev));
    327      1.37  augustss 
    328      1.42  augustss 	/*
    329      1.42  augustss 	 * To have the best chance of success we do things in the exact same
    330      1.42  augustss 	 * order as Windoze98.  This should not be necessary, but some
    331      1.42  augustss 	 * devices do not follow the USB specs to the letter.
    332      1.42  augustss 	 *
    333      1.42  augustss 	 * These are the events on the bus when a hub is attached:
    334      1.42  augustss 	 *  Get device and config descriptors (see attach code)
    335      1.42  augustss 	 *  Get hub descriptor (see above)
    336      1.42  augustss 	 *  For all ports
    337      1.42  augustss 	 *     turn on power
    338      1.42  augustss 	 *     wait for power to become stable
    339      1.42  augustss 	 * (all below happens in explore code)
    340      1.42  augustss 	 *  For all ports
    341      1.42  augustss 	 *     clear C_PORT_CONNECTION
    342      1.42  augustss 	 *  For all ports
    343      1.42  augustss 	 *     get port status
    344      1.42  augustss 	 *     if device connected
    345      1.57  augustss 	 *        wait 100 ms
    346      1.42  augustss 	 *        turn on reset
    347      1.42  augustss 	 *        wait
    348      1.42  augustss 	 *        clear C_PORT_RESET
    349      1.42  augustss 	 *        get port status
    350      1.42  augustss 	 *        proceed with device attachment
    351      1.42  augustss 	 */
    352      1.42  augustss 
    353  1.85.8.1     itohy 	if (UHUB_IS_HIGH_SPEED(sc)) {
    354      1.70  augustss 		tts = malloc((UHUB_IS_SINGLE_TT(sc) ? 1 : nports) *
    355  1.85.8.1     itohy 		    sizeof (struct usbd_tt), M_USBDEV, M_NOWAIT);
    356      1.70  augustss 		if (!tts)
    357      1.70  augustss 			goto bad;
    358      1.70  augustss 	}
    359  1.85.8.1     itohy 
    360      1.42  augustss 	/* Set up data structures */
    361      1.11  augustss 	for (p = 0; p < nports; p++) {
    362      1.11  augustss 		struct usbd_port *up = &hub->ports[p];
    363      1.70  augustss 		up->device = NULL;
    364      1.11  augustss 		up->parent = dev;
    365      1.11  augustss 		up->portno = p+1;
    366      1.42  augustss 		if (dev->self_powered)
    367      1.42  augustss 			/* Self powered hub, give ports maximum current. */
    368      1.42  augustss 			up->power = USB_MAX_POWER;
    369      1.42  augustss 		else
    370      1.42  augustss 			up->power = USB_MIN_POWER;
    371      1.67    petrov 		up->restartcnt = 0;
    372      1.72      joff 		up->reattach = 0;
    373      1.70  augustss 		if (UHUB_IS_HIGH_SPEED(sc)) {
    374      1.70  augustss 			up->tt = &tts[UHUB_IS_SINGLE_TT(sc) ? 0 : p];
    375      1.70  augustss 			up->tt->hub = hub;
    376      1.70  augustss 		} else {
    377      1.70  augustss 			up->tt = NULL;
    378      1.70  augustss 		}
    379      1.42  augustss 	}
    380      1.42  augustss 
    381      1.42  augustss 	/* XXX should check for none, individual, or ganged power? */
    382      1.42  augustss 
    383      1.42  augustss 	pwrdly = dev->hub->hubdesc.bPwrOn2PwrGood * UHD_PWRON_FACTOR
    384      1.42  augustss 	    + USB_EXTRA_POWER_UP_TIME;
    385      1.42  augustss 	for (port = 1; port <= nports; port++) {
    386      1.42  augustss 		/* Turn the power on. */
    387      1.42  augustss 		err = usbd_set_port_feature(dev, port, UHF_PORT_POWER);
    388      1.33  augustss 		if (err)
    389      1.58  augustss 			printf("%s: port %d power on failed, %s\n",
    390      1.42  augustss 			       USBDEVNAME(sc->sc_dev), port,
    391      1.42  augustss 			       usbd_errstr(err));
    392      1.42  augustss 		DPRINTF(("usb_init_port: turn on port %d power\n", port));
    393      1.42  augustss 		/* Wait for stable power. */
    394      1.42  augustss 		usbd_delay_ms(dev, pwrdly);
    395       1.1  augustss 	}
    396      1.42  augustss 
    397      1.42  augustss 	/* The usual exploration will finish the setup. */
    398      1.42  augustss 
    399       1.1  augustss 	sc->sc_running = 1;
    400      1.11  augustss 
    401      1.11  augustss 	USB_ATTACH_SUCCESS_RETURN;
    402      1.11  augustss 
    403      1.18  augustss  bad:
    404      1.84  drochner 	if (sc->sc_status)
    405      1.84  drochner 		free(sc->sc_status, M_USBDEV);
    406      1.70  augustss 	if (hub)
    407      1.70  augustss 		free(hub, M_USBDEV);
    408      1.70  augustss 	dev->hub = NULL;
    409      1.18  augustss 	USB_ATTACH_ERROR_RETURN;
    410      1.11  augustss }
    411      1.11  augustss 
    412       1.1  augustss usbd_status
    413      1.45  augustss uhub_explore(usbd_device_handle dev)
    414       1.1  augustss {
    415       1.1  augustss 	usb_hub_descriptor_t *hd = &dev->hub->hubdesc;
    416      1.11  augustss 	struct uhub_softc *sc = dev->hub->hubsoftc;
    417       1.1  augustss 	struct usbd_port *up;
    418      1.33  augustss 	usbd_status err;
    419      1.56  augustss 	int speed;
    420       1.1  augustss 	int port;
    421      1.72      joff 	int change, status, reconnect;
    422       1.1  augustss 
    423      1.11  augustss 	DPRINTFN(10, ("uhub_explore dev=%p addr=%d\n", dev, dev->address));
    424       1.1  augustss 
    425       1.1  augustss 	if (!sc->sc_running)
    426       1.1  augustss 		return (USBD_NOT_STARTED);
    427       1.1  augustss 
    428       1.1  augustss 	/* Ignore hubs that are too deep. */
    429       1.1  augustss 	if (dev->depth > USB_HUB_MAX_DEPTH)
    430       1.1  augustss 		return (USBD_TOO_DEEP);
    431       1.1  augustss 
    432      1.84  drochner 	for (port = 1; port <= hd->bNbrPorts; port++) {
    433       1.1  augustss 		up = &dev->hub->ports[port-1];
    434  1.85.8.3     itohy 
    435  1.85.8.3     itohy 		/* reattach is needed after firmware upload */
    436      1.72      joff 		reconnect = up->reattach;
    437      1.72      joff 		up->reattach = 0;
    438  1.85.8.3     itohy 
    439  1.85.8.3     itohy 		status = change = 0;
    440  1.85.8.3     itohy 
    441  1.85.8.3     itohy 		/* don't check if no change summary notification */
    442  1.85.8.3     itohy 		if (PORTSTAT_ISSET(sc, port) || reconnect) {
    443  1.85.8.3     itohy 			err = usbd_get_port_status(dev, port, &up->status);
    444  1.85.8.3     itohy 			if (err) {
    445  1.85.8.3     itohy 				DPRINTF(("%s: uhub_explore: get port stat failed, "
    446  1.85.8.3     itohy 					 "error=%s\n", USBDEVNAME(sc->sc_dev),
    447  1.85.8.3     itohy 					 usbd_errstr(err)));
    448  1.85.8.3     itohy 				continue;
    449  1.85.8.3     itohy 			}
    450  1.85.8.3     itohy 			status = UGETW(up->status.wPortStatus);
    451  1.85.8.3     itohy 			change = UGETW(up->status.wPortChange);
    452  1.85.8.3     itohy 		}
    453  1.85.8.3     itohy 		if (!change && !reconnect) {
    454  1.85.8.3     itohy 			/* No status change, just do recursive explore. */
    455  1.85.8.3     itohy 			if (up->device != NULL && up->device->hub != NULL)
    456  1.85.8.3     itohy 				up->device->hub->explore(up->device);
    457  1.85.8.3     itohy 			continue;
    458  1.85.8.3     itohy 		}
    459  1.85.8.3     itohy 
    460      1.11  augustss 		if (change & UPS_C_PORT_ENABLED) {
    461  1.85.8.1     itohy 			DPRINTF(("uhub_explore: C_PORT_ENABLED 0x%x\n", change));
    462      1.11  augustss 			usbd_clear_port_feature(dev, port, UHF_C_PORT_ENABLE);
    463      1.68   mycroft 			if (change & UPS_C_CONNECT_STATUS) {
    464      1.68   mycroft 				/* Ignore the port error if the device
    465      1.68   mycroft 				   vanished. */
    466      1.68   mycroft 			} else if (status & UPS_PORT_ENABLED) {
    467      1.11  augustss 				printf("%s: illegal enable change, port %d\n",
    468      1.11  augustss 				       USBDEVNAME(sc->sc_dev), port);
    469      1.11  augustss 			} else {
    470      1.11  augustss 				/* Port error condition. */
    471      1.47  augustss 				if (up->restartcnt) /* no message first time */
    472      1.11  augustss 					printf("%s: port error, restarting "
    473      1.11  augustss 					       "port %d\n",
    474      1.11  augustss 					       USBDEVNAME(sc->sc_dev), port);
    475      1.47  augustss 
    476      1.47  augustss 				if (up->restartcnt++ < USBD_RESTART_MAX)
    477      1.11  augustss 					goto disco;
    478      1.47  augustss 				else
    479      1.11  augustss 					printf("%s: port error, giving up "
    480      1.11  augustss 					       "port %d\n",
    481      1.11  augustss 					       USBDEVNAME(sc->sc_dev), port);
    482      1.11  augustss 			}
    483      1.11  augustss 		}
    484  1.85.8.3     itohy 
    485  1.85.8.3     itohy 		/* XXX handle overcurrent and resume events! */
    486  1.85.8.3     itohy 
    487  1.85.8.3     itohy 		if (!(change & UPS_C_CONNECT_STATUS))
    488       1.1  augustss 			continue;
    489      1.42  augustss 
    490      1.42  augustss 		/* We have a connect status change, handle it. */
    491      1.42  augustss 
    492       1.1  augustss 		DPRINTF(("uhub_explore: status change hub=%d port=%d\n",
    493       1.1  augustss 			 dev->address, port));
    494       1.1  augustss 		usbd_clear_port_feature(dev, port, UHF_C_PORT_CONNECTION);
    495       1.1  augustss 		/*
    496       1.1  augustss 		 * If there is already a device on the port the change status
    497       1.1  augustss 		 * must mean that is has disconnected.  Looking at the
    498       1.1  augustss 		 * current connect status is not enough to figure this out
    499       1.1  augustss 		 * since a new unit may have been connected before we handle
    500       1.1  augustss 		 * the disconnect.
    501       1.1  augustss 		 */
    502      1.11  augustss 	disco:
    503      1.33  augustss 		if (up->device != NULL) {
    504       1.1  augustss 			/* Disconnected */
    505      1.35  augustss 			DPRINTF(("uhub_explore: device addr=%d disappeared "
    506      1.31  augustss 				 "on port %d\n", up->device->address, port));
    507      1.31  augustss 			usb_disconnect_port(up, USBDEV(sc->sc_dev));
    508      1.58  augustss 			usbd_clear_port_feature(dev, port,
    509       1.1  augustss 						UHF_C_PORT_CONNECTION);
    510       1.1  augustss 		}
    511      1.35  augustss 		if (!(status & UPS_CURRENT_CONNECT_STATUS)) {
    512      1.42  augustss 			/* Nothing connected, just ignore it. */
    513      1.35  augustss 			DPRINTFN(3,("uhub_explore: port=%d !CURRENT_CONNECT"
    514      1.35  augustss 				    "_STATUS\n", port));
    515       1.1  augustss 			continue;
    516      1.35  augustss 		}
    517       1.1  augustss 
    518       1.1  augustss 		/* Connected */
    519      1.42  augustss 
    520      1.42  augustss 		if (!(status & UPS_PORT_POWER))
    521      1.42  augustss 			printf("%s: strange, connected port %d has no power\n",
    522      1.42  augustss 			       USBDEVNAME(sc->sc_dev), port);
    523      1.42  augustss 
    524       1.1  augustss 		/* Wait for maximum device power up time. */
    525      1.13  augustss 		usbd_delay_ms(dev, USB_PORT_POWERUP_DELAY);
    526      1.11  augustss 
    527       1.1  augustss 		/* Reset port, which implies enabling it. */
    528      1.35  augustss 		if (usbd_reset_port(dev, port, &up->status)) {
    529      1.55  augustss 			printf("%s: port %d reset failed\n",
    530      1.55  augustss 			       USBDEVNAME(sc->sc_dev), port);
    531      1.54  augustss 			continue;
    532      1.54  augustss 		}
    533      1.54  augustss 		/* Get port status again, it might have changed during reset */
    534      1.54  augustss 		err = usbd_get_port_status(dev, port, &up->status);
    535      1.54  augustss 		if (err) {
    536      1.54  augustss 			DPRINTF(("uhub_explore: get port status failed, "
    537      1.54  augustss 				 "error=%s\n", usbd_errstr(err)));
    538      1.54  augustss 			continue;
    539      1.54  augustss 		}
    540      1.54  augustss 		status = UGETW(up->status.wPortStatus);
    541      1.54  augustss 		change = UGETW(up->status.wPortChange);
    542      1.54  augustss 		if (!(status & UPS_CURRENT_CONNECT_STATUS)) {
    543      1.54  augustss 			/* Nothing connected, just ignore it. */
    544      1.54  augustss #ifdef DIAGNOSTIC
    545      1.56  augustss 			printf("%s: port %d, device disappeared after reset\n",
    546      1.54  augustss 			       USBDEVNAME(sc->sc_dev), port);
    547      1.54  augustss #endif
    548       1.1  augustss 			continue;
    549      1.35  augustss 		}
    550       1.1  augustss 
    551      1.56  augustss 		/* Figure out device speed */
    552      1.56  augustss 		if (status & UPS_HIGH_SPEED)
    553      1.56  augustss 			speed = USB_SPEED_HIGH;
    554      1.56  augustss 		else if (status & UPS_LOW_SPEED)
    555      1.56  augustss 			speed = USB_SPEED_LOW;
    556      1.56  augustss 		else
    557      1.56  augustss 			speed = USB_SPEED_FULL;
    558       1.1  augustss 		/* Get device info and set its address. */
    559      1.58  augustss 		err = usbd_new_device(USBDEV(sc->sc_dev), dev->bus,
    560  1.85.8.1     itohy 		    dev->depth + 1, speed, port, up);
    561       1.1  augustss 		/* XXX retry a few times? */
    562      1.33  augustss 		if (err) {
    563      1.10  drochner 			DPRINTFN(-1,("uhub_explore: usb_new_device failed, "
    564      1.33  augustss 				     "error=%s\n", usbd_errstr(err)));
    565       1.1  augustss 			/* Avoid addressing problems by disabling. */
    566       1.1  augustss 			/* usbd_reset_port(dev, port, &up->status); */
    567      1.30  augustss 
    568      1.58  augustss 			/*
    569      1.30  augustss 			 * The unit refused to accept a new address, or had
    570      1.30  augustss 			 * some other serious problem.  Since we cannot leave
    571      1.30  augustss 			 * at 0 we have to disable the port instead.
    572      1.30  augustss 			 */
    573  1.85.8.1     itohy 			printf("%s: device problem (%s), disabling port %d\n",
    574  1.85.8.1     itohy 			       USBDEVNAME(sc->sc_dev), usbd_errstr(err), port);
    575      1.30  augustss 			usbd_clear_port_feature(dev, port, UHF_PORT_ENABLE);
    576       1.1  augustss 		} else {
    577      1.47  augustss 			/* The port set up succeeded, reset error count. */
    578      1.47  augustss 			up->restartcnt = 0;
    579      1.47  augustss 
    580      1.34  augustss 			if (up->device->hub)
    581      1.11  augustss 				up->device->hub->explore(up->device);
    582       1.1  augustss 		}
    583       1.1  augustss 	}
    584  1.85.8.3     itohy 	/* enable status change notifications again */
    585  1.85.8.3     itohy 	sc->sc_explorepending = 0;
    586       1.1  augustss 	return (USBD_NORMAL_COMPLETION);
    587       1.1  augustss }
    588       1.1  augustss 
    589      1.32  augustss #if defined(__NetBSD__) || defined(__OpenBSD__)
    590      1.18  augustss int
    591      1.45  augustss uhub_activate(device_ptr_t self, enum devact act)
    592      1.18  augustss {
    593      1.27  augustss 	struct uhub_softc *sc = (struct uhub_softc *)self;
    594      1.39  augustss 	struct usbd_hub *hub = sc->sc_hub->hub;
    595      1.34  augustss 	usbd_device_handle dev;
    596      1.34  augustss 	int nports, port, i;
    597      1.27  augustss 
    598      1.23  augustss 	switch (act) {
    599      1.23  augustss 	case DVACT_ACTIVATE:
    600      1.23  augustss 		return (EOPNOTSUPP);
    601      1.23  augustss 
    602      1.23  augustss 	case DVACT_DEACTIVATE:
    603      1.39  augustss 		if (hub == NULL) /* malfunctioning hub */
    604      1.39  augustss 			break;
    605      1.39  augustss 		nports = hub->hubdesc.bNbrPorts;
    606      1.34  augustss 		for(port = 0; port < nports; port++) {
    607      1.39  augustss 			dev = hub->ports[port].device;
    608      1.46  augustss 			if (dev != NULL && dev->subdevs != NULL) {
    609      1.46  augustss 				for (i = 0; dev->subdevs[i] != NULL; i++)
    610      1.27  augustss 					config_deactivate(dev->subdevs[i]);
    611      1.27  augustss 			}
    612      1.27  augustss 		}
    613      1.23  augustss 		break;
    614      1.23  augustss 	}
    615      1.18  augustss 	return (0);
    616      1.18  augustss }
    617      1.32  augustss #endif
    618      1.18  augustss 
    619      1.18  augustss /*
    620      1.18  augustss  * Called from process context when the hub is gone.
    621      1.18  augustss  * Detach all devices on active ports.
    622      1.18  augustss  */
    623      1.32  augustss USB_DETACH(uhub)
    624      1.18  augustss {
    625      1.32  augustss 	USB_DETACH_START(uhub, sc);
    626      1.39  augustss 	struct usbd_hub *hub = sc->sc_hub->hub;
    627      1.18  augustss 	struct usbd_port *rup;
    628      1.32  augustss 	int port, nports;
    629      1.18  augustss 
    630      1.32  augustss #if defined(__NetBSD__) || defined(__OpenBSD__)
    631      1.18  augustss 	DPRINTF(("uhub_detach: sc=%p flags=%d\n", sc, flags));
    632      1.32  augustss #elif defined(__FreeBSD__)
    633      1.32  augustss 	DPRINTF(("uhub_detach: sc=%port\n", sc));
    634      1.32  augustss #endif
    635      1.18  augustss 
    636      1.39  augustss 	if (hub == NULL)		/* Must be partially working */
    637      1.18  augustss 		return (0);
    638      1.18  augustss 
    639      1.18  augustss 	usbd_abort_pipe(sc->sc_ipipe);
    640      1.18  augustss 	usbd_close_pipe(sc->sc_ipipe);
    641      1.18  augustss 
    642      1.39  augustss 	nports = hub->hubdesc.bNbrPorts;
    643      1.32  augustss 	for(port = 0; port < nports; port++) {
    644      1.39  augustss 		rup = &hub->ports[port];
    645      1.18  augustss 		if (rup->device)
    646      1.31  augustss 			usb_disconnect_port(rup, self);
    647      1.18  augustss 	}
    648      1.58  augustss 
    649      1.39  augustss 	usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_hub,
    650      1.39  augustss 			   USBDEV(sc->sc_dev));
    651      1.37  augustss 
    652      1.70  augustss 	if (hub->ports[0].tt)
    653      1.70  augustss 		free(hub->ports[0].tt, M_USBDEV);
    654      1.71  augustss 	free(hub, M_USBDEV);
    655      1.39  augustss 	sc->sc_hub->hub = NULL;
    656      1.84  drochner 	if (sc->sc_status)
    657      1.84  drochner 		free(sc->sc_status, M_USBDEV);
    658      1.18  augustss 
    659      1.18  augustss 	return (0);
    660      1.18  augustss }
    661      1.34  augustss 
    662      1.34  augustss #if defined(__FreeBSD__)
    663  1.85.8.1     itohy int
    664  1.85.8.1     itohy uhub_child_location_str(device_t cbdev, device_t child, char *buf,
    665  1.85.8.1     itohy     size_t buflen)
    666      1.34  augustss {
    667  1.85.8.1     itohy 	struct uhub_softc *sc = device_get_softc(cbdev);
    668  1.85.8.1     itohy 	usbd_device_handle devhub = sc->sc_hub;
    669  1.85.8.1     itohy 	usbd_device_handle dev;
    670  1.85.8.1     itohy 	int nports;
    671  1.85.8.1     itohy 	int port;
    672  1.85.8.1     itohy 	int i;
    673  1.85.8.1     itohy 
    674  1.85.8.1     itohy 	mtx_lock(&Giant);
    675  1.85.8.1     itohy 	nports = devhub->hub->hubdesc.bNbrPorts;
    676  1.85.8.1     itohy 	for (port = 0; port < nports; port++) {
    677  1.85.8.1     itohy 		dev = devhub->hub->ports[port].device;
    678  1.85.8.1     itohy 		if (dev && dev->subdevs) {
    679  1.85.8.1     itohy 			for (i = 0; dev->subdevs[i]; i++) {
    680  1.85.8.1     itohy 				if (dev->subdevs[i] == child) {
    681  1.85.8.1     itohy 					if (dev->ifacenums == NULL) {
    682  1.85.8.1     itohy 						snprintf(buf, buflen,
    683  1.85.8.1     itohy 						    "port=%i", port);
    684  1.85.8.1     itohy 					} else {
    685  1.85.8.1     itohy 						snprintf(buf, buflen,
    686  1.85.8.1     itohy 						    "port=%i interface=%i",
    687  1.85.8.1     itohy 						    port, dev->ifacenums[i]);
    688  1.85.8.1     itohy 					}
    689  1.85.8.1     itohy 					goto found_dev;
    690  1.85.8.1     itohy 				}
    691  1.85.8.1     itohy 			}
    692  1.85.8.1     itohy 		}
    693  1.85.8.1     itohy 	}
    694  1.85.8.1     itohy 	DPRINTFN(0,("uhub_child_location_str: device not on hub\n"));
    695  1.85.8.1     itohy 	buf[0] = '\0';
    696  1.85.8.1     itohy found_dev:
    697  1.85.8.1     itohy 	mtx_unlock(&Giant);
    698  1.85.8.1     itohy 	return (0);
    699      1.34  augustss }
    700      1.34  augustss 
    701  1.85.8.1     itohy int
    702  1.85.8.1     itohy uhub_child_pnpinfo_str(device_t cbdev, device_t child, char *buf,
    703  1.85.8.1     itohy     size_t buflen)
    704  1.85.8.1     itohy {
    705  1.85.8.1     itohy 	struct uhub_softc *sc = device_get_softc(cbdev);
    706  1.85.8.1     itohy 	usbd_device_handle devhub = sc->sc_hub;
    707  1.85.8.1     itohy 	usbd_device_handle dev;
    708  1.85.8.1     itohy 	struct usbd_interface *iface;
    709  1.85.8.1     itohy 	char serial[128];
    710  1.85.8.1     itohy 	int nports;
    711  1.85.8.1     itohy 	int port;
    712  1.85.8.1     itohy 	int i;
    713  1.85.8.1     itohy 
    714  1.85.8.1     itohy 	mtx_lock(&Giant);
    715  1.85.8.1     itohy 	nports = devhub->hub->hubdesc.bNbrPorts;
    716  1.85.8.1     itohy 	for (port = 0; port < nports; port++) {
    717  1.85.8.1     itohy 		dev = devhub->hub->ports[port].device;
    718  1.85.8.1     itohy 		if (dev && dev->subdevs) {
    719  1.85.8.1     itohy 			for (i = 0; dev->subdevs[i]; i++) {
    720  1.85.8.1     itohy 				if (dev->subdevs[i] == child) {
    721  1.85.8.1     itohy 					goto found_dev;
    722  1.85.8.1     itohy 				}
    723  1.85.8.1     itohy 			}
    724  1.85.8.1     itohy 		}
    725  1.85.8.1     itohy 	}
    726  1.85.8.1     itohy 	DPRINTFN(0,("uhub_child_pnpinfo_str: device not on hub\n"));
    727  1.85.8.1     itohy 	buf[0] = '\0';
    728  1.85.8.1     itohy 	mtx_unlock(&Giant);
    729  1.85.8.1     itohy 	return (0);
    730  1.85.8.1     itohy 
    731  1.85.8.1     itohy found_dev:
    732  1.85.8.1     itohy 	/* XXX can sleep */
    733  1.85.8.1     itohy 	(void)usbd_get_string(dev, dev->ddesc.iSerialNumber, &serial[0]);
    734  1.85.8.1     itohy 	if (dev->ifacenums == NULL) {
    735  1.85.8.1     itohy 		snprintf(buf, buflen, "vendor=0x%04x product=0x%04x "
    736  1.85.8.1     itohy 		    "devclass=0x%02x devsubclass=0x%02x "
    737  1.85.8.1     itohy 		    "release=0x%04x sernum=\"%s\"",
    738  1.85.8.1     itohy 		    UGETW(dev->ddesc.idVendor), UGETW(dev->ddesc.idProduct),
    739  1.85.8.1     itohy 		    dev->ddesc.bDeviceClass, dev->ddesc.bDeviceSubClass,
    740  1.85.8.1     itohy 		    UGETW(dev->ddesc.bcdDevice), serial);
    741  1.85.8.1     itohy 	} else {
    742  1.85.8.1     itohy 		iface = &dev->ifaces[dev->ifacenums[i]];
    743  1.85.8.1     itohy 		snprintf(buf, buflen, "vendor=0x%04x product=0x%04x "
    744  1.85.8.1     itohy 		    "devclass=0x%02x devsubclass=0x%02x "
    745  1.85.8.1     itohy 		    "release=0x%04x sernum=\"%s\" "
    746  1.85.8.1     itohy 		    "intclass=0x%02x intsubclass=0x%02x",
    747  1.85.8.1     itohy 		    UGETW(dev->ddesc.idVendor), UGETW(dev->ddesc.idProduct),
    748  1.85.8.1     itohy 		    dev->ddesc.bDeviceClass, dev->ddesc.bDeviceSubClass,
    749  1.85.8.1     itohy 		    UGETW(dev->ddesc.bcdDevice), serial,
    750  1.85.8.1     itohy 		    iface->idesc->bInterfaceClass,
    751  1.85.8.1     itohy 		    iface->idesc->bInterfaceSubClass);
    752  1.85.8.1     itohy 	}
    753  1.85.8.1     itohy 	mtx_unlock(&Giant);
    754  1.85.8.1     itohy 	return (0);
    755  1.85.8.1     itohy }
    756  1.85.8.1     itohy #endif /* defined(__FreeBSD__) */
    757      1.18  augustss 
    758      1.18  augustss /*
    759      1.18  augustss  * Hub interrupt.
    760      1.18  augustss  * This an indication that some port has changed status.
    761      1.18  augustss  * Notify the bus event handler thread that we need
    762      1.18  augustss  * to be explored again.
    763      1.18  augustss  */
    764       1.1  augustss void
    765      1.81  christos uhub_intr(usbd_xfer_handle xfer, usbd_private_handle addr,
    766      1.79  christos     usbd_status status)
    767       1.1  augustss {
    768       1.1  augustss 	struct uhub_softc *sc = addr;
    769       1.1  augustss 
    770      1.11  augustss 	DPRINTFN(5,("uhub_intr: sc=%p\n", sc));
    771  1.85.8.3     itohy 
    772      1.50  augustss 	if (status == USBD_STALLED)
    773       1.9  augustss 		usbd_clear_endpoint_stall_async(sc->sc_ipipe);
    774  1.85.8.3     itohy 	else if (status == USBD_NORMAL_COMPLETION &&
    775  1.85.8.3     itohy 		 !sc->sc_explorepending) {
    776  1.85.8.3     itohy 		/*
    777  1.85.8.3     itohy 		 * Make sure the status is not overwritten in between.
    778  1.85.8.3     itohy 		 * XXX we should suspend the pipe instead
    779  1.85.8.3     itohy 		 */
    780  1.85.8.3     itohy 		memcpy(sc->sc_status, sc->sc_statusbuf, sc->sc_statuslen);
    781  1.85.8.3     itohy 		sc->sc_explorepending = 1;
    782      1.50  augustss 		usb_needs_explore(sc->sc_hub);
    783  1.85.8.3     itohy 	}
    784       1.1  augustss }
    785      1.11  augustss 
    786      1.11  augustss #if defined(__FreeBSD__)
    787      1.19  augustss DRIVER_MODULE(uhub, usb, uhubroot_driver, uhubroot_devclass, 0, 0);
    788      1.19  augustss DRIVER_MODULE(uhub, uhub, uhub_driver, uhub_devclass, usbd_driver_load, 0);
    789      1.11  augustss #endif
    790