if_cdce.c revision 192502
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 192502 2009-05-21 01:48:42Z 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> 51184610Salfred 52184610Salfred#define USB_DEBUG_VAR cdce_debug 53184610Salfred 54188942Sthompsa#include <dev/usb/usb_core.h> 55188942Sthompsa#include <dev/usb/usb_lookup.h> 56188942Sthompsa#include <dev/usb/usb_process.h> 57188942Sthompsa#include <dev/usb/usb_debug.h> 58188942Sthompsa#include <dev/usb/usb_request.h> 59188942Sthompsa#include <dev/usb/usb_busdma.h> 60188942Sthompsa#include <dev/usb/usb_util.h> 61188942Sthompsa#include <dev/usb/usb_parse.h> 62188942Sthompsa#include <dev/usb/usb_device.h> 63184610Salfred 64188942Sthompsa#include <dev/usb/net/usb_ethernet.h> 65188942Sthompsa#include <dev/usb/net/if_cdcereg.h> 66184610Salfred 67184610Salfredstatic device_probe_t cdce_probe; 68184610Salfredstatic device_attach_t cdce_attach; 69184610Salfredstatic device_detach_t cdce_detach; 70184610Salfredstatic device_suspend_t cdce_suspend; 71184610Salfredstatic device_resume_t cdce_resume; 72188942Sthompsastatic usb_handle_request_t cdce_handle_request; 73184610Salfred 74184610Salfredstatic usb2_callback_t cdce_bulk_write_callback; 75184610Salfredstatic usb2_callback_t cdce_bulk_read_callback; 76184610Salfredstatic usb2_callback_t cdce_intr_read_callback; 77184610Salfredstatic usb2_callback_t cdce_intr_write_callback; 78184610Salfred 79188412Sthompsastatic usb2_ether_fn_t cdce_attach_post; 80188412Sthompsastatic usb2_ether_fn_t cdce_init; 81188412Sthompsastatic usb2_ether_fn_t cdce_stop; 82188412Sthompsastatic usb2_ether_fn_t cdce_start; 83188412Sthompsastatic usb2_ether_fn_t cdce_setmulti; 84188412Sthompsastatic usb2_ether_fn_t cdce_setpromisc; 85188412Sthompsa 86185948Sthompsastatic uint32_t cdce_m_crc32(struct mbuf *, uint32_t, uint32_t); 87184610Salfred 88184610Salfred#if USB_DEBUG 89184610Salfredstatic int cdce_debug = 0; 90184610Salfred 91192502SthompsaSYSCTL_NODE(_hw_usb, OID_AUTO, cdce, CTLFLAG_RW, 0, "USB CDC-Ethernet"); 92192502SthompsaSYSCTL_INT(_hw_usb_cdce, OID_AUTO, debug, CTLFLAG_RW, &cdce_debug, 0, 93188412Sthompsa "Debug level"); 94184610Salfred#endif 95184610Salfred 96184610Salfredstatic const struct usb2_config cdce_config[CDCE_N_TRANSFER] = { 97184610Salfred 98190734Sthompsa [CDCE_BULK_RX] = { 99184610Salfred .type = UE_BULK, 100184610Salfred .endpoint = UE_ADDR_ANY, 101190734Sthompsa .direction = UE_DIR_RX, 102184610Salfred .if_index = 0, 103190734Sthompsa .frames = CDCE_FRAMES_MAX, 104190734Sthompsa .bufsize = (CDCE_FRAMES_MAX * MCLBYTES), 105190734Sthompsa .flags = {.pipe_bof = 1,.short_frames_ok = 1,.short_xfer_ok = 1,.ext_buffer = 1,}, 106190734Sthompsa .callback = cdce_bulk_read_callback, 107190734Sthompsa .timeout = 0, /* no timeout */ 108192499Sthompsa .usb_mode = USB_MODE_DUAL, /* both modes */ 109184610Salfred }, 110184610Salfred 111190734Sthompsa [CDCE_BULK_TX] = { 112184610Salfred .type = UE_BULK, 113184610Salfred .endpoint = UE_ADDR_ANY, 114190734Sthompsa .direction = UE_DIR_TX, 115184610Salfred .if_index = 0, 116190734Sthompsa .frames = CDCE_FRAMES_MAX, 117190734Sthompsa .bufsize = (CDCE_FRAMES_MAX * MCLBYTES), 118190734Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,.ext_buffer = 1,}, 119190734Sthompsa .callback = cdce_bulk_write_callback, 120190734Sthompsa .timeout = 10000, /* 10 seconds */ 121192499Sthompsa .usb_mode = USB_MODE_DUAL, /* both modes */ 122184610Salfred }, 123184610Salfred 124190734Sthompsa [CDCE_INTR_RX] = { 125184610Salfred .type = UE_INTERRUPT, 126184610Salfred .endpoint = UE_ADDR_ANY, 127190734Sthompsa .direction = UE_DIR_RX, 128184610Salfred .if_index = 1, 129190734Sthompsa .bufsize = CDCE_IND_SIZE_MAX, 130190734Sthompsa .flags = {.pipe_bof = 1,.short_xfer_ok = 1,.no_pipe_ok = 1,}, 131190734Sthompsa .callback = cdce_intr_read_callback, 132190734Sthompsa .timeout = 0, 133190734Sthompsa .usb_mode = USB_MODE_HOST, 134184610Salfred }, 135190734Sthompsa 136190734Sthompsa [CDCE_INTR_TX] = { 137190734Sthompsa .type = UE_INTERRUPT, 138190734Sthompsa .endpoint = UE_ADDR_ANY, 139190734Sthompsa .direction = UE_DIR_TX, 140190734Sthompsa .if_index = 1, 141190734Sthompsa .bufsize = CDCE_IND_SIZE_MAX, 142190734Sthompsa .flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,}, 143190734Sthompsa .callback = cdce_intr_write_callback, 144190734Sthompsa .timeout = 10000, /* 10 seconds */ 145190734Sthompsa .usb_mode = USB_MODE_DEVICE, 146190734Sthompsa }, 147184610Salfred}; 148184610Salfred 149184610Salfredstatic device_method_t cdce_methods[] = { 150184610Salfred /* USB interface */ 151188942Sthompsa DEVMETHOD(usb_handle_request, cdce_handle_request), 152184610Salfred 153184610Salfred /* Device interface */ 154184610Salfred DEVMETHOD(device_probe, cdce_probe), 155184610Salfred DEVMETHOD(device_attach, cdce_attach), 156184610Salfred DEVMETHOD(device_detach, cdce_detach), 157184610Salfred DEVMETHOD(device_suspend, cdce_suspend), 158184610Salfred DEVMETHOD(device_resume, cdce_resume), 159184610Salfred 160184610Salfred {0, 0} 161184610Salfred}; 162184610Salfred 163184610Salfredstatic driver_t cdce_driver = { 164184610Salfred .name = "cdce", 165184610Salfred .methods = cdce_methods, 166184610Salfred .size = sizeof(struct cdce_softc), 167184610Salfred}; 168184610Salfred 169184610Salfredstatic devclass_t cdce_devclass; 170184610Salfred 171189275SthompsaDRIVER_MODULE(cdce, uhub, cdce_driver, cdce_devclass, NULL, 0); 172184610SalfredMODULE_VERSION(cdce, 1); 173188942SthompsaMODULE_DEPEND(cdce, uether, 1, 1, 1); 174188942SthompsaMODULE_DEPEND(cdce, usb, 1, 1, 1); 175184610SalfredMODULE_DEPEND(cdce, ether, 1, 1, 1); 176184610Salfred 177188412Sthompsastatic const struct usb2_ether_methods cdce_ue_methods = { 178188412Sthompsa .ue_attach_post = cdce_attach_post, 179188412Sthompsa .ue_start = cdce_start, 180188412Sthompsa .ue_init = cdce_init, 181188412Sthompsa .ue_stop = cdce_stop, 182188412Sthompsa .ue_setmulti = cdce_setmulti, 183188412Sthompsa .ue_setpromisc = cdce_setpromisc, 184188412Sthompsa}; 185188412Sthompsa 186184610Salfredstatic const struct usb2_device_id cdce_devs[] = { 187184610Salfred {USB_IF_CSI(UICLASS_CDC, UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL, 0)}, 188184610Salfred {USB_IF_CSI(UICLASS_CDC, UISUBCLASS_MOBILE_DIRECT_LINE_MODEL, 0)}, 189184610Salfred 190184610Salfred {USB_VPI(USB_VENDOR_ACERLABS, USB_PRODUCT_ACERLABS_M5632, CDCE_FLAG_NO_UNION)}, 191184610Salfred {USB_VPI(USB_VENDOR_AMBIT, USB_PRODUCT_AMBIT_NTL_250, CDCE_FLAG_NO_UNION)}, 192184610Salfred {USB_VPI(USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_IPAQLINUX, CDCE_FLAG_NO_UNION)}, 193184610Salfred {USB_VPI(USB_VENDOR_GMATE, USB_PRODUCT_GMATE_YP3X00, CDCE_FLAG_NO_UNION)}, 194184610Salfred {USB_VPI(USB_VENDOR_MOTOROLA2, USB_PRODUCT_MOTOROLA2_USBLAN, CDCE_FLAG_ZAURUS | CDCE_FLAG_NO_UNION)}, 195184610Salfred {USB_VPI(USB_VENDOR_MOTOROLA2, USB_PRODUCT_MOTOROLA2_USBLAN2, CDCE_FLAG_ZAURUS | CDCE_FLAG_NO_UNION)}, 196184610Salfred {USB_VPI(USB_VENDOR_NETCHIP, USB_PRODUCT_NETCHIP_ETHERNETGADGET, CDCE_FLAG_NO_UNION)}, 197184610Salfred {USB_VPI(USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2501, CDCE_FLAG_NO_UNION)}, 198184610Salfred {USB_VPI(USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5500, CDCE_FLAG_ZAURUS)}, 199184610Salfred {USB_VPI(USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5600, CDCE_FLAG_ZAURUS | CDCE_FLAG_NO_UNION)}, 200184610Salfred {USB_VPI(USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SLA300, CDCE_FLAG_ZAURUS | CDCE_FLAG_NO_UNION)}, 201184610Salfred {USB_VPI(USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SLC700, CDCE_FLAG_ZAURUS | CDCE_FLAG_NO_UNION)}, 202184610Salfred {USB_VPI(USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SLC750, CDCE_FLAG_ZAURUS | CDCE_FLAG_NO_UNION)}, 203184610Salfred}; 204184610Salfred 205184610Salfredstatic int 206184610Salfredcdce_probe(device_t dev) 207184610Salfred{ 208184610Salfred struct usb2_attach_arg *uaa = device_get_ivars(dev); 209184610Salfred 210184610Salfred return (usb2_lookup_id_by_uaa(cdce_devs, sizeof(cdce_devs), uaa)); 211184610Salfred} 212184610Salfred 213188412Sthompsastatic void 214188412Sthompsacdce_attach_post(struct usb2_ether *ue) 215188412Sthompsa{ 216188412Sthompsa /* no-op */ 217188412Sthompsa return; 218188412Sthompsa} 219188412Sthompsa 220184610Salfredstatic int 221184610Salfredcdce_attach(device_t dev) 222184610Salfred{ 223184610Salfred struct cdce_softc *sc = device_get_softc(dev); 224188412Sthompsa struct usb2_ether *ue = &sc->sc_ue; 225184610Salfred struct usb2_attach_arg *uaa = device_get_ivars(dev); 226184610Salfred struct usb2_interface *iface; 227184610Salfred const struct usb2_cdc_union_descriptor *ud; 228184610Salfred const struct usb2_interface_descriptor *id; 229188412Sthompsa const struct usb2_cdc_ethernet_descriptor *ued; 230184610Salfred int error; 231184610Salfred uint8_t i; 232184610Salfred char eaddr_str[5 * ETHER_ADDR_LEN]; /* approx */ 233184610Salfred 234184610Salfred sc->sc_flags = USB_GET_DRIVER_INFO(uaa); 235184610Salfred 236184610Salfred device_set_usb2_desc(dev); 237184610Salfred 238188412Sthompsa mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 239184610Salfred 240184610Salfred if (sc->sc_flags & CDCE_FLAG_NO_UNION) { 241184610Salfred sc->sc_ifaces_index[0] = uaa->info.bIfaceIndex; 242184610Salfred sc->sc_ifaces_index[1] = uaa->info.bIfaceIndex; 243184610Salfred sc->sc_data_iface_no = 0; /* not used */ 244184610Salfred goto alloc_transfers; 245184610Salfred } 246184610Salfred ud = usb2_find_descriptor 247184610Salfred (uaa->device, NULL, uaa->info.bIfaceIndex, 248184610Salfred UDESC_CS_INTERFACE, 0 - 1, UDESCSUB_CDC_UNION, 0 - 1); 249184610Salfred 250184610Salfred if ((ud == NULL) || (ud->bLength < sizeof(*ud))) { 251184610Salfred device_printf(dev, "no union descriptor!\n"); 252184610Salfred goto detach; 253184610Salfred } 254184610Salfred sc->sc_data_iface_no = ud->bSlaveInterface[0]; 255184610Salfred 256184610Salfred for (i = 0;; i++) { 257184610Salfred 258184610Salfred iface = usb2_get_iface(uaa->device, i); 259184610Salfred 260184610Salfred if (iface) { 261184610Salfred 262184610Salfred id = usb2_get_interface_descriptor(iface); 263184610Salfred 264184610Salfred if (id && (id->bInterfaceNumber == 265184610Salfred sc->sc_data_iface_no)) { 266184610Salfred sc->sc_ifaces_index[0] = i; 267184610Salfred sc->sc_ifaces_index[1] = uaa->info.bIfaceIndex; 268184610Salfred usb2_set_parent_iface(uaa->device, i, uaa->info.bIfaceIndex); 269184610Salfred break; 270184610Salfred } 271184610Salfred } else { 272184610Salfred device_printf(dev, "no data interface found!\n"); 273184610Salfred goto detach; 274184610Salfred } 275184610Salfred } 276184610Salfred 277184610Salfred /* 278184610Salfred * <quote> 279184610Salfred * 280184610Salfred * The Data Class interface of a networking device shall have 281184610Salfred * a minimum of two interface settings. The first setting 282184610Salfred * (the default interface setting) includes no endpoints and 283184610Salfred * therefore no networking traffic is exchanged whenever the 284184610Salfred * default interface setting is selected. One or more 285184610Salfred * additional interface settings are used for normal 286184610Salfred * operation, and therefore each includes a pair of endpoints 287184610Salfred * (one IN, and one OUT) to exchange network traffic. Select 288184610Salfred * an alternate interface setting to initialize the network 289184610Salfred * aspects of the device and to enable the exchange of 290184610Salfred * network traffic. 291184610Salfred * 292184610Salfred * </quote> 293184610Salfred * 294184610Salfred * Some devices, most notably cable modems, include interface 295184610Salfred * settings that have no IN or OUT endpoint, therefore loop 296184610Salfred * through the list of all available interface settings 297184610Salfred * looking for one with both IN and OUT endpoints. 298184610Salfred */ 299184610Salfred 300184610Salfredalloc_transfers: 301184610Salfred 302188412Sthompsa for (i = 0; i != 32; i++) { 303184610Salfred 304184610Salfred error = usb2_set_alt_interface_index 305184610Salfred (uaa->device, sc->sc_ifaces_index[0], i); 306184610Salfred 307184610Salfred if (error) { 308184610Salfred device_printf(dev, "no valid alternate " 309184610Salfred "setting found!\n"); 310184610Salfred goto detach; 311184610Salfred } 312184610Salfred error = usb2_transfer_setup 313184610Salfred (uaa->device, sc->sc_ifaces_index, 314184610Salfred sc->sc_xfer, cdce_config, CDCE_N_TRANSFER, 315184610Salfred sc, &sc->sc_mtx); 316184610Salfred 317184610Salfred if (error == 0) { 318184610Salfred break; 319184610Salfred } 320184610Salfred } 321184610Salfred 322188412Sthompsa ued = usb2_find_descriptor 323184610Salfred (uaa->device, NULL, uaa->info.bIfaceIndex, 324184610Salfred UDESC_CS_INTERFACE, 0 - 1, UDESCSUB_CDC_ENF, 0 - 1); 325184610Salfred 326188412Sthompsa if ((ued == NULL) || (ued->bLength < sizeof(*ued))) { 327184610Salfred error = USB_ERR_INVAL; 328184610Salfred } else { 329188412Sthompsa error = usb2_req_get_string_any(uaa->device, NULL, 330188412Sthompsa eaddr_str, sizeof(eaddr_str), ued->iMacAddress); 331184610Salfred } 332184610Salfred 333184610Salfred if (error) { 334184610Salfred 335184610Salfred /* fake MAC address */ 336184610Salfred 337184610Salfred device_printf(dev, "faking MAC address\n"); 338188412Sthompsa sc->sc_ue.ue_eaddr[0] = 0x2a; 339188412Sthompsa memcpy(&sc->sc_ue.ue_eaddr[1], &ticks, sizeof(uint32_t)); 340188412Sthompsa sc->sc_ue.ue_eaddr[5] = device_get_unit(dev); 341184610Salfred 342184610Salfred } else { 343184610Salfred 344188412Sthompsa bzero(sc->sc_ue.ue_eaddr, sizeof(sc->sc_ue.ue_eaddr)); 345184610Salfred 346188412Sthompsa for (i = 0; i != (ETHER_ADDR_LEN * 2); i++) { 347184610Salfred 348184610Salfred char c = eaddr_str[i]; 349184610Salfred 350188412Sthompsa if ('0' <= c && c <= '9') 351184610Salfred c -= '0'; 352188412Sthompsa else if (c != 0) 353184610Salfred c -= 'A' - 10; 354188412Sthompsa else 355184610Salfred break; 356184610Salfred 357184610Salfred c &= 0xf; 358184610Salfred 359188412Sthompsa if ((i & 1) == 0) 360184610Salfred c <<= 4; 361188412Sthompsa sc->sc_ue.ue_eaddr[i / 2] |= c; 362184610Salfred } 363184610Salfred 364192499Sthompsa if (uaa->usb_mode == USB_MODE_DEVICE) { 365184610Salfred /* 366184610Salfred * Do not use the same MAC address like the peer ! 367184610Salfred */ 368188412Sthompsa sc->sc_ue.ue_eaddr[5] ^= 0xFF; 369184610Salfred } 370184610Salfred } 371184610Salfred 372188412Sthompsa ue->ue_sc = sc; 373188412Sthompsa ue->ue_dev = dev; 374188412Sthompsa ue->ue_udev = uaa->device; 375188412Sthompsa ue->ue_mtx = &sc->sc_mtx; 376188412Sthompsa ue->ue_methods = &cdce_ue_methods; 377184610Salfred 378188412Sthompsa error = usb2_ether_ifattach(ue); 379188412Sthompsa if (error) { 380188412Sthompsa device_printf(dev, "could not attach interface\n"); 381184610Salfred goto detach; 382184610Salfred } 383184610Salfred return (0); /* success */ 384184610Salfred 385184610Salfreddetach: 386184610Salfred cdce_detach(dev); 387184610Salfred return (ENXIO); /* failure */ 388184610Salfred} 389184610Salfred 390184610Salfredstatic int 391184610Salfredcdce_detach(device_t dev) 392184610Salfred{ 393184610Salfred struct cdce_softc *sc = device_get_softc(dev); 394188412Sthompsa struct usb2_ether *ue = &sc->sc_ue; 395184610Salfred 396184610Salfred /* stop all USB transfers first */ 397184610Salfred usb2_transfer_unsetup(sc->sc_xfer, CDCE_N_TRANSFER); 398188412Sthompsa usb2_ether_ifdetach(ue); 399184610Salfred mtx_destroy(&sc->sc_mtx); 400184610Salfred 401184610Salfred return (0); 402184610Salfred} 403184610Salfred 404184610Salfredstatic void 405188412Sthompsacdce_start(struct usb2_ether *ue) 406184610Salfred{ 407188412Sthompsa struct cdce_softc *sc = usb2_ether_getsc(ue); 408184610Salfred 409188412Sthompsa /* 410188412Sthompsa * Start the USB transfers, if not already started: 411188412Sthompsa */ 412190734Sthompsa usb2_transfer_start(sc->sc_xfer[CDCE_BULK_TX]); 413190734Sthompsa usb2_transfer_start(sc->sc_xfer[CDCE_BULK_RX]); 414184610Salfred} 415184610Salfred 416184610Salfredstatic void 417188412Sthompsacdce_free_queue(struct mbuf **ppm, uint8_t n) 418184610Salfred{ 419188412Sthompsa uint8_t x; 420188412Sthompsa for (x = 0; x != n; x++) { 421188412Sthompsa if (ppm[x] != NULL) { 422188412Sthompsa m_freem(ppm[x]); 423188412Sthompsa ppm[x] = NULL; 424184610Salfred } 425184610Salfred } 426184610Salfred} 427184610Salfred 428184610Salfredstatic void 429188412Sthompsacdce_bulk_write_callback(struct usb2_xfer *xfer) 430184610Salfred{ 431184610Salfred struct cdce_softc *sc = xfer->priv_sc; 432188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(&sc->sc_ue); 433184610Salfred struct mbuf *m; 434184610Salfred struct mbuf *mt; 435188412Sthompsa uint32_t crc; 436188412Sthompsa uint8_t x; 437184610Salfred 438188412Sthompsa DPRINTFN(1, "\n"); 439188412Sthompsa 440184610Salfred switch (USB_GET_STATE(xfer)) { 441184610Salfred case USB_ST_TRANSFERRED: 442184610Salfred DPRINTFN(11, "transfer complete: " 443188412Sthompsa "%u bytes in %u frames\n", xfer->actlen, 444188412Sthompsa xfer->aframes); 445184610Salfred 446188412Sthompsa ifp->if_opackets++; 447184610Salfred 448188412Sthompsa /* free all previous TX buffers */ 449188412Sthompsa cdce_free_queue(sc->sc_tx_buf, CDCE_FRAMES_MAX); 450184610Salfred 451188412Sthompsa /* FALLTHROUGH */ 452184610Salfred case USB_ST_SETUP: 453184610Salfredtr_setup: 454188412Sthompsa for (x = 0; x != CDCE_FRAMES_MAX; x++) { 455184610Salfred 456184610Salfred IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 457184610Salfred 458188412Sthompsa if (m == NULL) 459184610Salfred break; 460188412Sthompsa 461188412Sthompsa if (sc->sc_flags & CDCE_FLAG_ZAURUS) { 462188412Sthompsa /* 463188412Sthompsa * Zaurus wants a 32-bit CRC appended 464188412Sthompsa * to every frame 465188412Sthompsa */ 466188412Sthompsa 467188412Sthompsa crc = cdce_m_crc32(m, 0, m->m_pkthdr.len); 468188412Sthompsa crc = htole32(crc); 469188412Sthompsa 470188412Sthompsa if (!m_append(m, 4, (void *)&crc)) { 471188412Sthompsa m_freem(m); 472188412Sthompsa ifp->if_oerrors++; 473188412Sthompsa continue; 474188412Sthompsa } 475184610Salfred } 476188412Sthompsa if (m->m_len != m->m_pkthdr.len) { 477184610Salfred mt = m_defrag(m, M_DONTWAIT); 478184610Salfred if (mt == NULL) { 479184610Salfred m_freem(m); 480184610Salfred ifp->if_oerrors++; 481184610Salfred continue; 482184610Salfred } 483184610Salfred m = mt; 484184610Salfred } 485188412Sthompsa if (m->m_pkthdr.len > MCLBYTES) { 486188412Sthompsa m->m_pkthdr.len = MCLBYTES; 487188412Sthompsa } 488188412Sthompsa sc->sc_tx_buf[x] = m; 489188412Sthompsa xfer->frlengths[x] = m->m_len; 490188412Sthompsa usb2_set_frame_data(xfer, m->m_data, x); 491184610Salfred 492184610Salfred /* 493188412Sthompsa * If there's a BPF listener, bounce a copy of 494188412Sthompsa * this frame to him: 495184610Salfred */ 496184610Salfred BPF_MTAP(ifp, m); 497184610Salfred } 498188412Sthompsa if (x != 0) { 499188412Sthompsa xfer->nframes = x; 500188412Sthompsa usb2_start_hardware(xfer); 501184610Salfred } 502184610Salfred break; 503184610Salfred 504184610Salfred default: /* Error */ 505184610Salfred DPRINTFN(11, "transfer error, %s\n", 506184610Salfred usb2_errstr(xfer->error)); 507184610Salfred 508188412Sthompsa /* free all previous TX buffers */ 509188412Sthompsa cdce_free_queue(sc->sc_tx_buf, CDCE_FRAMES_MAX); 510184610Salfred 511188412Sthompsa /* count output errors */ 512184610Salfred ifp->if_oerrors++; 513184610Salfred 514184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 515184610Salfred /* try to clear stall first */ 516184610Salfred xfer->flags.stall_pipe = 1; 517184610Salfred goto tr_setup; 518184610Salfred } 519184610Salfred break; 520184610Salfred } 521184610Salfred} 522184610Salfred 523184610Salfredstatic int32_t 524184610Salfredcdce_m_crc32_cb(void *arg, void *src, uint32_t count) 525184610Salfred{ 526188412Sthompsa uint32_t *p_crc = arg; 527184610Salfred 528184610Salfred *p_crc = crc32_raw(src, count, *p_crc); 529184610Salfred return (0); 530184610Salfred} 531184610Salfred 532184610Salfredstatic uint32_t 533184610Salfredcdce_m_crc32(struct mbuf *m, uint32_t src_offset, uint32_t src_len) 534184610Salfred{ 535184610Salfred uint32_t crc = 0xFFFFFFFF; 536188412Sthompsa int error; 537184610Salfred 538188412Sthompsa error = m_apply(m, src_offset, src_len, cdce_m_crc32_cb, &crc); 539184610Salfred return (crc ^ 0xFFFFFFFF); 540184610Salfred} 541184610Salfred 542184610Salfredstatic void 543188412Sthompsacdce_init(struct usb2_ether *ue) 544184610Salfred{ 545188412Sthompsa struct cdce_softc *sc = usb2_ether_getsc(ue); 546188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(ue); 547184610Salfred 548188412Sthompsa CDCE_LOCK_ASSERT(sc, MA_OWNED); 549184610Salfred 550188412Sthompsa ifp->if_drv_flags |= IFF_DRV_RUNNING; 551184610Salfred 552188412Sthompsa /* start interrupt transfer */ 553190734Sthompsa usb2_transfer_start(sc->sc_xfer[CDCE_INTR_RX]); 554190734Sthompsa usb2_transfer_start(sc->sc_xfer[CDCE_INTR_TX]); 555188412Sthompsa 556188412Sthompsa /* stall data write direction, which depends on USB mode */ 557190734Sthompsa usb2_transfer_set_stall(sc->sc_xfer[CDCE_BULK_TX]); 558188412Sthompsa 559188412Sthompsa /* start data transfers */ 560188412Sthompsa cdce_start(ue); 561188412Sthompsa} 562188412Sthompsa 563188412Sthompsastatic void 564188412Sthompsacdce_stop(struct usb2_ether *ue) 565188412Sthompsa{ 566188412Sthompsa struct cdce_softc *sc = usb2_ether_getsc(ue); 567188412Sthompsa struct ifnet *ifp = usb2_ether_getifp(ue); 568188412Sthompsa 569188412Sthompsa CDCE_LOCK_ASSERT(sc, MA_OWNED); 570188412Sthompsa 571188412Sthompsa ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 572188412Sthompsa 573184610Salfred /* 574184610Salfred * stop all the transfers, if not already stopped: 575184610Salfred */ 576190734Sthompsa usb2_transfer_stop(sc->sc_xfer[CDCE_BULK_RX]); 577190734Sthompsa usb2_transfer_stop(sc->sc_xfer[CDCE_BULK_TX]); 578190734Sthompsa usb2_transfer_stop(sc->sc_xfer[CDCE_INTR_RX]); 579190734Sthompsa usb2_transfer_stop(sc->sc_xfer[CDCE_INTR_TX]); 580184610Salfred} 581184610Salfred 582188412Sthompsastatic void 583188412Sthompsacdce_setmulti(struct usb2_ether *ue) 584188412Sthompsa{ 585188412Sthompsa /* no-op */ 586188412Sthompsa return; 587188412Sthompsa} 588188412Sthompsa 589188412Sthompsastatic void 590188412Sthompsacdce_setpromisc(struct usb2_ether *ue) 591188412Sthompsa{ 592188412Sthompsa /* no-op */ 593188412Sthompsa return; 594188412Sthompsa} 595188412Sthompsa 596184610Salfredstatic int 597184610Salfredcdce_suspend(device_t dev) 598184610Salfred{ 599184610Salfred device_printf(dev, "Suspending\n"); 600184610Salfred return (0); 601184610Salfred} 602184610Salfred 603184610Salfredstatic int 604184610Salfredcdce_resume(device_t dev) 605184610Salfred{ 606184610Salfred device_printf(dev, "Resuming\n"); 607184610Salfred return (0); 608184610Salfred} 609184610Salfred 610184610Salfredstatic void 611188412Sthompsacdce_bulk_read_callback(struct usb2_xfer *xfer) 612184610Salfred{ 613184610Salfred struct cdce_softc *sc = xfer->priv_sc; 614184610Salfred struct mbuf *m; 615188412Sthompsa uint8_t x; 616184610Salfred 617184610Salfred switch (USB_GET_STATE(xfer)) { 618184610Salfred case USB_ST_TRANSFERRED: 619184610Salfred 620184610Salfred DPRINTF("received %u bytes in %u frames\n", 621184610Salfred xfer->actlen, xfer->aframes); 622184610Salfred 623188412Sthompsa for (x = 0; x != xfer->aframes; x++) { 624184610Salfred 625188412Sthompsa m = sc->sc_rx_buf[x]; 626188412Sthompsa sc->sc_rx_buf[x] = NULL; 627188412Sthompsa 628188412Sthompsa /* Strip off CRC added by Zaurus, if any */ 629188412Sthompsa if ((sc->sc_flags & CDCE_FLAG_ZAURUS) && 630188412Sthompsa (xfer->frlengths[x] >= 14)) 631188412Sthompsa xfer->frlengths[x] -= 4; 632188412Sthompsa 633188412Sthompsa if (xfer->frlengths[x] < sizeof(struct ether_header)) { 634188412Sthompsa m_freem(m); 635188412Sthompsa continue; 636184610Salfred } 637188412Sthompsa /* queue up mbuf */ 638188412Sthompsa usb2_ether_rxmbuf(&sc->sc_ue, m, xfer->frlengths[x]); 639184610Salfred } 640184610Salfred 641188412Sthompsa /* FALLTHROUGH */ 642184610Salfred case USB_ST_SETUP: 643188412Sthompsa /* 644188412Sthompsa * TODO: Implement support for multi frame transfers, 645188412Sthompsa * when the USB hardware supports it. 646184610Salfred */ 647188412Sthompsa for (x = 0; x != 1; x++) { 648188412Sthompsa if (sc->sc_rx_buf[x] == NULL) { 649189528Sthompsa m = usb2_ether_newbuf(); 650188412Sthompsa if (m == NULL) 651188412Sthompsa goto tr_stall; 652188412Sthompsa sc->sc_rx_buf[x] = m; 653184610Salfred } else { 654188412Sthompsa m = sc->sc_rx_buf[x]; 655184610Salfred } 656184610Salfred 657188412Sthompsa usb2_set_frame_data(xfer, m->m_data, x); 658188412Sthompsa xfer->frlengths[x] = m->m_len; 659184610Salfred } 660188412Sthompsa /* set number of frames and start hardware */ 661184610Salfred xfer->nframes = x; 662184610Salfred usb2_start_hardware(xfer); 663188412Sthompsa /* flush any received frames */ 664188412Sthompsa usb2_ether_rxflush(&sc->sc_ue); 665184610Salfred break; 666184610Salfred 667184610Salfred default: /* Error */ 668184610Salfred DPRINTF("error = %s\n", 669184610Salfred usb2_errstr(xfer->error)); 670184610Salfred 671184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 672188412Sthompsatr_stall: 673184610Salfred /* try to clear stall first */ 674184610Salfred xfer->flags.stall_pipe = 1; 675188412Sthompsa xfer->nframes = 0; 676188412Sthompsa usb2_start_hardware(xfer); 677188412Sthompsa break; 678184610Salfred } 679184610Salfred 680188412Sthompsa /* need to free the RX-mbufs when we are cancelled */ 681188412Sthompsa cdce_free_queue(sc->sc_rx_buf, CDCE_FRAMES_MAX); 682184610Salfred break; 683184610Salfred } 684184610Salfred} 685184610Salfred 686184610Salfredstatic void 687184610Salfredcdce_intr_read_callback(struct usb2_xfer *xfer) 688184610Salfred{ 689184610Salfred ; /* style fix */ 690184610Salfred switch (USB_GET_STATE(xfer)) { 691184610Salfred case USB_ST_TRANSFERRED: 692184610Salfred 693184610Salfred DPRINTF("Received %d bytes\n", 694184610Salfred xfer->actlen); 695184610Salfred 696184610Salfred /* TODO: decode some indications */ 697184610Salfred 698188412Sthompsa /* FALLTHROUGH */ 699184610Salfred case USB_ST_SETUP: 700184610Salfredtr_setup: 701184610Salfred xfer->frlengths[0] = xfer->max_data_length; 702184610Salfred usb2_start_hardware(xfer); 703184610Salfred break; 704184610Salfred 705184610Salfred default: /* Error */ 706184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 707184610Salfred /* start clear stall */ 708184610Salfred xfer->flags.stall_pipe = 1; 709184610Salfred goto tr_setup; 710184610Salfred } 711184610Salfred break; 712184610Salfred } 713184610Salfred} 714184610Salfred 715184610Salfredstatic void 716184610Salfredcdce_intr_write_callback(struct usb2_xfer *xfer) 717184610Salfred{ 718184610Salfred ; /* style fix */ 719184610Salfred switch (USB_GET_STATE(xfer)) { 720184610Salfred case USB_ST_TRANSFERRED: 721184610Salfred 722184610Salfred DPRINTF("Transferred %d bytes\n", xfer->actlen); 723184610Salfred 724188412Sthompsa /* FALLTHROUGH */ 725184610Salfred case USB_ST_SETUP: 726184610Salfredtr_setup: 727184610Salfred#if 0 728184610Salfred xfer->frlengths[0] = XXX; 729184610Salfred usb2_start_hardware(xfer); 730184610Salfred#endif 731184610Salfred break; 732184610Salfred 733184610Salfred default: /* Error */ 734184610Salfred if (xfer->error != USB_ERR_CANCELLED) { 735184610Salfred /* start clear stall */ 736184610Salfred xfer->flags.stall_pipe = 1; 737184610Salfred goto tr_setup; 738184610Salfred } 739184610Salfred break; 740184610Salfred } 741184610Salfred} 742184610Salfred 743184610Salfredstatic int 744184610Salfredcdce_handle_request(device_t dev, 745184610Salfred const void *req, void **pptr, uint16_t *plen, 746184610Salfred uint16_t offset, uint8_t is_complete) 747184610Salfred{ 748184610Salfred return (ENXIO); /* use builtin handler */ 749184610Salfred} 750