tech-net archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: Another update for axe(4)



On Mon, 14 Jun 2010, Izumi Tsutsui wrote:

I still looking for some guidance on whether or not my changes or
Fukaumi-san's changes (or neither?) should be committed?

Well, probably it's great to merge both changes ;-)

With a quick glance, these ones should be pulled from Fukaumi-san's one:
- more KNF cleanup (u_char -> uint8_t, no braces for return etc.)
  (I don't like uWord though)
- make axe_init() return int to match our (*ifp->if_init)()
- change axe_stop() args to match our (*ifp->if_stop)()
- USETW()/UGETW() macro
- set ETHERCAP_VLAN_MTU
- callout_setfunc()/callout_schedule() rather than callout_reset()
- callout_destroy() is required on detach?
- one ether_ifdetach(ifp) is enough in axe_detach()
- IFQ_POLL() should be used to check TX mbuf and
  IF_DEQUEUE() should be called after TX is actually ready in axe_start()
- probably needs callout_stop() (or axe_stop()?) in axe_init()
- AXE_RXCMD_MULTICAST in rxmode is required or not?
- AXE_RXCMD_PROMISC and AXE_RXCMD_BROADCAST should be set in axe_setmulti()?
- ioctl function is much simpler and seems correct (per other drivers)
- IFQ_IS_EMPTY() macro in axe_watchdog()

I've merged all of the above, except for two items

- it might be worth to try axe_start() in axe_tick_task()?
- USBD_NO_COPY is better? (not sure if buffers are allocated by bus_dma(9))


No idea for PHY/MII media options etc.

I merged in these changes, too, but they don't currently work. :) I will attempt to figure out what's going on and fixing them. But I think it would be worth updating the driver without them, just to get support for the additional chips.

Attached is the current set of diffs, with the MII stuff disabled via

        #if notyet
        ...
        #endif

This round of diffs is quite a bit larger than the earlier ones, but most of it is fairly cosmetic KNF stuff.

Comments, criticisms, and/or suggestions welcomed as always.


-------------------------------------------------------------------------
| Paul Goyette     | PGP Key fingerprint:     | E-mail addresses:       |
| Customer Service | FA29 0E3B 35AF E8AE 6651 | paul at whooppee.com    |
| Network Engineer | 0786 F758 55DE 53BA 7731 | pgoyette at juniper.net |
| Kernel Developer |                          | pgoyette at netbsd.org  |
-------------------------------------------------------------------------
Index: if_axe.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/if_axe.c,v
retrieving revision 1.32
diff -u -p -r1.32 if_axe.c
--- if_axe.c    5 Apr 2010 07:21:48 -0000       1.32
+++ if_axe.c    15 Jun 2010 04:10:31 -0000
@@ -1,4 +1,21 @@
 /*     $NetBSD: if_axe.c,v 1.32 2010/04/05 07:21:48 joerg Exp $        */
+/*     $OpenBSD: if_axe.c,v 1.96 2010/01/09 05:33:08 jsg Exp $ */
+
+/*
+ * Copyright (c) 2005, 2006, 2007 Jonathan Gray <jsg%openbsd.org@localhost>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
 
 /*
  * Copyright (c) 1997, 1998, 1999, 2000-2003
@@ -38,7 +55,6 @@
  *
  * Manuals available from:
  * http://www.asix.com.tw/datasheet/mac/Ax88172.PDF
- * (also http://people.freebsd.org/~wpaul/ASIX/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
@@ -82,55 +98,33 @@ __KERNEL_RCSID(0, "$NetBSD: if_axe.c,v 1
 
 
 #include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/sockio.h>
-#include <sys/mutex.h>
-#include <sys/mbuf.h>
+#include <sys/bus.h>
+#include <sys/device.h>
 #include <sys/kernel.h>
-#if defined(__OpenBSD__)
-#include <sys/proc.h>
-#endif
+#include <sys/mbuf.h>
+#include <sys/mutex.h>
 #include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/systm.h>
 
-#include <sys/device.h>
 #if NRND > 0
 #include <sys/rnd.h>
 #endif
 
 #include <net/if.h>
-#if defined(__NetBSD__)
-#include <net/if_arp.h>
-#endif
 #include <net/if_dl.h>
+#include <net/if_ether.h>
 #include <net/if_media.h>
 
 #include <net/bpf.h>
 
-#if defined(__NetBSD__)
-#include <net/if_ether.h>
-#ifdef INET
-#include <netinet/in.h>
-#include <netinet/if_inarp.h>
-#endif
-#endif /* defined(__NetBSD__) */
-
-#if defined(__OpenBSD__)
-#ifdef INET
-#include <netinet/in.h>
-#include <netinet/in_systm.h>
-#include <netinet/in_var.h>
-#include <netinet/ip.h>
-#include <netinet/if_ether.h>
-#endif
-#endif /* defined(__OpenBSD__) */
-
-
 #include <dev/mii/mii.h>
 #include <dev/mii/miivar.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/if_axereg.h>
@@ -147,61 +141,87 @@ int       axedebug = 0;
 /*
  * Various supported device vendors/products.
  */
-Static const struct axe_type axe_devs[] = {
+static const struct axe_type axe_devs[] = {
+       { { USB_VENDOR_ABOCOM,          USB_PRODUCT_ABOCOM_UFE2000}, 0 },
+       { { USB_VENDOR_ACERCM,          USB_PRODUCT_ACERCM_EP1427X2}, 0 },
+       { { USB_VENDOR_APPLE,           USB_PRODUCT_APPLE_ETHERNET }, AX772 },
        { { USB_VENDOR_ASIX,            USB_PRODUCT_ASIX_AX88172}, 0 },
+       { { USB_VENDOR_ASIX,            USB_PRODUCT_ASIX_AX88772}, AX772 },
+       { { USB_VENDOR_ASIX,            USB_PRODUCT_ASIX_AX88772A}, AX772 },
+       { { USB_VENDOR_ASIX,            USB_PRODUCT_ASIX_AX88178}, AX178 },
+       { { USB_VENDOR_ATEN,            USB_PRODUCT_ATEN_UC210T}, 0 },
+       { { USB_VENDOR_BELKIN,          USB_PRODUCT_BELKIN_F5D5055 }, AX178 },
+       { { USB_VENDOR_BILLIONTON,      USB_PRODUCT_BILLIONTON_USB2AR}, 0},
+       { { USB_VENDOR_CISCOLINKSYS,    USB_PRODUCT_CISCOLINKSYS_USB200MV2}, 
AX772 },
        { { USB_VENDOR_COREGA,          USB_PRODUCT_COREGA_FETHER_USB2_TX }, 0},
        { { USB_VENDOR_DLINK,           USB_PRODUCT_DLINK_DUBE100}, 0 },
+       { { USB_VENDOR_DLINK,           USB_PRODUCT_DLINK_DUBE100B1 }, AX772 },
+       { { USB_VENDOR_GOODWAY,         USB_PRODUCT_GOODWAY_GWUSB2E}, 0 },
+       { { USB_VENDOR_IODATA,          USB_PRODUCT_IODATA_ETGUS2 }, AX178 },
+       { { USB_VENDOR_JVC,             USB_PRODUCT_JVC_MP_PRX1}, 0 },
        { { USB_VENDOR_LINKSYS2,        USB_PRODUCT_LINKSYS2_USB200M}, 0 },
+       { { USB_VENDOR_LINKSYS4,        USB_PRODUCT_LINKSYS4_USB1000 }, AX178 },
+       { { USB_VENDOR_LOGITEC,         USB_PRODUCT_LOGITEC_LAN_GTJU2}, AX178 },
+       { { USB_VENDOR_MELCO,           USB_PRODUCT_MELCO_LUAU2GT}, AX178 },
        { { USB_VENDOR_MELCO,           USB_PRODUCT_MELCO_LUAU2KTX}, 0 },
+       { { USB_VENDOR_MSI,             USB_PRODUCT_MSI_AX88772A}, AX772 },
        { { USB_VENDOR_NETGEAR,         USB_PRODUCT_NETGEAR_FA120}, 0 },
-       { { USB_VENDOR_SITECOM,         USB_PRODUCT_SITECOM_LN029}, 0 },
+       { { USB_VENDOR_OQO,             USB_PRODUCT_OQO_ETHER01PLUS }, AX772 },
+       { { USB_VENDOR_PLANEX3,         USB_PRODUCT_PLANEX3_GU1000T }, AX178 },
        { { USB_VENDOR_SYSTEMTALKS,     USB_PRODUCT_SYSTEMTALKS_SGCX2UL}, 0 },
+       { { USB_VENDOR_SITECOM,         USB_PRODUCT_SITECOM_LN029}, 0 },
+       { { USB_VENDOR_SITECOMEU,       USB_PRODUCT_SITECOMEU_LN028 }, AX178 }
 };
 #define axe_lookup(v, p) ((const struct axe_type *)usb_lookup(axe_devs, v, p))
 
-int axe_match(device_t, cfdata_t, void *);
-void axe_attach(device_t, device_t, void *);
-int axe_detach(device_t, int);
-int axe_activate(device_t, enum devact);
-extern struct cfdriver axe_cd;
-CFATTACH_DECL_NEW(axe, sizeof(struct axe_softc), axe_match, axe_attach,
-    axe_detach, axe_activate);
-
-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_tick_task(void *);
-#if 0
-Static void axe_rxstart(struct ifnet *);
+int    axe_match(device_t, cfdata_t, void *);
+void   axe_attach(device_t, device_t, void *);
+int    axe_detach(device_t, int);
+int    axe_activate(device_t, devact_t);
+
+CFATTACH_DECL_NEW(axe, sizeof(struct axe_softc),
+       axe_match, axe_attach, axe_detach, axe_activate);
+
+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_tick_task(void *);
+static void    axe_start(struct ifnet *);
+static int     axe_ioctl(struct ifnet *, u_long, void *);
+static int     axe_init(struct ifnet *);
+static void    axe_stop(struct ifnet *, int);
+static void    axe_watchdog(struct ifnet *);
+static int     axe_miibus_readreg(device_t, int, int);
+static void    axe_miibus_writereg(device_t, int, int, int);
+static void    axe_miibus_statchg(device_t);
+static int     axe_cmd(struct axe_softc *, int, int, int, void *);
+static void    axe_reset(struct axe_softc *sc);
+#if notyet
+static int     axe_ifmedia_upd(struct ifnet *);
+static void    axe_ifmedia_sts(struct ifnet *, struct ifmediareq *);
 #endif
-Static void axe_start(struct ifnet *);
-Static int axe_ioctl(struct ifnet *, u_long, void *);
-Static void axe_init(void *);
-Static void axe_stop(struct axe_softc *);
-Static void axe_watchdog(struct ifnet *);
-Static int axe_miibus_readreg(device_t, int, int);
-Static void axe_miibus_writereg(device_t, int, int, int);
-Static void axe_miibus_statchg(device_t);
-Static int axe_cmd(struct axe_softc *, int, int, int, void *);
-Static void axe_reset(struct axe_softc *sc);
-
-Static void axe_setmulti(struct axe_softc *);
-Static void axe_lock_mii(struct axe_softc *sc);
-Static void axe_unlock_mii(struct axe_softc *sc);
+
+static void axe_setmulti(struct axe_softc *);
+static void axe_lock_mii(struct axe_softc *sc);
+static void axe_unlock_mii(struct axe_softc *sc);
+
+static void axe_ax88178_init(struct axe_softc *);
+static void axe_ax88772_init(struct axe_softc *);
 
 /* Get exclusive access to the MII registers */
-Static void
+static void
 axe_lock_mii(struct axe_softc *sc)
 {
        sc->axe_refcnt++;
        mutex_enter(&sc->axe_mii_lock);
 }
 
-Static void
+static void
 axe_unlock_mii(struct axe_softc *sc)
 {
        mutex_exit(&sc->axe_mii_lock);
@@ -209,7 +229,7 @@ axe_unlock_mii(struct axe_softc *sc)
                usb_detach_wakeup((sc->axe_dev));
 }
 
-Static int
+static int
 axe_cmd(struct axe_softc *sc, int cmd, int index, int val, void *buf)
 {
        usb_device_request_t    req;
@@ -218,7 +238,7 @@ axe_cmd(struct axe_softc *sc, int cmd, i
        KASSERT(mutex_owned(&sc->axe_mii_lock));
 
        if (sc->axe_dying)
-               return(0);
+               return 0;
 
        if (AXE_CMD_DIR(cmd))
                req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
@@ -231,13 +251,14 @@ axe_cmd(struct axe_softc *sc, int cmd, i
 
        err = usbd_do_request(sc->axe_udev, &req, buf);
 
-       if (err)
-               return(-1);
-
-       return(0);
+       if (err) {
+               DPRINTF(("axe_cmd err: cmd %d err %d\n", cmd, err));
+               return -1;
+       }
+       return 0;
 }
 
-Static int
+static int
 axe_miibus_readreg(device_t dev, int phy, int reg)
 {
        struct axe_softc *sc = device_private(dev);
@@ -246,23 +267,20 @@ axe_miibus_readreg(device_t dev, int phy
 
        if (sc->axe_dying) {
                DPRINTF(("axe: dying\n"));
-               return(0);
+               return 0;
        }
 
-#ifdef notdef
        /*
         * The chip tells us the MII address of any supported
         * PHYs attached to the chip, so only read from those.
+        * XXX
+        * But if we are ignoring the reported addresses (see
+        * axe_attach() ) we will read from any PHY.
         */
-
-       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);
-#endif
-       if (sc->axe_phyaddrs[0] != 0xFF && sc->axe_phyaddrs[0] != phy)
-               return (0);
+       if ((sc->axe_phyaddrs[0] != 0xFF || sc->axe_phyaddrs[0] != 0xFF) &&
+           phy != sc->axe_phyaddrs[0] && phy != sc->axe_phyaddrs[1] &&
+           phy != AXE_NOPHY)
+               return 0;
 
        val = 0;
 
@@ -274,19 +292,21 @@ axe_miibus_readreg(device_t dev, int phy
 
        if (err) {
                aprint_error_dev(sc->axe_dev, "read PHY failed\n");
-               return(-1);
+               return -1;
        }
+       DPRINTF(("axe_miibus_readreg: phy 0x%x reg 0x%x val 0x%x\n",
+           phy, reg, val));
 
-       if (val)
+       if (val && val != 0xffff)
                sc->axe_phyaddrs[0] = phy;
 
        return (le16toh(val));
 }
 
-Static void
+static void
 axe_miibus_writereg(device_t dev, int phy, int reg, int aval)
 {
-       struct axe_softc *sc = device_private(dev);
+       struct axe_softc        *sc = device_private(dev);
        usbd_status             err;
        u_int16_t               val;
 
@@ -306,17 +326,34 @@ axe_miibus_writereg(device_t dev, int ph
        }
 }
 
-Static void
+static void
 axe_miibus_statchg(device_t dev)
 {
        struct axe_softc *sc = device_private(dev);
-       struct mii_data         *mii = GET_MII(sc);
+       struct mii_data         *mii = &sc->axe_mii;
        int val, err;
 
        if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX)
                val = AXE_MEDIA_FULL_DUPLEX;
        else
                val = 0;
+
+       if (sc->axe_flags & AX178 || sc->axe_flags & AX772) {
+               val |= (AXE_178_MEDIA_RX_EN | AXE_178_MEDIA_MAGIC);
+
+               switch (IFM_SUBTYPE(mii->mii_media_active)) {
+               case IFM_1000_T:  
+                       val |= AXE_178_MEDIA_GMII | AXE_178_MEDIA_ENCK;
+                       break;
+               case IFM_100_TX:
+                       val |= AXE_178_MEDIA_100TX;
+                       break;
+               case IFM_10_T:
+                       /* doesn't need to be handled */
+                       break;
+               }
+       }
+
        DPRINTF(("axe_miibus_statchg: val=0x%x\n", val));
        axe_lock_mii(sc);
        err = axe_cmd(sc, AXE_CMD_WRITE_MEDIA, 0, val, NULL);
@@ -327,12 +364,49 @@ axe_miibus_statchg(device_t dev)
        }
 }
 
-Static void
+#if notyet
+/*
+ * Set media options
+ */
+static int
+axe_ifmedia_upd(struct ifnet *ifp)
+{
+       struct axe_softc        *sc = ifp->if_softc;
+       struct mii_data         *mii = &sc->axe_mii;
+
+       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 = &sc->axe_mii;
+
+       mii_pollstat(mii);
+       ifmr->ifm_active = mii->mii_media_active;
+       ifmr->ifm_status = mii->mii_media_status;
+}
+#endif
+
+static void
 axe_setmulti(struct axe_softc *sc)
 {
-       struct ifnet            *ifp;
-       struct ether_multi *enm;
-       struct ether_multistep step;
+       struct ifnet            *ifp = &sc->sc_if;
+       struct ether_multi      *enm;
+       struct ether_multistep  step;
        u_int32_t               h = 0;
        u_int16_t               rxmode;
        u_int8_t                hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
@@ -340,44 +414,44 @@ axe_setmulti(struct axe_softc *sc)
        if (sc->axe_dying)
                return;
 
-       ifp = GET_IFP(sc);
-
        axe_lock_mii(sc);
        axe_cmd(sc, AXE_CMD_RXCTL_READ, 0, 0, (void *)&rxmode);
        rxmode = le16toh(rxmode);
 
-       if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
-       allmulti:
-               rxmode |= AXE_RXCMD_ALLMULTI;
-               axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL);
-               return;
-       } else
-               rxmode &= ~AXE_RXCMD_ALLMULTI;
+       rxmode &= ~(AXE_RXCMD_ALLMULTI | AXE_RXCMD_PROMISC);
 
-       /* now program new ones */
-#if defined(__NetBSD__)
+       /* If we want promiscuous mode, set the allframes bit */
+       if (ifp->if_flags & IFF_ALLMULTI) {
+               rxmode |= AXE_RXCMD_PROMISC;
+               goto allmulti;
+       }
+
+       /* Now program new ones */
        ETHER_FIRST_MULTI(step, &sc->axe_ec, enm);
-#else
-       ETHER_FIRST_MULTI(step, &sc->arpcom, enm);
-#endif
        while (enm != NULL) {
                if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
                           ETHER_ADDR_LEN) != 0)
                        goto allmulti;
 
                h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN) >> 26;
