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$"); 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 54194677Sthompsa#include <sys/stdint.h> 55194677Sthompsa#include <sys/stddef.h> 56194677Sthompsa#include <sys/param.h> 57194677Sthompsa#include <sys/queue.h> 58194677Sthompsa#include <sys/types.h> 59194677Sthompsa#include <sys/systm.h> 60194677Sthompsa#include <sys/kernel.h> 61194677Sthompsa#include <sys/bus.h> 62194677Sthompsa#include <sys/module.h> 63194677Sthompsa#include <sys/lock.h> 64194677Sthompsa#include <sys/mutex.h> 65194677Sthompsa#include <sys/condvar.h> 66194677Sthompsa#include <sys/sysctl.h> 67194677Sthompsa#include <sys/sx.h> 68194677Sthompsa#include <sys/unistd.h> 69194677Sthompsa#include <sys/callout.h> 70194677Sthompsa#include <sys/malloc.h> 71194677Sthompsa#include <sys/priv.h> 72194677Sthompsa 73194677Sthompsa#include <dev/usb/usb.h> 74194677Sthompsa#include <dev/usb/usbdi.h> 75194677Sthompsa#include <dev/usb/usbdi_util.h> 76188746Sthompsa#include "usbdevs.h" 77184610Salfred 78184610Salfred#define USB_DEBUG_VAR cue_debug 79194677Sthompsa#include <dev/usb/usb_debug.h> 80188942Sthompsa#include <dev/usb/usb_process.h> 81184610Salfred 82188942Sthompsa#include <dev/usb/net/usb_ethernet.h> 83188942Sthompsa#include <dev/usb/net/if_cuereg.h> 84184610Salfred 85184610Salfred/* 86184610Salfred * Various supported device vendors/products. 87184610Salfred */ 88184610Salfred 89184610Salfred/* Belkin F5U111 adapter covered by NETMATE entry */ 90184610Salfred 91223486Shselaskystatic const STRUCT_USB_HOST_ID cue_devs[] = { 92201028Sthompsa#define CUE_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) } 93201028Sthompsa CUE_DEV(CATC, NETMATE), 94201028Sthompsa CUE_DEV(CATC, NETMATE2), 95201028Sthompsa CUE_DEV(SMARTBRIDGES, SMARTLINK), 96201028Sthompsa#undef CUE_DEV 97184610Salfred}; 98184610Salfred 99184610Salfred/* prototypes */ 100184610Salfred 101184610Salfredstatic device_probe_t cue_probe; 102184610Salfredstatic device_attach_t cue_attach; 103184610Salfredstatic device_detach_t cue_detach; 104184610Salfred 105193045Sthompsastatic usb_callback_t cue_bulk_read_callback; 106193045Sthompsastatic usb_callback_t cue_bulk_write_callback; 107184610Salfred 108193045Sthompsastatic uether_fn_t cue_attach_post; 109193045Sthompsastatic uether_fn_t cue_init; 110193045Sthompsastatic uether_fn_t cue_stop; 111193045Sthompsastatic uether_fn_t cue_start; 112193045Sthompsastatic uether_fn_t cue_tick; 113193045Sthompsastatic uether_fn_t cue_setmulti; 114193045Sthompsastatic uether_fn_t cue_setpromisc; 115184610Salfred 116188412Sthompsastatic uint8_t cue_csr_read_1(struct cue_softc *, uint16_t); 117188412Sthompsastatic uint16_t cue_csr_read_2(struct cue_softc *, uint8_t); 118188412Sthompsastatic int cue_csr_write_1(struct cue_softc *, uint16_t, uint16_t); 119188412Sthompsastatic int cue_mem(struct cue_softc *, uint8_t, uint16_t, void *, int); 120188412Sthompsastatic int cue_getmac(struct cue_softc *, void *); 121188412Sthompsastatic uint32_t cue_mchash(const uint8_t *); 122188412Sthompsastatic void cue_reset(struct cue_softc *); 123184610Salfred 124207077Sthompsa#ifdef USB_DEBUG 125184610Salfredstatic int cue_debug = 0; 126184610Salfred 127227309Sedstatic SYSCTL_NODE(_hw_usb, OID_AUTO, cue, CTLFLAG_RW, 0, "USB cue"); 128192502SthompsaSYSCTL_INT(_hw_usb_cue, OID_AUTO, debug, CTLFLAG_RW, &cue_debug, 0, 129184610Salfred "Debug level"); 130184610Salfred#endif 131184610Salfred 132192984Sthompsastatic const struct usb_config cue_config[CUE_N_TRANSFER] = { 133184610Salfred 134187259Sthompsa [CUE_BULK_DT_WR] = { 135184610Salfred .type = UE_BULK, 136184610Salfred .endpoint = UE_ADDR_ANY, 137184610Salfred .direction = UE_DIR_OUT, 138190734Sthompsa .bufsize = (MCLBYTES + 2), 139190734Sthompsa .flags = {.pipe_bof = 1,}, 140190734Sthompsa .callback = cue_bulk_write_callback, 141190734Sthompsa .timeout = 10000, /* 10 seconds */ 142184610Salfred }, 143184610Salfred 144187259Sthompsa [CUE_BULK_DT_RD] = { 145184610Salfred .type = UE_BULK, 146184610Salfred .endpoint = UE_ADDR_ANY, 147184610Salfred .direction = UE_DIR_IN, 148190734Sthompsa .bufsize = (MCLBYTES + 2), 149190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 150190734Sthompsa .callback = cue_bulk_read_callback, 151184610Salfred }, 152184610Salfred}; 153184610Salfred 154184610Salfredstatic device_method_t cue_methods[] = { 155184610Salfred /* Device interface */ 156184610Salfred DEVMETHOD(device_probe, cue_probe), 157184610Salfred DEVMETHOD(device_attach, cue_attach), 158184610Salfred DEVMETHOD(device_detach, cue_detach), 159184610Salfred 160246128Ssbz DEVMETHOD_END 161184610Salfred}; 162184610Salfred 163184610Salfredstatic driver_t cue_driver = { 164184610Salfred .name = "cue", 165184610Salfred .methods = cue_methods, 166184610Salfred .size = sizeof(struct cue_softc), 167184610Salfred}; 168184610Salfred 169184610Salfredstatic devclass_t cue_devclass; 170184610Salfred 171189275SthompsaDRIVER_MODULE(cue, uhub, cue_driver, cue_devclass, NULL, 0); 172188942SthompsaMODULE_DEPEND(cue, uether, 1, 1, 1); 173188942SthompsaMODULE_DEPEND(cue, usb, 1, 1, 1); 174184610SalfredMODULE_DEPEND(cue, ether, 1, 1, 1); 175212122SthompsaMODULE_VERSION(cue, 1); 176184610Salfred 177192984Sthompsastatic const struct usb_ether_methods cue_ue_methods = { 178188412Sthompsa .ue_attach_post = cue_attach_post, 179188412Sthompsa .ue_start = cue_start, 180188412Sthompsa .ue_init = cue_init, 181188412Sthompsa .ue_stop = cue_stop, 182188412Sthompsa .ue_tick = cue_tick, 183188412Sthompsa .ue_setmulti = cue_setmulti, 184188412Sthompsa .ue_setpromisc = cue_setpromisc, 185188412Sthompsa}; 186184610Salfred 187188412Sthompsa#define CUE_SETBIT(sc, reg, x) \ 188188412Sthompsa cue_csr_write_1(sc, reg, cue_csr_read_1(sc, reg) | (x)) 189184610Salfred 190188412Sthompsa#define CUE_CLRBIT(sc, reg, x) \ 191188412Sthompsa cue_csr_write_1(sc, reg, cue_csr_read_1(sc, reg) & ~(x)) 192184610Salfred 193184610Salfredstatic uint8_t 194188412Sthompsacue_csr_read_1(struct cue_softc *sc, uint16_t reg) 195184610Salfred{ 196192984Sthompsa struct usb_device_request req; 197184610Salfred uint8_t val; 198184610Salfred 199184610Salfred req.bmRequestType = UT_READ_VENDOR_DEVICE; 200184610Salfred req.bRequest = CUE_CMD_READREG; 201184610Salfred USETW(req.wValue, 0); 202184610Salfred USETW(req.wIndex, reg); 203184610Salfred USETW(req.wLength, 1); 204184610Salfred 205194228Sthompsa if (uether_do_request(&sc->sc_ue, &req, &val, 1000)) { 206188412Sthompsa /* ignore any errors */ 207188412Sthompsa } 208184610Salfred return (val); 209184610Salfred} 210184610Salfred 211184610Salfredstatic uint16_t 212188412Sthompsacue_csr_read_2(struct cue_softc *sc, uint8_t reg) 213184610Salfred{ 214192984Sthompsa struct usb_device_request req; 215184610Salfred uint16_t val; 216184610Salfred 217184610Salfred req.bmRequestType = UT_READ_VENDOR_DEVICE; 218184610Salfred req.bRequest = CUE_CMD_READREG; 219184610Salfred USETW(req.wValue, 0); 220184610Salfred USETW(req.wIndex, reg); 221184610Salfred USETW(req.wLength, 2); 222184610Salfred 223194228Sthompsa (void)uether_do_request(&sc->sc_ue, &req, &val, 1000); 224184610Salfred return (le16toh(val)); 225184610Salfred} 226184610Salfred 227188412Sthompsastatic int 228188412Sthompsacue_csr_write_1(struct cue_softc *sc, uint16_t reg, uint16_t val) 229184610Salfred{ 230192984Sthompsa struct usb_device_request req; 231184610Salfred 232184610Salfred req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 233184610Salfred req.bRequest = CUE_CMD_WRITEREG; 234184610Salfred USETW(req.wValue, val); 235184610Salfred USETW(req.wIndex, reg); 236184610Salfred USETW(req.wLength, 0); 237184610Salfred 238194228Sthompsa return (uether_do_request(&sc->sc_ue, &req, NULL, 1000)); 239184610Salfred} 240184610Salfred 241188412Sthompsastatic int 242188412Sthompsacue_mem(struct cue_softc *sc, uint8_t cmd, uint16_t addr, void *buf, int len) 243184610Salfred{ 244192984Sthompsa struct usb_device_request req; 245184610Salfred 246188412Sthompsa if (cmd == CUE_CMD_READSRAM) 247184610Salfred req.bmRequestType = UT_READ_VENDOR_DEVICE; 248188412Sthompsa else 249184610Salfred req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 250184610Salfred req.bRequest = cmd; 251184610Salfred USETW(req.wValue, 0); 252184610Salfred USETW(req.wIndex, addr); 253184610Salfred USETW(req.wLength, len); 254184610Salfred 255194228Sthompsa return (uether_do_request(&sc->sc_ue, &req, buf, 1000)); 256184610Salfred} 257184610Salfred 258188412Sthompsastatic int 259188412Sthompsacue_getmac(struct cue_softc *sc, void *buf) 260184610Salfred{ 261192984Sthompsa struct usb_device_request req; 262184610Salfred 263184610Salfred req.bmRequestType = UT_READ_VENDOR_DEVICE; 264184610Salfred req.bRequest = CUE_CMD_GET_MACADDR; 265184610Salfred USETW(req.wValue, 0); 266184610Salfred USETW(req.wIndex, 0); 267184610Salfred USETW(req.wLength, ETHER_ADDR_LEN); 268184610Salfred 269194228Sthompsa return (uether_do_request(&sc->sc_ue, &req, buf, 1000)); 270184610Salfred} 271184610Salfred 272184610Salfred#define CUE_BITS 9 273184610Salfred 274188412Sthompsastatic uint32_t 275188412Sthompsacue_mchash(const uint8_t *addr) 276184610Salfred{ 277188412Sthompsa uint32_t crc; 278184610Salfred 279188412Sthompsa /* Compute CRC for the address value. */ 280188412Sthompsa crc = ether_crc32_le(addr, ETHER_ADDR_LEN); 281188412Sthompsa 282188412Sthompsa return (crc & ((1 << CUE_BITS) - 1)); 283184610Salfred} 284184610Salfred 285184610Salfredstatic void 286192984Sthompsacue_setpromisc(struct usb_ether *ue) 287184610Salfred{ 288194228Sthompsa struct cue_softc *sc = uether_getsc(ue); 289194228Sthompsa struct ifnet *ifp = uether_getifp(ue); 290188412Sthompsa 291188412Sthompsa CUE_LOCK_ASSERT(sc, MA_OWNED); 292188412Sthompsa 293184610Salfred /* if we want promiscuous mode, set the allframes bit */ 294188412Sthompsa if (ifp->if_flags & IFF_PROMISC) 295188412Sthompsa CUE_SETBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC); 296188412Sthompsa else 297188412Sthompsa CUE_CLRBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC); 298184610Salfred 299184610Salfred /* write multicast hash-bits */ 300188412Sthompsa cue_setmulti(ue); 301184610Salfred} 302184610Salfred 303184610Salfredstatic void 304192984Sthompsacue_setmulti(struct usb_ether *ue) 305184610Salfred{ 306194228Sthompsa struct cue_softc *sc = uether_getsc(ue); 307194228Sthompsa struct ifnet *ifp = uether_getifp(ue); 308188412Sthompsa struct ifmultiaddr *ifma; 309188412Sthompsa uint32_t h = 0, i; 310188412Sthompsa uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 311188412Sthompsa 312188412Sthompsa CUE_LOCK_ASSERT(sc, MA_OWNED); 313188412Sthompsa 314188412Sthompsa if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 315188412Sthompsa for (i = 0; i < 8; i++) 316188412Sthompsa hashtbl[i] = 0xff; 317188412Sthompsa cue_mem(sc, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR, 318188412Sthompsa &hashtbl, 8); 319188412Sthompsa return; 320188412Sthompsa } 321188412Sthompsa 322188412Sthompsa /* now program new ones */ 323195049Srwatson if_maddr_rlock(ifp); 324188412Sthompsa TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) 325188412Sthompsa { 326188412Sthompsa if (ifma->ifma_addr->sa_family != AF_LINK) 327188412Sthompsa continue; 328188412Sthompsa h = cue_mchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 329188412Sthompsa hashtbl[h >> 3] |= 1 << (h & 0x7); 330188412Sthompsa } 331195049Srwatson if_maddr_runlock(ifp); 332188412Sthompsa 333188412Sthompsa /* 334188412Sthompsa * Also include the broadcast address in the filter 335188412Sthompsa * so we can receive broadcast frames. 336188412Sthompsa */ 337188412Sthompsa if (ifp->if_flags & IFF_BROADCAST) { 338188412Sthompsa h = cue_mchash(ifp->if_broadcastaddr); 339188412Sthompsa hashtbl[h >> 3] |= 1 << (h & 0x7); 340188412Sthompsa } 341188412Sthompsa 342188412Sthompsa cue_mem(sc, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR, &hashtbl, 8); 343184610Salfred} 344184610Salfred 345184610Salfredstatic void 346188412Sthompsacue_reset(struct cue_softc *sc) 347184610Salfred{ 348192984Sthompsa struct usb_device_request req; 349184610Salfred 350184610Salfred req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 351184610Salfred req.bRequest = CUE_CMD_RESET; 352184610Salfred USETW(req.wValue, 0); 353184610Salfred USETW(req.wIndex, 0); 354184610Salfred USETW(req.wLength, 0); 355184610Salfred 356194228Sthompsa if (uether_do_request(&sc->sc_ue, &req, NULL, 1000)) { 357188412Sthompsa /* ignore any errors */ 358188412Sthompsa } 359184610Salfred 360184610Salfred /* 361184610Salfred * wait a little while for the chip to get its brains in order: 362184610Salfred */ 363194228Sthompsa uether_pause(&sc->sc_ue, hz / 100); 364188412Sthompsa} 365184610Salfred 366188412Sthompsastatic void 367192984Sthompsacue_attach_post(struct usb_ether *ue) 368188412Sthompsa{ 369194228Sthompsa struct cue_softc *sc = uether_getsc(ue); 370188412Sthompsa 371188412Sthompsa cue_getmac(sc, ue->ue_eaddr); 372184610Salfred} 373184610Salfred 374184610Salfredstatic int 375184610Salfredcue_probe(device_t dev) 376184610Salfred{ 377192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 378184610Salfred 379192499Sthompsa if (uaa->usb_mode != USB_MODE_HOST) 380184610Salfred return (ENXIO); 381188412Sthompsa if (uaa->info.bConfigIndex != CUE_CONFIG_IDX) 382184610Salfred return (ENXIO); 383188412Sthompsa if (uaa->info.bIfaceIndex != CUE_IFACE_IDX) 384184610Salfred return (ENXIO); 385188412Sthompsa 386194228Sthompsa return (usbd_lookup_id_by_uaa(cue_devs, sizeof(cue_devs), uaa)); 387184610Salfred} 388184610Salfred 389188412Sthompsa/* 390188412Sthompsa * Attach the interface. Allocate softc structures, do ifmedia 391188412Sthompsa * setup and ethernet/BPF attach. 392188412Sthompsa */ 393184610Salfredstatic int 394184610Salfredcue_attach(device_t dev) 395184610Salfred{ 396192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 397184610Salfred struct cue_softc *sc = device_get_softc(dev); 398192984Sthompsa struct usb_ether *ue = &sc->sc_ue; 399184610Salfred uint8_t iface_index; 400188412Sthompsa int error; 401184610Salfred 402194228Sthompsa device_set_usb_desc(dev); 403188412Sthompsa mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 404184610Salfred 405184610Salfred iface_index = CUE_IFACE_IDX; 406194228Sthompsa error = usbd_transfer_setup(uaa->device, &iface_index, 407187259Sthompsa sc->sc_xfer, cue_config, CUE_N_TRANSFER, sc, &sc->sc_mtx); 408184610Salfred if (error) { 409199816Sthompsa device_printf(dev, "allocating USB transfers failed\n"); 410184610Salfred goto detach; 411184610Salfred } 412188412Sthompsa 413188412Sthompsa ue->ue_sc = sc; 414188412Sthompsa ue->ue_dev = dev; 415188412Sthompsa ue->ue_udev = uaa->device; 416188412Sthompsa ue->ue_mtx = &sc->sc_mtx; 417188412Sthompsa ue->ue_methods = &cue_ue_methods; 418188412Sthompsa 419194228Sthompsa error = uether_ifattach(ue); 420184610Salfred if (error) { 421188412Sthompsa device_printf(dev, "could not attach interface\n"); 422184610Salfred goto detach; 423184610Salfred } 424184610Salfred return (0); /* success */ 425184610Salfred 426184610Salfreddetach: 427184610Salfred cue_detach(dev); 428184610Salfred return (ENXIO); /* failure */ 429184610Salfred} 430184610Salfred 431184610Salfredstatic int 432184610Salfredcue_detach(device_t dev) 433184610Salfred{ 434184610Salfred struct cue_softc *sc = device_get_softc(dev); 435192984Sthompsa struct usb_ether *ue = &sc->sc_ue; 436184610Salfred 437194228Sthompsa usbd_transfer_unsetup(sc->sc_xfer, CUE_N_TRANSFER); 438194228Sthompsa uether_ifdetach(ue); 439184610Salfred mtx_destroy(&sc->sc_mtx); 440184610Salfred 441184610Salfred return (0); 442184610Salfred} 443184610Salfred 444184610Salfredstatic void 445194677Sthompsacue_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) 446184610Salfred{ 447194677Sthompsa struct cue_softc *sc = usbd_xfer_softc(xfer); 448192984Sthompsa struct usb_ether *ue = &sc->sc_ue; 449194228Sthompsa struct ifnet *ifp = uether_getifp(ue); 450194677Sthompsa struct usb_page_cache *pc; 451184610Salfred uint8_t buf[2]; 452188412Sthompsa int len; 453194677Sthompsa int actlen; 454184610Salfred 455194677Sthompsa usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 456194677Sthompsa 457184610Salfred switch (USB_GET_STATE(xfer)) { 458184610Salfred case USB_ST_TRANSFERRED: 459184610Salfred 460233774Shselasky if (actlen <= (int)(2 + sizeof(struct ether_header))) { 461184610Salfred ifp->if_ierrors++; 462184610Salfred goto tr_setup; 463184610Salfred } 464194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 465194677Sthompsa usbd_copy_out(pc, 0, buf, 2); 466194677Sthompsa actlen -= 2; 467184610Salfred len = buf[0] | (buf[1] << 8); 468194677Sthompsa len = min(actlen, len); 469184610Salfred 470194677Sthompsa uether_rxbuf(ue, pc, 2, len); 471188412Sthompsa /* FALLTHROUGH */ 472184610Salfred case USB_ST_SETUP: 473184610Salfredtr_setup: 474194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 475194228Sthompsa usbd_transfer_submit(xfer); 476194228Sthompsa uether_rxflush(ue); 477184610Salfred return; 478184610Salfred 479184610Salfred default: /* Error */ 480188412Sthompsa DPRINTF("bulk read error, %s\n", 481194677Sthompsa usbd_errstr(error)); 482188412Sthompsa 483194677Sthompsa if (error != USB_ERR_CANCELLED) { 484184610Salfred /* try to clear stall first */ 485194677Sthompsa usbd_xfer_set_stall(xfer); 486188412Sthompsa goto tr_setup; 487184610Salfred } 488184610Salfred return; 489184610Salfred 490184610Salfred } 491184610Salfred} 492184610Salfred 493184610Salfredstatic void 494194677Sthompsacue_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) 495184610Salfred{ 496194677Sthompsa struct cue_softc *sc = usbd_xfer_softc(xfer); 497194228Sthompsa struct ifnet *ifp = uether_getifp(&sc->sc_ue); 498194677Sthompsa struct usb_page_cache *pc; 499184610Salfred struct mbuf *m; 500184610Salfred uint8_t buf[2]; 501184610Salfred 502184610Salfred switch (USB_GET_STATE(xfer)) { 503184610Salfred case USB_ST_TRANSFERRED: 504184610Salfred DPRINTFN(11, "transfer complete\n"); 505184610Salfred ifp->if_opackets++; 506184610Salfred 507188412Sthompsa /* FALLTHROUGH */ 508184610Salfred case USB_ST_SETUP: 509188412Sthompsatr_setup: 510184610Salfred IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 511184610Salfred 512188412Sthompsa if (m == NULL) 513188412Sthompsa return; 514188412Sthompsa if (m->m_pkthdr.len > MCLBYTES) 515184610Salfred m->m_pkthdr.len = MCLBYTES; 516194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, (m->m_pkthdr.len + 2)); 517184610Salfred 518184610Salfred /* the first two bytes are the frame length */ 519184610Salfred 520184610Salfred buf[0] = (uint8_t)(m->m_pkthdr.len); 521184610Salfred buf[1] = (uint8_t)(m->m_pkthdr.len >> 8); 522184610Salfred 523194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 524194677Sthompsa usbd_copy_in(pc, 0, buf, 2); 525194677Sthompsa usbd_m_copy_in(pc, 2, m, 0, m->m_pkthdr.len); 526184610Salfred 527184610Salfred /* 528184610Salfred * If there's a BPF listener, bounce a copy of this frame 529184610Salfred * to him. 530184610Salfred */ 531184610Salfred BPF_MTAP(ifp, m); 532184610Salfred 533184610Salfred m_freem(m); 534184610Salfred 535194228Sthompsa usbd_transfer_submit(xfer); 536184610Salfred 537184610Salfred return; 538184610Salfred 539184610Salfred default: /* Error */ 540184610Salfred DPRINTFN(11, "transfer error, %s\n", 541194677Sthompsa usbd_errstr(error)); 542184610Salfred 543188412Sthompsa ifp->if_oerrors++; 544188412Sthompsa 545194677Sthompsa if (error != USB_ERR_CANCELLED) { 546184610Salfred /* try to clear stall first */ 547194677Sthompsa usbd_xfer_set_stall(xfer); 548188412Sthompsa goto tr_setup; 549184610Salfred } 550184610Salfred return; 551184610Salfred } 552184610Salfred} 553184610Salfred 554184610Salfredstatic void 555192984Sthompsacue_tick(struct usb_ether *ue) 556184610Salfred{ 557194228Sthompsa struct cue_softc *sc = uether_getsc(ue); 558194228Sthompsa struct ifnet *ifp = uether_getifp(ue); 559184610Salfred 560188412Sthompsa CUE_LOCK_ASSERT(sc, MA_OWNED); 561188412Sthompsa 562188412Sthompsa ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_SINGLECOLL); 563188412Sthompsa ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_MULTICOLL); 564188412Sthompsa ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_EXCESSCOLL); 565188412Sthompsa 566188412Sthompsa if (cue_csr_read_2(sc, CUE_RX_FRAMEERR)) 567188412Sthompsa ifp->if_ierrors++; 568184610Salfred} 569184610Salfred 570184610Salfredstatic void 571192984Sthompsacue_start(struct usb_ether *ue) 572184610Salfred{ 573194228Sthompsa struct cue_softc *sc = uether_getsc(ue); 574184610Salfred 575188412Sthompsa /* 576188412Sthompsa * start the USB transfers, if not already started: 577188412Sthompsa */ 578194228Sthompsa usbd_transfer_start(sc->sc_xfer[CUE_BULK_DT_RD]); 579194228Sthompsa usbd_transfer_start(sc->sc_xfer[CUE_BULK_DT_WR]); 580184610Salfred} 581184610Salfred 582184610Salfredstatic void 583192984Sthompsacue_init(struct usb_ether *ue) 584184610Salfred{ 585194228Sthompsa struct cue_softc *sc = uether_getsc(ue); 586194228Sthompsa struct ifnet *ifp = uether_getifp(ue); 587188412Sthompsa int i; 588184610Salfred 589188412Sthompsa CUE_LOCK_ASSERT(sc, MA_OWNED); 590188412Sthompsa 591184610Salfred /* 592184610Salfred * Cancel pending I/O and free all RX/TX buffers. 593184610Salfred */ 594188412Sthompsa cue_stop(ue); 595184610Salfred#if 0 596188412Sthompsa cue_reset(sc); 597184610Salfred#endif 598184610Salfred /* Set MAC address */ 599188412Sthompsa for (i = 0; i < ETHER_ADDR_LEN; i++) 600188412Sthompsa cue_csr_write_1(sc, CUE_PAR0 - i, IF_LLADDR(ifp)[i]); 601184610Salfred 602184610Salfred /* Enable RX logic. */ 603188412Sthompsa cue_csr_write_1(sc, CUE_ETHCTL, CUE_ETHCTL_RX_ON | CUE_ETHCTL_MCAST_ON); 604184610Salfred 605184610Salfred /* Load the multicast filter */ 606188412Sthompsa cue_setpromisc(ue); 607184610Salfred 608184610Salfred /* 609184610Salfred * Set the number of RX and TX buffers that we want 610184610Salfred * to reserve inside the ASIC. 611184610Salfred */ 612188412Sthompsa cue_csr_write_1(sc, CUE_RX_BUFPKTS, CUE_RX_FRAMES); 613188412Sthompsa cue_csr_write_1(sc, CUE_TX_BUFPKTS, CUE_TX_FRAMES); 614184610Salfred 615184610Salfred /* Set advanced operation modes. */ 616188412Sthompsa cue_csr_write_1(sc, CUE_ADVANCED_OPMODES, 617184610Salfred CUE_AOP_EMBED_RXLEN | 0x01);/* 1 wait state */ 618184610Salfred 619184610Salfred /* Program the LED operation. */ 620188412Sthompsa cue_csr_write_1(sc, CUE_LEDCTL, CUE_LEDCTL_FOLLOW_LINK); 621184610Salfred 622194677Sthompsa usbd_xfer_set_stall(sc->sc_xfer[CUE_BULK_DT_WR]); 623184610Salfred 624188412Sthompsa ifp->if_drv_flags |= IFF_DRV_RUNNING; 625188412Sthompsa cue_start(ue); 626184610Salfred} 627184610Salfred 628184610Salfred/* 629184610Salfred * Stop the adapter and free any mbufs allocated to the 630184610Salfred * RX and TX lists. 631184610Salfred */ 632184610Salfredstatic void 633192984Sthompsacue_stop(struct usb_ether *ue) 634184610Salfred{ 635194228Sthompsa struct cue_softc *sc = uether_getsc(ue); 636194228Sthompsa struct ifnet *ifp = uether_getifp(ue); 637184610Salfred 638188412Sthompsa CUE_LOCK_ASSERT(sc, MA_OWNED); 639184610Salfred 640188412Sthompsa ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 641184610Salfred 642184610Salfred /* 643184610Salfred * stop all the transfers, if not already stopped: 644184610Salfred */ 645194228Sthompsa usbd_transfer_stop(sc->sc_xfer[CUE_BULK_DT_WR]); 646194228Sthompsa usbd_transfer_stop(sc->sc_xfer[CUE_BULK_DT_RD]); 647184610Salfred 648188412Sthompsa cue_csr_write_1(sc, CUE_ETHCTL, 0); 649188412Sthompsa cue_reset(sc); 650184610Salfred} 651