Line data Source code
1 : /* $OpenBSD: if_kue.c,v 1.88 2017/04/08 02:57:25 deraadt Exp $ */
2 : /* $NetBSD: if_kue.c,v 1.50 2002/07/16 22:00:31 augustss Exp $ */
3 : /*
4 : * Copyright (c) 1997, 1998, 1999, 2000
5 : * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved.
6 : *
7 : * Redistribution and use in source and binary forms, with or without
8 : * modification, are permitted provided that the following conditions
9 : * are met:
10 : * 1. Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : * 2. Redistributions in binary form must reproduce the above copyright
13 : * notice, this list of conditions and the following disclaimer in the
14 : * documentation and/or other materials provided with the distribution.
15 : * 3. All advertising materials mentioning features or use of this software
16 : * must display the following acknowledgement:
17 : * This product includes software developed by Bill Paul.
18 : * 4. Neither the name of the author nor the names of any co-contributors
19 : * may be used to endorse or promote products derived from this software
20 : * without specific prior written permission.
21 : *
22 : * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
23 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 : * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
26 : * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 : * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 : * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 : * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 : * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32 : * THE POSSIBILITY OF SUCH DAMAGE.
33 : *
34 : * $FreeBSD: src/sys/dev/usb/if_kue.c,v 1.14 2000/01/14 01:36:15 wpaul Exp $
35 : */
36 :
37 : /*
38 : * Kawasaki LSI KL5KUSB101B USB to ethernet adapter driver.
39 : *
40 : * Written by Bill Paul <wpaul@ee.columbia.edu>
41 : * Electrical Engineering Department
42 : * Columbia University, New York City
43 : */
44 :
45 : /*
46 : * The KLSI USB to ethernet adapter chip contains an USB serial interface,
47 : * ethernet MAC and embedded microcontroller (called the QT Engine).
48 : * The chip must have firmware loaded into it before it will operate.
49 : * Packets are passed between the chip and host via bulk transfers.
50 : * There is an interrupt endpoint mentioned in the software spec, however
51 : * it's currently unused. This device is 10Mbps half-duplex only, hence
52 : * there is no media selection logic. The MAC supports a 128 entry
53 : * multicast filter, though the exact size of the filter can depend
54 : * on the firmware. Curiously, while the software spec describes various
55 : * ethernet statistics counters, my sample adapter and firmware combination
56 : * claims not to support any statistics counters at all.
57 : *
58 : * Note that once we load the firmware in the device, we have to be
59 : * careful not to load it again: if you restart your computer but
60 : * leave the adapter attached to the USB controller, it may remain
61 : * powered on and retain its firmware. In this case, we don't need
62 : * to load the firmware a second time.
63 : *
64 : * Special thanks to Rob Furr for providing an ADS Technologies
65 : * adapter for development and testing. No monkeys were harmed during
66 : * the development of this driver.
67 : */
68 :
69 : /*
70 : * Ported to NetBSD and somewhat rewritten by Lennart Augustsson.
71 : */
72 :
73 : #include "bpfilter.h"
74 :
75 : #include <sys/param.h>
76 : #include <sys/systm.h>
77 : #include <sys/sockio.h>
78 : #include <sys/mbuf.h>
79 : #include <sys/malloc.h>
80 : #include <sys/kernel.h>
81 : #include <sys/socket.h>
82 : #include <sys/device.h>
83 :
84 : #include <net/if.h>
85 :
86 : #if NBPFILTER > 0
87 : #include <net/bpf.h>
88 : #endif
89 :
90 : #include <netinet/in.h>
91 : #include <netinet/if_ether.h>
92 :
93 : #include <dev/usb/usb.h>
94 : #include <dev/usb/usbdi.h>
95 : #include <dev/usb/usbdi_util.h>
96 : #include <dev/usb/usbdevs.h>
97 :
98 : #include <dev/usb/if_kuereg.h>
99 : #include <dev/usb/if_kuevar.h>
100 :
101 : #ifdef KUE_DEBUG
102 : #define DPRINTF(x) do { if (kuedebug) printf x; } while (0)
103 : #define DPRINTFN(n,x) do { if (kuedebug >= (n)) printf x; } while (0)
104 : int kuedebug = 0;
105 : #else
106 : #define DPRINTF(x)
107 : #define DPRINTFN(n,x)
108 : #endif
109 :
110 : /*
111 : * Various supported device vendors/products.
112 : */
113 : const struct usb_devno kue_devs[] = {
114 : { USB_VENDOR_3COM, USB_PRODUCT_3COM_3C19250 },
115 : { USB_VENDOR_3COM, USB_PRODUCT_3COM_3C460 },
116 : { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_URE450 },
117 : { USB_VENDOR_ADS, USB_PRODUCT_ADS_UBS10BT },
118 : { USB_VENDOR_ADS, USB_PRODUCT_ADS_UBS10BTX },
119 : { USB_VENDOR_AOX, USB_PRODUCT_AOX_USB101 },
120 : { USB_VENDOR_ASANTE, USB_PRODUCT_ASANTE_EA },
121 : { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC10T },
122 : { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_DSB650C },
123 : { USB_VENDOR_COREGA, USB_PRODUCT_COREGA_ETHER_USB_T },
124 : { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DSB650C },
125 : { USB_VENDOR_ENTREGA, USB_PRODUCT_ENTREGA_E45 },
126 : { USB_VENDOR_ENTREGA, USB_PRODUCT_ENTREGA_XX1 },
127 : { USB_VENDOR_ENTREGA, USB_PRODUCT_ENTREGA_XX2 },
128 : { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBETT },
129 : { USB_VENDOR_JATON, USB_PRODUCT_JATON_EDA },
130 : { USB_VENDOR_KINGSTON, USB_PRODUCT_KINGSTON_XX1 },
131 : { USB_VENDOR_KLSI, USB_PRODUCT_KLSI_DUH3E10BT },
132 : { USB_VENDOR_KLSI, USB_PRODUCT_KLSI_DUH3E10BTN },
133 : { USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_USB10T },
134 : { USB_VENDOR_MOBILITY, USB_PRODUCT_MOBILITY_EA },
135 : { USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_EA101 },
136 : { USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_EA101X },
137 : { USB_VENDOR_PERACOM, USB_PRODUCT_PERACOM_ENET },
138 : { USB_VENDOR_PERACOM, USB_PRODUCT_PERACOM_ENET2 },
139 : { USB_VENDOR_PERACOM, USB_PRODUCT_PERACOM_ENET3 },
140 : { USB_VENDOR_PORTGEAR, USB_PRODUCT_PORTGEAR_EA8 },
141 : { USB_VENDOR_PORTGEAR, USB_PRODUCT_PORTGEAR_EA9 },
142 : { USB_VENDOR_PORTSMITH, USB_PRODUCT_PORTSMITH_EEA },
143 : { USB_VENDOR_SHARK, USB_PRODUCT_SHARK_PA },
144 : { USB_VENDOR_SILICOM, USB_PRODUCT_SILICOM_U2E },
145 : { USB_VENDOR_SILICOM, USB_PRODUCT_SILICOM_GPE },
146 : { USB_VENDOR_SMC, USB_PRODUCT_SMC_2102USB },
147 : };
148 :
149 : int kue_match(struct device *, void *, void *);
150 : void kue_attach(struct device *, struct device *, void *);
151 : int kue_detach(struct device *, int);
152 :
153 : struct cfdriver kue_cd = {
154 : NULL, "kue", DV_IFNET
155 : };
156 :
157 : const struct cfattach kue_ca = {
158 : sizeof(struct kue_softc), kue_match, kue_attach, kue_detach
159 : };
160 :
161 : int kue_tx_list_init(struct kue_softc *);
162 : int kue_rx_list_init(struct kue_softc *);
163 : int kue_newbuf(struct kue_softc *, struct kue_chain *,struct mbuf *);
164 : int kue_send(struct kue_softc *, struct mbuf *, int);
165 : int kue_open_pipes(struct kue_softc *);
166 : void kue_rxeof(struct usbd_xfer *, void *, usbd_status);
167 : void kue_txeof(struct usbd_xfer *, void *, usbd_status);
168 : void kue_start(struct ifnet *);
169 : int kue_ioctl(struct ifnet *, u_long, caddr_t);
170 : void kue_init(void *);
171 : void kue_stop(struct kue_softc *);
172 : void kue_watchdog(struct ifnet *);
173 :
174 : void kue_setmulti(struct kue_softc *);
175 : void kue_reset(struct kue_softc *);
176 :
177 : usbd_status kue_ctl(struct kue_softc *, int, u_int8_t,
178 : u_int16_t, void *, u_int32_t);
179 : usbd_status kue_setword(struct kue_softc *, u_int8_t, u_int16_t);
180 : int kue_load_fw(struct kue_softc *);
181 : void kue_attachhook(struct device *);
182 :
183 : usbd_status
184 0 : kue_setword(struct kue_softc *sc, u_int8_t breq, u_int16_t word)
185 : {
186 0 : usb_device_request_t req;
187 :
188 : DPRINTFN(10,("%s: %s: enter\n", sc->kue_dev.dv_xname,__func__));
189 :
190 0 : req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
191 0 : req.bRequest = breq;
192 0 : USETW(req.wValue, word);
193 0 : USETW(req.wIndex, 0);
194 0 : USETW(req.wLength, 0);
195 :
196 0 : return (usbd_do_request(sc->kue_udev, &req, NULL));
197 0 : }
198 :
199 : usbd_status
200 0 : kue_ctl(struct kue_softc *sc, int rw, u_int8_t breq, u_int16_t val,
201 : void *data, u_int32_t len)
202 : {
203 0 : usb_device_request_t req;
204 :
205 : DPRINTFN(10,("%s: %s: enter, len=%d\n", sc->kue_dev.dv_xname,
206 : __func__, len));
207 :
208 0 : if (rw == KUE_CTL_WRITE)
209 0 : req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
210 : else
211 0 : req.bmRequestType = UT_READ_VENDOR_DEVICE;
212 :
213 0 : req.bRequest = breq;
214 0 : USETW(req.wValue, val);
215 0 : USETW(req.wIndex, 0);
216 0 : USETW(req.wLength, len);
217 :
218 0 : return (usbd_do_request(sc->kue_udev, &req, data));
219 0 : }
220 :
221 : int
222 0 : kue_load_fw(struct kue_softc *sc)
223 : {
224 : usb_device_descriptor_t *dd;
225 : usbd_status err;
226 : struct kue_firmware *fw;
227 0 : u_char *buf;
228 0 : size_t buflen;
229 :
230 : DPRINTFN(1,("%s: %s: enter\n", sc->kue_dev.dv_xname, __func__));
231 :
232 : /*
233 : * First, check if we even need to load the firmware.
234 : * If the device was still attached when the system was
235 : * rebooted, it may already have firmware loaded in it.
236 : * If this is the case, we don't need to do it again.
237 : * And in fact, if we try to load it again, we'll hang,
238 : * so we have to avoid this condition if we don't want
239 : * to look stupid.
240 : *
241 : * We can test this quickly by checking the bcdRevision
242 : * code. The NIC will return a different revision code if
243 : * it's probed while the firmware is still loaded and
244 : * running.
245 : */
246 0 : if ((dd = usbd_get_device_descriptor(sc->kue_udev)) == NULL)
247 0 : return (EIO);
248 0 : if (UGETW(dd->bcdDevice) >= KUE_WARM_REV) {
249 0 : printf("%s: warm boot, no firmware download\n",
250 0 : sc->kue_dev.dv_xname);
251 0 : return (0);
252 : }
253 :
254 0 : err = loadfirmware("kue", &buf, &buflen);
255 0 : if (err) {
256 0 : printf("%s: failed loadfirmware of file %s: errno %d\n",
257 0 : sc->kue_dev.dv_xname, "kue", err);
258 0 : return (err);
259 : }
260 0 : fw = (struct kue_firmware *)buf;
261 :
262 0 : printf("%s: cold boot, downloading firmware\n",
263 0 : sc->kue_dev.dv_xname);
264 :
265 : /* Load code segment */
266 : DPRINTFN(1,("%s: kue_load_fw: download code_seg\n",
267 : sc->kue_dev.dv_xname));
268 0 : err = kue_ctl(sc, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN,
269 0 : 0, (void *)&fw->data[0], ntohl(fw->codeseglen));
270 0 : if (err) {
271 0 : printf("%s: failed to load code segment: %s\n",
272 0 : sc->kue_dev.dv_xname, usbd_errstr(err));
273 0 : free(buf, M_DEVBUF, buflen);
274 0 : return (EIO);
275 : }
276 :
277 : /* Load fixup segment */
278 : DPRINTFN(1,("%s: kue_load_fw: download fix_seg\n",
279 : sc->kue_dev.dv_xname));
280 0 : err = kue_ctl(sc, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN,
281 0 : 0, (void *)&fw->data[ntohl(fw->codeseglen)], ntohl(fw->fixseglen));
282 0 : if (err) {
283 0 : printf("%s: failed to load fixup segment: %s\n",
284 0 : sc->kue_dev.dv_xname, usbd_errstr(err));
285 0 : free(buf, M_DEVBUF, buflen);
286 0 : return (EIO);
287 : }
288 :
289 : /* Send trigger command. */
290 : DPRINTFN(1,("%s: kue_load_fw: download trig_seg\n",
291 : sc->kue_dev.dv_xname));
292 0 : err = kue_ctl(sc, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN,
293 0 : 0, (void *)&fw->data[ntohl(fw->codeseglen) + ntohl(fw->fixseglen)],
294 0 : ntohl(fw->trigseglen));
295 0 : if (err) {
296 0 : printf("%s: failed to load trigger segment: %s\n",
297 0 : sc->kue_dev.dv_xname, usbd_errstr(err));
298 0 : free(buf, M_DEVBUF, buflen);
299 0 : return (EIO);
300 : }
301 0 : free(buf, M_DEVBUF, buflen);
302 :
303 0 : usbd_delay_ms(sc->kue_udev, 10);
304 :
305 : /*
306 : * Reload device descriptor.
307 : * Why? The chip without the firmware loaded returns
308 : * one revision code. The chip with the firmware
309 : * loaded and running returns a *different* revision
310 : * code. This confuses the quirk mechanism, which is
311 : * dependent on the revision data.
312 : */
313 0 : (void)usbd_reload_device_desc(sc->kue_udev);
314 :
315 : DPRINTFN(1,("%s: %s: done\n", sc->kue_dev.dv_xname, __func__));
316 :
317 : /* Reset the adapter. */
318 0 : kue_reset(sc);
319 :
320 0 : return (0);
321 0 : }
322 :
323 : void
324 0 : kue_setmulti(struct kue_softc *sc)
325 : {
326 0 : struct arpcom *ac = &sc->arpcom;
327 0 : struct ifnet *ifp = GET_IFP(sc);
328 : struct ether_multi *enm;
329 : struct ether_multistep step;
330 : int i;
331 :
332 : DPRINTFN(5,("%s: %s: enter\n", sc->kue_dev.dv_xname, __func__));
333 :
334 0 : if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) {
335 : allmulti:
336 0 : ifp->if_flags |= IFF_ALLMULTI;
337 0 : sc->kue_rxfilt |= KUE_RXFILT_ALLMULTI;
338 0 : sc->kue_rxfilt &= ~KUE_RXFILT_MULTICAST;
339 0 : kue_setword(sc, KUE_CMD_SET_PKT_FILTER, sc->kue_rxfilt);
340 0 : return;
341 : }
342 :
343 0 : sc->kue_rxfilt &= ~KUE_RXFILT_ALLMULTI;
344 :
345 : i = 0;
346 0 : ETHER_FIRST_MULTI(step, ac, enm);
347 0 : while (enm != NULL) {
348 0 : if (i == KUE_MCFILTCNT(sc))
349 : goto allmulti;
350 :
351 0 : memcpy(KUE_MCFILT(sc, i), enm->enm_addrlo, ETHER_ADDR_LEN);
352 0 : ETHER_NEXT_MULTI(step, enm);
353 0 : i++;
354 : }
355 :
356 0 : ifp->if_flags &= ~IFF_ALLMULTI;
357 :
358 0 : sc->kue_rxfilt |= KUE_RXFILT_MULTICAST;
359 0 : kue_ctl(sc, KUE_CTL_WRITE, KUE_CMD_SET_MCAST_FILTERS,
360 0 : i, sc->kue_mcfilters, i * ETHER_ADDR_LEN);
361 :
362 0 : kue_setword(sc, KUE_CMD_SET_PKT_FILTER, sc->kue_rxfilt);
363 0 : }
364 :
365 : /*
366 : * Issue a SET_CONFIGURATION command to reset the MAC. This should be
367 : * done after the firmware is loaded into the adapter in order to
368 : * bring it into proper operation.
369 : */
370 : void
371 0 : kue_reset(struct kue_softc *sc)
372 : {
373 : DPRINTFN(5,("%s: %s: enter\n", sc->kue_dev.dv_xname, __func__));
374 :
375 0 : if (usbd_set_config_no(sc->kue_udev, KUE_CONFIG_NO, 1) ||
376 0 : usbd_device2interface_handle(sc->kue_udev, KUE_IFACE_IDX,
377 0 : &sc->kue_iface))
378 0 : printf("%s: reset failed\n", sc->kue_dev.dv_xname);
379 :
380 : /* Wait a little while for the chip to get its brains in order. */
381 0 : usbd_delay_ms(sc->kue_udev, 10);
382 0 : }
383 :
384 : /*
385 : * Probe for a KLSI chip.
386 : */
387 : int
388 0 : kue_match(struct device *parent, void *match, void *aux)
389 : {
390 0 : struct usb_attach_arg *uaa = aux;
391 :
392 : DPRINTFN(25,("kue_match: enter\n"));
393 :
394 0 : if (uaa->iface != NULL)
395 0 : return (UMATCH_NONE);
396 :
397 0 : return (usb_lookup(kue_devs, uaa->vendor, uaa->product) != NULL ?
398 : UMATCH_VENDOR_PRODUCT : UMATCH_NONE);
399 0 : }
400 :
401 : void
402 0 : kue_attachhook(struct device *self)
403 : {
404 0 : struct kue_softc *sc = (struct kue_softc *)self;
405 : int s;
406 : struct ifnet *ifp;
407 0 : struct usbd_device *dev = sc->kue_udev;
408 0 : struct usbd_interface *iface;
409 : usbd_status err;
410 : usb_interface_descriptor_t *id;
411 : usb_endpoint_descriptor_t *ed;
412 : int i;
413 :
414 : /* Load the firmware into the NIC. */
415 0 : if (kue_load_fw(sc)) {
416 0 : printf("%s: loading firmware failed\n",
417 0 : sc->kue_dev.dv_xname);
418 0 : return;
419 : }
420 :
421 0 : err = usbd_device2interface_handle(dev, KUE_IFACE_IDX, &iface);
422 0 : if (err) {
423 0 : printf("%s: getting interface handle failed\n",
424 0 : sc->kue_dev.dv_xname);
425 0 : return;
426 : }
427 :
428 0 : sc->kue_iface = iface;
429 0 : id = usbd_get_interface_descriptor(iface);
430 :
431 : /* Find endpoints. */
432 0 : for (i = 0; i < id->bNumEndpoints; i++) {
433 0 : ed = usbd_interface2endpoint_descriptor(iface, i);
434 0 : if (ed == NULL) {
435 0 : printf("%s: couldn't get ep %d\n",
436 0 : sc->kue_dev.dv_xname, i);
437 0 : return;
438 : }
439 0 : if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
440 0 : UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
441 0 : sc->kue_ed[KUE_ENDPT_RX] = ed->bEndpointAddress;
442 0 : } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
443 0 : UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
444 0 : sc->kue_ed[KUE_ENDPT_TX] = ed->bEndpointAddress;
445 0 : } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
446 0 : UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
447 0 : sc->kue_ed[KUE_ENDPT_INTR] = ed->bEndpointAddress;
448 0 : }
449 : }
450 :
451 0 : if (sc->kue_ed[KUE_ENDPT_RX] == 0 || sc->kue_ed[KUE_ENDPT_TX] == 0) {
452 0 : printf("%s: missing endpoint\n", sc->kue_dev.dv_xname);
453 0 : return;
454 : }
455 :
456 : /* Read ethernet descriptor */
457 0 : err = kue_ctl(sc, KUE_CTL_READ, KUE_CMD_GET_ETHER_DESCRIPTOR,
458 0 : 0, &sc->kue_desc, sizeof(sc->kue_desc));
459 0 : if (err) {
460 0 : printf("%s: could not read Ethernet descriptor\n",
461 0 : sc->kue_dev.dv_xname);
462 0 : return;
463 : }
464 :
465 0 : sc->kue_mcfilters = mallocarray(KUE_MCFILTCNT(sc), ETHER_ADDR_LEN,
466 : M_USBDEV, M_NOWAIT);
467 0 : if (sc->kue_mcfilters == NULL) {
468 0 : printf("%s: no memory for multicast filter buffer\n",
469 0 : sc->kue_dev.dv_xname);
470 0 : return;
471 : }
472 0 : sc->kue_mcfilterslen = KUE_MCFILTCNT(sc);
473 :
474 0 : s = splnet();
475 :
476 : /*
477 : * A KLSI chip was detected. Inform the world.
478 : */
479 0 : printf("%s: address %s\n", sc->kue_dev.dv_xname,
480 0 : ether_sprintf(sc->kue_desc.kue_macaddr));
481 :
482 0 : bcopy(sc->kue_desc.kue_macaddr,
483 0 : (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
484 :
485 : /* Initialize interface info.*/
486 0 : ifp = GET_IFP(sc);
487 0 : ifp->if_softc = sc;
488 0 : ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
489 0 : ifp->if_ioctl = kue_ioctl;
490 0 : ifp->if_start = kue_start;
491 0 : ifp->if_watchdog = kue_watchdog;
492 0 : strlcpy(ifp->if_xname, sc->kue_dev.dv_xname, IFNAMSIZ);
493 :
494 : /* Attach the interface. */
495 0 : if_attach(ifp);
496 0 : ether_ifattach(ifp);
497 :
498 0 : sc->kue_attached = 1;
499 0 : splx(s);
500 :
501 0 : }
502 :
503 : /*
504 : * Attach the interface. Allocate softc structures, do
505 : * setup and ethernet/BPF attach.
506 : */
507 : void
508 0 : kue_attach(struct device *parent, struct device *self, void *aux)
509 : {
510 0 : struct kue_softc *sc = (struct kue_softc *)self;
511 0 : struct usb_attach_arg *uaa = aux;
512 0 : struct usbd_device *dev = uaa->device;
513 : usbd_status err;
514 :
515 : DPRINTFN(5,(" : kue_attach: sc=%p, dev=%p", sc, dev));
516 :
517 0 : err = usbd_set_config_no(dev, KUE_CONFIG_NO, 1);
518 0 : if (err) {
519 0 : printf("%s: setting config no failed\n",
520 0 : sc->kue_dev.dv_xname);
521 0 : return;
522 : }
523 :
524 0 : sc->kue_udev = dev;
525 0 : sc->kue_product = uaa->product;
526 0 : sc->kue_vendor = uaa->vendor;
527 :
528 0 : config_mountroot(self, kue_attachhook);
529 0 : }
530 :
531 : int
532 0 : kue_detach(struct device *self, int flags)
533 : {
534 0 : struct kue_softc *sc = (struct kue_softc *)self;
535 0 : struct ifnet *ifp = GET_IFP(sc);
536 : int s;
537 :
538 : /* Detached before attached finished, so just bail out. */
539 0 : if (!sc->kue_attached)
540 0 : return (0);
541 :
542 0 : s = splusb(); /* XXX why? */
543 :
544 0 : if (sc->kue_mcfilters != NULL) {
545 0 : free(sc->kue_mcfilters, M_USBDEV, sc->kue_mcfilterslen);
546 0 : sc->kue_mcfilters = NULL;
547 0 : }
548 :
549 0 : if (ifp->if_flags & IFF_RUNNING)
550 0 : kue_stop(sc);
551 :
552 0 : if (ifp->if_softc != NULL) {
553 0 : ether_ifdetach(ifp);
554 0 : if_detach(ifp);
555 0 : }
556 :
557 : #ifdef DIAGNOSTIC
558 0 : if (sc->kue_ep[KUE_ENDPT_TX] != NULL ||
559 0 : sc->kue_ep[KUE_ENDPT_RX] != NULL ||
560 0 : sc->kue_ep[KUE_ENDPT_INTR] != NULL)
561 0 : printf("%s: detach has active endpoints\n",
562 0 : sc->kue_dev.dv_xname);
563 : #endif
564 :
565 0 : sc->kue_attached = 0;
566 0 : splx(s);
567 :
568 0 : return (0);
569 0 : }
570 :
571 : /*
572 : * Initialize an RX descriptor and attach an MBUF cluster.
573 : */
574 : int
575 0 : kue_newbuf(struct kue_softc *sc, struct kue_chain *c, struct mbuf *m)
576 : {
577 : struct mbuf *m_new = NULL;
578 :
579 : DPRINTFN(10,("%s: %s: enter\n", sc->kue_dev.dv_xname,__func__));
580 :
581 0 : if (m == NULL) {
582 0 : MGETHDR(m_new, M_DONTWAIT, MT_DATA);
583 0 : if (m_new == NULL) {
584 0 : printf("%s: no memory for rx list "
585 0 : "-- packet dropped!\n", sc->kue_dev.dv_xname);
586 0 : return (ENOBUFS);
587 : }
588 :
589 0 : MCLGET(m_new, M_DONTWAIT);
590 0 : if (!(m_new->m_flags & M_EXT)) {
591 0 : printf("%s: no memory for rx list "
592 0 : "-- packet dropped!\n", sc->kue_dev.dv_xname);
593 0 : m_freem(m_new);
594 0 : return (ENOBUFS);
595 : }
596 0 : m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
597 0 : } else {
598 : m_new = m;
599 0 : m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
600 0 : m_new->m_data = m_new->m_ext.ext_buf;
601 : }
602 :
603 0 : c->kue_mbuf = m_new;
604 :
605 0 : return (0);
606 0 : }
607 :
608 : int
609 0 : kue_rx_list_init(struct kue_softc *sc)
610 : {
611 : struct kue_cdata *cd;
612 : struct kue_chain *c;
613 : int i;
614 :
615 : DPRINTFN(5,("%s: %s: enter\n", sc->kue_dev.dv_xname, __func__));
616 :
617 0 : cd = &sc->kue_cdata;
618 0 : for (i = 0; i < KUE_RX_LIST_CNT; i++) {
619 0 : c = &cd->kue_rx_chain[i];
620 0 : c->kue_sc = sc;
621 0 : c->kue_idx = i;
622 0 : if (kue_newbuf(sc, c, NULL) == ENOBUFS)
623 0 : return (ENOBUFS);
624 0 : if (c->kue_xfer == NULL) {
625 0 : c->kue_xfer = usbd_alloc_xfer(sc->kue_udev);
626 0 : if (c->kue_xfer == NULL)
627 0 : return (ENOBUFS);
628 0 : c->kue_buf = usbd_alloc_buffer(c->kue_xfer, KUE_BUFSZ);
629 0 : if (c->kue_buf == NULL)
630 0 : return (ENOBUFS); /* XXX free xfer */
631 : }
632 : }
633 :
634 0 : return (0);
635 0 : }
636 :
637 : int
638 0 : kue_tx_list_init(struct kue_softc *sc)
639 : {
640 : struct kue_cdata *cd;
641 : struct kue_chain *c;
642 : int i;
643 :
644 : DPRINTFN(5,("%s: %s: enter\n", sc->kue_dev.dv_xname, __func__));
645 :
646 0 : cd = &sc->kue_cdata;
647 0 : for (i = 0; i < KUE_TX_LIST_CNT; i++) {
648 0 : c = &cd->kue_tx_chain[i];
649 0 : c->kue_sc = sc;
650 0 : c->kue_idx = i;
651 0 : c->kue_mbuf = NULL;
652 0 : if (c->kue_xfer == NULL) {
653 0 : c->kue_xfer = usbd_alloc_xfer(sc->kue_udev);
654 0 : if (c->kue_xfer == NULL)
655 0 : return (ENOBUFS);
656 0 : c->kue_buf = usbd_alloc_buffer(c->kue_xfer, KUE_BUFSZ);
657 0 : if (c->kue_buf == NULL)
658 0 : return (ENOBUFS);
659 : }
660 : }
661 :
662 0 : return (0);
663 0 : }
664 :
665 : /*
666 : * A frame has been uploaded: pass the resulting mbuf chain up to
667 : * the higher level protocols.
668 : */
669 : void
670 0 : kue_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
671 : {
672 0 : struct kue_chain *c = priv;
673 0 : struct kue_softc *sc = c->kue_sc;
674 0 : struct ifnet *ifp = GET_IFP(sc);
675 0 : struct mbuf_list ml = MBUF_LIST_INITIALIZER();
676 : struct mbuf *m;
677 0 : int total_len = 0;
678 : int s;
679 :
680 : DPRINTFN(10,("%s: %s: enter status=%d\n", sc->kue_dev.dv_xname,
681 : __func__, status));
682 :
683 0 : if (usbd_is_dying(sc->kue_udev))
684 0 : return;
685 :
686 0 : if (!(ifp->if_flags & IFF_RUNNING))
687 0 : return;
688 :
689 0 : if (status != USBD_NORMAL_COMPLETION) {
690 0 : if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
691 0 : return;
692 0 : sc->kue_rx_errs++;
693 0 : if (usbd_ratecheck(&sc->kue_rx_notice)) {
694 0 : printf("%s: %u usb errors on rx: %s\n",
695 0 : sc->kue_dev.dv_xname, sc->kue_rx_errs,
696 0 : usbd_errstr(status));
697 0 : sc->kue_rx_errs = 0;
698 0 : }
699 0 : if (status == USBD_STALLED)
700 0 : usbd_clear_endpoint_stall_async(sc->kue_ep[KUE_ENDPT_RX]);
701 : goto done;
702 : }
703 :
704 0 : usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
705 :
706 : DPRINTFN(10,("%s: %s: total_len=%d len=%d\n", sc->kue_dev.dv_xname,
707 : __func__, total_len,
708 : UGETW(mtod(c->kue_mbuf, u_int8_t *))));
709 :
710 0 : if (total_len <= 1)
711 : goto done;
712 :
713 0 : m = c->kue_mbuf;
714 : /* copy data to mbuf */
715 0 : memcpy(mtod(m, char *), c->kue_buf, total_len);
716 :
717 : /* No errors; receive the packet. */
718 0 : total_len = UGETW(mtod(m, u_int8_t *));
719 0 : m_adj(m, sizeof(u_int16_t));
720 :
721 0 : if (total_len < sizeof(struct ether_header)) {
722 0 : ifp->if_ierrors++;
723 0 : goto done;
724 : }
725 :
726 0 : m->m_pkthdr.len = m->m_len = total_len;
727 0 : ml_enqueue(&ml, m);
728 :
729 0 : if (kue_newbuf(sc, c, NULL) == ENOBUFS) {
730 0 : ifp->if_ierrors++;
731 0 : goto done;
732 : }
733 :
734 0 : s = splnet();
735 0 : if_input(ifp, &ml);
736 0 : splx(s);
737 :
738 : done:
739 :
740 : /* Setup new transfer. */
741 0 : usbd_setup_xfer(c->kue_xfer, sc->kue_ep[KUE_ENDPT_RX],
742 0 : c, c->kue_buf, KUE_BUFSZ, USBD_SHORT_XFER_OK | USBD_NO_COPY,
743 : USBD_NO_TIMEOUT, kue_rxeof);
744 0 : usbd_transfer(c->kue_xfer);
745 :
746 : DPRINTFN(10,("%s: %s: start rx\n", sc->kue_dev.dv_xname,
747 : __func__));
748 0 : }
749 :
750 : /*
751 : * A frame was downloaded to the chip. It's safe for us to clean up
752 : * the list buffers.
753 : */
754 :
755 : void
756 0 : kue_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
757 : {
758 0 : struct kue_chain *c = priv;
759 0 : struct kue_softc *sc = c->kue_sc;
760 0 : struct ifnet *ifp = GET_IFP(sc);
761 : int s;
762 :
763 0 : if (usbd_is_dying(sc->kue_udev))
764 0 : return;
765 :
766 0 : s = splnet();
767 :
768 : DPRINTFN(10,("%s: %s: enter status=%d\n", sc->kue_dev.dv_xname,
769 : __func__, status));
770 :
771 0 : ifp->if_timer = 0;
772 0 : ifq_clr_oactive(&ifp->if_snd);
773 :
774 0 : if (status != USBD_NORMAL_COMPLETION) {
775 0 : if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
776 0 : splx(s);
777 0 : return;
778 : }
779 0 : ifp->if_oerrors++;
780 0 : printf("%s: usb error on tx: %s\n", sc->kue_dev.dv_xname,
781 0 : usbd_errstr(status));
782 0 : if (status == USBD_STALLED)
783 0 : usbd_clear_endpoint_stall_async(sc->kue_ep[KUE_ENDPT_TX]);
784 0 : splx(s);
785 0 : return;
786 : }
787 :
788 0 : m_freem(c->kue_mbuf);
789 0 : c->kue_mbuf = NULL;
790 :
791 0 : if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
792 0 : kue_start(ifp);
793 :
794 0 : splx(s);
795 0 : }
796 :
797 : int
798 0 : kue_send(struct kue_softc *sc, struct mbuf *m, int idx)
799 : {
800 : int total_len;
801 : struct kue_chain *c;
802 : usbd_status err;
803 :
804 : DPRINTFN(10,("%s: %s: enter\n", sc->kue_dev.dv_xname,__func__));
805 :
806 0 : c = &sc->kue_cdata.kue_tx_chain[idx];
807 :
808 : /*
809 : * Copy the mbuf data into a contiguous buffer, leaving two
810 : * bytes at the beginning to hold the frame length.
811 : */
812 0 : m_copydata(m, 0, m->m_pkthdr.len, c->kue_buf + 2);
813 0 : c->kue_mbuf = m;
814 :
815 0 : total_len = m->m_pkthdr.len + 2;
816 : /* XXX what's this? */
817 0 : total_len += 64 - (total_len % 64);
818 :
819 : /* Frame length is specified in the first 2 bytes of the buffer. */
820 0 : c->kue_buf[0] = (u_int8_t)m->m_pkthdr.len;
821 0 : c->kue_buf[1] = (u_int8_t)(m->m_pkthdr.len >> 8);
822 :
823 0 : usbd_setup_xfer(c->kue_xfer, sc->kue_ep[KUE_ENDPT_TX],
824 0 : c, c->kue_buf, total_len, USBD_NO_COPY, USBD_DEFAULT_TIMEOUT,
825 : kue_txeof);
826 :
827 : /* Transmit */
828 0 : err = usbd_transfer(c->kue_xfer);
829 0 : if (err != USBD_IN_PROGRESS) {
830 0 : printf("%s: kue_send error=%s\n", sc->kue_dev.dv_xname,
831 0 : usbd_errstr(err));
832 0 : kue_stop(sc);
833 0 : return (EIO);
834 : }
835 :
836 0 : sc->kue_cdata.kue_tx_cnt++;
837 :
838 0 : return (0);
839 0 : }
840 :
841 : void
842 0 : kue_start(struct ifnet *ifp)
843 : {
844 0 : struct kue_softc *sc = ifp->if_softc;
845 : struct mbuf *m_head = NULL;
846 :
847 : DPRINTFN(10,("%s: %s: enter\n", sc->kue_dev.dv_xname,__func__));
848 :
849 0 : if (usbd_is_dying(sc->kue_udev))
850 0 : return;
851 :
852 0 : if (ifq_is_oactive(&ifp->if_snd))
853 0 : return;
854 :
855 0 : m_head = ifq_deq_begin(&ifp->if_snd);
856 0 : if (m_head == NULL)
857 0 : return;
858 :
859 0 : if (kue_send(sc, m_head, 0)) {
860 0 : ifq_deq_rollback(&ifp->if_snd, m_head);
861 0 : ifq_set_oactive(&ifp->if_snd);
862 0 : return;
863 : }
864 :
865 0 : ifq_deq_commit(&ifp->if_snd, m_head);
866 :
867 : #if NBPFILTER > 0
868 : /*
869 : * If there's a BPF listener, bounce a copy of this frame
870 : * to him.
871 : */
872 0 : if (ifp->if_bpf)
873 0 : bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
874 : #endif
875 :
876 0 : ifq_set_oactive(&ifp->if_snd);
877 :
878 : /*
879 : * Set a timeout in case the chip goes out to lunch.
880 : */
881 0 : ifp->if_timer = 6;
882 0 : }
883 :
884 : void
885 0 : kue_init(void *xsc)
886 : {
887 0 : struct kue_softc *sc = xsc;
888 0 : struct ifnet *ifp = GET_IFP(sc);
889 : int s;
890 : u_char *eaddr;
891 :
892 : DPRINTFN(5,("%s: %s: enter\n", sc->kue_dev.dv_xname,__func__));
893 :
894 0 : if (ifp->if_flags & IFF_RUNNING)
895 0 : return;
896 :
897 0 : s = splnet();
898 :
899 0 : eaddr = sc->arpcom.ac_enaddr;
900 : /* Set MAC address */
901 0 : kue_ctl(sc, KUE_CTL_WRITE, KUE_CMD_SET_MAC, 0, eaddr, ETHER_ADDR_LEN);
902 :
903 0 : sc->kue_rxfilt = KUE_RXFILT_UNICAST | KUE_RXFILT_BROADCAST;
904 :
905 : /* If we want promiscuous mode, set the allframes bit. */
906 0 : if (ifp->if_flags & IFF_PROMISC)
907 0 : sc->kue_rxfilt |= KUE_RXFILT_PROMISC;
908 :
909 0 : kue_setword(sc, KUE_CMD_SET_PKT_FILTER, sc->kue_rxfilt);
910 :
911 : /* I'm not sure how to tune these. */
912 : #if 0
913 : /*
914 : * Leave this one alone for now; setting it
915 : * wrong causes lockups on some machines/controllers.
916 : */
917 : kue_setword(sc, KUE_CMD_SET_SOFS, 1);
918 : #endif
919 0 : kue_setword(sc, KUE_CMD_SET_URB_SIZE, 64);
920 :
921 : /* Init TX ring. */
922 0 : if (kue_tx_list_init(sc) == ENOBUFS) {
923 0 : printf("%s: tx list init failed\n", sc->kue_dev.dv_xname);
924 0 : splx(s);
925 0 : return;
926 : }
927 :
928 : /* Init RX ring. */
929 0 : if (kue_rx_list_init(sc) == ENOBUFS) {
930 0 : printf("%s: rx list init failed\n", sc->kue_dev.dv_xname);
931 0 : splx(s);
932 0 : return;
933 : }
934 :
935 : /* Load the multicast filter. */
936 0 : kue_setmulti(sc);
937 :
938 0 : if (sc->kue_ep[KUE_ENDPT_RX] == NULL) {
939 0 : if (kue_open_pipes(sc)) {
940 0 : splx(s);
941 0 : return;
942 : }
943 : }
944 :
945 0 : ifp->if_flags |= IFF_RUNNING;
946 0 : ifq_clr_oactive(&ifp->if_snd);
947 :
948 0 : splx(s);
949 0 : }
950 :
951 : int
952 0 : kue_open_pipes(struct kue_softc *sc)
953 : {
954 : usbd_status err;
955 : struct kue_chain *c;
956 : int i;
957 :
958 : DPRINTFN(5,("%s: %s: enter\n", sc->kue_dev.dv_xname,__func__));
959 :
960 : /* Open RX and TX pipes. */
961 0 : err = usbd_open_pipe(sc->kue_iface, sc->kue_ed[KUE_ENDPT_RX],
962 0 : USBD_EXCLUSIVE_USE, &sc->kue_ep[KUE_ENDPT_RX]);
963 0 : if (err) {
964 0 : printf("%s: open rx pipe failed: %s\n",
965 0 : sc->kue_dev.dv_xname, usbd_errstr(err));
966 0 : return (EIO);
967 : }
968 :
969 0 : err = usbd_open_pipe(sc->kue_iface, sc->kue_ed[KUE_ENDPT_TX],
970 0 : USBD_EXCLUSIVE_USE, &sc->kue_ep[KUE_ENDPT_TX]);
971 0 : if (err) {
972 0 : printf("%s: open tx pipe failed: %s\n",
973 0 : sc->kue_dev.dv_xname, usbd_errstr(err));
974 0 : return (EIO);
975 : }
976 :
977 : /* Start up the receive pipe. */
978 0 : for (i = 0; i < KUE_RX_LIST_CNT; i++) {
979 0 : c = &sc->kue_cdata.kue_rx_chain[i];
980 0 : usbd_setup_xfer(c->kue_xfer, sc->kue_ep[KUE_ENDPT_RX],
981 0 : c, c->kue_buf, KUE_BUFSZ,
982 : USBD_SHORT_XFER_OK | USBD_NO_COPY, USBD_NO_TIMEOUT,
983 : kue_rxeof);
984 : DPRINTFN(5,("%s: %s: start read\n", sc->kue_dev.dv_xname,
985 : __func__));
986 0 : usbd_transfer(c->kue_xfer);
987 : }
988 :
989 0 : return (0);
990 0 : }
991 :
992 : int
993 0 : kue_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
994 : {
995 0 : struct kue_softc *sc = ifp->if_softc;
996 : int s, error = 0;
997 :
998 : DPRINTFN(5,("%s: %s: enter\n", sc->kue_dev.dv_xname,__func__));
999 :
1000 0 : if (usbd_is_dying(sc->kue_udev))
1001 0 : return (EIO);
1002 :
1003 : #ifdef DIAGNOSTIC
1004 0 : if (!curproc) {
1005 0 : printf("%s: no proc!!\n", sc->kue_dev.dv_xname);
1006 0 : return EIO;
1007 : }
1008 : #endif
1009 :
1010 0 : s = splnet();
1011 :
1012 0 : switch(command) {
1013 : case SIOCSIFADDR:
1014 0 : ifp->if_flags |= IFF_UP;
1015 0 : kue_init(sc);
1016 0 : break;
1017 :
1018 : case SIOCSIFFLAGS:
1019 0 : if (ifp->if_flags & IFF_UP) {
1020 0 : if (ifp->if_flags & IFF_RUNNING &&
1021 0 : ifp->if_flags & IFF_PROMISC &&
1022 0 : !(sc->kue_if_flags & IFF_PROMISC)) {
1023 0 : sc->kue_rxfilt |= KUE_RXFILT_PROMISC;
1024 0 : kue_setword(sc, KUE_CMD_SET_PKT_FILTER,
1025 : sc->kue_rxfilt);
1026 0 : } else if (ifp->if_flags & IFF_RUNNING &&
1027 0 : !(ifp->if_flags & IFF_PROMISC) &&
1028 0 : sc->kue_if_flags & IFF_PROMISC) {
1029 0 : sc->kue_rxfilt &= ~KUE_RXFILT_PROMISC;
1030 0 : kue_setword(sc, KUE_CMD_SET_PKT_FILTER,
1031 : sc->kue_rxfilt);
1032 0 : } else if (!(ifp->if_flags & IFF_RUNNING))
1033 0 : kue_init(sc);
1034 : } else {
1035 0 : if (ifp->if_flags & IFF_RUNNING)
1036 0 : kue_stop(sc);
1037 : }
1038 0 : sc->kue_if_flags = ifp->if_flags;
1039 : error = 0;
1040 0 : break;
1041 :
1042 : default:
1043 0 : error = ether_ioctl(ifp, &sc->arpcom, command, data);
1044 0 : }
1045 :
1046 0 : if (error == ENETRESET) {
1047 0 : if (ifp->if_flags & IFF_RUNNING)
1048 0 : kue_setmulti(sc);
1049 : error = 0;
1050 0 : }
1051 :
1052 0 : splx(s);
1053 0 : return (error);
1054 0 : }
1055 :
1056 : void
1057 0 : kue_watchdog(struct ifnet *ifp)
1058 : {
1059 0 : struct kue_softc *sc = ifp->if_softc;
1060 : struct kue_chain *c;
1061 0 : usbd_status stat;
1062 : int s;
1063 :
1064 : DPRINTFN(5,("%s: %s: enter\n", sc->kue_dev.dv_xname,__func__));
1065 :
1066 0 : if (usbd_is_dying(sc->kue_udev))
1067 0 : return;
1068 :
1069 0 : ifp->if_oerrors++;
1070 0 : printf("%s: watchdog timeout\n", sc->kue_dev.dv_xname);
1071 :
1072 0 : s = splusb();
1073 0 : c = &sc->kue_cdata.kue_tx_chain[0];
1074 0 : usbd_get_xfer_status(c->kue_xfer, NULL, NULL, NULL, &stat);
1075 0 : kue_txeof(c->kue_xfer, c, stat);
1076 :
1077 0 : if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
1078 0 : kue_start(ifp);
1079 0 : splx(s);
1080 0 : }
1081 :
1082 : /*
1083 : * Stop the adapter and free any mbufs allocated to the
1084 : * RX and TX lists.
1085 : */
1086 : void
1087 0 : kue_stop(struct kue_softc *sc)
1088 : {
1089 : usbd_status err;
1090 : struct ifnet *ifp;
1091 : int i;
1092 :
1093 : DPRINTFN(5,("%s: %s: enter\n", sc->kue_dev.dv_xname,__func__));
1094 :
1095 0 : ifp = GET_IFP(sc);
1096 0 : ifp->if_timer = 0;
1097 0 : ifp->if_flags &= ~IFF_RUNNING;
1098 0 : ifq_clr_oactive(&ifp->if_snd);
1099 :
1100 : /* Stop transfers. */
1101 0 : if (sc->kue_ep[KUE_ENDPT_RX] != NULL) {
1102 0 : usbd_abort_pipe(sc->kue_ep[KUE_ENDPT_RX]);
1103 0 : err = usbd_close_pipe(sc->kue_ep[KUE_ENDPT_RX]);
1104 0 : if (err) {
1105 0 : printf("%s: close rx pipe failed: %s\n",
1106 0 : sc->kue_dev.dv_xname, usbd_errstr(err));
1107 0 : }
1108 0 : sc->kue_ep[KUE_ENDPT_RX] = NULL;
1109 0 : }
1110 :
1111 0 : if (sc->kue_ep[KUE_ENDPT_TX] != NULL) {
1112 0 : usbd_abort_pipe(sc->kue_ep[KUE_ENDPT_TX]);
1113 0 : err = usbd_close_pipe(sc->kue_ep[KUE_ENDPT_TX]);
1114 0 : if (err) {
1115 0 : printf("%s: close tx pipe failed: %s\n",
1116 0 : sc->kue_dev.dv_xname, usbd_errstr(err));
1117 0 : }
1118 0 : sc->kue_ep[KUE_ENDPT_TX] = NULL;
1119 0 : }
1120 :
1121 0 : if (sc->kue_ep[KUE_ENDPT_INTR] != NULL) {
1122 0 : usbd_abort_pipe(sc->kue_ep[KUE_ENDPT_INTR]);
1123 0 : err = usbd_close_pipe(sc->kue_ep[KUE_ENDPT_INTR]);
1124 0 : if (err) {
1125 0 : printf("%s: close intr pipe failed: %s\n",
1126 0 : sc->kue_dev.dv_xname, usbd_errstr(err));
1127 0 : }
1128 0 : sc->kue_ep[KUE_ENDPT_INTR] = NULL;
1129 0 : }
1130 :
1131 : /* Free RX resources. */
1132 0 : for (i = 0; i < KUE_RX_LIST_CNT; i++) {
1133 0 : if (sc->kue_cdata.kue_rx_chain[i].kue_mbuf != NULL) {
1134 0 : m_freem(sc->kue_cdata.kue_rx_chain[i].kue_mbuf);
1135 0 : sc->kue_cdata.kue_rx_chain[i].kue_mbuf = NULL;
1136 0 : }
1137 0 : if (sc->kue_cdata.kue_rx_chain[i].kue_xfer != NULL) {
1138 0 : usbd_free_xfer(sc->kue_cdata.kue_rx_chain[i].kue_xfer);
1139 0 : sc->kue_cdata.kue_rx_chain[i].kue_xfer = NULL;
1140 0 : }
1141 : }
1142 :
1143 : /* Free TX resources. */
1144 0 : for (i = 0; i < KUE_TX_LIST_CNT; i++) {
1145 0 : if (sc->kue_cdata.kue_tx_chain[i].kue_mbuf != NULL) {
1146 0 : m_freem(sc->kue_cdata.kue_tx_chain[i].kue_mbuf);
1147 0 : sc->kue_cdata.kue_tx_chain[i].kue_mbuf = NULL;
1148 0 : }
1149 0 : if (sc->kue_cdata.kue_tx_chain[i].kue_xfer != NULL) {
1150 0 : usbd_free_xfer(sc->kue_cdata.kue_tx_chain[i].kue_xfer);
1151 0 : sc->kue_cdata.kue_tx_chain[i].kue_xfer = NULL;
1152 0 : }
1153 : }
1154 0 : }
|