-               hashtbl[h / 8] |= 1 << (h % 8);
+               hashtbl[h >> 3] |= 1U << (h & 7);
                ETHER_NEXT_MULTI(step, enm);
        }
-
        ifp->if_flags &= ~IFF_ALLMULTI;
        axe_cmd(sc, AXE_CMD_WRITE_MCAST, 0, 0, (void *)&hashtbl);
        axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL);
        axe_unlock_mii(sc);
        return;
+
+ allmulti:
+       ifp->if_flags |= IFF_ALLMULTI;
+       rxmode |= AXE_RXCMD_ALLMULTI;
+       axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL);
+       axe_unlock_mii(sc);
+       return;
 }
 
-Static void
+static void
 axe_reset(struct axe_softc *sc)
 {
        if (sc->axe_dying)
@@ -389,6 +463,104 @@ axe_reset(struct axe_softc *sc)
        return;
 }
 
+static void
+axe_ax88178_init(struct axe_softc *sc)
+{
+       int gpio0 = 0, phymode = 0;
+       uint16_t eeprom;
+
+       axe_cmd(sc, AXE_CMD_SROM_WR_ENABLE, 0, 0, NULL);
+       /* XXX magic */
+       axe_cmd(sc, AXE_CMD_SROM_READ, 0, 0x0017, &eeprom);
+       axe_cmd(sc, AXE_CMD_SROM_WR_DISABLE, 0, 0, NULL);
+
+       eeprom = le16toh(eeprom);
+
+       DPRINTF((" EEPROM is 0x%x\n", eeprom));
+
+       /* if EEPROM is invalid we have to use to GPIO0 */
+       if (eeprom == 0xffff) {
+               phymode = 0;
+               gpio0 = 1;
+       } else {
+               phymode = eeprom & 7;
+               gpio0 = (eeprom & 0x80) ? 0 : 1;
+       }
+
+       DPRINTF(("use gpio0: %d, phymode %d\n", gpio0, phymode));
+
+       axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x008c, NULL);
+       usbd_delay_ms(sc->axe_udev, 40);
+       if ((eeprom >> 8) != 1) {
+               axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x003c, NULL);
+               usbd_delay_ms(sc->axe_udev, 30);
+
+               axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x001c, NULL);
+               usbd_delay_ms(sc->axe_udev, 300);
+
+               axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x003c, NULL);
+               usbd_delay_ms(sc->axe_udev, 30);
+       } else {
+               DPRINTF(("axe gpio phymode == 1 path\n"));
+               axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x0004, NULL);
+               usbd_delay_ms(sc->axe_udev, 30);
+               axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x000c, NULL);
+               usbd_delay_ms(sc->axe_udev, 30);
+       }
+
+       /* soft reset */
+       axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL);
+       usbd_delay_ms(sc->axe_udev, 150);
+       axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0,
+           AXE_SW_RESET_PRL | AXE_178_RESET_MAGIC, NULL);
+       usbd_delay_ms(sc->axe_udev, 150);
+       /* Enable MII/GMII/RGMII for external PHY */
+       axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0, NULL);
+       usbd_delay_ms(sc->axe_udev, 10);
+       axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL);
+}
+
+static void
+axe_ax88772_init(struct axe_softc *sc)
+{
+
+       axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x00b0, NULL);
+       usbd_delay_ms(sc->axe_udev, 40);
+
+       if (sc->axe_phyaddrs[1] == AXE_INTPHY) {
+               /* ask for the embedded PHY */
+               axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0x01, NULL);
+               usbd_delay_ms(sc->axe_udev, 10);
+
+               /* power down and reset state, pin reset state */
+               axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL);
+               usbd_delay_ms(sc->axe_udev, 60);
+
+               /* power down/reset state, pin operating state */
+               axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0,
+                   AXE_SW_RESET_IPPD | AXE_SW_RESET_PRL, NULL);
+               usbd_delay_ms(sc->axe_udev, 150);
+
+               /* power up, reset */
+               axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_PRL, NULL);
+
+               /* power up, operating */
+               axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0,
+                   AXE_SW_RESET_IPRL | AXE_SW_RESET_PRL, NULL);
+       } else {
+               /* ask for external PHY */
+               axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0x00, NULL);
+               usbd_delay_ms(sc->axe_udev, 10);
+
+               /* power down internal PHY */
+               axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0,
+                   AXE_SW_RESET_IPPD | AXE_SW_RESET_PRL, NULL);
+       }
+
+       usbd_delay_ms(sc->axe_udev, 150);
+       axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL);
+}
+
 /*
  * Probe for a AX88172 chip.
  */
