xref: /openbsd-src/sys/dev/usb/if_ugl.c (revision e5157e49389faebcb42b7237d55fbf096d9c2523)
1 /*	$OpenBSD: if_ugl.c,v 1.7 2014/07/13 15:52:49 mpi 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 #include <sys/kernel.h>
62 #include <sys/socket.h>
63 
64 #include <sys/device.h>
65 
66 #include <net/if.h>
67 #include <net/if_types.h>
68 #include <net/if_dl.h>
69 #include <net/netisr.h>
70 
71 #if NBPFILTER > 0
72 #include <net/bpf.h>
73 #endif
74 
75 #include <netinet/in.h>
76 #include <netinet/if_ether.h>
77 
78 #include <dev/usb/usb.h>
79 #include <dev/usb/usbdi.h>
80 #include <dev/usb/usbdi_util.h>
81 #include <dev/usb/usbdevs.h>
82 
83 #define UGL_INTR_PKTLEN		8
84 #define UGL_BULK_PKTLEN		64
85 
86 #define UGL_CONFIG_NO		1
87 #define UGL_IFACE_IDX		0
88 
89 /***/
90 
91 #define UGL_INTR_INTERVAL	20
92 
93 #define UGL_MAX_MTU		1514
94 #define UGL_BUFSZ		roundup(sizeof(struct ugl_packet), UGL_BULK_PKTLEN)
95 
96 #define UGL_RX_FRAMES		1	/* must be one */
97 #define UGL_TX_FRAMES		1	/* must be one */
98 
99 #define UGL_RX_LIST_CNT		1
100 #define UGL_TX_LIST_CNT		1
101 
102 #define UGL_ENDPT_RX		0x0
103 #define UGL_ENDPT_TX		0x1
104 #define UGL_ENDPT_INTR		0x2
105 #define UGL_ENDPT_MAX		0x3
106 
107 struct ugl_softc;
108 
109 struct ugl_packet {
110 	uDWord			pkt_count;
111 	uDWord			pkt_length;
112 	char			pkt_data[UGL_MAX_MTU];
113 } __packed;
114 
115 struct ugl_chain {
116 	struct ugl_softc	*ugl_sc;
117 	struct usbd_xfer	*ugl_xfer;
118 	struct ugl_packet	*ugl_buf;
119 	struct mbuf		*ugl_mbuf;
120 	int			ugl_idx;
121 };
122 
123 struct ugl_cdata {
124 	struct ugl_chain	ugl_tx_chain[UGL_TX_LIST_CNT];
125 	struct ugl_chain	ugl_rx_chain[UGL_RX_LIST_CNT];
126 	int			ugl_tx_prod;
127 	int			ugl_tx_cons;
128 	int			ugl_tx_cnt;
129 	int			ugl_rx_prod;
130 };
131 
132 struct ugl_softc {
133 	struct device		sc_dev;
134 
135 	struct arpcom		sc_arpcom;
136 #define GET_IFP(sc) (&(sc)->sc_arpcom.ac_if)
137 	struct timeout		sc_stat_ch;
138 
139 	struct usbd_device	*sc_udev;
140 	struct usbd_interface	*sc_iface;
141 	int			sc_ed[UGL_ENDPT_MAX];
142 	struct usbd_pipe	*sc_ep[UGL_ENDPT_MAX];
143 	struct ugl_cdata	sc_cdata;
144 
145 	uByte			sc_ibuf[UGL_INTR_PKTLEN];
146 
147 	u_int			sc_rx_errs;
148 	struct timeval		sc_rx_notice;
149 	u_int			sc_intr_errs;
150 };
151 
152 #ifdef UGL_DEBUG
153 #define DPRINTF(x)	do { if (ugldebug) printf x; } while (0)
154 #define DPRINTFN(n,x)	do { if (ugldebug >= (n)) printf x; } while (0)
155 int	ugldebug = 0;
156 #else
157 #define DPRINTF(x)
158 #define DPRINTFN(n,x)
159 #endif
160 
161 extern int ticks;
162 
163 /*
164  * Various supported device vendors/products.
165  */
166 struct usb_devno ugl_devs[] = {
167 	{ USB_VENDOR_GENESYS, USB_PRODUCT_GENESYS_GL620USB_A },
168 };
169 
170 int ugl_match(struct device *, void *, void *);
171 void ugl_attach(struct device *, struct device *, void *);
172 int ugl_detach(struct device *, int);
173 
174 struct cfdriver ugl_cd = {
175 	NULL, "ugl", DV_IFNET
176 };
177 
178 const struct cfattach ugl_ca = {
179 	sizeof(struct ugl_softc), ugl_match, ugl_attach, ugl_detach
180 };
181 
182 int ugl_openpipes(struct ugl_softc *);
183 int ugl_tx_list_init(struct ugl_softc *);
184 int ugl_rx_list_init(struct ugl_softc *);
185 int ugl_newbuf(struct ugl_softc *, struct ugl_chain *, struct mbuf *);
186 int ugl_send(struct ugl_softc *, struct mbuf *, int);
187 void ugl_intr(struct usbd_xfer *, void *, usbd_status);
188 void ugl_rxeof(struct usbd_xfer *, void *, usbd_status);
189 void ugl_txeof(struct usbd_xfer *, void *, usbd_status);
190 void ugl_start(struct ifnet *);
191 int ugl_ioctl(struct ifnet *, u_long, caddr_t);
192 void ugl_init(void *);
193 void ugl_stop(struct ugl_softc *);
194 void ugl_watchdog(struct ifnet *);
195 
196 /*
197  * Probe for a Genesys Logic chip.
198  */
199 int
200 ugl_match(struct device *parent, void *match, void *aux)
201 {
202 	struct usb_attach_arg		*uaa = aux;
203 
204 	if (uaa->iface != NULL)
205 		return (UMATCH_NONE);
206 
207 	return (usb_lookup(ugl_devs, uaa->vendor, uaa->product) != NULL ?
208 	    UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
209 }
210 
211 void
212 ugl_attach(struct device *parent, struct device *self, void *aux)
213 {
214 	struct ugl_softc	*sc = (struct ugl_softc *)self;
215 	struct usb_attach_arg	*uaa = aux;
216 	int			s;
217 	struct usbd_device	*dev = uaa->device;
218 	struct usbd_interface	*iface;
219 	usbd_status		err;
220 	struct ifnet		*ifp;
221 	usb_interface_descriptor_t	*id;
222 	usb_endpoint_descriptor_t	*ed;
223 	int			i;
224 	u_int16_t		macaddr_hi;
225 
226 	DPRINTFN(5,(" : ugl_attach: sc=%p, dev=%p", sc, dev));
227 
228 	err = usbd_set_config_no(dev, UGL_CONFIG_NO, 1);
229 	if (err) {
230 		printf("%s: setting config no failed\n",
231 		    sc->sc_dev.dv_xname);
232 		return;
233 	}
234 
235 	sc->sc_udev = dev;
236 
237 	err = usbd_device2interface_handle(dev, UGL_IFACE_IDX, &iface);
238 	if (err) {
239 		printf("%s: getting interface handle failed\n",
240 		    sc->sc_dev.dv_xname);
241 		return;
242 	}
243 
244 	sc->sc_iface = iface;
245 	id = usbd_get_interface_descriptor(iface);
246 
247 	/* Find endpoints. */
248 	for (i = 0; i < id->bNumEndpoints; i++) {
249 		ed = usbd_interface2endpoint_descriptor(iface, i);
250 		if (ed == NULL) {
251 			printf("%s: couldn't get ep %d\n",
252 			    sc->sc_dev.dv_xname, i);
253 			return;
254 		}
255 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
256 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
257 			sc->sc_ed[UGL_ENDPT_RX] = ed->bEndpointAddress;
258 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
259 			   UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
260 			sc->sc_ed[UGL_ENDPT_TX] = ed->bEndpointAddress;
261 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
262 			   UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
263 			sc->sc_ed[UGL_ENDPT_INTR] = ed->bEndpointAddress;
264 		}
265 	}
266 
267 	if (sc->sc_ed[UGL_ENDPT_RX] == 0 || sc->sc_ed[UGL_ENDPT_TX] == 0 ||
268 	    sc->sc_ed[UGL_ENDPT_INTR] == 0) {
269 		printf("%s: missing endpoint\n", sc->sc_dev.dv_xname);
270 		return;
271 	}
272 
273 	s = splnet();
274 
275 	macaddr_hi = htons(0x2acb);
276 	bcopy(&macaddr_hi, &sc->sc_arpcom.ac_enaddr[0], sizeof(u_int16_t));
277 	bcopy(&ticks, &sc->sc_arpcom.ac_enaddr[2], sizeof(u_int32_t));
278 	sc->sc_arpcom.ac_enaddr[5] = (u_int8_t)(sc->sc_dev.dv_unit);
279 
280 	printf("%s: address %s\n",
281 	    sc->sc_dev.dv_xname, ether_sprintf(sc->sc_arpcom.ac_enaddr));
282 
283 	/* Initialize interface info.*/
284 	ifp = GET_IFP(sc);
285 	ifp->if_softc = sc;
286 	ifp->if_hardmtu = UGL_MAX_MTU;
287 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
288 	ifp->if_ioctl = ugl_ioctl;
289 	ifp->if_start = ugl_start;
290 	ifp->if_watchdog = ugl_watchdog;
291 	strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
292 
293 	IFQ_SET_READY(&ifp->if_snd);
294 
295 	/* Attach the interface. */
296 	if_attach(ifp);
297 	ether_ifattach(ifp);
298 
299 	splx(s);
300 }
301 
302 int
303 ugl_detach(struct device *self, int flags)
304 {
305 	struct ugl_softc	*sc = (struct ugl_softc *)self;
306 	struct ifnet		*ifp = GET_IFP(sc);
307 	int			s;
308 
309 	DPRINTFN(2,("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
310 
311 	s = splusb();
312 
313 	if (ifp->if_flags & IFF_RUNNING)
314 		ugl_stop(sc);
315 
316 	if (ifp->if_softc != NULL)
317 		if_detach(ifp);
318 
319 #ifdef DIAGNOSTIC
320 	if (sc->sc_ep[UGL_ENDPT_TX] != NULL ||
321 	    sc->sc_ep[UGL_ENDPT_RX] != NULL ||
322 	    sc->sc_ep[UGL_ENDPT_INTR] != NULL)
323 		printf("%s: detach has active endpoints\n",
324 		       sc->sc_dev.dv_xname);
325 #endif
326 
327 	splx(s);
328 
329 	return (0);
330 }
331 
332 /*
333  * Initialize an RX descriptor and attach an MBUF cluster.
334  */
335 int
336 ugl_newbuf(struct ugl_softc *sc, struct ugl_chain *c, struct mbuf *m)
337 {
338 	struct mbuf		*m_new = NULL;
339 
340 	DPRINTFN(8,("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
341 
342 	if (m == NULL) {
343 		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
344 		if (m_new == NULL) {
345 			printf("%s: no memory for rx list "
346 			    "-- packet dropped!\n", sc->sc_dev.dv_xname);
347 			return (ENOBUFS);
348 		}
349 
350 		MCLGET(m_new, M_DONTWAIT);
351 		if (!(m_new->m_flags & M_EXT)) {
352 			printf("%s: no memory for rx list "
353 			    "-- packet dropped!\n", sc->sc_dev.dv_xname);
354 			m_freem(m_new);
355 			return (ENOBUFS);
356 		}
357 		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
358 	} else {
359 		m_new = m;
360 		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
361 		m_new->m_data = m_new->m_ext.ext_buf;
362 	}
363 
364 	c->ugl_mbuf = m_new;
365 
366 	return (0);
367 }
368 
369 int
370 ugl_rx_list_init(struct ugl_softc *sc)
371 {
372 	struct ugl_cdata	*cd;
373 	struct ugl_chain	*c;
374 	int			i;
375 
376 	DPRINTFN(5,("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
377 
378 	cd = &sc->sc_cdata;
379 	for (i = 0; i < UGL_RX_LIST_CNT; i++) {
380 		c = &cd->ugl_rx_chain[i];
381 		c->ugl_sc = sc;
382 		c->ugl_idx = i;
383 		if (ugl_newbuf(sc, c, NULL) == ENOBUFS)
384 			return (ENOBUFS);
385 		if (c->ugl_xfer == NULL) {
386 			c->ugl_xfer = usbd_alloc_xfer(sc->sc_udev);
387 			if (c->ugl_xfer == NULL)
388 				return (ENOBUFS);
389 			c->ugl_buf = usbd_alloc_buffer(c->ugl_xfer, UGL_BUFSZ);
390 			if (c->ugl_buf == NULL) {
391 				usbd_free_xfer(c->ugl_xfer);
392 				return (ENOBUFS);
393 			}
394 		}
395 	}
396 
397 	return (0);
398 }
399 
400 int
401 ugl_tx_list_init(struct ugl_softc *sc)
402 {
403 	struct ugl_cdata	*cd;
404 	struct ugl_chain	*c;
405 	int			i;
406 
407 	DPRINTFN(5,("%s: %s: enter\n", sc->sc_dev.dv_xname, __func__));
408 
409 	cd = &sc->sc_cdata;
410 	for (i = 0; i < UGL_TX_LIST_CNT; i++) {
411 		c = &cd->ugl_tx_chain[i];
412 		c->ugl_sc = sc;
413 		c->ugl_idx = i;
414 		c->ugl_mbuf = NULL;
415 		if (c->ugl_xfer == NULL) {
416 			c->ugl_xfer = usbd_alloc_xfer(sc->sc_udev);
417 			if (c->ugl_xfer == NULL)
418 				return (ENOBUFS);
419 			c->ugl_buf = usbd_alloc_buffer(c->ugl_xfer, UGL_BUFSZ);
420 			if (c->ugl_buf == NULL) {
421 				usbd_free_xfer(c->ugl_xfer);
422 				return (ENOBUFS);
423 			}
424 		}
425 	}
426 
427 	return (0);
428 }
429 
430 /*
431  * A frame has been uploaded: pass the resulting mbuf chain up to
432  * the higher level protocols.
433  */
434 void
435 ugl_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
436 {
437 	struct ugl_chain	*c = priv;
438 	struct ugl_softc	*sc = c->ugl_sc;
439 	struct ifnet		*ifp = GET_IFP(sc);
440 	struct mbuf		*m;
441 	int			total_len = 0;
442 	unsigned int		packet_len, packet_count;
443 	int			s;
444 
445 	if (usbd_is_dying(sc->sc_udev))
446 		return;
447 
448 	if (!(ifp->if_flags & IFF_RUNNING))
449 		return;
450 
451 	if (status != USBD_NORMAL_COMPLETION) {
452 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
453 			return;
454 		sc->sc_rx_errs++;
455 		if (usbd_ratecheck(&sc->sc_rx_notice)) {
456 			printf("%s: %u usb errors on rx: %s\n",
457 			    sc->sc_dev.dv_xname, sc->sc_rx_errs,
458 			    usbd_errstr(status));
459 			sc->sc_rx_errs = 0;
460 		}
461 		if (status == USBD_STALLED)
462 			usbd_clear_endpoint_stall_async(sc->sc_ep[UGL_ENDPT_RX]);
463 		goto done;
464 	}
465 
466 	usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
467 
468 	DPRINTFN(9,("%s: %s: enter status=%d length=%d\n",
469 		    sc->sc_dev.dv_xname, __func__, status, total_len));
470 
471 	if (total_len < offsetof(struct ugl_packet, pkt_data)) {
472 		printf("%s: bad header (length=%d)\n",
473 		    sc->sc_dev.dv_xname, total_len);
474 
475 		goto done;
476 	}
477 
478 	packet_count = UGETDW(c->ugl_buf->pkt_count);
479 	if (packet_count != UGL_RX_FRAMES) {
480 		printf("%s: bad packet count (%d)\n",
481 		    sc->sc_dev.dv_xname, packet_count);
482 
483 		if (packet_count == 0)
484 			goto done;
485 	}
486 
487 	packet_len = UGETDW(c->ugl_buf->pkt_length);
488 	if (total_len < packet_len) {
489 		printf("%s: bad packet size(%d), length=%d\n",
490 		    sc->sc_dev.dv_xname, packet_len, total_len);
491 
492 		if (packet_len == 0)
493 			goto done;
494 	}
495 
496 	m = c->ugl_mbuf;
497 	memcpy(mtod(c->ugl_mbuf, char *), c->ugl_buf->pkt_data, packet_len);
498 
499 	ifp->if_ipackets++;
500 	m->m_pkthdr.len = m->m_len = packet_len;
501 
502 	m->m_pkthdr.rcvif = ifp;
503 
504 	s = splnet();
505 
506 	/* XXX ugly */
507 	if (ugl_newbuf(sc, c, NULL) == ENOBUFS) {
508 		ifp->if_ierrors++;
509 		goto done1;
510 	}
511 
512 #if NBPFILTER > 0
513 	/*
514 	 * Handle BPF listeners. Let the BPF user see the packet, but
515 	 * don't pass it up to the ether_input() layer unless it's
516 	 * a broadcast packet, multicast packet, matches our ethernet
517 	 * address or the interface is in promiscuous mode.
518 	 */
519 	if (ifp->if_bpf) {
520 		bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
521 	}
522 #endif
523 
524 	DPRINTFN(10,("%s: %s: deliver %d\n", sc->sc_dev.dv_xname,
525 		    __func__, m->m_len));
526 
527 	ether_input_mbuf(ifp, m);
528 
529  done1:
530 	splx(s);
531 
532  done:
533 	/* Setup new transfer. */
534 	usbd_setup_xfer(c->ugl_xfer, sc->sc_ep[UGL_ENDPT_RX],
535 	    c, c->ugl_buf, UGL_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
536 	    USBD_NO_TIMEOUT, ugl_rxeof);
537 	usbd_transfer(c->ugl_xfer);
538 
539 	DPRINTFN(10,("%s: %s: start rx\n", sc->sc_dev.dv_xname,
540 		    __func__));
541 }
542 
543 /*
544  * A frame was downloaded to the chip. It's safe for us to clean up
545  * the list buffers.
546  */
547 void
548 ugl_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
549 {
550 	struct ugl_chain	*c = priv;
551 	struct ugl_softc	*sc = c->ugl_sc;
552 	struct ifnet		*ifp = GET_IFP(sc);
553 	int			s;
554 
555 	if (usbd_is_dying(sc->sc_udev))
556 		return;
557 
558 	s = splnet();
559 
560 	DPRINTFN(10,("%s: %s: enter status=%d\n", sc->sc_dev.dv_xname,
561 		    __func__, status));
562 
563 	ifp->if_timer = 0;
564 	ifp->if_flags &= ~IFF_OACTIVE;
565 
566 	if (status != USBD_NORMAL_COMPLETION) {
567 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
568 			splx(s);
569 			return;
570 		}
571 		ifp->if_oerrors++;
572 		printf("%s: usb error on tx: %s\n", sc->sc_dev.dv_xname,
573 		    usbd_errstr(status));
574 		if (status == USBD_STALLED)
575 			usbd_clear_endpoint_stall_async(sc->sc_ep[UGL_ENDPT_TX]);
576 		splx(s);
577 		return;
578 	}
579 
580 	ifp->if_opackets++;
581 
582 	m_freem(c->ugl_mbuf);
583 	c->ugl_mbuf = NULL;
584 
585 	if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
586 		ugl_start(ifp);
587 
588 	splx(s);
589 }
590 
591 int
592 ugl_send(struct ugl_softc *sc, struct mbuf *m, int idx)
593 {
594 	int			total_len;
595 	struct ugl_chain	*c;
596 	usbd_status		err;
597 
598 	c = &sc->sc_cdata.ugl_tx_chain[idx];
599 
600 	/*
601 	 * Copy the mbuf data into a contiguous buffer, leaving two
602 	 * bytes at the beginning to hold the frame length.
603 	 */
604 	USETDW(c->ugl_buf->pkt_count, UGL_TX_FRAMES);
605 	USETDW(c->ugl_buf->pkt_length, m->m_pkthdr.len);
606 	m_copydata(m, 0, m->m_pkthdr.len, c->ugl_buf->pkt_data);
607 	c->ugl_mbuf = m;
608 
609 	total_len = offsetof(struct ugl_packet, pkt_data[m->m_pkthdr.len]);
610 
611 	DPRINTFN(10,("%s: %s: total_len=%d\n",
612 		     sc->sc_dev.dv_xname, __func__, total_len));
613 
614 	usbd_setup_xfer(c->ugl_xfer, sc->sc_ep[UGL_ENDPT_TX],
615 	    c, c->ugl_buf, total_len, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
616 	    USBD_DEFAULT_TIMEOUT, ugl_txeof);
617 
618 	/* Transmit */
619 	err = usbd_transfer(c->ugl_xfer);
620 	if (err != USBD_IN_PROGRESS) {
621 		printf("%s: ugl_send error=%s\n", sc->sc_dev.dv_xname,
622 		       usbd_errstr(err));
623 		ugl_stop(sc);
624 		return (EIO);
625 	}
626 
627 	sc->sc_cdata.ugl_tx_cnt++;
628 
629 	return (0);
630 }
631 
632 void
633 ugl_start(struct ifnet *ifp)
634 {
635 	struct ugl_softc	*sc = ifp->if_softc;
636 	struct mbuf		*m_head = NULL;
637 
638 	if (usbd_is_dying(sc->sc_udev))
639 		return;
640 
641 	DPRINTFN(10,("%s: %s: enter\n", sc->sc_dev.dv_xname,__func__));
642 
643 	if (ifp->if_flags & IFF_OACTIVE)
644 		return;
645 
646 	IFQ_POLL(&ifp->if_snd, m_head);
647 	if (m_head == NULL)
648 		return;
649 
650 	if (ugl_send(sc, m_head, 0)) {
651 		ifp->if_flags |= IFF_OACTIVE;
652 		return;
653 	}
654 
655 	IFQ_DEQUEUE(&ifp->if_snd, m_head);
656 
657 #if NBPFILTER > 0
658 	/*
659 	 * If there's a BPF listener, bounce a copy of this frame
660 	 * to him.
661 	 */
662 	if (ifp->if_bpf)
663 		bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
664 #endif
665 
666 	ifp->if_flags |= IFF_OACTIVE;
667 
668 	/*
669 	 * Set a timeout in case the chip goes out to lunch.
670 	 */
671 	ifp->if_timer = 5;
672 }
673 
674 void
675 ugl_init(void *xsc)
676 {
677 	struct ugl_softc	*sc = xsc;
678 	struct ifnet		*ifp = GET_IFP(sc);
679 	int			s;
680 
681 	if (usbd_is_dying(sc->sc_udev))
682 		return;
683 
684 	DPRINTFN(10,("%s: %s: enter\n", sc->sc_dev.dv_xname,__func__));
685 
686 	s = splnet();
687 
688 	/* Init TX ring. */
689 	if (ugl_tx_list_init(sc) == ENOBUFS) {
690 		printf("%s: tx list init failed\n", sc->sc_dev.dv_xname);
691 		splx(s);
692 		return;
693 	}
694 
695 	/* Init RX ring. */
696 	if (ugl_rx_list_init(sc) == ENOBUFS) {
697 		printf("%s: rx list init failed\n", sc->sc_dev.dv_xname);
698 		splx(s);
699 		return;
700 	}
701 
702 	if (sc->sc_ep[UGL_ENDPT_RX] == NULL) {
703 		if (ugl_openpipes(sc)) {
704 			splx(s);
705 			return;
706 		}
707 	}
708 
709 	ifp->if_flags |= IFF_RUNNING;
710 	ifp->if_flags &= ~IFF_OACTIVE;
711 
712 	splx(s);
713 }
714 
715 int
716 ugl_openpipes(struct ugl_softc *sc)
717 {
718 	struct ugl_chain	*c;
719 	usbd_status		err;
720 	int			i;
721 
722 	/* Open RX and TX pipes. */
723 	err = usbd_open_pipe(sc->sc_iface, sc->sc_ed[UGL_ENDPT_RX],
724 	    USBD_EXCLUSIVE_USE, &sc->sc_ep[UGL_ENDPT_RX]);
725 	if (err) {
726 		printf("%s: open rx pipe failed: %s\n",
727 		    sc->sc_dev.dv_xname, usbd_errstr(err));
728 		return (EIO);
729 	}
730 	err = usbd_open_pipe(sc->sc_iface, sc->sc_ed[UGL_ENDPT_TX],
731 	    USBD_EXCLUSIVE_USE, &sc->sc_ep[UGL_ENDPT_TX]);
732 	if (err) {
733 		printf("%s: open tx pipe failed: %s\n",
734 		    sc->sc_dev.dv_xname, usbd_errstr(err));
735 		return (EIO);
736 	}
737 	err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ed[UGL_ENDPT_INTR],
738 	    USBD_EXCLUSIVE_USE, &sc->sc_ep[UGL_ENDPT_INTR], sc,
739 	    sc->sc_ibuf, UGL_INTR_PKTLEN, ugl_intr,
740 	    UGL_INTR_INTERVAL);
741 	if (err) {
742 		printf("%s: open intr pipe failed: %s\n",
743 		    sc->sc_dev.dv_xname, usbd_errstr(err));
744 		return (EIO);
745 	}
746 
747 	/* Start up the receive pipe. */
748 	for (i = 0; i < UGL_RX_LIST_CNT; i++) {
749 		c = &sc->sc_cdata.ugl_rx_chain[i];
750 		usbd_setup_xfer(c->ugl_xfer, sc->sc_ep[UGL_ENDPT_RX],
751 		    c, c->ugl_buf, UGL_BUFSZ,
752 		    USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
753 		    ugl_rxeof);
754 		usbd_transfer(c->ugl_xfer);
755 	}
756 
757 	return (0);
758 }
759 
760 void
761 ugl_intr(struct usbd_xfer *xfer, void *priv, usbd_status status)
762 {
763 	struct ugl_softc	*sc = priv;
764 	struct ifnet		*ifp = GET_IFP(sc);
765 	int			i;
766 
767 	DPRINTFN(15,("%s: %s: enter\n", sc->sc_dev.dv_xname,__func__));
768 
769 	if (usbd_is_dying(sc->sc_udev))
770 		return;
771 
772 	if (!(ifp->if_flags & IFF_RUNNING))
773 		return;
774 
775 	if (status != USBD_NORMAL_COMPLETION) {
776 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
777 			return;
778 		}
779 		sc->sc_intr_errs++;
780 		if (usbd_ratecheck(&sc->sc_rx_notice)) {
781 			printf("%s: %u usb errors on intr: %s\n",
782 			    sc->sc_dev.dv_xname, sc->sc_rx_errs,
783 			    usbd_errstr(status));
784 			sc->sc_intr_errs = 0;
785 		}
786 		if (status == USBD_STALLED)
787 			usbd_clear_endpoint_stall_async(sc->sc_ep[UGL_ENDPT_RX]);
788 		return;
789 	}
790 
791 	DPRINTFN(10,("%s: %s:", sc->sc_dev.dv_xname, __func__));
792 	for (i = 0; i < UGL_INTR_PKTLEN; i++)
793 		DPRINTFN(10,(" 0x%02x", sc->sc_ibuf[i]));
794 	DPRINTFN(10,("\n"));
795 
796 }
797 
798 int
799 ugl_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
800 {
801 	struct ugl_softc	*sc = ifp->if_softc;
802 	struct ifaddr 		*ifa = (struct ifaddr *)data;
803 	int			s, error = 0;
804 
805 	if (usbd_is_dying(sc->sc_udev))
806 		return (EIO);
807 
808 	DPRINTFN(5,("%s: %s: cmd=0x%08lx\n",
809 		    sc->sc_dev.dv_xname, __func__, command));
810 
811 	s = splnet();
812 
813 	switch(command) {
814 	case SIOCSIFADDR:
815 		ifp->if_flags |= IFF_UP;
816 		if (!(ifp->if_flags & IFF_RUNNING))
817 			ugl_init(sc);
818 #ifdef INET
819 		if (ifa->ifa_addr->sa_family == AF_INET)
820 			arp_ifinit(&sc->sc_arpcom, ifa);
821 #endif
822 		break;
823 
824 	case SIOCSIFFLAGS:
825 		if (ifp->if_flags & IFF_UP) {
826 			if (ifp->if_flags & IFF_RUNNING)
827 				error = ENETRESET;
828 			else
829 				ugl_init(sc);
830 		} else {
831 			if (ifp->if_flags & IFF_RUNNING)
832 				ugl_stop(sc);
833 		}
834 		break;
835 
836 	default:
837 		error = ether_ioctl(ifp, &sc->sc_arpcom, command, data);
838 		break;
839 	}
840 
841 	if (error == ENETRESET)
842 		error = 0;
843 
844 	splx(s);
845 	return (error);
846 }
847 
848 void
849 ugl_watchdog(struct ifnet *ifp)
850 {
851 	struct ugl_softc	*sc = ifp->if_softc;
852 
853 	if (usbd_is_dying(sc->sc_udev))
854 		return;
855 
856 	ifp->if_oerrors++;
857 	printf("%s: watchdog timeout\n", sc->sc_dev.dv_xname);
858 }
859 
860 /*
861  * Stop the adapter and free any mbufs allocated to the
862  * RX and TX lists.
863  */
864 void
865 ugl_stop(struct ugl_softc *sc)
866 {
867 	struct ifnet		*ifp;
868 	int			i;
869 
870 	DPRINTFN(10,("%s: %s: enter\n", sc->sc_dev.dv_xname,__func__));
871 
872 	ifp = GET_IFP(sc);
873 	ifp->if_timer = 0;
874 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
875 
876 	/* Stop transfers. */
877 	if (sc->sc_ep[UGL_ENDPT_RX] != NULL) {
878 		usbd_abort_pipe(sc->sc_ep[UGL_ENDPT_RX]);
879 		usbd_close_pipe(sc->sc_ep[UGL_ENDPT_RX]);
880 		sc->sc_ep[UGL_ENDPT_RX] = NULL;
881 	}
882 
883 	if (sc->sc_ep[UGL_ENDPT_TX] != NULL) {
884 		usbd_abort_pipe(sc->sc_ep[UGL_ENDPT_TX]);
885 		usbd_close_pipe(sc->sc_ep[UGL_ENDPT_TX]);
886 		sc->sc_ep[UGL_ENDPT_TX] = NULL;
887 	}
888 
889 	if (sc->sc_ep[UGL_ENDPT_INTR] != NULL) {
890 		usbd_abort_pipe(sc->sc_ep[UGL_ENDPT_INTR]);
891 		usbd_close_pipe(sc->sc_ep[UGL_ENDPT_INTR]);
892 		sc->sc_ep[UGL_ENDPT_INTR] = NULL;
893 	}
894 
895 	/* Free RX resources. */
896 	for (i = 0; i < UGL_RX_LIST_CNT; i++) {
897 		if (sc->sc_cdata.ugl_rx_chain[i].ugl_mbuf != NULL) {
898 			m_freem(sc->sc_cdata.ugl_rx_chain[i].ugl_mbuf);
899 			sc->sc_cdata.ugl_rx_chain[i].ugl_mbuf = NULL;
900 		}
901 		if (sc->sc_cdata.ugl_rx_chain[i].ugl_xfer != NULL) {
902 			usbd_free_xfer(sc->sc_cdata.ugl_rx_chain[i].ugl_xfer);
903 			sc->sc_cdata.ugl_rx_chain[i].ugl_xfer = NULL;
904 		}
905 	}
906 
907 	/* Free TX resources. */
908 	for (i = 0; i < UGL_TX_LIST_CNT; i++) {
909 		if (sc->sc_cdata.ugl_tx_chain[i].ugl_mbuf != NULL) {
910 			m_freem(sc->sc_cdata.ugl_tx_chain[i].ugl_mbuf);
911 			sc->sc_cdata.ugl_tx_chain[i].ugl_mbuf = NULL;
912 		}
913 		if (sc->sc_cdata.ugl_tx_chain[i].ugl_xfer != NULL) {
914 			usbd_free_xfer(sc->sc_cdata.ugl_tx_chain[i].ugl_xfer);
915 			sc->sc_cdata.ugl_tx_chain[i].ugl_xfer = NULL;
916 		}
917 	}
918 }
919