xref: /openbsd/sys/dev/usb/if_upl.c (revision 81508fe3)
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