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