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