예제 #1
0
static void
uhid_write_callback(struct usb_xfer *xfer, usb_error_t error)
{
	struct uhid_softc *sc = usbd_xfer_softc(xfer);
	struct usb_device_request req;
	struct usb_page_cache *pc;
	uint32_t size = sc->sc_osize;
	uint32_t actlen;
	uint8_t id;

	switch (USB_GET_STATE(xfer)) {
	case USB_ST_TRANSFERRED:
	case USB_ST_SETUP:
		/* try to extract the ID byte */
		if (sc->sc_oid) {
			pc = usbd_xfer_get_frame(xfer, 0);
			if (usb_fifo_get_data(sc->sc_fifo.fp[USB_FIFO_TX], pc,
			    0, 1, &actlen, 0)) {
				if (actlen != 1) {
					goto tr_error;
				}
				usbd_copy_out(pc, 0, &id, 1);

			} else {
				return;
			}
			if (size) {
				size--;
			}
		} else {
			id = 0;
		}

		pc = usbd_xfer_get_frame(xfer, 1);
		if (usb_fifo_get_data(sc->sc_fifo.fp[USB_FIFO_TX], pc,
		    0, UHID_BSIZE, &actlen, 1)) {
			if (actlen != size) {
				goto tr_error;
			}
			uhid_fill_set_report
			    (&req, sc->sc_iface_no,
			    UHID_OUTPUT_REPORT, id, size);

			pc = usbd_xfer_get_frame(xfer, 0);
			usbd_copy_in(pc, 0, &req, sizeof(req));

			usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
			usbd_xfer_set_frame_len(xfer, 1, size);
			usbd_xfer_set_frames(xfer, size ? 2 : 1);
			usbd_transfer_submit(xfer);
		}
		return;

	default:
tr_error:
		/* bomb out */
		usb_fifo_get_data_error(sc->sc_fifo.fp[USB_FIFO_TX]);
		return;
	}
}
예제 #2
0
파일: uhso.c 프로젝트: vkhromov/freebsd
static void
uhso_mux_read_callback(struct usb_xfer *xfer, usb_error_t error)
{
	struct uhso_softc *sc = usbd_xfer_softc(xfer);
	struct usb_page_cache *pc;
	struct usb_device_request req;
	struct uhso_tty *ht;
	int actlen, len;

	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);

	UHSO_DPRINTF(3, "status %d\n", USB_GET_STATE(xfer));

	ht = usbd_xfer_get_priv(xfer);
	UHSO_DPRINTF(3, "ht=%p open=%d\n", ht, ht->ht_open);

	switch (USB_GET_STATE(xfer)) {
	case USB_ST_TRANSFERRED:
		/* Got data, send to ucom */
		pc = usbd_xfer_get_frame(xfer, 1);
		len = usbd_xfer_frame_len(xfer, 1);

		UHSO_DPRINTF(3, "got %d bytes on mux port %d\n", len,
		    ht->ht_muxport);
		if (len <= 0) {
			usbd_transfer_start(sc->sc_xfer[UHSO_MUX_ENDPT_INTR]);
			break;
		}

		/* Deliver data if the TTY is open, discard otherwise */
		if (ht->ht_open)
			ucom_put_data(&sc->sc_ucom[ht->ht_muxport], pc, 0, len);
		/* FALLTHROUGH */
	case USB_ST_SETUP:
tr_setup:
		memset(&req, 0, sizeof(struct usb_device_request));
		req.bmRequestType = UT_READ_CLASS_INTERFACE;
		req.bRequest = UCDC_GET_ENCAPSULATED_RESPONSE;
		USETW(req.wValue, 0);
		USETW(req.wIndex, ht->ht_muxport);
		USETW(req.wLength, 1024);

		pc = usbd_xfer_get_frame(xfer, 0);
		usbd_copy_in(pc, 0, &req, sizeof(req));

		usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
		usbd_xfer_set_frame_len(xfer, 1, 1024);
		usbd_xfer_set_frames(xfer, 2);
		usbd_transfer_submit(xfer);
		break;
	default:
		UHSO_DPRINTF(0, "error: %s\n", usbd_errstr(error));
		if (error == USB_ERR_CANCELLED)
			break;
		usbd_xfer_set_stall(xfer);
		goto tr_setup;
	}
}
예제 #3
0
static int
usbd_m_copy_in_cb(void *arg, void *src, uint32_t count)
{
	register struct usb_m_copy_in_arg *ua = arg;

	usbd_copy_in(ua->cache, ua->dst_offset, src, count);
	ua->dst_offset += count;
	return (0);
}
예제 #4
0
파일: uhso.c 프로젝트: vkhromov/freebsd
static void
uhso_mux_write_callback(struct usb_xfer *xfer, usb_error_t error)
{
	struct uhso_softc *sc = usbd_xfer_softc(xfer);
	struct uhso_tty *ht;
	struct usb_page_cache *pc;
	struct usb_device_request req;
	int actlen;
	struct usb_page_search res;

	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);

	ht = usbd_xfer_get_priv(xfer);
	UHSO_DPRINTF(3, "status=%d, using mux port %d\n",
	    USB_GET_STATE(xfer), ht->ht_muxport);

	switch (USB_GET_STATE(xfer)) {
	case USB_ST_TRANSFERRED:
		UHSO_DPRINTF(3, "wrote %zd data bytes to muxport %d\n",
		    actlen - sizeof(struct usb_device_request) ,
		    ht->ht_muxport);
		/* FALLTHROUGH */
	case USB_ST_SETUP:
		pc = usbd_xfer_get_frame(xfer, 1);
		if (ucom_get_data(&sc->sc_ucom[ht->ht_muxport], pc,
		    0, 32, &actlen)) {

			usbd_get_page(pc, 0, &res);

			memset(&req, 0, sizeof(struct usb_device_request));
			req.bmRequestType = UT_WRITE_CLASS_INTERFACE;
			req.bRequest = UCDC_SEND_ENCAPSULATED_COMMAND;
			USETW(req.wValue, 0);
			USETW(req.wIndex, ht->ht_muxport);
			USETW(req.wLength, actlen);

			pc = usbd_xfer_get_frame(xfer, 0);
			usbd_copy_in(pc, 0, &req, sizeof(req));

			usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
			usbd_xfer_set_frame_len(xfer, 1, actlen);
			usbd_xfer_set_frames(xfer, 2);

			UHSO_DPRINTF(3, "Prepared %d bytes for transmit "
			    "on muxport %d\n", actlen, ht->ht_muxport);

			usbd_transfer_submit(xfer);
		}
		break;
	default:
		UHSO_DPRINTF(0, "error: %s\n", usbd_errstr(error));
		if (error == USB_ERR_CANCELLED)
			break;
		break;
	}
}
예제 #5
0
static void
uhid_read_callback(struct usb_xfer *xfer, usb_error_t error)
{
	struct uhid_softc *sc = usbd_xfer_softc(xfer);
	struct usb_device_request req;
	struct usb_page_cache *pc;

	pc = usbd_xfer_get_frame(xfer, 0);

	switch (USB_GET_STATE(xfer)) {
	case USB_ST_TRANSFERRED:
		usb_fifo_put_data(sc->sc_fifo.fp[USB_FIFO_RX], pc, sizeof(req),
		    sc->sc_isize, 1);
		return;

	case USB_ST_SETUP:

		if (usb_fifo_put_bytes_max(sc->sc_fifo.fp[USB_FIFO_RX]) > 0) {

			uhid_fill_get_report
			    (&req, sc->sc_iface_no, UHID_INPUT_REPORT,
			    sc->sc_iid, sc->sc_isize);

			usbd_copy_in(pc, 0, &req, sizeof(req));

			usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
			usbd_xfer_set_frame_len(xfer, 1, sc->sc_isize);
			usbd_xfer_set_frames(xfer, sc->sc_isize ? 2 : 1);
			usbd_transfer_submit(xfer);
		}
		return;

	default:			/* Error */
		/* bomb out */
		usb_fifo_put_data_error(sc->sc_fifo.fp[USB_FIFO_RX]);
		return;
	}
}
/*------------------------------------------------------------------------*
 *	usb_handle_request
 *
 * Internal state sequence:
 *
 * USB_HR_NOT_COMPLETE -> USB_HR_COMPLETE_OK v USB_HR_COMPLETE_ERR
 *
 * Returns:
 * 0: Ready to start hardware
 * Else: Stall current transfer, if any
 *------------------------------------------------------------------------*/
