1f9f848faSopenharmony_ci/* $NetBSD: if_cdce.c,v 1.4 2004/10/24 12:50:54 augustss Exp $ */ 2f9f848faSopenharmony_ci 3f9f848faSopenharmony_ci/*- 4f9f848faSopenharmony_ci * SPDX-License-Identifier: BSD-4-Clause 5f9f848faSopenharmony_ci * 6f9f848faSopenharmony_ci * Copyright (c) 1997, 1998, 1999, 2000-2003 Bill Paul <wpaul@windriver.com> 7f9f848faSopenharmony_ci * Copyright (c) 2003-2005 Craig Boston 8f9f848faSopenharmony_ci * Copyright (c) 2004 Daniel Hartmeier 9f9f848faSopenharmony_ci * Copyright (c) 2009 Hans Petter Selasky 10f9f848faSopenharmony_ci * All rights reserved. 11f9f848faSopenharmony_ci * 12f9f848faSopenharmony_ci * Redistribution and use in source and binary forms, with or without 13f9f848faSopenharmony_ci * modification, are permitted provided that the following conditions 14f9f848faSopenharmony_ci * are met: 15f9f848faSopenharmony_ci * 1. Redistributions of source code must retain the above copyright 16f9f848faSopenharmony_ci * notice, this list of conditions and the following disclaimer. 17f9f848faSopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 18f9f848faSopenharmony_ci * notice, this list of conditions and the following disclaimer in the 19f9f848faSopenharmony_ci * documentation and/or other materials provided with the distribution. 20f9f848faSopenharmony_ci * 3. All advertising materials mentioning features or use of this software 21f9f848faSopenharmony_ci * must display the following acknowledgement: 22f9f848faSopenharmony_ci * This product includes software developed by Bill Paul. 23f9f848faSopenharmony_ci * 4. Neither the name of the author nor the names of any co-contributors 24f9f848faSopenharmony_ci * may be used to endorse or promote products derived from this software 25f9f848faSopenharmony_ci * without specific prior written permission. 26f9f848faSopenharmony_ci * 27f9f848faSopenharmony_ci * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 28f9f848faSopenharmony_ci * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29f9f848faSopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30f9f848faSopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul, THE VOICES IN HIS HEAD OR 31f9f848faSopenharmony_ci * THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 32f9f848faSopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 33f9f848faSopenharmony_ci * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 34f9f848faSopenharmony_ci * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 35f9f848faSopenharmony_ci * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 36f9f848faSopenharmony_ci * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 37f9f848faSopenharmony_ci * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38f9f848faSopenharmony_ci */ 39f9f848faSopenharmony_ci 40f9f848faSopenharmony_ci/* 41f9f848faSopenharmony_ci * USB Communication Device Class (Ethernet Networking Control Model) 42f9f848faSopenharmony_ci * http://www.usb.org/developers/devclass_docs/usbcdc11.pdf 43f9f848faSopenharmony_ci */ 44f9f848faSopenharmony_ci 45f9f848faSopenharmony_ci/* 46f9f848faSopenharmony_ci * USB Network Control Model (NCM) 47f9f848faSopenharmony_ci * http://www.usb.org/developers/devclass_docs/NCM10.zip 48f9f848faSopenharmony_ci */ 49f9f848faSopenharmony_ci 50f9f848faSopenharmony_ci#include <sys/cdefs.h> 51f9f848faSopenharmony_ci 52f9f848faSopenharmony_ci#include "los_crc32.h" 53f9f848faSopenharmony_ci 54f9f848faSopenharmony_ci#include "implementation/global_implementation.h" 55f9f848faSopenharmony_ci#include "usb_ethernet.h" 56f9f848faSopenharmony_ci#include "if_cdcereg.h" 57f9f848faSopenharmony_ci 58f9f848faSopenharmony_cistatic device_probe_t cdce_probe; 59f9f848faSopenharmony_cistatic device_attach_t cdce_attach; 60f9f848faSopenharmony_cistatic device_detach_t cdce_detach; 61f9f848faSopenharmony_cistatic device_suspend_t cdce_suspend; 62f9f848faSopenharmony_cistatic device_resume_t cdce_resume; 63f9f848faSopenharmony_cistatic usb_handle_request_t cdce_handle_request; 64f9f848faSopenharmony_ci 65f9f848faSopenharmony_cistatic usb_callback_t cdce_bulk_write_callback; 66f9f848faSopenharmony_cistatic usb_callback_t cdce_bulk_read_callback; 67f9f848faSopenharmony_cistatic usb_callback_t cdce_intr_read_callback; 68f9f848faSopenharmony_cistatic usb_callback_t cdce_intr_write_callback; 69f9f848faSopenharmony_ci 70f9f848faSopenharmony_ci#if CDCE_HAVE_NCM 71f9f848faSopenharmony_cistatic usb_callback_t cdce_ncm_bulk_write_callback; 72f9f848faSopenharmony_cistatic usb_callback_t cdce_ncm_bulk_read_callback; 73f9f848faSopenharmony_ci#endif 74f9f848faSopenharmony_ci 75f9f848faSopenharmony_cistatic uether_fn_t cdce_attach_post; 76f9f848faSopenharmony_cistatic uether_fn_t cdce_init; 77f9f848faSopenharmony_cistatic uether_fn_t cdce_stop; 78f9f848faSopenharmony_cistatic uether_fn_t cdce_start; 79f9f848faSopenharmony_cistatic uether_fn_t cdce_setmulti; 80f9f848faSopenharmony_cistatic uether_fn_t cdce_setpromisc; 81f9f848faSopenharmony_ci 82f9f848faSopenharmony_cistatic uint32_t cdce_m_crc32(struct pbuf *, uint32_t, uint32_t); 83f9f848faSopenharmony_ci 84f9f848faSopenharmony_ci#undef USB_DEBUG_VAR 85f9f848faSopenharmony_ci#define USB_DEBUG_VAR cdce_debug 86f9f848faSopenharmony_ci#ifdef LOSCFG_USB_DEBUG 87f9f848faSopenharmony_cistatic int cdce_debug = 0; 88f9f848faSopenharmony_civoid 89f9f848faSopenharmony_ciusb_cdce_debug_func(int level) 90f9f848faSopenharmony_ci{ 91f9f848faSopenharmony_ci cdce_debug = level; 92f9f848faSopenharmony_ci PRINTK("The level of usb cdce debug is %d\n", level); 93f9f848faSopenharmony_ci} 94f9f848faSopenharmony_ciDEBUG_MODULE(cdce, usb_cdce_debug_func); 95f9f848faSopenharmony_ci#endif 96f9f848faSopenharmony_ci 97f9f848faSopenharmony_cistatic const struct usb_config cdce_config[CDCE_N_TRANSFER] = { 98f9f848faSopenharmony_ci [CDCE_BULK_RX] = { 99f9f848faSopenharmony_ci .type = UE_BULK, 100f9f848faSopenharmony_ci .endpoint = UE_ADDR_ANY, 101f9f848faSopenharmony_ci .direction = UE_DIR_RX, 102f9f848faSopenharmony_ci .if_index = 0, 103f9f848faSopenharmony_ci .frames = CDCE_FRAMES_MAX, 104f9f848faSopenharmony_ci .bufsize = (CDCE_FRAMES_MAX * MCLBYTES), 105f9f848faSopenharmony_ci .flags = {.pipe_bof = 1,.short_frames_ok = 1,.short_xfer_ok = 1,.ext_buffer = 1,}, 106f9f848faSopenharmony_ci .callback = cdce_bulk_read_callback, 107f9f848faSopenharmony_ci .timeout = 0, /* no timeout */ 108f9f848faSopenharmony_ci .usb_mode = USB_MODE_DUAL, /* both modes */ 109f9f848faSopenharmony_ci }, 110f9f848faSopenharmony_ci 111f9f848faSopenharmony_ci [CDCE_BULK_TX] = { 112f9f848faSopenharmony_ci .type = UE_BULK, 113f9f848faSopenharmony_ci .endpoint = UE_ADDR_ANY, 114f9f848faSopenharmony_ci .direction = UE_DIR_TX, 115f9f848faSopenharmony_ci .if_index = 0, 116f9f848faSopenharmony_ci .frames = CDCE_FRAMES_MAX, 117f9f848faSopenharmony_ci .bufsize = (CDCE_FRAMES_MAX * MCLBYTES), 118f9f848faSopenharmony_ci .flags = {.pipe_bof = 1,.force_short_xfer = 1,.ext_buffer = 1,}, 119f9f848faSopenharmony_ci .callback = cdce_bulk_write_callback, 120f9f848faSopenharmony_ci .timeout = 10000, /* 10 seconds */ 121f9f848faSopenharmony_ci .usb_mode = USB_MODE_DUAL, /* both modes */ 122f9f848faSopenharmony_ci }, 123f9f848faSopenharmony_ci 124f9f848faSopenharmony_ci [CDCE_INTR_RX] = { 125f9f848faSopenharmony_ci .type = UE_INTERRUPT, 126f9f848faSopenharmony_ci .endpoint = UE_ADDR_ANY, 127f9f848faSopenharmony_ci .direction = UE_DIR_RX, 128f9f848faSopenharmony_ci .if_index = 1, 129f9f848faSopenharmony_ci .bufsize = CDCE_IND_SIZE_MAX, 130f9f848faSopenharmony_ci .flags = {.pipe_bof = 1,.short_xfer_ok = 1,.no_pipe_ok = 1,}, 131f9f848faSopenharmony_ci .callback = cdce_intr_read_callback, 132f9f848faSopenharmony_ci .timeout = 0, 133f9f848faSopenharmony_ci .usb_mode = USB_MODE_HOST, 134f9f848faSopenharmony_ci }, 135f9f848faSopenharmony_ci 136f9f848faSopenharmony_ci [CDCE_INTR_TX] = { 137f9f848faSopenharmony_ci .type = UE_INTERRUPT, 138f9f848faSopenharmony_ci .endpoint = UE_ADDR_ANY, 139f9f848faSopenharmony_ci .direction = UE_DIR_TX, 140f9f848faSopenharmony_ci .if_index = 1, 141f9f848faSopenharmony_ci .bufsize = CDCE_IND_SIZE_MAX, 142f9f848faSopenharmony_ci .flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,}, 143f9f848faSopenharmony_ci .callback = cdce_intr_write_callback, 144f9f848faSopenharmony_ci .timeout = 10000, /* 10 seconds */ 145f9f848faSopenharmony_ci .usb_mode = USB_MODE_DEVICE, 146f9f848faSopenharmony_ci }, 147f9f848faSopenharmony_ci}; 148f9f848faSopenharmony_ci 149f9f848faSopenharmony_ci#if CDCE_HAVE_NCM 150f9f848faSopenharmony_cistatic const struct usb_config cdce_ncm_config[CDCE_N_TRANSFER] = { 151f9f848faSopenharmony_ci [CDCE_BULK_RX] = { 152f9f848faSopenharmony_ci .type = UE_BULK, 153f9f848faSopenharmony_ci .endpoint = UE_ADDR_ANY, 154f9f848faSopenharmony_ci .direction = UE_DIR_RX, 155f9f848faSopenharmony_ci .if_index = 0, 156f9f848faSopenharmony_ci .frames = CDCE_NCM_RX_FRAMES_MAX, 157f9f848faSopenharmony_ci .bufsize = (CDCE_NCM_RX_FRAMES_MAX * CDCE_NCM_RX_MAXLEN), 158f9f848faSopenharmony_ci .flags = {.pipe_bof = 1,.short_frames_ok = 1,.short_xfer_ok = 1,}, 159f9f848faSopenharmony_ci .callback = cdce_ncm_bulk_read_callback, 160f9f848faSopenharmony_ci .timeout = 0, /* no timeout */ 161f9f848faSopenharmony_ci .usb_mode = USB_MODE_DUAL, /* both modes */ 162f9f848faSopenharmony_ci }, 163f9f848faSopenharmony_ci 164f9f848faSopenharmony_ci [CDCE_BULK_TX] = { 165f9f848faSopenharmony_ci .type = UE_BULK, 166f9f848faSopenharmony_ci .endpoint = UE_ADDR_ANY, 167f9f848faSopenharmony_ci .direction = UE_DIR_TX, 168f9f848faSopenharmony_ci .if_index = 0, 169f9f848faSopenharmony_ci .frames = CDCE_NCM_TX_FRAMES_MAX, 170f9f848faSopenharmony_ci .bufsize = (CDCE_NCM_TX_FRAMES_MAX * CDCE_NCM_TX_MAXLEN), 171f9f848faSopenharmony_ci .flags = {.pipe_bof = 1,}, 172f9f848faSopenharmony_ci .callback = cdce_ncm_bulk_write_callback, 173f9f848faSopenharmony_ci .timeout = 10000, /* 10 seconds */ 174f9f848faSopenharmony_ci .usb_mode = USB_MODE_DUAL, /* both modes */ 175f9f848faSopenharmony_ci }, 176f9f848faSopenharmony_ci 177f9f848faSopenharmony_ci [CDCE_INTR_RX] = { 178f9f848faSopenharmony_ci .type = UE_INTERRUPT, 179f9f848faSopenharmony_ci .endpoint = UE_ADDR_ANY, 180f9f848faSopenharmony_ci .direction = UE_DIR_RX, 181f9f848faSopenharmony_ci .if_index = 1, 182f9f848faSopenharmony_ci .bufsize = CDCE_IND_SIZE_MAX, 183f9f848faSopenharmony_ci .flags = {.pipe_bof = 1,.short_xfer_ok = 1,.no_pipe_ok = 1,}, 184f9f848faSopenharmony_ci .callback = cdce_intr_read_callback, 185f9f848faSopenharmony_ci .timeout = 0, 186f9f848faSopenharmony_ci .usb_mode = USB_MODE_HOST, 187f9f848faSopenharmony_ci }, 188f9f848faSopenharmony_ci 189f9f848faSopenharmony_ci [CDCE_INTR_TX] = { 190f9f848faSopenharmony_ci .type = UE_INTERRUPT, 191f9f848faSopenharmony_ci .endpoint = UE_ADDR_ANY, 192f9f848faSopenharmony_ci .direction = UE_DIR_TX, 193f9f848faSopenharmony_ci .if_index = 1, 194f9f848faSopenharmony_ci .bufsize = CDCE_IND_SIZE_MAX, 195f9f848faSopenharmony_ci .flags = {.pipe_bof = 1,.force_short_xfer = 1,.no_pipe_ok = 1,}, 196f9f848faSopenharmony_ci .callback = cdce_intr_write_callback, 197f9f848faSopenharmony_ci .timeout = 10000, /* 10 seconds */ 198f9f848faSopenharmony_ci .usb_mode = USB_MODE_DEVICE, 199f9f848faSopenharmony_ci }, 200f9f848faSopenharmony_ci}; 201f9f848faSopenharmony_ci#endif 202f9f848faSopenharmony_ci 203f9f848faSopenharmony_cistatic device_method_t cdce_methods[] = { 204f9f848faSopenharmony_ci /* USB interface */ 205f9f848faSopenharmony_ci DEVMETHOD(usb_handle_request, cdce_handle_request), 206f9f848faSopenharmony_ci 207f9f848faSopenharmony_ci /* Device interface */ 208f9f848faSopenharmony_ci DEVMETHOD(device_probe, cdce_probe), 209f9f848faSopenharmony_ci DEVMETHOD(device_attach, cdce_attach), 210f9f848faSopenharmony_ci DEVMETHOD(device_detach, cdce_detach), 211f9f848faSopenharmony_ci DEVMETHOD(device_suspend, cdce_suspend), 212f9f848faSopenharmony_ci DEVMETHOD(device_resume, cdce_resume), 213f9f848faSopenharmony_ci 214f9f848faSopenharmony_ci DEVMETHOD_END 215f9f848faSopenharmony_ci}; 216f9f848faSopenharmony_ci 217f9f848faSopenharmony_cistatic driver_t cdce_driver = { 218f9f848faSopenharmony_ci .name = "cdce", 219f9f848faSopenharmony_ci .methods = cdce_methods, 220f9f848faSopenharmony_ci .size = sizeof(struct cdce_softc), 221f9f848faSopenharmony_ci}; 222f9f848faSopenharmony_ci 223f9f848faSopenharmony_cistatic devclass_t cdce_devclass; 224f9f848faSopenharmony_ci 225f9f848faSopenharmony_ciDRIVER_MODULE(cdce, uhub, cdce_driver, cdce_devclass, NULL, 0); 226f9f848faSopenharmony_ci 227f9f848faSopenharmony_cistatic const struct usb_ether_methods cdce_ue_methods = { 228f9f848faSopenharmony_ci .ue_attach_post = cdce_attach_post, 229f9f848faSopenharmony_ci .ue_start = cdce_start, 230f9f848faSopenharmony_ci .ue_init = cdce_init, 231f9f848faSopenharmony_ci .ue_stop = cdce_stop, 232f9f848faSopenharmony_ci .ue_setmulti = cdce_setmulti, 233f9f848faSopenharmony_ci .ue_setpromisc = cdce_setpromisc, 234f9f848faSopenharmony_ci}; 235f9f848faSopenharmony_ci 236f9f848faSopenharmony_cistatic const STRUCT_USB_HOST_ID cdce_host_devs[] = { 237f9f848faSopenharmony_ci 238f9f848faSopenharmony_ci}; 239f9f848faSopenharmony_ci 240f9f848faSopenharmony_cistatic const STRUCT_USB_DUAL_ID cdce_dual_devs[] = { 241f9f848faSopenharmony_ci {USB_IF_CSI(UICLASS_CDC, UISUBCLASS_ETHERNET_NETWORKING_CONTROL_MODEL, 0)}, 242f9f848faSopenharmony_ci {USB_IF_CSI(UICLASS_CDC, UISUBCLASS_MOBILE_DIRECT_LINE_MODEL, 0)}, 243f9f848faSopenharmony_ci {USB_IF_CSI(UICLASS_CDC, UISUBCLASS_NETWORK_CONTROL_MODEL, 0)}, 244f9f848faSopenharmony_ci}; 245f9f848faSopenharmony_ci 246f9f848faSopenharmony_ci#if CDCE_HAVE_NCM 247f9f848faSopenharmony_ci/*------------------------------------------------------------------------* 248f9f848faSopenharmony_ci * cdce_ncm_init 249f9f848faSopenharmony_ci * 250f9f848faSopenharmony_ci * Return values: 251f9f848faSopenharmony_ci * 0: Success 252f9f848faSopenharmony_ci * Else: Failure 253f9f848faSopenharmony_ci *------------------------------------------------------------------------*/ 254f9f848faSopenharmony_cistatic uint8_t 255f9f848faSopenharmony_cicdce_ncm_init(struct cdce_softc *sc) 256f9f848faSopenharmony_ci{ 257f9f848faSopenharmony_ci struct usb_ncm_parameters temp; 258f9f848faSopenharmony_ci struct usb_device_request req; 259f9f848faSopenharmony_ci struct usb_ncm_func_descriptor *ufd; 260f9f848faSopenharmony_ci uint8_t value[8]; 261f9f848faSopenharmony_ci int err; 262f9f848faSopenharmony_ci 263f9f848faSopenharmony_ci DPRINTFN(1, "\n"); 264f9f848faSopenharmony_ci 265f9f848faSopenharmony_ci ufd = usbd_find_descriptor(sc->sc_ue.ue_udev, NULL, 266f9f848faSopenharmony_ci sc->sc_ifaces_index[1], UDESC_CS_INTERFACE, 0xFF, 267f9f848faSopenharmony_ci UCDC_NCM_FUNC_DESC_SUBTYPE, 0xFF); 268f9f848faSopenharmony_ci 269f9f848faSopenharmony_ci /* verify length of NCM functional descriptor */ 270f9f848faSopenharmony_ci if (ufd != NULL) { 271f9f848faSopenharmony_ci if (ufd->bLength < sizeof(*ufd)) 272f9f848faSopenharmony_ci ufd = NULL; 273f9f848faSopenharmony_ci else 274f9f848faSopenharmony_ci DPRINTFN(1, "Found NCM functional descriptor.\n"); 275f9f848faSopenharmony_ci } 276f9f848faSopenharmony_ci 277f9f848faSopenharmony_ci req.bmRequestType = UT_READ_CLASS_INTERFACE; 278f9f848faSopenharmony_ci req.bRequest = UCDC_NCM_GET_NTB_PARAMETERS; 279f9f848faSopenharmony_ci USETW(req.wValue, 0); 280f9f848faSopenharmony_ci req.wIndex[0] = sc->sc_ifaces_index[1]; 281f9f848faSopenharmony_ci req.wIndex[1] = 0; 282f9f848faSopenharmony_ci USETW(req.wLength, sizeof(temp)); 283f9f848faSopenharmony_ci 284f9f848faSopenharmony_ci err = usbd_do_request_flags(sc->sc_ue.ue_udev, NULL, &req, 285f9f848faSopenharmony_ci &temp, 0, NULL, 1000 /* ms */); 286f9f848faSopenharmony_ci if (err){ 287f9f848faSopenharmony_ci DPRINTFN(1, "request error!\n"); 288f9f848faSopenharmony_ci return (1); 289f9f848faSopenharmony_ci } 290f9f848faSopenharmony_ci /* Read correct set of parameters according to device mode */ 291f9f848faSopenharmony_ci DPRINTFN(1, "line %d!\n",__LINE__); 292f9f848faSopenharmony_ci 293f9f848faSopenharmony_ci if (usbd_get_mode(sc->sc_ue.ue_udev) == USB_MODE_HOST) { 294f9f848faSopenharmony_ci sc->sc_ncm.rx_max = UGETDW(temp.dwNtbInMaxSize); 295f9f848faSopenharmony_ci sc->sc_ncm.tx_max = UGETDW(temp.dwNtbOutMaxSize); 296f9f848faSopenharmony_ci sc->sc_ncm.tx_remainder = UGETW(temp.wNdpOutPayloadRemainder); 297f9f848faSopenharmony_ci sc->sc_ncm.tx_modulus = UGETW(temp.wNdpOutDivisor); 298f9f848faSopenharmony_ci sc->sc_ncm.tx_struct_align = UGETW(temp.wNdpOutAlignment); 299f9f848faSopenharmony_ci sc->sc_ncm.tx_nframe = UGETW(temp.wNtbOutMaxDatagrams); 300f9f848faSopenharmony_ci } else { 301f9f848faSopenharmony_ci sc->sc_ncm.rx_max = UGETDW(temp.dwNtbOutMaxSize); 302f9f848faSopenharmony_ci sc->sc_ncm.tx_max = UGETDW(temp.dwNtbInMaxSize); 303f9f848faSopenharmony_ci sc->sc_ncm.tx_remainder = UGETW(temp.wNdpInPayloadRemainder); 304f9f848faSopenharmony_ci sc->sc_ncm.tx_modulus = UGETW(temp.wNdpInDivisor); 305f9f848faSopenharmony_ci sc->sc_ncm.tx_struct_align = UGETW(temp.wNdpInAlignment); 306f9f848faSopenharmony_ci sc->sc_ncm.tx_nframe = UGETW(temp.wNtbOutMaxDatagrams); 307f9f848faSopenharmony_ci } 308f9f848faSopenharmony_ci 309f9f848faSopenharmony_ci /* Verify maximum receive length */ 310f9f848faSopenharmony_ci 311f9f848faSopenharmony_ci if ((sc->sc_ncm.rx_max < 32) || 312f9f848faSopenharmony_ci (sc->sc_ncm.rx_max > CDCE_NCM_RX_MAXLEN)) { 313f9f848faSopenharmony_ci DPRINTFN(1, "Using default maximum receive length\n"); 314f9f848faSopenharmony_ci sc->sc_ncm.rx_max = CDCE_NCM_RX_MAXLEN; 315f9f848faSopenharmony_ci } 316f9f848faSopenharmony_ci 317f9f848faSopenharmony_ci /* Verify maximum transmit length */ 318f9f848faSopenharmony_ci 319f9f848faSopenharmony_ci if ((sc->sc_ncm.tx_max < 32) || 320f9f848faSopenharmony_ci (sc->sc_ncm.tx_max > CDCE_NCM_TX_MAXLEN)) { 321f9f848faSopenharmony_ci DPRINTFN(1, "Using default maximum transmit length\n"); 322f9f848faSopenharmony_ci sc->sc_ncm.tx_max = CDCE_NCM_TX_MAXLEN; 323f9f848faSopenharmony_ci } 324f9f848faSopenharmony_ci 325f9f848faSopenharmony_ci /* 326f9f848faSopenharmony_ci * Verify that the structure alignment is: 327f9f848faSopenharmony_ci * - power of two 328f9f848faSopenharmony_ci * - not greater than the maximum transmit length 329f9f848faSopenharmony_ci * - not less than four bytes 330f9f848faSopenharmony_ci */ 331f9f848faSopenharmony_ci if ((sc->sc_ncm.tx_struct_align < 4) || 332f9f848faSopenharmony_ci (sc->sc_ncm.tx_struct_align != 333f9f848faSopenharmony_ci ((-sc->sc_ncm.tx_struct_align) & sc->sc_ncm.tx_struct_align)) || 334f9f848faSopenharmony_ci (sc->sc_ncm.tx_struct_align >= sc->sc_ncm.tx_max)) { 335f9f848faSopenharmony_ci DPRINTFN(1, "Using default other alignment: 4 bytes\n"); 336f9f848faSopenharmony_ci sc->sc_ncm.tx_struct_align = 4; 337f9f848faSopenharmony_ci } 338f9f848faSopenharmony_ci 339f9f848faSopenharmony_ci /* 340f9f848faSopenharmony_ci * Verify that the payload alignment is: 341f9f848faSopenharmony_ci * - power of two 342f9f848faSopenharmony_ci * - not greater than the maximum transmit length 343f9f848faSopenharmony_ci * - not less than four bytes 344f9f848faSopenharmony_ci */ 345f9f848faSopenharmony_ci if ((sc->sc_ncm.tx_modulus < 4) || 346f9f848faSopenharmony_ci (sc->sc_ncm.tx_modulus != 347f9f848faSopenharmony_ci ((-sc->sc_ncm.tx_modulus) & sc->sc_ncm.tx_modulus)) || 348f9f848faSopenharmony_ci (sc->sc_ncm.tx_modulus >= sc->sc_ncm.tx_max)) { 349f9f848faSopenharmony_ci DPRINTFN(1, "Using default transmit modulus: 4 bytes\n"); 350f9f848faSopenharmony_ci sc->sc_ncm.tx_modulus = 4; 351f9f848faSopenharmony_ci } 352f9f848faSopenharmony_ci 353f9f848faSopenharmony_ci /* Verify that the payload remainder */ 354f9f848faSopenharmony_ci 355f9f848faSopenharmony_ci if ((sc->sc_ncm.tx_remainder >= sc->sc_ncm.tx_modulus)) { 356f9f848faSopenharmony_ci DPRINTFN(1, "Using default transmit remainder: 0 bytes\n"); 357f9f848faSopenharmony_ci sc->sc_ncm.tx_remainder = 0; 358f9f848faSopenharmony_ci } 359f9f848faSopenharmony_ci 360f9f848faSopenharmony_ci /* 361f9f848faSopenharmony_ci * Offset the TX remainder so that IP packet payload starts at 362f9f848faSopenharmony_ci * the tx_modulus. This is not too clear in the specification. 363f9f848faSopenharmony_ci */ 364f9f848faSopenharmony_ci 365f9f848faSopenharmony_ci sc->sc_ncm.tx_remainder = 366f9f848faSopenharmony_ci (sc->sc_ncm.tx_remainder - ETHER_HDR_LEN) & 367f9f848faSopenharmony_ci (sc->sc_ncm.tx_modulus - 1); 368f9f848faSopenharmony_ci 369f9f848faSopenharmony_ci /* Verify max datagrams */ 370f9f848faSopenharmony_ci 371f9f848faSopenharmony_ci if (sc->sc_ncm.tx_nframe == 0 || 372f9f848faSopenharmony_ci sc->sc_ncm.tx_nframe > (CDCE_NCM_SUBFRAMES_MAX - 1)) { 373f9f848faSopenharmony_ci DPRINTFN(1, "Using default max " 374f9f848faSopenharmony_ci "subframes: %u units\n", CDCE_NCM_SUBFRAMES_MAX - 1); 375f9f848faSopenharmony_ci /* need to reserve one entry for zero padding */ 376f9f848faSopenharmony_ci sc->sc_ncm.tx_nframe = (CDCE_NCM_SUBFRAMES_MAX - 1); 377f9f848faSopenharmony_ci } 378f9f848faSopenharmony_ci 379f9f848faSopenharmony_ci /* Additional configuration, will fail in device side mode, which is OK. */ 380f9f848faSopenharmony_ci 381f9f848faSopenharmony_ci req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 382f9f848faSopenharmony_ci req.bRequest = UCDC_NCM_SET_NTB_INPUT_SIZE; 383f9f848faSopenharmony_ci USETW(req.wValue, 0); 384f9f848faSopenharmony_ci req.wIndex[0] = sc->sc_ifaces_index[1]; 385f9f848faSopenharmony_ci req.wIndex[1] = 0; 386f9f848faSopenharmony_ci 387f9f848faSopenharmony_ci if ((ufd != NULL) && 388f9f848faSopenharmony_ci (ufd->bmNetworkCapabilities & UCDC_NCM_CAP_MAX_DGRAM)) { 389f9f848faSopenharmony_ci USETW(req.wLength, 8); 390f9f848faSopenharmony_ci USETDW(value, sc->sc_ncm.rx_max); 391f9f848faSopenharmony_ci USETW(value + 4, (CDCE_NCM_SUBFRAMES_MAX - 1)); 392f9f848faSopenharmony_ci USETW(value + 6, 0); 393f9f848faSopenharmony_ci } else { 394f9f848faSopenharmony_ci USETW(req.wLength, 4); 395f9f848faSopenharmony_ci USETDW(value, sc->sc_ncm.rx_max); 396f9f848faSopenharmony_ci } 397f9f848faSopenharmony_ci 398f9f848faSopenharmony_ci err = usbd_do_request_flags(sc->sc_ue.ue_udev, NULL, &req, 399f9f848faSopenharmony_ci &value, 0, NULL, 1000 /* ms */); 400f9f848faSopenharmony_ci if (err) { 401f9f848faSopenharmony_ci DPRINTFN(1, "Setting input size " 402f9f848faSopenharmony_ci "to %u failed.\n", sc->sc_ncm.rx_max); 403f9f848faSopenharmony_ci } 404f9f848faSopenharmony_ci 405f9f848faSopenharmony_ci req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 406f9f848faSopenharmony_ci req.bRequest = UCDC_NCM_SET_CRC_MODE; 407f9f848faSopenharmony_ci USETW(req.wValue, 0); /* no CRC */ 408f9f848faSopenharmony_ci req.wIndex[0] = sc->sc_ifaces_index[1]; 409f9f848faSopenharmony_ci req.wIndex[1] = 0; 410f9f848faSopenharmony_ci USETW(req.wLength, 0); 411f9f848faSopenharmony_ci 412f9f848faSopenharmony_ci err = usbd_do_request_flags(sc->sc_ue.ue_udev, NULL, &req, 413f9f848faSopenharmony_ci NULL, 0, NULL, 1000 /* ms */); 414f9f848faSopenharmony_ci if (err) { 415f9f848faSopenharmony_ci DPRINTFN(1, "Setting CRC mode to off failed.\n"); 416f9f848faSopenharmony_ci } 417f9f848faSopenharmony_ci 418f9f848faSopenharmony_ci req.bmRequestType = UT_WRITE_CLASS_INTERFACE; 419f9f848faSopenharmony_ci req.bRequest = UCDC_NCM_SET_NTB_FORMAT; 420f9f848faSopenharmony_ci USETW(req.wValue, 0); /* NTB-16 */ 421f9f848faSopenharmony_ci req.wIndex[0] = sc->sc_ifaces_index[1]; 422f9f848faSopenharmony_ci req.wIndex[1] = 0; 423f9f848faSopenharmony_ci USETW(req.wLength, 0); 424f9f848faSopenharmony_ci 425f9f848faSopenharmony_ci err = usbd_do_request_flags(sc->sc_ue.ue_udev, NULL, &req, 426f9f848faSopenharmony_ci NULL, 0, NULL, 1000 /* ms */); 427f9f848faSopenharmony_ci if (err) { 428f9f848faSopenharmony_ci DPRINTFN(1, "Setting NTB format to 16-bit failed.\n"); 429f9f848faSopenharmony_ci } 430f9f848faSopenharmony_ci 431f9f848faSopenharmony_ci DPRINTFN(1, " -->end!\n"); 432f9f848faSopenharmony_ci 433f9f848faSopenharmony_ci return (0); /* success */ 434f9f848faSopenharmony_ci} 435f9f848faSopenharmony_ci#endif 436f9f848faSopenharmony_ci 437f9f848faSopenharmony_cistatic int 438f9f848faSopenharmony_cicdce_probe(device_t dev) 439f9f848faSopenharmony_ci{ 440f9f848faSopenharmony_ci struct usb_attach_arg *uaa = (struct usb_attach_arg *)device_get_ivars(dev); 441f9f848faSopenharmony_ci int error; 442f9f848faSopenharmony_ci 443f9f848faSopenharmony_ci error = usbd_lookup_id_by_uaa(cdce_host_devs, sizeof(cdce_host_devs), uaa); 444f9f848faSopenharmony_ci 445f9f848faSopenharmony_ci if (error) 446f9f848faSopenharmony_ci error = usbd_lookup_id_by_uaa(cdce_dual_devs, sizeof(cdce_dual_devs), uaa); 447f9f848faSopenharmony_ci return (error); 448f9f848faSopenharmony_ci} 449f9f848faSopenharmony_ci 450f9f848faSopenharmony_cistatic void 451f9f848faSopenharmony_cicdce_attach_post(struct usb_ether *ue) 452f9f848faSopenharmony_ci{ 453f9f848faSopenharmony_ci /* no-op */ 454f9f848faSopenharmony_ci return; 455f9f848faSopenharmony_ci} 456f9f848faSopenharmony_ci 457f9f848faSopenharmony_cistatic int 458f9f848faSopenharmony_cicdce_attach(device_t dev) 459f9f848faSopenharmony_ci{ 460f9f848faSopenharmony_ci struct cdce_softc *sc = (struct cdce_softc *)device_get_softc(dev); 461f9f848faSopenharmony_ci struct usb_ether *ue = &sc->sc_ue; 462f9f848faSopenharmony_ci struct usb_attach_arg *uaa = (struct usb_attach_arg *)device_get_ivars(dev); 463f9f848faSopenharmony_ci struct usb_interface *iface; 464f9f848faSopenharmony_ci const struct usb_cdc_union_descriptor *ud; 465f9f848faSopenharmony_ci const struct usb_interface_descriptor *id; 466f9f848faSopenharmony_ci const struct usb_cdc_ethernet_descriptor *ued; 467f9f848faSopenharmony_ci const struct usb_config *pcfg; 468f9f848faSopenharmony_ci uint32_t seed; 469f9f848faSopenharmony_ci usb_error_t error; 470f9f848faSopenharmony_ci uint8_t i; 471f9f848faSopenharmony_ci uint8_t data_iface_no; 472f9f848faSopenharmony_ci char eaddr_str[5 * NETIF_MAX_HWADDR_LEN]; /* approx */ 473f9f848faSopenharmony_ci 474f9f848faSopenharmony_ci DPRINTFN(1, "\n"); 475f9f848faSopenharmony_ci 476f9f848faSopenharmony_ci sc->sc_flags = USB_GET_DRIVER_INFO(uaa); 477f9f848faSopenharmony_ci sc->sc_ue.ue_udev = uaa->device; 478f9f848faSopenharmony_ci 479f9f848faSopenharmony_ci device_set_usb_desc(dev); 480f9f848faSopenharmony_ci 481f9f848faSopenharmony_ci mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 482f9f848faSopenharmony_ci 483f9f848faSopenharmony_ci ud = (const struct usb_cdc_union_descriptor *)usbd_find_descriptor 484f9f848faSopenharmony_ci (uaa->device, NULL, uaa->info.bIfaceIndex, UDESC_CS_INTERFACE, 485f9f848faSopenharmony_ci 0xFF, UDESCSUB_CDC_UNION, 0xFF); 486f9f848faSopenharmony_ci 487f9f848faSopenharmony_ci if ((ud == NULL) || (ud->bLength < sizeof(*ud)) || 488f9f848faSopenharmony_ci (sc->sc_flags & CDCE_FLAG_NO_UNION)) { 489f9f848faSopenharmony_ci DPRINTFN(1, "No union descriptor!\n"); 490f9f848faSopenharmony_ci sc->sc_ifaces_index[0] = uaa->info.bIfaceIndex; 491f9f848faSopenharmony_ci sc->sc_ifaces_index[1] = uaa->info.bIfaceIndex; 492f9f848faSopenharmony_ci goto alloc_transfers; 493f9f848faSopenharmony_ci } 494f9f848faSopenharmony_ci data_iface_no = ud->bSlaveInterface[0]; 495f9f848faSopenharmony_ci DPRINTFN(1, "data_iface_no = %d!\n", data_iface_no); 496f9f848faSopenharmony_ci 497f9f848faSopenharmony_ci for (i = 0;; i++) { 498f9f848faSopenharmony_ci iface = usbd_get_iface(uaa->device, i); 499f9f848faSopenharmony_ci 500f9f848faSopenharmony_ci if (iface) { 501f9f848faSopenharmony_ci id = usbd_get_interface_descriptor(iface); 502f9f848faSopenharmony_ci 503f9f848faSopenharmony_ci if (id && (id->bInterfaceNumber == data_iface_no)) { 504f9f848faSopenharmony_ci sc->sc_ifaces_index[0] = i; 505f9f848faSopenharmony_ci sc->sc_ifaces_index[1] = uaa->info.bIfaceIndex; 506f9f848faSopenharmony_ci DPRINTFN(1, "index 0 = %d, index 1 = %d!\n", i, uaa->info.bIfaceIndex); 507f9f848faSopenharmony_ci usbd_set_parent_iface(uaa->device, i, uaa->info.bIfaceIndex); 508f9f848faSopenharmony_ci break; 509f9f848faSopenharmony_ci } 510f9f848faSopenharmony_ci } else { 511f9f848faSopenharmony_ci device_printf(dev, "no data interface found\n"); 512f9f848faSopenharmony_ci goto detach; 513f9f848faSopenharmony_ci } 514f9f848faSopenharmony_ci } 515f9f848faSopenharmony_ci 516f9f848faSopenharmony_ci /* 517f9f848faSopenharmony_ci * <quote> 518f9f848faSopenharmony_ci * 519f9f848faSopenharmony_ci * The Data Class interface of a networking device shall have 520f9f848faSopenharmony_ci * a minimum of two interface settings. The first setting 521f9f848faSopenharmony_ci * (the default interface setting) includes no endpoints and 522f9f848faSopenharmony_ci * therefore no networking traffic is exchanged whenever the 523f9f848faSopenharmony_ci * default interface setting is selected. One or more 524f9f848faSopenharmony_ci * additional interface settings are used for normal 525f9f848faSopenharmony_ci * operation, and therefore each includes a pair of endpoints 526f9f848faSopenharmony_ci * (one IN, and one OUT) to exchange network traffic. Select 527f9f848faSopenharmony_ci * an alternate interface setting to initialize the network 528f9f848faSopenharmony_ci * aspects of the device and to enable the exchange of 529f9f848faSopenharmony_ci * network traffic. 530f9f848faSopenharmony_ci * 531f9f848faSopenharmony_ci * </quote> 532f9f848faSopenharmony_ci * 533f9f848faSopenharmony_ci * Some devices, most notably cable modems, include interface 534f9f848faSopenharmony_ci * settings that have no IN or OUT endpoint, therefore loop 535f9f848faSopenharmony_ci * through the list of all available interface settings 536f9f848faSopenharmony_ci * looking for one with both IN and OUT endpoints. 537f9f848faSopenharmony_ci */ 538f9f848faSopenharmony_ci 539f9f848faSopenharmony_cialloc_transfers: 540f9f848faSopenharmony_ci 541f9f848faSopenharmony_ci pcfg = cdce_config; /* Default Configuration */ 542f9f848faSopenharmony_ci 543f9f848faSopenharmony_ci for (i = 0; i != 32; i++) { 544f9f848faSopenharmony_ci error = usbd_set_alt_interface_index(uaa->device, 545f9f848faSopenharmony_ci sc->sc_ifaces_index[0], i); 546f9f848faSopenharmony_ci if (error) { 547f9f848faSopenharmony_ci break; 548f9f848faSopenharmony_ci } 549f9f848faSopenharmony_ci 550f9f848faSopenharmony_ci#if CDCE_HAVE_NCM 551f9f848faSopenharmony_ci if ((i == 0) && (cdce_ncm_init(sc) == 0)) 552f9f848faSopenharmony_ci pcfg = cdce_ncm_config; 553f9f848faSopenharmony_ci#endif 554f9f848faSopenharmony_ci error = usbd_transfer_setup(uaa->device, 555f9f848faSopenharmony_ci sc->sc_ifaces_index, sc->sc_xfer, 556f9f848faSopenharmony_ci pcfg, CDCE_N_TRANSFER, sc, &sc->sc_mtx); 557f9f848faSopenharmony_ci 558f9f848faSopenharmony_ci if (error == 0) { 559f9f848faSopenharmony_ci break; 560f9f848faSopenharmony_ci } 561f9f848faSopenharmony_ci } 562f9f848faSopenharmony_ci 563f9f848faSopenharmony_ci if (error || (i == 32)) { 564f9f848faSopenharmony_ci device_printf(dev, "No valid alternate " 565f9f848faSopenharmony_ci "setting found\n"); 566f9f848faSopenharmony_ci goto detach; 567f9f848faSopenharmony_ci } 568f9f848faSopenharmony_ci 569f9f848faSopenharmony_ci ued = (const struct usb_cdc_ethernet_descriptor *)usbd_find_descriptor 570f9f848faSopenharmony_ci (uaa->device, NULL, uaa->info.bIfaceIndex, UDESC_CS_INTERFACE, 571f9f848faSopenharmony_ci 0xFF, UDESCSUB_CDC_ENF, 0xFF); 572f9f848faSopenharmony_ci 573f9f848faSopenharmony_ci if ((ued == NULL) || (ued->bLength < sizeof(*ued))) { 574f9f848faSopenharmony_ci error = USB_ERR_INVAL; 575f9f848faSopenharmony_ci } else { 576f9f848faSopenharmony_ci error = usbd_req_get_string_any(uaa->device, NULL, 577f9f848faSopenharmony_ci eaddr_str, sizeof(eaddr_str), ued->iMacAddress); 578f9f848faSopenharmony_ci } 579f9f848faSopenharmony_ci 580f9f848faSopenharmony_ci if (error) { 581f9f848faSopenharmony_ci /* fake MAC address */ 582f9f848faSopenharmony_ci 583f9f848faSopenharmony_ci device_printf(dev, "faking MAC address\n"); 584f9f848faSopenharmony_ci seed = CUR_TICKS; 585f9f848faSopenharmony_ci (void)memcpy_s(&sc->sc_ue.ue_eaddr[1], (NETIF_MAX_HWADDR_LEN - 2), &seed, sizeof(uint32_t)); 586f9f848faSopenharmony_ci sc->sc_ue.ue_eaddr[0] = 0x2a; 587f9f848faSopenharmony_ci sc->sc_ue.ue_eaddr[5] = device_get_unit(dev); 588f9f848faSopenharmony_ci 589f9f848faSopenharmony_ci } else { 590f9f848faSopenharmony_ci (void)memset_s(sc->sc_ue.ue_eaddr, sizeof(sc->sc_ue.ue_eaddr), 0, sizeof(sc->sc_ue.ue_eaddr)); 591f9f848faSopenharmony_ci 592f9f848faSopenharmony_ci for (i = 0; i != (NETIF_MAX_HWADDR_LEN * 2); i++) { 593f9f848faSopenharmony_ci char c = eaddr_str[i]; 594f9f848faSopenharmony_ci 595f9f848faSopenharmony_ci if (('0' <= c) && (c <= '9')) 596f9f848faSopenharmony_ci c -= '0'; 597f9f848faSopenharmony_ci else if (c != 0) 598f9f848faSopenharmony_ci c -= 'A' - 10; 599f9f848faSopenharmony_ci else 600f9f848faSopenharmony_ci break; 601f9f848faSopenharmony_ci 602f9f848faSopenharmony_ci c &= 0xf; 603f9f848faSopenharmony_ci 604f9f848faSopenharmony_ci if ((i & 1) == 0) 605f9f848faSopenharmony_ci c <<= 4; 606f9f848faSopenharmony_ci sc->sc_ue.ue_eaddr[i / 2] |= c; 607f9f848faSopenharmony_ci } 608f9f848faSopenharmony_ci 609f9f848faSopenharmony_ci if (uaa->usb_mode == USB_MODE_DEVICE) { 610f9f848faSopenharmony_ci /* 611f9f848faSopenharmony_ci * Do not use the same MAC address like the peer ! 612f9f848faSopenharmony_ci */ 613f9f848faSopenharmony_ci sc->sc_ue.ue_eaddr[5] ^= 0xFF; 614f9f848faSopenharmony_ci } 615f9f848faSopenharmony_ci } 616f9f848faSopenharmony_ci 617f9f848faSopenharmony_ci ue->ue_sc = sc; 618f9f848faSopenharmony_ci ue->ue_dev = dev; 619f9f848faSopenharmony_ci ue->ue_udev = uaa->device; 620f9f848faSopenharmony_ci ue->ue_mtx = &sc->sc_mtx; 621f9f848faSopenharmony_ci ue->ue_methods = &cdce_ue_methods; 622f9f848faSopenharmony_ci 623f9f848faSopenharmony_ci error = (usb_error_t)uether_ifattach(ue); 624f9f848faSopenharmony_ci if (error) { 625f9f848faSopenharmony_ci device_printf(dev, "could not attach interface\n"); 626f9f848faSopenharmony_ci goto detach; 627f9f848faSopenharmony_ci } 628f9f848faSopenharmony_ci return (0); /* success */ 629f9f848faSopenharmony_ci 630f9f848faSopenharmony_cidetach: 631f9f848faSopenharmony_ci (void)cdce_detach(dev); 632f9f848faSopenharmony_ci return (ENXIO); /* failure */ 633f9f848faSopenharmony_ci} 634f9f848faSopenharmony_ci 635f9f848faSopenharmony_cistatic int 636f9f848faSopenharmony_cicdce_detach(device_t dev) 637f9f848faSopenharmony_ci{ 638f9f848faSopenharmony_ci struct cdce_softc *sc = (struct cdce_softc *)device_get_softc(dev); 639f9f848faSopenharmony_ci struct usb_ether *ue = &sc->sc_ue; 640f9f848faSopenharmony_ci 641f9f848faSopenharmony_ci /* stop all USB transfers first */ 642f9f848faSopenharmony_ci usbd_transfer_unsetup(sc->sc_xfer, CDCE_N_TRANSFER); 643f9f848faSopenharmony_ci uether_ifdetach(ue); 644f9f848faSopenharmony_ci mtx_destroy(&sc->sc_mtx); 645f9f848faSopenharmony_ci 646f9f848faSopenharmony_ci return (0); 647f9f848faSopenharmony_ci} 648f9f848faSopenharmony_ci 649f9f848faSopenharmony_cistatic void 650f9f848faSopenharmony_cicdce_start(struct usb_ether *ue) 651f9f848faSopenharmony_ci{ 652f9f848faSopenharmony_ci struct cdce_softc *sc = (struct cdce_softc *)uether_getsc(ue); 653f9f848faSopenharmony_ci 654f9f848faSopenharmony_ci DPRINTFN(1, "\n"); 655f9f848faSopenharmony_ci /* 656f9f848faSopenharmony_ci * Start the USB transfers, if not already started: 657f9f848faSopenharmony_ci */ 658f9f848faSopenharmony_ci usbd_transfer_start(sc->sc_xfer[CDCE_BULK_TX]); 659f9f848faSopenharmony_ci usbd_transfer_start(sc->sc_xfer[CDCE_BULK_RX]); 660f9f848faSopenharmony_ci} 661f9f848faSopenharmony_ci 662f9f848faSopenharmony_cistatic void 663f9f848faSopenharmony_cicdce_free_queue(struct pbuf **ppm, uint8_t n) 664f9f848faSopenharmony_ci{ 665f9f848faSopenharmony_ci uint8_t x; 666f9f848faSopenharmony_ci for (x = 0; x != n; x++) { 667f9f848faSopenharmony_ci if (ppm[x] != NULL) { 668f9f848faSopenharmony_ci uether_freebuf(ppm[x]); 669f9f848faSopenharmony_ci ppm[x] = NULL; 670f9f848faSopenharmony_ci } 671f9f848faSopenharmony_ci } 672f9f848faSopenharmony_ci} 673f9f848faSopenharmony_ci 674f9f848faSopenharmony_ci/* 675f9f848faSopenharmony_ci * There is something wrong with the original function and delete the code; 676f9f848faSopenharmony_ci * If you want to use, you should realize it again. 677f9f848faSopenharmony_ci */ 678f9f848faSopenharmony_ciint 679f9f848faSopenharmony_cipbuf_append(struct pbuf *m0, int length, void* cp) 680f9f848faSopenharmony_ci{ 681f9f848faSopenharmony_ci return (0); 682f9f848faSopenharmony_ci} 683f9f848faSopenharmony_ci 684f9f848faSopenharmony_ci 685f9f848faSopenharmony_ci 686f9f848faSopenharmony_cistatic void 687f9f848faSopenharmony_cicdce_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) 688f9f848faSopenharmony_ci{ 689f9f848faSopenharmony_ci struct cdce_softc *sc = (struct cdce_softc *)usbd_xfer_softc(xfer); 690f9f848faSopenharmony_ci struct usb_ether *ue = &sc->sc_ue; 691f9f848faSopenharmony_ci struct pbuf *m; 692f9f848faSopenharmony_ci uint32_t crc; 693f9f848faSopenharmony_ci uint8_t x; 694f9f848faSopenharmony_ci int actlen, aframes; 695f9f848faSopenharmony_ci 696f9f848faSopenharmony_ci DPRINTFN(10, "\n"); 697f9f848faSopenharmony_ci 698f9f848faSopenharmony_ci usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL); 699f9f848faSopenharmony_ci 700f9f848faSopenharmony_ci switch (USB_GET_STATE(xfer)) { 701f9f848faSopenharmony_ci case USB_ST_TRANSFERRED: 702f9f848faSopenharmony_ci DPRINTFN(10, "transfer complete: %u bytes in %u frames\n",actlen, aframes); 703f9f848faSopenharmony_ci 704f9f848faSopenharmony_ci /* free all previous TX buffers */ 705f9f848faSopenharmony_ci cdce_free_queue(sc->sc_tx_buf, CDCE_FRAMES_MAX); 706f9f848faSopenharmony_ci 707f9f848faSopenharmony_ci /* FALLTHROUGH */ 708f9f848faSopenharmony_ci case USB_ST_SETUP: 709f9f848faSopenharmony_citr_setup: 710f9f848faSopenharmony_ci for (x = 0; x != CDCE_FRAMES_MAX; x++) { 711f9f848faSopenharmony_ci UE_LOCK(ue); 712f9f848faSopenharmony_ci IF_DEQUEUE(&(ue->ue_txq), m); 713f9f848faSopenharmony_ci UE_UNLOCK(ue); 714f9f848faSopenharmony_ci if (m == NULL) 715f9f848faSopenharmony_ci break; 716f9f848faSopenharmony_ci 717f9f848faSopenharmony_ci if (sc->sc_flags & CDCE_FLAG_ZAURUS) { 718f9f848faSopenharmony_ci /* 719f9f848faSopenharmony_ci * Zaurus wants a 32-bit CRC appended 720f9f848faSopenharmony_ci * to every frame 721f9f848faSopenharmony_ci */ 722f9f848faSopenharmony_ci 723f9f848faSopenharmony_ci crc = cdce_m_crc32(m, 0, m->len); 724f9f848faSopenharmony_ci crc = htole32(crc); 725f9f848faSopenharmony_ci 726f9f848faSopenharmony_ci if (!pbuf_append(m, 4, (void *)&crc)) { 727f9f848faSopenharmony_ci free(m); 728f9f848faSopenharmony_ci continue; 729f9f848faSopenharmony_ci } 730f9f848faSopenharmony_ci } 731f9f848faSopenharmony_ci 732f9f848faSopenharmony_ci sc->sc_tx_buf[x] = m; 733f9f848faSopenharmony_ci usbd_xfer_set_frame_data(xfer, x, m->payload, m->len); 734f9f848faSopenharmony_ci 735f9f848faSopenharmony_ci /* 736f9f848faSopenharmony_ci * If there's a BPF listener, bounce a copy of 737f9f848faSopenharmony_ci * this frame to him: 738f9f848faSopenharmony_ci */ 739f9f848faSopenharmony_ci } 740f9f848faSopenharmony_ci if (x != 0) { 741f9f848faSopenharmony_ci usbd_xfer_set_frames(xfer, x); 742f9f848faSopenharmony_ci usbd_transfer_submit(xfer); 743f9f848faSopenharmony_ci } 744f9f848faSopenharmony_ci break; 745f9f848faSopenharmony_ci 746f9f848faSopenharmony_ci default: /* Error */ 747f9f848faSopenharmony_ci DPRINTFN(11, "transfer error, %s\n",usbd_errstr(error)); 748f9f848faSopenharmony_ci PRINTK("transfer error, %s\n",usbd_errstr(error)); 749f9f848faSopenharmony_ci 750f9f848faSopenharmony_ci /* free all previous TX buffers */ 751f9f848faSopenharmony_ci cdce_free_queue(sc->sc_tx_buf, CDCE_FRAMES_MAX); 752f9f848faSopenharmony_ci 753f9f848faSopenharmony_ci if (error != USB_ERR_CANCELLED) { 754f9f848faSopenharmony_ci /* try to clear stall first */ 755f9f848faSopenharmony_ci usbd_xfer_set_stall(xfer); 756f9f848faSopenharmony_ci goto tr_setup; 757f9f848faSopenharmony_ci } 758f9f848faSopenharmony_ci break; 759f9f848faSopenharmony_ci } 760f9f848faSopenharmony_ci} 761f9f848faSopenharmony_ci 762f9f848faSopenharmony_cistatic uint32_t 763f9f848faSopenharmony_cicdce_m_crc32(struct pbuf *m, uint32_t src_offset, uint32_t src_len) 764f9f848faSopenharmony_ci{ 765f9f848faSopenharmony_ci uint32_t crc = 0xFFFFFFFF; 766f9f848faSopenharmony_ci 767f9f848faSopenharmony_ci crc = crc32(crc, m->payload, src_len); 768f9f848faSopenharmony_ci return (crc ^ 0xFFFFFFFF); 769f9f848faSopenharmony_ci} 770f9f848faSopenharmony_ci 771f9f848faSopenharmony_cistatic void 772f9f848faSopenharmony_cicdce_init(struct usb_ether *ue) 773f9f848faSopenharmony_ci{ 774f9f848faSopenharmony_ci struct cdce_softc *sc = (struct cdce_softc *)uether_getsc(ue); 775f9f848faSopenharmony_ci struct los_eth_driver *ifp = ue->ue_drv_sc; 776f9f848faSopenharmony_ci struct eth_drv_sc *drv_sc = (struct eth_drv_sc *)ifp->driver_context; 777f9f848faSopenharmony_ci 778f9f848faSopenharmony_ci DPRINTFN(1, "\n"); 779f9f848faSopenharmony_ci 780f9f848faSopenharmony_ci CDCE_LOCK_ASSERT(sc, MA_OWNED); 781f9f848faSopenharmony_ci 782f9f848faSopenharmony_ci drv_sc->state |= IFF_DRV_RUNNING; 783f9f848faSopenharmony_ci 784f9f848faSopenharmony_ci /* start interrupt transfer */ 785f9f848faSopenharmony_ci usbd_transfer_start(sc->sc_xfer[CDCE_INTR_RX]); 786f9f848faSopenharmony_ci usbd_transfer_start(sc->sc_xfer[CDCE_INTR_TX]); 787f9f848faSopenharmony_ci 788f9f848faSopenharmony_ci /* 789f9f848faSopenharmony_ci * Stall data write direction, which depends on USB mode. 790f9f848faSopenharmony_ci * 791f9f848faSopenharmony_ci * Some USB host stacks (e.g. Mac OS X) don't clears stall 792f9f848faSopenharmony_ci * bit as it should, so set it in our host mode only. 793f9f848faSopenharmony_ci */ 794f9f848faSopenharmony_ci if (usbd_get_mode(sc->sc_ue.ue_udev) == USB_MODE_HOST) 795f9f848faSopenharmony_ci usbd_xfer_set_stall(sc->sc_xfer[CDCE_BULK_TX]); 796f9f848faSopenharmony_ci 797f9f848faSopenharmony_ci /* start data transfers */ 798f9f848faSopenharmony_ci cdce_start(ue); 799f9f848faSopenharmony_ci} 800f9f848faSopenharmony_ci 801f9f848faSopenharmony_cistatic void 802f9f848faSopenharmony_cicdce_stop(struct usb_ether *ue) 803f9f848faSopenharmony_ci{ 804f9f848faSopenharmony_ci struct cdce_softc *sc = (struct cdce_softc *)uether_getsc(ue); 805f9f848faSopenharmony_ci struct los_eth_driver *ifp = ue->ue_drv_sc; 806f9f848faSopenharmony_ci struct eth_drv_sc *drv_sc = (struct eth_drv_sc *)ifp->driver_context; 807f9f848faSopenharmony_ci 808f9f848faSopenharmony_ci DPRINTFN(1, "\n"); 809f9f848faSopenharmony_ci 810f9f848faSopenharmony_ci CDCE_LOCK_ASSERT(sc, MA_OWNED); 811f9f848faSopenharmony_ci 812f9f848faSopenharmony_ci drv_sc->state &= ~IFF_DRV_RUNNING; 813f9f848faSopenharmony_ci 814f9f848faSopenharmony_ci /* 815f9f848faSopenharmony_ci * stop all the transfers, if not already stopped: 816f9f848faSopenharmony_ci */ 817f9f848faSopenharmony_ci usbd_transfer_stop(sc->sc_xfer[CDCE_BULK_RX]); 818f9f848faSopenharmony_ci usbd_transfer_stop(sc->sc_xfer[CDCE_BULK_TX]); 819f9f848faSopenharmony_ci usbd_transfer_stop(sc->sc_xfer[CDCE_INTR_RX]); 820f9f848faSopenharmony_ci usbd_transfer_stop(sc->sc_xfer[CDCE_INTR_TX]); 821f9f848faSopenharmony_ci} 822f9f848faSopenharmony_ci 823f9f848faSopenharmony_cistatic void 824f9f848faSopenharmony_cicdce_setmulti(struct usb_ether *ue) 825f9f848faSopenharmony_ci{ 826f9f848faSopenharmony_ci /* no-op */ 827f9f848faSopenharmony_ci return; 828f9f848faSopenharmony_ci} 829f9f848faSopenharmony_ci 830f9f848faSopenharmony_cistatic void 831f9f848faSopenharmony_cicdce_setpromisc(struct usb_ether *ue) 832f9f848faSopenharmony_ci{ 833f9f848faSopenharmony_ci /* no-op */ 834f9f848faSopenharmony_ci return; 835f9f848faSopenharmony_ci} 836f9f848faSopenharmony_ci 837f9f848faSopenharmony_cistatic int 838f9f848faSopenharmony_cicdce_suspend(device_t dev) 839f9f848faSopenharmony_ci{ 840f9f848faSopenharmony_ci device_printf(dev, "Suspending\n"); 841f9f848faSopenharmony_ci return (0); 842f9f848faSopenharmony_ci} 843f9f848faSopenharmony_ci 844f9f848faSopenharmony_cistatic int 845f9f848faSopenharmony_cicdce_resume(device_t dev) 846f9f848faSopenharmony_ci{ 847f9f848faSopenharmony_ci device_printf(dev, "Resuming\n"); 848f9f848faSopenharmony_ci return (0); 849f9f848faSopenharmony_ci} 850f9f848faSopenharmony_ci 851f9f848faSopenharmony_cistatic void 852f9f848faSopenharmony_cicdce_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) 853f9f848faSopenharmony_ci{ 854f9f848faSopenharmony_ci struct cdce_softc *sc = (struct cdce_softc *)usbd_xfer_softc(xfer); 855f9f848faSopenharmony_ci struct pbuf *m; 856f9f848faSopenharmony_ci uint8_t x; 857f9f848faSopenharmony_ci int actlen; 858f9f848faSopenharmony_ci int aframes; 859f9f848faSopenharmony_ci int len; 860f9f848faSopenharmony_ci 861f9f848faSopenharmony_ci DPRINTFN(1, "\n"); 862f9f848faSopenharmony_ci usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL); 863f9f848faSopenharmony_ci 864f9f848faSopenharmony_ci switch (USB_GET_STATE(xfer)) { 865f9f848faSopenharmony_ci case USB_ST_TRANSFERRED: 866f9f848faSopenharmony_ci 867f9f848faSopenharmony_ci DPRINTF("received %u bytes in %u frames\n", actlen, aframes); 868f9f848faSopenharmony_ci 869f9f848faSopenharmony_ci for (x = 0; x != aframes; x++) { 870f9f848faSopenharmony_ci m = sc->sc_rx_buf[x]; 871f9f848faSopenharmony_ci sc->sc_rx_buf[x] = NULL; 872f9f848faSopenharmony_ci len = usbd_xfer_frame_len(xfer, x); 873f9f848faSopenharmony_ci 874f9f848faSopenharmony_ci /* Strip off CRC added by Zaurus, if any */ 875f9f848faSopenharmony_ci if ((sc->sc_flags & CDCE_FLAG_ZAURUS) && len >= 14) 876f9f848faSopenharmony_ci len -= 4; 877f9f848faSopenharmony_ci 878f9f848faSopenharmony_ci if (len < (int)sizeof(struct ether_header)) { 879f9f848faSopenharmony_ci uether_freebuf(m); 880f9f848faSopenharmony_ci continue; 881f9f848faSopenharmony_ci } 882f9f848faSopenharmony_ci /* queue up mbuf */ 883f9f848faSopenharmony_ci (void)uether_rxmbuf(&sc->sc_ue, m, len); 884f9f848faSopenharmony_ci } 885f9f848faSopenharmony_ci 886f9f848faSopenharmony_ci /* FALLTHROUGH */ 887f9f848faSopenharmony_ci case USB_ST_SETUP: 888f9f848faSopenharmony_ci /* 889f9f848faSopenharmony_ci * TODO: Implement support for multi frame transfers, 890f9f848faSopenharmony_ci * when the USB hardware supports it. 891f9f848faSopenharmony_ci */ 892f9f848faSopenharmony_ci for (x = 0; x != 1; x++) { /* why x is alway 0? */ 893f9f848faSopenharmony_ci if (sc->sc_rx_buf[x] == NULL) { 894f9f848faSopenharmony_ci m = uether_newbuf(MAX_ETH_MSG); 895f9f848faSopenharmony_ci if (m == NULL) 896f9f848faSopenharmony_ci goto tr_stall; 897f9f848faSopenharmony_ci sc->sc_rx_buf[x] = m; 898f9f848faSopenharmony_ci } else { 899f9f848faSopenharmony_ci m = sc->sc_rx_buf[x]; 900f9f848faSopenharmony_ci } 901f9f848faSopenharmony_ci 902f9f848faSopenharmony_ci DPRINTFN(1, "new buffer length %d\n", m->len); 903f9f848faSopenharmony_ci usbd_xfer_set_frame_data(xfer, x, m->payload, m->len); 904f9f848faSopenharmony_ci } 905f9f848faSopenharmony_ci /* set number of frames and start hardware */ 906f9f848faSopenharmony_ci usbd_xfer_set_frames(xfer, x); 907f9f848faSopenharmony_ci usbd_transfer_submit(xfer); 908f9f848faSopenharmony_ci /* flush any received frames */ 909f9f848faSopenharmony_ci uether_rxflush(&sc->sc_ue); 910f9f848faSopenharmony_ci break; 911f9f848faSopenharmony_ci 912f9f848faSopenharmony_ci default: /* Error */ 913f9f848faSopenharmony_ci DPRINTF("error = %s\n",usbd_errstr(error)); 914f9f848faSopenharmony_ci 915f9f848faSopenharmony_ci if (error != USB_ERR_CANCELLED) { 916f9f848faSopenharmony_citr_stall: 917f9f848faSopenharmony_ci /* try to clear stall first */ 918f9f848faSopenharmony_ci usbd_xfer_set_stall(xfer); 919f9f848faSopenharmony_ci usbd_xfer_set_frames(xfer, 0); 920f9f848faSopenharmony_ci usbd_transfer_submit(xfer); 921f9f848faSopenharmony_ci break; 922f9f848faSopenharmony_ci } 923f9f848faSopenharmony_ci 924f9f848faSopenharmony_ci /* need to free the RX-mbufs when we are cancelled */ 925f9f848faSopenharmony_ci cdce_free_queue(sc->sc_rx_buf, CDCE_FRAMES_MAX); 926f9f848faSopenharmony_ci break; 927f9f848faSopenharmony_ci } 928f9f848faSopenharmony_ci} 929f9f848faSopenharmony_ci 930f9f848faSopenharmony_cistatic void 931f9f848faSopenharmony_cicdce_intr_read_callback(struct usb_xfer *xfer, usb_error_t error) 932f9f848faSopenharmony_ci{ 933f9f848faSopenharmony_ci int actlen; 934f9f848faSopenharmony_ci 935f9f848faSopenharmony_ci DPRINTFN(1, "\n"); 936f9f848faSopenharmony_ci 937f9f848faSopenharmony_ci usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 938f9f848faSopenharmony_ci 939f9f848faSopenharmony_ci switch (USB_GET_STATE(xfer)) { 940f9f848faSopenharmony_ci case USB_ST_TRANSFERRED: 941f9f848faSopenharmony_ci 942f9f848faSopenharmony_ci DPRINTF("cdce_intr_read_callback Received %d bytes\n", actlen); 943f9f848faSopenharmony_ci 944f9f848faSopenharmony_ci /* TODO: decode some indications */ 945f9f848faSopenharmony_ci 946f9f848faSopenharmony_ci /* FALLTHROUGH */ 947f9f848faSopenharmony_ci case USB_ST_SETUP: 948f9f848faSopenharmony_citr_setup: 949f9f848faSopenharmony_ci usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 950f9f848faSopenharmony_ci usbd_transfer_submit(xfer); 951f9f848faSopenharmony_ci break; 952f9f848faSopenharmony_ci 953f9f848faSopenharmony_ci default: /* Error */ 954f9f848faSopenharmony_ci if (error != USB_ERR_CANCELLED) { 955f9f848faSopenharmony_ci /* start clear stall */ 956f9f848faSopenharmony_ci usbd_xfer_set_stall(xfer); 957f9f848faSopenharmony_ci goto tr_setup; 958f9f848faSopenharmony_ci } 959f9f848faSopenharmony_ci break; 960f9f848faSopenharmony_ci } 961f9f848faSopenharmony_ci} 962f9f848faSopenharmony_ci 963f9f848faSopenharmony_cistatic void 964f9f848faSopenharmony_cicdce_intr_write_callback(struct usb_xfer *xfer, usb_error_t error) 965f9f848faSopenharmony_ci{ 966f9f848faSopenharmony_ci struct cdce_softc *sc = usbd_xfer_softc(xfer); 967f9f848faSopenharmony_ci struct usb_cdc_notification req; 968f9f848faSopenharmony_ci struct usb_page_cache *pc; 969f9f848faSopenharmony_ci uint32_t speed; 970f9f848faSopenharmony_ci int actlen; 971f9f848faSopenharmony_ci 972f9f848faSopenharmony_ci DPRINTFN(1, "\n"); 973f9f848faSopenharmony_ci 974f9f848faSopenharmony_ci usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 975f9f848faSopenharmony_ci 976f9f848faSopenharmony_ci switch (USB_GET_STATE(xfer)) { 977f9f848faSopenharmony_ci case USB_ST_TRANSFERRED: 978f9f848faSopenharmony_ci 979f9f848faSopenharmony_ci DPRINTF("Transferred %d bytes\n", actlen); 980f9f848faSopenharmony_ci 981f9f848faSopenharmony_ci switch (sc->sc_notify_state) { 982f9f848faSopenharmony_ci case CDCE_NOTIFY_NETWORK_CONNECTION: 983f9f848faSopenharmony_ci sc->sc_notify_state = CDCE_NOTIFY_SPEED_CHANGE; 984f9f848faSopenharmony_ci break; 985f9f848faSopenharmony_ci case CDCE_NOTIFY_SPEED_CHANGE: 986f9f848faSopenharmony_ci sc->sc_notify_state = CDCE_NOTIFY_DONE; 987f9f848faSopenharmony_ci break; 988f9f848faSopenharmony_ci default: 989f9f848faSopenharmony_ci break; 990f9f848faSopenharmony_ci } 991f9f848faSopenharmony_ci /* FALLTHROUGH */ 992f9f848faSopenharmony_ci case USB_ST_SETUP: 993f9f848faSopenharmony_citr_setup: 994f9f848faSopenharmony_ci /* 995f9f848faSopenharmony_ci * Inform host about connection. Required according to USB CDC 996f9f848faSopenharmony_ci * specification and communicating to Mac OS X USB host stack. 997f9f848faSopenharmony_ci * Some of the values seems ignored by Mac OS X though. 998f9f848faSopenharmony_ci */ 999f9f848faSopenharmony_ci if (sc->sc_notify_state == CDCE_NOTIFY_NETWORK_CONNECTION) { 1000f9f848faSopenharmony_ci req.bmRequestType = UCDC_NOTIFICATION; 1001f9f848faSopenharmony_ci req.bNotification = UCDC_N_NETWORK_CONNECTION; 1002f9f848faSopenharmony_ci req.wIndex[0] = sc->sc_ifaces_index[1]; 1003f9f848faSopenharmony_ci req.wIndex[1] = 0; 1004f9f848faSopenharmony_ci USETW(req.wValue, 1); /* Connected */ 1005f9f848faSopenharmony_ci USETW(req.wLength, 0); 1006f9f848faSopenharmony_ci 1007f9f848faSopenharmony_ci pc = usbd_xfer_get_frame(xfer, 0); 1008f9f848faSopenharmony_ci usbd_copy_in(pc, 0, &req, sizeof(req)); 1009f9f848faSopenharmony_ci usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); 1010f9f848faSopenharmony_ci usbd_xfer_set_frames(xfer, 1); 1011f9f848faSopenharmony_ci usbd_transfer_submit(xfer); 1012f9f848faSopenharmony_ci } else if (sc->sc_notify_state == CDCE_NOTIFY_SPEED_CHANGE) { 1013f9f848faSopenharmony_ci req.bmRequestType = UCDC_NOTIFICATION; 1014f9f848faSopenharmony_ci req.bNotification = UCDC_N_CONNECTION_SPEED_CHANGE; 1015f9f848faSopenharmony_ci req.wIndex[0] = sc->sc_ifaces_index[1]; 1016f9f848faSopenharmony_ci req.wIndex[1] = 0; 1017f9f848faSopenharmony_ci USETW(req.wValue, 0); 1018f9f848faSopenharmony_ci USETW(req.wLength, 8); 1019f9f848faSopenharmony_ci 1020f9f848faSopenharmony_ci /* Peak theoretical bulk trasfer rate in bits/s */ 1021f9f848faSopenharmony_ci if (usbd_get_speed(sc->sc_ue.ue_udev) != USB_SPEED_FULL) 1022f9f848faSopenharmony_ci speed = (13 * 512 * 8 * 1000 * 8); 1023f9f848faSopenharmony_ci else 1024f9f848faSopenharmony_ci speed = (19 * 64 * 1 * 1000 * 8); 1025f9f848faSopenharmony_ci 1026f9f848faSopenharmony_ci USETDW(req.data + 0, speed); /* Upstream bit rate */ 1027f9f848faSopenharmony_ci USETDW(req.data + 4, speed); /* Downstream bit rate */ 1028f9f848faSopenharmony_ci 1029f9f848faSopenharmony_ci pc = usbd_xfer_get_frame(xfer, 0); 1030f9f848faSopenharmony_ci usbd_copy_in(pc, 0, &req, sizeof(req)); 1031f9f848faSopenharmony_ci usbd_xfer_set_frame_len(xfer, 0, sizeof(req)); 1032f9f848faSopenharmony_ci usbd_xfer_set_frames(xfer, 1); 1033f9f848faSopenharmony_ci usbd_transfer_submit(xfer); 1034f9f848faSopenharmony_ci } 1035f9f848faSopenharmony_ci break; 1036f9f848faSopenharmony_ci 1037f9f848faSopenharmony_ci default: /* Error */ 1038f9f848faSopenharmony_ci if (error != USB_ERR_CANCELLED) { 1039f9f848faSopenharmony_ci /* start clear stall */ 1040f9f848faSopenharmony_ci usbd_xfer_set_stall(xfer); 1041f9f848faSopenharmony_ci goto tr_setup; 1042f9f848faSopenharmony_ci } 1043f9f848faSopenharmony_ci break; 1044f9f848faSopenharmony_ci } 1045f9f848faSopenharmony_ci} 1046f9f848faSopenharmony_ci 1047f9f848faSopenharmony_cistatic int 1048f9f848faSopenharmony_cicdce_handle_request(device_t dev, 1049f9f848faSopenharmony_ci const void *preq, void **pptr, uint16_t *plen, 1050f9f848faSopenharmony_ci uint16_t offset, uint8_t *pstate) 1051f9f848faSopenharmony_ci{ 1052f9f848faSopenharmony_ci struct cdce_softc *sc = device_get_softc(dev); 1053f9f848faSopenharmony_ci const struct usb_device_request *req = preq; 1054f9f848faSopenharmony_ci uint8_t is_complete = *pstate; 1055f9f848faSopenharmony_ci 1056f9f848faSopenharmony_ci /* 1057f9f848faSopenharmony_ci * When Mac OS X resumes after suspending it expects 1058f9f848faSopenharmony_ci * to be notified again after this request. 1059f9f848faSopenharmony_ci */ 1060f9f848faSopenharmony_ci if (req->bmRequestType == UT_WRITE_CLASS_INTERFACE && \ 1061f9f848faSopenharmony_ci req->bRequest == UCDC_NCM_SET_ETHERNET_PACKET_FILTER) { 1062f9f848faSopenharmony_ci if (is_complete == 1) { 1063f9f848faSopenharmony_ci mtx_lock(&sc->sc_mtx); 1064f9f848faSopenharmony_ci sc->sc_notify_state = CDCE_NOTIFY_SPEED_CHANGE; 1065f9f848faSopenharmony_ci usbd_transfer_start(sc->sc_xfer[CDCE_INTR_TX]); 1066f9f848faSopenharmony_ci mtx_unlock(&sc->sc_mtx); 1067f9f848faSopenharmony_ci } 1068f9f848faSopenharmony_ci 1069f9f848faSopenharmony_ci return (0); 1070f9f848faSopenharmony_ci } 1071f9f848faSopenharmony_ci 1072f9f848faSopenharmony_ci return (ENXIO); /* use builtin handler */ 1073f9f848faSopenharmony_ci} 1074f9f848faSopenharmony_ci 1075f9f848faSopenharmony_ci#if CDCE_HAVE_NCM 1076f9f848faSopenharmony_cistatic void 1077f9f848faSopenharmony_cicdce_ncm_tx_zero(struct usb_page_cache *pc, 1078f9f848faSopenharmony_ci uint32_t start, uint32_t end) 1079f9f848faSopenharmony_ci{ 1080f9f848faSopenharmony_ci DPRINTFN(1, "\n"); 1081f9f848faSopenharmony_ci 1082f9f848faSopenharmony_ci if (start >= CDCE_NCM_TX_MAXLEN) 1083f9f848faSopenharmony_ci return; 1084f9f848faSopenharmony_ci if (end > CDCE_NCM_TX_MAXLEN) 1085f9f848faSopenharmony_ci end = CDCE_NCM_TX_MAXLEN; 1086f9f848faSopenharmony_ci 1087f9f848faSopenharmony_ci usbd_frame_zero(pc, start, end - start); 1088f9f848faSopenharmony_ci} 1089f9f848faSopenharmony_ci 1090f9f848faSopenharmony_cistatic uint8_t 1091f9f848faSopenharmony_cicdce_ncm_fill_tx_frames(struct usb_xfer *xfer, uint8_t index) 1092f9f848faSopenharmony_ci{ 1093f9f848faSopenharmony_ci struct cdce_softc *sc = usbd_xfer_softc(xfer); 1094f9f848faSopenharmony_ci struct usb_ether *ue = &sc->sc_ue; 1095f9f848faSopenharmony_ci struct usb_page_cache *pc = usbd_xfer_get_frame(xfer, index); 1096f9f848faSopenharmony_ci struct pbuf *m; 1097f9f848faSopenharmony_ci uint32_t rem; 1098f9f848faSopenharmony_ci uint32_t offset; 1099f9f848faSopenharmony_ci uint32_t last_offset; 1100f9f848faSopenharmony_ci uint16_t n; 1101f9f848faSopenharmony_ci uint8_t retval; 1102f9f848faSopenharmony_ci 1103f9f848faSopenharmony_ci DPRINTFN(1, "\n"); 1104f9f848faSopenharmony_ci 1105f9f848faSopenharmony_ci usbd_xfer_set_frame_offset(xfer, index * CDCE_NCM_TX_MAXLEN, index); 1106f9f848faSopenharmony_ci 1107f9f848faSopenharmony_ci offset = sizeof(sc->sc_ncm.hdr) + 1108f9f848faSopenharmony_ci sizeof(sc->sc_ncm.dpt) + sizeof(sc->sc_ncm.dp); 1109f9f848faSopenharmony_ci 1110f9f848faSopenharmony_ci /* Store last valid offset before alignment */ 1111f9f848faSopenharmony_ci last_offset = offset; 1112f9f848faSopenharmony_ci 1113f9f848faSopenharmony_ci /* Align offset */ 1114f9f848faSopenharmony_ci offset = CDCE_NCM_ALIGN(sc->sc_ncm.tx_remainder, 1115f9f848faSopenharmony_ci offset, sc->sc_ncm.tx_modulus); 1116f9f848faSopenharmony_ci 1117f9f848faSopenharmony_ci /* Zero pad */ 1118f9f848faSopenharmony_ci cdce_ncm_tx_zero(pc, last_offset, offset); 1119f9f848faSopenharmony_ci 1120f9f848faSopenharmony_ci /* buffer full */ 1121f9f848faSopenharmony_ci retval = 2; 1122f9f848faSopenharmony_ci 1123f9f848faSopenharmony_ci for (n = 0; n != sc->sc_ncm.tx_nframe; n++) { 1124f9f848faSopenharmony_ci /* check if end of transmit buffer is reached */ 1125f9f848faSopenharmony_ci 1126f9f848faSopenharmony_ci if (offset >= sc->sc_ncm.tx_max) 1127f9f848faSopenharmony_ci break; 1128f9f848faSopenharmony_ci 1129f9f848faSopenharmony_ci /* compute maximum buffer size */ 1130f9f848faSopenharmony_ci 1131f9f848faSopenharmony_ci rem = sc->sc_ncm.tx_max - offset; 1132f9f848faSopenharmony_ci 1133f9f848faSopenharmony_ci IF_DEQUEUE(&(ue->ue_txq), m); 1134f9f848faSopenharmony_ci 1135f9f848faSopenharmony_ci if (m == NULL) { 1136f9f848faSopenharmony_ci /* buffer not full */ 1137f9f848faSopenharmony_ci retval = 1; 1138f9f848faSopenharmony_ci break; 1139f9f848faSopenharmony_ci } 1140f9f848faSopenharmony_ci 1141f9f848faSopenharmony_ci if (m->len > (int)rem) { 1142f9f848faSopenharmony_ci if (n == 0) { 1143f9f848faSopenharmony_ci /* The frame won't fit in our buffer */ 1144f9f848faSopenharmony_ci DPRINTFN(1, "Frame too big to be transmitted!\n"); 1145f9f848faSopenharmony_ci pbuf_free(m); 1146f9f848faSopenharmony_ci n--; 1147f9f848faSopenharmony_ci continue; 1148f9f848faSopenharmony_ci } 1149f9f848faSopenharmony_ci /* Wait till next buffer becomes ready */ 1150f9f848faSopenharmony_ci IF_PREPEND(&(ue->ue_txq), m); 1151f9f848faSopenharmony_ci break; 1152f9f848faSopenharmony_ci } 1153f9f848faSopenharmony_ci usbd_copy_in(pc, offset, m->payload, m->len); 1154f9f848faSopenharmony_ci 1155f9f848faSopenharmony_ci USETW(sc->sc_ncm.dp[n].wFrameLength, m->len); 1156f9f848faSopenharmony_ci USETW(sc->sc_ncm.dp[n].wFrameIndex, offset); 1157f9f848faSopenharmony_ci 1158f9f848faSopenharmony_ci /* Update offset */ 1159f9f848faSopenharmony_ci offset += m->len; 1160f9f848faSopenharmony_ci 1161f9f848faSopenharmony_ci /* Store last valid offset before alignment */ 1162f9f848faSopenharmony_ci last_offset = offset; 1163f9f848faSopenharmony_ci 1164f9f848faSopenharmony_ci /* Align offset */ 1165f9f848faSopenharmony_ci offset = CDCE_NCM_ALIGN(sc->sc_ncm.tx_remainder, 1166f9f848faSopenharmony_ci offset, sc->sc_ncm.tx_modulus); 1167f9f848faSopenharmony_ci 1168f9f848faSopenharmony_ci /* Zero pad */ 1169f9f848faSopenharmony_ci cdce_ncm_tx_zero(pc, last_offset, offset); 1170f9f848faSopenharmony_ci 1171f9f848faSopenharmony_ci /* Free mbuf */ 1172f9f848faSopenharmony_ci pbuf_free(m); 1173f9f848faSopenharmony_ci } 1174f9f848faSopenharmony_ci 1175f9f848faSopenharmony_ci if (n == 0) 1176f9f848faSopenharmony_ci return (0); 1177f9f848faSopenharmony_ci 1178f9f848faSopenharmony_ci rem = (sizeof(sc->sc_ncm.dpt) + (4 * n) + 4); 1179f9f848faSopenharmony_ci 1180f9f848faSopenharmony_ci USETW(sc->sc_ncm.dpt.wLength, rem); 1181f9f848faSopenharmony_ci 1182f9f848faSopenharmony_ci /* zero the rest of the data pointer entries */ 1183f9f848faSopenharmony_ci for (; n != CDCE_NCM_SUBFRAMES_MAX; n++) { 1184f9f848faSopenharmony_ci USETW(sc->sc_ncm.dp[n].wFrameLength, 0); 1185f9f848faSopenharmony_ci USETW(sc->sc_ncm.dp[n].wFrameIndex, 0); 1186f9f848faSopenharmony_ci } 1187f9f848faSopenharmony_ci 1188f9f848faSopenharmony_ci offset = last_offset; 1189f9f848faSopenharmony_ci 1190f9f848faSopenharmony_ci /* Align offset */ 1191f9f848faSopenharmony_ci offset = CDCE_NCM_ALIGN(0, offset, CDCE_NCM_TX_MINLEN); 1192f9f848faSopenharmony_ci 1193f9f848faSopenharmony_ci /* Optimise, save bandwidth and force short termination */ 1194f9f848faSopenharmony_ci if (offset >= sc->sc_ncm.tx_max) 1195f9f848faSopenharmony_ci offset = sc->sc_ncm.tx_max; 1196f9f848faSopenharmony_ci else 1197f9f848faSopenharmony_ci offset ++; 1198f9f848faSopenharmony_ci 1199f9f848faSopenharmony_ci /* Zero pad */ 1200f9f848faSopenharmony_ci cdce_ncm_tx_zero(pc, last_offset, offset); 1201f9f848faSopenharmony_ci 1202f9f848faSopenharmony_ci /* set frame length */ 1203f9f848faSopenharmony_ci usbd_xfer_set_frame_len(xfer, index, offset); 1204f9f848faSopenharmony_ci 1205f9f848faSopenharmony_ci /* Fill out 16-bit header */ 1206f9f848faSopenharmony_ci sc->sc_ncm.hdr.dwSignature[0] = 'N'; 1207f9f848faSopenharmony_ci sc->sc_ncm.hdr.dwSignature[1] = 'C'; 1208f9f848faSopenharmony_ci sc->sc_ncm.hdr.dwSignature[2] = 'M'; 1209f9f848faSopenharmony_ci sc->sc_ncm.hdr.dwSignature[3] = 'H'; 1210f9f848faSopenharmony_ci USETW(sc->sc_ncm.hdr.wHeaderLength, sizeof(sc->sc_ncm.hdr)); 1211f9f848faSopenharmony_ci USETW(sc->sc_ncm.hdr.wBlockLength, offset); 1212f9f848faSopenharmony_ci USETW(sc->sc_ncm.hdr.wSequence, sc->sc_ncm.tx_seq); 1213f9f848faSopenharmony_ci USETW(sc->sc_ncm.hdr.wDptIndex, sizeof(sc->sc_ncm.hdr)); 1214f9f848faSopenharmony_ci 1215f9f848faSopenharmony_ci sc->sc_ncm.tx_seq++; 1216f9f848faSopenharmony_ci 1217f9f848faSopenharmony_ci /* Fill out 16-bit frame table header */ 1218f9f848faSopenharmony_ci sc->sc_ncm.dpt.dwSignature[0] = 'N'; 1219f9f848faSopenharmony_ci sc->sc_ncm.dpt.dwSignature[1] = 'C'; 1220f9f848faSopenharmony_ci sc->sc_ncm.dpt.dwSignature[2] = 'M'; 1221f9f848faSopenharmony_ci sc->sc_ncm.dpt.dwSignature[3] = '0'; 1222f9f848faSopenharmony_ci USETW(sc->sc_ncm.dpt.wNextNdpIndex, 0); /* reserved */ 1223f9f848faSopenharmony_ci 1224f9f848faSopenharmony_ci usbd_copy_in(pc, 0, &(sc->sc_ncm.hdr), sizeof(sc->sc_ncm.hdr)); 1225f9f848faSopenharmony_ci usbd_copy_in(pc, sizeof(sc->sc_ncm.hdr), &(sc->sc_ncm.dpt), 1226f9f848faSopenharmony_ci sizeof(sc->sc_ncm.dpt)); 1227f9f848faSopenharmony_ci usbd_copy_in(pc, sizeof(sc->sc_ncm.hdr) + sizeof(sc->sc_ncm.dpt), 1228f9f848faSopenharmony_ci &(sc->sc_ncm.dp), sizeof(sc->sc_ncm.dp)); 1229f9f848faSopenharmony_ci return (retval); 1230f9f848faSopenharmony_ci} 1231f9f848faSopenharmony_ci 1232f9f848faSopenharmony_cistatic void 1233f9f848faSopenharmony_cicdce_ncm_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) 1234f9f848faSopenharmony_ci{ 1235f9f848faSopenharmony_ci uint16_t x; 1236f9f848faSopenharmony_ci uint8_t temp; 1237f9f848faSopenharmony_ci int actlen; 1238f9f848faSopenharmony_ci int aframes; 1239f9f848faSopenharmony_ci 1240f9f848faSopenharmony_ci DPRINTFN(1, "\n"); 1241f9f848faSopenharmony_ci 1242f9f848faSopenharmony_ci switch (USB_GET_STATE(xfer)) { 1243f9f848faSopenharmony_ci case USB_ST_TRANSFERRED: 1244f9f848faSopenharmony_ci 1245f9f848faSopenharmony_ci usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL); 1246f9f848faSopenharmony_ci 1247f9f848faSopenharmony_ci DPRINTFN(10, "transfer complete: " 1248f9f848faSopenharmony_ci "%u bytes in %u frames\n", actlen, aframes); 1249f9f848faSopenharmony_ci 1250f9f848faSopenharmony_ci case USB_ST_SETUP: 1251f9f848faSopenharmony_ci for (x = 0; x != CDCE_NCM_TX_FRAMES_MAX; x++) { 1252f9f848faSopenharmony_ci temp = cdce_ncm_fill_tx_frames(xfer, x); 1253f9f848faSopenharmony_ci if (temp == 0) 1254f9f848faSopenharmony_ci break; 1255f9f848faSopenharmony_ci if (temp == 1) { 1256f9f848faSopenharmony_ci x++; 1257f9f848faSopenharmony_ci break; 1258f9f848faSopenharmony_ci } 1259f9f848faSopenharmony_ci } 1260f9f848faSopenharmony_ci 1261f9f848faSopenharmony_ci if (x != 0) { 1262f9f848faSopenharmony_ci#ifdef LOSCFG_USB_DEBUG 1263f9f848faSopenharmony_ci usbd_xfer_set_interval(xfer, cdce_tx_interval); 1264f9f848faSopenharmony_ci#endif 1265f9f848faSopenharmony_ci usbd_xfer_set_frames(xfer, x); 1266f9f848faSopenharmony_ci usbd_transfer_submit(xfer); 1267f9f848faSopenharmony_ci } 1268f9f848faSopenharmony_ci break; 1269f9f848faSopenharmony_ci 1270f9f848faSopenharmony_ci default: /* Error */ 1271f9f848faSopenharmony_ci DPRINTFN(10, "Transfer error: %s\n", 1272f9f848faSopenharmony_ci usbd_errstr(error)); 1273f9f848faSopenharmony_ci 1274f9f848faSopenharmony_ci if (error != USB_ERR_CANCELLED) { 1275f9f848faSopenharmony_ci /* try to clear stall first */ 1276f9f848faSopenharmony_ci usbd_xfer_set_stall(xfer); 1277f9f848faSopenharmony_ci usbd_xfer_set_frames(xfer, 0); 1278f9f848faSopenharmony_ci usbd_transfer_submit(xfer); 1279f9f848faSopenharmony_ci } 1280f9f848faSopenharmony_ci break; 1281f9f848faSopenharmony_ci } 1282f9f848faSopenharmony_ci} 1283f9f848faSopenharmony_ci 1284f9f848faSopenharmony_cistatic void 1285f9f848faSopenharmony_cicdce_ncm_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) 1286f9f848faSopenharmony_ci{ 1287f9f848faSopenharmony_ci struct cdce_softc *sc = usbd_xfer_softc(xfer); 1288f9f848faSopenharmony_ci struct usb_page_cache *pc = usbd_xfer_get_frame(xfer, 0); 1289f9f848faSopenharmony_ci struct pbuf *m; 1290f9f848faSopenharmony_ci int sumdata; 1291f9f848faSopenharmony_ci int sumlen; 1292f9f848faSopenharmony_ci int actlen; 1293f9f848faSopenharmony_ci int aframes; 1294f9f848faSopenharmony_ci int temp; 1295f9f848faSopenharmony_ci int nframes; 1296f9f848faSopenharmony_ci int x; 1297f9f848faSopenharmony_ci int offset; 1298f9f848faSopenharmony_ci 1299f9f848faSopenharmony_ci DPRINTFN(1, "\n"); 1300f9f848faSopenharmony_ci 1301f9f848faSopenharmony_ci switch (USB_GET_STATE(xfer)) { 1302f9f848faSopenharmony_ci case USB_ST_TRANSFERRED: 1303f9f848faSopenharmony_ci 1304f9f848faSopenharmony_ci usbd_xfer_status(xfer, &actlen, &sumlen, &aframes, NULL); 1305f9f848faSopenharmony_ci 1306f9f848faSopenharmony_ci DPRINTFN(1, "received %u bytes in %u frames\n", 1307f9f848faSopenharmony_ci actlen, aframes); 1308f9f848faSopenharmony_ci 1309f9f848faSopenharmony_ci if (actlen < (int)(sizeof(sc->sc_ncm.hdr) + 1310f9f848faSopenharmony_ci sizeof(sc->sc_ncm.dpt))) { 1311f9f848faSopenharmony_ci DPRINTFN(1, "frame too short\n"); 1312f9f848faSopenharmony_ci goto tr_setup; 1313f9f848faSopenharmony_ci } 1314f9f848faSopenharmony_ci usbd_copy_out(pc, 0, &(sc->sc_ncm.hdr), 1315f9f848faSopenharmony_ci sizeof(sc->sc_ncm.hdr)); 1316f9f848faSopenharmony_ci 1317f9f848faSopenharmony_ci if ((sc->sc_ncm.hdr.dwSignature[0] != 'N') || 1318f9f848faSopenharmony_ci (sc->sc_ncm.hdr.dwSignature[1] != 'C') || 1319f9f848faSopenharmony_ci (sc->sc_ncm.hdr.dwSignature[2] != 'M') || 1320f9f848faSopenharmony_ci (sc->sc_ncm.hdr.dwSignature[3] != 'H')) { 1321f9f848faSopenharmony_ci DPRINTFN(1, "invalid HDR signature: " 1322f9f848faSopenharmony_ci "0x%02x:0x%02x:0x%02x:0x%02x\n", 1323f9f848faSopenharmony_ci sc->sc_ncm.hdr.dwSignature[0], 1324f9f848faSopenharmony_ci sc->sc_ncm.hdr.dwSignature[1], 1325f9f848faSopenharmony_ci sc->sc_ncm.hdr.dwSignature[2], 1326f9f848faSopenharmony_ci sc->sc_ncm.hdr.dwSignature[3]); 1327f9f848faSopenharmony_ci goto tr_stall; 1328f9f848faSopenharmony_ci } 1329f9f848faSopenharmony_ci temp = UGETW(sc->sc_ncm.hdr.wBlockLength); 1330f9f848faSopenharmony_ci if (temp > sumlen) { 1331f9f848faSopenharmony_ci DPRINTFN(1, "unsupported block length %u/%u\n", 1332f9f848faSopenharmony_ci temp, sumlen); 1333f9f848faSopenharmony_ci goto tr_stall; 1334f9f848faSopenharmony_ci } 1335f9f848faSopenharmony_ci temp = UGETW(sc->sc_ncm.hdr.wDptIndex); 1336f9f848faSopenharmony_ci if ((int)(temp + sizeof(sc->sc_ncm.dpt)) > actlen) { 1337f9f848faSopenharmony_ci DPRINTFN(1, "invalid DPT index: 0x%04x\n", temp); 1338f9f848faSopenharmony_ci goto tr_stall; 1339f9f848faSopenharmony_ci } 1340f9f848faSopenharmony_ci usbd_copy_out(pc, temp, &(sc->sc_ncm.dpt), 1341f9f848faSopenharmony_ci sizeof(sc->sc_ncm.dpt)); 1342f9f848faSopenharmony_ci 1343f9f848faSopenharmony_ci if ((sc->sc_ncm.dpt.dwSignature[0] != 'N') || 1344f9f848faSopenharmony_ci (sc->sc_ncm.dpt.dwSignature[1] != 'C') || 1345f9f848faSopenharmony_ci (sc->sc_ncm.dpt.dwSignature[2] != 'M') || 1346f9f848faSopenharmony_ci (sc->sc_ncm.dpt.dwSignature[3] != '0')) { 1347f9f848faSopenharmony_ci DPRINTFN(1, "invalid DPT signature" 1348f9f848faSopenharmony_ci "0x%02x:0x%02x:0x%02x:0x%02x\n", 1349f9f848faSopenharmony_ci sc->sc_ncm.dpt.dwSignature[0], 1350f9f848faSopenharmony_ci sc->sc_ncm.dpt.dwSignature[1], 1351f9f848faSopenharmony_ci sc->sc_ncm.dpt.dwSignature[2], 1352f9f848faSopenharmony_ci sc->sc_ncm.dpt.dwSignature[3]); 1353f9f848faSopenharmony_ci goto tr_stall; 1354f9f848faSopenharmony_ci } 1355f9f848faSopenharmony_ci nframes = UGETW(sc->sc_ncm.dpt.wLength) / 4; 1356f9f848faSopenharmony_ci 1357f9f848faSopenharmony_ci /* Subtract size of header and last zero padded entry */ 1358f9f848faSopenharmony_ci if (nframes >= (2 + 1)) 1359f9f848faSopenharmony_ci nframes -= (2 + 1); 1360f9f848faSopenharmony_ci else 1361f9f848faSopenharmony_ci nframes = 0; 1362f9f848faSopenharmony_ci 1363f9f848faSopenharmony_ci DPRINTFN(1, "nframes = %u\n", nframes); 1364f9f848faSopenharmony_ci 1365f9f848faSopenharmony_ci temp += sizeof(sc->sc_ncm.dpt); 1366f9f848faSopenharmony_ci 1367f9f848faSopenharmony_ci if ((temp + (4 * nframes)) > actlen) 1368f9f848faSopenharmony_ci goto tr_stall; 1369f9f848faSopenharmony_ci 1370f9f848faSopenharmony_ci if (nframes > CDCE_NCM_SUBFRAMES_MAX) { 1371f9f848faSopenharmony_ci DPRINTFN(1, "Truncating number of frames from %u to %u\n", 1372f9f848faSopenharmony_ci nframes, CDCE_NCM_SUBFRAMES_MAX); 1373f9f848faSopenharmony_ci nframes = CDCE_NCM_SUBFRAMES_MAX; 1374f9f848faSopenharmony_ci } 1375f9f848faSopenharmony_ci usbd_copy_out(pc, temp, &(sc->sc_ncm.dp), (4 * nframes)); 1376f9f848faSopenharmony_ci 1377f9f848faSopenharmony_ci sumdata = 0; 1378f9f848faSopenharmony_ci 1379f9f848faSopenharmony_ci for (x = 0; x != nframes; x++) { 1380f9f848faSopenharmony_ci 1381f9f848faSopenharmony_ci offset = UGETW(sc->sc_ncm.dp[x].wFrameIndex); 1382f9f848faSopenharmony_ci temp = UGETW(sc->sc_ncm.dp[x].wFrameLength); 1383f9f848faSopenharmony_ci 1384f9f848faSopenharmony_ci if ((offset == 0) || 1385f9f848faSopenharmony_ci (temp < (int)sizeof(struct ether_header)) || 1386f9f848faSopenharmony_ci (temp > (MCLBYTES - ETHER_ALIGN))) { 1387f9f848faSopenharmony_ci DPRINTFN(1, "NULL frame detected at %d\n", x); 1388f9f848faSopenharmony_ci m = NULL; 1389f9f848faSopenharmony_ci /* silently ignore this frame */ 1390f9f848faSopenharmony_ci continue; 1391f9f848faSopenharmony_ci } else if ((offset + temp) > actlen) { 1392f9f848faSopenharmony_ci DPRINTFN(1, "invalid frame " 1393f9f848faSopenharmony_ci "detected at %d\n", x); 1394f9f848faSopenharmony_ci m = NULL; 1395f9f848faSopenharmony_ci /* silently ignore this frame */ 1396f9f848faSopenharmony_ci continue; 1397f9f848faSopenharmony_ci } else { 1398f9f848faSopenharmony_ci /* if the tmep here is fragmentary,you could do deallocation */ 1399f9f848faSopenharmony_ci m = pbuf_alloc(PBUF_RAW, temp+ETH_PAD_SIZE, PBUF_RAM); 1400f9f848faSopenharmony_ci } 1401f9f848faSopenharmony_ci 1402f9f848faSopenharmony_ci DPRINTFN(16, "frame %u, offset = %u, length = %u \n", 1403f9f848faSopenharmony_ci x, offset, temp); 1404f9f848faSopenharmony_ci 1405f9f848faSopenharmony_ci /* check if we have a buffer */ 1406f9f848faSopenharmony_ci if (m) { 1407f9f848faSopenharmony_ci #if ETH_PAD_SIZE 1408f9f848faSopenharmony_ci pbuf_header(m, -ETH_PAD_SIZE); /* drop the padding word */ 1409f9f848faSopenharmony_ci #endif 1410f9f848faSopenharmony_ci 1411f9f848faSopenharmony_ci usbd_copy_out(pc, offset, m->payload, temp); 1412f9f848faSopenharmony_ci 1413f9f848faSopenharmony_ci #if ETH_PAD_SIZE 1414f9f848faSopenharmony_ci pbuf_header(m, ETH_PAD_SIZE); /* drop the padding word */ 1415f9f848faSopenharmony_ci #endif 1416f9f848faSopenharmony_ci 1417f9f848faSopenharmony_ci /* enqueue */ 1418f9f848faSopenharmony_ci uether_rxmbuf(&sc->sc_ue, m, temp); 1419f9f848faSopenharmony_ci 1420f9f848faSopenharmony_ci sumdata += temp; 1421f9f848faSopenharmony_ci } 1422f9f848faSopenharmony_ci } 1423f9f848faSopenharmony_ci 1424f9f848faSopenharmony_ci DPRINTFN(1, "Efficiency: %u/%u bytes\n", sumdata, actlen); 1425f9f848faSopenharmony_ci 1426f9f848faSopenharmony_ci case USB_ST_SETUP: 1427f9f848faSopenharmony_citr_setup: 1428f9f848faSopenharmony_ci usbd_xfer_set_frame_len(xfer, 0, sc->sc_ncm.rx_max); 1429f9f848faSopenharmony_ci usbd_xfer_set_frames(xfer, 1); 1430f9f848faSopenharmony_ci usbd_transfer_submit(xfer); 1431f9f848faSopenharmony_ci uether_rxflush(&sc->sc_ue); /* must be last */ 1432f9f848faSopenharmony_ci break; 1433f9f848faSopenharmony_ci 1434f9f848faSopenharmony_ci default: /* Error */ 1435f9f848faSopenharmony_ci DPRINTFN(1, "error = %s\n", 1436f9f848faSopenharmony_ci usbd_errstr(error)); 1437f9f848faSopenharmony_ci 1438f9f848faSopenharmony_ci if (error != USB_ERR_CANCELLED) { 1439f9f848faSopenharmony_citr_stall: 1440f9f848faSopenharmony_ci /* try to clear stall first */ 1441f9f848faSopenharmony_ci usbd_xfer_set_stall(xfer); 1442f9f848faSopenharmony_ci usbd_xfer_set_frames(xfer, 0); 1443f9f848faSopenharmony_ci usbd_transfer_submit(xfer); 1444f9f848faSopenharmony_ci } 1445f9f848faSopenharmony_ci break; 1446f9f848faSopenharmony_ci } 1447f9f848faSopenharmony_ci} 1448f9f848faSopenharmony_ci#endif 1449f9f848faSopenharmony_ci 1450f9f848faSopenharmony_ci#undef USB_DEBUG_VAR 1451