示例#1
0
static void
usie_uc_tx_callback(struct usb_xfer *xfer, usb_error_t error)
{
	struct ucom_softc *ucom = usbd_xfer_softc(xfer);
	struct usb_page_cache *pc;
	uint32_t actlen;

	switch (USB_GET_STATE(xfer)) {
	case USB_ST_TRANSFERRED:
	case USB_ST_SETUP:
tr_setup:
		pc = usbd_xfer_get_frame(xfer, 0);

		/* handle CnS request */
		struct mbuf *m = usbd_xfer_get_priv(xfer);

		if (m != NULL) {
			usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len);
			usbd_xfer_set_frame_len(xfer, 0, m->m_pkthdr.len);
			usbd_xfer_set_priv(xfer, NULL);
			usbd_transfer_submit(xfer);
			m_freem(m);
			break;
		}
		/* standard ucom transfer */
		if (ucom_get_data(ucom, pc, 0, USIE_BUFSIZE, &actlen)) {
			usbd_xfer_set_frame_len(xfer, 0, actlen);
			usbd_transfer_submit(xfer);
		}
		break;

	default:			/* Error */
		if (error != USB_ERR_CANCELLED) {
			usbd_xfer_set_stall(xfer);
			goto tr_setup;
		}
		break;
	}
}
示例#2
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;
	}
}
示例#3
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);
}
示例#4
0
static void
ipheth_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
{
	struct ipheth_softc *sc = usbd_xfer_softc(xfer);
	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
	struct usb_page_cache *pc;
	struct mbuf *m;
	uint8_t x;
	int actlen;
	int aframes;

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

	DPRINTFN(1, "\n");

	switch (USB_GET_STATE(xfer)) {
	case USB_ST_TRANSFERRED:
		DPRINTFN(11, "transfer complete: %u bytes in %u frames\n",
		    actlen, aframes);

		ifp->if_opackets++;

		/* free all previous TX buffers */
		ipheth_free_queue(sc->sc_tx_buf, IPHETH_TX_FRAMES_MAX);

		/* FALLTHROUGH */
	case USB_ST_SETUP:
tr_setup:
		for (x = 0; x != IPHETH_TX_FRAMES_MAX; x++) {

			IFQ_DRV_DEQUEUE(&ifp->if_snd, m);

			if (m == NULL)
				break;

			usbd_xfer_set_frame_offset(xfer,
			    x * IPHETH_BUF_SIZE, x);

			pc = usbd_xfer_get_frame(xfer, x);

			sc->sc_tx_buf[x] = m;

			if (m->m_pkthdr.len > IPHETH_BUF_SIZE)
				m->m_pkthdr.len = IPHETH_BUF_SIZE;

			usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len);

			usbd_xfer_set_frame_len(xfer, x, IPHETH_BUF_SIZE);

			if (IPHETH_BUF_SIZE != m->m_pkthdr.len) {
				usbd_frame_zero(pc, m->m_pkthdr.len,
					IPHETH_BUF_SIZE - m->m_pkthdr.len);
			}

			/*
			 * If there's a BPF listener, bounce a copy of
			 * this frame to him:
			 */
			BPF_MTAP(ifp, m);
		}
		if (x != 0) {
			usbd_xfer_set_frames(xfer, x);

			usbd_transfer_submit(xfer);
		}
		break;

	default:			/* Error */
		DPRINTFN(11, "transfer error, %s\n",
		    usbd_errstr(error));

		/* free all previous TX buffers */
		ipheth_free_queue(sc->sc_tx_buf, IPHETH_TX_FRAMES_MAX);

		/* count output errors */
		ifp->if_oerrors++;

		if (error != USB_ERR_CANCELLED) {
			/* try to clear stall first */
			usbd_xfer_set_stall(xfer);
			goto tr_setup;
		}
		break;
	}
}
示例#5
0
文件: ng_ubt.c 项目: 2asoft/freebsd
static void
ubt_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
{
	struct ubt_softc	*sc = usbd_xfer_softc(xfer);
	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 bulk-out pipe\n", actlen);
		UBT_STAT_BYTES_SENT(sc, actlen);
		UBT_STAT_PCKTS_SENT(sc);
		/* FALLTHROUGH */

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

		if (m == NULL) {
			UBT_INFO(sc, "ACL data queue is empty\n");
			break; /* transfer completed */
		}

		/*
		 * Copy ACL data frame back to a linear USB transfer buffer
		 * and schedule transfer
		 */

		pc = usbd_xfer_get_frame(xfer, 0);
		usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len);
		usbd_xfer_set_frame_len(xfer, 0, m->m_pkthdr.len);

		UBT_INFO(sc, "bulk-out transfer has been started, len=%d\n",
			m->m_pkthdr.len);

		NG_FREE_M(m);

		usbd_transfer_submit(xfer);
		break;

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

			UBT_STAT_OERROR(sc);

			/* try to clear stall first */
			usbd_xfer_set_stall(xfer);
			goto send_next;
		}
			/* transfer cancelled */
		break;
	}
} /* ubt_bulk_write_callback */
示例#6
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 */
示例#7
0
文件: ng_ubt.c 项目: 2asoft/freebsd
static void
ubt_isoc_write_callback(struct usb_xfer *xfer, usb_error_t error)
{
	struct ubt_softc	*sc = usbd_xfer_softc(xfer);
	struct usb_page_cache	*pc;
	struct mbuf		*m;
	int			n, space, offset;
	int			actlen, nframes;

	usbd_xfer_status(xfer, &actlen, NULL, NULL, &nframes);
	pc = usbd_xfer_get_frame(xfer, 0);

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

	case USB_ST_SETUP:
send_next:
		offset = 0;
		space = usbd_xfer_max_framelen(xfer) * nframes;
		m = NULL;

		while (space > 0) {
			if (m == NULL) {
				UBT_NG_LOCK(sc);
				NG_BT_MBUFQ_DEQUEUE(&sc->sc_scoq, m);
				UBT_NG_UNLOCK(sc);

				if (m == NULL)
					break;
			}

			n = min(space, m->m_pkthdr.len);
			if (n > 0) {
				usbd_m_copy_in(pc, offset, m,0, n);
				m_adj(m, n);

				offset += n;
				space -= n;
			}

			if (m->m_pkthdr.len == 0)
				NG_FREE_M(m); /* sets m = NULL */
		}

		/* Put whatever is left from mbuf back on queue */
		if (m != NULL) {
			UBT_NG_LOCK(sc);
			NG_BT_MBUFQ_PREPEND(&sc->sc_scoq, m);
			UBT_NG_UNLOCK(sc);
		}

		/*
		 * Calculate sizes for isoc frames.
		 * Note that offset could be 0 at this point (i.e. we have
		 * nothing to send). That is fine, as we have isoc. transfers
		 * going in both directions all the time. In this case it
		 * would be just empty isoc. transfer.
		 */

		for (n = 0; n < nframes; n ++) {
			usbd_xfer_set_frame_len(xfer, n,
			    min(offset, usbd_xfer_max_framelen(xfer)));
			offset -= usbd_xfer_frame_len(xfer, n);
		}

		usbd_transfer_submit(xfer);
		break;

	default: /* Error */
		if (error != USB_ERR_CANCELLED) {
			UBT_STAT_OERROR(sc);
			goto send_next;
		}

		/* transfer cancelled */
		break;
	}
}