Ejemplo n.º 1
0
usbd_status
usbd_reset_port(usbd_device_handle dev, int port, usb_port_status_t *ps)
{
	usb_device_request_t req;
	usbd_status err;
	int n;

	req.bmRequestType = UT_WRITE_CLASS_OTHER;
	req.bRequest = UR_SET_FEATURE;
	USETW(req.wValue, UHF_PORT_RESET);
	USETW(req.wIndex, port);
	USETW(req.wLength, 0);
	err = usbd_do_request(dev, &req, 0);
	DPRINTFN(1,("usbd_reset_port: port %d reset done, error=%s\n",
		    port, usbd_errstr(err)));
	if (err)
		return (err);
	n = 10;
	do {
		/* Wait for device to recover from reset. */
		usbd_delay_ms(dev, USB_PORT_RESET_DELAY);
		err = usbd_get_port_status(dev, port, ps);
		if (err) {
			DPRINTF(("usbd_reset_port: get status failed %d\n",
				 err));
			return (err);
		}
		/* If the device disappeared, just give up. */
		if (!(UGETW(ps->wPortStatus) & UPS_CURRENT_CONNECT_STATUS))
			return (USBD_NORMAL_COMPLETION);
	} while ((UGETW(ps->wPortChange) & UPS_C_PORT_RESET) == 0 && --n > 0);
	if (n == 0)
		return (USBD_TIMEOUT);
	err = usbd_clear_port_feature(dev, port, UHF_C_PORT_RESET);
#ifdef USB_DEBUG
	if (err)
		DPRINTF(("usbd_reset_port: clear port feature failed %d\n",
			 err));
#endif

	/* Wait for the device to recover from reset. */
	usbd_delay_ms(dev, USB_PORT_RESET_RECOVERY);
	return (err);
}
Ejemplo n.º 2
0
usbd_status
uhub_explore(usbd_device_handle dev)
{
	usb_hub_descriptor_t *hd = &dev->hub->hubdesc;
	device_t self = dev->hub->hubdev;
	struct uhub_softc *sc = device_get_softc(self);
	struct usbd_port *up;
	usbd_status err;
	int speed;
	int port;
	int change, status;

	DPRINTFN(10, ("uhub_explore dev=%p addr=%d\n", dev, dev->address));

	if (!sc->sc_running)
		return (USBD_NOT_STARTED);

	/* Ignore hubs that are too deep. */
	if (dev->depth > USB_HUB_MAX_DEPTH)
		return (USBD_TOO_DEEP);

	for(port = 1; port <= hd->bNbrPorts; port++) {
		up = &dev->hub->ports[port-1];
		err = usbd_get_port_status(dev, port, &up->status);
		if (err) {
			DPRINTF(("uhub_explore: get port status failed, "
				 "error=%s\n", usbd_errstr(err)));
			continue;
		}
		status = UGETW(up->status.wPortStatus);
		change = UGETW(up->status.wPortChange);
		DPRINTFN(3,("uhub_explore: %s port %d status 0x%04x 0x%04x\n",
			    device_get_nameunit(self), port, status, change));
		if (change & UPS_C_PORT_ENABLED) {
			DPRINTF(("uhub_explore: C_PORT_ENABLED 0x%x\n", change));
			usbd_clear_port_feature(dev, port, UHF_C_PORT_ENABLE);
			if (change & UPS_C_CONNECT_STATUS) {
				/* Ignore the port error if the device
				   vanished. */
			} else if (status & UPS_PORT_ENABLED) {
				device_printf(self,
				    "illegal enable change, port %d\n", port);
			} else {
				/* Port error condition. */
				if (up->restartcnt) /* no message first time */
					device_printf(self,
					    "port error, restarting "
					    "port %d\n", port);

				if (up->restartcnt++ < USBD_RESTART_MAX)
					goto disco;
				else
					device_printf(self,
					    "port error, giving up "
					    "port %d\n", port);
			}
		}
		if (!(change & UPS_C_CONNECT_STATUS)) {
			DPRINTFN(3,("uhub_explore: port=%d !C_CONNECT_"
				    "STATUS\n", port));
			/* No status change, just do recursive explore. */
			if (up->device != NULL && up->device->hub != NULL)
				up->device->hub->explore(up->device);
#if 0 && defined(DIAGNOSTIC)
			if (up->device == NULL &&
			    (status & UPS_CURRENT_CONNECT_STATUS))
				device_printf(self,
				    "connected, no device\n");
#endif
			continue;
		}

		/* We have a connect status change, handle it. */

		DPRINTF(("uhub_explore: status change hub=%d port=%d\n",
			 dev->address, port));
		usbd_clear_port_feature(dev, port, UHF_C_PORT_CONNECTION);
		/*usbd_clear_port_feature(dev, port, UHF_C_PORT_ENABLE);*/
		/*
		 * If there is already a device on the port the change status
		 * must mean that is has disconnected.  Looking at the
		 * current connect status is not enough to figure this out
		 * since a new unit may have been connected before we handle
		 * the disconnect.
		 */
	disco:
		if (up->device != NULL) {
			/* Disconnected */
			DPRINTF(("uhub_explore: device addr=%d disappeared "
				 "on port %d\n", up->device->address, port));
			usb_disconnect_port(up, self);
			usbd_clear_port_feature(dev, port,
						UHF_C_PORT_CONNECTION);
		}
		if (!(status & UPS_CURRENT_CONNECT_STATUS)) {
			/* Nothing connected, just ignore it. */
			DPRINTFN(3,("uhub_explore: port=%d !CURRENT_CONNECT"
				    "_STATUS\n", port));
			continue;
		}

		/* Connected */

		if (!(status & UPS_PORT_POWER))
			device_printf(self,
			    "strange, connected port %d has no power\n",
			    port);

		/* Wait for maximum device power up time. */
		usbd_delay_ms(dev, USB_PORT_POWERUP_DELAY);

		/* Reset port, which implies enabling it. */
		if (usbd_reset_port(dev, port, &up->status)) {
			device_printf(self,
			    "port %d reset failed\n", port);
			continue;
		}
		/* Get port status again, it might have changed during reset */
		err = usbd_get_port_status(dev, port, &up->status);
		if (err) {
			DPRINTF(("uhub_explore: get port status failed, "
				 "error=%s\n", usbd_errstr(err)));
			continue;
		}
		status = UGETW(up->status.wPortStatus);
		change = UGETW(up->status.wPortChange);
		if (!(status & UPS_CURRENT_CONNECT_STATUS)) {
			/* Nothing connected, just ignore it. */
#ifdef DIAGNOSTIC
			device_printf(self,
			    "port %d, device disappeared after reset\n",
			    port);
#endif
			continue;
		}

#if 0
		if (UHUB_IS_HIGH_SPEED(sc) && !(status & UPS_HIGH_SPEED)) {
			device_printf(self,
			    "port %d, transaction translation not "
			    "implemented, low/full speed device ignored\n",
			    port);
			continue;
		}
#endif

		/* Figure out device speed */
		if (status & UPS_HIGH_SPEED)
			speed = USB_SPEED_HIGH;
		else if (status & UPS_LOW_SPEED)
			speed = USB_SPEED_LOW;
		else
			speed = USB_SPEED_FULL;
		/* Get device info and set its address. */
		err = usbd_new_device(self, dev->bus,
				      dev->depth + 1, speed, port, up);
		/* XXX retry a few times? */
		if (err) {
			DPRINTFN(-1,("uhub_explore: usb_new_device failed, "
				     "error=%s\n", usbd_errstr(err)));
			/* Avoid addressing problems by disabling. */
			/* usbd_reset_port(dev, port, &up->status); */

			/*
			 * The unit refused to accept a new address, or had
			 * some other serious problem.  Since we cannot leave
			 * at 0 we have to disable the port instead.
			 */
			device_printf(self,
			    "device problem (%s), disabling port %d\n",
			    usbd_errstr(err), port);
			usbd_clear_port_feature(dev, port, UHF_PORT_ENABLE);
		} else {
			/* The port set up succeeded, reset error count. */
			up->restartcnt = 0;

			if (up->device->hub)
				up->device->hub->explore(up->device);
		}
	}
	return (USBD_NORMAL_COMPLETION);
}
Ejemplo n.º 3
0
int
uhub_port_connect(struct uhub_softc *sc, int port, int status, int change)
{
	struct usbd_port *up = &sc->sc_hub->hub->ports[port-1];
	int speed;

	/* We have a connect status change, handle it. */
	usbd_clear_port_feature(sc->sc_hub, port, UHF_C_PORT_CONNECTION);

	/*
	 * If there is already a device on the port the change status
	 * must mean that is has disconnected.  Looking at the
	 * current connect status is not enough to figure this out
	 * since a new unit may have been connected before we handle
	 * the disconnect.
	 */
	if (up->device != NULL) {
		/* Disconnected */
		usbd_detach(up->device, &sc->sc_dev);
		up->device = NULL;
	}

	/* Nothing connected, just ignore it. */
	if ((status & UPS_CURRENT_CONNECT_STATUS) == 0)
		return (0);

	/* Connected */
	if ((status & (UPS_PORT_POWER|UPS_PORT_POWER_SS)) == 0) {
		printf("%s: connected port %d has no power\n", DEVNAME(sc),
		    port);
		return (-1);
	}

	/* Wait for maximum device power up time. */
	usbd_delay_ms(sc->sc_hub, USB_PORT_POWERUP_DELAY);

	/* Reset port, which implies enabling it. */
	if (usbd_reset_port(sc->sc_hub, port)) {
		printf("%s: port %d reset failed\n", DEVNAME(sc), port);
		return (-1);
	}
	/* Get port status again, it might have changed during reset */
	if (usbd_get_port_status(sc->sc_hub, port, &up->status))
		return (-1);

	status = UGETW(up->status.wPortStatus);
	change = UGETW(up->status.wPortChange);
	DPRINTF("%s: port %d status=0x%04x change=0x%04x\n", DEVNAME(sc),
	    port, status, change);

	/* Nothing connected, just ignore it. */
	if ((status & UPS_CURRENT_CONNECT_STATUS) == 0) {
		DPRINTF("%s: port %d, device disappeared after reset\n",
		    DEVNAME(sc), port);
		return (-1);
	}

	/*
	 * Figure out device speed.  This is a bit tricky because
	 * UPS_PORT_POWER_SS and UPS_LOW_SPEED share the same bit.
	 */
	if ((status & UPS_PORT_POWER) == 0)
		status &= ~UPS_PORT_POWER_SS;

	if (status & UPS_HIGH_SPEED)
		speed = USB_SPEED_HIGH;
	else if (status & UPS_LOW_SPEED)
		speed = USB_SPEED_LOW;
	else {
		/*
		 * If there is no power bit set, it is certainly
		 * a Super Speed device, so use the speed of its
		 * parent hub.
		 */
		if (status & UPS_PORT_POWER)
			speed = USB_SPEED_FULL;
		else
			speed = sc->sc_hub->speed;
	}

	/*
	 * Reduce the speed, otherwise we won't setup the proper
	 * transfer methods.
	 */
	if (speed > sc->sc_hub->speed)
		speed = sc->sc_hub->speed;

	/* Get device info and set its address. */
	if (usbd_new_device(&sc->sc_dev, sc->sc_hub->bus, sc->sc_hub->depth + 1,
	    speed, port, up)) {
		/*
		 * The unit refused to accept a new address, or had
		 * some other serious problem.  Since we cannot leave
		 * at 0 we have to disable the port instead.
		 */
		printf("%s: device problem, disabling port %d\n", DEVNAME(sc),
		    port);
		usbd_clear_port_feature(sc->sc_hub, port, UHF_PORT_ENABLE);

		return (-1);
	}

	return (0);
}
Ejemplo n.º 4
0
int
uhub_explore(struct usbd_device *dev)
{
	struct uhub_softc *sc = dev->hub->hubsoftc;
	struct usbd_port *up;
	int status, change;
	int port;

	if (usbd_is_dying(sc->sc_hub))
		return (EIO);

	if (!sc->sc_running)
		return (ENXIO);

	/* Ignore hubs that are too deep. */
	if (sc->sc_hub->depth > USB_HUB_MAX_DEPTH)
		return (EOPNOTSUPP);

	for (port = 1; port <= sc->sc_hub->hub->nports; port++) {
		up = &sc->sc_hub->hub->ports[port-1];

		change = 0;
		status = 0;

		if ((sc->sc_status & (1 << port)) || up->reattach) {
			sc->sc_status &= ~(1 << port);

			if (usbd_get_port_status(dev, port, &up->status))
				continue;

			status = UGETW(up->status.wPortStatus);
			change = UGETW(up->status.wPortChange);
			DPRINTF("%s: port %d status=0x%04x change=0x%04x\n",
			    sc->sc_dev.dv_xname, port, status, change);
		}

		if (up->reattach) {
			change |= UPS_C_CONNECT_STATUS;
			up->reattach = 0;
		}

		if (change & UPS_C_PORT_ENABLED) {
			usbd_clear_port_feature(sc->sc_hub, port,
			    UHF_C_PORT_ENABLE);
			if (change & UPS_C_CONNECT_STATUS) {
				/* Ignore the port error if the device
				   vanished. */
			} else if (status & UPS_PORT_ENABLED) {
				printf("%s: illegal enable change, port %d\n",
				       sc->sc_dev.dv_xname, port);
			} else {
				/* Port error condition. */
				if (up->restartcnt) /* no message first time */
					printf("%s: port error, restarting "
					       "port %d\n",
					       sc->sc_dev.dv_xname, port);

				if (up->restartcnt++ < USBD_RESTART_MAX)
					change |= UPS_C_CONNECT_STATUS;
				else
					printf("%s: port error, giving up "
					       "port %d\n",
					       sc->sc_dev.dv_xname, port);
			}
		}

		if (change & UPS_C_CONNECT_STATUS) {
			if (uhub_port_connect(sc, port, status, change))
				continue;

			/* The port set up succeeded, reset error count. */
			up->restartcnt = 0;
		}

		if (change & UPS_C_PORT_LINK_STATE) {
			usbd_clear_port_feature(sc->sc_hub, port,
			    UHF_C_PORT_LINK_STATE);
		}

		/* Recursive explore. */
		if (up->device != NULL && up->device->hub != NULL)
			up->device->hub->explore(up->device);
	}

	return (0);
}
Ejemplo n.º 5
0
/*
 ****************************************************************
 *	Varre as portas de uma unidade				*
 ****************************************************************
 */