static usb_error_t
usb_handle_request(struct usb_xfer *xfer)
{
	struct usb_device_request req;
	struct usb_device *udev;
	const void *src_zcopy;		/* zero-copy source pointer */
	const void *src_mcopy;		/* non zero-copy source pointer */
	uint16_t off;			/* data offset */
	uint16_t rem;			/* data remainder */
	uint16_t max_len;		/* max fragment length */
	uint16_t wValue;
	uint16_t wIndex;
	uint8_t state;
	uint8_t is_complete = 1;
	usb_error_t err;
	union {
		uWord	wStatus;
		uint8_t	buf[2];
	}     temp;

	/*
	 * Filter the USB transfer state into
	 * something which we understand:
	 */

	switch (USB_GET_STATE(xfer)) {
	case USB_ST_SETUP:
		state = USB_HR_NOT_COMPLETE;

		if (!xfer->flags_int.control_act) {
			/* nothing to do */
			goto tr_stalled;
		}
		break;
	case USB_ST_TRANSFERRED:
		if (!xfer->flags_int.control_act) {
			state = USB_HR_COMPLETE_OK;
		} else {
			state = USB_HR_NOT_COMPLETE;
		}
		break;
	default:
		state = USB_HR_COMPLETE_ERR;
		break;
	}

	/* reset frame stuff */

	usbd_xfer_set_frame_len(xfer, 0, 0);

	usbd_xfer_set_frame_offset(xfer, 0, 0);
	usbd_xfer_set_frame_offset(xfer, sizeof(req), 1);

	/* get the current request, if any */

	usbd_copy_out(xfer->frbuffers, 0, &req, sizeof(req));

	if (xfer->flags_int.control_rem == 0xFFFF) {
		/* first time - not initialised */
		rem = UGETW(req.wLength);
		off = 0;
	} else {
		/* not first time - initialised */
		rem = xfer->flags_int.control_rem;
		off = UGETW(req.wLength) - rem;
	}

	/* set some defaults */

	max_len = 0;
	src_zcopy = NULL;
	src_mcopy = NULL;
	udev = xfer->xroot->udev;

	/* get some request fields decoded */

	wValue = UGETW(req.wValue);
	wIndex = UGETW(req.wIndex);

	DPRINTF("req 0x%02x 0x%02x 0x%04x 0x%04x "
	    "off=0x%x rem=0x%x, state=%d\n", req.bmRequestType,
	    req.bRequest, wValue, wIndex, off, rem, state);

	/* demultiplex the control request */

	switch (req.bmRequestType) {
	case UT_READ_DEVICE:
		if (state != USB_HR_NOT_COMPLETE) {
			break;
		}
		switch (req.bRequest) {
		case UR_GET_DESCRIPTOR:
			goto tr_handle_get_descriptor;
		case UR_GET_CONFIG:
			goto tr_handle_get_config;
		case UR_GET_STATUS:
			goto tr_handle_get_status;
		default:
			goto tr_stalled;
		}
		break;

	case UT_WRITE_DEVICE:
		switch (req.bRequest) {
		case UR_SET_ADDRESS:
			goto tr_handle_set_address;
		case UR_SET_CONFIG:
			goto tr_handle_set_config;
		case UR_CLEAR_FEATURE:
			switch (wValue) {
			case UF_DEVICE_REMOTE_WAKEUP:
				goto tr_handle_clear_wakeup;
			default:
				goto tr_stalled;
			}
			break;
		case UR_SET_FEATURE:
			switch (wValue) {
			case UF_DEVICE_REMOTE_WAKEUP:
				goto tr_handle_set_wakeup;
			default:
				goto tr_stalled;
			}
			break;
		default:
			goto tr_stalled;
		}
		break;

	case UT_WRITE_ENDPOINT:
		switch (req.bRequest) {
		case UR_CLEAR_FEATURE:
			switch (wValue) {
			case UF_ENDPOINT_HALT:
				goto tr_handle_clear_halt;
			default:
				goto tr_stalled;
			}
			break;
		case UR_SET_FEATURE:
			switch (wValue) {
			case UF_ENDPOINT_HALT:
				goto tr_handle_set_halt;
			default:
				goto tr_stalled;
			}
			break;
		default:
			goto tr_stalled;
		}
		break;

	case UT_READ_ENDPOINT:
		switch (req.bRequest) {
		case UR_GET_STATUS:
			goto tr_handle_get_ep_status;
		default:
			goto tr_stalled;
		}
		break;
	default:
		/* we use "USB_ADD_BYTES" to de-const the src_zcopy */
		err = usb_handle_iface_request(xfer,
		    USB_ADD_BYTES(&src_zcopy, 0),
		    &max_len, req, off, state);
		if (err == 0) {
			is_complete = 0;
			goto tr_valid;
		} else if (err == USB_ERR_SHORT_XFER) {
			goto tr_valid;
		}
		/*
		 * Reset zero-copy pointer and max length
		 * variable in case they were unintentionally
		 * set:
		 */
		src_zcopy = NULL;
		max_len = 0;

		/*
		 * Check if we have a vendor specific
		 * descriptor:
		 */
		goto tr_handle_get_descriptor;
	}
	goto tr_valid;

tr_handle_get_descriptor:
	err = (usb_temp_get_desc_p) (udev, &req, &src_zcopy, &max_len);
	if (err)
		goto tr_stalled;
	if (src_zcopy == NULL)
		goto tr_stalled;
	goto tr_valid;

tr_handle_get_config:
	temp.buf[0] = udev->curr_config_no;
	src_mcopy = temp.buf;
	max_len = 1;
	goto tr_valid;

tr_handle_get_status:

	wValue = 0;

	USB_BUS_LOCK(udev->bus);
	if (udev->flags.remote_wakeup) {
		wValue |= UDS_REMOTE_WAKEUP;
	}
	if (udev->flags.self_powered) {
		wValue |= UDS_SELF_POWERED;
	}
	USB_BUS_UNLOCK(udev->bus);

	USETW(temp.wStatus, wValue);
	src_mcopy = temp.wStatus;
	max_len = sizeof(temp.wStatus);
	goto tr_valid;

tr_handle_set_address:
	if (state == USB_HR_NOT_COMPLETE) {
		if (wValue >= 0x80) {
			/* invalid value */
			goto tr_stalled;
		} else if (udev->curr_config_no != 0) {
			/* we are configured ! */
			goto tr_stalled;
		}
	} else if (state != USB_HR_NOT_COMPLETE) {
		udev->address = (wValue & 0x7F);
		goto tr_bad_context;
	}
	goto tr_valid;

tr_handle_set_config:
	if (state == USB_HR_NOT_COMPLETE) {
		if (usb_handle_set_config(xfer, req.wValue[0])) {
			goto tr_stalled;
		}
	}
	goto tr_valid;

tr_handle_clear_halt:
	if (state == USB_HR_NOT_COMPLETE) {
		if (usb_handle_set_stall(xfer, req.wIndex[0], 0)) {
			goto tr_stalled;
		}
	}
	goto tr_valid;

tr_handle_clear_wakeup:
	if (state == USB_HR_NOT_COMPLETE) {
		if (usb_handle_remote_wakeup(xfer, 0)) {
			goto tr_stalled;
		}
	}
	goto tr_valid;

tr_handle_set_halt:
	if (state == USB_HR_NOT_COMPLETE) {
		if (usb_handle_set_stall(xfer, req.wIndex[0], 1)) {
			goto tr_stalled;
		}
	}
	goto tr_valid;

tr_handle_set_wakeup:
	if (state == USB_HR_NOT_COMPLETE) {
		if (usb_handle_remote_wakeup(xfer, 1)) {
			goto tr_stalled;
		}
	}
	goto tr_valid;

tr_handle_get_ep_status:
	if (state == USB_HR_NOT_COMPLETE) {
		temp.wStatus[0] =
		    usb_handle_get_stall(udev, req.wIndex[0]);
		temp.wStatus[1] = 0;
		src_mcopy = temp.wStatus;
		max_len = sizeof(temp.wStatus);
	}
	goto tr_valid;

tr_valid:
	if (state != USB_HR_NOT_COMPLETE) {
		goto tr_stalled;
	}
	/* subtract offset from length */

	max_len -= off;

	/* Compute the real maximum data length */

	if (max_len > xfer->max_data_length) {
		max_len = usbd_xfer_max_len(xfer);
	}
	if (max_len > rem) {
		max_len = rem;
	}
	/*
	 * If the remainder is greater than the maximum data length,
	 * we need to truncate the value for the sake of the
	 * comparison below:
	 */
	if (rem > xfer->max_data_length) {
		rem = usbd_xfer_max_len(xfer);
	}
	if ((rem != max_len) && (is_complete != 0)) {
		/*
	         * If we don't transfer the data we can transfer, then
	         * the transfer is short !
	         */
		xfer->flags.force_short_xfer = 1;
		xfer->nframes = 2;
	} else {
		/*
		 * Default case
		 */
		xfer->flags.force_short_xfer = 0;
		xfer->nframes = max_len ? 2 : 1;
	}
	if (max_len > 0) {
		if (src_mcopy) {
			src_mcopy = USB_ADD_BYTES(src_mcopy, off);
			usbd_copy_in(xfer->frbuffers + 1, 0,
			    src_mcopy, max_len);
			usbd_xfer_set_frame_len(xfer, 1, max_len);
		} else {
			usbd_xfer_set_frame_data(xfer, 1,
			    USB_ADD_BYTES(src_zcopy, off), max_len);
		}
	} else {
		/* the end is reached, send status */
		xfer->flags.manual_status = 0;
		usbd_xfer_set_frame_len(xfer, 1, 0);
	}
	DPRINTF("success\n");
	return (0);			/* success */

tr_stalled:
	DPRINTF("%s\n", (state != USB_HR_NOT_COMPLETE) ?
	    "complete" : "stalled");
	return (USB_ERR_STALLED);

tr_bad_context:
	DPRINTF("bad context\n");
	return (USB_ERR_BAD_CONTEXT);
}
예제 #7
0
static void
usie_if_tx_callback(struct usb_xfer *xfer, usb_error_t error)
{
	struct usie_softc *sc = usbd_xfer_softc(xfer);
	struct usb_page_cache *pc;
	struct ifnet *ifp = sc->sc_ifp;
	struct mbuf *m;
	uint16_t size;

	switch (USB_GET_STATE(xfer)) {
	case USB_ST_TRANSFERRED:
		DPRINTFN(11, "transfer complete\n");
		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
		ifp->if_opackets++;

		/* fall though */
	case USB_ST_SETUP:
tr_setup:

		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
			break;

		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
		if (m == NULL)
			break;

		if (m->m_pkthdr.len > (MCLBYTES - ETHER_HDR_LEN +
		    ETHER_CRC_LEN - sizeof(sc->sc_txd))) {
			DPRINTF("packet len is too big: %d\n",
			    m->m_pkthdr.len);
			break;
		}
		pc = usbd_xfer_get_frame(xfer, 0);

		sc->sc_txd.hip.len = htobe16(m->m_pkthdr.len +
		    ETHER_HDR_LEN + ETHER_CRC_LEN);
		size = sizeof(sc->sc_txd);

		usbd_copy_in(pc, 0, &sc->sc_txd, size);
		usbd_m_copy_in(pc, size, m, 0, m->m_pkthdr.len);
		usbd_xfer_set_frame_len(xfer, 0, m->m_pkthdr.len +
		    size + ETHER_CRC_LEN);

		BPF_MTAP(ifp, m);

		m_freem(m);

		usbd_transfer_submit(xfer);
		break;

	default:			/* Error */
		DPRINTF("USB transfer error, %s\n",
		    usbd_errstr(error));
		ifp->if_oerrors++;

		if (error != USB_ERR_CANCELLED) {
			usbd_xfer_set_stall(xfer);
			ifp->if_ierrors++;
			goto tr_setup;
		}
		break;
	}
}
예제 #8
0
static uint8_t
cdce_ncm_fill_tx_frames(struct usb_xfer *xfer, uint8_t index)
{
	struct cdce_softc *sc = usbd_xfer_softc(xfer);
	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
	struct usb_page_cache *pc = usbd_xfer_get_frame(xfer, index);
	struct mbuf *m;
	uint32_t rem;
	uint32_t offset;
	uint32_t last_offset;
	uint16_t n;
	uint8_t retval;

	usbd_xfer_set_frame_offset(xfer, index * CDCE_NCM_TX_MAXLEN, index);

	offset = sizeof(sc->sc_ncm.hdr) +
	    sizeof(sc->sc_ncm.dpt) + sizeof(sc->sc_ncm.dp);

	/* Store last valid offset before alignment */
	last_offset = offset;

	/* Align offset */
	offset = CDCE_NCM_ALIGN(sc->sc_ncm.tx_remainder,
	    offset, sc->sc_ncm.tx_modulus);

	/* Zero pad */
	cdce_ncm_tx_zero(pc, last_offset, offset);

	/* buffer full */
	retval = 2;

	for (n = 0; n != sc->sc_ncm.tx_nframe; n++) {

		/* check if end of transmit buffer is reached */

		if (offset >= sc->sc_ncm.tx_max)
			break;

		/* compute maximum buffer size */

		rem = sc->sc_ncm.tx_max - offset;

		IFQ_DRV_DEQUEUE(&(ifp->if_snd), m);

		if (m == NULL) {
			/* buffer not full */
			retval = 1;
			break;
		}

		if (m->m_pkthdr.len > rem) {
			if (n == 0) {
				/* The frame won't fit in our buffer */
				DPRINTFN(1, "Frame too big to be transmitted!\n");
				m_freem(m);
				ifp->if_oerrors++;
				n--;
				continue;
			}
			/* Wait till next buffer becomes ready */
			IFQ_DRV_PREPEND(&(ifp->if_snd), m);
			break;
		}
		usbd_m_copy_in(pc, offset, m, 0, m->m_pkthdr.len);

		USETW(sc->sc_ncm.dp[n].wFrameLength, m->m_pkthdr.len);
		USETW(sc->sc_ncm.dp[n].wFrameIndex, offset);

		/* Update offset */
		offset += m->m_pkthdr.len;

		/* Store last valid offset before alignment */
		last_offset = offset;

		/* Align offset */
		offset = CDCE_NCM_ALIGN(sc->sc_ncm.tx_remainder,
		    offset, sc->sc_ncm.tx_modulus);

		/* Zero pad */
		cdce_ncm_tx_zero(pc, last_offset, offset);

		/*
		 * If there's a BPF listener, bounce a copy
		 * of this frame to him:
		 */
		BPF_MTAP(ifp, m);

		/* Free mbuf */

		m_freem(m);

		/* Pre-increment interface counter */

		ifp->if_opackets++;
	}

	if (n == 0)
		return (0);

	rem = (sizeof(sc->sc_ncm.dpt) + (4 * n) + 4);

	USETW(sc->sc_ncm.dpt.wLength, rem);

	/* zero the rest of the data pointer entries */
	for (; n != CDCE_NCM_SUBFRAMES_MAX; n++) {
		USETW(sc->sc_ncm.dp[n].wFrameLength, 0);
		USETW(sc->sc_ncm.dp[n].wFrameIndex, 0);
	}

	offset = last_offset;

	/* Align offset */
	offset = CDCE_NCM_ALIGN(0, offset, CDCE_NCM_TX_MINLEN);

	/* Optimise, save bandwidth and force short termination */
	if (offset >= sc->sc_ncm.tx_max)
		offset = sc->sc_ncm.tx_max;
	else
		offset ++;

	/* Zero pad */
	cdce_ncm_tx_zero(pc, last_offset, offset);

	/* set frame length */
	usbd_xfer_set_frame_len(xfer, index, offset);

	/* Fill out 16-bit header */
	sc->sc_ncm.hdr.dwSignature[0] = 'N';
	sc->sc_ncm.hdr.dwSignature[1] = 'C';
	sc->sc_ncm.hdr.dwSignature[2] = 'M';
	sc->sc_ncm.hdr.dwSignature[3] = 'H';
	USETW(sc->sc_ncm.hdr.wHeaderLength, sizeof(sc->sc_ncm.hdr));
	USETW(sc->sc_ncm.hdr.wBlockLength, offset);
	USETW(sc->sc_ncm.hdr.wSequence, sc->sc_ncm.tx_seq);
	USETW(sc->sc_ncm.hdr.wDptIndex, sizeof(sc->sc_ncm.hdr));

	sc->sc_ncm.tx_seq++;

	/* Fill out 16-bit frame table header */
	sc->sc_ncm.dpt.dwSignature[0] = 'N';
	sc->sc_ncm.dpt.dwSignature[1] = 'C';
	sc->sc_ncm.dpt.dwSignature[2] = 'M';
	sc->sc_ncm.dpt.dwSignature[3] = '0';
	USETW(sc->sc_ncm.dpt.wNextNdpIndex, 0);		/* reserved */

	usbd_copy_in(pc, 0, &(sc->sc_ncm.hdr), sizeof(sc->sc_ncm.hdr));
	usbd_copy_in(pc, sizeof(sc->sc_ncm.hdr), &(sc->sc_ncm.dpt),
	    sizeof(sc->sc_ncm.dpt));
	usbd_copy_in(pc, sizeof(sc->sc_ncm.hdr) + sizeof(sc->sc_ncm.dpt),
	    &(sc->sc_ncm.dp), sizeof(sc->sc_ncm.dp));
	return (retval);
}
예제 #9
0
/*------------------------------------------------------------------------*
 *	ucom_get_data
 *
 * Return values:
 * 0: No data is available.
 * Else: Data is available.
 *------------------------------------------------------------------------*/
