if_cue.c revision 188746
1184610Salfred/*-
2184610Salfred * Copyright (c) 1997, 1998, 1999, 2000
3184610Salfred *	Bill Paul <wpaul@ee.columbia.edu>.  All rights reserved.
4184610Salfred *
5184610Salfred * Redistribution and use in source and binary forms, with or without
6184610Salfred * modification, are permitted provided that the following conditions
7184610Salfred * are met:
8184610Salfred * 1. Redistributions of source code must retain the above copyright
9184610Salfred *    notice, this list of conditions and the following disclaimer.
10184610Salfred * 2. Redistributions in binary form must reproduce the above copyright
11184610Salfred *    notice, this list of conditions and the following disclaimer in the
12184610Salfred *    documentation and/or other materials provided with the distribution.
13184610Salfred * 3. All advertising materials mentioning features or use of this software
14184610Salfred *    must display the following acknowledgement:
15184610Salfred *	This product includes software developed by Bill Paul.
16184610Salfred * 4. Neither the name of the author nor the names of any co-contributors
17184610Salfred *    may be used to endorse or promote products derived from this software
18184610Salfred *    without specific prior written permission.
19184610Salfred *
20184610Salfred * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23184610Salfred * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24184610Salfred * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25184610Salfred * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26184610Salfred * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27184610Salfred * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28184610Salfred * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29184610Salfred * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30184610Salfred * THE POSSIBILITY OF SUCH DAMAGE.
31184610Salfred */
32184610Salfred
33184610Salfred#include <sys/cdefs.h>
34184610Salfred__FBSDID("$FreeBSD: head/sys/dev/usb2/ethernet/if_cue2.c 188746 2009-02-18 06:33:10Z thompsa $");
35184610Salfred
36184610Salfred/*
37184610Salfred * CATC USB-EL1210A USB to ethernet driver. Used in the CATC Netmate
38184610Salfred * adapters and others.
39184610Salfred *
40184610Salfred * Written by Bill Paul <wpaul@ee.columbia.edu>
41184610Salfred * Electrical Engineering Department
42184610Salfred * Columbia University, New York City
43184610Salfred */
44184610Salfred
45184610Salfred/*
46184610Salfred * The CATC USB-EL1210A provides USB ethernet support at 10Mbps. The
47184610Salfred * RX filter uses a 512-bit multicast hash table, single perfect entry
48184610Salfred * for the station address, and promiscuous mode. Unlike the ADMtek
49184610Salfred * and KLSI chips, the CATC ASIC supports read and write combining
50184610Salfred * mode where multiple packets can be transfered using a single bulk
51184610Salfred * transaction, which helps performance a great deal.
52184610Salfred */
53184610Salfred
54188746Sthompsa#include "usbdevs.h"
55184610Salfred#include <dev/usb2/include/usb2_standard.h>
56184610Salfred#include <dev/usb2/include/usb2_mfunc.h>
57184610Salfred#include <dev/usb2/include/usb2_error.h>
58184610Salfred
59184610Salfred#define	USB_DEBUG_VAR cue_debug
60184610Salfred
61184610Salfred#include <dev/usb2/core/usb2_core.h>
62184610Salfred#include <dev/usb2/core/usb2_lookup.h>
63184610Salfred#include <dev/usb2/core/usb2_process.h>
64184610Salfred#include <dev/usb2/core/usb2_debug.h>
65184610Salfred#include <dev/usb2/core/usb2_request.h>
66184610Salfred#include <dev/usb2/core/usb2_busdma.h>
67184610Salfred#include <dev/usb2/core/usb2_util.h>
68184610Salfred
69184610Salfred#include <dev/usb2/ethernet/usb2_ethernet.h>
70187192Sthompsa#include <dev/usb2/ethernet/if_cuereg.h>
71184610Salfred
72184610Salfred/*
73184610Salfred * Various supported device vendors/products.
74184610Salfred */
75184610Salfred
76184610Salfred/* Belkin F5U111 adapter covered by NETMATE entry */
77184610Salfred
78184610Salfredstatic const struct usb2_device_id cue_devs[] = {
79184610Salfred	{USB_VPI(USB_VENDOR_CATC, USB_PRODUCT_CATC_NETMATE, 0)},
80184610Salfred	{USB_VPI(USB_VENDOR_CATC, USB_PRODUCT_CATC_NETMATE2, 0)},
81184610Salfred	{USB_VPI(USB_VENDOR_SMARTBRIDGES, USB_PRODUCT_SMARTBRIDGES_SMARTLINK, 0)},
82184610Salfred};
83184610Salfred
84184610Salfred/* prototypes */
85184610Salfred
86184610Salfredstatic device_probe_t cue_probe;
87184610Salfredstatic device_attach_t cue_attach;
88184610Salfredstatic device_detach_t cue_detach;
89184610Salfredstatic device_shutdown_t cue_shutdown;
90184610Salfred
91184610Salfredstatic usb2_callback_t cue_bulk_read_callback;
92184610Salfredstatic usb2_callback_t cue_bulk_write_callback;
93184610Salfred
94188412Sthompsastatic usb2_ether_fn_t cue_attach_post;
95188412Sthompsastatic usb2_ether_fn_t cue_init;
96188412Sthompsastatic usb2_ether_fn_t cue_stop;
97188412Sthompsastatic usb2_ether_fn_t cue_start;
98188412Sthompsastatic usb2_ether_fn_t cue_tick;
99188412Sthompsastatic usb2_ether_fn_t cue_setmulti;
100188412Sthompsastatic usb2_ether_fn_t cue_setpromisc;
101184610Salfred
102188412Sthompsastatic uint8_t	cue_csr_read_1(struct cue_softc *, uint16_t);
103188412Sthompsastatic uint16_t	cue_csr_read_2(struct cue_softc *, uint8_t);
104188412Sthompsastatic int	cue_csr_write_1(struct cue_softc *, uint16_t, uint16_t);
105188412Sthompsastatic int	cue_mem(struct cue_softc *, uint8_t, uint16_t, void *, int);
106188412Sthompsastatic int	cue_getmac(struct cue_softc *, void *);
107188412Sthompsastatic uint32_t	cue_mchash(const uint8_t *);
108188412Sthompsastatic void	cue_reset(struct cue_softc *);
109184610Salfred
110184610Salfred#if USB_DEBUG
111184610Salfredstatic int cue_debug = 0;
112184610Salfred
113184610SalfredSYSCTL_NODE(_hw_usb2, OID_AUTO, cue, CTLFLAG_RW, 0, "USB cue");
114184610SalfredSYSCTL_INT(_hw_usb2_cue, OID_AUTO, debug, CTLFLAG_RW, &cue_debug, 0,
115184610Salfred    "Debug level");
116184610Salfred#endif
117184610Salfred
118187259Sthompsastatic const struct usb2_config cue_config[CUE_N_TRANSFER] = {
119184610Salfred
120187259Sthompsa	[CUE_BULK_DT_WR] = {
121184610Salfred		.type = UE_BULK,
122184610Salfred		.endpoint = UE_ADDR_ANY,
123184610Salfred		.direction = UE_DIR_OUT,
124184610Salfred		.mh.bufsize = (MCLBYTES + 2),
125184610Salfred		.mh.flags = {.pipe_bof = 1,},
126188412Sthompsa		.mh.callback = cue_bulk_write_callback,
127184610Salfred		.mh.timeout = 10000,	/* 10 seconds */
128184610Salfred	},
129184610Salfred
130187259Sthompsa	[CUE_BULK_DT_RD] = {
131184610Salfred		.type = UE_BULK,
132184610Salfred		.endpoint = UE_ADDR_ANY,
133184610Salfred		.direction = UE_DIR_IN,
134184610Salfred		.mh.bufsize = (MCLBYTES + 2),
135184610Salfred		.mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
136188412Sthompsa		.mh.callback = cue_bulk_read_callback,
137184610Salfred	},
138184610Salfred};
139184610Salfred
140184610Salfredstatic device_method_t cue_methods[] = {
141184610Salfred	/* Device interface */
142184610Salfred	DEVMETHOD(device_probe, cue_probe),
143184610Salfred	DEVMETHOD(device_attach, cue_attach),
144184610Salfred	DEVMETHOD(device_detach, cue_detach),
145184610Salfred	DEVMETHOD(device_shutdown, cue_shutdown),
146184610Salfred
147184610Salfred	{0, 0}
148184610Salfred};
149184610Salfred
150184610Salfredstatic driver_t cue_driver = {
151184610Salfred	.name = "cue",
152184610Salfred	.methods = cue_methods,
153184610Salfred	.size = sizeof(struct cue_softc),
154184610Salfred};
155184610Salfred
156184610Salfredstatic devclass_t cue_devclass;
157184610Salfred
158184610SalfredDRIVER_MODULE(cue, ushub, cue_driver, cue_devclass, NULL, 0);
159184610SalfredMODULE_DEPEND(cue, usb2_ethernet, 1, 1, 1);
160184610SalfredMODULE_DEPEND(cue, usb2_core, 1, 1, 1);
161184610SalfredMODULE_DEPEND(cue, ether, 1, 1, 1);
162184610Salfred
163188412Sthompsastatic const struct usb2_ether_methods cue_ue_methods = {
164188412Sthompsa	.ue_attach_post = cue_attach_post,
165188412Sthompsa	.ue_start = cue_start,
166188412Sthompsa	.ue_init = cue_init,
167188412Sthompsa	.ue_stop = cue_stop,
168188412Sthompsa	.ue_tick = cue_tick,
169188412Sthompsa	.ue_setmulti = cue_setmulti,
170188412Sthompsa	.ue_setpromisc = cue_setpromisc,
171188412Sthompsa};
172184610Salfred
173188412Sthompsa#define	CUE_SETBIT(sc, reg, x)				\
174188412Sthompsa	cue_csr_write_1(sc, reg, cue_csr_read_1(sc, reg) | (x))
175184610Salfred
176188412Sthompsa#define	CUE_CLRBIT(sc, reg, x)				\
177188412Sthompsa	cue_csr_write_1(sc, reg, cue_csr_read_1(sc, reg) & ~(x))
178184610Salfred
179184610Salfredstatic uint8_t
180188412Sthompsacue_csr_read_1(struct cue_softc *sc, uint16_t reg)
181184610Salfred{
182184610Salfred	struct usb2_device_request req;
183184610Salfred	uint8_t val;
184184610Salfred
185184610Salfred	req.bmRequestType = UT_READ_VENDOR_DEVICE;
186184610Salfred	req.bRequest = CUE_CMD_READREG;
187184610Salfred	USETW(req.wValue, 0);
188184610Salfred	USETW(req.wIndex, reg);
189184610Salfred	USETW(req.wLength, 1);
190184610Salfred
191188412Sthompsa	if (usb2_ether_do_request(&sc->sc_ue, &req, &val, 1000)) {
192188412Sthompsa		/* ignore any errors */
193188412Sthompsa	}
194184610Salfred	return (val);
195184610Salfred}
196184610Salfred
197184610Salfredstatic uint16_t
198188412Sthompsacue_csr_read_2(struct cue_softc *sc, uint8_t reg)
199184610Salfred{
200184610Salfred	struct usb2_device_request req;
201184610Salfred	uint16_t val;
202184610Salfred
203184610Salfred	req.bmRequestType = UT_READ_VENDOR_DEVICE;
204184610Salfred	req.bRequest = CUE_CMD_READREG;
205184610Salfred	USETW(req.wValue, 0);
206184610Salfred	USETW(req.wIndex, reg);
207184610Salfred	USETW(req.wLength, 2);
208184610Salfred
209188412Sthompsa	(void)usb2_ether_do_request(&sc->sc_ue, &req, &val, 1000);
210184610Salfred	return (le16toh(val));
211184610Salfred}
212184610Salfred
213188412Sthompsastatic int
214188412Sthompsacue_csr_write_1(struct cue_softc *sc, uint16_t reg, uint16_t val)
215184610Salfred{
216184610Salfred	struct usb2_device_request req;
217184610Salfred
218184610Salfred	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
219184610Salfred	req.bRequest = CUE_CMD_WRITEREG;
220184610Salfred	USETW(req.wValue, val);
221184610Salfred	USETW(req.wIndex, reg);
222184610Salfred	USETW(req.wLength, 0);
223184610Salfred
224188412Sthompsa	return (usb2_ether_do_request(&sc->sc_ue, &req, NULL, 1000));
225184610Salfred}
226184610Salfred
227188412Sthompsastatic int
228188412Sthompsacue_mem(struct cue_softc *sc, uint8_t cmd, uint16_t addr, void *buf, int len)
229184610Salfred{
230184610Salfred	struct usb2_device_request req;
231184610Salfred
232188412Sthompsa	if (cmd == CUE_CMD_READSRAM)
233184610Salfred		req.bmRequestType = UT_READ_VENDOR_DEVICE;
234188412Sthompsa	else
235184610Salfred		req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
236184610Salfred	req.bRequest = cmd;
237184610Salfred	USETW(req.wValue, 0);
238184610Salfred	USETW(req.wIndex, addr);
239184610Salfred	USETW(req.wLength, len);
240184610Salfred
241188412Sthompsa	return (usb2_ether_do_request(&sc->sc_ue, &req, buf, 1000));
242184610Salfred}
243184610Salfred
244188412Sthompsastatic int
245188412Sthompsacue_getmac(struct cue_softc *sc, void *buf)
246184610Salfred{
247184610Salfred	struct usb2_device_request req;
248184610Salfred
249184610Salfred	req.bmRequestType = UT_READ_VENDOR_DEVICE;
250184610Salfred	req.bRequest = CUE_CMD_GET_MACADDR;
251184610Salfred	USETW(req.wValue, 0);
252184610Salfred	USETW(req.wIndex, 0);
253184610Salfred	USETW(req.wLength, ETHER_ADDR_LEN);
254184610Salfred
255188412Sthompsa	return (usb2_ether_do_request(&sc->sc_ue, &req, buf, 1000));
256184610Salfred}
257184610Salfred
258184610Salfred#define	CUE_BITS 9
259184610Salfred
260188412Sthompsastatic uint32_t
261188412Sthompsacue_mchash(const uint8_t *addr)
262184610Salfred{
263188412Sthompsa	uint32_t crc;
264184610Salfred
265188412Sthompsa	/* Compute CRC for the address value. */
266188412Sthompsa	crc = ether_crc32_le(addr, ETHER_ADDR_LEN);
267188412Sthompsa
268188412Sthompsa	return (crc & ((1 << CUE_BITS) - 1));
269184610Salfred}
270184610Salfred
271184610Salfredstatic void
272188412Sthompsacue_setpromisc(struct usb2_ether *ue)
273184610Salfred{
274188412Sthompsa	struct cue_softc *sc = usb2_ether_getsc(ue);
275188412Sthompsa	struct ifnet *ifp = usb2_ether_getifp(ue);
276188412Sthompsa
277188412Sthompsa	CUE_LOCK_ASSERT(sc, MA_OWNED);
278188412Sthompsa
279184610Salfred	/* if we want promiscuous mode, set the allframes bit */
280188412Sthompsa	if (ifp->if_flags & IFF_PROMISC)
281188412Sthompsa		CUE_SETBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC);
282188412Sthompsa	else
283188412Sthompsa		CUE_CLRBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC);
284184610Salfred
285184610Salfred	/* write multicast hash-bits */
286188412Sthompsa	cue_setmulti(ue);
287184610Salfred}
288184610Salfred
289184610Salfredstatic void
290188412Sthompsacue_setmulti(struct usb2_ether *ue)
291184610Salfred{
292188412Sthompsa	struct cue_softc *sc = usb2_ether_getsc(ue);
293188412Sthompsa	struct ifnet *ifp = usb2_ether_getifp(ue);
294188412Sthompsa	struct ifmultiaddr *ifma;
295188412Sthompsa	uint32_t h = 0, i;
296188412Sthompsa	uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
297188412Sthompsa
298188412Sthompsa	CUE_LOCK_ASSERT(sc, MA_OWNED);
299188412Sthompsa
300188412Sthompsa	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
301188412Sthompsa		for (i = 0; i < 8; i++)
302188412Sthompsa			hashtbl[i] = 0xff;
303188412Sthompsa		cue_mem(sc, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR,
304188412Sthompsa		    &hashtbl, 8);
305188412Sthompsa		return;
306188412Sthompsa	}
307188412Sthompsa
308188412Sthompsa	/* now program new ones */
309188412Sthompsa	IF_ADDR_LOCK(ifp);
310188412Sthompsa	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
311188412Sthompsa	{
312188412Sthompsa		if (ifma->ifma_addr->sa_family != AF_LINK)
313188412Sthompsa			continue;
314188412Sthompsa		h = cue_mchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
315188412Sthompsa		hashtbl[h >> 3] |= 1 << (h & 0x7);
316188412Sthompsa	}
317188412Sthompsa	IF_ADDR_UNLOCK(ifp);
318188412Sthompsa
319188412Sthompsa	/*
320188412Sthompsa	 * Also include the broadcast address in the filter
321188412Sthompsa	 * so we can receive broadcast frames.
322188412Sthompsa 	 */
323188412Sthompsa	if (ifp->if_flags & IFF_BROADCAST) {
324188412Sthompsa		h = cue_mchash(ifp->if_broadcastaddr);
325188412Sthompsa		hashtbl[h >> 3] |= 1 << (h & 0x7);
326188412Sthompsa	}
327188412Sthompsa
328188412Sthompsa	cue_mem(sc, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR, &hashtbl, 8);
329184610Salfred}
330184610Salfred
331184610Salfredstatic void
332188412Sthompsacue_reset(struct cue_softc *sc)
333184610Salfred{
334184610Salfred	struct usb2_device_request req;
335184610Salfred
336184610Salfred	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
337184610Salfred	req.bRequest = CUE_CMD_RESET;
338184610Salfred	USETW(req.wValue, 0);
339184610Salfred	USETW(req.wIndex, 0);
340184610Salfred	USETW(req.wLength, 0);
341184610Salfred
342188412Sthompsa	if (usb2_ether_do_request(&sc->sc_ue, &req, NULL, 1000)) {
343188412Sthompsa		/* ignore any errors */
344188412Sthompsa	}
345184610Salfred
346184610Salfred	/*
347184610Salfred	 * wait a little while for the chip to get its brains in order:
348184610Salfred	 */
349188412Sthompsa	usb2_ether_pause(&sc->sc_ue, hz / 100);
350188412Sthompsa}
351184610Salfred
352188412Sthompsastatic void
353188412Sthompsacue_attach_post(struct usb2_ether *ue)
354188412Sthompsa{
355188412Sthompsa	struct cue_softc *sc = usb2_ether_getsc(ue);
356188412Sthompsa
357188412Sthompsa	cue_getmac(sc, ue->ue_eaddr);
358184610Salfred}
359184610Salfred
360184610Salfredstatic int
361184610Salfredcue_probe(device_t dev)
362184610Salfred{
363184610Salfred	struct usb2_attach_arg *uaa = device_get_ivars(dev);
364184610Salfred
365188412Sthompsa	if (uaa->usb2_mode != USB_MODE_HOST)
366184610Salfred		return (ENXIO);
367188412Sthompsa	if (uaa->info.bConfigIndex != CUE_CONFIG_IDX)
368184610Salfred		return (ENXIO);
369188412Sthompsa	if (uaa->info.bIfaceIndex != CUE_IFACE_IDX)
370184610Salfred		return (ENXIO);
371188412Sthompsa
372184610Salfred	return (usb2_lookup_id_by_uaa(cue_devs, sizeof(cue_devs), uaa));
373184610Salfred}
374184610Salfred
375188412Sthompsa/*
376188412Sthompsa * Attach the interface. Allocate softc structures, do ifmedia
377188412Sthompsa * setup and ethernet/BPF attach.
378188412Sthompsa */
379184610Salfredstatic int
380184610Salfredcue_attach(device_t dev)
381184610Salfred{
382184610Salfred	struct usb2_attach_arg *uaa = device_get_ivars(dev);
383184610Salfred	struct cue_softc *sc = device_get_softc(dev);
384188412Sthompsa	struct usb2_ether *ue = &sc->sc_ue;
385184610Salfred	uint8_t iface_index;
386188412Sthompsa	int error;
387184610Salfred
388184610Salfred	device_set_usb2_desc(dev);
389188412Sthompsa	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
390184610Salfred
391184610Salfred	iface_index = CUE_IFACE_IDX;
392184610Salfred	error = usb2_transfer_setup(uaa->device, &iface_index,
393187259Sthompsa	    sc->sc_xfer, cue_config, CUE_N_TRANSFER, sc, &sc->sc_mtx);
394184610Salfred	if (error) {
395188412Sthompsa		device_printf(dev, "allocating USB transfers failed!\n");
396184610Salfred		goto detach;
397184610Salfred	}
398188412Sthompsa
399188412Sthompsa	ue->ue_sc = sc;
400188412Sthompsa	ue->ue_dev = dev;
401188412Sthompsa	ue->ue_udev = uaa->device;
402188412Sthompsa	ue->ue_mtx = &sc->sc_mtx;
403188412Sthompsa	ue->ue_methods = &cue_ue_methods;
404188412Sthompsa
405188412Sthompsa	error = usb2_ether_ifattach(ue);
406184610Salfred	if (error) {
407188412Sthompsa		device_printf(dev, "could not attach interface\n");
408184610Salfred		goto detach;
409184610Salfred	}
410184610Salfred	return (0);			/* success */
411184610Salfred
412184610Salfreddetach:
413184610Salfred	cue_detach(dev);
414184610Salfred	return (ENXIO);			/* failure */
415184610Salfred}
416184610Salfred
417184610Salfredstatic int
418184610Salfredcue_detach(device_t dev)
419184610Salfred{
420184610Salfred	struct cue_softc *sc = device_get_softc(dev);
421188412Sthompsa	struct usb2_ether *ue = &sc->sc_ue;
422184610Salfred
423187259Sthompsa	usb2_transfer_unsetup(sc->sc_xfer, CUE_N_TRANSFER);
424188412Sthompsa	usb2_ether_ifdetach(ue);
425184610Salfred	mtx_destroy(&sc->sc_mtx);
426184610Salfred
427184610Salfred	return (0);
428184610Salfred}
429184610Salfred
430184610Salfredstatic void
431184610Salfredcue_bulk_read_callback(struct usb2_xfer *xfer)
432184610Salfred{
433184610Salfred	struct cue_softc *sc = xfer->priv_sc;
434188412Sthompsa	struct usb2_ether *ue = &sc->sc_ue;
435188412Sthompsa	struct ifnet *ifp = usb2_ether_getifp(ue);
436184610Salfred	uint8_t buf[2];
437188412Sthompsa	int len;
438184610Salfred
439184610Salfred	switch (USB_GET_STATE(xfer)) {
440184610Salfred	case USB_ST_TRANSFERRED:
441184610Salfred
442184610Salfred		if (xfer->actlen <= (2 + sizeof(struct ether_header))) {
443184610Salfred			ifp->if_ierrors++;
444184610Salfred			goto tr_setup;
445184610Salfred		}
446184610Salfred		usb2_copy_out(xfer->frbuffers, 0, buf, 2);
447188412Sthompsa		xfer->actlen -= 2;
448184610Salfred		len = buf[0] | (buf[1] << 8);
449188412Sthompsa		len = min(xfer->actlen, len);
450184610Salfred
451188412Sthompsa		usb2_ether_rxbuf(ue, xfer->frbuffers, 2, len);
452188412Sthompsa		/* FALLTHROUGH */
453184610Salfred	case USB_ST_SETUP:
454184610Salfredtr_setup:
455188412Sthompsa		xfer->frlengths[0] = xfer->max_data_length;
456188412Sthompsa		usb2_start_hardware(xfer);
457188412Sthompsa		usb2_ether_rxflush(ue);
458184610Salfred		return;
459184610Salfred
460184610Salfred	default:			/* Error */
461188412Sthompsa		DPRINTF("bulk read error, %s\n",
462188412Sthompsa		    usb2_errstr(xfer->error));
463188412Sthompsa
464184610Salfred		if (xfer->error != USB_ERR_CANCELLED) {
465184610Salfred			/* try to clear stall first */
466188412Sthompsa			xfer->flags.stall_pipe = 1;
467188412Sthompsa			goto tr_setup;
468184610Salfred		}
469184610Salfred		return;
470184610Salfred
471184610Salfred	}
472184610Salfred}
473184610Salfred
474184610Salfredstatic void
475184610Salfredcue_bulk_write_callback(struct usb2_xfer *xfer)
476184610Salfred{
477184610Salfred	struct cue_softc *sc = xfer->priv_sc;
478188412Sthompsa	struct ifnet *ifp = usb2_ether_getifp(&sc->sc_ue);
479184610Salfred	struct mbuf *m;
480184610Salfred	uint8_t buf[2];
481184610Salfred
482184610Salfred	switch (USB_GET_STATE(xfer)) {
483184610Salfred	case USB_ST_TRANSFERRED:
484184610Salfred		DPRINTFN(11, "transfer complete\n");
485184610Salfred		ifp->if_opackets++;
486184610Salfred
487188412Sthompsa		/* FALLTHROUGH */
488184610Salfred	case USB_ST_SETUP:
489188412Sthompsatr_setup:
490184610Salfred		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
491184610Salfred
492188412Sthompsa		if (m == NULL)
493188412Sthompsa			return;
494188412Sthompsa		if (m->m_pkthdr.len > MCLBYTES)
495184610Salfred			m->m_pkthdr.len = MCLBYTES;
496184610Salfred		xfer->frlengths[0] = (m->m_pkthdr.len + 2);
497184610Salfred
498184610Salfred		/* the first two bytes are the frame length */
499184610Salfred
500184610Salfred		buf[0] = (uint8_t)(m->m_pkthdr.len);
501184610Salfred		buf[1] = (uint8_t)(m->m_pkthdr.len >> 8);
502184610Salfred
503184610Salfred		usb2_copy_in(xfer->frbuffers, 0, buf, 2);
504184610Salfred
505184610Salfred		usb2_m_copy_in(xfer->frbuffers, 2,
506184610Salfred		    m, 0, m->m_pkthdr.len);
507184610Salfred
508184610Salfred		/*
509184610Salfred		 * If there's a BPF listener, bounce a copy of this frame
510184610Salfred		 * to him.
511184610Salfred		 */
512184610Salfred		BPF_MTAP(ifp, m);
513184610Salfred
514184610Salfred		m_freem(m);
515184610Salfred
516184610Salfred		usb2_start_hardware(xfer);
517184610Salfred
518184610Salfred		return;
519184610Salfred
520184610Salfred	default:			/* Error */
521184610Salfred		DPRINTFN(11, "transfer error, %s\n",
522184610Salfred		    usb2_errstr(xfer->error));
523184610Salfred
524188412Sthompsa		ifp->if_oerrors++;
525188412Sthompsa
526184610Salfred		if (xfer->error != USB_ERR_CANCELLED) {
527184610Salfred			/* try to clear stall first */
528188412Sthompsa			xfer->flags.stall_pipe = 1;
529188412Sthompsa			goto tr_setup;
530184610Salfred		}
531184610Salfred		return;
532184610Salfred	}
533184610Salfred}
534184610Salfred
535184610Salfredstatic void
536188412Sthompsacue_tick(struct usb2_ether *ue)
537184610Salfred{
538188412Sthompsa	struct cue_softc *sc = usb2_ether_getsc(ue);
539188412Sthompsa	struct ifnet *ifp = usb2_ether_getifp(ue);
540184610Salfred
541188412Sthompsa	CUE_LOCK_ASSERT(sc, MA_OWNED);
542188412Sthompsa
543188412Sthompsa	ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_SINGLECOLL);
544188412Sthompsa	ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_MULTICOLL);
545188412Sthompsa	ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_EXCESSCOLL);
546188412Sthompsa
547188412Sthompsa	if (cue_csr_read_2(sc, CUE_RX_FRAMEERR))
548188412Sthompsa		ifp->if_ierrors++;
549184610Salfred}
550184610Salfred
551184610Salfredstatic void
552188412Sthompsacue_start(struct usb2_ether *ue)
553184610Salfred{
554188412Sthompsa	struct cue_softc *sc = usb2_ether_getsc(ue);
555184610Salfred
556188412Sthompsa	/*
557188412Sthompsa	 * start the USB transfers, if not already started:
558188412Sthompsa	 */
559188412Sthompsa	usb2_transfer_start(sc->sc_xfer[CUE_BULK_DT_RD]);
560188412Sthompsa	usb2_transfer_start(sc->sc_xfer[CUE_BULK_DT_WR]);
561184610Salfred}
562184610Salfred
563184610Salfredstatic void
564188412Sthompsacue_init(struct usb2_ether *ue)
565184610Salfred{
566188412Sthompsa	struct cue_softc *sc = usb2_ether_getsc(ue);
567188412Sthompsa	struct ifnet *ifp = usb2_ether_getifp(ue);
568188412Sthompsa	int i;
569184610Salfred
570188412Sthompsa	CUE_LOCK_ASSERT(sc, MA_OWNED);
571188412Sthompsa
572184610Salfred	/*
573184610Salfred	 * Cancel pending I/O and free all RX/TX buffers.
574184610Salfred	 */
575188412Sthompsa	cue_stop(ue);
576184610Salfred#if 0
577188412Sthompsa	cue_reset(sc);
578184610Salfred#endif
579184610Salfred	/* Set MAC address */
580188412Sthompsa	for (i = 0; i < ETHER_ADDR_LEN; i++)
581188412Sthompsa		cue_csr_write_1(sc, CUE_PAR0 - i, IF_LLADDR(ifp)[i]);
582184610Salfred
583184610Salfred	/* Enable RX logic. */
584188412Sthompsa	cue_csr_write_1(sc, CUE_ETHCTL, CUE_ETHCTL_RX_ON | CUE_ETHCTL_MCAST_ON);
585184610Salfred
586184610Salfred	/* Load the multicast filter */
587188412Sthompsa	cue_setpromisc(ue);
588184610Salfred
589184610Salfred	/*
590184610Salfred	 * Set the number of RX and TX buffers that we want
591184610Salfred	 * to reserve inside the ASIC.
592184610Salfred	 */
593188412Sthompsa	cue_csr_write_1(sc, CUE_RX_BUFPKTS, CUE_RX_FRAMES);
594188412Sthompsa	cue_csr_write_1(sc, CUE_TX_BUFPKTS, CUE_TX_FRAMES);
595184610Salfred
596184610Salfred	/* Set advanced operation modes. */
597188412Sthompsa	cue_csr_write_1(sc, CUE_ADVANCED_OPMODES,
598184610Salfred	    CUE_AOP_EMBED_RXLEN | 0x01);/* 1 wait state */
599184610Salfred
600184610Salfred	/* Program the LED operation. */
601188412Sthompsa	cue_csr_write_1(sc, CUE_LEDCTL, CUE_LEDCTL_FOLLOW_LINK);
602184610Salfred
603188412Sthompsa	usb2_transfer_set_stall(sc->sc_xfer[CUE_BULK_DT_WR]);
604184610Salfred
605188412Sthompsa	ifp->if_drv_flags |= IFF_DRV_RUNNING;
606188412Sthompsa	cue_start(ue);
607184610Salfred}
608184610Salfred
609184610Salfred/*
610184610Salfred * Stop the adapter and free any mbufs allocated to the
611184610Salfred * RX and TX lists.
612184610Salfred */
613184610Salfredstatic void
614188412Sthompsacue_stop(struct usb2_ether *ue)
615184610Salfred{
616188412Sthompsa	struct cue_softc *sc = usb2_ether_getsc(ue);
617188412Sthompsa	struct ifnet *ifp = usb2_ether_getifp(ue);
618184610Salfred
619188412Sthompsa	CUE_LOCK_ASSERT(sc, MA_OWNED);
620184610Salfred
621188412Sthompsa	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
622184610Salfred
623184610Salfred	/*
624184610Salfred	 * stop all the transfers, if not already stopped:
625184610Salfred	 */
626187259Sthompsa	usb2_transfer_stop(sc->sc_xfer[CUE_BULK_DT_WR]);
627187259Sthompsa	usb2_transfer_stop(sc->sc_xfer[CUE_BULK_DT_RD]);
628184610Salfred
629188412Sthompsa	cue_csr_write_1(sc, CUE_ETHCTL, 0);
630188412Sthompsa	cue_reset(sc);
631184610Salfred}
632184610Salfred
633184610Salfred/*
634184610Salfred * Stop all chip I/O so that the kernel's probe routines don't
635184610Salfred * get confused by errant DMAs when rebooting.
636184610Salfred */
637184610Salfredstatic int
638184610Salfredcue_shutdown(device_t dev)
639184610Salfred{
640184610Salfred	struct cue_softc *sc = device_get_softc(dev);
641184610Salfred
642188412Sthompsa	usb2_ether_ifshutdown(&sc->sc_ue);
643184610Salfred
644184610Salfred	return (0);
645184610Salfred}
646