112bd3c8bSSascha Wildner /*- 212bd3c8bSSascha Wildner * Copyright (c) 1997, 1998, 1999, 2000 312bd3c8bSSascha Wildner * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved. 412bd3c8bSSascha Wildner * 512bd3c8bSSascha Wildner * Redistribution and use in source and binary forms, with or without 612bd3c8bSSascha Wildner * modification, are permitted provided that the following conditions 712bd3c8bSSascha Wildner * are met: 812bd3c8bSSascha Wildner * 1. Redistributions of source code must retain the above copyright 912bd3c8bSSascha Wildner * notice, this list of conditions and the following disclaimer. 1012bd3c8bSSascha Wildner * 2. Redistributions in binary form must reproduce the above copyright 1112bd3c8bSSascha Wildner * notice, this list of conditions and the following disclaimer in the 1212bd3c8bSSascha Wildner * documentation and/or other materials provided with the distribution. 1312bd3c8bSSascha Wildner * 3. All advertising materials mentioning features or use of this software 1412bd3c8bSSascha Wildner * must display the following acknowledgement: 1512bd3c8bSSascha Wildner * This product includes software developed by Bill Paul. 1612bd3c8bSSascha Wildner * 4. Neither the name of the author nor the names of any co-contributors 1712bd3c8bSSascha Wildner * may be used to endorse or promote products derived from this software 1812bd3c8bSSascha Wildner * without specific prior written permission. 1912bd3c8bSSascha Wildner * 2012bd3c8bSSascha Wildner * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 2112bd3c8bSSascha Wildner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2212bd3c8bSSascha Wildner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2312bd3c8bSSascha Wildner * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 2412bd3c8bSSascha Wildner * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2512bd3c8bSSascha Wildner * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2612bd3c8bSSascha Wildner * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2712bd3c8bSSascha Wildner * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2812bd3c8bSSascha Wildner * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2912bd3c8bSSascha Wildner * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 3012bd3c8bSSascha Wildner * THE POSSIBILITY OF SUCH DAMAGE. 3112bd3c8bSSascha Wildner */ 3212bd3c8bSSascha Wildner 3312bd3c8bSSascha Wildner #include <sys/cdefs.h> 3412bd3c8bSSascha Wildner __FBSDID("$FreeBSD$"); 3512bd3c8bSSascha Wildner 3612bd3c8bSSascha Wildner /* 3712bd3c8bSSascha Wildner * Kawasaki LSI KL5KUSB101B USB to ethernet adapter driver. 3812bd3c8bSSascha Wildner * 3912bd3c8bSSascha Wildner * Written by Bill Paul <wpaul@ee.columbia.edu> 4012bd3c8bSSascha Wildner * Electrical Engineering Department 4112bd3c8bSSascha Wildner * Columbia University, New York City 4212bd3c8bSSascha Wildner */ 4312bd3c8bSSascha Wildner 4412bd3c8bSSascha Wildner /* 4512bd3c8bSSascha Wildner * The KLSI USB to ethernet adapter chip contains an USB serial interface, 4612bd3c8bSSascha Wildner * ethernet MAC and embedded microcontroller (called the QT Engine). 4712bd3c8bSSascha Wildner * The chip must have firmware loaded into it before it will operate. 4812bd3c8bSSascha Wildner * Packets are passed between the chip and host via bulk transfers. 4912bd3c8bSSascha Wildner * There is an interrupt endpoint mentioned in the software spec, however 5012bd3c8bSSascha Wildner * it's currently unused. This device is 10Mbps half-duplex only, hence 5112bd3c8bSSascha Wildner * there is no media selection logic. The MAC supports a 128 entry 5212bd3c8bSSascha Wildner * multicast filter, though the exact size of the filter can depend 5312bd3c8bSSascha Wildner * on the firmware. Curiously, while the software spec describes various 5412bd3c8bSSascha Wildner * ethernet statistics counters, my sample adapter and firmware combination 5512bd3c8bSSascha Wildner * claims not to support any statistics counters at all. 5612bd3c8bSSascha Wildner * 5712bd3c8bSSascha Wildner * Note that once we load the firmware in the device, we have to be 5812bd3c8bSSascha Wildner * careful not to load it again: if you restart your computer but 5912bd3c8bSSascha Wildner * leave the adapter attached to the USB controller, it may remain 6012bd3c8bSSascha Wildner * powered on and retain its firmware. In this case, we don't need 6112bd3c8bSSascha Wildner * to load the firmware a second time. 6212bd3c8bSSascha Wildner * 6312bd3c8bSSascha Wildner * Special thanks to Rob Furr for providing an ADS Technologies 6412bd3c8bSSascha Wildner * adapter for development and testing. No monkeys were harmed during 6512bd3c8bSSascha Wildner * the development of this driver. 6612bd3c8bSSascha Wildner */ 6712bd3c8bSSascha Wildner 6812bd3c8bSSascha Wildner #include <sys/stdint.h> 6912bd3c8bSSascha Wildner #include <sys/stddef.h> 7012bd3c8bSSascha Wildner #include <sys/param.h> 7112bd3c8bSSascha Wildner #include <sys/queue.h> 7212bd3c8bSSascha Wildner #include <sys/types.h> 7312bd3c8bSSascha Wildner #include <sys/systm.h> 7412bd3c8bSSascha Wildner #include <sys/kernel.h> 7512bd3c8bSSascha Wildner #include <sys/bus.h> 7612bd3c8bSSascha Wildner #include <sys/module.h> 7712bd3c8bSSascha Wildner #include <sys/lock.h> 7812bd3c8bSSascha Wildner #include <sys/mutex.h> 7912bd3c8bSSascha Wildner #include <sys/condvar.h> 8012bd3c8bSSascha Wildner #include <sys/sysctl.h> 8112bd3c8bSSascha Wildner #include <sys/sx.h> 8212bd3c8bSSascha Wildner #include <sys/unistd.h> 8312bd3c8bSSascha Wildner #include <sys/callout.h> 8412bd3c8bSSascha Wildner #include <sys/malloc.h> 8512bd3c8bSSascha Wildner #include <sys/priv.h> 8612bd3c8bSSascha Wildner 8712bd3c8bSSascha Wildner #include <dev/usb/usb.h> 8812bd3c8bSSascha Wildner #include <dev/usb/usbdi.h> 8912bd3c8bSSascha Wildner #include <dev/usb/usbdi_util.h> 9012bd3c8bSSascha Wildner #include "usbdevs.h" 9112bd3c8bSSascha Wildner 9212bd3c8bSSascha Wildner #define USB_DEBUG_VAR kue_debug 9312bd3c8bSSascha Wildner #include <dev/usb/usb_debug.h> 9412bd3c8bSSascha Wildner #include <dev/usb/usb_process.h> 9512bd3c8bSSascha Wildner 9612bd3c8bSSascha Wildner #include <dev/usb/net/usb_ethernet.h> 9712bd3c8bSSascha Wildner #include <dev/usb/net/if_kuereg.h> 9812bd3c8bSSascha Wildner #include <dev/usb/net/if_kuefw.h> 9912bd3c8bSSascha Wildner 10012bd3c8bSSascha Wildner /* 10112bd3c8bSSascha Wildner * Various supported device vendors/products. 10212bd3c8bSSascha Wildner */ 10312bd3c8bSSascha Wildner static const STRUCT_USB_HOST_ID kue_devs[] = { 10412bd3c8bSSascha Wildner #define KUE_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) } 10512bd3c8bSSascha Wildner KUE_DEV(3COM, 3C19250), 10612bd3c8bSSascha Wildner KUE_DEV(3COM, 3C460), 10712bd3c8bSSascha Wildner KUE_DEV(ABOCOM, URE450), 10812bd3c8bSSascha Wildner KUE_DEV(ADS, UBS10BT), 10912bd3c8bSSascha Wildner KUE_DEV(ADS, UBS10BTX), 11012bd3c8bSSascha Wildner KUE_DEV(AOX, USB101), 11112bd3c8bSSascha Wildner KUE_DEV(ASANTE, EA), 11212bd3c8bSSascha Wildner KUE_DEV(ATEN, DSB650C), 11312bd3c8bSSascha Wildner KUE_DEV(ATEN, UC10T), 11412bd3c8bSSascha Wildner KUE_DEV(COREGA, ETHER_USB_T), 11512bd3c8bSSascha Wildner KUE_DEV(DLINK, DSB650C), 11612bd3c8bSSascha Wildner KUE_DEV(ENTREGA, E45), 11712bd3c8bSSascha Wildner KUE_DEV(ENTREGA, XX1), 11812bd3c8bSSascha Wildner KUE_DEV(ENTREGA, XX2), 11912bd3c8bSSascha Wildner KUE_DEV(IODATA, USBETT), 12012bd3c8bSSascha Wildner KUE_DEV(JATON, EDA), 12112bd3c8bSSascha Wildner KUE_DEV(KINGSTON, XX1), 12212bd3c8bSSascha Wildner KUE_DEV(KLSI, DUH3E10BT), 12312bd3c8bSSascha Wildner KUE_DEV(KLSI, DUH3E10BTN), 12412bd3c8bSSascha Wildner KUE_DEV(LINKSYS, USB10T), 12512bd3c8bSSascha Wildner KUE_DEV(MOBILITY, EA), 12612bd3c8bSSascha Wildner KUE_DEV(NETGEAR, EA101), 12712bd3c8bSSascha Wildner KUE_DEV(NETGEAR, EA101X), 12812bd3c8bSSascha Wildner KUE_DEV(PERACOM, ENET), 12912bd3c8bSSascha Wildner KUE_DEV(PERACOM, ENET2), 13012bd3c8bSSascha Wildner KUE_DEV(PERACOM, ENET3), 13112bd3c8bSSascha Wildner KUE_DEV(PORTGEAR, EA8), 13212bd3c8bSSascha Wildner KUE_DEV(PORTGEAR, EA9), 13312bd3c8bSSascha Wildner KUE_DEV(PORTSMITH, EEA), 13412bd3c8bSSascha Wildner KUE_DEV(SHARK, PA), 13512bd3c8bSSascha Wildner KUE_DEV(SILICOM, GPE), 13612bd3c8bSSascha Wildner KUE_DEV(SILICOM, U2E), 13712bd3c8bSSascha Wildner KUE_DEV(SMC, 2102USB), 13812bd3c8bSSascha Wildner #undef KUE_DEV 13912bd3c8bSSascha Wildner }; 14012bd3c8bSSascha Wildner 14112bd3c8bSSascha Wildner /* prototypes */ 14212bd3c8bSSascha Wildner 14312bd3c8bSSascha Wildner static device_probe_t kue_probe; 14412bd3c8bSSascha Wildner static device_attach_t kue_attach; 14512bd3c8bSSascha Wildner static device_detach_t kue_detach; 14612bd3c8bSSascha Wildner 14712bd3c8bSSascha Wildner static usb_callback_t kue_bulk_read_callback; 14812bd3c8bSSascha Wildner static usb_callback_t kue_bulk_write_callback; 14912bd3c8bSSascha Wildner 15012bd3c8bSSascha Wildner static uether_fn_t kue_attach_post; 15112bd3c8bSSascha Wildner static uether_fn_t kue_init; 15212bd3c8bSSascha Wildner static uether_fn_t kue_stop; 15312bd3c8bSSascha Wildner static uether_fn_t kue_start; 15412bd3c8bSSascha Wildner static uether_fn_t kue_setmulti; 15512bd3c8bSSascha Wildner static uether_fn_t kue_setpromisc; 15612bd3c8bSSascha Wildner 15712bd3c8bSSascha Wildner static int kue_do_request(struct kue_softc *, 15812bd3c8bSSascha Wildner struct usb_device_request *, void *); 15912bd3c8bSSascha Wildner static int kue_setword(struct kue_softc *, uint8_t, uint16_t); 16012bd3c8bSSascha Wildner static int kue_ctl(struct kue_softc *, uint8_t, uint8_t, uint16_t, 16112bd3c8bSSascha Wildner void *, int); 16212bd3c8bSSascha Wildner static int kue_load_fw(struct kue_softc *); 16312bd3c8bSSascha Wildner static void kue_reset(struct kue_softc *); 16412bd3c8bSSascha Wildner 16512bd3c8bSSascha Wildner #ifdef USB_DEBUG 16612bd3c8bSSascha Wildner static int kue_debug = 0; 16712bd3c8bSSascha Wildner 16812bd3c8bSSascha Wildner static SYSCTL_NODE(_hw_usb, OID_AUTO, kue, CTLFLAG_RW, 0, "USB kue"); 16912bd3c8bSSascha Wildner SYSCTL_INT(_hw_usb_kue, OID_AUTO, debug, CTLFLAG_RW, &kue_debug, 0, 17012bd3c8bSSascha Wildner "Debug level"); 17112bd3c8bSSascha Wildner #endif 17212bd3c8bSSascha Wildner 17312bd3c8bSSascha Wildner static const struct usb_config kue_config[KUE_N_TRANSFER] = { 17412bd3c8bSSascha Wildner 17512bd3c8bSSascha Wildner [KUE_BULK_DT_WR] = { 17612bd3c8bSSascha Wildner .type = UE_BULK, 17712bd3c8bSSascha Wildner .endpoint = UE_ADDR_ANY, 17812bd3c8bSSascha Wildner .direction = UE_DIR_OUT, 17912bd3c8bSSascha Wildner .bufsize = (MCLBYTES + 2 + 64), 18012bd3c8bSSascha Wildner .flags = {.pipe_bof = 1,}, 18112bd3c8bSSascha Wildner .callback = kue_bulk_write_callback, 18212bd3c8bSSascha Wildner .timeout = 10000, /* 10 seconds */ 18312bd3c8bSSascha Wildner }, 18412bd3c8bSSascha Wildner 18512bd3c8bSSascha Wildner [KUE_BULK_DT_RD] = { 18612bd3c8bSSascha Wildner .type = UE_BULK, 18712bd3c8bSSascha Wildner .endpoint = UE_ADDR_ANY, 18812bd3c8bSSascha Wildner .direction = UE_DIR_IN, 18912bd3c8bSSascha Wildner .bufsize = (MCLBYTES + 2), 19012bd3c8bSSascha Wildner .flags = {.pipe_bof = 1,.short_xfer_ok = 1,}, 19112bd3c8bSSascha Wildner .callback = kue_bulk_read_callback, 19212bd3c8bSSascha Wildner .timeout = 0, /* no timeout */ 19312bd3c8bSSascha Wildner }, 19412bd3c8bSSascha Wildner }; 19512bd3c8bSSascha Wildner 19612bd3c8bSSascha Wildner static device_method_t kue_methods[] = { 19712bd3c8bSSascha Wildner /* Device interface */ 19812bd3c8bSSascha Wildner DEVMETHOD(device_probe, kue_probe), 19912bd3c8bSSascha Wildner DEVMETHOD(device_attach, kue_attach), 20012bd3c8bSSascha Wildner DEVMETHOD(device_detach, kue_detach), 20112bd3c8bSSascha Wildner 202d3c9c58eSSascha Wildner DEVMETHOD_END 20312bd3c8bSSascha Wildner }; 20412bd3c8bSSascha Wildner 20512bd3c8bSSascha Wildner static driver_t kue_driver = { 20612bd3c8bSSascha Wildner .name = "kue", 20712bd3c8bSSascha Wildner .methods = kue_methods, 20812bd3c8bSSascha Wildner .size = sizeof(struct kue_softc), 20912bd3c8bSSascha Wildner }; 21012bd3c8bSSascha Wildner 21112bd3c8bSSascha Wildner static devclass_t kue_devclass; 21212bd3c8bSSascha Wildner 213*3a25be87SSascha Wildner DRIVER_MODULE(kue, uhub, kue_driver, kue_devclass, NULL, NULL); 21412bd3c8bSSascha Wildner MODULE_DEPEND(kue, uether, 1, 1, 1); 21512bd3c8bSSascha Wildner MODULE_DEPEND(kue, usb, 1, 1, 1); 21612bd3c8bSSascha Wildner MODULE_DEPEND(kue, ether, 1, 1, 1); 21712bd3c8bSSascha Wildner MODULE_VERSION(kue, 1); 21812bd3c8bSSascha Wildner 21912bd3c8bSSascha Wildner static const struct usb_ether_methods kue_ue_methods = { 22012bd3c8bSSascha Wildner .ue_attach_post = kue_attach_post, 22112bd3c8bSSascha Wildner .ue_start = kue_start, 22212bd3c8bSSascha Wildner .ue_init = kue_init, 22312bd3c8bSSascha Wildner .ue_stop = kue_stop, 22412bd3c8bSSascha Wildner .ue_setmulti = kue_setmulti, 22512bd3c8bSSascha Wildner .ue_setpromisc = kue_setpromisc, 22612bd3c8bSSascha Wildner }; 22712bd3c8bSSascha Wildner 22812bd3c8bSSascha Wildner /* 22912bd3c8bSSascha Wildner * We have a custom do_request function which is almost like the 23012bd3c8bSSascha Wildner * regular do_request function, except it has a much longer timeout. 23112bd3c8bSSascha Wildner * Why? Because we need to make requests over the control endpoint 23212bd3c8bSSascha Wildner * to download the firmware to the device, which can take longer 23312bd3c8bSSascha Wildner * than the default timeout. 23412bd3c8bSSascha Wildner */ 23512bd3c8bSSascha Wildner static int 23612bd3c8bSSascha Wildner kue_do_request(struct kue_softc *sc, struct usb_device_request *req, 23712bd3c8bSSascha Wildner void *data) 23812bd3c8bSSascha Wildner { 23912bd3c8bSSascha Wildner usb_error_t err; 24012bd3c8bSSascha Wildner 24112bd3c8bSSascha Wildner err = uether_do_request(&sc->sc_ue, req, data, 60000); 24212bd3c8bSSascha Wildner 24312bd3c8bSSascha Wildner return (err); 24412bd3c8bSSascha Wildner } 24512bd3c8bSSascha Wildner 24612bd3c8bSSascha Wildner static int 24712bd3c8bSSascha Wildner kue_setword(struct kue_softc *sc, uint8_t breq, uint16_t word) 24812bd3c8bSSascha Wildner { 24912bd3c8bSSascha Wildner struct usb_device_request req; 25012bd3c8bSSascha Wildner 25112bd3c8bSSascha Wildner req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 25212bd3c8bSSascha Wildner req.bRequest = breq; 25312bd3c8bSSascha Wildner USETW(req.wValue, word); 25412bd3c8bSSascha Wildner USETW(req.wIndex, 0); 25512bd3c8bSSascha Wildner USETW(req.wLength, 0); 25612bd3c8bSSascha Wildner 25712bd3c8bSSascha Wildner return (kue_do_request(sc, &req, NULL)); 25812bd3c8bSSascha Wildner } 25912bd3c8bSSascha Wildner 26012bd3c8bSSascha Wildner static int 26112bd3c8bSSascha Wildner kue_ctl(struct kue_softc *sc, uint8_t rw, uint8_t breq, 26212bd3c8bSSascha Wildner uint16_t val, void *data, int len) 26312bd3c8bSSascha Wildner { 26412bd3c8bSSascha Wildner struct usb_device_request req; 26512bd3c8bSSascha Wildner 26612bd3c8bSSascha Wildner if (rw == KUE_CTL_WRITE) 26712bd3c8bSSascha Wildner req.bmRequestType = UT_WRITE_VENDOR_DEVICE; 26812bd3c8bSSascha Wildner else 26912bd3c8bSSascha Wildner req.bmRequestType = UT_READ_VENDOR_DEVICE; 27012bd3c8bSSascha Wildner 27112bd3c8bSSascha Wildner 27212bd3c8bSSascha Wildner req.bRequest = breq; 27312bd3c8bSSascha Wildner USETW(req.wValue, val); 27412bd3c8bSSascha Wildner USETW(req.wIndex, 0); 27512bd3c8bSSascha Wildner USETW(req.wLength, len); 27612bd3c8bSSascha Wildner 27712bd3c8bSSascha Wildner return (kue_do_request(sc, &req, data)); 27812bd3c8bSSascha Wildner } 27912bd3c8bSSascha Wildner 28012bd3c8bSSascha Wildner static int 28112bd3c8bSSascha Wildner kue_load_fw(struct kue_softc *sc) 28212bd3c8bSSascha Wildner { 28312bd3c8bSSascha Wildner struct usb_device_descriptor *dd; 28412bd3c8bSSascha Wildner uint16_t hwrev; 28512bd3c8bSSascha Wildner usb_error_t err; 28612bd3c8bSSascha Wildner 28712bd3c8bSSascha Wildner dd = usbd_get_device_descriptor(sc->sc_ue.ue_udev); 28812bd3c8bSSascha Wildner hwrev = UGETW(dd->bcdDevice); 28912bd3c8bSSascha Wildner 29012bd3c8bSSascha Wildner /* 29112bd3c8bSSascha Wildner * First, check if we even need to load the firmware. 29212bd3c8bSSascha Wildner * If the device was still attached when the system was 29312bd3c8bSSascha Wildner * rebooted, it may already have firmware loaded in it. 29412bd3c8bSSascha Wildner * If this is the case, we don't need to do it again. 29512bd3c8bSSascha Wildner * And in fact, if we try to load it again, we'll hang, 29612bd3c8bSSascha Wildner * so we have to avoid this condition if we don't want 29712bd3c8bSSascha Wildner * to look stupid. 29812bd3c8bSSascha Wildner * 29912bd3c8bSSascha Wildner * We can test this quickly by checking the bcdRevision 30012bd3c8bSSascha Wildner * code. The NIC will return a different revision code if 30112bd3c8bSSascha Wildner * it's probed while the firmware is still loaded and 30212bd3c8bSSascha Wildner * running. 30312bd3c8bSSascha Wildner */ 30412bd3c8bSSascha Wildner if (hwrev == 0x0202) 30512bd3c8bSSascha Wildner return(0); 30612bd3c8bSSascha Wildner 30712bd3c8bSSascha Wildner /* Load code segment */ 30812bd3c8bSSascha Wildner err = kue_ctl(sc, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN, 30912bd3c8bSSascha Wildner 0, kue_code_seg, sizeof(kue_code_seg)); 31012bd3c8bSSascha Wildner if (err) { 31112bd3c8bSSascha Wildner device_printf(sc->sc_ue.ue_dev, "failed to load code segment: %s\n", 31212bd3c8bSSascha Wildner usbd_errstr(err)); 31312bd3c8bSSascha Wildner return(ENXIO); 31412bd3c8bSSascha Wildner } 31512bd3c8bSSascha Wildner 31612bd3c8bSSascha Wildner /* Load fixup segment */ 31712bd3c8bSSascha Wildner err = kue_ctl(sc, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN, 31812bd3c8bSSascha Wildner 0, kue_fix_seg, sizeof(kue_fix_seg)); 31912bd3c8bSSascha Wildner if (err) { 32012bd3c8bSSascha Wildner device_printf(sc->sc_ue.ue_dev, "failed to load fixup segment: %s\n", 32112bd3c8bSSascha Wildner usbd_errstr(err)); 32212bd3c8bSSascha Wildner return(ENXIO); 32312bd3c8bSSascha Wildner } 32412bd3c8bSSascha Wildner 32512bd3c8bSSascha Wildner /* Send trigger command. */ 32612bd3c8bSSascha Wildner err = kue_ctl(sc, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN, 32712bd3c8bSSascha Wildner 0, kue_trig_seg, sizeof(kue_trig_seg)); 32812bd3c8bSSascha Wildner if (err) { 32912bd3c8bSSascha Wildner device_printf(sc->sc_ue.ue_dev, "failed to load trigger segment: %s\n", 33012bd3c8bSSascha Wildner usbd_errstr(err)); 33112bd3c8bSSascha Wildner return(ENXIO); 33212bd3c8bSSascha Wildner } 33312bd3c8bSSascha Wildner 33412bd3c8bSSascha Wildner return (0); 33512bd3c8bSSascha Wildner } 33612bd3c8bSSascha Wildner 33712bd3c8bSSascha Wildner static void 33812bd3c8bSSascha Wildner kue_setpromisc(struct usb_ether *ue) 33912bd3c8bSSascha Wildner { 34012bd3c8bSSascha Wildner struct kue_softc *sc = uether_getsc(ue); 34112bd3c8bSSascha Wildner struct ifnet *ifp = uether_getifp(ue); 34212bd3c8bSSascha Wildner 34312bd3c8bSSascha Wildner KUE_LOCK_ASSERT(sc, MA_OWNED); 34412bd3c8bSSascha Wildner 34512bd3c8bSSascha Wildner if (ifp->if_flags & IFF_PROMISC) 34612bd3c8bSSascha Wildner sc->sc_rxfilt |= KUE_RXFILT_PROMISC; 34712bd3c8bSSascha Wildner else 34812bd3c8bSSascha Wildner sc->sc_rxfilt &= ~KUE_RXFILT_PROMISC; 34912bd3c8bSSascha Wildner 35012bd3c8bSSascha Wildner kue_setword(sc, KUE_CMD_SET_PKT_FILTER, sc->sc_rxfilt); 35112bd3c8bSSascha Wildner } 35212bd3c8bSSascha Wildner 35312bd3c8bSSascha Wildner static void 35412bd3c8bSSascha Wildner kue_setmulti(struct usb_ether *ue) 35512bd3c8bSSascha Wildner { 35612bd3c8bSSascha Wildner struct kue_softc *sc = uether_getsc(ue); 35712bd3c8bSSascha Wildner struct ifnet *ifp = uether_getifp(ue); 35812bd3c8bSSascha Wildner struct ifmultiaddr *ifma; 35912bd3c8bSSascha Wildner int i = 0; 36012bd3c8bSSascha Wildner 36112bd3c8bSSascha Wildner KUE_LOCK_ASSERT(sc, MA_OWNED); 36212bd3c8bSSascha Wildner 36312bd3c8bSSascha Wildner if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) { 36412bd3c8bSSascha Wildner sc->sc_rxfilt |= KUE_RXFILT_ALLMULTI; 36512bd3c8bSSascha Wildner sc->sc_rxfilt &= ~KUE_RXFILT_MULTICAST; 36612bd3c8bSSascha Wildner kue_setword(sc, KUE_CMD_SET_PKT_FILTER, sc->sc_rxfilt); 36712bd3c8bSSascha Wildner return; 36812bd3c8bSSascha Wildner } 36912bd3c8bSSascha Wildner 37012bd3c8bSSascha Wildner sc->sc_rxfilt &= ~KUE_RXFILT_ALLMULTI; 37112bd3c8bSSascha Wildner 37212bd3c8bSSascha Wildner if_maddr_rlock(ifp); 37312bd3c8bSSascha Wildner TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) 37412bd3c8bSSascha Wildner { 37512bd3c8bSSascha Wildner if (ifma->ifma_addr->sa_family != AF_LINK) 37612bd3c8bSSascha Wildner continue; 37712bd3c8bSSascha Wildner /* 37812bd3c8bSSascha Wildner * If there are too many addresses for the 37912bd3c8bSSascha Wildner * internal filter, switch over to allmulti mode. 38012bd3c8bSSascha Wildner */ 38112bd3c8bSSascha Wildner if (i == KUE_MCFILTCNT(sc)) 38212bd3c8bSSascha Wildner break; 38312bd3c8bSSascha Wildner memcpy(KUE_MCFILT(sc, i), 38412bd3c8bSSascha Wildner LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 38512bd3c8bSSascha Wildner ETHER_ADDR_LEN); 38612bd3c8bSSascha Wildner i++; 38712bd3c8bSSascha Wildner } 38812bd3c8bSSascha Wildner if_maddr_runlock(ifp); 38912bd3c8bSSascha Wildner 39012bd3c8bSSascha Wildner if (i == KUE_MCFILTCNT(sc)) 39112bd3c8bSSascha Wildner sc->sc_rxfilt |= KUE_RXFILT_ALLMULTI; 39212bd3c8bSSascha Wildner else { 39312bd3c8bSSascha Wildner sc->sc_rxfilt |= KUE_RXFILT_MULTICAST; 39412bd3c8bSSascha Wildner kue_ctl(sc, KUE_CTL_WRITE, KUE_CMD_SET_MCAST_FILTERS, 39512bd3c8bSSascha Wildner i, sc->sc_mcfilters, i * ETHER_ADDR_LEN); 39612bd3c8bSSascha Wildner } 39712bd3c8bSSascha Wildner 39812bd3c8bSSascha Wildner kue_setword(sc, KUE_CMD_SET_PKT_FILTER, sc->sc_rxfilt); 39912bd3c8bSSascha Wildner } 40012bd3c8bSSascha Wildner 40112bd3c8bSSascha Wildner /* 40212bd3c8bSSascha Wildner * Issue a SET_CONFIGURATION command to reset the MAC. This should be 40312bd3c8bSSascha Wildner * done after the firmware is loaded into the adapter in order to 40412bd3c8bSSascha Wildner * bring it into proper operation. 40512bd3c8bSSascha Wildner */ 40612bd3c8bSSascha Wildner static void 40712bd3c8bSSascha Wildner kue_reset(struct kue_softc *sc) 40812bd3c8bSSascha Wildner { 40912bd3c8bSSascha Wildner struct usb_config_descriptor *cd; 41012bd3c8bSSascha Wildner usb_error_t err; 41112bd3c8bSSascha Wildner 41212bd3c8bSSascha Wildner cd = usbd_get_config_descriptor(sc->sc_ue.ue_udev); 41312bd3c8bSSascha Wildner 41412bd3c8bSSascha Wildner err = usbd_req_set_config(sc->sc_ue.ue_udev, &sc->sc_mtx, 41512bd3c8bSSascha Wildner cd->bConfigurationValue); 41612bd3c8bSSascha Wildner if (err) 41712bd3c8bSSascha Wildner DPRINTF("reset failed (ignored)\n"); 41812bd3c8bSSascha Wildner 41912bd3c8bSSascha Wildner /* wait a little while for the chip to get its brains in order */ 42012bd3c8bSSascha Wildner uether_pause(&sc->sc_ue, hz / 100); 42112bd3c8bSSascha Wildner } 42212bd3c8bSSascha Wildner 42312bd3c8bSSascha Wildner static void 42412bd3c8bSSascha Wildner kue_attach_post(struct usb_ether *ue) 42512bd3c8bSSascha Wildner { 42612bd3c8bSSascha Wildner struct kue_softc *sc = uether_getsc(ue); 42712bd3c8bSSascha Wildner int error; 42812bd3c8bSSascha Wildner 42912bd3c8bSSascha Wildner /* load the firmware into the NIC */ 43012bd3c8bSSascha Wildner error = kue_load_fw(sc); 43112bd3c8bSSascha Wildner if (error) { 43212bd3c8bSSascha Wildner device_printf(sc->sc_ue.ue_dev, "could not load firmware\n"); 43312bd3c8bSSascha Wildner /* ignore the error */ 43412bd3c8bSSascha Wildner } 43512bd3c8bSSascha Wildner 43612bd3c8bSSascha Wildner /* reset the adapter */ 43712bd3c8bSSascha Wildner kue_reset(sc); 43812bd3c8bSSascha Wildner 43912bd3c8bSSascha Wildner /* read ethernet descriptor */ 44012bd3c8bSSascha Wildner kue_ctl(sc, KUE_CTL_READ, KUE_CMD_GET_ETHER_DESCRIPTOR, 44112bd3c8bSSascha Wildner 0, &sc->sc_desc, sizeof(sc->sc_desc)); 44212bd3c8bSSascha Wildner 44312bd3c8bSSascha Wildner /* copy in ethernet address */ 44412bd3c8bSSascha Wildner memcpy(ue->ue_eaddr, sc->sc_desc.kue_macaddr, sizeof(ue->ue_eaddr)); 44512bd3c8bSSascha Wildner } 44612bd3c8bSSascha Wildner 44712bd3c8bSSascha Wildner /* 44812bd3c8bSSascha Wildner * Probe for a KLSI chip. 44912bd3c8bSSascha Wildner */ 45012bd3c8bSSascha Wildner static int 45112bd3c8bSSascha Wildner kue_probe(device_t dev) 45212bd3c8bSSascha Wildner { 45312bd3c8bSSascha Wildner struct usb_attach_arg *uaa = device_get_ivars(dev); 45412bd3c8bSSascha Wildner 45512bd3c8bSSascha Wildner if (uaa->usb_mode != USB_MODE_HOST) 45612bd3c8bSSascha Wildner return (ENXIO); 45712bd3c8bSSascha Wildner if (uaa->info.bConfigIndex != KUE_CONFIG_IDX) 45812bd3c8bSSascha Wildner return (ENXIO); 45912bd3c8bSSascha Wildner if (uaa->info.bIfaceIndex != KUE_IFACE_IDX) 46012bd3c8bSSascha Wildner return (ENXIO); 46112bd3c8bSSascha Wildner 46212bd3c8bSSascha Wildner return (usbd_lookup_id_by_uaa(kue_devs, sizeof(kue_devs), uaa)); 46312bd3c8bSSascha Wildner } 46412bd3c8bSSascha Wildner 46512bd3c8bSSascha Wildner /* 46612bd3c8bSSascha Wildner * Attach the interface. Allocate softc structures, do 46712bd3c8bSSascha Wildner * setup and ethernet/BPF attach. 46812bd3c8bSSascha Wildner */ 46912bd3c8bSSascha Wildner static int 47012bd3c8bSSascha Wildner kue_attach(device_t dev) 47112bd3c8bSSascha Wildner { 47212bd3c8bSSascha Wildner struct usb_attach_arg *uaa = device_get_ivars(dev); 47312bd3c8bSSascha Wildner struct kue_softc *sc = device_get_softc(dev); 47412bd3c8bSSascha Wildner struct usb_ether *ue = &sc->sc_ue; 47512bd3c8bSSascha Wildner uint8_t iface_index; 47612bd3c8bSSascha Wildner int error; 47712bd3c8bSSascha Wildner 47812bd3c8bSSascha Wildner device_set_usb_desc(dev); 47912bd3c8bSSascha Wildner mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 48012bd3c8bSSascha Wildner 48112bd3c8bSSascha Wildner iface_index = KUE_IFACE_IDX; 48212bd3c8bSSascha Wildner error = usbd_transfer_setup(uaa->device, &iface_index, 48312bd3c8bSSascha Wildner sc->sc_xfer, kue_config, KUE_N_TRANSFER, sc, &sc->sc_mtx); 48412bd3c8bSSascha Wildner if (error) { 48512bd3c8bSSascha Wildner device_printf(dev, "allocating USB transfers failed\n"); 48612bd3c8bSSascha Wildner goto detach; 48712bd3c8bSSascha Wildner } 48812bd3c8bSSascha Wildner 48912bd3c8bSSascha Wildner sc->sc_mcfilters = malloc(KUE_MCFILTCNT(sc) * ETHER_ADDR_LEN, 49012bd3c8bSSascha Wildner M_USBDEV, M_WAITOK); 49112bd3c8bSSascha Wildner if (sc->sc_mcfilters == NULL) { 49212bd3c8bSSascha Wildner device_printf(dev, "failed allocating USB memory\n"); 49312bd3c8bSSascha Wildner goto detach; 49412bd3c8bSSascha Wildner } 49512bd3c8bSSascha Wildner 49612bd3c8bSSascha Wildner ue->ue_sc = sc; 49712bd3c8bSSascha Wildner ue->ue_dev = dev; 49812bd3c8bSSascha Wildner ue->ue_udev = uaa->device; 49912bd3c8bSSascha Wildner ue->ue_mtx = &sc->sc_mtx; 50012bd3c8bSSascha Wildner ue->ue_methods = &kue_ue_methods; 50112bd3c8bSSascha Wildner 50212bd3c8bSSascha Wildner error = uether_ifattach(ue); 50312bd3c8bSSascha Wildner if (error) { 50412bd3c8bSSascha Wildner device_printf(dev, "could not attach interface\n"); 50512bd3c8bSSascha Wildner goto detach; 50612bd3c8bSSascha Wildner } 50712bd3c8bSSascha Wildner return (0); /* success */ 50812bd3c8bSSascha Wildner 50912bd3c8bSSascha Wildner detach: 51012bd3c8bSSascha Wildner kue_detach(dev); 51112bd3c8bSSascha Wildner return (ENXIO); /* failure */ 51212bd3c8bSSascha Wildner } 51312bd3c8bSSascha Wildner 51412bd3c8bSSascha Wildner static int 51512bd3c8bSSascha Wildner kue_detach(device_t dev) 51612bd3c8bSSascha Wildner { 51712bd3c8bSSascha Wildner struct kue_softc *sc = device_get_softc(dev); 51812bd3c8bSSascha Wildner struct usb_ether *ue = &sc->sc_ue; 51912bd3c8bSSascha Wildner 52012bd3c8bSSascha Wildner usbd_transfer_unsetup(sc->sc_xfer, KUE_N_TRANSFER); 52112bd3c8bSSascha Wildner uether_ifdetach(ue); 52212bd3c8bSSascha Wildner mtx_destroy(&sc->sc_mtx); 52312bd3c8bSSascha Wildner free(sc->sc_mcfilters, M_USBDEV); 52412bd3c8bSSascha Wildner 52512bd3c8bSSascha Wildner return (0); 52612bd3c8bSSascha Wildner } 52712bd3c8bSSascha Wildner 52812bd3c8bSSascha Wildner /* 52912bd3c8bSSascha Wildner * A frame has been uploaded: pass the resulting mbuf chain up to 53012bd3c8bSSascha Wildner * the higher level protocols. 53112bd3c8bSSascha Wildner */ 53212bd3c8bSSascha Wildner static void 53312bd3c8bSSascha Wildner kue_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error) 53412bd3c8bSSascha Wildner { 53512bd3c8bSSascha Wildner struct kue_softc *sc = usbd_xfer_softc(xfer); 53612bd3c8bSSascha Wildner struct usb_ether *ue = &sc->sc_ue; 53712bd3c8bSSascha Wildner struct ifnet *ifp = uether_getifp(ue); 53812bd3c8bSSascha Wildner struct usb_page_cache *pc; 53912bd3c8bSSascha Wildner uint8_t buf[2]; 54012bd3c8bSSascha Wildner int len; 54112bd3c8bSSascha Wildner int actlen; 54212bd3c8bSSascha Wildner 54312bd3c8bSSascha Wildner usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); 54412bd3c8bSSascha Wildner 54512bd3c8bSSascha Wildner switch (USB_GET_STATE(xfer)) { 54612bd3c8bSSascha Wildner case USB_ST_TRANSFERRED: 54712bd3c8bSSascha Wildner 54812bd3c8bSSascha Wildner if (actlen <= (2 + sizeof(struct ether_header))) { 54912bd3c8bSSascha Wildner ifp->if_ierrors++; 55012bd3c8bSSascha Wildner goto tr_setup; 55112bd3c8bSSascha Wildner } 55212bd3c8bSSascha Wildner pc = usbd_xfer_get_frame(xfer, 0); 55312bd3c8bSSascha Wildner usbd_copy_out(pc, 0, buf, 2); 55412bd3c8bSSascha Wildner actlen -= 2; 55512bd3c8bSSascha Wildner len = buf[0] | (buf[1] << 8); 55612bd3c8bSSascha Wildner len = min(actlen, len); 55712bd3c8bSSascha Wildner 55812bd3c8bSSascha Wildner uether_rxbuf(ue, pc, 2, len); 55912bd3c8bSSascha Wildner /* FALLTHROUGH */ 56012bd3c8bSSascha Wildner case USB_ST_SETUP: 56112bd3c8bSSascha Wildner tr_setup: 56212bd3c8bSSascha Wildner usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); 56312bd3c8bSSascha Wildner usbd_transfer_submit(xfer); 56412bd3c8bSSascha Wildner uether_rxflush(ue); 56512bd3c8bSSascha Wildner return; 56612bd3c8bSSascha Wildner 56712bd3c8bSSascha Wildner default: /* Error */ 56812bd3c8bSSascha Wildner DPRINTF("bulk read error, %s\n", 56912bd3c8bSSascha Wildner usbd_errstr(error)); 57012bd3c8bSSascha Wildner 57112bd3c8bSSascha Wildner if (error != USB_ERR_CANCELLED) { 57212bd3c8bSSascha Wildner /* try to clear stall first */ 57312bd3c8bSSascha Wildner usbd_xfer_set_stall(xfer); 57412bd3c8bSSascha Wildner goto tr_setup; 57512bd3c8bSSascha Wildner } 57612bd3c8bSSascha Wildner return; 57712bd3c8bSSascha Wildner 57812bd3c8bSSascha Wildner } 57912bd3c8bSSascha Wildner } 58012bd3c8bSSascha Wildner 58112bd3c8bSSascha Wildner static void 58212bd3c8bSSascha Wildner kue_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error) 58312bd3c8bSSascha Wildner { 58412bd3c8bSSascha Wildner struct kue_softc *sc = usbd_xfer_softc(xfer); 58512bd3c8bSSascha Wildner struct ifnet *ifp = uether_getifp(&sc->sc_ue); 58612bd3c8bSSascha Wildner struct usb_page_cache *pc; 58712bd3c8bSSascha Wildner struct mbuf *m; 58812bd3c8bSSascha Wildner int total_len; 58912bd3c8bSSascha Wildner int temp_len; 59012bd3c8bSSascha Wildner uint8_t buf[2]; 59112bd3c8bSSascha Wildner 59212bd3c8bSSascha Wildner switch (USB_GET_STATE(xfer)) { 59312bd3c8bSSascha Wildner case USB_ST_TRANSFERRED: 59412bd3c8bSSascha Wildner DPRINTFN(11, "transfer complete\n"); 59512bd3c8bSSascha Wildner ifp->if_opackets++; 59612bd3c8bSSascha Wildner 59712bd3c8bSSascha Wildner /* FALLTHROUGH */ 59812bd3c8bSSascha Wildner case USB_ST_SETUP: 59912bd3c8bSSascha Wildner tr_setup: 60012bd3c8bSSascha Wildner IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 60112bd3c8bSSascha Wildner 60212bd3c8bSSascha Wildner if (m == NULL) 60312bd3c8bSSascha Wildner return; 60412bd3c8bSSascha Wildner if (m->m_pkthdr.len > MCLBYTES) 60512bd3c8bSSascha Wildner m->m_pkthdr.len = MCLBYTES; 60612bd3c8bSSascha Wildner temp_len = (m->m_pkthdr.len + 2); 60712bd3c8bSSascha Wildner total_len = (temp_len + (64 - (temp_len % 64))); 60812bd3c8bSSascha Wildner 60912bd3c8bSSascha Wildner /* the first two bytes are the frame length */ 61012bd3c8bSSascha Wildner 61112bd3c8bSSascha Wildner buf[0] = (uint8_t)(m->m_pkthdr.len); 61212bd3c8bSSascha Wildner buf[1] = (uint8_t)(m->m_pkthdr.len >> 8); 61312bd3c8bSSascha Wildner 61412bd3c8bSSascha Wildner pc = usbd_xfer_get_frame(xfer, 0); 61512bd3c8bSSascha Wildner usbd_copy_in(pc, 0, buf, 2); 61612bd3c8bSSascha Wildner usbd_m_copy_in(pc, 2, m, 0, m->m_pkthdr.len); 61712bd3c8bSSascha Wildner 61812bd3c8bSSascha Wildner usbd_frame_zero(pc, temp_len, total_len - temp_len); 61912bd3c8bSSascha Wildner usbd_xfer_set_frame_len(xfer, 0, total_len); 62012bd3c8bSSascha Wildner 62112bd3c8bSSascha Wildner /* 62212bd3c8bSSascha Wildner * if there's a BPF listener, bounce a copy 62312bd3c8bSSascha Wildner * of this frame to him: 62412bd3c8bSSascha Wildner */ 62512bd3c8bSSascha Wildner BPF_MTAP(ifp, m); 62612bd3c8bSSascha Wildner 62712bd3c8bSSascha Wildner m_freem(m); 62812bd3c8bSSascha Wildner 62912bd3c8bSSascha Wildner usbd_transfer_submit(xfer); 63012bd3c8bSSascha Wildner 63112bd3c8bSSascha Wildner return; 63212bd3c8bSSascha Wildner 63312bd3c8bSSascha Wildner default: /* Error */ 63412bd3c8bSSascha Wildner DPRINTFN(11, "transfer error, %s\n", 63512bd3c8bSSascha Wildner usbd_errstr(error)); 63612bd3c8bSSascha Wildner 63712bd3c8bSSascha Wildner ifp->if_oerrors++; 63812bd3c8bSSascha Wildner 63912bd3c8bSSascha Wildner if (error != USB_ERR_CANCELLED) { 64012bd3c8bSSascha Wildner /* try to clear stall first */ 64112bd3c8bSSascha Wildner usbd_xfer_set_stall(xfer); 64212bd3c8bSSascha Wildner goto tr_setup; 64312bd3c8bSSascha Wildner } 64412bd3c8bSSascha Wildner return; 64512bd3c8bSSascha Wildner 64612bd3c8bSSascha Wildner } 64712bd3c8bSSascha Wildner } 64812bd3c8bSSascha Wildner 64912bd3c8bSSascha Wildner static void 65012bd3c8bSSascha Wildner kue_start(struct usb_ether *ue) 65112bd3c8bSSascha Wildner { 65212bd3c8bSSascha Wildner struct kue_softc *sc = uether_getsc(ue); 65312bd3c8bSSascha Wildner 65412bd3c8bSSascha Wildner /* 65512bd3c8bSSascha Wildner * start the USB transfers, if not already started: 65612bd3c8bSSascha Wildner */ 65712bd3c8bSSascha Wildner usbd_transfer_start(sc->sc_xfer[KUE_BULK_DT_RD]); 65812bd3c8bSSascha Wildner usbd_transfer_start(sc->sc_xfer[KUE_BULK_DT_WR]); 65912bd3c8bSSascha Wildner } 66012bd3c8bSSascha Wildner 66112bd3c8bSSascha Wildner static void 66212bd3c8bSSascha Wildner kue_init(struct usb_ether *ue) 66312bd3c8bSSascha Wildner { 66412bd3c8bSSascha Wildner struct kue_softc *sc = uether_getsc(ue); 66512bd3c8bSSascha Wildner struct ifnet *ifp = uether_getifp(ue); 66612bd3c8bSSascha Wildner 66712bd3c8bSSascha Wildner KUE_LOCK_ASSERT(sc, MA_OWNED); 66812bd3c8bSSascha Wildner 66912bd3c8bSSascha Wildner /* set MAC address */ 67012bd3c8bSSascha Wildner kue_ctl(sc, KUE_CTL_WRITE, KUE_CMD_SET_MAC, 67112bd3c8bSSascha Wildner 0, IF_LLADDR(ifp), ETHER_ADDR_LEN); 67212bd3c8bSSascha Wildner 67312bd3c8bSSascha Wildner /* I'm not sure how to tune these. */ 67412bd3c8bSSascha Wildner #if 0 67512bd3c8bSSascha Wildner /* 67612bd3c8bSSascha Wildner * Leave this one alone for now; setting it 67712bd3c8bSSascha Wildner * wrong causes lockups on some machines/controllers. 67812bd3c8bSSascha Wildner */ 67912bd3c8bSSascha Wildner kue_setword(sc, KUE_CMD_SET_SOFS, 1); 68012bd3c8bSSascha Wildner #endif 68112bd3c8bSSascha Wildner kue_setword(sc, KUE_CMD_SET_URB_SIZE, 64); 68212bd3c8bSSascha Wildner 68312bd3c8bSSascha Wildner /* load the multicast filter */ 68412bd3c8bSSascha Wildner kue_setpromisc(ue); 68512bd3c8bSSascha Wildner 68612bd3c8bSSascha Wildner usbd_xfer_set_stall(sc->sc_xfer[KUE_BULK_DT_WR]); 68712bd3c8bSSascha Wildner 68812bd3c8bSSascha Wildner ifp->if_drv_flags |= IFF_DRV_RUNNING; 68912bd3c8bSSascha Wildner kue_start(ue); 69012bd3c8bSSascha Wildner } 69112bd3c8bSSascha Wildner 69212bd3c8bSSascha Wildner static void 69312bd3c8bSSascha Wildner kue_stop(struct usb_ether *ue) 69412bd3c8bSSascha Wildner { 69512bd3c8bSSascha Wildner struct kue_softc *sc = uether_getsc(ue); 69612bd3c8bSSascha Wildner struct ifnet *ifp = uether_getifp(ue); 69712bd3c8bSSascha Wildner 69812bd3c8bSSascha Wildner KUE_LOCK_ASSERT(sc, MA_OWNED); 69912bd3c8bSSascha Wildner 70012bd3c8bSSascha Wildner ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 70112bd3c8bSSascha Wildner 70212bd3c8bSSascha Wildner /* 70312bd3c8bSSascha Wildner * stop all the transfers, if not already stopped: 70412bd3c8bSSascha Wildner */ 70512bd3c8bSSascha Wildner usbd_transfer_stop(sc->sc_xfer[KUE_BULK_DT_WR]); 70612bd3c8bSSascha Wildner usbd_transfer_stop(sc->sc_xfer[KUE_BULK_DT_RD]); 70712bd3c8bSSascha Wildner } 708