1213805Shselasky/*- 2213805Shselasky * Copyright (c) 2010 Hans Petter Selasky. All rights reserved. 3213805Shselasky * Copyright (c) 2009 Diego Giagio. All rights reserved. 4213805Shselasky * 5213805Shselasky * Redistribution and use in source and binary forms, with or without 6213805Shselasky * modification, are permitted provided that the following conditions 7213805Shselasky * are met: 8213805Shselasky * 1. Redistributions of source code must retain the above copyright 9213805Shselasky * notice, this list of conditions and the following disclaimer. 10213805Shselasky * 2. Redistributions in binary form must reproduce the above copyright 11213805Shselasky * notice, this list of conditions and the following disclaimer in the 12213805Shselasky * documentation and/or other materials provided with the distribution. 13213805Shselasky * 14213805Shselasky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15213805Shselasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16213805Shselasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17213805Shselasky * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18213805Shselasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19213805Shselasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20213805Shselasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21213805Shselasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22213805Shselasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23213805Shselasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24213805Shselasky * SUCH DAMAGE. 25213805Shselasky */ 26213805Shselasky 27213805Shselasky/* 28213805Shselasky * Thanks to Diego Giagio for figuring out the programming details for 29213805Shselasky * the Apple iPhone Ethernet driver. 30213805Shselasky */ 31213805Shselasky 32213805Shselasky#include <sys/cdefs.h> 33213805Shselasky__FBSDID("$FreeBSD$"); 34213805Shselasky 35213805Shselasky#include <sys/stdint.h> 36213805Shselasky#include <sys/stddef.h> 37213805Shselasky#include <sys/param.h> 38213805Shselasky#include <sys/queue.h> 39213805Shselasky#include <sys/types.h> 40213805Shselasky#include <sys/systm.h> 41213805Shselasky#include <sys/kernel.h> 42213805Shselasky#include <sys/bus.h> 43213805Shselasky#include <sys/module.h> 44213805Shselasky#include <sys/lock.h> 45213805Shselasky#include <sys/mutex.h> 46213805Shselasky#include <sys/condvar.h> 47257241Sglebius#include <sys/socket.h> 48213805Shselasky#include <sys/sysctl.h> 49213805Shselasky#include <sys/sx.h> 50213805Shselasky#include <sys/unistd.h> 51213805Shselasky#include <sys/callout.h> 52213805Shselasky#include <sys/malloc.h> 53213805Shselasky#include <sys/priv.h> 54213805Shselasky 55257241Sglebius#include <net/if.h> 56257241Sglebius#include <net/if_var.h> 57257241Sglebius 58213805Shselasky#include <dev/usb/usb.h> 59213805Shselasky#include <dev/usb/usbdi.h> 60213805Shselasky#include <dev/usb/usbdi_util.h> 61213805Shselasky#include "usbdevs.h" 62213805Shselasky 63213805Shselasky#define USB_DEBUG_VAR ipheth_debug 64213805Shselasky#include <dev/usb/usb_debug.h> 65213805Shselasky#include <dev/usb/usb_process.h> 66213805Shselasky 67213805Shselasky#include <dev/usb/net/usb_ethernet.h> 68213805Shselasky#include <dev/usb/net/if_iphethvar.h> 69213805Shselasky 70213805Shselaskystatic device_probe_t ipheth_probe; 71213805Shselaskystatic device_attach_t ipheth_attach; 72213805Shselaskystatic device_detach_t ipheth_detach; 73213805Shselasky 74213805Shselaskystatic usb_callback_t ipheth_bulk_write_callback; 75213805Shselaskystatic usb_callback_t ipheth_bulk_read_callback; 76213805Shselasky 77213805Shselaskystatic uether_fn_t ipheth_attach_post; 78213805Shselaskystatic uether_fn_t ipheth_tick; 79213805Shselaskystatic uether_fn_t ipheth_init; 80213805Shselaskystatic uether_fn_t ipheth_stop; 81213805Shselaskystatic uether_fn_t ipheth_start; 82213805Shselaskystatic uether_fn_t ipheth_setmulti; 83213805Shselaskystatic uether_fn_t ipheth_setpromisc; 84213805Shselasky 85213805Shselasky#ifdef USB_DEBUG 86213805Shselaskystatic int ipheth_debug = 0; 87213805Shselasky 88227309Sedstatic SYSCTL_NODE(_hw_usb, OID_AUTO, ipheth, CTLFLAG_RW, 0, "USB iPhone ethernet"); 89276701ShselaskySYSCTL_INT(_hw_usb_ipheth, OID_AUTO, debug, CTLFLAG_RWTUN, &ipheth_debug, 0, "Debug level"); 90213805Shselasky#endif 91213805Shselasky 92213805Shselaskystatic const struct usb_config ipheth_config[IPHETH_N_TRANSFER] = { 93213805Shselasky 94213805Shselasky [IPHETH_BULK_RX] = { 95213805Shselasky .type = UE_BULK, 96213805Shselasky .endpoint = UE_ADDR_ANY, 97213805Shselasky .direction = UE_DIR_RX, 98213805Shselasky .frames = IPHETH_RX_FRAMES_MAX, 99213805Shselasky .bufsize = (IPHETH_RX_FRAMES_MAX * MCLBYTES), 100213805Shselasky .flags = {.short_frames_ok = 1,.short_xfer_ok = 1,.ext_buffer = 1,}, 101213805Shselasky .callback = ipheth_bulk_read_callback, 102213805Shselasky .timeout = 0, /* no timeout */ 103213805Shselasky }, 104213805Shselasky 105213805Shselasky [IPHETH_BULK_TX] = { 106213805Shselasky .type = UE_BULK, 107213805Shselasky .endpoint = UE_ADDR_ANY, 108213805Shselasky .direction = UE_DIR_TX, 109213805Shselasky .frames = IPHETH_TX_FRAMES_MAX, 110213805Shselasky .bufsize = (IPHETH_TX_FRAMES_MAX * IPHETH_BUF_SIZE), 111213805Shselasky .flags = {.force_short_xfer = 1,}, 112213805Shselasky .callback = ipheth_bulk_write_callback, 113213805Shselasky .timeout = IPHETH_TX_TIMEOUT, 114213805Shselasky }, 115213805Shselasky}; 116213805Shselasky 117213805Shselaskystatic device_method_t ipheth_methods[] = { 118213805Shselasky /* Device interface */ 119213805Shselasky DEVMETHOD(device_probe, ipheth_probe), 120213805Shselasky DEVMETHOD(device_attach, ipheth_attach), 121213805Shselasky DEVMETHOD(device_detach, ipheth_detach), 122213805Shselasky 123246128Ssbz DEVMETHOD_END 124213805Shselasky}; 125213805Shselasky 126213805Shselaskystatic driver_t ipheth_driver = { 127213805Shselasky .name = "ipheth", 128213805Shselasky .methods = ipheth_methods, 129213805Shselasky .size = sizeof(struct ipheth_softc), 130213805Shselasky}; 131213805Shselasky 132213805Shselaskystatic devclass_t ipheth_devclass; 133213805Shselasky 134223486Shselaskystatic const STRUCT_USB_HOST_ID ipheth_devs[] = { 135253670Shselasky#if 0 136213805Shselasky {IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE, 137213805Shselasky IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, 138213805Shselasky IPHETH_USBINTF_PROTO)}, 139213805Shselasky {IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE_3G, 140213805Shselasky IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, 141213805Shselasky IPHETH_USBINTF_PROTO)}, 142213805Shselasky {IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE_3GS, 143213805Shselasky IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, 144213805Shselasky IPHETH_USBINTF_PROTO)}, 145213805Shselasky {IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE_4, 146213805Shselasky IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, 147213805Shselasky IPHETH_USBINTF_PROTO)}, 148251109Seadler {IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE_4S, 149251109Seadler IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, 150251109Seadler IPHETH_USBINTF_PROTO)}, 151241793Seadler {IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE_5, 152241793Seadler IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, 153241793Seadler IPHETH_USBINTF_PROTO)}, 154253670Shselasky#else 155253670Shselasky /* product agnostic interface match */ 156253670Shselasky {USB_VENDOR(USB_VENDOR_APPLE), 157253670Shselasky USB_IFACE_CLASS(IPHETH_USBINTF_CLASS), 158253670Shselasky USB_IFACE_SUBCLASS(IPHETH_USBINTF_SUBCLASS), 159253670Shselasky USB_IFACE_PROTOCOL(IPHETH_USBINTF_PROTO)}, 160253670Shselasky#endif 161213805Shselasky}; 162213805Shselasky 163292080SimpDRIVER_MODULE(ipheth, uhub, ipheth_driver, ipheth_devclass, NULL, 0); 164292080SimpMODULE_VERSION(ipheth, 1); 165292080SimpMODULE_DEPEND(ipheth, uether, 1, 1, 1); 166292080SimpMODULE_DEPEND(ipheth, usb, 1, 1, 1); 167292080SimpMODULE_DEPEND(ipheth, ether, 1, 1, 1); 168292080SimpUSB_PNP_HOST_INFO(ipheth_devs); 169292080Simp 170292080Simpstatic const struct usb_ether_methods ipheth_ue_methods = { 171292080Simp .ue_attach_post = ipheth_attach_post, 172292080Simp .ue_start = ipheth_start, 173292080Simp .ue_init = ipheth_init, 174292080Simp .ue_tick = ipheth_tick, 175292080Simp .ue_stop = ipheth_stop, 176292080Simp .ue_setmulti = ipheth_setmulti, 177292080Simp .ue_setpromisc = ipheth_setpromisc, 178292080Simp}; 179292080Simp 180292080Simp#define IPHETH_ID(v,p,c,sc,pt) \ 181292080Simp USB_VENDOR(v), USB_PRODUCT(p), \ 182292080Simp USB_IFACE_CLASS(c), USB_IFACE_SUBCLASS(sc), \ 183292080Simp USB_IFACE_PROTOCOL(pt) 184292080Simp 185213805Shselaskystatic int 186213805Shselaskyipheth_get_mac_addr(struct ipheth_softc *sc) 187213805Shselasky{ 188213805Shselasky struct usb_device_request req; 189213805Shselasky int error; 190213805Shselasky 191213805Shselasky req.bmRequestType = UT_READ_VENDOR_DEVICE; 192213805Shselasky req.bRequest = IPHETH_CMD_GET_MACADDR; 193213805Shselasky req.wValue[0] = 0; 194213805Shselasky req.wValue[1] = 0; 195213805Shselasky req.wIndex[0] = sc->sc_iface_no; 196213805Shselasky req.wIndex[1] = 0; 197213805Shselasky req.wLength[0] = ETHER_ADDR_LEN; 198213805Shselasky req.wLength[1] = 0; 199213805Shselasky 200213805Shselasky error = usbd_do_request(sc->sc_ue.ue_udev, NULL, &req, sc->sc_data); 201213805Shselasky 202213805Shselasky if (error) 203213805Shselasky return (error); 204213805Shselasky 205213805Shselasky memcpy(sc->sc_ue.ue_eaddr, sc->sc_data, ETHER_ADDR_LEN); 206213805Shselasky 207213805Shselasky return (0); 208213805Shselasky} 209213805Shselasky 210213805Shselaskystatic int 211213805Shselaskyipheth_probe(device_t dev) 212213805Shselasky{ 213213805Shselasky struct usb_attach_arg *uaa = device_get_ivars(dev); 214213805Shselasky 215213805Shselasky if (uaa->usb_mode != USB_MODE_HOST) 216213805Shselasky return (ENXIO); 217213805Shselasky 218213805Shselasky return (usbd_lookup_id_by_uaa(ipheth_devs, sizeof(ipheth_devs), uaa)); 219213805Shselasky} 220213805Shselasky 221213805Shselaskystatic int 222213805Shselaskyipheth_attach(device_t dev) 223213805Shselasky{ 224213805Shselasky struct ipheth_softc *sc = device_get_softc(dev); 225213805Shselasky struct usb_ether *ue = &sc->sc_ue; 226213805Shselasky struct usb_attach_arg *uaa = device_get_ivars(dev); 227213805Shselasky int error; 228213805Shselasky 229213805Shselasky sc->sc_iface_no = uaa->info.bIfaceIndex; 230213805Shselasky 231213805Shselasky device_set_usb_desc(dev); 232213805Shselasky 233213805Shselasky mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 234213805Shselasky 235213805Shselasky error = usbd_set_alt_interface_index(uaa->device, 236213805Shselasky uaa->info.bIfaceIndex, IPHETH_ALT_INTFNUM); 237213805Shselasky if (error) { 238213805Shselasky device_printf(dev, "Cannot set alternate setting\n"); 239213805Shselasky goto detach; 240213805Shselasky } 241213805Shselasky error = usbd_transfer_setup(uaa->device, &sc->sc_iface_no, 242213805Shselasky sc->sc_xfer, ipheth_config, IPHETH_N_TRANSFER, sc, &sc->sc_mtx); 243213805Shselasky if (error) { 244213805Shselasky device_printf(dev, "Cannot setup USB transfers\n"); 245213805Shselasky goto detach; 246213805Shselasky } 247213805Shselasky ue->ue_sc = sc; 248213805Shselasky ue->ue_dev = dev; 249213805Shselasky ue->ue_udev = uaa->device; 250213805Shselasky ue->ue_mtx = &sc->sc_mtx; 251213805Shselasky ue->ue_methods = &ipheth_ue_methods; 252213805Shselasky 253213805Shselasky error = ipheth_get_mac_addr(sc); 254213805Shselasky if (error) { 255213805Shselasky device_printf(dev, "Cannot get MAC address\n"); 256213805Shselasky goto detach; 257213805Shselasky } 258213805Shselasky 259213805Shselasky error = uether_ifattach(ue); 260213805Shselasky if (error) { 261213805Shselasky device_printf(dev, "could not attach interface\n"); 262213805Shselasky goto detach; 263213805Shselasky } 264213805Shselasky return (0); /* success */ 265213805Shselasky 266213805Shselaskydetach: 267213805Shselasky ipheth_detach(dev); 268213805Shselasky return (ENXIO); /* failure */ 269213805Shselasky} 270213805Shselasky 271213805Shselaskystatic int 272213805Shselaskyipheth_detach(device_t dev) 273213805Shselasky{ 274213805Shselasky struct ipheth_softc *sc = device_get_softc(dev); 275213805Shselasky struct usb_ether *ue = &sc->sc_ue; 276213805Shselasky 277213805Shselasky /* stop all USB transfers first */ 278213805Shselasky usbd_transfer_unsetup(sc->sc_xfer, IPHETH_N_TRANSFER); 279213805Shselasky 280213805Shselasky uether_ifdetach(ue); 281213805Shselasky 282213805Shselasky mtx_destroy(&sc->sc_mtx); 283213805Shselasky 284213805Shselasky return (0); 285213805Shselasky} 286213805Shselasky 287213805Shselaskystatic void 288213805Shselaskyipheth_start(struct usb_ether *ue) 289213805Shselasky{ 290213805Shselasky struct ipheth_softc *sc = uether_getsc(ue); 291213805Shselasky 292213805Shselasky /* 293213805Shselasky * Start the USB transfers, if not already started: 294213805Shselasky */ 295213805Shselasky usbd_transfer_start(sc->sc_xfer[IPHETH_BULK_TX]); 296213805Shselasky usbd_transfer_start(sc->sc_xfer[IPHETH_BULK_RX]); 297213805Shselasky} 298213805Shselasky 299213805Shselaskystatic void 300213805Shselaskyipheth_stop(struct usb_ether *ue) 301213805Shselasky{ 302213805Shselasky struct ipheth_softc *sc = uether_getsc(ue); 303213805Shselasky 304213805Shselasky /* 305213805Shselasky * Stop the USB transfers, if not already stopped: 306213805Shselasky */ 307213805Shselasky usbd_transfer_stop(sc->sc_xfer[IPHETH_BULK_TX]); 308213805Shselasky usbd_transfer_stop(sc->sc_xfer[IPHETH_BULK_RX]); 309213805Shselasky} 310213805Shselasky 311213805Shselaskystatic void 312213805Shselaskyipheth_tick(struct usb_ether *ue) 313213805Shselasky{ 314213805Shselasky struct ipheth_softc *sc = uether_getsc(ue); 315213805Shselasky struct usb_device_request req; 316213805Shselasky int error; 317213805Shselasky 318213805Shselasky req.bmRequestType = UT_READ_VENDOR_DEVICE; 319213805Shselasky req.bRequest = IPHETH_CMD_CARRIER_CHECK; 320213805Shselasky req.wValue[0] = 0; 321213805Shselasky req.wValue[1] = 0; 322213805Shselasky req.wIndex[0] = sc->sc_iface_no; 323213805Shselasky req.wIndex[1] = 0; 324213805Shselasky req.wLength[0] = IPHETH_CTRL_BUF_SIZE; 325213805Shselasky req.wLength[1] = 0; 326213805Shselasky 327213805Shselasky error = uether_do_request(ue, &req, sc->sc_data, IPHETH_CTRL_TIMEOUT); 328213805Shselasky 329213805Shselasky if (error) 330213805Shselasky return; 331213805Shselasky 332213805Shselasky sc->sc_carrier_on = 333213805Shselasky (sc->sc_data[0] == IPHETH_CARRIER_ON); 334213805Shselasky} 335213805Shselasky 336213805Shselaskystatic void 337213805Shselaskyipheth_attach_post(struct usb_ether *ue) 338213805Shselasky{ 339213805Shselasky 340213805Shselasky} 341213805Shselasky 342213805Shselaskystatic void 343213805Shselaskyipheth_init(struct usb_ether *ue) 344213805Shselasky{ 345213805Shselasky struct ipheth_softc *sc = uether_getsc(ue); 346213805Shselasky struct ifnet *ifp = uether_getifp(ue); 347213805Shselasky 348213805Shselasky IPHETH_LOCK_ASSERT(sc, MA_OWNED); 349213805Shselasky 350213805Shselasky ifp->if_drv_flags |= IFF_DRV_RUNNING; 351213805Shselasky 352213805Shselasky /* stall data write direction, which depends on USB mode */ 353213805Shselasky usbd_xfer_set_stall(sc->sc_xfer[IPHETH_BULK_TX]); 354213805Shselasky 355213805Shselasky /* start data transfers */ 356213805Shselasky ipheth_start(ue); 357213805Shselasky} 358213805Shselasky 359213805Shselaskystatic void 360213805Shselaskyipheth_setmulti(struct usb_ether *ue) 361213805Shselasky{ 362213805Shselasky 363213805Shselasky} 364213805Shselasky 365213805Shselaskystatic void 366213805Shselaskyipheth_setpromisc(struct usb_ether *ue) 367213805Shselasky{ 368213805Shselasky 369213805Shselasky} 370213805Shselasky 371213805Shselaskystatic void 372213805Shselaskyipheth_free_queue(struct mbuf **ppm, uint8_t n) 373213805Shselasky{ 374213805Shselasky uint8_t x; 375213805Shselasky 376213805Shselasky for (x = 0; x != n; x++) { 377213805Shselasky if (ppm[x] != NULL) { 378213805Shselasky m_freem(ppm[x]); 379213805Shselasky ppm[x] = NULL; 380213805Shselasky } 381213805Shselasky } 382213805Shselasky} 383213805Shselasky 384213805Shselaskystatic void 385213805Shselaskyipheth_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) 386213805Shselasky{ 387213805Shselasky struct ipheth_softc *sc = usbd_xfer_softc(xfer); 388213805Shselasky struct ifnet *ifp = uether_getifp(&sc->sc_ue); 389213805Shselasky struct usb_page_cache *pc; 390213805Shselasky struct mbuf *m; 391213805Shselasky uint8_t x; 392213805Shselasky int actlen; 393213805Shselasky int aframes; 394213805Shselasky 395213805Shselasky usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL); 396213805Shselasky 397213805Shselasky DPRINTFN(1, "\n"); 398213805Shselasky 399213805Shselasky switch (USB_GET_STATE(xfer)) { 400213805Shselasky case USB_ST_TRANSFERRED: 401213805Shselasky DPRINTFN(11, "transfer complete: %u bytes in %u frames\n", 402213805Shselasky actlen, aframes); 403213805Shselasky 404271832Sglebius if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 405213805Shselasky 406213805Shselasky /* free all previous TX buffers */ 407213805Shselasky ipheth_free_queue(sc->sc_tx_buf, IPHETH_TX_FRAMES_MAX); 408213805Shselasky 409213805Shselasky /* FALLTHROUGH */ 410213805Shselasky case USB_ST_SETUP: 411213805Shselaskytr_setup: 412213805Shselasky for (x = 0; x != IPHETH_TX_FRAMES_MAX; x++) { 413213805Shselasky 414213805Shselasky IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 415213805Shselasky 416213805Shselasky if (m == NULL) 417213805Shselasky break; 418213805Shselasky 419213805Shselasky usbd_xfer_set_frame_offset(xfer, 420213805Shselasky x * IPHETH_BUF_SIZE, x); 421213805Shselasky 422213805Shselasky pc = usbd_xfer_get_frame(xfer, x); 423213805Shselasky 424213805Shselasky sc->sc_tx_buf[x] = m; 425213805Shselasky 426213805Shselasky if (m->m_pkthdr.len > IPHETH_BUF_SIZE) 427213805Shselasky m->m_pkthdr.len = IPHETH_BUF_SIZE; 428213805Shselasky 429213805Shselasky usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len); 430213805Shselasky 431213805Shselasky usbd_xfer_set_frame_len(xfer, x, IPHETH_BUF_SIZE); 432213805Shselasky 433213805Shselasky if (IPHETH_BUF_SIZE != m->m_pkthdr.len) { 434213805Shselasky usbd_frame_zero(pc, m->m_pkthdr.len, 435213805Shselasky IPHETH_BUF_SIZE - m->m_pkthdr.len); 436213805Shselasky } 437213805Shselasky 438213805Shselasky /* 439213805Shselasky * If there's a BPF listener, bounce a copy of 440213805Shselasky * this frame to him: 441213805Shselasky */ 442213805Shselasky BPF_MTAP(ifp, m); 443213805Shselasky } 444213805Shselasky if (x != 0) { 445213805Shselasky usbd_xfer_set_frames(xfer, x); 446213805Shselasky 447213805Shselasky usbd_transfer_submit(xfer); 448213805Shselasky } 449213805Shselasky break; 450213805Shselasky 451213805Shselasky default: /* Error */ 452213805Shselasky DPRINTFN(11, "transfer error, %s\n", 453213805Shselasky usbd_errstr(error)); 454213805Shselasky 455213805Shselasky /* free all previous TX buffers */ 456213805Shselasky ipheth_free_queue(sc->sc_tx_buf, IPHETH_TX_FRAMES_MAX); 457213805Shselasky 458213805Shselasky /* count output errors */ 459271832Sglebius if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 460213805Shselasky 461213805Shselasky if (error != USB_ERR_CANCELLED) { 462213805Shselasky /* try to clear stall first */ 463213805Shselasky usbd_xfer_set_stall(xfer); 464213805Shselasky goto tr_setup; 465213805Shselasky } 466213805Shselasky break; 467213805Shselasky } 468213805Shselasky} 469213805Shselasky 470213805Shselaskystatic void 471213805Shselaskyipheth_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) 472213805Shselasky{ 473213805Shselasky struct ipheth_softc *sc = usbd_xfer_softc(xfer); 474213805Shselasky struct mbuf *m; 475213805Shselasky uint8_t x; 476213805Shselasky int actlen; 477213805Shselasky int aframes; 478213805Shselasky int len; 479213805Shselasky 480213805Shselasky usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL); 481213805Shselasky 482213805Shselasky switch (USB_GET_STATE(xfer)) { 483213805Shselasky case USB_ST_TRANSFERRED: 484213805Shselasky 485213805Shselasky DPRINTF("received %u bytes in %u frames\n", actlen, aframes); 486213805Shselasky 487213805Shselasky for (x = 0; x != aframes; x++) { 488213805Shselasky 489213805Shselasky m = sc->sc_rx_buf[x]; 490213805Shselasky sc->sc_rx_buf[x] = NULL; 491213805Shselasky len = usbd_xfer_frame_len(xfer, x); 492213805Shselasky 493233774Shselasky if (len < (int)(sizeof(struct ether_header) + 494213805Shselasky IPHETH_RX_ADJ)) { 495213805Shselasky m_freem(m); 496213805Shselasky continue; 497213805Shselasky } 498213805Shselasky 499213805Shselasky m_adj(m, IPHETH_RX_ADJ); 500213805Shselasky 501213805Shselasky /* queue up mbuf */ 502213805Shselasky uether_rxmbuf(&sc->sc_ue, m, len - IPHETH_RX_ADJ); 503213805Shselasky } 504213805Shselasky 505213805Shselasky /* FALLTHROUGH */ 506213805Shselasky case USB_ST_SETUP: 507213805Shselasky 508213805Shselasky for (x = 0; x != IPHETH_RX_FRAMES_MAX; x++) { 509213805Shselasky if (sc->sc_rx_buf[x] == NULL) { 510213805Shselasky m = uether_newbuf(); 511213805Shselasky if (m == NULL) 512213805Shselasky goto tr_stall; 513213805Shselasky 514213805Shselasky /* cancel alignment for ethernet */ 515213805Shselasky m_adj(m, ETHER_ALIGN); 516213805Shselasky 517213805Shselasky sc->sc_rx_buf[x] = m; 518213805Shselasky } else { 519213805Shselasky m = sc->sc_rx_buf[x]; 520213805Shselasky } 521213805Shselasky 522213805Shselasky usbd_xfer_set_frame_data(xfer, x, m->m_data, m->m_len); 523213805Shselasky } 524213805Shselasky /* set number of frames and start hardware */ 525213805Shselasky usbd_xfer_set_frames(xfer, x); 526213805Shselasky usbd_transfer_submit(xfer); 527213805Shselasky /* flush any received frames */ 528213805Shselasky uether_rxflush(&sc->sc_ue); 529213805Shselasky break; 530213805Shselasky 531213805Shselasky default: /* Error */ 532213805Shselasky DPRINTF("error = %s\n", usbd_errstr(error)); 533213805Shselasky 534213805Shselasky if (error != USB_ERR_CANCELLED) { 535213805Shselasky tr_stall: 536213805Shselasky /* try to clear stall first */ 537213805Shselasky usbd_xfer_set_stall(xfer); 538213805Shselasky usbd_xfer_set_frames(xfer, 0); 539213805Shselasky usbd_transfer_submit(xfer); 540213805Shselasky break; 541213805Shselasky } 542213805Shselasky /* need to free the RX-mbufs when we are cancelled */ 543213805Shselasky ipheth_free_queue(sc->sc_rx_buf, IPHETH_RX_FRAMES_MAX); 544213805Shselasky break; 545213805Shselasky } 546213805Shselasky} 547