usb_subr.c

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

C
1,109
字号
				    !(UGETW(hs.wHubStatus) & UHS_LOCAL_POWER))					selfpowered = 1;			} else {				r = usbd_get_device_status(dev, &ds);				if (r == USBD_NORMAL_COMPLETION && 				    (UGETW(ds.wStatus) & UDS_SELF_POWERED))					selfpowered = 1;			}			DPRINTF(("usbd_set_config_index: status=0x%04x, %s\n",				 UGETW(ds.wStatus), usbd_errstr(r)));		} else			selfpowered = 1;	}	DPRINTF(("usbd_set_config_index: (addr %d) attr=0x%02x, "		 "selfpowered=%d, power=%d, powerquirk=%x\n", 		 dev->address, cdp->bmAttributes, 		 selfpowered, cdp->bMaxPower * 2,		 dev->quirks->uq_flags & UQ_HUB_POWER));#ifdef USB_DEBUG	if (!dev->powersrc) {		printf("usbd_set_config_index: No power source?\n");		return (USBD_IOERROR);	}#endif	power = cdp->bMaxPower * 2;	if (power > dev->powersrc->power) {		/* XXX print nicer message. */		if (msg)			printf("%s: device addr %d (config %d) exceeds power "				 "budget, %d mA > %d mA\n",			       USBDEVNAME(dev->bus->bdev), dev->address, 			       cdp->bConfigurationValue, 			       power, dev->powersrc->power);		r = USBD_NO_POWER;		goto bad;	}	dev->power = power;	dev->self_powered = selfpowered;	DPRINTF(("usbd_set_config_index: set config %d\n",		 cdp->bConfigurationValue));	r = usbd_set_config(dev, cdp->bConfigurationValue);	if (r != USBD_NORMAL_COMPLETION) {		DPRINTF(("usbd_set_config_index: setting config=%d failed, %s\n",			 cdp->bConfigurationValue, usbd_errstr(r)));		goto bad;	}	DPRINTF(("usbd_set_config_index: setting new config %d\n",		 cdp->bConfigurationValue));	nifc = cdp->bNumInterface;	dev->ifaces = malloc(nifc * sizeof(struct usbd_interface), 			     M_USB, M_NOWAIT);	if (dev->ifaces == 0) {		r = USBD_NOMEM;		goto bad;	}	DPRINTFN(5,("usbd_set_config_index: dev=%p cdesc=%p\n", dev, cdp));	dev->cdesc = cdp;	dev->config = cdp->bConfigurationValue;	dev->state = USBD_DEVICE_CONFIGURED;	for (ifcidx = 0; ifcidx < nifc; ifcidx++) {		r = usbd_fill_iface_data(dev, ifcidx, 0);		if (r != USBD_NORMAL_COMPLETION) {			while (--ifcidx >= 0)				usbd_free_iface_data(dev, ifcidx);			goto bad;		}	}	return (USBD_NORMAL_COMPLETION); bad:	free(cdp, M_USB);	return (r);}/* XXX add function for alternate settings */usbd_statususbd_setup_pipe(dev, iface, ep, pipe)	usbd_device_handle dev;	usbd_interface_handle iface; 	struct usbd_endpoint *ep;	usbd_pipe_handle *pipe;{	usbd_pipe_handle p;	usbd_status r;	DPRINTFN(1,("usbd_setup_pipe: dev=%p iface=%p ep=%p pipe=%p\n",		    dev, iface, ep, pipe));	p = malloc(dev->bus->pipe_size, M_USB, M_NOWAIT);	if (p == 0)		return (USBD_NOMEM);	p->device = dev;	p->iface = iface;	p->state = USBD_PIPE_ACTIVE;	p->endpoint = ep;	ep->refcnt++;	p->refcnt = 1;	p->intrreqh = 0;	p->running = 0;	p->disco = 0;	p->discoarg = 0;	SIMPLEQ_INIT(&p->queue);	r = dev->bus->open_pipe(p);	if (r != USBD_NORMAL_COMPLETION) {		DPRINTFN(-1,("usbd_setup_pipe: endpoint=0x%x failed, %s\n",			 ep->edesc->bEndpointAddress, usbd_errstr(r)));		free(p, M_USB);		return (r);	}	*pipe = p;	return (USBD_NORMAL_COMPLETION);}/* Abort the device control pipe. */voidusbd_kill_pipe(pipe)	usbd_pipe_handle pipe;{	pipe->methods->close(pipe);	pipe->endpoint->refcnt--;	free(pipe, M_USB);}intusbd_getnewaddr(bus)	usbd_bus_handle bus;{	int addr;	for (addr = 1; addr < USB_MAX_DEVICES; addr++)		if (bus->devices[addr] == 0)			return (addr);	return (-1);}usbd_statususbd_probe_and_attach(parent, dev, port, addr)	bdevice *parent;	usbd_device_handle dev;	int port;	int addr;{	struct usb_attach_arg uaa;	usb_device_descriptor_t *dd = &dev->ddesc;#if defined(__NetBSD__)	int found = 0;#endif	int r, i, confi, nifaces;	usbd_interface_handle ifaces[256]; /* 256 is the absolute max */#if defined(__FreeBSD__)/* XXX uaa is a static var. Not a problem as it _should_ be used only * during probe and attach. Should be changed however */	bdevice bdev;	bdev = device_add_child(*parent, NULL, -1, &uaa);	if (!bdev) {	    printf("%s: Device creation failed\n", USBDEVNAME(dev->bus->bdev));	    return (USBD_INVAL);	}#endif	uaa.device = dev;	uaa.iface = 0;	uaa.ifaces = 0;	uaa.nifaces = 0;	uaa.usegeneric = 0;	uaa.port = port;	uaa.configno = UHUB_UNK_CONFIGURATION;	uaa.ifaceno = UHUB_UNK_INTERFACE;	/* First try with device specific drivers. */	if (USB_DO_ATTACH(dev, bdev, parent, &uaa, usbd_print, usbd_submatch))		return (USBD_NORMAL_COMPLETION);	DPRINTF(("usbd_probe_and_attach: no device specific driver found\n"));	/* Next try with interface drivers. */	for (confi = 0; confi < dd->bNumConfigurations; confi++) {		DPRINTFN(1,("usbd_probe_and_attach: trying config idx=%d\n",			    confi));		r = usbd_set_config_index(dev, confi, 1);		if (r != USBD_NORMAL_COMPLETION) {			printf("%s: port %d, set config at addr %d failed, %s\n",			       USBDEVNAME(*parent), port, addr, usbd_errstr(r));			return (r);		}		nifaces = dev->cdesc->bNumInterface;		uaa.configno = dev->cdesc->bConfigurationValue;		for (i = 0; i < nifaces; i++)			ifaces[i] = &dev->ifaces[i];		uaa.ifaces = ifaces;		uaa.nifaces = nifaces;		for (i = 0; i < nifaces; i++) {			if (!ifaces[i])				continue; /* interface already claimed */			uaa.iface = ifaces[i];			uaa.ifaceno = ifaces[i]->idesc->bInterfaceNumber;			if (USB_DO_ATTACH(dev, bdev, parent, &uaa, usbd_print, 					  usbd_submatch)) {#if defined(__NetBSD__)				found++;				ifaces[i] = 0; /* consumed */#elif defined(__FreeBSD__)				/* XXX FreeBSD can't handle multiple intfaces				 *     on 1 device yet */				return (USBD_NORMAL_COMPLETION);#endif			}		}#if defined(__NetBSD__)		if (found != 0)			return (USBD_NORMAL_COMPLETION);#endif	}	/* No interfaces were attached in any of the configurations. */	if (dd->bNumConfigurations > 1)/* don't change if only 1 config */		usbd_set_config_index(dev, 0, 0);	DPRINTF(("usbd_probe_and_attach: no interface drivers found\n"));	/* Finally try the generic driver. */	uaa.iface = 0;	uaa.usegeneric = 1;	uaa.configno = UHUB_UNK_CONFIGURATION;	uaa.ifaceno = UHUB_UNK_INTERFACE;	if (USB_DO_ATTACH(dev, bdev, parent, &uaa, usbd_print, usbd_submatch))		return (USBD_NORMAL_COMPLETION);	/* 	 * The generic attach failed, but leave the device as it is.	 * We just did not find any drivers, that's all.  The device is	 * fully operational and not harming anyone.	 */	DPRINTF(("usbd_probe_and_attach: generic attach failed\n"));#if defined(__FreeBSD__)/* * XXX should we delete the child again? Left for now to avoid dangling * references.	device_delete_child(*parent, bdev);*/#endif	return (USBD_NORMAL_COMPLETION);}/* * Called when a new device has been put in the powered state, * but not yet in the addressed state. * Get initial descriptor, set the address, get full descriptor, * and attach a driver. */usbd_statususbd_new_device(parent, bus, depth, lowspeed, port, up)	bdevice *parent;	usbd_bus_handle bus;	int depth;	int lowspeed;	int port;	struct usbd_port *up;{	usbd_device_handle dev;	usb_device_descriptor_t *dd;	usbd_status r;	int addr;	int i;	DPRINTF(("usbd_new_device bus=%p depth=%d lowspeed=%d\n",		 bus, depth, lowspeed));	addr = usbd_getnewaddr(bus);	if (addr < 0) {		printf("%s: No free USB addresses, new device ignored.\n", 		       USBDEVNAME(bus->bdev));		return (USBD_NO_ADDR);	}	dev = malloc(sizeof *dev, M_USB, M_NOWAIT);	if (dev == 0)		return (USBD_NOMEM);	memset(dev, 0, sizeof(*dev));	dev->bus = bus;	/* Set up default endpoint handle. */	dev->def_ep.edesc = &dev->def_ep_desc;	dev->def_ep.state = USBD_ENDPOINT_ACTIVE;	/* Set up default endpoint descriptor. */	dev->def_ep_desc.bLength = USB_ENDPOINT_DESCRIPTOR_SIZE;	dev->def_ep_desc.bDescriptorType = UDESC_ENDPOINT;	dev->def_ep_desc.bEndpointAddress = USB_CONTROL_ENDPOINT;	dev->def_ep_desc.bmAttributes = UE_CONTROL;	USETW(dev->def_ep_desc.wMaxPacketSize, USB_MAX_IPACKET);	dev->def_ep_desc.bInterval = 0;	dev->state = USBD_DEVICE_DEFAULT;	dev->quirks = &usbd_no_quirk;	dev->address = USB_START_ADDR;	dev->ddesc.bMaxPacketSize = 0;	dev->lowspeed = lowspeed != 0;	dev->depth = depth;	dev->powersrc = up;	dev->langid = USBD_NOLANG;	/* Establish the the default pipe. */	r = usbd_setup_pipe(dev, 0, &dev->def_ep, &dev->default_pipe);	if (r != USBD_NORMAL_COMPLETION) {		usbd_remove_device(dev, up);		return (r);	}	up->device = dev;	dd = &dev->ddesc;	/* Try a few times in case the device is slow (i.e. outside specs.) */	for (i = 0; i < 5; i++) {		/* Get the first 8 bytes of the device descriptor. */		r = usbd_get_desc(dev, UDESC_DEVICE, 0, USB_MAX_IPACKET, dd);		if (r == USBD_NORMAL_COMPLETION)			break;		usbd_delay_ms(dev, 200);	}	if (r != USBD_NORMAL_COMPLETION) {		DPRINTFN(-1, ("usbd_new_device: addr=%d, getting first desc "			      "failed\n",			      addr));		usbd_remove_device(dev, up);		return (r);	}	if (dd->bDescriptorType != UDESC_DEVICE) {		/* Illegal device descriptor */		DPRINTFN(-1,("usbd_new_device: illegal descriptor %d\n",			     dd->bDescriptorType));		usbd_remove_device(dev, up);		return (USBD_INVAL);	}	DPRINTF(("usbd_new_device: adding unit addr=%d, rev=%02x, class=%d, "		 "subclass=%d, protocol=%d, maxpacket=%d, ls=%d\n", 		 addr,UGETW(dd->bcdUSB), dd->bDeviceClass, dd->bDeviceSubClass,		 dd->bDeviceProtocol, dd->bMaxPacketSize, dev->lowspeed));	USETW(dev->def_ep_desc.wMaxPacketSize, dd->bMaxPacketSize);	/* Get the full device descriptor. */	r = usbd_get_device_desc(dev, dd);	if (r != USBD_NORMAL_COMPLETION) {		DPRINTFN(-1, ("usbd_new_device: addr=%d, getting full desc "			      "failed\n", addr));		usbd_remove_device(dev, up);		return (r);	}	/* Figure out what's wrong with this device. */	dev->quirks = usbd_find_quirk(dd);	/* Set the address */	r = usbd_set_address(dev, addr);	if (r != USBD_NORMAL_COMPLETION) {		DPRINTFN(-1,("usbd_new_device: set address %d failed\n",addr));		r = USBD_SET_ADDR_FAILED;		usbd_remove_device(dev, up);		return (r);	}	/* Allow device time to set new address */	usbd_delay_ms(dev, USB_SET_ADDRESS_SETTLE);	dev->address = addr;	/* New device address now */	dev->state = USBD_DEVICE_ADDRESSED;	bus->devices[addr] = dev;	/* Assume 100mA bus powered for now. Changed when configured. */	dev->power = USB_MIN_POWER;	dev->self_powered = 0;	DPRINTF(("usbd_new_device: new dev (addr %d), dev=%p, parent=%p\n", 		 addr, dev, parent));	r = usbd_probe_and_attach(parent, dev, port, addr);	if (r != USBD_NORMAL_COMPLETION) {		usbd_remove_device(dev, up);		return (r);  	}   	return (USBD_NORMAL_COMPLETION);}voidusbd_remove_device(dev, up)	usbd_device_handle dev;	struct usbd_port *up;{	DPRINTF(("usbd_remove_device: %p\n", dev));  	if (dev->default_pipe)		usbd_kill_pipe(dev->default_pipe);	up->device = 0;	dev->bus->devices[dev->address] = 0;	free(dev, M_USB);}#if defined(__NetBSD__)  intusbd_print(aux, pnp)	void *aux;	const char *pnp;{	struct usb_attach_arg *uaa = aux;	char devinfo[1024];	DPRINTFN(15, ("usbd_print dev=%p\n", uaa->device));	if (pnp) {		if (!uaa->usegeneric)			return (QUIET);		usbd_devinfo(uaa->device, 1, devinfo);		printf("%s, %s", devinfo, pnp);	}	if (uaa->port != 0)		printf(" port %d", uaa->port);	if (uaa->configno != UHUB_UNK_CONFIGURATION)		printf(" configuration %d", uaa->configno);	if (uaa->ifaceno != UHUB_UNK_INTERFACE)		printf(" interface %d", uaa->ifaceno);	return (UNCONF);}intusbd_submatch(parent, cf, aux)	struct device *parent;	struct cfdata *cf;	void *aux;{	struct usb_attach_arg *uaa = aux;	if ((uaa->port != 0 &&	     cf->uhubcf_port != UHUB_UNK_PORT &&	     cf->uhubcf_port != uaa->port) ||	    (uaa->configno != UHUB_UNK_CONFIGURATION &&	     cf->uhubcf_configuration != UHUB_UNK_CONFIGURATION &&	     cf->uhubcf_configuration != uaa->configno) ||	    (uaa->ifaceno != UHUB_UNK_INTERFACE &&	     cf->uhubcf_interface != UHUB_UNK_INTERFACE &&	     cf->uhubcf_interface != uaa->ifaceno))		return 0;	return ((*cf->cf_attach->ca_match)(parent, cf, aux));}#endifusbd_statususb_insert_transfer(reqh)	usbd_request_handle reqh;{	usbd_pipe_handle pipe = reqh->pipe;	usbd_interface_handle iface = pipe->iface;	if (pipe->state == USBD_PIPE_IDLE ||	    (iface && iface->state == USBD_INTERFACE_IDLE))		return (USBD_IS_IDLE);	SIMPLEQ_INSERT_TAIL(&pipe->queue, reqh, next);	if (pipe->state != USBD_PIPE_ACTIVE ||	    (iface && iface->state != USBD_INTERFACE_ACTIVE))		return (USBD_NOT_STARTED);	if (pipe->running)		return (USBD_IN_PROGRESS);	pipe->running = 1;	return (USBD_NORMAL_COMPLETION);}voidusb_start_next(pipe)	usbd_pipe_handle pipe;{	usbd_request_handle reqh;	usbd_status r;#ifdef DIAGNOSTIC	if (SIMPLEQ_FIRST(&pipe->queue) == 0) {		printf("usb_start_next: empty\n");		return;	}#endif	/* First remove remove old */#if defined(__NetBSD__)	SIMPLEQ_REMOVE_HEAD(&pipe->queue, SIMPLEQ_FIRST(&pipe->queue), next);#elif defined(__FreeBSD__)	SIMPLEQ_REMOVE_HEAD(&pipe->queue, next);#endif	if (pipe->state != USBD_PIPE_ACTIVE) {		pipe->running = 0;		return;	}	reqh = SIMPLEQ_FIRST(&pipe->queue);	DPRINTFN(5, ("usb_start_next: start reqh=%p\n", reqh));	if (!reqh)		pipe->running = 0;	else {		r = pipe->methods->start(reqh);		if (r != USBD_IN_PROGRESS) {			printf("usb_start_next: error=%d\n", r);			pipe->running = 0;			/* XXX do what? */		}	}}voidusbd_fill_deviceinfo(dev, di)	usbd_device_handle dev;	struct usb_device_info *di;{	struct usbd_port *p;	int i, r, s;	di->config = dev->config;	usbd_devinfo_vp(dev, di->vendor, di->product);	usbd_printBCD(di->revision, UGETW(dev->ddesc.bcdDevice));	di->vendorNo = UGETW(dev->ddesc.idVendor);	di->productNo = UGETW(dev->ddesc.idProduct);	di->class = dev->ddesc.bDeviceClass;	di->power = dev->self_powered ? 0 : dev->power;	di->lowspeed = dev->lowspeed;	di->addr = dev->address;	if (dev->hub) {		for (i = 0; 		     i < sizeof(di->ports) / sizeof(di->ports[0]) &&			     i < dev->hub->hubdesc.bNbrPorts;		     i++) {			p = &dev->hub->ports[i];			if (p->device)				r = p->device->address;			else {				s = UGETW(p->status.wPortStatus);				if (s & UPS_PORT_ENABLED)					r = USB_PORT_ENABLED;				else if (s & UPS_SUSPEND)					r = USB_PORT_SUSPENDED;				else if (s & UPS_PORT_POWER)					r = USB_PORT_POWERED;				else					r = USB_PORT_DISABLED;			}			di->ports[i] = r;		}		di->nports = dev->hub->hubdesc.bNbrPorts;	} else		di->nports = 0;}

⌨️ 快捷键说明

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