uhub.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 528 行 · 第 1/2 页

C
528
字号
uhub_init_port(up)	struct usbd_port *up;{	int port = up->portno;	usbd_device_handle dev = up->parent;	usbd_status r;	u_int16_t pstatus;	r = usbd_get_port_status(dev, port, &up->status);	if (r != USBD_NORMAL_COMPLETION)		return (r);	pstatus = UGETW(up->status.wPortStatus);	DPRINTF(("usbd_init_port: adding hub port=%d status=0x%04x "		 "change=0x%04x\n",		 port, pstatus, UGETW(up->status.wPortChange)));	if ((pstatus & UPS_PORT_POWER) == 0) {		/* Port lacks power, turn it on */		/* First let the device go through a good power cycle, */		usbd_delay_ms(dev, USB_PORT_POWER_DOWN_TIME);		/* then turn the power on. */		r = usbd_set_port_feature(dev, port, UHF_PORT_POWER);		if (r != USBD_NORMAL_COMPLETION)			return (r);		r = usbd_get_port_status(dev, port, &up->status);		if (r != USBD_NORMAL_COMPLETION)			return (r);		DPRINTF(("usb_init_port: turn on port %d power status=0x%04x "			 "change=0x%04x\n",			 port, UGETW(up->status.wPortStatus),			 UGETW(up->status.wPortChange)));		/* Wait for stable power. */		usbd_delay_ms(dev, dev->hub->hubdesc.bPwrOn2PwrGood * 			           UHD_PWRON_FACTOR);	}	if (dev->self_powered)		/* Self powered hub, give ports maximum current. */		up->power = USB_MAX_POWER;	else		up->power = USB_MIN_POWER;	return (USBD_NORMAL_COMPLETION);}usbd_statusuhub_explore(dev)	usbd_device_handle dev;{	usb_hub_descriptor_t *hd = &dev->hub->hubdesc;	struct uhub_softc *sc = dev->hub->hubsoftc;	struct usbd_port *up;	usbd_status r;	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];		r = usbd_get_port_status(dev, port, &up->status);		if (r != USBD_NORMAL_COMPLETION) {			DPRINTF(("uhub_explore: get port %d status failed, %s\n",				 port, usbd_errstr(r)));			continue;		}		status = UGETW(up->status.wPortStatus);		change = UGETW(up->status.wPortChange);		DPRINTFN(5, ("uhub_explore: port %d status 0x%04x 0x%04x\n",			     port, status, change));		if (change & UPS_C_PORT_ENABLED) {			usbd_clear_port_feature(dev, port, UHF_C_PORT_ENABLE);			if (status & UPS_PORT_ENABLED) {				printf("%s: port %d illegal enable change\n",				       USBDEVNAME(sc->sc_dev), port);			} else {				/* Port error condition. */				if (up->restartcnt++ < USBD_RESTART_MAX) {					printf("%s: port %d error, restarting\n",					       USBDEVNAME(sc->sc_dev), port);					goto disco;				} else {					printf("%s: port %d error, giving up\n",					       USBDEVNAME(sc->sc_dev), port);				}			}		}		if (!(change & UPS_C_CONNECT_STATUS)) {			/* No status change, just do recursive explore. */			if (up->device && up->device->hub)				up->device->hub->explore(up->device);			continue;		}		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) {			/* Disconnected */			DPRINTF(("uhub_explore: device %d disappeared "				 "on port %d\n", 				 up->device->address, port));			uhub_disconnect_port(up);			usbd_clear_port_feature(dev, port, 						UHF_C_PORT_CONNECTION);		}		if (!(status & UPS_CURRENT_CONNECT_STATUS))			continue;		/* Connected */		up->restartcnt = 0;		/* 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) != 		    USBD_NORMAL_COMPLETION)			continue;		/* Get device info and set its address. */		r = usbd_new_device(&sc->sc_dev, dev->bus, 				    dev->depth + 1, status & UPS_LOW_SPEED, 				    port, up);		/* XXX retry a few times? */		if (r != USBD_NORMAL_COMPLETION) {			DPRINTFN(-1,("uhub_explore: usb_new_device failed, %s\n",				     usbd_errstr(r)));			/* Avoid addressing problems by disabling. */			/* usbd_reset_port(dev, port, &up->status); *//* XXX * What should we do.  The device may or may not be at its * assigned address.  In any case we'd like to ignore it. * Maybe the port should be disabled until the device is * disconnected. */			if (r == USBD_SET_ADDR_FAILED || 1) {/* XXX */				/* The unit refused to accept a new				 * address, and since we cannot leave				 * it at 0 we have to disable the port				 * instead. */				printf("%s: device problem, disabling "				       "port %d\n",				       USBDEVNAME(sc->sc_dev), port);				usbd_clear_port_feature(dev, port, 							UHF_PORT_ENABLE);				/* Make sure we don't try to restart it. */				up->restartcnt = USBD_RESTART_MAX;			}		} else {			if (up->device->hub)				up->device->hub->explore(up->device);		}	}	return (USBD_NORMAL_COMPLETION);}voiduhub_disconnect_port(up)	struct usbd_port *up;{	usbd_device_handle dev = up->device;	usbd_pipe_handle p, n;	int i;	struct softc {		/* all softc begin like this */		bdevice sc_dev;	};	struct softc *sc;	struct softc *scp;	if (!dev) 		/* no device driver attached at port */		return;	sc = (struct softc *)dev->softc;	scp = (struct softc *)up->parent->softc;	DPRINTFN(3,("uhub_disconnect_port: up=%p dev=%p port=%d\n", 		    up, dev, up->portno));	printf("%s: at %s port %d (addr %d) disconnected\n",	       USBDEVNAME(sc->sc_dev), USBDEVNAME(scp->sc_dev),	       up->portno, dev->address);	if (!dev->cdesc) {		/* Partially attached device, just drop it. */		dev->bus->devices[dev->address] = 0;		up->device = 0;		return;	}	/* Remove the device */	for (i = 0; i < dev->cdesc->bNumInterface; i++) {		for (p = LIST_FIRST(&dev->ifaces[i].pipes); p; p = n) {			n = LIST_NEXT(p, next);			if (p->disco)				p->disco(p->discoarg);		}	}	/* XXX Free all data structures and disable further I/O. */	if (dev->hub) {		struct usbd_port *rup;		int p, nports;		DPRINTFN(3,("usb_disconnect: hub, recursing\n"));		nports = dev->hub->hubdesc.bNbrPorts;		for(p = 0; p < nports; p++) {			rup = &dev->hub->ports[p];			if (rup->device)				uhub_disconnect_port(rup);		}	}#if defined(__FreeBSD__)	device_delete_child(scp->sc_dev, sc->sc_dev);#endif	/* clean up the kitchen */	for (i = 0; i < dev->cdesc->bNumInterface; i++) {		for (p = LIST_FIRST(&dev->ifaces[i].pipes); p; p = n) {			n = LIST_NEXT(p, next);			usbd_abort_pipe(p);			usbd_close_pipe(p);		}	}	dev->bus->devices[dev->address] = 0;	up->device = 0;	/* XXX free */}voiduhub_intr(reqh, addr, status)	usbd_request_handle reqh;	usbd_private_handle addr;	usbd_status status;{	struct uhub_softc *sc = addr;	DPRINTFN(5,("uhub_intr: sc=%p\n", sc));	if (status != USBD_NORMAL_COMPLETION)		usbd_clear_endpoint_stall_async(sc->sc_ipipe);	else		usb_needs_explore(sc->sc_hub->bus);}#if defined(__FreeBSD__)DRIVER_MODULE(uhub, usb, uhubroot_driver, uhubroot_devclass, 0, 0);DRIVER_MODULE(uhub, uhub, uhub_driver, uhub_devclass, usbd_driver_load, 0);#endif

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?