1 /* $OpenBSD: if_cdce.c,v 1.75 2018/10/02 19:49:10 stsp Exp $ */ 2 3 /* 4 * Copyright (c) 1997, 1998, 1999, 2000-2003 Bill Paul <wpaul@windriver.com> 5 * Copyright (c) 2003 Craig Boston 6 * Copyright (c) 2004 Daniel Hartmeier 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by Bill Paul. 20 * 4. Neither the name of the author nor the names of any co-contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul, THE VOICES IN HIS HEAD OR 28 * THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 29 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 30 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 31 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 32 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 33 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 34 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 */ 36 37 /* 38 * USB Communication Device Class (Ethernet Networking Control Model) 39 * http://www.usb.org/developers/devclass_docs/usbcdc11.pdf 40 * 41 */ 42 43 #include <bpfilter.h> 44 45 #include <sys/param.h> 46 #include <sys/systm.h> 47 #include <sys/sockio.h> 48 #include <sys/mbuf.h> 49 #include <sys/kernel.h> 50 #include <sys/socket.h> 51 #include <sys/device.h> 52 53 #include <net/if.h> 54 55 #if NBPFILTER > 0 56 #include <net/bpf.h> 57 #endif 58 59 #include <netinet/in.h> 60 #include <netinet/if_ether.h> 61 62 #include <dev/usb/usb.h> 63 #include <dev/usb/usbdi.h> 64 #include <dev/usb/usbdi_util.h> 65 #include <dev/usb/usbdevs.h> 66 #include <dev/usb/usbcdc.h> 67 68 #include <dev/usb/if_cdcereg.h> 69 70 #ifdef CDCE_DEBUG 71 #define DPRINTFN(n, x) do { if (cdcedebug > (n)) printf x; } while (0) 72 int cdcedebug = 0; 73 #else 74 #define DPRINTFN(n, x) 75 #endif 76 #define DPRINTF(x) DPRINTFN(0, x) 77 78 int cdce_tx_list_init(struct cdce_softc *); 79 int cdce_rx_list_init(struct cdce_softc *); 80 int cdce_newbuf(struct cdce_softc *, struct cdce_chain *, 81 struct mbuf *); 82 int cdce_encap(struct cdce_softc *, struct mbuf *, int); 83 void cdce_rxeof(struct usbd_xfer *, void *, usbd_status); 84 void cdce_txeof(struct usbd_xfer *, void *, usbd_status); 85 void cdce_start(struct ifnet *); 86 int cdce_ioctl(struct ifnet *, u_long, caddr_t); 87 void cdce_init(void *); 88 void cdce_watchdog(struct ifnet *); 89 void cdce_stop(struct cdce_softc *); 90 void cdce_intr(struct usbd_xfer *, void *, usbd_status); 91 92 const struct cdce_type cdce_devs[] = { 93 {{ USB_VENDOR_ACERLABS, USB_PRODUCT_ACERLABS_M5632 }, 0 }, 94 {{ USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2501 }, 0 }, 95 {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5500 }, CDCE_CRC32 }, 96 {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_A300 }, CDCE_CRC32 }, 97 {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5600 }, CDCE_CRC32 }, 98 {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_C700 }, CDCE_CRC32 }, 99 {{ USB_VENDOR_SHARP, USB_PRODUCT_SHARP_C750 }, CDCE_CRC32 }, 100 {{ USB_VENDOR_MOTOROLA2, USB_PRODUCT_MOTOROLA2_USBLAN }, CDCE_CRC32 }, 101 {{ USB_VENDOR_MOTOROLA2, USB_PRODUCT_MOTOROLA2_USBLAN2 }, CDCE_CRC32 }, 102 {{ USB_VENDOR_GMATE, USB_PRODUCT_GMATE_YP3X00 }, 0 }, 103 {{ USB_VENDOR_NETCHIP, USB_PRODUCT_NETCHIP_ETHERNETGADGET }, 0 }, 104 {{ USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_IPAQLINUX }, 0 }, 105 {{ USB_VENDOR_AMBIT, USB_PRODUCT_AMBIT_NTL_250 }, CDCE_SWAPUNION }, 106 }; 107 #define cdce_lookup(v, p) \ 108 ((const struct cdce_type *)usb_lookup(cdce_devs, v, p)) 109 110 int cdce_match(struct device *, void *, void *); 111 void cdce_attach(struct device *, struct device *, void *); 112 int cdce_detach(struct device *, int); 113 114 struct cfdriver cdce_cd = { 115 NULL, "cdce", DV_IFNET 116 }; 117 118 const struct cfattach cdce_ca = { 119 sizeof(struct cdce_softc), cdce_match, cdce_attach, cdce_detach 120 }; 121 122 int 123 cdce_match(struct device *parent, void *match, void *aux) 124 { 125 struct usb_attach_arg *uaa = aux; 126 usb_interface_descriptor_t *id; 127 128 if (uaa->iface == NULL) 129 return (UMATCH_NONE); 130 131 id = usbd_get_interface_descriptor(uaa->iface); 132 if (id == NULL) 133 return (UMATCH_NONE); 134 135 if (cdce_lookup(uaa->vendor, uaa->product) != NULL) 136 return (UMATCH_VENDOR_PRODUCT); 137 138 if (id->bInterfaceClass == UICLASS_CDC && 139 (id->bInterfaceSubClass == 140 UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL || 141 id->bInterfaceSubClass == UISUBCLASS_MOBILE_DIRECT_LINE_MODEL)) 142 return (UMATCH_IFACECLASS_GENERIC); 143 144 return (UMATCH_NONE); 145 } 146 147 void 148 cdce_attach(struct device *parent, struct device *self, void *aux) 149 { 150 struct cdce_softc *sc = (struct cdce_softc *)self; 151 struct usb_attach_arg *uaa = aux; 152 int s; 153 struct ifnet *ifp = GET_IFP(sc); 154 struct usbd_device *dev = uaa->device; 155 const struct cdce_type *t; 156 usb_interface_descriptor_t *id; 157 usb_endpoint_descriptor_t *ed; 158 struct usb_cdc_union_descriptor *ud; 159 struct usb_cdc_ethernet_descriptor *ethd; 160 usb_config_descriptor_t *cd; 161 const usb_descriptor_t *desc; 162 struct usbd_desc_iter iter; 163 usb_string_descriptor_t eaddr_str; 164 int i, j, numalts, len; 165 int ctl_ifcno = -1; 166 int data_ifcno = -1; 167 168 sc->cdce_udev = uaa->device; 169 sc->cdce_ctl_iface = uaa->iface; 170 id = usbd_get_interface_descriptor(sc->cdce_ctl_iface); 171 ctl_ifcno = id->bInterfaceNumber; 172 173 t = cdce_lookup(uaa->vendor, uaa->product); 174 if (t) 175 sc->cdce_flags = t->cdce_flags; 176 177 /* Get the data interface no. and capabilities */ 178 ethd = NULL; 179 usbd_desc_iter_init(dev, &iter); 180 desc = usbd_desc_iter_next(&iter); 181 while (desc) { 182 if (desc->bDescriptorType != UDESC_CS_INTERFACE) { 183 desc = usbd_desc_iter_next(&iter); 184 continue; 185 } 186 switch(desc->bDescriptorSubtype) { 187 case UDESCSUB_CDC_UNION: 188 ud = (struct usb_cdc_union_descriptor *)desc; 189 if ((sc->cdce_flags & CDCE_SWAPUNION) == 0 && 190 ud->bMasterInterface == ctl_ifcno) 191 data_ifcno = ud->bSlaveInterface[0]; 192 if ((sc->cdce_flags & CDCE_SWAPUNION) && 193 ud->bSlaveInterface[0] == ctl_ifcno) 194 data_ifcno = ud->bMasterInterface; 195 break; 196 case UDESCSUB_CDC_ENF: 197 if (ethd) { 198 printf("%s: ", sc->cdce_dev.dv_xname); 199 printf("extra ethernet descriptor\n"); 200 return; 201 } 202 ethd = (struct usb_cdc_ethernet_descriptor *)desc; 203 break; 204 } 205 desc = usbd_desc_iter_next(&iter); 206 } 207 208 if (data_ifcno == -1) { 209 DPRINTF(("cdce_attach: no union interface\n")); 210 sc->cdce_data_iface = sc->cdce_ctl_iface; 211 } else { 212 DPRINTF(("cdce_attach: union interface: ctl=%d, data=%d\n", 213 ctl_ifcno, data_ifcno)); 214 for (i = 0; i < uaa->nifaces; i++) { 215 if (usbd_iface_claimed(sc->cdce_udev, i)) 216 continue; 217 id = usbd_get_interface_descriptor(uaa->ifaces[i]); 218 if (id != NULL && id->bInterfaceNumber == data_ifcno) { 219 sc->cdce_data_iface = uaa->ifaces[i]; 220 usbd_claim_iface(sc->cdce_udev, i); 221 } 222 } 223 } 224 225 if (sc->cdce_data_iface == NULL) { 226 printf("%s: no data interface\n", sc->cdce_dev.dv_xname); 227 return; 228 } 229 230 id = usbd_get_interface_descriptor(sc->cdce_ctl_iface); 231 sc->cdce_intr_no = -1; 232 for (i = 0; i < id->bNumEndpoints && sc->cdce_intr_no == -1; i++) { 233 ed = usbd_interface2endpoint_descriptor(sc->cdce_ctl_iface, i); 234 if (!ed) { 235 printf("%s: no descriptor for interrupt endpoint %d\n", 236 sc->cdce_dev.dv_xname, i); 237 return; 238 } 239 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 240 UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) { 241 sc->cdce_intr_no = ed->bEndpointAddress; 242 sc->cdce_intr_size = sizeof(sc->cdce_intr_buf); 243 } 244 } 245 246 id = usbd_get_interface_descriptor(sc->cdce_data_iface); 247 cd = usbd_get_config_descriptor(sc->cdce_udev); 248 numalts = usbd_get_no_alts(cd, id->bInterfaceNumber); 249 250 for (j = 0; j < numalts; j++) { 251 if (usbd_set_interface(sc->cdce_data_iface, j)) { 252 printf("%s: interface alternate setting %d failed\n", 253 sc->cdce_dev.dv_xname, j); 254 return; 255 } 256 /* Find endpoints. */ 257 id = usbd_get_interface_descriptor(sc->cdce_data_iface); 258 sc->cdce_bulkin_no = sc->cdce_bulkout_no = -1; 259 for (i = 0; i < id->bNumEndpoints; i++) { 260 ed = usbd_interface2endpoint_descriptor( 261 sc->cdce_data_iface, i); 262 if (!ed) { 263 printf("%s: no descriptor for bulk endpoint " 264 "%d\n", sc->cdce_dev.dv_xname, i); 265 return; 266 } 267 if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && 268 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 269 sc->cdce_bulkin_no = ed->bEndpointAddress; 270 } else if ( 271 UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && 272 UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { 273 sc->cdce_bulkout_no = ed->bEndpointAddress; 274 } 275 #ifdef CDCE_DEBUG 276 else if ( 277 UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN && 278 UE_GET_XFERTYPE(ed->bmAttributes) != UE_INTERRUPT) { 279 printf("%s: unexpected endpoint, ep=%x attr=%x" 280 "\n", sc->cdce_dev.dv_xname, 281 ed->bEndpointAddress, ed->bmAttributes); 282 } 283 #endif 284 } 285 if ((sc->cdce_bulkin_no != -1) && (sc->cdce_bulkout_no != -1)) { 286 DPRINTF(("cdce_attach: intr=0x%x, in=0x%x, out=0x%x\n", 287 sc->cdce_intr_no, sc->cdce_bulkin_no, 288 sc->cdce_bulkout_no)); 289 goto found; 290 } 291 } 292 293 if (sc->cdce_bulkin_no == -1) { 294 printf("%s: could not find data bulk in\n", 295 sc->cdce_dev.dv_xname); 296 return; 297 } 298 if (sc->cdce_bulkout_no == -1 ) { 299 printf("%s: could not find data bulk out\n", 300 sc->cdce_dev.dv_xname); 301 return; 302 } 303 304 found: 305 s = splnet(); 306 307 if (!ethd || usbd_get_string_desc(sc->cdce_udev, ethd->iMacAddress, 0, 308 &eaddr_str, &len)) { 309 ether_fakeaddr(ifp); 310 } else { 311 for (i = 0; i < ETHER_ADDR_LEN * 2; i++) { 312 int c = UGETW(eaddr_str.bString[i]); 313 314 if ('0' <= c && c <= '9') 315 c -= '0'; 316 else if ('A' <= c && c <= 'F') 317 c -= 'A' - 10; 318 else if ('a' <= c && c <= 'f') 319 c -= 'a' - 10; 320 c &= 0xf; 321 if (i % 2 == 0) 322 c <<= 4; 323 sc->cdce_arpcom.ac_enaddr[i / 2] |= c; 324 } 325 } 326 327 printf("%s: address %s\n", sc->cdce_dev.dv_xname, 328 ether_sprintf(sc->cdce_arpcom.ac_enaddr)); 329 330 ifp->if_softc = sc; 331 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 332 ifp->if_ioctl = cdce_ioctl; 333 ifp->if_start = cdce_start; 334 ifp->if_watchdog = cdce_watchdog; 335 strlcpy(ifp->if_xname, sc->cdce_dev.dv_xname, IFNAMSIZ); 336 337 if_attach(ifp); 338 ether_ifattach(ifp); 339 340 sc->cdce_attached = 1; 341 splx(s); 342 } 343 344 int 345 cdce_detach(struct device *self, int flags) 346 { 347 struct cdce_softc *sc = (struct cdce_softc *)self; 348 struct ifnet *ifp = GET_IFP(sc); 349 int s; 350 351 if (!sc->cdce_attached) 352 return (0); 353 354 s = splusb(); 355 356 if (ifp->if_flags & IFF_RUNNING) 357 cdce_stop(sc); 358 359 if (ifp->if_softc != NULL) { 360 ether_ifdetach(ifp); 361 if_detach(ifp); 362 } 363 364 sc->cdce_attached = 0; 365 splx(s); 366 367 return (0); 368 } 369 370 void 371 cdce_start(struct ifnet *ifp) 372 { 373 struct cdce_softc *sc = ifp->if_softc; 374 struct mbuf *m_head = NULL; 375 376 if (usbd_is_dying(sc->cdce_udev) || ifq_is_oactive(&ifp->if_snd)) 377 return; 378 379 m_head = ifq_deq_begin(&ifp->if_snd); 380 if (m_head == NULL) 381 return; 382 383 if (cdce_encap(sc, m_head, 0)) { 384 ifq_deq_rollback(&ifp->if_snd, m_head); 385 ifq_set_oactive(&ifp->if_snd); 386 return; 387 } 388 389 ifq_deq_commit(&ifp->if_snd, m_head); 390 391 #if NBPFILTER > 0 392 if (ifp->if_bpf) 393 bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT); 394 #endif 395 396 ifq_set_oactive(&ifp->if_snd); 397 398 ifp->if_timer = 6; 399 } 400 401 int 402 cdce_encap(struct cdce_softc *sc, struct mbuf *m, int idx) 403 { 404 struct cdce_chain *c; 405 usbd_status err; 406 int extra = 0; 407 408 c = &sc->cdce_cdata.cdce_tx_chain[idx]; 409 410 m_copydata(m, 0, m->m_pkthdr.len, c->cdce_buf); 411 if (sc->cdce_flags & CDCE_CRC32) { 412 /* Some devices want a 32-bit CRC appended to every frame */ 413 u_int32_t crc; 414 415 crc = ether_crc32_le(c->cdce_buf, m->m_pkthdr.len) ^ ~0U; 416 bcopy(&crc, c->cdce_buf + m->m_pkthdr.len, 4); 417 extra = 4; 418 } 419 c->cdce_mbuf = m; 420 421 usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkout_pipe, c, c->cdce_buf, 422 m->m_pkthdr.len + extra, USBD_FORCE_SHORT_XFER | USBD_NO_COPY, 423 10000, cdce_txeof); 424 err = usbd_transfer(c->cdce_xfer); 425 if (err != USBD_IN_PROGRESS) { 426 cdce_stop(sc); 427 return (EIO); 428 } 429 430 sc->cdce_cdata.cdce_tx_cnt++; 431 432 return (0); 433 } 434 435 void 436 cdce_stop(struct cdce_softc *sc) 437 { 438 usbd_status err; 439 struct ifnet *ifp = GET_IFP(sc); 440 int i; 441 442 ifp->if_timer = 0; 443 ifp->if_flags &= ~IFF_RUNNING; 444 ifq_clr_oactive(&ifp->if_snd); 445 446 if (sc->cdce_bulkin_pipe != NULL) { 447 usbd_abort_pipe(sc->cdce_bulkin_pipe); 448 err = usbd_close_pipe(sc->cdce_bulkin_pipe); 449 if (err) 450 printf("%s: close rx pipe failed: %s\n", 451 sc->cdce_dev.dv_xname, usbd_errstr(err)); 452 sc->cdce_bulkin_pipe = NULL; 453 } 454 455 if (sc->cdce_bulkout_pipe != NULL) { 456 usbd_abort_pipe(sc->cdce_bulkout_pipe); 457 err = usbd_close_pipe(sc->cdce_bulkout_pipe); 458 if (err) 459 printf("%s: close tx pipe failed: %s\n", 460 sc->cdce_dev.dv_xname, usbd_errstr(err)); 461 sc->cdce_bulkout_pipe = NULL; 462 } 463 464 if (sc->cdce_intr_pipe != NULL) { 465 usbd_abort_pipe(sc->cdce_intr_pipe); 466 err = usbd_close_pipe(sc->cdce_intr_pipe); 467 if (err) 468 printf("%s: close interrupt pipe failed: %s\n", 469 sc->cdce_dev.dv_xname, usbd_errstr(err)); 470 sc->cdce_intr_pipe = NULL; 471 } 472 473 for (i = 0; i < CDCE_RX_LIST_CNT; i++) { 474 if (sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf != NULL) { 475 m_freem(sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf); 476 sc->cdce_cdata.cdce_rx_chain[i].cdce_mbuf = NULL; 477 } 478 if (sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer != NULL) { 479 usbd_free_xfer(sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer); 480 sc->cdce_cdata.cdce_rx_chain[i].cdce_xfer = NULL; 481 } 482 } 483 484 for (i = 0; i < CDCE_TX_LIST_CNT; i++) { 485 if (sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf != NULL) { 486 m_freem(sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf); 487 sc->cdce_cdata.cdce_tx_chain[i].cdce_mbuf = NULL; 488 } 489 if (sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer != NULL) { 490 usbd_free_xfer( 491 sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer); 492 sc->cdce_cdata.cdce_tx_chain[i].cdce_xfer = NULL; 493 } 494 } 495 } 496 497 int 498 cdce_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 499 { 500 struct cdce_softc *sc = ifp->if_softc; 501 int s, error = 0; 502 503 if (usbd_is_dying(sc->cdce_udev)) 504 return ENXIO; 505 506 s = splnet(); 507 508 switch(command) { 509 case SIOCSIFADDR: 510 ifp->if_flags |= IFF_UP; 511 if (!(ifp->if_flags & IFF_RUNNING)) 512 cdce_init(sc); 513 break; 514 515 case SIOCSIFFLAGS: 516 if (ifp->if_flags & IFF_UP) { 517 if (ifp->if_flags & IFF_RUNNING) 518 error = ENETRESET; 519 else 520 cdce_init(sc); 521 } else { 522 if (ifp->if_flags & IFF_RUNNING) 523 cdce_stop(sc); 524 } 525 break; 526 527 default: 528 error = ether_ioctl(ifp, &sc->cdce_arpcom, command, data); 529 break; 530 } 531 532 if (error == ENETRESET) 533 error = 0; 534 535 splx(s); 536 return (error); 537 } 538 539 void 540 cdce_watchdog(struct ifnet *ifp) 541 { 542 struct cdce_softc *sc = ifp->if_softc; 543 544 if (usbd_is_dying(sc->cdce_udev)) 545 return; 546 547 ifp->if_oerrors++; 548 printf("%s: watchdog timeout\n", sc->cdce_dev.dv_xname); 549 } 550 551 void 552 cdce_init(void *xsc) 553 { 554 struct cdce_softc *sc = xsc; 555 struct ifnet *ifp = GET_IFP(sc); 556 struct cdce_chain *c; 557 usbd_status err; 558 int s, i; 559 560 s = splnet(); 561 562 if (sc->cdce_intr_no != -1 && sc->cdce_intr_pipe == NULL) { 563 DPRINTFN(1, ("cdce_init: establish interrupt pipe\n")); 564 err = usbd_open_pipe_intr(sc->cdce_ctl_iface, sc->cdce_intr_no, 565 USBD_SHORT_XFER_OK, &sc->cdce_intr_pipe, sc, 566 &sc->cdce_intr_buf, sc->cdce_intr_size, cdce_intr, 567 USBD_DEFAULT_INTERVAL); 568 if (err) { 569 printf("%s: open interrupt pipe failed: %s\n", 570 sc->cdce_dev.dv_xname, usbd_errstr(err)); 571 splx(s); 572 return; 573 } 574 } 575 576 if (cdce_tx_list_init(sc) == ENOBUFS) { 577 printf("%s: tx list init failed\n", sc->cdce_dev.dv_xname); 578 splx(s); 579 return; 580 } 581 582 if (cdce_rx_list_init(sc) == ENOBUFS) { 583 printf("%s: rx list init failed\n", sc->cdce_dev.dv_xname); 584 splx(s); 585 return; 586 } 587 588 /* Maybe set multicast / broadcast here??? */ 589 590 err = usbd_open_pipe(sc->cdce_data_iface, sc->cdce_bulkin_no, 591 USBD_EXCLUSIVE_USE, &sc->cdce_bulkin_pipe); 592 if (err) { 593 printf("%s: open rx pipe failed: %s\n", sc->cdce_dev.dv_xname, 594 usbd_errstr(err)); 595 splx(s); 596 return; 597 } 598 599 err = usbd_open_pipe(sc->cdce_data_iface, sc->cdce_bulkout_no, 600 USBD_EXCLUSIVE_USE, &sc->cdce_bulkout_pipe); 601 if (err) { 602 printf("%s: open tx pipe failed: %s\n", sc->cdce_dev.dv_xname, 603 usbd_errstr(err)); 604 splx(s); 605 return; 606 } 607 608 for (i = 0; i < CDCE_RX_LIST_CNT; i++) { 609 c = &sc->cdce_cdata.cdce_rx_chain[i]; 610 usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkin_pipe, c, 611 c->cdce_buf, CDCE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY, 612 USBD_NO_TIMEOUT, cdce_rxeof); 613 usbd_transfer(c->cdce_xfer); 614 } 615 616 ifp->if_flags |= IFF_RUNNING; 617 ifq_clr_oactive(&ifp->if_snd); 618 619 splx(s); 620 } 621 622 int 623 cdce_newbuf(struct cdce_softc *sc, struct cdce_chain *c, struct mbuf *m) 624 { 625 struct mbuf *m_new = NULL; 626 627 if (m == NULL) { 628 MGETHDR(m_new, M_DONTWAIT, MT_DATA); 629 if (m_new == NULL) { 630 printf("%s: no memory for rx list " 631 "-- packet dropped!\n", sc->cdce_dev.dv_xname); 632 return (ENOBUFS); 633 } 634 MCLGET(m_new, M_DONTWAIT); 635 if (!(m_new->m_flags & M_EXT)) { 636 printf("%s: no memory for rx list " 637 "-- packet dropped!\n", sc->cdce_dev.dv_xname); 638 m_freem(m_new); 639 return (ENOBUFS); 640 } 641 m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 642 } else { 643 m_new = m; 644 m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; 645 m_new->m_data = m_new->m_ext.ext_buf; 646 } 647 648 m_adj(m_new, ETHER_ALIGN); 649 c->cdce_mbuf = m_new; 650 return (0); 651 } 652 653 int 654 cdce_rx_list_init(struct cdce_softc *sc) 655 { 656 struct cdce_cdata *cd; 657 struct cdce_chain *c; 658 int i; 659 660 cd = &sc->cdce_cdata; 661 for (i = 0; i < CDCE_RX_LIST_CNT; i++) { 662 c = &cd->cdce_rx_chain[i]; 663 c->cdce_sc = sc; 664 c->cdce_idx = i; 665 if (cdce_newbuf(sc, c, NULL) == ENOBUFS) 666 return (ENOBUFS); 667 if (c->cdce_xfer == NULL) { 668 c->cdce_xfer = usbd_alloc_xfer(sc->cdce_udev); 669 if (c->cdce_xfer == NULL) 670 return (ENOBUFS); 671 c->cdce_buf = usbd_alloc_buffer(c->cdce_xfer, 672 CDCE_BUFSZ); 673 if (c->cdce_buf == NULL) 674 return (ENOBUFS); 675 } 676 } 677 678 return (0); 679 } 680 681 int 682 cdce_tx_list_init(struct cdce_softc *sc) 683 { 684 struct cdce_cdata *cd; 685 struct cdce_chain *c; 686 int i; 687 688 cd = &sc->cdce_cdata; 689 for (i = 0; i < CDCE_TX_LIST_CNT; i++) { 690 c = &cd->cdce_tx_chain[i]; 691 c->cdce_sc = sc; 692 c->cdce_idx = i; 693 c->cdce_mbuf = NULL; 694 if (c->cdce_xfer == NULL) { 695 c->cdce_xfer = usbd_alloc_xfer(sc->cdce_udev); 696 if (c->cdce_xfer == NULL) 697 return (ENOBUFS); 698 c->cdce_buf = usbd_alloc_buffer(c->cdce_xfer, 699 CDCE_BUFSZ); 700 if (c->cdce_buf == NULL) 701 return (ENOBUFS); 702 } 703 } 704 705 return (0); 706 } 707 708 void 709 cdce_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status) 710 { 711 struct cdce_chain *c = priv; 712 struct cdce_softc *sc = c->cdce_sc; 713 struct ifnet *ifp = GET_IFP(sc); 714 struct mbuf *m; 715 struct mbuf_list ml = MBUF_LIST_INITIALIZER(); 716 int total_len = 0; 717 int s; 718 719 if (usbd_is_dying(sc->cdce_udev) || !(ifp->if_flags & IFF_RUNNING)) 720 return; 721 722 if (status != USBD_NORMAL_COMPLETION) { 723 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) 724 return; 725 if (sc->cdce_rxeof_errors == 0) 726 printf("%s: usb error on rx: %s\n", 727 sc->cdce_dev.dv_xname, usbd_errstr(status)); 728 if (status == USBD_STALLED) 729 usbd_clear_endpoint_stall_async(sc->cdce_bulkin_pipe); 730 DELAY(sc->cdce_rxeof_errors * 10000); 731 if (sc->cdce_rxeof_errors++ > 10) { 732 printf("%s: too many errors, disabling\n", 733 sc->cdce_dev.dv_xname); 734 usbd_deactivate(sc->cdce_udev); 735 return; 736 } 737 goto done; 738 } 739 740 sc->cdce_rxeof_errors = 0; 741 742 usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL); 743 if (sc->cdce_flags & CDCE_CRC32) 744 total_len -= 4; /* Strip off added CRC */ 745 if (total_len <= 1) 746 goto done; 747 748 m = c->cdce_mbuf; 749 memcpy(mtod(m, char *), c->cdce_buf, total_len); 750 751 if (total_len < sizeof(struct ether_header)) { 752 ifp->if_ierrors++; 753 goto done; 754 } 755 756 m->m_pkthdr.len = m->m_len = total_len; 757 ml_enqueue(&ml, m); 758 759 if (cdce_newbuf(sc, c, NULL) == ENOBUFS) { 760 ifp->if_ierrors++; 761 goto done; 762 } 763 764 s = splnet(); 765 if_input(ifp, &ml); 766 splx(s); 767 768 done: 769 /* Setup new transfer. */ 770 usbd_setup_xfer(c->cdce_xfer, sc->cdce_bulkin_pipe, c, c->cdce_buf, 771 CDCE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT, 772 cdce_rxeof); 773 usbd_transfer(c->cdce_xfer); 774 } 775 776 void 777 cdce_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status) 778 { 779 struct cdce_chain *c = priv; 780 struct cdce_softc *sc = c->cdce_sc; 781 struct ifnet *ifp = GET_IFP(sc); 782 usbd_status err; 783 int s; 784 785 if (usbd_is_dying(sc->cdce_udev)) 786 return; 787 788 s = splnet(); 789 790 ifp->if_timer = 0; 791 ifq_clr_oactive(&ifp->if_snd); 792 793 if (status != USBD_NORMAL_COMPLETION) { 794 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) { 795 splx(s); 796 return; 797 } 798 ifp->if_oerrors++; 799 printf("%s: usb error on tx: %s\n", sc->cdce_dev.dv_xname, 800 usbd_errstr(status)); 801 if (status == USBD_STALLED) 802 usbd_clear_endpoint_stall_async(sc->cdce_bulkout_pipe); 803 splx(s); 804 return; 805 } 806 807 usbd_get_xfer_status(c->cdce_xfer, NULL, NULL, NULL, &err); 808 809 if (c->cdce_mbuf != NULL) { 810 m_freem(c->cdce_mbuf); 811 c->cdce_mbuf = NULL; 812 } 813 814 if (err) 815 ifp->if_oerrors++; 816 817 if (IFQ_IS_EMPTY(&ifp->if_snd) == 0) 818 cdce_start(ifp); 819 820 splx(s); 821 } 822 823 void 824 cdce_intr(struct usbd_xfer *xfer, void *addr, usbd_status status) 825 { 826 struct cdce_softc *sc = addr; 827 struct usb_cdc_notification *buf = &sc->cdce_intr_buf; 828 struct usb_cdc_connection_speed *speed; 829 u_int32_t count; 830 831 if (status == USBD_CANCELLED) 832 return; 833 834 if (status != USBD_NORMAL_COMPLETION) { 835 DPRINTFN(2, ("cdce_intr: status=%d\n", status)); 836 if (status == USBD_STALLED) 837 usbd_clear_endpoint_stall_async(sc->cdce_intr_pipe); 838 return; 839 } 840 841 usbd_get_xfer_status(xfer, NULL, NULL, &count, NULL); 842 843 if (buf->bmRequestType == UCDC_NOTIFICATION) { 844 switch (buf->bNotification) { 845 case UCDC_N_NETWORK_CONNECTION: 846 DPRINTFN(1, ("cdce_intr: network %s\n", 847 UGETW(buf->wValue) ? "connected" : "disconnected")); 848 break; 849 case UCDC_N_CONNECTION_SPEED_CHANGE: 850 speed = (struct usb_cdc_connection_speed *)&buf->data; 851 DPRINTFN(1, ("cdce_intr: up=%d, down=%d\n", 852 UGETDW(speed->dwUSBitRate), 853 UGETDW(speed->dwDSBitRate))); 854 break; 855 default: 856 DPRINTF(("cdce_intr: bNotification 0x%x\n", 857 buf->bNotification)); 858 } 859 } 860 #ifdef CDCE_DEBUG 861 else { 862 printf("cdce_intr: bmRequestType=%d ", buf->bmRequestType); 863 printf("wValue=%d wIndex=%d wLength=%d\n", UGETW(buf->wValue), 864 UGETW(buf->wIndex), UGETW(buf->wLength)); 865 } 866 #endif 867 } 868