1 /* $OpenBSD: if_ugl.c,v 1.28 2024/05/23 03:21:09 jsg Exp $ */ 2 /* $NetBSD: if_upl.c,v 1.19 2002/07/11 21:14:26 augustss Exp $ */ 3 /* 4 * Copyright (c) 2013 SASANO Takayoshi <uaa@uaa.org.uk> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /* 20 * Copyright (c) 2000 The NetBSD Foundation, Inc. 21 * All rights reserved. 22 * 23 * This code is derived from software contributed to The NetBSD Foundation 24 * by Lennart Augustsson (lennart@augustsson.net) at 25 * Carlstedt Research & Technology. 26 * 27 * Redistribution and use in source and binary forms, with or without 28 * modification, are permitted provided that the following conditions 29 * are met: 30 * 1. Redistributions of source code must retain the above copyright 31 * notice, this list of conditions and the following disclaimer. 32 * 2. Redistributions in binary form must reproduce the above copyright 33 * notice, this list of conditions and the following disclaimer in the 34 * documentation and/or other materials provided with the distribution. 35 * 36 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 37 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 38 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 39 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 40 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 41 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 42 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 43 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 44 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 45 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 46 * POSSIBILITY OF SUCH DAMAGE. 47 */ 48 49 /* 50 * Genesys Logic GL620USB-A driver 51 * This driver is based on Prolific PL2301/PL2302 driver (if_upl.c). 52 */ 53 54 #include <bpfilter.h> 55 56 #include <sys/param.h> 57 #include <sys/systm.h> 58 #include <sys/timeout.h> 59 #include <sys/sockio.h> 60 #include <sys/mbuf.h> 61 62 #include <sys/device.h> 63 64 #include <net/if.h> 65 66 #if NBPFILTER > 0 67 #include <net/bpf.h> 68 #endif 69 70 #include <netinet/in.h> 71 #include <netinet/if_ether.h> 72 73 #include <dev/usb/usb.h> 74 #include <dev/usb/usbdi.h> 75 #include <dev/usb/usbdevs.h> 76 77 #define UGL_INTR_PKTLEN 8 78 #define UGL_BULK_PKTLEN 64 79 80 /***/ 81 82 #define UGL_INTR_INTERVAL 20 83 84 #define UGL_MAX_MTU 1514 85 #define UGL_BUFSZ roundup(sizeof(struct ugl_packet), UGL_BULK_PKTLEN) 86 87 #define UGL_RX_FRAMES 1 /* must be one */ 88 #define UGL_TX_FRAMES 1 /* must be one */ 89 90 #define UGL_RX_LIST_CNT 1 91 #define UGL_TX_LIST_CNT 1 92 93 #define UGL_ENDPT_RX 0x0 94 #define UGL_ENDPT_TX 0x1 95 #define UGL_ENDPT_INTR 0x2 96 #define UGL_ENDPT_MAX 0x3 97 98 struct ugl_softc; 99 100 struct ugl_packet { 101 uDWord pkt_count; 102 uDWord pkt_length; 103 char pkt_data[UGL_MAX_MTU]; 104 } __packed; 105 106 struct ugl_chain { 107 struct ugl_softc *ugl_sc; 108 struct usbd_xfer *ugl_xfer; 109 struct ugl_packet *ugl_buf; 110 struct mbuf *ugl_mbuf; 111 int ugl_idx; 112 }; 113 114 struct ugl_cdata { 115 struct ugl_chain ugl_tx_chain[UGL_TX_LIST_CNT]; 116 struct ugl_chain ugl_rx_chain[UGL_RX_LIST_CNT]; 117 int ugl_tx_prod; 118 int ugl_tx_cons; 119 int ugl_tx_cnt; 120 int ugl_rx_prod; 121 }; 122 123 struct ugl_softc { 124 struct device sc_dev; 125 126 struct arpcom sc_arpcom; 127 #define GET_IFP(sc) (&(sc)->sc_arpcom.ac_if) 128 struct timeout sc_stat_ch; 129 130 struct usbd_device *sc_udev; 131 struct usbd_interface *sc_iface; 132 int sc_ed[UGL_ENDPT_MAX]; 133 struct usbd_pipe *sc_ep[UGL_ENDPT_MAX]; 134 struct ugl_cdata sc_cdata; 135 136 uByte sc_ibuf[UGL_INTR_PKTLEN]; 137 138 u_int sc_rx_errs; 139 struct timeval sc_rx_notice; 140 u_int sc_intr_errs; 141 }; 142 143 #ifdef UGL_DEBUG 144 #define DPRINTF(x) do { if (ugldebug) printf x; } while (0) 145 #define DPRINTFN(n,x) do { if (ugldebug >= (n)) printf x; } while (0) 146 int ugldebug = 0; 147 #else 148 #define DPRINTF(x) 149 #define DPRINTFN(n,x) 150 #endif 151 152 /* 153 * Various supported device vendors/products. 154 */ 155 struct usb_devno ugl_devs[] = { 156 { USB_VENDOR_GENESYS, USB_PRODUCT_GENESYS_GL620USB_A }, 157 }; 158 159 int ugl_match(struct device *, void *, void *); 160 void ugl_attach(struct device *, struct device *, void *); 161 int ugl_detach(struct device *, int); 162 163 struct cfdriver ugl_cd = { 164 NULL, "ugl", DV_IFNET 165 }; 166 167 const struct cfattach ugl_ca = { 168 sizeof(struct ugl_softc), ugl_match, ugl_attach, ugl_detach 169 }; 170 171 int ugl_openpipes(struct ugl_softc *); 172 int ugl_tx_list_init(struct ugl_softc *); 173 int ugl_rx_list_init(struct ugl_softc *); 174 int ugl_newbuf(struct ugl_softc *, struct ugl_chain *, struct mbuf *); 175 int ugl_send(struct ugl_softc *, struct mbuf *, int); 176 void ugl_intr(struct usbd_xfer *, void *, usbd_status); 177 void ugl_rxeof(struct usbd_xfer *, void *, usbd_status); 178 void ugl_txeof(struct usbd_xfer *, void *, usbd_status); 179 void ugl_start(struct ifnet *); 180 int ugl_ioctl(struct ifnet *, u_long, caddr_t); 181 void ugl_init(void *); 182 void ugl_stop(struct ugl_softc *); 183 void ugl_watchdog(struct ifnet *); 184 185 /* 186 * Probe for a Genesys Logic chip. 187 */ 188 int 189 ugl_match(struct device *parent, void *match, void *aux) 190 { 191 struct usb_attach_arg *uaa = aux; 192 193 if (uaa->iface == NULL || uaa->configno != 1) 194 return (UMATCH_NONE); 195 196 return (usb_lookup(ugl_devs, uaa->vendor, uaa->product) != NULL ? 197 UMATCH_VENDOR_PRODUCT_CONF_IFACE : UMATCH_NONE); 198 } 199 200 void 201 ugl_attach(struct device *parent, struct device *self, void *aux) 202 { 203 struct ugl_softc *sc = (struct ugl_softc *)self; 204 struct usb_attach_arg *uaa = aux; 205 int s; 206 struct usbd_device *dev = uaa->device; 207 struct usbd_interface *iface = uaa->iface; 208 struct ifnet *ifp = GET_IFP(sc); 209 usb_interface_descriptor_t *id; 210 usb_endpoint_descriptor_t *ed; 211 int i; 212 213 DPRINTFN(5,(" : ugl_attach: sc=%p, dev=%p", sc, dev)); 214 215 sc->sc_udev = dev; 216 sc->sc_iface = iface; 217 id = usbd_get_interface_descriptor(iface); 218 219 /* Find endpoints. */ 220 for (i = 0; i < id->bNumEndpoints; i++) { 221 ed = usbd_interface2endpoint_descriptor(iface, i); 222 if (ed == NULL) { 223 printf("%s: couldn't get ep %d\n", 224 sc->sc_dev.dv_xname, i); 225 return; 226 } 227 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 228 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 229 sc->sc_ed[UGL_ENDPT_RX] = ed->bEndpointAddress; 230 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && 231 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 232 sc->sc_ed[UGL_ENDPT_TX] = ed->bEndpointAddress; 233 } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 234 UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { 235 sc->sc_ed[UGL_ENDPT_INTR] = ed->bEndpointAddress; 236 } 237 } 238 239 if (sc->sc_ed[UGL_ENDPT_RX] == 0 || sc->sc_ed[UGL_ENDPT_TX] == 0 || 240 sc->sc_ed[UGL_ENDPT_INTR] == 0) { 241 printf("%s: missing endpoint\n", sc->sc_dev.dv_xname); 242 return; 243 } 244 245 s = splnet(); 246 247 ether_fakeaddr(ifp); 248 printf("%s: address %s\n", 249 sc->sc_dev.dv_xname, ether_sprintf(sc->sc_arpcom.ac_enaddr)); 250 251 /* Initialize interface info.*/ 252 ifp->if_softc = sc; 253 ifp->if_hardmtu = UGL_MAX_MTU; 254 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 255 ifp->if_ioctl = ugl_ioctl; 256 ifp->if_start = ugl_start; 257 ifp->if_watchdog = ugl_watchdog; 258 strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ); 259 260 /* Attach the interface. */ 261 if_attach(ifp); 262 ether_ifattach(ifp); 263 264 splx(s); 265 } 266 267 int 268 ugl_detach(struct device *self, int flags) 269 { 270 struct ugl_softc *sc = (struct ugl_softc *)self; 271 struct ifnet *ifp = GET_IFP(sc); 272 int s; 273 274 DPRINTFN(2,("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__)); 275 276 s = splusb(); 277 278 if (ifp->if_flags & IFF_RUNNING) 279 ugl_stop(sc); 280 281 if (ifp->if_softc != NULL) 282 if_detach(ifp); 283 284 #ifdef DIAGNOSTIC 285 if (sc->sc_ep[UGL_ENDPT_TX] != NULL || 286 sc->sc_ep[UGL_ENDPT_RX] != NULL || 287 sc->sc_ep[UGL_ENDPT_INTR] != NULL) 288 printf("%s: detach has active endpoints\n", 289 sc->sc_dev.dv_xname); 290 #endif 291 292 splx(s); 293 294 return (0); 295 } 296 297 /* 298 * Initialize an RX descriptor and attach an MBUF cluster. 299 */ 300 int 301 ugl_newbuf(struct ugl_softc *sc, struct ugl_chain *c, struct mbuf *m) 302 { 303 struct mbuf *m_new = NULL; 304 305 DPRINTFN(8,("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__)); 306 307 if (m == NULL) { 308 MGETHDR(m_new, M_DONTWAIT, MT_DATA); 309 if (m_new == NULL) { 310 printf("%s: no memory for rx list " 311 "-- packet dropped!\n", sc->sc_dev.dv_xname); 312 return (ENOBUFS); 313 } 314 315 MCLGET(m_new, M_DONTWAIT); 316 if (!(m_new->m_flags & M_EXT)) { 317 printf("%s: no memory for rx list " 318 "-- packet dropped!\n", sc->sc_dev.dv_xname); 319 m_freem(m_new); 320 return (ENOBUFS); 321 } 322 m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 323 } else { 324 m_new = m; 325 m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 326 m_new->m_data = m_new->m_ext.ext_buf; 327 } 328 329 c->ugl_mbuf = m_new; 330 331 return (0); 332 } 333 334 int 335 ugl_rx_list_init(struct ugl_softc *sc) 336 { 337 struct ugl_cdata *cd; 338 struct ugl_chain *c; 339 int i; 340 341 DPRINTFN(5,("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__)); 342 343 cd = &sc->sc_cdata; 344 for (i = 0; i < UGL_RX_LIST_CNT; i++) { 345 c = &cd->ugl_rx_chain[i]; 346 c->ugl_sc = sc; 347 c->ugl_idx = i; 348 if (ugl_newbuf(sc, c, NULL) == ENOBUFS) 349 return (ENOBUFS); 350 if (c->ugl_xfer == NULL) { 351 c->ugl_xfer = usbd_alloc_xfer(sc->sc_udev); 352 if (c->ugl_xfer == NULL) 353 return (ENOBUFS); 354 c->ugl_buf = usbd_alloc_buffer(c->ugl_xfer, UGL_BUFSZ); 355 if (c->ugl_buf == NULL) { 356 usbd_free_xfer(c->ugl_xfer); 357 return (ENOBUFS); 358 } 359 } 360 } 361 362 return (0); 363 } 364 365 int 366 ugl_tx_list_init(struct ugl_softc *sc) 367 { 368 struct ugl_cdata *cd; 369 struct ugl_chain *c; 370 int i; 371 372 DPRINTFN(5,("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__)); 373 374 cd = &sc->sc_cdata; 375 for (i = 0; i < UGL_TX_LIST_CNT; i++) { 376 c = &cd->ugl_tx_chain[i]; 377 c->ugl_sc = sc; 378 c->ugl_idx = i; 379 c->ugl_mbuf = NULL; 380 if (c->ugl_xfer == NULL) { 381 c->ugl_xfer = usbd_alloc_xfer(sc->sc_udev); 382 if (c->ugl_xfer == NULL) 383 return (ENOBUFS); 384 c->ugl_buf = usbd_alloc_buffer(c->ugl_xfer, UGL_BUFSZ); 385 if (c->ugl_buf == NULL) { 386 usbd_free_xfer(c->ugl_xfer); 387 return (ENOBUFS); 388 } 389 } 390 } 391 392 return (0); 393 } 394 395 /* 396 * A frame has been uploaded: pass the resulting mbuf chain up to 397 * the higher level protocols. 398 */ 399 void 400 ugl_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status) 401 { 402 struct ugl_chain *c = priv; 403 struct ugl_softc *sc = c->ugl_sc; 404 struct ifnet *ifp = GET_IFP(sc); 405 struct mbuf_list ml = MBUF_LIST_INITIALIZER(); 406 struct mbuf *m; 407 int total_len = 0; 408 unsigned int packet_len, packet_count; 409 int s; 410 411 if (usbd_is_dying(sc->sc_udev)) 412 return; 413 414 if (!(ifp->if_flags & IFF_RUNNING)) 415 return; 416 417 if (status != USBD_NORMAL_COMPLETION) { 418 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) 419 return; 420 sc->sc_rx_errs++; 421 if (usbd_ratecheck(&sc->sc_rx_notice)) { 422 printf("%s: %u usb errors on rx: %s\n", 423 sc->sc_dev.dv_xname, sc->sc_rx_errs, 424 usbd_errstr(status)); 425 sc->sc_rx_errs = 0; 426 } 427 if (status == USBD_STALLED) 428 usbd_clear_endpoint_stall_async(sc->sc_ep[UGL_ENDPT_RX]); 429 goto done; 430 } 431 432 usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL); 433 434 DPRINTFN(9,("%s: %s: enter status=%d length=%d\n", 435 sc->sc_dev.dv_xname, __func__, status, total_len)); 436 437 if (total_len < offsetof(struct ugl_packet, pkt_data)) { 438 printf("%s: bad header (length=%d)\n", 439 sc->sc_dev.dv_xname, total_len); 440 441 goto done; 442 } 443 444 packet_count = UGETDW(c->ugl_buf->pkt_count); 445 if (packet_count != UGL_RX_FRAMES) { 446 printf("%s: bad packet count (%d)\n", 447 sc->sc_dev.dv_xname, packet_count); 448 449 if (packet_count == 0) 450 goto done; 451 } 452 453 packet_len = UGETDW(c->ugl_buf->pkt_length); 454 if (total_len < packet_len) { 455 printf("%s: bad packet size(%d), length=%d\n", 456 sc->sc_dev.dv_xname, packet_len, total_len); 457 458 if (packet_len == 0) 459 goto done; 460 } 461 462 m = c->ugl_mbuf; 463 memcpy(mtod(c->ugl_mbuf, char *), c->ugl_buf->pkt_data, packet_len); 464 465 m->m_pkthdr.len = m->m_len = packet_len; 466 ml_enqueue(&ml, m); 467 468 if (ugl_newbuf(sc, c, NULL) == ENOBUFS) { 469 ifp->if_ierrors++; 470 goto done; 471 } 472 473 s = splnet(); 474 if_input(ifp, &ml); 475 splx(s); 476 477 done: 478 /* Setup new transfer. */ 479 usbd_setup_xfer(c->ugl_xfer, sc->sc_ep[UGL_ENDPT_RX], 480 c, c->ugl_buf, UGL_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY, 481 USBD_NO_TIMEOUT, ugl_rxeof); 482 usbd_transfer(c->ugl_xfer); 483 484 DPRINTFN(10,("%s: %s: start rx\n", sc->sc_dev.dv_xname, 485 __func__)); 486 } 487 488 /* 489 * A frame was downloaded to the chip. It's safe for us to clean up 490 * the list buffers. 491 */ 492 void 493 ugl_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status) 494 { 495 struct ugl_chain *c = priv; 496 struct ugl_softc *sc = c->ugl_sc; 497 struct ifnet *ifp = GET_IFP(sc); 498 int s; 499 500 if (usbd_is_dying(sc->sc_udev)) 501 return; 502 503 s = splnet(); 504 505 DPRINTFN(10,("%s: %s: enter status=%d\n", sc->sc_dev.dv_xname, 506 __func__, status)); 507 508 ifp->if_timer = 0; 509 ifq_clr_oactive(&ifp->if_snd); 510 511 if (status != USBD_NORMAL_COMPLETION) { 512 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) { 513 splx(s); 514 return; 515 } 516 ifp->if_oerrors++; 517 printf("%s: usb error on tx: %s\n", sc->sc_dev.dv_xname, 518 usbd_errstr(status)); 519 if (status == USBD_STALLED) 520 usbd_clear_endpoint_stall_async(sc->sc_ep[UGL_ENDPT_TX]); 521 splx(s); 522 return; 523 } 524 525 m_freem(c->ugl_mbuf); 526 c->ugl_mbuf = NULL; 527 528 if (ifq_empty(&ifp->if_snd) == 0) 529 ugl_start(ifp); 530 531 splx(s); 532 } 533 534 int 535 ugl_send(struct ugl_softc *sc, struct mbuf *m, int idx) 536 { 537 int total_len; 538 struct ugl_chain *c; 539 usbd_status err; 540 541 c = &sc->sc_cdata.ugl_tx_chain[idx]; 542 543 /* 544 * Copy the mbuf data into a contiguous buffer, leaving two 545 * bytes at the beginning to hold the frame length. 546 */ 547 USETDW(c->ugl_buf->pkt_count, UGL_TX_FRAMES); 548 USETDW(c->ugl_buf->pkt_length, m->m_pkthdr.len); 549 m_copydata(m, 0, m->m_pkthdr.len, c->ugl_buf->pkt_data); 550 c->ugl_mbuf = m; 551 552 total_len = offsetof(struct ugl_packet, pkt_data[m->m_pkthdr.len]); 553 554 DPRINTFN(10,("%s: %s: total_len=%d\n", 555 sc->sc_dev.dv_xname, __func__, total_len)); 556 557 usbd_setup_xfer(c->ugl_xfer, sc->sc_ep[UGL_ENDPT_TX], 558 c, c->ugl_buf, total_len, USBD_FORCE_SHORT_XFER | USBD_NO_COPY, 559 USBD_DEFAULT_TIMEOUT, ugl_txeof); 560 561 /* Transmit */ 562 err = usbd_transfer(c->ugl_xfer); 563 if (err != USBD_IN_PROGRESS) { 564 printf("%s: ugl_send error=%s\n", sc->sc_dev.dv_xname, 565 usbd_errstr(err)); 566 c->ugl_mbuf = NULL; 567 ugl_stop(sc); 568 return (EIO); 569 } 570 571 sc->sc_cdata.ugl_tx_cnt++; 572 573 return (0); 574 } 575 576 void 577 ugl_start(struct ifnet *ifp) 578 { 579 struct ugl_softc *sc = ifp->if_softc; 580 struct mbuf *m_head = NULL; 581 582 if (usbd_is_dying(sc->sc_udev)) 583 return; 584 585 DPRINTFN(10,("%s: %s: enter\n", sc->sc_dev.dv_xname,__func__)); 586 587 if (ifq_is_oactive(&ifp->if_snd)) 588 return; 589 590 m_head = ifq_dequeue(&ifp->if_snd); 591 if (m_head == NULL) 592 return; 593 594 if (ugl_send(sc, m_head, 0)) { 595 m_freem(m_head); 596 ifq_set_oactive(&ifp->if_snd); 597 return; 598 } 599 600 #if NBPFILTER > 0 601 /* 602 * If there's a BPF listener, bounce a copy of this frame 603 * to him. 604 */ 605 if (ifp->if_bpf) 606 bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT); 607 #endif 608 609 ifq_set_oactive(&ifp->if_snd); 610 611 /* 612 * Set a timeout in case the chip goes out to lunch. 613 */ 614 ifp->if_timer = 5; 615 } 616 617 void 618 ugl_init(void *xsc) 619 { 620 struct ugl_softc *sc = xsc; 621 struct ifnet *ifp = GET_IFP(sc); 622 int s; 623 624 if (usbd_is_dying(sc->sc_udev)) 625 return; 626 627 DPRINTFN(10,("%s: %s: enter\n", sc->sc_dev.dv_xname,__func__)); 628 629 s = splnet(); 630 631 /* Init TX ring. */ 632 if (ugl_tx_list_init(sc) == ENOBUFS) { 633 printf("%s: tx list init failed\n", sc->sc_dev.dv_xname); 634 splx(s); 635 return; 636 } 637 638 /* Init RX ring. */ 639 if (ugl_rx_list_init(sc) == ENOBUFS) { 640 printf("%s: rx list init failed\n", sc->sc_dev.dv_xname); 641 splx(s); 642 return; 643 } 644 645 if (sc->sc_ep[UGL_ENDPT_RX] == NULL) { 646 if (ugl_openpipes(sc)) { 647 splx(s); 648 return; 649 } 650 } 651 652 ifp->if_flags |= IFF_RUNNING; 653 ifq_clr_oactive(&ifp->if_snd); 654 655 splx(s); 656 } 657 658 int 659 ugl_openpipes(struct ugl_softc *sc) 660 { 661 struct ugl_chain *c; 662 usbd_status err; 663 int i; 664 665 /* Open RX and TX pipes. */ 666 err = usbd_open_pipe(sc->sc_iface, sc->sc_ed[UGL_ENDPT_RX], 667 USBD_EXCLUSIVE_USE, &sc->sc_ep[UGL_ENDPT_RX]); 668 if (err) { 669 printf("%s: open rx pipe failed: %s\n", 670 sc->sc_dev.dv_xname, usbd_errstr(err)); 671 return (EIO); 672 } 673 err = usbd_open_pipe(sc->sc_iface, sc->sc_ed[UGL_ENDPT_TX], 674 USBD_EXCLUSIVE_USE, &sc->sc_ep[UGL_ENDPT_TX]); 675 if (err) { 676 printf("%s: open tx pipe failed: %s\n", 677 sc->sc_dev.dv_xname, usbd_errstr(err)); 678 return (EIO); 679 } 680 err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ed[UGL_ENDPT_INTR], 681 0, &sc->sc_ep[UGL_ENDPT_INTR], sc, 682 sc->sc_ibuf, UGL_INTR_PKTLEN, ugl_intr, 683 UGL_INTR_INTERVAL); 684 if (err) { 685 printf("%s: open intr pipe failed: %s\n", 686 sc->sc_dev.dv_xname, usbd_errstr(err)); 687 return (EIO); 688 } 689 690 /* Start up the receive pipe. */ 691 for (i = 0; i < UGL_RX_LIST_CNT; i++) { 692 c = &sc->sc_cdata.ugl_rx_chain[i]; 693 usbd_setup_xfer(c->ugl_xfer, sc->sc_ep[UGL_ENDPT_RX], 694 c, c->ugl_buf, UGL_BUFSZ, 695 USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT, 696 ugl_rxeof); 697 usbd_transfer(c->ugl_xfer); 698 } 699 700 return (0); 701 } 702 703 void 704 ugl_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) 705 { 706 struct ugl_softc *sc = priv; 707 struct ifnet *ifp = GET_IFP(sc); 708 int i; 709 710 DPRINTFN(15,("%s: %s: enter\n", sc->sc_dev.dv_xname,__func__)); 711 712 if (usbd_is_dying(sc->sc_udev)) 713 return; 714 715 if (!(ifp->if_flags & IFF_RUNNING)) 716 return; 717 718 if (status != USBD_NORMAL_COMPLETION) { 719 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) { 720 return; 721 } 722 sc->sc_intr_errs++; 723 if (usbd_ratecheck(&sc->sc_rx_notice)) { 724 printf("%s: %u usb errors on intr: %s\n", 725 sc->sc_dev.dv_xname, sc->sc_rx_errs, 726 usbd_errstr(status)); 727 sc->sc_intr_errs = 0; 728 } 729 if (status == USBD_STALLED) 730 usbd_clear_endpoint_stall_async(sc->sc_ep[UGL_ENDPT_RX]); 731 return; 732 } 733 734 DPRINTFN(10,("%s: %s:", sc->sc_dev.dv_xname, __func__)); 735 for (i = 0; i < UGL_INTR_PKTLEN; i++) 736 DPRINTFN(10,(" 0x%02x", sc->sc_ibuf[i])); 737 DPRINTFN(10,("\n")); 738 739 } 740 741 int 742 ugl_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 743 { 744 struct ugl_softc *sc = ifp->if_softc; 745 int s, error = 0; 746 747 if (usbd_is_dying(sc->sc_udev)) 748 return ENXIO; 749 750 DPRINTFN(5,("%s: %s: cmd=0x%08lx\n", 751 sc->sc_dev.dv_xname, __func__, command)); 752 753 s = splnet(); 754 755 switch(command) { 756 case SIOCSIFADDR: 757 ifp->if_flags |= IFF_UP; 758 if (!(ifp->if_flags & IFF_RUNNING)) 759 ugl_init(sc); 760 break; 761 762 case SIOCSIFFLAGS: 763 if (ifp->if_flags & IFF_UP) { 764 if (ifp->if_flags & IFF_RUNNING) 765 error = ENETRESET; 766 else 767 ugl_init(sc); 768 } else { 769 if (ifp->if_flags & IFF_RUNNING) 770 ugl_stop(sc); 771 } 772 break; 773 774 default: 775 error = ether_ioctl(ifp, &sc->sc_arpcom, command, data); 776 break; 777 } 778 779 if (error == ENETRESET) 780 error = 0; 781 782 splx(s); 783 return (error); 784 } 785 786 void 787 ugl_watchdog(struct ifnet *ifp) 788 { 789 struct ugl_softc *sc = ifp->if_softc; 790 791 if (usbd_is_dying(sc->sc_udev)) 792 return; 793 794 ifp->if_oerrors++; 795 printf("%s: watchdog timeout\n", sc->sc_dev.dv_xname); 796 } 797 798 /* 799 * Stop the adapter and free any mbufs allocated to the 800 * RX and TX lists. 801 */ 802 void 803 ugl_stop(struct ugl_softc *sc) 804 { 805 struct ifnet *ifp; 806 int i; 807 808 DPRINTFN(10,("%s: %s: enter\n", sc->sc_dev.dv_xname,__func__)); 809 810 ifp = GET_IFP(sc); 811 ifp->if_timer = 0; 812 ifp->if_flags &= ~IFF_RUNNING; 813 ifq_clr_oactive(&ifp->if_snd); 814 815 /* Stop transfers. */ 816 if (sc->sc_ep[UGL_ENDPT_RX] != NULL) { 817 usbd_close_pipe(sc->sc_ep[UGL_ENDPT_RX]); 818 sc->sc_ep[UGL_ENDPT_RX] = NULL; 819 } 820 821 if (sc->sc_ep[UGL_ENDPT_TX] != NULL) { 822 usbd_close_pipe(sc->sc_ep[UGL_ENDPT_TX]); 823 sc->sc_ep[UGL_ENDPT_TX] = NULL; 824 } 825 826 if (sc->sc_ep[UGL_ENDPT_INTR] != NULL) { 827 usbd_close_pipe(sc->sc_ep[UGL_ENDPT_INTR]); 828 sc->sc_ep[UGL_ENDPT_INTR] = NULL; 829 } 830 831 /* Free RX resources. */ 832 for (i = 0; i < UGL_RX_LIST_CNT; i++) { 833 if (sc->sc_cdata.ugl_rx_chain[i].ugl_mbuf != NULL) { 834 m_freem(sc->sc_cdata.ugl_rx_chain[i].ugl_mbuf); 835 sc->sc_cdata.ugl_rx_chain[i].ugl_mbuf = NULL; 836 } 837 if (sc->sc_cdata.ugl_rx_chain[i].ugl_xfer != NULL) { 838 usbd_free_xfer(sc->sc_cdata.ugl_rx_chain[i].ugl_xfer); 839 sc->sc_cdata.ugl_rx_chain[i].ugl_xfer = NULL; 840 } 841 } 842 843 /* Free TX resources. */ 844 for (i = 0; i < UGL_TX_LIST_CNT; i++) { 845 if (sc->sc_cdata.ugl_tx_chain[i].ugl_mbuf != NULL) { 846 m_freem(sc->sc_cdata.ugl_tx_chain[i].ugl_mbuf); 847 sc->sc_cdata.ugl_tx_chain[i].ugl_mbuf = NULL; 848 } 849 if (sc->sc_cdata.ugl_tx_chain[i].ugl_xfer != NULL) { 850 usbd_free_xfer(sc->sc_cdata.ugl_tx_chain[i].ugl_xfer); 851 sc->sc_cdata.ugl_tx_chain[i].ugl_xfer = NULL; 852 } 853 } 854 } 855