summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwpaul <wpaul@FreeBSD.org>2003-04-20 19:05:33 +0000
committerwpaul <wpaul@FreeBSD.org>2003-04-20 19:05:33 +0000
commite41f6225faec622d3f1ce943cff4e3647d65df97 (patch)
tree97ca9c3274a2a29ea03460b6181e805043e61e46
parentdce3b02b367216359cd6e26f70d0d523caf70ab3 (diff)
downloadFreeBSD-src-e41f6225faec622d3f1ce943cff4e3647d65df97.zip
FreeBSD-src-e41f6225faec622d3f1ce943cff4e3647d65df97.tar.gz
Add device driver support for the ASIX Electronics AX88172 USB 2.0
ethernet controller. The driver has been tested with the LinkSys USB200M adapter. I know for a fact that there are other devices out there with this chip but don't have all the USB vendor/device IDs. Note: I'm not sure if this will force the driver to end up in the install kernel image or not. Special magic needs to be done to exclude it to keep the boot floppies from bloating again, someone please advise.
-rw-r--r--share/man/man4/Makefile1
-rw-r--r--share/man/man4/axe.4144
-rw-r--r--sys/alpha/conf/GENERIC1
-rw-r--r--sys/amd64/conf/GENERIC1
-rw-r--r--sys/conf/files1
-rw-r--r--sys/dev/usb/if_axe.c1192
-rw-r--r--sys/dev/usb/if_axereg.h178
-rw-r--r--sys/dev/usb/usbdevs4
-rw-r--r--sys/i386/conf/GENERIC1
-rw-r--r--sys/modules/Makefile1
-rw-r--r--sys/modules/axe/Makefile10
-rw-r--r--sys/modules/netgraph/Makefile1
-rw-r--r--sys/pc98/conf/GENERIC1
-rw-r--r--sys/sparc64/conf/GENERIC1
-rw-r--r--usr.sbin/sade/devices.c1
-rw-r--r--usr.sbin/sysinstall/devices.c1
16 files changed, 1539 insertions, 0 deletions
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
index 6d8eed0..3d8fba4 100644
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -20,6 +20,7 @@ MAN= aac.4 \
atkbdc.4 \
aue.4 \
awi.4 \
+ axe.4 \
bge.4 \
bktr.4 \
blackhole.4 \
diff --git a/share/man/man4/axe.4 b/share/man/man4/axe.4
new file mode 100644
index 0000000..9113c28
--- /dev/null
+++ b/share/man/man4/axe.4
@@ -0,0 +1,144 @@
+.\" Copyright (c) 1997, 1998, 1999, 2000-2003
+.\" Bill Paul <wpaul@windriver.com>. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Bill Paul.
+.\" 4. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+.\" THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd April 20, 2003
+.Dt AXE 4
+.Os
+.Sh NAME
+.Nm axe
+.Nd ASIX Electronics AX88172 USB Ethernet driver
+.Sh SYNOPSIS
+.Cd "device ehci"
+.Cd "device uhci"
+.Cd "device ohci"
+.Cd "device usb"
+.Cd "device miibus"
+.Cd "device axe"
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for USB ethernet adapters based on the ASIX
+Electronics AX88172 USB 2.0 chipset, including the LinkSys USB200M.
+.Pp
+The AX88172 is a USB 2.0 device which contains a 10/100
+ethernet MAC with MII interface and is designed to work with both
+ethernet and HomePNA transceivers. The AX88172 will operate with
+both USB 1.x and USB 2.0 controllers, however performace with 1.x
+contollers will be limited since the USB 1.x standard specifies a
+maximum transfer speed of 12Mbps.
+Users with USB 1.x controllers should therefore not expect to actually
+achieve 100Mbps speeds with these devices.
+.Pp
+The AX88172 supports a 64-bit multicast hash table, single perfect
+filter entry for the station address, all-multicast mode and promiscuous mode.
+Packets are
+received and transmitted over separate USB bulk transfer endpoints.
+.Pp
+The
+.Nm
+driver supports the following media types:
+.Pp
+.Bl -tag -width xxxxxxxxxxxxxxxxxxxx
+.It autoselect
+Enable autoselection of the media type and options.
+The user can manually override
+the autoselected mode by adding media options to the
+.Pa /etc/rc.conf
+file.
+.It 10baseT/UTP
+Set 10Mbps operation.
+The
+.Ar mediaopt
+option can also be used to enable
+.Ar full-duplex
+operation.
+Not specifying
+.Ar full duplex
+implies
+.Ar half-duplex
+mode.
+.It 100baseTX
+Set 100Mbps (fast ethernet) operation.
+The
+.Ar mediaopt
+option can also be used to enable
+.Ar full-duplex
+operation.
+Not specifying
+.Ar full duplex
+implies
+.Ar half-duplex
+mode.
+.El
+.Pp
+The
+.Nm
+driver supports the following media options:
+.Pp
+.Bl -tag -width xxxxxxxxxxxxxxxxxxxx
+.It full-duplex
+Force full duplex operation.
+The interface will operate in
+half duplex mode if this media option is not specified.
+.El
+.Pp
+For more information on configuring this device, see
+.Xr ifconfig 8 .
+.Sh DIAGNOSTICS
+.Bl -diag
+.It "axe%d: watchdog timeout"
+A packet was queued for transmission and a transmit command was
+issued, however the device failed to acknowledge the transmission
+before a timeout expired.
+.It "axe%d: no memory for rx list"
+The driver failed to allocate an mbuf for the receiver ring.
+.El
+.Sh SEE ALSO
+.Xr arp 4 ,
+.Xr miibus 4 ,
+.Xr netintro 4 ,
+.Xr ng_ether 4 ,
+.Xr ifconfig 8
+.Rs
+.%T ASIX AX88172 data sheet
+.%O http://www.asix.com.tw
+.Re
+.Sh HISTORY
+The
+.Nm
+device driver first appeared in
+.Fx 5.0 .
+.Sh AUTHORS
+The
+.Nm
+driver was written by
+.An Bill Paul Aq wpaul@windriver.com .
diff --git a/sys/alpha/conf/GENERIC b/sys/alpha/conf/GENERIC
index 13d01c1..5854ad5 100644
--- a/sys/alpha/conf/GENERIC
+++ b/sys/alpha/conf/GENERIC
@@ -184,5 +184,6 @@ device umass # Disks/Mass storage - Requires scbus and da0
device ums # Mouse
# USB Ethernet
device aue # ADMtek USB ethernet
+device axe # ASIX Electronics USB ethernet
device cue # CATC USB ethernet
device kue # Kawasaki LSI USB ethernet
diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC
index 730261b..34ad789 100644
--- a/sys/amd64/conf/GENERIC
+++ b/sys/amd64/conf/GENERIC
@@ -252,5 +252,6 @@ device urio # Diamond Rio 500 MP3 player
device uscanner # Scanners
# USB Ethernet, requires mii
device aue # ADMtek USB ethernet
+device axe # ASIX Electronics USB ethernet
device cue # CATC USB ethernet
device kue # Kawasaki LSI USB ethernet
diff --git a/sys/conf/files b/sys/conf/files
index 45f0ecf..85142d2 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -754,6 +754,7 @@ dev/ubsec/ubsec.c optional ubsec
dev/usb/usb_if.m optional usb
dev/usb/hid.c optional usb
dev/usb/if_aue.c optional aue
+dev/usb/if_axe.c optional axe
dev/usb/if_cue.c optional cue
dev/usb/if_kue.c optional kue
dev/usb/ehci.c optional ehci
diff --git a/sys/dev/usb/if_axe.c b/sys/dev/usb/if_axe.c
new file mode 100644
index 0000000..5c243fa
--- /dev/null
+++ b/sys/dev/usb/if_axe.c
@@ -0,0 +1,1192 @@
+/*
+ * Copyright (c) 1997, 1998, 1999, 2000-2003
+ * Bill Paul <wpaul@windriver.com>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * ASIX Electronics AX88172 USB 2.0 ethernet driver. Used in the
+ * LinkSys USB200M and various other adapters.
+ *
+ * Manuals available from:
+ * http://www.asix.com.tw/datasheet/mac/Ax88172.PDF
+ * Note: you need the manual for the AX88170 chip (USB 1.x ethernet
+ * controller) to find the definitions for the RX control register.
+ * http://www.asix.com.tw/datasheet/mac/Ax88170.PDF
+ *
+ * Written by Bill Paul <wpaul@windriver.com>
+ * Senior Engineer
+ * Wind River Systems
+ */
+
+/*
+ * The AX88172 provides USB ethernet supports at 10 and 100Mbps.
+ * It uses an external PHY (reference designs use a RealTek chip),
+ * and has a 64-bit multicast hash filter. There is some information
+ * missing from the manual which one needs to know in order to make
+ * the chip function:
+ *
+ * - You must set bit 7 in the RX control register, otherwise the
+ * chip won't receive any packets.
+ * - You must initialize all 3 IPG registers, or you won't be able
+ * to send any packets.
+ *
+ * Note that this device appears to only support loading the station
+ * address via autload from the EEPROM (i.e. there's no way to manaully
+ * set it).
+ *
+ * (Adam Weinberger wanted me to name this driver if_gir.c.)
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+
+#include <net/bpf.h>
+
+#include <sys/bus.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdi_util.h>
+#include <dev/usb/usbdivar.h>
+#include <dev/usb/usbdevs.h>
+#include <dev/usb/usb_ethersubr.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+/* "controller miibus0" required. See GENERIC if you get errors here. */
+#include "miibus_if.h"
+
+#include <dev/usb/if_axereg.h>
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif
+
+/*
+ * Various supported device vendors/products.
+ */
+Static struct axe_type axe_devs[] = {
+ { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88172 },
+ { 0, 0 }
+};
+
+Static struct usb_qdat axe_qdat;
+
+Static int axe_match(device_ptr_t);
+Static int axe_attach(device_ptr_t);
+Static int axe_detach(device_ptr_t);
+
+Static int axe_tx_list_init(struct axe_softc *);
+Static int axe_rx_list_init(struct axe_softc *);
+Static int axe_newbuf(struct axe_softc *, struct axe_chain *, struct mbuf *);
+Static int axe_encap(struct axe_softc *, struct mbuf *, int);
+Static void axe_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
+Static void axe_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
+Static void axe_tick(void *);
+Static void axe_rxstart(struct ifnet *);
+Static void axe_start(struct ifnet *);
+Static int axe_ioctl(struct ifnet *, u_long, caddr_t);
+Static void axe_init(void *);
+Static void axe_stop(struct axe_softc *);
+Static void axe_watchdog(struct ifnet *);
+Static void axe_shutdown(device_ptr_t);
+Static int axe_miibus_readreg(device_ptr_t, int, int);
+Static int axe_miibus_writereg(device_ptr_t, int, int, int);
+Static void axe_miibus_statchg(device_ptr_t);
+Static int axe_cmd(struct axe_softc *, int, int, int, void *);
+Static int axe_ifmedia_upd(struct ifnet *);
+Static void axe_ifmedia_sts(struct ifnet *, struct ifmediareq *);
+
+Static void axe_setmulti(struct axe_softc *);
+Static u_int32_t axe_crc(caddr_t);
+
+Static device_method_t axe_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, axe_match),
+ DEVMETHOD(device_attach, axe_attach),
+ DEVMETHOD(device_detach, axe_detach),
+ DEVMETHOD(device_shutdown, axe_shutdown),
+
+ /* bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+
+ /* MII interface */
+ DEVMETHOD(miibus_readreg, axe_miibus_readreg),
+ DEVMETHOD(miibus_writereg, axe_miibus_writereg),
+ DEVMETHOD(miibus_statchg, axe_miibus_statchg),
+
+ { 0, 0 }
+};
+
+Static driver_t axe_driver = {
+ "axe",
+ axe_methods,
+ sizeof(struct axe_softc)
+};
+
+Static devclass_t axe_devclass;
+
+DRIVER_MODULE(axe, uhub, axe_driver, axe_devclass, usbd_driver_load, 0);
+DRIVER_MODULE(miibus, axe, miibus_driver, miibus_devclass, 0, 0);
+MODULE_DEPEND(axe, usb, 1, 1, 1);
+MODULE_DEPEND(axe, miibus, 1, 1, 1);
+
+Static int
+axe_cmd(struct axe_softc *sc, int cmd, int index, int val, void *buf)
+{
+ usb_device_request_t req;
+ usbd_status err;
+
+ if (sc->axe_dying)
+ return(0);
+
+ if (AXE_CMD_DIR(cmd))
+ req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+ else
+ req.bmRequestType = UT_READ_VENDOR_DEVICE;
+ req.bRequest = AXE_CMD_CMD(cmd);
+ USETW(req.wValue, val);
+ USETW(req.wIndex, index);
+ USETW(req.wLength, AXE_CMD_LEN(cmd));
+
+ err = usbd_do_request(sc->axe_udev, &req, buf);
+
+ if (err)
+ return(-1);
+
+ return(0);
+}
+
+Static int
+axe_miibus_readreg(device_ptr_t dev, int phy, int reg)
+{
+ struct axe_softc *sc = USBGETSOFTC(dev);
+ usbd_status err;
+ u_int16_t val;
+
+ if (sc->axe_dying)
+ return(0);
+
+ /*
+ * The chip tells us the MII address of any supported
+ * PHYs attached to the chip, so only read from those.
+ */
+
+ if (sc->axe_phyaddrs[0] != AXE_NOPHY && phy != sc->axe_phyaddrs[0])
+ return (0);
+
+ if (sc->axe_phyaddrs[1] != AXE_NOPHY && phy != sc->axe_phyaddrs[1])
+ return (0);
+
+ AXE_LOCK(sc);
+ axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL);
+ err = axe_cmd(sc, AXE_CMD_MII_READ_REG, reg, phy, (void *)&val);
+ axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL);
+ AXE_UNLOCK(sc);
+
+ if (err) {
+ printf("axe%d: read PHY failed\n", sc->axe_unit);
+ return(-1);
+ }
+
+ return (val);
+}
+
+Static int
+axe_miibus_writereg(device_ptr_t dev, int phy, int reg, int val)
+{
+ struct axe_softc *sc = USBGETSOFTC(dev);
+ usbd_status err;
+
+ if (sc->axe_dying)
+ return(0);
+
+ AXE_LOCK(sc);
+ axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL);
+ err = axe_cmd(sc, AXE_CMD_MII_WRITE_REG, reg, phy, (void *)&val);
+ axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL);
+ AXE_UNLOCK(sc);
+
+ if (err) {
+ printf("axe%d: write PHY failed\n", sc->axe_unit);
+ return(-1);
+ }
+
+ return (0);
+}
+
+Static void
+axe_miibus_statchg(device_ptr_t dev)
+{
+#ifdef notdef
+ struct axe_softc *sc = USBGETSOFTC(dev);
+ struct mii_data *mii = GET_MII(sc);
+#endif
+ /* doesn't seem to be necessary */
+
+ return;
+}
+
+/*
+ * Set media options.
+ */
+Static int
+axe_ifmedia_upd(struct ifnet *ifp)
+{
+ struct axe_softc *sc = ifp->if_softc;
+ struct mii_data *mii = GET_MII(sc);
+
+ sc->axe_link = 0;
+ if (mii->mii_instance) {
+ struct mii_softc *miisc;
+ LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
+ mii_phy_reset(miisc);
+ }
+ mii_mediachg(mii);
+
+ return (0);
+}
+
+/*
+ * Report current media status.
+ */
+Static void
+axe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+ struct axe_softc *sc = ifp->if_softc;
+ struct mii_data *mii = GET_MII(sc);
+
+ mii_pollstat(mii);
+ ifmr->ifm_active = mii->mii_media_active;
+ ifmr->ifm_status = mii->mii_media_status;
+
+ return;
+}
+
+Static u_int32_t
+axe_crc(caddr_t addr)
+{
+ u_int32_t crc, carry;
+ int i, j;
+ u_int8_t c;
+
+ /* Compute CRC for the address value. */
+ crc = 0xFFFFFFFF; /* initial value */
+
+ for (i = 0; i < 6; i++) {
+ c = *(addr + i);
+ for (j = 0; j < 8; j++) {
+ carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01);
+ crc <<= 1;
+ c >>= 1;
+ if (carry)
+ crc = (crc ^ 0x04c11db6) | carry;
+ }
+ }
+
+ /* return the filter bit position */
+ return((crc >> 26) & 0x0000003F);
+}
+
+Static void
+axe_setmulti(struct axe_softc *sc)
+{
+ struct ifnet *ifp;
+ struct ifmultiaddr *ifma;
+ u_int32_t h = 0;
+ u_int16_t rxmode;
+ u_int8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ ifp = &sc->arpcom.ac_if;
+
+ AXE_LOCK(sc);
+ axe_cmd(sc, AXE_CMD_RXCTL_READ, 0, 0, (void *)&rxmode);
+
+ if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
+ rxmode |= AXE_RXCMD_ALLMULTI;
+ axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL);
+ AXE_UNLOCK(sc);
+ return;
+ } else
+ rxmode &= ~AXE_RXCMD_ALLMULTI;
+
+ TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+ if (ifma->ifma_addr->sa_family != AF_LINK)
+ continue;
+ h = axe_crc(LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
+ hashtbl[h / 8] |= 1 << (h % 8);
+ }
+
+ axe_cmd(sc, AXE_CMD_WRITE_MCAST, 0, 0, (void *)&hashtbl);
+ axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL);
+ AXE_UNLOCK(sc);
+
+ return;
+}
+
+Static void
+axe_reset(struct axe_softc *sc)
+{
+ if (sc->axe_dying)
+ return;
+
+ if (usbd_set_config_no(sc->axe_udev, AXE_CONFIG_NO, 1) ||
+ usbd_device2interface_handle(sc->axe_udev, 0 /*AXE_IFACE_IDX*/,
+ &sc->axe_iface)) {
+ printf("axe%d: getting interface handle failed\n",
+ sc->axe_unit);
+ }
+
+ /* Wait a little while for the chip to get its brains in order. */
+ DELAY(1000);
+ return;
+}
+
+/*
+ * Probe for a AX88172 chip.
+ */
+USB_MATCH(axe)
+{
+ USB_MATCH_START(axe, uaa);
+ struct axe_type *t;
+
+ if (!uaa->iface)
+ return(UMATCH_NONE);
+
+ t = axe_devs;
+ while(t->axe_vid) {
+ if (uaa->vendor == t->axe_vid &&
+ uaa->product == t->axe_did) {
+ return(UMATCH_VENDOR_PRODUCT);
+ }
+ t++;
+ }
+
+ return(UMATCH_NONE);
+}
+
+/*
+ * Attach the interface. Allocate softc structures, do ifmedia
+ * setup and ethernet/BPF attach.
+ */
+USB_ATTACH(axe)
+{
+ USB_ATTACH_START(axe, sc, uaa);
+ char devinfo[1024];
+ u_char eaddr[ETHER_ADDR_LEN];
+ struct ifnet *ifp;
+ usb_interface_descriptor_t *id;
+ usb_endpoint_descriptor_t *ed;
+ int i;
+
+ bzero(sc, sizeof(struct axe_softc));
+ sc->axe_iface = uaa->iface;
+ sc->axe_udev = uaa->device;
+ sc->axe_dev = self;
+ sc->axe_unit = device_get_unit(self);
+
+ if (usbd_set_config_no(sc->axe_udev, AXE_CONFIG_NO, 1)) {
+ printf("axe%d: getting interface handle failed\n",
+ sc->axe_unit);
+ USB_ATTACH_ERROR_RETURN;
+ }
+
+ id = usbd_get_interface_descriptor(uaa->iface);
+
+ usbd_devinfo(uaa->device, 0, devinfo);
+ device_set_desc_copy(self, devinfo);
+ printf("%s: %s\n", USBDEVNAME(self), devinfo);
+
+ /* Find endpoints. */
+ for (i = 0; i < id->bNumEndpoints; i++) {
+ ed = usbd_interface2endpoint_descriptor(uaa->iface, i);
+ if (!ed) {
+ printf("axe%d: couldn't get ep %d\n",
+ sc->axe_unit, i);
+ USB_ATTACH_ERROR_RETURN;
+ }
+ if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
+ UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
+ sc->axe_ed[AXE_ENDPT_RX] = ed->bEndpointAddress;
+ } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
+ UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
+ sc->axe_ed[AXE_ENDPT_TX] = ed->bEndpointAddress;
+ } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
+ UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
+ sc->axe_ed[AXE_ENDPT_INTR] = ed->bEndpointAddress;
+ }
+ }
+
+ mtx_init(&sc->axe_mtx, device_get_nameunit(self), MTX_NETWORK_LOCK,
+ MTX_DEF | MTX_RECURSE);
+ AXE_LOCK(sc);
+
+ /*
+ * Get station address.
+ */
+ axe_cmd(sc, AXE_CMD_READ_NODEID, 0, 0, &eaddr);
+
+ /*
+ * Load IPG values and PHY indexes.
+ */
+ axe_cmd(sc, AXE_CMD_READ_IPG012, 0, 0, (void *)&sc->axe_ipgs);
+ axe_cmd(sc, AXE_CMD_READ_PHYID, 0, 0, (void *)&sc->axe_phyaddrs);
+
+ /*
+ * An ASIX chip was detected. Inform the world.
+ */
+ printf("axe%d: Ethernet address: %6D\n", sc->axe_unit, eaddr, ":");
+
+ bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
+
+ ifp = &sc->arpcom.ac_if;
+ ifp->if_softc = sc;
+ ifp->if_unit = sc->axe_unit;
+ ifp->if_name = "axe";
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_ioctl = axe_ioctl;
+ ifp->if_output = ether_output;
+ ifp->if_start = axe_start;
+ ifp->if_watchdog = axe_watchdog;
+ ifp->if_init = axe_init;
+ ifp->if_baudrate = 10000000;
+ ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
+
+ axe_qdat.ifp = ifp;
+ axe_qdat.if_rxstart = axe_rxstart;
+
+ if (mii_phy_probe(self, &sc->axe_miibus,
+ axe_ifmedia_upd, axe_ifmedia_sts)) {
+ printf("axe%d: MII without any PHY!\n", sc->axe_unit);
+ AXE_UNLOCK(sc);
+ mtx_destroy(&sc->axe_mtx);
+ USB_ATTACH_ERROR_RETURN;
+ }
+
+ /*
+ * Call MI attach routine.
+ */
+
+ ether_ifattach(ifp, eaddr);
+ callout_handle_init(&sc->axe_stat_ch);
+ usb_register_netisr();
+
+ sc->axe_dying = 0;
+
+ AXE_UNLOCK(sc);
+
+ USB_ATTACH_SUCCESS_RETURN;
+}
+
+Static int
+axe_detach(device_ptr_t dev)
+{
+ struct axe_softc *sc;
+ struct ifnet *ifp;
+
+ sc = device_get_softc(dev);
+ AXE_LOCK(sc);
+ ifp = &sc->arpcom.ac_if;
+
+ sc->axe_dying = 1;
+ untimeout(axe_tick, sc, sc->axe_stat_ch);
+ ether_ifdetach(ifp);
+
+ if (sc->axe_ep[AXE_ENDPT_TX] != NULL)
+ usbd_abort_pipe(sc->axe_ep[AXE_ENDPT_TX]);
+ if (sc->axe_ep[AXE_ENDPT_RX] != NULL)
+ usbd_abort_pipe(sc->axe_ep[AXE_ENDPT_RX]);
+ if (sc->axe_ep[AXE_ENDPT_INTR] != NULL)
+ usbd_abort_pipe(sc->axe_ep[AXE_ENDPT_INTR]);
+
+ AXE_UNLOCK(sc);
+ mtx_destroy(&sc->axe_mtx);
+
+ return(0);
+}
+
+/*
+ * Initialize an RX descriptor and attach an MBUF cluster.
+ */
+Static int
+axe_newbuf(struct axe_softc *sc, struct axe_chain *c, struct mbuf *m)
+{
+ struct mbuf *m_new = NULL;
+
+ if (m == NULL) {
+ m_new = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+ if (m_new == NULL) {
+ printf("axe%d: no memory for rx list "
+ "-- packet dropped!\n", sc->axe_unit);
+ return(ENOBUFS);
+ }
+ m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
+ } else {
+ m_new = m;
+ m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
+ m_new->m_data = m_new->m_ext.ext_buf;
+ }
+
+ m_adj(m_new, ETHER_ALIGN);
+ c->axe_mbuf = m_new;
+
+ return(0);
+}
+
+Static int
+axe_rx_list_init(struct axe_softc *sc)
+{
+ struct axe_cdata *cd;
+ struct axe_chain *c;
+ int i;
+
+ cd = &sc->axe_cdata;
+ for (i = 0; i < AXE_RX_LIST_CNT; i++) {
+ c = &cd->axe_rx_chain[i];
+ c->axe_sc = sc;
+ c->axe_idx = i;
+ if (axe_newbuf(sc, c, NULL) == ENOBUFS)
+ return(ENOBUFS);
+ if (c->axe_xfer == NULL) {
+ c->axe_xfer = usbd_alloc_xfer(sc->axe_udev);
+ if (c->axe_xfer == NULL)
+ return(ENOBUFS);
+ }
+ }
+
+ return(0);
+}
+
+Static int
+axe_tx_list_init(struct axe_softc *sc)
+{
+ struct axe_cdata *cd;
+ struct axe_chain *c;
+ int i;
+
+ cd = &sc->axe_cdata;
+ for (i = 0; i < AXE_TX_LIST_CNT; i++) {
+ c = &cd->axe_tx_chain[i];
+ c->axe_sc = sc;
+ c->axe_idx = i;
+ c->axe_mbuf = NULL;
+ if (c->axe_xfer == NULL) {
+ c->axe_xfer = usbd_alloc_xfer(sc->axe_udev);
+ if (c->axe_xfer == NULL)
+ return(ENOBUFS);
+ }
+ c->axe_buf = malloc(AXE_BUFSZ, M_USBDEV, M_NOWAIT);
+ if (c->axe_buf == NULL)
+ return(ENOBUFS);
+ }
+
+ return(0);
+}
+
+Static void
+axe_rxstart(struct ifnet *ifp)
+{
+ struct axe_softc *sc;
+ struct axe_chain *c;
+
+ sc = ifp->if_softc;
+ AXE_LOCK(sc);
+ c = &sc->axe_cdata.axe_rx_chain[sc->axe_cdata.axe_rx_prod];
+
+ if (axe_newbuf(sc, c, NULL) == ENOBUFS) {
+ ifp->if_ierrors++;
+ AXE_UNLOCK(sc);
+ return;
+ }
+
+ /* Setup new transfer. */
+ usbd_setup_xfer(c->axe_xfer, sc->axe_ep[AXE_ENDPT_RX],
+ c, mtod(c->axe_mbuf, char *), AXE_BUFSZ, USBD_SHORT_XFER_OK,
+ USBD_NO_TIMEOUT, axe_rxeof);
+ usbd_transfer(c->axe_xfer);
+ AXE_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * A frame has been uploaded: pass the resulting mbuf chain up to
+ * the higher level protocols.
+ */
+Static void
+axe_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
+{
+ struct axe_softc *sc;
+ struct axe_chain *c;
+ struct mbuf *m;
+ struct ifnet *ifp;
+ int total_len = 0;
+
+ c = priv;
+ sc = c->axe_sc;
+ AXE_LOCK(sc);
+ ifp = &sc->arpcom.ac_if;
+
+ if (!(ifp->if_flags & IFF_RUNNING)) {
+ AXE_UNLOCK(sc);
+ return;
+ }
+
+ if (status != USBD_NORMAL_COMPLETION) {
+ if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
+ AXE_UNLOCK(sc);
+ return;
+ }
+ if (usbd_ratecheck(&sc->axe_rx_notice))
+ printf("axe%d: usb error on rx: %s\n", sc->axe_unit,
+ usbd_errstr(status));
+ if (status == USBD_STALLED)
+ usbd_clear_endpoint_stall(sc->axe_ep[AXE_ENDPT_RX]);
+ goto done;
+ }
+
+ usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
+
+ m = c->axe_mbuf;
+
+ if (total_len < sizeof(struct ether_header)) {
+ ifp->if_ierrors++;
+ goto done;
+ }
+
+ ifp->if_ipackets++;
+ m->m_pkthdr.rcvif = (struct ifnet *)&axe_qdat;
+ m->m_pkthdr.len = m->m_len = total_len;
+
+ /* Put the packet on the special USB input queue. */
+ usb_ether_input(m);
+ AXE_UNLOCK(sc);
+
+ return;
+done:
+ /* Setup new transfer. */
+ usbd_setup_xfer(c->axe_xfer, sc->axe_ep[AXE_ENDPT_RX],
+ c, mtod(c->axe_mbuf, char *), AXE_BUFSZ, USBD_SHORT_XFER_OK,
+ USBD_NO_TIMEOUT, axe_rxeof);
+ usbd_transfer(c->axe_xfer);
+ AXE_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * A frame was downloaded to the chip. It's safe for us to clean up
+ * the list buffers.
+ */
+
+Static void
+axe_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
+{
+ struct axe_softc *sc;
+ struct axe_chain *c;
+ struct ifnet *ifp;
+ usbd_status err;
+
+ c = priv;
+ sc = c->axe_sc;
+ AXE_LOCK(sc);
+ ifp = &sc->arpcom.ac_if;
+
+ if (status != USBD_NORMAL_COMPLETION) {
+ if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
+ AXE_UNLOCK(sc);
+ return;
+ }
+ printf("axe%d: usb error on tx: %s\n", sc->axe_unit,
+ usbd_errstr(status));
+ if (status == USBD_STALLED)
+ usbd_clear_endpoint_stall(sc->axe_ep[AXE_ENDPT_TX]);
+ AXE_UNLOCK(sc);
+ return;
+ }
+
+ ifp->if_timer = 0;
+ ifp->if_flags &= ~IFF_OACTIVE;
+ usbd_get_xfer_status(c->axe_xfer, NULL, NULL, NULL, &err);
+
+ if (c->axe_mbuf != NULL) {
+ c->axe_mbuf->m_pkthdr.rcvif = ifp;
+ usb_tx_done(c->axe_mbuf);
+ c->axe_mbuf = NULL;
+ }
+
+ if (err)
+ ifp->if_oerrors++;
+ else
+ ifp->if_opackets++;
+
+ AXE_UNLOCK(sc);
+
+ return;
+}
+
+Static void
+axe_tick(void *xsc)
+{
+ struct axe_softc *sc;
+ struct ifnet *ifp;
+ struct mii_data *mii;
+
+ sc = xsc;
+
+ if (sc == NULL)
+ return;
+
+ AXE_LOCK(sc);
+
+ ifp = &sc->arpcom.ac_if;
+ mii = GET_MII(sc);
+ if (mii == NULL) {
+ AXE_UNLOCK(sc);
+ return;
+ }
+
+ mii_tick(mii);
+ if (!sc->axe_link && mii->mii_media_status & IFM_ACTIVE &&
+ IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
+ sc->axe_link++;
+ if (ifp->if_snd.ifq_head != NULL)
+ axe_start(ifp);
+ }
+
+ sc->axe_stat_ch = timeout(axe_tick, sc, hz);
+
+ AXE_UNLOCK(sc);
+
+ return;
+}
+
+Static int
+axe_encap(struct axe_softc *sc, struct mbuf *m, int idx)
+{
+ struct axe_chain *c;
+ usbd_status err;
+
+ c = &sc->axe_cdata.axe_tx_chain[idx];
+
+ /*
+ * Copy the mbuf data into a contiguous buffer, leaving two
+ * bytes at the beginning to hold the frame length.
+ */
+ m_copydata(m, 0, m->m_pkthdr.len, c->axe_buf);
+ c->axe_mbuf = m;
+
+ usbd_setup_xfer(c->axe_xfer, sc->axe_ep[AXE_ENDPT_TX],
+ c, c->axe_buf, m->m_pkthdr.len, 0, 10000, axe_txeof);
+
+ /* Transmit */
+ err = usbd_transfer(c->axe_xfer);
+ if (err != USBD_IN_PROGRESS) {
+ axe_stop(sc);
+ return(EIO);
+ }
+
+ sc->axe_cdata.axe_tx_cnt++;
+
+ return(0);
+}
+
+Static void
+axe_start(struct ifnet *ifp)
+{
+ struct axe_softc *sc;
+ struct mbuf *m_head = NULL;
+
+ sc = ifp->if_softc;
+ AXE_LOCK(sc);
+
+ if (!sc->axe_link) {
+ AXE_UNLOCK(sc);
+ return;
+ }
+
+ if (ifp->if_flags & IFF_OACTIVE) {
+ AXE_UNLOCK(sc);
+ return;
+ }
+
+ IF_DEQUEUE(&ifp->if_snd, m_head);
+ if (m_head == NULL) {
+ AXE_UNLOCK(sc);
+ return;
+ }
+
+ if (axe_encap(sc, m_head, 0)) {
+ IF_PREPEND(&ifp->if_snd, m_head);
+ ifp->if_flags |= IFF_OACTIVE;
+ AXE_UNLOCK(sc);
+ return;
+ }
+
+ /*
+ * If there's a BPF listener, bounce a copy of this frame
+ * to him.
+ */
+ BPF_MTAP(ifp, m_head);
+
+ ifp->if_flags |= IFF_OACTIVE;
+
+ /*
+ * Set a timeout in case the chip goes out to lunch.
+ */
+ ifp->if_timer = 5;
+ AXE_UNLOCK(sc);
+
+ return;
+}
+
+Static void
+axe_init(void *xsc)
+{
+ struct axe_softc *sc = xsc;
+ struct ifnet *ifp = &sc->arpcom.ac_if;
+ struct axe_chain *c;
+ usbd_status err;
+ int i;
+ int rxmode;
+
+ if (ifp->if_flags & IFF_RUNNING)
+ return;
+
+ AXE_LOCK(sc);
+
+ /*
+ * Cancel pending I/O and free all RX/TX buffers.
+ */
+
+ axe_reset(sc);
+
+#ifdef notdef
+ /* Set MAC address */
+ axe_mac(sc, sc->arpcom.ac_enaddr, 1);
+#endif
+
+ /* Enable RX logic. */
+
+ /* Init TX ring. */
+ if (axe_tx_list_init(sc) == ENOBUFS) {
+ printf("axe%d: tx list init failed\n", sc->axe_unit);
+ AXE_UNLOCK(sc);
+ return;
+ }
+
+ /* Init RX ring. */
+ if (axe_rx_list_init(sc) == ENOBUFS) {
+ printf("axe%d: rx list init failed\n", sc->axe_unit);
+ AXE_UNLOCK(sc);
+ return;
+ }
+
+ /* Set transmitter IPG values */
+ axe_cmd(sc, AXE_CMD_WRITE_IPG0, 0, sc->axe_ipgs[0], NULL);
+ axe_cmd(sc, AXE_CMD_WRITE_IPG1, 0, sc->axe_ipgs[1], NULL);
+ axe_cmd(sc, AXE_CMD_WRITE_IPG2, 0, sc->axe_ipgs[2], NULL);
+
+ /* Enable receiver, set RX mode */
+ rxmode = AXE_RXCMD_UNICAST|AXE_RXCMD_MULTICAST|AXE_RXCMD_ENABLE;
+
+ /* If we want promiscuous mode, set the allframes bit. */
+ if (ifp->if_flags & IFF_PROMISC)
+ rxmode |= AXE_RXCMD_PROMISC;
+
+ if (ifp->if_flags & IFF_BROADCAST)
+ rxmode |= AXE_RXCMD_BROADCAST;
+
+ axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL);
+
+ /* Load the multicast filter. */
+ axe_setmulti(sc);
+
+ /* Open RX and TX pipes. */
+ err = usbd_open_pipe(sc->axe_iface, sc->axe_ed[AXE_ENDPT_RX],
+ USBD_EXCLUSIVE_USE, &sc->axe_ep[AXE_ENDPT_RX]);
+ if (err) {
+ printf("axe%d: open rx pipe failed: %s\n",
+ sc->axe_unit, usbd_errstr(err));
+ AXE_UNLOCK(sc);
+ return;
+ }
+
+ err = usbd_open_pipe(sc->axe_iface, sc->axe_ed[AXE_ENDPT_TX],
+ USBD_EXCLUSIVE_USE, &sc->axe_ep[AXE_ENDPT_TX]);
+ if (err) {
+ printf("axe%d: open tx pipe failed: %s\n",
+ sc->axe_unit, usbd_errstr(err));
+ AXE_UNLOCK(sc);
+ return;
+ }
+
+ /* Start up the receive pipe. */
+ for (i = 0; i < AXE_RX_LIST_CNT; i++) {
+ c = &sc->axe_cdata.axe_rx_chain[i];
+ usbd_setup_xfer(c->axe_xfer, sc->axe_ep[AXE_ENDPT_RX],
+ c, mtod(c->axe_mbuf, char *), AXE_BUFSZ,
+ USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, axe_rxeof);
+ usbd_transfer(c->axe_xfer);
+ }
+
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+
+ AXE_UNLOCK(sc);
+
+ sc->axe_stat_ch = timeout(axe_tick, sc, hz);
+
+ return;
+}
+
+Static int
+axe_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
+{
+ struct axe_softc *sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *)data;
+ struct mii_data *mii;
+ u_int16_t rxmode;
+ int error = 0;
+
+ switch(command) {
+ case SIOCSIFFLAGS:
+ if (ifp->if_flags & IFF_UP) {
+ if (ifp->if_flags & IFF_RUNNING &&
+ ifp->if_flags & IFF_PROMISC &&
+ !(sc->axe_if_flags & IFF_PROMISC)) {
+ AXE_LOCK(sc);
+ axe_cmd(sc, AXE_CMD_RXCTL_READ,
+ 0, 0, (void *)&rxmode);
+ rxmode |= AXE_RXCMD_PROMISC;
+ axe_cmd(sc, AXE_CMD_RXCTL_WRITE,
+ 0, rxmode, NULL);
+ AXE_UNLOCK(sc);
+ axe_setmulti(sc);
+ } else if (ifp->if_flags & IFF_RUNNING &&
+ !(ifp->if_flags & IFF_PROMISC) &&
+ sc->axe_if_flags & IFF_PROMISC) {
+ AXE_LOCK(sc);
+ axe_cmd(sc, AXE_CMD_RXCTL_READ,
+ 0, 0, (void *)&rxmode);
+ rxmode &= ~AXE_RXCMD_PROMISC;
+ axe_cmd(sc, AXE_CMD_RXCTL_WRITE,
+ 0, rxmode, NULL);
+ AXE_UNLOCK(sc);
+ axe_setmulti(sc);
+ } else if (!(ifp->if_flags & IFF_RUNNING))
+ axe_init(sc);
+ } else {
+ if (ifp->if_flags & IFF_RUNNING)
+ axe_stop(sc);
+ }
+ sc->axe_if_flags = ifp->if_flags;
+ error = 0;
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ axe_setmulti(sc);
+ error = 0;
+ break;
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ mii = GET_MII(sc);
+ error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
+ break;
+
+ default:
+ error = ether_ioctl(ifp, command, data);
+ break;
+ }
+
+ AXE_UNLOCK(sc);
+
+ return(error);
+}
+
+Static void
+axe_watchdog(struct ifnet *ifp)
+{
+ struct axe_softc *sc;
+ struct axe_chain *c;
+ usbd_status stat;
+
+ sc = ifp->if_softc;
+ AXE_LOCK(sc);
+
+ ifp->if_oerrors++;
+ printf("axe%d: watchdog timeout\n", sc->axe_unit);
+
+ c = &sc->axe_cdata.axe_tx_chain[0];
+ usbd_get_xfer_status(c->axe_xfer, NULL, NULL, NULL, &stat);
+ axe_txeof(c->axe_xfer, c, stat);
+
+ AXE_UNLOCK(sc);
+
+ if (ifp->if_snd.ifq_head != NULL)
+ axe_start(ifp);
+
+ return;
+}
+
+/*
+ * Stop the adapter and free any mbufs allocated to the
+ * RX and TX lists.
+ */
+Static void
+axe_stop(struct axe_softc *sc)
+{
+ usbd_status err;
+ struct ifnet *ifp;
+ int i;
+
+ AXE_LOCK(sc);
+
+ axe_reset(sc);
+
+ ifp = &sc->arpcom.ac_if;
+ ifp->if_timer = 0;
+
+ untimeout(axe_tick, sc, sc->axe_stat_ch);
+
+ /* Stop transfers. */
+ if (sc->axe_ep[AXE_ENDPT_RX] != NULL) {
+ err = usbd_abort_pipe(sc->axe_ep[AXE_ENDPT_RX]);
+ if (err) {
+ printf("axe%d: abort rx pipe failed: %s\n",
+ sc->axe_unit, usbd_errstr(err));
+ }
+ err = usbd_close_pipe(sc->axe_ep[AXE_ENDPT_RX]);
+ if (err) {
+ printf("axe%d: close rx pipe failed: %s\n",
+ sc->axe_unit, usbd_errstr(err));
+ }
+ sc->axe_ep[AXE_ENDPT_RX] = NULL;
+ }
+
+ if (sc->axe_ep[AXE_ENDPT_TX] != NULL) {
+ err = usbd_abort_pipe(sc->axe_ep[AXE_ENDPT_TX]);
+ if (err) {
+ printf("axe%d: abort tx pipe failed: %s\n",
+ sc->axe_unit, usbd_errstr(err));
+ }
+ err = usbd_close_pipe(sc->axe_ep[AXE_ENDPT_TX]);
+ if (err) {
+ printf("axe%d: close tx pipe failed: %s\n",
+ sc->axe_unit, usbd_errstr(err));
+ }
+ sc->axe_ep[AXE_ENDPT_TX] = NULL;
+ }
+
+ if (sc->axe_ep[AXE_ENDPT_INTR] != NULL) {
+ err = usbd_abort_pipe(sc->axe_ep[AXE_ENDPT_INTR]);
+ if (err) {
+ printf("axe%d: abort intr pipe failed: %s\n",
+ sc->axe_unit, usbd_errstr(err));
+ }
+ err = usbd_close_pipe(sc->axe_ep[AXE_ENDPT_INTR]);
+ if (err) {
+ printf("axe%d: close intr pipe failed: %s\n",
+ sc->axe_unit, usbd_errstr(err));
+ }
+ sc->axe_ep[AXE_ENDPT_INTR] = NULL;
+ }
+
+ /* Free RX resources. */
+ for (i = 0; i < AXE_RX_LIST_CNT; i++) {
+ if (sc->axe_cdata.axe_rx_chain[i].axe_buf != NULL) {
+ free(sc->axe_cdata.axe_rx_chain[i].axe_buf, M_USBDEV);
+ sc->axe_cdata.axe_rx_chain[i].axe_buf = NULL;
+ }
+ if (sc->axe_cdata.axe_rx_chain[i].axe_mbuf != NULL) {
+ m_freem(sc->axe_cdata.axe_rx_chain[i].axe_mbuf);
+ sc->axe_cdata.axe_rx_chain[i].axe_mbuf = NULL;
+ }
+ if (sc->axe_cdata.axe_rx_chain[i].axe_xfer != NULL) {
+ usbd_free_xfer(sc->axe_cdata.axe_rx_chain[i].axe_xfer);
+ sc->axe_cdata.axe_rx_chain[i].axe_xfer = NULL;
+ }
+ }
+
+ /* Free TX resources. */
+ for (i = 0; i < AXE_TX_LIST_CNT; i++) {
+ if (sc->axe_cdata.axe_tx_chain[i].axe_buf != NULL) {
+ free(sc->axe_cdata.axe_tx_chain[i].axe_buf, M_USBDEV);
+ sc->axe_cdata.axe_tx_chain[i].axe_buf = NULL;
+ }
+ if (sc->axe_cdata.axe_tx_chain[i].axe_mbuf != NULL) {
+ m_freem(sc->axe_cdata.axe_tx_chain[i].axe_mbuf);
+ sc->axe_cdata.axe_tx_chain[i].axe_mbuf = NULL;
+ }
+ if (sc->axe_cdata.axe_tx_chain[i].axe_xfer != NULL) {
+ usbd_free_xfer(sc->axe_cdata.axe_tx_chain[i].axe_xfer);
+ sc->axe_cdata.axe_tx_chain[i].axe_xfer = NULL;
+ }
+ }
+
+ ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+ sc->axe_link = 0;
+ AXE_UNLOCK(sc);
+
+ return;
+}
+
+/*
+ * Stop all chip I/O so that the kernel's probe routines don't
+ * get confused by errant DMAs when rebooting.
+ */
+Static void
+axe_shutdown(device_ptr_t dev)
+{
+ struct axe_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ axe_stop(sc);
+
+ return;
+}
diff --git a/sys/dev/usb/if_axereg.h b/sys/dev/usb/if_axereg.h
new file mode 100644
index 0000000..b293f04
--- /dev/null
+++ b/sys/dev/usb/if_axereg.h
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 1997, 1998, 1999, 2000-2003
+ * Bill Paul <wpaul@windriver.com>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Definitions for the ASIX Electronics AX88172 to ethernet controller.
+ */
+
+
+/*
+ * Vendor specific commands
+ * ASIX conveniently doesn't document the 'set NODEID' command in their
+ * datasheet (thanks a lot guys).
+ * To make handling these commands easier, I added some extra data
+ * which is decided by the axe_cmd() routine. Commands are encoded
+ * in 16 bites, with the format: LDCC. L and D are both nibbles in
+ * the high byte. L represents the data length (0 to 15) and D
+ * represents the direction (0 for vendor read, 1 for vendor write).
+ * CC is the command byte, as specified in the manual.
+ */
+
+#define AXE_CMD_DIR(x) (((x) & 0x0F00) >> 8)
+#define AXE_CMD_LEN(x) (((x) & 0xF000) >> 12)
+#define AXE_CMD_CMD(x) ((x) & 0x00FF)
+
+#define AXE_CMD_READ_RXTX_SRAM 0x2002
+#define AXE_CMD_WRITE_RX_SRAM 0x0103
+#define AXE_CMD_WRITE_TX_SRAM 0x0104
+#define AXE_CMD_MII_OPMODE_SW 0x0106
+#define AXE_CMD_MII_READ_REG 0x2007
+#define AXE_CMD_MII_WRITE_REG 0x2108
+#define AXE_CMD_MII_READ_OPMODE 0x1009
+#define AXE_CMD_MII_OPMODE_HW 0x010A
+#define AXE_CMD_SROM_READ 0x200B
+#define AXE_CMD_SROM_WRITE 0x010C
+#define AXE_CMD_SROM_WR_ENABLE 0x010D
+#define AXE_CMD_SROM_WR_DISABLE 0x010E
+#define AXE_CMD_RXCTL_READ 0x200F
+#define AXE_CMD_RXCTL_WRITE 0x0110
+#define AXE_CMD_READ_IPG012 0x3011
+#define AXE_CMD_WRITE_IPG0 0x0112
+#define AXE_CMD_WRITE_IPG1 0x0113
+#define AXE_CMD_WRITE_IPG2 0x0114
+#define AXE_CMD_READ_MCAST 0x8015
+#define AXE_CMD_WRITE_MCAST 0x8116
+#define AXE_CMD_READ_NODEID 0x6017
+#define AXE_CMD_WRITE_NODEID 0x6118
+#define AXE_CMD_READ_PHYID 0x2019
+#define AXE_CMD_READ_MEDIA 0x101A
+#define AXE_CMD_WRITE_MEDIA 0x011B
+#define AXE_CMD_READ_MONITOR_MODE 0x101C
+#define AXE_CMD_WRITE_MONITOR_MODE 0x011D
+#define AXE_CMD_READ_GPIO 0x101E
+#define AXE_CMD_WRITE_GPIO 0x011F
+
+#define AXE_RXCMD_PROMISC 0x0001
+#define AXE_RXCMD_ALLMULTI 0x0002
+#define AXE_RXCMD_UNICAST 0x0004
+#define AXE_RXCMD_BROADCAST 0x0008
+#define AXE_RXCMD_MULTICAST 0x0010
+#define AXE_RXCMD_ENABLE 0x0080
+
+#define AXE_NOPHY 0xE0
+
+#define AXE_TIMEOUT 1000
+#define AXE_BUFSZ 1536
+#define AXE_MIN_FRAMELEN 60
+#define AXE_RX_FRAMES 1
+#define AXE_TX_FRAMES 1
+
+#define AXE_RX_LIST_CNT 1
+#define AXE_TX_LIST_CNT 1
+
+#define AXE_CTL_READ 0x01
+#define AXE_CTL_WRITE 0x02
+
+#define AXE_CONFIG_NO 1
+
+/*
+ * The interrupt endpoint is currently unused
+ * by the ASIX part.
+ */
+#define AXE_ENDPT_RX 0x0
+#define AXE_ENDPT_TX 0x1
+#define AXE_ENDPT_INTR 0x2
+#define AXE_ENDPT_MAX 0x3
+
+struct axe_type {
+ u_int16_t axe_vid;
+ u_int16_t axe_did;
+};
+
+struct axe_softc;
+
+struct axe_chain {
+ struct axe_softc *axe_sc;
+ usbd_xfer_handle axe_xfer;
+ char *axe_buf;
+ struct mbuf *axe_mbuf;
+ int axe_accum;
+ int axe_idx;
+};
+
+struct axe_cdata {
+ struct axe_chain axe_tx_chain[AXE_TX_LIST_CNT];
+ struct axe_chain axe_rx_chain[AXE_RX_LIST_CNT];
+ int axe_tx_prod;
+ int axe_tx_cons;
+ int axe_tx_cnt;
+ int axe_rx_prod;
+};
+
+#define AXE_INC(x, y) (x) = (x + 1) % y
+
+struct axe_softc {
+#if defined(__FreeBSD__)
+#define GET_MII(sc) (device_get_softc((sc)->axe_miibus))
+#elif defined(__NetBSD__)
+#define GET_MII(sc) (&(sc)->axe_mii)
+#elif defined(__OpenBSD__)
+#define GET_MII(sc) (&(sc)->axe_mii)
+#endif
+ struct arpcom arpcom;
+ device_t axe_miibus;
+ device_t axe_dev;
+ usbd_device_handle axe_udev;
+ usbd_interface_handle axe_iface;
+ int axe_ed[AXE_ENDPT_MAX];
+ usbd_pipe_handle axe_ep[AXE_ENDPT_MAX];
+ int axe_unit;
+ int axe_if_flags;
+ struct axe_cdata axe_cdata;
+ struct callout_handle axe_stat_ch;
+ struct mtx axe_mtx;
+ char axe_dying;
+ int axe_link;
+ unsigned char axe_ipgs[3];
+ unsigned char axe_phyaddrs[2];
+ struct timeval axe_rx_notice;
+};
+
+#if 0
+#define AXE_LOCK(_sc) mtx_lock(&(_sc)->axe_mtx)
+#define AXE_UNLOCK(_sc) mtx_unlock(&(_sc)->axe_mtx)
+#else
+#define AXE_LOCK(_sc)
+#define AXE_UNLOCK(_sc)
+#endif
diff --git a/sys/dev/usb/usbdevs b/sys/dev/usb/usbdevs
index 49d002e..8c71f55 100644
--- a/sys/dev/usb/usbdevs
+++ b/sys/dev/usb/usbdevs
@@ -252,6 +252,7 @@ vendor MCT 0x0711 MCT
vendor DIGITALSTREAM 0x074e Digital Stream
vendor AUREAL 0x0755 Aureal Semiconductor
vendor MIDIMAN 0x0763 Midiman
+vendor ASIX 0x077b ASIX Electronics
vendor GRIFFIN 0x077d Griffin Technology
vendor SANDISK 0x0781 SanDisk Corp
vendor BRIMAX 0x078e Brimax
@@ -451,6 +452,9 @@ product APPLE SPEAKERS 0x1101 Speakers
/* Asahi Optical products */
product ASAHIOPTICAL OPTIO230 0x0004 Digital camera
+/* ASIX Electronics products */
+product ASIX AX88172 0x2226 USB 2.0 10/100 ethernet controller
+
/* ATen products */
product ATEN UC1284 0x2001 Parallel printer adapter
product ATEN UC10T 0x2002 10Mbps ethernet adapter
diff --git a/sys/i386/conf/GENERIC b/sys/i386/conf/GENERIC
index 730261b..34ad789 100644
--- a/sys/i386/conf/GENERIC
+++ b/sys/i386/conf/GENERIC
@@ -252,5 +252,6 @@ device urio # Diamond Rio 500 MP3 player
device uscanner # Scanners
# USB Ethernet, requires mii
device aue # ADMtek USB ethernet
+device axe # ASIX Electronics USB ethernet
device cue # CATC USB ethernet
device kue # Kawasaki LSI USB ethernet
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
index 2abdabc..12133a4 100644
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -16,6 +16,7 @@ SUBDIR= accf_data \
amr \
an \
aue \
+ axe \
bge \
bridge \
cam \
diff --git a/sys/modules/axe/Makefile b/sys/modules/axe/Makefile
new file mode 100644
index 0000000..ed4c5ef
--- /dev/null
+++ b/sys/modules/axe/Makefile
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+S= ${.CURDIR}/../..
+.PATH: $S/dev/usb
+
+KMOD= if_axe
+SRCS= if_axe.c opt_bdg.h opt_usb.h device_if.h bus_if.h
+SRCS+= miibus_if.h
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/netgraph/Makefile b/sys/modules/netgraph/Makefile
index f0a8421..12ebb58 100644
--- a/sys/modules/netgraph/Makefile
+++ b/sys/modules/netgraph/Makefile
@@ -10,6 +10,7 @@ SUBDIR= UI \
eiface \
etf \
ether \
+ fec \
frame_relay \
gif \
gif_demux \
diff --git a/sys/pc98/conf/GENERIC b/sys/pc98/conf/GENERIC
index 8d01b54..e083acd 100644
--- a/sys/pc98/conf/GENERIC
+++ b/sys/pc98/conf/GENERIC
@@ -239,5 +239,6 @@ device bpf # Berkeley packet filter
#device uscanner # Scanners
# USB Ethernet, requires mii
#device aue # ADMtek USB ethernet
+#device axe # ASIX Electronics USB ethernet
#device cue # CATC USB ethernet
#device kue # Kawasaki LSI USB ethernet
diff --git a/sys/sparc64/conf/GENERIC b/sys/sparc64/conf/GENERIC
index 87a6e42..81602e6 100644
--- a/sys/sparc64/conf/GENERIC
+++ b/sys/sparc64/conf/GENERIC
@@ -191,6 +191,7 @@ device bpf #Berkeley packet filter
#device ums # Mouse
# USB Ethernet
#device aue # ADMtek USB ethernet
+#device axe # ASIX Electronics USB ethernet
#device cue # CATC USB ethernet
#device kue # Kawasaki LSI USB ethernet
diff --git a/usr.sbin/sade/devices.c b/usr.sbin/sade/devices.c
index 910b230..6b00ced 100644
--- a/usr.sbin/sade/devices.c
+++ b/usr.sbin/sade/devices.c
@@ -83,6 +83,7 @@ static struct _devname {
{ DEVICE_TYPE_FLOPPY, "fd%d", "floppy drive unit A", 9, 0, 64, 4 },
{ DEVICE_TYPE_NETWORK, "an", "Aironet 4500/4800 802.11 wireless adapter" },
{ DEVICE_TYPE_NETWORK, "aue", "ADMtek USB ethernet adapter" },
+ { DEVICE_TYPE_NETWORK, "axe", "ASIX Electronics USB ethernet adapter" },
{ DEVICE_TYPE_NETWORK, "bge", "Broadcom BCM570x PCI gigabit ethernet card" },
{ DEVICE_TYPE_NETWORK, "cue", "CATC USB ethernet adapter" },
{ DEVICE_TYPE_NETWORK, "fpa", "DEC DEFPA PCI FDDI card" },
diff --git a/usr.sbin/sysinstall/devices.c b/usr.sbin/sysinstall/devices.c
index 910b230..6b00ced 100644
--- a/usr.sbin/sysinstall/devices.c
+++ b/usr.sbin/sysinstall/devices.c
@@ -83,6 +83,7 @@ static struct _devname {
{ DEVICE_TYPE_FLOPPY, "fd%d", "floppy drive unit A", 9, 0, 64, 4 },
{ DEVICE_TYPE_NETWORK, "an", "Aironet 4500/4800 802.11 wireless adapter" },
{ DEVICE_TYPE_NETWORK, "aue", "ADMtek USB ethernet adapter" },
+ { DEVICE_TYPE_NETWORK, "axe", "ASIX Electronics USB ethernet adapter" },
{ DEVICE_TYPE_NETWORK, "bge", "Broadcom BCM570x PCI gigabit ethernet card" },
{ DEVICE_TYPE_NETWORK, "cue", "CATC USB ethernet adapter" },
{ DEVICE_TYPE_NETWORK, "fpa", "DEC DEFPA PCI FDDI card" },
OpenPOWER on IntegriCloud