kernel/usb4bsd: Bring in the axge(4) ethernet driver.
authorSascha Wildner <saw@online.de>
Sat, 15 Nov 2014 16:50:05 +0000 (17:50 +0100)
committerSascha Wildner <saw@online.de>
Sat, 15 Nov 2014 16:59:34 +0000 (17:59 +0100)
It supports USB Gigabit Ethernet adapters based on the
ASIX Electronics AX88179 USB 3.0 and AX88178A USB 2.0
chipsets.

Taken-from: FreeBSD

13 files changed:
etc/devd/usb.conf
share/man/man4/Makefile
share/man/man4/axge.4 [new file with mode: 0644]
share/man/man4/miibus.4
share/man/man4/usb.4
sys/bus/u4b/net/Makefile
sys/bus/u4b/net/axge/Makefile [new file with mode: 0644]
sys/bus/u4b/net/if_axge.c [new file with mode: 0644]
sys/bus/u4b/net/if_axgereg.h [new file with mode: 0644]
sys/bus/u4b/usbdevs
sys/conf/files
sys/config/LINT
sys/config/LINT64

index bad52da..0f69cd1 100644 (file)
@@ -1599,7 +1599,23 @@ nomatch 32 {
        match "bus" "uhub[0-9]+";
        match "mode" "host";
        match "vendor" "0x0b95";
-       match "product" "(0x1720|0x1780|0x7720|0x772a|0x772b|0x7e2b)";
+       match "product" "(0x1720|0x1780)";
+       action "kldload -n if_axe";
+};
+
+nomatch 32 {
+       match "bus" "uhub[0-9]+";
+       match "mode" "host";
+       match "vendor" "0x0b95";
+       match "product" "(0x178a|0x1790)";
+       action "kldload -n if_axge";
+};
+
+nomatch 32 {
+       match "bus" "uhub[0-9]+";
+       match "mode" "host";
+       match "vendor" "0x0b95";
+       match "product" "(0x7720|0x772a|0x772b|0x7e2b)";
        action "kldload -n if_axe";
 };
 
@@ -1763,6 +1779,14 @@ nomatch 32 {
        action "kldload -n if_urtwn";
 };
 
