usbd_status usbd_get_string_desc(struct usbd_device *dev, int sindex, int langid, usb_string_descriptor_t *sdesc, int *sizep) { 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); /* size and descriptor type 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) { DPRINTFN(-1, ("usbd_get_string_desc: expected %d, got %d\n", sdesc->bLength, actlen)); } *sizep = actlen; return (USBD_NORMAL_COMPLETION); }
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; }
usbd_status usbd_get_string_desc(usbd_device_handle dev, juint8_t sindex, jint16_t langid, usb_string_descriptor_t *sdesc, juint32_t *sizep) { usb_device_request_t req; usbd_status err; juint32_t 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, (void *)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, (void *)sdesc, USBD_SHORT_XFER_OK, &actlen, USBD_DEFAULT_TIMEOUT); if (err) return (err); if (actlen != sdesc->bLength) { DBG_E(DHOST_SUBR, ("usbd_get_string_desc: expected %d, " "got %ld\n", sdesc->bLength, actlen)); } *sizep = actlen; return (USBD_NORMAL_COMPLETION); }
/*------------------------------------------------------------------------* * usbd_do_request_proc - factored out code * * This function is factored out code. It does basically the same like * usbd_do_request_flags, except it will check the status of the * passed process argument before doing the USB request. If the * process is draining the USB_ERR_IOERROR code will be returned. It * is assumed that the mutex associated with the process is locked * when calling this function. *------------------------------------------------------------------------*/ usb_error_t usbd_do_request_proc(struct usb_device *udev, struct usb_process *pproc, struct usb_device_request *req, void *data, uint16_t flags, uint16_t *actlen, usb_timeout_t timeout) { usb_error_t err; uint16_t len; /* get request data length */ len = UGETW(req->wLength); /* check if the device is being detached */ if (usb_proc_is_gone(pproc)) { err = USB_ERR_IOERROR; goto done; } /* forward the USB request */ err = usbd_do_request_flags(udev, pproc->up_mtx, req, data, flags, actlen, timeout); done: /* on failure we zero the data */ /* on short packet we zero the unused data */ if ((len != 0) && (req->bmRequestType & UE_DIR_IN)) { if (err) memset(data, 0, len); else if (actlen && *actlen != len) memset(((uint8_t *)data) + *actlen, 0, len - *actlen); } return (err); }
int uhidev_get_report(struct uhidev_softc *sc, int type, int id, void *data, int len) { usb_device_request_t req; char *buf = data; usbd_status err; int actlen; if (id > 0) { len++; buf = malloc(len, M_TEMP, M_WAITOK|M_ZERO); } req.bmRequestType = UT_READ_CLASS_INTERFACE; req.bRequest = UR_GET_REPORT; USETW2(req.wValue, type, id); USETW(req.wIndex, sc->sc_ifaceno); USETW(req.wLength, len); err = usbd_do_request_flags(sc->sc_udev, &req, buf, 0, &actlen, USBD_DEFAULT_TIMEOUT); if (err != USBD_NORMAL_COMPLETION && err != USBD_SHORT_XFER) actlen = -1; /* Skip the reportID. */ if (id > 0) { memcpy(data, buf + 1, len - 1); free(buf, M_TEMP, len); } return (actlen); }
static int rtwn_do_request(struct rtwn_softc *sc, struct usb_device_request *req, void *data) { struct rtwn_usb_softc *uc = RTWN_USB_SOFTC(sc); usb_error_t err; int ntries = 10; RTWN_ASSERT_LOCKED(sc); while (ntries--) { err = usbd_do_request_flags(uc->uc_udev, &sc->sc_mtx, req, data, 0, NULL, 250 /* ms */); if (err == USB_ERR_NORMAL_COMPLETION) return (0); RTWN_DPRINTF(sc, RTWN_DEBUG_USB, "%s: control request failed, %s (retries left: %d)\n", __func__, usbd_errstr(err), ntries); if (err == USB_ERR_NOT_CONFIGURED) return (ENXIO); usb_pause_mtx(&sc->sc_mtx, hz / 100); } return (EIO); }
int ugen_do_request(struct usb_fifo *f, struct usb_ctl_request *ur) { int error; uint16_t len; uint16_t actlen; if (ugen_check_request(f->udev, &ur->ucr_request)) { return (EPERM); } len = UGETW(ur->ucr_request.wLength); /* check if "ucr_data" is valid */ if (len != 0) { if (ur->ucr_data == NULL) { return (EFAULT); } } /* do the USB request */ error = usbd_do_request_flags (f->udev, NULL, &ur->ucr_request, ur->ucr_data, (ur->ucr_flags & USB_SHORT_XFER_OK) | USB_USER_DATA_PTR, &actlen, USB_DEFAULT_TIMEOUT); ur->ucr_actlen = actlen; if (error) { error = EIO; } return (error); }
/* * Probe the interface type by querying the device. The elements * of an array indicates the capabilities of a particular interface. * Returns a bit mask with the interface capabilities. */ static int uhso_probe_iface_auto(struct usb_device *udev, int index) { struct usb_device_request req; usb_error_t uerr; uint16_t actlen = 0; char port; char buf[17] = {0}; req.bmRequestType = UT_READ_VENDOR_DEVICE; req.bRequest = 0x86; USETW(req.wValue, 0); USETW(req.wIndex, 0); USETW(req.wLength, 17); uerr = usbd_do_request_flags(udev, NULL, &req, buf, 0, &actlen, USB_MS_HZ); if (uerr != 0) { printf("%s: usbd_do_request_flags failed, %s\n", __func__, usbd_errstr(uerr)); return (0); } UHSO_DPRINTF(1, "actlen=%d\n", actlen); UHSO_HEXDUMP(buf, 17); if (index < 0 || index > 16) { UHSO_DPRINTF(0, "Index %d out of range\n", index); return (0); } UHSO_DPRINTF(1, "index=%d, type=%x[%s]\n", index, buf[index], uhso_port_type[(int)uhso_port_map[(int)buf[index]]]); if (buf[index] >= uhso_port_map_max) port = 0; else port = uhso_port_map[(int)buf[index]]; switch (port) { case UHSO_PORT_TYPE_NETWORK: return (UHSO_IFACE_SPEC(UHSO_IF_NET | UHSO_IF_MUX, UHSO_PORT_SERIAL | UHSO_PORT_NETWORK, port)); case UHSO_PORT_TYPE_DIAG: case UHSO_PORT_TYPE_DIAG2: case UHSO_PORT_TYPE_CTL: case UHSO_PORT_TYPE_APP: case UHSO_PORT_TYPE_APP2: case UHSO_PORT_TYPE_MODEM: return (UHSO_IFACE_SPEC(UHSO_IF_BULK, UHSO_PORT_SERIAL, port)); case UHSO_PORT_TYPE_MSD: return (0); case UHSO_PORT_TYPE_UNKNOWN: default: return (0); } return (0); }
static void uslsa_get_status(void *vsc, int portno, u_char *lsr, u_char *msr) { struct uslsa_softc *sc; usb_device_request_t req; usbd_status err; int actlen; uint16_t flowreg; sc = vsc; DPRINTF(("uslsa_get_status:\n")); req.bmRequestType = USLSA_REQUEST_GET; req.bRequest = USLSA_REQ_GET_FLOW; USETW(req.wValue, 0); USETW(req.wIndex, 0); USETW(req.wLength, sizeof(flowreg)); err = usbd_do_request_flags(sc->sc_udev, &req, &flowreg, USBD_SHORT_XFER_OK, &actlen, USBD_DEFAULT_TIMEOUT); if (err) printf("%s: uslsa_get_status: %s\n", USBDEVNAME(sc->sc_dev), usbd_errstr(err)); DPRINTF(("uslsa_get_status: flowreg=0x%x\n", flowreg)); sc->sc_msr = (u_char)(USLSA_FLOW_MSR_MASK & flowreg); if (lsr != NULL) *lsr = sc->sc_lsr; if (msr != NULL) *msr = sc->sc_msr; }
void uvisor_close(void *addr, int portno) { struct uvisor_softc *sc = addr; usb_device_request_t req; struct uvisor_connection_info coninfo; /* XXX ? */ int actlen; if (sc->sc_dying) return; req.bmRequestType = UT_READ_VENDOR_ENDPOINT; /* XXX read? */ req.bRequest = UVISOR_CLOSE_NOTIFICATION; USETW(req.wValue, 0); USETW(req.wIndex, 0); USETW(req.wLength, UVISOR_CONNECTION_INFO_SIZE); (void)usbd_do_request_flags(sc->sc_udev, &req, &coninfo, USBD_SHORT_XFER_OK, &actlen); }
static void usie_autoinst(void *arg, struct usb_device *udev, struct usb_attach_arg *uaa) { struct usb_interface *iface; struct usb_interface_descriptor *id; struct usb_device_request req; int err; if (uaa->dev_state != UAA_DEV_READY) return; iface = usbd_get_iface(udev, 0); if (iface == NULL) return; id = iface->idesc; if (id == NULL || id->bInterfaceClass != UICLASS_MASS) return; if (usbd_lookup_id_by_uaa(usie_devs, sizeof(usie_devs), uaa) != 0) return; /* no device match */ if (bootverbose) { DPRINTF("Ejecting %s %s\n", usb_get_manufacturer(udev), usb_get_product(udev)); } req.bmRequestType = UT_VENDOR; req.bRequest = UR_SET_INTERFACE; USETW(req.wValue, UF_DEVICE_REMOTE_WAKEUP); USETW(req.wIndex, UHF_PORT_CONNECTION); USETW(req.wLength, 0); /* at this moment there is no mutex */ err = usbd_do_request_flags(udev, NULL, &req, NULL, 0, NULL, 250 /* ms */ ); /* success, mark the udev as disappearing */ if (err == 0) uaa->dev_state = UAA_DEV_EJECTING; }
/* * Get the first 8 bytes of the device descriptor. * Do as Windows does: try to read 64 bytes -- there are devices which * recognize the initial descriptor fetch (before the control endpoint's * MaxPacketSize is known by the host) by exactly this length. */ usbd_status usbd_get_initial_ddesc(struct usbd_device *dev, usb_device_descriptor_t *desc) { USBHIST_FUNC(); USBHIST_CALLED(usbdebug); usb_device_request_t req; char buf[64]; int res, actlen; DPRINTFN(5, "dev %p", dev, 0, 0, 0); req.bmRequestType = UT_READ_DEVICE; req.bRequest = UR_GET_DESCRIPTOR; USETW2(req.wValue, UDESC_DEVICE, 0); USETW(req.wIndex, 0); USETW(req.wLength, 64); res = usbd_do_request_flags(dev, &req, buf, USBD_SHORT_XFER_OK, &actlen, USBD_DEFAULT_TIMEOUT); if (res) return res; if (actlen < 8) return USBD_SHORT_XFER; memcpy(desc, buf, 8); return USBD_NORMAL_COMPLETION; }
int urioioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) { struct urio_softc * sc; int unit = URIOUNIT(dev); struct urio_command *rcmd; int requesttype, len; struct iovec iov; struct uio uio; usb_device_request_t req; usbd_status err; u_int32_t req_actlen = 0; void *ptr = NULL; int error = 0; sc = urio_cd.cd_devs[unit]; if (usbd_is_dying(sc->sc_udev)) return (EIO); rcmd = (struct urio_command *)addr; switch (cmd) { case URIO_RECV_COMMAND: requesttype = rcmd->requesttype | UT_READ_VENDOR_DEVICE; break; case URIO_SEND_COMMAND: requesttype = rcmd->requesttype | UT_WRITE_VENDOR_DEVICE; break; default: return (EINVAL); break; } if (!(flag & FWRITE)) return (EPERM); len = rcmd->length; DPRINTFN(1,("urio_ioctl: cmd=0x%08lx reqtype=0x%0x req=0x%0x " "value=0x%0x index=0x%0x len=0x%0x\n", cmd, requesttype, rcmd->request, rcmd->value, rcmd->index, len)); /* Send rio control message */ req.bmRequestType = requesttype; req.bRequest = rcmd->request; USETW(req.wValue, rcmd->value); USETW(req.wIndex, rcmd->index); USETW(req.wLength, len); if (len < 0 || len > 32767) return (EINVAL); if (len != 0) { iov.iov_base = (caddr_t)rcmd->buffer; iov.iov_len = len; uio.uio_iov = &iov; uio.uio_iovcnt = 1; uio.uio_resid = len; uio.uio_offset = 0; uio.uio_segflg = UIO_USERSPACE; uio.uio_rw = req.bmRequestType & UT_READ ? UIO_READ : UIO_WRITE; uio.uio_procp = p; ptr = malloc(len, M_TEMP, M_WAITOK); if (uio.uio_rw == UIO_WRITE) { error = uiomove(ptr, len, &uio); if (error) goto ret; } } sc->sc_refcnt++; err = usbd_do_request_flags(sc->sc_udev, &req, ptr, 0, &req_actlen, USBD_DEFAULT_TIMEOUT); if (--sc->sc_refcnt < 0) usb_detach_wakeup(&sc->sc_dev); if (err) { error = EIO; } else { if (req_actlen != 0 && uio.uio_rw == UIO_READ) error = uiomove(ptr, req_actlen, &uio); } ret: if (ptr != NULL) free(ptr, M_TEMP); return (error); }
static void usie_if_status_cb(void *arg, int pending) { struct usie_softc *sc = arg; struct ifnet *ifp = sc->sc_ifp; struct usb_device_request req; struct usie_hip *hip; struct usie_lsi *lsi; uint16_t actlen; uint8_t ntries; uint8_t pad; mtx_lock(&sc->sc_mtx); req.bmRequestType = UT_READ_CLASS_INTERFACE; req.bRequest = UCDC_GET_ENCAPSULATED_RESPONSE; USETW(req.wValue, 0); USETW(req.wIndex, sc->sc_if_ifnum); USETW(req.wLength, sizeof(sc->sc_status_temp)); for (ntries = 0; ntries != 10; ntries++) { int err; err = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx, &req, sc->sc_status_temp, USB_SHORT_XFER_OK, &actlen, USB_DEFAULT_TIMEOUT); if (err == 0) break; DPRINTF("Control request failed: %s %d/10\n", usbd_errstr(err), ntries); usb_pause_mtx(&sc->sc_mtx, USB_MS_TO_TICKS(10)); } if (ntries == 10) { mtx_unlock(&sc->sc_mtx); DPRINTF("Timeout\n"); return; } hip = (struct usie_hip *)sc->sc_status_temp; pad = (hip->id & USIE_HIP_PAD) ? 1 : 0; DPRINTF("hip.id=%x hip.len=%d actlen=%u pad=%d\n", hip->id, be16toh(hip->len), actlen, pad); switch (hip->id & USIE_HIP_MASK) { case USIE_HIP_SYNC2H: usie_if_cmd(sc, USIE_HIP_SYNC2M); break; case USIE_HIP_RESTR: usb_callout_stop(&sc->sc_if_sync_ch); break; case USIE_HIP_UMTS: lsi = (struct usie_lsi *)( sc->sc_status_temp + sizeof(struct usie_hip) + pad); DPRINTF("lsi.proto=%x lsi.len=%d\n", lsi->proto, be16toh(lsi->len)); if (lsi->proto != USIE_LSI_UMTS) break; if (lsi->area == USIE_LSI_AREA_NO || lsi->area == USIE_LSI_AREA_NODATA) { device_printf(sc->sc_dev, "no service available\n"); break; } if (lsi->state == USIE_LSI_STATE_IDLE) { DPRINTF("lsi.state=%x\n", lsi->state); break; } DPRINTF("ctx=%x\n", hip->param); sc->sc_txd.hip.param = hip->param; sc->sc_net.addr_len = lsi->pdp_addr_len; memcpy(&sc->sc_net.dns1_addr, &lsi->dns1_addr, 16); memcpy(&sc->sc_net.dns2_addr, &lsi->dns2_addr, 16); memcpy(sc->sc_net.pdp_addr, lsi->pdp_addr, 16); memcpy(sc->sc_net.gw_addr, lsi->gw_addr, 16); ifp->if_flags |= IFF_UP; ifp->if_drv_flags |= IFF_DRV_RUNNING; device_printf(sc->sc_dev, "IP Addr=%d.%d.%d.%d\n", *lsi->pdp_addr, *(lsi->pdp_addr + 1), *(lsi->pdp_addr + 2), *(lsi->pdp_addr + 3)); device_printf(sc->sc_dev, "Gateway Addr=%d.%d.%d.%d\n", *lsi->gw_addr, *(lsi->gw_addr + 1), *(lsi->gw_addr + 2), *(lsi->gw_addr + 3)); device_printf(sc->sc_dev, "Prim NS Addr=%d.%d.%d.%d\n", *lsi->dns1_addr, *(lsi->dns1_addr + 1), *(lsi->dns1_addr + 2), *(lsi->dns1_addr + 3)); device_printf(sc->sc_dev, "Scnd NS Addr=%d.%d.%d.%d\n", *lsi->dns2_addr, *(lsi->dns2_addr + 1), *(lsi->dns2_addr + 2), *(lsi->dns2_addr + 3)); usie_cns_req(sc, USIE_CNS_ID_RSSI, USIE_CNS_OB_RSSI); break; case USIE_HIP_RCGI: /* ignore, workaround for sloppy windows */ break; default: DPRINTF("undefined msgid: %x\n", hip->id); break; } mtx_unlock(&sc->sc_mtx); }
/*------------------------------------------------------------------------* * cdce_ncm_init * * Return values: * 0: Success * Else: Failure *------------------------------------------------------------------------*/ static uint8_t cdce_ncm_init(struct cdce_softc *sc) { struct usb_ncm_parameters temp; struct usb_device_request req; struct usb_ncm_func_descriptor *ufd; uint8_t value[8]; int err; ufd = usbd_find_descriptor(sc->sc_ue.ue_udev, NULL, sc->sc_ifaces_index[1], UDESC_CS_INTERFACE, 0 - 1, UCDC_NCM_FUNC_DESC_SUBTYPE, 0 - 1); /* verify length of NCM functional descriptor */ if (ufd != NULL) { if (ufd->bLength < sizeof(*ufd)) ufd = NULL; else DPRINTFN(1, "Found NCM functional descriptor.\n"); } req.bmRequestType = UT_READ_CLASS_INTERFACE; req.bRequest = UCDC_NCM_GET_NTB_PARAMETERS; USETW(req.wValue, 0); req.wIndex[0] = sc->sc_ifaces_index[1]; req.wIndex[1] = 0; USETW(req.wLength, sizeof(temp)); err = usbd_do_request_flags(sc->sc_ue.ue_udev, NULL, &req, &temp, 0, NULL, 1000 /* ms */); if (err) return (1); /* Read correct set of parameters according to device mode */ if (usbd_get_mode(sc->sc_ue.ue_udev) == USB_MODE_HOST) { sc->sc_ncm.rx_max = UGETDW(temp.dwNtbInMaxSize); sc->sc_ncm.tx_max = UGETDW(temp.dwNtbOutMaxSize); sc->sc_ncm.tx_remainder = UGETW(temp.wNdpOutPayloadRemainder); sc->sc_ncm.tx_modulus = UGETW(temp.wNdpOutDivisor); sc->sc_ncm.tx_struct_align = UGETW(temp.wNdpOutAlignment); sc->sc_ncm.tx_nframe = UGETW(temp.wNtbOutMaxDatagrams); } else { sc->sc_ncm.rx_max = UGETDW(temp.dwNtbOutMaxSize); sc->sc_ncm.tx_max = UGETDW(temp.dwNtbInMaxSize); sc->sc_ncm.tx_remainder = UGETW(temp.wNdpInPayloadRemainder); sc->sc_ncm.tx_modulus = UGETW(temp.wNdpInDivisor); sc->sc_ncm.tx_struct_align = UGETW(temp.wNdpInAlignment); sc->sc_ncm.tx_nframe = UGETW(temp.wNtbOutMaxDatagrams); } /* Verify maximum receive length */ if ((sc->sc_ncm.rx_max < 32) || (sc->sc_ncm.rx_max > CDCE_NCM_RX_MAXLEN)) { DPRINTFN(1, "Using default maximum receive length\n"); sc->sc_ncm.rx_max = CDCE_NCM_RX_MAXLEN; } /* Verify maximum transmit length */ if ((sc->sc_ncm.tx_max < 32) || (sc->sc_ncm.tx_max > CDCE_NCM_TX_MAXLEN)) { DPRINTFN(1, "Using default maximum transmit length\n"); sc->sc_ncm.tx_max = CDCE_NCM_TX_MAXLEN; } /* * Verify that the structure alignment is: * - power of two * - not greater than the maximum transmit length * - not less than four bytes */ if ((sc->sc_ncm.tx_struct_align < 4) || (sc->sc_ncm.tx_struct_align != ((-sc->sc_ncm.tx_struct_align) & sc->sc_ncm.tx_struct_align)) || (sc->sc_ncm.tx_struct_align >= sc->sc_ncm.tx_max)) { DPRINTFN(1, "Using default other alignment: 4 bytes\n"); sc->sc_ncm.tx_struct_align = 4; } /* * Verify that the payload alignment is: * - power of two * - not greater than the maximum transmit length * - not less than four bytes */ if ((sc->sc_ncm.tx_modulus < 4) || (sc->sc_ncm.tx_modulus != ((-sc->sc_ncm.tx_modulus) & sc->sc_ncm.tx_modulus)) || (sc->sc_ncm.tx_modulus >= sc->sc_ncm.tx_max)) { DPRINTFN(1, "Using default transmit modulus: 4 bytes\n"); sc->sc_ncm.tx_modulus = 4; } /* Verify that the payload remainder */ if ((sc->sc_ncm.tx_remainder >= sc->sc_ncm.tx_modulus)) { DPRINTFN(1, "Using default transmit remainder: 0 bytes\n"); sc->sc_ncm.tx_remainder = 0; } /* * Offset the TX remainder so that IP packet payload starts at * the tx_modulus. This is not too clear in the specification. */ sc->sc_ncm.tx_remainder = (sc->sc_ncm.tx_remainder - ETHER_HDR_LEN) & (sc->sc_ncm.tx_modulus - 1); /* Verify max datagrams */ if (sc->sc_ncm.tx_nframe == 0 || sc->sc_ncm.tx_nframe > (CDCE_NCM_SUBFRAMES_MAX - 1)) { DPRINTFN(1, "Using default max " "subframes: %u units\n", CDCE_NCM_SUBFRAMES_MAX - 1); /* need to reserve one entry for zero padding */ sc->sc_ncm.tx_nframe = (CDCE_NCM_SUBFRAMES_MAX - 1); } /* Additional configuration, will fail in device side mode, which is OK. */ req.bmRequestType = UT_WRITE_CLASS_INTERFACE; req.bRequest = UCDC_NCM_SET_NTB_INPUT_SIZE; USETW(req.wValue, 0); req.wIndex[0] = sc->sc_ifaces_index[1]; req.wIndex[1] = 0; if (ufd != NULL && (ufd->bmNetworkCapabilities & UCDC_NCM_CAP_MAX_DGRAM)) { USETW(req.wLength, 8); USETDW(value, sc->sc_ncm.rx_max); USETW(value + 4, (CDCE_NCM_SUBFRAMES_MAX - 1)); USETW(value + 6, 0); } else { USETW(req.wLength, 4); USETDW(value, sc->sc_ncm.rx_max); } err = usbd_do_request_flags(sc->sc_ue.ue_udev, NULL, &req, &value, 0, NULL, 1000 /* ms */); if (err) { DPRINTFN(1, "Setting input size " "to %u failed.\n", sc->sc_ncm.rx_max); } req.bmRequestType = UT_WRITE_CLASS_INTERFACE; req.bRequest = UCDC_NCM_SET_CRC_MODE; USETW(req.wValue, 0); /* no CRC */ req.wIndex[0] = sc->sc_ifaces_index[1]; req.wIndex[1] = 0; USETW(req.wLength, 0); err = usbd_do_request_flags(sc->sc_ue.ue_udev, NULL, &req, NULL, 0, NULL, 1000 /* ms */); if (err) { DPRINTFN(1, "Setting CRC mode to off failed.\n"); } req.bmRequestType = UT_WRITE_CLASS_INTERFACE; req.bRequest = UCDC_NCM_SET_NTB_FORMAT; USETW(req.wValue, 0); /* NTB-16 */ req.wIndex[0] = sc->sc_ifaces_index[1]; req.wIndex[1] = 0; USETW(req.wLength, 0); err = usbd_do_request_flags(sc->sc_ue.ue_udev, NULL, &req, NULL, 0, NULL, 1000 /* ms */); if (err) { DPRINTFN(1, "Setting NTB format to 16-bit failed.\n"); } return (0); /* success */ }
int urioioctl(struct dev_ioctl_args *ap) { cdev_t dev = ap->a_head.a_dev; #if (USBDI >= 1) struct urio_softc * sc; #endif int unit = URIOUNIT(dev); struct RioCommand *rio_cmd; int requesttype, len; struct iovec iov; struct uio uio; usb_device_request_t req; int req_flags = 0, req_actlen = 0; void *ptr = NULL; int error = 0; usbd_status r; sc = devclass_get_softc(urio_devclass, unit); switch (ap->a_cmd) { case RIO_RECV_COMMAND: if (!(ap->a_fflag & FWRITE)) return EPERM; rio_cmd = (struct RioCommand *)ap->a_data; if (rio_cmd == NULL) return EINVAL; len = rio_cmd->length; requesttype = rio_cmd->requesttype | UT_READ_VENDOR_DEVICE; DPRINTFN(1,("sending command:reqtype=%0x req=%0x value=%0x index=%0x len=%0x\n", requesttype, rio_cmd->request, rio_cmd->value, rio_cmd->index, len)); break; case RIO_SEND_COMMAND: if (!(ap->a_fflag & FWRITE)) return EPERM; rio_cmd = (struct RioCommand *)ap->a_data; if (rio_cmd == NULL) return EINVAL; len = rio_cmd->length; requesttype = rio_cmd->requesttype | UT_WRITE_VENDOR_DEVICE; DPRINTFN(1,("sending command:reqtype=%0x req=%0x value=%0x index=%0x len=%0x\n", requesttype, rio_cmd->request, rio_cmd->value, rio_cmd->index, len)); break; default: return EINVAL; break; } /* Send rio control message */ req.bmRequestType = requesttype; req.bRequest = rio_cmd->request; USETW(req.wValue, rio_cmd->value); USETW(req.wIndex, rio_cmd->index); USETW(req.wLength, len); if (len < 0 || len > 32767) return EINVAL; if (len != 0) { iov.iov_base = (caddr_t)rio_cmd->buffer; iov.iov_len = len; uio.uio_iov = &iov; uio.uio_iovcnt = 1; uio.uio_resid = len; uio.uio_offset = 0; uio.uio_segflg = UIO_USERSPACE; uio.uio_rw = req.bmRequestType & UT_READ ? UIO_READ : UIO_WRITE; uio.uio_td = curthread; ptr = kmalloc(len, M_TEMP, M_WAITOK); if (uio.uio_rw == UIO_WRITE) { error = uiomove(ptr, len, &uio); if (error) goto ret; } } r = usbd_do_request_flags(sc->sc_udev, &req, ptr, req_flags, &req_actlen, USBD_DEFAULT_TIMEOUT); if (r == USBD_NORMAL_COMPLETION) { error = 0; if (len != 0) { if (uio.uio_rw == UIO_READ) { error = uiomove(ptr, len, &uio); } } } else { error = EIO; } ret: if (ptr) kfree(ptr, M_TEMP); return error; }
void uhidev_attach(device_t parent, device_t self, void *aux) { struct uhidev_softc *sc = device_private(self); struct usbif_attach_arg *uiaa = aux; struct usbd_interface *iface = uiaa->uiaa_iface; usb_interface_descriptor_t *id; usb_endpoint_descriptor_t *ed; struct uhidev_attach_arg uha; device_t dev; struct uhidev *csc; int maxinpktsize, size, nrepid, repid, repsz; int *repsizes; int i; void *desc; const void *descptr; usbd_status err; char *devinfop; int locs[UHIDBUSCF_NLOCS]; sc->sc_dev = self; sc->sc_udev = uiaa->uiaa_device; sc->sc_iface = iface; aprint_naive("\n"); aprint_normal("\n"); mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_SOFTUSB); id = usbd_get_interface_descriptor(iface); devinfop = usbd_devinfo_alloc(uiaa->uiaa_device, 0); aprint_normal_dev(self, "%s, iclass %d/%d\n", devinfop, id->bInterfaceClass, id->bInterfaceSubClass); usbd_devinfo_free(devinfop); if (!pmf_device_register(self, NULL, NULL)) aprint_error_dev(self, "couldn't establish power handler\n"); (void)usbd_set_idle(iface, 0, 0); #if 0 if ((usbd_get_quirks(sc->sc_udev)->uq_flags & UQ_NO_SET_PROTO) == 0 && id->bInterfaceSubClass != UISUBCLASS_BOOT) (void)usbd_set_protocol(iface, 1); #endif maxinpktsize = 0; sc->sc_iep_addr = sc->sc_oep_addr = -1; for (i = 0; i < id->bNumEndpoints; i++) { ed = usbd_interface2endpoint_descriptor(iface, i); if (ed == NULL) { aprint_error_dev(self, "could not read endpoint descriptor\n"); sc->sc_dying = 1; return; } DPRINTFN(10,("uhidev_attach: bLength=%d bDescriptorType=%d " "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d" " bInterval=%d\n", ed->bLength, ed->bDescriptorType, ed->bEndpointAddress & UE_ADDR, UE_GET_DIR(ed->bEndpointAddress)==UE_DIR_IN? "in" : "out", ed->bmAttributes & UE_XFERTYPE, UGETW(ed->wMaxPacketSize), ed->bInterval)); if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) { maxinpktsize = UGETW(ed->wMaxPacketSize); sc->sc_iep_addr = ed->bEndpointAddress; } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && (ed->bmAttributes & UE_XFERTYPE) == UE_INTERRUPT) { sc->sc_oep_addr = ed->bEndpointAddress; } else { aprint_verbose_dev(self, "endpoint %d: ignored\n", i); } } /* * Check that we found an input interrupt endpoint. The output interrupt * endpoint is optional */ if (sc->sc_iep_addr == -1) { aprint_error_dev(self, "no input interrupt endpoint\n"); sc->sc_dying = 1; return; } /* XXX need to extend this */ descptr = NULL; if (uiaa->uiaa_vendor == USB_VENDOR_WACOM) { static uByte reportbuf[] = {2, 2, 2}; /* The report descriptor for the Wacom Graphire is broken. */ switch (uiaa->uiaa_product) { case USB_PRODUCT_WACOM_GRAPHIRE: case USB_PRODUCT_WACOM_GRAPHIRE2: case USB_PRODUCT_WACOM_GRAPHIRE3_4X5: case USB_PRODUCT_WACOM_GRAPHIRE3_6X8: case USB_PRODUCT_WACOM_GRAPHIRE4_4X5: /* The 6x8 too? */ /* * The Graphire3 needs 0x0202 to be written to * feature report ID 2 before it'll start * returning digitizer data. */ usbd_set_report(uiaa->uiaa_iface, UHID_FEATURE_REPORT, 2, &reportbuf, sizeof(reportbuf)); size = sizeof(uhid_graphire3_4x5_report_descr); descptr = uhid_graphire3_4x5_report_descr; break; default: /* Keep descriptor */ break; } } if (USBIF_IS_XINPUT(uiaa)) { size = sizeof(uhid_xinput_report_descr); descptr = uhid_xinput_report_descr; } if (USBIF_IS_X1INPUT(uiaa)) { sc->sc_flags |= UHIDEV_F_XB1; size = sizeof(uhid_x1input_report_descr); descptr = uhid_x1input_report_descr; } if (descptr) { desc = kmem_alloc(size, KM_SLEEP); if (desc == NULL) err = USBD_NOMEM; else { err = USBD_NORMAL_COMPLETION; memcpy(desc, descptr, size); } } else { desc = NULL; err = usbd_read_report_desc(uiaa->uiaa_iface, &desc, &size); } if (err) { aprint_error_dev(self, "no report descriptor\n"); sc->sc_dying = 1; return; } if (uiaa->uiaa_vendor == USB_VENDOR_HOSIDEN && uiaa->uiaa_product == USB_PRODUCT_HOSIDEN_PPP) { static uByte reportbuf[] = { 1 }; /* * This device was sold by Konami with its ParaParaParadise * game for PlayStation2. It needs to be "turned on" * before it will send any reports. */ usbd_set_report(uiaa->uiaa_iface, UHID_FEATURE_REPORT, 0, &reportbuf, sizeof(reportbuf)); } if (uiaa->uiaa_vendor == USB_VENDOR_LOGITECH && uiaa->uiaa_product == USB_PRODUCT_LOGITECH_CBT44 && size == 0xb1) { uint8_t *data = desc; /* * This device has a odd USAGE_MINIMUM value that would * cause the multimedia keys to have their usage number * shifted up one usage. Adjust so the usages are sane. */ if (data[0x56] == 0x19 && data[0x57] == 0x01 && data[0x58] == 0x2a && data[0x59] == 0x8c) data[0x57] = 0x00; } /* * Enable the Six Axis and DualShock 3 controllers. * See http://ps3.jim.sh/sixaxis/usb/ */ if (uiaa->uiaa_vendor == USB_VENDOR_SONY && uiaa->uiaa_product == USB_PRODUCT_SONY_PS3CONTROLLER) { usb_device_request_t req; char data[17]; int actlen; req.bmRequestType = UT_READ_CLASS_INTERFACE; req.bRequest = 1; USETW(req.wValue, 0x3f2); USETW(req.wIndex, 0); USETW(req.wLength, sizeof(data)); usbd_do_request_flags(sc->sc_udev, &req, data, USBD_SHORT_XFER_OK, &actlen, USBD_DEFAULT_TIMEOUT); } sc->sc_repdesc = desc; sc->sc_repdesc_size = size; uha.uiaa = uiaa; nrepid = uhidev_maxrepid(desc, size); if (nrepid < 0) return; if (nrepid > 0) aprint_normal_dev(self, "%d report ids\n", nrepid); nrepid++; repsizes = kmem_alloc(nrepid * sizeof(*repsizes), KM_SLEEP); if (repsizes == NULL) goto nomem; sc->sc_subdevs = kmem_zalloc(nrepid * sizeof(device_t), KM_SLEEP); if (sc->sc_subdevs == NULL) { kmem_free(repsizes, nrepid * sizeof(*repsizes)); nomem: aprint_error_dev(self, "no memory\n"); return; } /* Just request max packet size for the interrupt pipe */ sc->sc_isize = maxinpktsize; sc->sc_nrepid = nrepid; usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, sc->sc_dev); for (repid = 0; repid < nrepid; repid++) { repsz = hid_report_size(desc, size, hid_input, repid); DPRINTF(("uhidev_match: repid=%d, repsz=%d\n", repid, repsz)); repsizes[repid] = repsz; } DPRINTF(("uhidev_attach: isize=%d\n", sc->sc_isize)); uha.parent = sc; for (repid = 0; repid < nrepid; repid++) { DPRINTF(("uhidev_match: try repid=%d\n", repid)); if (hid_report_size(desc, size, hid_input, repid) == 0 && hid_report_size(desc, size, hid_output, repid) == 0 && hid_report_size(desc, size, hid_feature, repid) == 0) { ; /* already NULL in sc->sc_subdevs[repid] */ } else { uha.reportid = repid; locs[UHIDBUSCF_REPORTID] = repid; dev = config_found_sm_loc(self, "uhidbus", locs, &uha, uhidevprint, config_stdsubmatch); sc->sc_subdevs[repid] = dev; if (dev != NULL) { csc = device_private(dev); csc->sc_in_rep_size = repsizes[repid]; #ifdef DIAGNOSTIC DPRINTF(("uhidev_match: repid=%d dev=%p\n", repid, dev)); if (csc->sc_intr == NULL) { kmem_free(repsizes, nrepid * sizeof(*repsizes)); aprint_error_dev(self, "sc_intr == NULL\n"); return; } #endif rnd_attach_source(&csc->rnd_source, device_xname(dev), RND_TYPE_TTY, RND_FLAG_DEFAULT); } } } kmem_free(repsizes, nrepid * sizeof(*repsizes)); return; }
/*------------------------------------------------------------------------* * usbd_req_get_desc * * This function can be used to retrieve USB descriptors. It contains * some additional logic like zeroing of missing descriptor bytes and * retrying an USB descriptor in case of failure. The "min_len" * argument specifies the minimum descriptor length. The "max_len" * argument specifies the maximum descriptor length. If the real * descriptor length is less than the minimum length the missing * byte(s) will be zeroed. The type field, the second byte of the USB * descriptor, will get forced to the correct type. If the "actlen" * pointer is non-NULL, the actual length of the transfer will get * stored in the 16-bit unsigned integer which it is pointing to. The * first byte of the descriptor will not get updated. If the "actlen" * pointer is NULL the first byte of the descriptor will get updated * to reflect the actual length instead. If "min_len" is not equal to * "max_len" then this function will try to retrive the beginning of * the descriptor and base the maximum length on the first byte of the * descriptor. * * Returns: * 0: Success * Else: Failure *------------------------------------------------------------------------*/ usb_error_t usbd_req_get_desc(struct usb_device *udev, struct mtx *mtx, uint16_t *actlen, void *desc, uint16_t min_len, uint16_t max_len, uint16_t id, uint8_t type, uint8_t index, uint8_t retries) { struct usb_device_request req; uint8_t *buf; usb_error_t err; DPRINTFN(4, "id=%d, type=%d, index=%d, max_len=%d\n", id, type, index, max_len); req.bmRequestType = UT_READ_DEVICE; req.bRequest = UR_GET_DESCRIPTOR; USETW2(req.wValue, type, index); USETW(req.wIndex, id); while (1) { if ((min_len < 2) || (max_len < 2)) { err = USB_ERR_INVAL; goto done; } USETW(req.wLength, min_len); err = usbd_do_request_flags(udev, mtx, &req, desc, 0, NULL, 1000); if (err) { if (!retries) { goto done; } retries--; usb_pause_mtx(mtx, hz / 5); continue; } buf = desc; if (min_len == max_len) { /* enforce correct length */ if ((buf[0] > min_len) && (actlen == NULL)) buf[0] = min_len; /* enforce correct type */ buf[1] = type; goto done; } /* range check */ if (max_len > buf[0]) { max_len = buf[0]; } /* zero minimum data */ while (min_len > max_len) { min_len--; buf[min_len] = 0; } /* set new minimum length */ min_len = max_len; } done: if (actlen != NULL) { if (err) *actlen = 0; else *actlen = min_len; } return (err); }
void ulpt_attach(struct device *parent, struct device *self, void *aux) { struct ulpt_softc *sc = (struct ulpt_softc *)self; struct usb_attach_arg *uaa = aux; struct usbd_device *dev = uaa->device; struct usbd_interface *iface = uaa->iface; usb_interface_descriptor_t *ifcd = usbd_get_interface_descriptor(iface); usb_interface_descriptor_t *id, *iend; usb_config_descriptor_t *cdesc; usbd_status err; usb_endpoint_descriptor_t *ed; u_int8_t epcount; int i, altno; DPRINTFN(10,("ulpt_attach: sc=%p\n", sc)); //printf("%s: iclass %d/%d\n", sc->sc_dev.dv_xname, // ifcd->bInterfaceClass, ifcd->bInterfaceSubClass); /* XXX * Stepping through the alternate settings needs to be abstracted out. */ cdesc = usbd_get_config_descriptor(dev); if (cdesc == NULL) { printf("%s: failed to get configuration descriptor\n", sc->sc_dev.dv_xname); return; } iend = (usb_interface_descriptor_t *) ((char *)cdesc + UGETW(cdesc->wTotalLength)); #ifdef DIAGNOSTIC if (ifcd < (usb_interface_descriptor_t *)cdesc || ifcd >= iend) panic("ulpt: iface desc out of range"); #endif /* Step through all the descriptors looking for bidir mode */ for (id = ifcd, altno = 0; id < iend; id = (void *)((char *)id + id->bLength)) { if (id->bDescriptorType == UDESC_INTERFACE && id->bInterfaceNumber == ifcd->bInterfaceNumber) { if (id->bInterfaceClass == UICLASS_PRINTER && id->bInterfaceSubClass == UISUBCLASS_PRINTER && (id->bInterfaceProtocol == UIPROTO_PRINTER_BI /*|| id->bInterfaceProtocol == UIPROTO_PRINTER_1284*/)) goto found; altno++; } } id = ifcd; /* not found, use original */ found: if (id != ifcd) { /* Found a new bidir setting */ DPRINTF(("ulpt_attach: set altno = %d\n", altno)); err = usbd_set_interface(iface, altno); if (err) { printf("%s: setting alternate interface failed\n", sc->sc_dev.dv_xname); usbd_deactivate(sc->sc_udev); return; } } epcount = 0; (void)usbd_endpoint_count(iface, &epcount); sc->sc_in = -1; sc->sc_out = -1; for (i = 0; i < epcount; i++) { ed = usbd_interface2endpoint_descriptor(iface, i); if (ed == NULL) { printf("%s: couldn't get ep %d\n", sc->sc_dev.dv_xname, i); return; } if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { sc->sc_in = ed->bEndpointAddress; } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { sc->sc_out = ed->bEndpointAddress; } } if (sc->sc_out == -1) { printf("%s: could not find bulk out endpoint\n", sc->sc_dev.dv_xname); usbd_deactivate(sc->sc_udev); return; } if (usbd_get_quirks(dev)->uq_flags & UQ_BROKEN_BIDIR) { /* This device doesn't handle reading properly. */ sc->sc_in = -1; } printf("%s: using %s-directional mode\n", sc->sc_dev.dv_xname, sc->sc_in >= 0 ? "bi" : "uni"); DPRINTFN(10, ("ulpt_attach: bulk=%d\n", sc->sc_out)); sc->sc_iface = iface; sc->sc_ifaceno = id->bInterfaceNumber; sc->sc_udev = dev; /* maybe the device needs firmware */ sc->sc_fwdev = ulpt_lookup(uaa->vendor, uaa->product); if (sc->sc_fwdev) { if (rootvp == NULL) mountroothook_establish(ulpt_load_firmware, sc); else ulpt_load_firmware(sc); } #if 0 /* * This code is disabled because for some mysterious reason it causes * printing not to work. But only sometimes, and mostly with * UHCI and less often with OHCI. *sigh* */ { usb_config_descriptor_t *cd = usbd_get_config_descriptor(dev); usb_device_request_t req; int len, alen; req.bmRequestType = UT_READ_CLASS_INTERFACE; req.bRequest = UR_GET_DEVICE_ID; USETW(req.wValue, cd->bConfigurationValue); USETW2(req.wIndex, id->bInterfaceNumber, id->bAlternateSetting); USETW(req.wLength, DEVINFOSIZE - 1); err = usbd_do_request_flags(dev, &req, devinfop, USBD_SHORT_XFER_OK, &alen, USBD_DEFAULT_TIMEOUT); if (err) { printf("%s: cannot get device id\n", sc->sc_dev.dv_xname); } else if (alen <= 2) { printf("%s: empty device id, no printer connected?\n", sc->sc_dev.dv_xname); } else { /* devinfop now contains an IEEE-1284 device ID */ len = ((devinfop[0] & 0xff) << 8) | (devinfop[1] & 0xff); if (len > DEVINFOSIZE - 3) len = DEVINFOSIZE - 3; devinfo[len] = 0; printf("%s: device id <", sc->sc_dev.dv_xname); ieee1284_print_id(devinfop+2); printf(">\n"); } } #endif }
int ugen_do_ioctl(struct ugen_softc *sc, int endpt, u_long cmd, caddr_t addr, int flag, struct proc *p) { struct ugen_endpoint *sce; int err; struct usbd_interface *iface; struct usb_config_desc *cd; usb_config_descriptor_t *cdesc; struct usb_interface_desc *id; usb_interface_descriptor_t *idesc; struct usb_endpoint_desc *ed; usb_endpoint_descriptor_t *edesc; struct usb_alt_interface *ai; struct usb_string_desc *si; u_int8_t conf, alt; DPRINTFN(5, ("ugenioctl: cmd=%08lx\n", cmd)); if (usbd_is_dying(sc->sc_udev)) return (EIO); switch (cmd) { case FIONBIO: /* All handled in the upper FS layer. */ return (0); case USB_SET_SHORT_XFER: if (endpt == USB_CONTROL_ENDPOINT) return (EINVAL); /* This flag only affects read */ sce = &sc->sc_endpoints[endpt][IN]; if (sce == NULL || sce->pipeh == NULL) return (EINVAL); if (*(int *)addr) sce->state |= UGEN_SHORT_OK; else sce->state &= ~UGEN_SHORT_OK; return (0); case USB_SET_TIMEOUT: sce = &sc->sc_endpoints[endpt][IN]; if (sce == NULL) return (EINVAL); sce->timeout = *(int *)addr; sce = &sc->sc_endpoints[endpt][OUT]; if (sce == NULL) return (EINVAL); sce->timeout = *(int *)addr; return (0); default: break; } if (endpt != USB_CONTROL_ENDPOINT) return (EINVAL); switch (cmd) { #ifdef UGEN_DEBUG case USB_SETDEBUG: ugendebug = *(int *)addr; break; #endif case USB_GET_CONFIG: err = usbd_get_config(sc->sc_udev, &conf); if (err) return (EIO); *(int *)addr = conf; break; case USB_SET_CONFIG: if (!(flag & FWRITE)) return (EPERM); err = ugen_set_config(sc, *(int *)addr); switch (err) { case USBD_NORMAL_COMPLETION: break; case USBD_IN_USE: return (EBUSY); default: return (EIO); } break; case USB_GET_ALTINTERFACE: ai = (struct usb_alt_interface *)addr; err = usbd_device2interface_handle(sc->sc_udev, ai->uai_interface_index, &iface); if (err) return (EINVAL); idesc = usbd_get_interface_descriptor(iface); if (idesc == NULL) return (EIO); ai->uai_alt_no = idesc->bAlternateSetting; break; case USB_SET_ALTINTERFACE: if (!(flag & FWRITE)) return (EPERM); ai = (struct usb_alt_interface *)addr; err = usbd_device2interface_handle(sc->sc_udev, ai->uai_interface_index, &iface); if (err) return (EINVAL); err = ugen_set_interface(sc, ai->uai_interface_index, ai->uai_alt_no); if (err) return (EINVAL); break; case USB_GET_NO_ALT: ai = (struct usb_alt_interface *)addr; cdesc = usbd_get_cdesc(sc->sc_udev, ai->uai_config_index, 0); if (cdesc == NULL) return (EINVAL); idesc = usbd_find_idesc(cdesc, ai->uai_interface_index, 0); if (idesc == NULL) { free(cdesc, M_TEMP, 0); return (EINVAL); } ai->uai_alt_no = usbd_get_no_alts(cdesc, idesc->bInterfaceNumber); free(cdesc, M_TEMP, 0); break; case USB_GET_DEVICE_DESC: *(usb_device_descriptor_t *)addr = *usbd_get_device_descriptor(sc->sc_udev); break; case USB_GET_CONFIG_DESC: cd = (struct usb_config_desc *)addr; cdesc = usbd_get_cdesc(sc->sc_udev, cd->ucd_config_index, 0); if (cdesc == NULL) return (EINVAL); cd->ucd_desc = *cdesc; free(cdesc, M_TEMP, 0); break; case USB_GET_INTERFACE_DESC: id = (struct usb_interface_desc *)addr; cdesc = usbd_get_cdesc(sc->sc_udev, id->uid_config_index, 0); if (cdesc == NULL) return (EINVAL); if (id->uid_config_index == USB_CURRENT_CONFIG_INDEX && id->uid_alt_index == USB_CURRENT_ALT_INDEX) alt = ugen_get_alt_index(sc, id->uid_interface_index); else alt = id->uid_alt_index; idesc = usbd_find_idesc(cdesc, id->uid_interface_index, alt); if (idesc == NULL) { free(cdesc, M_TEMP, 0); return (EINVAL); } id->uid_desc = *idesc; free(cdesc, M_TEMP, 0); break; case USB_GET_ENDPOINT_DESC: ed = (struct usb_endpoint_desc *)addr; cdesc = usbd_get_cdesc(sc->sc_udev, ed->ued_config_index, 0); if (cdesc == NULL) return (EINVAL); if (ed->ued_config_index == USB_CURRENT_CONFIG_INDEX && ed->ued_alt_index == USB_CURRENT_ALT_INDEX) alt = ugen_get_alt_index(sc, ed->ued_interface_index); else alt = ed->ued_alt_index; edesc = usbd_find_edesc(cdesc, ed->ued_interface_index, alt, ed->ued_endpoint_index); if (edesc == NULL) { free(cdesc, M_TEMP, 0); return (EINVAL); } ed->ued_desc = *edesc; free(cdesc, M_TEMP, 0); break; case USB_GET_FULL_DESC: { int len; struct iovec iov; struct uio uio; struct usb_full_desc *fd = (struct usb_full_desc *)addr; int error; cdesc = usbd_get_cdesc(sc->sc_udev, fd->ufd_config_index, &len); if (cdesc == NULL) return (EINVAL); if (len > fd->ufd_size) len = fd->ufd_size; iov.iov_base = (caddr_t)fd->ufd_data; iov.iov_len = len; uio.uio_iov = &iov; uio.uio_iovcnt = 1; uio.uio_resid = len; uio.uio_offset = 0; uio.uio_segflg = UIO_USERSPACE; uio.uio_rw = UIO_READ; uio.uio_procp = p; error = uiomove((void *)cdesc, len, &uio); free(cdesc, M_TEMP, 0); return (error); } case USB_GET_STRING_DESC: { int len; si = (struct usb_string_desc *)addr; err = usbd_get_string_desc(sc->sc_udev, si->usd_string_index, si->usd_language_id, &si->usd_desc, &len); if (err) return (EINVAL); break; } case USB_DO_REQUEST: { struct usb_ctl_request *ur = (void *)addr; int len = UGETW(ur->ucr_request.wLength); struct iovec iov; struct uio uio; void *ptr = 0; int error = 0; if (!(flag & FWRITE)) return (EPERM); /* Avoid requests that would damage the bus integrity. */ if ((ur->ucr_request.bmRequestType == UT_WRITE_DEVICE && ur->ucr_request.bRequest == UR_SET_ADDRESS) || (ur->ucr_request.bmRequestType == UT_WRITE_DEVICE && ur->ucr_request.bRequest == UR_SET_CONFIG) || (ur->ucr_request.bmRequestType == UT_WRITE_INTERFACE && ur->ucr_request.bRequest == UR_SET_INTERFACE)) return (EINVAL); if (len < 0 || len > 32767) return (EINVAL); if (len != 0) { iov.iov_base = (caddr_t)ur->ucr_data; iov.iov_len = len; uio.uio_iov = &iov; uio.uio_iovcnt = 1; uio.uio_resid = len; uio.uio_offset = 0; uio.uio_segflg = UIO_USERSPACE; uio.uio_rw = ur->ucr_request.bmRequestType & UT_READ ? UIO_READ : UIO_WRITE; uio.uio_procp = p; ptr = malloc(len, M_TEMP, M_WAITOK); if (uio.uio_rw == UIO_WRITE) { error = uiomove(ptr, len, &uio); if (error) goto ret; } } sce = &sc->sc_endpoints[endpt][IN]; err = usbd_do_request_flags(sc->sc_udev, &ur->ucr_request, ptr, ur->ucr_flags, &ur->ucr_actlen, sce->timeout); if (err) { error = EIO; goto ret; } /* Only if USBD_SHORT_XFER_OK is set. */ if (len > ur->ucr_actlen) len = ur->ucr_actlen; if (len != 0) { if (uio.uio_rw == UIO_READ) { error = uiomove(ptr, len, &uio); if (error) goto ret; } } ret: if (ptr) free(ptr, M_TEMP, 0); return (error); } case USB_GET_DEVICEINFO: usbd_fill_deviceinfo(sc->sc_udev, (struct usb_device_info *)addr, 1); break; default: return (EINVAL); } return (0); }
usbd_status uvisor_init(struct uvisor_softc *sc) { usbd_status err; usb_device_request_t req; struct uvisor_connection_info coninfo; int actlen; uWord avail; DPRINTF(("uvisor_init: getting connection info\n")); req.bmRequestType = UT_READ_VENDOR_ENDPOINT; req.bRequest = UVISOR_GET_CONNECTION_INFORMATION; USETW(req.wValue, 0); USETW(req.wIndex, 0); USETW(req.wLength, UVISOR_CONNECTION_INFO_SIZE); err = usbd_do_request_flags(sc->sc_udev, &req, &coninfo, USBD_SHORT_XFER_OK, &actlen); if (err) return (err); #ifdef UVISOR_DEBUG { int i, np; char *string; np = UGETW(coninfo.num_ports); printf("%s: Number of ports: %d\n", USBDEVNAME(sc->sc_dev), np); for (i = 0; i < np; ++i) { switch (coninfo.connections[i].port_function_id) { case UVISOR_FUNCTION_GENERIC: string = "Generic"; break; case UVISOR_FUNCTION_DEBUGGER: string = "Debugger"; break; case UVISOR_FUNCTION_HOTSYNC: string = "HotSync"; break; case UVISOR_FUNCTION_REMOTE_FILE_SYS: string = "Remote File System"; break; default: string = "unknown"; break; } printf("%s: port %d, is for %s\n", USBDEVNAME(sc->sc_dev), coninfo.connections[i].port, string); } } #endif DPRINTF(("uvisor_init: getting available bytes\n")); req.bmRequestType = UT_READ_VENDOR_ENDPOINT; req.bRequest = UVISOR_REQUEST_BYTES_AVAILABLE; USETW(req.wValue, 0); USETW(req.wIndex, 5); USETW(req.wLength, sizeof avail); err = usbd_do_request(sc->sc_udev, &req, &avail); if (err) return (err); DPRINTF(("uvisor_init: avail=%d\n", UGETW(avail))); DPRINTF(("uvisor_init: done\n")); return (err); }