if_cue.c revision 190734
11592Srgrimes/*-
21592Srgrimes * Copyright (c) 1997, 1998, 1999, 2000
31592Srgrimes *	Bill Paul <wpaul@ee.columbia.edu>.  All rights reserved.
496195Sdes *
596195Sdes * Redistribution and use in source and binary forms, with or without
61592Srgrimes * modification, are permitted provided that the following conditions
796195Sdes * are met:
896195Sdes * 1. Redistributions of source code must retain the above copyright
996195Sdes *    notice, this list of conditions and the following disclaimer.
1096195Sdes * 2. Redistributions in binary form must reproduce the above copyright
1196195Sdes *    notice, this list of conditions and the following disclaimer in the
121592Srgrimes *    documentation and/or other materials provided with the distribution.
131592Srgrimes * 3. All advertising materials mentioning features or use of this software
141592Srgrimes *    must display the following acknowledgement:
151592Srgrimes *	This product includes software developed by Bill Paul.
161592Srgrimes * 4. Neither the name of the author nor the names of any co-contributors
171592Srgrimes *    may be used to endorse or promote products derived from this software
181592Srgrimes *    without specific prior written permission.
191592Srgrimes *
201592Srgrimes * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
211592Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221592Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231592Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
241592Srgrimes * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
251592Srgrimes * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
261592Srgrimes * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
271592Srgrimes * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
281592Srgrimes * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
291592Srgrimes * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
301592Srgrimes * THE POSSIBILITY OF SUCH DAMAGE.
311592Srgrimes */
321592Srgrimes
331592Srgrimes#include <sys/cdefs.h>
341592Srgrimes__FBSDID("$FreeBSD: head/sys/dev/usb/net/if_cue.c 190734 2009-04-05 18:20:38Z thompsa $");
351592Srgrimes
361592Srgrimes/*
371592Srgrimes * CATC USB-EL1210A USB to ethernet driver. Used in the CATC Netmate
381592Srgrimes * adapters and others.
391592Srgrimes *
401592Srgrimes * Written by Bill Paul <wpaul@ee.columbia.edu>
411592Srgrimes * Electrical Engineering Department
4229917Smarkm * Columbia University, New York City
431592Srgrimes */
441592Srgrimes
451592Srgrimes/*
461592Srgrimes * The CATC USB-EL1210A provides USB ethernet support at 10Mbps. The
471592Srgrimes * RX filter uses a 512-bit multicast hash table, single perfect entry
4831490Scharnier * for the station address, and promiscuous mode. Unlike the ADMtek
4929917Smarkm * and KLSI chips, the CATC ASIC supports read and write combining
5031490Scharnier * mode where multiple packets can be transfered using a single bulk
511592Srgrimes * transaction, which helps performance a great deal.
521592Srgrimes */
5398885Smarkm
5498885Smarkm#include "usbdevs.h"
5598885Smarkm#include <dev/usb/usb.h>
561592Srgrimes#include <dev/usb/usb_mfunc.h>
571592Srgrimes#include <dev/usb/usb_error.h>
581592Srgrimes
5996195Sdes#define	USB_DEBUG_VAR cue_debug
6096195Sdes
611592Srgrimes#include <dev/usb/usb_core.h>
621592Srgrimes#include <dev/usb/usb_lookup.h>
631592Srgrimes#include <dev/usb/usb_process.h>
641592Srgrimes#include <dev/usb/usb_debug.h>
651592Srgrimes#include <dev/usb/usb_request.h>
661592Srgrimes#include <dev/usb/usb_busdma.h>
671592Srgrimes#include <dev/usb/usb_util.h>
681592Srgrimes
6922454Simp#include <dev/usb/net/usb_ethernet.h>
701592Srgrimes#include <dev/usb/net/if_cuereg.h>
7122454Simp
7241445Sdg/*
731592Srgrimes * Various supported device vendors/products.
741592Srgrimes */
751592Srgrimes
7676094Smarkm/* Belkin F5U111 adapter covered by NETMATE entry */
771592Srgrimes
781592Srgrimesstatic const struct usb2_device_id cue_devs[] = {
7945393Sbrian	{USB_VPI(USB_VENDOR_CATC, USB_PRODUCT_CATC_NETMATE, 0)},
801592Srgrimes	{USB_VPI(USB_VENDOR_CATC, USB_PRODUCT_CATC_NETMATE2, 0)},
811592Srgrimes	{USB_VPI(USB_VENDOR_SMARTBRIDGES, USB_PRODUCT_SMARTBRIDGES_SMARTLINK, 0)},
821592Srgrimes};
8376134Smarkm
841592Srgrimes/* prototypes */
851592Srgrimes
861592Srgrimesstatic device_probe_t cue_probe;
871592Srgrimesstatic device_attach_t cue_attach;
881592Srgrimesstatic device_detach_t cue_detach;
8925099Sdavidnstatic device_shutdown_t cue_shutdown;
901592Srgrimes
9174874Smarkmstatic usb2_callback_t cue_bulk_read_callback;
9296195Sdesstatic usb2_callback_t cue_bulk_write_callback;
9374874Smarkm
9474874Smarkmstatic usb2_ether_fn_t cue_attach_post;
9596195Sdesstatic usb2_ether_fn_t cue_init;
9674874Smarkmstatic usb2_ether_fn_t cue_stop;
9796195Sdesstatic usb2_ether_fn_t cue_start;
9874874Smarkmstatic usb2_ether_fn_t cue_tick;
9974874Smarkmstatic usb2_ether_fn_t cue_setmulti;
10096195Sdesstatic usb2_ether_fn_t cue_setpromisc;
10196195Sdes
10296195Sdesstatic uint8_t	cue_csr_read_1(struct cue_softc *, uint16_t);
10396195Sdesstatic uint16_t	cue_csr_read_2(struct cue_softc *, uint8_t);
10496195Sdesstatic int	cue_csr_write_1(struct cue_softc *, uint16_t, uint16_t);
10596195Sdesstatic int	cue_mem(struct cue_softc *, uint8_t, uint16_t, void *, int);
10674874Smarkmstatic int	cue_getmac(struct cue_softc *, void *);
10774874Smarkmstatic uint32_t	cue_mchash(const uint8_t *);
1081592Srgrimesstatic void	cue_reset(struct cue_softc *);
1091592Srgrimes
1101592Srgrimes#if USB_DEBUG
11141445Sdgstatic int cue_debug = 0;
1121592Srgrimes
11396195SdesSYSCTL_NODE(_hw_usb2, OID_AUTO, cue, CTLFLAG_RW, 0, "USB cue");
11490334SimpSYSCTL_INT(_hw_usb2_cue, OID_AUTO, debug, CTLFLAG_RW, &cue_debug, 0,
11590335Simp    "Debug level");
11690334Simp#endif
11790334Simp
11890334Simpstatic const struct usb2_config cue_config[CUE_N_TRANSFER] = {
1191592Srgrimes
12098885Smarkm	[CUE_BULK_DT_WR] = {
12198885Smarkm		.type = UE_BULK,
12298885Smarkm		.endpoint = UE_ADDR_ANY,
123141589Sru		.direction = UE_DIR_OUT,
12451433Smarkm		.bufsize = (MCLBYTES + 2),
1251592Srgrimes		.flags = {.pipe_bof = 1,},
12690334Simp		.callback = cue_bulk_write_callback,
1271592Srgrimes		.timeout = 10000,	/* 10 seconds */
1281592Srgrimes	},
1291592Srgrimes
130141918Sstefanf	[CUE_BULK_DT_RD] = {
131141918Sstefanf		.type = UE_BULK,
13256590Sshin		.endpoint = UE_ADDR_ANY,
1331592Srgrimes		.direction = UE_DIR_IN,
1341592Srgrimes		.bufsize = (MCLBYTES + 2),
1351592Srgrimes		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
1361592Srgrimes		.callback = cue_bulk_read_callback,
13724349Simp	},
1381592Srgrimes};
1391592Srgrimes
14072093Sasmodaistatic device_method_t cue_methods[] = {
1411592Srgrimes	/* Device interface */
1421592Srgrimes	DEVMETHOD(device_probe, cue_probe),
1431592Srgrimes	DEVMETHOD(device_attach, cue_attach),
1441592Srgrimes	DEVMETHOD(device_detach, cue_detach),
1451592Srgrimes	DEVMETHOD(device_shutdown, cue_shutdown),
1461592Srgrimes
1471592Srgrimes	{0, 0}
14841445Sdg};
14941445Sdg
15041445Sdgstatic driver_t cue_driver = {
1511592Srgrimes	.name = "cue",
1521592Srgrimes	.methods = cue_methods,
1531592Srgrimes	.size = sizeof(struct cue_softc),
1541592Srgrimes};
1551592Srgrimes
1561592Srgrimesstatic devclass_t cue_devclass;
1571592Srgrimes
1581592SrgrimesDRIVER_MODULE(cue, uhub, cue_driver, cue_devclass, NULL, 0);
1591592SrgrimesMODULE_DEPEND(cue, uether, 1, 1, 1);
1601592SrgrimesMODULE_DEPEND(cue, usb, 1, 1, 1);
1611592SrgrimesMODULE_DEPEND(cue, ether, 1, 1, 1);
1621592Srgrimes
1631592Srgrimesstatic const struct usb2_ether_methods cue_ue_methods = {
1641592Srgrimes	.ue_attach_post = cue_attach_post,
1651592Srgrimes	.ue_start = cue_start,
16635728Srnordier	.ue_init = cue_init,
1671592Srgrimes	.ue_stop = cue_stop,
1681592Srgrimes	.ue_tick = cue_tick,
1691592Srgrimes	.ue_setmulti = cue_setmulti,
1701592Srgrimes	.ue_setpromisc = cue_setpromisc,
1711592Srgrimes};
1721592Srgrimes
1731592Srgrimes#define	CUE_SETBIT(sc, reg, x)				\
1741592Srgrimes	cue_csr_write_1(sc, reg, cue_csr_read_1(sc, reg) | (x))
1751592Srgrimes
1761592Srgrimes#define	CUE_CLRBIT(sc, reg, x)				\
17741445Sdg	cue_csr_write_1(sc, reg, cue_csr_read_1(sc, reg) & ~(x))
17841445Sdg
17941445Sdgstatic uint8_t
18096195Sdescue_csr_read_1(struct cue_softc *sc, uint16_t reg)
1811592Srgrimes{
18229917Smarkm	struct usb2_device_request req;
1831592Srgrimes	uint8_t val;
1841592Srgrimes
18596195Sdes	req.bmRequestType = UT_READ_VENDOR_DEVICE;
18674874Smarkm	req.bRequest = CUE_CMD_READREG;
1871592Srgrimes	USETW(req.wValue, 0);
18896195Sdes	USETW(req.wIndex, reg);
1891592Srgrimes	USETW(req.wLength, 1);
1901592Srgrimes
1911592Srgrimes	if (usb2_ether_do_request(&sc->sc_ue, &req, &val, 1000)) {
1921592Srgrimes		/* ignore any errors */
1931592Srgrimes	}
19496195Sdes	return (val);
1951592Srgrimes}
19696195Sdes
19796195Sdesstatic uint16_t
198143907Sdascue_csr_read_2(struct cue_softc *sc, uint8_t reg)
19996195Sdes{
20056590Sshin	struct usb2_device_request req;
20198885Smarkm	uint16_t val;
202143907Sdas
20325099Sdavidn	req.bmRequestType = UT_READ_VENDOR_DEVICE;
2041592Srgrimes	req.bRequest = CUE_CMD_READREG;
205143907Sdas	USETW(req.wValue, 0);
206143907Sdas	USETW(req.wIndex, reg);
207143907Sdas	USETW(req.wLength, 2);
208143907Sdas
2091592Srgrimes	(void)usb2_ether_do_request(&sc->sc_ue, &req, &val, 1000);
2101592Srgrimes	return (le16toh(val));
2111592Srgrimes}
21296195Sdes
21396195Sdesstatic int
21496195Sdescue_csr_write_1(struct cue_softc *sc, uint16_t reg, uint16_t val)
21596195Sdes{
21696195Sdes	struct usb2_device_request req;
21796195Sdes
21896195Sdes	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
21996195Sdes	req.bRequest = CUE_CMD_WRITEREG;
22096195Sdes	USETW(req.wValue, val);
22174874Smarkm	USETW(req.wIndex, reg);
2221592Srgrimes	USETW(req.wLength, 0);
2231592Srgrimes
2241592Srgrimes	return (usb2_ether_do_request(&sc->sc_ue, &req, NULL, 1000));
22596195Sdes}
22696195Sdes
227141918Sstefanfstatic int
22896195Sdescue_mem(struct cue_softc *sc, uint8_t cmd, uint16_t addr, void *buf, int len)
2291592Srgrimes{
23096195Sdes	struct usb2_device_request req;
23196195Sdes
23296195Sdes	if (cmd == CUE_CMD_READSRAM)
23396195Sdes		req.bmRequestType = UT_READ_VENDOR_DEVICE;
23496195Sdes	else
23596195Sdes		req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
23696195Sdes	req.bRequest = cmd;
23796195Sdes	USETW(req.wValue, 0);
23896195Sdes	USETW(req.wIndex, addr);
23996195Sdes	USETW(req.wLength, len);
24096195Sdes
24196195Sdes	return (usb2_ether_do_request(&sc->sc_ue, &req, buf, 1000));
24296195Sdes}
24396195Sdes
24496195Sdesstatic int
24596195Sdescue_getmac(struct cue_softc *sc, void *buf)
24696195Sdes{
24796195Sdes	struct usb2_device_request req;
24822454Simp
2491592Srgrimes	req.bmRequestType = UT_READ_VENDOR_DEVICE;
2501592Srgrimes	req.bRequest = CUE_CMD_GET_MACADDR;
2511592Srgrimes	USETW(req.wValue, 0);
2521592Srgrimes	USETW(req.wIndex, 0);
25396195Sdes	USETW(req.wLength, ETHER_ADDR_LEN);
25496195Sdes
25551433Smarkm	return (usb2_ether_do_request(&sc->sc_ue, &req, buf, 1000));
25651433Smarkm}
25756590Sshin
25896195Sdes#define	CUE_BITS 9
25951433Smarkm
26051433Smarkmstatic uint32_t
2611592Srgrimescue_mchash(const uint8_t *addr)
2621592Srgrimes{
2631592Srgrimes	uint32_t crc;
26441860Speter
2651592Srgrimes	/* Compute CRC for the address value. */
2661592Srgrimes	crc = ether_crc32_le(addr, ETHER_ADDR_LEN);
2671592Srgrimes
2681592Srgrimes	return (crc & ((1 << CUE_BITS) - 1));
2691592Srgrimes}
270146074Sjmallett
2711592Srgrimesstatic void
2721592Srgrimescue_setpromisc(struct usb2_ether *ue)
27341860Speter{
2741592Srgrimes	struct cue_softc *sc = usb2_ether_getsc(ue);
2751592Srgrimes	struct ifnet *ifp = usb2_ether_getifp(ue);
2761592Srgrimes
2771592Srgrimes	CUE_LOCK_ASSERT(sc, MA_OWNED);
2781592Srgrimes
2791592Srgrimes	/* if we want promiscuous mode, set the allframes bit */
2801592Srgrimes	if (ifp->if_flags & IFF_PROMISC)
28156590Sshin		CUE_SETBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC);
2821592Srgrimes	else
2831592Srgrimes		CUE_CLRBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC);
2841592Srgrimes
2851592Srgrimes	/* write multicast hash-bits */
28651433Smarkm	cue_setmulti(ue);
28751433Smarkm}
28851433Smarkm
28951433Smarkmstatic void
29056590Sshincue_setmulti(struct usb2_ether *ue)
29151433Smarkm{
29251433Smarkm	struct cue_softc *sc = usb2_ether_getsc(ue);
29351433Smarkm	struct ifnet *ifp = usb2_ether_getifp(ue);
29496195Sdes	struct ifmultiaddr *ifma;
29596195Sdes	uint32_t h = 0, i;
2961592Srgrimes	uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
2971592Srgrimes
2981592Srgrimes	CUE_LOCK_ASSERT(sc, MA_OWNED);
2991592Srgrimes
3001592Srgrimes	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
3011592Srgrimes		for (i = 0; i < 8; i++)
30296195Sdes			hashtbl[i] = 0xff;
30396195Sdes		cue_mem(sc, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR,
30496195Sdes		    &hashtbl, 8);
3051592Srgrimes		return;
30696195Sdes	}
30796195Sdes
30896195Sdes	/* now program new ones */
309143907Sdas	IF_ADDR_LOCK(ifp);
31096195Sdes	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
31174874Smarkm	{
31296195Sdes		if (ifma->ifma_addr->sa_family != AF_LINK)
31396195Sdes			continue;
31496195Sdes		h = cue_mchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
31596195Sdes		hashtbl[h >> 3] |= 1 << (h & 0x7);
31676134Smarkm	}
31774874Smarkm	IF_ADDR_UNLOCK(ifp);
31874874Smarkm
31996195Sdes	/*
320227208Sbrueffer	 * Also include the broadcast address in the filter
32196195Sdes	 * so we can receive broadcast frames.
32296195Sdes 	 */
32376134Smarkm	if (ifp->if_flags & IFF_BROADCAST) {
32474874Smarkm		h = cue_mchash(ifp->if_broadcastaddr);
32574874Smarkm		hashtbl[h >> 3] |= 1 << (h & 0x7);
32696195Sdes	}
32796195Sdes
32896195Sdes	cue_mem(sc, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR, &hashtbl, 8);
32996195Sdes}
33096195Sdes
33196195Sdesstatic void
33296195Sdescue_reset(struct cue_softc *sc)
33396195Sdes{
33474874Smarkm	struct usb2_device_request req;
33596195Sdes
33696195Sdes	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
33796195Sdes	req.bRequest = CUE_CMD_RESET;
33896195Sdes	USETW(req.wValue, 0);
33976134Smarkm	USETW(req.wIndex, 0);
34074874Smarkm	USETW(req.wLength, 0);
34174874Smarkm
3421592Srgrimes	if (usb2_ether_do_request(&sc->sc_ue, &req, NULL, 1000)) {
34396195Sdes		/* ignore any errors */
3441592Srgrimes	}
3451592Srgrimes
3461592Srgrimes	/*
34796195Sdes	 * wait a little while for the chip to get its brains in order:
3481592Srgrimes	 */
34976094Smarkm	usb2_ether_pause(&sc->sc_ue, hz / 100);
35096195Sdes}
3511592Srgrimes
35274874Smarkmstatic void
35325674Sdavidncue_attach_post(struct usb2_ether *ue)
35474874Smarkm{
35574874Smarkm	struct cue_softc *sc = usb2_ether_getsc(ue);
35674874Smarkm
3571592Srgrimes	cue_getmac(sc, ue->ue_eaddr);
35825099Sdavidn}
35925099Sdavidn
36025099Sdavidnstatic int
36125099Sdavidncue_probe(device_t dev)
36296195Sdes{
36376134Smarkm	struct usb2_attach_arg *uaa = device_get_ivars(dev);
36425099Sdavidn
36598885Smarkm	if (uaa->usb2_mode != USB_MODE_HOST)
3661592Srgrimes		return (ENXIO);
3671592Srgrimes	if (uaa->info.bConfigIndex != CUE_CONFIG_IDX)
36896195Sdes		return (ENXIO);
36925099Sdavidn	if (uaa->info.bIfaceIndex != CUE_IFACE_IDX)
37025099Sdavidn		return (ENXIO);
37156590Sshin
37225099Sdavidn	return (usb2_lookup_id_by_uaa(cue_devs, sizeof(cue_devs), uaa));
37325099Sdavidn}
37496195Sdes
37596195Sdes/*
37625099Sdavidn * Attach the interface. Allocate softc structures, do ifmedia
37725099Sdavidn * setup and ethernet/BPF attach.
37896195Sdes */
37925099Sdavidnstatic int
38076134Smarkmcue_attach(device_t dev)
38125099Sdavidn{
38276094Smarkm	struct usb2_attach_arg *uaa = device_get_ivars(dev);
38376134Smarkm	struct cue_softc *sc = device_get_softc(dev);
38425099Sdavidn	struct usb2_ether *ue = &sc->sc_ue;
3851592Srgrimes	uint8_t iface_index;
38674874Smarkm	int error;
38774874Smarkm
38874874Smarkm	device_set_usb2_desc(dev);
38974874Smarkm	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
39074874Smarkm
39174874Smarkm	iface_index = CUE_IFACE_IDX;
39296195Sdes	error = usb2_transfer_setup(uaa->device, &iface_index,
39374874Smarkm	    sc->sc_xfer, cue_config, CUE_N_TRANSFER, sc, &sc->sc_mtx);
39474874Smarkm	if (error) {
39574874Smarkm		device_printf(dev, "allocating USB transfers failed!\n");
39696195Sdes		goto detach;
39796195Sdes	}
39896195Sdes
39996195Sdes	ue->ue_sc = sc;
40074874Smarkm	ue->ue_dev = dev;
40174874Smarkm	ue->ue_udev = uaa->device;
4021592Srgrimes	ue->ue_mtx = &sc->sc_mtx;
4031592Srgrimes	ue->ue_methods = &cue_ue_methods;
4041592Srgrimes
4051592Srgrimes	error = usb2_ether_ifattach(ue);
40676094Smarkm	if (error) {
40776134Smarkm		device_printf(dev, "could not attach interface\n");
4081592Srgrimes		goto detach;
40976094Smarkm	}
41076134Smarkm	return (0);			/* success */
4111592Srgrimes
41298885Smarkmdetach:
41398885Smarkm	cue_detach(dev);
4141592Srgrimes	return (ENXIO);			/* failure */
4151592Srgrimes}
4161592Srgrimes
4171592Srgrimesstatic int
4181592Srgrimescue_detach(device_t dev)
4191592Srgrimes{
4201592Srgrimes	struct cue_softc *sc = device_get_softc(dev);
4211592Srgrimes	struct usb2_ether *ue = &sc->sc_ue;
4221592Srgrimes
4231592Srgrimes	usb2_transfer_unsetup(sc->sc_xfer, CUE_N_TRANSFER);
4241592Srgrimes	usb2_ether_ifdetach(ue);
4251592Srgrimes	mtx_destroy(&sc->sc_mtx);
4261592Srgrimes
4271592Srgrimes	return (0);
4281592Srgrimes}
4291592Srgrimes
43098885Smarkmstatic void
43198885Smarkmcue_bulk_read_callback(struct usb2_xfer *xfer)
43298885Smarkm{
4331592Srgrimes	struct cue_softc *sc = xfer->priv_sc;
4341592Srgrimes	struct usb2_ether *ue = &sc->sc_ue;
4351592Srgrimes	struct ifnet *ifp = usb2_ether_getifp(ue);
43698885Smarkm	uint8_t buf[2];
43798885Smarkm	int len;
43898885Smarkm
43998885Smarkm	switch (USB_GET_STATE(xfer)) {
4401592Srgrimes	case USB_ST_TRANSFERRED:
4411592Srgrimes
4421592Srgrimes		if (xfer->actlen <= (2 + sizeof(struct ether_header))) {
4431592Srgrimes			ifp->if_ierrors++;
4441592Srgrimes			goto tr_setup;
445146074Sjmallett		}
4461592Srgrimes		usb2_copy_out(xfer->frbuffers, 0, buf, 2);
4471592Srgrimes		xfer->actlen -= 2;
44898885Smarkm		len = buf[0] | (buf[1] << 8);
4491592Srgrimes		len = min(xfer->actlen, len);
4501592Srgrimes
4511592Srgrimes		usb2_ether_rxbuf(ue, xfer->frbuffers, 2, len);
4521592Srgrimes		/* FALLTHROUGH */
4531592Srgrimes	case USB_ST_SETUP:
45474874Smarkmtr_setup:
4551592Srgrimes		xfer->frlengths[0] = xfer->max_data_length;
4561592Srgrimes		usb2_start_hardware(xfer);
4571592Srgrimes		usb2_ether_rxflush(ue);
4581592Srgrimes		return;
4591592Srgrimes
4601592Srgrimes	default:			/* Error */
4611592Srgrimes		DPRINTF("bulk read error, %s\n",
46274874Smarkm		    usb2_errstr(xfer->error));
46374874Smarkm
46476094Smarkm		if (xfer->error != USB_ERR_CANCELLED) {
46576134Smarkm			/* try to clear stall first */
46674874Smarkm			xfer->flags.stall_pipe = 1;
46774874Smarkm			goto tr_setup;
46896195Sdes		}
46996195Sdes		return;
47074874Smarkm
47174874Smarkm	}
47274874Smarkm}
47374874Smarkm
47474874Smarkmstatic void
47596195Sdescue_bulk_write_callback(struct usb2_xfer *xfer)
47696195Sdes{
47796195Sdes	struct cue_softc *sc = xfer->priv_sc;
47896195Sdes	struct ifnet *ifp = usb2_ether_getifp(&sc->sc_ue);
47996195Sdes	struct mbuf *m;
48096195Sdes	uint8_t buf[2];
48196195Sdes
4821592Srgrimes	switch (USB_GET_STATE(xfer)) {
48398885Smarkm	case USB_ST_TRANSFERRED:
48496195Sdes		DPRINTFN(11, "transfer complete\n");
48596195Sdes		ifp->if_opackets++;
48696195Sdes
48796195Sdes		/* FALLTHROUGH */
48896195Sdes	case USB_ST_SETUP:
48996195Sdestr_setup:
4901592Srgrimes		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
4911592Srgrimes
4921592Srgrimes		if (m == NULL)
4931592Srgrimes			return;
4941592Srgrimes		if (m->m_pkthdr.len > MCLBYTES)
49574874Smarkm			m->m_pkthdr.len = MCLBYTES;
49696195Sdes		xfer->frlengths[0] = (m->m_pkthdr.len + 2);
49796195Sdes
49896195Sdes		/* the first two bytes are the frame length */
49925099Sdavidn
50025099Sdavidn		buf[0] = (uint8_t)(m->m_pkthdr.len);
50125099Sdavidn		buf[1] = (uint8_t)(m->m_pkthdr.len >> 8);
5021592Srgrimes
5031592Srgrimes		usb2_copy_in(xfer->frbuffers, 0, buf, 2);
5041592Srgrimes
50596195Sdes		usb2_m_copy_in(xfer->frbuffers, 2,
5061592Srgrimes		    m, 0, m->m_pkthdr.len);
507127864Smux
50896195Sdes		/*
5091592Srgrimes		 * If there's a BPF listener, bounce a copy of this frame
5101592Srgrimes		 * to him.
5111592Srgrimes		 */
51276134Smarkm		BPF_MTAP(ifp, m);
51376134Smarkm
51476134Smarkm		m_freem(m);
51576134Smarkm
51676134Smarkm		usb2_start_hardware(xfer);
51776134Smarkm
51876134Smarkm		return;
51976134Smarkm
52076134Smarkm	default:			/* Error */
52176134Smarkm		DPRINTFN(11, "transfer error, %s\n",
52276134Smarkm		    usb2_errstr(xfer->error));
52376134Smarkm
52476134Smarkm		ifp->if_oerrors++;
52576134Smarkm
52676134Smarkm		if (xfer->error != USB_ERR_CANCELLED) {
52776134Smarkm			/* try to clear stall first */
52876134Smarkm			xfer->flags.stall_pipe = 1;
52976134Smarkm			goto tr_setup;
53076134Smarkm		}
53176134Smarkm		return;
5321592Srgrimes	}
53390335Simp}
5341592Srgrimes
5351592Srgrimesstatic void
5361592Srgrimescue_tick(struct usb2_ether *ue)
5371592Srgrimes{
5381592Srgrimes	struct cue_softc *sc = usb2_ether_getsc(ue);
5391592Srgrimes	struct ifnet *ifp = usb2_ether_getifp(ue);
5401592Srgrimes
54176125Smarkm	CUE_LOCK_ASSERT(sc, MA_OWNED);
54290335Simp
5431592Srgrimes	ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_SINGLECOLL);
5441592Srgrimes	ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_MULTICOLL);
5451592Srgrimes	ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_EXCESSCOLL);
5461592Srgrimes
5471592Srgrimes	if (cue_csr_read_2(sc, CUE_RX_FRAMEERR))
5481592Srgrimes		ifp->if_ierrors++;
5491592Srgrimes}
5501592Srgrimes
5511592Srgrimesstatic void
5521592Srgrimescue_start(struct usb2_ether *ue)
5531592Srgrimes{
5541592Srgrimes	struct cue_softc *sc = usb2_ether_getsc(ue);
55590334Simp
5561592Srgrimes	/*
5571592Srgrimes	 * start the USB transfers, if not already started:
5581592Srgrimes	 */
5591592Srgrimes	usb2_transfer_start(sc->sc_xfer[CUE_BULK_DT_RD]);
5601592Srgrimes	usb2_transfer_start(sc->sc_xfer[CUE_BULK_DT_WR]);
56145422Sbrian}
56245422Sbrian
56396195Sdesstatic void
5641592Srgrimescue_init(struct usb2_ether *ue)
5651592Srgrimes{
5661592Srgrimes	struct cue_softc *sc = usb2_ether_getsc(ue);
5671592Srgrimes	struct ifnet *ifp = usb2_ether_getifp(ue);
5681592Srgrimes	int i;
5691592Srgrimes
5701592Srgrimes	CUE_LOCK_ASSERT(sc, MA_OWNED);
5711592Srgrimes
57290334Simp	/*
5731592Srgrimes	 * Cancel pending I/O and free all RX/TX buffers.
5741592Srgrimes	 */
5751592Srgrimes	cue_stop(ue);
5761592Srgrimes#if 0
5771592Srgrimes	cue_reset(sc);
5781592Srgrimes#endif
5791592Srgrimes	/* Set MAC address */
5801592Srgrimes	for (i = 0; i < ETHER_ADDR_LEN; i++)
5811592Srgrimes		cue_csr_write_1(sc, CUE_PAR0 - i, IF_LLADDR(ifp)[i]);
5821592Srgrimes
5831592Srgrimes	/* Enable RX logic. */
5841592Srgrimes	cue_csr_write_1(sc, CUE_ETHCTL, CUE_ETHCTL_RX_ON | CUE_ETHCTL_MCAST_ON);
5851592Srgrimes
5861592Srgrimes	/* Load the multicast filter */
5871592Srgrimes	cue_setpromisc(ue);
58890334Simp
5891592Srgrimes	/*
5901592Srgrimes	 * Set the number of RX and TX buffers that we want
5911592Srgrimes	 * to reserve inside the ASIC.
5921592Srgrimes	 */
5931592Srgrimes	cue_csr_write_1(sc, CUE_RX_BUFPKTS, CUE_RX_FRAMES);
594	cue_csr_write_1(sc, CUE_TX_BUFPKTS, CUE_TX_FRAMES);
595
596	/* Set advanced operation modes. */
597	cue_csr_write_1(sc, CUE_ADVANCED_OPMODES,
598	    CUE_AOP_EMBED_RXLEN | 0x01);/* 1 wait state */
599
600	/* Program the LED operation. */
601	cue_csr_write_1(sc, CUE_LEDCTL, CUE_LEDCTL_FOLLOW_LINK);
602
603	usb2_transfer_set_stall(sc->sc_xfer[CUE_BULK_DT_WR]);
604
605	ifp->if_drv_flags |= IFF_DRV_RUNNING;
606	cue_start(ue);
607}
608
609/*
610 * Stop the adapter and free any mbufs allocated to the
611 * RX and TX lists.
612 */
613static void
614cue_stop(struct usb2_ether *ue)
615{
616	struct cue_softc *sc = usb2_ether_getsc(ue);
617	struct ifnet *ifp = usb2_ether_getifp(ue);
618
619	CUE_LOCK_ASSERT(sc, MA_OWNED);
620
621	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
622
623	/*
624	 * stop all the transfers, if not already stopped:
625	 */
626	usb2_transfer_stop(sc->sc_xfer[CUE_BULK_DT_WR]);
627	usb2_transfer_stop(sc->sc_xfer[CUE_BULK_DT_RD]);
628
629	cue_csr_write_1(sc, CUE_ETHCTL, 0);
630	cue_reset(sc);
631}
632
633/*
634 * Stop all chip I/O so that the kernel's probe routines don't
635 * get confused by errant DMAs when rebooting.
636 */
637static int
638cue_shutdown(device_t dev)
639{
640	struct cue_softc *sc = device_get_softc(dev);
641
642	usb2_ether_ifshutdown(&sc->sc_ue);
643
644	return (0);
645}
646