if_cdce.c revision 189528
1184610Salfred/* $NetBSD: if_cdce.c,v 1.4 2004/10/24 12:50:54 augustss Exp $ */ 2184610Salfred 3184610Salfred/*- 4184610Salfred * Copyright (c) 1997, 1998, 1999, 2000-2003 Bill Paul <wpaul@windriver.com> 5184610Salfred * Copyright (c) 2003-2005 Craig Boston 6184610Salfred * Copyright (c) 2004 Daniel Hartmeier 7188412Sthompsa * Copyright (c) 2009 Hans Petter Selasky 8184610Salfred * All rights reserved. 9184610Salfred * 10184610Salfred * Redistribution and use in source and binary forms, with or without 11184610Salfred * modification, are permitted provided that the following conditions 12184610Salfred * are met: 13184610Salfred * 1. Redistributions of source code must retain the above copyright 14184610Salfred * notice, this list of conditions and the following disclaimer. 15184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 16184610Salfred * notice, this list of conditions and the following disclaimer in the 17184610Salfred * documentation and/or other materials provided with the distribution. 18184610Salfred * 3. All advertising materials mentioning features or use of this software 19184610Salfred * must display the following acknowledgement: 20184610Salfred * This product includes software developed by Bill Paul. 21184610Salfred * 4. Neither the name of the author nor the names of any co-contributors 22184610Salfred * may be used to endorse or promote products derived from this software 23184610Salfred * without specific prior written permission. 24184610Salfred * 25184610Salfred * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 26184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul, THE VOICES IN HIS HEAD OR 29184610Salfred * THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 30184610Salfred * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 31184610Salfred * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 32184610Salfred * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 33184610Salfred * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 34184610Salfred * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 35184610Salfred * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36184610Salfred */ 37184610Salfred 38184610Salfred/* 39184610Salfred * USB Communication Device Class (Ethernet Networking Control Model) 40184610Salfred * http://www.usb.org/developers/devclass_docs/usbcdc11.pdf 41184610Salfred */ 42184610Salfred 43184610Salfred#include <sys/cdefs.h> 44184610Salfred__FBSDID("$FreeBSD: head/sys/dev/usb/net/if_cdce.c 189528 2009-03-08 06:56:13Z thompsa $"); 45184610Salfred 46188746Sthompsa#include "usbdevs.h" 47188942Sthompsa#include <dev/usb/usb.h> 48188942Sthompsa#include <dev/usb/usb_mfunc.h> 49188942Sthompsa#include <dev/usb/usb_error.h> 50188942Sthompsa#include <dev/usb/usb_cdc.h> 51188942Sthompsa#include <dev/usb/usb_defs.h> 52184610Salfred 53184610Salfred#define USB_DEBUG_VAR cdce_debug 54184610Salfred 55188942Sthompsa#include <dev/usb/usb_core.h> 56188942Sthompsa#include <dev/usb/usb_lookup.h> 57188942Sthompsa#include <dev/usb/usb_process.h> 58188942Sthompsa#include <dev/usb/usb_debug.h> 59188942Sthompsa#include <dev/usb/usb_request.h> 60188942Sthompsa#include <dev/usb/usb_busdma.h> 61188942Sthompsa#include <dev/usb/usb_util.h> 62188942Sthompsa#include <dev/usb/usb_parse.h> 63188942Sthompsa#include <dev/usb/usb_device.h> 64184610Salfred 65188942Sthompsa#include <dev/usb/net/usb_ethernet.h> 66188942Sthompsa#include <dev/usb/net/if_cdcereg.h> 67184610Salfred 68184610Salfredstatic device_probe_t cdce_probe; 69184610Salfredstatic device_attach_t cdce_attach; 70184610Salfredstatic device_detach_t cdce_detach; 71184610Salfredstatic device_shutdown_t cdce_shutdown; 72184610Salfredstatic device_suspend_t cdce_suspend; 73184610Salfredstatic device_resume_t cdce_resume; 74188942Sthompsastatic usb_handle_request_t cdce_handle_request; 75184610Salfred 76184610Salfredstatic usb2_callback_t cdce_bulk_write_callback; 77184610Salfredstatic usb2_callback_t cdce_bulk_read_callback; 78184610Salfredstatic usb2_callback_t cdce_intr_read_callback; 79184610Salfredstatic usb2_callback_t cdce_intr_write_callback; 80184610Salfred 81188412Sthompsastatic usb2_ether_fn_t cdce_attach_post; 82188412Sthompsastatic usb2_ether_fn_t cdce_init; 83188412Sthompsastatic usb2_ether_fn_t cdce_stop; 84188412Sthompsastatic usb2_ether_fn_t cdce_start; 85188412Sthompsastatic usb2_ether_fn_t cdce_setmulti; 86188412Sthompsastatic usb2_ether_fn_t cdce_setpromisc; 87188412Sthompsa 88185948Sthompsastatic uint32_t cdce_m_crc32(struct mbuf *, uint32_t, uint32_t); 89184610Salfred 90184610Salfred#if USB_DEBUG 91184610Salfredstatic int cdce_debug = 0; 92184610Salfred 93188412SthompsaSYSCTL_NODE(_hw_usb2, OID_AUTO, cdce, CTLFLAG_RW, 0, "USB CDC-Ethernet"); 94184610SalfredSYSCTL_INT(_hw_usb2_cdce, OID_AUTO, debug, CTLFLAG_RW, &cdce_debug, 0, 95188412Sthompsa "Debug level"); 96184610Salfred#endif 97184610Salfred 98184610Salfredstatic const struct usb2_config cdce_config[CDCE_N_TRANSFER] = { 99184610Salfred 100187259Sthompsa [CDCE_BULK_A] = { 101184610Salfred .type = UE_BULK, 102184610Salfred .endpoint = UE_ADDR_ANY, 103184610Salfred .direction = UE_DIR_OUT, 104184610Salfred .if_index = 0, 105184610Salfred /* Host Mode */ 106188412Sthompsa .mh.frames = CDCE_FRAMES_MAX, 107188412Sthompsa .mh.bufsize = (CDCE_FRAMES_MAX * MCLBYTES), 108184610Salfred .mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,.ext_buffer = 1,}, 109188412Sthompsa .mh.callback = cdce_bulk_write_callback, 110184610Salfred .mh.timeout = 10000, /* 10 seconds */ 111184610Salfred /* Device Mode */ 112188412Sthompsa .md.frames = CDCE_FRAMES_MAX, 113188412Sthompsa .md.bufsize = (CDCE_FRAMES_MAX * MCLBYTES), 114188412Sthompsa .md.flags = {.pipe_bof = 1,.short_frames_ok = 1,.short_xfer_ok = 1,.ext_buffer = 1,}, 115188412Sthompsa .md.callback = cdce_bulk_read_callback, 116184610Salfred .md.timeout = 0, /* no timeout */ 117184610Salfred }, 118184610Salfred 119187259Sthompsa [CDCE_BULK_B] = { 120184610Salfred .type = UE_BULK, 121184610Salfred .endpoint = UE_ADDR_ANY, 122184610Salfred .direction = UE_DIR_IN, 123184610Salfred .if_index = 0, 124184610Salfred /* Host Mode */ 125188412Sthompsa .mh.frames = CDCE_FRAMES_MAX, 126188412Sthompsa .mh.bufsize = (CDCE_FRAMES_MAX * MCLBYTES), 127188412Sthompsa .mh.flags = {.pipe_bof = 1,.short_frames_ok = 1,.short_xfer_ok = 1,.ext_buffer = 1,}, 128188412Sthompsa .mh.callback = cdce_bulk_read_callback, 129184610Salfred .mh.timeout = 0, /* no timeout */ 130184610Salfred /* Device Mode */ 131188412Sthompsa .md.frames = CDCE_FRAMES_MAX, 132188412Sthompsa .md.bufsize = (CDCE_FRAMES_MAX * MCLBYTES), 133184610Salfred .md.flags = {.pipe_bof = 1,.force_short_xfer = 1,.ext_buffer = 1,}, 134188412Sthompsa .md.callback = cdce_bulk_write_callback, 135184610Salfred .md.timeout = 10000, /* 10 seconds */ 136184610Salfred }, 137184610Salfred 138187259Sthompsa [CDCE_INTR] = { 139184610Salfred .type = UE_INTERRUPT, 140184610Salfred .endpoint = UE_ADDR_ANY, 141184610Salfred .direction = UE_DIR_IN, 142184610Salfred .if_index = 1, 143184610Salfred /* Host Mode */ 144184610Salfred .mh.bufsize = CDCE_IND_SIZE_MAX, 145184610Salfred .mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,.no_pipe_ok = 1,}, 146188412Sthompsa .mh.callback = cdce_intr_read_callback, 147184610Salfred .mh.timeout = 0, 148184610Salfred /* Device Mode */ 149184610Salfred .md.bufsize = CDCE_IND_SIZE_MAX, 150184610Salfred .md.flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,}, 151188412Sthompsa .md.callback = cdce_intr_write_callback, 152184610Salfred .md.timeout = 10000, /* 10 seconds */ 153184610Salfred }, 154184610Salfred}; 155184610Salfred 156184610Salfredstatic device_method_t cdce_methods[] = { 157184610Salfred /* USB interface */ 158188942Sthompsa DEVMETHOD(usb_handle_request, cdce_handle_request), 159184610Salfred 160184610Salfred /* Device interface */ 161184610Salfred DEVMETHOD(device_probe, cdce_probe), 162184610Salfred DEVMETHOD(device_attach, cdce_attach), 163184610Salfred DEVMETHOD(device_detach, cdce_detach), 164184610Salfred DEVMETHOD(device_suspend, cdce_suspend), 165184610Salfred DEVMETHOD(device_resume, cdce_resume), 166184610Salfred DEVMETHOD(device_shutdown, cdce_shutdown), 167184610Salfred 168184610Salfred {0, 0} 169184610Salfred}; 170184610Salfred 171184610Salfredstatic driver_t cdce_driver = { 172184610Salfred .name = "cdce", 173184610Salfred .methods = cdce_methods, 174184610Salfred .size = sizeof(struct cdce_softc), 175184610Salfred}; 176184610Salfred 177184610Salfredstatic devclass_t cdce_devclass; 178184610Salfred 179189275SthompsaDRIVER_MODULE(cdce, uhub, cdce_driver, cdce_devclass, NULL, 0); 180184610SalfredMODULE_VERSION(cdce, 1); 181188942SthompsaMODULE_DEPEND(cdce, uether, 1, 1, 1); 182188942SthompsaMODULE_DEPEND(cdce, usb, 1, 1, 1); 183184610SalfredMODULE_DEPEND(cdce, ether, 1, 1, 1); 184184610Salfred 185188412Sthompsastatic const struct usb2_ether_methods cdce_ue_methods = { 186188412Sthompsa .ue_attach_post = cdce_attach_post, 187188412Sthompsa .ue_start = cdce_start, 188188412Sthompsa .ue_init = cdce_init, 189188412Sthompsa .ue_stop = cdce_stop, 190188412Sthompsa .ue_setmulti = cdce_setmulti, 191188412Sthompsa .ue_setpromisc = cdce_setpromisc, 192188412Sthompsa}; 193188412Sthompsa 194184610Salfredstatic const struct usb2_device_id cdce_devs[] = { 195184610Salfred {USB_IF_CSI(UICLASS_CDC, UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL, 0)}, 196184610Salfred {USB_IF_CSI(UICLASS_CDC, UISUBCLASS_MOBILE_DIRECT_LINE_MODEL, 0)}, 197184610Salfred 198184610Salfred {USB_VPI(USB_VENDOR_ACERLABS, USB_PRODUCT_ACERLABS_M5632, CDCE_FLAG_NO_UNION)}, 199184610Salfred {USB_VPI(USB_VENDOR_AMBIT, USB_PRODUCT_AMBIT_NTL_250, CDCE_FLAG_NO_UNION)}, 200184610Salfred {USB_VPI(USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_IPAQLINUX, CDCE_FLAG_NO_UNION)}, 201184610Salfred {USB_VPI(USB_VENDOR_GMATE, USB_PRODUCT_GMATE_YP3X00, CDCE_FLAG_NO_UNION)}, 202184610Salfred {USB_VPI(USB_VENDOR_MOTOROLA2, USB_PRODUCT_MOTOROLA2_USBLAN, CDCE_FLAG_ZAURUS | CDCE_FLAG_NO_UNION)}, 203184610Salfred {USB_VPI(USB_VENDOR_MOTOROLA2, USB_PRODUCT_MOTOROLA2_USBLAN2, CDCE_FLAG_ZAURUS | CDCE_FLAG_NO_UNION)}, 204184610Salfred {USB_VPI(USB_VENDOR_NETCHIP, USB_PRODUCT_NETCHIP_ETHERNETGADGET, CDCE_FLAG_NO_UNION)}, 205184610Salfred {USB_VPI(USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2501, CDCE_FLAG_NO_UNION)}, 206184610Salfred {USB_VPI(USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5500, CDCE_FLAG_ZAURUS)}, 207184610Salfred {USB_VPI(USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5600, CDCE_FLAG_ZAURUS | CDCE_FLAG_NO_UNION)}, 208184610Salfred {USB_VPI(USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SLA300, CDCE_FLAG_ZAURUS | CDCE_FLAG_NO_UNION)}, 209184610Salfred {USB_VPI(USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SLC700, CDCE_FLAG_ZAURUS | CDCE_FLAG_NO_UNION)}, 210184610Salfred {USB_VPI(USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SLC750, CDCE_FLAG_ZAURUS | CDCE_FLAG_NO_UNION)}, 211184610Salfred}; 212184610Salfred 213184610Salfredstatic int 214184610Salfredcdce_probe(device_t dev) 215184610Salfred{ 216184610Salfred struct usb2_attach_arg *uaa = device_get_ivars(dev); 217184610Salfred 218184610Salfred return (usb2_lookup_id_by_uaa(cdce_devs, sizeof(cdce_devs), uaa)); 219184610Salfred} 220184610Salfred 221188412Sthompsastatic void 222188412Sthompsacdce_attach_post(struct usb2_ether *ue) 223188412Sthompsa{ 224188412Sthompsa /* no-op */ 225188412Sthompsa return; 226188412Sthompsa} 227188412Sthompsa 228184610Salfredstatic int 229184610Salfredcdce_attach(device_t dev) 230184610Salfred{ 231184610Salfred struct cdce_softc *sc = device_get_softc(dev); 232188412Sthompsa struct usb2_ether *ue = &sc->sc_ue; 233184610Salfred struct usb2_attach_arg *uaa = device_get_ivars(dev); 234184610Salfred struct usb2_interface *iface; 235184610Salfred const struct usb2_cdc_union_descriptor *ud; 236184610Salfred const struct usb2_interface_descriptor *id; 237188412Sthompsa const struct usb2_cdc_ethernet_descriptor *ued; 238184610Salfred int error; 239184610Salfred uint8_t i; 240184610Salfred char eaddr_str[5 * ETHER_ADDR_LEN]; /* approx */ 241184610Salfred 242184610Salfred sc->sc_flags = USB_GET_DRIVER_INFO(uaa); 243184610Salfred 244184610Salfred device_set_usb2_desc(dev); 245184610Salfred 246188412Sthompsa mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 247184610Salfred 248184610Salfred if (sc->sc_flags & CDCE_FLAG_NO_UNION) { 249184610Salfred sc->sc_ifaces_index[0] = uaa->info.bIfaceIndex; 250184610Salfred sc->sc_ifaces_index[1] = uaa->info.bIfaceIndex; 251184610Salfred sc->sc_data_iface_no = 0; /* not used */ 252184610Salfred goto alloc_transfers; 253184610Salfred } 254184610Salfred ud = usb2_find_descriptor 255184610Salfred (uaa->device, NULL, uaa->info.bIfaceIndex, 256184610Salfred UDESC_CS_INTERFACE, 0 - 1, UDESCSUB_CDC_UNION, 0 - 1); 257184610Salfred 258184610Salfred if ((ud == NULL) || (ud->bLength < sizeof(*ud))) { 259184610Salfred device_printf(dev, "no union descriptor!\n"); 260184610Salfred goto detach; 261184610Salfred } 262184610Salfred sc->sc_data_iface_no = ud->bSlaveInterface[0]; 263184610Salfred 264184610Salfred for (i = 0;; i++) { 265184610Salfred 266184610Salfred iface = usb2_get_iface(uaa->device, i); 267184610Salfred 268184610Salfred if (iface) { 269184610Salfred 270184610Salfred id = usb2_get_interface_descriptor(iface); 271184610Salfred 272184610Salfred if (id && (id->bInterfaceNumber == 273184610Salfred sc->sc_data_iface_no)) { 274184610Salfred sc->sc_ifaces_index[0] = i; 275184610Salfred sc->sc_ifaces_index[1] = uaa->info.bIfaceIndex; 276184610Salfred usb2_set_parent_iface(uaa->device, i, uaa->info.bIfaceIndex); 277184610Salfred break; 278184610Salfred } 279184610Salfred } else { 280184610Salfred device_printf(dev, "no data interface found!\n"); 281184610Salfred goto detach; 282184610Salfred } 283184610Salfred } 284184610Salfred 285184610Salfred /* 286184610Salfred * <quote> 287184610Salfred * 288184610Salfred * The Data Class interface of a networking device shall have 289184610Salfred * a minimum of two interface settings. The first setting 290184610Salfred * (the default interface setting) includes no endpoints and 291184610Salfred * therefore no networking traffic is exchanged whenever the 292184610Salfred * default interface setting is selected. One or more 293184610Salfred * additional interface settings are used for normal 294184610Salfred * operation, and therefore each includes a pair of endpoints 295184610Salfred * (one IN, and one OUT) to exchange network traffic. Select 296184610Salfred * an alternate interface setting to initialize the network 297184610Salfred * aspects of the device and to enable the exchange of 298184610Salfred * network traffic. 299184610Salfred * 300184610Salfred * </quote> 301184610Salfred * 302184610Salfred * Some devices, most notably cable modems, include interface 303184610Salfred * settings that have no IN or OUT endpoint, therefore loop 304184610Salfred * through the list of all available interface settings 305184610Salfred * looking for one with both IN and OUT endpoints. 306184610Salfred */ 307184610Salfred 308184610Salfredalloc_transfers: 309184610Salfred 310188412Sthompsa for (i = 0; i != 32; i++) { 311184610Salfred 312184610Salfred error = usb2_set_alt_interface_index 313184610Salfred (uaa->device, sc->sc_ifaces_index[0], i); 314184610Salfred 315184610Salfred if (error) { 316184610Salfred device_printf(dev, "no valid alternate " 317184610Salfred "setting found!\n"); 318184610Salfred goto detach; 319184610Salfred } 320184610Salfred error = usb2_transfer_setup 321184610Salfred (uaa->device, sc->sc_ifaces_index, 322184610Salfred sc->sc_xfer, cdce_config, CDCE_N_TRANSFER, 323184610Salfred sc, &sc->sc_mtx); 324184610Salfred 325184610Salfred if (error == 0) { 326184610Salfred break; 327184610Salfred } 328184610Salfred } 329184610Salfred 330188412Sthompsa ued = usb2_find_descriptor 331184610Salfred (uaa->device, NULL, uaa->info.bIfaceIndex, 332184610Salfred UDESC_CS_INTERFACE, 0 - 1, UDESCSUB_CDC_ENF, 0 - 1); 333184610Salfred 334188412Sthompsa if ((ued == NULL) || (ued->bLength < sizeof(*ued))) { 335184610Salfred error = USB_ERR_INVAL; 336184610Salfred } else { 337188412Sthompsa error = usb2_req_get_string_any(uaa->device, NULL, 338188412Sthompsa eaddr_str, sizeof(eaddr_str), ued->iMacAddress); 339184610Salfred } 340184610Salfred 341184610Salfred if (error) { 342184610Salfred 343184610Salfred /* fake MAC address */ 344184610Salfred 345184610Salfred device_printf(dev, "faking MAC address\n"); 346188412Sthompsa sc->sc_ue.ue_eaddr[0] = 0x2a; 347188412Sthompsa memcpy(&sc->sc_ue.ue_eaddr[1], &ticks, sizeof(uint32_t)); 348188412Sthompsa sc->sc_ue.ue_eaddr[5] = device_get_unit(dev); 349184610Salfred 350184610Salfred } else { 351184610Salfred 352188412Sthompsa bzero(sc->sc_ue.ue_eaddr, sizeof(sc->sc_ue.ue_eaddr)); 353184610Salfred 354188412Sthompsa for (i = 0; i != (ETHER_ADDR_LEN * 2); i++) { 355184610Salfred 356184610Salfred char c = eaddr_str[i]; 357184610Salfred 358188412Sthompsa if ('0' <= c && c <= '9') 359184610Salfred c -= '0'; 360188412Sthompsa else if (c != 0) 361184610Salfred c -= 'A' - 10; 362188412Sthompsa else 363184610Salfred break; 364184610Salfred 365184610Salfred c &= 0xf; 366184610Salfred 367188412Sthompsa if ((i & 1) == 0) 368184610Salfred c <<= 4; 369188412Sthompsa sc->sc_ue.ue_eaddr[i / 2] |= c; 370184610Salfred } 371184610Salfred 372184610Salfred if (uaa->usb2_mode == USB_MODE_DEVICE) { 373184610Salfred /* 374184610Salfred * Do not use the same MAC address like the peer ! 375184610Salfred */ 376188412Sthompsa sc->sc_ue.ue_eaddr[5] ^= 0xFF; 377184610Salfred } 378184610Salfred } 379184610Salfred 380188412Sthompsa ue->ue_sc = sc; 381188412Sthompsa ue->ue_dev = dev; 382188412Sthompsa ue->ue_udev = uaa->device; 383188412Sthompsa ue->ue_mtx = &sc->sc_mtx; 384188412Sthompsa ue->ue_methods = &cdce_ue_methods; 385184610Salfred 386188412Sthompsa error = usb2_ether_ifattach(ue); 387188412Sthompsa if (error) { 388188412Sthompsa device_printf(dev, "could not attach interface\n"); 389184610Salfred goto detach; 390184610Salfred } 391184610Salfred return (0); /* success */ 392184610Salfred 393184610Salfreddetach: 394184610Salfred cdce_detach(dev); 395184610Salfred return (ENXIO); /* failure */ 396184610Salfred} 397184610Salfred 398184610Salfredstatic int 399184610Salfredcdce_detach(device_t dev) 400184610Salfred{ 401184610Salfred struct cdce_softc *sc = device_get_softc(dev); 402188412Sthompsa struct usb2_ether *ue = &sc->sc_ue; 403184610Salfred 404184610Salfred /* stop all USB transfers first */ 405184610Salfred usb2_transfer_unsetup(sc->sc_xfer, CDCE_N_TRANSFER); 406188412Sthompsa usb2_ether_ifdetach(ue); 407184610Salfred mtx_destroy(&sc->sc_mtx); 408184610Salfred 409184610Salfred return (0); 410184610Salfred} 411184610Salfred 412184610Salfredstatic void 413188412Sthompsacdce_start(struct usb2_ether *ue) 414184610Salfred{ 415188412Sthompsa struct cdce_softc *sc = usb2_ether_getsc(ue); 416184610Salfred 417188412Sthompsa /* 418188412Sthompsa * Start the USB transfers, if not already started: 419188412Sthompsa */ 420188412Sthompsa usb2_transfer_start(sc->sc_xfer[CDCE_BULK_B]); 421188412Sthompsa usb2_transfer_start(sc->sc_xfer[CDCE_BULK_A]); 422184610Salfred} 423184610Salfred 424184610Salfredstatic void 425188412Sthompsacdce_free_queue(struct mbuf **ppm, uint8_t n) 426184610Salfred{ 427188412Sthompsa uint8_t x; 428188412Sthompsa for (x = 0; x != n; x++) { 429188412Sthompsa if (ppm[x] != NULL) { 430188412Sthompsa m_freem(ppm[x]); 431188412Sthompsa ppm[x] = NULL; 432184610Salfred } 433184610Salfred } 434184610Salfred} 435184610Salfred 436184610Salfredstatic void 437188412Sthompsacdce_bulk_write_callback(struct usb2_xfer *xfer) 438184610Salfred{ 439184610Salfred struct cdce_softc *sc = xfer->priv_sc; 440188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(&sc->sc_ue); 441184610Salfred struct mbuf *m; 442184610Salfred struct mbuf *mt; 443188412Sthompsa uint32_t crc; 444188412Sthompsa uint8_t x; 445184610Salfred 446188412Sthompsa DPRINTFN(1, "\n"); 447188412Sthompsa 448184610Salfred switch (USB_GET_STATE(xfer)) { 449184610Salfred case USB_ST_TRANSFERRED: 450184610Salfred DPRINTFN(11, "transfer complete: " 451188412Sthompsa "%u bytes in %u frames\n", xfer->actlen, 452188412Sthompsa xfer->aframes); 453184610Salfred 454188412Sthompsa ifp->if_opackets++; 455184610Salfred 456188412Sthompsa /* free all previous TX buffers */ 457188412Sthompsa cdce_free_queue(sc->sc_tx_buf, CDCE_FRAMES_MAX); 458184610Salfred 459188412Sthompsa /* FALLTHROUGH */ 460184610Salfred case USB_ST_SETUP: 461184610Salfredtr_setup: 462188412Sthompsa for (x = 0; x != CDCE_FRAMES_MAX; x++) { 463184610Salfred 464184610Salfred IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 465184610Salfred 466188412Sthompsa if (m == NULL) 467184610Salfred break; 468188412Sthompsa 469188412Sthompsa if (sc->sc_flags & CDCE_FLAG_ZAURUS) { 470188412Sthompsa /* 471188412Sthompsa * Zaurus wants a 32-bit CRC appended 472188412Sthompsa * to every frame 473188412Sthompsa */ 474188412Sthompsa 475188412Sthompsa crc = cdce_m_crc32(m, 0, m->m_pkthdr.len); 476188412Sthompsa crc = htole32(crc); 477188412Sthompsa 478188412Sthompsa if (!m_append(m, 4, (void *)&crc)) { 479188412Sthompsa m_freem(m); 480188412Sthompsa ifp->if_oerrors++; 481188412Sthompsa continue; 482188412Sthompsa } 483184610Salfred } 484188412Sthompsa if (m->m_len != m->m_pkthdr.len) { 485184610Salfred mt = m_defrag(m, M_DONTWAIT); 486184610Salfred if (mt == NULL) { 487184610Salfred m_freem(m); 488184610Salfred ifp->if_oerrors++; 489184610Salfred continue; 490184610Salfred } 491184610Salfred m = mt; 492184610Salfred } 493188412Sthompsa if (m->m_pkthdr.len > MCLBYTES) { 494188412Sthompsa m->m_pkthdr.len = MCLBYTES; 495188412Sthompsa } 496188412Sthompsa sc->sc_tx_buf[x] = m; 497188412Sthompsa xfer->frlengths[x] = m->m_len; 498188412Sthompsa usb2_set_frame_data(xfer, m->m_data, x); 499184610Salfred 500184610Salfred /* 501188412Sthompsa * If there's a BPF listener, bounce a copy of 502188412Sthompsa * this frame to him: 503184610Salfred */ 504184610Salfred BPF_MTAP(ifp, m); 505184610Salfred } 506188412Sthompsa if (x != 0) { 507188412Sthompsa xfer->nframes = x; 508188412Sthompsa usb2_start_hardware(xfer); 509184610Salfred } 510184610Salfred break; 511184610Salfred 512184610Salfred default: /* Error */ 513184610Salfred DPRINTFN(11, "transfer error, %s\n", 514184610Salfred usb2_errstr(xfer->error)); 515184610Salfred 516188412Sthompsa /* free all previous TX buffers */ 517188412Sthompsa cdce_free_queue(sc->sc_tx_buf, CDCE_FRAMES_MAX); 518184610Salfred 519188412Sthompsa /* count output errors */ 520184610Salfred ifp->if_oerrors++; 521184610Salfred 522184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 523184610Salfred /* try to clear stall first */ 524184610Salfred xfer->flags.stall_pipe = 1; 525184610Salfred goto tr_setup; 526184610Salfred } 527184610Salfred break; 528184610Salfred } 529184610Salfred} 530184610Salfred 531184610Salfredstatic int32_t 532184610Salfredcdce_m_crc32_cb(void *arg, void *src, uint32_t count) 533184610Salfred{ 534188412Sthompsa uint32_t *p_crc = arg; 535184610Salfred 536184610Salfred *p_crc = crc32_raw(src, count, *p_crc); 537184610Salfred return (0); 538184610Salfred} 539184610Salfred 540184610Salfredstatic uint32_t 541184610Salfredcdce_m_crc32(struct mbuf *m, uint32_t src_offset, uint32_t src_len) 542184610Salfred{ 543184610Salfred uint32_t crc = 0xFFFFFFFF; 544188412Sthompsa int error; 545184610Salfred 546188412Sthompsa error = m_apply(m, src_offset, src_len, cdce_m_crc32_cb, &crc); 547184610Salfred return (crc ^ 0xFFFFFFFF); 548184610Salfred} 549184610Salfred 550184610Salfredstatic void 551188412Sthompsacdce_init(struct usb2_ether *ue) 552184610Salfred{ 553188412Sthompsa struct cdce_softc *sc = usb2_ether_getsc(ue); 554188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(ue); 555184610Salfred 556188412Sthompsa CDCE_LOCK_ASSERT(sc, MA_OWNED); 557184610Salfred 558188412Sthompsa ifp->if_drv_flags |= IFF_DRV_RUNNING; 559184610Salfred 560188412Sthompsa /* start interrupt transfer */ 561188412Sthompsa usb2_transfer_start(sc->sc_xfer[CDCE_INTR]); 562188412Sthompsa 563188412Sthompsa /* stall data write direction, which depends on USB mode */ 564188412Sthompsa if (usb2_get_mode(sc->sc_ue.ue_udev) == USB_MODE_HOST) 565188412Sthompsa usb2_transfer_set_stall(sc->sc_xfer[CDCE_BULK_A]); 566188412Sthompsa else 567188412Sthompsa usb2_transfer_set_stall(sc->sc_xfer[CDCE_BULK_B]); 568188412Sthompsa 569188412Sthompsa /* start data transfers */ 570188412Sthompsa cdce_start(ue); 571188412Sthompsa} 572188412Sthompsa 573188412Sthompsastatic void 574188412Sthompsacdce_stop(struct usb2_ether *ue) 575188412Sthompsa{ 576188412Sthompsa struct cdce_softc *sc = usb2_ether_getsc(ue); 577188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(ue); 578188412Sthompsa 579188412Sthompsa CDCE_LOCK_ASSERT(sc, MA_OWNED); 580188412Sthompsa 581188412Sthompsa ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 582188412Sthompsa 583184610Salfred /* 584184610Salfred * stop all the transfers, if not already stopped: 585184610Salfred */ 586187259Sthompsa usb2_transfer_stop(sc->sc_xfer[CDCE_BULK_A]); 587187259Sthompsa usb2_transfer_stop(sc->sc_xfer[CDCE_BULK_B]); 588188412Sthompsa usb2_transfer_stop(sc->sc_xfer[CDCE_INTR]); 589184610Salfred} 590184610Salfred 591188412Sthompsastatic void 592188412Sthompsacdce_setmulti(struct usb2_ether *ue) 593188412Sthompsa{ 594188412Sthompsa /* no-op */ 595188412Sthompsa return; 596188412Sthompsa} 597188412Sthompsa 598188412Sthompsastatic void 599188412Sthompsacdce_setpromisc(struct usb2_ether *ue) 600188412Sthompsa{ 601188412Sthompsa /* no-op */ 602188412Sthompsa return; 603188412Sthompsa} 604188412Sthompsa 605184610Salfredstatic int 606184610Salfredcdce_shutdown(device_t dev) 607184610Salfred{ 608184610Salfred struct cdce_softc *sc = device_get_softc(dev); 609184610Salfred 610188412Sthompsa usb2_ether_ifshutdown(&sc->sc_ue); 611184610Salfred 612184610Salfred return (0); 613184610Salfred} 614184610Salfred 615184610Salfredstatic int 616184610Salfredcdce_suspend(device_t dev) 617184610Salfred{ 618184610Salfred device_printf(dev, "Suspending\n"); 619184610Salfred return (0); 620184610Salfred} 621184610Salfred 622184610Salfredstatic int 623184610Salfredcdce_resume(device_t dev) 624184610Salfred{ 625184610Salfred device_printf(dev, "Resuming\n"); 626184610Salfred return (0); 627184610Salfred} 628184610Salfred 629184610Salfredstatic void 630188412Sthompsacdce_bulk_read_callback(struct usb2_xfer *xfer) 631184610Salfred{ 632184610Salfred struct cdce_softc *sc = xfer->priv_sc; 633184610Salfred struct mbuf *m; 634188412Sthompsa uint8_t x; 635184610Salfred 636184610Salfred switch (USB_GET_STATE(xfer)) { 637184610Salfred case USB_ST_TRANSFERRED: 638184610Salfred 639184610Salfred DPRINTF("received %u bytes in %u frames\n", 640184610Salfred xfer->actlen, xfer->aframes); 641184610Salfred 642188412Sthompsa for (x = 0; x != xfer->aframes; x++) { 643184610Salfred 644188412Sthompsa m = sc->sc_rx_buf[x]; 645188412Sthompsa sc->sc_rx_buf[x] = NULL; 646188412Sthompsa 647188412Sthompsa /* Strip off CRC added by Zaurus, if any */ 648188412Sthompsa if ((sc->sc_flags & CDCE_FLAG_ZAURUS) && 649188412Sthompsa (xfer->frlengths[x] >= 14)) 650188412Sthompsa xfer->frlengths[x] -= 4; 651188412Sthompsa 652188412Sthompsa if (xfer->frlengths[x] < sizeof(struct ether_header)) { 653188412Sthompsa m_freem(m); 654188412Sthompsa continue; 655184610Salfred } 656188412Sthompsa /* queue up mbuf */ 657188412Sthompsa usb2_ether_rxmbuf(&sc->sc_ue, m, xfer->frlengths[x]); 658184610Salfred } 659184610Salfred 660188412Sthompsa /* FALLTHROUGH */ 661184610Salfred case USB_ST_SETUP: 662188412Sthompsa /* 663188412Sthompsa * TODO: Implement support for multi frame transfers, 664188412Sthompsa * when the USB hardware supports it. 665184610Salfred */ 666188412Sthompsa for (x = 0; x != 1; x++) { 667188412Sthompsa if (sc->sc_rx_buf[x] == NULL) { 668189528Sthompsa m = usb2_ether_newbuf(); 669188412Sthompsa if (m == NULL) 670188412Sthompsa goto tr_stall; 671188412Sthompsa sc->sc_rx_buf[x] = m; 672184610Salfred } else { 673188412Sthompsa m = sc->sc_rx_buf[x]; 674184610Salfred } 675184610Salfred 676188412Sthompsa usb2_set_frame_data(xfer, m->m_data, x); 677188412Sthompsa xfer->frlengths[x] = m->m_len; 678184610Salfred } 679188412Sthompsa /* set number of frames and start hardware */ 680184610Salfred xfer->nframes = x; 681184610Salfred usb2_start_hardware(xfer); 682188412Sthompsa /* flush any received frames */ 683188412Sthompsa usb2_ether_rxflush(&sc->sc_ue); 684184610Salfred break; 685184610Salfred 686184610Salfred default: /* Error */ 687184610Salfred DPRINTF("error = %s\n", 688184610Salfred usb2_errstr(xfer->error)); 689184610Salfred 690184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 691188412Sthompsatr_stall: 692184610Salfred /* try to clear stall first */ 693184610Salfred xfer->flags.stall_pipe = 1; 694188412Sthompsa xfer->nframes = 0; 695188412Sthompsa usb2_start_hardware(xfer); 696188412Sthompsa break; 697184610Salfred } 698184610Salfred 699188412Sthompsa /* need to free the RX-mbufs when we are cancelled */ 700188412Sthompsa cdce_free_queue(sc->sc_rx_buf, CDCE_FRAMES_MAX); 701184610Salfred break; 702184610Salfred } 703184610Salfred} 704184610Salfred 705184610Salfredstatic void 706184610Salfredcdce_intr_read_callback(struct usb2_xfer *xfer) 707184610Salfred{ 708184610Salfred ; /* style fix */ 709184610Salfred switch (USB_GET_STATE(xfer)) { 710184610Salfred case USB_ST_TRANSFERRED: 711184610Salfred 712184610Salfred DPRINTF("Received %d bytes\n", 713184610Salfred xfer->actlen); 714184610Salfred 715184610Salfred /* TODO: decode some indications */ 716184610Salfred 717188412Sthompsa /* FALLTHROUGH */ 718184610Salfred case USB_ST_SETUP: 719184610Salfredtr_setup: 720184610Salfred xfer->frlengths[0] = xfer->max_data_length; 721184610Salfred usb2_start_hardware(xfer); 722184610Salfred break; 723184610Salfred 724184610Salfred default: /* Error */ 725184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 726184610Salfred /* start clear stall */ 727184610Salfred xfer->flags.stall_pipe = 1; 728184610Salfred goto tr_setup; 729184610Salfred } 730184610Salfred break; 731184610Salfred } 732184610Salfred} 733184610Salfred 734184610Salfredstatic void 735184610Salfredcdce_intr_write_callback(struct usb2_xfer *xfer) 736184610Salfred{ 737184610Salfred ; /* style fix */ 738184610Salfred switch (USB_GET_STATE(xfer)) { 739184610Salfred case USB_ST_TRANSFERRED: 740184610Salfred 741184610Salfred DPRINTF("Transferred %d bytes\n", xfer->actlen); 742184610Salfred 743188412Sthompsa /* FALLTHROUGH */ 744184610Salfred case USB_ST_SETUP: 745184610Salfredtr_setup: 746184610Salfred#if 0 747184610Salfred xfer->frlengths[0] = XXX; 748184610Salfred usb2_start_hardware(xfer); 749184610Salfred#endif 750184610Salfred break; 751184610Salfred 752184610Salfred default: /* Error */ 753184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 754184610Salfred /* start clear stall */ 755184610Salfred xfer->flags.stall_pipe = 1; 756184610Salfred goto tr_setup; 757184610Salfred } 758184610Salfred break; 759184610Salfred } 760184610Salfred} 761184610Salfred 762184610Salfredstatic int 763184610Salfredcdce_handle_request(device_t dev, 764184610Salfred const void *req, void **pptr, uint16_t *plen, 765184610Salfred uint16_t offset, uint8_t is_complete) 766184610Salfred{ 767184610Salfred return (ENXIO); /* use builtin handler */ 768184610Salfred} 769