int
uhub_explore (struct usbd_device *dev)
{
	struct usb_hub_descriptor	*hd = &dev->hub->hubdesc;
	struct uhub_softc		*sc = dev->hub->hubsoftc;
	struct usbd_port		*up;
	int				err, speed;
	int				port, change, status;

#ifdef	USB_MSG
	printf ("uhub_explore (%s)\n", sc->sc_dev->nameunit);
	printf ("uhub_explore: dev= %P addr = %d\n", dev, dev->address);
#endif	USB_MSG

	if (sc->sc_running == 0)
		return (USBD_NOT_STARTED);

	if (dev->depth > USB_HUB_MAX_DEPTH)
		return (USBD_TOO_DEEP);

	for (port = 1; port <= hd->bNbrPorts; port++)
	{
		up = &dev->hub->ports[port - 1];

		if (err = usbd_get_port_status (dev, port, &up->status))
		{
			printf
			(	"uhub_explore (%s): erro ao ler o estado da porta %d (%s)\n",
				sc->sc_dev->nameunit, port, usbd_errstr (err)
			);
			continue;
		}

		status = UGETW (up->status.wPortStatus);
		change = UGETW (up->status.wPortChange);

#ifdef	USB_MSG
		printf
		(	"uhub_explore (%s) porta %d status = 0x%04X change = 0x%04X\n",
			sc->sc_dev->nameunit, port, status, change
		);
#endif	USB_MSG

		if (change & UPS_C_PORT_ENABLED)
		{
#ifdef	USB_MSG
			printf ("uhub_explore: C_PORT_ENABLED\n");
#endif	USB_MSG

			usbd_clear_port_feature (dev, port, UHF_C_PORT_ENABLE);

			if   (change & UPS_C_CONNECT_STATUS)
			{
				/* Ignore the port error if the device vanished. */
#ifdef	USB_MSG
				printf
				(	"uhub_explore (%s): ignorando erro, porta %d\n",
					sc->sc_dev->nameunit, port
				);
#endif	USB_MSG
			}
			elif (status & UPS_PORT_ENABLED)
			{
				printf
				(	"uhub_explore (%s): mudança inválida de habilitação, porta %d\n",
					sc->sc_dev->nameunit, port
				);
			}
			else
			{
				/* Port error condition */

				if (up->restartcnt)		/* no message first time */