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