if_cue.c revision 192499
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/usb/net/if_cue.c 192499 2009-05-21 00:04:17Z 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" 55188942Sthompsa#include <dev/usb/usb.h> 56188942Sthompsa#include <dev/usb/usb_mfunc.h> 57188942Sthompsa#include <dev/usb/usb_error.h> 58184610Salfred 59184610Salfred#define USB_DEBUG_VAR cue_debug 60184610Salfred 61188942Sthompsa#include <dev/usb/usb_core.h> 62188942Sthompsa#include <dev/usb/usb_lookup.h> 63188942Sthompsa#include <dev/usb/usb_process.h> 64188942Sthompsa#include <dev/usb/usb_debug.h> 65188942Sthompsa#include <dev/usb/usb_request.h> 66188942Sthompsa#include <dev/usb/usb_busdma.h> 67188942Sthompsa#include <dev/usb/usb_util.h> 68184610Salfred 69188942Sthompsa#include <dev/usb/net/usb_ethernet.h> 70188942Sthompsa#include <dev/usb/net/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; 89184610Salfred 90184610Salfredstatic usb2_callback_t cue_bulk_read_callback; 91184610Salfredstatic usb2_callback_t cue_bulk_write_callback; 92184610Salfred 93188412Sthompsastatic usb2_ether_fn_t cue_attach_post; 94188412Sthompsastatic usb2_ether_fn_t cue_init; 95188412Sthompsastatic usb2_ether_fn_t cue_stop; 96188412Sthompsastatic usb2_ether_fn_t cue_start; 97188412Sthompsastatic usb2_ether_fn_t cue_tick; 98188412Sthompsastatic usb2_ether_fn_t cue_setmulti; 99188412Sthompsastatic usb2_ether_fn_t cue_setpromisc; 100184610Salfred 101188412Sthompsastatic uint8_t cue_csr_read_1(struct cue_softc *, uint16_t); 102188412Sthompsastatic uint16_t cue_csr_read_2(struct cue_softc *, uint8_t); 103188412Sthompsastatic int cue_csr_write_1(struct cue_softc *, uint16_t, uint16_t); 104188412Sthompsastatic int cue_mem(struct cue_softc *, uint8_t, uint16_t, void *, int); 105188412Sthompsastatic int cue_getmac(struct cue_softc *, void *); 106188412Sthompsastatic uint32_t cue_mchash(const uint8_t *); 107188412Sthompsastatic void cue_reset(struct cue_softc *); 108184610Salfred 109184610Salfred#if USB_DEBUG 110184610Salfredstatic int cue_debug = 0; 111184610Salfred 112184610SalfredSYSCTL_NODE(_hw_usb2, OID_AUTO, cue, CTLFLAG_RW, 0, "USB cue"); 113184610SalfredSYSCTL_INT(_hw_usb2_cue, OID_AUTO, debug, CTLFLAG_RW, &cue_debug, 0, 114184610Salfred "Debug level"); 115184610Salfred#endif 116184610Salfred 117187259Sthompsastatic const struct usb2_config cue_config[CUE_N_TRANSFER] = { 118184610Salfred 119187259Sthompsa [CUE_BULK_DT_WR] = { 120184610Salfred .type = UE_BULK, 121184610Salfred .endpoint = UE_ADDR_ANY, 122184610Salfred .direction = UE_DIR_OUT, 123190734Sthompsa .bufsize = (MCLBYTES + 2), 124190734Sthompsa .flags = {.pipe_bof = 1,}, 125190734Sthompsa .callback = cue_bulk_write_callback, 126190734Sthompsa .timeout = 10000, /* 10 seconds */ 127184610Salfred }, 128184610Salfred 129187259Sthompsa [CUE_BULK_DT_RD] = { 130184610Salfred .type = UE_BULK, 131184610Salfred .endpoint = UE_ADDR_ANY, 132184610Salfred .direction = UE_DIR_IN, 133190734Sthompsa .bufsize = (MCLBYTES + 2), 134190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 135190734Sthompsa .callback = cue_bulk_read_callback, 136184610Salfred }, 137184610Salfred}; 138184610Salfred 139184610Salfredstatic device_method_t cue_methods[] = { 140184610Salfred /* Device interface */ 141184610Salfred DEVMETHOD(device_probe, cue_probe), 142184610Salfred DEVMETHOD(device_attach, cue_attach), 143184610Salfred DEVMETHOD(device_detach, cue_detach), 144184610Salfred 145184610Salfred {0, 0} 146184610Salfred}; 147184610Salfred 148184610Salfredstatic driver_t cue_driver = { 149184610Salfred .name = "cue", 150184610Salfred .methods = cue_methods, 151184610Salfred .size = sizeof(struct cue_softc), 152184610Salfred}; 153184610Salfred 154184610Salfredstatic devclass_t cue_devclass; 155184610Salfred 156189275SthompsaDRIVER_MODULE(cue, uhub, cue_driver, cue_devclass, NULL, 0); 157188942SthompsaMODULE_DEPEND(cue, uether, 1, 1, 1); 158188942SthompsaMODULE_DEPEND(cue, usb, 1, 1, 1); 159184610SalfredMODULE_DEPEND(cue, ether, 1, 1, 1); 160184610Salfred 161188412Sthompsastatic const struct usb2_ether_methods cue_ue_methods = { 162188412Sthompsa .ue_attach_post = cue_attach_post, 163188412Sthompsa .ue_start = cue_start, 164188412Sthompsa .ue_init = cue_init, 165188412Sthompsa .ue_stop = cue_stop, 166188412Sthompsa .ue_tick = cue_tick, 167188412Sthompsa .ue_setmulti = cue_setmulti, 168188412Sthompsa .ue_setpromisc = cue_setpromisc, 169188412Sthompsa}; 170184610Salfred 171188412Sthompsa#define CUE_SETBIT(sc, reg, x) \ 172188412Sthompsa cue_csr_write_1(sc, reg, cue_csr_read_1(sc, reg) | (x)) 173184610Salfred 174188412Sthompsa#define CUE_CLRBIT(sc, reg, x) \ 175188412Sthompsa cue_csr_write_1(sc, reg, cue_csr_read_1(sc, reg) & ~(x)) 176184610Salfred 177184610Salfredstatic uint8_t 178188412Sthompsacue_csr_read_1(struct cue_softc *sc, uint16_t reg) 179184610Salfred{ 180184610Salfred struct usb2_device_request req; 181184610Salfred uint8_t val; 182184610Salfred 183184610Salfred req.bmRequestType = UT_READ_VENDOR_DEVICE; 184184610Salfred req.bRequest = CUE_CMD_READREG; 185184610Salfred USETW(req.wValue, 0); 186184610Salfred USETW(req.wIndex, reg); 187184610Salfred USETW(req.wLength, 1); 188184610Salfred 189188412Sthompsa if (usb2_ether_do_request(&sc->sc_ue, &req, &val, 1000)) { 190188412Sthompsa /* ignore any errors */ 191188412Sthompsa } 192184610Salfred return (val); 193184610Salfred} 194184610Salfred 195184610Salfredstatic uint16_t 196188412Sthompsacue_csr_read_2(struct cue_softc *sc, uint8_t reg) 197184610Salfred{ 198184610Salfred struct usb2_device_request req; 199184610Salfred uint16_t val; 200184610Salfred 201184610Salfred req.bmRequestType = UT_READ_VENDOR_DEVICE; 202184610Salfred req.bRequest = CUE_CMD_READREG; 203184610Salfred USETW(req.wValue, 0); 204184610Salfred USETW(req.wIndex, reg); 205184610Salfred USETW(req.wLength, 2); 206184610Salfred 207188412Sthompsa (void)usb2_ether_do_request(&sc->sc_ue, &req, &val, 1000); 208184610Salfred return (le16toh(val)); 209184610Salfred} 210184610Salfred 211188412Sthompsastatic int 212188412Sthompsacue_csr_write_1(struct cue_softc *sc, uint16_t reg, uint16_t val) 213184610Salfred{ 214184610Salfred struct usb2_device_request req; 215184610Salfred 216184610Salfred req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 217184610Salfred req.bRequest = CUE_CMD_WRITEREG; 218184610Salfred USETW(req.wValue, val); 219184610Salfred USETW(req.wIndex, reg); 220184610Salfred USETW(req.wLength, 0); 221184610Salfred 222188412Sthompsa return (usb2_ether_do_request(&sc->sc_ue, &req, NULL, 1000)); 223184610Salfred} 224184610Salfred 225188412Sthompsastatic int 226188412Sthompsacue_mem(struct cue_softc *sc, uint8_t cmd, uint16_t addr, void *buf, int len) 227184610Salfred{ 228184610Salfred struct usb2_device_request req; 229184610Salfred 230188412Sthompsa if (cmd == CUE_CMD_READSRAM) 231184610Salfred req.bmRequestType = UT_READ_VENDOR_DEVICE; 232188412Sthompsa else 233184610Salfred req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 234184610Salfred req.bRequest = cmd; 235184610Salfred USETW(req.wValue, 0); 236184610Salfred USETW(req.wIndex, addr); 237184610Salfred USETW(req.wLength, len); 238184610Salfred 239188412Sthompsa return (usb2_ether_do_request(&sc->sc_ue, &req, buf, 1000)); 240184610Salfred} 241184610Salfred 242188412Sthompsastatic int 243188412Sthompsacue_getmac(struct cue_softc *sc, void *buf) 244184610Salfred{ 245184610Salfred struct usb2_device_request req; 246184610Salfred 247184610Salfred req.bmRequestType = UT_READ_VENDOR_DEVICE; 248184610Salfred req.bRequest = CUE_CMD_GET_MACADDR; 249184610Salfred USETW(req.wValue, 0); 250184610Salfred USETW(req.wIndex, 0); 251184610Salfred USETW(req.wLength, ETHER_ADDR_LEN); 252184610Salfred 253188412Sthompsa return (usb2_ether_do_request(&sc->sc_ue, &req, buf, 1000)); 254184610Salfred} 255184610Salfred 256184610Salfred#define CUE_BITS 9 257184610Salfred 258188412Sthompsastatic uint32_t 259188412Sthompsacue_mchash(const uint8_t *addr) 260184610Salfred{ 261188412Sthompsa uint32_t crc; 262184610Salfred 263188412Sthompsa /* Compute CRC for the address value. */ 264188412Sthompsa crc = ether_crc32_le(addr, ETHER_ADDR_LEN); 265188412Sthompsa 266188412Sthompsa return (crc & ((1 << CUE_BITS) - 1)); 267184610Salfred} 268184610Salfred 269184610Salfredstatic void 270188412Sthompsacue_setpromisc(struct usb2_ether *ue) 271184610Salfred{ 272188412Sthompsa struct cue_softc *sc = usb2_ether_getsc(ue); 273188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(ue); 274188412Sthompsa 275188412Sthompsa CUE_LOCK_ASSERT(sc, MA_OWNED); 276188412Sthompsa 277184610Salfred /* if we want promiscuous mode, set the allframes bit */ 278188412Sthompsa if (ifp->if_flags & IFF_PROMISC) 279188412Sthompsa CUE_SETBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC); 280188412Sthompsa else 281188412Sthompsa CUE_CLRBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC); 282184610Salfred 283184610Salfred /* write multicast hash-bits */ 284188412Sthompsa cue_setmulti(ue); 285184610Salfred} 286184610Salfred 287184610Salfredstatic void 288188412Sthompsacue_setmulti(struct usb2_ether *ue) 289184610Salfred{ 290188412Sthompsa struct cue_softc *sc = usb2_ether_getsc(ue); 291188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(ue); 292188412Sthompsa struct ifmultiaddr *ifma; 293188412Sthompsa uint32_t h = 0, i; 294188412Sthompsa uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 295188412Sthompsa 296188412Sthompsa CUE_LOCK_ASSERT(sc, MA_OWNED); 297188412Sthompsa 298188412Sthompsa if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 299188412Sthompsa for (i = 0; i < 8; i++) 300188412Sthompsa hashtbl[i] = 0xff; 301188412Sthompsa cue_mem(sc, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR, 302188412Sthompsa &hashtbl, 8); 303188412Sthompsa return; 304188412Sthompsa } 305188412Sthompsa 306188412Sthompsa /* now program new ones */ 307188412Sthompsa IF_ADDR_LOCK(ifp); 308188412Sthompsa TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) 309188412Sthompsa { 310188412Sthompsa if (ifma->ifma_addr->sa_family != AF_LINK) 311188412Sthompsa continue; 312188412Sthompsa h = cue_mchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 313188412Sthompsa hashtbl[h >> 3] |= 1 << (h & 0x7); 314188412Sthompsa } 315188412Sthompsa IF_ADDR_UNLOCK(ifp); 316188412Sthompsa 317188412Sthompsa /* 318188412Sthompsa * Also include the broadcast address in the filter 319188412Sthompsa * so we can receive broadcast frames. 320188412Sthompsa */ 321188412Sthompsa if (ifp->if_flags & IFF_BROADCAST) { 322188412Sthompsa h = cue_mchash(ifp->if_broadcastaddr); 323188412Sthompsa hashtbl[h >> 3] |= 1 << (h & 0x7); 324188412Sthompsa } 325188412Sthompsa 326188412Sthompsa cue_mem(sc, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR, &hashtbl, 8); 327184610Salfred} 328184610Salfred 329184610Salfredstatic void 330188412Sthompsacue_reset(struct cue_softc *sc) 331184610Salfred{ 332184610Salfred struct usb2_device_request req; 333184610Salfred 334184610Salfred req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 335184610Salfred req.bRequest = CUE_CMD_RESET; 336184610Salfred USETW(req.wValue, 0); 337184610Salfred USETW(req.wIndex, 0); 338184610Salfred USETW(req.wLength, 0); 339184610Salfred 340188412Sthompsa if (usb2_ether_do_request(&sc->sc_ue, &req, NULL, 1000)) { 341188412Sthompsa /* ignore any errors */ 342188412Sthompsa } 343184610Salfred 344184610Salfred /* 345184610Salfred * wait a little while for the chip to get its brains in order: 346184610Salfred */ 347188412Sthompsa usb2_ether_pause(&sc->sc_ue, hz / 100); 348188412Sthompsa} 349184610Salfred 350188412Sthompsastatic void 351188412Sthompsacue_attach_post(struct usb2_ether *ue) 352188412Sthompsa{ 353188412Sthompsa struct cue_softc *sc = usb2_ether_getsc(ue); 354188412Sthompsa 355188412Sthompsa cue_getmac(sc, ue->ue_eaddr); 356184610Salfred} 357184610Salfred 358184610Salfredstatic int 359184610Salfredcue_probe(device_t dev) 360184610Salfred{ 361184610Salfred struct usb2_attach_arg *uaa = device_get_ivars(dev); 362184610Salfred 363192499Sthompsa if (uaa->usb_mode != USB_MODE_HOST) 364184610Salfred return (ENXIO); 365188412Sthompsa if (uaa->info.bConfigIndex != CUE_CONFIG_IDX) 366184610Salfred return (ENXIO); 367188412Sthompsa if (uaa->info.bIfaceIndex != CUE_IFACE_IDX) 368184610Salfred return (ENXIO); 369188412Sthompsa 370184610Salfred return (usb2_lookup_id_by_uaa(cue_devs, sizeof(cue_devs), uaa)); 371184610Salfred} 372184610Salfred 373188412Sthompsa/* 374188412Sthompsa * Attach the interface. Allocate softc structures, do ifmedia 375188412Sthompsa * setup and ethernet/BPF attach. 376188412Sthompsa */ 377184610Salfredstatic int 378184610Salfredcue_attach(device_t dev) 379184610Salfred{ 380184610Salfred struct usb2_attach_arg *uaa = device_get_ivars(dev); 381184610Salfred struct cue_softc *sc = device_get_softc(dev); 382188412Sthompsa struct usb2_ether *ue = &sc->sc_ue; 383184610Salfred uint8_t iface_index; 384188412Sthompsa int error; 385184610Salfred 386184610Salfred device_set_usb2_desc(dev); 387188412Sthompsa mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 388184610Salfred 389184610Salfred iface_index = CUE_IFACE_IDX; 390184610Salfred error = usb2_transfer_setup(uaa->device, &iface_index, 391187259Sthompsa sc->sc_xfer, cue_config, CUE_N_TRANSFER, sc, &sc->sc_mtx); 392184610Salfred if (error) { 393188412Sthompsa device_printf(dev, "allocating USB transfers failed!\n"); 394184610Salfred goto detach; 395184610Salfred } 396188412Sthompsa 397188412Sthompsa ue->ue_sc = sc; 398188412Sthompsa ue->ue_dev = dev; 399188412Sthompsa ue->ue_udev = uaa->device; 400188412Sthompsa ue->ue_mtx = &sc->sc_mtx; 401188412Sthompsa ue->ue_methods = &cue_ue_methods; 402188412Sthompsa 403188412Sthompsa error = usb2_ether_ifattach(ue); 404184610Salfred if (error) { 405188412Sthompsa device_printf(dev, "could not attach interface\n"); 406184610Salfred goto detach; 407184610Salfred } 408184610Salfred return (0); /* success */ 409184610Salfred 410184610Salfreddetach: 411184610Salfred cue_detach(dev); 412184610Salfred return (ENXIO); /* failure */ 413184610Salfred} 414184610Salfred 415184610Salfredstatic int 416184610Salfredcue_detach(device_t dev) 417184610Salfred{ 418184610Salfred struct cue_softc *sc = device_get_softc(dev); 419188412Sthompsa struct usb2_ether *ue = &sc->sc_ue; 420184610Salfred 421187259Sthompsa usb2_transfer_unsetup(sc->sc_xfer, CUE_N_TRANSFER); 422188412Sthompsa usb2_ether_ifdetach(ue); 423184610Salfred mtx_destroy(&sc->sc_mtx); 424184610Salfred 425184610Salfred return (0); 426184610Salfred} 427184610Salfred 428184610Salfredstatic void 429184610Salfredcue_bulk_read_callback(struct usb2_xfer *xfer) 430184610Salfred{ 431184610Salfred struct cue_softc *sc = xfer->priv_sc; 432188412Sthompsa struct usb2_ether *ue = &sc->sc_ue; 433188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(ue); 434184610Salfred uint8_t buf[2]; 435188412Sthompsa int len; 436184610Salfred 437184610Salfred switch (USB_GET_STATE(xfer)) { 438184610Salfred case USB_ST_TRANSFERRED: 439184610Salfred 440184610Salfred if (xfer->actlen <= (2 + sizeof(struct ether_header))) { 441184610Salfred ifp->if_ierrors++; 442184610Salfred goto tr_setup; 443184610Salfred } 444184610Salfred usb2_copy_out(xfer->frbuffers, 0, buf, 2); 445188412Sthompsa xfer->actlen -= 2; 446184610Salfred len = buf[0] | (buf[1] << 8); 447188412Sthompsa len = min(xfer->actlen, len); 448184610Salfred 449188412Sthompsa usb2_ether_rxbuf(ue, xfer->frbuffers, 2, len); 450188412Sthompsa /* FALLTHROUGH */ 451184610Salfred case USB_ST_SETUP: 452184610Salfredtr_setup: 453188412Sthompsa xfer->frlengths[0] = xfer->max_data_length; 454188412Sthompsa usb2_start_hardware(xfer); 455188412Sthompsa usb2_ether_rxflush(ue); 456184610Salfred return; 457184610Salfred 458184610Salfred default: /* Error */ 459188412Sthompsa DPRINTF("bulk read error, %s\n", 460188412Sthompsa usb2_errstr(xfer->error)); 461188412Sthompsa 462184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 463184610Salfred /* try to clear stall first */ 464188412Sthompsa xfer->flags.stall_pipe = 1; 465188412Sthompsa goto tr_setup; 466184610Salfred } 467184610Salfred return; 468184610Salfred 469184610Salfred } 470184610Salfred} 471184610Salfred 472184610Salfredstatic void 473184610Salfredcue_bulk_write_callback(struct usb2_xfer *xfer) 474184610Salfred{ 475184610Salfred struct cue_softc *sc = xfer->priv_sc; 476188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(&sc->sc_ue); 477184610Salfred struct mbuf *m; 478184610Salfred uint8_t buf[2]; 479184610Salfred 480184610Salfred switch (USB_GET_STATE(xfer)) { 481184610Salfred case USB_ST_TRANSFERRED: 482184610Salfred DPRINTFN(11, "transfer complete\n"); 483184610Salfred ifp->if_opackets++; 484184610Salfred 485188412Sthompsa /* FALLTHROUGH */ 486184610Salfred case USB_ST_SETUP: 487188412Sthompsatr_setup: 488184610Salfred IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 489184610Salfred 490188412Sthompsa if (m == NULL) 491188412Sthompsa return; 492188412Sthompsa if (m->m_pkthdr.len > MCLBYTES) 493184610Salfred m->m_pkthdr.len = MCLBYTES; 494184610Salfred xfer->frlengths[0] = (m->m_pkthdr.len + 2); 495184610Salfred 496184610Salfred /* the first two bytes are the frame length */ 497184610Salfred 498184610Salfred buf[0] = (uint8_t)(m->m_pkthdr.len); 499184610Salfred buf[1] = (uint8_t)(m->m_pkthdr.len >> 8); 500184610Salfred 501184610Salfred usb2_copy_in(xfer->frbuffers, 0, buf, 2); 502184610Salfred 503184610Salfred usb2_m_copy_in(xfer->frbuffers, 2, 504184610Salfred m, 0, m->m_pkthdr.len); 505184610Salfred 506184610Salfred /* 507184610Salfred * If there's a BPF listener, bounce a copy of this frame 508184610Salfred * to him. 509184610Salfred */ 510184610Salfred BPF_MTAP(ifp, m); 511184610Salfred 512184610Salfred m_freem(m); 513184610Salfred 514184610Salfred usb2_start_hardware(xfer); 515184610Salfred 516184610Salfred return; 517184610Salfred 518184610Salfred default: /* Error */ 519184610Salfred DPRINTFN(11, "transfer error, %s\n", 520184610Salfred usb2_errstr(xfer->error)); 521184610Salfred 522188412Sthompsa ifp->if_oerrors++; 523188412Sthompsa 524184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 525184610Salfred /* try to clear stall first */ 526188412Sthompsa xfer->flags.stall_pipe = 1; 527188412Sthompsa goto tr_setup; 528184610Salfred } 529184610Salfred return; 530184610Salfred } 531184610Salfred} 532184610Salfred 533184610Salfredstatic void 534188412Sthompsacue_tick(struct usb2_ether *ue) 535184610Salfred{ 536188412Sthompsa struct cue_softc *sc = usb2_ether_getsc(ue); 537188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(ue); 538184610Salfred 539188412Sthompsa CUE_LOCK_ASSERT(sc, MA_OWNED); 540188412Sthompsa 541188412Sthompsa ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_SINGLECOLL); 542188412Sthompsa ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_MULTICOLL); 543188412Sthompsa ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_EXCESSCOLL); 544188412Sthompsa 545188412Sthompsa if (cue_csr_read_2(sc, CUE_RX_FRAMEERR)) 546188412Sthompsa ifp->if_ierrors++; 547184610Salfred} 548184610Salfred 549184610Salfredstatic void 550188412Sthompsacue_start(struct usb2_ether *ue) 551184610Salfred{ 552188412Sthompsa struct cue_softc *sc = usb2_ether_getsc(ue); 553184610Salfred 554188412Sthompsa /* 555188412Sthompsa * start the USB transfers, if not already started: 556188412Sthompsa */ 557188412Sthompsa usb2_transfer_start(sc->sc_xfer[CUE_BULK_DT_RD]); 558188412Sthompsa usb2_transfer_start(sc->sc_xfer[CUE_BULK_DT_WR]); 559184610Salfred} 560184610Salfred 561184610Salfredstatic void 562188412Sthompsacue_init(struct usb2_ether *ue) 563184610Salfred{ 564188412Sthompsa struct cue_softc *sc = usb2_ether_getsc(ue); 565188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(ue); 566188412Sthompsa int i; 567184610Salfred 568188412Sthompsa CUE_LOCK_ASSERT(sc, MA_OWNED); 569188412Sthompsa 570184610Salfred /* 571184610Salfred * Cancel pending I/O and free all RX/TX buffers. 572184610Salfred */ 573188412Sthompsa cue_stop(ue); 574184610Salfred#if 0 575188412Sthompsa cue_reset(sc); 576184610Salfred#endif 577184610Salfred /* Set MAC address */ 578188412Sthompsa for (i = 0; i < ETHER_ADDR_LEN; i++) 579188412Sthompsa cue_csr_write_1(sc, CUE_PAR0 - i, IF_LLADDR(ifp)[i]); 580184610Salfred 581184610Salfred /* Enable RX logic. */ 582188412Sthompsa cue_csr_write_1(sc, CUE_ETHCTL, CUE_ETHCTL_RX_ON | CUE_ETHCTL_MCAST_ON); 583184610Salfred 584184610Salfred /* Load the multicast filter */ 585188412Sthompsa cue_setpromisc(ue); 586184610Salfred 587184610Salfred /* 588184610Salfred * Set the number of RX and TX buffers that we want 589184610Salfred * to reserve inside the ASIC. 590184610Salfred */ 591188412Sthompsa cue_csr_write_1(sc, CUE_RX_BUFPKTS, CUE_RX_FRAMES); 592188412Sthompsa cue_csr_write_1(sc, CUE_TX_BUFPKTS, CUE_TX_FRAMES); 593184610Salfred 594184610Salfred /* Set advanced operation modes. */ 595188412Sthompsa cue_csr_write_1(sc, CUE_ADVANCED_OPMODES, 596184610Salfred CUE_AOP_EMBED_RXLEN | 0x01);/* 1 wait state */ 597184610Salfred 598184610Salfred /* Program the LED operation. */ 599188412Sthompsa cue_csr_write_1(sc, CUE_LEDCTL, CUE_LEDCTL_FOLLOW_LINK); 600184610Salfred 601188412Sthompsa usb2_transfer_set_stall(sc->sc_xfer[CUE_BULK_DT_WR]); 602184610Salfred 603188412Sthompsa ifp->if_drv_flags |= IFF_DRV_RUNNING; 604188412Sthompsa cue_start(ue); 605184610Salfred} 606184610Salfred 607184610Salfred/* 608184610Salfred * Stop the adapter and free any mbufs allocated to the 609184610Salfred * RX and TX lists. 610184610Salfred */ 611184610Salfredstatic void 612188412Sthompsacue_stop(struct usb2_ether *ue) 613184610Salfred{ 614188412Sthompsa struct cue_softc *sc = usb2_ether_getsc(ue); 615188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(ue); 616184610Salfred 617188412Sthompsa CUE_LOCK_ASSERT(sc, MA_OWNED); 618184610Salfred 619188412Sthompsa ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 620184610Salfred 621184610Salfred /* 622184610Salfred * stop all the transfers, if not already stopped: 623184610Salfred */ 624187259Sthompsa usb2_transfer_stop(sc->sc_xfer[CUE_BULK_DT_WR]); 625187259Sthompsa usb2_transfer_stop(sc->sc_xfer[CUE_BULK_DT_RD]); 626184610Salfred 627188412Sthompsa cue_csr_write_1(sc, CUE_ETHCTL, 0); 628188412Sthompsa cue_reset(sc); 629184610Salfred} 630