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 50298932Spfg * mode where multiple packets can be transferred 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> 60257176Sglebius#include <sys/socket.h> 61194677Sthompsa#include <sys/kernel.h> 62194677Sthompsa#include <sys/bus.h> 63194677Sthompsa#include <sys/module.h> 64194677Sthompsa#include <sys/lock.h> 65194677Sthompsa#include <sys/mutex.h> 66194677Sthompsa#include <sys/condvar.h> 67194677Sthompsa#include <sys/sysctl.h> 68194677Sthompsa#include <sys/sx.h> 69194677Sthompsa#include <sys/unistd.h> 70194677Sthompsa#include <sys/callout.h> 71194677Sthompsa#include <sys/malloc.h> 72194677Sthompsa#include <sys/priv.h> 73194677Sthompsa 74257176Sglebius#include <net/if.h> 75257176Sglebius#include <net/if_var.h> 76257176Sglebius 77194677Sthompsa#include <dev/usb/usb.h> 78194677Sthompsa#include <dev/usb/usbdi.h> 79194677Sthompsa#include <dev/usb/usbdi_util.h> 80188746Sthompsa#include "usbdevs.h" 81184610Salfred 82184610Salfred#define USB_DEBUG_VAR cue_debug 83194677Sthompsa#include <dev/usb/usb_debug.h> 84188942Sthompsa#include <dev/usb/usb_process.h> 85184610Salfred 86188942Sthompsa#include <dev/usb/net/usb_ethernet.h> 87188942Sthompsa#include <dev/usb/net/if_cuereg.h> 88184610Salfred 89184610Salfred/* 90184610Salfred * Various supported device vendors/products. 91184610Salfred */ 92184610Salfred 93184610Salfred/* Belkin F5U111 adapter covered by NETMATE entry */ 94184610Salfred 95223486Shselaskystatic const STRUCT_USB_HOST_ID cue_devs[] = { 96201028Sthompsa#define CUE_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) } 97201028Sthompsa CUE_DEV(CATC, NETMATE), 98201028Sthompsa CUE_DEV(CATC, NETMATE2), 99201028Sthompsa CUE_DEV(SMARTBRIDGES, SMARTLINK), 100201028Sthompsa#undef CUE_DEV 101184610Salfred}; 102184610Salfred 103184610Salfred/* prototypes */ 104184610Salfred 105184610Salfredstatic device_probe_t cue_probe; 106184610Salfredstatic device_attach_t cue_attach; 107184610Salfredstatic device_detach_t cue_detach; 108184610Salfred 109193045Sthompsastatic usb_callback_t cue_bulk_read_callback; 110193045Sthompsastatic usb_callback_t cue_bulk_write_callback; 111184610Salfred 112193045Sthompsastatic uether_fn_t cue_attach_post; 113193045Sthompsastatic uether_fn_t cue_init; 114193045Sthompsastatic uether_fn_t cue_stop; 115193045Sthompsastatic uether_fn_t cue_start; 116193045Sthompsastatic uether_fn_t cue_tick; 117193045Sthompsastatic uether_fn_t cue_setmulti; 118193045Sthompsastatic uether_fn_t cue_setpromisc; 119184610Salfred 120188412Sthompsastatic uint8_t cue_csr_read_1(struct cue_softc *, uint16_t); 121188412Sthompsastatic uint16_t cue_csr_read_2(struct cue_softc *, uint8_t); 122188412Sthompsastatic int cue_csr_write_1(struct cue_softc *, uint16_t, uint16_t); 123188412Sthompsastatic int cue_mem(struct cue_softc *, uint8_t, uint16_t, void *, int); 124188412Sthompsastatic int cue_getmac(struct cue_softc *, void *); 125188412Sthompsastatic uint32_t cue_mchash(const uint8_t *); 126188412Sthompsastatic void cue_reset(struct cue_softc *); 127184610Salfred 128207077Sthompsa#ifdef USB_DEBUG 129184610Salfredstatic int cue_debug = 0; 130184610Salfred 131227309Sedstatic SYSCTL_NODE(_hw_usb, OID_AUTO, cue, CTLFLAG_RW, 0, "USB cue"); 132276701ShselaskySYSCTL_INT(_hw_usb_cue, OID_AUTO, debug, CTLFLAG_RWTUN, &cue_debug, 0, 133184610Salfred "Debug level"); 134184610Salfred#endif 135184610Salfred 136192984Sthompsastatic const struct usb_config cue_config[CUE_N_TRANSFER] = { 137184610Salfred 138187259Sthompsa [CUE_BULK_DT_WR] = { 139184610Salfred .type = UE_BULK, 140184610Salfred .endpoint = UE_ADDR_ANY, 141184610Salfred .direction = UE_DIR_OUT, 142190734Sthompsa .bufsize = (MCLBYTES + 2), 143190734Sthompsa .flags = {.pipe_bof = 1,}, 144190734Sthompsa .callback = cue_bulk_write_callback, 145190734Sthompsa .timeout = 10000, /* 10 seconds */ 146184610Salfred }, 147184610Salfred 148187259Sthompsa [CUE_BULK_DT_RD] = { 149184610Salfred .type = UE_BULK, 150184610Salfred .endpoint = UE_ADDR_ANY, 151184610Salfred .direction = UE_DIR_IN, 152190734Sthompsa .bufsize = (MCLBYTES + 2), 153190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 154190734Sthompsa .callback = cue_bulk_read_callback, 155184610Salfred }, 156184610Salfred}; 157184610Salfred 158184610Salfredstatic device_method_t cue_methods[] = { 159184610Salfred /* Device interface */ 160184610Salfred DEVMETHOD(device_probe, cue_probe), 161184610Salfred DEVMETHOD(device_attach, cue_attach), 162184610Salfred DEVMETHOD(device_detach, cue_detach), 163184610Salfred 164246128Ssbz DEVMETHOD_END 165184610Salfred}; 166184610Salfred 167184610Salfredstatic driver_t cue_driver = { 168184610Salfred .name = "cue", 169184610Salfred .methods = cue_methods, 170184610Salfred .size = sizeof(struct cue_softc), 171184610Salfred}; 172184610Salfred 173184610Salfredstatic devclass_t cue_devclass; 174184610Salfred 175189275SthompsaDRIVER_MODULE(cue, uhub, cue_driver, cue_devclass, NULL, 0); 176188942SthompsaMODULE_DEPEND(cue, uether, 1, 1, 1); 177188942SthompsaMODULE_DEPEND(cue, usb, 1, 1, 1); 178184610SalfredMODULE_DEPEND(cue, ether, 1, 1, 1); 179212122SthompsaMODULE_VERSION(cue, 1); 180292080SimpUSB_PNP_HOST_INFO(cue_devs); 181184610Salfred 182192984Sthompsastatic const struct usb_ether_methods cue_ue_methods = { 183188412Sthompsa .ue_attach_post = cue_attach_post, 184188412Sthompsa .ue_start = cue_start, 185188412Sthompsa .ue_init = cue_init, 186188412Sthompsa .ue_stop = cue_stop, 187188412Sthompsa .ue_tick = cue_tick, 188188412Sthompsa .ue_setmulti = cue_setmulti, 189188412Sthompsa .ue_setpromisc = cue_setpromisc, 190188412Sthompsa}; 191184610Salfred 192188412Sthompsa#define CUE_SETBIT(sc, reg, x) \ 193188412Sthompsa cue_csr_write_1(sc, reg, cue_csr_read_1(sc, reg) | (x)) 194184610Salfred 195188412Sthompsa#define CUE_CLRBIT(sc, reg, x) \ 196188412Sthompsa cue_csr_write_1(sc, reg, cue_csr_read_1(sc, reg) & ~(x)) 197184610Salfred 198184610Salfredstatic uint8_t 199188412Sthompsacue_csr_read_1(struct cue_softc *sc, uint16_t reg) 200184610Salfred{ 201192984Sthompsa struct usb_device_request req; 202184610Salfred uint8_t val; 203184610Salfred 204184610Salfred req.bmRequestType = UT_READ_VENDOR_DEVICE; 205184610Salfred req.bRequest = CUE_CMD_READREG; 206184610Salfred USETW(req.wValue, 0); 207184610Salfred USETW(req.wIndex, reg); 208184610Salfred USETW(req.wLength, 1); 209184610Salfred 210194228Sthompsa if (uether_do_request(&sc->sc_ue, &req, &val, 1000)) { 211188412Sthompsa /* ignore any errors */ 212188412Sthompsa } 213184610Salfred return (val); 214184610Salfred} 215184610Salfred 216184610Salfredstatic uint16_t 217188412Sthompsacue_csr_read_2(struct cue_softc *sc, uint8_t reg) 218184610Salfred{ 219192984Sthompsa struct usb_device_request req; 220184610Salfred uint16_t val; 221184610Salfred 222184610Salfred req.bmRequestType = UT_READ_VENDOR_DEVICE; 223184610Salfred req.bRequest = CUE_CMD_READREG; 224184610Salfred USETW(req.wValue, 0); 225184610Salfred USETW(req.wIndex, reg); 226184610Salfred USETW(req.wLength, 2); 227184610Salfred 228194228Sthompsa (void)uether_do_request(&sc->sc_ue, &req, &val, 1000); 229184610Salfred return (le16toh(val)); 230184610Salfred} 231184610Salfred 232188412Sthompsastatic int 233188412Sthompsacue_csr_write_1(struct cue_softc *sc, uint16_t reg, uint16_t val) 234184610Salfred{ 235192984Sthompsa struct usb_device_request req; 236184610Salfred 237184610Salfred req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 238184610Salfred req.bRequest = CUE_CMD_WRITEREG; 239184610Salfred USETW(req.wValue, val); 240184610Salfred USETW(req.wIndex, reg); 241184610Salfred USETW(req.wLength, 0); 242184610Salfred 243194228Sthompsa return (uether_do_request(&sc->sc_ue, &req, NULL, 1000)); 244184610Salfred} 245184610Salfred 246188412Sthompsastatic int 247188412Sthompsacue_mem(struct cue_softc *sc, uint8_t cmd, uint16_t addr, void *buf, int len) 248184610Salfred{ 249192984Sthompsa struct usb_device_request req; 250184610Salfred 251188412Sthompsa if (cmd == CUE_CMD_READSRAM) 252184610Salfred req.bmRequestType = UT_READ_VENDOR_DEVICE; 253188412Sthompsa else 254184610Salfred req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 255184610Salfred req.bRequest = cmd; 256184610Salfred USETW(req.wValue, 0); 257184610Salfred USETW(req.wIndex, addr); 258184610Salfred USETW(req.wLength, len); 259184610Salfred 260194228Sthompsa return (uether_do_request(&sc->sc_ue, &req, buf, 1000)); 261184610Salfred} 262184610Salfred 263188412Sthompsastatic int 264188412Sthompsacue_getmac(struct cue_softc *sc, void *buf) 265184610Salfred{ 266192984Sthompsa struct usb_device_request req; 267184610Salfred 268184610Salfred req.bmRequestType = UT_READ_VENDOR_DEVICE; 269184610Salfred req.bRequest = CUE_CMD_GET_MACADDR; 270184610Salfred USETW(req.wValue, 0); 271184610Salfred USETW(req.wIndex, 0); 272184610Salfred USETW(req.wLength, ETHER_ADDR_LEN); 273184610Salfred 274194228Sthompsa return (uether_do_request(&sc->sc_ue, &req, buf, 1000)); 275184610Salfred} 276184610Salfred 277184610Salfred#define CUE_BITS 9 278184610Salfred 279188412Sthompsastatic uint32_t 280188412Sthompsacue_mchash(const uint8_t *addr) 281184610Salfred{ 282188412Sthompsa uint32_t crc; 283184610Salfred 284188412Sthompsa /* Compute CRC for the address value. */ 285188412Sthompsa crc = ether_crc32_le(addr, ETHER_ADDR_LEN); 286188412Sthompsa 287188412Sthompsa return (crc & ((1 << CUE_BITS) - 1)); 288184610Salfred} 289184610Salfred 290184610Salfredstatic void 291192984Sthompsacue_setpromisc(struct usb_ether *ue) 292184610Salfred{ 293194228Sthompsa struct cue_softc *sc = uether_getsc(ue); 294194228Sthompsa struct ifnet *ifp = uether_getifp(ue); 295188412Sthompsa 296188412Sthompsa CUE_LOCK_ASSERT(sc, MA_OWNED); 297188412Sthompsa 298184610Salfred /* if we want promiscuous mode, set the allframes bit */ 299188412Sthompsa if (ifp->if_flags & IFF_PROMISC) 300188412Sthompsa CUE_SETBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC); 301188412Sthompsa else 302188412Sthompsa CUE_CLRBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC); 303184610Salfred 304184610Salfred /* write multicast hash-bits */ 305188412Sthompsa cue_setmulti(ue); 306184610Salfred} 307184610Salfred 308184610Salfredstatic void 309192984Sthompsacue_setmulti(struct usb_ether *ue) 310184610Salfred{ 311194228Sthompsa struct cue_softc *sc = uether_getsc(ue); 312194228Sthompsa struct ifnet *ifp = uether_getifp(ue); 313188412Sthompsa struct ifmultiaddr *ifma; 314188412Sthompsa uint32_t h = 0, i; 315188412Sthompsa uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 316188412Sthompsa 317188412Sthompsa CUE_LOCK_ASSERT(sc, MA_OWNED); 318188412Sthompsa 319188412Sthompsa if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 320188412Sthompsa for (i = 0; i < 8; i++) 321188412Sthompsa hashtbl[i] = 0xff; 322188412Sthompsa cue_mem(sc, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR, 323188412Sthompsa &hashtbl, 8); 324188412Sthompsa return; 325188412Sthompsa } 326188412Sthompsa 327188412Sthompsa /* now program new ones */ 328195049Srwatson if_maddr_rlock(ifp); 329188412Sthompsa TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) 330188412Sthompsa { 331188412Sthompsa if (ifma->ifma_addr->sa_family != AF_LINK) 332188412Sthompsa continue; 333188412Sthompsa h = cue_mchash(LLADDR((struct sockaddr_dl *)ifma->ifma_addr)); 334188412Sthompsa hashtbl[h >> 3] |= 1 << (h & 0x7); 335188412Sthompsa } 336195049Srwatson if_maddr_runlock(ifp); 337188412Sthompsa 338188412Sthompsa /* 339188412Sthompsa * Also include the broadcast address in the filter 340188412Sthompsa * so we can receive broadcast frames. 341188412Sthompsa */ 342188412Sthompsa if (ifp->if_flags & IFF_BROADCAST) { 343188412Sthompsa h = cue_mchash(ifp->if_broadcastaddr); 344188412Sthompsa hashtbl[h >> 3] |= 1 << (h & 0x7); 345188412Sthompsa } 346188412Sthompsa 347188412Sthompsa cue_mem(sc, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR, &hashtbl, 8); 348184610Salfred} 349184610Salfred 350184610Salfredstatic void 351188412Sthompsacue_reset(struct cue_softc *sc) 352184610Salfred{ 353192984Sthompsa struct usb_device_request req; 354184610Salfred 355184610Salfred req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 356184610Salfred req.bRequest = CUE_CMD_RESET; 357184610Salfred USETW(req.wValue, 0); 358184610Salfred USETW(req.wIndex, 0); 359184610Salfred USETW(req.wLength, 0); 360184610Salfred 361194228Sthompsa if (uether_do_request(&sc->sc_ue, &req, NULL, 1000)) { 362188412Sthompsa /* ignore any errors */ 363188412Sthompsa } 364184610Salfred 365184610Salfred /* 366184610Salfred * wait a little while for the chip to get its brains in order: 367184610Salfred */ 368194228Sthompsa uether_pause(&sc->sc_ue, hz / 100); 369188412Sthompsa} 370184610Salfred 371188412Sthompsastatic void 372192984Sthompsacue_attach_post(struct usb_ether *ue) 373188412Sthompsa{ 374194228Sthompsa struct cue_softc *sc = uether_getsc(ue); 375188412Sthompsa 376188412Sthompsa cue_getmac(sc, ue->ue_eaddr); 377184610Salfred} 378184610Salfred 379184610Salfredstatic int 380184610Salfredcue_probe(device_t dev) 381184610Salfred{ 382192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 383184610Salfred 384192499Sthompsa if (uaa->usb_mode != USB_MODE_HOST) 385184610Salfred return (ENXIO); 386188412Sthompsa if (uaa->info.bConfigIndex != CUE_CONFIG_IDX) 387184610Salfred return (ENXIO); 388188412Sthompsa if (uaa->info.bIfaceIndex != CUE_IFACE_IDX) 389184610Salfred return (ENXIO); 390188412Sthompsa 391194228Sthompsa return (usbd_lookup_id_by_uaa(cue_devs, sizeof(cue_devs), uaa)); 392184610Salfred} 393184610Salfred 394188412Sthompsa/* 395188412Sthompsa * Attach the interface. Allocate softc structures, do ifmedia 396188412Sthompsa * setup and ethernet/BPF attach. 397188412Sthompsa */ 398184610Salfredstatic int 399184610Salfredcue_attach(device_t dev) 400184610Salfred{ 401192984Sthompsa struct usb_attach_arg *uaa = device_get_ivars(dev); 402184610Salfred struct cue_softc *sc = device_get_softc(dev); 403192984Sthompsa struct usb_ether *ue = &sc->sc_ue; 404184610Salfred uint8_t iface_index; 405188412Sthompsa int error; 406184610Salfred 407194228Sthompsa device_set_usb_desc(dev); 408188412Sthompsa mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 409184610Salfred 410184610Salfred iface_index = CUE_IFACE_IDX; 411194228Sthompsa error = usbd_transfer_setup(uaa->device, &iface_index, 412187259Sthompsa sc->sc_xfer, cue_config, CUE_N_TRANSFER, sc, &sc->sc_mtx); 413184610Salfred if (error) { 414199816Sthompsa device_printf(dev, "allocating USB transfers failed\n"); 415184610Salfred goto detach; 416184610Salfred } 417188412Sthompsa 418188412Sthompsa ue->ue_sc = sc; 419188412Sthompsa ue->ue_dev = dev; 420188412Sthompsa ue->ue_udev = uaa->device; 421188412Sthompsa ue->ue_mtx = &sc->sc_mtx; 422188412Sthompsa ue->ue_methods = &cue_ue_methods; 423188412Sthompsa 424194228Sthompsa error = uether_ifattach(ue); 425184610Salfred if (error) { 426188412Sthompsa device_printf(dev, "could not attach interface\n"); 427184610Salfred goto detach; 428184610Salfred } 429184610Salfred return (0); /* success */ 430184610Salfred 431184610Salfreddetach: 432184610Salfred cue_detach(dev); 433184610Salfred return (ENXIO); /* failure */ 434184610Salfred} 435184610Salfred 436184610Salfredstatic int 437184610Salfredcue_detach(device_t dev) 438184610Salfred{ 439184610Salfred struct cue_softc *sc = device_get_softc(dev); 440192984Sthompsa struct usb_ether *ue = &sc->sc_ue; 441184610Salfred 442194228Sthompsa usbd_transfer_unsetup(sc->sc_xfer, CUE_N_TRANSFER); 443194228Sthompsa uether_ifdetach(ue); 444184610Salfred mtx_destroy(&sc->sc_mtx); 445184610Salfred 446184610Salfred return (0); 447184610Salfred} 448184610Salfred 449184610Salfredstatic void 450194677Sthompsacue_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) 451184610Salfred{ 452194677Sthompsa struct cue_softc *sc = usbd_xfer_softc(xfer); 453192984Sthompsa struct usb_ether *ue = &sc->sc_ue; 454194228Sthompsa struct ifnet *ifp = uether_getifp(ue); 455194677Sthompsa struct usb_page_cache *pc; 456184610Salfred uint8_t buf[2]; 457188412Sthompsa int len; 458194677Sthompsa int actlen; 459184610Salfred 460194677Sthompsa usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 461194677Sthompsa 462184610Salfred switch (USB_GET_STATE(xfer)) { 463184610Salfred case USB_ST_TRANSFERRED: 464184610Salfred 465233774Shselasky if (actlen <= (int)(2 + sizeof(struct ether_header))) { 466271832Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 467184610Salfred goto tr_setup; 468184610Salfred } 469194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 470194677Sthompsa usbd_copy_out(pc, 0, buf, 2); 471194677Sthompsa actlen -= 2; 472184610Salfred len = buf[0] | (buf[1] << 8); 473194677Sthompsa len = min(actlen, len); 474184610Salfred 475194677Sthompsa uether_rxbuf(ue, pc, 2, len); 476188412Sthompsa /* FALLTHROUGH */ 477184610Salfred case USB_ST_SETUP: 478184610Salfredtr_setup: 479194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 480194228Sthompsa usbd_transfer_submit(xfer); 481194228Sthompsa uether_rxflush(ue); 482184610Salfred return; 483184610Salfred 484184610Salfred default: /* Error */ 485188412Sthompsa DPRINTF("bulk read error, %s\n", 486194677Sthompsa usbd_errstr(error)); 487188412Sthompsa 488194677Sthompsa if (error != USB_ERR_CANCELLED) { 489184610Salfred /* try to clear stall first */ 490194677Sthompsa usbd_xfer_set_stall(xfer); 491188412Sthompsa goto tr_setup; 492184610Salfred } 493184610Salfred return; 494184610Salfred 495184610Salfred } 496184610Salfred} 497184610Salfred 498184610Salfredstatic void 499194677Sthompsacue_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) 500184610Salfred{ 501194677Sthompsa struct cue_softc *sc = usbd_xfer_softc(xfer); 502194228Sthompsa struct ifnet *ifp = uether_getifp(&sc->sc_ue); 503194677Sthompsa struct usb_page_cache *pc; 504184610Salfred struct mbuf *m; 505184610Salfred uint8_t buf[2]; 506184610Salfred 507184610Salfred switch (USB_GET_STATE(xfer)) { 508184610Salfred case USB_ST_TRANSFERRED: 509184610Salfred DPRINTFN(11, "transfer complete\n"); 510271832Sglebius if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 511184610Salfred 512188412Sthompsa /* FALLTHROUGH */ 513184610Salfred case USB_ST_SETUP: 514188412Sthompsatr_setup: 515184610Salfred IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 516184610Salfred 517188412Sthompsa if (m == NULL) 518188412Sthompsa return; 519188412Sthompsa if (m->m_pkthdr.len > MCLBYTES) 520184610Salfred m->m_pkthdr.len = MCLBYTES; 521194677Sthompsa usbd_xfer_set_frame_len(xfer, 0, (m->m_pkthdr.len + 2)); 522184610Salfred 523184610Salfred /* the first two bytes are the frame length */ 524184610Salfred 525184610Salfred buf[0] = (uint8_t)(m->m_pkthdr.len); 526184610Salfred buf[1] = (uint8_t)(m->m_pkthdr.len >> 8); 527184610Salfred 528194677Sthompsa pc = usbd_xfer_get_frame(xfer, 0); 529194677Sthompsa usbd_copy_in(pc, 0, buf, 2); 530194677Sthompsa usbd_m_copy_in(pc, 2, m, 0, m->m_pkthdr.len); 531184610Salfred 532184610Salfred /* 533184610Salfred * If there's a BPF listener, bounce a copy of this frame 534184610Salfred * to him. 535184610Salfred */ 536184610Salfred BPF_MTAP(ifp, m); 537184610Salfred 538184610Salfred m_freem(m); 539184610Salfred 540194228Sthompsa usbd_transfer_submit(xfer); 541184610Salfred 542184610Salfred return; 543184610Salfred 544184610Salfred default: /* Error */ 545184610Salfred DPRINTFN(11, "transfer error, %s\n", 546194677Sthompsa usbd_errstr(error)); 547184610Salfred 548271832Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 549188412Sthompsa 550194677Sthompsa if (error != USB_ERR_CANCELLED) { 551184610Salfred /* try to clear stall first */ 552194677Sthompsa usbd_xfer_set_stall(xfer); 553188412Sthompsa goto tr_setup; 554184610Salfred } 555184610Salfred return; 556184610Salfred } 557184610Salfred} 558184610Salfred 559184610Salfredstatic void 560192984Sthompsacue_tick(struct usb_ether *ue) 561184610Salfred{ 562194228Sthompsa struct cue_softc *sc = uether_getsc(ue); 563194228Sthompsa struct ifnet *ifp = uether_getifp(ue); 564184610Salfred 565188412Sthompsa CUE_LOCK_ASSERT(sc, MA_OWNED); 566188412Sthompsa 567271832Sglebius if_inc_counter(ifp, IFCOUNTER_COLLISIONS, cue_csr_read_2(sc, CUE_TX_SINGLECOLL)); 568271832Sglebius if_inc_counter(ifp, IFCOUNTER_COLLISIONS, cue_csr_read_2(sc, CUE_TX_MULTICOLL)); 569271832Sglebius if_inc_counter(ifp, IFCOUNTER_COLLISIONS, cue_csr_read_2(sc, CUE_TX_EXCESSCOLL)); 570188412Sthompsa 571188412Sthompsa if (cue_csr_read_2(sc, CUE_RX_FRAMEERR)) 572271832Sglebius if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 573184610Salfred} 574184610Salfred 575184610Salfredstatic void 576192984Sthompsacue_start(struct usb_ether *ue) 577184610Salfred{ 578194228Sthompsa struct cue_softc *sc = uether_getsc(ue); 579184610Salfred 580188412Sthompsa /* 581188412Sthompsa * start the USB transfers, if not already started: 582188412Sthompsa */ 583194228Sthompsa usbd_transfer_start(sc->sc_xfer[CUE_BULK_DT_RD]); 584194228Sthompsa usbd_transfer_start(sc->sc_xfer[CUE_BULK_DT_WR]); 585184610Salfred} 586184610Salfred 587184610Salfredstatic void 588192984Sthompsacue_init(struct usb_ether *ue) 589184610Salfred{ 590194228Sthompsa struct cue_softc *sc = uether_getsc(ue); 591194228Sthompsa struct ifnet *ifp = uether_getifp(ue); 592188412Sthompsa int i; 593184610Salfred 594188412Sthompsa CUE_LOCK_ASSERT(sc, MA_OWNED); 595188412Sthompsa 596184610Salfred /* 597184610Salfred * Cancel pending I/O and free all RX/TX buffers. 598184610Salfred */ 599188412Sthompsa cue_stop(ue); 600184610Salfred#if 0 601188412Sthompsa cue_reset(sc); 602184610Salfred#endif 603184610Salfred /* Set MAC address */ 604188412Sthompsa for (i = 0; i < ETHER_ADDR_LEN; i++) 605188412Sthompsa cue_csr_write_1(sc, CUE_PAR0 - i, IF_LLADDR(ifp)[i]); 606184610Salfred 607184610Salfred /* Enable RX logic. */ 608188412Sthompsa cue_csr_write_1(sc, CUE_ETHCTL, CUE_ETHCTL_RX_ON | CUE_ETHCTL_MCAST_ON); 609184610Salfred 610184610Salfred /* Load the multicast filter */ 611188412Sthompsa cue_setpromisc(ue); 612184610Salfred 613184610Salfred /* 614184610Salfred * Set the number of RX and TX buffers that we want 615184610Salfred * to reserve inside the ASIC. 616184610Salfred */ 617188412Sthompsa cue_csr_write_1(sc, CUE_RX_BUFPKTS, CUE_RX_FRAMES); 618188412Sthompsa cue_csr_write_1(sc, CUE_TX_BUFPKTS, CUE_TX_FRAMES); 619184610Salfred 620184610Salfred /* Set advanced operation modes. */ 621188412Sthompsa cue_csr_write_1(sc, CUE_ADVANCED_OPMODES, 622184610Salfred CUE_AOP_EMBED_RXLEN | 0x01);/* 1 wait state */ 623184610Salfred 624184610Salfred /* Program the LED operation. */ 625188412Sthompsa cue_csr_write_1(sc, CUE_LEDCTL, CUE_LEDCTL_FOLLOW_LINK); 626184610Salfred 627194677Sthompsa usbd_xfer_set_stall(sc->sc_xfer[CUE_BULK_DT_WR]); 628184610Salfred 629188412Sthompsa ifp->if_drv_flags |= IFF_DRV_RUNNING; 630188412Sthompsa cue_start(ue); 631184610Salfred} 632184610Salfred 633184610Salfred/* 634184610Salfred * Stop the adapter and free any mbufs allocated to the 635184610Salfred * RX and TX lists. 636184610Salfred */ 637184610Salfredstatic void 638192984Sthompsacue_stop(struct usb_ether *ue) 639184610Salfred{ 640194228Sthompsa struct cue_softc *sc = uether_getsc(ue); 641194228Sthompsa struct ifnet *ifp = uether_getifp(ue); 642184610Salfred 643188412Sthompsa CUE_LOCK_ASSERT(sc, MA_OWNED); 644184610Salfred 645188412Sthompsa ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 646184610Salfred 647184610Salfred /* 648184610Salfred * stop all the transfers, if not already stopped: 649184610Salfred */ 650194228Sthompsa usbd_transfer_stop(sc->sc_xfer[CUE_BULK_DT_WR]); 651194228Sthompsa usbd_transfer_stop(sc->sc_xfer[CUE_BULK_DT_RD]); 652184610Salfred 653188412Sthompsa cue_csr_write_1(sc, CUE_ETHCTL, 0); 654188412Sthompsa cue_reset(sc); 655184610Salfred} 656