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