+nomatch 32 {
+       match "bus" "uhub[0-9]+";
+       match "mode" "host";
+       match "vendor" "0x0df6";
+       match "product" "0x0072";
+       action "kldload -n if_axge";
+};
+
 nomatch 32 {
        match "bus" "uhub[0-9]+";
        match "mode" "host";
@@ -2895,7 +2919,23 @@ nomatch 32 {
        match "bus" "uhub[0-9]+";
        match "mode" "host";
        match "vendor" "0x2001";
-       match "product" "(0x4001|0x4002|0x4003|0x400b|0x4102|0xabc1)";
+       match "product" "(0x4001|0x4002|0x4003|0x400b|0x4102)";
+       action "kldload -n if_aue";
+};
+
+nomatch 32 {
+       match "bus" "uhub[0-9]+";
+       match "mode" "host";
+       match "vendor" "0x2001";
+       match "product" "0x4a00";
+       action "kldload -n if_axge";
+};
+
+nomatch 32 {
+       match "bus" "uhub[0-9]+";
+       match "mode" "host";
+       match "vendor" "0x2001";
+       match "product" "0xabc1";
        action "kldload -n if_aue";
 };
 
@@ -3383,5 +3423,5 @@ nomatch 32 {
        action "kldload -n umass";
 };
 
-# 1531 USB entries processed
+# 1535 USB entries processed
 
index a3a56f4..49325a5 100644 (file)
@@ -46,6 +46,7 @@ MAN=  aac.4 \
        atkbdc.4 \
        aue.4 \
        axe.4 \
+       axge.4 \
        bce.4 \
        bfe.4 \
        bge.4 \
@@ -419,6 +420,7 @@ MLINKS+=an.4 if_an.4
 MLINKS+=ath.4 if_ath.4
 MLINKS+=aue.4 if_aue.4
 MLINKS+=axe.4 if_axe.4
+MLINKS+=axge.4 if_axge.4
 MLINKS+=bce.4 if_bce.4
 MLINKS+=bfe.4 if_bfe.4
 MLINKS+=bge.4 if_bge.4
diff --git a/share/man/man4/axge.4 b/share/man/man4/axge.4
new file mode 100644 (file)
index 0000000..78b370f
--- /dev/null
@@ -0,0 +1,152 @@
+.\" 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: head/share/man/man4/axge.4 267938 2014-06-26 21:46:14Z bapt $
+.\"
+.Dd November 15, 2014
+.Dt AXGE 4
+.Os
+.Sh NAME
+.Nm axge
+.Nd "ASIX Electronics AX88178A/AX88179 USB Gigabit Ethernet driver"
+.Sh SYNOPSIS
+To compile this driver into the kernel,
+place the following lines in your
+kernel configuration file:
+.Bd -ragged -offset indent
+.Cd "device xhci"
+.Cd "device ehci"
+.Cd "device uhci"
+.Cd "device ohci"
+.Cd "device usb"
+.Cd "device miibus"
+.Cd "device axge"
+.Ed
+.Pp
+Alternatively, to load the driver as a
+module at boot time, place the following line in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+if_axge_load="YES"
+.Ed
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for USB Gigabit Ethernet adapters based on the ASIX
+Electronics AX88179 USB 3.0 and AX88178A USB 2.0 chipsets.
+.Pp
+The AX88179 and AX88178A contain a 10/100/1000 Ethernet MAC with a GMII
+interface for interfacing with the Gigabit Ethernet PHY.
+.Pp
+These devices will operate with both USB 1.x and USB 2.0 controllers, and the
+AX88179 will operate with USB 3.0 controllers.
+Packets are received and transmitted over separate USB bulk transfer endpoints.
+.Pp
+The
+.Nm
+driver supports the following media types:
+.Bl -tag -width ".Cm 10baseT/UTP"
+.It Cm autoselect
+Enable autoselection of the media type and options.
+The user can manually override
+the autoselected mode by adding media options to
+.Xr rc.conf 5 .
+.It Cm 10baseT/UTP
+Set 10Mbps operation.
+The
+.Xr ifconfig 8
+.Cm mediaopt
+option can also be used to select either
+.Cm full-duplex
+or
+.Cm half-duplex
+modes.
+.It Cm 100baseTX
+Set 100Mbps (Fast Ethernet) operation.
+The
+.Xr ifconfig 8
+.Cm mediaopt
+option can also be used to select either
+.Cm full-duplex
+or
+.Cm half-duplex
+modes.
+.It Cm 1000baseT
+Set 1000Mbps (Gigabit Ethernet) operation (AX88178 only).
+The
+.Xr ifconfig 8
+.Cm mediaopt
+option can also be used to select either
+.Cm full-duplex
+or
+.Cm half-duplex
+modes.
+.El
+.Pp
+The
+.Nm
+driver supports the following media options:
+.Bl -tag -width ".Cm full-duplex"
+.It Cm full-duplex
+Force full duplex operation.
+.It Cm half-duplex
+Force half duplex operation.
+.El
+.Pp
+For more information on configuring this device, see
+.Xr ifconfig 8 .
+.Sh SEE ALSO
+.Xr altq 4 ,
+.Xr arp 4 ,
+.Xr ifmedia 4 ,
+.Xr miibus 4 ,
+.Xr netintro 4 ,
+.Xr ng_ether 4 ,
+.Xr rgephy 4 ,
+.Xr vlan 4 ,
+.Xr ifconfig 8
+.Sh HISTORY
+The
+.Nm
+device driver first appeared in
+.Fx 10.1 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+driver was written by
+.An Kevin Lo Aq Mt kevlo@FreeBSD.org
+and
+.An Li-Wen Hsu Aq Mt lwhsu@FreeBSD.org .
+This manual page was adapted by
+.An Mark Johnston Aq Mt markj@FreeBSD.org
+from the
+.Xr axe 4
+manual page.
index 085454f..c775590 100644 (file)
@@ -59,6 +59,8 @@ Atheros AR8121/AR8113/AR8114 Gigabit/Fast Ethernet
 ADMtek USB Ethernet
 .It Xr axe 4
 ASIX Electronics AX88172 USB Ethernet
+.It Xr axge 4
+ASIX Electronics AX88178A/AX88179 USB Gigabit Ethernet
 .It Xr bce 4
 Broadcom BCM5706/BCM5708 Gigabit Ethernet
 .It Xr bfe 4
@@ -135,6 +137,7 @@ but as a result are not well behaved newbus device drivers.
 .Xr arp 4 ,
 .Xr aue 4 ,
 .Xr axe 4 ,
+.Xr axge 4 ,
 .Xr bce 4 ,
 .Xr bfe 4 ,
 .Xr bge 4 ,
index 1667bb0..ec1ab21 100644 (file)
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD: head/share/man/man4/usb.4 258618 2013-11-26 07:52:40Z lwhsu $
 .\"
-.Dd November 10, 2014
+.Dd November 15, 2014
 .Dt USB 4
 .Os
 .Sh NAME
@@ -98,6 +98,8 @@ Mass storage driver for device-side mode
 ADMtek AN986 Pegasus Ethernet driver
 .It Xr axe 4
 ASIX Electronics AX88x7x/760 USB Ethernet driver
+.It Xr axge 4
+ASIX Electronics AX88178A/AX88179 USB Gigabit Ethernet driver
 .It Xr cue 4
 CATC USB-EL1210A Ethernet driver
 .It Xr ipheth 4
@@ -271,7 +273,7 @@ specifications can be found at:
 .Xr libusb 3 ,
 .Xr aue 4 ,
 .Xr axe 4 ,
-.\".Xr axge 4 ,
+.Xr axge 4 ,
 .Xr cue 4 ,
 .Xr ehci 4 ,
 .Xr ipheth 4 ,
index d9dc762..a13690d 100644 (file)
@@ -1,6 +1,6 @@
 #
-# XXX MISSING: axge cdce rue smsc uhso usie
+# XXX MISSING: cdce rue smsc uhso usie
 
-SUBDIR=        aue axe cue ipheth kue mos udav uether urndis
+SUBDIR=        aue axe axge cue ipheth kue mos udav uether urndis
 
 .include <bsd.subdir.mk>
diff --git a/sys/bus/u4b/net/axge/Makefile b/sys/bus/u4b/net/axge/Makefile
new file mode 100644 (file)
index 0000000..83c46dd
--- /dev/null
@@ -0,0 +1,10 @@
+# $FreeBSD: head/sys/modules/usb/axge/Makefile 258331 2013-11-19 00:37:53Z markj $
+
+.PATH: ${.CURDIR}/..
+
+KMOD=  if_axge
+SRCS+= if_axge.c usbdevs.h
+SRCS+= bus_if.h device_if.h miibus_if.h usb_if.h \
+       opt_bus.h opt_inet.h opt_usb.h
+
+.include <bsd.kmod.mk>
diff --git a/sys/bus/u4b/net/if_axge.c b/sys/bus/u4b/net/if_axge.c
new file mode 100644 (file)
index 0000000..90f244f
--- /dev/null
@@ -0,0 +1,1036 @@
+/*-
+ * Copyright (c) 2013-2014 Kevin Lo
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 THE AUTHOR OR CONTRIBUTORS 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: head/sys/dev/usb/net/if_axge.c 271832 2014-09-18 21:09:22Z glebius $
+ */
+
+/*
+ * ASIX Electronics AX88178A/AX88179 USB 2.0/3.0 gigabit ethernet driver.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/condvar.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/unistd.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/ifq_var.h>
+
+#include <bus/u4b/usb.h>
+#include <bus/u4b/usbdi.h>
+#include <bus/u4b/usbdi_util.h>
+#include "usbdevs.h"
+
+#define        USB_DEBUG_VAR   axge_debug
+#include <bus/u4b/usb_debug.h>
+#include <bus/u4b/usb_process.h>
+
+#include <bus/u4b/net/usb_ethernet.h>
+#include <bus/u4b/net/if_axgereg.h>
+
+/*
+ * Various supported device vendors/products.
+ */
+
+static const STRUCT_USB_HOST_ID axge_devs[] = {
+#define        AXGE_DEV(v,p) { USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) }
+       AXGE_DEV(ASIX, AX88178A),
+       AXGE_DEV(ASIX, AX88179),
+       AXGE_DEV(DLINK, DUB1312),
+       AXGE_DEV(SITECOMEU, LN032),
+#undef AXGE_DEV
+};
+
+static const struct {
+       uint8_t ctrl;
+       uint8_t timer_l;
+       uint8_t timer_h;
+       uint8_t size;
+       uint8_t ifg;
+} __packed axge_bulk_size[] = {
+       { 7, 0x4f, 0x00, 0x12, 0xff },
+       { 7, 0x20, 0x03, 0x16, 0xff },
+       { 7, 0xae, 0x07, 0x18, 0xff },
+       { 7, 0xcc, 0x4c, 0x18, 0x08 }
+};
+
+/* prototypes */
+
+static device_probe_t axge_probe;
+static device_attach_t axge_attach;
+static device_detach_t axge_detach;
+
+static usb_callback_t axge_bulk_read_callback;
+static usb_callback_t axge_bulk_write_callback;
+
+static miibus_readreg_t axge_miibus_readreg;
+static miibus_writereg_t axge_miibus_writereg;
+static miibus_statchg_t axge_miibus_statchg;
+
+static uether_fn_t axge_attach_post;
+static uether_fn_t axge_init;
+static uether_fn_t axge_stop;
+static uether_fn_t axge_start;
+static uether_fn_t axge_tick;
+static uether_fn_t axge_setmulti;
+static uether_fn_t axge_setpromisc;
+
+static int     axge_read_mem(struct axge_softc *, uint8_t, uint16_t,
+                   uint16_t, void *, int);
+static void    axge_write_mem(struct axge_softc *, uint8_t, uint16_t,
+                   uint16_t, void *, int);
+static uint8_t axge_read_cmd_1(struct axge_softc *, uint8_t, uint16_t);
+static uint16_t        axge_read_cmd_2(struct axge_softc *, uint8_t, uint16_t,
+                   uint16_t);
+static void    axge_write_cmd_1(struct axge_softc *, uint8_t, uint16_t,
+                   uint8_t);
+static void    axge_write_cmd_2(struct axge_softc *, uint8_t, uint16_t,
+                   uint16_t, uint16_t);
+static void    axge_chip_init(struct axge_softc *);
+static void    axge_reset(struct axge_softc *);
+
+static int     axge_attach_post_sub(struct usb_ether *);
+static int     axge_ifmedia_upd(struct ifnet *);
+static void    axge_ifmedia_sts(struct ifnet *, struct ifmediareq *);
+static int     axge_ioctl(struct ifnet *, u_long, caddr_t, struct ucred *);
+static void    axge_rx_frame(struct usb_ether *, struct usb_page_cache *, int);
+static void    axge_rxeof(struct usb_ether *, struct usb_page_cache *,
+                   unsigned int, unsigned int, uint32_t);
+static void    axge_csum_cfg(struct usb_ether *);
+
+#define        AXGE_CSUM_FEATURES      (CSUM_IP | CSUM_TCP | CSUM_UDP)
+
+#ifdef USB_DEBUG
+static int axge_debug = 0;
+
+static SYSCTL_NODE(_hw_usb, OID_AUTO, axge, CTLFLAG_RW, 0, "USB axge");
+SYSCTL_INT(_hw_usb_axge, OID_AUTO, debug, CTLFLAG_RW, &axge_debug, 0,
+    "Debug level");
+#endif
+
+static const struct usb_config axge_config[AXGE_N_TRANSFER] = {
+       [AXGE_BULK_DT_WR] = {
+               .type = UE_BULK,
+               .endpoint = UE_ADDR_ANY,
+               .direction = UE_DIR_OUT,
+               .frames = 16,
+               .bufsize = 16 * MCLBYTES,
+               .flags = {.pipe_bof = 1,.force_short_xfer = 1,},
+               .callback = axge_bulk_write_callback,
+               .timeout = 10000,       /* 10 seconds */
+       },
+       [AXGE_BULK_DT_RD] = {
+               .type = UE_BULK,
+               .endpoint = UE_ADDR_ANY,
+               .direction = UE_DIR_IN,
+               .bufsize = 65536,
+               .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
+               .callback = axge_bulk_read_callback,
+               .timeout = 0,           /* no timeout */
+       },
+};
+
+static device_method_t axge_methods[] = {
+       /* Device interface. */
+       DEVMETHOD(device_probe,         axge_probe),
+       DEVMETHOD(device_attach,        axge_attach),
+       DEVMETHOD(device_detach,        axge_detach),
+
+       /* MII interface. */
+       DEVMETHOD(miibus_readreg,       axge_miibus_readreg),
+       DEVMETHOD(miibus_writereg,      axge_miibus_writereg),
+       DEVMETHOD(miibus_statchg,       axge_miibus_statchg),
+
+       DEVMETHOD_END
+};
+
+static driver_t axge_driver = {
+       .name = "axge",
+       .methods = axge_methods,
+       .size = sizeof(struct axge_softc),
+};
+
+static devclass_t axge_devclass;
+
+DRIVER_MODULE(axge, uhub, axge_driver, axge_devclass, NULL, NULL);
+DRIVER_MODULE(miibus, axge, miibus_driver, miibus_devclass, NULL, NULL);
+MODULE_DEPEND(axge, uether, 1, 1, 1);
+MODULE_DEPEND(axge, usb, 1, 1, 1);
+MODULE_DEPEND(axge, ether, 1, 1, 1);
+MODULE_DEPEND(axge, miibus, 1, 1, 1);
+MODULE_VERSION(axge, 1);
+
+static const struct usb_ether_methods axge_ue_methods = {
+       .ue_attach_post = axge_attach_post,
+       .ue_attach_post_sub = axge_attach_post_sub,
+       .ue_start = axge_start,
+       .ue_init = axge_init,
+       .ue_stop = axge_stop,
+       .ue_tick = axge_tick,
+       .ue_setmulti = axge_setmulti,
+       .ue_setpromisc = axge_setpromisc,
+       .ue_mii_upd = axge_ifmedia_upd,
+       .ue_mii_sts = axge_ifmedia_sts,
+};
+
+static int
+axge_read_mem(struct axge_softc *sc, uint8_t cmd, uint16_t index,
+    uint16_t val, void *buf, int len)
+{
+       struct usb_device_request req;
+
+       AXGE_LOCK_ASSERT(sc);
+
+       req.bmRequestType = UT_READ_VENDOR_DEVICE;
+       req.bRequest = cmd;
+       USETW(req.wValue, val);
+       USETW(req.wIndex, index);
+       USETW(req.wLength, len);
+
+       return (uether_do_request(&sc->sc_ue, &req, buf, 1000));
+}
+
+static void
+axge_write_mem(struct axge_softc *sc, uint8_t cmd, uint16_t index,
+    uint16_t val, void *buf, int len)
+{
+       struct usb_device_request req;
+
+       AXGE_LOCK_ASSERT(sc);
+
+       req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+       req.bRequest = cmd;
+       USETW(req.wValue, val);
+       USETW(req.wIndex, index);
+       USETW(req.wLength, len);
+
+       if (uether_do_request(&sc->sc_ue, &req, buf, 1000)) {
+               /* Error ignored. */
+       }
+}
+
+static uint8_t
+axge_read_cmd_1(struct axge_softc *sc, uint8_t cmd, uint16_t reg)
+{
+       uint8_t val;
+
+       axge_read_mem(sc, cmd, 1, reg, &val, 1);
+       return (val);
+}
+
+static uint16_t
+axge_read_cmd_2(struct axge_softc *sc, uint8_t cmd, uint16_t index,
+    uint16_t reg)
+{
+       uint8_t val[2];
+
+       axge_read_mem(sc, cmd, index, reg, &val, 2);
+       return (UGETW(val));
+}
+
+static void
+axge_write_cmd_1(struct axge_softc *sc, uint8_t cmd, uint16_t reg, uint8_t val)
+{
+       axge_write_mem(sc, cmd, 1, reg, &val, 1);
+}
+
+static void
+axge_write_cmd_2(struct axge_softc *sc, uint8_t cmd, uint16_t index,
+    uint16_t reg, uint16_t val)
+{
+       uint8_t temp[2];
+
+       USETW(temp, val);
+       axge_write_mem(sc, cmd, index, reg, &temp, 2);
+}
+
+static int
+axge_miibus_readreg(device_t dev, int phy, int reg)
+{
+       struct axge_softc *sc;
+       uint16_t val;
+       int locked;
+
+       sc = device_get_softc(dev);
+       locked = lockowned(&sc->sc_lock);
+       if (!locked)
+               AXGE_LOCK(sc);
+
+       val = axge_read_cmd_2(sc, AXGE_ACCESS_PHY, reg, phy);
+
+       if (!locked)
+               AXGE_UNLOCK(sc);
+
+       return (val);
+}
+
+static int
+axge_miibus_writereg(device_t dev, int phy, int reg, int val)
+{
+       struct axge_softc *sc;
+       int locked;
+
+       sc = device_get_softc(dev);
+       if (sc->sc_phyno != phy)
+               return (0);
+       locked = lockowned(&sc->sc_lock);
+       if (!locked)
+               AXGE_LOCK(sc);
+
+       axge_write_cmd_2(sc, AXGE_ACCESS_PHY, reg, phy, val);
+
+       if (!locked)
+               AXGE_UNLOCK(sc);
+
+       return (0);
+}
+
+static void
+axge_miibus_statchg(device_t dev)
+{
+       struct axge_softc *sc;
+       struct mii_data *mii;
+       struct ifnet *ifp;
+       uint8_t link_status, tmp[5];
+       uint16_t val;
+       int locked;
+
+       sc = device_get_softc(dev);
+       mii = GET_MII(sc);
+       locked = lockowned(&sc->sc_lock);
+       if (!locked)
+               AXGE_LOCK(sc);
+
+       ifp = uether_getifp(&sc->sc_ue);
+       if (mii == NULL || ifp == NULL ||
+           (ifp->if_flags & IFF_RUNNING) == 0)
+               goto done;
+
+       sc->sc_flags &= ~AXGE_FLAG_LINK;
+       if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
+           (IFM_ACTIVE | IFM_AVALID)) {
+               switch (IFM_SUBTYPE(mii->mii_media_active)) {
+               case IFM_10_T:
+               case IFM_100_TX:
+               case IFM_1000_T:
+                       sc->sc_flags |= AXGE_FLAG_LINK;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       /* Lost link, do nothing. */
+       if ((sc->sc_flags & AXGE_FLAG_LINK) == 0)
+               goto done;
+
+       link_status = axge_read_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_PLSR);
+
+       val = 0;
+       if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) {
+               val |= MSR_FD;
+               if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0)
+                       val |= MSR_TFC;
+               if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0)
+                       val |= MSR_RFC;
+       }
+       val |=  MSR_RE;
+       switch (IFM_SUBTYPE(mii->mii_media_active)) {
+       case IFM_1000_T:
+               val |= MSR_GM | MSR_EN_125MHZ;
+               if (link_status & PLSR_USB_SS)
+                       memcpy(tmp, &axge_bulk_size[0], 5);
+               else if (link_status & PLSR_USB_HS)
+                       memcpy(tmp, &axge_bulk_size[1], 5);
+               else
+                       memcpy(tmp, &axge_bulk_size[3], 5);
+               break;
+       case IFM_100_TX:
+               val |= MSR_PS;
+               if (link_status & (PLSR_USB_SS | PLSR_USB_HS))
+                       memcpy(tmp, &axge_bulk_size[2], 5);
+               else
+                       memcpy(tmp, &axge_bulk_size[3], 5);
+               break;
+       case IFM_10_T:
+               memcpy(tmp, &axge_bulk_size[3], 5);
+               break;
+       }
+       /* Rx bulk configuration. */
+       axge_write_mem(sc, AXGE_ACCESS_MAC, 5, AXGE_RX_BULKIN_QCTRL, tmp, 5);
+       axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_MSR, val);
+done:
+       if (!locked)
+               AXGE_UNLOCK(sc);
+}
+
+static void
+axge_chip_init(struct axge_softc *sc)
+{
+       /* Power up ethernet PHY. */
+       axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_EPPRCR, 0);
+       axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_EPPRCR, EPPRCR_IPRL);
+       uether_pause(&sc->sc_ue, hz / 4);
+       axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_CLK_SELECT,
+           AXGE_CLK_SELECT_ACS | AXGE_CLK_SELECT_BCS);
+       uether_pause(&sc->sc_ue, hz / 10);
+}
+
+static void
+axge_reset(struct axge_softc *sc)
+{
+       struct usb_config_descriptor *cd;
+       usb_error_t err;
+
+       cd = usbd_get_config_descriptor(sc->sc_ue.ue_udev);
+
+       err = usbd_req_set_config(sc->sc_ue.ue_udev, &sc->sc_lock,
+           cd->bConfigurationValue);
+       if (err)
+               DPRINTF("reset failed (ignored)\n");
+
+       /* Wait a little while for the chip to get its brains in order. */
+       uether_pause(&sc->sc_ue, hz / 100);
+
+       /* Reinitialize controller to achieve full reset. */
+       axge_chip_init(sc);
+}
+
+static void
+axge_attach_post(struct usb_ether *ue)
+{
+       struct axge_softc *sc;
+
+       sc = uether_getsc(ue);
+       sc->sc_phyno = 3;
+
+       /* Initialize controller and get station address. */
+       axge_chip_init(sc);
+       axge_read_mem(sc, AXGE_ACCESS_MAC, ETHER_ADDR_LEN, AXGE_NIDR,
+           ue->ue_eaddr, ETHER_ADDR_LEN);
+}
+
+static int
+axge_attach_post_sub(struct usb_ether *ue)
+{
+       struct axge_softc *sc;
+       struct ifnet *ifp;
+       int error;
+
+       sc = uether_getsc(ue);
+       ifp = uether_getifp(ue);
+       ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+       ifp->if_start = uether_start;
+       ifp->if_ioctl = axge_ioctl;
+       ifp->if_init = uether_init;
+       ifq_set_maxlen(&ifp->if_snd, ifqmaxlen);
+       ifq_set_ready(&ifp->if_snd);
+
+       ifp->if_capabilities |= IFCAP_VLAN_MTU | IFCAP_TXCSUM | IFCAP_RXCSUM;
+       ifp->if_hwassist = AXGE_CSUM_FEATURES;
+       ifp->if_capenable = ifp->if_capabilities;
+
+       /*
+        * NB: miibus assumes that the first member of the softc
+        * of it's parent is an arpcom structure
+        */
+       error = mii_phy_probe(ue->ue_dev, &ue->ue_miibus, 
+               uether_ifmedia_upd, ue->ue_methods->ue_mii_sts);
+
+       return (error);
+}
+
+/*
+ * Set media options.
+ */
+static int
+axge_ifmedia_upd(struct ifnet *ifp)
+{
+       struct axge_softc *sc;
+       struct mii_data *mii;
+       struct mii_softc *miisc;
+       int error;
+
+       sc = ifp->if_softc;
+       mii = GET_MII(sc);
+       AXGE_LOCK_ASSERT(sc);
+
+       LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
+           mii_phy_reset(miisc);
+       error = mii_mediachg(mii);
+
+       return (error);
+}
+
+/*
+ * Report current media status.
+ */
+static void
+axge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+       struct axge_softc *sc;
+       struct mii_data *mii;
+
+       sc = ifp->if_softc;
+       mii = GET_MII(sc);
+       AXGE_LOCK(sc);
+       mii_pollstat(mii);
+       ifmr->ifm_active = mii->mii_media_active;
+       ifmr->ifm_status = mii->mii_media_status;
+       AXGE_UNLOCK(sc);
+}
+
+/*
+ * Probe for a AX88179 chip.
+ */
+static int
+axge_probe(device_t dev)
+{
+       struct usb_attach_arg *uaa;
+
+       uaa = device_get_ivars(dev);
+       if (uaa->usb_mode != USB_MODE_HOST)
+               return (ENXIO);
+       if (uaa->info.bConfigIndex != AXGE_CONFIG_IDX)
+               return (ENXIO);
+       if (uaa->info.bIfaceIndex != AXGE_IFACE_IDX)
+               return (ENXIO);
+
+       return (usbd_lookup_id_by_uaa(axge_devs, sizeof(axge_devs), uaa));
+}
+
+/*
+ * Attach the interface. Allocate softc structures, do ifmedia
+ * setup and ethernet/BPF attach.
+ */
+static int
+axge_attach(device_t dev)
+{
+       struct usb_attach_arg *uaa;
+       struct axge_softc *sc;
+       struct usb_ether *ue;
+       uint8_t iface_index;
+       int error;
+
+       uaa = device_get_ivars(dev);
+       sc = device_get_softc(dev);
+       ue = &sc->sc_ue;
+
+       device_set_usb_desc(dev);
+       lockinit(&sc->sc_lock, device_get_nameunit(dev), 0, LK_CANRECURSE);
+
+       iface_index = AXGE_IFACE_IDX;
+       error = usbd_transfer_setup(uaa->device, &iface_index,
+           sc->sc_xfer, axge_config, AXGE_N_TRANSFER, sc, &sc->sc_lock);
+       if (error) {
+               device_printf(dev, "allocating USB transfers failed\n");
+               goto detach;
+       }
+
+       ue->ue_sc = sc;
+       ue->ue_dev = dev;
+       ue->ue_udev = uaa->device;
+       ue->ue_lock = &sc->sc_lock;
+       ue->ue_methods = &axge_ue_methods;
+
+       error = uether_ifattach(ue);
+       if (error) {
+               device_printf(dev, "could not attach interface\n");
+               goto detach;
+       }
+       return (0);                     /* success */
+
+detach:
+       axge_detach(dev);
+       return (ENXIO);                 /* failure */
+}
+
+static int
+axge_detach(device_t dev)
+{
+       struct axge_softc *sc;
+       struct usb_ether *ue;
+
+       sc = device_get_softc(dev);
+       ue = &sc->sc_ue;
+       usbd_transfer_unsetup(sc->sc_xfer, AXGE_N_TRANSFER);
+       uether_ifdetach(ue);
+       lockuninit(&sc->sc_lock);
+
+       return (0);
+}
+
+static void
+axge_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
+{
+       struct axge_softc *sc;
+       struct usb_ether *ue;
+       struct usb_page_cache *pc;
+       int actlen;
+
+       sc = usbd_xfer_softc(xfer);
+       ue = &sc->sc_ue;
+       usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
+
+       switch (USB_GET_STATE(xfer)) {
+       case USB_ST_TRANSFERRED:
+               pc = usbd_xfer_get_frame(xfer, 0);
+               axge_rx_frame(ue, pc, actlen);
+
+               /* FALLTHROUGH */
+       case USB_ST_SETUP:
+tr_setup:
+               usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
+               usbd_transfer_submit(xfer);
+               uether_rxflush(ue);
+               break;
+
+       default:
+               if (error != USB_ERR_CANCELLED) {
+                       usbd_xfer_set_stall(xfer);
+                       goto tr_setup;
+               }
+               break;
+       }
+}
+
+static void
+axge_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
+{
+       struct axge_softc *sc;
+       struct ifnet *ifp;
+       struct usb_page_cache *pc;
+       struct mbuf *m;
+       uint32_t txhdr;
+       int nframes, pos;
+
+       sc = usbd_xfer_softc(xfer);
+       ifp = uether_getifp(&sc->sc_ue);
+
+       switch (USB_GET_STATE(xfer)) {
+       case USB_ST_TRANSFERRED:
+               ifq_clr_oactive(&ifp->if_snd);
+               /* FALLTHROUGH */
+       case USB_ST_SETUP:
+tr_setup:
+               if ((sc->sc_flags & AXGE_FLAG_LINK) == 0 ||
+                   ifq_is_oactive(&ifp->if_snd)) {
+                       /*
+                        * Don't send anything if there is no link or
+                        * controller is busy.
+                        */
+                       return;
+               }
+
+               for (nframes = 0; nframes < 16 &&
+                   !ifq_is_empty(&ifp->if_snd); nframes++) {
+                       m = ifq_dequeue(&ifp->if_snd);
+                       if (m == NULL)
+                               break;
+                       usbd_xfer_set_frame_offset(xfer, nframes * MCLBYTES,
+                               nframes);
+                       pos = 0;
+                       pc = usbd_xfer_get_frame(xfer, nframes);
+                       txhdr = htole32(m->m_pkthdr.len);
+                       usbd_copy_in(pc, 0, &txhdr, sizeof(txhdr));
+                       txhdr = 0;
+                       txhdr = htole32(txhdr);
+                       usbd_copy_in(pc, 4, &txhdr, sizeof(txhdr));
+                       pos += 8;
+                       usbd_m_copy_in(pc, pos, m, 0, m->m_pkthdr.len);
+                       pos += m->m_pkthdr.len;
+                       if ((pos % usbd_xfer_max_framelen(xfer)) == 0)
+                               txhdr |= 0x80008000;
+
+                       /*
+                        * XXX
+                        * Update TX packet counter here. This is not
+                        * correct way but it seems that there is no way
+                        * to know how many packets are sent at the end
+                        * of transfer because controller combines
+                        * multiple writes into single one if there is
+                        * room in TX buffer of controller.
+                        */
+                       IFNET_STAT_INC(ifp, opackets, 1);
+
+                       /*
+                        * if there's a BPF listener, bounce a copy
+                        * of this frame to him:
+                        */
+                       BPF_MTAP(ifp, m);
+
+                       m_freem(m);
+
+                       /* Set frame length. */
+                       usbd_xfer_set_frame_len(xfer, nframes, pos);
+               }
+               if (nframes != 0) {
+                       usbd_xfer_set_frames(xfer, nframes);
+                       usbd_transfer_submit(xfer);
+                       ifq_set_oactive(&ifp->if_snd);
+               }
+               return;
+               /* NOTREACHED */
+       default:
+               IFNET_STAT_INC(ifp, oerrors, 1);
+               ifq_clr_oactive(&ifp->if_snd);
+
+               if (error != USB_ERR_CANCELLED) {
+                       usbd_xfer_set_stall(xfer);
+                       goto tr_setup;
+               }
+               return;
+
+       }
+}
+
+static void
+axge_tick(struct usb_ether *ue)
+{
+       struct axge_softc *sc;
+       struct mii_data *mii;
+
+       sc = uether_getsc(ue);
+       mii = GET_MII(sc);
+       AXGE_LOCK_ASSERT(sc);
+
+       mii_tick(mii);
+       if ((sc->sc_flags & AXGE_FLAG_LINK) == 0) {
+               axge_miibus_statchg(ue->ue_dev);
+               if ((sc->sc_flags & AXGE_FLAG_LINK) != 0)
+                       axge_start(ue);
+       }
+}
+
+static void
+axge_setmulti(struct usb_ether *ue)
+{
+       struct axge_softc *sc;
+       struct ifnet *ifp;
+       struct ifmultiaddr *ifma;
+       uint32_t h;
+       uint16_t rxmode;
+       uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+       sc = uether_getsc(ue);
+       ifp = uether_getifp(ue);
+       h = 0;
+       AXGE_LOCK_ASSERT(sc);
+
+       rxmode = axge_read_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR);
+       if (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) {
+               rxmode |= RCR_AMALL;
+               axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR, rxmode);
+               return;
+       }
+       rxmode &= ~RCR_AMALL;
+
+       TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+               if (ifma->ifma_addr->sa_family != AF_LINK)
+                       continue;
+               h = ether_crc32_be(LLADDR((struct sockaddr_dl *)
+                   ifma->ifma_addr), ETHER_ADDR_LEN) >> 26;
+               hashtbl[h / 8] |= 1 << (h % 8);
+       }
+
+       axge_write_mem(sc, AXGE_ACCESS_MAC, 8, AXGE_MFA, (void *)&hashtbl, 8);
+       axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR, rxmode);
+}
+
+static void
+axge_setpromisc(struct usb_ether *ue)
+{
+       struct axge_softc *sc;
+       struct ifnet *ifp;
+       uint16_t rxmode;
+
+       sc = uether_getsc(ue);
+       ifp = uether_getifp(ue);
+       rxmode = axge_read_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR);
+
+       if (ifp->if_flags & IFF_PROMISC)
+               rxmode |= RCR_PRO;
+       else
+               rxmode &= ~RCR_PRO;
+
+       axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR, rxmode);
+       axge_setmulti(ue);
+}
+
+static void
+axge_start(struct usb_ether *ue)
+{
+       struct axge_softc *sc;
+
+       sc = uether_getsc(ue);
+       /*
+        * Start the USB transfers, if not already started.
+        */
+       usbd_transfer_start(sc->sc_xfer[AXGE_BULK_DT_RD]);
+       usbd_transfer_start(sc->sc_xfer[AXGE_BULK_DT_WR]);
+}
+
+static void
+axge_init(struct usb_ether *ue)
+{
+       struct axge_softc *sc;
+       struct ifnet *ifp;
+       uint16_t rxmode;
+
+       sc = uether_getsc(ue);
+       ifp = uether_getifp(ue);
+       AXGE_LOCK_ASSERT(sc);
+
+       if ((ifp->if_flags & IFF_RUNNING) != 0)
+               return;
+
+       /*
+        * Cancel pending I/O and free all RX/TX buffers.
+        */
+       axge_stop(ue);
+
+       axge_reset(sc);
+
+       /* Set MAC address. */
+       axge_write_mem(sc, AXGE_ACCESS_MAC, ETHER_ADDR_LEN, AXGE_NIDR,
+           IF_LLADDR(ifp), ETHER_ADDR_LEN);
+
+       axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_PWLLR, 0x34);
+       axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_PWLHR, 0x52);
+
+       /* Configure TX/RX checksum offloading. */
+       axge_csum_cfg(ue);
+
+       /* Configure RX settings. */
+       rxmode = (RCR_AM | RCR_SO | RCR_DROP_CRCE);
+       if ((ifp->if_capenable & IFCAP_RXCSUM) != 0)
+               rxmode |= RCR_IPE;
+
+       /* If we want promiscuous mode, set the allframes bit. */
+       if (ifp->if_flags & IFF_PROMISC)
+               rxmode |= RCR_PRO;
+
+       if (ifp->if_flags & IFF_BROADCAST)
+               rxmode |= RCR_AB;
+
+       axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR, rxmode);
+
+       axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_MMSR, 
+           MMSR_PME_TYPE | MMSR_PME_POL | MMSR_RWMP);
+
+       /* Load the multicast filter. */
+       axge_setmulti(ue);
+
+       usbd_xfer_set_stall(sc->sc_xfer[AXGE_BULK_DT_WR]);
+
+       ifp->if_flags |= IFF_RUNNING;
+       /* Switch to selected media. */
+       axge_ifmedia_upd(ifp);
+}
+
+static void
+axge_stop(struct usb_ether *ue)
+{
+       struct axge_softc *sc;
+       struct ifnet *ifp;
+
+       sc = uether_getsc(ue);
+       ifp = uether_getifp(ue);
+
+       AXGE_LOCK_ASSERT(sc);
+
+       ifp->if_flags &= ~IFF_RUNNING;
+       ifq_clr_oactive(&ifp->if_snd);
+       sc->sc_flags &= ~AXGE_FLAG_LINK;
+
+       /*
+        * Stop all the transfers, if not already stopped:
+        */
+       usbd_transfer_stop(sc->sc_xfer[AXGE_BULK_DT_WR]);
+       usbd_transfer_stop(sc->sc_xfer[AXGE_BULK_DT_RD]);
+}
+
+static int
+axge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *uc)
+{
+       struct usb_ether *ue;
+       struct axge_softc *sc;
+       struct ifreq *ifr;
+       int error, mask, reinit;
+
+       ue = ifp->if_softc;
+       sc = uether_getsc(ue);
+       ifr = (struct ifreq *)data;
+       error = 0;
+       reinit = 0;
+       if (cmd == SIOCSIFCAP) {
+               AXGE_LOCK(sc);
+               mask = ifr->ifr_reqcap ^ ifp->if_capenable;
+               if ((mask & IFCAP_TXCSUM) != 0 &&
+                   (ifp->if_capabilities & IFCAP_TXCSUM) != 0) {
+                       ifp->if_capenable ^= IFCAP_TXCSUM;
+                       if ((ifp->if_capenable & IFCAP_TXCSUM) != 0)
+                               ifp->if_hwassist |= AXGE_CSUM_FEATURES;
+                       else
+                               ifp->if_hwassist &= ~AXGE_CSUM_FEATURES;
+                       reinit++;
+               }
+               if ((mask & IFCAP_RXCSUM) != 0 &&
+                   (ifp->if_capabilities & IFCAP_RXCSUM) != 0) {
+                       ifp->if_capenable ^= IFCAP_RXCSUM;
+                       reinit++;
+               }
+               if (reinit > 0 && ifp->if_flags & IFF_RUNNING)
+                       ifp->if_flags &= ~IFF_RUNNING;
+               else
+                       reinit = 0;
+               AXGE_UNLOCK(sc);
+               if (reinit > 0)
+                       uether_init(ue);
+       } else
+               error = uether_ioctl(ifp, cmd, data, uc);
+
+       return (error);
+}
+
+static void
+axge_rx_frame(struct usb_ether *ue, struct usb_page_cache *pc, int actlen)
+{
+       uint32_t pos;
+       uint32_t pkt_cnt;
+       uint32_t rxhdr;
+       uint32_t pkt_hdr;
+       uint32_t hdr_off;
+       uint32_t pktlen; 
+
+       /* verify we have enough data */
+       if (actlen < (int)sizeof(rxhdr))
+               return;
+
+       pos = 0;
+
+       usbd_copy_out(pc, actlen - sizeof(rxhdr), &rxhdr, sizeof(rxhdr));
+       rxhdr = le32toh(rxhdr);
+
+       pkt_cnt = (uint16_t)rxhdr;
+       hdr_off = (uint16_t)(rxhdr >> 16);
+
+       while (pkt_cnt--) {
+               /* verify the header offset */
+               if ((int)(hdr_off + sizeof(pkt_hdr)) > actlen) {
+                       DPRINTF("End of packet headers\n");
+                       break;
+               }
+               if ((int)pos >= actlen) {
+                       DPRINTF("Data position reached end\n");
+                       break;
+               }
+               usbd_copy_out(pc, hdr_off, &pkt_hdr, sizeof(pkt_hdr));
+
+               pkt_hdr = le32toh(pkt_hdr);
+               pktlen = (pkt_hdr >> 16) & 0x1fff;
+               if (pkt_hdr & (AXGE_RXHDR_CRC_ERR | AXGE_RXHDR_DROP_ERR)) {
+                       DPRINTF("Dropped a packet\n");
+                       IFNET_STAT_INC(uether_getifp(ue), ierrors, 1);
+               }
+               if (pktlen >= 6 && (int)(pos + pktlen) <= actlen) {
+                       axge_rxeof(ue, pc, pos + 2, pktlen - 6, pkt_hdr);
+               } else {
+                       DPRINTF("Invalid packet pos=%d len=%d\n",
+                           (int)pos, (int)pktlen);
+               }
+               pos += (pktlen + 7) & ~7;
+               hdr_off += sizeof(pkt_hdr);
+       }
+}
+
+static void
+axge_rxeof(struct usb_ether *ue, struct usb_page_cache *pc,
+    unsigned int offset, unsigned int len, uint32_t pkt_hdr)
+{
+       struct ifnet *ifp;
+       struct mbuf *m;
+
+       ifp = uether_getifp(ue);
+       if (len < ETHER_HDR_LEN || len > MCLBYTES - ETHER_ALIGN) {
+               IFNET_STAT_INC(ifp, ierrors, 1);
+               return;
+       }
+
+       m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
+       if (m == NULL) {
+               IFNET_STAT_INC(ifp, iqdrops, 1);
+               return;
+       }
+       m->m_pkthdr.rcvif = ifp;
+       m->m_len = m->m_pkthdr.len = len + ETHER_ALIGN;
+       m_adj(m, ETHER_ALIGN);
+
+       usbd_copy_out(pc, offset, mtod(m, uint8_t *), len);
+
+       IFNET_STAT_INC(ifp, ipackets, 1);
+
+       if ((pkt_hdr & (AXGE_RXHDR_L4CSUM_ERR | AXGE_RXHDR_L3CSUM_ERR)) == 0) {
+               if ((pkt_hdr & AXGE_RXHDR_L4_TYPE_MASK) ==
+                   AXGE_RXHDR_L4_TYPE_TCP ||
+                   (pkt_hdr & AXGE_RXHDR_L4_TYPE_MASK) ==
+                   AXGE_RXHDR_L4_TYPE_UDP) {
+                       m->m_pkthdr.csum_flags |= CSUM_DATA_VALID |
+                           CSUM_PSEUDO_HDR | CSUM_IP_CHECKED | CSUM_IP_VALID;
+                       m->m_pkthdr.csum_data = 0xffff;
+               }
+       }
+
+       IF_ENQUEUE(&ue->ue_rxq, m);
+}
+
+static void
+axge_csum_cfg(struct usb_ether *ue)
+{
+       struct axge_softc *sc;
+       struct ifnet *ifp;
+       uint8_t csum;
+
+       sc = uether_getsc(ue);
+       AXGE_LOCK_ASSERT(sc);
+       ifp = uether_getifp(ue);
+
+       csum = 0;
+       if ((ifp->if_capenable & IFCAP_TXCSUM) != 0)
+               csum |= CTCR_IP | CTCR_TCP | CTCR_UDP;
+       axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_CTCR, csum);
+
+       csum = 0;
+       if ((ifp->if_capenable & IFCAP_RXCSUM) != 0)
+               csum |= CRCR_IP | CRCR_TCP | CRCR_UDP;
+       axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_CRCR, csum);
+}
diff --git a/sys/bus/u4b/net/if_axgereg.h b/sys/bus/u4b/net/if_axgereg.h
new file mode 100644 (file)
index 0000000..ce7f203
--- /dev/null
@@ -0,0 +1,173 @@
+/*-
+ * Copyright (c) 2013-2014 Kevin Lo
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 THE AUTHOR OR CONTRIBUTORS 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: head/sys/dev/usb/net/if_axgereg.h 269322 2014-07-31 05:12:21Z kevlo $
+ */
+
+#define        AXGE_ACCESS_MAC                 0x01
+#define        AXGE_ACCESS_PHY                 0x02
+#define        AXGE_ACCESS_WAKEUP              0x03
+#define        AXGE_ACCESS_EEPROM              0x04
+#define        AXGE_ACCESS_EFUSE               0x05
+#define        AXGE_RELOAD_EEPROM_EFUSE        0x06
+#define        AXGE_WRITE_EFUSE_EN             0x09
+#define        AXGE_WRITE_EFUSE_DIS            0x0A
+#define        AXGE_ACCESS_MFAB                0x10
+
+/* Physical link status register */
+#define        AXGE_PLSR                       0x02
+#define        PLSR_USB_FS                     0x01
+#define        PLSR_USB_HS                     0x02
+#define        PLSR_USB_SS                     0x04
+
+/* EEPROM address register */
+#define        AXGE_EAR                        0x07
+
+/* EEPROM data low register */
+#define        AXGE_EDLR                       0x08
+
+/* EEPROM data high register */
+#define        AXGE_EDHR                       0x09
+
+/* EEPROM command register */
+#define        AXGE_ECR                        0x0a
+
+/* Rx control register */
+#define        AXGE_RCR                        0x0b
+#define        RCR_STOP                        0x0000
+#define        RCR_PRO                         0x0001
+#define        RCR_AMALL                       0x0002
+#define        RCR_AB                          0x0008
+#define        RCR_AM                          0x0010
+#define        RCR_AP                          0x0020
+#define        RCR_SO                          0x0080
+#define        RCR_DROP_CRCE                   0x0100
+#define        RCR_IPE                         0x0200
+#define        RCR_TX_CRC_PAD                  0x0400
+
+/* Node id register */
+#define        AXGE_NIDR                       0x10
+
+/* Multicast filter array */
+#define        AXGE_MFA                        0x16
+
+/* Medium status register */
+#define        AXGE_MSR                        0x22
+#define        MSR_GM                          0x0001
+#define        MSR_FD                          0x0002
+#define        MSR_EN_125MHZ                   0x0008
+#define        MSR_RFC                         0x0010
+#define        MSR_TFC                         0x0020
+#define        MSR_RE                          0x0100
+#define        MSR_PS                          0x0200
+
+/* Monitor mode status register */
+#define        AXGE_MMSR                       0x24
+#define        MMSR_RWLC                       0x02
+#define        MMSR_RWMP                       0x04
+#define        MMSR_RWWF                       0x08
+#define        MMSR_RW_FLAG                    0x10
+#define        MMSR_PME_POL                    0x20
+#define        MMSR_PME_TYPE                   0x40
+#define        MMSR_PME_IND                    0x80
+
+/* GPIO control/status register */
+#define        AXGE_GPIOCR                     0x25
+
+/* Ethernet PHY power & reset control register */
+#define        AXGE_EPPRCR                     0x26
+#define        EPPRCR_BZ                       0x0010
+#define        EPPRCR_IPRL                     0x0020
+#define        EPPRCR_AUTODETACH               0x1000
+
+#define        AXGE_RX_BULKIN_QCTRL            0x2e
+
+#define        AXGE_CLK_SELECT                 0x33
+#define        AXGE_CLK_SELECT_BCS             0x01
+#define        AXGE_CLK_SELECT_ACS             0x02
+#define        AXGE_CLK_SELECT_ACSREQ          0x10
+#define        AXGE_CLK_SELECT_ULR             0x08
+
+/* COE Rx control register */
+#define        AXGE_CRCR                       0x34
+#define        CRCR_IP                         0x01
+#define        CRCR_TCP                        0x02
+#define        CRCR_UDP                        0x04
+#define        CRCR_ICMP                       0x08
+#define        CRCR_IGMP                       0x10
+#define        CRCR_TCPV6                      0x20
+#define        CRCR_UDPV6                      0x40
+#define        CRCR_ICMPV6                     0x80
+
+/* COE Tx control register */
+#define        AXGE_CTCR                       0x35
+#define        CTCR_IP                         0x01
+#define        CTCR_TCP                        0x02
+#define        CTCR_UDP                        0x04
+#define        CTCR_ICMP                       0x08
+#define        CTCR_IGMP                       0x10
+#define        CTCR_TCPV6                      0x20
+#define        CTCR_UDPV6                      0x40
+#define        CTCR_ICMPV6                     0x80
+
+/* Pause water level high register */
+#define        AXGE_PWLHR                      0x54
+
+/* Pause water level low register */
+#define        AXGE_PWLLR                      0x55
+
+#define        AXGE_CONFIG_IDX                 0       /* config number 1 */
+#define        AXGE_IFACE_IDX                  0
+
+#define        AXGE_RXHDR_L4_TYPE_MASK         0x1c
+#define        AXGE_RXHDR_L4CSUM_ERR           1
+#define        AXGE_RXHDR_L3CSUM_ERR           2
+#define        AXGE_RXHDR_L4_TYPE_UDP          4
+#define        AXGE_RXHDR_L4_TYPE_TCP          16
+#define        AXGE_RXHDR_CRC_ERR              0x20000000
+#define        AXGE_RXHDR_DROP_ERR             0x80000000
+
+#define        GET_MII(sc)             uether_getmii(&(sc)->sc_ue)
+
+/* The interrupt endpoint is currently unused by the ASIX part. */
+enum {
+       AXGE_BULK_DT_WR,
+       AXGE_BULK_DT_RD,
+       AXGE_N_TRANSFER,
+};
+
+struct axge_softc {
+       struct usb_ether        sc_ue;
+       struct lock             sc_lock;
+       struct usb_xfer         *sc_xfer[AXGE_N_TRANSFER];
+       int                     sc_phyno;
+
+       int                     sc_flags;
+#define        AXGE_FLAG_LINK          0x0001  /* got a link */
+};
+
+#define        AXGE_LOCK(_sc)                  lockmgr(&(_sc)->sc_lock, LK_EXCLUSIVE)
+#define        AXGE_UNLOCK(_sc)                lockmgr(&(_sc)->sc_lock, LK_RELEASE)
+#define        AXGE_LOCK_ASSERT(_sc)           KKASSERT(lockowned(&(_sc)->sc_lock))
index e2acf94..86698ad 100644 (file)
@@ -1562,6 +1562,7 @@ product DLINK DSB650TX            0x4002  10/100 Ethernet
 product DLINK DSB650TX_PNA     0x4003  1/10/100 Ethernet
 product DLINK DSB650TX3                0x400b  10/100 Ethernet
 product DLINK DSB650TX2                0x4102  10/100 Ethernet