uint8_t
ucom_get_data(struct ucom_softc *sc, struct usb_page_cache *pc,
    uint32_t offset, uint32_t len, uint32_t *actlen)
{
	struct usb_page_search res;
	struct tty *tp = sc->sc_tty;
	uint32_t cnt;
	uint32_t offset_orig;

	UCOM_MTX_ASSERT(sc, MA_OWNED);

	if (sc->sc_flag & UCOM_FLAG_CONSOLE) {
		unsigned int temp;

		/* get total TX length */

		temp = ucom_cons_tx_high - ucom_cons_tx_low;
		temp %= UCOM_CONS_BUFSIZE;

		/* limit TX length */

		if (temp > (UCOM_CONS_BUFSIZE - ucom_cons_tx_low))
			temp = (UCOM_CONS_BUFSIZE - ucom_cons_tx_low);

		if (temp > len)
			temp = len;

		/* copy in data */

		usbd_copy_in(pc, offset, ucom_cons_tx_buf + ucom_cons_tx_low, temp);

		/* update counters */

		ucom_cons_tx_low += temp;
		ucom_cons_tx_low %= UCOM_CONS_BUFSIZE;

		/* store actual length */

		*actlen = temp;

		return (temp ? 1 : 0);
	}

	if (tty_gone(tp) ||
	    !(sc->sc_flag & UCOM_FLAG_GP_DATA)) {
		actlen[0] = 0;
		return (0);		/* multiport device polling */
	}
	offset_orig = offset;

	while (len != 0) {

		usbd_get_page(pc, offset, &res);

		if (res.length > len) {
			res.length = len;
		}
		/* copy data directly into USB buffer */
		cnt = ttydisc_getc(tp, res.buffer, res.length);

		offset += cnt;
		len -= cnt;

		if (cnt < res.length) {
			/* end of buffer */
			break;
		}
	}

	actlen[0] = offset - offset_orig;

	DPRINTF("cnt=%d\n", actlen[0]);

	if (actlen[0] == 0) {
		return (0);
	}
	return (1);
}
예제 #10
0
파일: subr_usbd.c 프로젝트: 2asoft/freebsd
static void
usbd_ctrl_callback(struct usb_xfer *xfer, usb_error_t error)
{
	irp *ip;
	struct ndis_softc *sc = usbd_xfer_softc(xfer);
	struct ndisusb_ep *ne = usbd_xfer_get_priv(xfer);
	struct ndisusb_xfer *nx;
	uint8_t irql;
	union usbd_urb *urb;
	struct usbd_urb_vendor_or_class_request *vcreq;
	struct usb_page_cache *pc;
	uint8_t type = 0;
	struct usb_device_request req;
	int len;

	switch (USB_GET_STATE(xfer)) {
	case USB_ST_TRANSFERRED:
		nx = usbd_aq_getfirst(sc, ne);
		if (nx == NULL)
			return;

		ip = nx->nx_priv;
		urb = usbd_geturb(ip);
		vcreq = &urb->uu_vcreq;

		if (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) {
			pc = usbd_xfer_get_frame(xfer, 1);
			len = usbd_xfer_frame_len(xfer, 1);
			usbd_copy_out(pc, 0, vcreq->uvc_trans_buf, len);
			nx->nx_urbactlen += len;
		}

		usbd_xfer_complete(sc, ne, nx, USB_ERR_NORMAL_COMPLETION);
		/* fall through */
	case USB_ST_SETUP:
next:
		/* get next transfer */
		KeAcquireSpinLock(&ne->ne_lock, &irql);
		if (IsListEmpty(&ne->ne_pending)) {
			KeReleaseSpinLock(&ne->ne_lock, irql);
			return;
		}
		nx = CONTAINING_RECORD(ne->ne_pending.nle_flink,
		    struct ndisusb_xfer, nx_next);
		RemoveEntryList(&nx->nx_next);
		/* add a entry to the active queue's tail.  */
		InsertTailList((&ne->ne_active), (&nx->nx_next));
		KeReleaseSpinLock(&ne->ne_lock, irql);

		ip = nx->nx_priv;
		urb = usbd_geturb(ip);
		vcreq = &urb->uu_vcreq;

		switch (urb->uu_hdr.uuh_func) {
		case URB_FUNCTION_CLASS_DEVICE:
			type = UT_CLASS | UT_DEVICE;
			break;
		case URB_FUNCTION_CLASS_INTERFACE:
			type = UT_CLASS | UT_INTERFACE;
			break;
		case URB_FUNCTION_CLASS_OTHER:
			type = UT_CLASS | UT_OTHER;
			break;
		case URB_FUNCTION_CLASS_ENDPOINT:
			type = UT_CLASS | UT_ENDPOINT;
			break;
		case URB_FUNCTION_VENDOR_DEVICE:
			type = UT_VENDOR | UT_DEVICE;
			break;
		case URB_FUNCTION_VENDOR_INTERFACE:
			type = UT_VENDOR | UT_INTERFACE;
			break;
		case URB_FUNCTION_VENDOR_OTHER:
			type = UT_VENDOR | UT_OTHER;
			break;
		case URB_FUNCTION_VENDOR_ENDPOINT:
			type = UT_VENDOR | UT_ENDPOINT;
			break;
		default:
			/* never reached.  */
			break;
		}

		type |= (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) ?
		    UT_READ : UT_WRITE;
		type |= vcreq->uvc_reserved1;

		req.bmRequestType = type;
		req.bRequest = vcreq->uvc_req;
		USETW(req.wIndex, vcreq->uvc_idx);
		USETW(req.wValue, vcreq->uvc_value);
		USETW(req.wLength, vcreq->uvc_trans_buflen);

		nx->nx_urbbuf		= vcreq->uvc_trans_buf;
		nx->nx_urblen		= vcreq->uvc_trans_buflen;
		nx->nx_urbactlen	= 0;

		pc = usbd_xfer_get_frame(xfer, 0);
		usbd_copy_in(pc, 0, &req, sizeof(req));
		usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
		usbd_xfer_set_frames(xfer, 1);
		if (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) {
			if (vcreq->uvc_trans_buflen >= USBD_CTRL_READ_BUFFER_SP)
				device_printf(sc->ndis_dev,
				    "warning: not enough buffer space (%d).\n",
				    vcreq->uvc_trans_buflen);
			usbd_xfer_set_frame_len(xfer, 1,
			    MIN(usbd_xfer_max_len(xfer),
				    vcreq->uvc_trans_buflen));
			usbd_xfer_set_frames(xfer, 2);
		} else {
			if (nx->nx_urblen > USBD_CTRL_WRITE_BUFFER_SP)
				device_printf(sc->ndis_dev,
				    "warning: not enough write buffer space"
				    " (%d).\n", nx->nx_urblen);
			/*
			 * XXX with my local tests there was no cases to require
			 * a extra buffer until now but it'd need to update in
			 * the future if it needs to be.
			 */
			if (nx->nx_urblen > 0) {
				pc = usbd_xfer_get_frame(xfer, 1);
				usbd_copy_in(pc, 0, nx->nx_urbbuf,
				    nx->nx_urblen);
				usbd_xfer_set_frame_len(xfer, 1, nx->nx_urblen);
				usbd_xfer_set_frames(xfer, 2);
			}
		}
		usbd_transfer_submit(xfer);
		break;
	default:
		nx = usbd_aq_getfirst(sc, ne);
		if (nx == NULL)
			return;
		if (error != USB_ERR_CANCELLED) {
			usbd_xfer_set_stall(xfer);
			device_printf(sc->ndis_dev, "usb xfer warning (%s)\n",
			    usbd_errstr(error));
		}
		usbd_xfer_complete(sc, ne, nx, error);
		if (error != USB_ERR_CANCELLED)
			goto next;
		break;
	}
}
예제 #11
0
파일: subr_usbd.c 프로젝트: 2asoft/freebsd
static void
usbd_non_isoc_callback(struct usb_xfer *xfer, usb_error_t error)
{
	irp *ip;
	struct ndis_softc *sc = usbd_xfer_softc(xfer);
	struct ndisusb_ep *ne = usbd_xfer_get_priv(xfer);
	struct ndisusb_xfer *nx;
	struct usbd_urb_bulk_or_intr_transfer *ubi;
	struct usb_page_cache *pc;
	uint8_t irql;
	uint32_t len;
	union usbd_urb *urb;
	usb_endpoint_descriptor_t *ep;
	int actlen, sumlen;

	usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL);

	switch (USB_GET_STATE(xfer)) {
	case USB_ST_TRANSFERRED:
		nx = usbd_aq_getfirst(sc, ne);
		pc = usbd_xfer_get_frame(xfer, 0);
		if (nx == NULL)
			return;

		/* copy in data with regard to the URB */
		if (ne->ne_dirin != 0)
			usbd_copy_out(pc, 0, nx->nx_urbbuf, actlen);
		nx->nx_urbbuf += actlen;
		nx->nx_urbactlen += actlen;
		nx->nx_urblen -= actlen;

		/* check for short transfer */
		if (actlen < sumlen)
			nx->nx_urblen = 0;
		else {
			/* check remainder */
			if (nx->nx_urblen > 0) {
				KeAcquireSpinLock(&ne->ne_lock, &irql);
				InsertHeadList((&ne->ne_active), (&nx->nx_next));
				KeReleaseSpinLock(&ne->ne_lock, irql);

				ip = nx->nx_priv;
				urb = usbd_geturb(ip);
				ubi = &urb->uu_bulkintr;
				ep = ubi->ubi_epdesc;
				goto extra;
			}
		}
		usbd_xfer_complete(sc, ne, nx,
		    ((actlen < sumlen) && (nx->nx_shortxfer == 0)) ?
		    USB_ERR_SHORT_XFER : USB_ERR_NORMAL_COMPLETION);

		/* fall through */
	case USB_ST_SETUP:
next:
		/* get next transfer */
		KeAcquireSpinLock(&ne->ne_lock, &irql);
		if (IsListEmpty(&ne->ne_pending)) {
			KeReleaseSpinLock(&ne->ne_lock, irql);
			return;
		}
		nx = CONTAINING_RECORD(ne->ne_pending.nle_flink,
		    struct ndisusb_xfer, nx_next);
		RemoveEntryList(&nx->nx_next);
		/* add a entry to the active queue's tail.  */
		InsertTailList((&ne->ne_active), (&nx->nx_next));
		KeReleaseSpinLock(&ne->ne_lock, irql);

		ip = nx->nx_priv;
		urb = usbd_geturb(ip);
		ubi = &urb->uu_bulkintr;
		ep = ubi->ubi_epdesc;

		nx->nx_urbbuf		= ubi->ubi_trans_buf;
		nx->nx_urbactlen	= 0;
		nx->nx_urblen		= ubi->ubi_trans_buflen;
		nx->nx_shortxfer	= (ubi->ubi_trans_flags &
		    USBD_SHORT_TRANSFER_OK) ? 1 : 0;
extra:
		len = MIN(usbd_xfer_max_len(xfer), nx->nx_urblen);
		pc = usbd_xfer_get_frame(xfer, 0);
		if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_OUT)
			usbd_copy_in(pc, 0, nx->nx_urbbuf, len);
		usbd_xfer_set_frame_len(xfer, 0, len);
		usbd_xfer_set_frames(xfer, 1);
		usbd_transfer_submit(xfer);
		break;
	default:
		nx = usbd_aq_getfirst(sc, ne);
		if (nx == NULL)
			return;
		if (error != USB_ERR_CANCELLED) {
			usbd_xfer_set_stall(xfer);
			device_printf(sc->ndis_dev, "usb xfer warning (%s)\n",
			    usbd_errstr(error));
		}
		usbd_xfer_complete(sc, ne, nx, error);
		if (error != USB_ERR_CANCELLED)
			goto next;
		break;
	}
}
예제 #12
0
파일: ng_ubt.c 프로젝트: 2asoft/freebsd
static void
ubt_ctrl_write_callback(struct usb_xfer *xfer, usb_error_t error)
{
	struct ubt_softc		*sc = usbd_xfer_softc(xfer);
	struct usb_device_request	req;
	struct mbuf			*m;
	struct usb_page_cache		*pc;
	int				actlen;

	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);

	switch (USB_GET_STATE(xfer)) {
	case USB_ST_TRANSFERRED:
		UBT_INFO(sc, "sent %d bytes to control pipe\n", actlen);
		UBT_STAT_BYTES_SENT(sc, actlen);
		UBT_STAT_PCKTS_SENT(sc);
		/* FALLTHROUGH */

	case USB_ST_SETUP:
send_next:
		/* Get next command mbuf, if any */
		UBT_NG_LOCK(sc);
		NG_BT_MBUFQ_DEQUEUE(&sc->sc_cmdq, m);
		UBT_NG_UNLOCK(sc);

		if (m == NULL) {
			UBT_INFO(sc, "HCI command queue is empty\n");
			break;	/* transfer complete */
		}

		/* Initialize a USB control request and then schedule it */
		bzero(&req, sizeof(req));
		req.bmRequestType = UBT_HCI_REQUEST;
		USETW(req.wLength, m->m_pkthdr.len);

		UBT_INFO(sc, "Sending control request, " \
			"bmRequestType=0x%02x, wLength=%d\n",
			req.bmRequestType, UGETW(req.wLength));

		pc = usbd_xfer_get_frame(xfer, 0);
		usbd_copy_in(pc, 0, &req, sizeof(req));
		pc = usbd_xfer_get_frame(xfer, 1);
		usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len);

		usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
		usbd_xfer_set_frame_len(xfer, 1, m->m_pkthdr.len);
		usbd_xfer_set_frames(xfer, 2);

		NG_FREE_M(m);

		usbd_transfer_submit(xfer);
		break;

	default: /* Error */
		if (error != USB_ERR_CANCELLED) {
			UBT_WARN(sc, "control transfer failed: %s\n",
				usbd_errstr(error));

			UBT_STAT_OERROR(sc);
			goto send_next;
		}

		/* transfer cancelled */
		break;
	}
} /* ubt_ctrl_write_callback */
예제 #13
0
/*------------------------------------------------------------------------*
 *	usbd_do_request_flags and usbd_do_request
 *
 * Description of arguments passed to these functions:
 *
 * "udev" - this is the "usb_device" structure pointer on which the
 * request should be performed. It is possible to call this function
 * in both Host Side mode and Device Side mode.
 *
 * "mtx" - if this argument is non-NULL the mutex pointed to by it
 * will get dropped and picked up during the execution of this
 * function, hence this function sometimes needs to sleep. If this
 * argument is NULL it has no effect.
 *
 * "req" - this argument must always be non-NULL and points to an
 * 8-byte structure holding the USB request to be done. The USB
 * request structure has a bit telling the direction of the USB
 * request, if it is a read or a write.
 *
 * "data" - if the "wLength" part of the structure pointed to by "req"
 * is non-zero this argument must point to a valid kernel buffer which
 * can hold at least "wLength" bytes. If "wLength" is zero "data" can
 * be NULL.
 *
 * "flags" - here is a list of valid flags:
 *
 *  o USB_SHORT_XFER_OK: allows the data transfer to be shorter than
 *  specified
 *
 *  o USB_DELAY_STATUS_STAGE: allows the status stage to be performed
 *  at a later point in time. This is tunable by the "hw.usb.ss_delay"
 *  sysctl. This flag is mostly useful for debugging.
 *
 *  o USB_USER_DATA_PTR: treat the "data" pointer like a userland
 *  pointer.
 *
 * "actlen" - if non-NULL the actual transfer length will be stored in
 * the 16-bit unsigned integer pointed to by "actlen". This
 * information is mostly useful when the "USB_SHORT_XFER_OK" flag is
 * used.
 *
 * "timeout" - gives the timeout for the control transfer in
 * milliseconds. A "timeout" value less than 50 milliseconds is
 * treated like a 50 millisecond timeout. A "timeout" value greater
 * than 30 seconds is treated like a 30 second timeout. This USB stack
 * does not allow control requests without a timeout.
 *
 * NOTE: This function is thread safe. All calls to
 * "usbd_do_request_flags" will be serialised by the use of an
 * internal "sx_lock".
 *
 * Returns:
 *    0: Success
 * Else: Failure
 *------------------------------------------------------------------------*/
