if_cdce.c revision 246128
1301771Simp/* $NetBSD: if_cdce.c,v 1.4 2004/10/24 12:50:54 augustss Exp $ */ 2301771Simp 3301771Simp/*- 4301771Simp * Copyright (c) 1997, 1998, 1999, 2000-2003 Bill Paul <wpaul@windriver.com> 5301771Simp * Copyright (c) 2003-2005 Craig Boston 6301771Simp * Copyright (c) 2004 Daniel Hartmeier 7301771Simp * Copyright (c) 2009 Hans Petter Selasky 8301771Simp * All rights reserved. 9301771Simp * 10301771Simp * Redistribution and use in source and binary forms, with or without 11301771Simp * modification, are permitted provided that the following conditions 12301771Simp * are met: 13301771Simp * 1. Redistributions of source code must retain the above copyright 14301771Simp * notice, this list of conditions and the following disclaimer. 15301771Simp * 2. Redistributions in binary form must reproduce the above copyright 16301771Simp * notice, this list of conditions and the following disclaimer in the 17301771Simp * documentation and/or other materials provided with the distribution. 18301771Simp * 3. All advertising materials mentioning features or use of this software 19301771Simp * must display the following acknowledgement: 20301771Simp * This product includes software developed by Bill Paul. 21301771Simp * 4. Neither the name of the author nor the names of any co-contributors 22301771Simp * may be used to endorse or promote products derived from this software 23301771Simp * without specific prior written permission. 24301771Simp * 25301771Simp * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 26301771Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27301771Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28301771Simp * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul, THE VOICES IN HIS HEAD OR 29301771Simp * THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 30301771Simp * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 31301771Simp * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 32301771Simp * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 33301771Simp * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 34301771Simp * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 35301771Simp * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36301771Simp */ 37301771Simp 38301771Simp/* 39301771Simp * USB Communication Device Class (Ethernet Networking Control Model) 40301771Simp * http://www.usb.org/developers/devclass_docs/usbcdc11.pdf 41301771Simp */ 42301771Simp 43301771Simp/* 44301771Simp * USB Network Control Model (NCM) 45301771Simp * http://www.usb.org/developers/devclass_docs/NCM10.zip 46301771Simp */ 47301771Simp 48301771Simp#include <sys/cdefs.h> 49301771Simp__FBSDID("$FreeBSD: head/sys/dev/usb/net/if_cdce.c 246128 2013-01-30 18:01:20Z sbz $"); 50301771Simp 51301771Simp#include <sys/stdint.h> 52301771Simp#include <sys/stddef.h> 53301771Simp#include <sys/param.h> 54301771Simp#include <sys/queue.h> 55301771Simp#include <sys/types.h> 56301771Simp#include <sys/systm.h> 57301771Simp#include <sys/kernel.h> 58301771Simp#include <sys/bus.h> 59301771Simp#include <sys/module.h> 60301771Simp#include <sys/lock.h> 61301771Simp#include <sys/mutex.h> 62301771Simp#include <sys/condvar.h> 63301771Simp#include <sys/sysctl.h> 64301771Simp#include <sys/sx.h> 65301771Simp#include <sys/unistd.h> 66301771Simp#include <sys/callout.h> 67301771Simp#include <sys/malloc.h> 68301771Simp#include <sys/priv.h> 69301771Simp 70301771Simp#include <dev/usb/usb.h> 71301771Simp#include <dev/usb/usbdi.h> 72301771Simp#include <dev/usb/usbdi_util.h> 73301771Simp#include <dev/usb/usb_cdc.h> 74301771Simp#include "usbdevs.h" 75301771Simp 76301771Simp#define USB_DEBUG_VAR cdce_debug 77301771Simp#include <dev/usb/usb_debug.h> 78301771Simp#include <dev/usb/usb_process.h> 79301771Simp#include "usb_if.h" 80301771Simp 81301771Simp#include <dev/usb/net/usb_ethernet.h> 82301771Simp#include <dev/usb/net/if_cdcereg.h> 83301771Simp 84301771Simpstatic device_probe_t cdce_probe; 85301771Simpstatic device_attach_t cdce_attach; 86301771Simpstatic device_detach_t cdce_detach; 87301771Simpstatic device_suspend_t cdce_suspend; 88301771Simpstatic device_resume_t cdce_resume; 89301771Simpstatic usb_handle_request_t cdce_handle_request; 90301771Simp 91301771Simpstatic usb_callback_t cdce_bulk_write_callback; 92301771Simpstatic usb_callback_t cdce_bulk_read_callback; 93301771Simpstatic usb_callback_t cdce_intr_read_callback; 94301771Simpstatic usb_callback_t cdce_intr_write_callback; 95301771Simp 96301771Simp#if CDCE_HAVE_NCM 97301771Simpstatic usb_callback_t cdce_ncm_bulk_write_callback; 98301771Simpstatic usb_callback_t cdce_ncm_bulk_read_callback; 99301771Simp#endif 100301771Simp 101301771Simpstatic uether_fn_t cdce_attach_post; 102301771Simpstatic uether_fn_t cdce_init; 103301771Simpstatic uether_fn_t cdce_stop; 104301771Simpstatic uether_fn_t cdce_start; 105301771Simpstatic uether_fn_t cdce_setmulti; 106301771Simpstatic uether_fn_t cdce_setpromisc; 107301771Simp 108301771Simpstatic uint32_t cdce_m_crc32(struct mbuf *, uint32_t, uint32_t); 109301771Simp 110301771Simp#ifdef USB_DEBUG 111301771Simpstatic int cdce_debug = 0; 112301771Simpstatic int cdce_tx_interval = 0; 113301771Simp 114301771Simpstatic SYSCTL_NODE(_hw_usb, OID_AUTO, cdce, CTLFLAG_RW, 0, "USB CDC-Ethernet"); 115301771SimpSYSCTL_INT(_hw_usb_cdce, OID_AUTO, debug, CTLFLAG_RW, &cdce_debug, 0, 116301771Simp "Debug level"); 117301771SimpSYSCTL_INT(_hw_usb_cdce, OID_AUTO, interval, CTLFLAG_RW, &cdce_tx_interval, 0, 118301771Simp "NCM transmit interval in ms"); 119301771Simp#endif 120301771Simp 121301771Simpstatic const struct usb_config cdce_config[CDCE_N_TRANSFER] = { 122301771Simp 123301771Simp [CDCE_BULK_RX] = { 124301771Simp .type = UE_BULK, 125301771Simp .endpoint = UE_ADDR_ANY, 126301771Simp .direction = UE_DIR_RX, 127301771Simp .if_index = 0, 128301771Simp .frames = CDCE_FRAMES_MAX, 129301771Simp .bufsize = (CDCE_FRAMES_MAX * MCLBYTES), 130301771Simp .flags = {.pipe_bof = 1,.short_frames_ok = 1,.short_xfer_ok = 1,.ext_buffer = 1,}, 131301771Simp .callback = cdce_bulk_read_callback, 132301771Simp .timeout = 0, /* no timeout */ 133301771Simp .usb_mode = USB_MODE_DUAL, /* both modes */ 134301771Simp }, 135301771Simp 136301771Simp [CDCE_BULK_TX] = { 137301771Simp .type = UE_BULK, 138301771Simp .endpoint = UE_ADDR_ANY, 139301771Simp .direction = UE_DIR_TX, 140301771Simp .if_index = 0, 141301771Simp .frames = CDCE_FRAMES_MAX, 142301771Simp .bufsize = (CDCE_FRAMES_MAX * MCLBYTES), 143301771Simp .flags = {.pipe_bof = 1,.force_short_xfer = 1,.ext_buffer = 1,}, 144301771Simp .callback = cdce_bulk_write_callback, 145301771Simp .timeout = 10000, /* 10 seconds */ 146301771Simp .usb_mode = USB_MODE_DUAL, /* both modes */ 147301771Simp }, 148301771Simp 149301771Simp [CDCE_INTR_RX] = { 150301771Simp .type = UE_INTERRUPT, 151301771Simp .endpoint = UE_ADDR_ANY, 152301771Simp .direction = UE_DIR_RX, 153301771Simp .if_index = 1, 154301771Simp .bufsize = CDCE_IND_SIZE_MAX, 155301771Simp .flags = {.pipe_bof = 1,.short_xfer_ok = 1,.no_pipe_ok = 1,}, 156301771Simp .callback = cdce_intr_read_callback, 157301771Simp .timeout = 0, 158301771Simp .usb_mode = USB_MODE_HOST, 159301771Simp }, 160301771Simp 161301771Simp [CDCE_INTR_TX] = { 162301771Simp .type = UE_INTERRUPT, 163301771Simp .endpoint = UE_ADDR_ANY, 164301771Simp .direction = UE_DIR_TX, 165301771Simp .if_index = 1, 166301771Simp .bufsize = CDCE_IND_SIZE_MAX, 167301771Simp .flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,}, 168301771Simp .callback = cdce_intr_write_callback, 169301771Simp .timeout = 10000, /* 10 seconds */ 170301771Simp .usb_mode = USB_MODE_DEVICE, 171301771Simp }, 172301771Simp}; 173301771Simp 174301771Simp#if CDCE_HAVE_NCM 175301771Simpstatic const struct usb_config cdce_ncm_config[CDCE_N_TRANSFER] = { 176301771Simp 177301771Simp [CDCE_BULK_RX] = { 178301771Simp .type = UE_BULK, 179301771Simp .endpoint = UE_ADDR_ANY, 180301771Simp .direction = UE_DIR_RX, 181301771Simp .if_index = 0, 182301771Simp .frames = CDCE_NCM_RX_FRAMES_MAX, 183301771Simp .bufsize = (CDCE_NCM_RX_FRAMES_MAX * CDCE_NCM_RX_MAXLEN), 184301771Simp .flags = {.pipe_bof = 1,.short_frames_ok = 1,.short_xfer_ok = 1,}, 185301771Simp .callback = cdce_ncm_bulk_read_callback, 186301771Simp .timeout = 0, /* no timeout */ 187301771Simp .usb_mode = USB_MODE_DUAL, /* both modes */ 188301771Simp }, 189301771Simp 190301771Simp [CDCE_BULK_TX] = { 191301771Simp .type = UE_BULK, 192301771Simp .endpoint = UE_ADDR_ANY, 193301771Simp .direction = UE_DIR_TX, 194301771Simp .if_index = 0, 195301771Simp .frames = CDCE_NCM_TX_FRAMES_MAX, 196301771Simp .bufsize = (CDCE_NCM_TX_FRAMES_MAX * CDCE_NCM_TX_MAXLEN), 197301771Simp .flags = {.pipe_bof = 1,}, 198301771Simp .callback = cdce_ncm_bulk_write_callback, 199301771Simp .timeout = 10000, /* 10 seconds */ 200301771Simp .usb_mode = USB_MODE_DUAL, /* both modes */ 201301771Simp }, 202301771Simp 203301771Simp [CDCE_INTR_RX] = { 204301771Simp .type = UE_INTERRUPT, 205301771Simp .endpoint = UE_ADDR_ANY, 206301771Simp .direction = UE_DIR_RX, 207301771Simp .if_index = 1, 208301771Simp .bufsize = CDCE_IND_SIZE_MAX, 209301771Simp .flags = {.pipe_bof = 1,.short_xfer_ok = 1,.no_pipe_ok = 1,}, 210301771Simp .callback = cdce_intr_read_callback, 211301771Simp .timeout = 0, 212301771Simp .usb_mode = USB_MODE_HOST, 213301771Simp }, 214301771Simp 215301771Simp [CDCE_INTR_TX] = { 216301771Simp .type = UE_INTERRUPT, 217301771Simp .endpoint = UE_ADDR_ANY, 218301771Simp .direction = UE_DIR_TX, 219301771Simp .if_index = 1, 220301771Simp .bufsize = CDCE_IND_SIZE_MAX, 221301771Simp .flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,}, 222301771Simp .callback = cdce_intr_write_callback, 223301771Simp .timeout = 10000, /* 10 seconds */ 224301771Simp .usb_mode = USB_MODE_DEVICE, 225301771Simp }, 226301771Simp}; 227301771Simp#endif 228301771Simp 229301771Simpstatic device_method_t cdce_methods[] = { 230301771Simp /* USB interface */ 231301771Simp DEVMETHOD(usb_handle_request, cdce_handle_request), 232301771Simp 233301771Simp /* Device interface */ 234301771Simp DEVMETHOD(device_probe, cdce_probe), 235301771Simp DEVMETHOD(device_attach, cdce_attach), 236301771Simp DEVMETHOD(device_detach, cdce_detach), 237301771Simp DEVMETHOD(device_suspend, cdce_suspend), 238301771Simp DEVMETHOD(device_resume, cdce_resume), 239301771Simp 240301771Simp DEVMETHOD_END 241301771Simp}; 242301771Simp 243301771Simpstatic driver_t cdce_driver = { 244301771Simp .name = "cdce", 245301771Simp .methods = cdce_methods, 246301771Simp .size = sizeof(struct cdce_softc), 247301771Simp}; 248301771Simp 249301771Simpstatic devclass_t cdce_devclass; 250301771Simp 251301771SimpDRIVER_MODULE(cdce, uhub, cdce_driver, cdce_devclass, NULL, 0); 252301771SimpMODULE_VERSION(cdce, 1); 253301771SimpMODULE_DEPEND(cdce, uether, 1, 1, 1); 254301771SimpMODULE_DEPEND(cdce, usb, 1, 1, 1); 255301771SimpMODULE_DEPEND(cdce, ether, 1, 1, 1); 256301771Simp 257301771Simpstatic const struct usb_ether_methods cdce_ue_methods = { 258301771Simp .ue_attach_post = cdce_attach_post, 259301771Simp .ue_start = cdce_start, 260301771Simp .ue_init = cdce_init, 261301771Simp .ue_stop = cdce_stop, 262301771Simp .ue_setmulti = cdce_setmulti, 263301771Simp .ue_setpromisc = cdce_setpromisc, 264301771Simp}; 265301771Simp 266301771Simpstatic const STRUCT_USB_HOST_ID cdce_host_devs[] = { 267301771Simp {USB_VPI(USB_VENDOR_ACERLABS, USB_PRODUCT_ACERLABS_M5632, CDCE_FLAG_NO_UNION)}, 268301771Simp {USB_VPI(USB_VENDOR_AMBIT, USB_PRODUCT_AMBIT_NTL_250, CDCE_FLAG_NO_UNION)}, 269301771Simp {USB_VPI(USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_IPAQLINUX, CDCE_FLAG_NO_UNION)}, 270301771Simp {USB_VPI(USB_VENDOR_GMATE, USB_PRODUCT_GMATE_YP3X00, CDCE_FLAG_NO_UNION)}, 271301771Simp {USB_VPI(USB_VENDOR_MOTOROLA2, USB_PRODUCT_MOTOROLA2_USBLAN, CDCE_FLAG_ZAURUS | CDCE_FLAG_NO_UNION)}, 272301771Simp {USB_VPI(USB_VENDOR_MOTOROLA2, USB_PRODUCT_MOTOROLA2_USBLAN2, CDCE_FLAG_ZAURUS | CDCE_FLAG_NO_UNION)}, 273301771Simp {USB_VPI(USB_VENDOR_NETCHIP, USB_PRODUCT_NETCHIP_ETHERNETGADGET, CDCE_FLAG_NO_UNION)}, 274301771Simp {USB_VPI(USB_VENDOR_PROLIFIC, USB_PRODUCT_PROLIFIC_PL2501, CDCE_FLAG_NO_UNION)}, 275301771Simp {USB_VPI(USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5500, CDCE_FLAG_ZAURUS)}, 276301771Simp {USB_VPI(USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SL5600, CDCE_FLAG_ZAURUS | CDCE_FLAG_NO_UNION)}, 277301771Simp {USB_VPI(USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SLA300, CDCE_FLAG_ZAURUS | CDCE_FLAG_NO_UNION)}, 278301771Simp {USB_VPI(USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SLC700, CDCE_FLAG_ZAURUS | CDCE_FLAG_NO_UNION)}, 279301771Simp {USB_VPI(USB_VENDOR_SHARP, USB_PRODUCT_SHARP_SLC750, CDCE_FLAG_ZAURUS | CDCE_FLAG_NO_UNION)}, 280301771Simp}; 281301771Simp 282301771Simpstatic const STRUCT_USB_DUAL_ID cdce_dual_devs[] = { 283301771Simp {USB_IF_CSI(UICLASS_CDC, UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL, 0)}, 284301771Simp {USB_IF_CSI(UICLASS_CDC, UISUBCLASS_MOBILE_DIRECT_LINE_MODEL, 0)}, 285301771Simp {USB_IF_CSI(UICLASS_CDC, UISUBCLASS_NETWORK_CONTROL_MODEL, 0)}, 286301771Simp}; 287301771Simp 288301771Simp#if CDCE_HAVE_NCM 289301771Simp/*------------------------------------------------------------------------* 290301771Simp * cdce_ncm_init 291301771Simp * 292301771Simp * Return values: 293301771Simp * 0: Success 294301771Simp * Else: Failure 295301771Simp *------------------------------------------------------------------------*/ 296301771Simpstatic uint8_t 297301771Simpcdce_ncm_init(struct cdce_softc *sc) 298301771Simp{ 299301771Simp struct usb_ncm_parameters temp; 300301771Simp struct usb_device_request req; 301301771Simp struct usb_ncm_func_descriptor *ufd; 302301771Simp uint8_t value[8]; 303301771Simp int err; 304301771Simp 305301771Simp ufd = usbd_find_descriptor(sc->sc_ue.ue_udev, NULL, 306301771Simp sc->sc_ifaces_index[1], UDESC_CS_INTERFACE, 0xFF, 307301771Simp UCDC_NCM_FUNC_DESC_SUBTYPE, 0xFF); 308301771Simp 309301771Simp /* verify length of NCM functional descriptor */ 310301771Simp if (ufd != NULL) { 311301771Simp if (ufd->bLength < sizeof(*ufd)) 312301771Simp ufd = NULL; 313301771Simp else 314301771Simp DPRINTFN(1, "Found NCM functional descriptor.\n"); 315301771Simp } 316301771Simp 317301771Simp req.bmRequestType = UT_READ_CLASS_INTERFACE; 318301771Simp req.bRequest = UCDC_NCM_GET_NTB_PARAMETERS; 319301771Simp USETW(req.wValue, 0); 320301771Simp req.wIndex[0] = sc->sc_ifaces_index[1]; 321301771Simp req.wIndex[1] = 0; 322301771Simp USETW(req.wLength, sizeof(temp)); 323301771Simp 324301771Simp err = usbd_do_request_flags(sc->sc_ue.ue_udev, NULL, &req, 325301771Simp &temp, 0, NULL, 1000 /* ms */); 326301771Simp if (err) 327301771Simp return (1); 328301771Simp 329301771Simp /* Read correct set of parameters according to device mode */ 330301771Simp 331301771Simp if (usbd_get_mode(sc->sc_ue.ue_udev) == USB_MODE_HOST) { 332301771Simp sc->sc_ncm.rx_max = UGETDW(temp.dwNtbInMaxSize); 333301771Simp sc->sc_ncm.tx_max = UGETDW(temp.dwNtbOutMaxSize); 334301771Simp sc->sc_ncm.tx_remainder = UGETW(temp.wNdpOutPayloadRemainder); 335301771Simp sc->sc_ncm.tx_modulus = UGETW(temp.wNdpOutDivisor); 336301771Simp sc->sc_ncm.tx_struct_align = UGETW(temp.wNdpOutAlignment); 337301771Simp sc->sc_ncm.tx_nframe = UGETW(temp.wNtbOutMaxDatagrams); 338301771Simp } else { 339301771Simp sc->sc_ncm.rx_max = UGETDW(temp.dwNtbOutMaxSize); 340301771Simp sc->sc_ncm.tx_max = UGETDW(temp.dwNtbInMaxSize); 341301771Simp sc->sc_ncm.tx_remainder = UGETW(temp.wNdpInPayloadRemainder); 342301771Simp sc->sc_ncm.tx_modulus = UGETW(temp.wNdpInDivisor); 343301771Simp sc->sc_ncm.tx_struct_align = UGETW(temp.wNdpInAlignment); 344301771Simp sc->sc_ncm.tx_nframe = UGETW(temp.wNtbOutMaxDatagrams); 345301771Simp } 346301771Simp 347301771Simp /* Verify maximum receive length */ 348301771Simp 349301771Simp if ((sc->sc_ncm.rx_max < 32) || 350301771Simp (sc->sc_ncm.rx_max > CDCE_NCM_RX_MAXLEN)) { 351301771Simp DPRINTFN(1, "Using default maximum receive length\n"); 352301771Simp sc->sc_ncm.rx_max = CDCE_NCM_RX_MAXLEN; 353301771Simp } 354301771Simp 355301771Simp /* Verify maximum transmit length */ 356301771Simp 357301771Simp if ((sc->sc_ncm.tx_max < 32) || 358301771Simp (sc->sc_ncm.tx_max > CDCE_NCM_TX_MAXLEN)) { 359301771Simp DPRINTFN(1, "Using default maximum transmit length\n"); 360301771Simp sc->sc_ncm.tx_max = CDCE_NCM_TX_MAXLEN; 361301771Simp } 362301771Simp 363301771Simp /* 364301771Simp * Verify that the structure alignment is: 365301771Simp * - power of two 366301771Simp * - not greater than the maximum transmit length 367301771Simp * - not less than four bytes 368301771Simp */ 369301771Simp if ((sc->sc_ncm.tx_struct_align < 4) || 370301771Simp (sc->sc_ncm.tx_struct_align != 371301771Simp ((-sc->sc_ncm.tx_struct_align) & sc->sc_ncm.tx_struct_align)) || 372301771Simp (sc->sc_ncm.tx_struct_align >= sc->sc_ncm.tx_max)) { 373301771Simp DPRINTFN(1, "Using default other alignment: 4 bytes\n"); 374301771Simp sc->sc_ncm.tx_struct_align = 4; 375301771Simp } 376301771Simp 377301771Simp /* 378301771Simp * Verify that the payload alignment is: 379301771Simp * - power of two 380301771Simp * - not greater than the maximum transmit length 381301771Simp * - not less than four bytes 382301771Simp */ 383301771Simp if ((sc->sc_ncm.tx_modulus < 4) || 384301771Simp (sc->sc_ncm.tx_modulus != 385301771Simp ((-sc->sc_ncm.tx_modulus) & sc->sc_ncm.tx_modulus)) || 386301771Simp (sc->sc_ncm.tx_modulus >= sc->sc_ncm.tx_max)) { 387301771Simp DPRINTFN(1, "Using default transmit modulus: 4 bytes\n"); 388301771Simp sc->sc_ncm.tx_modulus = 4; 389301771Simp } 390301771Simp 391301771Simp /* Verify that the payload remainder */ 392301771Simp 393301771Simp if ((sc->sc_ncm.tx_remainder >= sc->sc_ncm.tx_modulus)) { 394301771Simp DPRINTFN(1, "Using default transmit remainder: 0 bytes\n"); 395301771Simp sc->sc_ncm.tx_remainder = 0; 396301771Simp } 397301771Simp 398301771Simp /* 399301771Simp * Offset the TX remainder so that IP packet payload starts at 400301771Simp * the tx_modulus. This is not too clear in the specification. 401301771Simp */ 402301771Simp 403301771Simp sc->sc_ncm.tx_remainder = 404301771Simp (sc->sc_ncm.tx_remainder - ETHER_HDR_LEN) & 405301771Simp (sc->sc_ncm.tx_modulus - 1); 406301771Simp 407301771Simp /* Verify max datagrams */ 408301771Simp 409301771Simp if (sc->sc_ncm.tx_nframe == 0 || 410301771Simp sc->sc_ncm.tx_nframe > (CDCE_NCM_SUBFRAMES_MAX - 1)) { 411301771Simp DPRINTFN(1, "Using default max " 412301771Simp "subframes: %u units\n", CDCE_NCM_SUBFRAMES_MAX - 1); 413301771Simp /* need to reserve one entry for zero padding */ 414301771Simp sc->sc_ncm.tx_nframe = (CDCE_NCM_SUBFRAMES_MAX - 1); 415301771Simp } 416301771Simp 417301771Simp /* Additional configuration, will fail in device side mode, which is OK. */ 418301771Simp 419301771Simp req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 420301771Simp req.bRequest = UCDC_NCM_SET_NTB_INPUT_SIZE; 421301771Simp USETW(req.wValue, 0); 422301771Simp req.wIndex[0] = sc->sc_ifaces_index[1]; 423301771Simp req.wIndex[1] = 0; 424301771Simp 425301771Simp if (ufd != NULL && 426301771Simp (ufd->bmNetworkCapabilities & UCDC_NCM_CAP_MAX_DGRAM)) { 427301771Simp USETW(req.wLength, 8); 428301771Simp USETDW(value, sc->sc_ncm.rx_max); 429301771Simp USETW(value + 4, (CDCE_NCM_SUBFRAMES_MAX - 1)); 430301771Simp USETW(value + 6, 0); 431301771Simp } else { 432301771Simp USETW(req.wLength, 4); 433301771Simp USETDW(value, sc->sc_ncm.rx_max); 434301771Simp } 435301771Simp 436301771Simp err = usbd_do_request_flags(sc->sc_ue.ue_udev, NULL, &req, 437301771Simp &value, 0, NULL, 1000 /* ms */); 438301771Simp if (err) { 439301771Simp DPRINTFN(1, "Setting input size " 440301771Simp "to %u failed.\n", sc->sc_ncm.rx_max); 441301771Simp } 442301771Simp 443301771Simp req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 444301771Simp req.bRequest = UCDC_NCM_SET_CRC_MODE; 445301771Simp USETW(req.wValue, 0); /* no CRC */ 446301771Simp req.wIndex[0] = sc->sc_ifaces_index[1]; 447301771Simp req.wIndex[1] = 0; 448301771Simp USETW(req.wLength, 0); 449301771Simp 450301771Simp err = usbd_do_request_flags(sc->sc_ue.ue_udev, NULL, &req, 451301771Simp NULL, 0, NULL, 1000 /* ms */); 452301771Simp if (err) { 453301771Simp DPRINTFN(1, "Setting CRC mode to off failed.\n"); 454301771Simp } 455301771Simp 456301771Simp req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 457301771Simp req.bRequest = UCDC_NCM_SET_NTB_FORMAT; 458301771Simp USETW(req.wValue, 0); /* NTB-16 */ 459301771Simp req.wIndex[0] = sc->sc_ifaces_index[1]; 460301771Simp req.wIndex[1] = 0; 461301771Simp USETW(req.wLength, 0); 462301771Simp 463301771Simp err = usbd_do_request_flags(sc->sc_ue.ue_udev, NULL, &req, 464301771Simp NULL, 0, NULL, 1000 /* ms */); 465301771Simp if (err) { 466301771Simp DPRINTFN(1, "Setting NTB format to 16-bit failed.\n"); 467301771Simp } 468301771Simp 469301771Simp return (0); /* success */ 470301771Simp} 471301771Simp#endif 472301771Simp 473301771Simpstatic int 474301771Simpcdce_probe(device_t dev) 475301771Simp{ 476301771Simp struct usb_attach_arg *uaa = device_get_ivars(dev); 477301771Simp int error; 478301771Simp 479301771Simp error = usbd_lookup_id_by_uaa(cdce_host_devs, sizeof(cdce_host_devs), uaa); 480301771Simp if (error) 481301771Simp error = usbd_lookup_id_by_uaa(cdce_dual_devs, sizeof(cdce_dual_devs), uaa); 482301771Simp return (error); 483301771Simp} 484301771Simp 485301771Simpstatic void 486301771Simpcdce_attach_post(struct usb_ether *ue) 487301771Simp{ 488301771Simp /* no-op */ 489301771Simp return; 490301771Simp} 491301771Simp 492301771Simpstatic int 493301771Simpcdce_attach(device_t dev) 494301771Simp{ 495301771Simp struct cdce_softc *sc = device_get_softc(dev); 496301771Simp struct usb_ether *ue = &sc->sc_ue; 497301771Simp struct usb_attach_arg *uaa = device_get_ivars(dev); 498301771Simp struct usb_interface *iface; 499301771Simp const struct usb_cdc_union_descriptor *ud; 500301771Simp const struct usb_interface_descriptor *id; 501301771Simp const struct usb_cdc_ethernet_descriptor *ued; 502301771Simp const struct usb_config *pcfg; 503301771Simp uint32_t seed; 504301771Simp int error; 505301771Simp uint8_t i; 506301771Simp uint8_t data_iface_no; 507301771Simp char eaddr_str[5 * ETHER_ADDR_LEN]; /* approx */ 508301771Simp 509301771Simp sc->sc_flags = USB_GET_DRIVER_INFO(uaa); 510301771Simp sc->sc_ue.ue_udev = uaa->device; 511301771Simp 512301771Simp device_set_usb_desc(dev); 513301771Simp 514301771Simp mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 515301771Simp 516301771Simp ud = usbd_find_descriptor 517301771Simp (uaa->device, NULL, uaa->info.bIfaceIndex, 518301771Simp UDESC_CS_INTERFACE, 0xFF, UDESCSUB_CDC_UNION, 0xFF); 519301771Simp 520301771Simp if ((ud == NULL) || (ud->bLength < sizeof(*ud)) || 521301771Simp (sc->sc_flags & CDCE_FLAG_NO_UNION)) { 522301771Simp DPRINTFN(1, "No union descriptor!\n"); 523301771Simp sc->sc_ifaces_index[0] = uaa->info.bIfaceIndex; 524301771Simp sc->sc_ifaces_index[1] = uaa->info.bIfaceIndex; 525301771Simp goto alloc_transfers; 526301771Simp } 527301771Simp data_iface_no = ud->bSlaveInterface[0]; 528301771Simp 529301771Simp for (i = 0;; i++) { 530301771Simp 531301771Simp iface = usbd_get_iface(uaa->device, i); 532301771Simp 533301771Simp if (iface) { 534301771Simp 535301771Simp id = usbd_get_interface_descriptor(iface); 536301771Simp 537301771Simp if (id && (id->bInterfaceNumber == data_iface_no)) { 538301771Simp sc->sc_ifaces_index[0] = i; 539301771Simp sc->sc_ifaces_index[1] = uaa->info.bIfaceIndex; 540301771Simp usbd_set_parent_iface(uaa->device, i, uaa->info.bIfaceIndex); 541301771Simp break; 542301771Simp } 543301771Simp } else { 544301771Simp device_printf(dev, "no data interface found\n"); 545301771Simp goto detach; 546301771Simp } 547301771Simp } 548301771Simp 549301771Simp /* 550301771Simp * <quote> 551301771Simp * 552301771Simp * The Data Class interface of a networking device shall have 553301771Simp * a minimum of two interface settings. The first setting 554301771Simp * (the default interface setting) includes no endpoints and 555301771Simp * therefore no networking traffic is exchanged whenever the 556301771Simp * default interface setting is selected. One or more 557301771Simp * additional interface settings are used for normal 558301771Simp * operation, and therefore each includes a pair of endpoints 559301771Simp * (one IN, and one OUT) to exchange network traffic. Select 560301771Simp * an alternate interface setting to initialize the network 561301771Simp * aspects of the device and to enable the exchange of 562301771Simp * network traffic. 563301771Simp * 564301771Simp * </quote> 565301771Simp * 566301771Simp * Some devices, most notably cable modems, include interface 567301771Simp * settings that have no IN or OUT endpoint, therefore loop 568301771Simp * through the list of all available interface settings 569301771Simp * looking for one with both IN and OUT endpoints. 570301771Simp */ 571301771Simp 572301771Simpalloc_transfers: 573301771Simp 574301771Simp pcfg = cdce_config; /* Default Configuration */ 575301771Simp 576301771Simp for (i = 0; i != 32; i++) { 577301771Simp 578301771Simp error = usbd_set_alt_interface_index(uaa->device, 579301771Simp sc->sc_ifaces_index[0], i); 580301771Simp if (error) 581301771Simp break; 582301771Simp#if CDCE_HAVE_NCM 583301771Simp if ((i == 0) && (cdce_ncm_init(sc) == 0)) 584301771Simp pcfg = cdce_ncm_config; 585301771Simp#endif 586301771Simp error = usbd_transfer_setup(uaa->device, 587301771Simp sc->sc_ifaces_index, sc->sc_xfer, 588301771Simp pcfg, CDCE_N_TRANSFER, sc, &sc->sc_mtx); 589301771Simp 590301771Simp if (error == 0) 591301771Simp break; 592301771Simp } 593301771Simp 594301771Simp if (error || (i == 32)) { 595301771Simp device_printf(dev, "No valid alternate " 596301771Simp "setting found\n"); 597301771Simp goto detach; 598301771Simp } 599301771Simp 600301771Simp ued = usbd_find_descriptor 601301771Simp (uaa->device, NULL, uaa->info.bIfaceIndex, 602301771Simp UDESC_CS_INTERFACE, 0xFF, UDESCSUB_CDC_ENF, 0xFF); 603301771Simp 604301771Simp if ((ued == NULL) || (ued->bLength < sizeof(*ued))) { 605301771Simp error = USB_ERR_INVAL; 606301771Simp } else { 607301771Simp error = usbd_req_get_string_any(uaa->device, NULL, 608301771Simp eaddr_str, sizeof(eaddr_str), ued->iMacAddress); 609301771Simp } 610301771Simp 611301771Simp if (error) { 612301771Simp 613301771Simp /* fake MAC address */ 614301771Simp 615301771Simp device_printf(dev, "faking MAC address\n"); 616301771Simp seed = ticks; 617301771Simp sc->sc_ue.ue_eaddr[0] = 0x2a; 618301771Simp memcpy(&sc->sc_ue.ue_eaddr[1], &seed, sizeof(uint32_t)); 619301771Simp sc->sc_ue.ue_eaddr[5] = device_get_unit(dev); 620301771Simp 621301771Simp } else { 622301771Simp 623301771Simp memset(sc->sc_ue.ue_eaddr, 0, sizeof(sc->sc_ue.ue_eaddr)); 624301771Simp 625301771Simp for (i = 0; i != (ETHER_ADDR_LEN * 2); i++) { 626301771Simp 627301771Simp char c = eaddr_str[i]; 628301771Simp 629301771Simp if ('0' <= c && c <= '9') 630301771Simp c -= '0'; 631301771Simp else if (c != 0) 632301771Simp c -= 'A' - 10; 633301771Simp else 634301771Simp break; 635301771Simp 636301771Simp c &= 0xf; 637301771Simp 638301771Simp if ((i & 1) == 0) 639301771Simp c <<= 4; 640301771Simp sc->sc_ue.ue_eaddr[i / 2] |= c; 641301771Simp } 642301771Simp 643301771Simp if (uaa->usb_mode == USB_MODE_DEVICE) { 644301771Simp /* 645301771Simp * Do not use the same MAC address like the peer ! 646301771Simp */ 647301771Simp sc->sc_ue.ue_eaddr[5] ^= 0xFF; 648301771Simp } 649301771Simp } 650301771Simp 651301771Simp ue->ue_sc = sc; 652301771Simp ue->ue_dev = dev; 653301771Simp ue->ue_udev = uaa->device; 654301771Simp ue->ue_mtx = &sc->sc_mtx; 655301771Simp ue->ue_methods = &cdce_ue_methods; 656301771Simp 657301771Simp error = uether_ifattach(ue); 658301771Simp if (error) { 659301771Simp device_printf(dev, "could not attach interface\n"); 660301771Simp goto detach; 661301771Simp } 662301771Simp return (0); /* success */ 663301771Simp 664301771Simpdetach: 665301771Simp cdce_detach(dev); 666301771Simp return (ENXIO); /* failure */ 667301771Simp} 668301771Simp 669301771Simpstatic int 670301771Simpcdce_detach(device_t dev) 671301771Simp{ 672301771Simp struct cdce_softc *sc = device_get_softc(dev); 673301771Simp struct usb_ether *ue = &sc->sc_ue; 674301771Simp 675301771Simp /* stop all USB transfers first */ 676301771Simp usbd_transfer_unsetup(sc->sc_xfer, CDCE_N_TRANSFER); 677301771Simp uether_ifdetach(ue); 678301771Simp mtx_destroy(&sc->sc_mtx); 679301771Simp 680301771Simp return (0); 681301771Simp} 682301771Simp 683301771Simpstatic void 684301771Simpcdce_start(struct usb_ether *ue) 685301771Simp{ 686301771Simp struct cdce_softc *sc = uether_getsc(ue); 687301771Simp 688301771Simp /* 689301771Simp * Start the USB transfers, if not already started: 690301771Simp */ 691301771Simp usbd_transfer_start(sc->sc_xfer[CDCE_BULK_TX]); 692301771Simp usbd_transfer_start(sc->sc_xfer[CDCE_BULK_RX]); 693301771Simp} 694301771Simp 695301771Simpstatic void 696301771Simpcdce_free_queue(struct mbuf **ppm, uint8_t n) 697301771Simp{ 698301771Simp uint8_t x; 699301771Simp for (x = 0; x != n; x++) { 700301771Simp if (ppm[x] != NULL) { 701301771Simp m_freem(ppm[x]); 702301771Simp ppm[x] = NULL; 703301771Simp } 704301771Simp } 705301771Simp} 706301771Simp 707301771Simpstatic void 708301771Simpcdce_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) 709301771Simp{ 710301771Simp struct cdce_softc *sc = usbd_xfer_softc(xfer); 711301771Simp struct ifnet *ifp = uether_getifp(&sc->sc_ue); 712301771Simp struct mbuf *m; 713301771Simp struct mbuf *mt; 714301771Simp uint32_t crc; 715301771Simp uint8_t x; 716301771Simp int actlen, aframes; 717301771Simp 718301771Simp usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL); 719301771Simp 720301771Simp DPRINTFN(1, "\n"); 721301771Simp 722301771Simp switch (USB_GET_STATE(xfer)) { 723301771Simp case USB_ST_TRANSFERRED: 724301771Simp DPRINTFN(11, "transfer complete: %u bytes in %u frames\n", 725301771Simp actlen, aframes); 726301771Simp 727301771Simp ifp->if_opackets++; 728301771Simp 729301771Simp /* free all previous TX buffers */ 730301771Simp cdce_free_queue(sc->sc_tx_buf, CDCE_FRAMES_MAX); 731301771Simp 732301771Simp /* FALLTHROUGH */ 733301771Simp case USB_ST_SETUP: 734301771Simptr_setup: 735301771Simp for (x = 0; x != CDCE_FRAMES_MAX; x++) { 736301771Simp 737301771Simp IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 738301771Simp 739301771Simp if (m == NULL) 740301771Simp break; 741301771Simp 742301771Simp if (sc->sc_flags & CDCE_FLAG_ZAURUS) { 743301771Simp /* 744301771Simp * Zaurus wants a 32-bit CRC appended 745301771Simp * to every frame 746301771Simp */ 747301771Simp 748301771Simp crc = cdce_m_crc32(m, 0, m->m_pkthdr.len); 749301771Simp crc = htole32(crc); 750301771Simp 751301771Simp if (!m_append(m, 4, (void *)&crc)) { 752301771Simp m_freem(m); 753301771Simp ifp->if_oerrors++; 754301771Simp continue; 755301771Simp } 756301771Simp } 757301771Simp if (m->m_len != m->m_pkthdr.len) { 758301771Simp mt = m_defrag(m, M_NOWAIT); 759301771Simp if (mt == NULL) { 760301771Simp m_freem(m); 761301771Simp ifp->if_oerrors++; 762301771Simp continue; 763301771Simp } 764301771Simp m = mt; 765301771Simp } 766301771Simp if (m->m_pkthdr.len > MCLBYTES) { 767301771Simp m->m_pkthdr.len = MCLBYTES; 768301771Simp } 769301771Simp sc->sc_tx_buf[x] = m; 770301771Simp usbd_xfer_set_frame_data(xfer, x, m->m_data, m->m_len); 771301771Simp 772301771Simp /* 773301771Simp * If there's a BPF listener, bounce a copy of 774301771Simp * this frame to him: 775301771Simp */ 776301771Simp BPF_MTAP(ifp, m); 777301771Simp } 778301771Simp if (x != 0) { 779301771Simp usbd_xfer_set_frames(xfer, x); 780301771Simp 781301771Simp usbd_transfer_submit(xfer); 782301771Simp } 783301771Simp break; 784301771Simp 785301771Simp default: /* Error */ 786301771Simp DPRINTFN(11, "transfer error, %s\n", 787301771Simp usbd_errstr(error)); 788301771Simp 789301771Simp /* free all previous TX buffers */ 790301771Simp cdce_free_queue(sc->sc_tx_buf, CDCE_FRAMES_MAX); 791301771Simp 792301771Simp /* count output errors */ 793301771Simp ifp->if_oerrors++; 794301771Simp 795301771Simp if (error != USB_ERR_CANCELLED) { 796301771Simp /* try to clear stall first */ 797301771Simp usbd_xfer_set_stall(xfer); 798301771Simp goto tr_setup; 799301771Simp } 800301771Simp break; 801301771Simp } 802301771Simp} 803301771Simp 804301771Simpstatic int32_t 805301771Simpcdce_m_crc32_cb(void *arg, void *src, uint32_t count) 806301771Simp{ 807301771Simp uint32_t *p_crc = arg; 808301771Simp 809301771Simp *p_crc = crc32_raw(src, count, *p_crc); 810301771Simp return (0); 811301771Simp} 812301771Simp 813301771Simpstatic uint32_t 814301771Simpcdce_m_crc32(struct mbuf *m, uint32_t src_offset, uint32_t src_len) 815301771Simp{ 816301771Simp uint32_t crc = 0xFFFFFFFF; 817301771Simp int error; 818301771Simp 819301771Simp error = m_apply(m, src_offset, src_len, cdce_m_crc32_cb, &crc); 820301771Simp return (crc ^ 0xFFFFFFFF); 821301771Simp} 822301771Simp 823301771Simpstatic void 824301771Simpcdce_init(struct usb_ether *ue) 825301771Simp{ 826301771Simp struct cdce_softc *sc = uether_getsc(ue); 827301771Simp struct ifnet *ifp = uether_getifp(ue); 828301771Simp 829301771Simp CDCE_LOCK_ASSERT(sc, MA_OWNED); 830301771Simp 831301771Simp ifp->if_drv_flags |= IFF_DRV_RUNNING; 832301771Simp 833301771Simp /* start interrupt transfer */ 834301771Simp usbd_transfer_start(sc->sc_xfer[CDCE_INTR_RX]); 835301771Simp usbd_transfer_start(sc->sc_xfer[CDCE_INTR_TX]); 836301771Simp 837301771Simp /* stall data write direction, which depends on USB mode */ 838301771Simp usbd_xfer_set_stall(sc->sc_xfer[CDCE_BULK_TX]); 839301771Simp 840301771Simp /* start data transfers */ 841301771Simp cdce_start(ue); 842301771Simp} 843301771Simp 844301771Simpstatic void 845301771Simpcdce_stop(struct usb_ether *ue) 846301771Simp{ 847301771Simp struct cdce_softc *sc = uether_getsc(ue); 848301771Simp struct ifnet *ifp = uether_getifp(ue); 849301771Simp 850301771Simp CDCE_LOCK_ASSERT(sc, MA_OWNED); 851301771Simp 852301771Simp ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 853301771Simp 854301771Simp /* 855301771Simp * stop all the transfers, if not already stopped: 856301771Simp */ 857301771Simp usbd_transfer_stop(sc->sc_xfer[CDCE_BULK_RX]); 858301771Simp usbd_transfer_stop(sc->sc_xfer[CDCE_BULK_TX]); 859301771Simp usbd_transfer_stop(sc->sc_xfer[CDCE_INTR_RX]); 860301771Simp usbd_transfer_stop(sc->sc_xfer[CDCE_INTR_TX]); 861301771Simp} 862301771Simp 863301771Simpstatic void 864301771Simpcdce_setmulti(struct usb_ether *ue) 865301771Simp{ 866301771Simp /* no-op */ 867301771Simp return; 868301771Simp} 869301771Simp 870301771Simpstatic void 871301771Simpcdce_setpromisc(struct usb_ether *ue) 872301771Simp{ 873301771Simp /* no-op */ 874301771Simp return; 875301771Simp} 876301771Simp 877301771Simpstatic int 878301771Simpcdce_suspend(device_t dev) 879301771Simp{ 880301771Simp device_printf(dev, "Suspending\n"); 881301771Simp return (0); 882301771Simp} 883301771Simp 884301771Simpstatic int 885301771Simpcdce_resume(device_t dev) 886301771Simp{ 887301771Simp device_printf(dev, "Resuming\n"); 888301771Simp return (0); 889301771Simp} 890301771Simp 891301771Simpstatic void 892301771Simpcdce_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) 893301771Simp{ 894301771Simp struct cdce_softc *sc = usbd_xfer_softc(xfer); 895301771Simp struct mbuf *m; 896301771Simp uint8_t x; 897301771Simp int actlen; 898301771Simp int aframes; 899301771Simp int len; 900301771Simp 901301771Simp usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL); 902301771Simp 903301771Simp switch (USB_GET_STATE(xfer)) { 904301771Simp case USB_ST_TRANSFERRED: 905301771Simp 906301771Simp DPRINTF("received %u bytes in %u frames\n", actlen, aframes); 907301771Simp 908301771Simp for (x = 0; x != aframes; x++) { 909301771Simp 910301771Simp m = sc->sc_rx_buf[x]; 911301771Simp sc->sc_rx_buf[x] = NULL; 912301771Simp len = usbd_xfer_frame_len(xfer, x); 913301771Simp 914301771Simp /* Strip off CRC added by Zaurus, if any */ 915301771Simp if ((sc->sc_flags & CDCE_FLAG_ZAURUS) && len >= 14) 916301771Simp len -= 4; 917301771Simp 918301771Simp if (len < (int)sizeof(struct ether_header)) { 919301771Simp m_freem(m); 920301771Simp continue; 921301771Simp } 922301771Simp /* queue up mbuf */ 923301771Simp uether_rxmbuf(&sc->sc_ue, m, len); 924301771Simp } 925301771Simp 926301771Simp /* FALLTHROUGH */ 927301771Simp case USB_ST_SETUP: 928301771Simp /* 929301771Simp * TODO: Implement support for multi frame transfers, 930301771Simp * when the USB hardware supports it. 931301771Simp */ 932301771Simp for (x = 0; x != 1; x++) { 933301771Simp if (sc->sc_rx_buf[x] == NULL) { 934301771Simp m = uether_newbuf(); 935301771Simp if (m == NULL) 936301771Simp goto tr_stall; 937301771Simp sc->sc_rx_buf[x] = m; 938301771Simp } else { 939301771Simp m = sc->sc_rx_buf[x]; 940301771Simp } 941301771Simp 942301771Simp usbd_xfer_set_frame_data(xfer, x, m->m_data, m->m_len); 943301771Simp } 944301771Simp /* set number of frames and start hardware */ 945301771Simp usbd_xfer_set_frames(xfer, x); 946301771Simp usbd_transfer_submit(xfer); 947301771Simp /* flush any received frames */ 948301771Simp uether_rxflush(&sc->sc_ue); 949301771Simp break; 950301771Simp 951301771Simp default: /* Error */ 952301771Simp DPRINTF("error = %s\n", 953301771Simp usbd_errstr(error)); 954301771Simp 955301771Simp if (error != USB_ERR_CANCELLED) { 956301771Simptr_stall: 957301771Simp /* try to clear stall first */ 958301771Simp usbd_xfer_set_stall(xfer); 959301771Simp usbd_xfer_set_frames(xfer, 0); 960301771Simp usbd_transfer_submit(xfer); 961301771Simp break; 962301771Simp } 963301771Simp 964301771Simp /* need to free the RX-mbufs when we are cancelled */ 965301771Simp cdce_free_queue(sc->sc_rx_buf, CDCE_FRAMES_MAX); 966301771Simp break; 967301771Simp } 968301771Simp} 969301771Simp 970301771Simpstatic void 971301771Simpcdce_intr_read_callback(struct usb_xfer *xfer, usb_error_t error) 972301771Simp{ 973301771Simp int actlen; 974301771Simp 975301771Simp usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 976301771Simp 977301771Simp switch (USB_GET_STATE(xfer)) { 978301771Simp case USB_ST_TRANSFERRED: 979301771Simp 980301771Simp DPRINTF("Received %d bytes\n", actlen); 981301771Simp 982301771Simp /* TODO: decode some indications */ 983301771Simp 984301771Simp /* FALLTHROUGH */ 985301771Simp case USB_ST_SETUP: 986301771Simptr_setup: 987301771Simp usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 988301771Simp usbd_transfer_submit(xfer); 989301771Simp break; 990301771Simp 991301771Simp default: /* Error */ 992301771Simp if (error != USB_ERR_CANCELLED) { 993301771Simp /* start clear stall */ 994301771Simp usbd_xfer_set_stall(xfer); 995301771Simp goto tr_setup; 996301771Simp } 997301771Simp break; 998301771Simp } 999301771Simp} 1000301771Simp 1001301771Simpstatic void 1002301771Simpcdce_intr_write_callback(struct usb_xfer *xfer, usb_error_t error) 1003301771Simp{ 1004301771Simp int actlen; 1005301771Simp 1006301771Simp usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 1007301771Simp 1008301771Simp switch (USB_GET_STATE(xfer)) { 1009301771Simp case USB_ST_TRANSFERRED: 1010301771Simp 1011301771Simp DPRINTF("Transferred %d bytes\n", actlen); 1012301771Simp 1013301771Simp /* FALLTHROUGH */ 1014301771Simp case USB_ST_SETUP: 1015301771Simptr_setup: 1016301771Simp#if 0 1017301771Simp usbd_xfer_set_frame_len(xfer, 0, XXX); 1018301771Simp usbd_transfer_submit(xfer); 1019301771Simp#endif 1020301771Simp break; 1021301771Simp 1022301771Simp default: /* Error */ 1023301771Simp if (error != USB_ERR_CANCELLED) { 1024301771Simp /* start clear stall */ 1025301771Simp usbd_xfer_set_stall(xfer); 1026301771Simp goto tr_setup; 1027301771Simp } 1028301771Simp break; 1029301771Simp } 1030301771Simp} 1031301771Simp 1032301771Simpstatic int 1033301771Simpcdce_handle_request(device_t dev, 1034301771Simp const void *req, void **pptr, uint16_t *plen, 1035301771Simp uint16_t offset, uint8_t *pstate) 1036301771Simp{ 1037301771Simp return (ENXIO); /* use builtin handler */ 1038301771Simp} 1039301771Simp 1040301771Simp#if CDCE_HAVE_NCM 1041301771Simpstatic void 1042301771Simpcdce_ncm_tx_zero(struct usb_page_cache *pc, 1043301771Simp uint32_t start, uint32_t end) 1044301771Simp{ 1045301771Simp if (start >= CDCE_NCM_TX_MAXLEN) 1046301771Simp return; 1047301771Simp if (end > CDCE_NCM_TX_MAXLEN) 1048301771Simp end = CDCE_NCM_TX_MAXLEN; 1049301771Simp 1050301771Simp usbd_frame_zero(pc, start, end - start); 1051301771Simp} 1052301771Simp 1053301771Simpstatic uint8_t 1054301771Simpcdce_ncm_fill_tx_frames(struct usb_xfer *xfer, uint8_t index) 1055301771Simp{ 1056301771Simp struct cdce_softc *sc = usbd_xfer_softc(xfer); 1057301771Simp struct ifnet *ifp = uether_getifp(&sc->sc_ue); 1058301771Simp struct usb_page_cache *pc = usbd_xfer_get_frame(xfer, index); 1059301771Simp struct mbuf *m; 1060301771Simp uint32_t rem; 1061301771Simp uint32_t offset; 1062301771Simp uint32_t last_offset; 1063301771Simp uint16_t n; 1064301771Simp uint8_t retval; 1065301771Simp 1066301771Simp usbd_xfer_set_frame_offset(xfer, index * CDCE_NCM_TX_MAXLEN, index); 1067301771Simp 1068301771Simp offset = sizeof(sc->sc_ncm.hdr) + 1069301771Simp sizeof(sc->sc_ncm.dpt) + sizeof(sc->sc_ncm.dp); 1070301771Simp 1071301771Simp /* Store last valid offset before alignment */ 1072301771Simp last_offset = offset; 1073301771Simp 1074301771Simp /* Align offset */ 1075301771Simp offset = CDCE_NCM_ALIGN(sc->sc_ncm.tx_remainder, 1076301771Simp offset, sc->sc_ncm.tx_modulus); 1077301771Simp 1078301771Simp /* Zero pad */ 1079301771Simp cdce_ncm_tx_zero(pc, last_offset, offset); 1080301771Simp 1081301771Simp /* buffer full */ 1082301771Simp retval = 2; 1083301771Simp 1084301771Simp for (n = 0; n != sc->sc_ncm.tx_nframe; n++) { 1085301771Simp 1086301771Simp /* check if end of transmit buffer is reached */ 1087301771Simp 1088301771Simp if (offset >= sc->sc_ncm.tx_max) 1089301771Simp break; 1090301771Simp 1091301771Simp /* compute maximum buffer size */ 1092301771Simp 1093301771Simp rem = sc->sc_ncm.tx_max - offset; 1094301771Simp 1095301771Simp IFQ_DRV_DEQUEUE(&(ifp->if_snd), m); 1096301771Simp 1097301771Simp if (m == NULL) { 1098301771Simp /* buffer not full */ 1099301771Simp retval = 1; 1100301771Simp break; 1101301771Simp } 1102301771Simp 1103301771Simp if (m->m_pkthdr.len > (int)rem) { 1104301771Simp if (n == 0) { 1105301771Simp /* The frame won't fit in our buffer */ 1106301771Simp DPRINTFN(1, "Frame too big to be transmitted!\n"); 1107301771Simp m_freem(m); 1108301771Simp ifp->if_oerrors++; 1109301771Simp n--; 1110301771Simp continue; 1111301771Simp } 1112301771Simp /* Wait till next buffer becomes ready */ 1113301771Simp IFQ_DRV_PREPEND(&(ifp->if_snd), m); 1114301771Simp break; 1115301771Simp } 1116301771Simp usbd_m_copy_in(pc, offset, m, 0, m->m_pkthdr.len); 1117301771Simp 1118301771Simp USETW(sc->sc_ncm.dp[n].wFrameLength, m->m_pkthdr.len); 1119301771Simp USETW(sc->sc_ncm.dp[n].wFrameIndex, offset); 1120301771Simp 1121301771Simp /* Update offset */ 1122301771Simp offset += m->m_pkthdr.len; 1123301771Simp 1124301771Simp /* Store last valid offset before alignment */ 1125301771Simp last_offset = offset; 1126301771Simp 1127301771Simp /* Align offset */ 1128301771Simp offset = CDCE_NCM_ALIGN(sc->sc_ncm.tx_remainder, 1129301771Simp offset, sc->sc_ncm.tx_modulus); 1130301771Simp 1131301771Simp /* Zero pad */ 1132301771Simp cdce_ncm_tx_zero(pc, last_offset, offset); 1133301771Simp 1134301771Simp /* 1135301771Simp * If there's a BPF listener, bounce a copy 1136301771Simp * of this frame to him: 1137301771Simp */ 1138301771Simp BPF_MTAP(ifp, m); 1139301771Simp 1140301771Simp /* Free mbuf */ 1141301771Simp 1142301771Simp m_freem(m); 1143301771Simp 1144301771Simp /* Pre-increment interface counter */ 1145301771Simp 1146301771Simp ifp->if_opackets++; 1147301771Simp } 1148301771Simp 1149301771Simp if (n == 0) 1150301771Simp return (0); 1151301771Simp 1152301771Simp rem = (sizeof(sc->sc_ncm.dpt) + (4 * n) + 4); 1153 1154 USETW(sc->sc_ncm.dpt.wLength, rem); 1155 1156 /* zero the rest of the data pointer entries */ 1157 for (; n != CDCE_NCM_SUBFRAMES_MAX; n++) { 1158 USETW(sc->sc_ncm.dp[n].wFrameLength, 0); 1159 USETW(sc->sc_ncm.dp[n].wFrameIndex, 0); 1160 } 1161 1162 offset = last_offset; 1163 1164 /* Align offset */ 1165 offset = CDCE_NCM_ALIGN(0, offset, CDCE_NCM_TX_MINLEN); 1166 1167 /* Optimise, save bandwidth and force short termination */ 1168 if (offset >= sc->sc_ncm.tx_max) 1169 offset = sc->sc_ncm.tx_max; 1170 else 1171 offset ++; 1172 1173 /* Zero pad */ 1174 cdce_ncm_tx_zero(pc, last_offset, offset); 1175 1176 /* set frame length */ 1177 usbd_xfer_set_frame_len(xfer, index, offset); 1178 1179 /* Fill out 16-bit header */ 1180 sc->sc_ncm.hdr.dwSignature[0] = 'N'; 1181 sc->sc_ncm.hdr.dwSignature[1] = 'C'; 1182 sc->sc_ncm.hdr.dwSignature[2] = 'M'; 1183 sc->sc_ncm.hdr.dwSignature[3] = 'H'; 1184 USETW(sc->sc_ncm.hdr.wHeaderLength, sizeof(sc->sc_ncm.hdr)); 1185 USETW(sc->sc_ncm.hdr.wBlockLength, offset); 1186 USETW(sc->sc_ncm.hdr.wSequence, sc->sc_ncm.tx_seq); 1187 USETW(sc->sc_ncm.hdr.wDptIndex, sizeof(sc->sc_ncm.hdr)); 1188 1189 sc->sc_ncm.tx_seq++; 1190 1191 /* Fill out 16-bit frame table header */ 1192 sc->sc_ncm.dpt.dwSignature[0] = 'N'; 1193 sc->sc_ncm.dpt.dwSignature[1] = 'C'; 1194 sc->sc_ncm.dpt.dwSignature[2] = 'M'; 1195 sc->sc_ncm.dpt.dwSignature[3] = '0'; 1196 USETW(sc->sc_ncm.dpt.wNextNdpIndex, 0); /* reserved */ 1197 1198 usbd_copy_in(pc, 0, &(sc->sc_ncm.hdr), sizeof(sc->sc_ncm.hdr)); 1199 usbd_copy_in(pc, sizeof(sc->sc_ncm.hdr), &(sc->sc_ncm.dpt), 1200 sizeof(sc->sc_ncm.dpt)); 1201 usbd_copy_in(pc, sizeof(sc->sc_ncm.hdr) + sizeof(sc->sc_ncm.dpt), 1202 &(sc->sc_ncm.dp), sizeof(sc->sc_ncm.dp)); 1203 return (retval); 1204} 1205 1206static void 1207cdce_ncm_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) 1208{ 1209 struct cdce_softc *sc = usbd_xfer_softc(xfer); 1210 struct ifnet *ifp = uether_getifp(&sc->sc_ue); 1211 uint16_t x; 1212 uint8_t temp; 1213 int actlen; 1214 int aframes; 1215 1216 switch (USB_GET_STATE(xfer)) { 1217 case USB_ST_TRANSFERRED: 1218 1219 usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL); 1220 1221 DPRINTFN(10, "transfer complete: " 1222 "%u bytes in %u frames\n", actlen, aframes); 1223 1224 case USB_ST_SETUP: 1225 for (x = 0; x != CDCE_NCM_TX_FRAMES_MAX; x++) { 1226 temp = cdce_ncm_fill_tx_frames(xfer, x); 1227 if (temp == 0) 1228 break; 1229 if (temp == 1) { 1230 x++; 1231 break; 1232 } 1233 } 1234 1235 if (x != 0) { 1236#ifdef USB_DEBUG 1237 usbd_xfer_set_interval(xfer, cdce_tx_interval); 1238#endif 1239 usbd_xfer_set_frames(xfer, x); 1240 usbd_transfer_submit(xfer); 1241 } 1242 break; 1243 1244 default: /* Error */ 1245 DPRINTFN(10, "Transfer error: %s\n", 1246 usbd_errstr(error)); 1247 1248 /* update error counter */ 1249 ifp->if_oerrors += 1; 1250 1251 if (error != USB_ERR_CANCELLED) { 1252 /* try to clear stall first */ 1253 usbd_xfer_set_stall(xfer); 1254 usbd_xfer_set_frames(xfer, 0); 1255 usbd_transfer_submit(xfer); 1256 } 1257 break; 1258 } 1259} 1260 1261static void 1262cdce_ncm_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) 1263{ 1264 struct cdce_softc *sc = usbd_xfer_softc(xfer); 1265 struct usb_page_cache *pc = usbd_xfer_get_frame(xfer, 0); 1266 struct ifnet *ifp = uether_getifp(&sc->sc_ue); 1267 struct mbuf *m; 1268 int sumdata; 1269 int sumlen; 1270 int actlen; 1271 int aframes; 1272 int temp; 1273 int nframes; 1274 int x; 1275 int offset; 1276 1277 switch (USB_GET_STATE(xfer)) { 1278 case USB_ST_TRANSFERRED: 1279 1280 usbd_xfer_status(xfer, &actlen, &sumlen, &aframes, NULL); 1281 1282 DPRINTFN(1, "received %u bytes in %u frames\n", 1283 actlen, aframes); 1284 1285 if (actlen < (int)(sizeof(sc->sc_ncm.hdr) + 1286 sizeof(sc->sc_ncm.dpt))) { 1287 DPRINTFN(1, "frame too short\n"); 1288 goto tr_setup; 1289 } 1290 usbd_copy_out(pc, 0, &(sc->sc_ncm.hdr), 1291 sizeof(sc->sc_ncm.hdr)); 1292 1293 if ((sc->sc_ncm.hdr.dwSignature[0] != 'N') || 1294 (sc->sc_ncm.hdr.dwSignature[1] != 'C') || 1295 (sc->sc_ncm.hdr.dwSignature[2] != 'M') || 1296 (sc->sc_ncm.hdr.dwSignature[3] != 'H')) { 1297 DPRINTFN(1, "invalid HDR signature: " 1298 "0x%02x:0x%02x:0x%02x:0x%02x\n", 1299 sc->sc_ncm.hdr.dwSignature[0], 1300 sc->sc_ncm.hdr.dwSignature[1], 1301 sc->sc_ncm.hdr.dwSignature[2], 1302 sc->sc_ncm.hdr.dwSignature[3]); 1303 goto tr_stall; 1304 } 1305 temp = UGETW(sc->sc_ncm.hdr.wBlockLength); 1306 if (temp > sumlen) { 1307 DPRINTFN(1, "unsupported block length %u/%u\n", 1308 temp, sumlen); 1309 goto tr_stall; 1310 } 1311 temp = UGETW(sc->sc_ncm.hdr.wDptIndex); 1312 if ((int)(temp + sizeof(sc->sc_ncm.dpt)) > actlen) { 1313 DPRINTFN(1, "invalid DPT index: 0x%04x\n", temp); 1314 goto tr_stall; 1315 } 1316 usbd_copy_out(pc, temp, &(sc->sc_ncm.dpt), 1317 sizeof(sc->sc_ncm.dpt)); 1318 1319 if ((sc->sc_ncm.dpt.dwSignature[0] != 'N') || 1320 (sc->sc_ncm.dpt.dwSignature[1] != 'C') || 1321 (sc->sc_ncm.dpt.dwSignature[2] != 'M') || 1322 (sc->sc_ncm.dpt.dwSignature[3] != '0')) { 1323 DPRINTFN(1, "invalid DPT signature" 1324 "0x%02x:0x%02x:0x%02x:0x%02x\n", 1325 sc->sc_ncm.dpt.dwSignature[0], 1326 sc->sc_ncm.dpt.dwSignature[1], 1327 sc->sc_ncm.dpt.dwSignature[2], 1328 sc->sc_ncm.dpt.dwSignature[3]); 1329 goto tr_stall; 1330 } 1331 nframes = UGETW(sc->sc_ncm.dpt.wLength) / 4; 1332 1333 /* Subtract size of header and last zero padded entry */ 1334 if (nframes >= (2 + 1)) 1335 nframes -= (2 + 1); 1336 else 1337 nframes = 0; 1338 1339 DPRINTFN(1, "nframes = %u\n", nframes); 1340 1341 temp += sizeof(sc->sc_ncm.dpt); 1342 1343 if ((temp + (4 * nframes)) > actlen) 1344 goto tr_stall; 1345 1346 if (nframes > CDCE_NCM_SUBFRAMES_MAX) { 1347 DPRINTFN(1, "Truncating number of frames from %u to %u\n", 1348 nframes, CDCE_NCM_SUBFRAMES_MAX); 1349 nframes = CDCE_NCM_SUBFRAMES_MAX; 1350 } 1351 usbd_copy_out(pc, temp, &(sc->sc_ncm.dp), (4 * nframes)); 1352 1353 sumdata = 0; 1354 1355 for (x = 0; x != nframes; x++) { 1356 1357 offset = UGETW(sc->sc_ncm.dp[x].wFrameIndex); 1358 temp = UGETW(sc->sc_ncm.dp[x].wFrameLength); 1359 1360 if ((offset == 0) || 1361 (temp < (int)sizeof(struct ether_header)) || 1362 (temp > (MCLBYTES - ETHER_ALIGN))) { 1363 DPRINTFN(1, "NULL frame detected at %d\n", x); 1364 m = NULL; 1365 /* silently ignore this frame */ 1366 continue; 1367 } else if ((offset + temp) > actlen) { 1368 DPRINTFN(1, "invalid frame " 1369 "detected at %d\n", x); 1370 m = NULL; 1371 /* silently ignore this frame */ 1372 continue; 1373 } else if (temp > (int)(MHLEN - ETHER_ALIGN)) { 1374 m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 1375 } else { 1376 m = m_gethdr(M_NOWAIT, MT_DATA); 1377 } 1378 1379 DPRINTFN(16, "frame %u, offset = %u, length = %u \n", 1380 x, offset, temp); 1381 1382 /* check if we have a buffer */ 1383 if (m) { 1384 m_adj(m, ETHER_ALIGN); 1385 1386 usbd_copy_out(pc, offset, m->m_data, temp); 1387 1388 /* enqueue */ 1389 uether_rxmbuf(&sc->sc_ue, m, temp); 1390 1391 sumdata += temp; 1392 } else { 1393 ifp->if_ierrors++; 1394 } 1395 } 1396 1397 DPRINTFN(1, "Efficiency: %u/%u bytes\n", sumdata, actlen); 1398 1399 case USB_ST_SETUP: 1400tr_setup: 1401 usbd_xfer_set_frame_len(xfer, 0, sc->sc_ncm.rx_max); 1402 usbd_xfer_set_frames(xfer, 1); 1403 usbd_transfer_submit(xfer); 1404 uether_rxflush(&sc->sc_ue); /* must be last */ 1405 break; 1406 1407 default: /* Error */ 1408 DPRINTFN(1, "error = %s\n", 1409 usbd_errstr(error)); 1410 1411 if (error != USB_ERR_CANCELLED) { 1412tr_stall: 1413 /* try to clear stall first */ 1414 usbd_xfer_set_stall(xfer); 1415 usbd_xfer_set_frames(xfer, 0); 1416 usbd_transfer_submit(xfer); 1417 } 1418 break; 1419 } 1420} 1421#endif 1422