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