1 /* $OpenBSD: if_cue.c,v 1.81 2024/05/23 03:21:08 jsg Exp $ */ 2 /* $NetBSD: if_cue.c,v 1.40 2002/07/11 21:14:26 augustss Exp $ */ 3 /* 4 * Copyright (c) 1997, 1998, 1999, 2000 5 * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Bill Paul. 18 * 4. Neither the name of the author nor the names of any co-contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 32 * THE POSSIBILITY OF SUCH DAMAGE. 33 * 34 * $FreeBSD: src/sys/dev/usb/if_cue.c,v 1.4 2000/01/16 22:45:06 wpaul Exp $ 35 */ 36 37 /* 38 * CATC USB-EL1210A USB to ethernet driver. Used in the CATC Netmate 39 * adapters and others. 40 * 41 * Written by Bill Paul <wpaul@ee.columbia.edu> 42 * Electrical Engineering Department 43 * Columbia University, New York City 44 */ 45 46 /* 47 * The CATC USB-EL1210A provides USB ethernet support at 10Mbps. The 48 * RX filter uses a 512-bit multicast hash table, single perfect entry 49 * for the station address, and promiscuous mode. Unlike the ADMtek 50 * and KLSI chips, the CATC ASIC supports read and write combining 51 * mode where multiple packets can be transferred using a single bulk 52 * transaction, which helps performance a great deal. 53 */ 54 55 /* 56 * Ported to NetBSD and somewhat rewritten by Lennart Augustsson. 57 */ 58 59 #include "bpfilter.h" 60 61 #include <sys/param.h> 62 #include <sys/systm.h> 63 #include <sys/sockio.h> 64 #include <sys/mbuf.h> 65 #include <sys/timeout.h> 66 #include <sys/device.h> 67 68 #include <net/if.h> 69 70 #if NBPFILTER > 0 71 #include <net/bpf.h> 72 #endif 73 74 #include <netinet/in.h> 75 #include <netinet/if_ether.h> 76 77 #include <dev/usb/usb.h> 78 #include <dev/usb/usbdi.h> 79 #include <dev/usb/usbdi_util.h> 80 #include <dev/usb/usbdevs.h> 81 82 #include <dev/usb/if_cuereg.h> 83 84 #ifdef CUE_DEBUG 85 #define DPRINTF(x) do { if (cuedebug) printf x; } while (0) 86 #define DPRINTFN(n,x) do { if (cuedebug >= (n)) printf x; } while (0) 87 int cuedebug = 0; 88 #else 89 #define DPRINTF(x) 90 #define DPRINTFN(n,x) 91 #endif 92 93 /* 94 * Various supported device vendors/products. 95 */ 96 struct usb_devno cue_devs[] = { 97 { USB_VENDOR_CATC, USB_PRODUCT_CATC_NETMATE }, 98 { USB_VENDOR_CATC, USB_PRODUCT_CATC_NETMATE2 }, 99 { USB_VENDOR_SMARTBRIDGES, USB_PRODUCT_SMARTBRIDGES_SMARTLINK }, 100 /* Belkin F5U111 adapter covered by NETMATE entry */ 101 }; 102 103 int cue_match(struct device *, void *, void *); 104 void cue_attach(struct device *, struct device *, void *); 105 int cue_detach(struct device *, int); 106 107 struct cfdriver cue_cd = { 108 NULL, "cue", DV_IFNET 109 }; 110 111 const struct cfattach cue_ca = { 112 sizeof(struct cue_softc), cue_match, cue_attach, cue_detach 113 }; 114 115 int cue_open_pipes(struct cue_softc *); 116 int cue_tx_list_init(struct cue_softc *); 117 int cue_rx_list_init(struct cue_softc *); 118 int cue_newbuf(struct cue_softc *, struct cue_chain *, struct mbuf *); 119 int cue_send(struct cue_softc *, struct mbuf *, int); 120 void cue_rxeof(struct usbd_xfer *, void *, usbd_status); 121 void cue_txeof(struct usbd_xfer *, void *, usbd_status); 122 void cue_tick(void *); 123 void cue_tick_task(void *); 124 void cue_start(struct ifnet *); 125 int cue_ioctl(struct ifnet *, u_long, caddr_t); 126 void cue_init(void *); 127 void cue_stop(struct cue_softc *); 128 void cue_watchdog(struct ifnet *); 129 130 void cue_setmulti(struct cue_softc *); 131 void cue_reset(struct cue_softc *); 132 133 int cue_csr_read_1(struct cue_softc *, int); 134 int cue_csr_write_1(struct cue_softc *, int, int); 135 int cue_csr_read_2(struct cue_softc *, int); 136 #if 0 137 int cue_csr_write_2(struct cue_softc *, int, int); 138 #endif 139 int cue_mem(struct cue_softc *, int, int, void *, int); 140 int cue_getmac(struct cue_softc *, void *); 141 142 #define CUE_SETBIT(sc, reg, x) \ 143 cue_csr_write_1(sc, reg, cue_csr_read_1(sc, reg) | (x)) 144 145 #define CUE_CLRBIT(sc, reg, x) \ 146 cue_csr_write_1(sc, reg, cue_csr_read_1(sc, reg) & ~(x)) 147 148 int 149 cue_csr_read_1(struct cue_softc *sc, int reg) 150 { 151 usb_device_request_t req; 152 usbd_status err; 153 u_int8_t val = 0; 154 155 if (usbd_is_dying(sc->cue_udev)) 156 return (0); 157 158 req.bmRequestType = UT_READ_VENDOR_DEVICE; 159 req.bRequest = CUE_CMD_READREG; 160 USETW(req.wValue, 0); 161 USETW(req.wIndex, reg); 162 USETW(req.wLength, 1); 163 164 err = usbd_do_request(sc->cue_udev, &req, &val); 165 166 if (err) { 167 DPRINTF(("%s: cue_csr_read_1: reg=0x%x err=%s\n", 168 sc->cue_dev.dv_xname, reg, usbd_errstr(err))); 169 return (0); 170 } 171 172 DPRINTFN(10,("%s: cue_csr_read_1 reg=0x%x val=0x%x\n", 173 sc->cue_dev.dv_xname, reg, val)); 174 175 return (val); 176 } 177 178 int 179 cue_csr_read_2(struct cue_softc *sc, int reg) 180 { 181 usb_device_request_t req; 182 usbd_status err; 183 uWord val; 184 185 if (usbd_is_dying(sc->cue_udev)) 186 return (0); 187 188 req.bmRequestType = UT_READ_VENDOR_DEVICE; 189 req.bRequest = CUE_CMD_READREG; 190 USETW(req.wValue, 0); 191 USETW(req.wIndex, reg); 192 USETW(req.wLength, 2); 193 194 err = usbd_do_request(sc->cue_udev, &req, &val); 195 196 DPRINTFN(10,("%s: cue_csr_read_2 reg=0x%x val=0x%x\n", 197 sc->cue_dev.dv_xname, reg, UGETW(val))); 198 199 if (err) { 200 DPRINTF(("%s: cue_csr_read_2: reg=0x%x err=%s\n", 201 sc->cue_dev.dv_xname, reg, usbd_errstr(err))); 202 return (0); 203 } 204 205 return (UGETW(val)); 206 } 207 208 int 209 cue_csr_write_1(struct cue_softc *sc, int reg, int val) 210 { 211 usb_device_request_t req; 212 usbd_status err; 213 214 if (usbd_is_dying(sc->cue_udev)) 215 return (0); 216 217 DPRINTFN(10,("%s: cue_csr_write_1 reg=0x%x val=0x%x\n", 218 sc->cue_dev.dv_xname, reg, val)); 219 220 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 221 req.bRequest = CUE_CMD_WRITEREG; 222 USETW(req.wValue, val); 223 USETW(req.wIndex, reg); 224 USETW(req.wLength, 0); 225 226 err = usbd_do_request(sc->cue_udev, &req, NULL); 227 228 if (err) { 229 DPRINTF(("%s: cue_csr_write_1: reg=0x%x err=%s\n", 230 sc->cue_dev.dv_xname, reg, usbd_errstr(err))); 231 return (-1); 232 } 233 234 DPRINTFN(20,("%s: cue_csr_write_1, after reg=0x%x val=0x%x\n", 235 sc->cue_dev.dv_xname, reg, cue_csr_read_1(sc, reg))); 236 237 return (0); 238 } 239 240 #if 0 241 int 242 cue_csr_write_2(struct cue_softc *sc, int reg, int aval) 243 { 244 usb_device_request_t req; 245 usbd_status err; 246 uWord val; 247 int s; 248 249 if (usbd_is_dying(sc->cue_udev)) 250 return (0); 251 252 DPRINTFN(10,("%s: cue_csr_write_2 reg=0x%x val=0x%x\n", 253 sc->cue_dev.dv_xname, reg, aval)); 254 255 USETW(val, aval); 256 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 257 req.bRequest = CUE_CMD_WRITEREG; 258 USETW(req.wValue, val); 259 USETW(req.wIndex, reg); 260 USETW(req.wLength, 0); 261 262 err = usbd_do_request(sc->cue_udev, &req, NULL); 263 264 if (err) { 265 DPRINTF(("%s: cue_csr_write_2: reg=0x%x err=%s\n", 266 sc->cue_dev.dv_xname, reg, usbd_errstr(err))); 267 return (-1); 268 } 269 270 return (0); 271 } 272 #endif 273 274 int 275 cue_mem(struct cue_softc *sc, int cmd, int addr, void *buf, int len) 276 { 277 usb_device_request_t req; 278 usbd_status err; 279 280 DPRINTFN(10,("%s: cue_mem cmd=0x%x addr=0x%x len=%d\n", 281 sc->cue_dev.dv_xname, cmd, addr, len)); 282 283 if (cmd == CUE_CMD_READSRAM) 284 req.bmRequestType = UT_READ_VENDOR_DEVICE; 285 else 286 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 287 req.bRequest = cmd; 288 USETW(req.wValue, 0); 289 USETW(req.wIndex, addr); 290 USETW(req.wLength, len); 291 292 err = usbd_do_request(sc->cue_udev, &req, buf); 293 294 if (err) { 295 DPRINTF(("%s: cue_csr_mem: addr=0x%x err=%s\n", 296 sc->cue_dev.dv_xname, addr, usbd_errstr(err))); 297 return (-1); 298 } 299 300 return (0); 301 } 302 303 int 304 cue_getmac(struct cue_softc *sc, void *buf) 305 { 306 usb_device_request_t req; 307 usbd_status err; 308 309 DPRINTFN(10,("%s: cue_getmac\n", sc->cue_dev.dv_xname)); 310 311 req.bmRequestType = UT_READ_VENDOR_DEVICE; 312 req.bRequest = CUE_CMD_GET_MACADDR; 313 USETW(req.wValue, 0); 314 USETW(req.wIndex, 0); 315 USETW(req.wLength, ETHER_ADDR_LEN); 316 317 err = usbd_do_request(sc->cue_udev, &req, buf); 318 319 if (err) { 320 printf("%s: read MAC address failed\n", 321 sc->cue_dev.dv_xname); 322 return (-1); 323 } 324 325 return (0); 326 } 327 328 #define CUE_BITS 9 329 330 void 331 cue_setmulti(struct cue_softc *sc) 332 { 333 struct arpcom *ac = &sc->arpcom; 334 struct ifnet *ifp; 335 struct ether_multi *enm; 336 struct ether_multistep step; 337 u_int32_t h, i; 338 339 ifp = GET_IFP(sc); 340 341 DPRINTFN(2,("%s: cue_setmulti if_flags=0x%x\n", 342 sc->cue_dev.dv_xname, ifp->if_flags)); 343 344 if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) { 345 ifp->if_flags |= IFF_ALLMULTI; 346 for (i = 0; i < CUE_MCAST_TABLE_LEN; i++) 347 sc->cue_mctab[i] = 0xFF; 348 cue_mem(sc, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR, 349 &sc->cue_mctab, CUE_MCAST_TABLE_LEN); 350 return; 351 } 352 353 /* first, zot all the existing hash bits */ 354 for (i = 0; i < CUE_MCAST_TABLE_LEN; i++) 355 sc->cue_mctab[i] = 0; 356 357 /* now program new ones */ 358 ETHER_FIRST_MULTI(step, ac, enm); 359 while (enm != NULL) { 360 h = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN) & 361 ((1 << CUE_BITS) - 1); 362 sc->cue_mctab[h >> 3] |= 1 << (h & 0x7); 363 ETHER_NEXT_MULTI(step, enm); 364 } 365 366 ifp->if_flags &= ~IFF_ALLMULTI; 367 368 /* 369 * Also include the broadcast address in the filter 370 * so we can receive broadcast frames. 371 */ 372 if (ifp->if_flags & IFF_BROADCAST) { 373 h = ether_crc32_le(etherbroadcastaddr, ETHER_ADDR_LEN) & 374 ((1 << CUE_BITS) - 1); 375 sc->cue_mctab[h >> 3] |= 1 << (h & 0x7); 376 } 377 378 cue_mem(sc, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR, 379 &sc->cue_mctab, CUE_MCAST_TABLE_LEN); 380 } 381 382 void 383 cue_reset(struct cue_softc *sc) 384 { 385 usb_device_request_t req; 386 usbd_status err; 387 388 DPRINTFN(2,("%s: cue_reset\n", sc->cue_dev.dv_xname)); 389 390 if (usbd_is_dying(sc->cue_udev)) 391 return; 392 393 req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 394 req.bRequest = CUE_CMD_RESET; 395 USETW(req.wValue, 0); 396 USETW(req.wIndex, 0); 397 USETW(req.wLength, 0); 398 399 err = usbd_do_request(sc->cue_udev, &req, NULL); 400 401 if (err) 402 printf("%s: reset failed\n", sc->cue_dev.dv_xname); 403 404 /* Wait a little while for the chip to get its brains in order. */ 405 usbd_delay_ms(sc->cue_udev, 1); 406 } 407 408 /* 409 * Probe for a CATC chip. 410 */ 411 int 412 cue_match(struct device *parent, void *match, void *aux) 413 { 414 struct usb_attach_arg *uaa = aux; 415 416 if (uaa->iface == NULL || uaa->configno != CUE_CONFIG_NO) 417 return (UMATCH_NONE); 418 419 return (usb_lookup(cue_devs, uaa->vendor, uaa->product) != NULL ? 420 UMATCH_VENDOR_PRODUCT : UMATCH_NONE); 421 } 422 423 /* 424 * Attach the interface. Allocate softc structures, do ifmedia 425 * setup and ethernet/BPF attach. 426 */ 427 void 428 cue_attach(struct device *parent, struct device *self, void *aux) 429 { 430 struct cue_softc *sc = (struct cue_softc *)self; 431 struct usb_attach_arg *uaa = aux; 432 int s; 433 u_char eaddr[ETHER_ADDR_LEN]; 434 struct usbd_device *dev = uaa->device; 435 struct usbd_interface *iface; 436 usbd_status err; 437 struct ifnet *ifp; 438 usb_interface_descriptor_t *id; 439 usb_endpoint_descriptor_t *ed; 440 int i; 441 442 DPRINTFN(5,(" : cue_attach: sc=%p, dev=%p", sc, dev)); 443 444 sc->cue_udev = dev; 445 sc->cue_product = uaa->product; 446 sc->cue_vendor = uaa->vendor; 447 448 usb_init_task(&sc->cue_tick_task, cue_tick_task, sc, 449 USB_TASK_TYPE_GENERIC); 450 usb_init_task(&sc->cue_stop_task, (void (*)(void *))cue_stop, sc, 451 USB_TASK_TYPE_GENERIC); 452 453 err = usbd_device2interface_handle(dev, CUE_IFACE_IDX, &iface); 454 if (err) { 455 printf("%s: getting interface handle failed\n", 456 sc->cue_dev.dv_xname); 457 return; 458 } 459 460 sc->cue_iface = iface; 461 id = usbd_get_interface_descriptor(iface); 462 463 /* Find endpoints. */ 464 for (i = 0; i < id->bNumEndpoints; i++) { 465 ed = usbd_interface2endpoint_descriptor(iface, i); 466 if (ed == NULL) { 467 printf("%s: couldn't get ep %d\n", 468 sc->cue_dev.dv_xname, i); 469 return; 470 } 471 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 472 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 473 sc->cue_ed[CUE_ENDPT_RX] = ed->bEndpointAddress; 474 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && 475 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 476 sc->cue_ed[CUE_ENDPT_TX] = ed->bEndpointAddress; 477 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 478 UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { 479 sc->cue_ed[CUE_ENDPT_INTR] = ed->bEndpointAddress; 480 } 481 } 482 483 #if 0 484 /* Reset the adapter. */ 485 cue_reset(sc); 486 #endif 487 /* 488 * Get station address. 489 */ 490 cue_getmac(sc, &eaddr); 491 492 s = splnet(); 493 494 /* 495 * A CATC chip was detected. Inform the world. 496 */ 497 printf("%s: address %s\n", sc->cue_dev.dv_xname, 498 ether_sprintf(eaddr)); 499 500 bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 501 502 /* Initialize interface info.*/ 503 ifp = GET_IFP(sc); 504 ifp->if_softc = sc; 505 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 506 ifp->if_ioctl = cue_ioctl; 507 ifp->if_start = cue_start; 508 ifp->if_watchdog = cue_watchdog; 509 strlcpy(ifp->if_xname, sc->cue_dev.dv_xname, IFNAMSIZ); 510 511 /* Attach the interface. */ 512 if_attach(ifp); 513 ether_ifattach(ifp); 514 515 timeout_set(&sc->cue_stat_ch, cue_tick, sc); 516 517 splx(s); 518 } 519 520 int 521 cue_detach(struct device *self, int flags) 522 { 523 struct cue_softc *sc = (struct cue_softc *)self; 524 struct ifnet *ifp = GET_IFP(sc); 525 int s; 526 527 DPRINTFN(2,("%s: %s: enter\n", sc->cue_dev.dv_xname, __func__)); 528 529 if (timeout_initialized(&sc->cue_stat_ch)) 530 timeout_del(&sc->cue_stat_ch); 531 532 /* 533 * Remove any pending task. It cannot be executing because it run 534 * in the same thread as detach. 535 */ 536 usb_rem_task(sc->cue_udev, &sc->cue_tick_task); 537 usb_rem_task(sc->cue_udev, &sc->cue_stop_task); 538 539 s = splusb(); 540 541 if (ifp->if_flags & IFF_RUNNING) 542 cue_stop(sc); 543 544 if (ifp->if_softc != NULL) { 545 ether_ifdetach(ifp); 546 if_detach(ifp); 547 } 548 549 #ifdef DIAGNOSTIC 550 if (sc->cue_ep[CUE_ENDPT_TX] != NULL || 551 sc->cue_ep[CUE_ENDPT_RX] != NULL || 552 sc->cue_ep[CUE_ENDPT_INTR] != NULL) 553 printf("%s: detach has active endpoints\n", 554 sc->cue_dev.dv_xname); 555 #endif 556 557 splx(s); 558 559 return (0); 560 } 561 562 /* 563 * Initialize an RX descriptor and attach an MBUF cluster. 564 */ 565 int 566 cue_newbuf(struct cue_softc *sc, struct cue_chain *c, struct mbuf *m) 567 { 568 struct mbuf *m_new = NULL; 569 570 if (m == NULL) { 571 MGETHDR(m_new, M_DONTWAIT, MT_DATA); 572 if (m_new == NULL) { 573 printf("%s: no memory for rx list " 574 "-- packet dropped!\n", sc->cue_dev.dv_xname); 575 return (ENOBUFS); 576 } 577 578 MCLGET(m_new, M_DONTWAIT); 579 if (!(m_new->m_flags & M_EXT)) { 580 printf("%s: no memory for rx list " 581 "-- packet dropped!\n", sc->cue_dev.dv_xname); 582 m_freem(m_new); 583 return (ENOBUFS); 584 } 585 m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 586 } else { 587 m_new = m; 588 m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 589 m_new->m_data = m_new->m_ext.ext_buf; 590 } 591 592 m_adj(m_new, ETHER_ALIGN); 593 c->cue_mbuf = m_new; 594 595 return (0); 596 } 597 598 int 599 cue_rx_list_init(struct cue_softc *sc) 600 { 601 struct cue_cdata *cd; 602 struct cue_chain *c; 603 int i; 604 605 cd = &sc->cue_cdata; 606 for (i = 0; i < CUE_RX_LIST_CNT; i++) { 607 c = &cd->cue_rx_chain[i]; 608 c->cue_sc = sc; 609 c->cue_idx = i; 610 if (cue_newbuf(sc, c, NULL) == ENOBUFS) 611 return (ENOBUFS); 612 if (c->cue_xfer == NULL) { 613 c->cue_xfer = usbd_alloc_xfer(sc->cue_udev); 614 if (c->cue_xfer == NULL) 615 return (ENOBUFS); 616 c->cue_buf = usbd_alloc_buffer(c->cue_xfer, CUE_BUFSZ); 617 if (c->cue_buf == NULL) { 618 usbd_free_xfer(c->cue_xfer); 619 return (ENOBUFS); 620 } 621 } 622 } 623 624 return (0); 625 } 626 627 int 628 cue_tx_list_init(struct cue_softc *sc) 629 { 630 struct cue_cdata *cd; 631 struct cue_chain *c; 632 int i; 633 634 cd = &sc->cue_cdata; 635 for (i = 0; i < CUE_TX_LIST_CNT; i++) { 636 c = &cd->cue_tx_chain[i]; 637 c->cue_sc = sc; 638 c->cue_idx = i; 639 c->cue_mbuf = NULL; 640 if (c->cue_xfer == NULL) { 641 c->cue_xfer = usbd_alloc_xfer(sc->cue_udev); 642 if (c->cue_xfer == NULL) 643 return (ENOBUFS); 644 c->cue_buf = usbd_alloc_buffer(c->cue_xfer, CUE_BUFSZ); 645 if (c->cue_buf == NULL) { 646 usbd_free_xfer(c->cue_xfer); 647 return (ENOBUFS); 648 } 649 } 650 } 651 652 return (0); 653 } 654 655 /* 656 * A frame has been uploaded: pass the resulting mbuf chain up to 657 * the higher level protocols. 658 */ 659 void 660 cue_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status) 661 { 662 struct cue_chain *c = priv; 663 struct cue_softc *sc = c->cue_sc; 664 struct ifnet *ifp = GET_IFP(sc); 665 struct mbuf_list ml = MBUF_LIST_INITIALIZER(); 666 struct mbuf *m; 667 int total_len = 0; 668 u_int16_t len; 669 int s; 670 671 DPRINTFN(10,("%s: %s: enter status=%d\n", sc->cue_dev.dv_xname, 672 __func__, status)); 673 674 if (usbd_is_dying(sc->cue_udev)) 675 return; 676 677 if (!(ifp->if_flags & IFF_RUNNING)) 678 return; 679 680 if (status != USBD_NORMAL_COMPLETION) { 681 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) 682 return; 683 sc->cue_rx_errs++; 684 if (usbd_ratecheck(&sc->cue_rx_notice)) { 685 printf("%s: %u usb errors on rx: %s\n", 686 sc->cue_dev.dv_xname, sc->cue_rx_errs, 687 usbd_errstr(status)); 688 sc->cue_rx_errs = 0; 689 } 690 if (status == USBD_STALLED) 691 usbd_clear_endpoint_stall_async(sc->cue_ep[CUE_ENDPT_RX]); 692 goto done; 693 } 694 695 usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL); 696 697 memcpy(mtod(c->cue_mbuf, char *), c->cue_buf, total_len); 698 699 m = c->cue_mbuf; 700 len = UGETW(mtod(m, u_int8_t *)); 701 702 /* No errors; receive the packet. */ 703 total_len = len; 704 705 if (len < sizeof(struct ether_header)) { 706 ifp->if_ierrors++; 707 goto done; 708 } 709 710 m_adj(m, sizeof(u_int16_t)); 711 m->m_pkthdr.len = m->m_len = total_len; 712 ml_enqueue(&ml, m); 713 714 if (cue_newbuf(sc, c, NULL) == ENOBUFS) { 715 ifp->if_ierrors++; 716 goto done; 717 } 718 719 s = splnet(); 720 if_input(ifp, &ml); 721 splx(s); 722 723 done: 724 /* Setup new transfer. */ 725 usbd_setup_xfer(c->cue_xfer, sc->cue_ep[CUE_ENDPT_RX], 726 c, c->cue_buf, CUE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY, 727 USBD_NO_TIMEOUT, cue_rxeof); 728 usbd_transfer(c->cue_xfer); 729 730 DPRINTFN(10,("%s: %s: start rx\n", sc->cue_dev.dv_xname, 731 __func__)); 732 } 733 734 /* 735 * A frame was downloaded to the chip. It's safe for us to clean up 736 * the list buffers. 737 */ 738 void 739 cue_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status) 740 { 741 struct cue_chain *c = priv; 742 struct cue_softc *sc = c->cue_sc; 743 struct ifnet *ifp = GET_IFP(sc); 744 int s; 745 746 if (usbd_is_dying(sc->cue_udev)) 747 return; 748 749 s = splnet(); 750 751 DPRINTFN(10,("%s: %s: enter status=%d\n", sc->cue_dev.dv_xname, 752 __func__, status)); 753 754 ifp->if_timer = 0; 755 ifq_clr_oactive(&ifp->if_snd); 756 757 if (status != USBD_NORMAL_COMPLETION) { 758 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) { 759 splx(s); 760 return; 761 } 762 ifp->if_oerrors++; 763 printf("%s: usb error on tx: %s\n", sc->cue_dev.dv_xname, 764 usbd_errstr(status)); 765 if (status == USBD_STALLED) 766 usbd_clear_endpoint_stall_async(sc->cue_ep[CUE_ENDPT_TX]); 767 splx(s); 768 return; 769 } 770 771 m_freem(c->cue_mbuf); 772 c->cue_mbuf = NULL; 773 774 if (ifq_empty(&ifp->if_snd) == 0) 775 cue_start(ifp); 776 777 splx(s); 778 } 779 780 void 781 cue_tick(void *xsc) 782 { 783 struct cue_softc *sc = xsc; 784 785 if (sc == NULL) 786 return; 787 788 if (usbd_is_dying(sc->cue_udev)) 789 return; 790 791 DPRINTFN(2,("%s: %s: enter\n", sc->cue_dev.dv_xname, __func__)); 792 793 /* Perform statistics update in process context. */ 794 usb_add_task(sc->cue_udev, &sc->cue_tick_task); 795 } 796 797 void 798 cue_tick_task(void *xsc) 799 { 800 struct cue_softc *sc = xsc; 801 struct ifnet *ifp; 802 803 if (usbd_is_dying(sc->cue_udev)) 804 return; 805 806 DPRINTFN(2,("%s: %s: enter\n", sc->cue_dev.dv_xname, __func__)); 807 808 ifp = GET_IFP(sc); 809 810 ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_SINGLECOLL); 811 ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_MULTICOLL); 812 ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_EXCESSCOLL); 813 814 if (cue_csr_read_2(sc, CUE_RX_FRAMEERR)) 815 ifp->if_ierrors++; 816 } 817 818 int 819 cue_send(struct cue_softc *sc, struct mbuf *m, int idx) 820 { 821 int total_len; 822 struct cue_chain *c; 823 usbd_status err; 824 825 c = &sc->cue_cdata.cue_tx_chain[idx]; 826 827 /* 828 * Copy the mbuf data into a contiguous buffer, leaving two 829 * bytes at the beginning to hold the frame length. 830 */ 831 m_copydata(m, 0, m->m_pkthdr.len, c->cue_buf + 2); 832 c->cue_mbuf = m; 833 834 total_len = m->m_pkthdr.len + 2; 835 836 DPRINTFN(10,("%s: %s: total_len=%d\n", 837 sc->cue_dev.dv_xname, __func__, total_len)); 838 839 /* The first two bytes are the frame length */ 840 c->cue_buf[0] = (u_int8_t)m->m_pkthdr.len; 841 c->cue_buf[1] = (u_int8_t)(m->m_pkthdr.len >> 8); 842 843 /* XXX 10000 */ 844 usbd_setup_xfer(c->cue_xfer, sc->cue_ep[CUE_ENDPT_TX], 845 c, c->cue_buf, total_len, USBD_NO_COPY, 10000, cue_txeof); 846 847 /* Transmit */ 848 err = usbd_transfer(c->cue_xfer); 849 if (err != USBD_IN_PROGRESS) { 850 printf("%s: cue_send error=%s\n", sc->cue_dev.dv_xname, 851 usbd_errstr(err)); 852 /* Stop the interface from process context. */ 853 usb_add_task(sc->cue_udev, &sc->cue_stop_task); 854 return (EIO); 855 } 856 857 sc->cue_cdata.cue_tx_cnt++; 858 859 return (0); 860 } 861 862 void 863 cue_start(struct ifnet *ifp) 864 { 865 struct cue_softc *sc = ifp->if_softc; 866 struct mbuf *m_head = NULL; 867 868 if (usbd_is_dying(sc->cue_udev)) 869 return; 870 871 DPRINTFN(10,("%s: %s: enter\n", sc->cue_dev.dv_xname,__func__)); 872 873 if (ifq_is_oactive(&ifp->if_snd)) 874 return; 875 876 m_head = ifq_deq_begin(&ifp->if_snd); 877 if (m_head == NULL) 878 return; 879 880 if (cue_send(sc, m_head, 0)) { 881 ifq_deq_rollback(&ifp->if_snd, m_head); 882 ifq_set_oactive(&ifp->if_snd); 883 return; 884 } 885 886 ifq_deq_commit(&ifp->if_snd, m_head); 887 888 #if NBPFILTER > 0 889 /* 890 * If there's a BPF listener, bounce a copy of this frame 891 * to him. 892 */ 893 if (ifp->if_bpf) 894 bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT); 895 #endif 896 897 ifq_set_oactive(&ifp->if_snd); 898 899 /* 900 * Set a timeout in case the chip goes out to lunch. 901 */ 902 ifp->if_timer = 5; 903 } 904 905 void 906 cue_init(void *xsc) 907 { 908 struct cue_softc *sc = xsc; 909 struct ifnet *ifp = GET_IFP(sc); 910 int i, s, ctl; 911 u_char *eaddr; 912 913 if (usbd_is_dying(sc->cue_udev)) 914 return; 915 916 DPRINTFN(10,("%s: %s: enter\n", sc->cue_dev.dv_xname,__func__)); 917 918 if (ifp->if_flags & IFF_RUNNING) 919 return; 920 921 s = splnet(); 922 923 /* 924 * Cancel pending I/O and free all RX/TX buffers. 925 */ 926 #if 1 927 cue_reset(sc); 928 #endif 929 930 /* Set advanced operation modes. */ 931 cue_csr_write_1(sc, CUE_ADVANCED_OPMODES, 932 CUE_AOP_EMBED_RXLEN | 0x03); /* 1 wait state */ 933 934 eaddr = sc->arpcom.ac_enaddr; 935 /* Set MAC address */ 936 for (i = 0; i < ETHER_ADDR_LEN; i++) 937 cue_csr_write_1(sc, CUE_PAR0 - i, eaddr[i]); 938 939 /* Enable RX logic. */ 940 ctl = CUE_ETHCTL_RX_ON | CUE_ETHCTL_MCAST_ON; 941 if (ifp->if_flags & IFF_PROMISC) 942 ctl |= CUE_ETHCTL_PROMISC; 943 cue_csr_write_1(sc, CUE_ETHCTL, ctl); 944 945 /* Init TX ring. */ 946 if (cue_tx_list_init(sc) == ENOBUFS) { 947 printf("%s: tx list init failed\n", sc->cue_dev.dv_xname); 948 splx(s); 949 return; 950 } 951 952 /* Init RX ring. */ 953 if (cue_rx_list_init(sc) == ENOBUFS) { 954 printf("%s: rx list init failed\n", sc->cue_dev.dv_xname); 955 splx(s); 956 return; 957 } 958 959 /* Load the multicast filter. */ 960 cue_setmulti(sc); 961 962 /* 963 * Set the number of RX and TX buffers that we want 964 * to reserve inside the ASIC. 965 */ 966 cue_csr_write_1(sc, CUE_RX_BUFPKTS, CUE_RX_FRAMES); 967 cue_csr_write_1(sc, CUE_TX_BUFPKTS, CUE_TX_FRAMES); 968 969 /* Set advanced operation modes. */ 970 cue_csr_write_1(sc, CUE_ADVANCED_OPMODES, 971 CUE_AOP_EMBED_RXLEN | 0x01); /* 1 wait state */ 972 973 /* Program the LED operation. */ 974 cue_csr_write_1(sc, CUE_LEDCTL, CUE_LEDCTL_FOLLOW_LINK); 975 976 if (sc->cue_ep[CUE_ENDPT_RX] == NULL) { 977 if (cue_open_pipes(sc)) { 978 splx(s); 979 return; 980 } 981 } 982 983 ifp->if_flags |= IFF_RUNNING; 984 ifq_clr_oactive(&ifp->if_snd); 985 986 splx(s); 987 988 timeout_add_sec(&sc->cue_stat_ch, 1); 989 } 990 991 int 992 cue_open_pipes(struct cue_softc *sc) 993 { 994 struct cue_chain *c; 995 usbd_status err; 996 int i; 997 998 /* Open RX and TX pipes. */ 999 err = usbd_open_pipe(sc->cue_iface, sc->cue_ed[CUE_ENDPT_RX], 1000 USBD_EXCLUSIVE_USE, &sc->cue_ep[CUE_ENDPT_RX]); 1001 if (err) { 1002 printf("%s: open rx pipe failed: %s\n", 1003 sc->cue_dev.dv_xname, usbd_errstr(err)); 1004 return (EIO); 1005 } 1006 err = usbd_open_pipe(sc->cue_iface, sc->cue_ed[CUE_ENDPT_TX], 1007 USBD_EXCLUSIVE_USE, &sc->cue_ep[CUE_ENDPT_TX]); 1008 if (err) { 1009 printf("%s: open tx pipe failed: %s\n", 1010 sc->cue_dev.dv_xname, usbd_errstr(err)); 1011 return (EIO); 1012 } 1013 1014 /* Start up the receive pipe. */ 1015 for (i = 0; i < CUE_RX_LIST_CNT; i++) { 1016 c = &sc->cue_cdata.cue_rx_chain[i]; 1017 usbd_setup_xfer(c->cue_xfer, sc->cue_ep[CUE_ENDPT_RX], 1018 c, c->cue_buf, CUE_BUFSZ, 1019 USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT, 1020 cue_rxeof); 1021 usbd_transfer(c->cue_xfer); 1022 } 1023 1024 return (0); 1025 } 1026 1027 int 1028 cue_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 1029 { 1030 struct cue_softc *sc = ifp->if_softc; 1031 int s, error = 0; 1032 1033 if (usbd_is_dying(sc->cue_udev)) 1034 return ENXIO; 1035 1036 s = splnet(); 1037 1038 switch(command) { 1039 case SIOCSIFADDR: 1040 ifp->if_flags |= IFF_UP; 1041 cue_init(sc); 1042 break; 1043 1044 case SIOCSIFFLAGS: 1045 if (ifp->if_flags & IFF_UP) { 1046 if (ifp->if_flags & IFF_RUNNING && 1047 ifp->if_flags & IFF_PROMISC && 1048 !(sc->cue_if_flags & IFF_PROMISC)) { 1049 CUE_SETBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC); 1050 cue_setmulti(sc); 1051 } else if (ifp->if_flags & IFF_RUNNING && 1052 !(ifp->if_flags & IFF_PROMISC) && 1053 sc->cue_if_flags & IFF_PROMISC) { 1054 CUE_CLRBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC); 1055 cue_setmulti(sc); 1056 } else if (!(ifp->if_flags & IFF_RUNNING)) 1057 cue_init(sc); 1058 } else { 1059 if (ifp->if_flags & IFF_RUNNING) 1060 cue_stop(sc); 1061 } 1062 sc->cue_if_flags = ifp->if_flags; 1063 error = 0; 1064 break; 1065 1066 default: 1067 error = ether_ioctl(ifp, &sc->arpcom, command, data); 1068 } 1069 1070 if (error == ENETRESET) { 1071 if (ifp->if_flags & IFF_RUNNING) 1072 cue_setmulti(sc); 1073 error = 0; 1074 } 1075 1076 splx(s); 1077 return (error); 1078 } 1079 1080 void 1081 cue_watchdog(struct ifnet *ifp) 1082 { 1083 struct cue_softc *sc = ifp->if_softc; 1084 struct cue_chain *c; 1085 usbd_status stat; 1086 int s; 1087 1088 DPRINTFN(5,("%s: %s: enter\n", sc->cue_dev.dv_xname,__func__)); 1089 1090 if (usbd_is_dying(sc->cue_udev)) 1091 return; 1092 1093 ifp->if_oerrors++; 1094 printf("%s: watchdog timeout\n", sc->cue_dev.dv_xname); 1095 1096 s = splusb(); 1097 c = &sc->cue_cdata.cue_tx_chain[0]; 1098 usbd_get_xfer_status(c->cue_xfer, NULL, NULL, NULL, &stat); 1099 cue_txeof(c->cue_xfer, c, stat); 1100 1101 if (ifq_empty(&ifp->if_snd) == 0) 1102 cue_start(ifp); 1103 splx(s); 1104 } 1105 1106 /* 1107 * Stop the adapter and free any mbufs allocated to the 1108 * RX and TX lists. 1109 */ 1110 void 1111 cue_stop(struct cue_softc *sc) 1112 { 1113 usbd_status err; 1114 struct ifnet *ifp; 1115 int i; 1116 1117 DPRINTFN(10,("%s: %s: enter\n", sc->cue_dev.dv_xname,__func__)); 1118 1119 ifp = GET_IFP(sc); 1120 ifp->if_timer = 0; 1121 ifp->if_flags &= ~IFF_RUNNING; 1122 ifq_clr_oactive(&ifp->if_snd); 1123 1124 cue_csr_write_1(sc, CUE_ETHCTL, 0); 1125 cue_reset(sc); 1126 timeout_del(&sc->cue_stat_ch); 1127 1128 /* Stop transfers. */ 1129 if (sc->cue_ep[CUE_ENDPT_RX] != NULL) { 1130 err = usbd_close_pipe(sc->cue_ep[CUE_ENDPT_RX]); 1131 if (err) { 1132 printf("%s: close rx pipe failed: %s\n", 1133 sc->cue_dev.dv_xname, usbd_errstr(err)); 1134 } 1135 sc->cue_ep[CUE_ENDPT_RX] = NULL; 1136 } 1137 1138 if (sc->cue_ep[CUE_ENDPT_TX] != NULL) { 1139 err = usbd_close_pipe(sc->cue_ep[CUE_ENDPT_TX]); 1140 if (err) { 1141 printf("%s: close tx pipe failed: %s\n", 1142 sc->cue_dev.dv_xname, usbd_errstr(err)); 1143 } 1144 sc->cue_ep[CUE_ENDPT_TX] = NULL; 1145 } 1146 1147 if (sc->cue_ep[CUE_ENDPT_INTR] != NULL) { 1148 err = usbd_close_pipe(sc->cue_ep[CUE_ENDPT_INTR]); 1149 if (err) { 1150 printf("%s: close intr pipe failed: %s\n", 1151 sc->cue_dev.dv_xname, usbd_errstr(err)); 1152 } 1153 sc->cue_ep[CUE_ENDPT_INTR] = NULL; 1154 } 1155 1156 /* Free RX resources. */ 1157 for (i = 0; i < CUE_RX_LIST_CNT; i++) { 1158 if (sc->cue_cdata.cue_rx_chain[i].cue_mbuf != NULL) { 1159 m_freem(sc->cue_cdata.cue_rx_chain[i].cue_mbuf); 1160 sc->cue_cdata.cue_rx_chain[i].cue_mbuf = NULL; 1161 } 1162 if (sc->cue_cdata.cue_rx_chain[i].cue_xfer != NULL) { 1163 usbd_free_xfer(sc->cue_cdata.cue_rx_chain[i].cue_xfer); 1164 sc->cue_cdata.cue_rx_chain[i].cue_xfer = NULL; 1165 } 1166 } 1167 1168 /* Free TX resources. */ 1169 for (i = 0; i < CUE_TX_LIST_CNT; i++) { 1170 if (sc->cue_cdata.cue_tx_chain[i].cue_mbuf != NULL) { 1171 m_freem(sc->cue_cdata.cue_tx_chain[i].cue_mbuf); 1172 sc->cue_cdata.cue_tx_chain[i].cue_mbuf = NULL; 1173 } 1174 if (sc->cue_cdata.cue_tx_chain[i].cue_xfer != NULL) { 1175 usbd_free_xfer(sc->cue_cdata.cue_tx_chain[i].cue_xfer); 1176 sc->cue_cdata.cue_tx_chain[i].cue_xfer = NULL; 1177 } 1178 } 1179 } 1180