Deleted Added
full compact
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: head/sys/dev/usb/net/if_ipheth.c 241793 2012-10-21 03:30:36Z eadler $");
33__FBSDID("$FreeBSD: head/sys/dev/usb/net/if_ipheth.c 246128 2013-01-30 18:01:20Z sbz $");
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
66static device_probe_t ipheth_probe;
67static device_attach_t ipheth_attach;
68static device_detach_t ipheth_detach;
69
70static usb_callback_t ipheth_bulk_write_callback;
71static usb_callback_t ipheth_bulk_read_callback;
72
73static uether_fn_t ipheth_attach_post;
74static uether_fn_t ipheth_tick;
75static uether_fn_t ipheth_init;
76static uether_fn_t ipheth_stop;
77static uether_fn_t ipheth_start;
78static uether_fn_t ipheth_setmulti;
79static uether_fn_t ipheth_setpromisc;
80
81#ifdef USB_DEBUG
82static int ipheth_debug = 0;
83
84static SYSCTL_NODE(_hw_usb, OID_AUTO, ipheth, CTLFLAG_RW, 0, "USB iPhone ethernet");
85SYSCTL_INT(_hw_usb_ipheth, OID_AUTO, debug, CTLFLAG_RW, &ipheth_debug, 0, "Debug level");
86#endif
87
88static 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
113static 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 {0, 0}
119 DEVMETHOD_END
120};
121
122static driver_t ipheth_driver = {
123 .name = "ipheth",
124 .methods = ipheth_methods,
125 .size = sizeof(struct ipheth_softc),
126};
127
128static devclass_t ipheth_devclass;
129
130DRIVER_MODULE(ipheth, uhub, ipheth_driver, ipheth_devclass, NULL, 0);
131MODULE_VERSION(ipheth, 1);
132MODULE_DEPEND(ipheth, uether, 1, 1, 1);
133MODULE_DEPEND(ipheth, usb, 1, 1, 1);
134MODULE_DEPEND(ipheth, ether, 1, 1, 1);
135
136static 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
151static 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_5,
165 IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
166 IPHETH_USBINTF_PROTO)},
167};
168
169static int
170ipheth_get_mac_addr(struct ipheth_softc *sc)
171{
172 struct usb_device_request req;
173 int error;
174
175 req.bmRequestType = UT_READ_VENDOR_DEVICE;
176 req.bRequest = IPHETH_CMD_GET_MACADDR;
177 req.wValue[0] = 0;
178 req.wValue[1] = 0;
179 req.wIndex[0] = sc->sc_iface_no;
180 req.wIndex[1] = 0;
181 req.wLength[0] = ETHER_ADDR_LEN;
182 req.wLength[1] = 0;
183
184 error = usbd_do_request(sc->sc_ue.ue_udev, NULL, &req, sc->sc_data);
185
186 if (error)
187 return (error);
188
189 memcpy(sc->sc_ue.ue_eaddr, sc->sc_data, ETHER_ADDR_LEN);
190
191 return (0);
192}
193
194static int
195ipheth_probe(device_t dev)
196{
197 struct usb_attach_arg *uaa = device_get_ivars(dev);
198
199 if (uaa->usb_mode != USB_MODE_HOST)
200 return (ENXIO);
201
202 return (usbd_lookup_id_by_uaa(ipheth_devs, sizeof(ipheth_devs), uaa));
203}
204
205static int
206ipheth_attach(device_t dev)
207{
208 struct ipheth_softc *sc = device_get_softc(dev);
209 struct usb_ether *ue = &sc->sc_ue;
210 struct usb_attach_arg *uaa = device_get_ivars(dev);
211 int error;
212
213 sc->sc_iface_no = uaa->info.bIfaceIndex;
214
215 device_set_usb_desc(dev);
216
217 mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
218
219 error = usbd_set_alt_interface_index(uaa->device,
220 uaa->info.bIfaceIndex, IPHETH_ALT_INTFNUM);
221 if (error) {
222 device_printf(dev, "Cannot set alternate setting\n");
223 goto detach;
224 }
225 error = usbd_transfer_setup(uaa->device, &sc->sc_iface_no,
226 sc->sc_xfer, ipheth_config, IPHETH_N_TRANSFER, sc, &sc->sc_mtx);
227 if (error) {
228 device_printf(dev, "Cannot setup USB transfers\n");
229 goto detach;
230 }
231 ue->ue_sc = sc;
232 ue->ue_dev = dev;
233 ue->ue_udev = uaa->device;
234 ue->ue_mtx = &sc->sc_mtx;
235 ue->ue_methods = &ipheth_ue_methods;
236
237 error = ipheth_get_mac_addr(sc);
238 if (error) {
239 device_printf(dev, "Cannot get MAC address\n");
240 goto detach;
241 }
242
243 error = uether_ifattach(ue);
244 if (error) {
245 device_printf(dev, "could not attach interface\n");
246 goto detach;
247 }
248 return (0); /* success */
249
250detach:
251 ipheth_detach(dev);
252 return (ENXIO); /* failure */
253}
254
255static int
256ipheth_detach(device_t dev)
257{
258 struct ipheth_softc *sc = device_get_softc(dev);
259 struct usb_ether *ue = &sc->sc_ue;
260
261 /* stop all USB transfers first */
262 usbd_transfer_unsetup(sc->sc_xfer, IPHETH_N_TRANSFER);
263
264 uether_ifdetach(ue);
265
266 mtx_destroy(&sc->sc_mtx);
267
268 return (0);
269}
270
271static void
272ipheth_start(struct usb_ether *ue)
273{
274 struct ipheth_softc *sc = uether_getsc(ue);
275
276 /*
277 * Start the USB transfers, if not already started:
278 */
279 usbd_transfer_start(sc->sc_xfer[IPHETH_BULK_TX]);
280 usbd_transfer_start(sc->sc_xfer[IPHETH_BULK_RX]);
281}
282
283static void
284ipheth_stop(struct usb_ether *ue)
285{
286 struct ipheth_softc *sc = uether_getsc(ue);
287
288 /*
289 * Stop the USB transfers, if not already stopped:
290 */
291 usbd_transfer_stop(sc->sc_xfer[IPHETH_BULK_TX]);
292 usbd_transfer_stop(sc->sc_xfer[IPHETH_BULK_RX]);
293}
294
295static void
296ipheth_tick(struct usb_ether *ue)
297{
298 struct ipheth_softc *sc = uether_getsc(ue);
299 struct usb_device_request req;
300 int error;
301
302 req.bmRequestType = UT_READ_VENDOR_DEVICE;
303 req.bRequest = IPHETH_CMD_CARRIER_CHECK;
304 req.wValue[0] = 0;
305 req.wValue[1] = 0;
306 req.wIndex[0] = sc->sc_iface_no;
307 req.wIndex[1] = 0;
308 req.wLength[0] = IPHETH_CTRL_BUF_SIZE;
309 req.wLength[1] = 0;
310
311 error = uether_do_request(ue, &req, sc->sc_data, IPHETH_CTRL_TIMEOUT);
312
313 if (error)
314 return;
315
316 sc->sc_carrier_on =
317 (sc->sc_data[0] == IPHETH_CARRIER_ON);
318}
319
320static void
321ipheth_attach_post(struct usb_ether *ue)
322{
323
324}
325
326static void
327ipheth_init(struct usb_ether *ue)
328{
329 struct ipheth_softc *sc = uether_getsc(ue);
330 struct ifnet *ifp = uether_getifp(ue);
331
332 IPHETH_LOCK_ASSERT(sc, MA_OWNED);
333
334 ifp->if_drv_flags |= IFF_DRV_RUNNING;
335
336 /* stall data write direction, which depends on USB mode */
337 usbd_xfer_set_stall(sc->sc_xfer[IPHETH_BULK_TX]);
338
339 /* start data transfers */
340 ipheth_start(ue);
341}
342
343static void
344ipheth_setmulti(struct usb_ether *ue)
345{
346
347}
348
349static void
350ipheth_setpromisc(struct usb_ether *ue)
351{
352
353}
354
355static void
356ipheth_free_queue(struct mbuf **ppm, uint8_t n)
357{
358 uint8_t x;
359
360 for (x = 0; x != n; x++) {
361 if (ppm[x] != NULL) {
362 m_freem(ppm[x]);
363 ppm[x] = NULL;
364 }
365 }
366}
367
368static void
369ipheth_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
370{
371 struct ipheth_softc *sc = usbd_xfer_softc(xfer);
372 struct ifnet *ifp = uether_getifp(&sc->sc_ue);
373 struct usb_page_cache *pc;
374 struct mbuf *m;
375 uint8_t x;
376 int actlen;
377 int aframes;
378
379 usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL);
380
381 DPRINTFN(1, "\n");
382
383 switch (USB_GET_STATE(xfer)) {
384 case USB_ST_TRANSFERRED:
385 DPRINTFN(11, "transfer complete: %u bytes in %u frames\n",
386 actlen, aframes);
387
388 ifp->if_opackets++;
389
390 /* free all previous TX buffers */
391 ipheth_free_queue(sc->sc_tx_buf, IPHETH_TX_FRAMES_MAX);
392
393 /* FALLTHROUGH */
394 case USB_ST_SETUP:
395tr_setup:
396 for (x = 0; x != IPHETH_TX_FRAMES_MAX; x++) {
397
398 IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
399
400 if (m == NULL)
401 break;
402
403 usbd_xfer_set_frame_offset(xfer,
404 x * IPHETH_BUF_SIZE, x);
405
406 pc = usbd_xfer_get_frame(xfer, x);
407
408 sc->sc_tx_buf[x] = m;
409
410 if (m->m_pkthdr.len > IPHETH_BUF_SIZE)
411 m->m_pkthdr.len = IPHETH_BUF_SIZE;
412
413 usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len);
414
415 usbd_xfer_set_frame_len(xfer, x, IPHETH_BUF_SIZE);
416
417 if (IPHETH_BUF_SIZE != m->m_pkthdr.len) {
418 usbd_frame_zero(pc, m->m_pkthdr.len,
419 IPHETH_BUF_SIZE - m->m_pkthdr.len);
420 }
421
422 /*
423 * If there's a BPF listener, bounce a copy of
424 * this frame to him:
425 */
426 BPF_MTAP(ifp, m);
427 }
428 if (x != 0) {
429 usbd_xfer_set_frames(xfer, x);
430
431 usbd_transfer_submit(xfer);
432 }
433 break;
434
435 default: /* Error */
436 DPRINTFN(11, "transfer error, %s\n",
437 usbd_errstr(error));
438
439 /* free all previous TX buffers */
440 ipheth_free_queue(sc->sc_tx_buf, IPHETH_TX_FRAMES_MAX);
441
442 /* count output errors */
443 ifp->if_oerrors++;
444
445 if (error != USB_ERR_CANCELLED) {
446 /* try to clear stall first */
447 usbd_xfer_set_stall(xfer);
448 goto tr_setup;
449 }
450 break;
451 }
452}
453
454static void
455ipheth_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
456{
457 struct ipheth_softc *sc = usbd_xfer_softc(xfer);
458 struct mbuf *m;
459 uint8_t x;
460 int actlen;
461 int aframes;
462 int len;
463
464 usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL);
465
466 switch (USB_GET_STATE(xfer)) {
467 case USB_ST_TRANSFERRED:
468
469 DPRINTF("received %u bytes in %u frames\n", actlen, aframes);
470
471 for (x = 0; x != aframes; x++) {
472
473 m = sc->sc_rx_buf[x];
474 sc->sc_rx_buf[x] = NULL;
475 len = usbd_xfer_frame_len(xfer, x);
476
477 if (len < (int)(sizeof(struct ether_header) +
478 IPHETH_RX_ADJ)) {
479 m_freem(m);
480 continue;
481 }
482
483 m_adj(m, IPHETH_RX_ADJ);
484
485 /* queue up mbuf */
486 uether_rxmbuf(&sc->sc_ue, m, len - IPHETH_RX_ADJ);
487 }
488
489 /* FALLTHROUGH */
490 case USB_ST_SETUP:
491
492 for (x = 0; x != IPHETH_RX_FRAMES_MAX; x++) {
493 if (sc->sc_rx_buf[x] == NULL) {
494 m = uether_newbuf();
495 if (m == NULL)
496 goto tr_stall;
497
498 /* cancel alignment for ethernet */
499 m_adj(m, ETHER_ALIGN);
500
501 sc->sc_rx_buf[x] = m;
502 } else {
503 m = sc->sc_rx_buf[x];
504 }
505
506 usbd_xfer_set_frame_data(xfer, x, m->m_data, m->m_len);
507 }
508 /* set number of frames and start hardware */
509 usbd_xfer_set_frames(xfer, x);
510 usbd_transfer_submit(xfer);
511 /* flush any received frames */
512 uether_rxflush(&sc->sc_ue);
513 break;
514
515 default: /* Error */
516 DPRINTF("error = %s\n", usbd_errstr(error));
517
518 if (error != USB_ERR_CANCELLED) {
519 tr_stall:
520 /* try to clear stall first */
521 usbd_xfer_set_stall(xfer);
522 usbd_xfer_set_frames(xfer, 0);
523 usbd_transfer_submit(xfer);
524 break;
525 }
526 /* need to free the RX-mbufs when we are cancelled */
527 ipheth_free_queue(sc->sc_rx_buf, IPHETH_RX_FRAMES_MAX);
528 break;
529 }
530}