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