1 /*- 2 * Copyright (c) 2010 Hans Petter Selasky. All rights reserved. 3 * Copyright (c) 2009 Diego Giagio. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 /* 28 * Thanks to Diego Giagio for figuring out the programming details for 29 * the Apple iPhone Ethernet driver. 30 */ 31 32 #include <sys/cdefs.h> 33 __FBSDID("$FreeBSD$"); 34 35 #include <sys/stdint.h> 36 #include <sys/stddef.h> 37 #include <sys/param.h> 38 #include <sys/queue.h> 39 #include <sys/types.h> 40 #include <sys/systm.h> 41 #include <sys/kernel.h> 42 #include <sys/bus.h> 43 #include <sys/module.h> 44 #include <sys/lock.h> 45 #include <sys/mutex.h> 46 #include <sys/condvar.h> 47 #include <sys/sysctl.h> 48 #include <sys/sx.h> 49 #include <sys/unistd.h> 50 #include <sys/callout.h> 51 #include <sys/malloc.h> 52 #include <sys/priv.h> 53 54 #include <dev/usb/usb.h> 55 #include <dev/usb/usbdi.h> 56 #include <dev/usb/usbdi_util.h> 57 #include "usbdevs.h" 58 59 #define USB_DEBUG_VAR ipheth_debug 60 #include <dev/usb/usb_debug.h> 61 #include <dev/usb/usb_process.h> 62 63 #include <dev/usb/net/usb_ethernet.h> 64 #include <dev/usb/net/if_iphethvar.h> 65 66 static device_probe_t ipheth_probe; 67 static device_attach_t ipheth_attach; 68 static device_detach_t ipheth_detach; 69 70 static usb_callback_t ipheth_bulk_write_callback; 71 static usb_callback_t ipheth_bulk_read_callback; 72 73 static uether_fn_t ipheth_attach_post; 74 static uether_fn_t ipheth_tick; 75 static uether_fn_t ipheth_init; 76 static uether_fn_t ipheth_stop; 77 static uether_fn_t ipheth_start; 78 static uether_fn_t ipheth_setmulti; 79 static uether_fn_t ipheth_setpromisc; 80 81 #ifdef USB_DEBUG 82 static int ipheth_debug = 0; 83 84 static SYSCTL_NODE(_hw_usb, OID_AUTO, ipheth, CTLFLAG_RW, 0, "USB iPhone ethernet"); 85 SYSCTL_INT(_hw_usb_ipheth, OID_AUTO, debug, CTLFLAG_RW, &ipheth_debug, 0, "Debug level"); 86 #endif 87 88 static const struct usb_config ipheth_config[IPHETH_N_TRANSFER] = { 89 90 [IPHETH_BULK_RX] = { 91 .type = UE_BULK, 92 .endpoint = UE_ADDR_ANY, 93 .direction = UE_DIR_RX, 94 .frames = IPHETH_RX_FRAMES_MAX, 95 .bufsize = (IPHETH_RX_FRAMES_MAX * MCLBYTES), 96 .flags = {.short_frames_ok = 1,.short_xfer_ok = 1,.ext_buffer = 1,}, 97 .callback = ipheth_bulk_read_callback, 98 .timeout = 0, /* no timeout */ 99 }, 100 101 [IPHETH_BULK_TX] = { 102 .type = UE_BULK, 103 .endpoint = UE_ADDR_ANY, 104 .direction = UE_DIR_TX, 105 .frames = IPHETH_TX_FRAMES_MAX, 106 .bufsize = (IPHETH_TX_FRAMES_MAX * IPHETH_BUF_SIZE), 107 .flags = {.force_short_xfer = 1,}, 108 .callback = ipheth_bulk_write_callback, 109 .timeout = IPHETH_TX_TIMEOUT, 110 }, 111 }; 112 113 static device_method_t ipheth_methods[] = { 114 /* Device interface */ 115 DEVMETHOD(device_probe, ipheth_probe), 116 DEVMETHOD(device_attach, ipheth_attach), 117 DEVMETHOD(device_detach, ipheth_detach), 118 119 DEVMETHOD_END 120 }; 121 122 static driver_t ipheth_driver = { 123 .name = "ipheth", 124 .methods = ipheth_methods, 125 .size = sizeof(struct ipheth_softc), 126 }; 127 128 static devclass_t ipheth_devclass; 129 130 DRIVER_MODULE(ipheth, uhub, ipheth_driver, ipheth_devclass, NULL, 0); 131 MODULE_VERSION(ipheth, 1); 132 MODULE_DEPEND(ipheth, uether, 1, 1, 1); 133 MODULE_DEPEND(ipheth, usb, 1, 1, 1); 134 MODULE_DEPEND(ipheth, ether, 1, 1, 1); 135 136 static const struct usb_ether_methods ipheth_ue_methods = { 137 .ue_attach_post = ipheth_attach_post, 138 .ue_start = ipheth_start, 139 .ue_init = ipheth_init, 140 .ue_tick = ipheth_tick, 141 .ue_stop = ipheth_stop, 142 .ue_setmulti = ipheth_setmulti, 143 .ue_setpromisc = ipheth_setpromisc, 144 }; 145 146 #define IPHETH_ID(v,p,c,sc,pt) \ 147 USB_VENDOR(v), USB_PRODUCT(p), \ 148 USB_IFACE_CLASS(c), USB_IFACE_SUBCLASS(sc), \ 149 USB_IFACE_PROTOCOL(pt) 150 151 static const STRUCT_USB_HOST_ID ipheth_devs[] = { 152 {IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE, 153 IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, 154 IPHETH_USBINTF_PROTO)}, 155 {IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE_3G, 156 IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, 157 IPHETH_USBINTF_PROTO)}, 158 {IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE_3GS, 159 IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, 160 IPHETH_USBINTF_PROTO)}, 161 {IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE_4, 162 IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, 163 IPHETH_USBINTF_PROTO)}, 164 {IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE_4S, 165 IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, 166 IPHETH_USBINTF_PROTO)}, 167 {IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE_5, 168 IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, 169 IPHETH_USBINTF_PROTO)}, 170 }; 171 172 static int 173 ipheth_get_mac_addr(struct ipheth_softc *sc) 174 { 175 struct usb_device_request req; 176 int error; 177 178 req.bmRequestType = UT_READ_VENDOR_DEVICE; 179 req.bRequest = IPHETH_CMD_GET_MACADDR; 180 req.wValue[0] = 0; 181 req.wValue[1] = 0; 182 req.wIndex[0] = sc->sc_iface_no; 183 req.wIndex[1] = 0; 184 req.wLength[0] = ETHER_ADDR_LEN; 185 req.wLength[1] = 0; 186 187 error = usbd_do_request(sc->sc_ue.ue_udev, NULL, &req, sc->sc_data); 188 189 if (error) 190 return (error); 191 192 memcpy(sc->sc_ue.ue_eaddr, sc->sc_data, ETHER_ADDR_LEN); 193 194 return (0); 195 } 196 197 static int 198 ipheth_probe(device_t dev) 199 { 200 struct usb_attach_arg *uaa = device_get_ivars(dev); 201 202 if (uaa->usb_mode != USB_MODE_HOST) 203 return (ENXIO); 204 205 return (usbd_lookup_id_by_uaa(ipheth_devs, sizeof(ipheth_devs), uaa)); 206 } 207 208 static int 209 ipheth_attach(device_t dev) 210 { 211 struct ipheth_softc *sc = device_get_softc(dev); 212 struct usb_ether *ue = &sc->sc_ue; 213 struct usb_attach_arg *uaa = device_get_ivars(dev); 214 int error; 215 216 sc->sc_iface_no = uaa->info.bIfaceIndex; 217 218 device_set_usb_desc(dev); 219 220 mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 221 222 error = usbd_set_alt_interface_index(uaa->device, 223 uaa->info.bIfaceIndex, IPHETH_ALT_INTFNUM); 224 if (error) { 225 device_printf(dev, "Cannot set alternate setting\n"); 226 goto detach; 227 } 228 error = usbd_transfer_setup(uaa->device, &sc->sc_iface_no, 229 sc->sc_xfer, ipheth_config, IPHETH_N_TRANSFER, sc, &sc->sc_mtx); 230 if (error) { 231 device_printf(dev, "Cannot setup USB transfers\n"); 232 goto detach; 233 } 234 ue->ue_sc = sc; 235 ue->ue_dev = dev; 236 ue->ue_udev = uaa->device; 237 ue->ue_mtx = &sc->sc_mtx; 238 ue->ue_methods = &ipheth_ue_methods; 239 240 error = ipheth_get_mac_addr(sc); 241 if (error) { 242 device_printf(dev, "Cannot get MAC address\n"); 243 goto detach; 244 } 245 246 error = uether_ifattach(ue); 247 if (error) { 248 device_printf(dev, "could not attach interface\n"); 249 goto detach; 250 } 251 return (0); /* success */ 252 253 detach: 254 ipheth_detach(dev); 255 return (ENXIO); /* failure */ 256 } 257 258 static int 259 ipheth_detach(device_t dev) 260 { 261 struct ipheth_softc *sc = device_get_softc(dev); 262 struct usb_ether *ue = &sc->sc_ue; 263 264 /* stop all USB transfers first */ 265 usbd_transfer_unsetup(sc->sc_xfer, IPHETH_N_TRANSFER); 266 267 uether_ifdetach(ue); 268 269 mtx_destroy(&sc->sc_mtx); 270 271 return (0); 272 } 273 274 static void 275 ipheth_start(struct usb_ether *ue) 276 { 277 struct ipheth_softc *sc = uether_getsc(ue); 278 279 /* 280 * Start the USB transfers, if not already started: 281 */ 282 usbd_transfer_start(sc->sc_xfer[IPHETH_BULK_TX]); 283 usbd_transfer_start(sc->sc_xfer[IPHETH_BULK_RX]); 284 } 285 286 static void 287 ipheth_stop(struct usb_ether *ue) 288 { 289 struct ipheth_softc *sc = uether_getsc(ue); 290 291 /* 292 * Stop the USB transfers, if not already stopped: 293 */ 294 usbd_transfer_stop(sc->sc_xfer[IPHETH_BULK_TX]); 295 usbd_transfer_stop(sc->sc_xfer[IPHETH_BULK_RX]); 296 } 297 298 static void 299 ipheth_tick(struct usb_ether *ue) 300 { 301 struct ipheth_softc *sc = uether_getsc(ue); 302 struct usb_device_request req; 303 int error; 304 305 req.bmRequestType = UT_READ_VENDOR_DEVICE; 306 req.bRequest = IPHETH_CMD_CARRIER_CHECK; 307 req.wValue[0] = 0; 308 req.wValue[1] = 0; 309 req.wIndex[0] = sc->sc_iface_no; 310 req.wIndex[1] = 0; 311 req.wLength[0] = IPHETH_CTRL_BUF_SIZE; 312 req.wLength[1] = 0; 313 314 error = uether_do_request(ue, &req, sc->sc_data, IPHETH_CTRL_TIMEOUT); 315 316 if (error) 317 return; 318 319 sc->sc_carrier_on = 320 (sc->sc_data[0] == IPHETH_CARRIER_ON); 321 } 322 323 static void 324 ipheth_attach_post(struct usb_ether *ue) 325 { 326 327 } 328 329 static void 330 ipheth_init(struct usb_ether *ue) 331 { 332 struct ipheth_softc *sc = uether_getsc(ue); 333 struct ifnet *ifp = uether_getifp(ue); 334 335 IPHETH_LOCK_ASSERT(sc, MA_OWNED); 336 337 ifp->if_drv_flags |= IFF_DRV_RUNNING; 338 339 /* stall data write direction, which depends on USB mode */ 340 usbd_xfer_set_stall(sc->sc_xfer[IPHETH_BULK_TX]); 341 342 /* start data transfers */ 343 ipheth_start(ue); 344 } 345 346 static void 347 ipheth_setmulti(struct usb_ether *ue) 348 { 349 350 } 351 352 static void 353 ipheth_setpromisc(struct usb_ether *ue) 354 { 355 356 } 357 358 static void 359 ipheth_free_queue(struct mbuf **ppm, uint8_t n) 360 { 361 uint8_t x; 362 363 for (x = 0; x != n; x++) { 364 if (ppm[x] != NULL) { 365 m_freem(ppm[x]); 366 ppm[x] = NULL; 367 } 368 } 369 } 370 371 static void 372 ipheth_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) 373 { 374 struct ipheth_softc *sc = usbd_xfer_softc(xfer); 375 struct ifnet *ifp = uether_getifp(&sc->sc_ue); 376 struct usb_page_cache *pc; 377 struct mbuf *m; 378 uint8_t x; 379 int actlen; 380 int aframes; 381 382 usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL); 383 384 DPRINTFN(1, "\n"); 385 386 switch (USB_GET_STATE(xfer)) { 387 case USB_ST_TRANSFERRED: 388 DPRINTFN(11, "transfer complete: %u bytes in %u frames\n", 389 actlen, aframes); 390 391 ifp->if_opackets++; 392 393 /* free all previous TX buffers */ 394 ipheth_free_queue(sc->sc_tx_buf, IPHETH_TX_FRAMES_MAX); 395 396 /* FALLTHROUGH */ 397 case USB_ST_SETUP: 398 tr_setup: 399 for (x = 0; x != IPHETH_TX_FRAMES_MAX; x++) { 400 401 IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 402 403 if (m == NULL) 404 break; 405 406 usbd_xfer_set_frame_offset(xfer, 407 x * IPHETH_BUF_SIZE, x); 408 409 pc = usbd_xfer_get_frame(xfer, x); 410 411 sc->sc_tx_buf[x] = m; 412 413 if (m->m_pkthdr.len > IPHETH_BUF_SIZE) 414 m->m_pkthdr.len = IPHETH_BUF_SIZE; 415 416 usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len); 417 418 usbd_xfer_set_frame_len(xfer, x, IPHETH_BUF_SIZE); 419 420 if (IPHETH_BUF_SIZE != m->m_pkthdr.len) { 421 usbd_frame_zero(pc, m->m_pkthdr.len, 422 IPHETH_BUF_SIZE - m->m_pkthdr.len); 423 } 424 425 /* 426 * If there's a BPF listener, bounce a copy of 427 * this frame to him: 428 */ 429 BPF_MTAP(ifp, m); 430 } 431 if (x != 0) { 432 usbd_xfer_set_frames(xfer, x); 433 434 usbd_transfer_submit(xfer); 435 } 436 break; 437 438 default: /* Error */ 439 DPRINTFN(11, "transfer error, %s\n", 440 usbd_errstr(error)); 441 442 /* free all previous TX buffers */ 443 ipheth_free_queue(sc->sc_tx_buf, IPHETH_TX_FRAMES_MAX); 444 445 /* count output errors */ 446 ifp->if_oerrors++; 447 448 if (error != USB_ERR_CANCELLED) { 449 /* try to clear stall first */ 450 usbd_xfer_set_stall(xfer); 451 goto tr_setup; 452 } 453 break; 454 } 455 } 456 457 static void 458 ipheth_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) 459 { 460 struct ipheth_softc *sc = usbd_xfer_softc(xfer); 461 struct mbuf *m; 462 uint8_t x; 463 int actlen; 464 int aframes; 465 int len; 466 467 usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL); 468 469 switch (USB_GET_STATE(xfer)) { 470 case USB_ST_TRANSFERRED: 471 472 DPRINTF("received %u bytes in %u frames\n", actlen, aframes); 473 474 for (x = 0; x != aframes; x++) { 475 476 m = sc->sc_rx_buf[x]; 477 sc->sc_rx_buf[x] = NULL; 478 len = usbd_xfer_frame_len(xfer, x); 479 480 if (len < (int)(sizeof(struct ether_header) + 481 IPHETH_RX_ADJ)) { 482 m_freem(m); 483 continue; 484 } 485 486 m_adj(m, IPHETH_RX_ADJ); 487 488 /* queue up mbuf */ 489 uether_rxmbuf(&sc->sc_ue, m, len - IPHETH_RX_ADJ); 490 } 491 492 /* FALLTHROUGH */ 493 case USB_ST_SETUP: 494 495 for (x = 0; x != IPHETH_RX_FRAMES_MAX; x++) { 496 if (sc->sc_rx_buf[x] == NULL) { 497 m = uether_newbuf(); 498 if (m == NULL) 499 goto tr_stall; 500 501 /* cancel alignment for ethernet */ 502 m_adj(m, ETHER_ALIGN); 503 504 sc->sc_rx_buf[x] = m; 505 } else { 506 m = sc->sc_rx_buf[x]; 507 } 508 509 usbd_xfer_set_frame_data(xfer, x, m->m_data, m->m_len); 510 } 511 /* set number of frames and start hardware */ 512 usbd_xfer_set_frames(xfer, x); 513 usbd_transfer_submit(xfer); 514 /* flush any received frames */ 515 uether_rxflush(&sc->sc_ue); 516 break; 517 518 default: /* Error */ 519 DPRINTF("error = %s\n", usbd_errstr(error)); 520 521 if (error != USB_ERR_CANCELLED) { 522 tr_stall: 523 /* try to clear stall first */ 524 usbd_xfer_set_stall(xfer); 525 usbd_xfer_set_frames(xfer, 0); 526 usbd_transfer_submit(xfer); 527 break; 528 } 529 /* need to free the RX-mbufs when we are cancelled */ 530 ipheth_free_queue(sc->sc_rx_buf, IPHETH_RX_FRAMES_MAX); 531 break; 532 } 533 } 534