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 + -
显示快捷键?