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