usbd_status usbd_intr_transfer(usbd_xfer_handle xfer, usbd_pipe_handle pipe, u_int16_t flags, u_int32_t timeout, void *buf, u_int32_t *size, const char *lbl) { usbd_status err; USBHIST_FUNC(); USBHIST_CALLED(usbdebug); usbd_setup_xfer(xfer, pipe, 0, buf, *size, flags, timeout, NULL); DPRINTFN(1, ("usbd_intr_transfer: start transfer %d bytes\n", *size)); err = usbd_sync_transfer_sig(xfer); usbd_get_xfer_status(xfer, NULL, NULL, size, NULL); DPRINTFN(1,("usbd_intr_transfer: transferred %d\n", *size)); if (err) { DPRINTF(("usbd_intr_transfer: error=%d\n", err)); usbd_clear_endpoint_stall(pipe); } USBHIST_LOG(usbdebug, "<- done err %d", xfer, err, 0, 0); return (err); }
usbd_status usbd_get_string_desc(struct usbd_device *dev, int sindex, int langid, usb_string_descriptor_t *sdesc, int *sizep) { USBHIST_FUNC(); USBHIST_CALLED(usbdebug); usb_device_request_t req; usbd_status err; int actlen; req.bmRequestType = UT_READ_DEVICE; req.bRequest = UR_GET_DESCRIPTOR; USETW2(req.wValue, UDESC_STRING, sindex); USETW(req.wIndex, langid); USETW(req.wLength, 2); /* only size byte first */ err = usbd_do_request_flags(dev, &req, sdesc, USBD_SHORT_XFER_OK, &actlen, USBD_DEFAULT_TIMEOUT); if (err) return err; if (actlen < 2) return USBD_SHORT_XFER; USETW(req.wLength, sdesc->bLength); /* the whole string */ err = usbd_do_request_flags(dev, &req, sdesc, USBD_SHORT_XFER_OK, &actlen, USBD_DEFAULT_TIMEOUT); if (err) return err; if (actlen != sdesc->bLength) { DPRINTF("expected %d, got %d", sdesc->bLength, actlen, 0, 0); } *sizep = actlen; return USBD_NORMAL_COMPLETION; }
usb_interface_descriptor_t * usbd_find_idesc(usb_config_descriptor_t *cd, int ifaceidx, int altidx) { USBHIST_FUNC(); USBHIST_CALLED(usbdebug); char *p = (char *)cd; char *end = p + UGETW(cd->wTotalLength); usb_interface_descriptor_t *d; int curidx, lastidx, curaidx = 0; for (curidx = lastidx = -1; p < end; ) { d = (usb_interface_descriptor_t *)p; DPRINTFN(4, "idx=%d(%d) altidx=%d(%d)", ifaceidx, curidx, altidx, curaidx); DPRINTFN(4, "len=%d type=%d", d->bLength, d->bDescriptorType, 0, 0); if (d->bLength == 0) /* bad descriptor */ break; p += d->bLength; if (p <= end && d->bDescriptorType == UDESC_INTERFACE) { if (d->bInterfaceNumber != lastidx) { lastidx = d->bInterfaceNumber; curidx++; curaidx = 0; } else curaidx++; if (ifaceidx == curidx && altidx == curaidx) return d; } } return NULL; }
usbd_status usbd_reload_device_desc(struct usbd_device *dev) { USBHIST_FUNC(); USBHIST_CALLED(usbdebug); usb_device_descriptor_t *udd = &dev->ud_ddesc; usbd_status err; /* Get the full device descriptor. */ err = usbd_get_device_desc(dev, udd); if (err) return err; DPRINTFN(15, "bLength %5u", udd->bLength, 0, 0, 0); DPRINTFN(15, "bDescriptorType %5u", udd->bDescriptorType, 0, 0, 0); DPRINTFN(15, "bcdUSB %2x.%02x", udd->bcdUSB[1], udd->bcdUSB[0], 0, 0); DPRINTFN(15, "bDeviceClass %5u", udd->bDeviceClass, 0, 0, 0); DPRINTFN(15, "bDeviceSubClass %5u", udd->bDeviceSubClass, 0, 0, 0); DPRINTFN(15, "bDeviceProtocol %5u", udd->bDeviceProtocol, 0, 0, 0); DPRINTFN(15, "bMaxPacketSize0 %5u", udd->bMaxPacketSize, 0, 0, 0); DPRINTFN(15, "idVendor 0x%04x", udd->idVendor, 0, 0, 0); DPRINTFN(15, "idProduct 0x%04x", udd->idProduct, 0, 0, 0); DPRINTFN(15, "bcdDevice %2x.%02x", udd->bcdDevice[1], udd->bcdDevice[0], 0, 0); DPRINTFN(15, "iManufacturer %5u", udd->iManufacturer, 0, 0, 0); DPRINTFN(15, "iProduct %5u", udd->iProduct, 0, 0, 0); DPRINTFN(15, "iSerial %5u", udd->iSerialNumber, 0, 0, 0); DPRINTFN(15, "bNumConfigurations %5u", udd->bNumConfigurations, 0, 0, 0); /* Figure out what's wrong with this device. */ dev->ud_quirks = usbd_find_quirk(udd); return USBD_NORMAL_COMPLETION; }
void usb_detach_broadcast(device_t dv, kcondvar_t *cv) { USBHIST_FUNC(); USBHIST_CALLED(usbdebug); DPRINTFN(1, "for dv %p", dv, 0, 0, 0); cv_broadcast(cv); }
usbd_status usbd_get_device_desc(struct usbd_device *dev, usb_device_descriptor_t *d) { USBHIST_FUNC(); USBHIST_CALLED(usbdebug); return (usbd_get_desc(dev, UDESC_DEVICE, 0, USB_DEVICE_DESCRIPTOR_SIZE, d)); }
void usb_detach_wakeupold(device_t dv) { USBHIST_FUNC(); USBHIST_CALLED(usbdebug); DPRINTFN(1, "for dv %p", dv, 0, 0, 0); wakeup(dv); /* XXXSMP ok */ }
usbd_status usbd_get_config_desc_full(struct usbd_device *dev, int conf, void *d, int size) { USBHIST_FUNC(); USBHIST_CALLED(usbdebug); DPRINTFN(3, "conf=%d", conf, 0, 0, 0); return usbd_get_desc(dev, UDESC_CONFIG, conf, size, d); }
void usb_detach_waitold(device_t dv) { USBHIST_FUNC(); USBHIST_CALLED(usbdebug); DPRINTFN(1, "waiting for dv %p", dv, 0, 0, 0); if (tsleep(dv, PZERO, "usbdet", hz * 60)) /* XXXSMP ok */ printf("usb_detach_waitold: %s didn't detach\n", device_xname(dv)); DPRINTFN(1, "done", 0, 0, 0, 0); }
void usb_detach_wait(device_t dv, kcondvar_t *cv, kmutex_t *lock) { USBHIST_FUNC(); USBHIST_CALLED(usbdebug); DPRINTFN(1, "waiting for dv %p", dv, 0, 0, 0); if (cv_timedwait(cv, lock, hz * 60)) // dv, PZERO, "usbdet", hz * 60 printf("usb_detach_wait: %s didn't detach\n", device_xname(dv)); DPRINTFN(1, "done", 0, 0, 0, 0); }
usbd_status usbd_get_device_status(struct usbd_device *dev, usb_status_t *st) { USBHIST_FUNC(); USBHIST_CALLED(usbdebug); usb_device_request_t req; req.bmRequestType = UT_READ_DEVICE; req.bRequest = UR_GET_STATUS; USETW(req.wValue, 0); USETW(req.wIndex, 0); USETW(req.wLength, sizeof(usb_status_t)); return usbd_do_request(dev, &req, st); }
usbd_status usbd_set_port_feature(struct usbd_device *dev, int port, int sel) { USBHIST_FUNC(); USBHIST_CALLED(usbdebug); usb_device_request_t req; DPRINTF("dev %p port %d sel %d", dev, sel, 0, 0); req.bmRequestType = UT_WRITE_CLASS_OTHER; req.bRequest = UR_SET_FEATURE; USETW(req.wValue, sel); USETW(req.wIndex, port); USETW(req.wLength, 0); return usbd_do_request(dev, &req, 0); }
usbd_status usbd_clear_hub_feature(struct usbd_device *dev, int sel) { USBHIST_FUNC(); USBHIST_CALLED(usbdebug); usb_device_request_t req; DPRINTF("dev %p sel %d", dev, sel, 0, 0); req.bmRequestType = UT_WRITE_CLASS_DEVICE; req.bRequest = UR_CLEAR_FEATURE; USETW(req.wValue, sel); USETW(req.wIndex, 0); USETW(req.wLength, 0); return usbd_do_request(dev, &req, 0); }
usbd_status usbd_get_port_status(struct usbd_device *dev, int port, usb_port_status_t *ps) { USBHIST_FUNC(); USBHIST_CALLED(usbdebug); usb_device_request_t req; DPRINTF("dev %p port %d", dev, port, 0, 0); req.bmRequestType = UT_READ_CLASS_OTHER; req.bRequest = UR_GET_STATUS; USETW(req.wValue, 0); USETW(req.wIndex, port); USETW(req.wLength, sizeof(*ps)); return usbd_do_request(dev, &req, ps); }
usbd_status usbd_set_address(struct usbd_device *dev, int addr) { USBHIST_FUNC(); USBHIST_CALLED(usbdebug); usb_device_request_t req; DPRINTF("dev %p addr %d", dev, addr, 0, 0); req.bmRequestType = UT_WRITE_DEVICE; req.bRequest = UR_SET_ADDRESS; USETW(req.wValue, addr); USETW(req.wIndex, 0); USETW(req.wLength, 0); return usbd_do_request(dev, &req, 0); }
usbd_status usbd_get_config(struct usbd_device *dev, uint8_t *conf) { USBHIST_FUNC(); USBHIST_CALLED(usbdebug); usb_device_request_t req; DPRINTF("dev %p", dev, 0, 0, 0); req.bmRequestType = UT_READ_DEVICE; req.bRequest = UR_GET_CONFIG; USETW(req.wValue, 0); USETW(req.wIndex, 0); USETW(req.wLength, 1); return usbd_do_request(dev, &req, conf); }
usbd_status usbd_set_port_u2_timeout(struct usbd_device *dev, int port, int timeout) { USBHIST_FUNC(); USBHIST_CALLED(usbdebug); usb_device_request_t req; DPRINTF("dev %p port %d timeout %d", dev, port, timeout, 0); req.bmRequestType = UT_WRITE_CLASS_OTHER; req.bRequest = UR_SET_FEATURE; USETW(req.wValue, UHF_PORT_U2_TIMEOUT); USETW2(req.wIndex, timeout, port); USETW(req.wLength, 0); return usbd_do_request(dev, &req, 0); }
Static usbd_status usbd_set_config(struct usbd_device *dev, int conf) { USBHIST_FUNC(); USBHIST_CALLED(usbdebug); usb_device_request_t req; DPRINTFN(5, "dev %p conf %d", dev, conf, 0, 0); req.bmRequestType = UT_WRITE_DEVICE; req.bRequest = UR_SET_CONFIG; USETW(req.wValue, conf); USETW(req.wIndex, 0); USETW(req.wLength, 0); return usbd_do_request(dev, &req, 0); }
usbd_status usbd_get_report_descriptor(struct usbd_device *dev, int ifcno, int size, void *d) { USBHIST_FUNC(); USBHIST_CALLED(usbdebug); usb_device_request_t req; DPRINTF("dev %p ifcno %d size %d", dev, ifcno, size, 0); req.bmRequestType = UT_READ_INTERFACE; req.bRequest = UR_GET_DESCRIPTOR; USETW2(req.wValue, UDESC_REPORT, 0); /* report id should be 0 */ USETW(req.wIndex, ifcno); USETW(req.wLength, size); return usbd_do_request(dev, &req, d); }
void usbd_remove_device(struct usbd_device *dev, struct usbd_port *up) { USBHIST_FUNC(); USBHIST_CALLED(usbdebug); DPRINTF("dev %p up %p", dev, up, 0, 0); if (dev->ud_pipe0 != NULL) usbd_kill_pipe(dev->ud_pipe0); up->up_dev = NULL; dev->ud_bus->ub_devices[dev->ud_addr] = NULL; kmem_free(dev, sizeof(*dev)); }
usbd_status usbd_get_desc(struct usbd_device *dev, int type, int index, int len, void *desc) { usb_device_request_t req; USBHIST_FUNC(); USBHIST_CALLED(usbdebug); DPRINTFN(3,"type=%d, index=%d, len=%d", type, index, len, 0); req.bmRequestType = UT_READ_DEVICE; req.bRequest = UR_GET_DESCRIPTOR; USETW2(req.wValue, type, index); USETW(req.wIndex, 0); USETW(req.wLength, len); return usbd_do_request(dev, &req, desc); }
usbd_status usbd_get_config_desc(struct usbd_device *dev, int confidx, usb_config_descriptor_t *d) { USBHIST_FUNC(); USBHIST_CALLED(usbdebug); usbd_status err; DPRINTFN(3, "confidx=%d", confidx, 0, 0, 0); err = usbd_get_desc(dev, UDESC_CONFIG, confidx, USB_CONFIG_DESCRIPTOR_SIZE, d); if (err) return err; if (d->bDescriptorType != UDESC_CONFIG) { DPRINTFN(1, "confidx=%d, bad desc len=%d type=%d", confidx, d->bLength, d->bDescriptorType, 0); return USBD_INVAL; } return USBD_NORMAL_COMPLETION; }
usbd_status usbd_setup_pipe_flags(struct usbd_device *dev, struct usbd_interface *iface, struct usbd_endpoint *ep, int ival, struct usbd_pipe **pipe, uint8_t flags) { USBHIST_FUNC(); USBHIST_CALLED(usbdebug); struct usbd_pipe *p; usbd_status err; p = kmem_alloc(dev->ud_bus->ub_pipesize, KM_SLEEP); DPRINTFN(1, "dev=%p addr=%d iface=%p ep=%p pipe=%p", dev, dev->ud_addr, iface, ep); if (p == NULL) { DPRINTFN(1, "(nomem)", 0, 0, 0, 0); return USBD_NOMEM; } p->up_dev = dev; p->up_iface = iface; p->up_endpoint = ep; ep->ue_refcnt++; p->up_intrxfer = NULL; p->up_running = 0; p->up_aborting = 0; p->up_serialise = true; p->up_repeat = 0; p->up_interval = ival; p->up_flags = flags; p->up_serialise = true; SIMPLEQ_INIT(&p->up_queue); err = dev->ud_bus->ub_methods->ubm_open(p); if (err) { DPRINTF("endpoint=0x%x failed, error=%d", ep->ue_edesc->bEndpointAddress, err, 0, 0); kmem_intr_free(p, dev->ud_bus->ub_pipesize); return err; } KASSERT(p->up_methods->upm_start || p->up_serialise == false); usb_init_task(&p->up_async_task, usbd_clear_endpoint_stall_task, p, USB_TASKQ_MPSAFE); DPRINTFN(1, "pipe=%p", p, 0, 0, 0); *pipe = p; return USBD_NORMAL_COMPLETION; }
usbd_status usbd_reset_port(struct usbd_device *dev, int port, usb_port_status_t *ps) { USBHIST_FUNC(); USBHIST_CALLED(usbdebug); 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, "port %d reset done, error=%d", port, err, 0, 0); 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("get status failed %d", err, 0, 0, 0); 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("clear port feature failed %d", err, 0, 0, 0); #endif /* Wait for the device to recover from reset. */ usbd_delay_ms(dev, USB_PORT_RESET_RECOVERY); return err; }
usbd_status usbd_get_protocol(struct usbd_interface *iface, uint8_t *report) { usb_interface_descriptor_t *id = usbd_get_interface_descriptor(iface); struct usbd_device *dev; usb_device_request_t req; USBHIST_FUNC(); USBHIST_CALLED(usbdebug); DPRINTFN(4, "iface=%p, endpt=%d", iface, id->bInterfaceNumber, 0, 0); if (id == NULL) return USBD_IOERROR; usbd_interface2device_handle(iface, &dev); req.bmRequestType = UT_READ_CLASS_INTERFACE; req.bRequest = UR_GET_PROTOCOL; USETW(req.wValue, 0); USETW(req.wIndex, id->bInterfaceNumber); USETW(req.wLength, 1); return usbd_do_request(dev, &req, report); }
usbd_status usbd_set_idle(struct usbd_interface *iface, int duration, int id) { usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface); struct usbd_device *dev; usb_device_request_t req; USBHIST_FUNC(); USBHIST_CALLED(usbdebug); DPRINTFN(4, "duration %d id %d", duration, id, 0, 0); if (ifd == NULL) return USBD_IOERROR; usbd_interface2device_handle(iface, &dev); req.bmRequestType = UT_WRITE_CLASS_INTERFACE; req.bRequest = UR_SET_IDLE; USETW2(req.wValue, duration, id); USETW(req.wIndex, ifd->bInterfaceNumber); USETW(req.wLength, 0); return usbd_do_request(dev, &req, 0); }
usbd_status usbd_get_report(struct usbd_interface *iface, int type, int id, void *data, int len) { usb_interface_descriptor_t *ifd = usbd_get_interface_descriptor(iface); struct usbd_device *dev; usb_device_request_t req; USBHIST_FUNC(); USBHIST_CALLED(usbdebug); DPRINTFN(4, "len=%d", len, 0, 0, 0); if (ifd == NULL) return USBD_IOERROR; usbd_interface2device_handle(iface, &dev); req.bmRequestType = UT_READ_CLASS_INTERFACE; req.bRequest = UR_GET_REPORT; USETW2(req.wValue, type, id); USETW(req.wIndex, ifd->bInterfaceNumber); USETW(req.wLength, len); return usbd_do_request(dev, &req, data); }
usbd_status usbd_bulk_transfer(struct usbd_xfer *xfer, struct usbd_pipe *pipe, uint16_t flags, uint32_t timeout, void *buf, uint32_t *size) { usbd_status err; USBHIST_FUNC(); USBHIST_CALLED(usbdebug); usbd_setup_xfer(xfer, 0, buf, *size, flags, timeout, NULL); DPRINTFN(1, "start transfer %d bytes", *size, 0, 0, 0); err = usbd_sync_transfer_sig(xfer); usbd_get_xfer_status(xfer, NULL, NULL, size, NULL); DPRINTFN(1, "transferred %d", *size, 0, 0, 0); if (err) { usbd_clear_endpoint_stall(pipe); } USBHIST_LOG(usbdebug, "<- done xfer %p err %d", xfer, err, 0, 0); return err; }
usbd_status usbd_set_config_no(struct usbd_device *dev, int no, int msg) { USBHIST_FUNC(); USBHIST_CALLED(usbdebug); usb_config_descriptor_t cd; usbd_status err; int index; if (no == USB_UNCONFIG_NO) return usbd_set_config_index(dev, USB_UNCONFIG_INDEX, msg); DPRINTFN(5, "%d", no, 0, 0, 0); /* Figure out what config index to use. */ for (index = 0; index < dev->ud_ddesc.bNumConfigurations; index++) { err = usbd_get_config_desc(dev, index, &cd); if (err) return err; if (cd.bConfigurationValue == no) return usbd_set_config_index(dev, index, msg); } return USBD_INVAL; }
/* * Called from process context when we discover that a port has * been disconnected. */ int usb_disconnect_port(struct usbd_port *up, device_t parent, int flags) { USBHIST_FUNC(); USBHIST_CALLED(usbdebug); struct usbd_device *dev = up->up_dev; device_t subdev; char subdevname[16]; const char *hubname = device_xname(parent); int i, rc; DPRINTFN(3, "up=%p dev=%p port=%d", up, dev, up->up_portno, 0); if (dev == NULL) { return 0; } if (dev->ud_subdevlen > 0) { DPRINTFN(3, "disconnect subdevs", 0, 0, 0, 0); for (i = 0; i < dev->ud_subdevlen; i++) { if ((subdev = dev->ud_subdevs[i]) == NULL) continue; strlcpy(subdevname, device_xname(subdev), sizeof(subdevname)); if ((rc = config_detach(subdev, flags)) != 0) return rc; printf("%s: at %s", subdevname, hubname); if (up->up_portno != 0) printf(" port %d", up->up_portno); printf(" (addr %d) disconnected\n", dev->ud_addr); } KASSERT(!dev->ud_nifaces_claimed); } usbd_add_dev_event(USB_EVENT_DEVICE_DETACH, dev); dev->ud_bus->ub_devices[dev->ud_addr] = NULL; up->up_dev = NULL; usb_free_device(dev); return 0; }