summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb/if_kue.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/usb/if_kue.c')
-rw-r--r--sys/dev/usb/if_kue.c60
1 files changed, 59 insertions, 1 deletions
diff --git a/sys/dev/usb/if_kue.c b/sys/dev/usb/if_kue.c
index f26bc2c..890d0f7 100644
--- a/sys/dev/usb/if_kue.c
+++ b/sys/dev/usb/if_kue.c
@@ -33,11 +33,33 @@
*/
/*
+ * Kawasaki LSI KL5KUSB101B USB to ethernet adapter driver.
+ *
* Written by Bill Paul <wpaul@ee.columbia.edu>
* Electrical Engineering Department
* Columbia University, New York City
*/
+/*
+ * The KLSI USB to ethernet adapter chip contains an USB serial interface,
+ * ethernet MAC and embedded microcontroller (called the QT Engine).
+ * The chip must have firmware loaded into it before it will operate.
+ * Packets are passed between the chip and host via bulk transfers.
+ * There is an interrupt endpoint mentioned in the software spec, however
+ * it's currently unused. This device is 10Mbps half-duplex only, hence
+ * there is no media selection logic. The MAC supports a 128 entry
+ * multicast filter, though the exact size of the filter can depend
+ * on the firmware. Curiously, while the software spec describes various
+ * ethernet statistics counters, my sample adapter and firmware combination
+ * claims not to support any statistics counters at all.
+ *
+ * Note that once we load the firmware in the device, we have to be
+ * careful not to load it again: if you restart your computer but
+ * leave the adapter attached to the USB controller, it may remain
+ * powered on and retain its firmware. In this case, we don't need
+ * to load the firmware a second time.
+ */
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/sockio.h>
@@ -69,6 +91,7 @@
#include <dev/usb/usbdi_util.h>
#include <dev/usb/usbdivar.h>
#include <dev/usb/usbdevs.h>
+#include <dev/usb/usb_quirks.h>
#include <dev/usb/if_kuereg.h>
#include <dev/usb/kue_fw.h>
@@ -234,6 +257,27 @@ static int kue_load_fw(sc)
struct kue_softc *sc;
{
usbd_status err;
+ u_int8_t eaddr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+
+ /*
+ * First, check if we even need to load the firmware.
+ * If the device was still attached when the system was
+ * rebooted, it may already have firmware loaded in it.
+ * If this is the case, we don't need to do it again.
+ * And in fact, if we try to load it again, we'll hang,
+ * so we have to avoid this condition if we don't want
+ * to look stupid.
+ *
+ * We can test this quickly by trying to read the MAC
+ * address; if this fails to return any data, the firmware
+ * needs to be reloaded, otherwise the device is already
+ * operational and we can just return.
+ */
+ err = kue_ctl(sc, KUE_CTL_READ, KUE_CMD_GET_MAC,
+ 0, (char *)&eaddr, ETHER_ADDR_LEN);
+
+ if (bcmp(eaddr, etherbroadcastaddr, ETHER_ADDR_LEN))
+ return(USBD_NORMAL_COMPLETION);
/* Load code segment */
err = kue_ctl(sc, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN,
@@ -257,7 +301,7 @@ static int kue_load_fw(sc)
err = kue_ctl(sc, KUE_CTL_WRITE, KUE_CMD_SEND_SCAN,
0, kue_trig_seg, sizeof(kue_trig_seg));
if (err) {
- printf("kue%d: failed to load fixup segment: %s\n",
+ printf("kue%d: failed to load trigger segment: %s\n",
sc->kue_unit, usbd_errstr(err));
return(ENXIO);
}
@@ -333,14 +377,28 @@ USB_MATCH(kue)
{
USB_MATCH_START(kue, uaa);
struct kue_type *t;
+ usb_device_descriptor_t *dd;
if (!uaa->iface)
return(UMATCH_NONE);
+ dd = &uaa->device->ddesc;
+
t = kue_devs;
while(t->kue_name != NULL) {
if (uaa->vendor == t->kue_vid &&
uaa->product == t->kue_did) {
+ /*
+ * Force the revision code and then rescan the
+ * quirks so that we get the right quirk bits set.
+ * Why? The chip without the firmware loaded returns
+ * one revision code. The chip with the firmware
+ * loaded and running returns a *different* revision
+ * code. This confuses the quirk mechanism, which is
+ * dependent on the revision data.
+ */
+ USETW(dd->bcdDevice, 0x002);
+ uaa->device->quirks = usbd_find_quirk(dd);
device_set_desc(self, t->kue_name);
return(UMATCH_VENDOR_PRODUCT);
}
OpenPOWER on IntegriCloud