Пример #1
0
static void
cdce_init(struct usb_ether *ue)
{
	struct cdce_softc *sc = uether_getsc(ue);
	struct ifnet *ifp = uether_getifp(ue);

	CDCE_LOCK_ASSERT(sc, MA_OWNED);

	ifp->if_drv_flags |= IFF_DRV_RUNNING;

	/* start interrupt transfer */
	usbd_transfer_start(sc->sc_xfer[CDCE_INTR_RX]);
	usbd_transfer_start(sc->sc_xfer[CDCE_INTR_TX]);

	/*
	 * Stall data write direction, which depends on USB mode.
	 *
	 * Some USB host stacks (e.g. Mac OS X) don't clears stall
	 * bit as it should, so set it in our host mode only.
	 */
	if (usbd_get_mode(sc->sc_ue.ue_udev) == USB_MODE_HOST)
		usbd_xfer_set_stall(sc->sc_xfer[CDCE_BULK_TX]);

	/* start data transfers */
	cdce_start(ue);
}
Пример #2
0
int
uether_rxbuf(struct usb_ether *ue, struct usb_page_cache *pc, 
    unsigned int offset, unsigned int len)
{
	struct ifnet *ifp = uether_getifp(ue);
	struct mbuf *m;

	UE_LOCK_ASSERT(ue);

	if (len < ETHER_HDR_LEN || len > MCLBYTES - ETHER_ALIGN)
		return (1);

	m = uether_newbuf();
	if (m == NULL) {
		IFNET_STAT_INC(ifp, iqdrops, 1);
		return (ENOMEM);
	}

	usbd_copy_out(pc, offset, mtod(m, uint8_t *), len);

	/* finalize mbuf */
	IFNET_STAT_INC(ifp, ipackets, 1);
	m->m_pkthdr.rcvif = ifp;
	m->m_pkthdr.len = m->m_len = len;

	/* enqueue for later when the lock can be released */
	IF_ENQUEUE(&ue->ue_rxq, m);
	return (0);
}
Пример #3
0
static void
cdce_ncm_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
{
	struct cdce_softc *sc = usbd_xfer_softc(xfer);
	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
	uint16_t x;
	uint8_t temp;
	int actlen;
	int aframes;

	switch (USB_GET_STATE(xfer)) {
	case USB_ST_TRANSFERRED:

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

		DPRINTFN(10, "transfer complete: "
		    "%u bytes in %u frames\n", actlen, aframes);

	case USB_ST_SETUP:
		for (x = 0; x != CDCE_NCM_TX_FRAMES_MAX; x++) {
			temp = cdce_ncm_fill_tx_frames(xfer, x);
			if (temp == 0)
				break;
			if (temp == 1) {
				x++;
				break;
			}
		}

		if (x != 0) {
#ifdef USB_DEBUG
			usbd_xfer_set_interval(xfer, cdce_tx_interval);
#endif
			usbd_xfer_set_frames(xfer, x);
			usbd_transfer_submit(xfer);
		}
		break;

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

		/* update error counter */
		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);

		if (error != USB_ERR_CANCELLED) {
			if (usbd_get_mode(sc->sc_ue.ue_udev) == USB_MODE_HOST) {
				/* try to clear stall first */
				usbd_xfer_set_stall(xfer);
				usbd_xfer_set_frames(xfer, 0);
				usbd_transfer_submit(xfer);
			}
		}
		break;
	}
}
Пример #4
0
static void
ue_ifmedia_task(struct usb_proc_msg *_task)
{
	struct usb_ether_cfg_task *task =
	    (struct usb_ether_cfg_task *)_task;
	struct usb_ether *ue = task->ue;
	struct ifnet *ifp = uether_getifp(ue);

	ue->ue_methods->ue_mii_upd(ifp);
}
Пример #5
0
static void
ue_tick_task(struct usb_proc_msg *_task)
{
	struct usb_ether_cfg_task *task =
	    (struct usb_ether_cfg_task *)_task;
	struct usb_ether *ue = task->ue;
	struct ifnet *ifp = uether_getifp(ue);

	if ((ifp->if_flags & IFF_RUNNING) == 0)
		return;

	ue->ue_methods->ue_tick(ue);
}
Пример #6
0
static void
ue_watchdog(void *arg)
{
	struct usb_ether *ue = arg;
	struct ifnet *ifp = uether_getifp(ue);

	if ((ifp->if_flags & IFF_RUNNING) == 0)
		return;

	ue_queue_command(ue, ue_tick_task,
	    &ue->ue_tick_task[0].hdr, 
	    &ue->ue_tick_task[1].hdr);

	usb_callout_reset(&ue->ue_watchdog, hz, ue_watchdog, ue);
}
Пример #7
0
static void
ipheth_init(struct usb_ether *ue)
{
	struct ipheth_softc *sc = uether_getsc(ue);
	struct ifnet *ifp = uether_getifp(ue);

	IPHETH_LOCK_ASSERT(sc, MA_OWNED);

	ifp->if_drv_flags |= IFF_DRV_RUNNING;

	/* stall data write direction, which depends on USB mode */
	usbd_xfer_set_stall(sc->sc_xfer[IPHETH_BULK_TX]);

	/* start data transfers */
	ipheth_start(ue);
}
Пример #8
0
int
uether_rxmbuf(struct usb_ether *ue, struct mbuf *m, 
    unsigned int len)
{
	struct ifnet *ifp = uether_getifp(ue);

	UE_LOCK_ASSERT(ue);

	/* finalize mbuf */
	IFNET_STAT_INC(ifp, ipackets, 1);
	m->m_pkthdr.rcvif = ifp;
	m->m_pkthdr.len = m->m_len = len;

	/* enqueue for later when the lock can be released */
	IF_ENQUEUE(&ue->ue_rxq, m);
	return (0);
}
Пример #9
0
static void
cdce_stop(struct usb_ether *ue)
{
	struct cdce_softc *sc = uether_getsc(ue);
	struct ifnet *ifp = uether_getifp(ue);

	CDCE_LOCK_ASSERT(sc, MA_OWNED);

	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;

	/*
	 * stop all the transfers, if not already stopped:
	 */
	usbd_transfer_stop(sc->sc_xfer[CDCE_BULK_RX]);
	usbd_transfer_stop(sc->sc_xfer[CDCE_BULK_TX]);
	usbd_transfer_stop(sc->sc_xfer[CDCE_INTR_RX]);
	usbd_transfer_stop(sc->sc_xfer[CDCE_INTR_TX]);
}
Пример #10
0
static void
ue_start_task(struct usb_proc_msg *_task)
{
	struct usb_ether_cfg_task *task =
	    (struct usb_ether_cfg_task *)_task;
	struct usb_ether *ue = task->ue;
	struct ifnet *ifp = uether_getifp(ue);

	UE_LOCK_ASSERT(ue);

	ue->ue_methods->ue_init(ue);

	if ((ifp->if_flags & IFF_RUNNING) == 0)
		return;

	if (ue->ue_methods->ue_tick != NULL)
		usb_callout_reset(&ue->ue_watchdog, hz, ue_watchdog, ue);
}
Пример #11
0
static void
cdce_init(struct usb_ether *ue)
{
	struct cdce_softc *sc = uether_getsc(ue);
	struct ifnet *ifp = uether_getifp(ue);

	CDCE_LOCK_ASSERT(sc, MA_OWNED);

	ifp->if_drv_flags |= IFF_DRV_RUNNING;

	/* start interrupt transfer */
	usbd_transfer_start(sc->sc_xfer[CDCE_INTR_RX]);
	usbd_transfer_start(sc->sc_xfer[CDCE_INTR_TX]);

	/* stall data write direction, which depends on USB mode */
	usbd_xfer_set_stall(sc->sc_xfer[CDCE_BULK_TX]);

	/* start data transfers */
	cdce_start(ue);
}
Пример #12
0
void
uether_rxflush(struct usb_ether *ue)
{
	struct ifnet *ifp = uether_getifp(ue);
	struct mbuf *m;

	UE_LOCK_ASSERT(ue);

	for (;;) {
		IF_DEQUEUE(&ue->ue_rxq, m);
		if (m == NULL)
			break;

		/*
		 * The USB xfer has been resubmitted so its safe to unlock now.
		 */
		UE_UNLOCK(ue);
		ifp->if_input(ifp, m, NULL, -1);
		UE_LOCK(ue);
	}
}
Пример #13
0
void
uether_ifdetach(struct usb_ether *ue)
{
	struct ifnet *ifp;

	/* wait for any post attach or other command to complete */
	usb_proc_drain(&ue->ue_tq);

	/* read "ifnet" pointer after taskqueue drain */
	ifp = uether_getifp(ue);

	if (ifp != NULL) {

		/* we are not running any more */
		UE_LOCK(ue);
		ifp->if_flags &= ~IFF_RUNNING;
		UE_UNLOCK(ue);

		/* drain any callouts */
		usb_callout_drain(&ue->ue_watchdog);

		/* detach miibus */
		if (ue->ue_miibus != NULL) {
			device_delete_child(ue->ue_dev, ue->ue_miibus);
		}

		/* detach ethernet */
		ether_ifdetach(ifp);

		/* free sysctl */
		sysctl_ctx_free(&ue->ue_sysctl_ctx);

		/* free unit */
		devfs_clone_bitmap_put(&DEVFS_CLONE_BITMAP(ue), ue->ue_unit);
	}

	/* free taskqueue, if any */
	usb_proc_free(&ue->ue_tq);
}
Пример #14
0
static void
cdce_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
{
	struct cdce_softc *sc = usbd_xfer_softc(xfer);
	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
	struct mbuf *m;
	struct mbuf *mt;
	uint32_t crc;
	uint8_t x;
	int actlen, 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 */
		cdce_free_queue(sc->sc_tx_buf, CDCE_FRAMES_MAX);

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

			IFQ_DRV_DEQUEUE(&ifp->if_snd, m);

			if (m == NULL)
				break;

			if (sc->sc_flags & CDCE_FLAG_ZAURUS) {
				/*
				 * Zaurus wants a 32-bit CRC appended
				 * to every frame
				 */

				crc = cdce_m_crc32(m, 0, m->m_pkthdr.len);
				crc = htole32(crc);

				if (!m_append(m, 4, (void *)&crc)) {
					m_freem(m);
					ifp->if_oerrors++;
					continue;
				}
			}
			if (m->m_len != m->m_pkthdr.len) {
				mt = m_defrag(m, M_DONTWAIT);
				if (mt == NULL) {
					m_freem(m);
					ifp->if_oerrors++;
					continue;
				}
				m = mt;
			}
			if (m->m_pkthdr.len > MCLBYTES) {
				m->m_pkthdr.len = MCLBYTES;
			}
			sc->sc_tx_buf[x] = m;
			usbd_xfer_set_frame_data(xfer, x, m->m_data, m->m_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 */
		cdce_free_queue(sc->sc_tx_buf, CDCE_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;
	}
}
Пример #15
0
static void
cdce_ncm_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
{
	struct cdce_softc *sc = usbd_xfer_softc(xfer);
	struct usb_page_cache *pc = usbd_xfer_get_frame(xfer, 0);
	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
	struct mbuf *m;
	int sumdata;
	int sumlen;
	int actlen;
	int aframes;
	int temp;
	int nframes;
	int x;
	int offset;

	switch (USB_GET_STATE(xfer)) {
	case USB_ST_TRANSFERRED:

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

		DPRINTFN(1, "received %u bytes in %u frames\n",
		    actlen, aframes);

		if (actlen < (sizeof(sc->sc_ncm.hdr) +
		    sizeof(sc->sc_ncm.dpt))) {
			DPRINTFN(1, "frame too short\n");
			goto tr_setup;
		}
		usbd_copy_out(pc, 0, &(sc->sc_ncm.hdr),
		    sizeof(sc->sc_ncm.hdr));

		if ((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')) {
			DPRINTFN(1, "invalid HDR signature: "
			    "0x%02x:0x%02x:0x%02x:0x%02x\n",
			    sc->sc_ncm.hdr.dwSignature[0],
			    sc->sc_ncm.hdr.dwSignature[1],
			    sc->sc_ncm.hdr.dwSignature[2],
			    sc->sc_ncm.hdr.dwSignature[3]);
			goto tr_stall;
		}
		temp = UGETW(sc->sc_ncm.hdr.wBlockLength);
		if (temp > sumlen) {
			DPRINTFN(1, "unsupported block length %u/%u\n",
			    temp, sumlen);
			goto tr_stall;
		}
		temp = UGETW(sc->sc_ncm.hdr.wDptIndex);
		if ((temp + sizeof(sc->sc_ncm.dpt)) > actlen) {
			DPRINTFN(1, "invalid DPT index: 0x%04x\n", temp);
			goto tr_stall;
		}
		usbd_copy_out(pc, temp, &(sc->sc_ncm.dpt),
		    sizeof(sc->sc_ncm.dpt));

		if ((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')) {
			DPRINTFN(1, "invalid DPT signature"
			    "0x%02x:0x%02x:0x%02x:0x%02x\n",
			    sc->sc_ncm.dpt.dwSignature[0],
			    sc->sc_ncm.dpt.dwSignature[1],
			    sc->sc_ncm.dpt.dwSignature[2],
			    sc->sc_ncm.dpt.dwSignature[3]);
			goto tr_stall;
		}
		nframes = UGETW(sc->sc_ncm.dpt.wLength) / 4;

		/* Subtract size of header and last zero padded entry */
		if (nframes >= (2 + 1))
			nframes -= (2 + 1);
		else
			nframes = 0;

		DPRINTFN(1, "nframes = %u\n", nframes);

		temp += sizeof(sc->sc_ncm.dpt);

		if ((temp + (4 * nframes)) > actlen)
			goto tr_stall;

		if (nframes > CDCE_NCM_SUBFRAMES_MAX) {
			DPRINTFN(1, "Truncating number of frames from %u to %u\n",
			    nframes, CDCE_NCM_SUBFRAMES_MAX);
			nframes = CDCE_NCM_SUBFRAMES_MAX;
		}
		usbd_copy_out(pc, temp, &(sc->sc_ncm.dp), (4 * nframes));

		sumdata = 0;

		for (x = 0; x != nframes; x++) {

			offset = UGETW(sc->sc_ncm.dp[x].wFrameIndex);
			temp = UGETW(sc->sc_ncm.dp[x].wFrameLength);

			if ((offset == 0) ||
			    (temp < sizeof(struct ether_header)) ||
			    (temp > (MCLBYTES - ETHER_ALIGN))) {
				DPRINTFN(1, "NULL frame detected at %d\n", x);
				m = NULL;
				/* silently ignore this frame */
				continue;
			} else if ((offset + temp) > actlen) {
				DPRINTFN(1, "invalid frame "
				    "detected at %d\n", x);
				m = NULL;
				/* silently ignore this frame */
				continue;
			} else if (temp > (MHLEN - ETHER_ALIGN)) {
				m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
			} else {
				m = m_gethdr(M_DONTWAIT, MT_DATA);
			}

			DPRINTFN(16, "frame %u, offset = %u, length = %u \n",
			    x, offset, temp);

			/* check if we have a buffer */
			if (m) {
				m_adj(m, ETHER_ALIGN);

				usbd_copy_out(pc, offset, m->m_data, temp);

				/* enqueue */
				uether_rxmbuf(&sc->sc_ue, m, temp);

				sumdata += temp;
			} else {
				ifp->if_ierrors++;
			}
		}

		DPRINTFN(1, "Efficiency: %u/%u bytes\n", sumdata, actlen);

	case USB_ST_SETUP:
tr_setup:
		usbd_xfer_set_frame_len(xfer, 0, sc->sc_ncm.rx_max);
		usbd_xfer_set_frames(xfer, 1);
		usbd_transfer_submit(xfer);
		uether_rxflush(&sc->sc_ue);	/* must be last */
		break;

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

		if (error != USB_ERR_CANCELLED) {
tr_stall:
			/* try to clear stall first */
			usbd_xfer_set_stall(xfer);
			usbd_xfer_set_frames(xfer, 0);
			usbd_transfer_submit(xfer);
		}
		break;
	}
}
Пример #16
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);
}
Пример #17
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;
	}
}
Пример #18
0
static void
ue_attach_post_task(struct usb_proc_msg *_task)
{
	struct usb_ether_cfg_task *task =
	    (struct usb_ether_cfg_task *)_task;
	struct usb_ether *ue = task->ue;
	struct ifnet *ifp = uether_getifp(ue);
	int error;
	char num[14];			/* sufficient for 32 bits */

	/* first call driver's post attach routine */
	ue->ue_methods->ue_attach_post(ue);

	UE_UNLOCK(ue);

	KKASSERT(!lockowned(ue->ue_lock));
	ue->ue_unit = devfs_clone_bitmap_get(&DEVFS_CLONE_BITMAP(ue), 0);
	usb_callout_init_mtx(&ue->ue_watchdog, ue->ue_lock, 0);
	sysctl_ctx_init(&ue->ue_sysctl_ctx);

	KKASSERT(!lockowned(ue->ue_lock));
	error = 0;

	ifp->if_softc = ue;
	if_initname(ifp, "ue", ue->ue_unit);
	if (ue->ue_methods->ue_attach_post_sub != NULL) {
		error = ue->ue_methods->ue_attach_post_sub(ue);
		KKASSERT(!lockowned(ue->ue_lock));
	} else {
		ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
		if (ue->ue_methods->ue_ioctl != NULL)
			ifp->if_ioctl = ue->ue_methods->ue_ioctl;
		else
			ifp->if_ioctl = uether_ioctl;
		ifp->if_start = ue_start;
		ifp->if_init = ue_init;
		ifq_set_maxlen(&ifp->if_snd, ifqmaxlen);
		ifq_set_ready(&ifp->if_snd);

		if (ue->ue_methods->ue_mii_upd != NULL &&
		    ue->ue_methods->ue_mii_sts != NULL) {
			error = mii_phy_probe(ue->ue_dev, &ue->ue_miibus, 
					      ue_ifmedia_upd, ue->ue_methods->ue_mii_sts);
		}
	}

	if (error) {
		device_printf(ue->ue_dev, "attaching PHYs failed\n");
		goto fail;
	}

	if_printf(ifp, "<USB Ethernet> on %s\n", device_get_nameunit(ue->ue_dev));
	ether_ifattach(ifp, ue->ue_eaddr, NULL);
	/* Tell upper layer we support VLAN oversized frames. */
	if (ifp->if_capabilities & IFCAP_VLAN_MTU)
		ifp->if_hdrlen = sizeof(struct ether_vlan_header);

	ksnprintf(num, sizeof(num), "%u", ue->ue_unit);
	ue->ue_sysctl_oid = SYSCTL_ADD_NODE(&ue->ue_sysctl_ctx,
	    &SYSCTL_NODE_CHILDREN(_net, ue),
	    OID_AUTO, num, CTLFLAG_RD, NULL, "");
	SYSCTL_ADD_PROC(&ue->ue_sysctl_ctx,
	    SYSCTL_CHILDREN(ue->ue_sysctl_oid), OID_AUTO,
	    "%parent", CTLTYPE_STRING | CTLFLAG_RD, ue, 0,
	    ue_sysctl_parent, "A", "parent device");

	KKASSERT(!lockowned(ue->ue_lock));
	UE_LOCK(ue);
	return;

fail:
	devfs_clone_bitmap_put(&DEVFS_CLONE_BITMAP(ue), ue->ue_unit);
	UE_LOCK(ue);
	return;
}