+product DLINK DUB1312          0x4a00  10/100/1000 Ethernet
 product DLINK DSB650           0xabc1  10/100 Ethernet
 product DLINK DUBH7            0xf103  DUB-H7 USB 2.0 7-Port Hub
 product DLINK DWR510_CD                0xa805  DWR-510 CD-ROM Mode
@@ -4039,6 +4040,7 @@ product SITECOMEU RT3072_6        0x004d  RT3072
 product SITECOMEU RTL8188CU_1  0x0052  RTL8188CU
 product SITECOMEU RTL8188CU_2  0x005c  RTL8188CU
 product SITECOMEU RTL8192CU    0x0061  RTL8192CU
+product SITECOMEU LN032                0x0072  LN-032
 product SITECOMEU LN028                0x061c  LN-028
 product SITECOMEU WL113                0x9071  WL-113
 product SITECOMEU ZD1211B      0x9075  ZD1211B
index 8ef4f43..f87e76d 100644 (file)
@@ -2265,6 +2265,7 @@ bus/u4b/storage/ustorage_fs.c             optional usfs usb
 bus/u4b/net/usb_ethernet.c             optional uether usb
 bus/u4b/net/if_aue.c                   optional aue uether usb
 bus/u4b/net/if_axe.c                   optional axe uether usb
+bus/u4b/net/if_axge.c                  optional axge uether usb
 bus/u4b/net/if_cue.c                   optional cue uether usb
 bus/u4b/net/if_ipheth.c                        optional ipheth uether usb
 bus/u4b/net/if_kue.c                   optional kue uether usb
index 4460ddd..676de74 100644 (file)
@@ -2151,6 +2151,9 @@ device            aue
 # LinkSys USB200M and various other adapters.
 device         axe
 #
+# ASIX Electronics AX88178A/AX88179 USB 2.0/3.0 gigabit ethernet driver.
+device         axge
+#
 # CATC USB-EL1201A USB ethernet. Supports the CATC Netmate
 # and Netmate II, and the Belkin F5U111.
 device         cue
index 1bd7ec2..7c466a3 100644 (file)
@@ -1982,6 +1982,9 @@ device            aue
 # LinkSys USB200M and various other adapters.
 device         axe
 #
+# ASIX Electronics AX88178A/AX88179 USB 2.0/3.0 gigabit ethernet driver.
+device         axge
+#
 # CATC USB-EL1201A USB ethernet. Supports the CATC Netmate
 # and Netmate II, and the Belkin F5U111.
 device         cue