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> 47213805Shselasky#include <sys/sysctl.h> 48213805Shselasky#include <sys/sx.h> 49213805Shselasky#include <sys/unistd.h> 50213805Shselasky#include <sys/callout.h> 51213805Shselasky#include <sys/malloc.h> 52213805Shselasky#include <sys/priv.h> 53213805Shselasky 54213805Shselasky#include <dev/usb/usb.h> 55213805Shselasky#include <dev/usb/usbdi.h> 56213805Shselasky#include <dev/usb/usbdi_util.h> 57213805Shselasky#include "usbdevs.h" 58213805Shselasky 59213805Shselasky#define USB_DEBUG_VAR ipheth_debug 60213805Shselasky#include <dev/usb/usb_debug.h> 61213805Shselasky#include <dev/usb/usb_process.h> 62213805Shselasky 63213805Shselasky#include <dev/usb/net/usb_ethernet.h> 64213805Shselasky#include <dev/usb/net/if_iphethvar.h> 65213805Shselasky 66213805Shselaskystatic device_probe_t ipheth_probe; 67213805Shselaskystatic device_attach_t ipheth_attach; 68213805Shselaskystatic device_detach_t ipheth_detach; 69213805Shselasky 70213805Shselaskystatic usb_callback_t ipheth_bulk_write_callback; 71213805Shselaskystatic usb_callback_t ipheth_bulk_read_callback; 72213805Shselasky 73213805Shselaskystatic uether_fn_t ipheth_attach_post; 74213805Shselaskystatic uether_fn_t ipheth_tick; 75213805Shselaskystatic uether_fn_t ipheth_init; 76213805Shselaskystatic uether_fn_t ipheth_stop; 77213805Shselaskystatic uether_fn_t ipheth_start; 78213805Shselaskystatic uether_fn_t ipheth_setmulti; 79213805Shselaskystatic uether_fn_t ipheth_setpromisc; 80213805Shselasky 81213805Shselasky#ifdef USB_DEBUG 82213805Shselaskystatic int ipheth_debug = 0; 83213805Shselasky 84227309Sedstatic SYSCTL_NODE(_hw_usb, OID_AUTO, ipheth, CTLFLAG_RW, 0, "USB iPhone ethernet"); 85213805ShselaskySYSCTL_INT(_hw_usb_ipheth, OID_AUTO, debug, CTLFLAG_RW, &ipheth_debug, 0, "Debug level"); 86213805Shselasky#endif 87213805Shselasky 88213805Shselaskystatic const struct usb_config ipheth_config[IPHETH_N_TRANSFER] = { 89213805Shselasky 90213805Shselasky [IPHETH_BULK_RX] = { 91213805Shselasky .type = UE_BULK, 92213805Shselasky .endpoint = UE_ADDR_ANY, 93213805Shselasky .direction = UE_DIR_RX, 94213805Shselasky .frames = IPHETH_RX_FRAMES_MAX, 95213805Shselasky .bufsize = (IPHETH_RX_FRAMES_MAX * MCLBYTES), 96213805Shselasky .flags = {.short_frames_ok = 1,.short_xfer_ok = 1,.ext_buffer = 1,}, 97213805Shselasky .callback = ipheth_bulk_read_callback, 98213805Shselasky .timeout = 0, /* no timeout */ 99213805Shselasky }, 100213805Shselasky 101213805Shselasky [IPHETH_BULK_TX] = { 102213805Shselasky .type = UE_BULK, 103213805Shselasky .endpoint = UE_ADDR_ANY, 104213805Shselasky .direction = UE_DIR_TX, 105213805Shselasky .frames = IPHETH_TX_FRAMES_MAX, 106213805Shselasky .bufsize = (IPHETH_TX_FRAMES_MAX * IPHETH_BUF_SIZE), 107213805Shselasky .flags = {.force_short_xfer = 1,}, 108213805Shselasky .callback = ipheth_bulk_write_callback, 109213805Shselasky .timeout = IPHETH_TX_TIMEOUT, 110213805Shselasky }, 111213805Shselasky}; 112213805Shselasky 113213805Shselaskystatic device_method_t ipheth_methods[] = { 114213805Shselasky /* Device interface */ 115213805Shselasky DEVMETHOD(device_probe, ipheth_probe), 116213805Shselasky DEVMETHOD(device_attach, ipheth_attach), 117213805Shselasky DEVMETHOD(device_detach, ipheth_detach), 118213805Shselasky 119246128Ssbz DEVMETHOD_END 120213805Shselasky}; 121213805Shselasky 122213805Shselaskystatic driver_t ipheth_driver = { 123213805Shselasky .name = "ipheth", 124213805Shselasky .methods = ipheth_methods, 125213805Shselasky .size = sizeof(struct ipheth_softc), 126213805Shselasky}; 127213805Shselasky 128213805Shselaskystatic devclass_t ipheth_devclass; 129213805Shselasky 130213805ShselaskyDRIVER_MODULE(ipheth, uhub, ipheth_driver, ipheth_devclass, NULL, 0); 131213805ShselaskyMODULE_VERSION(ipheth, 1); 132213805ShselaskyMODULE_DEPEND(ipheth, uether, 1, 1, 1); 133213805ShselaskyMODULE_DEPEND(ipheth, usb, 1, 1, 1); 134213805ShselaskyMODULE_DEPEND(ipheth, ether, 1, 1, 1); 135213805Shselasky 136213805Shselaskystatic const struct usb_ether_methods ipheth_ue_methods = { 137213805Shselasky .ue_attach_post = ipheth_attach_post, 138213805Shselasky .ue_start = ipheth_start, 139213805Shselasky .ue_init = ipheth_init, 140213805Shselasky .ue_tick = ipheth_tick, 141213805Shselasky .ue_stop = ipheth_stop, 142213805Shselasky .ue_setmulti = ipheth_setmulti, 143213805Shselasky .ue_setpromisc = ipheth_setpromisc, 144213805Shselasky}; 145213805Shselasky 146213805Shselasky#define IPHETH_ID(v,p,c,sc,pt) \ 147213805Shselasky USB_VENDOR(v), USB_PRODUCT(p), \ 148213805Shselasky USB_IFACE_CLASS(c), USB_IFACE_SUBCLASS(sc), \ 149213805Shselasky USB_IFACE_PROTOCOL(pt) 150213805Shselasky 151223486Shselaskystatic const STRUCT_USB_HOST_ID ipheth_devs[] = { 152253670Shselasky#if 0 153213805Shselasky {IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE, 154213805Shselasky IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, 155213805Shselasky IPHETH_USBINTF_PROTO)}, 156213805Shselasky {IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE_3G, 157213805Shselasky IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, 158213805Shselasky IPHETH_USBINTF_PROTO)}, 159213805Shselasky {IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE_3GS, 160213805Shselasky IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, 161213805Shselasky IPHETH_USBINTF_PROTO)}, 162213805Shselasky {IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE_4, 163213805Shselasky IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, 164213805Shselasky IPHETH_USBINTF_PROTO)}, 165251109Seadler {IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE_4S, 166251109Seadler IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, 167251109Seadler IPHETH_USBINTF_PROTO)}, 168241793Seadler {IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE_5, 169241793Seadler IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, 170241793Seadler IPHETH_USBINTF_PROTO)}, 171253670Shselasky#else 172253670Shselasky /* product agnostic interface match */ 173253670Shselasky {USB_VENDOR(USB_VENDOR_APPLE), 174253670Shselasky USB_IFACE_CLASS(IPHETH_USBINTF_CLASS), 175253670Shselasky USB_IFACE_SUBCLASS(IPHETH_USBINTF_SUBCLASS), 176253670Shselasky USB_IFACE_PROTOCOL(IPHETH_USBINTF_PROTO)}, 177253670Shselasky#endif 178213805Shselasky}; 179213805Shselasky 180213805Shselaskystatic int 181213805Shselaskyipheth_get_mac_addr(struct ipheth_softc *sc) 182213805Shselasky{ 183213805Shselasky struct usb_device_request req; 184213805Shselasky int error; 185213805Shselasky 186213805Shselasky req.bmRequestType = UT_READ_VENDOR_DEVICE; 187213805Shselasky req.bRequest = IPHETH_CMD_GET_MACADDR; 188213805Shselasky req.wValue[0] = 0; 189213805Shselasky req.wValue[1] = 0; 190213805Shselasky req.wIndex[0] = sc->sc_iface_no; 191213805Shselasky req.wIndex[1] = 0; 192213805Shselasky req.wLength[0] = ETHER_ADDR_LEN; 193213805Shselasky req.wLength[1] = 0; 194213805Shselasky 195213805Shselasky error = usbd_do_request(sc->sc_ue.ue_udev, NULL, &req, sc->sc_data); 196213805Shselasky 197213805Shselasky if (error) 198213805Shselasky return (error); 199213805Shselasky 200213805Shselasky memcpy(sc->sc_ue.ue_eaddr, sc->sc_data, ETHER_ADDR_LEN); 201213805Shselasky 202213805Shselasky return (0); 203213805Shselasky} 204213805Shselasky 205213805Shselaskystatic int 206213805Shselaskyipheth_probe(device_t dev) 207213805Shselasky{ 208213805Shselasky struct usb_attach_arg *uaa = device_get_ivars(dev); 209213805Shselasky 210213805Shselasky if (uaa->usb_mode != USB_MODE_HOST) 211213805Shselasky return (ENXIO); 212213805Shselasky 213213805Shselasky return (usbd_lookup_id_by_uaa(ipheth_devs, sizeof(ipheth_devs), uaa)); 214213805Shselasky} 215213805Shselasky 216213805Shselaskystatic int 217213805Shselaskyipheth_attach(device_t dev) 218213805Shselasky{ 219213805Shselasky struct ipheth_softc *sc = device_get_softc(dev); 220213805Shselasky struct usb_ether *ue = &sc->sc_ue; 221213805Shselasky struct usb_attach_arg *uaa = device_get_ivars(dev); 222213805Shselasky int error; 223213805Shselasky 224213805Shselasky sc->sc_iface_no = uaa->info.bIfaceIndex; 225213805Shselasky 226213805Shselasky device_set_usb_desc(dev); 227213805Shselasky 228213805Shselasky mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 229213805Shselasky 230213805Shselasky error = usbd_set_alt_interface_index(uaa->device, 231213805Shselasky uaa->info.bIfaceIndex, IPHETH_ALT_INTFNUM); 232213805Shselasky if (error) { 233213805Shselasky device_printf(dev, "Cannot set alternate setting\n"); 234213805Shselasky goto detach; 235213805Shselasky } 236213805Shselasky error = usbd_transfer_setup(uaa->device, &sc->sc_iface_no, 237213805Shselasky sc->sc_xfer, ipheth_config, IPHETH_N_TRANSFER, sc, &sc->sc_mtx); 238213805Shselasky if (error) { 239213805Shselasky device_printf(dev, "Cannot setup USB transfers\n"); 240213805Shselasky goto detach; 241213805Shselasky } 242213805Shselasky ue->ue_sc = sc; 243213805Shselasky ue->ue_dev = dev; 244213805Shselasky ue->ue_udev = uaa->device; 245213805Shselasky ue->ue_mtx = &sc->sc_mtx; 246213805Shselasky ue->ue_methods = &ipheth_ue_methods; 247213805Shselasky 248213805Shselasky error = ipheth_get_mac_addr(sc); 249213805Shselasky if (error) { 250213805Shselasky device_printf(dev, "Cannot get MAC address\n"); 251213805Shselasky goto detach; 252213805Shselasky } 253213805Shselasky 254213805Shselasky error = uether_ifattach(ue); 255213805Shselasky if (error) { 256213805Shselasky device_printf(dev, "could not attach interface\n"); 257213805Shselasky goto detach; 258213805Shselasky } 259213805Shselasky return (0); /* success */ 260213805Shselasky 261213805Shselaskydetach: 262213805Shselasky ipheth_detach(dev); 263213805Shselasky return (ENXIO); /* failure */ 264213805Shselasky} 265213805Shselasky 266213805Shselaskystatic int 267213805Shselaskyipheth_detach(device_t dev) 268213805Shselasky{ 269213805Shselasky struct ipheth_softc *sc = device_get_softc(dev); 270213805Shselasky struct usb_ether *ue = &sc->sc_ue; 271213805Shselasky 272213805Shselasky /* stop all USB transfers first */ 273213805Shselasky usbd_transfer_unsetup(sc->sc_xfer, IPHETH_N_TRANSFER); 274213805Shselasky 275213805Shselasky uether_ifdetach(ue); 276213805Shselasky 277213805Shselasky mtx_destroy(&sc->sc_mtx); 278213805Shselasky 279213805Shselasky return (0); 280213805Shselasky} 281213805Shselasky 282213805Shselaskystatic void 283213805Shselaskyipheth_start(struct usb_ether *ue) 284213805Shselasky{ 285213805Shselasky struct ipheth_softc *sc = uether_getsc(ue); 286213805Shselasky 287213805Shselasky /* 288213805Shselasky * Start the USB transfers, if not already started: 289213805Shselasky */ 290213805Shselasky usbd_transfer_start(sc->sc_xfer[IPHETH_BULK_TX]); 291213805Shselasky usbd_transfer_start(sc->sc_xfer[IPHETH_BULK_RX]); 292213805Shselasky} 293213805Shselasky 294213805Shselaskystatic void 295213805Shselaskyipheth_stop(struct usb_ether *ue) 296213805Shselasky{ 297213805Shselasky struct ipheth_softc *sc = uether_getsc(ue); 298213805Shselasky 299213805Shselasky /* 300213805Shselasky * Stop the USB transfers, if not already stopped: 301213805Shselasky */ 302213805Shselasky usbd_transfer_stop(sc->sc_xfer[IPHETH_BULK_TX]); 303213805Shselasky usbd_transfer_stop(sc->sc_xfer[IPHETH_BULK_RX]); 304213805Shselasky} 305213805Shselasky 306213805Shselaskystatic void 307213805Shselaskyipheth_tick(struct usb_ether *ue) 308213805Shselasky{ 309213805Shselasky struct ipheth_softc *sc = uether_getsc(ue); 310213805Shselasky struct usb_device_request req; 311213805Shselasky int error; 312213805Shselasky 313213805Shselasky req.bmRequestType = UT_READ_VENDOR_DEVICE; 314213805Shselasky req.bRequest = IPHETH_CMD_CARRIER_CHECK; 315213805Shselasky req.wValue[0] = 0; 316213805Shselasky req.wValue[1] = 0; 317213805Shselasky req.wIndex[0] = sc->sc_iface_no; 318213805Shselasky req.wIndex[1] = 0; 319213805Shselasky req.wLength[0] = IPHETH_CTRL_BUF_SIZE; 320213805Shselasky req.wLength[1] = 0; 321213805Shselasky 322213805Shselasky error = uether_do_request(ue, &req, sc->sc_data, IPHETH_CTRL_TIMEOUT); 323213805Shselasky 324213805Shselasky if (error) 325213805Shselasky return; 326213805Shselasky 327213805Shselasky sc->sc_carrier_on = 328213805Shselasky (sc->sc_data[0] == IPHETH_CARRIER_ON); 329213805Shselasky} 330213805Shselasky 331213805Shselaskystatic void 332213805Shselaskyipheth_attach_post(struct usb_ether *ue) 333213805Shselasky{ 334213805Shselasky 335213805Shselasky} 336213805Shselasky 337213805Shselaskystatic void 338213805Shselaskyipheth_init(struct usb_ether *ue) 339213805Shselasky{ 340213805Shselasky struct ipheth_softc *sc = uether_getsc(ue); 341213805Shselasky struct ifnet *ifp = uether_getifp(ue); 342213805Shselasky 343213805Shselasky IPHETH_LOCK_ASSERT(sc, MA_OWNED); 344213805Shselasky 345213805Shselasky ifp->if_drv_flags |= IFF_DRV_RUNNING; 346213805Shselasky 347213805Shselasky /* stall data write direction, which depends on USB mode */ 348213805Shselasky usbd_xfer_set_stall(sc->sc_xfer[IPHETH_BULK_TX]); 349213805Shselasky 350213805Shselasky /* start data transfers */ 351213805Shselasky ipheth_start(ue); 352213805Shselasky} 353213805Shselasky 354213805Shselaskystatic void 355213805Shselaskyipheth_setmulti(struct usb_ether *ue) 356213805Shselasky{ 357213805Shselasky 358213805Shselasky} 359213805Shselasky 360213805Shselaskystatic void 361213805Shselaskyipheth_setpromisc(struct usb_ether *ue) 362213805Shselasky{ 363213805Shselasky 364213805Shselasky} 365213805Shselasky 366213805Shselaskystatic void 367213805Shselaskyipheth_free_queue(struct mbuf **ppm, uint8_t n) 368213805Shselasky{ 369213805Shselasky uint8_t x; 370213805Shselasky 371213805Shselasky for (x = 0; x != n; x++) { 372213805Shselasky if (ppm[x] != NULL) { 373213805Shselasky m_freem(ppm[x]); 374213805Shselasky ppm[x] = NULL; 375213805Shselasky } 376213805Shselasky } 377213805Shselasky} 378213805Shselasky 379213805Shselaskystatic void 380213805Shselaskyipheth_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) 381213805Shselasky{ 382213805Shselasky struct ipheth_softc *sc = usbd_xfer_softc(xfer); 383213805Shselasky struct ifnet *ifp = uether_getifp(&sc->sc_ue); 384213805Shselasky struct usb_page_cache *pc; 385213805Shselasky struct mbuf *m; 386213805Shselasky uint8_t x; 387213805Shselasky int actlen; 388213805Shselasky int aframes; 389213805Shselasky 390213805Shselasky usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL); 391213805Shselasky 392213805Shselasky DPRINTFN(1, "\n"); 393213805Shselasky 394213805Shselasky switch (USB_GET_STATE(xfer)) { 395213805Shselasky case USB_ST_TRANSFERRED: 396213805Shselasky DPRINTFN(11, "transfer complete: %u bytes in %u frames\n", 397213805Shselasky actlen, aframes); 398213805Shselasky 399213805Shselasky ifp->if_opackets++; 400213805Shselasky 401213805Shselasky /* free all previous TX buffers */ 402213805Shselasky ipheth_free_queue(sc->sc_tx_buf, IPHETH_TX_FRAMES_MAX); 403213805Shselasky 404213805Shselasky /* FALLTHROUGH */ 405213805Shselasky case USB_ST_SETUP: 406213805Shselaskytr_setup: 407213805Shselasky for (x = 0; x != IPHETH_TX_FRAMES_MAX; x++) { 408213805Shselasky 409213805Shselasky IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 410213805Shselasky 411213805Shselasky if (m == NULL) 412213805Shselasky break; 413213805Shselasky 414213805Shselasky usbd_xfer_set_frame_offset(xfer, 415213805Shselasky x * IPHETH_BUF_SIZE, x); 416213805Shselasky 417213805Shselasky pc = usbd_xfer_get_frame(xfer, x); 418213805Shselasky 419213805Shselasky sc->sc_tx_buf[x] = m; 420213805Shselasky 421213805Shselasky if (m->m_pkthdr.len > IPHETH_BUF_SIZE) 422213805Shselasky m->m_pkthdr.len = IPHETH_BUF_SIZE; 423213805Shselasky 424213805Shselasky usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len); 425213805Shselasky 426213805Shselasky usbd_xfer_set_frame_len(xfer, x, IPHETH_BUF_SIZE); 427213805Shselasky 428213805Shselasky if (IPHETH_BUF_SIZE != m->m_pkthdr.len) { 429213805Shselasky usbd_frame_zero(pc, m->m_pkthdr.len, 430213805Shselasky IPHETH_BUF_SIZE - m->m_pkthdr.len); 431213805Shselasky } 432213805Shselasky 433213805Shselasky /* 434213805Shselasky * If there's a BPF listener, bounce a copy of 435213805Shselasky * this frame to him: 436213805Shselasky */ 437213805Shselasky BPF_MTAP(ifp, m); 438213805Shselasky } 439213805Shselasky if (x != 0) { 440213805Shselasky usbd_xfer_set_frames(xfer, x); 441213805Shselasky 442213805Shselasky usbd_transfer_submit(xfer); 443213805Shselasky } 444213805Shselasky break; 445213805Shselasky 446213805Shselasky default: /* Error */ 447213805Shselasky DPRINTFN(11, "transfer error, %s\n", 448213805Shselasky usbd_errstr(error)); 449213805Shselasky 450213805Shselasky /* free all previous TX buffers */ 451213805Shselasky ipheth_free_queue(sc->sc_tx_buf, IPHETH_TX_FRAMES_MAX); 452213805Shselasky 453213805Shselasky /* count output errors */ 454213805Shselasky ifp->if_oerrors++; 455213805Shselasky 456213805Shselasky if (error != USB_ERR_CANCELLED) { 457213805Shselasky /* try to clear stall first */ 458213805Shselasky usbd_xfer_set_stall(xfer); 459213805Shselasky goto tr_setup; 460213805Shselasky } 461213805Shselasky break; 462213805Shselasky } 463213805Shselasky} 464213805Shselasky 465213805Shselaskystatic void 466213805Shselaskyipheth_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) 467213805Shselasky{ 468213805Shselasky struct ipheth_softc *sc = usbd_xfer_softc(xfer); 469213805Shselasky struct mbuf *m; 470213805Shselasky uint8_t x; 471213805Shselasky int actlen; 472213805Shselasky int aframes; 473213805Shselasky int len; 474213805Shselasky 475213805Shselasky usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL); 476213805Shselasky 477213805Shselasky switch (USB_GET_STATE(xfer)) { 478213805Shselasky case USB_ST_TRANSFERRED: 479213805Shselasky 480213805Shselasky DPRINTF("received %u bytes in %u frames\n", actlen, aframes); 481213805Shselasky 482213805Shselasky for (x = 0; x != aframes; x++) { 483213805Shselasky 484213805Shselasky m = sc->sc_rx_buf[x]; 485213805Shselasky sc->sc_rx_buf[x] = NULL; 486213805Shselasky len = usbd_xfer_frame_len(xfer, x); 487213805Shselasky 488233774Shselasky if (len < (int)(sizeof(struct ether_header) + 489213805Shselasky IPHETH_RX_ADJ)) { 490213805Shselasky m_freem(m); 491213805Shselasky continue; 492213805Shselasky } 493213805Shselasky 494213805Shselasky m_adj(m, IPHETH_RX_ADJ); 495213805Shselasky 496213805Shselasky /* queue up mbuf */ 497213805Shselasky uether_rxmbuf(&sc->sc_ue, m, len - IPHETH_RX_ADJ); 498213805Shselasky } 499213805Shselasky 500213805Shselasky /* FALLTHROUGH */ 501213805Shselasky case USB_ST_SETUP: 502213805Shselasky 503213805Shselasky for (x = 0; x != IPHETH_RX_FRAMES_MAX; x++) { 504213805Shselasky if (sc->sc_rx_buf[x] == NULL) { 505213805Shselasky m = uether_newbuf(); 506213805Shselasky if (m == NULL) 507213805Shselasky goto tr_stall; 508213805Shselasky 509213805Shselasky /* cancel alignment for ethernet */ 510213805Shselasky m_adj(m, ETHER_ALIGN); 511213805Shselasky 512213805Shselasky sc->sc_rx_buf[x] = m; 513213805Shselasky } else { 514213805Shselasky m = sc->sc_rx_buf[x]; 515213805Shselasky } 516213805Shselasky 517213805Shselasky usbd_xfer_set_frame_data(xfer, x, m->m_data, m->m_len); 518213805Shselasky } 519213805Shselasky /* set number of frames and start hardware */ 520213805Shselasky usbd_xfer_set_frames(xfer, x); 521213805Shselasky usbd_transfer_submit(xfer); 522213805Shselasky /* flush any received frames */ 523213805Shselasky uether_rxflush(&sc->sc_ue); 524213805Shselasky break; 525213805Shselasky 526213805Shselasky default: /* Error */ 527213805Shselasky DPRINTF("error = %s\n", usbd_errstr(error)); 528213805Shselasky 529213805Shselasky if (error != USB_ERR_CANCELLED) { 530213805Shselasky tr_stall: 531213805Shselasky /* try to clear stall first */ 532213805Shselasky usbd_xfer_set_stall(xfer); 533213805Shselasky usbd_xfer_set_frames(xfer, 0); 534213805Shselasky usbd_transfer_submit(xfer); 535213805Shselasky break; 536213805Shselasky } 537213805Shselasky /* need to free the RX-mbufs when we are cancelled */ 538213805Shselasky ipheth_free_queue(sc->sc_rx_buf, IPHETH_RX_FRAMES_MAX); 539213805Shselasky break; 540213805Shselasky } 541213805Shselasky} 542