xref: /openbsd-src/sys/dev/usb/if_ugl.c (revision 81508fe356eb7772a68118f65f91723ce5261d7d)
1*81508fe3Sjsg /*	$OpenBSD: if_ugl.c,v 1.28 2024/05/23 03:21:09 jsg Exp $	*/
2e737caceSsasano /*	$NetBSD: if_upl.c,v 1.19 2002/07/11 21:14:26 augustss Exp $	*/
3e737caceSsasano /*
4da28f5dbSsasano  * Copyright (c) 2013 SASANO Takayoshi <uaa@uaa.org.uk>
5da28f5dbSsasano  *
6da28f5dbSsasano  * Permission to use, copy, modify, and distribute this software for any
7da28f5dbSsasano  * purpose with or without fee is hereby granted, provided that the above
8da28f5dbSsasano  * copyright notice and this permission notice appear in all copies.
9da28f5dbSsasano  *
10da28f5dbSsasano  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11da28f5dbSsasano  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12da28f5dbSsasano  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13da28f5dbSsasano  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14da28f5dbSsasano  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15da28f5dbSsasano  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16da28f5dbSsasano  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17da28f5dbSsasano  */
18da28f5dbSsasano 
19da28f5dbSsasano /*
20e737caceSsasano  * Copyright (c) 2000 The NetBSD Foundation, Inc.
21e737caceSsasano  * All rights reserved.
22e737caceSsasano  *
23e737caceSsasano  * This code is derived from software contributed to The NetBSD Foundation
24e737caceSsasano  * by Lennart Augustsson (lennart@augustsson.net) at
25e737caceSsasano  * Carlstedt Research & Technology.
26e737caceSsasano  *
27e737caceSsasano  * Redistribution and use in source and binary forms, with or without
28e737caceSsasano  * modification, are permitted provided that the following conditions
29e737caceSsasano  * are met:
30e737caceSsasano  * 1. Redistributions of source code must retain the above copyright
31e737caceSsasano  *    notice, this list of conditions and the following disclaimer.
32e737caceSsasano  * 2. Redistributions in binary form must reproduce the above copyright
33e737caceSsasano  *    notice, this list of conditions and the following disclaimer in the
34e737caceSsasano  *    documentation and/or other materials provided with the distribution.
35e737caceSsasano  *
36e737caceSsasano  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
37e737caceSsasano  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
38e737caceSsasano  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
39e737caceSsasano  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
40e737caceSsasano  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
41e737caceSsasano  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
42e737caceSsasano  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
43e737caceSsasano  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
44e737caceSsasano  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
45e737caceSsasano  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46e737caceSsasano  * POSSIBILITY OF SUCH DAMAGE.
47e737caceSsasano  */
48e737caceSsasano 
49e737caceSsasano /*
50e737caceSsasano  * Genesys Logic GL620USB-A driver
51e737caceSsasano  *   This driver is based on Prolific PL2301/PL2302 driver (if_upl.c).
52e737caceSsasano  */
53e737caceSsasano 
54e737caceSsasano #include <bpfilter.h>
55e737caceSsasano 
56e737caceSsasano #include <sys/param.h>
57e737caceSsasano #include <sys/systm.h>
58e737caceSsasano #include <sys/timeout.h>
59e737caceSsasano #include <sys/sockio.h>
60e737caceSsasano #include <sys/mbuf.h>
61e737caceSsasano 
62e737caceSsasano #include <sys/device.h>
63e737caceSsasano 
64e737caceSsasano #include <net/if.h>
65e737caceSsasano 
66e737caceSsasano #if NBPFILTER > 0
67e737caceSsasano #include <net/bpf.h>
68e737caceSsasano #endif
69e737caceSsasano 
70e737caceSsasano #include <netinet/in.h>
71e737caceSsasano #include <netinet/if_ether.h>
72e737caceSsasano 
73e737caceSsasano #include <dev/usb/usb.h>
74e737caceSsasano #include <dev/usb/usbdi.h>
75e737caceSsasano #include <dev/usb/usbdevs.h>
76e737caceSsasano 
77e737caceSsasano #define UGL_INTR_PKTLEN		8
78e737caceSsasano #define UGL_BULK_PKTLEN		64
79e737caceSsasano 
80e737caceSsasano /***/
81e737caceSsasano 
82e737caceSsasano #define UGL_INTR_INTERVAL	20
83e737caceSsasano 
84e737caceSsasano #define UGL_MAX_MTU		1514
85e737caceSsasano #define UGL_BUFSZ		roundup(sizeof(struct ugl_packet), UGL_BULK_PKTLEN)
86e737caceSsasano 
87e737caceSsasano #define UGL_RX_FRAMES		1	/* must be one */
88e737caceSsasano #define UGL_TX_FRAMES		1	/* must be one */
89e737caceSsasano 
90e737caceSsasano #define UGL_RX_LIST_CNT		1
91e737caceSsasano #define UGL_TX_LIST_CNT		1
92e737caceSsasano 
93e737caceSsasano #define UGL_ENDPT_RX		0x0
94e737caceSsasano #define UGL_ENDPT_TX		0x1
95e737caceSsasano #define UGL_ENDPT_INTR		0x2
96e737caceSsasano #define UGL_ENDPT_MAX		0x3
97e737caceSsasano 
98e737caceSsasano struct ugl_softc;
99e737caceSsasano 
100e737caceSsasano struct ugl_packet {
101e737caceSsasano 	uDWord			pkt_count;
102e737caceSsasano 	uDWord			pkt_length;
103e737caceSsasano 	char			pkt_data[UGL_MAX_MTU];
104e737caceSsasano } __packed;
105e737caceSsasano 
106e737caceSsasano struct ugl_chain {
107e737caceSsasano 	struct ugl_softc	*ugl_sc;
108e737caceSsasano 	struct usbd_xfer	*ugl_xfer;
109e737caceSsasano 	struct ugl_packet	*ugl_buf;
110e737caceSsasano 	struct mbuf		*ugl_mbuf;
111e737caceSsasano 	int			ugl_idx;
112e737caceSsasano };
113e737caceSsasano 
114e737caceSsasano struct ugl_cdata {
115e737caceSsasano 	struct ugl_chain	ugl_tx_chain[UGL_TX_LIST_CNT];
116e737caceSsasano 	struct ugl_chain	ugl_rx_chain[UGL_RX_LIST_CNT];
117e737caceSsasano 	int			ugl_tx_prod;
118e737caceSsasano 	int			ugl_tx_cons;
119e737caceSsasano 	int			ugl_tx_cnt;
120e737caceSsasano 	int			ugl_rx_prod;
121e737caceSsasano };
122e737caceSsasano 
123e737caceSsasano struct ugl_softc {
124e737caceSsasano 	struct device		sc_dev;
125e737caceSsasano 
126e737caceSsasano 	struct arpcom		sc_arpcom;
127e737caceSsasano #define GET_IFP(sc) (&(sc)->sc_arpcom.ac_if)
128e737caceSsasano 	struct timeout		sc_stat_ch;
129e737caceSsasano 
130e737caceSsasano 	struct usbd_device	*sc_udev;
131e737caceSsasano 	struct usbd_interface	*sc_iface;
132e737caceSsasano 	int			sc_ed[UGL_ENDPT_MAX];
133e737caceSsasano 	struct usbd_pipe	*sc_ep[UGL_ENDPT_MAX];
134e737caceSsasano 	struct ugl_cdata	sc_cdata;
135e737caceSsasano 
136e737caceSsasano 	uByte			sc_ibuf[UGL_INTR_PKTLEN];
137e737caceSsasano 
138e737caceSsasano 	u_int			sc_rx_errs;
139e737caceSsasano 	struct timeval		sc_rx_notice;
140e737caceSsasano 	u_int			sc_intr_errs;
141e737caceSsasano };
142e737caceSsasano 
143e737caceSsasano #ifdef UGL_DEBUG
144e737caceSsasano #define DPRINTF(x)	do { if (ugldebug) printf x; } while (0)
145e737caceSsasano #define DPRINTFN(n,x)	do { if (ugldebug >= (n)) printf x; } while (0)
146e737caceSsasano int	ugldebug = 0;
147e737caceSsasano #else
148e737caceSsasano #define DPRINTF(x)
149e737caceSsasano #define DPRINTFN(n,x)
150e737caceSsasano #endif
151e737caceSsasano 
152e737caceSsasano /*
153e737caceSsasano  * Various supported device vendors/products.
154e737caceSsasano  */
155e737caceSsasano struct usb_devno ugl_devs[] = {
156e737caceSsasano 	{ USB_VENDOR_GENESYS, USB_PRODUCT_GENESYS_GL620USB_A },
157e737caceSsasano };
158e737caceSsasano 
159e737caceSsasano int ugl_match(struct device *, void *, void *);
160e737caceSsasano void ugl_attach(struct device *, struct device *, void *);
161e737caceSsasano int ugl_detach(struct device *, int);
162e737caceSsasano 
163e737caceSsasano struct cfdriver ugl_cd = {
164e737caceSsasano 	NULL, "ugl", DV_IFNET
165e737caceSsasano };
166e737caceSsasano 
167e737caceSsasano const struct cfattach ugl_ca = {
16853c6612dSmpi 	sizeof(struct ugl_softc), ugl_match, ugl_attach, ugl_detach
169e737caceSsasano };
170e737caceSsasano 
171e737caceSsasano int ugl_openpipes(struct ugl_softc *);
172e737caceSsasano int ugl_tx_list_init(struct ugl_softc *);
173e737caceSsasano int ugl_rx_list_init(struct ugl_softc *);
174e737caceSsasano int ugl_newbuf(struct ugl_softc *, struct ugl_chain *, struct mbuf *);
175e737caceSsasano int ugl_send(struct ugl_softc *, struct mbuf *, int);
176e737caceSsasano void ugl_intr(struct usbd_xfer *, void *, usbd_status);
177e737caceSsasano void ugl_rxeof(struct usbd_xfer *, void *, usbd_status);
178e737caceSsasano void ugl_txeof(struct usbd_xfer *, void *, usbd_status);
179e737caceSsasano void ugl_start(struct ifnet *);
180e737caceSsasano int ugl_ioctl(struct ifnet *, u_long, caddr_t);
181e737caceSsasano void ugl_init(void *);
182e737caceSsasano void ugl_stop(struct ugl_softc *);
183e737caceSsasano void ugl_watchdog(struct ifnet *);
184e737caceSsasano 
185e737caceSsasano /*
186e737caceSsasano  * Probe for a Genesys Logic chip.
187e737caceSsasano  */
188e737caceSsasano int
ugl_match(struct device * parent,void * match,void * aux)189e737caceSsasano ugl_match(struct device *parent, void *match, void *aux)
190e737caceSsasano {
191e737caceSsasano 	struct usb_attach_arg		*uaa = aux;
192e737caceSsasano 
193cca60b12Smpi 	if (uaa->iface == NULL || uaa->configno != 1)
194e737caceSsasano 		return (UMATCH_NONE);
195e737caceSsasano 
196e737caceSsasano 	return (usb_lookup(ugl_devs, uaa->vendor, uaa->product) != NULL ?
197cca60b12Smpi 	    UMATCH_VENDOR_PRODUCT_CONF_IFACE : UMATCH_NONE);
198e737caceSsasano }
199e737caceSsasano 
200e737caceSsasano void
ugl_attach(struct device * parent,struct device * self,void * aux)201e737caceSsasano ugl_attach(struct device *parent, struct device *self, void *aux)
202e737caceSsasano {
203e737caceSsasano 	struct ugl_softc	*sc = (struct ugl_softc *)self;
204e737caceSsasano 	struct usb_attach_arg	*uaa = aux;
205e737caceSsasano 	int			s;
206e737caceSsasano 	struct usbd_device	*dev = uaa->device;
207cca60b12Smpi 	struct usbd_interface	*iface = uaa->iface;
208777f3d7fSmpi 	struct ifnet		*ifp = GET_IFP(sc);
209e737caceSsasano 	usb_interface_descriptor_t	*id;
210e737caceSsasano 	usb_endpoint_descriptor_t	*ed;
211e737caceSsasano 	int			i;
212e737caceSsasano 
213e737caceSsasano 	DPRINTFN(5,(" : ugl_attach: sc=%p, dev=%p", sc, dev));
214e737caceSsasano 
215e737caceSsasano 	sc->sc_udev = dev;
216e737caceSsasano 	sc->sc_iface = iface;
217e737caceSsasano 	id = usbd_get_interface_descriptor(iface);
218e737caceSsasano 
219e737caceSsasano 	/* Find endpoints. */
220e737caceSsasano 	for (i = 0; i < id->bNumEndpoints; i++) {
221e737caceSsasano 		ed = usbd_interface2endpoint_descriptor(iface, i);
222e737caceSsasano 		if (ed == NULL) {
223e737caceSsasano 			printf("%s: couldn't get ep %d\n",
224e737caceSsasano 			    sc->sc_dev.dv_xname, i);
225e737caceSsasano 			return;
226e737caceSsasano 		}
227e737caceSsasano 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
228e737caceSsasano 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
229e737caceSsasano 			sc->sc_ed[UGL_ENDPT_RX] = ed->bEndpointAddress;
230e737caceSsasano 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
231e737caceSsasano 			   UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
232e737caceSsasano 			sc->sc_ed[UGL_ENDPT_TX] = ed->bEndpointAddress;
233e737caceSsasano 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
234e737caceSsasano 			   UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
235e737caceSsasano 			sc->sc_ed[UGL_ENDPT_INTR] = ed->bEndpointAddress;
236e737caceSsasano 		}
237e737caceSsasano 	}
238e737caceSsasano 
239e737caceSsasano 	if (sc->sc_ed[UGL_ENDPT_RX] == 0 || sc->sc_ed[UGL_ENDPT_TX] == 0 ||
240e737caceSsasano 	    sc->sc_ed[UGL_ENDPT_INTR] == 0) {
241e737caceSsasano 		printf("%s: missing endpoint\n", sc->sc_dev.dv_xname);
242e737caceSsasano 		return;
243e737caceSsasano 	}
244e737caceSsasano 
245e737caceSsasano 	s = splnet();
246e737caceSsasano 
247777f3d7fSmpi 	ether_fakeaddr(ifp);
248e737caceSsasano 	printf("%s: address %s\n",
249e737caceSsasano 	    sc->sc_dev.dv_xname, ether_sprintf(sc->sc_arpcom.ac_enaddr));
250e737caceSsasano 
251e737caceSsasano 	/* Initialize interface info.*/
252e737caceSsasano 	ifp->if_softc = sc;
25344fce25bSbrad 	ifp->if_hardmtu = UGL_MAX_MTU;
254e737caceSsasano 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
255e737caceSsasano 	ifp->if_ioctl = ugl_ioctl;
256e737caceSsasano 	ifp->if_start = ugl_start;
257e737caceSsasano 	ifp->if_watchdog = ugl_watchdog;
258e737caceSsasano 	strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
259e737caceSsasano 
260e737caceSsasano 	/* Attach the interface. */
261e737caceSsasano 	if_attach(ifp);
262e737caceSsasano 	ether_ifattach(ifp);
263e737caceSsasano 
264e737caceSsasano 	splx(s);
265e737caceSsasano }
266e737caceSsasano 
267e737caceSsasano int
ugl_detach(struct device * self,int flags)268e737caceSsasano ugl_detach(struct device *self, int flags)
269e737caceSsasano {
270e737caceSsasano 	struct ugl_softc	*sc = (struct ugl_softc *)self;
271e737caceSsasano 	struct ifnet		*ifp = GET_IFP(sc);
272e737caceSsasano 	int			s;
273e737caceSsasano 
274e737caceSsasano 	DPRINTFN(2,("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
275e737caceSsasano 
276e737caceSsasano 	s = splusb();
277e737caceSsasano 
278e737caceSsasano 	if (ifp->if_flags & IFF_RUNNING)
279e737caceSsasano 		ugl_stop(sc);
280e737caceSsasano 
281e737caceSsasano 	if (ifp->if_softc != NULL)
282e737caceSsasano 		if_detach(ifp);
283e737caceSsasano 
284e737caceSsasano #ifdef DIAGNOSTIC
285e737caceSsasano 	if (sc->sc_ep[UGL_ENDPT_TX] != NULL ||
286e737caceSsasano 	    sc->sc_ep[UGL_ENDPT_RX] != NULL ||
287e737caceSsasano 	    sc->sc_ep[UGL_ENDPT_INTR] != NULL)
288e737caceSsasano 		printf("%s: detach has active endpoints\n",
289e737caceSsasano 		       sc->sc_dev.dv_xname);
290e737caceSsasano #endif
291e737caceSsasano 
292e737caceSsasano 	splx(s);
293e737caceSsasano 
294e737caceSsasano 	return (0);
295e737caceSsasano }
296e737caceSsasano 
297e737caceSsasano /*
298e737caceSsasano  * Initialize an RX descriptor and attach an MBUF cluster.
299e737caceSsasano  */
300e737caceSsasano int
ugl_newbuf(struct ugl_softc * sc,struct ugl_chain * c,struct mbuf * m)301e737caceSsasano ugl_newbuf(struct ugl_softc *sc, struct ugl_chain *c, struct mbuf *m)
302e737caceSsasano {
303e737caceSsasano 	struct mbuf		*m_new = NULL;
304e737caceSsasano 
305e737caceSsasano 	DPRINTFN(8,("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
306e737caceSsasano 
307e737caceSsasano 	if (m == NULL) {
308e737caceSsasano 		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
309e737caceSsasano 		if (m_new == NULL) {
310e737caceSsasano 			printf("%s: no memory for rx list "
311e737caceSsasano 			    "-- packet dropped!\n", sc->sc_dev.dv_xname);
312e737caceSsasano 			return (ENOBUFS);
313e737caceSsasano 		}
314e737caceSsasano 
315e737caceSsasano 		MCLGET(m_new, M_DONTWAIT);
316e737caceSsasano 		if (!(m_new->m_flags & M_EXT)) {
317e737caceSsasano 			printf("%s: no memory for rx list "
318e737caceSsasano 			    "-- packet dropped!\n", sc->sc_dev.dv_xname);
319e737caceSsasano 			m_freem(m_new);
320e737caceSsasano 			return (ENOBUFS);
321e737caceSsasano 		}
322e737caceSsasano 		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
323e737caceSsasano 	} else {
324e737caceSsasano 		m_new = m;
325e737caceSsasano 		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
326e737caceSsasano 		m_new->m_data = m_new->m_ext.ext_buf;
327e737caceSsasano 	}
328e737caceSsasano 
329e737caceSsasano 	c->ugl_mbuf = m_new;
330e737caceSsasano 
331e737caceSsasano 	return (0);
332e737caceSsasano }
333e737caceSsasano 
334e737caceSsasano int
ugl_rx_list_init(struct ugl_softc * sc)335e737caceSsasano ugl_rx_list_init(struct ugl_softc *sc)
336e737caceSsasano {
337e737caceSsasano 	struct ugl_cdata	*cd;
338e737caceSsasano 	struct ugl_chain	*c;
339e737caceSsasano 	int			i;
340e737caceSsasano 
341e737caceSsasano 	DPRINTFN(5,("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
342e737caceSsasano 
343e737caceSsasano 	cd = &sc->sc_cdata;
344e737caceSsasano 	for (i = 0; i < UGL_RX_LIST_CNT; i++) {
345e737caceSsasano 		c = &cd->ugl_rx_chain[i];
346e737caceSsasano 		c->ugl_sc = sc;
347e737caceSsasano 		c->ugl_idx = i;
348e737caceSsasano 		if (ugl_newbuf(sc, c, NULL) == ENOBUFS)
349e737caceSsasano 			return (ENOBUFS);
350e737caceSsasano 		if (c->ugl_xfer == NULL) {
351e737caceSsasano 			c->ugl_xfer = usbd_alloc_xfer(sc->sc_udev);
352e737caceSsasano 			if (c->ugl_xfer == NULL)
353e737caceSsasano 				return (ENOBUFS);
354e737caceSsasano 			c->ugl_buf = usbd_alloc_buffer(c->ugl_xfer, UGL_BUFSZ);
355e737caceSsasano 			if (c->ugl_buf == NULL) {
356e737caceSsasano 				usbd_free_xfer(c->ugl_xfer);
357e737caceSsasano 				return (ENOBUFS);
358e737caceSsasano 			}
359e737caceSsasano 		}
360e737caceSsasano 	}
361e737caceSsasano 
362e737caceSsasano 	return (0);
363e737caceSsasano }
364e737caceSsasano 
365e737caceSsasano int
ugl_tx_list_init(struct ugl_softc * sc)366e737caceSsasano ugl_tx_list_init(struct ugl_softc *sc)
367e737caceSsasano {
368e737caceSsasano 	struct ugl_cdata	*cd;
369e737caceSsasano 	struct ugl_chain	*c;
370e737caceSsasano 	int			i;
371e737caceSsasano 
372e737caceSsasano 	DPRINTFN(5,("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
373e737caceSsasano 
374e737caceSsasano 	cd = &sc->sc_cdata;
375e737caceSsasano 	for (i = 0; i < UGL_TX_LIST_CNT; i++) {
376e737caceSsasano 		c = &cd->ugl_tx_chain[i];
377e737caceSsasano 		c->ugl_sc = sc;
378e737caceSsasano 		c->ugl_idx = i;
379e737caceSsasano 		c->ugl_mbuf = NULL;
380e737caceSsasano 		if (c->ugl_xfer == NULL) {
381e737caceSsasano 			c->ugl_xfer = usbd_alloc_xfer(sc->sc_udev);
382e737caceSsasano 			if (c->ugl_xfer == NULL)
383e737caceSsasano 				return (ENOBUFS);
384e737caceSsasano 			c->ugl_buf = usbd_alloc_buffer(c->ugl_xfer, UGL_BUFSZ);
385e737caceSsasano 			if (c->ugl_buf == NULL) {
386e737caceSsasano 				usbd_free_xfer(c->ugl_xfer);
387e737caceSsasano 				return (ENOBUFS);
388e737caceSsasano 			}
389e737caceSsasano 		}
390e737caceSsasano 	}
391e737caceSsasano 
392e737caceSsasano 	return (0);
393e737caceSsasano }
394e737caceSsasano 
395e737caceSsasano /*
396e737caceSsasano  * A frame has been uploaded: pass the resulting mbuf chain up to
397e737caceSsasano  * the higher level protocols.
398e737caceSsasano  */
399e737caceSsasano void
ugl_rxeof(struct usbd_xfer * xfer,void * priv,usbd_status status)400e737caceSsasano ugl_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
401e737caceSsasano {
402e737caceSsasano 	struct ugl_chain	*c = priv;
403e737caceSsasano 	struct ugl_softc	*sc = c->ugl_sc;
404e737caceSsasano 	struct ifnet		*ifp = GET_IFP(sc);
405aa0dd4f6Smpi 	struct mbuf_list	ml = MBUF_LIST_INITIALIZER();
406e737caceSsasano 	struct mbuf		*m;
407e737caceSsasano 	int			total_len = 0;
408e737caceSsasano 	unsigned int		packet_len, packet_count;
409e737caceSsasano 	int			s;
410e737caceSsasano 
411e737caceSsasano 	if (usbd_is_dying(sc->sc_udev))
412e737caceSsasano 		return;
413e737caceSsasano 
414e737caceSsasano 	if (!(ifp->if_flags & IFF_RUNNING))
415e737caceSsasano 		return;
416e737caceSsasano 
417e737caceSsasano 	if (status != USBD_NORMAL_COMPLETION) {
418e737caceSsasano 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
419e737caceSsasano 			return;
420e737caceSsasano 		sc->sc_rx_errs++;
421e737caceSsasano 		if (usbd_ratecheck(&sc->sc_rx_notice)) {
422e737caceSsasano 			printf("%s: %u usb errors on rx: %s\n",
423e737caceSsasano 			    sc->sc_dev.dv_xname, sc->sc_rx_errs,
424e737caceSsasano 			    usbd_errstr(status));
425e737caceSsasano 			sc->sc_rx_errs = 0;
426e737caceSsasano 		}
427e737caceSsasano 		if (status == USBD_STALLED)
428e737caceSsasano 			usbd_clear_endpoint_stall_async(sc->sc_ep[UGL_ENDPT_RX]);
429e737caceSsasano 		goto done;
430e737caceSsasano 	}
431e737caceSsasano 
432e737caceSsasano 	usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
433e737caceSsasano 
434e737caceSsasano 	DPRINTFN(9,("%s: %s: enter status=%d length=%d\n",
435e737caceSsasano 		    sc->sc_dev.dv_xname, __func__, status, total_len));
436e737caceSsasano 
437e737caceSsasano 	if (total_len < offsetof(struct ugl_packet, pkt_data)) {
438e737caceSsasano 		printf("%s: bad header (length=%d)\n",
439e737caceSsasano 		    sc->sc_dev.dv_xname, total_len);
440e737caceSsasano 
441e737caceSsasano 		goto done;
442e737caceSsasano 	}
443e737caceSsasano 
444e737caceSsasano 	packet_count = UGETDW(c->ugl_buf->pkt_count);
445e737caceSsasano 	if (packet_count != UGL_RX_FRAMES) {
446e737caceSsasano 		printf("%s: bad packet count (%d)\n",
447e737caceSsasano 		    sc->sc_dev.dv_xname, packet_count);
448e737caceSsasano 
449e737caceSsasano 		if (packet_count == 0)
450e737caceSsasano 			goto done;
451e737caceSsasano 	}
452e737caceSsasano 
453e737caceSsasano 	packet_len = UGETDW(c->ugl_buf->pkt_length);
454e737caceSsasano 	if (total_len < packet_len) {
455e737caceSsasano 		printf("%s: bad packet size(%d), length=%d\n",
456e737caceSsasano 		    sc->sc_dev.dv_xname, packet_len, total_len);
457e737caceSsasano 
458e737caceSsasano 		if (packet_len == 0)
459e737caceSsasano 			goto done;
460e737caceSsasano 	}
461e737caceSsasano 
462e737caceSsasano 	m = c->ugl_mbuf;
463e737caceSsasano 	memcpy(mtod(c->ugl_mbuf, char *), c->ugl_buf->pkt_data, packet_len);
464e737caceSsasano 
465e737caceSsasano 	m->m_pkthdr.len = m->m_len = packet_len;
466aa0dd4f6Smpi 	ml_enqueue(&ml, m);
467e737caceSsasano 
468e737caceSsasano 	if (ugl_newbuf(sc, c, NULL) == ENOBUFS) {
469e737caceSsasano 		ifp->if_ierrors++;
470aa0dd4f6Smpi 		goto done;
471e737caceSsasano 	}
472e737caceSsasano 
473aa0dd4f6Smpi 	s = splnet();
474aa0dd4f6Smpi 	if_input(ifp, &ml);
475e737caceSsasano 	splx(s);
476e737caceSsasano 
477e737caceSsasano  done:
478e737caceSsasano 	/* Setup new transfer. */
479e737caceSsasano 	usbd_setup_xfer(c->ugl_xfer, sc->sc_ep[UGL_ENDPT_RX],
480e737caceSsasano 	    c, c->ugl_buf, UGL_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
481e737caceSsasano 	    USBD_NO_TIMEOUT, ugl_rxeof);
482e737caceSsasano 	usbd_transfer(c->ugl_xfer);
483e737caceSsasano 
484e737caceSsasano 	DPRINTFN(10,("%s: %s: start rx\n", sc->sc_dev.dv_xname,
485e737caceSsasano 		    __func__));
486e737caceSsasano }
487e737caceSsasano 
488e737caceSsasano /*
489e737caceSsasano  * A frame was downloaded to the chip. It's safe for us to clean up
490e737caceSsasano  * the list buffers.
491e737caceSsasano  */
492e737caceSsasano void
ugl_txeof(struct usbd_xfer * xfer,void * priv,usbd_status status)493e737caceSsasano ugl_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
494e737caceSsasano {
495e737caceSsasano 	struct ugl_chain	*c = priv;
496e737caceSsasano 	struct ugl_softc	*sc = c->ugl_sc;
497e737caceSsasano 	struct ifnet		*ifp = GET_IFP(sc);
498e737caceSsasano 	int			s;
499e737caceSsasano 
500e737caceSsasano 	if (usbd_is_dying(sc->sc_udev))
501e737caceSsasano 		return;
502e737caceSsasano 
503e737caceSsasano 	s = splnet();
504e737caceSsasano 
505e737caceSsasano 	DPRINTFN(10,("%s: %s: enter status=%d\n", sc->sc_dev.dv_xname,
506e737caceSsasano 		    __func__, status));
507e737caceSsasano 
508e737caceSsasano 	ifp->if_timer = 0;
509de6cd8fbSdlg 	ifq_clr_oactive(&ifp->if_snd);
510e737caceSsasano 
511e737caceSsasano 	if (status != USBD_NORMAL_COMPLETION) {
512e737caceSsasano 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
513e737caceSsasano 			splx(s);
514e737caceSsasano 			return;
515e737caceSsasano 		}
516e737caceSsasano 		ifp->if_oerrors++;
517e737caceSsasano 		printf("%s: usb error on tx: %s\n", sc->sc_dev.dv_xname,
518e737caceSsasano 		    usbd_errstr(status));
519e737caceSsasano 		if (status == USBD_STALLED)
520e737caceSsasano 			usbd_clear_endpoint_stall_async(sc->sc_ep[UGL_ENDPT_TX]);
521e737caceSsasano 		splx(s);
522e737caceSsasano 		return;
523e737caceSsasano 	}
524e737caceSsasano 
525e737caceSsasano 	m_freem(c->ugl_mbuf);
526e737caceSsasano 	c->ugl_mbuf = NULL;
527e737caceSsasano 
5280cae21bdSpatrick 	if (ifq_empty(&ifp->if_snd) == 0)
529e737caceSsasano 		ugl_start(ifp);
530e737caceSsasano 
531e737caceSsasano 	splx(s);
532e737caceSsasano }
533e737caceSsasano 
534e737caceSsasano int
ugl_send(struct ugl_softc * sc,struct mbuf * m,int idx)535e737caceSsasano ugl_send(struct ugl_softc *sc, struct mbuf *m, int idx)
536e737caceSsasano {
537e737caceSsasano 	int			total_len;
538e737caceSsasano 	struct ugl_chain	*c;
539e737caceSsasano 	usbd_status		err;
540e737caceSsasano 
541e737caceSsasano 	c = &sc->sc_cdata.ugl_tx_chain[idx];
542e737caceSsasano 
543e737caceSsasano 	/*
544e737caceSsasano 	 * Copy the mbuf data into a contiguous buffer, leaving two
545e737caceSsasano 	 * bytes at the beginning to hold the frame length.
546e737caceSsasano 	 */
547e737caceSsasano 	USETDW(c->ugl_buf->pkt_count, UGL_TX_FRAMES);
548e737caceSsasano 	USETDW(c->ugl_buf->pkt_length, m->m_pkthdr.len);
549e737caceSsasano 	m_copydata(m, 0, m->m_pkthdr.len, c->ugl_buf->pkt_data);
550e737caceSsasano 	c->ugl_mbuf = m;
551e737caceSsasano 
552e737caceSsasano 	total_len = offsetof(struct ugl_packet, pkt_data[m->m_pkthdr.len]);
553e737caceSsasano 
554e737caceSsasano 	DPRINTFN(10,("%s: %s: total_len=%d\n",
555e737caceSsasano 		     sc->sc_dev.dv_xname, __func__, total_len));
556e737caceSsasano 
557e737caceSsasano 	usbd_setup_xfer(c->ugl_xfer, sc->sc_ep[UGL_ENDPT_TX],
558e737caceSsasano 	    c, c->ugl_buf, total_len, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
559e737caceSsasano 	    USBD_DEFAULT_TIMEOUT, ugl_txeof);
560e737caceSsasano 
561e737caceSsasano 	/* Transmit */
562e737caceSsasano 	err = usbd_transfer(c->ugl_xfer);
563e737caceSsasano 	if (err != USBD_IN_PROGRESS) {
564e737caceSsasano 		printf("%s: ugl_send error=%s\n", sc->sc_dev.dv_xname,
565e737caceSsasano 		       usbd_errstr(err));
5664ced949bSgerhard 		c->ugl_mbuf = NULL;
567e737caceSsasano 		ugl_stop(sc);
568e737caceSsasano 		return (EIO);
569e737caceSsasano 	}
570e737caceSsasano 
571e737caceSsasano 	sc->sc_cdata.ugl_tx_cnt++;
572e737caceSsasano 
573e737caceSsasano 	return (0);
574e737caceSsasano }
575e737caceSsasano 
576e737caceSsasano void
ugl_start(struct ifnet * ifp)577e737caceSsasano ugl_start(struct ifnet *ifp)
578e737caceSsasano {
579e737caceSsasano 	struct ugl_softc	*sc = ifp->if_softc;
580e737caceSsasano 	struct mbuf		*m_head = NULL;
581e737caceSsasano 
582e737caceSsasano 	if (usbd_is_dying(sc->sc_udev))
583e737caceSsasano 		return;
584e737caceSsasano 
585e737caceSsasano 	DPRINTFN(10,("%s: %s: enter\n", sc->sc_dev.dv_xname,__func__));
586e737caceSsasano 
587de6cd8fbSdlg 	if (ifq_is_oactive(&ifp->if_snd))
588e737caceSsasano 		return;
589e737caceSsasano 
5904ced949bSgerhard 	m_head = ifq_dequeue(&ifp->if_snd);
591e737caceSsasano 	if (m_head == NULL)
592e737caceSsasano 		return;
593e737caceSsasano 
594e737caceSsasano 	if (ugl_send(sc, m_head, 0)) {
5954ced949bSgerhard 		m_freem(m_head);
596de6cd8fbSdlg 		ifq_set_oactive(&ifp->if_snd);
597e737caceSsasano 		return;
598e737caceSsasano 	}
599e737caceSsasano 
600e737caceSsasano #if NBPFILTER > 0
601e737caceSsasano 	/*
602e737caceSsasano 	 * If there's a BPF listener, bounce a copy of this frame
603e737caceSsasano 	 * to him.
604e737caceSsasano 	 */
605e737caceSsasano 	if (ifp->if_bpf)
606e737caceSsasano 		bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
607e737caceSsasano #endif
608e737caceSsasano 
609de6cd8fbSdlg 	ifq_set_oactive(&ifp->if_snd);
610e737caceSsasano 
611e737caceSsasano 	/*
612e737caceSsasano 	 * Set a timeout in case the chip goes out to lunch.
613e737caceSsasano 	 */
614e737caceSsasano 	ifp->if_timer = 5;
615e737caceSsasano }
616e737caceSsasano 
617e737caceSsasano void
ugl_init(void * xsc)618e737caceSsasano ugl_init(void *xsc)
619e737caceSsasano {
620e737caceSsasano 	struct ugl_softc	*sc = xsc;
621e737caceSsasano 	struct ifnet		*ifp = GET_IFP(sc);
622e737caceSsasano 	int			s;
623e737caceSsasano 
624e737caceSsasano 	if (usbd_is_dying(sc->sc_udev))
625e737caceSsasano 		return;
626e737caceSsasano 
627e737caceSsasano 	DPRINTFN(10,("%s: %s: enter\n", sc->sc_dev.dv_xname,__func__));
628e737caceSsasano 
629e737caceSsasano 	s = splnet();
630e737caceSsasano 
631e737caceSsasano 	/* Init TX ring. */
632e737caceSsasano 	if (ugl_tx_list_init(sc) == ENOBUFS) {
633e737caceSsasano 		printf("%s: tx list init failed\n", sc->sc_dev.dv_xname);
634e737caceSsasano 		splx(s);
635e737caceSsasano 		return;
636e737caceSsasano 	}
637e737caceSsasano 
638e737caceSsasano 	/* Init RX ring. */
639e737caceSsasano 	if (ugl_rx_list_init(sc) == ENOBUFS) {
640e737caceSsasano 		printf("%s: rx list init failed\n", sc->sc_dev.dv_xname);
641e737caceSsasano 		splx(s);
642e737caceSsasano 		return;
643e737caceSsasano 	}
644e737caceSsasano 
645e737caceSsasano 	if (sc->sc_ep[UGL_ENDPT_RX] == NULL) {
646e737caceSsasano 		if (ugl_openpipes(sc)) {
647e737caceSsasano 			splx(s);
648e737caceSsasano 			return;
649e737caceSsasano 		}
650e737caceSsasano 	}
651e737caceSsasano 
652e737caceSsasano 	ifp->if_flags |= IFF_RUNNING;
653de6cd8fbSdlg 	ifq_clr_oactive(&ifp->if_snd);
6544bedc3dcSuaa 
6554bedc3dcSuaa 	splx(s);
656e737caceSsasano }
657e737caceSsasano 
658e737caceSsasano int
ugl_openpipes(struct ugl_softc * sc)659e737caceSsasano ugl_openpipes(struct ugl_softc *sc)
660e737caceSsasano {
661e737caceSsasano 	struct ugl_chain	*c;
662e737caceSsasano 	usbd_status		err;
663e737caceSsasano 	int			i;
664e737caceSsasano 
665e737caceSsasano 	/* Open RX and TX pipes. */
666e737caceSsasano 	err = usbd_open_pipe(sc->sc_iface, sc->sc_ed[UGL_ENDPT_RX],
667e737caceSsasano 	    USBD_EXCLUSIVE_USE, &sc->sc_ep[UGL_ENDPT_RX]);
668e737caceSsasano 	if (err) {
669e737caceSsasano 		printf("%s: open rx pipe failed: %s\n",
670e737caceSsasano 		    sc->sc_dev.dv_xname, usbd_errstr(err));
671e737caceSsasano 		return (EIO);
672e737caceSsasano 	}
673e737caceSsasano 	err = usbd_open_pipe(sc->sc_iface, sc->sc_ed[UGL_ENDPT_TX],
674e737caceSsasano 	    USBD_EXCLUSIVE_USE, &sc->sc_ep[UGL_ENDPT_TX]);
675e737caceSsasano 	if (err) {
676e737caceSsasano 		printf("%s: open tx pipe failed: %s\n",
677e737caceSsasano 		    sc->sc_dev.dv_xname, usbd_errstr(err));
678e737caceSsasano 		return (EIO);
679e737caceSsasano 	}
680e737caceSsasano 	err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ed[UGL_ENDPT_INTR],
6819d477d68Sjmatthew 	    0, &sc->sc_ep[UGL_ENDPT_INTR], sc,
682e737caceSsasano 	    sc->sc_ibuf, UGL_INTR_PKTLEN, ugl_intr,
683e737caceSsasano 	    UGL_INTR_INTERVAL);
684e737caceSsasano 	if (err) {
685e737caceSsasano 		printf("%s: open intr pipe failed: %s\n",
686e737caceSsasano 		    sc->sc_dev.dv_xname, usbd_errstr(err));
687e737caceSsasano 		return (EIO);
688e737caceSsasano 	}
689e737caceSsasano 
690e737caceSsasano 	/* Start up the receive pipe. */
691e737caceSsasano 	for (i = 0; i < UGL_RX_LIST_CNT; i++) {
692e737caceSsasano 		c = &sc->sc_cdata.ugl_rx_chain[i];
693e737caceSsasano 		usbd_setup_xfer(c->ugl_xfer, sc->sc_ep[UGL_ENDPT_RX],
694e737caceSsasano 		    c, c->ugl_buf, UGL_BUFSZ,
695e737caceSsasano 		    USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
696e737caceSsasano 		    ugl_rxeof);
697e737caceSsasano 		usbd_transfer(c->ugl_xfer);
698e737caceSsasano 	}
699e737caceSsasano 
700e737caceSsasano 	return (0);
701e737caceSsasano }
702e737caceSsasano 
703e737caceSsasano void
ugl_intr(struct usbd_xfer * xfer,void * priv,usbd_status status)704e737caceSsasano ugl_intr(struct usbd_xfer *xfer, void *priv, usbd_status status)
705e737caceSsasano {
706e737caceSsasano 	struct ugl_softc	*sc = priv;
707e737caceSsasano 	struct ifnet		*ifp = GET_IFP(sc);
708e737caceSsasano 	int			i;
709e737caceSsasano 
710e737caceSsasano 	DPRINTFN(15,("%s: %s: enter\n", sc->sc_dev.dv_xname,__func__));
711e737caceSsasano 
712e737caceSsasano 	if (usbd_is_dying(sc->sc_udev))
713e737caceSsasano 		return;
714e737caceSsasano 
715e737caceSsasano 	if (!(ifp->if_flags & IFF_RUNNING))
716e737caceSsasano 		return;
717e737caceSsasano 
718e737caceSsasano 	if (status != USBD_NORMAL_COMPLETION) {
719e737caceSsasano 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
720e737caceSsasano 			return;
721e737caceSsasano 		}
722e737caceSsasano 		sc->sc_intr_errs++;
723e737caceSsasano 		if (usbd_ratecheck(&sc->sc_rx_notice)) {
724e737caceSsasano 			printf("%s: %u usb errors on intr: %s\n",
725e737caceSsasano 			    sc->sc_dev.dv_xname, sc->sc_rx_errs,
726e737caceSsasano 			    usbd_errstr(status));
727e737caceSsasano 			sc->sc_intr_errs = 0;
728e737caceSsasano 		}
729e737caceSsasano 		if (status == USBD_STALLED)
730e737caceSsasano 			usbd_clear_endpoint_stall_async(sc->sc_ep[UGL_ENDPT_RX]);
731e737caceSsasano 		return;
732e737caceSsasano 	}
733e737caceSsasano 
734e737caceSsasano 	DPRINTFN(10,("%s: %s:", sc->sc_dev.dv_xname, __func__));
735e737caceSsasano 	for (i = 0; i < UGL_INTR_PKTLEN; i++)
736e737caceSsasano 		DPRINTFN(10,(" 0x%02x", sc->sc_ibuf[i]));
737e737caceSsasano 	DPRINTFN(10,("\n"));
738e737caceSsasano 
739e737caceSsasano }
740e737caceSsasano 
741e737caceSsasano int
ugl_ioctl(struct ifnet * ifp,u_long command,caddr_t data)742e737caceSsasano ugl_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
743e737caceSsasano {
744e737caceSsasano 	struct ugl_softc	*sc = ifp->if_softc;
745e737caceSsasano 	int			s, error = 0;
746e737caceSsasano 
747e737caceSsasano 	if (usbd_is_dying(sc->sc_udev))
748947e4cccSstsp 		return ENXIO;
749e737caceSsasano 
750e737caceSsasano 	DPRINTFN(5,("%s: %s: cmd=0x%08lx\n",
751e737caceSsasano 		    sc->sc_dev.dv_xname, __func__, command));
752e737caceSsasano 
753e737caceSsasano 	s = splnet();
754e737caceSsasano 
755e737caceSsasano 	switch(command) {
756e737caceSsasano 	case SIOCSIFADDR:
757e737caceSsasano 		ifp->if_flags |= IFF_UP;
75844fce25bSbrad 		if (!(ifp->if_flags & IFF_RUNNING))
759e737caceSsasano 			ugl_init(sc);
760e737caceSsasano 		break;
761e737caceSsasano 
762e737caceSsasano 	case SIOCSIFFLAGS:
763e737caceSsasano 		if (ifp->if_flags & IFF_UP) {
76444fce25bSbrad 			if (ifp->if_flags & IFF_RUNNING)
76544fce25bSbrad 				error = ENETRESET;
76644fce25bSbrad 			else
767e737caceSsasano 				ugl_init(sc);
768e737caceSsasano 		} else {
769e737caceSsasano 			if (ifp->if_flags & IFF_RUNNING)
770e737caceSsasano 				ugl_stop(sc);
771e737caceSsasano 		}
772e737caceSsasano 		break;
77344fce25bSbrad 
774e737caceSsasano 	default:
77544fce25bSbrad 		error = ether_ioctl(ifp, &sc->sc_arpcom, command, data);
776e737caceSsasano 		break;
777e737caceSsasano 	}
778e737caceSsasano 
77944fce25bSbrad 	if (error == ENETRESET)
78044fce25bSbrad 		error = 0;
78144fce25bSbrad 
782e737caceSsasano 	splx(s);
783e737caceSsasano 	return (error);
784e737caceSsasano }
785e737caceSsasano 
786e737caceSsasano void
ugl_watchdog(struct ifnet * ifp)787e737caceSsasano ugl_watchdog(struct ifnet *ifp)
788e737caceSsasano {
789e737caceSsasano 	struct ugl_softc	*sc = ifp->if_softc;
790e737caceSsasano 
791e737caceSsasano 	if (usbd_is_dying(sc->sc_udev))
792e737caceSsasano 		return;
793e737caceSsasano 
794e737caceSsasano 	ifp->if_oerrors++;
795e737caceSsasano 	printf("%s: watchdog timeout\n", sc->sc_dev.dv_xname);
796e737caceSsasano }
797e737caceSsasano 
798e737caceSsasano /*
799e737caceSsasano  * Stop the adapter and free any mbufs allocated to the
800e737caceSsasano  * RX and TX lists.
801e737caceSsasano  */
802e737caceSsasano void
ugl_stop(struct ugl_softc * sc)803e737caceSsasano ugl_stop(struct ugl_softc *sc)
804e737caceSsasano {
805e737caceSsasano 	struct ifnet		*ifp;
806e737caceSsasano 	int			i;
807e737caceSsasano 
808e737caceSsasano 	DPRINTFN(10,("%s: %s: enter\n", sc->sc_dev.dv_xname,__func__));
809e737caceSsasano 
810e737caceSsasano 	ifp = GET_IFP(sc);
811e737caceSsasano 	ifp->if_timer = 0;
812de6cd8fbSdlg 	ifp->if_flags &= ~IFF_RUNNING;
813de6cd8fbSdlg 	ifq_clr_oactive(&ifp->if_snd);
814e737caceSsasano 
815e737caceSsasano 	/* Stop transfers. */
816e737caceSsasano 	if (sc->sc_ep[UGL_ENDPT_RX] != NULL) {
817e737caceSsasano 		usbd_close_pipe(sc->sc_ep[UGL_ENDPT_RX]);
818e737caceSsasano 		sc->sc_ep[UGL_ENDPT_RX] = NULL;
819e737caceSsasano 	}
820e737caceSsasano 
821e737caceSsasano 	if (sc->sc_ep[UGL_ENDPT_TX] != NULL) {
822e737caceSsasano 		usbd_close_pipe(sc->sc_ep[UGL_ENDPT_TX]);
823e737caceSsasano 		sc->sc_ep[UGL_ENDPT_TX] = NULL;
824e737caceSsasano 	}
825e737caceSsasano 
826e737caceSsasano 	if (sc->sc_ep[UGL_ENDPT_INTR] != NULL) {
827e737caceSsasano 		usbd_close_pipe(sc->sc_ep[UGL_ENDPT_INTR]);
828e737caceSsasano 		sc->sc_ep[UGL_ENDPT_INTR] = NULL;
829e737caceSsasano 	}
830e737caceSsasano 
831e737caceSsasano 	/* Free RX resources. */
832e737caceSsasano 	for (i = 0; i < UGL_RX_LIST_CNT; i++) {
833e737caceSsasano 		if (sc->sc_cdata.ugl_rx_chain[i].ugl_mbuf != NULL) {
834e737caceSsasano 			m_freem(sc->sc_cdata.ugl_rx_chain[i].ugl_mbuf);
835e737caceSsasano 			sc->sc_cdata.ugl_rx_chain[i].ugl_mbuf = NULL;
836e737caceSsasano 		}
837e737caceSsasano 		if (sc->sc_cdata.ugl_rx_chain[i].ugl_xfer != NULL) {
838e737caceSsasano 			usbd_free_xfer(sc->sc_cdata.ugl_rx_chain[i].ugl_xfer);
839e737caceSsasano 			sc->sc_cdata.ugl_rx_chain[i].ugl_xfer = NULL;
840e737caceSsasano 		}
841e737caceSsasano 	}
842e737caceSsasano 
843e737caceSsasano 	/* Free TX resources. */
844e737caceSsasano 	for (i = 0; i < UGL_TX_LIST_CNT; i++) {
845e737caceSsasano 		if (sc->sc_cdata.ugl_tx_chain[i].ugl_mbuf != NULL) {
846e737caceSsasano 			m_freem(sc->sc_cdata.ugl_tx_chain[i].ugl_mbuf);
847e737caceSsasano 			sc->sc_cdata.ugl_tx_chain[i].ugl_mbuf = NULL;
848e737caceSsasano 		}
849e737caceSsasano 		if (sc->sc_cdata.ugl_tx_chain[i].ugl_xfer != NULL) {
850e737caceSsasano 			usbd_free_xfer(sc->sc_cdata.ugl_tx_chain[i].ugl_xfer);
851e737caceSsasano 			sc->sc_cdata.ugl_tx_chain[i].ugl_xfer = NULL;
852e737caceSsasano 		}
853e737caceSsasano 	}
854e737caceSsasano }
855