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