@@ -415,17 +587,18 @@ axe_attach(device_t parent, device_t sel
        usb_interface_descriptor_t *id;
        usb_endpoint_descriptor_t *ed;
        struct mii_data *mii;
-       u_char eaddr[ETHER_ADDR_LEN];
+       uint8_t eaddr[ETHER_ADDR_LEN];
        char *devinfop;
        const char *devname = device_xname(self);
        struct ifnet *ifp;
        int i, s;
 
-       sc->axe_dev = self;
-
        aprint_naive("\n");
        aprint_normal("\n");
 
+       sc->axe_dev = self;
+       sc->axe_udev = dev;
+
        devinfop = usbd_devinfo_alloc(dev, 0);
        aprint_normal_dev(self, "%s\n", devinfop);
        usbd_devinfo_free(devinfop);
@@ -436,8 +609,10 @@ axe_attach(device_t parent, device_t sel
                return;
        }
 
-       usb_init_task(&sc->axe_tick_task, axe_tick_task, sc);
+       sc->axe_flags = axe_lookup(uaa->vendor, uaa->product)->axe_flags;
+
        mutex_init(&sc->axe_mii_lock, MUTEX_DEFAULT, IPL_NONE);
+       usb_init_task(&sc->axe_tick_task, axe_tick_task, sc);
        usb_init_task(&sc->axe_stop_task, (void (*)(void *))axe_stop, sc);
 
        err = usbd_device2interface_handle(dev, AXE_IFACE_IDX, &sc->axe_iface);
@@ -446,12 +621,18 @@ axe_attach(device_t parent, device_t sel
                return;
        }
 
-       sc->axe_udev = dev;
        sc->axe_product = uaa->product;
        sc->axe_vendor = uaa->vendor;
 
        id = usbd_get_interface_descriptor(sc->axe_iface);
 
+       /* decide on what our bufsize will be */
+       if (sc->axe_flags & AX178 || sc->axe_flags & AX772)
+               sc->axe_bufsz = (sc->axe_udev->speed == USB_SPEED_HIGH) ?
+                   AXE_178_MAX_BUFSZ : AXE_178_MIN_BUFSZ;
+       else
+               sc->axe_bufsz = AXE_172_BUFSZ;
+
        /* Find endpoints. */
        for (i = 0; i < id->bNumEndpoints; i++) {
                ed = usbd_interface2endpoint_descriptor(sc->axe_iface, i);
@@ -473,14 +654,28 @@ axe_attach(device_t parent, device_t sel
 
        s = splnet();
 
+       /* We need the PHYID for init dance in some cases */
+       axe_cmd(sc, AXE_CMD_READ_PHYID, 0, 0, (void *)&sc->axe_phyaddrs);
+
+       DPRINTF((" phyaddrs[0]: %x phyaddrs[1]: %x\n",
+           sc->axe_phyaddrs[0], sc->axe_phyaddrs[1]));
+
+       if (sc->axe_flags & AX178)
+               axe_ax88178_init(sc);
+       else if (sc->axe_flags & AX772)
+               axe_ax88772_init(sc);
+
        /*
         * Get station address.
         */
        axe_lock_mii(sc);
-       axe_cmd(sc, AXE_CMD_READ_NODEID, 0, 0, &eaddr);
+       if (sc->axe_flags & AX178 || sc->axe_flags & AX772)
+               axe_cmd(sc, AXE_178_CMD_READ_NODEID, 0, 0, &eaddr);
+       else    
+               axe_cmd(sc, AXE_172_CMD_READ_NODEID, 0, 0, &eaddr);
 
        /*
-        * Load IPG values and PHY indexes.
+        * Load IPG values
         */
        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);
@@ -489,30 +684,32 @@ axe_attach(device_t parent, device_t sel
        /*
         * Work around broken adapters that appear to lie about
         * their PHY addresses.
+        *
+        * This should probably be done with a quirk, but for now
+        * we simply ignore the addresses reported by the chip.
         */
        sc->axe_phyaddrs[0] = sc->axe_phyaddrs[1] = 0xFF;
 
        /*
         * An ASIX chip was detected. Inform the world.
         */
-       aprint_normal_dev(self, "Ethernet address %s\n",
-           ether_sprintf(eaddr));
+       aprint_normal_dev(self, "Ethernet address %s\n", ether_sprintf(eaddr));
 
        /* Initialize interface info.*/
-       ifp = GET_IFP(sc);
+       ifp = &sc->sc_if;
        ifp->if_softc = sc;
        strncpy(ifp->if_xname, devname, IFNAMSIZ);
        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
        ifp->if_ioctl = axe_ioctl;
        ifp->if_start = axe_start;
-
+       ifp->if_init = axe_init;
+       ifp->if_stop = axe_stop;
        ifp->if_watchdog = axe_watchdog;
 
-/*     ifp->if_baudrate = 10000000; */
-/*     ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;*/
-
        IFQ_SET_READY(&ifp->if_snd);
 
+       sc->axe_ec.ec_capabilities = ETHERCAP_VLAN_MTU;
+
        /* Initialize MII/media info. */
        mii = &sc->axe_mii;
        mii->mii_ifp = ifp;
@@ -522,7 +719,11 @@ axe_attach(device_t parent, device_t sel
        mii->mii_flags = MIIF_AUTOTSLEEP;
 
        sc->axe_ec.ec_mii = mii;
+#if notyet
+       ifmedia_init(&mii->mii_media, 0, axe_ifmedia_upd, axe_ifmedia_sts);
+#else
        ifmedia_init(&mii->mii_media, 0, ether_mediachange, ether_mediastatus);
+#endif
        mii_attach(self, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, 0);
 
        if (LIST_EMPTY(&mii->mii_phys)) {
@@ -539,7 +740,8 @@ axe_attach(device_t parent, device_t sel
            RND_TYPE_NET, 0);
 #endif
 
-       callout_init(&(sc->axe_stat_ch), 0);
+       callout_init(&sc->axe_stat_ch, 0);
+       callout_setfunc(&sc->axe_stat_ch, axe_tick, sc);
 
        sc->axe_attached = 1;
        splx(s);
@@ -552,22 +754,20 @@ axe_attach(device_t parent, device_t sel
 int
 axe_detach(device_t self, int flags)
 {
-       struct axe_softc *sc = device_private(self);
+       struct axe_softc        *sc = device_private(self);
        int                     s;
-       struct ifnet            *ifp = GET_IFP(sc);
+       struct ifnet            *ifp = &sc->sc_if;
 
        DPRINTFN(2,("%s: %s: enter\n", USBDEVNAME(sc->axe_dev), __func__));
 
        /* Detached before attached finished, so just bail out. */
        if (!sc->axe_attached)
-               return (0);
+               return 0;
 
-       callout_stop(&(sc->axe_stat_ch));
+       callout_destroy(&sc->axe_stat_ch);
 
        sc->axe_dying = 1;
 
-       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)
@@ -590,13 +790,11 @@ axe_detach(device_t self, int flags)
        }
 
        if (ifp->if_flags & IFF_RUNNING)
-               axe_stop(sc);
+               axe_stop(ifp, 1);
 
-#if defined(__NetBSD__)
 #if NRND > 0
        rnd_detach_source(&sc->rnd_source);
 #endif
-#endif /* __NetBSD__ */
        mii_detach(&sc->axe_mii, MII_PHY_ANY, MII_OFFSET_ANY);
        ifmedia_delete_instance(&sc->axe_mii.mii_media, IFM_INST_ANY);
        ether_ifdetach(ifp);
@@ -619,11 +817,11 @@ axe_detach(device_t self, int flags)
 
        usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->axe_udev, sc->axe_dev);
 
-       return (0);
+       return 0;
 }
 
 int
-axe_activate(device_t self, enum devact act)
+axe_activate(device_t self, devact_t act)
 {
        struct axe_softc *sc = device_private(self);
 
@@ -642,7 +840,7 @@ axe_activate(device_t self, enum devact 
 /*
  * Initialize an RX descriptor and attach an MBUF cluster.
  */
-Static int
+static int
 axe_newbuf(struct axe_softc *sc, struct axe_chain *c, struct mbuf *m)
 {
        struct mbuf             *m_new = NULL;
@@ -677,7 +875,7 @@ axe_newbuf(struct axe_softc *sc, struct 
        return (0);
 }
 
-Static int
+static int
 axe_rx_list_init(struct axe_softc *sc)
 {
        struct axe_cdata *cd;
@@ -697,7 +895,8 @@ axe_rx_list_init(struct axe_softc *sc)
                        c->axe_xfer = usbd_alloc_xfer(sc->axe_udev);
                        if (c->axe_xfer == NULL)
                                return (ENOBUFS);
-                       c->axe_buf = usbd_alloc_buffer(c->axe_xfer, AXE_BUFSZ);
+                       c->axe_buf = usbd_alloc_buffer(c->axe_xfer,
+                           sc->axe_bufsz);
                        if (c->axe_buf == NULL) {
                                usbd_free_xfer(c->axe_xfer);
                                return (ENOBUFS);
@@ -705,10 +904,10 @@ axe_rx_list_init(struct axe_softc *sc)
                }
        }
 
-       return (0);
+       return 0;
 }
 
-Static int
+static int
 axe_tx_list_init(struct axe_softc *sc)
 {
        struct axe_cdata *cd;
@@ -727,7 +926,8 @@ axe_tx_list_init(struct axe_softc *sc)
                        c->axe_xfer = usbd_alloc_xfer(sc->axe_udev);
                        if (c->axe_xfer == NULL)
                                return (ENOBUFS);
-                       c->axe_buf = usbd_alloc_buffer(c->axe_xfer, AXE_BUFSZ);
+                       c->axe_buf = usbd_alloc_buffer(c->axe_xfer,
+                           sc->axe_bufsz);
                        if (c->axe_buf == NULL) {
                                usbd_free_xfer(c->axe_xfer);
                                return (ENOBUFS);
@@ -735,54 +935,30 @@ axe_tx_list_init(struct axe_softc *sc)
                }
        }
 
-       return (0);
+       return 0;
 }
 
-#if 0
-Static void
-axe_rxstart(struct ifnet *ifp)
-{
-       struct axe_softc        *sc;
-       struct axe_chain        *c;
-
-       sc = ifp->if_softc;
-       axe_lock_mii(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_mii(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_mii(sc);
-
-       return;
-}
-#endif
-
 /*
  * A frame has been uploaded: pass the resulting mbuf chain up to
  * the higher level protocols.
  */
-Static void
+static void
 axe_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
 {
        struct axe_softc        *sc;
        struct axe_chain        *c;
        struct ifnet            *ifp;
-       struct mbuf             *m;
+       uint8_t                 *buf;
        u_int32_t               total_len;
+       u_int16_t               pktlen = 0;
+       struct mbuf             *m;
+       struct axe_sframe_hdr   hdr;
        int                     s;
 
-       c = priv;
+       c = (struct axe_chain *)priv;
        sc = c->axe_sc;
-       ifp = GET_IFP(sc);
+       buf = c->axe_buf;
+       ifp = &sc->sc_if;
 
        DPRINTFN(10,("%s: %s: enter\n", USBDEVNAME(sc->axe_dev),__func__));
 
@@ -795,10 +971,9 @@ axe_rxeof(usbd_xfer_handle xfer, usbd_pr
        if (status != USBD_NORMAL_COMPLETION) {
                if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
                        return;
-               if (usbd_ratecheck(&sc->axe_rx_notice)) {
-                       printf("%s: usb errors on rx: %s\n",
-                           device_xname(sc->axe_dev), usbd_errstr(status));
-               }
+               if (usbd_ratecheck(&sc->axe_rx_notice))
+                       aprint_error_dev(sc->axe_dev, "usb errors on rx: %s\n",
+                           usbd_errstr(status));
                if (status == USBD_STALLED)
                        
usbd_clear_endpoint_stall_async(sc->axe_ep[AXE_ENDPT_RX]);
                goto done;
@@ -806,44 +981,74 @@ axe_rxeof(usbd_xfer_handle xfer, usbd_pr
 
        usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
 
-       m = c->axe_mbuf;
+       do {
+               if (sc->axe_flags & AX178 || sc->axe_flags & AX772) {
+                       if (total_len < sizeof(hdr)) {
+                               ifp->if_ierrors++;
+                               goto done;
+                       }
+                       buf += pktlen;
 
-       if (total_len <= sizeof(struct ether_header)) {
-               ifp->if_ierrors++;
-               goto done;
-       }
+                       memcpy(&hdr, buf, sizeof(hdr));
+                       total_len -= sizeof(hdr);
 
-       ifp->if_ipackets++;
-       m->m_pkthdr.rcvif = ifp;
-       m->m_pkthdr.len = m->m_len = total_len;
+                       if ((hdr.len ^ hdr.ilen) != 0xffff) {
+                               ifp->if_ierrors++;
+                               goto done;
+                       }
+                       pktlen = le16toh(hdr.len);
+                       if (pktlen > total_len) {
+                               ifp->if_ierrors++;
+                               goto done;
+                       }
 
+                       buf += sizeof(hdr);
 
-       memcpy(mtod(c->axe_mbuf, char *), c->axe_buf, total_len);
+                       pktlen = roundup2(pktlen, 2);
 
-       /* No errors; receive the packet. */
-       total_len -= ETHER_CRC_LEN + 4;
+                       if (total_len < pktlen)
+                               total_len = 0;
+                       else
+                               total_len -= pktlen;
+               } else { /* AX172 */
+                       pktlen = total_len;
+                       total_len = 0;
+               }
 
-       s = splnet();
+               m = c->axe_mbuf;
 
-       /* XXX ugly */
-       if (axe_newbuf(sc, c, NULL) == ENOBUFS) {
-               ifp->if_ierrors++;
-               goto done1;
-       }
+               /* XXX ugly */
+               if (axe_newbuf(sc, c, NULL) == ENOBUFS) {
+                       ifp->if_ierrors++;
+                       goto done;
+               }
 
-       bpf_mtap(ifp, m);
-
-       DPRINTFN(10,("%s: %s: deliver %d\n", USBDEVNAME(sc->axe_dev),
-                   __func__, m->m_len));
-       (*(ifp)->if_input)((ifp), (m));
- done1:
-       splx(s);
+               ifp->if_ipackets++;
+               m->m_pkthdr.rcvif = ifp;
+               m->m_pkthdr.len = m->m_len = pktlen;
+
+               memcpy(mtod(m, char *), buf, pktlen);
+
+               /* No errors; receive the packet. */
+               pktlen -= ETHER_CRC_LEN + 4;
+
+               s = splnet();
+
+               bpf_mtap(ifp, m);
+
+               DPRINTFN(10,("%s: %s: deliver %d\n", USBDEVNAME(sc->axe_dev),
+                           __func__, m->m_len));
+               (*(ifp)->if_input)((ifp), (m));
+
+               splx(s);
+
+       } while (total_len > 0);
 
  done:
 
        /* Setup new transfer. */
        usbd_setup_xfer(xfer, sc->axe_ep[AXE_ENDPT_RX],
-           c, c->axe_buf, AXE_BUFSZ,
+           c, c->axe_buf, sc->axe_bufsz,
            USBD_SHORT_XFER_OK | USBD_NO_COPY,
            USBD_NO_TIMEOUT, axe_rxeof);
        usbd_transfer(xfer);
@@ -858,7 +1063,7 @@ axe_rxeof(usbd_xfer_handle xfer, usbd_pr
  * the list buffers.
  */
 
-Static void
+static void
 axe_txeof(usbd_xfer_handle xfer, usbd_private_handle priv,
     usbd_status status)
 {
@@ -869,7 +1074,7 @@ axe_txeof(usbd_xfer_handle xfer, usbd_pr
 
        c = priv;
        sc = c->axe_sc;
-       ifp = GET_IFP(sc);
+       ifp = &sc->sc_if;
 
        if (sc->axe_dying)
                return;
@@ -882,7 +1087,7 @@ axe_txeof(usbd_xfer_handle xfer, usbd_pr
                        return;
                }
                ifp->if_oerrors++;
-               printf("%s: usb error on tx: %s\n", device_xname(sc->axe_dev),
+               aprint_error_dev(sc->axe_dev, "usb error on tx: %s\n",
                    usbd_errstr(status));
                if (status == USBD_STALLED)
                        
usbd_clear_endpoint_stall_async(sc->axe_ep[AXE_ENDPT_TX]);
@@ -904,7 +1109,7 @@ axe_txeof(usbd_xfer_handle xfer, usbd_pr
        return;
 }
 
-Static void
+static void
 axe_tick(void *xsc)
 {
        struct axe_softc *sc = xsc;
@@ -923,7 +1128,7 @@ axe_tick(void *xsc)
 
 }
 
-Static void
+static void
 axe_tick_task(void *xsc)
 {
        int                     s;
@@ -939,25 +1144,38 @@ axe_tick_task(void *xsc)
        if (sc->axe_dying)
                return;
 
-       ifp = GET_IFP(sc);
-       mii = GET_MII(sc);
+       ifp = &sc->sc_if;
+       mii = &sc->axe_mii;
        if (mii == NULL)
                return;
 
        s = splnet();
 
        mii_tick(mii);
+#if notyet
+       if (!sc->axe_link && mii->mii_media_status & IFM_ACTIVE &&
+           IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
+               DPRINTF(("%s: %s: got link\n", device_xname(sc->axe_dev),
+                   __func__));
+               sc->axe_link++;
+               if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
+                       axe_start(ifp);
+       }
+#endif
 
-       callout_reset(&(sc->axe_stat_ch), (hz), (axe_tick), (sc));
+       callout_schedule(&sc->axe_stat_ch, hz);
 
        splx(s);
 }
 
-Static int
+static int
 axe_encap(struct axe_softc *sc, struct mbuf *m, int idx)
 {
+       struct ifnet            *ifp = &sc->sc_if;
        struct axe_chain        *c;
        usbd_status             err;
+       struct axe_sframe_hdr   hdr;
+       int                     length, boundary;
 
        c = &sc->axe_cdata.axe_tx_chain[idx];
 
@@ -965,26 +1183,47 @@ axe_encap(struct axe_softc *sc, struct m
         * 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);
+       if (sc->axe_flags & AX178 || sc->axe_flags & AX772) {
+               boundary = (sc->axe_udev->speed == USB_SPEED_HIGH) ? 512 : 64;
+
+               hdr.len = htole16(m->m_pkthdr.len);
+               hdr.ilen = ~hdr.len;
+
+               memcpy(c->axe_buf, &hdr, sizeof(hdr));
+               length = sizeof(hdr);
+
+               m_copydata(m, 0, m->m_pkthdr.len, c->axe_buf + length);
+               length += m->m_pkthdr.len;
+
+               if ((length % boundary) == 0) {
+                       hdr.len = 0x0000;
+                       hdr.ilen = 0xffff;
+                       memcpy(c->axe_buf + length, &hdr, sizeof(hdr));
+                       length += sizeof(hdr);
+               }
+       } else {
+               m_copydata(m, 0, m->m_pkthdr.len, c->axe_buf);
+               length = m->m_pkthdr.len;
+       }
        c->axe_mbuf = m;
 
        usbd_setup_xfer(c->axe_xfer, sc->axe_ep[AXE_ENDPT_TX],
-           c, c->axe_buf, m->m_pkthdr.len, USBD_FORCE_SHORT_XFER, 10000,
+           c, c->axe_buf, length, USBD_FORCE_SHORT_XFER, 10000,
            axe_txeof);
 
        /* Transmit */
        err = usbd_transfer(c->axe_xfer);
        if (err != USBD_IN_PROGRESS) {
-               axe_stop(sc);
-               return(EIO);
+               axe_stop(ifp, 0);
+               return EIO;
        }
 
        sc->axe_cdata.axe_tx_cnt++;
 
-       return(0);
+       return 0;
 }
 
-Static void
+static void
 axe_start(struct ifnet *ifp)
 {
        struct axe_softc        *sc;
@@ -992,19 +1231,24 @@ axe_start(struct ifnet *ifp)
 
        sc = ifp->if_softc;
 
+#if notyet
+       if (!sc->axe_link)
+               return;
+#endif
+
        if ((ifp->if_flags & (IFF_OACTIVE|IFF_RUNNING)) != IFF_RUNNING)
                return;
 
-       IF_DEQUEUE(&ifp->if_snd, m_head);
+       IFQ_POLL(&ifp->if_snd, m_head);
        if (m_head == NULL) {
                return;
        }
 
        if (axe_encap(sc, m_head, 0)) {
-               IF_PREPEND(&ifp->if_snd, m_head);
                ifp->if_flags |= IFF_OACTIVE;
                return;
        }
+       IFQ_DEQUEUE(&ifp->if_snd, m_head);
 
        /*
         * If there's a BPF listener, bounce a copy of this frame
@@ -1022,18 +1266,18 @@ axe_start(struct ifnet *ifp)
        return;
 }
 
-Static void
-axe_init(void *xsc)
+static int
+axe_init(struct ifnet *ifp)
 {
-       struct axe_softc        *sc = xsc;
-       struct ifnet            *ifp = GET_IFP(sc);
+       struct axe_softc        *sc = ifp->if_softc;
        struct axe_chain        *c;
        usbd_status             err;
        int                     rxmode;
        int                     i, s;
+       uint8_t                 eaddr[ETHER_ADDR_LEN];
 
        if (ifp->if_flags & IFF_RUNNING)
-               return;
+               axe_stop(ifp, 0);
 
        s = splnet();
 
@@ -1042,30 +1286,48 @@ axe_init(void *xsc)
         */
        axe_reset(sc);
 
+       /* Set MAC address */
+       if (sc->axe_flags & AX178 || sc->axe_flags & AX772) {
+               memcpy(eaddr, CLLADDR(ifp->if_sadl), sizeof(eaddr));
+               axe_cmd(sc, AXE_178_CMD_WRITE_NODEID, 0, 0, eaddr);
+       }
+
        /* Enable RX logic. */
 
        /* Init RX ring. */
        if (axe_rx_list_init(sc) == ENOBUFS) {
-               printf("%s: rx list init failed\n", device_xname(sc->axe_dev));
+               aprint_error_dev(sc->axe_dev, "rx list init failed\n");
                splx(s);
-               return;
+               return ENOBUFS;
        }
 
        /* Init TX ring. */
        if (axe_tx_list_init(sc) == ENOBUFS) {
-               printf("%s: tx list init failed\n", device_xname(sc->axe_dev));
+               aprint_error_dev(sc->axe_dev, "tx list init failed\n");
                splx(s);
-               return;
+               return ENOBUFS;
        }
 
        /* Set transmitter IPG values */
        axe_lock_mii(sc);
-       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);
+       if (sc->axe_flags & AX178 || sc->axe_flags & AX772)
+               axe_cmd(sc, AXE_178_CMD_WRITE_IPG012, sc->axe_ipgs[2],
+                   (sc->axe_ipgs[1] << 8) | (sc->axe_ipgs[0]), NULL);
+       else {
+               axe_cmd(sc, AXE_172_CMD_WRITE_IPG0, 0, sc->axe_ipgs[0], NULL);
+               axe_cmd(sc, AXE_172_CMD_WRITE_IPG1, 0, sc->axe_ipgs[1], NULL);
+               axe_cmd(sc, AXE_172_CMD_WRITE_IPG2, 0, sc->axe_ipgs[2], NULL);
+       }
 
        /* Enable receiver, set RX mode */
-       rxmode = AXE_RXCMD_UNICAST|AXE_RXCMD_MULTICAST|AXE_RXCMD_ENABLE;
+       rxmode = AXE_RXCMD_BROADCAST | AXE_RXCMD_MULTICAST | AXE_RXCMD_ENABLE;
+       if (sc->axe_flags & AX178 || sc->axe_flags & AX772) {
+               if (sc->axe_udev->speed == USB_SPEED_HIGH) {
+                       /* Largest possible USB buffer size for AX88178 */
+                       rxmode |= AXE_178_RXCMD_MFB;
+               }
+       } else
+               rxmode |= AXE_172_RXCMD_UNICAST;
 
        /* If we want promiscuous mode, set the allframes bit. */
        if (ifp->if_flags & IFF_PROMISC)
@@ -1084,26 +1346,26 @@ axe_init(void *xsc)
        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("%s: open rx pipe failed: %s\n",
-                   device_xname(sc->axe_dev), usbd_errstr(err));
+               aprint_error_dev(sc->axe_dev, "open rx pipe failed: %s\n",
+                   usbd_errstr(err));
                splx(s);
-               return;
+               return EIO;
        }
 
        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("%s: open tx pipe failed: %s\n",
-                   device_xname(sc->axe_dev), usbd_errstr(err));
+               aprint_error_dev(sc->axe_dev, "open tx pipe failed: %s\n",
+                   usbd_errstr(err));
                splx(s);
-               return;
+               return EIO;
        }
 
        /* 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,
+                   c, mtod(c->axe_mbuf, char *), sc->axe_bufsz,
                    USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, axe_rxeof);
                usbd_transfer(c->axe_xfer);
        }
@@ -1113,111 +1375,54 @@ axe_init(void *xsc)
 
        splx(s);
 
-       callout_init(&(sc->axe_stat_ch), 0);
-       callout_reset(&(sc->axe_stat_ch), (hz), (axe_tick), (sc));
-       return;
+       callout_schedule(&sc->axe_stat_ch, hz);
+       return 0;
 }
 
-Static int
+static int
 axe_ioctl(struct ifnet *ifp, u_long cmd, void *data)
 {
        struct axe_softc        *sc = ifp->if_softc;
-       struct ifreq            *ifr = (struct ifreq *)data;
-       struct ifaddr           *ifa = (struct ifaddr *)data;
-       u_int16_t               rxmode;
+       int                     s;
        int                     error = 0;
 
-       switch(cmd) {
-       case SIOCINITIFADDR:
-               ifp->if_flags |= IFF_UP;
-               axe_init(sc);
-
-               switch (ifa->ifa_addr->sa_family) {
-#ifdef INET
-               case AF_INET:
-#if defined(__NetBSD__)
-                       arp_ifinit(ifp, ifa);
-#else
-                       arp_ifinit(&sc->arpcom, ifa);
-#endif
-                       break;
-#endif /* INET */
-               }
-               break;
-
-       case SIOCSIFMTU:
-               if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ETHERMTU)
-                       error = EINVAL;
-               else if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET)
-                       error = 0;
-               break;
+       s = splnet();
 
+       switch(cmd) {
        case SIOCSIFFLAGS:
-               if ((error = ifioctl_common(ifp, cmd, data)) != 0)
+               switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
+               case IFF_RUNNING:
+                       axe_stop(ifp, 1);
                        break;
-               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_mii(sc);
-                               axe_cmd(sc, AXE_CMD_RXCTL_READ,
-                                       0, 0, (void *)&rxmode);
-                               rxmode = le16toh(rxmode) | AXE_RXCMD_PROMISC;
-                               axe_cmd(sc, AXE_CMD_RXCTL_WRITE,
-                                       0, rxmode, NULL);
-                               axe_unlock_mii(sc);
-
-                               axe_setmulti(sc);
-                       } else if (ifp->if_flags & IFF_RUNNING &&
-                           !(ifp->if_flags & IFF_PROMISC) &&
-                           sc->axe_if_flags & IFF_PROMISC) {
-                               axe_lock_mii(sc);
-                               axe_cmd(sc, AXE_CMD_RXCTL_READ,
-                                       0, 0, (void *)&rxmode);
-                               rxmode = le16toh(rxmode) & ~AXE_RXCMD_PROMISC;
-                               axe_cmd(sc, AXE_CMD_RXCTL_WRITE,
-                                       0, rxmode, NULL);
-                               axe_unlock_mii(sc);
+               case IFF_UP:
+                       axe_init(ifp);
+                       break;
+               case IFF_UP | IFF_RUNNING:
+                       if ((ifp->if_flags ^ sc->axe_if_flags) == IFF_PROMISC)
                                axe_setmulti(sc);
-                       } else if (!(ifp->if_flags & IFF_RUNNING))
-                               axe_init(sc);
-               } else {
-                       if (ifp->if_flags & IFF_RUNNING)
-                               axe_stop(sc);
+                       else
+                               axe_init(ifp);
+                       break;
                }
                sc->axe_if_flags = ifp->if_flags;
-               error = 0;
-               break;
-       case SIOCADDMULTI:
-       case SIOCDELMULTI:
-       case SIOCGIFMEDIA:
-       case SIOCSIFMEDIA:
-               error = ether_ioctl(ifp, cmd, data);
-               if (error == ENETRESET) {
-                       /*
-                        * Multicast list has changed; set the hardware
-                        * filter accordingly.
-                        */
-                       if (ifp->if_flags & IFF_RUNNING)
-                               axe_setmulti(sc);
-                       error = 0;
-               }
                break;
+
        default:
-               error = ether_ioctl(ifp, cmd, data);
-               break;
+               if ((error = ether_ioctl(ifp, cmd, data)) != ENETRESET)
+                       break;
+
+               error = 0;
+
+               if (cmd == SIOCADDMULTI || cmd == SIOCDELMULTI)
+                       axe_setmulti(sc);
+
        }
+       splx(s);
 
-       return(error);
+       return error;
 }
 
-/*
- * XXX
- * You can't call axe_txeof since the USB transfer has not
- * completed yet.
- */
-Static void
+static void
 axe_watchdog(struct ifnet *ifp)
 {
        struct axe_softc        *sc;
@@ -1228,14 +1433,14 @@ axe_watchdog(struct ifnet *ifp)
        sc = ifp->if_softc;
 
        ifp->if_oerrors++;
-       printf("%s: watchdog timeout\n", device_xname(sc->axe_dev));
+       aprint_error_dev(sc->axe_dev, "watchdog timeout\n");
 
        s = splusb();
        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);
 
-       if (ifp->if_snd.ifq_head != NULL)
+       if (IFQ_IS_EMPTY(&ifp->if_snd))
                axe_start(ifp);
        splx(s);
 }
@@ -1244,17 +1449,17 @@ axe_watchdog(struct ifnet *ifp)
  * Stop the adapter and free any mbufs allocated to the
  * RX and TX lists.
  */
-Static void
-axe_stop(struct axe_softc *sc)
+static void
+axe_stop(struct ifnet *ifp, int disable)
 {
+       struct axe_softc        *sc = ifp->if_softc;
        usbd_status             err;
-       struct ifnet            *ifp;
        int                     i;
 
        axe_reset(sc);
 
-       ifp = GET_IFP(sc);
        ifp->if_timer = 0;
+       ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
 
        callout_stop(&(sc->axe_stat_ch));
 
@@ -1262,13 +1467,13 @@ axe_stop(struct axe_softc *sc)
        if (sc->axe_ep[AXE_ENDPT_RX] != NULL) {
                err = usbd_abort_pipe(sc->axe_ep[AXE_ENDPT_RX]);
                if (err) {
-                       printf("%s: abort rx pipe failed: %s\n",
-                           device_xname(sc->axe_dev), usbd_errstr(err));
+                       aprint_error_dev(sc->axe_dev,
+                           "abort rx pipe failed: %s\n", usbd_errstr(err));
                }
                err = usbd_close_pipe(sc->axe_ep[AXE_ENDPT_RX]);
                if (err) {
-                       printf("%s: close rx pipe failed: %s\n",
-                           device_xname(sc->axe_dev), usbd_errstr(err));
+                       aprint_error_dev(sc->axe_dev,
+                           "close rx pipe failed: %s\n", usbd_errstr(err));
                }
                sc->axe_ep[AXE_ENDPT_RX] = NULL;
        }
@@ -1276,13 +1481,13 @@ axe_stop(struct axe_softc *sc)
        if (sc->axe_ep[AXE_ENDPT_TX] != NULL) {
                err = usbd_abort_pipe(sc->axe_ep[AXE_ENDPT_TX]);
                if (err) {
-                       printf("%s: abort tx pipe failed: %s\n",
-                           device_xname(sc->axe_dev), usbd_errstr(err));
+                       aprint_error_dev(sc->axe_dev,
+                           "abort tx pipe failed: %s\n", usbd_errstr(err));
                }
                err = usbd_close_pipe(sc->axe_ep[AXE_ENDPT_TX]);
                if (err) {
-                       printf("%s: close tx pipe failed: %s\n",
-                           device_xname(sc->axe_dev), usbd_errstr(err));
+                       aprint_error_dev(sc->axe_dev,
+                           "close tx pipe failed: %s\n", usbd_errstr(err));
                }
                sc->axe_ep[AXE_ENDPT_TX] = NULL;
        }
@@ -1290,13 +1495,13 @@ axe_stop(struct axe_softc *sc)
        if (sc->axe_ep[AXE_ENDPT_INTR] != NULL) {
                err = usbd_abort_pipe(sc->axe_ep[AXE_ENDPT_INTR]);
                if (err) {
-                       printf("%s: abort intr pipe failed: %s\n",
-                           device_xname(sc->axe_dev), usbd_errstr(err));
+                       aprint_error_dev(sc->axe_dev,
+                           "abort intr pipe failed: %s\n", usbd_errstr(err));
                }
                err = usbd_close_pipe(sc->axe_ep[AXE_ENDPT_INTR]);
                if (err) {
-                       printf("%s: close intr pipe failed: %s\n",
-                           device_xname(sc->axe_dev), usbd_errstr(err));
+                       aprint_error_dev(sc->axe_dev,
+                           "close intr pipe failed: %s\n", usbd_errstr(err));
                }
                sc->axe_ep[AXE_ENDPT_INTR] = NULL;
        }
@@ -1325,5 +1530,5 @@ axe_stop(struct axe_softc *sc)
                }
        }
 
-       ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+       sc->axe_link = 0;
 }
Index: if_axereg.h
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/if_axereg.h,v
retrieving revision 1.7
diff -u -p -r1.7 if_axereg.h
--- if_axereg.h 4 Sep 2009 18:10:08 -0000       1.7
+++ if_axereg.h 15 Jun 2010 04:10:31 -0000
@@ -55,9 +55,11 @@
 #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_172_CMD_READ_RXTX_SRAM             0x2002
+#define AXE_182_CMD_READ_RXTX_SRAM             0x6002
+#define AXE_172_CMD_WRITE_RX_SRAM              0x0103
+#define AXE_172_CMD_WRITE_TX_SRAM              0x0104
+#define AXE_182_CMD_WRITE_RXTX_SRAM            0x8103
 #define AXE_CMD_MII_OPMODE_SW                  0x0106
 #define AXE_CMD_MII_READ_REG                   0x2007
 #define AXE_CMD_MII_WRITE_REG                  0x2108
@@ -70,36 +72,74 @@
 #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_172_CMD_WRITE_IPG0                 0x0112
+#define AXE_172_CMD_WRITE_IPG1                 0x0113
+#define AXE_172_CMD_WRITE_IPG2                 0x0114
+#define AXE_178_CMD_WRITE_IPG012               0x0112
 #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_172_CMD_READ_NODEID                        0x6017
+#define AXE_172_CMD_WRITE_NODEID               0x6118
+#define AXE_178_CMD_READ_NODEID                        0x6013
+#define AXE_178_CMD_WRITE_NODEID               0x6114
 #define AXE_CMD_READ_PHYID                     0x2019
-#define AXE_CMD_READ_MEDIA                     0x101A
+#define AXE_172_CMD_READ_MEDIA                 0x101A
+#define AXE_178_CMD_READ_MEDIA                 0x201A
 #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_MEDIA_FULL_DUPLEX                  0x02
-#define AXE_MEDIA_TX_ABORT_ALLOW               0x04
-#define AXE_MEDIA_FLOW_CONTROL_EN              0x10
+#define AXE_CMD_SW_RESET_REG                   0x0120
+#define AXE_CMD_SW_PHY_STATUS                  0x0021
+#define AXE_CMD_SW_PHY_SELECT                  0x0122
+
+#define AXE_SW_RESET_CLEAR                     0x00
+#define AXE_SW_RESET_RR                                0x01
+#define AXE_SW_RESET_RT                                0x02
+#define AXE_SW_RESET_PRTE                      0x04
+#define AXE_SW_RESET_PRL                       0x08
+#define AXE_SW_RESET_BZ                                0x10
+#define AXE_SW_RESET_IPRL                      0x20
+#define AXE_SW_RESET_IPPD                      0x40
+
+/* AX88178 documentation says to always write this bit... */
+#define AXE_178_RESET_MAGIC                    0x40
+
+#define AXE_178_MEDIA_GMII                     0x0001
+#define AXE_MEDIA_FULL_DUPLEX                  0x0002
+#define AXE_172_MEDIA_TX_ABORT_ALLOW           0x0004
+/* AX88178 documentation says to always write 1 to reserved bit... */
+#define AXE_178_MEDIA_MAGIC                    0x0004
+#define AXE_178_MEDIA_ENCK                     0x0008
+#define AXE_172_MEDIA_FLOW_CONTROL_EN          0x0010
+#define AXE_178_MEDIA_RXFLOW_CONTROL_EN                0x0010
+#define AXE_178_MEDIA_TXFLOW_CONTROL_EN                0x0020
+#define AXE_178_MEDIA_JUMBO_EN                 0x0040
+#define AXE_178_MEDIA_LTPF_ONLY                        0x0080
+#define AXE_178_MEDIA_RX_EN                    0x0100
+#define AXE_178_MEDIA_100TX                    0x0200
+#define AXE_178_MEDIA_SBP                      0x0800
+#define AXE_178_MEDIA_SUPERMAC                 0x1000
 
 #define AXE_RXCMD_PROMISC                      0x0001
 #define AXE_RXCMD_ALLMULTI                     0x0002
-#define AXE_RXCMD_UNICAST                      0x0004
+#define AXE_172_RXCMD_UNICAST                  0x0004
+#define AXE_178_RXCMD_KEEP_INVALID_CRC         0x0004
 #define AXE_RXCMD_BROADCAST                    0x0008
 #define AXE_RXCMD_MULTICAST                    0x0010
 #define AXE_RXCMD_ENABLE                       0x0080
+#define AXE_178_RXCMD_MFB                      0x0300
 
 #define AXE_NOPHY                              0xE0
+#define AXE_INTPHY                             0x10
 
 #define AXE_TIMEOUT            1000
-#define AXE_BUFSZ              1536
+
+#define AXE_172_BUFSZ          1536
+#define AXE_178_MIN_BUFSZ      2048
+#define AXE_178_MAX_BUFSZ      16384
+
 #define AXE_MIN_FRAMELEN       60
 #define AXE_RX_FRAMES          1
 #define AXE_TX_FRAMES          1
@@ -125,7 +165,8 @@
 struct axe_type {
        struct usb_devno        axe_dev;
        u_int16_t               axe_flags;
-/* XXX No flags so far */
+#define AX178  0x0001          /* AX88178 */
+#define AX772  0x0002          /* AX88772 */
 };
 
 struct axe_softc;
@@ -148,7 +189,10 @@ struct axe_cdata {
        int                     axe_rx_prod;
 };
 
-#define AXE_INC(x, y)          (x) = (x + 1) % y
+struct axe_sframe_hdr {
+       u_int16_t               len;
+       u_int16_t               ilen;
+} __packed;
 
 struct axe_softc {
        device_t axe_dev;
@@ -157,13 +201,12 @@ struct axe_softc {
 #if NRND > 0
        rndsource_element_t     rnd_source;
 #endif
-#define GET_IFP(sc) (&(sc)->axe_ec.ec_if)
-#define GET_MII(sc) (&(sc)->axe_mii)
        usbd_device_handle      axe_udev;
        usbd_interface_handle   axe_iface;
 
        u_int16_t               axe_vendor;
        u_int16_t               axe_product;
+       u_int16_t               axe_flags;
 
        int                     axe_ed[AXE_ENDPT_MAX];
        usbd_pipe_handle        axe_ep[AXE_ENDPT_MAX];
@@ -180,17 +223,14 @@ struct axe_softc {
 
        kmutex_t                axe_mii_lock;
 
+       int                     axe_link;
+
        unsigned char           axe_ipgs[3];
        unsigned char           axe_phyaddrs[2];
        struct timeval          axe_rx_notice;
-};
+       int                     axe_bufsz;
 
-#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
+#define sc_if  axe_ec.ec_if
+};
 
 #define ETHER_ALIGN            2


Home | Main Index | Thread Index | Old Index