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