xref: /openbsd/sys/dev/usb/if_cue.c (revision e5dd7070)
1 /*	$OpenBSD: if_cue.c,v 1.80 2020/07/31 10:49:32 mglocker 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 
72 #if NBPFILTER > 0
73 #include <net/bpf.h>
74 #endif
75 
76 #include <netinet/in.h>
77 #include <netinet/if_ether.h>
78 
79 #include <dev/usb/usb.h>
80 #include <dev/usb/usbdi.h>
81 #include <dev/usb/usbdi_util.h>
82 #include <dev/usb/usbdevs.h>
83 
84 #include <dev/usb/if_cuereg.h>
85 
86 #ifdef CUE_DEBUG
87 #define DPRINTF(x)	do { if (cuedebug) printf x; } while (0)
88 #define DPRINTFN(n,x)	do { if (cuedebug >= (n)) printf x; } while (0)
89 int	cuedebug = 0;
90 #else
91 #define DPRINTF(x)
92 #define DPRINTFN(n,x)
93 #endif
94 
95 /*
96  * Various supported device vendors/products.
97  */
98 struct usb_devno cue_devs[] = {
99 	{ USB_VENDOR_CATC, USB_PRODUCT_CATC_NETMATE },
100 	{ USB_VENDOR_CATC, USB_PRODUCT_CATC_NETMATE2 },
101 	{ USB_VENDOR_SMARTBRIDGES, USB_PRODUCT_SMARTBRIDGES_SMARTLINK },
102 	/* Belkin F5U111 adapter covered by NETMATE entry */
103 };
104 
105 int cue_match(struct device *, void *, void *);
106 void cue_attach(struct device *, struct device *, void *);
107 int cue_detach(struct device *, int);
108 
109 struct cfdriver cue_cd = {
110 	NULL, "cue", DV_IFNET
111 };
112 
113 const struct cfattach cue_ca = {
114 	sizeof(struct cue_softc), cue_match, cue_attach, cue_detach
115 };
116 
117 int cue_open_pipes(struct cue_softc *);
118 int cue_tx_list_init(struct cue_softc *);
119 int cue_rx_list_init(struct cue_softc *);
120 int cue_newbuf(struct cue_softc *, struct cue_chain *, struct mbuf *);
121 int cue_send(struct cue_softc *, struct mbuf *, int);
122 void cue_rxeof(struct usbd_xfer *, void *, usbd_status);
123 void cue_txeof(struct usbd_xfer *, void *, usbd_status);
124 void cue_tick(void *);
125 void cue_tick_task(void *);
126 void cue_start(struct ifnet *);
127 int cue_ioctl(struct ifnet *, u_long, caddr_t);
128 void cue_init(void *);
129 void cue_stop(struct cue_softc *);
130 void cue_watchdog(struct ifnet *);
131 
132 void cue_setmulti(struct cue_softc *);
133 void cue_reset(struct cue_softc *);
134 
135 int cue_csr_read_1(struct cue_softc *, int);
136 int cue_csr_write_1(struct cue_softc *, int, int);
137 int cue_csr_read_2(struct cue_softc *, int);
138 #if 0
139 int cue_csr_write_2(struct cue_softc *, int, int);
140 #endif
141 int cue_mem(struct cue_softc *, int, int, void *, int);
142 int cue_getmac(struct cue_softc *, void *);
143 
144 #define CUE_SETBIT(sc, reg, x)				\
145 	cue_csr_write_1(sc, reg, cue_csr_read_1(sc, reg) | (x))
146 
147 #define CUE_CLRBIT(sc, reg, x)				\
148 	cue_csr_write_1(sc, reg, cue_csr_read_1(sc, reg) & ~(x))
149 
150 int
151 cue_csr_read_1(struct cue_softc *sc, int reg)
152 {
153 	usb_device_request_t	req;
154 	usbd_status		err;
155 	u_int8_t		val = 0;
156 
157 	if (usbd_is_dying(sc->cue_udev))
158 		return (0);
159 
160 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
161 	req.bRequest = CUE_CMD_READREG;
162 	USETW(req.wValue, 0);
163 	USETW(req.wIndex, reg);
164 	USETW(req.wLength, 1);
165 
166 	err = usbd_do_request(sc->cue_udev, &req, &val);
167 
168 	if (err) {
169 		DPRINTF(("%s: cue_csr_read_1: reg=0x%x err=%s\n",
170 			 sc->cue_dev.dv_xname, reg, usbd_errstr(err)));
171 		return (0);
172 	}
173 
174 	DPRINTFN(10,("%s: cue_csr_read_1 reg=0x%x val=0x%x\n",
175 		     sc->cue_dev.dv_xname, reg, val));
176 
177 	return (val);
178 }
179 
180 int
181 cue_csr_read_2(struct cue_softc *sc, int reg)
182 {
183 	usb_device_request_t	req;
184 	usbd_status		err;
185 	uWord			val;
186 
187 	if (usbd_is_dying(sc->cue_udev))
188 		return (0);
189 
190 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
191 	req.bRequest = CUE_CMD_READREG;
192 	USETW(req.wValue, 0);
193 	USETW(req.wIndex, reg);
194 	USETW(req.wLength, 2);
195 
196 	err = usbd_do_request(sc->cue_udev, &req, &val);
197 
198 	DPRINTFN(10,("%s: cue_csr_read_2 reg=0x%x val=0x%x\n",
199 		     sc->cue_dev.dv_xname, reg, UGETW(val)));
200 
201 	if (err) {
202 		DPRINTF(("%s: cue_csr_read_2: reg=0x%x err=%s\n",
203 			 sc->cue_dev.dv_xname, reg, usbd_errstr(err)));
204 		return (0);
205 	}
206 
207 	return (UGETW(val));
208 }
209 
210 int
211 cue_csr_write_1(struct cue_softc *sc, int reg, int val)
212 {
213 	usb_device_request_t	req;
214 	usbd_status		err;
215 
216 	if (usbd_is_dying(sc->cue_udev))
217 		return (0);
218 
219 	DPRINTFN(10,("%s: cue_csr_write_1 reg=0x%x val=0x%x\n",
220 		     sc->cue_dev.dv_xname, reg, val));
221 
222 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
223 	req.bRequest = CUE_CMD_WRITEREG;
224 	USETW(req.wValue, val);
225 	USETW(req.wIndex, reg);
226 	USETW(req.wLength, 0);
227 
228 	err = usbd_do_request(sc->cue_udev, &req, NULL);
229 
230 	if (err) {
231 		DPRINTF(("%s: cue_csr_write_1: reg=0x%x err=%s\n",
232 			 sc->cue_dev.dv_xname, reg, usbd_errstr(err)));
233 		return (-1);
234 	}
235 
236 	DPRINTFN(20,("%s: cue_csr_write_1, after reg=0x%x val=0x%x\n",
237 		     sc->cue_dev.dv_xname, reg, cue_csr_read_1(sc, reg)));
238 
239 	return (0);
240 }
241 
242 #if 0
243 int
244 cue_csr_write_2(struct cue_softc *sc, int reg, int aval)
245 {
246 	usb_device_request_t	req;
247 	usbd_status		err;
248 	uWord			val;
249 	int			s;
250 
251 	if (usbd_is_dying(sc->cue_udev))
252 		return (0);
253 
254 	DPRINTFN(10,("%s: cue_csr_write_2 reg=0x%x val=0x%x\n",
255 		     sc->cue_dev.dv_xname, reg, aval));
256 
257 	USETW(val, aval);
258 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
259 	req.bRequest = CUE_CMD_WRITEREG;
260 	USETW(req.wValue, val);
261 	USETW(req.wIndex, reg);
262 	USETW(req.wLength, 0);
263 
264 	err = usbd_do_request(sc->cue_udev, &req, NULL);
265 
266 	if (err) {
267 		DPRINTF(("%s: cue_csr_write_2: reg=0x%x err=%s\n",
268 			 sc->cue_dev.dv_xname, reg, usbd_errstr(err)));
269 		return (-1);
270 	}
271 
272 	return (0);
273 }
274 #endif
275 
276 int
277 cue_mem(struct cue_softc *sc, int cmd, int addr, void *buf, int len)
278 {
279 	usb_device_request_t	req;
280 	usbd_status		err;
281 
282 	DPRINTFN(10,("%s: cue_mem cmd=0x%x addr=0x%x len=%d\n",
283 		     sc->cue_dev.dv_xname, cmd, addr, len));
284 
285 	if (cmd == CUE_CMD_READSRAM)
286 		req.bmRequestType = UT_READ_VENDOR_DEVICE;
287 	else
288 		req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
289 	req.bRequest = cmd;
290 	USETW(req.wValue, 0);
291 	USETW(req.wIndex, addr);
292 	USETW(req.wLength, len);
293 
294 	err = usbd_do_request(sc->cue_udev, &req, buf);
295 
296 	if (err) {
297 		DPRINTF(("%s: cue_csr_mem: addr=0x%x err=%s\n",
298 			 sc->cue_dev.dv_xname, addr, usbd_errstr(err)));
299 		return (-1);
300 	}
301 
302 	return (0);
303 }
304 
305 int
306 cue_getmac(struct cue_softc *sc, void *buf)
307 {
308 	usb_device_request_t	req;
309 	usbd_status		err;
310 
311 	DPRINTFN(10,("%s: cue_getmac\n", sc->cue_dev.dv_xname));
312 
313 	req.bmRequestType = UT_READ_VENDOR_DEVICE;
314 	req.bRequest = CUE_CMD_GET_MACADDR;
315 	USETW(req.wValue, 0);
316 	USETW(req.wIndex, 0);
317 	USETW(req.wLength, ETHER_ADDR_LEN);
318 
319 	err = usbd_do_request(sc->cue_udev, &req, buf);
320 
321 	if (err) {
322 		printf("%s: read MAC address failed\n",
323 		       sc->cue_dev.dv_xname);
324 		return (-1);
325 	}
326 
327 	return (0);
328 }
329 
330 #define CUE_BITS	9
331 
332 void
333 cue_setmulti(struct cue_softc *sc)
334 {
335 	struct arpcom		*ac = &sc->arpcom;
336 	struct ifnet		*ifp;
337 	struct ether_multi	*enm;
338 	struct ether_multistep	step;
339 	u_int32_t		h, i;
340 
341 	ifp = GET_IFP(sc);
342 
343 	DPRINTFN(2,("%s: cue_setmulti if_flags=0x%x\n",
344 		    sc->cue_dev.dv_xname, ifp->if_flags));
345 
346 	if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) {
347 		ifp->if_flags |= IFF_ALLMULTI;
348 		for (i = 0; i < CUE_MCAST_TABLE_LEN; i++)
349 			sc->cue_mctab[i] = 0xFF;
350 		cue_mem(sc, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR,
351 		    &sc->cue_mctab, CUE_MCAST_TABLE_LEN);
352 		return;
353 	}
354 
355 	/* first, zot all the existing hash bits */
356 	for (i = 0; i < CUE_MCAST_TABLE_LEN; i++)
357 		sc->cue_mctab[i] = 0;
358 
359 	/* now program new ones */
360 	ETHER_FIRST_MULTI(step, ac, enm);
361 	while (enm != NULL) {
362 		h = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN) &
363 		    ((1 << CUE_BITS) - 1);
364 		sc->cue_mctab[h >> 3] |= 1 << (h & 0x7);
365 		ETHER_NEXT_MULTI(step, enm);
366 	}
367 
368 	ifp->if_flags &= ~IFF_ALLMULTI;
369 
370 	/*
371 	 * Also include the broadcast address in the filter
372 	 * so we can receive broadcast frames.
373 	 */
374 	if (ifp->if_flags & IFF_BROADCAST) {
375 		h = ether_crc32_le(etherbroadcastaddr, ETHER_ADDR_LEN) &
376 		    ((1 << CUE_BITS) - 1);
377 		sc->cue_mctab[h >> 3] |= 1 << (h & 0x7);
378 	}
379 
380 	cue_mem(sc, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR,
381 	    &sc->cue_mctab, CUE_MCAST_TABLE_LEN);
382 }
383 
384 void
385 cue_reset(struct cue_softc *sc)
386 {
387 	usb_device_request_t	req;
388 	usbd_status		err;
389 
390 	DPRINTFN(2,("%s: cue_reset\n", sc->cue_dev.dv_xname));
391 
392 	if (usbd_is_dying(sc->cue_udev))
393 		return;
394 
395 	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
396 	req.bRequest = CUE_CMD_RESET;
397 	USETW(req.wValue, 0);
398 	USETW(req.wIndex, 0);
399 	USETW(req.wLength, 0);
400 
401 	err = usbd_do_request(sc->cue_udev, &req, NULL);
402 
403 	if (err)
404 		printf("%s: reset failed\n", sc->cue_dev.dv_xname);
405 
406 	/* Wait a little while for the chip to get its brains in order. */
407 	usbd_delay_ms(sc->cue_udev, 1);
408 }
409 
410 /*
411  * Probe for a CATC chip.
412  */
413 int
414 cue_match(struct device *parent, void *match, void *aux)
415 {
416 	struct usb_attach_arg	*uaa = aux;
417 
418 	if (uaa->iface == NULL || uaa->configno != CUE_CONFIG_NO)
419 		return (UMATCH_NONE);
420 
421 	return (usb_lookup(cue_devs, uaa->vendor, uaa->product) != NULL ?
422 	    UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
423 }
424 
425 /*
426  * Attach the interface. Allocate softc structures, do ifmedia
427  * setup and ethernet/BPF attach.
428  */
429 void
430 cue_attach(struct device *parent, struct device *self, void *aux)
431 {
432 	struct cue_softc	*sc = (struct cue_softc *)self;
433 	struct usb_attach_arg	*uaa = aux;
434 	int			s;
435 	u_char			eaddr[ETHER_ADDR_LEN];
436 	struct usbd_device	*dev = uaa->device;
437 	struct usbd_interface	*iface;
438 	usbd_status		err;
439 	struct ifnet		*ifp;
440 	usb_interface_descriptor_t	*id;
441 	usb_endpoint_descriptor_t	*ed;
442 	int			i;
443 
444 	DPRINTFN(5,(" : cue_attach: sc=%p, dev=%p", sc, dev));
445 
446 	sc->cue_udev = dev;
447 	sc->cue_product = uaa->product;
448 	sc->cue_vendor = uaa->vendor;
449 
450 	usb_init_task(&sc->cue_tick_task, cue_tick_task, sc,
451 	    USB_TASK_TYPE_GENERIC);
452 	usb_init_task(&sc->cue_stop_task, (void (*)(void *))cue_stop, sc,
453 	    USB_TASK_TYPE_GENERIC);
454 
455 	err = usbd_device2interface_handle(dev, CUE_IFACE_IDX, &iface);
456 	if (err) {
457 		printf("%s: getting interface handle failed\n",
458 		    sc->cue_dev.dv_xname);
459 		return;
460 	}
461 
462 	sc->cue_iface = iface;
463 	id = usbd_get_interface_descriptor(iface);
464 
465 	/* Find endpoints. */
466 	for (i = 0; i < id->bNumEndpoints; i++) {
467 		ed = usbd_interface2endpoint_descriptor(iface, i);
468 		if (ed == NULL) {
469 			printf("%s: couldn't get ep %d\n",
470 			    sc->cue_dev.dv_xname, i);
471 			return;
472 		}
473 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
474 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
475 			sc->cue_ed[CUE_ENDPT_RX] = ed->bEndpointAddress;
476 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
477 			   UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
478 			sc->cue_ed[CUE_ENDPT_TX] = ed->bEndpointAddress;
479 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
480 			   UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
481 			sc->cue_ed[CUE_ENDPT_INTR] = ed->bEndpointAddress;
482 		}
483 	}
484 
485 #if 0
486 	/* Reset the adapter. */
487 	cue_reset(sc);
488 #endif
489 	/*
490 	 * Get station address.
491 	 */
492 	cue_getmac(sc, &eaddr);
493 
494 	s = splnet();
495 
496 	/*
497 	 * A CATC chip was detected. Inform the world.
498 	 */
499 	printf("%s: address %s\n", sc->cue_dev.dv_xname,
500 	    ether_sprintf(eaddr));
501 
502 	bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
503 
504 	/* Initialize interface info.*/
505 	ifp = GET_IFP(sc);
506 	ifp->if_softc = sc;
507 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
508 	ifp->if_ioctl = cue_ioctl;
509 	ifp->if_start = cue_start;
510 	ifp->if_watchdog = cue_watchdog;
511 	strlcpy(ifp->if_xname, sc->cue_dev.dv_xname, IFNAMSIZ);
512 
513 	/* Attach the interface. */
514 	if_attach(ifp);
515 	ether_ifattach(ifp);
516 
517 	timeout_set(&sc->cue_stat_ch, cue_tick, sc);
518 
519 	splx(s);
520 }
521 
522 int
523 cue_detach(struct device *self, int flags)
524 {
525 	struct cue_softc	*sc = (struct cue_softc *)self;
526 	struct ifnet		*ifp = GET_IFP(sc);
527 	int			s;
528 
529 	DPRINTFN(2,("%s: %s: enter\n", sc->cue_dev.dv_xname, __func__));
530 
531 	if (timeout_initialized(&sc->cue_stat_ch))
532 		timeout_del(&sc->cue_stat_ch);
533 
534 	/*
535 	 * Remove any pending task.  It cannot be executing because it run
536 	 * in the same thread as detach.
537 	 */
538 	usb_rem_task(sc->cue_udev, &sc->cue_tick_task);
539 	usb_rem_task(sc->cue_udev, &sc->cue_stop_task);
540 
541 	s = splusb();
542 
543 	if (ifp->if_flags & IFF_RUNNING)
544 		cue_stop(sc);
545 
546 	if (ifp->if_softc != NULL) {
547 		ether_ifdetach(ifp);
548 		if_detach(ifp);
549 	}
550 
551 #ifdef DIAGNOSTIC
552 	if (sc->cue_ep[CUE_ENDPT_TX] != NULL ||
553 	    sc->cue_ep[CUE_ENDPT_RX] != NULL ||
554 	    sc->cue_ep[CUE_ENDPT_INTR] != NULL)
555 		printf("%s: detach has active endpoints\n",
556 		       sc->cue_dev.dv_xname);
557 #endif
558 
559 	splx(s);
560 
561 	return (0);
562 }
563 
564 /*
565  * Initialize an RX descriptor and attach an MBUF cluster.
566  */
567 int
568 cue_newbuf(struct cue_softc *sc, struct cue_chain *c, struct mbuf *m)
569 {
570 	struct mbuf		*m_new = NULL;
571 
572 	if (m == NULL) {
573 		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
574 		if (m_new == NULL) {
575 			printf("%s: no memory for rx list "
576 			    "-- packet dropped!\n", sc->cue_dev.dv_xname);
577 			return (ENOBUFS);
578 		}
579 
580 		MCLGET(m_new, M_DONTWAIT);
581 		if (!(m_new->m_flags & M_EXT)) {
582 			printf("%s: no memory for rx list "
583 			    "-- packet dropped!\n", sc->cue_dev.dv_xname);
584 			m_freem(m_new);
585 			return (ENOBUFS);
586 		}
587 		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
588 	} else {
589 		m_new = m;
590 		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
591 		m_new->m_data = m_new->m_ext.ext_buf;
592 	}
593 
594 	m_adj(m_new, ETHER_ALIGN);
595 	c->cue_mbuf = m_new;
596 
597 	return (0);
598 }
599 
600 int
601 cue_rx_list_init(struct cue_softc *sc)
602 {
603 	struct cue_cdata	*cd;
604 	struct cue_chain	*c;
605 	int			i;
606 
607 	cd = &sc->cue_cdata;
608 	for (i = 0; i < CUE_RX_LIST_CNT; i++) {
609 		c = &cd->cue_rx_chain[i];
610 		c->cue_sc = sc;
611 		c->cue_idx = i;
612 		if (cue_newbuf(sc, c, NULL) == ENOBUFS)
613 			return (ENOBUFS);
614 		if (c->cue_xfer == NULL) {
615 			c->cue_xfer = usbd_alloc_xfer(sc->cue_udev);
616 			if (c->cue_xfer == NULL)
617 				return (ENOBUFS);
618 			c->cue_buf = usbd_alloc_buffer(c->cue_xfer, CUE_BUFSZ);
619 			if (c->cue_buf == NULL) {
620 				usbd_free_xfer(c->cue_xfer);
621 				return (ENOBUFS);
622 			}
623 		}
624 	}
625 
626 	return (0);
627 }
628 
629 int
630 cue_tx_list_init(struct cue_softc *sc)
631 {
632 	struct cue_cdata	*cd;
633 	struct cue_chain	*c;
634 	int			i;
635 
636 	cd = &sc->cue_cdata;
637 	for (i = 0; i < CUE_TX_LIST_CNT; i++) {
638 		c = &cd->cue_tx_chain[i];
639 		c->cue_sc = sc;
640 		c->cue_idx = i;
641 		c->cue_mbuf = NULL;
642 		if (c->cue_xfer == NULL) {
643 			c->cue_xfer = usbd_alloc_xfer(sc->cue_udev);
644 			if (c->cue_xfer == NULL)
645 				return (ENOBUFS);
646 			c->cue_buf = usbd_alloc_buffer(c->cue_xfer, CUE_BUFSZ);
647 			if (c->cue_buf == NULL) {
648 				usbd_free_xfer(c->cue_xfer);
649 				return (ENOBUFS);
650 			}
651 		}
652 	}
653 
654 	return (0);
655 }
656 
657 /*
658  * A frame has been uploaded: pass the resulting mbuf chain up to
659  * the higher level protocols.
660  */
661 void
662 cue_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
663 {
664 	struct cue_chain	*c = priv;
665 	struct cue_softc	*sc = c->cue_sc;
666 	struct ifnet		*ifp = GET_IFP(sc);
667 	struct mbuf_list	ml = MBUF_LIST_INITIALIZER();
668 	struct mbuf		*m;
669 	int			total_len = 0;
670 	u_int16_t		len;
671 	int			s;
672 
673 	DPRINTFN(10,("%s: %s: enter status=%d\n", sc->cue_dev.dv_xname,
674 		     __func__, status));
675 
676 	if (usbd_is_dying(sc->cue_udev))
677 		return;
678 
679 	if (!(ifp->if_flags & IFF_RUNNING))
680 		return;
681 
682 	if (status != USBD_NORMAL_COMPLETION) {
683 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
684 			return;
685 		sc->cue_rx_errs++;
686 		if (usbd_ratecheck(&sc->cue_rx_notice)) {
687 			printf("%s: %u usb errors on rx: %s\n",
688 			    sc->cue_dev.dv_xname, sc->cue_rx_errs,
689 			    usbd_errstr(status));
690 			sc->cue_rx_errs = 0;
691 		}
692 		if (status == USBD_STALLED)
693 			usbd_clear_endpoint_stall_async(sc->cue_ep[CUE_ENDPT_RX]);
694 		goto done;
695 	}
696 
697 	usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
698 
699 	memcpy(mtod(c->cue_mbuf, char *), c->cue_buf, total_len);
700 
701 	m = c->cue_mbuf;
702 	len = UGETW(mtod(m, u_int8_t *));
703 
704 	/* No errors; receive the packet. */
705 	total_len = len;
706 
707 	if (len < sizeof(struct ether_header)) {
708 		ifp->if_ierrors++;
709 		goto done;
710 	}
711 
712 	m_adj(m, sizeof(u_int16_t));
713 	m->m_pkthdr.len = m->m_len = total_len;
714 	ml_enqueue(&ml, m);
715 
716 	if (cue_newbuf(sc, c, NULL) == ENOBUFS) {
717 		ifp->if_ierrors++;
718 		goto done;
719 	}
720 
721 	s = splnet();
722 	if_input(ifp, &ml);
723 	splx(s);
724 
725 done:
726 	/* Setup new transfer. */
727 	usbd_setup_xfer(c->cue_xfer, sc->cue_ep[CUE_ENDPT_RX],
728 	    c, c->cue_buf, CUE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
729 	    USBD_NO_TIMEOUT, cue_rxeof);
730 	usbd_transfer(c->cue_xfer);
731 
732 	DPRINTFN(10,("%s: %s: start rx\n", sc->cue_dev.dv_xname,
733 		    __func__));
734 }
735 
736 /*
737  * A frame was downloaded to the chip. It's safe for us to clean up
738  * the list buffers.
739  */
740 void
741 cue_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
742 {
743 	struct cue_chain	*c = priv;
744 	struct cue_softc	*sc = c->cue_sc;
745 	struct ifnet		*ifp = GET_IFP(sc);
746 	int			s;
747 
748 	if (usbd_is_dying(sc->cue_udev))
749 		return;
750 
751 	s = splnet();
752 
753 	DPRINTFN(10,("%s: %s: enter status=%d\n", sc->cue_dev.dv_xname,
754 		    __func__, status));
755 
756 	ifp->if_timer = 0;
757 	ifq_clr_oactive(&ifp->if_snd);
758 
759 	if (status != USBD_NORMAL_COMPLETION) {
760 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
761 			splx(s);
762 			return;
763 		}
764 		ifp->if_oerrors++;
765 		printf("%s: usb error on tx: %s\n", sc->cue_dev.dv_xname,
766 		    usbd_errstr(status));
767 		if (status == USBD_STALLED)
768 			usbd_clear_endpoint_stall_async(sc->cue_ep[CUE_ENDPT_TX]);
769 		splx(s);
770 		return;
771 	}
772 
773 	m_freem(c->cue_mbuf);
774 	c->cue_mbuf = NULL;
775 
776 	if (ifq_empty(&ifp->if_snd) == 0)
777 		cue_start(ifp);
778 
779 	splx(s);
780 }
781 
782 void
783 cue_tick(void *xsc)
784 {
785 	struct cue_softc	*sc = xsc;
786 
787 	if (sc == NULL)
788 		return;
789 
790 	if (usbd_is_dying(sc->cue_udev))
791 		return;
792 
793 	DPRINTFN(2,("%s: %s: enter\n", sc->cue_dev.dv_xname, __func__));
794 
795 	/* Perform statistics update in process context. */
796 	usb_add_task(sc->cue_udev, &sc->cue_tick_task);
797 }
798 
799 void
800 cue_tick_task(void *xsc)
801 {
802 	struct cue_softc	*sc = xsc;
803 	struct ifnet		*ifp;
804 
805 	if (usbd_is_dying(sc->cue_udev))
806 		return;
807 
808 	DPRINTFN(2,("%s: %s: enter\n", sc->cue_dev.dv_xname, __func__));
809 
810 	ifp = GET_IFP(sc);
811 
812 	ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_SINGLECOLL);
813 	ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_MULTICOLL);
814 	ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_EXCESSCOLL);
815 
816 	if (cue_csr_read_2(sc, CUE_RX_FRAMEERR))
817 		ifp->if_ierrors++;
818 }
819 
820 int
821 cue_send(struct cue_softc *sc, struct mbuf *m, int idx)
822 {
823 	int			total_len;
824 	struct cue_chain	*c;
825 	usbd_status		err;
826 
827 	c = &sc->cue_cdata.cue_tx_chain[idx];
828 
829 	/*
830 	 * Copy the mbuf data into a contiguous buffer, leaving two
831 	 * bytes at the beginning to hold the frame length.
832 	 */
833 	m_copydata(m, 0, m->m_pkthdr.len, c->cue_buf + 2);
834 	c->cue_mbuf = m;
835 
836 	total_len = m->m_pkthdr.len + 2;
837 
838 	DPRINTFN(10,("%s: %s: total_len=%d\n",
839 		     sc->cue_dev.dv_xname, __func__, total_len));
840 
841 	/* The first two bytes are the frame length */
842 	c->cue_buf[0] = (u_int8_t)m->m_pkthdr.len;
843 	c->cue_buf[1] = (u_int8_t)(m->m_pkthdr.len >> 8);
844 
845 	/* XXX 10000 */
846 	usbd_setup_xfer(c->cue_xfer, sc->cue_ep[CUE_ENDPT_TX],
847 	    c, c->cue_buf, total_len, USBD_NO_COPY, 10000, cue_txeof);
848 
849 	/* Transmit */
850 	err = usbd_transfer(c->cue_xfer);
851 	if (err != USBD_IN_PROGRESS) {
852 		printf("%s: cue_send error=%s\n", sc->cue_dev.dv_xname,
853 		       usbd_errstr(err));
854 		/* Stop the interface from process context. */
855 		usb_add_task(sc->cue_udev, &sc->cue_stop_task);
856 		return (EIO);
857 	}
858 
859 	sc->cue_cdata.cue_tx_cnt++;
860 
861 	return (0);
862 }
863 
864 void
865 cue_start(struct ifnet *ifp)
866 {
867 	struct cue_softc	*sc = ifp->if_softc;
868 	struct mbuf		*m_head = NULL;
869 
870 	if (usbd_is_dying(sc->cue_udev))
871 		return;
872 
873 	DPRINTFN(10,("%s: %s: enter\n", sc->cue_dev.dv_xname,__func__));
874 
875 	if (ifq_is_oactive(&ifp->if_snd))
876 		return;
877 
878 	m_head = ifq_deq_begin(&ifp->if_snd);
879 	if (m_head == NULL)
880 		return;
881 
882 	if (cue_send(sc, m_head, 0)) {
883 		ifq_deq_rollback(&ifp->if_snd, m_head);
884 		ifq_set_oactive(&ifp->if_snd);
885 		return;
886 	}
887 
888 	ifq_deq_commit(&ifp->if_snd, m_head);
889 
890 #if NBPFILTER > 0
891 	/*
892 	 * If there's a BPF listener, bounce a copy of this frame
893 	 * to him.
894 	 */
895 	if (ifp->if_bpf)
896 		bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
897 #endif
898 
899 	ifq_set_oactive(&ifp->if_snd);
900 
901 	/*
902 	 * Set a timeout in case the chip goes out to lunch.
903 	 */
904 	ifp->if_timer = 5;
905 }
906 
907 void
908 cue_init(void *xsc)
909 {
910 	struct cue_softc	*sc = xsc;
911 	struct ifnet		*ifp = GET_IFP(sc);
912 	int			i, s, ctl;
913 	u_char			*eaddr;
914 
915 	if (usbd_is_dying(sc->cue_udev))
916 		return;
917 
918 	DPRINTFN(10,("%s: %s: enter\n", sc->cue_dev.dv_xname,__func__));
919 
920 	if (ifp->if_flags & IFF_RUNNING)
921 		return;
922 
923 	s = splnet();
924 
925 	/*
926 	 * Cancel pending I/O and free all RX/TX buffers.
927 	 */
928 #if 1
929 	cue_reset(sc);
930 #endif
931 
932 	/* Set advanced operation modes. */
933 	cue_csr_write_1(sc, CUE_ADVANCED_OPMODES,
934 	    CUE_AOP_EMBED_RXLEN | 0x03); /* 1 wait state */
935 
936 	eaddr = sc->arpcom.ac_enaddr;
937 	/* Set MAC address */
938 	for (i = 0; i < ETHER_ADDR_LEN; i++)
939 		cue_csr_write_1(sc, CUE_PAR0 - i, eaddr[i]);
940 
941 	/* Enable RX logic. */
942 	ctl = CUE_ETHCTL_RX_ON | CUE_ETHCTL_MCAST_ON;
943 	if (ifp->if_flags & IFF_PROMISC)
944 		ctl |= CUE_ETHCTL_PROMISC;
945 	cue_csr_write_1(sc, CUE_ETHCTL, ctl);
946 
947 	/* Init TX ring. */
948 	if (cue_tx_list_init(sc) == ENOBUFS) {
949 		printf("%s: tx list init failed\n", sc->cue_dev.dv_xname);
950 		splx(s);
951 		return;
952 	}
953 
954 	/* Init RX ring. */
955 	if (cue_rx_list_init(sc) == ENOBUFS) {
956 		printf("%s: rx list init failed\n", sc->cue_dev.dv_xname);
957 		splx(s);
958 		return;
959 	}
960 
961 	/* Load the multicast filter. */
962 	cue_setmulti(sc);
963 
964 	/*
965 	 * Set the number of RX and TX buffers that we want
966 	 * to reserve inside the ASIC.
967 	 */
968 	cue_csr_write_1(sc, CUE_RX_BUFPKTS, CUE_RX_FRAMES);
969 	cue_csr_write_1(sc, CUE_TX_BUFPKTS, CUE_TX_FRAMES);
970 
971 	/* Set advanced operation modes. */
972 	cue_csr_write_1(sc, CUE_ADVANCED_OPMODES,
973 	    CUE_AOP_EMBED_RXLEN | 0x01); /* 1 wait state */
974 
975 	/* Program the LED operation. */
976 	cue_csr_write_1(sc, CUE_LEDCTL, CUE_LEDCTL_FOLLOW_LINK);
977 
978 	if (sc->cue_ep[CUE_ENDPT_RX] == NULL) {
979 		if (cue_open_pipes(sc)) {
980 			splx(s);
981 			return;
982 		}
983 	}
984 
985 	ifp->if_flags |= IFF_RUNNING;
986 	ifq_clr_oactive(&ifp->if_snd);
987 
988 	splx(s);
989 
990 	timeout_add_sec(&sc->cue_stat_ch, 1);
991 }
992 
993 int
994 cue_open_pipes(struct cue_softc *sc)
995 {
996 	struct cue_chain	*c;
997 	usbd_status		err;
998 	int			i;
999 
1000 	/* Open RX and TX pipes. */
1001 	err = usbd_open_pipe(sc->cue_iface, sc->cue_ed[CUE_ENDPT_RX],
1002 	    USBD_EXCLUSIVE_USE, &sc->cue_ep[CUE_ENDPT_RX]);
1003 	if (err) {
1004 		printf("%s: open rx pipe failed: %s\n",
1005 		    sc->cue_dev.dv_xname, usbd_errstr(err));
1006 		return (EIO);
1007 	}
1008 	err = usbd_open_pipe(sc->cue_iface, sc->cue_ed[CUE_ENDPT_TX],
1009 	    USBD_EXCLUSIVE_USE, &sc->cue_ep[CUE_ENDPT_TX]);
1010 	if (err) {
1011 		printf("%s: open tx pipe failed: %s\n",
1012 		    sc->cue_dev.dv_xname, usbd_errstr(err));
1013 		return (EIO);
1014 	}
1015 
1016 	/* Start up the receive pipe. */
1017 	for (i = 0; i < CUE_RX_LIST_CNT; i++) {
1018 		c = &sc->cue_cdata.cue_rx_chain[i];
1019 		usbd_setup_xfer(c->cue_xfer, sc->cue_ep[CUE_ENDPT_RX],
1020 		    c, c->cue_buf, CUE_BUFSZ,
1021 		    USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
1022 		    cue_rxeof);
1023 		usbd_transfer(c->cue_xfer);
1024 	}
1025 
1026 	return (0);
1027 }
1028 
1029 int
1030 cue_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
1031 {
1032 	struct cue_softc	*sc = ifp->if_softc;
1033 	int			s, error = 0;
1034 
1035 	if (usbd_is_dying(sc->cue_udev))
1036 		return ENXIO;
1037 
1038 	s = splnet();
1039 
1040 	switch(command) {
1041 	case SIOCSIFADDR:
1042 		ifp->if_flags |= IFF_UP;
1043 		cue_init(sc);
1044 		break;
1045 
1046 	case SIOCSIFFLAGS:
1047 		if (ifp->if_flags & IFF_UP) {
1048 			if (ifp->if_flags & IFF_RUNNING &&
1049 			    ifp->if_flags & IFF_PROMISC &&
1050 			    !(sc->cue_if_flags & IFF_PROMISC)) {
1051 				CUE_SETBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC);
1052 				cue_setmulti(sc);
1053 			} else if (ifp->if_flags & IFF_RUNNING &&
1054 			    !(ifp->if_flags & IFF_PROMISC) &&
1055 			    sc->cue_if_flags & IFF_PROMISC) {
1056 				CUE_CLRBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC);
1057 				cue_setmulti(sc);
1058 			} else if (!(ifp->if_flags & IFF_RUNNING))
1059 				cue_init(sc);
1060 		} else {
1061 			if (ifp->if_flags & IFF_RUNNING)
1062 				cue_stop(sc);
1063 		}
1064 		sc->cue_if_flags = ifp->if_flags;
1065 		error = 0;
1066 		break;
1067 
1068 	default:
1069 		error = ether_ioctl(ifp, &sc->arpcom, command, data);
1070 	}
1071 
1072 	if (error == ENETRESET) {
1073 		if (ifp->if_flags & IFF_RUNNING)
1074 			cue_setmulti(sc);
1075 		error = 0;
1076 	}
1077 
1078 	splx(s);
1079 	return (error);
1080 }
1081 
1082 void
1083 cue_watchdog(struct ifnet *ifp)
1084 {
1085 	struct cue_softc	*sc = ifp->if_softc;
1086 	struct cue_chain	*c;
1087 	usbd_status		stat;
1088 	int			s;
1089 
1090 	DPRINTFN(5,("%s: %s: enter\n", sc->cue_dev.dv_xname,__func__));
1091 
1092 	if (usbd_is_dying(sc->cue_udev))
1093 		return;
1094 
1095 	ifp->if_oerrors++;
1096 	printf("%s: watchdog timeout\n", sc->cue_dev.dv_xname);
1097 
1098 	s = splusb();
1099 	c = &sc->cue_cdata.cue_tx_chain[0];
1100 	usbd_get_xfer_status(c->cue_xfer, NULL, NULL, NULL, &stat);
1101 	cue_txeof(c->cue_xfer, c, stat);
1102 
1103 	if (ifq_empty(&ifp->if_snd) == 0)
1104 		cue_start(ifp);
1105 	splx(s);
1106 }
1107 
1108 /*
1109  * Stop the adapter and free any mbufs allocated to the
1110  * RX and TX lists.
1111  */
1112 void
1113 cue_stop(struct cue_softc *sc)
1114 {
1115 	usbd_status		err;
1116 	struct ifnet		*ifp;
1117 	int			i;
1118 
1119 	DPRINTFN(10,("%s: %s: enter\n", sc->cue_dev.dv_xname,__func__));
1120 
1121 	ifp = GET_IFP(sc);
1122 	ifp->if_timer = 0;
1123 	ifp->if_flags &= ~IFF_RUNNING;
1124 	ifq_clr_oactive(&ifp->if_snd);
1125 
1126 	cue_csr_write_1(sc, CUE_ETHCTL, 0);
1127 	cue_reset(sc);
1128 	timeout_del(&sc->cue_stat_ch);
1129 
1130 	/* Stop transfers. */
1131 	if (sc->cue_ep[CUE_ENDPT_RX] != NULL) {
1132 		err = usbd_close_pipe(sc->cue_ep[CUE_ENDPT_RX]);
1133 		if (err) {
1134 			printf("%s: close rx pipe failed: %s\n",
1135 			sc->cue_dev.dv_xname, usbd_errstr(err));
1136 		}
1137 		sc->cue_ep[CUE_ENDPT_RX] = NULL;
1138 	}
1139 
1140 	if (sc->cue_ep[CUE_ENDPT_TX] != NULL) {
1141 		err = usbd_close_pipe(sc->cue_ep[CUE_ENDPT_TX]);
1142 		if (err) {
1143 			printf("%s: close tx pipe failed: %s\n",
1144 			    sc->cue_dev.dv_xname, usbd_errstr(err));
1145 		}
1146 		sc->cue_ep[CUE_ENDPT_TX] = NULL;
1147 	}
1148 
1149 	if (sc->cue_ep[CUE_ENDPT_INTR] != NULL) {
1150 		err = usbd_close_pipe(sc->cue_ep[CUE_ENDPT_INTR]);
1151 		if (err) {
1152 			printf("%s: close intr pipe failed: %s\n",
1153 			    sc->cue_dev.dv_xname, usbd_errstr(err));
1154 		}
1155 		sc->cue_ep[CUE_ENDPT_INTR] = NULL;
1156 	}
1157 
1158 	/* Free RX resources. */
1159 	for (i = 0; i < CUE_RX_LIST_CNT; i++) {
1160 		if (sc->cue_cdata.cue_rx_chain[i].cue_mbuf != NULL) {
1161 			m_freem(sc->cue_cdata.cue_rx_chain[i].cue_mbuf);
1162 			sc->cue_cdata.cue_rx_chain[i].cue_mbuf = NULL;
1163 		}
1164 		if (sc->cue_cdata.cue_rx_chain[i].cue_xfer != NULL) {
1165 			usbd_free_xfer(sc->cue_cdata.cue_rx_chain[i].cue_xfer);
1166 			sc->cue_cdata.cue_rx_chain[i].cue_xfer = NULL;
1167 		}
1168 	}
1169 
1170 	/* Free TX resources. */
1171 	for (i = 0; i < CUE_TX_LIST_CNT; i++) {
1172 		if (sc->cue_cdata.cue_tx_chain[i].cue_mbuf != NULL) {
1173 			m_freem(sc->cue_cdata.cue_tx_chain[i].cue_mbuf);
1174 			sc->cue_cdata.cue_tx_chain[i].cue_mbuf = NULL;
1175 		}
1176 		if (sc->cue_cdata.cue_tx_chain[i].cue_xfer != NULL) {
1177 			usbd_free_xfer(sc->cue_cdata.cue_tx_chain[i].cue_xfer);
1178 			sc->cue_cdata.cue_tx_chain[i].cue_xfer = NULL;
1179 		}
1180 	}
1181 }
1182