if_ipheth.c revision 213805
1132718Skan/*-
2169689Skan * Copyright (c) 2010 Hans Petter Selasky. All rights reserved.
3132718Skan * Copyright (c) 2009 Diego Giagio. All rights reserved.
4132718Skan *
5132718Skan * Redistribution and use in source and binary forms, with or without
6132718Skan * modification, are permitted provided that the following conditions
7132718Skan * are met:
8132718Skan * 1. Redistributions of source code must retain the above copyright
9132718Skan *    notice, this list of conditions and the following disclaimer.
10132718Skan * 2. Redistributions in binary form must reproduce the above copyright
11132718Skan *    notice, this list of conditions and the following disclaimer in the
12132718Skan *    documentation and/or other materials provided with the distribution.
13132718Skan *
14132718Skan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15132718Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16132718Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17132718Skan * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18132718Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19169689Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20169689Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21132718Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22169689Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23169689Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24169689Skan * SUCH DAMAGE.
25169689Skan */
26169689Skan
27169689Skan/*
28169689Skan * Thanks to Diego Giagio for figuring out the programming details for
29169689Skan * the Apple iPhone Ethernet driver.
30169689Skan */
31169689Skan
32169689Skan#include <sys/cdefs.h>
33169689Skan__FBSDID("$FreeBSD: head/sys/dev/usb/net/if_ipheth.c 213805 2010-10-13 21:36:42Z hselasky $");
34169689Skan
35169689Skan#include <sys/stdint.h>
36169689Skan#include <sys/stddef.h>
37169689Skan#include <sys/param.h>
38169689Skan#include <sys/queue.h>
39169689Skan#include <sys/types.h>
40169689Skan#include <sys/systm.h>
41169689Skan#include <sys/kernel.h>
42169689Skan#include <sys/bus.h>
43169689Skan#include <sys/linker_set.h>
44169689Skan#include <sys/module.h>
45169689Skan#include <sys/lock.h>
46169689Skan#include <sys/mutex.h>
47169689Skan#include <sys/condvar.h>
48169689Skan#include <sys/sysctl.h>
49169689Skan#include <sys/sx.h>
50169689Skan#include <sys/unistd.h>
51169689Skan#include <sys/callout.h>
52169689Skan#include <sys/malloc.h>
53169689Skan#include <sys/priv.h>
54169689Skan
55169689Skan#include <dev/usb/usb.h>
56169689Skan#include <dev/usb/usbdi.h>
57169689Skan#include <dev/usb/usbdi_util.h>
58169689Skan#include "usbdevs.h"
59169689Skan
60169689Skan#define	USB_DEBUG_VAR ipheth_debug
61169689Skan#include <dev/usb/usb_debug.h>
62169689Skan#include <dev/usb/usb_process.h>
63169689Skan
64169689Skan#include <dev/usb/net/usb_ethernet.h>
65169689Skan#include <dev/usb/net/if_iphethvar.h>
66169689Skan
67169689Skanstatic device_probe_t ipheth_probe;
68169689Skanstatic device_attach_t ipheth_attach;
69169689Skanstatic device_detach_t ipheth_detach;
70169689Skan
71169689Skanstatic usb_callback_t ipheth_bulk_write_callback;
72169689Skanstatic usb_callback_t ipheth_bulk_read_callback;
73169689Skan
74169689Skanstatic uether_fn_t ipheth_attach_post;
75169689Skanstatic uether_fn_t ipheth_tick;
76169689Skanstatic uether_fn_t ipheth_init;
77169689Skanstatic uether_fn_t ipheth_stop;
78169689Skanstatic uether_fn_t ipheth_start;
79169689Skanstatic uether_fn_t ipheth_setmulti;
80169689Skanstatic uether_fn_t ipheth_setpromisc;
81169689Skan
82132718Skan#ifdef USB_DEBUG
83132718Skanstatic int ipheth_debug = 0;
84132718Skan
85132718SkanSYSCTL_NODE(_hw_usb, OID_AUTO, ipheth, CTLFLAG_RW, 0, "USB iPhone ethernet");
86132718SkanSYSCTL_INT(_hw_usb_ipheth, OID_AUTO, debug, CTLFLAG_RW, &ipheth_debug, 0, "Debug level");
87169689Skan#endif
88132718Skan
89132718Skanstatic const struct usb_config ipheth_config[IPHETH_N_TRANSFER] = {
90132718Skan
91132718Skan	[IPHETH_BULK_RX] = {
92132718Skan		.type = UE_BULK,
93132718Skan		.endpoint = UE_ADDR_ANY,
94132718Skan		.direction = UE_DIR_RX,
95169689Skan		.frames = IPHETH_RX_FRAMES_MAX,
96132718Skan		.bufsize = (IPHETH_RX_FRAMES_MAX * MCLBYTES),
97132718Skan		.flags = {.short_frames_ok = 1,.short_xfer_ok = 1,.ext_buffer = 1,},
98132718Skan		.callback = ipheth_bulk_read_callback,
99132718Skan		.timeout = 0,		/* no timeout */
100169689Skan	},
101169689Skan
102132718Skan	[IPHETH_BULK_TX] = {
103169689Skan		.type = UE_BULK,
104169689Skan		.endpoint = UE_ADDR_ANY,
105169689Skan		.direction = UE_DIR_TX,
106132718Skan		.frames = IPHETH_TX_FRAMES_MAX,
107132718Skan		.bufsize = (IPHETH_TX_FRAMES_MAX * IPHETH_BUF_SIZE),
108132718Skan		.flags = {.force_short_xfer = 1,},
109132718Skan		.callback = ipheth_bulk_write_callback,
110132718Skan		.timeout = IPHETH_TX_TIMEOUT,
111132718Skan	},
112132718Skan};
113132718Skan
114132718Skanstatic device_method_t ipheth_methods[] = {
115132718Skan	/* Device interface */
116169689Skan	DEVMETHOD(device_probe, ipheth_probe),
117169689Skan	DEVMETHOD(device_attach, ipheth_attach),
118169689Skan	DEVMETHOD(device_detach, ipheth_detach),
119169689Skan
120169689Skan	{0, 0}
121132718Skan};
122132718Skan
123132718Skanstatic driver_t ipheth_driver = {
124132718Skan	.name = "ipheth",
125132718Skan	.methods = ipheth_methods,
126132718Skan	.size = sizeof(struct ipheth_softc),
127132718Skan};
128132718Skan
129132718Skanstatic devclass_t ipheth_devclass;
130169689Skan
131169689SkanDRIVER_MODULE(ipheth, uhub, ipheth_driver, ipheth_devclass, NULL, 0);
132169689SkanMODULE_VERSION(ipheth, 1);
133132718SkanMODULE_DEPEND(ipheth, uether, 1, 1, 1);
134132718SkanMODULE_DEPEND(ipheth, usb, 1, 1, 1);
135132718SkanMODULE_DEPEND(ipheth, ether, 1, 1, 1);
136132718Skan
137169689Skanstatic const struct usb_ether_methods ipheth_ue_methods = {
138132718Skan	.ue_attach_post = ipheth_attach_post,
139132718Skan	.ue_start = ipheth_start,
140169689Skan	.ue_init = ipheth_init,
141132718Skan	.ue_tick = ipheth_tick,
142169689Skan	.ue_stop = ipheth_stop,
143169689Skan	.ue_setmulti = ipheth_setmulti,
144169689Skan	.ue_setpromisc = ipheth_setpromisc,
145169689Skan};
146169689Skan
147169689Skan#define	IPHETH_ID(v,p,c,sc,pt) \
148169689Skan    USB_VENDOR(v), USB_PRODUCT(p), \
149169689Skan    USB_IFACE_CLASS(c), USB_IFACE_SUBCLASS(sc), \
150169689Skan    USB_IFACE_PROTOCOL(pt)
151169689Skan
152169689Skanstatic const struct usb_device_id ipheth_devs[] = {
153169689Skan	{IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE,
154169689Skan	    IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
155169689Skan	    IPHETH_USBINTF_PROTO)},
156132718Skan	{IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE_3G,
157132718Skan	    IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
158132718Skan	    IPHETH_USBINTF_PROTO)},
159132718Skan	{IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE_3GS,
160132718Skan	    IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
161132718Skan	    IPHETH_USBINTF_PROTO)},
162132718Skan	{IPHETH_ID(USB_VENDOR_APPLE, USB_PRODUCT_APPLE_IPHONE_4,
163132718Skan	    IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
164169689Skan	    IPHETH_USBINTF_PROTO)},
165169689Skan};
166132718Skan
167132718Skanstatic int
168132718Skanipheth_get_mac_addr(struct ipheth_softc *sc)
169132718Skan{
170132718Skan	struct usb_device_request req;
171132718Skan	int error;
172132718Skan
173169689Skan	req.bmRequestType = UT_READ_VENDOR_DEVICE;
174169689Skan	req.bRequest = IPHETH_CMD_GET_MACADDR;
175169689Skan	req.wValue[0] = 0;
176132718Skan	req.wValue[1] = 0;
177132718Skan	req.wIndex[0] = sc->sc_iface_no;
178169689Skan	req.wIndex[1] = 0;
179169689Skan	req.wLength[0] = ETHER_ADDR_LEN;
180169689Skan	req.wLength[1] = 0;
181169689Skan
182169689Skan	error = usbd_do_request(sc->sc_ue.ue_udev, NULL, &req, sc->sc_data);
183169689Skan
184169689Skan	if (error)
185169689Skan		return (error);
186169689Skan
187169689Skan	memcpy(sc->sc_ue.ue_eaddr, sc->sc_data, ETHER_ADDR_LEN);
188169689Skan
189169689Skan	return (0);
190169689Skan}
191169689Skan
192169689Skanstatic int
193169689Skanipheth_probe(device_t dev)
194169689Skan{
195169689Skan	struct usb_attach_arg *uaa = device_get_ivars(dev);
196169689Skan
197132718Skan	if (uaa->usb_mode != USB_MODE_HOST)
198132718Skan		return (ENXIO);
199132718Skan
200132718Skan	return (usbd_lookup_id_by_uaa(ipheth_devs, sizeof(ipheth_devs), uaa));
201169689Skan}
202132718Skan
203169689Skanstatic int
204132718Skanipheth_attach(device_t dev)
205132718Skan{
206132718Skan	struct ipheth_softc *sc = device_get_softc(dev);
207132718Skan	struct usb_ether *ue = &sc->sc_ue;
208169689Skan	struct usb_attach_arg *uaa = device_get_ivars(dev);
209169689Skan	int error;
210169689Skan
211169689Skan	sc->sc_iface_no = uaa->info.bIfaceIndex;
212132718Skan
213169689Skan	device_set_usb_desc(dev);
214169689Skan
215169689Skan	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
216169689Skan
217169689Skan	error = usbd_set_alt_interface_index(uaa->device,
218169689Skan	    uaa->info.bIfaceIndex, IPHETH_ALT_INTFNUM);
219169689Skan	if (error) {
220169689Skan		device_printf(dev, "Cannot set alternate setting\n");
221132718Skan		goto detach;
222132718Skan	}
223132718Skan	error = usbd_transfer_setup(uaa->device, &sc->sc_iface_no,
224132718Skan	    sc->sc_xfer, ipheth_config, IPHETH_N_TRANSFER, sc, &sc->sc_mtx);
225132718Skan	if (error) {
226132718Skan		device_printf(dev, "Cannot setup USB transfers\n");
227132718Skan		goto detach;
228169689Skan	}
229132718Skan	ue->ue_sc = sc;
230132718Skan	ue->ue_dev = dev;
231132718Skan	ue->ue_udev = uaa->device;
232132718Skan	ue->ue_mtx = &sc->sc_mtx;
233169689Skan	ue->ue_methods = &ipheth_ue_methods;
234169689Skan
235169689Skan	error = ipheth_get_mac_addr(sc);
236169689Skan	if (error) {
237132718Skan		device_printf(dev, "Cannot get MAC address\n");
238132718Skan		goto detach;
239132718Skan	}
240169689Skan
241132718Skan	error = uether_ifattach(ue);
242169689Skan	if (error) {
243169689Skan		device_printf(dev, "could not attach interface\n");
244169689Skan		goto detach;
245132718Skan	}
246169689Skan	return (0);			/* success */
247169689Skan
248169689Skandetach:
249169689Skan	ipheth_detach(dev);
250169689Skan	return (ENXIO);			/* failure */
251169689Skan}
252169689Skan
253169689Skanstatic int
254169689Skanipheth_detach(device_t dev)
255169689Skan{
256169689Skan	struct ipheth_softc *sc = device_get_softc(dev);
257169689Skan	struct usb_ether *ue = &sc->sc_ue;
258169689Skan
259169689Skan	/* stop all USB transfers first */
260169689Skan	usbd_transfer_unsetup(sc->sc_xfer, IPHETH_N_TRANSFER);
261169689Skan
262169689Skan	uether_ifdetach(ue);
263169689Skan
264169689Skan	mtx_destroy(&sc->sc_mtx);
265169689Skan
266169689Skan	return (0);
267169689Skan}
268169689Skan
269169689Skanstatic void
270169689Skanipheth_start(struct usb_ether *ue)
271169689Skan{
272169689Skan	struct ipheth_softc *sc = uether_getsc(ue);
273169689Skan
274169689Skan	/*
275169689Skan	 * Start the USB transfers, if not already started:
276169689Skan	 */
277169689Skan	usbd_transfer_start(sc->sc_xfer[IPHETH_BULK_TX]);
278132718Skan	usbd_transfer_start(sc->sc_xfer[IPHETH_BULK_RX]);
279132718Skan}
280169689Skan
281169689Skanstatic void
282169689Skanipheth_stop(struct usb_ether *ue)
283169689Skan{
284169689Skan	struct ipheth_softc *sc = uether_getsc(ue);
285169689Skan
286169689Skan	/*
287169689Skan	 * Stop the USB transfers, if not already stopped:
288169689Skan	 */
289169689Skan	usbd_transfer_stop(sc->sc_xfer[IPHETH_BULK_TX]);
290169689Skan	usbd_transfer_stop(sc->sc_xfer[IPHETH_BULK_RX]);
291169689Skan}
292169689Skan
293169689Skanstatic void
294169689Skanipheth_tick(struct usb_ether *ue)
295169689Skan{
296169689Skan	struct ipheth_softc *sc = uether_getsc(ue);
297169689Skan	struct usb_device_request req;
298169689Skan	int error;
299169689Skan
300169689Skan	req.bmRequestType = UT_READ_VENDOR_DEVICE;
301169689Skan	req.bRequest = IPHETH_CMD_CARRIER_CHECK;
302169689Skan	req.wValue[0] = 0;
303169689Skan	req.wValue[1] = 0;
304169689Skan	req.wIndex[0] = sc->sc_iface_no;
305169689Skan	req.wIndex[1] = 0;
306169689Skan	req.wLength[0] = IPHETH_CTRL_BUF_SIZE;
307169689Skan	req.wLength[1] = 0;
308169689Skan
309169689Skan	error = uether_do_request(ue, &req, sc->sc_data, IPHETH_CTRL_TIMEOUT);
310169689Skan
311169689Skan	if (error)
312169689Skan		return;
313169689Skan
314169689Skan	sc->sc_carrier_on =
315169689Skan	    (sc->sc_data[0] == IPHETH_CARRIER_ON);
316169689Skan}
317169689Skan
318169689Skanstatic void
319169689Skanipheth_attach_post(struct usb_ether *ue)
320169689Skan{
321169689Skan
322169689Skan}
323169689Skan
324169689Skanstatic void
325169689Skanipheth_init(struct usb_ether *ue)
326169689Skan{
327169689Skan	struct ipheth_softc *sc = uether_getsc(ue);
328169689Skan	struct ifnet *ifp = uether_getifp(ue);
329169689Skan
330169689Skan	IPHETH_LOCK_ASSERT(sc, MA_OWNED);
331169689Skan
332169689Skan	ifp->if_drv_flags |= IFF_DRV_RUNNING;
333169689Skan
334169689Skan	/* stall data write direction, which depends on USB mode */
335169689Skan	usbd_xfer_set_stall(sc->sc_xfer[IPHETH_BULK_TX]);
336169689Skan
337169689Skan	/* start data transfers */
338169689Skan	ipheth_start(ue);
339169689Skan}
340169689Skan
341169689Skanstatic void
342169689Skanipheth_setmulti(struct usb_ether *ue)
343169689Skan{
344169689Skan
345169689Skan}
346169689Skan
347169689Skanstatic void
348169689Skanipheth_setpromisc(struct usb_ether *ue)
349169689Skan{
350169689Skan
351169689Skan}
352169689Skan
353169689Skanstatic void
354169689Skanipheth_free_queue(struct mbuf **ppm, uint8_t n)
355169689Skan{
356169689Skan	uint8_t x;
357169689Skan
358169689Skan	for (x = 0; x != n; x++) {
359169689Skan		if (ppm[x] != NULL) {
360169689Skan			m_freem(ppm[x]);
361169689Skan			ppm[x] = NULL;
362169689Skan		}
363169689Skan	}
364169689Skan}
365169689Skan
366169689Skanstatic void
367169689Skanipheth_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
368169689Skan{
369169689Skan	struct ipheth_softc *sc = usbd_xfer_softc(xfer);
370169689Skan	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
371169689Skan	struct usb_page_cache *pc;
372169689Skan	struct mbuf *m;
373169689Skan	uint8_t x;
374132718Skan	int actlen;
375132718Skan	int aframes;
376169689Skan
377169689Skan	usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL);
378169689Skan
379132718Skan	DPRINTFN(1, "\n");
380169689Skan
381169689Skan	switch (USB_GET_STATE(xfer)) {
382169689Skan	case USB_ST_TRANSFERRED:
383132718Skan		DPRINTFN(11, "transfer complete: %u bytes in %u frames\n",
384169689Skan		    actlen, aframes);
385169689Skan
386169689Skan		ifp->if_opackets++;
387169689Skan
388169689Skan		/* free all previous TX buffers */
389169689Skan		ipheth_free_queue(sc->sc_tx_buf, IPHETH_TX_FRAMES_MAX);
390132718Skan
391132718Skan		/* FALLTHROUGH */
392132718Skan	case USB_ST_SETUP:
393132718Skantr_setup:
394132718Skan		for (x = 0; x != IPHETH_TX_FRAMES_MAX; x++) {
395132718Skan
396132718Skan			IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
397132718Skan
398132718Skan			if (m == NULL)
399132718Skan				break;
400169689Skan
401132718Skan			usbd_xfer_set_frame_offset(xfer,
402132718Skan			    x * IPHETH_BUF_SIZE, x);
403132718Skan
404169689Skan			pc = usbd_xfer_get_frame(xfer, x);
405169689Skan
406132718Skan			sc->sc_tx_buf[x] = m;
407169689Skan
408169689Skan			if (m->m_pkthdr.len > IPHETH_BUF_SIZE)
409169689Skan				m->m_pkthdr.len = IPHETH_BUF_SIZE;
410132718Skan
411169689Skan			usbd_m_copy_in(pc, 0, m, 0, m->m_pkthdr.len);
412169689Skan
413132718Skan			usbd_xfer_set_frame_len(xfer, x, IPHETH_BUF_SIZE);
414132718Skan
415169689Skan			if (IPHETH_BUF_SIZE != m->m_pkthdr.len) {
416169689Skan				usbd_frame_zero(pc, m->m_pkthdr.len,
417169689Skan					IPHETH_BUF_SIZE - m->m_pkthdr.len);
418169689Skan			}
419169689Skan
420169689Skan			/*
421169689Skan			 * If there's a BPF listener, bounce a copy of
422169689Skan			 * this frame to him:
423169689Skan			 */
424169689Skan			BPF_MTAP(ifp, m);
425169689Skan		}
426169689Skan		if (x != 0) {
427169689Skan			usbd_xfer_set_frames(xfer, x);
428132718Skan
429132718Skan			usbd_transfer_submit(xfer);
430132718Skan		}
431169689Skan		break;
432132718Skan
433169689Skan	default:			/* Error */
434169689Skan		DPRINTFN(11, "transfer error, %s\n",
435169689Skan		    usbd_errstr(error));
436169689Skan
437169689Skan		/* free all previous TX buffers */
438169689Skan		ipheth_free_queue(sc->sc_tx_buf, IPHETH_TX_FRAMES_MAX);
439169689Skan
440169689Skan		/* count output errors */
441169689Skan		ifp->if_oerrors++;
442169689Skan
443169689Skan		if (error != USB_ERR_CANCELLED) {
444169689Skan			/* try to clear stall first */
445169689Skan			usbd_xfer_set_stall(xfer);
446169689Skan			goto tr_setup;
447169689Skan		}
448169689Skan		break;
449169689Skan	}
450169689Skan}
451169689Skan
452169689Skanstatic void
453169689Skanipheth_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
454169689Skan{
455169689Skan	struct ipheth_softc *sc = usbd_xfer_softc(xfer);
456169689Skan	struct mbuf *m;
457169689Skan	uint8_t x;
458169689Skan	int actlen;
459169689Skan	int aframes;
460169689Skan	int len;
461169689Skan
462169689Skan	usbd_xfer_status(xfer, &actlen, NULL, &aframes, NULL);
463132718Skan
464169689Skan	switch (USB_GET_STATE(xfer)) {
465132718Skan	case USB_ST_TRANSFERRED:
466169689Skan
467169689Skan		DPRINTF("received %u bytes in %u frames\n", actlen, aframes);
468132718Skan
469169689Skan		for (x = 0; x != aframes; x++) {
470169689Skan
471132718Skan			m = sc->sc_rx_buf[x];
472132718Skan			sc->sc_rx_buf[x] = NULL;
473169689Skan			len = usbd_xfer_frame_len(xfer, x);
474169689Skan
475169689Skan			if (len < (sizeof(struct ether_header) +
476169689Skan			    IPHETH_RX_ADJ)) {
477169689Skan				m_freem(m);
478169689Skan				continue;
479169689Skan			}
480169689Skan
481169689Skan			m_adj(m, IPHETH_RX_ADJ);
482169689Skan
483169689Skan			/* queue up mbuf */
484169689Skan			uether_rxmbuf(&sc->sc_ue, m, len - IPHETH_RX_ADJ);
485169689Skan		}
486169689Skan
487169689Skan		/* FALLTHROUGH */
488169689Skan	case USB_ST_SETUP:
489169689Skan
490169689Skan		for (x = 0; x != IPHETH_RX_FRAMES_MAX; x++) {
491169689Skan			if (sc->sc_rx_buf[x] == NULL) {
492169689Skan				m = uether_newbuf();
493169689Skan				if (m == NULL)
494169689Skan					goto tr_stall;
495169689Skan
496169689Skan				/* cancel alignment for ethernet */
497169689Skan				m_adj(m, ETHER_ALIGN);
498169689Skan
499169689Skan				sc->sc_rx_buf[x] = m;
500169689Skan			} else {
501169689Skan				m = sc->sc_rx_buf[x];
502169689Skan			}
503169689Skan
504169689Skan			usbd_xfer_set_frame_data(xfer, x, m->m_data, m->m_len);
505169689Skan		}
506169689Skan		/* set number of frames and start hardware */
507169689Skan		usbd_xfer_set_frames(xfer, x);
508169689Skan		usbd_transfer_submit(xfer);
509169689Skan		/* flush any received frames */
510169689Skan		uether_rxflush(&sc->sc_ue);
511169689Skan		break;
512169689Skan
513169689Skan	default:			/* Error */
514169689Skan		DPRINTF("error = %s\n", usbd_errstr(error));
515169689Skan
516169689Skan		if (error != USB_ERR_CANCELLED) {
517169689Skan	tr_stall:
518169689Skan			/* try to clear stall first */
519169689Skan			usbd_xfer_set_stall(xfer);
520169689Skan			usbd_xfer_set_frames(xfer, 0);
521169689Skan			usbd_transfer_submit(xfer);
522169689Skan			break;
523169689Skan		}
524169689Skan		/* need to free the RX-mbufs when we are cancelled */
525169689Skan		ipheth_free_queue(sc->sc_rx_buf, IPHETH_RX_FRAMES_MAX);
526132718Skan		break;
527132718Skan	}
528132718Skan}
529132718Skan