Exemple #1
0
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);
}
Exemple #2
0
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;
}
Exemple #3
0
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);
}
Exemple #5
0
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);
}
Exemple #6
0
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);
}
Exemple #8
0
/*
 * 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);
}
Exemple #9
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;
}
Exemple #10
0
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);
}
Exemple #11
0
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;
}
Exemple #12
0
/*
 * 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;
}
Exemple #13
0
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);
}
Exemple #14
0
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);
}
Exemple #15
0
/*------------------------------------------------------------------------*
 *	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 */
}
Exemple #16
0
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;
}
Exemple #17
0
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);
}
Exemple #19
0
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
}
Exemple #20
0
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);
}
Exemple #21
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);
}