Home | History | Annotate | Line # | Download | only in usb
uhub.c revision 1.16.4.2
      1  1.16.4.2   thorpej /*	$NetBSD: uhub.c,v 1.16.4.2 1999/07/01 23:40:22 thorpej Exp $	*/
      2       1.1  augustss 
      3       1.1  augustss /*
      4       1.1  augustss  * Copyright (c) 1998 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.6  augustss  * by Lennart Augustsson (augustss (at) carlstedt.se) 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.15  augustss  * USB spec: http://www.usb.org/cgi-usb/mailmerge.cgi/home/usb/docs/developers/cgiform.tpl
     42       1.1  augustss  */
     43       1.1  augustss 
     44       1.1  augustss #include <sys/param.h>
     45       1.1  augustss #include <sys/systm.h>
     46       1.1  augustss #include <sys/kernel.h>
     47       1.1  augustss #include <sys/malloc.h>
     48      1.11  augustss #if defined(__NetBSD__)
     49       1.1  augustss #include <sys/device.h>
     50      1.11  augustss #elif defined(__FreeBSD__)
     51      1.11  augustss #include <sys/module.h>
     52      1.11  augustss #include <sys/bus.h>
     53      1.11  augustss #endif
     54       1.1  augustss #include <sys/proc.h>
     55       1.1  augustss 
     56       1.1  augustss #include <dev/usb/usb.h>
     57       1.1  augustss #include <dev/usb/usbdi.h>
     58       1.1  augustss #include <dev/usb/usbdi_util.h>
     59       1.1  augustss #include <dev/usb/usbdivar.h>
     60       1.1  augustss 
     61       1.1  augustss #ifdef USB_DEBUG
     62       1.1  augustss #define DPRINTF(x)	if (usbdebug) printf x
     63       1.1  augustss #define DPRINTFN(n,x)	if (usbdebug>(n)) printf x
     64       1.1  augustss extern int	usbdebug;
     65       1.8  augustss extern char 	*usbd_error_strs[];
     66       1.1  augustss #else
     67       1.1  augustss #define DPRINTF(x)
     68       1.1  augustss #define DPRINTFN(n,x)
     69       1.1  augustss #endif
     70       1.1  augustss 
     71       1.1  augustss struct uhub_softc {
     72      1.11  augustss 	bdevice			sc_dev;		/* base device */
     73      1.11  augustss 	usbd_device_handle	sc_hub;		/* USB device */
     74      1.11  augustss 	usbd_pipe_handle	sc_ipipe;	/* interrupt pipe */
     75      1.11  augustss 	u_int8_t		sc_status[1];	/* XXX more ports */
     76      1.11  augustss 	u_char			sc_running;
     77       1.1  augustss };
     78       1.1  augustss 
     79      1.11  augustss usbd_status uhub_init_port __P((struct usbd_port *));
     80  1.16.4.2   thorpej void uhub_disconnect_port __P((struct usbd_port *up));
     81      1.11  augustss usbd_status uhub_explore __P((usbd_device_handle hub));
     82       1.1  augustss void uhub_intr __P((usbd_request_handle, usbd_private_handle, usbd_status));
     83       1.1  augustss 
     84      1.14  augustss USB_DECLARE_DRIVER_NAME(usb, uhub);
     85       1.1  augustss 
     86      1.11  augustss #if defined(__NetBSD__)
     87       1.1  augustss struct cfattach uhub_uhub_ca = {
     88  1.16.4.2   thorpej 	sizeof(struct uhub_softc), uhub_match, uhub_attach,
     89  1.16.4.2   thorpej 	uhub_detach, uhub_activate
     90       1.1  augustss };
     91      1.11  augustss #endif
     92       1.1  augustss 
     93      1.11  augustss USB_MATCH(uhub)
     94       1.1  augustss {
     95      1.11  augustss 	USB_MATCH_START(uhub, uaa);
     96       1.1  augustss 	usb_device_descriptor_t *dd = usbd_get_device_descriptor(uaa->device);
     97       1.1  augustss 
     98      1.11  augustss 	DPRINTFN(5,("uhub_match, dd=%p\n", dd));
     99       1.1  augustss 	/*
    100       1.1  augustss 	 * The subclass for hubs seems to be 0 for some and 1 for others,
    101       1.1  augustss 	 * so we just ignore the subclass.
    102       1.1  augustss 	 */
    103       1.1  augustss 	if (uaa->iface == 0 && dd->bDeviceClass == UCLASS_HUB)
    104       1.1  augustss 		return (UMATCH_DEVCLASS_DEVSUBCLASS);
    105       1.1  augustss 	return (UMATCH_NONE);
    106       1.1  augustss }
    107       1.1  augustss 
    108      1.11  augustss USB_ATTACH(uhub)
    109       1.1  augustss {
    110      1.11  augustss 	USB_ATTACH_START(uhub, sc, uaa);
    111       1.1  augustss 	usbd_device_handle dev = uaa->device;
    112       1.1  augustss 	char devinfo[1024];
    113       1.1  augustss 	usbd_status r;
    114       1.1  augustss 	struct usbd_hub *hub;
    115       1.1  augustss 	usb_device_request_t req;
    116       1.1  augustss 	usb_hub_descriptor_t hubdesc;
    117      1.11  augustss 	int p, port, nports, nremov;
    118       1.1  augustss 	usbd_interface_handle iface;
    119       1.1  augustss 	usb_endpoint_descriptor_t *ed;
    120       1.1  augustss 
    121       1.1  augustss 	DPRINTFN(1,("uhub_attach\n"));
    122       1.1  augustss 	sc->sc_hub = dev;
    123       1.1  augustss 	usbd_devinfo(dev, 1, devinfo);
    124      1.11  augustss 	USB_ATTACH_SETUP;
    125      1.11  augustss 	printf("%s: %s\n", USBDEVNAME(sc->sc_dev), devinfo);
    126       1.1  augustss 
    127       1.8  augustss 	r = usbd_set_config_index(dev, 0, 1);
    128       1.1  augustss 	if (r != USBD_NORMAL_COMPLETION) {
    129      1.10  drochner 		DPRINTF(("%s: configuration failed, error=%d(%s)\n",
    130      1.11  augustss 			 USBDEVNAME(sc->sc_dev), r, usbd_error_strs[r]));
    131      1.11  augustss 		USB_ATTACH_ERROR_RETURN;
    132       1.1  augustss 	}
    133       1.1  augustss 
    134       1.1  augustss 	if (dev->depth > USB_HUB_MAX_DEPTH) {
    135       1.1  augustss 		printf("%s: hub depth (%d) exceeded, hub ignored\n",
    136      1.11  augustss 		       USBDEVNAME(sc->sc_dev), USB_HUB_MAX_DEPTH);
    137      1.11  augustss 		USB_ATTACH_ERROR_RETURN;
    138       1.1  augustss 	}
    139       1.1  augustss 
    140       1.1  augustss 	/* Get hub descriptor. */
    141       1.1  augustss 	req.bmRequestType = UT_READ_CLASS_DEVICE;
    142       1.1  augustss 	req.bRequest = UR_GET_DESCRIPTOR;
    143       1.1  augustss 	USETW(req.wValue, 0);
    144       1.1  augustss 	USETW(req.wIndex, 0);
    145       1.1  augustss 	USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE);
    146       1.1  augustss 	DPRINTFN(1,("usb_init_hub: getting hub descriptor\n"));
    147       1.1  augustss 	r = usbd_do_request(dev, &req, &hubdesc);
    148      1.11  augustss 	nports = hubdesc.bNbrPorts;
    149      1.11  augustss 	if (r == USBD_NORMAL_COMPLETION && nports > 7) {
    150      1.11  augustss 		USETW(req.wLength, USB_HUB_DESCRIPTOR_SIZE + (nports+1) / 8);
    151      1.11  augustss 		r = usbd_do_request(dev, &req, &hubdesc);
    152      1.11  augustss 	}
    153       1.1  augustss 	if (r != USBD_NORMAL_COMPLETION) {
    154      1.10  drochner 		DPRINTF(("%s: getting hub descriptor failed, error=%d(%s)\n",
    155      1.11  augustss 			 USBDEVNAME(sc->sc_dev), r, usbd_error_strs[r]));
    156      1.11  augustss 		USB_ATTACH_ERROR_RETURN;
    157       1.1  augustss 	}
    158       1.1  augustss 
    159      1.11  augustss 	for (nremov = 0, port = 1; port <= nports; port++)
    160      1.11  augustss 		if (!UHD_NOT_REMOV(&hubdesc, port))
    161      1.11  augustss 			nremov++;
    162      1.11  augustss 	printf("%s: %d port%s with %d removable, %s powered\n",
    163      1.11  augustss 	       USBDEVNAME(sc->sc_dev), nports, nports != 1 ? "s" : "",
    164      1.11  augustss 	       nremov, dev->self_powered ? "self" : "bus");
    165      1.11  augustss 
    166      1.11  augustss 
    167       1.1  augustss 	hub = malloc(sizeof(*hub) + (nports-1) * sizeof(struct usbd_port),
    168  1.16.4.2   thorpej 		     M_USBDEV, M_NOWAIT);
    169       1.1  augustss 	if (hub == 0)
    170      1.11  augustss 		USB_ATTACH_ERROR_RETURN;
    171       1.1  augustss 	dev->hub = hub;
    172      1.11  augustss 	dev->hub->hubsoftc = sc;
    173       1.1  augustss 	hub->explore = uhub_explore;
    174       1.1  augustss 	hub->hubdesc = hubdesc;
    175       1.1  augustss 
    176      1.10  drochner 	DPRINTFN(1,("usbhub_init_hub: selfpowered=%d, parent=%p, "
    177      1.10  drochner 		    "parent->selfpowered=%d\n",
    178       1.1  augustss 		 dev->self_powered, dev->powersrc->parent,
    179       1.1  augustss 		 dev->powersrc->parent ?
    180       1.1  augustss 		 dev->powersrc->parent->self_powered : 0));
    181       1.1  augustss 	if (!dev->self_powered && dev->powersrc->parent &&
    182       1.1  augustss 	    !dev->powersrc->parent->self_powered) {
    183      1.10  drochner 		printf("%s: bus powered hub connected to bus powered hub, "
    184      1.10  drochner 		       "ignored\n",
    185      1.11  augustss 		       USBDEVNAME(sc->sc_dev));
    186  1.16.4.2   thorpej 		goto bad;
    187       1.1  augustss 	}
    188       1.1  augustss 
    189       1.1  augustss 	/* Set up interrupt pipe. */
    190       1.1  augustss 	r = usbd_device2interface_handle(dev, 0, &iface);
    191       1.1  augustss 	if (r != USBD_NORMAL_COMPLETION) {
    192      1.11  augustss 		printf("%s: no interface handle\n", USBDEVNAME(sc->sc_dev));
    193  1.16.4.2   thorpej 		goto bad;
    194       1.1  augustss 	}
    195       1.1  augustss 	ed = usbd_interface2endpoint_descriptor(iface, 0);
    196       1.1  augustss 	if (ed == 0) {
    197      1.11  augustss 		printf("%s: no endpoint descriptor\n", USBDEVNAME(sc->sc_dev));
    198  1.16.4.2   thorpej 		goto bad;
    199       1.1  augustss 	}
    200       1.1  augustss 	if ((ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) {
    201      1.11  augustss 		printf("%s: bad interrupt endpoint\n", USBDEVNAME(sc->sc_dev));
    202  1.16.4.2   thorpej 		goto bad;
    203       1.1  augustss 	}
    204       1.1  augustss 
    205       1.1  augustss 	r = usbd_open_pipe_intr(iface, ed->bEndpointAddress,USBD_SHORT_XFER_OK,
    206       1.1  augustss 				&sc->sc_ipipe, sc, sc->sc_status,
    207       1.1  augustss 				sizeof(sc->sc_status),
    208       1.1  augustss 				uhub_intr);
    209       1.1  augustss 	if (r != USBD_NORMAL_COMPLETION) {
    210      1.11  augustss 		printf("%s: cannot open interrupt pipe\n",
    211      1.11  augustss 		       USBDEVNAME(sc->sc_dev));
    212  1.16.4.2   thorpej 		goto bad;
    213       1.1  augustss 	}
    214       1.1  augustss 
    215      1.11  augustss 	/* Wait with power off for a while. */
    216      1.13  augustss 	usbd_delay_ms(dev, USB_POWER_DOWN_TIME);
    217      1.11  augustss 
    218      1.11  augustss 	for (p = 0; p < nports; p++) {
    219      1.11  augustss 		struct usbd_port *up = &hub->ports[p];
    220      1.11  augustss 		up->device = 0;
    221      1.11  augustss 		up->parent = dev;
    222      1.11  augustss 		up->portno = p+1;
    223      1.11  augustss 		r = uhub_init_port(up);
    224       1.1  augustss 		if (r != USBD_NORMAL_COMPLETION)
    225       1.1  augustss 			printf("%s: init of port %d failed\n",
    226      1.11  augustss 			       USBDEVNAME(sc->sc_dev), up->portno);
    227       1.1  augustss 	}
    228       1.1  augustss 	sc->sc_running = 1;
    229      1.11  augustss 
    230      1.11  augustss 	USB_ATTACH_SUCCESS_RETURN;
    231      1.11  augustss 
    232  1.16.4.2   thorpej  bad:
    233  1.16.4.2   thorpej 	free(hub, M_USBDEV);
    234  1.16.4.2   thorpej 	dev->hub = 0;
    235  1.16.4.2   thorpej 	USB_ATTACH_ERROR_RETURN;
    236      1.11  augustss }
    237      1.11  augustss 
    238       1.1  augustss usbd_status
    239      1.11  augustss uhub_init_port(up)
    240      1.11  augustss 	struct usbd_port *up;
    241       1.1  augustss {
    242      1.11  augustss 	int port = up->portno;
    243      1.11  augustss 	usbd_device_handle dev = up->parent;
    244       1.1  augustss 	usbd_status r;
    245       1.1  augustss 	u_int16_t pstatus;
    246       1.1  augustss 
    247      1.11  augustss 	r = usbd_get_port_status(dev, port, &up->status);
    248       1.1  augustss 	if (r != USBD_NORMAL_COMPLETION)
    249      1.11  augustss 		return (r);
    250      1.11  augustss 	pstatus = UGETW(up->status.wPortStatus);
    251      1.10  drochner 	DPRINTF(("usbd_init_port: adding hub port=%d status=0x%04x "
    252      1.10  drochner 		 "change=0x%04x\n",
    253      1.11  augustss 		 port, pstatus, UGETW(up->status.wPortChange)));
    254       1.1  augustss 	if ((pstatus & UPS_PORT_POWER) == 0) {
    255       1.1  augustss 		/* Port lacks power, turn it on */
    256      1.12  augustss 
    257       1.8  augustss 		/* First let the device go through a good power cycle, */
    258      1.13  augustss 		usbd_delay_ms(dev, USB_PORT_POWER_DOWN_TIME);
    259      1.12  augustss 
    260       1.8  augustss 		/* then turn the power on. */
    261       1.1  augustss 		r = usbd_set_port_feature(dev, port, UHF_PORT_POWER);
    262       1.1  augustss 		if (r != USBD_NORMAL_COMPLETION)
    263       1.1  augustss 			return (r);
    264      1.10  drochner 		DPRINTF(("usb_init_port: turn on port %d power status=0x%04x "
    265      1.10  drochner 			 "change=0x%04x\n",
    266      1.11  augustss 			 port, UGETW(up->status.wPortStatus),
    267      1.11  augustss 			 UGETW(up->status.wPortChange)));
    268       1.1  augustss 		/* Wait for stable power. */
    269      1.13  augustss 		usbd_delay_ms(dev, dev->hub->hubdesc.bPwrOn2PwrGood *
    270      1.13  augustss 			           UHD_PWRON_FACTOR);
    271  1.16.4.1   thorpej 		/* Get the port status again. */
    272  1.16.4.1   thorpej 		r = usbd_get_port_status(dev, port, &up->status);
    273  1.16.4.1   thorpej 		if (r != USBD_NORMAL_COMPLETION)
    274  1.16.4.1   thorpej 			return (r);
    275  1.16.4.1   thorpej 		pstatus = UGETW(up->status.wPortStatus);
    276  1.16.4.1   thorpej 		if ((pstatus & UPS_PORT_POWER) == 0)
    277  1.16.4.1   thorpej 			printf("%s: port %d did not power up\n",
    278  1.16.4.1   thorpej  USBDEVNAME(((struct uhub_softc *)dev->hub->hubsoftc)->sc_dev), port);
    279  1.16.4.1   thorpej 
    280       1.1  augustss 	}
    281       1.1  augustss 	if (dev->self_powered)
    282       1.1  augustss 		/* Self powered hub, give ports maximum current. */
    283      1.11  augustss 		up->power = USB_MAX_POWER;
    284       1.1  augustss 	else
    285      1.11  augustss 		up->power = USB_MIN_POWER;
    286       1.1  augustss 	return (USBD_NORMAL_COMPLETION);
    287       1.1  augustss }
    288       1.1  augustss 
    289       1.1  augustss usbd_status
    290      1.11  augustss uhub_explore(dev)
    291       1.1  augustss 	usbd_device_handle dev;
    292       1.1  augustss {
    293       1.1  augustss 	usb_hub_descriptor_t *hd = &dev->hub->hubdesc;
    294      1.11  augustss 	struct uhub_softc *sc = dev->hub->hubsoftc;
    295       1.1  augustss 	struct usbd_port *up;
    296       1.1  augustss 	usbd_status r;
    297       1.1  augustss 	int port;
    298       1.1  augustss 	int change, status;
    299       1.1  augustss 
    300      1.11  augustss 	DPRINTFN(10, ("uhub_explore dev=%p addr=%d\n", dev, dev->address));
    301       1.1  augustss 
    302       1.1  augustss 	if (!sc->sc_running)
    303       1.1  augustss 		return (USBD_NOT_STARTED);
    304       1.1  augustss 
    305       1.1  augustss 	/* Ignore hubs that are too deep. */
    306       1.1  augustss 	if (dev->depth > USB_HUB_MAX_DEPTH)
    307       1.1  augustss 		return (USBD_TOO_DEEP);
    308       1.1  augustss 
    309       1.1  augustss 	for(port = 1; port <= hd->bNbrPorts; port++) {
    310       1.1  augustss 		up = &dev->hub->ports[port-1];
    311       1.1  augustss 		r = usbd_get_port_status(dev, port, &up->status);
    312       1.1  augustss 		if (r != USBD_NORMAL_COMPLETION) {
    313      1.10  drochner 			DPRINTF(("uhub_explore: get port status failed, "
    314      1.10  drochner 				 "error=%d(%s)\n",
    315       1.8  augustss 				 r, usbd_error_strs[r]));
    316       1.1  augustss 			continue;
    317       1.1  augustss 		}
    318       1.1  augustss 		status = UGETW(up->status.wPortStatus);
    319       1.1  augustss 		change = UGETW(up->status.wPortChange);
    320       1.1  augustss 		DPRINTFN(5, ("uhub_explore: port %d status 0x%04x 0x%04x\n",
    321       1.1  augustss 			     port, status, change));
    322      1.11  augustss 		if (change & UPS_C_PORT_ENABLED) {
    323      1.11  augustss 			usbd_clear_port_feature(dev, port, UHF_C_PORT_ENABLE);
    324      1.11  augustss 			if (status & UPS_PORT_ENABLED) {
    325      1.11  augustss 				printf("%s: illegal enable change, port %d\n",
    326      1.11  augustss 				       USBDEVNAME(sc->sc_dev), port);
    327      1.11  augustss 			} else {
    328      1.11  augustss 				/* Port error condition. */
    329      1.11  augustss 				if (up->restartcnt++ < USBD_RESTART_MAX) {
    330      1.11  augustss 					printf("%s: port error, restarting "
    331      1.11  augustss 					       "port %d\n",
    332      1.11  augustss 					       USBDEVNAME(sc->sc_dev), port);
    333      1.11  augustss 					goto disco;
    334      1.11  augustss 				} else {
    335      1.11  augustss 					printf("%s: port error, giving up "
    336      1.11  augustss 					       "port %d\n",
    337      1.11  augustss 					       USBDEVNAME(sc->sc_dev), port);
    338      1.11  augustss 				}
    339      1.11  augustss 			}
    340      1.11  augustss 		}
    341      1.11  augustss 		if (!(change & UPS_C_CONNECT_STATUS)) {
    342       1.1  augustss 			/* No status change, just do recursive explore. */
    343       1.1  augustss 			if (up->device && up->device->hub)
    344      1.11  augustss 				up->device->hub->explore(up->device);
    345       1.1  augustss 			continue;
    346       1.1  augustss 		}
    347       1.1  augustss 		DPRINTF(("uhub_explore: status change hub=%d port=%d\n",
    348       1.1  augustss 			 dev->address, port));
    349       1.1  augustss 		usbd_clear_port_feature(dev, port, UHF_C_PORT_CONNECTION);
    350       1.1  augustss 		usbd_clear_port_feature(dev, port, UHF_C_PORT_ENABLE);
    351       1.1  augustss 		/*
    352       1.1  augustss 		 * If there is already a device on the port the change status
    353       1.1  augustss 		 * must mean that is has disconnected.  Looking at the
    354       1.1  augustss 		 * current connect status is not enough to figure this out
    355       1.1  augustss 		 * since a new unit may have been connected before we handle
    356       1.1  augustss 		 * the disconnect.
    357       1.1  augustss 		 */
    358      1.11  augustss 	disco:
    359       1.1  augustss 		if (up->device) {
    360       1.1  augustss 			/* Disconnected */
    361      1.10  drochner 			DPRINTF(("uhub_explore: device %d disappeared "
    362      1.10  drochner 				 "on port %d\n",
    363       1.1  augustss 				 up->device->address, port));
    364  1.16.4.2   thorpej 			uhub_disconnect_port(up);
    365       1.1  augustss 			usbd_clear_port_feature(dev, port,
    366       1.1  augustss 						UHF_C_PORT_CONNECTION);
    367       1.1  augustss 		}
    368       1.1  augustss 		if (!(status & UPS_CURRENT_CONNECT_STATUS))
    369       1.1  augustss 			continue;
    370       1.1  augustss 
    371       1.1  augustss 		/* Connected */
    372      1.11  augustss 		up->restartcnt = 0;
    373      1.11  augustss 
    374       1.1  augustss 		/* Wait for maximum device power up time. */
    375      1.13  augustss 		usbd_delay_ms(dev, USB_PORT_POWERUP_DELAY);
    376      1.11  augustss 
    377       1.1  augustss 		/* Reset port, which implies enabling it. */
    378       1.1  augustss 		if (usbd_reset_port(dev, port, &up->status) !=
    379       1.1  augustss 		    USBD_NORMAL_COMPLETION)
    380       1.1  augustss 			continue;
    381       1.1  augustss 
    382       1.1  augustss 		/* Get device info and set its address. */
    383      1.11  augustss 		r = usbd_new_device(&sc->sc_dev, dev->bus,
    384       1.1  augustss 				    dev->depth + 1, status & UPS_LOW_SPEED,
    385       1.1  augustss 				    port, up);
    386       1.1  augustss 		/* XXX retry a few times? */
    387       1.1  augustss 		if (r != USBD_NORMAL_COMPLETION) {
    388      1.10  drochner 			DPRINTFN(-1,("uhub_explore: usb_new_device failed, "
    389      1.10  drochner 				     "error=%d(%s)\n", r, usbd_error_strs[r]));
    390       1.1  augustss 			/* Avoid addressing problems by disabling. */
    391       1.1  augustss 			/* usbd_reset_port(dev, port, &up->status); */
    392       1.1  augustss /* XXX
    393       1.1  augustss  * What should we do.  The device may or may not be at its
    394       1.1  augustss  * assigned address.  In any case we'd like to ignore it.
    395       1.1  augustss  * Maybe the port should be disabled until the device is
    396       1.1  augustss  * disconnected.
    397       1.1  augustss  */
    398       1.1  augustss 			if (r == USBD_SET_ADDR_FAILED || 1) {/* XXX */
    399       1.1  augustss 				/* The unit refused to accept a new
    400       1.1  augustss 				 * address, and since we cannot leave
    401       1.1  augustss 				 * at 0 we have to disable the port
    402       1.1  augustss 				 * instead. */
    403      1.10  drochner 				printf("%s: device problem, disabling "
    404      1.10  drochner 				       "port %d\n",
    405      1.11  augustss 				       USBDEVNAME(sc->sc_dev), port);
    406       1.1  augustss 				usbd_clear_port_feature(dev, port,
    407       1.1  augustss 							UHF_PORT_ENABLE);
    408      1.11  augustss 				/* Make sure we don't try to restart it. */
    409      1.11  augustss 				up->restartcnt = USBD_RESTART_MAX;
    410       1.1  augustss 			}
    411       1.1  augustss 		} else {
    412       1.1  augustss 			if (up->device->hub)
    413      1.11  augustss 				up->device->hub->explore(up->device);
    414       1.1  augustss 		}
    415       1.1  augustss 	}
    416       1.1  augustss 	return (USBD_NORMAL_COMPLETION);
    417       1.1  augustss }
    418       1.1  augustss 
    419  1.16.4.2   thorpej /*
    420  1.16.4.2   thorpej  * The general mechanism for detaching drivers works as follows: Each
    421  1.16.4.2   thorpej  * driver is responsible for maintaining a reference count on the
    422  1.16.4.2   thorpej  * number of outstanding references to its softc (e.g.  from
    423  1.16.4.2   thorpej  * processing hanging in a read or write).  The detach method of the
    424  1.16.4.2   thorpej  * driver decrements this counter and flags in the softc that the
    425  1.16.4.2   thorpej  * driver is dying and then wakes any sleepers.  It then sleeps on the
    426  1.16.4.2   thorpej  * softc.  Each place that can sleep must maintain the reference
    427  1.16.4.2   thorpej  * count.  When the reference count drops to -1 (0 is the normal value
    428  1.16.4.2   thorpej  * of the reference count) the a wakeup on the softc is performed
    429  1.16.4.2   thorpej  * signaling to the detach waiter that all references are gone.
    430  1.16.4.2   thorpej  */
    431  1.16.4.2   thorpej 
    432  1.16.4.2   thorpej /*
    433  1.16.4.2   thorpej  * Called from process context when we discover that a port has
    434  1.16.4.2   thorpej  * been disconnected.
    435  1.16.4.2   thorpej  */
    436       1.1  augustss void
    437  1.16.4.2   thorpej uhub_disconnect_port(up)
    438       1.1  augustss 	struct usbd_port *up;
    439       1.1  augustss {
    440       1.1  augustss 	usbd_device_handle dev = up->device;
    441  1.16.4.2   thorpej 	char *hubname;
    442      1.11  augustss 	int i;
    443       1.1  augustss 
    444       1.1  augustss 	DPRINTFN(3,("uhub_disconnect: up=%p dev=%p port=%d\n",
    445      1.11  augustss 		    up, dev, up->portno));
    446       1.1  augustss 
    447      1.11  augustss 	if (!dev->cdesc) {
    448      1.11  augustss 		/* Partially attached device, just drop it. */
    449      1.11  augustss 		dev->bus->devices[dev->address] = 0;
    450      1.11  augustss 		up->device = 0;
    451      1.11  augustss 		return;
    452      1.11  augustss 	}
    453       1.1  augustss 
    454  1.16.4.2   thorpej 	hubname = USBDEVNAME(*up->parent->subdevs[0]);
    455  1.16.4.2   thorpej 	for (i = 0; dev->subdevs[i]; i++) {
    456  1.16.4.2   thorpej 		printf("%s: at %s port %d (addr %d) disconnected\n",
    457  1.16.4.2   thorpej 		       USBDEVNAME(*dev->subdevs[i]), hubname,
    458  1.16.4.2   thorpej 		       up->portno, dev->address);
    459  1.16.4.2   thorpej 		config_detach(dev->subdevs[i], DETACH_FORCE);
    460       1.1  augustss 	}
    461       1.1  augustss 
    462       1.1  augustss 	dev->bus->devices[dev->address] = 0;
    463       1.1  augustss 	up->device = 0;
    464  1.16.4.2   thorpej 	usb_free_device(dev);
    465  1.16.4.2   thorpej 
    466      1.14  augustss #if defined(__FreeBSD__)
    467      1.14  augustss       device_delete_child(
    468      1.14  augustss 	  device_get_parent(((struct softc *)dev->softc)->sc_dev),
    469      1.14  augustss 	  ((struct softc *)dev->softc)->sc_dev);
    470      1.11  augustss #endif
    471       1.1  augustss }
    472       1.1  augustss 
    473  1.16.4.2   thorpej int
    474  1.16.4.2   thorpej uhub_activate(self, act)
    475  1.16.4.2   thorpej 	struct device *self;
    476  1.16.4.2   thorpej 	enum devact act;
    477  1.16.4.2   thorpej {
    478  1.16.4.2   thorpej 	return (0);
    479  1.16.4.2   thorpej }
    480  1.16.4.2   thorpej 
    481  1.16.4.2   thorpej /*
    482  1.16.4.2   thorpej  * Called from process context when the hub is gone.
    483  1.16.4.2   thorpej  * Detach all devices on active ports.
    484  1.16.4.2   thorpej  */
    485  1.16.4.2   thorpej int
    486  1.16.4.2   thorpej uhub_detach(self, flags)
    487  1.16.4.2   thorpej 	struct device *self;
    488  1.16.4.2   thorpej 	int flags;
    489  1.16.4.2   thorpej {
    490  1.16.4.2   thorpej 	struct uhub_softc *sc = (struct uhub_softc *)self;
    491  1.16.4.2   thorpej 	usbd_device_handle dev = sc->sc_hub;
    492  1.16.4.2   thorpej 	struct usbd_port *rup;
    493  1.16.4.2   thorpej 	int p, nports;
    494  1.16.4.2   thorpej 
    495  1.16.4.2   thorpej 	DPRINTF(("uhub_detach: sc=%p flags=%d\n", sc, flags));
    496  1.16.4.2   thorpej 
    497  1.16.4.2   thorpej 	if (!dev->hub) {
    498  1.16.4.2   thorpej 		/* Must be partially working */
    499  1.16.4.2   thorpej 		return (0);
    500  1.16.4.2   thorpej 	}
    501  1.16.4.2   thorpej 
    502  1.16.4.2   thorpej 	usbd_abort_pipe(sc->sc_ipipe);
    503  1.16.4.2   thorpej 	usbd_close_pipe(sc->sc_ipipe);
    504  1.16.4.2   thorpej 
    505  1.16.4.2   thorpej 	nports = dev->hub->hubdesc.bNbrPorts;
    506  1.16.4.2   thorpej 	for(p = 0; p < nports; p++) {
    507  1.16.4.2   thorpej 		rup = &dev->hub->ports[p];
    508  1.16.4.2   thorpej 		if (rup->device)
    509  1.16.4.2   thorpej 			uhub_disconnect_port(rup);
    510  1.16.4.2   thorpej 	}
    511  1.16.4.2   thorpej 
    512  1.16.4.2   thorpej 	free(dev->hub, M_USBDEV);
    513  1.16.4.2   thorpej 	dev->hub = 0;
    514  1.16.4.2   thorpej 
    515  1.16.4.2   thorpej 	return (0);
    516  1.16.4.2   thorpej }
    517  1.16.4.2   thorpej 
    518  1.16.4.2   thorpej /*
    519  1.16.4.2   thorpej  * Hub interrupt.
    520  1.16.4.2   thorpej  * This an indication that some port has changed status.
    521  1.16.4.2   thorpej  * Notify the bus event handler thread that we need
    522  1.16.4.2   thorpej  * to be explored again.
    523  1.16.4.2   thorpej  */
    524       1.1  augustss void
    525       1.1  augustss uhub_intr(reqh, addr, status)
    526       1.1  augustss 	usbd_request_handle reqh;
    527       1.1  augustss 	usbd_private_handle addr;
    528       1.1  augustss 	usbd_status status;
    529       1.1  augustss {
    530       1.1  augustss 	struct uhub_softc *sc = addr;
    531       1.1  augustss 
    532      1.11  augustss 	DPRINTFN(5,("uhub_intr: sc=%p\n", sc));
    533       1.1  augustss 	if (status != USBD_NORMAL_COMPLETION)
    534       1.9  augustss 		usbd_clear_endpoint_stall_async(sc->sc_ipipe);
    535  1.16.4.2   thorpej 
    536  1.16.4.2   thorpej 	usb_needs_explore(sc->sc_hub->bus);
    537       1.1  augustss }
    538      1.11  augustss 
    539      1.11  augustss #if defined(__FreeBSD__)
    540      1.14  augustss DRIVER_MODULE(uhub, usb, uhub_driver, uhub_devclass, usbd_driver_load, 0);
    541      1.11  augustss #endif
    542