usb_error_t
usbd_do_request_flags(struct usb_device *udev, struct mtx *mtx,
    struct usb_device_request *req, void *data, uint16_t flags,
    uint16_t *actlen, usb_timeout_t timeout)
{
	usb_handle_req_t *hr_func;
	struct usb_xfer *xfer;
	const void *desc;
	int err = 0;
	usb_ticks_t start_ticks;
	usb_ticks_t delta_ticks;
	usb_ticks_t max_ticks;
	uint16_t length;
	uint16_t temp;

	if (timeout < 50) {
		/* timeout is too small */
		timeout = 50;
	}
	if (timeout > 30000) {
		/* timeout is too big */
		timeout = 30000;
	}
	length = UGETW(req->wLength);

	DPRINTFN(5, "udev=%p bmRequestType=0x%02x bRequest=0x%02x "
	    "wValue=0x%02x%02x wIndex=0x%02x%02x wLength=0x%02x%02x\n",
	    udev, req->bmRequestType, req->bRequest,
	    req->wValue[1], req->wValue[0],
	    req->wIndex[1], req->wIndex[0],
	    req->wLength[1], req->wLength[0]);

	/* Check if the device is still alive */
	if (udev->state < USB_STATE_POWERED) {
		DPRINTF("usb device has gone\n");
		return (USB_ERR_NOT_CONFIGURED);
	}

	/*
	 * Set "actlen" to a known value in case the caller does not
	 * check the return value:
	 */
	if (actlen)
		*actlen = 0;

#if (USB_HAVE_USER_IO == 0)
	if (flags & USB_USER_DATA_PTR)
		return (USB_ERR_INVAL);
#endif
	if (mtx) {
		mtx_unlock(mtx);
		if (mtx != &Giant) {
			mtx_assert(mtx, MA_NOTOWNED);
		}
	}
	/*
	 * Grab the default sx-lock so that serialisation
	 * is achieved when multiple threads are involved:
	 */

	sx_xlock(udev->default_sx);

	hr_func = usbd_get_hr_func(udev);

	if (hr_func != NULL) {
		DPRINTF("Handle Request function is set\n");

		desc = NULL;
		temp = 0;

		if (!(req->bmRequestType & UT_READ)) {
			if (length != 0) {
				DPRINTFN(1, "The handle request function "
				    "does not support writing data!\n");
				err = USB_ERR_INVAL;
				goto done;
			}
		}

		/* The root HUB code needs the BUS lock locked */

		USB_BUS_LOCK(udev->bus);
		err = (hr_func) (udev, req, &desc, &temp);
		USB_BUS_UNLOCK(udev->bus);

		if (err)
			goto done;

		if (length > temp) {
			if (!(flags & USB_SHORT_XFER_OK)) {
				err = USB_ERR_SHORT_XFER;
				goto done;
			}
			length = temp;
		}
		if (actlen)
			*actlen = length;

		if (length > 0) {
#if USB_HAVE_USER_IO
			if (flags & USB_USER_DATA_PTR) {
				if (copyout(desc, data, length)) {
					err = USB_ERR_INVAL;
					goto done;
				}
			} else
#endif
				bcopy(desc, data, length);
		}
		goto done;		/* success */
	}

	/*
	 * Setup a new USB transfer or use the existing one, if any:
	 */
	usbd_default_transfer_setup(udev);

	xfer = udev->default_xfer[0];
	if (xfer == NULL) {
		/* most likely out of memory */
		err = USB_ERR_NOMEM;
		goto done;
	}
	USB_XFER_LOCK(xfer);

	if (flags & USB_DELAY_STATUS_STAGE)
		xfer->flags.manual_status = 1;
	else
		xfer->flags.manual_status = 0;

	if (flags & USB_SHORT_XFER_OK)
		xfer->flags.short_xfer_ok = 1;
	else
		xfer->flags.short_xfer_ok = 0;

	xfer->timeout = timeout;

	start_ticks = ticks;

	max_ticks = USB_MS_TO_TICKS(timeout);

	usbd_copy_in(xfer->frbuffers, 0, req, sizeof(*req));

	usbd_xfer_set_frame_len(xfer, 0, sizeof(*req));
	xfer->nframes = 2;

	while (1) {
		temp = length;
		if (temp > xfer->max_data_length) {
			temp = usbd_xfer_max_len(xfer);
		}
		usbd_xfer_set_frame_len(xfer, 1, temp);

		if (temp > 0) {
			if (!(req->bmRequestType & UT_READ)) {
#if USB_HAVE_USER_IO
				if (flags & USB_USER_DATA_PTR) {
					USB_XFER_UNLOCK(xfer);
					err = usbd_copy_in_user(xfer->frbuffers + 1,
					    0, data, temp);
					USB_XFER_LOCK(xfer);
					if (err) {
						err = USB_ERR_INVAL;
						break;
					}
				} else
#endif
					usbd_copy_in(xfer->frbuffers + 1,
					    0, data, temp);
			}
			xfer->nframes = 2;
		} else {
			if (xfer->frlengths[0] == 0) {
				if (xfer->flags.manual_status) {
#if USB_DEBUG
					int temp;

					temp = usb_ss_delay;
					if (temp > 5000) {
						temp = 5000;
					}
					if (temp > 0) {
						usb_pause_mtx(
						    xfer->xroot->xfer_mtx,
						    USB_MS_TO_TICKS(temp));
					}
#endif
					xfer->flags.manual_status = 0;
				} else {
					break;
				}
			}
			xfer->nframes = 1;
		}

		usbd_transfer_start(xfer);

		while (usbd_transfer_pending(xfer)) {
			cv_wait(udev->default_cv,
			    xfer->xroot->xfer_mtx);
		}

		err = xfer->error;

		if (err) {
			break;
		}
		/* subtract length of SETUP packet, if any */

		if (xfer->aframes > 0) {
			xfer->actlen -= xfer->frlengths[0];
		} else {
			xfer->actlen = 0;
		}

		/* check for short packet */

		if (temp > xfer->actlen) {
			temp = xfer->actlen;
			length = temp;
		}
		if (temp > 0) {
			if (req->bmRequestType & UT_READ) {
#if USB_HAVE_USER_IO
				if (flags & USB_USER_DATA_PTR) {
					USB_XFER_UNLOCK(xfer);
					err = usbd_copy_out_user(xfer->frbuffers + 1,
					    0, data, temp);
					USB_XFER_LOCK(xfer);
					if (err) {
						err = USB_ERR_INVAL;
						break;
					}
				} else
#endif
					usbd_copy_out(xfer->frbuffers + 1,
					    0, data, temp);
			}
		}
		/*
		 * Clear "frlengths[0]" so that we don't send the setup
		 * packet again:
		 */
		usbd_xfer_set_frame_len(xfer, 0, 0);

		/* update length and data pointer */
		length -= temp;
		data = USB_ADD_BYTES(data, temp);

		if (actlen) {
			(*actlen) += temp;
		}
		/* check for timeout */

		delta_ticks = ticks - start_ticks;
		if (delta_ticks > max_ticks) {
			if (!err) {
				err = USB_ERR_TIMEOUT;
			}
		}
		if (err) {
			break;
		}
	}

	if (err) {
		/*
		 * Make sure that the control endpoint is no longer
		 * blocked in case of a non-transfer related error:
		 */
		usbd_transfer_stop(xfer);
	}
	USB_XFER_UNLOCK(xfer);

done:
	sx_xunlock(udev->default_sx);

	if (mtx) {
		mtx_lock(mtx);
	}
	return ((usb_error_t)err);
}
예제 #14
0
/*------------------------------------------------------------------------*
 *	usb_do_clear_stall_callback
 *
 * This function is the USB callback for generic clear stall requests.
 *------------------------------------------------------------------------*/
