Line data Source code
1 : /* $OpenBSD: if_cue.c,v 1.77 2017/01/22 10:17:39 dlg 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 0 : cue_csr_read_1(struct cue_softc *sc, int reg)
152 : {
153 0 : usb_device_request_t req;
154 : usbd_status err;
155 0 : u_int8_t val = 0;
156 :
157 0 : if (usbd_is_dying(sc->cue_udev))
158 0 : return (0);
159 :
160 0 : req.bmRequestType = UT_READ_VENDOR_DEVICE;
161 0 : req.bRequest = CUE_CMD_READREG;
162 0 : USETW(req.wValue, 0);
163 0 : USETW(req.wIndex, reg);
164 0 : USETW(req.wLength, 1);
165 :
166 0 : err = usbd_do_request(sc->cue_udev, &req, &val);
167 :
168 0 : 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 0 : 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 0 : return (val);
178 0 : }
179 :
180 : int
181 0 : cue_csr_read_2(struct cue_softc *sc, int reg)
182 : {
183 0 : usb_device_request_t req;
184 : usbd_status err;
185 0 : uWord val;
186 :
187 0 : if (usbd_is_dying(sc->cue_udev))
188 0 : return (0);
189 :
190 0 : req.bmRequestType = UT_READ_VENDOR_DEVICE;
191 0 : req.bRequest = CUE_CMD_READREG;
192 0 : USETW(req.wValue, 0);
193 0 : USETW(req.wIndex, reg);
194 0 : USETW(req.wLength, 2);
195 :
196 0 : 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 0 : 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 0 : return (0);
205 : }
206 :
207 0 : return (UGETW(val));
208 0 : }
209 :
210 : int
211 0 : cue_csr_write_1(struct cue_softc *sc, int reg, int val)
212 : {
213 0 : usb_device_request_t req;
214 : usbd_status err;
215 :
216 0 : if (usbd_is_dying(sc->cue_udev))
217 0 : 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 0 : req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
223 0 : req.bRequest = CUE_CMD_WRITEREG;
224 0 : USETW(req.wValue, val);
225 0 : USETW(req.wIndex, reg);
226 0 : USETW(req.wLength, 0);
227 :
228 0 : err = usbd_do_request(sc->cue_udev, &req, NULL);
229 :
230 0 : 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 0 : 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 0 : return (0);
240 0 : }
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 0 : cue_mem(struct cue_softc *sc, int cmd, int addr, void *buf, int len)
278 : {
279 0 : 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 0 : if (cmd == CUE_CMD_READSRAM)
286 0 : req.bmRequestType = UT_READ_VENDOR_DEVICE;
287 : else
288 0 : req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
289 0 : req.bRequest = cmd;
290 0 : USETW(req.wValue, 0);
291 0 : USETW(req.wIndex, addr);
292 0 : USETW(req.wLength, len);
293 :
294 0 : err = usbd_do_request(sc->cue_udev, &req, buf);
295 :
296 0 : 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 0 : return (-1);
300 : }
301 :
302 0 : return (0);
303 0 : }
304 :
305 : int
306 0 : cue_getmac(struct cue_softc *sc, void *buf)
307 : {
308 0 : usb_device_request_t req;
309 : usbd_status err;
310 :
311 : DPRINTFN(10,("%s: cue_getmac\n", sc->cue_dev.dv_xname));
312 :
313 0 : req.bmRequestType = UT_READ_VENDOR_DEVICE;
314 0 : req.bRequest = CUE_CMD_GET_MACADDR;
315 0 : USETW(req.wValue, 0);
316 0 : USETW(req.wIndex, 0);
317 0 : USETW(req.wLength, ETHER_ADDR_LEN);
318 :
319 0 : err = usbd_do_request(sc->cue_udev, &req, buf);
320 :
321 0 : if (err) {
322 0 : printf("%s: read MAC address failed\n",
323 0 : sc->cue_dev.dv_xname);
324 0 : return (-1);
325 : }
326 :
327 0 : return (0);
328 0 : }
329 :
330 : #define CUE_BITS 9
331 :
332 : void
333 0 : cue_setmulti(struct cue_softc *sc)
334 : {
335 0 : 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 0 : 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 0 : if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) {
347 0 : ifp->if_flags |= IFF_ALLMULTI;
348 0 : for (i = 0; i < CUE_MCAST_TABLE_LEN; i++)
349 0 : sc->cue_mctab[i] = 0xFF;
350 0 : cue_mem(sc, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR,
351 0 : &sc->cue_mctab, CUE_MCAST_TABLE_LEN);
352 0 : return;
353 : }
354 :
355 : /* first, zot all the existing hash bits */
356 0 : for (i = 0; i < CUE_MCAST_TABLE_LEN; i++)
357 0 : sc->cue_mctab[i] = 0;
358 :
359 : /* now program new ones */
360 0 : ETHER_FIRST_MULTI(step, ac, enm);
361 0 : while (enm != NULL) {
362 0 : h = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN) &
363 : ((1 << CUE_BITS) - 1);
364 0 : sc->cue_mctab[h >> 3] |= 1 << (h & 0x7);
365 0 : ETHER_NEXT_MULTI(step, enm);
366 : }
367 :
368 0 : 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 0 : if (ifp->if_flags & IFF_BROADCAST) {
375 0 : h = ether_crc32_le(etherbroadcastaddr, ETHER_ADDR_LEN) &
376 : ((1 << CUE_BITS) - 1);
377 0 : sc->cue_mctab[h >> 3] |= 1 << (h & 0x7);
378 0 : }
379 :
380 0 : cue_mem(sc, CUE_CMD_WRITESRAM, CUE_MCAST_TABLE_ADDR,
381 0 : &sc->cue_mctab, CUE_MCAST_TABLE_LEN);
382 0 : }
383 :
384 : void
385 0 : cue_reset(struct cue_softc *sc)
386 : {
387 0 : usb_device_request_t req;
388 : usbd_status err;
389 :
390 : DPRINTFN(2,("%s: cue_reset\n", sc->cue_dev.dv_xname));
391 :
392 0 : if (usbd_is_dying(sc->cue_udev))
393 0 : return;
394 :
395 0 : req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
396 0 : req.bRequest = CUE_CMD_RESET;
397 0 : USETW(req.wValue, 0);
398 0 : USETW(req.wIndex, 0);
399 0 : USETW(req.wLength, 0);
400 :
401 0 : err = usbd_do_request(sc->cue_udev, &req, NULL);
402 :
403 0 : if (err)
404 0 : 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 0 : usbd_delay_ms(sc->cue_udev, 1);
408 0 : }
409 :
410 : /*
411 : * Probe for a CATC chip.
412 : */
413 : int
414 0 : cue_match(struct device *parent, void *match, void *aux)
415 : {
416 0 : struct usb_attach_arg *uaa = aux;
417 :
418 0 : if (uaa->iface == NULL || uaa->configno != CUE_CONFIG_NO)
419 0 : return (UMATCH_NONE);
420 :
421 0 : return (usb_lookup(cue_devs, uaa->vendor, uaa->product) != NULL ?
422 : UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
423 0 : }
424 :
425 : /*
426 : * Attach the interface. Allocate softc structures, do ifmedia
427 : * setup and ethernet/BPF attach.
428 : */
429 : void
430 0 : cue_attach(struct device *parent, struct device *self, void *aux)
431 : {
432 0 : struct cue_softc *sc = (struct cue_softc *)self;
433 0 : struct usb_attach_arg *uaa = aux;
434 : int s;
435 0 : u_char eaddr[ETHER_ADDR_LEN];
436 0 : struct usbd_device *dev = uaa->device;
437 0 : 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 0 : sc->cue_udev = dev;
447 0 : sc->cue_product = uaa->product;
448 0 : sc->cue_vendor = uaa->vendor;
449 :
450 0 : usb_init_task(&sc->cue_tick_task, cue_tick_task, sc,
451 : USB_TASK_TYPE_GENERIC);
452 0 : usb_init_task(&sc->cue_stop_task, (void (*)(void *))cue_stop, sc,
453 : USB_TASK_TYPE_GENERIC);
454 :
455 0 : err = usbd_device2interface_handle(dev, CUE_IFACE_IDX, &iface);
456 0 : if (err) {
457 0 : printf("%s: getting interface handle failed\n",
458 0 : sc->cue_dev.dv_xname);
459 0 : return;
460 : }
461 :
462 0 : sc->cue_iface = iface;
463 0 : id = usbd_get_interface_descriptor(iface);
464 :
465 : /* Find endpoints. */
466 0 : for (i = 0; i < id->bNumEndpoints; i++) {
467 0 : ed = usbd_interface2endpoint_descriptor(iface, i);
468 0 : if (ed == NULL) {
469 0 : printf("%s: couldn't get ep %d\n",
470 0 : sc->cue_dev.dv_xname, i);
471 0 : return;
472 : }
473 0 : if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
474 0 : UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
475 0 : sc->cue_ed[CUE_ENDPT_RX] = ed->bEndpointAddress;
476 0 : } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
477 0 : UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
478 0 : sc->cue_ed[CUE_ENDPT_TX] = ed->bEndpointAddress;
479 0 : } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
480 0 : UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
481 0 : sc->cue_ed[CUE_ENDPT_INTR] = ed->bEndpointAddress;
482 0 : }
483 : }
484 :
485 : #if 0
486 : /* Reset the adapter. */
487 : cue_reset(sc);
488 : #endif
489 : /*
490 : * Get station address.
491 : */
492 0 : cue_getmac(sc, &eaddr);
493 :
494 0 : s = splnet();
495 :
496 : /*
497 : * A CATC chip was detected. Inform the world.
498 : */
499 0 : printf("%s: address %s\n", sc->cue_dev.dv_xname,
500 0 : ether_sprintf(eaddr));
501 :
502 0 : bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
503 :
504 : /* Initialize interface info.*/
505 0 : ifp = GET_IFP(sc);
506 0 : ifp->if_softc = sc;
507 0 : ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
508 0 : ifp->if_ioctl = cue_ioctl;
509 0 : ifp->if_start = cue_start;
510 0 : ifp->if_watchdog = cue_watchdog;
511 0 : strlcpy(ifp->if_xname, sc->cue_dev.dv_xname, IFNAMSIZ);
512 :
513 : /* Attach the interface. */
514 0 : if_attach(ifp);
515 0 : ether_ifattach(ifp);
516 :
517 0 : timeout_set(&sc->cue_stat_ch, cue_tick, sc);
518 :
519 0 : splx(s);
520 0 : }
521 :
522 : int
523 0 : cue_detach(struct device *self, int flags)
524 : {
525 0 : struct cue_softc *sc = (struct cue_softc *)self;
526 0 : 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 0 : if (timeout_initialized(&sc->cue_stat_ch))
532 0 : 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 0 : usb_rem_task(sc->cue_udev, &sc->cue_tick_task);
539 0 : usb_rem_task(sc->cue_udev, &sc->cue_stop_task);
540 :
541 0 : s = splusb();
542 :
543 0 : if (ifp->if_flags & IFF_RUNNING)
544 0 : cue_stop(sc);
545 :
546 0 : if (ifp->if_softc != NULL) {
547 0 : ether_ifdetach(ifp);
548 0 : if_detach(ifp);
549 0 : }
550 :
551 : #ifdef DIAGNOSTIC
552 0 : if (sc->cue_ep[CUE_ENDPT_TX] != NULL ||
553 0 : sc->cue_ep[CUE_ENDPT_RX] != NULL ||
554 0 : sc->cue_ep[CUE_ENDPT_INTR] != NULL)
555 0 : printf("%s: detach has active endpoints\n",
556 0 : sc->cue_dev.dv_xname);
557 : #endif
558 :
559 0 : splx(s);
560 :
561 0 : return (0);
562 : }
563 :
564 : /*
565 : * Initialize an RX descriptor and attach an MBUF cluster.
566 : */
567 : int
568 0 : cue_newbuf(struct cue_softc *sc, struct cue_chain *c, struct mbuf *m)
569 : {
570 : struct mbuf *m_new = NULL;
571 :
572 0 : if (m == NULL) {
573 0 : MGETHDR(m_new, M_DONTWAIT, MT_DATA);
574 0 : if (m_new == NULL) {
575 0 : printf("%s: no memory for rx list "
576 0 : "-- packet dropped!\n", sc->cue_dev.dv_xname);
577 0 : return (ENOBUFS);
578 : }
579 :
580 0 : MCLGET(m_new, M_DONTWAIT);
581 0 : if (!(m_new->m_flags & M_EXT)) {
582 0 : printf("%s: no memory for rx list "
583 0 : "-- packet dropped!\n", sc->cue_dev.dv_xname);
584 0 : m_freem(m_new);
585 0 : return (ENOBUFS);
586 : }
587 0 : m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
588 0 : } else {
589 : m_new = m;
590 0 : m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
591 0 : m_new->m_data = m_new->m_ext.ext_buf;
592 : }
593 :
594 0 : m_adj(m_new, ETHER_ALIGN);
595 0 : c->cue_mbuf = m_new;
596 :
597 0 : return (0);
598 0 : }
599 :
600 : int
601 0 : cue_rx_list_init(struct cue_softc *sc)
602 : {
603 : struct cue_cdata *cd;
604 : struct cue_chain *c;
605 : int i;
606 :
607 0 : cd = &sc->cue_cdata;
608 0 : for (i = 0; i < CUE_RX_LIST_CNT; i++) {
609 0 : c = &cd->cue_rx_chain[i];
610 0 : c->cue_sc = sc;
611 0 : c->cue_idx = i;
612 0 : if (cue_newbuf(sc, c, NULL) == ENOBUFS)
613 0 : return (ENOBUFS);
614 0 : if (c->cue_xfer == NULL) {
615 0 : c->cue_xfer = usbd_alloc_xfer(sc->cue_udev);
616 0 : if (c->cue_xfer == NULL)
617 0 : return (ENOBUFS);
618 0 : c->cue_buf = usbd_alloc_buffer(c->cue_xfer, CUE_BUFSZ);
619 0 : if (c->cue_buf == NULL) {
620 0 : usbd_free_xfer(c->cue_xfer);
621 0 : return (ENOBUFS);
622 : }
623 : }
624 : }
625 :
626 0 : return (0);
627 0 : }
628 :
629 : int
630 0 : cue_tx_list_init(struct cue_softc *sc)
631 : {
632 : struct cue_cdata *cd;
633 : struct cue_chain *c;
634 : int i;
635 :
636 0 : cd = &sc->cue_cdata;
637 0 : for (i = 0; i < CUE_TX_LIST_CNT; i++) {
638 0 : c = &cd->cue_tx_chain[i];
639 0 : c->cue_sc = sc;
640 0 : c->cue_idx = i;
641 0 : c->cue_mbuf = NULL;
642 0 : if (c->cue_xfer == NULL) {
643 0 : c->cue_xfer = usbd_alloc_xfer(sc->cue_udev);
644 0 : if (c->cue_xfer == NULL)
645 0 : return (ENOBUFS);
646 0 : c->cue_buf = usbd_alloc_buffer(c->cue_xfer, CUE_BUFSZ);
647 0 : if (c->cue_buf == NULL) {
648 0 : usbd_free_xfer(c->cue_xfer);
649 0 : return (ENOBUFS);
650 : }
651 : }
652 : }
653 :
654 0 : return (0);
655 0 : }
656 :
657 : /*
658 : * A frame has been uploaded: pass the resulting mbuf chain up to
659 : * the higher level protocols.
660 : */
661 : void
662 0 : cue_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
663 : {
664 0 : struct cue_chain *c = priv;
665 0 : struct cue_softc *sc = c->cue_sc;
666 0 : struct ifnet *ifp = GET_IFP(sc);
667 0 : struct mbuf_list ml = MBUF_LIST_INITIALIZER();
668 : struct mbuf *m;
669 0 : 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 0 : if (usbd_is_dying(sc->cue_udev))
677 0 : return;
678 :
679 0 : if (!(ifp->if_flags & IFF_RUNNING))
680 0 : return;
681 :
682 0 : if (status != USBD_NORMAL_COMPLETION) {
683 0 : if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
684 0 : return;
685 0 : sc->cue_rx_errs++;
686 0 : if (usbd_ratecheck(&sc->cue_rx_notice)) {
687 0 : printf("%s: %u usb errors on rx: %s\n",
688 0 : sc->cue_dev.dv_xname, sc->cue_rx_errs,
689 0 : usbd_errstr(status));
690 0 : sc->cue_rx_errs = 0;
691 0 : }
692 0 : if (status == USBD_STALLED)
693 0 : usbd_clear_endpoint_stall_async(sc->cue_ep[CUE_ENDPT_RX]);
694 : goto done;
695 : }
696 :
697 0 : usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
698 :
699 0 : memcpy(mtod(c->cue_mbuf, char *), c->cue_buf, total_len);
700 :
701 0 : m = c->cue_mbuf;
702 0 : len = UGETW(mtod(m, u_int8_t *));
703 :
704 : /* No errors; receive the packet. */
705 0 : total_len = len;
706 :
707 0 : if (len < sizeof(struct ether_header)) {
708 0 : ifp->if_ierrors++;
709 0 : goto done;
710 : }
711 :
712 0 : m_adj(m, sizeof(u_int16_t));
713 0 : m->m_pkthdr.len = m->m_len = total_len;
714 0 : ml_enqueue(&ml, m);
715 :
716 0 : if (cue_newbuf(sc, c, NULL) == ENOBUFS) {
717 0 : ifp->if_ierrors++;
718 0 : goto done;
719 : }
720 :
721 0 : s = splnet();
722 0 : if_input(ifp, &ml);
723 0 : splx(s);
724 :
725 : done:
726 : /* Setup new transfer. */
727 0 : usbd_setup_xfer(c->cue_xfer, sc->cue_ep[CUE_ENDPT_RX],
728 0 : c, c->cue_buf, CUE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
729 : USBD_NO_TIMEOUT, cue_rxeof);
730 0 : usbd_transfer(c->cue_xfer);
731 :
732 : DPRINTFN(10,("%s: %s: start rx\n", sc->cue_dev.dv_xname,
733 : __func__));
734 0 : }
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 0 : cue_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
742 : {
743 0 : struct cue_chain *c = priv;
744 0 : struct cue_softc *sc = c->cue_sc;
745 0 : struct ifnet *ifp = GET_IFP(sc);
746 : int s;
747 :
748 0 : if (usbd_is_dying(sc->cue_udev))
749 0 : return;
750 :
751 0 : s = splnet();
752 :
753 : DPRINTFN(10,("%s: %s: enter status=%d\n", sc->cue_dev.dv_xname,
754 : __func__, status));
755 :
756 0 : ifp->if_timer = 0;
757 0 : ifq_clr_oactive(&ifp->if_snd);
758 :
759 0 : if (status != USBD_NORMAL_COMPLETION) {
760 0 : if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
761 0 : splx(s);
762 0 : return;
763 : }
764 0 : ifp->if_oerrors++;
765 0 : printf("%s: usb error on tx: %s\n", sc->cue_dev.dv_xname,
766 0 : usbd_errstr(status));
767 0 : if (status == USBD_STALLED)
768 0 : usbd_clear_endpoint_stall_async(sc->cue_ep[CUE_ENDPT_TX]);
769 0 : splx(s);
770 0 : return;
771 : }
772 :
773 0 : m_freem(c->cue_mbuf);
774 0 : c->cue_mbuf = NULL;
775 :
776 0 : if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
777 0 : cue_start(ifp);
778 :
779 0 : splx(s);
780 0 : }
781 :
782 : void
783 0 : cue_tick(void *xsc)
784 : {
785 0 : struct cue_softc *sc = xsc;
786 :
787 0 : if (sc == NULL)
788 0 : return;
789 :
790 0 : if (usbd_is_dying(sc->cue_udev))
791 0 : return;
792 :
793 : DPRINTFN(2,("%s: %s: enter\n", sc->cue_dev.dv_xname, __func__));
794 :
795 : /* Perform statistics update in process context. */
796 0 : usb_add_task(sc->cue_udev, &sc->cue_tick_task);
797 0 : }
798 :
799 : void
800 0 : cue_tick_task(void *xsc)
801 : {
802 0 : struct cue_softc *sc = xsc;
803 : struct ifnet *ifp;
804 :
805 0 : if (usbd_is_dying(sc->cue_udev))
806 0 : return;
807 :
808 : DPRINTFN(2,("%s: %s: enter\n", sc->cue_dev.dv_xname, __func__));
809 :
810 0 : ifp = GET_IFP(sc);
811 :
812 0 : ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_SINGLECOLL);
813 0 : ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_MULTICOLL);
814 0 : ifp->if_collisions += cue_csr_read_2(sc, CUE_TX_EXCESSCOLL);
815 :
816 0 : if (cue_csr_read_2(sc, CUE_RX_FRAMEERR))
817 0 : ifp->if_ierrors++;
818 0 : }
819 :
820 : int
821 0 : 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 0 : 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 0 : m_copydata(m, 0, m->m_pkthdr.len, c->cue_buf + 2);
834 0 : c->cue_mbuf = m;
835 :
836 0 : 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 0 : c->cue_buf[0] = (u_int8_t)m->m_pkthdr.len;
843 0 : c->cue_buf[1] = (u_int8_t)(m->m_pkthdr.len >> 8);
844 :
845 : /* XXX 10000 */
846 0 : usbd_setup_xfer(c->cue_xfer, sc->cue_ep[CUE_ENDPT_TX],
847 0 : c, c->cue_buf, total_len, USBD_NO_COPY, 10000, cue_txeof);
848 :
849 : /* Transmit */
850 0 : err = usbd_transfer(c->cue_xfer);
851 0 : if (err != USBD_IN_PROGRESS) {
852 0 : printf("%s: cue_send error=%s\n", sc->cue_dev.dv_xname,
853 0 : usbd_errstr(err));
854 : /* Stop the interface from process context. */
855 0 : usb_add_task(sc->cue_udev, &sc->cue_stop_task);
856 0 : return (EIO);
857 : }
858 :
859 0 : sc->cue_cdata.cue_tx_cnt++;
860 :
861 0 : return (0);
862 0 : }
863 :
864 : void
865 0 : cue_start(struct ifnet *ifp)
866 : {
867 0 : struct cue_softc *sc = ifp->if_softc;
868 : struct mbuf *m_head = NULL;
869 :
870 0 : if (usbd_is_dying(sc->cue_udev))
871 0 : return;
872 :
873 : DPRINTFN(10,("%s: %s: enter\n", sc->cue_dev.dv_xname,__func__));
874 :
875 0 : if (ifq_is_oactive(&ifp->if_snd))
876 0 : return;
877 :
878 0 : m_head = ifq_deq_begin(&ifp->if_snd);
879 0 : if (m_head == NULL)
880 0 : return;
881 :
882 0 : if (cue_send(sc, m_head, 0)) {
883 0 : ifq_deq_rollback(&ifp->if_snd, m_head);
884 0 : ifq_set_oactive(&ifp->if_snd);
885 0 : return;
886 : }
887 :
888 0 : 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 0 : if (ifp->if_bpf)
896 0 : bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
897 : #endif
898 :
899 0 : ifq_set_oactive(&ifp->if_snd);
900 :
901 : /*
902 : * Set a timeout in case the chip goes out to lunch.
903 : */
904 0 : ifp->if_timer = 5;
905 0 : }
906 :
907 : void
908 0 : cue_init(void *xsc)
909 : {
910 0 : struct cue_softc *sc = xsc;
911 0 : struct ifnet *ifp = GET_IFP(sc);
912 : int i, s, ctl;
913 : u_char *eaddr;
914 :
915 0 : if (usbd_is_dying(sc->cue_udev))
916 0 : return;
917 :
918 : DPRINTFN(10,("%s: %s: enter\n", sc->cue_dev.dv_xname,__func__));
919 :
920 0 : if (ifp->if_flags & IFF_RUNNING)
921 0 : return;
922 :
923 0 : s = splnet();
924 :
925 : /*
926 : * Cancel pending I/O and free all RX/TX buffers.
927 : */
928 : #if 1
929 0 : cue_reset(sc);
930 : #endif
931 :
932 : /* Set advanced operation modes. */
933 0 : cue_csr_write_1(sc, CUE_ADVANCED_OPMODES,
934 : CUE_AOP_EMBED_RXLEN | 0x03); /* 1 wait state */
935 :
936 0 : eaddr = sc->arpcom.ac_enaddr;
937 : /* Set MAC address */
938 0 : for (i = 0; i < ETHER_ADDR_LEN; i++)
939 0 : 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 0 : if (ifp->if_flags & IFF_PROMISC)
944 0 : ctl |= CUE_ETHCTL_PROMISC;
945 0 : cue_csr_write_1(sc, CUE_ETHCTL, ctl);
946 :
947 : /* Init TX ring. */
948 0 : if (cue_tx_list_init(sc) == ENOBUFS) {
949 0 : printf("%s: tx list init failed\n", sc->cue_dev.dv_xname);
950 0 : splx(s);
951 0 : return;
952 : }
953 :
954 : /* Init RX ring. */
955 0 : if (cue_rx_list_init(sc) == ENOBUFS) {
956 0 : printf("%s: rx list init failed\n", sc->cue_dev.dv_xname);
957 0 : splx(s);
958 0 : return;
959 : }
960 :
961 : /* Load the multicast filter. */
962 0 : 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 0 : cue_csr_write_1(sc, CUE_RX_BUFPKTS, CUE_RX_FRAMES);
969 0 : cue_csr_write_1(sc, CUE_TX_BUFPKTS, CUE_TX_FRAMES);
970 :
971 : /* Set advanced operation modes. */
972 0 : cue_csr_write_1(sc, CUE_ADVANCED_OPMODES,
973 : CUE_AOP_EMBED_RXLEN | 0x01); /* 1 wait state */
974 :
975 : /* Program the LED operation. */
976 0 : cue_csr_write_1(sc, CUE_LEDCTL, CUE_LEDCTL_FOLLOW_LINK);
977 :
978 0 : if (sc->cue_ep[CUE_ENDPT_RX] == NULL) {
979 0 : if (cue_open_pipes(sc)) {
980 0 : splx(s);
981 0 : return;
982 : }
983 : }
984 :
985 0 : ifp->if_flags |= IFF_RUNNING;
986 0 : ifq_clr_oactive(&ifp->if_snd);
987 :
988 0 : splx(s);
989 :
990 0 : timeout_add_sec(&sc->cue_stat_ch, 1);
991 0 : }
992 :
993 : int
994 0 : 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 0 : err = usbd_open_pipe(sc->cue_iface, sc->cue_ed[CUE_ENDPT_RX],
1002 0 : USBD_EXCLUSIVE_USE, &sc->cue_ep[CUE_ENDPT_RX]);
1003 0 : if (err) {
1004 0 : printf("%s: open rx pipe failed: %s\n",
1005 0 : sc->cue_dev.dv_xname, usbd_errstr(err));
1006 0 : return (EIO);
1007 : }
1008 0 : err = usbd_open_pipe(sc->cue_iface, sc->cue_ed[CUE_ENDPT_TX],
1009 0 : USBD_EXCLUSIVE_USE, &sc->cue_ep[CUE_ENDPT_TX]);
1010 0 : if (err) {
1011 0 : printf("%s: open tx pipe failed: %s\n",
1012 0 : sc->cue_dev.dv_xname, usbd_errstr(err));
1013 0 : return (EIO);
1014 : }
1015 :
1016 : /* Start up the receive pipe. */
1017 0 : for (i = 0; i < CUE_RX_LIST_CNT; i++) {
1018 0 : c = &sc->cue_cdata.cue_rx_chain[i];
1019 0 : usbd_setup_xfer(c->cue_xfer, sc->cue_ep[CUE_ENDPT_RX],
1020 0 : c, c->cue_buf, CUE_BUFSZ,
1021 : USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
1022 : cue_rxeof);
1023 0 : usbd_transfer(c->cue_xfer);
1024 : }
1025 :
1026 0 : return (0);
1027 0 : }
1028 :
1029 : int
1030 0 : cue_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
1031 : {
1032 0 : struct cue_softc *sc = ifp->if_softc;
1033 : int s, error = 0;
1034 :
1035 0 : if (usbd_is_dying(sc->cue_udev))
1036 0 : return (EIO);
1037 :
1038 0 : s = splnet();
1039 :
1040 0 : switch(command) {
1041 : case SIOCSIFADDR:
1042 0 : ifp->if_flags |= IFF_UP;
1043 0 : cue_init(sc);
1044 0 : break;
1045 :
1046 : case SIOCSIFFLAGS:
1047 0 : if (ifp->if_flags & IFF_UP) {
1048 0 : if (ifp->if_flags & IFF_RUNNING &&
1049 0 : ifp->if_flags & IFF_PROMISC &&
1050 0 : !(sc->cue_if_flags & IFF_PROMISC)) {
1051 0 : CUE_SETBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC);
1052 0 : cue_setmulti(sc);
1053 0 : } else if (ifp->if_flags & IFF_RUNNING &&
1054 0 : !(ifp->if_flags & IFF_PROMISC) &&
1055 0 : sc->cue_if_flags & IFF_PROMISC) {
1056 0 : CUE_CLRBIT(sc, CUE_ETHCTL, CUE_ETHCTL_PROMISC);
1057 0 : cue_setmulti(sc);
1058 0 : } else if (!(ifp->if_flags & IFF_RUNNING))
1059 0 : cue_init(sc);
1060 : } else {
1061 0 : if (ifp->if_flags & IFF_RUNNING)
1062 0 : cue_stop(sc);
1063 : }
1064 0 : sc->cue_if_flags = ifp->if_flags;
1065 : error = 0;
1066 0 : break;
1067 :
1068 : default:
1069 0 : error = ether_ioctl(ifp, &sc->arpcom, command, data);
1070 0 : }
1071 :
1072 0 : if (error == ENETRESET) {
1073 0 : if (ifp->if_flags & IFF_RUNNING)
1074 0 : cue_setmulti(sc);
1075 : error = 0;
1076 0 : }
1077 :
1078 0 : splx(s);
1079 0 : return (error);
1080 0 : }
1081 :
1082 : void
1083 0 : cue_watchdog(struct ifnet *ifp)
1084 : {
1085 0 : struct cue_softc *sc = ifp->if_softc;
1086 : struct cue_chain *c;
1087 0 : usbd_status stat;
1088 : int s;
1089 :
1090 : DPRINTFN(5,("%s: %s: enter\n", sc->cue_dev.dv_xname,__func__));
1091 :
1092 0 : if (usbd_is_dying(sc->cue_udev))
1093 0 : return;
1094 :
1095 0 : ifp->if_oerrors++;
1096 0 : printf("%s: watchdog timeout\n", sc->cue_dev.dv_xname);
1097 :
1098 0 : s = splusb();
1099 0 : c = &sc->cue_cdata.cue_tx_chain[0];
1100 0 : usbd_get_xfer_status(c->cue_xfer, NULL, NULL, NULL, &stat);
1101 0 : cue_txeof(c->cue_xfer, c, stat);
1102 :
1103 0 : if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
1104 0 : cue_start(ifp);
1105 0 : splx(s);
1106 0 : }
1107 :
1108 : /*
1109 : * Stop the adapter and free any mbufs allocated to the
1110 : * RX and TX lists.
1111 : */
1112 : void
1113 0 : 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 0 : ifp = GET_IFP(sc);
1122 0 : ifp->if_timer = 0;
1123 0 : ifp->if_flags &= ~IFF_RUNNING;
1124 0 : ifq_clr_oactive(&ifp->if_snd);
1125 :
1126 0 : cue_csr_write_1(sc, CUE_ETHCTL, 0);
1127 0 : cue_reset(sc);
1128 0 : timeout_del(&sc->cue_stat_ch);
1129 :
1130 : /* Stop transfers. */
1131 0 : if (sc->cue_ep[CUE_ENDPT_RX] != NULL) {
1132 0 : usbd_abort_pipe(sc->cue_ep[CUE_ENDPT_RX]);
1133 0 : err = usbd_close_pipe(sc->cue_ep[CUE_ENDPT_RX]);
1134 0 : if (err) {
1135 0 : printf("%s: close rx pipe failed: %s\n",
1136 0 : sc->cue_dev.dv_xname, usbd_errstr(err));
1137 0 : }
1138 0 : sc->cue_ep[CUE_ENDPT_RX] = NULL;
1139 0 : }
1140 :
1141 0 : if (sc->cue_ep[CUE_ENDPT_TX] != NULL) {
1142 0 : usbd_abort_pipe(sc->cue_ep[CUE_ENDPT_TX]);
1143 0 : err = usbd_close_pipe(sc->cue_ep[CUE_ENDPT_TX]);
1144 0 : if (err) {
1145 0 : printf("%s: close tx pipe failed: %s\n",
1146 0 : sc->cue_dev.dv_xname, usbd_errstr(err));
1147 0 : }
1148 0 : sc->cue_ep[CUE_ENDPT_TX] = NULL;
1149 0 : }
1150 :
1151 0 : if (sc->cue_ep[CUE_ENDPT_INTR] != NULL) {
1152 0 : usbd_abort_pipe(sc->cue_ep[CUE_ENDPT_INTR]);
1153 0 : err = usbd_close_pipe(sc->cue_ep[CUE_ENDPT_INTR]);
1154 0 : if (err) {
1155 0 : printf("%s: close intr pipe failed: %s\n",
1156 0 : sc->cue_dev.dv_xname, usbd_errstr(err));
1157 0 : }
1158 0 : sc->cue_ep[CUE_ENDPT_INTR] = NULL;
1159 0 : }
1160 :
1161 : /* Free RX resources. */
1162 0 : for (i = 0; i < CUE_RX_LIST_CNT; i++) {
1163 0 : if (sc->cue_cdata.cue_rx_chain[i].cue_mbuf != NULL) {
1164 0 : m_freem(sc->cue_cdata.cue_rx_chain[i].cue_mbuf);
1165 0 : sc->cue_cdata.cue_rx_chain[i].cue_mbuf = NULL;
1166 0 : }
1167 0 : if (sc->cue_cdata.cue_rx_chain[i].cue_xfer != NULL) {
1168 0 : usbd_free_xfer(sc->cue_cdata.cue_rx_chain[i].cue_xfer);
1169 0 : sc->cue_cdata.cue_rx_chain[i].cue_xfer = NULL;
1170 0 : }
1171 : }
1172 :
1173 : /* Free TX resources. */
1174 0 : for (i = 0; i < CUE_TX_LIST_CNT; i++) {
1175 0 : if (sc->cue_cdata.cue_tx_chain[i].cue_mbuf != NULL) {
1176 0 : m_freem(sc->cue_cdata.cue_tx_chain[i].cue_mbuf);
1177 0 : sc->cue_cdata.cue_tx_chain[i].cue_mbuf = NULL;
1178 0 : }
1179 0 : if (sc->cue_cdata.cue_tx_chain[i].cue_xfer != NULL) {
1180 0 : usbd_free_xfer(sc->cue_cdata.cue_tx_chain[i].cue_xfer);
1181 0 : sc->cue_cdata.cue_tx_chain[i].cue_xfer = NULL;
1182 0 : }
1183 : }
1184 0 : }
|