xref: /openbsd-src/sys/dev/usb/if_cue.c (revision 850e275390052b330d93020bf619a739a3c277ac)
1 /*	$OpenBSD: if_cue.c,v 1.49 2008/09/10 14:01:23 blambert Exp $ */
2 /*	$NetBSD: if_cue.c,v 1.40 2002/07/11 21:14:26 augustss Exp $	*/
3 /*
4  * Copyright (c) 1997, 1998, 1999, 2000
5  *	Bill Paul <wpaul@ee.columbia.edu>.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by Bill Paul.
18  * 4. Neither the name of the author nor the names of any co-contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32  * THE POSSIBILITY OF SUCH DAMAGE.
33  *
34  * $FreeBSD: src/sys/dev/usb/if_cue.c,v 1.4 2000/01/16 22:45:06 wpaul Exp $
35  */
36 
37 /*
38  * CATC USB-EL1210A USB to ethernet driver. Used in the CATC Netmate
39  * adapters and others.
40  *
41  * Written by Bill Paul <wpaul@ee.columbia.edu>
42  * Electrical Engineering Department
43  * Columbia University, New York City
44  */
45 
46 /*
47  * The CATC USB-EL1210A provides USB ethernet support at 10Mbps. The
48  * RX filter uses a 512-bit multicast hash table, single perfect entry
49  * for the station address, and promiscuous mode. Unlike the ADMtek
50  * and KLSI chips, the CATC ASIC supports read and write combining
51  * mode where multiple packets can be transferred using a single bulk
52  * transaction, which helps performance a great deal.
53  */
54 
55 /*
56  * Ported to NetBSD and somewhat rewritten by Lennart Augustsson.
57  */
58 
59 #include "bpfilter.h"
60 
61 #include <sys/param.h>
62 #include <sys/systm.h>
63 #include <sys/sockio.h>
64 #include <sys/mbuf.h>
65 #include <sys/kernel.h>
66 #include <sys/socket.h>
67 #include <sys/timeout.h>
68 #include <sys/device.h>
69 
70 #include <net/if.h>
71 #include <net/if_dl.h>
72 
73 #if NBPFILTER > 0
74 #include <net/bpf.h>
75 #endif
76 
77 #ifdef INET
78 #include <netinet/in.h>
79 #include <netinet/in_systm.h>
80 #include <netinet/in_var.h>
81 #include <netinet/ip.h>
82 #include <netinet/if_ether.h>
83 #endif
84 
85 #include <dev/usb/usb.h>
86 #include <dev/usb/usbdi.h>
87 #include <dev/usb/usbdi_util.h>
88 #include <dev/usb/usbdevs.h>
89 
90 #include <dev/usb/if_cuereg.h>
91 
92 #ifdef CUE_DEBUG
93 #define DPRINTF(x)	do { if (cuedebug) printf x; } while (0)
94 #define DPRINTFN(n,x)	do { if (cuedebug >= (n)) printf x; } while (0)
95 int	cuedebug = 0;
96 #else
97 #define DPRINTF(x)
98 #define DPRINTFN(n,x)
99 #endif
100 
101 /*
102  * Various supported device vendors/products.
103  */
104 struct usb_devno cue_devs[] = {
105 	{ USB_VENDOR_CATC, USB_PRODUCT_CATC_NETMATE },
106 	{ USB_VENDOR_CATC, USB_PRODUCT_CATC_NETMATE2 },
107 	{ USB_VENDOR_SMARTBRIDGES, USB_PRODUCT_SMARTBRIDGES_SMARTLINK },
108 	/* Belkin F5U111 adapter covered by NETMATE entry */
109 };
110 #define cue_lookup(v, p) (usb_lookup(cue_devs, v, p))
111 
112 int cue_match(struct device *, void *, void *);
113 void cue_attach(struct device *, struct device *, void *);
114 int cue_detach(struct device *, int);
115 int cue_activate(struct device *, enum devact);
116 
117 struct cfdriver cue_cd = {
118 	NULL, "cue", DV_IFNET
119 };
120 
121 const struct cfattach cue_ca = {
122 	sizeof(struct cue_softc),
123 	cue_match,
124 	cue_attach,
125 	cue_detach,
126 	cue_activate,
127 };
128 
129 int cue_open_pipes(struct cue_softc *);
130 int cue_tx_list_init(struct cue_softc *);
131 int cue_rx_list_init(struct cue_softc *);
132 int cue_newbuf(struct cue_softc *, struct cue_chain *, struct mbuf *);
133 int cue_send(struct cue_softc *, struct mbuf *, int);
134 void cue_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
135 void cue_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
136 void cue_tick(void *);
137 void cue_tick_task(void *);
138 void cue_start(struct ifnet *);
139 int cue_ioctl(struct ifnet *, u_long, caddr_t);
140 void cue_init(void *);
141 void cue_stop(struct cue_softc *);
142 void cue_watchdog(struct ifnet *);
143 
144 void cue_setmulti(struct cue_softc *);
145 void cue_reset(struct cue_softc *);
146 
147 int cue_csr_read_1(struct cue_softc *, int);
148 int cue_csr_write_1(struct cue_softc *, int, int);
149 int cue_csr_read_2(struct cue_softc *, int);
150 #if 0
151 int cue_csr_write_2(struct cue_softc *, int, int);
152 #endif
153 int cue_mem(struct cue_softc *, int, int, void *, int);
154 int cue_getmac(struct cue_softc *, void *);
155 
156 #define CUE_SETBIT(sc, reg, x)				\
157 	cue_csr_write_1(sc, reg, cue_csr_read_1(sc, reg) | (x))
158 
159 #define CUE_CLRBIT(sc, reg, x)				\
160 	cue_csr_write_1(sc, reg, cue_csr_read_1(sc, reg) & ~(x))
161 
162 int
163 cue_csr_read_1(struct cue_softc *sc, int reg)
164 {
165 	usb_device_request_t	req;
166 	usbd_status		err;
167 	u_int8_t		val = 0;
168 
169 	if (sc->cue_dying)
170 		return (0);
171 
172 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
173 	req.bRequest = CUE_CMD_READREG;
174 	USETW(req.wValue, 0);
175 	USETW(req.wIndex, reg);
176 	USETW(req.wLength, 1);
177 
178 	err = usbd_do_request(sc->cue_udev, &req, &val);
179 
180 	if (err) {
181 		DPRINTF(("%s: cue_csr_read_1: reg=0x%x err=%s\n",
182 			 sc->cue_dev.dv_xname, reg, usbd_errstr(err)));
183 		return (0);
184 	}
185 
186 	DPRINTFN(10,("%s: cue_csr_read_1 reg=0x%x val=0x%x\n",
187 		     sc->cue_dev.dv_xname, reg, val));
188 
189 	return (val);
190 }
191 
192 int
193 cue_csr_read_2(struct cue_softc *sc, int reg)
194 {
195 	usb_device_request_t	req;
196 	usbd_status		err;
197 	uWord			val;
198 
199 	if (sc->cue_dying)
200 		return (0);
201 
202 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
203 	req.bRequest = CUE_CMD_READREG;
204 	USETW(req.wValue, 0);
205 	USETW(req.wIndex, reg);
206 	USETW(req.wLength, 2);
207 
208 	err = usbd_do_request(sc->cue_udev, &req, &val);
209 
210 	DPRINTFN(10,("%s: cue_csr_read_2 reg=0x%x val=0x%x\n",
211 		     sc->cue_dev.dv_xname, reg, UGETW(val)));
212 
213 	if (err) {
214 		DPRINTF(("%s: cue_csr_read_2: reg=0x%x err=%s\n",
215 			 sc->cue_dev.dv_xname, reg, usbd_errstr(err)));
216 		return (0);
217 	}
218 
219 	return (UGETW(val));
220 }
221 
222 int
223 cue_csr_write_1(struct cue_softc *sc, int reg, int val)
224 {
225 	usb_device_request_t	req;
226 	usbd_status		err;
227 
228 	if (sc->cue_dying)
229 		return (0);
230 
231 	DPRINTFN(10,("%s: cue_csr_write_1 reg=0x%x val=0x%x\n",
232 		     sc->cue_dev.dv_xname, reg, val));
233 
234 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
235 	req.bRequest = CUE_CMD_WRITEREG;
236 	USETW(req.wValue, val);
237 	USETW(req.wIndex, reg);
238 	USETW(req.wLength, 0);
239 
240 	err = usbd_do_request(sc->cue_udev, &req, NULL);
241 
242 	if (err) {
243 		DPRINTF(("%s: cue_csr_write_1: reg=0x%x err=%s\n",
244 			 sc->cue_dev.dv_xname, reg, usbd_errstr(err)));
245 		return (-1);
246 	}
247 
248 	DPRINTFN(20,("%s: cue_csr_write_1, after reg=0x%x val=0x%x\n",
249 		     sc->cue_dev.dv_xname, reg, cue_csr_read_1(sc, reg)));
250 
251 	return (0);
252 }
253 
254 #if 0
255 int
256 cue_csr_write_2(struct cue_softc *sc, int reg, int aval)
257 {
258 	usb_device_request_t	req;
259 	usbd_status		err;
260 	uWord			val;
261 	int			s;
262 
263 	if (sc->cue_dying)
264 		return (0);
265 
266 	DPRINTFN(10,("%s: cue_csr_write_2 reg=0x%x val=0x%x\n",
267 		     sc->cue_dev.dv_xname, reg, aval));
268 
269 	USETW(val, aval);
270 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
271 	req.bRequest = CUE_CMD_WRITEREG;
272 	USETW(req.wValue, val);
273 	USETW(req.wIndex, reg);
274 	USETW(req.wLength, 0);
275 
276 	err = usbd_do_request(sc->cue_udev, &req, NULL);
277 
278 	if (err) {
279 		DPRINTF(("%s: cue_csr_write_2: reg=0x%x err=%s\n",
280 			 sc->cue_dev.dv_xname, reg, usbd_errstr(err)));
281 		return (-1);
282 	}
283 
284 	return (0);
285 }
286 #endif
287 
288 int
289 cue_mem(struct cue_softc *sc, int cmd, int addr, void *buf, int len)
290 {
291 	usb_device_request_t	req;
292 	usbd_status		err;
293 
294 	DPRINTFN(10,("%s: cue_mem cmd=0x%x addr=0x%x len=%d\n",
295 		     sc->cue_dev.dv_xname, cmd, addr, len));
296 
297 	if (cmd == CUE_CMD_READSRAM)
298 		req.bmRequestType = UT_READ_VENDOR_DEVICE;
299 	else
300 		req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
301 	req.bRequest = cmd;
302 	USETW(req.wValue, 0);
303 	USETW(req.wIndex, addr);
304 	USETW(req.wLength, len);
305 
306 	err = usbd_do_request(sc->cue_udev, &req, buf);
307 
308 	if (err) {
309 		DPRINTF(("%s: cue_csr_mem: addr=0x%x err=%s\n",
310 			 sc->cue_dev.dv_xname, addr, usbd_errstr(err)));
311 		return (-1);
312 	}
313 
314 	return (0);
315 }
316 
317 int
318 cue_getmac(struct cue_softc *sc, void *buf)
319 {
320 	usb_device_request_t	req;
321 	usbd_status		err;
322 
323 	DPRINTFN(10,("%s: cue_getmac\n", sc->cue_dev.dv_xname));
324 
325 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
326 	req.bRequest = CUE_CMD_GET_MACADDR;
327 	USETW(req.wValue, 0);
328 	USETW(req.wIndex, 0);
329 	USETW(req.wLength, ETHER_ADDR_LEN);
330 
331 	err = usbd_do_request(sc->cue_udev, &req, buf);
332 
333 	if (err) {
334 		printf("%s: read MAC address failed\n",
335 		       sc->cue_dev.dv_xname);
336 		return (-1);
337 	}
338 
339 	return (0);
340 }
341 
342 #define CUE_BITS	9
343 
344 void
345 cue_setmulti(struct cue_softc *sc)
346 {
347 	struct ifnet		*ifp;
348 	struct ether_multi	*enm;
349 	struct ether_multistep	step;
350 	u_int32_t		h, i;
351 
352 	ifp = GET_IFP(sc);
353 
354 	DPRINTFN(2,("%s: cue_setmulti if_flags=0x%x\n",
355 		    sc->cue_dev.dv_xname, ifp->if_flags));
356 
357 	if (ifp->if_flags & IFF_PROMISC) {
358 allmulti:
359 		ifp->if_flags |= IFF_ALLMULTI;
360 		for (i = 0; i < CUE_MCAST_TABLE_LEN; i++)
361 			sc->cue_mctab[i] = 0xFF;
362 		cue_mem(sc, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR,
363 		    &sc->cue_mctab, CUE_MCAST_TABLE_LEN);
364 		return;
365 	}
366 
367 	/* first, zot all the existing hash bits */
368 	for (i = 0; i < CUE_MCAST_TABLE_LEN; i++)
369 		sc->cue_mctab[i] = 0;
370 
371 	/* now program new ones */
372 	ETHER_FIRST_MULTI(step, &sc->arpcom, enm);
373 	while (enm != NULL) {
374 		if (memcmp(enm->enm_addrlo,
375 		    enm->enm_addrhi, ETHER_ADDR_LEN) != 0)
376 			goto allmulti;
377 
378 		h = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN) &
379 		    ((1 << CUE_BITS) - 1);
380 		sc->cue_mctab[h >> 3] |= 1 << (h & 0x7);
381 		ETHER_NEXT_MULTI(step, enm);
382 	}
383 
384 	ifp->if_flags &= ~IFF_ALLMULTI;
385 
386 	/*
387 	 * Also include the broadcast address in the filter
388 	 * so we can receive broadcast frames.
389 	 */
390 	if (ifp->if_flags & IFF_BROADCAST) {
391 		h = ether_crc32_le(etherbroadcastaddr, ETHER_ADDR_LEN) &
392 		    ((1 << CUE_BITS) - 1);
393 		sc->cue_mctab[h >> 3] |= 1 << (h & 0x7);
394 	}
395 
396 	cue_mem(sc, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR,
397 	    &sc->cue_mctab, CUE_MCAST_TABLE_LEN);
398 }
399 
400 void
401 cue_reset(struct cue_softc *sc)
402 {
403 	usb_device_request_t	req;
404 	usbd_status		err;
405 
406 	DPRINTFN(2,("%s: cue_reset\n", sc->cue_dev.dv_xname));
407 
408 	if (sc->cue_dying)
409 		return;
410 
411 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
412 	req.bRequest = CUE_CMD_RESET;
413 	USETW(req.wValue, 0);
414 	USETW(req.wIndex, 0);
415 	USETW(req.wLength, 0);
416 
417 	err = usbd_do_request(sc->cue_udev, &req, NULL);
418 
419 	if (err)
420 		printf("%s: reset failed\n", sc->cue_dev.dv_xname);
421 
422 	/* Wait a little while for the chip to get its brains in order. */
423 	usbd_delay_ms(sc->cue_udev, 1);
424 }
425 
426 /*
427  * Probe for a CATC chip.
428  */
429 int
430 cue_match(struct device *parent, void *match, void *aux)
431 {
432 	struct usb_attach_arg	*uaa = aux;
433 
434 	if (uaa->iface != NULL)
435 		return (UMATCH_NONE);
436 
437 	return (cue_lookup(uaa->vendor, uaa->product) != NULL ?
438 		UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
439 }
440 
441 /*
442  * Attach the interface. Allocate softc structures, do ifmedia
443  * setup and ethernet/BPF attach.
444  */
445 void
446 cue_attach(struct device *parent, struct device *self, void *aux)
447 {
448 	struct cue_softc	*sc = (struct cue_softc *)self;
449 	struct usb_attach_arg	*uaa = aux;
450 	int			s;
451 	u_char			eaddr[ETHER_ADDR_LEN];
452 	usbd_device_handle	dev = uaa->device;
453 	usbd_interface_handle	iface;
454 	usbd_status		err;
455 	struct ifnet		*ifp;
456 	usb_interface_descriptor_t	*id;
457 	usb_endpoint_descriptor_t	*ed;
458 	int			i;
459 
460 	DPRINTFN(5,(" : cue_attach: sc=%p, dev=%p", sc, dev));
461 
462 	err = usbd_set_config_no(dev, CUE_CONFIG_NO, 1);
463 	if (err) {
464 		printf("%s: setting config no failed\n",
465 		    sc->cue_dev.dv_xname);
466 		return;
467 	}
468 
469 	sc->cue_udev = dev;
470 	sc->cue_product = uaa->product;
471 	sc->cue_vendor = uaa->vendor;
472 
473 	usb_init_task(&sc->cue_tick_task, cue_tick_task, sc);
474 	usb_init_task(&sc->cue_stop_task, (void (*)(void *))cue_stop, sc);
475 
476 	err = usbd_device2interface_handle(dev, CUE_IFACE_IDX, &iface);
477 	if (err) {
478 		printf("%s: getting interface handle failed\n",
479 		    sc->cue_dev.dv_xname);
480 		return;
481 	}
482 
483 	sc->cue_iface = iface;
484 	id = usbd_get_interface_descriptor(iface);
485 
486 	/* Find endpoints. */
487 	for (i = 0; i < id->bNumEndpoints; i++) {
488 		ed = usbd_interface2endpoint_descriptor(iface, i);
489 		if (ed == NULL) {
490 			printf("%s: couldn't get ep %d\n",
491 			    sc->cue_dev.dv_xname, i);
492 			return;
493 		}
494 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
495 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
496 			sc->cue_ed[CUE_ENDPT_RX] = ed->bEndpointAddress;
497 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
498 			   UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
499 			sc->cue_ed[CUE_ENDPT_TX] = ed->bEndpointAddress;
500 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
501 			   UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
502 			sc->cue_ed[CUE_ENDPT_INTR] = ed->bEndpointAddress;
503 		}
504 	}
505 
506 #if 0
507 	/* Reset the adapter. */
508 	cue_reset(sc);
509 #endif
510 	/*
511 	 * Get station address.
512 	 */
513 	cue_getmac(sc, &eaddr);
514 
515 	s = splnet();
516 
517 	/*
518 	 * A CATC chip was detected. Inform the world.
519 	 */
520 	printf("%s: address %s\n", sc->cue_dev.dv_xname,
521 	    ether_sprintf(eaddr));
522 
523 	bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
524 
525 	/* Initialize interface info.*/
526 	ifp = GET_IFP(sc);
527 	ifp->if_softc = sc;
528 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
529 	ifp->if_ioctl = cue_ioctl;
530 	ifp->if_start = cue_start;
531 	ifp->if_watchdog = cue_watchdog;
532 	strlcpy(ifp->if_xname, sc->cue_dev.dv_xname, IFNAMSIZ);
533 
534 	IFQ_SET_READY(&ifp->if_snd);
535 
536 	/* Attach the interface. */
537 	if_attach(ifp);
538 	ether_ifattach(ifp);
539 
540 	timeout_set(&sc->cue_stat_ch, cue_tick, sc);
541 
542 	sc->cue_attached = 1;
543 	splx(s);
544 
545 	usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->cue_udev,
546 	    &sc->cue_dev);
547 }
548 
549 int
550 cue_detach(struct device *self, int flags)
551 {
552 	struct cue_softc	*sc = (struct cue_softc *)self;
553 	struct ifnet		*ifp = GET_IFP(sc);
554 	int			s;
555 
556 	DPRINTFN(2,("%s: %s: enter\n", sc->cue_dev.dv_xname, __func__));
557 
558 	timeout_del(&sc->cue_stat_ch);
559 	/*
560 	 * Remove any pending task.  It cannot be executing because it run
561 	 * in the same thread as detach.
562 	 */
563 	usb_rem_task(sc->cue_udev, &sc->cue_tick_task);
564 	usb_rem_task(sc->cue_udev, &sc->cue_stop_task);
565 
566 	if (!sc->cue_attached) {
567 		/* Detached before attached finished, so just bail out. */
568 		return (0);
569 	}
570 
571 	s = splusb();
572 
573 	if (ifp->if_flags & IFF_RUNNING)
574 		cue_stop(sc);
575 
576 	ether_ifdetach(ifp);
577 
578 	if_detach(ifp);
579 
580 #ifdef DIAGNOSTIC
581 	if (sc->cue_ep[CUE_ENDPT_TX] != NULL ||
582 	    sc->cue_ep[CUE_ENDPT_RX] != NULL ||
583 	    sc->cue_ep[CUE_ENDPT_INTR] != NULL)
584 		printf("%s: detach has active endpoints\n",
585 		       sc->cue_dev.dv_xname);
586 #endif
587 
588 	sc->cue_attached = 0;
589 	splx(s);
590 
591 	usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->cue_udev,
592 	    &sc->cue_dev);
593 
594 	return (0);
595 }
596 
597 int
598 cue_activate(struct device *self, enum devact act)
599 {
600 	struct cue_softc *sc = (struct cue_softc *)self;
601 
602 	DPRINTFN(2,("%s: %s: enter\n", sc->cue_dev.dv_xname, __func__));
603 
604 	switch (act) {
605 	case DVACT_ACTIVATE:
606 		break;
607 
608 	case DVACT_DEACTIVATE:
609 		sc->cue_dying = 1;
610 		break;
611 	}
612 	return (0);
613 }
614 
615 /*
616  * Initialize an RX descriptor and attach an MBUF cluster.
617  */
618 int
619 cue_newbuf(struct cue_softc *sc, struct cue_chain *c, struct mbuf *m)
620 {
621 	struct mbuf		*m_new = NULL;
622 
623 	if (m == NULL) {
624 		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
625 		if (m_new == NULL) {
626 			printf("%s: no memory for rx list "
627 			    "-- packet dropped!\n", sc->cue_dev.dv_xname);
628 			return (ENOBUFS);
629 		}
630 
631 		MCLGET(m_new, M_DONTWAIT);
632 		if (!(m_new->m_flags & M_EXT)) {
633 			printf("%s: no memory for rx list "
634 			    "-- packet dropped!\n", sc->cue_dev.dv_xname);
635 			m_freem(m_new);
636 			return (ENOBUFS);
637 		}
638 		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
639 	} else {
640 		m_new = m;
641 		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
642 		m_new->m_data = m_new->m_ext.ext_buf;
643 	}
644 
645 	m_adj(m_new, ETHER_ALIGN);
646 	c->cue_mbuf = m_new;
647 
648 	return (0);
649 }
650 
651 int
652 cue_rx_list_init(struct cue_softc *sc)
653 {
654 	struct cue_cdata	*cd;
655 	struct cue_chain	*c;
656 	int			i;
657 
658 	cd = &sc->cue_cdata;
659 	for (i = 0; i < CUE_RX_LIST_CNT; i++) {
660 		c = &cd->cue_rx_chain[i];
661 		c->cue_sc = sc;
662 		c->cue_idx = i;
663 		if (cue_newbuf(sc, c, NULL) == ENOBUFS)
664 			return (ENOBUFS);
665 		if (c->cue_xfer == NULL) {
666 			c->cue_xfer = usbd_alloc_xfer(sc->cue_udev);
667 			if (c->cue_xfer == NULL)
668 				return (ENOBUFS);
669 			c->cue_buf = usbd_alloc_buffer(c->cue_xfer, CUE_BUFSZ);
670 			if (c->cue_buf == NULL) {
671 				usbd_free_xfer(c->cue_xfer);
672 				return (ENOBUFS);
673 			}
674 		}
675 	}
676 
677 	return (0);
678 }
679 
680 int
681 cue_tx_list_init(struct cue_softc *sc)
682 {
683 	struct cue_cdata	*cd;
684 	struct cue_chain	*c;
685 	int			i;
686 
687 	cd = &sc->cue_cdata;
688 	for (i = 0; i < CUE_TX_LIST_CNT; i++) {
689 		c = &cd->cue_tx_chain[i];
690 		c->cue_sc = sc;
691 		c->cue_idx = i;
692 		c->cue_mbuf = NULL;
693 		if (c->cue_xfer == NULL) {
694 			c->cue_xfer = usbd_alloc_xfer(sc->cue_udev);
695 			if (c->cue_xfer == NULL)
696 				return (ENOBUFS);
697 			c->cue_buf = usbd_alloc_buffer(c->cue_xfer, CUE_BUFSZ);
698 			if (c->cue_buf == NULL) {
699 				usbd_free_xfer(c->cue_xfer);
700 				return (ENOBUFS);
701 			}
702 		}
703 	}
704 
705 	return (0);
706 }
707 
708 /*
709  * A frame has been uploaded: pass the resulting mbuf chain up to
710  * the higher level protocols.
711  */
712 void
713 cue_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
714 {
715 	struct cue_chain	*c = priv;
716 	struct cue_softc	*sc = c->cue_sc;
717 	struct ifnet		*ifp = GET_IFP(sc);
718 	struct mbuf		*m;
719 	int			total_len = 0;
720 	u_int16_t		len;
721 	int			s;
722 
723 	DPRINTFN(10,("%s: %s: enter status=%d\n", sc->cue_dev.dv_xname,
724 		     __func__, status));
725 
726 	if (sc->cue_dying)
727 		return;
728 
729 	if (!(ifp->if_flags & IFF_RUNNING))
730 		return;
731 
732 	if (status != USBD_NORMAL_COMPLETION) {
733 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
734 			return;
735 		sc->cue_rx_errs++;
736 		if (usbd_ratecheck(&sc->cue_rx_notice)) {
737 			printf("%s: %u usb errors on rx: %s\n",
738 			    sc->cue_dev.dv_xname, sc->cue_rx_errs,
739 			    usbd_errstr(status));
740 			sc->cue_rx_errs = 0;
741 		}
742 		if (status == USBD_STALLED)
743 			usbd_clear_endpoint_stall_async(sc->cue_ep[CUE_ENDPT_RX]);
744 		goto done;
745 	}
746 
747 	usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
748 
749 	memcpy(mtod(c->cue_mbuf, char *), c->cue_buf, total_len);
750 
751 	m = c->cue_mbuf;
752 	len = UGETW(mtod(m, u_int8_t *));
753 
754 	/* No errors; receive the packet. */
755 	total_len = len;
756 
757 	if (len < sizeof(struct ether_header)) {
758 		ifp->if_ierrors++;
759 		goto done;
760 	}
761 
762 	ifp->if_ipackets++;
763 	m_adj(m, sizeof(u_int16_t));
764 	m->m_pkthdr.len = m->m_len = total_len;
765 
766 	m->m_pkthdr.rcvif = ifp;
767 
768 	s = splnet();
769 
770 	/* XXX ugly */
771 	if (cue_newbuf(sc, c, NULL) == ENOBUFS) {
772 		ifp->if_ierrors++;
773 		goto done1;
774 	}
775 
776 #if NBPFILTER > 0
777 	/*
778 	 * Handle BPF listeners. Let the BPF user see the packet, but
779 	 * don't pass it up to the ether_input() layer unless it's
780 	 * a broadcast packet, multicast packet, matches our ethernet
781 	 * address or the interface is in promiscuous mode.
782 	 */
783 	if (ifp->if_bpf)
784 		bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
785 #endif
786 
787 	DPRINTFN(10,("%s: %s: deliver %d\n", sc->cue_dev.dv_xname,
788 		    __func__, m->m_len));
789 	ether_input_mbuf(ifp, m);
790  done1:
791 	splx(s);
792 
793 done:
794 	/* Setup new transfer. */
795 	usbd_setup_xfer(c->cue_xfer, sc->cue_ep[CUE_ENDPT_RX],
796 	    c, c->cue_buf, CUE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
797 	    USBD_NO_TIMEOUT, cue_rxeof);
798 	usbd_transfer(c->cue_xfer);
799 
800 	DPRINTFN(10,("%s: %s: start rx\n", sc->cue_dev.dv_xname,
801 		    __func__));
802 }
803 
804 /*
805  * A frame was downloaded to the chip. It's safe for us to clean up
806  * the list buffers.
807  */
808 void
809 cue_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
810 {
811 	struct cue_chain	*c = priv;
812 	struct cue_softc	*sc = c->cue_sc;
813 	struct ifnet		*ifp = GET_IFP(sc);
814 	int			s;
815 
816 	if (sc->cue_dying)
817 		return;
818 
819 	s = splnet();
820 
821 	DPRINTFN(10,("%s: %s: enter status=%d\n", sc->cue_dev.dv_xname,
822 		    __func__, status));
823 
824 	ifp->if_timer = 0;
825 	ifp->if_flags &= ~IFF_OACTIVE;
826 
827 	if (status != USBD_NORMAL_COMPLETION) {
828 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
829 			splx(s);
830 			return;
831 		}
832 		ifp->if_oerrors++;
833 		printf("%s: usb error on tx: %s\n", sc->cue_dev.dv_xname,
834 		    usbd_errstr(status));
835 		if (status == USBD_STALLED)
836 			usbd_clear_endpoint_stall_async(sc->cue_ep[CUE_ENDPT_TX]);
837 		splx(s);
838 		return;
839 	}
840 
841 	ifp->if_opackets++;
842 
843 	m_freem(c->cue_mbuf);
844 	c->cue_mbuf = NULL;
845 
846 	if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
847 		cue_start(ifp);
848 
849 	splx(s);
850 }
851 
852 void
853 cue_tick(void *xsc)
854 {
855 	struct cue_softc	*sc = xsc;
856 
857 	if (sc == NULL)
858 		return;
859 
860 	if (sc->cue_dying)
861 		return;
862 
863 	DPRINTFN(2,("%s: %s: enter\n", sc->cue_dev.dv_xname, __func__));
864 
865 	/* Perform statistics update in process context. */
866 	usb_add_task(sc->cue_udev, &sc->cue_tick_task);
867 }
868 
869 void
870 cue_tick_task(void *xsc)
871 {
872 	struct cue_softc	*sc = xsc;
873 	struct ifnet		*ifp;
874 
875 	if (sc->cue_dying)
876 		return;
877 
878 	DPRINTFN(2,("%s: %s: enter\n", sc->cue_dev.dv_xname, __func__));
879 
880 	ifp = GET_IFP(sc);
881 
882 	ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_SINGLECOLL);
883 	ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_MULTICOLL);
884 	ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_EXCESSCOLL);
885 
886 	if (cue_csr_read_2(sc, CUE_RX_FRAMEERR))
887 		ifp->if_ierrors++;
888 }
889 
890 int
891 cue_send(struct cue_softc *sc, struct mbuf *m, int idx)
892 {
893 	int			total_len;
894 	struct cue_chain	*c;
895 	usbd_status		err;
896 
897 	c = &sc->cue_cdata.cue_tx_chain[idx];
898 
899 	/*
900 	 * Copy the mbuf data into a contiguous buffer, leaving two
901 	 * bytes at the beginning to hold the frame length.
902 	 */
903 	m_copydata(m, 0, m->m_pkthdr.len, c->cue_buf + 2);
904 	c->cue_mbuf = m;
905 
906 	total_len = m->m_pkthdr.len + 2;
907 
908 	DPRINTFN(10,("%s: %s: total_len=%d\n",
909 		     sc->cue_dev.dv_xname, __func__, total_len));
910 
911 	/* The first two bytes are the frame length */
912 	c->cue_buf[0] = (u_int8_t)m->m_pkthdr.len;
913 	c->cue_buf[1] = (u_int8_t)(m->m_pkthdr.len >> 8);
914 
915 	/* XXX 10000 */
916 	usbd_setup_xfer(c->cue_xfer, sc->cue_ep[CUE_ENDPT_TX],
917 	    c, c->cue_buf, total_len, USBD_NO_COPY, 10000, cue_txeof);
918 
919 	/* Transmit */
920 	err = usbd_transfer(c->cue_xfer);
921 	if (err != USBD_IN_PROGRESS) {
922 		printf("%s: cue_send error=%s\n", sc->cue_dev.dv_xname,
923 		       usbd_errstr(err));
924 		/* Stop the interface from process context. */
925 		usb_add_task(sc->cue_udev, &sc->cue_stop_task);
926 		return (EIO);
927 	}
928 
929 	sc->cue_cdata.cue_tx_cnt++;
930 
931 	return (0);
932 }
933 
934 void
935 cue_start(struct ifnet *ifp)
936 {
937 	struct cue_softc	*sc = ifp->if_softc;
938 	struct mbuf		*m_head = NULL;
939 
940 	if (sc->cue_dying)
941 		return;
942 
943 	DPRINTFN(10,("%s: %s: enter\n", sc->cue_dev.dv_xname,__func__));
944 
945 	if (ifp->if_flags & IFF_OACTIVE)
946 		return;
947 
948 	IFQ_POLL(&ifp->if_snd, m_head);
949 	if (m_head == NULL)
950 		return;
951 
952 	if (cue_send(sc, m_head, 0)) {
953 		ifp->if_flags |= IFF_OACTIVE;
954 		return;
955 	}
956 
957 	IFQ_DEQUEUE(&ifp->if_snd, m_head);
958 
959 #if NBPFILTER > 0
960 	/*
961 	 * If there's a BPF listener, bounce a copy of this frame
962 	 * to him.
963 	 */
964 	if (ifp->if_bpf)
965 		bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
966 #endif
967 
968 	ifp->if_flags |= IFF_OACTIVE;
969 
970 	/*
971 	 * Set a timeout in case the chip goes out to lunch.
972 	 */
973 	ifp->if_timer = 5;
974 }
975 
976 void
977 cue_init(void *xsc)
978 {
979 	struct cue_softc	*sc = xsc;
980 	struct ifnet		*ifp = GET_IFP(sc);
981 	int			i, s, ctl;
982 	u_char			*eaddr;
983 
984 	if (sc->cue_dying)
985 		return;
986 
987 	DPRINTFN(10,("%s: %s: enter\n", sc->cue_dev.dv_xname,__func__));
988 
989 	if (ifp->if_flags & IFF_RUNNING)
990 		return;
991 
992 	s = splnet();
993 
994 	/*
995 	 * Cancel pending I/O and free all RX/TX buffers.
996 	 */
997 #if 1
998 	cue_reset(sc);
999 #endif
1000 
1001 	/* Set advanced operation modes. */
1002 	cue_csr_write_1(sc, CUE_ADVANCED_OPMODES,
1003 	    CUE_AOP_EMBED_RXLEN | 0x03); /* 1 wait state */
1004 
1005 	eaddr = sc->arpcom.ac_enaddr;
1006 	/* Set MAC address */
1007 	for (i = 0; i < ETHER_ADDR_LEN; i++)
1008 		cue_csr_write_1(sc, CUE_PAR0 - i, eaddr[i]);
1009 
1010 	/* Enable RX logic. */
1011 	ctl = CUE_ETHCTL_RX_ON | CUE_ETHCTL_MCAST_ON;
1012 	if (ifp->if_flags & IFF_PROMISC)
1013 		ctl |= CUE_ETHCTL_PROMISC;
1014 	cue_csr_write_1(sc, CUE_ETHCTL, ctl);
1015 
1016 	/* Init TX ring. */
1017 	if (cue_tx_list_init(sc) == ENOBUFS) {
1018 		printf("%s: tx list init failed\n", sc->cue_dev.dv_xname);
1019 		splx(s);
1020 		return;
1021 	}
1022 
1023 	/* Init RX ring. */
1024 	if (cue_rx_list_init(sc) == ENOBUFS) {
1025 		printf("%s: rx list init failed\n", sc->cue_dev.dv_xname);
1026 		splx(s);
1027 		return;
1028 	}
1029 
1030 	/* Load the multicast filter. */
1031 	cue_setmulti(sc);
1032 
1033 	/*
1034 	 * Set the number of RX and TX buffers that we want
1035 	 * to reserve inside the ASIC.
1036 	 */
1037 	cue_csr_write_1(sc, CUE_RX_BUFPKTS, CUE_RX_FRAMES);
1038 	cue_csr_write_1(sc, CUE_TX_BUFPKTS, CUE_TX_FRAMES);
1039 
1040 	/* Set advanced operation modes. */
1041 	cue_csr_write_1(sc, CUE_ADVANCED_OPMODES,
1042 	    CUE_AOP_EMBED_RXLEN | 0x01); /* 1 wait state */
1043 
1044 	/* Program the LED operation. */
1045 	cue_csr_write_1(sc, CUE_LEDCTL, CUE_LEDCTL_FOLLOW_LINK);
1046 
1047 	if (sc->cue_ep[CUE_ENDPT_RX] == NULL) {
1048 		if (cue_open_pipes(sc)) {
1049 			splx(s);
1050 			return;
1051 		}
1052 	}
1053 
1054 	ifp->if_flags |= IFF_RUNNING;
1055 	ifp->if_flags &= ~IFF_OACTIVE;
1056 
1057 	splx(s);
1058 
1059 	timeout_add_sec(&sc->cue_stat_ch, 1);
1060 }
1061 
1062 int
1063 cue_open_pipes(struct cue_softc *sc)
1064 {
1065 	struct cue_chain	*c;
1066 	usbd_status		err;
1067 	int			i;
1068 
1069 	/* Open RX and TX pipes. */
1070 	err = usbd_open_pipe(sc->cue_iface, sc->cue_ed[CUE_ENDPT_RX],
1071 	    USBD_EXCLUSIVE_USE, &sc->cue_ep[CUE_ENDPT_RX]);
1072 	if (err) {
1073 		printf("%s: open rx pipe failed: %s\n",
1074 		    sc->cue_dev.dv_xname, usbd_errstr(err));
1075 		return (EIO);
1076 	}
1077 	err = usbd_open_pipe(sc->cue_iface, sc->cue_ed[CUE_ENDPT_TX],
1078 	    USBD_EXCLUSIVE_USE, &sc->cue_ep[CUE_ENDPT_TX]);
1079 	if (err) {
1080 		printf("%s: open tx pipe failed: %s\n",
1081 		    sc->cue_dev.dv_xname, usbd_errstr(err));
1082 		return (EIO);
1083 	}
1084 
1085 	/* Start up the receive pipe. */
1086 	for (i = 0; i < CUE_RX_LIST_CNT; i++) {
1087 		c = &sc->cue_cdata.cue_rx_chain[i];
1088 		usbd_setup_xfer(c->cue_xfer, sc->cue_ep[CUE_ENDPT_RX],
1089 		    c, c->cue_buf, CUE_BUFSZ,
1090 		    USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
1091 		    cue_rxeof);
1092 		usbd_transfer(c->cue_xfer);
1093 	}
1094 
1095 	return (0);
1096 }
1097 
1098 int
1099 cue_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
1100 {
1101 	struct cue_softc	*sc = ifp->if_softc;
1102 	struct ifaddr 		*ifa = (struct ifaddr *)data;
1103 	struct ifreq		*ifr = (struct ifreq *)data;
1104 	int			s, error = 0;
1105 
1106 	if (sc->cue_dying)
1107 		return (EIO);
1108 
1109 	s = splnet();
1110 
1111 	switch(command) {
1112 	case SIOCSIFADDR:
1113 		ifp->if_flags |= IFF_UP;
1114 		cue_init(sc);
1115 
1116 		switch (ifa->ifa_addr->sa_family) {
1117 #ifdef INET
1118 		case AF_INET:
1119 			arp_ifinit(&sc->arpcom, ifa);
1120 			break;
1121 #endif /* INET */
1122 		}
1123 		break;
1124 
1125 	case SIOCSIFMTU:
1126 		if (ifr->ifr_mtu > ETHERMTU)
1127 			error = EINVAL;
1128 		else
1129 			ifp->if_mtu = ifr->ifr_mtu;
1130 		break;
1131 
1132 	case SIOCSIFFLAGS:
1133 		if (ifp->if_flags & IFF_UP) {
1134 			if (ifp->if_flags & IFF_RUNNING &&
1135 			    ifp->if_flags & IFF_PROMISC &&
1136 			    !(sc->cue_if_flags & IFF_PROMISC)) {
1137 				CUE_SETBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC);
1138 				cue_setmulti(sc);
1139 			} else if (ifp->if_flags & IFF_RUNNING &&
1140 			    !(ifp->if_flags & IFF_PROMISC) &&
1141 			    sc->cue_if_flags & IFF_PROMISC) {
1142 				CUE_CLRBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC);
1143 				cue_setmulti(sc);
1144 			} else if (!(ifp->if_flags & IFF_RUNNING))
1145 				cue_init(sc);
1146 		} else {
1147 			if (ifp->if_flags & IFF_RUNNING)
1148 				cue_stop(sc);
1149 		}
1150 		sc->cue_if_flags = ifp->if_flags;
1151 		error = 0;
1152 		break;
1153 	case SIOCADDMULTI:
1154 	case SIOCDELMULTI:
1155 		error = (command == SIOCADDMULTI) ?
1156 		    ether_addmulti(ifr, &sc->arpcom) :
1157 		    ether_delmulti(ifr, &sc->arpcom);
1158 
1159 		if (error == ENETRESET) {
1160 			/*
1161 			 * Multicast list has changed; set the hardware
1162 			 * filter accordingly.
1163 			 */
1164 			if (ifp->if_flags & IFF_RUNNING)
1165 				cue_setmulti(sc);
1166 			error = 0;
1167 		}
1168 		break;
1169 	default:
1170 		error = EINVAL;
1171 		break;
1172 	}
1173 
1174 	splx(s);
1175 
1176 	return (error);
1177 }
1178 
1179 void
1180 cue_watchdog(struct ifnet *ifp)
1181 {
1182 	struct cue_softc	*sc = ifp->if_softc;
1183 	struct cue_chain	*c;
1184 	usbd_status		stat;
1185 	int			s;
1186 
1187 	DPRINTFN(5,("%s: %s: enter\n", sc->cue_dev.dv_xname,__func__));
1188 
1189 	if (sc->cue_dying)
1190 		return;
1191 
1192 	ifp->if_oerrors++;
1193 	printf("%s: watchdog timeout\n", sc->cue_dev.dv_xname);
1194 
1195 	s = splusb();
1196 	c = &sc->cue_cdata.cue_tx_chain[0];
1197 	usbd_get_xfer_status(c->cue_xfer, NULL, NULL, NULL, &stat);
1198 	cue_txeof(c->cue_xfer, c, stat);
1199 
1200 	if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
1201 		cue_start(ifp);
1202 	splx(s);
1203 }
1204 
1205 /*
1206  * Stop the adapter and free any mbufs allocated to the
1207  * RX and TX lists.
1208  */
1209 void
1210 cue_stop(struct cue_softc *sc)
1211 {
1212 	usbd_status		err;
1213 	struct ifnet		*ifp;
1214 	int			i;
1215 
1216 	DPRINTFN(10,("%s: %s: enter\n", sc->cue_dev.dv_xname,__func__));
1217 
1218 	ifp = GET_IFP(sc);
1219 	ifp->if_timer = 0;
1220 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
1221 
1222 	cue_csr_write_1(sc, CUE_ETHCTL, 0);
1223 	cue_reset(sc);
1224 	timeout_del(&sc->cue_stat_ch);
1225 
1226 	/* Stop transfers. */
1227 	if (sc->cue_ep[CUE_ENDPT_RX] != NULL) {
1228 		err = usbd_abort_pipe(sc->cue_ep[CUE_ENDPT_RX]);
1229 		if (err) {
1230 			printf("%s: abort rx pipe failed: %s\n",
1231 			sc->cue_dev.dv_xname, usbd_errstr(err));
1232 		}
1233 		err = usbd_close_pipe(sc->cue_ep[CUE_ENDPT_RX]);
1234 		if (err) {
1235 			printf("%s: close rx pipe failed: %s\n",
1236 			sc->cue_dev.dv_xname, usbd_errstr(err));
1237 		}
1238 		sc->cue_ep[CUE_ENDPT_RX] = NULL;
1239 	}
1240 
1241 	if (sc->cue_ep[CUE_ENDPT_TX] != NULL) {
1242 		err = usbd_abort_pipe(sc->cue_ep[CUE_ENDPT_TX]);
1243 		if (err) {
1244 			printf("%s: abort tx pipe failed: %s\n",
1245 			sc->cue_dev.dv_xname, usbd_errstr(err));
1246 		}
1247 		err = usbd_close_pipe(sc->cue_ep[CUE_ENDPT_TX]);
1248 		if (err) {
1249 			printf("%s: close tx pipe failed: %s\n",
1250 			    sc->cue_dev.dv_xname, usbd_errstr(err));
1251 		}
1252 		sc->cue_ep[CUE_ENDPT_TX] = NULL;
1253 	}
1254 
1255 	if (sc->cue_ep[CUE_ENDPT_INTR] != NULL) {
1256 		err = usbd_abort_pipe(sc->cue_ep[CUE_ENDPT_INTR]);
1257 		if (err) {
1258 			printf("%s: abort intr pipe failed: %s\n",
1259 			sc->cue_dev.dv_xname, usbd_errstr(err));
1260 		}
1261 		err = usbd_close_pipe(sc->cue_ep[CUE_ENDPT_INTR]);
1262 		if (err) {
1263 			printf("%s: close intr pipe failed: %s\n",
1264 			    sc->cue_dev.dv_xname, usbd_errstr(err));
1265 		}
1266 		sc->cue_ep[CUE_ENDPT_INTR] = NULL;
1267 	}
1268 
1269 	/* Free RX resources. */
1270 	for (i = 0; i < CUE_RX_LIST_CNT; i++) {
1271 		if (sc->cue_cdata.cue_rx_chain[i].cue_mbuf != NULL) {
1272 			m_freem(sc->cue_cdata.cue_rx_chain[i].cue_mbuf);
1273 			sc->cue_cdata.cue_rx_chain[i].cue_mbuf = NULL;
1274 		}
1275 		if (sc->cue_cdata.cue_rx_chain[i].cue_xfer != NULL) {
1276 			usbd_free_xfer(sc->cue_cdata.cue_rx_chain[i].cue_xfer);
1277 			sc->cue_cdata.cue_rx_chain[i].cue_xfer = NULL;
1278 		}
1279 	}
1280 
1281 	/* Free TX resources. */
1282 	for (i = 0; i < CUE_TX_LIST_CNT; i++) {
1283 		if (sc->cue_cdata.cue_tx_chain[i].cue_mbuf != NULL) {
1284 			m_freem(sc->cue_cdata.cue_tx_chain[i].cue_mbuf);
1285 			sc->cue_cdata.cue_tx_chain[i].cue_mbuf = NULL;
1286 		}
1287 		if (sc->cue_cdata.cue_tx_chain[i].cue_xfer != NULL) {
1288 			usbd_free_xfer(sc->cue_cdata.cue_tx_chain[i].cue_xfer);
1289 			sc->cue_cdata.cue_tx_chain[i].cue_xfer = NULL;
1290 		}
1291 	}
1292 }
1293