void
usb_do_clear_stall_callback(struct usb_xfer *xfer, usb_error_t error)
{
	struct usb_device_request req;
	struct usb_device *udev;
	struct usb_endpoint *ep;
	struct usb_endpoint *ep_end;
	struct usb_endpoint *ep_first;
	uint8_t to;

	udev = xfer->xroot->udev;

	USB_BUS_LOCK(udev->bus);

	/* round robin endpoint clear stall */

	ep = udev->ep_curr;
	ep_end = udev->endpoints + udev->endpoints_max;
	ep_first = udev->endpoints;
	to = udev->endpoints_max;

	switch (USB_GET_STATE(xfer)) {
	case USB_ST_TRANSFERRED:
		if (ep == NULL)
			goto tr_setup;		/* device was unconfigured */
		if (ep->edesc &&
		    ep->is_stalled) {
			ep->toggle_next = 0;
			ep->is_stalled = 0;
			/* start up the current or next transfer, if any */
			usb_command_wrapper(&ep->endpoint_q,
			    ep->endpoint_q.curr);
		}
		ep++;

	case USB_ST_SETUP:
tr_setup:
		if (to == 0)
			break;			/* no endpoints - nothing to do */
		if ((ep < ep_first) || (ep >= ep_end))
			ep = ep_first;	/* endpoint wrapped around */
		if (ep->edesc &&
		    ep->is_stalled) {

			/* setup a clear-stall packet */

			req.bmRequestType = UT_WRITE_ENDPOINT;
			req.bRequest = UR_CLEAR_FEATURE;
			USETW(req.wValue, UF_ENDPOINT_HALT);
			req.wIndex[0] = ep->edesc->bEndpointAddress;
			req.wIndex[1] = 0;
			USETW(req.wLength, 0);

			/* copy in the transfer */

			usbd_copy_in(xfer->frbuffers, 0, &req, sizeof(req));

			/* set length */
			usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
			xfer->nframes = 1;
			USB_BUS_UNLOCK(udev->bus);

			usbd_transfer_submit(xfer);

			USB_BUS_LOCK(udev->bus);
			break;
		}
		ep++;
		to--;
		goto tr_setup;

	default:
		if (xfer->error == USB_ERR_CANCELLED) {
			break;
		}
		goto tr_setup;
	}

	/* store current endpoint */
	udev->ep_curr = ep;
	USB_BUS_UNLOCK(udev->bus);
}
예제 #15
0
파일: if_cdce.c 프로젝트: hbsciw/freebsd
static void
cdce_intr_write_callback(struct usb_xfer *xfer, usb_error_t error)
{
	struct cdce_softc *sc = usbd_xfer_softc(xfer);
	struct usb_cdc_notification req;
	struct usb_page_cache *pc;
	uint32_t speed;
	int actlen;

	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);

	switch (USB_GET_STATE(xfer)) {
	case USB_ST_TRANSFERRED:

		DPRINTF("Transferred %d bytes\n", actlen);

		switch (sc->sc_notify_state) {
		case CDCE_NOTIFY_NETWORK_CONNECTION:
			sc->sc_notify_state = CDCE_NOTIFY_SPEED_CHANGE;
			break;
		case CDCE_NOTIFY_SPEED_CHANGE:
			sc->sc_notify_state = CDCE_NOTIFY_DONE;
			break;
		default:
			break;
		}

		/* FALLTHROUGH */
	case USB_ST_SETUP:
tr_setup:
		/*
		 * Inform host about connection. Required according to USB CDC
		 * specification and communicating to Mac OS X USB host stack.
		 * Some of the values seems ignored by Mac OS X though.
		 */
		if (sc->sc_notify_state == CDCE_NOTIFY_NETWORK_CONNECTION) {
			req.bmRequestType = UCDC_NOTIFICATION;
			req.bNotification = UCDC_N_NETWORK_CONNECTION;
			req.wIndex[0] = sc->sc_ifaces_index[1];
			req.wIndex[1] = 0;
			USETW(req.wValue, 1); /* Connected */
			USETW(req.wLength, 0);

			pc = usbd_xfer_get_frame(xfer, 0);
			usbd_copy_in(pc, 0, &req, sizeof(req));
			usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
			usbd_xfer_set_frames(xfer, 1);
			usbd_transfer_submit(xfer); 

		} else if (sc->sc_notify_state == CDCE_NOTIFY_SPEED_CHANGE) {
			req.bmRequestType = UCDC_NOTIFICATION;
			req.bNotification = UCDC_N_CONNECTION_SPEED_CHANGE;
			req.wIndex[0] = sc->sc_ifaces_index[1];
			req.wIndex[1] = 0;
			USETW(req.wValue, 0);
			USETW(req.wLength, 8);

			/* Peak theoretical bulk trasfer rate in bits/s */
			if (usbd_get_speed(sc->sc_ue.ue_udev) != USB_SPEED_FULL)
				speed = (13 * 512 * 8 * 1000 * 8);
			else
				speed = (19 * 64 * 1 * 1000 * 8);

			USETDW(req.data + 0, speed); /* Upstream bit rate */
			USETDW(req.data + 4, speed); /* Downstream bit rate */
 
			pc = usbd_xfer_get_frame(xfer, 0);
			usbd_copy_in(pc, 0, &req, sizeof(req));
			usbd_xfer_set_frame_len(xfer, 0, sizeof(req));
			usbd_xfer_set_frames(xfer, 1);
			usbd_transfer_submit(xfer); 
		}
		break;

	default:			/* Error */
		if (error != USB_ERR_CANCELLED) {
			if (usbd_get_mode(sc->sc_ue.ue_udev) == USB_MODE_HOST) {
				/* start clear stall */
				usbd_xfer_set_stall(xfer);
			}
			goto tr_setup;
		}
		break;
	}
}