Index: /freebsd-rtl-driver/Makefile
===================================================================
--- /freebsd-rtl-driver/Makefile	(revision 384)
+++ /freebsd-rtl-driver/Makefile	(revision 384)
@@ -0,0 +1,34 @@
+# Copyright (c) 2010 Rick van der Zwet <info@rickvanderzwet.nl>
+#
+# 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.
+
+DEBUG_FLAGS= -g
+KMOD=	if_rtl
+SRCS=	opt_bus.h opt_usb.h device_if.h bus_if.h usb_if.h usbdevs.h \
+	miibus_if.h opt_inet.h \
+	if_rtl.c
+
+.include <bsd.kmod.mk>
+
+lsmod:
+	kldstat
+
+core:
+	kgdb /usr/obj/usr/src/sys/GENERIC/kernel.debug `ls /var/crash/vmcore.* | tail -1`
+
+ipload: load
+	sleep 5
+	ifconfig ue0 10.0.1.1/24
+
+code:
+	vim -o /usr/src/sys/dev/usb/net/if_rue.c if_rtl.c
Index: /freebsd-rtl-driver/README
===================================================================
--- /freebsd-rtl-driver/README	(revision 384)
+++ /freebsd-rtl-driver/README	(revision 384)
@@ -0,0 +1,36 @@
+EXPERIMENTAL Beta code, use with care. Active development.
+
+Status: Development
+Target: Get it on 10-STABLE to make it into release.
+
+No datasheets available after requests, I quote: ``` Due to company policy, we
+only release Datasheet to our ODM/OEM ( which have signed a company to company
+NDA with Realtek ). Please follow the linux source code for porting, thanks.
+"""
+
+Linux reference driver: http://lxr.free-electrons.com/source/drivers/net/usb/r8152.c
+
+
+== INTRO ==
+The FreeBSD if_rtl.c driver is based on various different sources:
+
+The vendor provided information at the following URL:
+http://www.moschip.com/data/products/MCS7830/Driver_FreeBSD_7830.tar.gz
+
+Mixed together with the Linux r8152.c driver for validation and checking
+and the FreeBSD if_rue.c as reference for the USB Ethernet framework.
+
+== COMPILE & RUN ==
+ 1. Make sure you got the FreeBSD source checked out in /usr/src
+ 2. make load
+ 3. Driver ready for use (device found is ue0)
+
+= COMPILE & INSTALL ==
+ 1. Follow steps as above
+ 2. make install
+
+
+Bugs and/or feedback are more than welcome! Please try to be verbose as
+possible.
+
+/Rick van der Zwet <info@rickvanderzwet.nl>
Index: /freebsd-rtl-driver/if_rtl.c
===================================================================
--- /freebsd-rtl-driver/if_rtl.c	(revision 384)
+++ /freebsd-rtl-driver/if_rtl.c	(revision 384)
@@ -0,0 +1,1751 @@
+/*-
+ * Copyright (c) 2011 Rick van der Zwet <info@rickvanderzwet.nl>
+ *
+ * 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) 2001-2003, Shunsuke Akiyama <akiyama@FreeBSD.org>.
+ * Copyright (c) 1997, 1998, 1999, 2000 Bill Paul <wpaul@ee.columbia.edu>.
+ * 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.
+ */
+/*-
+ * Copyright (c) 1997, 1998, 1999, 2000
+ *	Bill Paul <wpaul@ee.columbia.edu>.  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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: release/10.1.0/sys/dev/usb/net/if_rtl.c 251734 2013-06-14 05:36:47Z kevlo $");
+
+/*
+ * RealTek RTL8152 USB to fast ethernet controller driver.
+ * http://www.realtek.com.tw/products/productsView.aspx?Langid=1&PFid=55&Level=5&Conn=4&ProdID=323
+ *
+ * /TODO: With some modification the RealTek RTL8153 USB to fast ethernet
+ * controller driver. should also be supported, but yet no hardware to test it
+ * http://www.realtek.com.tw/products/productsView.aspx?Langid=1&PFid=56&Level=5&Conn=4&ProdID=326
+ *
+ */
+
+#include <sys/stdint.h>
+#include <sys/stddef.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+#include <sys/sysctl.h>
+#include <sys/sx.h>
+#include <sys/unistd.h>
+#include <sys/callout.h>
+#include <sys/malloc.h>
+#include <sys/priv.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdi_util.h>
+#include "usbdevs.h"
+
+#define	USB_DEBUG_VAR rtl_debug
+#include <dev/usb/usb_debug.h>
+#include <dev/usb/usb_process.h>
+
+#include <dev/usb/net/usb_ethernet.h>
+#include <dev/usb/net/if_rtlreg.h>
+
+#ifdef USB_DEBUG
+static int rtl_debug = 1;
+
+static SYSCTL_NODE(_hw_usb, OID_AUTO, rtl, CTLFLAG_RW, 0, "USB rtl");
+SYSCTL_INT(_hw_usb_rtl, OID_AUTO, debug, CTLFLAG_RW,
+    &rtl_debug, 0, "Debug level");
+#endif
+
+/*
+ * Various supported device vendors/products.
+ */
+
+static const STRUCT_USB_HOST_ID rtl_devs[] = {
+	{USB_VPI(USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8152, 0)},
+};
+
+/* prototypes */
+
+static device_probe_t rtl_probe;
+static device_attach_t rtl_attach;
+static device_detach_t rtl_detach;
+
+static miibus_readreg_t rtl_miibus_readreg;
+static miibus_writereg_t rtl_miibus_writereg;
+static miibus_statchg_t rtl_miibus_statchg;
+
+static usb_callback_t rtl_intr_callback;
+static usb_callback_t rtl_bulk_read_callback;
+static usb_callback_t rtl_bulk_write_callback;
+
+static uether_fn_t rtl_attach_post;
+static uether_fn_t rtl_init;
+static uether_fn_t rtl_stop;
+static uether_fn_t rtl_start;
+static uether_fn_t rtl_tick;
+static uether_fn_t rtl_setpromisc_and_multi;
+
+static void	rtl_reset(struct rtl_softc *);
+static int	rtl_ifmedia_upd(struct ifnet *);
+static void	rtl_ifmedia_sts(struct ifnet *, struct ifmediareq *);
+
+static const struct usb_config rtl_config[RTL_N_TRANSFER] = {
+
+	[RTL_BULK_DT_RD] = {
+		.type = UE_BULK,
+		.endpoint = UE_ADDR_ANY,
+		.direction = UE_DIR_IN,
+		.bufsize = 16384,
+		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
+		.callback = rtl_bulk_read_callback,
+		.timeout = 0,	/* no timeout */
+	},
+
+	[RTL_BULK_DT_WR] = {
+		.type = UE_BULK,
+		.endpoint = UE_ADDR_ANY,
+		.direction = UE_DIR_OUT,
+		.bufsize = 16384,
+		.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
+		.callback = rtl_bulk_write_callback,
+		.timeout = 1000,	/* 1 seconds */
+	},
+
+	[RTL_INTR_DT_RD] = {
+		.type = UE_INTERRUPT,
+		.endpoint = UE_ADDR_ANY,
+		.direction = UE_DIR_IN,
+		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
+		.bufsize = 0,	/* use wMaxPacketSize */
+		.callback = rtl_intr_callback,
+	},
+};
+
+static device_method_t rtl_methods[] = {
+	/* Device interface */
+	DEVMETHOD(device_probe, rtl_probe),
+	DEVMETHOD(device_attach, rtl_attach),
+	DEVMETHOD(device_detach, rtl_detach),
+
+	/* MII interface */
+	DEVMETHOD(miibus_readreg, rtl_miibus_readreg),
+	DEVMETHOD(miibus_writereg, rtl_miibus_writereg),
+	DEVMETHOD(miibus_statchg, rtl_miibus_statchg),
+
+	DEVMETHOD_END
+};
+
+static driver_t rtl_driver = {
+	.name = "rtl",
+	.methods = rtl_methods,
+	.size = sizeof(struct rtl_softc),
+};
+
+static devclass_t rtl_devclass;
+
+DRIVER_MODULE_ORDERED(rtl, uhub, rtl_driver, rtl_devclass, NULL, NULL,
+    SI_ORDER_ANY);
+DRIVER_MODULE(miibus, rtl, miibus_driver, miibus_devclass, NULL, NULL);
+MODULE_DEPEND(rtl, uether, 1, 1, 1);
+MODULE_DEPEND(rtl, usb, 1, 1, 1);
+MODULE_DEPEND(rtl, ether, 1, 1, 1);
+MODULE_DEPEND(rtl, miibus, 1, 1, 1);
+MODULE_VERSION(rtl, 1);
+
+static const struct usb_ether_methods rtl_ue_methods = {
+	.ue_attach_post = rtl_attach_post,
+	.ue_start = rtl_start,
+	.ue_init = rtl_init,
+	.ue_stop = rtl_stop,
+	.ue_tick = rtl_tick,
+	.ue_setmulti = rtl_setpromisc_and_multi,
+	.ue_setpromisc = rtl_setpromisc_and_multi,
+	.ue_mii_upd = rtl_ifmedia_upd,
+	.ue_mii_sts = rtl_ifmedia_sts,
+};
+
+static int
+generic_ocp_read(struct rtl_softc *sc, uint16_t index, uint16_t addr, void *buf, int len)
+{
+	struct usb_device_request req;
+	// TODO: This seems to be a global defined variable
+	uint16_t limit = 64;
+	int ret = 0;
+
+	/* both size and indix must be 4 bytes align */
+	// TODO: Argue whether are supposed to be non-fatal values
+	if ((len & 3) || !len || (index & 3) || (!buf)) {
+		printf("[foo] generic_ocp_read(len=%x index=%x): not alligned error\n",
+		   len, index);
+		return (ENXIO);
+	}
+
+	if ((uint32_t)index + (uint32_t)addr > 0xffff) {
+		printf("[foo] generic_ocp_read(index=%x addr=%x): overflow error\n",
+		   len, index);
+		return (ENXIO);
+	}
+
+	//TODO: Deal with the fact if len > limit (block fetching)
+	if (len > limit) {
+		printf("[foo] generic_ocp_read(len=%x limit=%x): size overflow\n",
+		   len, limit);
+		return (ENXIO);
+	}
+
+	req.bmRequestType = UT_READ_VENDOR_DEVICE;
+	req.bRequest = UR_SET_ADDRESS;
+	USETW(req.wIndex, index);
+	USETW(req.wValue, addr);
+	USETW(req.wLength, len);
+
+	ret = uether_do_request(&sc->sc_ue, &req, buf, 500);
+	return ret;
+}
+
+static int
+set_registers(struct rtl_softc *sc, uint16_t index, uint16_t addr, void *buf, int len) {
+	struct usb_device_request req;
+
+	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+	req.bRequest = UR_SET_ADDRESS;
+	USETW(req.wIndex, index);
+	USETW(req.wValue, addr);
+	USETW(req.wLength, len);
+
+	//TODO: Make timeout some kind of define global?
+	return (uether_do_request(&sc->sc_ue, &req, buf, 500));
+}
+
+static int
+ocp_write(struct rtl_softc *sc, uint16_t index, uint16_t addr,
+		    uint16_t byteen, void *buf, int len)
+{
+	uint16_t byteen_start, byteen_end, byen;
+	uint16_t limit = 512;
+	int ret;
+
+	/* both size and indix must be 4 bytes align */
+	// TODO: Argue whether are supposed to be non-fatal values
+	if ((len & 3) || !len || (index & 3) || (!buf)) {
+		printf("[foo] ocp_write(len=%x index=%x): not alligned error\n",
+		   len, index);
+		return (ENXIO);
+	}
+
+	if ((uint32_t)index + (uint32_t)addr > 0xffff) {
+		printf("[foo] ocp_write(index=%x addr=%x): overflow error\n",
+		   len, index);
+		return (ENXIO);
+	}
+
+	//TODO: Deal with the fact if len > limit (block fetching)
+	if (len > limit) {
+		printf("[foo] ocp_write(len=%x limit=%x): size overflow\n",
+		   len, limit);
+		return (ENXIO);
+	}
+
+	byteen_start = byteen & BYTE_EN_START_MASK;
+	byteen_end = byteen & BYTE_EN_END_MASK;
+
+	byen = byteen_start | (byteen_start << 4);
+
+	ret = set_registers(sc, index, addr | byen , buf, 4);
+	if (ret < 0)
+		return ret;
+
+	//TODO: Implement if size > limit
+	return ret;
+}
+
+static uint8_t
+ocp_read_1(struct rtl_softc *sc, uint16_t index, uint16_t addr)
+{
+	uint32_t data;
+	//TODO: __le32 tmp;
+	uint32_t tmp;
+
+	generic_ocp_read(sc, index, addr & ~3, &tmp, 4);
+
+	//TODO: data = __le32_to_cpu(tmp);
+	data = tmp;
+	data >>= ((addr & 3) * 8);
+	data &= 0xff;
+
+	//printf("[foo] ocp_read_1(index=%x, addr=%x) => 0x%x\n", index, addr, data);
+
+	return (uint8_t)data;
+}
+
+static uint16_t
+ocp_read_2(struct rtl_softc *sc, uint16_t index, uint16_t addr)
+{
+	uint32_t data;
+	//TODO: __le32 tmp;
+	uint32_t tmp;
+
+	generic_ocp_read(sc, index, addr & ~3, &tmp, 4);
+
+	//TODO: data = __le32_to_cpu(tmp);
+	data = tmp;
+	data >>= ((addr & 2) * 8);
+	data &= 0xffff;
+
+	//printf("[foo] ocp_read_2(index=%x, addr=%x) => tmp=%x data=%x\n", index, addr, tmp, data);
+
+	return (uint16_t)data;
+}
+
+static uint32_t
+ocp_read_4(struct rtl_softc *sc, uint16_t index, uint16_t addr)
+{
+	uint32_t data;
+	//TODO: __le32 tmp;
+	uint32_t tmp;
+
+	generic_ocp_read(sc, index, addr, &tmp, 4);
+
+	//TODO: data = __le32_to_cpu(tmp);
+	data = tmp;
+
+	return data;
+}
+
+static int
+ocp_write_1(struct rtl_softc *sc, uint16_t index, uint16_t addr, uint8_t val)
+{
+	uint32_t mask = 0xff;
+	//TODO: __le32 tmp;
+	uint32_t tmp;
+	uint16_t byten = BYTE_EN_BYTE;
+	uint8_t shift = addr & 3;
+	uint32_t data = val;
+	int ret;
+
+	data &= mask;
+
+	//printf("[foo] ocp_write_1(index=%x, addr=%x, val=%x)\n", index, addr, val);
+
+	if (index & 3) {
+		byten <<= shift;
+		mask <<= (shift * 8);
+		data <<= (shift * 8);
+		addr &= ~3;
+	}
+
+	ret = generic_ocp_read(sc, index, addr, &tmp, 4);
+	if (ret < 0)
+		return ret;
+
+	//TODO: data |= __le32_to_cpu(tmp) & ~mask;
+	data |= tmp & ~mask;
+	//TODO: tmp = __cpu_to_le32(data);
+	tmp = data;
+
+	return (ocp_write(sc, index, addr, byten, &tmp, 4));
+}
+
+static int
+ocp_write_2(struct rtl_softc *sc, uint16_t index, uint16_t addr, uint16_t val)
+{
+	uint32_t mask = 0xffff;
+	//TODO: __le32 tmp;
+	uint32_t tmp;
+	uint16_t byten = BYTE_EN_WORD;
+	uint8_t shift = addr & 2;
+	uint32_t data = val;
+	int ret;
+
+	printf("[foo] ocp_write_2(index=%x, addr=%x, val=%x)\n", index, addr, val);
+
+	data &= mask;
+
+	if (index & 2) {
+		byten <<= shift;
+		mask <<= (shift * 8);
+		data <<= (shift * 8);
+		addr &= ~3;
+	}
+
+	ret = generic_ocp_read(sc, index, addr, &tmp, 4);
+	if (ret < 0)
+		return ret;
+
+
+	//TODO: data |= __le32_to_cpu(tmp) & ~mask;
+	data |= tmp & ~mask;
+	//TODO: tmp = __cpu_to_le32(data);
+	tmp = data;
+
+	 return (ocp_write(sc, index, addr, byten, &tmp, 4));
+}
+
+
+static int
+ocp_write_4(struct rtl_softc *sc, uint16_t index, uint16_t addr, uint32_t val)
+{
+	//TODO: __le32 tmp;
+	uint32_t tmp;
+
+	//TODO: tmp = __le32_to_cpu(data);
+	tmp = val;
+
+	//printf("[foo] ocp_write_4(index=%x, addr=%x, val=%x)\n", index, addr, tmp);
+	return (ocp_write(sc, index, addr, BYTE_EN_DWORD, &tmp, 4));
+}
+
+static uint16_t
+ocp_reg_read(struct rtl_softc *sc, uint16_t addr)
+{
+	uint16_t ocp_base = addr & 0xf000;
+	uint16_t ocp_index = (addr & 0x0fff) | 0xb000;
+
+	if (ocp_base != sc->ocp_base) {
+		ocp_write_2(sc, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, ocp_base);
+		sc->ocp_base = ocp_base;
+	}
+
+	return ocp_read_2(sc, MCU_TYPE_PLA, ocp_index);
+}
+
+static void
+ocp_reg_write(struct rtl_softc *sc, uint16_t addr, uint16_t val)
+{
+	uint16_t ocp_base = addr & 0xf000;
+	uint16_t ocp_index = (addr & 0x0fff) | 0xb000;
+
+	if (ocp_base != sc->ocp_base) {
+		ocp_write_2(sc, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, ocp_base);
+		sc->ocp_base = ocp_base;
+	}
+
+	ocp_write_2(sc, MCU_TYPE_PLA, ocp_index, val);
+}
+
+static inline void
+r8152_mdio_write(struct rtl_softc *sc, uint32_t addr, uint32_t val)
+{
+	ocp_reg_write(sc, OCP_BASE_MII + addr * 2, val);
+}
+
+static inline uint32_t
+r8152_mdio_read(struct rtl_softc *sc, uint32_t addr)
+{
+	return ocp_reg_read(sc, OCP_BASE_MII + addr * 2);
+}
+
+static int
+rtl_miibus_readreg(device_t dev, int phy, int reg)
+{
+	//printf("[foo] rtl_miibus_readreg(phy=%x, reg=%x)\n", phy, reg);
+	struct rtl_softc *sc = device_get_softc(dev);
+	uint16_t rval;
+	int locked;
+
+	if (phy != 0)		/* RTL8152 supports PHY == 0, only */
+		return (0);
+
+	locked = mtx_owned(&sc->sc_mtx);
+	if (!locked)
+		RTL_LOCK(sc);
+
+	rval = r8152_mdio_read(sc, reg);
+
+	if (!locked)
+		RTL_UNLOCK(sc);
+	//printf("[foo] rtl_miibus_readreg(phy=%x, reg=%x) => rval=%x\n", phy, reg, rval);
+	return (rval);
+}
+
+static int
+rtl_miibus_writereg(device_t dev, int phy, int reg, int data)
+{
+	printf("[foo] rtl_miibus_writereg(phy=%x reg=%x data=%x\n", phy, reg, data);
+	return (0);
+	struct rtl_softc *sc = device_get_softc(dev);
+	int locked;
+
+	if (phy != 0)		/* RTL8152 supports PHY == 0, only */
+		return (0);
+
+	locked = mtx_owned(&sc->sc_mtx);
+	if (!locked)
+		RTL_LOCK(sc);
+
+	r8152_mdio_write(sc, reg, data);
+
+	if (!locked)
+		RTL_UNLOCK(sc);
+	return (0);
+}
+
+static void
+rtl_miibus_statchg(device_t dev)
+{
+	printf("[foo] %s\n", __func__);
+#if 0
+	struct rtl_softc *sc = device_get_softc(dev);
+	struct mii_data *mii = GET_MII(sc);
+	uint16_t bmcr;
+	int locked;
+
+	locked = mtx_owned(&sc->sc_mtx);
+	if (!locked)
+		RTL_LOCK(sc);
+
+	RTL_CLRBIT(sc, RTL_CR, (RTL_CR_RE | RTL_CR_TE));
+
+	bmcr = rtl_csr_read_2(sc, RTL_BMCR);
+
+	if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX)
+		bmcr |= RTL_BMCR_SPD_SET;
+	else
+		bmcr &= ~RTL_BMCR_SPD_SET;
+
+	if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX)
+		bmcr |= RTL_BMCR_DUPLEX;
+	else
+		bmcr &= ~RTL_BMCR_DUPLEX;
+
+	rtl_csr_write_2(sc, RTL_BMCR, bmcr);
+
+	RTL_SETBIT(sc, RTL_CR, (RTL_CR_RE | RTL_CR_TE));
+
+	if (!locked)
+		RTL_UNLOCK(sc);
+#endif
+}
+
+//TODO: Make global defines
+static const int multicast_filter_limit = 32;
+//static const unsigned int agg_buf_sz = 16384;
+
+
+/*
+ * Program the 64-bit multicast hash filter and promiscuous mode
+ */
+static void
+rtl_setpromisc_and_multi(struct usb_ether *ue)
+{
+	printf("[foo] %s\n", __func__);
+	struct rtl_softc *sc = uether_getsc(ue);
+	struct ifnet *ifp = uether_getifp(ue);
+	int h = 0;
+	uint32_t hashes[2] = { 0, 0 };
+	uint32_t tmp[2];
+	uint32_t ocp_data;
+	struct ifmultiaddr *ifma;
+	int mcnt = 0;
+
+	RTL_LOCK_ASSERT(sc, MA_OWNED);
+
+	ocp_data = ocp_read_4(sc, MCU_TYPE_PLA, PLA_RCR);
+	ocp_data &= ~RCR_ACPT_ALL;
+	ocp_data |= RCR_AB | RCR_APM;
+
+
+	/* Make multicast filter */
+	if_maddr_rlock(ifp);
+	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;
+
+		hashes[h >> 5] |= 1 << (h & 31);
+		mcnt++;
+	}
+	if_maddr_runlock(ifp);
+
+
+	if (ifp->if_flags & IFF_PROMISC) {
+		ocp_data |= RCR_AM | RCR_AAP;
+		hashes[0] = 0xffffffff;
+		hashes[1] = 0xffffffff;
+	} else if ((mcnt > multicast_filter_limit) || 
+		   (ifp->if_flags & IFF_ALLMULTI)) {
+		/* Too many to filter perfectly -- accept all multicasts. */
+		ocp_data |= RCR_AM;
+		hashes[0] = 0xffffffff;
+		hashes[1] = 0xffffffff;
+	} else if (mcnt > 0) {
+		ocp_data |= RCR_AM;
+	}
+
+	//TODO: tmp[0] = __cpu_to_le32(swab32(mc_filter[1]));
+	//TODO: tmp[1] = __cpu_to_le32(swab32(mc_filter[0]));
+	tmp[0] = hashes[0];
+	tmp[1] = hashes[1];
+
+	ocp_write(sc, MCU_TYPE_PLA, PLA_MAR, BYTE_EN_DWORD, tmp, sizeof(tmp));
+	ocp_write_4(sc, MCU_TYPE_PLA, PLA_RCR, ocp_data);
+}
+
+static void
+rtl_reset(struct rtl_softc *sc)
+{
+	printf("[foo] %s\n", __func__);
+	int i;
+
+	ocp_write_1(sc, MCU_TYPE_PLA, PLA_CR, CR_RST);
+
+	for (i = 0; i != RTL_TIMEOUT; i++) {
+		if (uether_pause(&sc->sc_ue, hz / 1000))
+			break;
+		if (!(ocp_read_1(sc, MCU_TYPE_PLA, PLA_CR) & CR_RST))
+			break;
+	}
+
+	if (i == RTL_TIMEOUT)
+		device_printf(sc->sc_ue.ue_dev, "reset never completed\n");
+
+	uether_pause(&sc->sc_ue, hz / 100);
+}
+
+static void
+rtl_attach_post(struct usb_ether *ue)
+{
+	printf("[foo] %s\n", __func__);
+	struct rtl_softc *sc = uether_getsc(ue);
+	int ret;
+
+	/* reset the adapter */
+	rtl_reset(sc);
+
+	uint32_t ocp_data;
+	uint16_t version;
+
+	ocp_data = ocp_read_2(sc, MCU_TYPE_PLA, PLA_TCR1);
+	version = (uint16_t)(ocp_data & VERSION_MASK);
+	switch (version) {
+		case 0x4c00:
+			sc->version = RTL_VER_01;
+			break;
+		case 0x4c10:
+			sc->version = RTL_VER_02;
+			break;
+		case 0x5c00:
+			sc->version = RTL_VER_03;
+			break;
+		case 0x5c10:
+			sc->version = RTL_VER_04;
+			break;
+		case 0x5c20:
+			sc->version = RTL_VER_05;
+			break;
+		default:
+			printf("[foo] Unknown version 0x%04x\n", version);
+			break;
+	}
+	printf("[foo] ocp_data=%x version=%x\n", ocp_data, version);
+	
+	/* Get station address from the EEPROM which needs to be aligned */
+	//TODO: Allign automatically(?)
+	if (sc->version == RTL_VER_01)
+		ret = generic_ocp_read(sc, MCU_TYPE_PLA, PLA_IDR, ue->ue_eaddr, 8);
+	else
+		ret = generic_ocp_read(sc, MCU_TYPE_PLA, PLA_BACKUP,ue->ue_eaddr, 8);
+
+	printf("[foo] attach_post: Read MAC address (version=%x ret=%x mac=%s\n", sc->version, ret, ue->ue_eaddr);
+
+	if (ret < 0) {
+	//TODO: How-to handle failures and/or invalid MAC addresses
+		printf("[foo] attach_post: Get ether addr fail\n");
+	//TODO: should we make a random MAC address?
+	// } else if (!is_valid_ether_addr(ue->ue_eaddr)) {
+	// TODO: If no MAC is returned the device is crashed and needs to be
+	// power-cycled, how-to inform user?
+	} else {
+		/* Later versions needs to have the MAC copied to the working location */
+		if (sc->version != RTL_VER_01) {
+			ocp_write_1(sc, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG);
+			ocp_write(sc, MCU_TYPE_PLA, PLA_IDR, BYTE_EN_SIX_BYTES,
+			                    ue->ue_eaddr, 8);
+			ocp_write_1(sc, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
+		}
+	}
+}
+
+/*
+ * Probe for a RTL8150 chip.
+ */
+static int
+rtl_probe(device_t dev)
+{
+	printf("[foo] %s\n", __func__);
+	struct usb_attach_arg *uaa = device_get_ivars(dev);
+
+	if (uaa->usb_mode != USB_MODE_HOST)
+		return (ENXIO);
+	if (uaa->info.bConfigIndex != RTL_CONFIG_IDX)
+		return (ENXIO);
+	if (uaa->info.bIfaceIndex != RTL_IFACE_IDX)
+		return (ENXIO);
+
+	return (usbd_lookup_id_by_uaa(rtl_devs, sizeof(rtl_devs), uaa));
+}
+
+/*
+ * Attach the interface. Allocate softc structures, do ifmedia
+ * setup and ethernet/BPF attach.
+ */
+static int
+rtl_attach(device_t dev)
+{
+	printf("[foo] %s\n", __func__);
+	struct usb_attach_arg *uaa = device_get_ivars(dev);
+	struct rtl_softc *sc = device_get_softc(dev);
+	struct usb_ether *ue = &sc->sc_ue;
+	uint8_t iface_index;
+	int error;
+
+	device_set_usb_desc(dev);
+	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
+
+	iface_index = RTL_IFACE_IDX;
+	error = usbd_transfer_setup(uaa->device, &iface_index,
+	    sc->sc_xfer, rtl_config, RTL_N_TRANSFER,
+	    sc, &sc->sc_mtx);
+	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_mtx = &sc->sc_mtx;
+	ue->ue_methods = &rtl_ue_methods;
+
+	error = uether_ifattach(ue);
+	if (error) {
+		device_printf(dev, "could not attach interface\n");
+		goto detach;
+	}
+	return (0);			/* success */
+
+detach:
+	rtl_detach(dev);
+	return (ENXIO);			/* failure */
+}
+
+static int
+rtl_detach(device_t dev)
+{
+	printf("[foo] %s\n", __func__);
+	struct rtl_softc *sc = device_get_softc(dev);
+	struct usb_ether *ue = &sc->sc_ue;
+
+	usbd_transfer_unsetup(sc->sc_xfer, RTL_N_TRANSFER);
+	uether_ifdetach(ue);
+	mtx_destroy(&sc->sc_mtx);
+
+	return (0);
+}
+
+static void
+rtl_intr_callback(struct usb_xfer *xfer, usb_error_t error)
+{
+	//struct rtl_softc *sc = usbd_xfer_softc(xfer);
+	//struct ifnet *ifp = uether_getifp(&sc->sc_ue);
+	//struct rtl_intrpkt pkt;
+	uint32_t pkt;
+	struct usb_page_cache *pc;
+	int actlen;
+
+	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
+
+	//printf("[foo] rtl_intr_callback USB_STATE=%i\n", USB_GET_STATE(xfer));
+	switch (USB_GET_STATE(xfer)) {
+	case USB_ST_TRANSFERRED:
+
+		//if (ifp && (ifp->if_drv_flags & IFF_DRV_RUNNING) &&
+		//    actlen >= (int)sizeof(pkt)) {
+		//if (ifp && (ifp->if_drv_flags & IFF_DRV_RUNNING)) {
+
+		pc = usbd_xfer_get_frame(xfer, 0);
+		usbd_copy_out(pc, 0, &pkt, sizeof(pkt));
+		//printf("[foo] rtl_intr_callback pkt=%x actlen=%i\n", pkt, actlen);
+
+			//ifp->if_ierrors += pkt.rtl_rxlost_cnt;
+			//ifp->if_ierrors += pkt.rtl_crcerr_cnt;
+			//ifp->if_collisions += pkt.rtl_col_cnt;
+		//}
+		/* FALLTHROUGH */
+	case USB_ST_SETUP:
+tr_setup:
+		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
+		usbd_transfer_submit(xfer);
+		return;
+
+	default:
+		if (error != USB_ERR_CANCELLED) {
+			usbd_xfer_set_stall(xfer);
+			goto tr_setup;
+		}
+		return;
+	}
+}
+
+static void
+rtl_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
+{
+	struct rtl_softc *sc = usbd_xfer_softc(xfer);
+	struct usb_ether *ue = &sc->sc_ue;
+	//struct ifnet *ifp = uether_getifp(ue);
+	struct usb_page_cache *pc;
+	struct rx_desc rx_desc;
+	//uint16_t status;
+	int actlen;
+	int pos = 0;
+	unsigned int pkt_len;
+
+	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
+
+	printf("[foo] rtl_bulk_read_callback USB_STATE=%i actlen=%d\n", USB_GET_STATE(xfer), actlen);
+	switch (USB_GET_STATE(xfer)) {
+	case USB_ST_TRANSFERRED:
+		pc = usbd_xfer_get_frame(xfer, 0);
+
+		while (actlen > pos) {
+			usbd_copy_out(pc, pos, &rx_desc, sizeof(rx_desc));
+			pos += (sizeof rx_desc);
+
+			pkt_len = rx_desc.opts1 & RX_LEN_MASK;
+			printf("[foo] pkt_len=%d\n", pkt_len);
+
+			//ETH_ZLEN (Min. octents in frame sans FCS)
+			if (pkt_len < 60)
+				break;
+
+			// TODO: Should we flag this as errors
+			if (actlen < (pos + pkt_len))
+				break;
+
+			// TODO: Chipset supports CRC and VLAN tagging
+			uether_rxbuf(ue, pc, pos, pkt_len - CRC_SIZE);
+
+			pos += pkt_len;
+			//TODO: Data get aligned?
+		}
+		/* 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);
+		return;
+
+	default:			/* Error */
+		printf("[foo] bulk read error, %s\n",
+		    usbd_errstr(error));
+
+		if (error != USB_ERR_CANCELLED) {
+			/* try to clear stall first */
+			usbd_xfer_set_stall(xfer);
+			goto tr_setup;
+		}
+		return;
+	}
+}
+
+static void
+rtl_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
+{
+	struct rtl_softc *sc = usbd_xfer_softc(xfer);
+	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
+	struct usb_page_cache *pc;
+	struct mbuf *m;
+	int pos;
+	struct tx_desc tx_desc;
+
+	printf("[foo] rtl_bulk_write_callback USB_STATE=%i\n", USB_GET_STATE(xfer));
+	switch (USB_GET_STATE(xfer)) {
+	case USB_ST_TRANSFERRED:
+		printf("[foo] rtl_bulk_write_callback: transfer complete\n");
+		DPRINTFN(11, "transfer complete\n");
+		ifp->if_opackets++;
+
+		/* FALLTHROUGH */
+	case USB_ST_SETUP:
+tr_setup:
+		//if ((sc->sc_flags & RTL_FLAG_LINK) == 0) {
+		//	printf("[foo] rtl_bulk_write_callback: error no link!\n");
+		//	/*
+		//	 * don't send anything if there is no link !
+		//	 */
+		//	return;
+		//}
+		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
+		if (m == NULL)
+			return;
+
+		//if (m->m_pkthdr.len > MCLBYTES)
+		//	m->m_pkthdr.len = MCLBYTES;
+		//temp_len = m->m_pkthdr.len;
+
+		pos = 0;
+		pc = usbd_xfer_get_frame(xfer, 0);
+
+		// Header description
+		// //TODO: Complete CRC
+		int transport_offset = 0;
+		tx_desc.opts1 = m->m_pkthdr.len | TX_FS | TX_LS;
+		tx_desc.opts1 |= transport_offset << GTTCPHO_SHIFT;
+		tx_desc.opts1 |= GTSENDV4;
+
+		usbd_copy_in(pc, pos, &tx_desc, sizeof(tx_desc));
+		pos += sizeof(tx_desc);
+
+		// Content
+		usbd_m_copy_in(pc, pos, m, 0, m->m_pkthdr.len);
+		pos += m->m_pkthdr.len;
+
+
+		printf("[foo] rtl_bulk_write_callback len=%i\n", m->m_pkthdr.len);
+		int i;
+		for (i = 0; i < m->m_pkthdr.len; i++)
+			printf("%x", m->m_data[i]);
+		printf("\n");
+
+		usbd_xfer_set_frame_len(xfer, 0, pos);
+
+		/*
+		 * if there's a BPF listener, bounce a copy
+		 * of this frame to him:
+		 */
+		BPF_MTAP(ifp, m);
+
+		m_freem(m);
+
+		usbd_transfer_submit(xfer);
+
+		return;
+
+	default:			/* Error */
+		printf("[foo] bulk write: transfer error, %s\n", usbd_errstr(error));
+		ifp->if_oerrors++;
+
+		if (error != USB_ERR_CANCELLED) {
+			/* try to clear stall first */
+			usbd_xfer_set_stall(xfer);
+			goto tr_setup;
+		}
+		return;
+	}
+}
+
+static void
+rtl_tick(struct usb_ether *ue)
+{
+	printf("[foo] %s\n", __func__);
+	struct rtl_softc *sc = uether_getsc(ue);
+	struct mii_data *mii = GET_MII(sc);
+
+	RTL_LOCK_ASSERT(sc, MA_OWNED);
+
+	mii_tick(mii);
+	if ((sc->sc_flags & RTL_FLAG_LINK) == 0
+	    && mii->mii_media_status & IFM_ACTIVE &&
+	    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
+		sc->sc_flags |= RTL_FLAG_LINK;
+		rtl_start(ue);
+	}
+}
+
+static void
+rtl8152_set_mac_address(struct usb_ether *ue)
+{
+	printf("[foo] %s\n", __func__);
+	struct rtl_softc *sc = uether_getsc(ue);
+
+	ocp_write_1(sc, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG);
+	ocp_write(sc, MCU_TYPE_PLA, PLA_IDR, BYTE_EN_SIX_BYTES, ue->ue_eaddr, 8);
+	ocp_write_1(sc, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
+}
+
+static void
+r8152b_reset_packet_filter(struct rtl_softc *sc)
+{
+	printf("[foo] %s\n", __func__);
+	uint32_t ocp_data;
+
+	ocp_data = ocp_read_2(sc, MCU_TYPE_PLA, PLA_FMC);
+	ocp_data &= ~FMC_FCR_MCU_EN;
+	ocp_write_2(sc, MCU_TYPE_PLA, PLA_FMC, ocp_data);
+	ocp_data |= FMC_FCR_MCU_EN;
+	ocp_write_2(sc, MCU_TYPE_PLA, PLA_FMC, ocp_data);
+}
+
+static void
+rtl8152_nic_reset(struct rtl_softc *sc)
+{
+	printf("[foo] %s\n", __func__);
+	int	i;
+
+	ocp_write_1(sc, MCU_TYPE_PLA, PLA_CR, CR_RST);
+
+	for (i = 0; i < 1000; i++) {
+		if (!(ocp_read_1(sc, MCU_TYPE_PLA, PLA_CR) & CR_RST))
+			break;
+		uether_pause(&sc->sc_ue, hz / 100);
+	}
+}
+
+static inline uint8_t
+rtl8152_get_speed(struct rtl_softc* sc)
+{
+	printf("[foo] %s\n", __func__);
+	return ocp_read_1(sc, MCU_TYPE_PLA, PLA_PHYSTATUS);
+}
+
+static void
+rtl_set_eee_plus(struct rtl_softc *sc)
+{
+	printf("[foo] %s\n", __func__);
+	uint32_t ocp_data;
+	uint8_t speed;
+
+	speed = rtl8152_get_speed(sc);
+	//TODO: Find out which bits represent which speed
+	//if (speed & _10bps) {
+	//	ocp_data = ocp_read_2(tp, MCU_TYPE_PLA, PLA_EEEP_CR);
+	//	ocp_data |= EEEP_CR_EEEP_TX;
+	//	ocp_write_2(tp, MCU_TYPE_PLA, PLA_EEEP_CR, ocp_data);
+	//} else {
+		ocp_data = ocp_read_2(sc, MCU_TYPE_PLA, PLA_EEEP_CR);
+		ocp_data &= ~EEEP_CR_EEEP_TX;
+		ocp_write_2(sc, MCU_TYPE_PLA, PLA_EEEP_CR, ocp_data);
+	//}
+}
+
+static void
+rxdy_gated_en(struct rtl_softc *sc, bool enable)
+{
+	printf("[foo] %s\n", __func__);
+	uint32_t ocp_data;
+
+	ocp_data = ocp_read_2(sc, MCU_TYPE_PLA, PLA_MISC_1);
+	if (enable)
+		ocp_data |= RXDY_GATED_EN;
+	else
+		ocp_data &= ~RXDY_GATED_EN;
+	ocp_write_2(sc, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
+}
+
+static int
+rtl_enable(struct rtl_softc *sc)
+{
+	printf("[foo] %s\n", __func__);
+	uint32_t ocp_data;
+
+	r8152b_reset_packet_filter(sc);
+
+	ocp_data = ocp_read_1(sc, MCU_TYPE_PLA, PLA_CR);
+	ocp_data |= CR_RE | CR_TE;
+	ocp_write_1(sc, MCU_TYPE_PLA, PLA_CR, ocp_data);
+
+	rxdy_gated_en(sc, false);
+
+	return 0;
+}
+
+
+static int
+rtl8152_enable(struct rtl_softc *sc)
+{
+	printf("[foo] %s\n", __func__);
+	//set_tx_qlen(sc);
+	rtl_set_eee_plus(sc);
+
+	return rtl_enable(sc);
+}
+
+static void
+rtl_disable(struct rtl_softc *sc)
+{
+	printf("[foo] %s\n", __func__);
+	uint32_t ocp_data;
+	int i;
+
+	ocp_data = ocp_read_4(sc, MCU_TYPE_PLA, PLA_RCR);
+	ocp_data &= ~RCR_ACPT_ALL;
+	ocp_write_4(sc, MCU_TYPE_PLA, PLA_RCR, ocp_data);
+
+	rxdy_gated_en(sc, true);
+
+	for (i = 0; i < 1000; i++) {
+		ocp_data = ocp_read_1(sc, MCU_TYPE_PLA, PLA_OOB_CTRL);
+		if ((ocp_data & FIFO_EMPTY) == FIFO_EMPTY)
+			break;
+		uether_pause(&sc->sc_ue, hz / 100);
+	}
+
+	for (i = 0; i < 1000; i++) {
+		if (ocp_read_2(sc, MCU_TYPE_PLA, PLA_TCR0) & TCR0_TX_EMPTY)
+			break;
+		uether_pause(&sc->sc_ue, hz / 100);
+	}
+
+	rtl8152_nic_reset(sc);
+}
+
+static void
+r8152_power_cut_en(struct rtl_softc *sc, bool enable)
+{
+	printf("[foo] %s\n", __func__);
+	uint32_t ocp_data;
+
+	ocp_data = ocp_read_2(sc, MCU_TYPE_USB, USB_UPS_CTRL);
+	if (enable)
+		ocp_data |= POWER_CUT;
+	else
+		ocp_data &= ~POWER_CUT;
+	ocp_write_2(sc, MCU_TYPE_USB, USB_UPS_CTRL, ocp_data);
+
+	ocp_data = ocp_read_2(sc, MCU_TYPE_USB, USB_PM_CTRL_STATUS);
+	ocp_data &= ~RESUME_INDICATE;
+	ocp_write_2(sc, MCU_TYPE_USB, USB_PM_CTRL_STATUS, ocp_data);
+}
+
+static void
+rtl_rx_vlan_en(struct rtl_softc *sc, bool enable)
+{
+	printf("[foo] %s\n", __func__);
+	uint32_t ocp_data;
+
+	ocp_data = ocp_read_2(sc, MCU_TYPE_PLA, PLA_CPCR);
+	if (enable)
+		ocp_data |= CPCR_RX_VLAN;
+	else
+		ocp_data &= ~CPCR_RX_VLAN;
+	ocp_write_2(sc, MCU_TYPE_PLA, PLA_CPCR, ocp_data);
+}
+
+//TODO convert
+//#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)
+
+static uint32_t
+__rtl_get_wol(struct rtl_softc *sc)
+{
+	printf("[foo] %s\n", __func__);
+	uint32_t ocp_data;
+	uint32_t wolopts = 0;
+
+	ocp_data = ocp_read_1(sc, MCU_TYPE_PLA, PLA_CONFIG5);
+	if (!(ocp_data & LAN_WAKE_EN))
+		return 0;
+
+//	ocp_data = ocp_read_2(sc, MCU_TYPE_PLA, PLA_CONFIG34);
+//	if (ocp_data & LINK_ON_WAKE_EN)
+//		wolopts |= WAKE_PHY;
+//
+//	ocp_data = ocp_read_2(sc, MCU_TYPE_PLA, PLA_CONFIG5);
+//	if (ocp_data & UWF_EN)
+//		wolopts |= WAKE_UCAST;
+//	if (ocp_data & BWF_EN)
+//		wolopts |= WAKE_BCAST;
+//	if (ocp_data & MWF_EN)
+//		wolopts |= WAKE_MCAST;
+//
+//	ocp_data = ocp_read_2(sc, MCU_TYPE_PLA, PLA_CFG_WOL);
+//	if (ocp_data & MAGIC_EN)
+//		wolopts |= WAKE_MAGIC;
+
+	return wolopts;
+}
+
+static void
+__rtl_set_wol(struct rtl_softc *sc, uint32_t wolopts)
+{
+	printf("[foo] %s\n", __func__);
+	uint32_t ocp_data;
+
+	ocp_write_1(sc, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG);
+
+	ocp_data = ocp_read_2(sc, MCU_TYPE_PLA, PLA_CONFIG34);
+	ocp_data &= ~LINK_ON_WAKE_EN;
+//	if (wolopts & WAKE_PHY)
+//		ocp_data |= LINK_ON_WAKE_EN;
+//	ocp_write_2(sc, MCU_TYPE_PLA, PLA_CONFIG34, ocp_data);
+//
+//	ocp_data = ocp_read_2(sc, MCU_TYPE_PLA, PLA_CONFIG5);
+//	ocp_data &= ~(UWF_EN | BWF_EN | MWF_EN | LAN_WAKE_EN);
+//	if (wolopts & WAKE_UCAST)
+//		ocp_data |= UWF_EN;
+//	if (wolopts & WAKE_BCAST)
+//		ocp_data |= BWF_EN;
+//	if (wolopts & WAKE_MCAST)
+//		ocp_data |= MWF_EN;
+//	if (wolopts & WAKE_ANY)
+//		ocp_data |= LAN_WAKE_EN;
+//	ocp_write_2(sc, MCU_TYPE_PLA, PLA_CONFIG5, ocp_data);
+//
+//	ocp_write_1(sc, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
+//
+//	ocp_data = ocp_read_2(sc, MCU_TYPE_PLA, PLA_CFG_WOL);
+//	ocp_data &= ~MAGIC_EN;
+//	if (wolopts & WAKE_MAGIC)
+//		ocp_data |= MAGIC_EN;
+//	ocp_write_2(sc, MCU_TYPE_PLA, PLA_CFG_WOL, ocp_data);
+}
+
+static void
+rtl_runtime_suspend_enable(struct rtl_softc *sc, bool enable)
+{
+	printf("[foo] %s\n", __func__);
+	uint32_t ocp_data;
+
+	if (enable) {
+		//__rtl_set_wol(sc, WAKE_ANY);
+
+		ocp_write_1(sc, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG);
+
+		ocp_data = ocp_read_2(sc, MCU_TYPE_PLA, PLA_CONFIG34);
+		ocp_data |= LINK_OFF_WAKE_EN;
+		ocp_write_2(sc, MCU_TYPE_PLA, PLA_CONFIG34, ocp_data);
+
+		ocp_write_1(sc, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
+	} else {
+		__rtl_set_wol(sc, sc->saved_wolopts);
+	}
+}
+
+static void
+rtl_phy_reset(struct rtl_softc *sc)
+{
+	printf("[foo] %s\n", __func__);
+	uint32_t data;
+	int i;
+
+	data = r8152_mdio_read(sc, MII_BMCR);
+
+	/* don't reset again before the previous one complete */
+	if (data & BMCR_RESET)
+		return;
+
+	data |= BMCR_RESET;
+	r8152_mdio_write(sc, MII_BMCR, data);
+
+	for (i = 0; i < 50; i++) {
+		uether_pause(&sc->sc_ue, hz / 1000);
+		if ((r8152_mdio_read(sc, MII_BMCR) & BMCR_RESET) == 0)
+			break;
+	}
+}
+
+static void
+r8153_teredo_off(struct rtl_softc *sc)
+{
+	printf("[foo] %s\n", __func__);
+	uint32_t ocp_data;
+
+	ocp_data = ocp_read_2(sc, MCU_TYPE_PLA, PLA_TEREDO_CFG);
+	ocp_data &= ~(TEREDO_SEL | TEREDO_RS_EVENT_MASK | OOB_TEREDO_EN);
+	ocp_write_2(sc, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data);
+
+	ocp_write_2(sc, MCU_TYPE_PLA, PLA_WDT6_CTRL, WDT6_SET_MODE);
+	ocp_write_2(sc, MCU_TYPE_PLA, PLA_REALWOW_TIMER, 0);
+	ocp_write_4(sc, MCU_TYPE_PLA, PLA_TEREDO_TIMER, 0);
+}
+
+static void
+r8152b_disable_aldps(struct rtl_softc *sc)
+{
+	printf("[foo] %s\n", __func__);
+	ocp_reg_write(sc, OCP_ALDPS_CONFIG, ENPDNPS | LINKENA | DIS_SDSAVE);
+	uether_pause(&sc->sc_ue, hz / 100);
+}
+
+static inline void
+r8152b_enable_aldps(struct rtl_softc *sc)
+{
+	printf("[foo] %s\n", __func__);
+	ocp_reg_write(sc, OCP_ALDPS_CONFIG, ENPWRSAVE | ENPDNPS |
+					    LINKENA | DIS_SDSAVE);
+}
+
+static void rtl8152_disable(struct rtl_softc *sc)
+{
+	printf("[foo] %s\n", __func__);
+	r8152b_disable_aldps(sc);
+	rtl_disable(sc);
+	r8152b_enable_aldps(sc);
+}
+
+static void r8152b_hw_phy_cfg(struct rtl_softc *sc)
+{
+	printf("[foo] %s\n", __func__);
+	uint16_t data;
+
+	data = r8152_mdio_read(sc, MII_BMCR);
+	if (data & BMCR_PDOWN) {
+		data &= ~BMCR_PDOWN;
+		r8152_mdio_write(sc, MII_BMCR, data);
+	}
+}
+
+static void
+r8152b_exit_oob(struct rtl_softc *sc)
+{
+	printf("[foo] %s\n", __func__);
+	uint32_t ocp_data;
+	int i;
+
+	ocp_data = ocp_read_4(sc, MCU_TYPE_PLA, PLA_RCR);
+	ocp_data &= ~RCR_ACPT_ALL;
+	ocp_write_4(sc, MCU_TYPE_PLA, PLA_RCR, ocp_data);
+
+	rxdy_gated_en(sc, true);
+	r8153_teredo_off(sc);
+	r8152b_hw_phy_cfg(sc);
+
+	ocp_write_1(sc, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML);
+	ocp_write_1(sc, MCU_TYPE_PLA, PLA_CR, 0x00);
+
+	ocp_data = ocp_read_1(sc, MCU_TYPE_PLA, PLA_OOB_CTRL);
+	ocp_data &= ~NOW_IS_OOB;
+	ocp_write_1(sc, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
+
+	ocp_data = ocp_read_2(sc, MCU_TYPE_PLA, PLA_SFF_STS_7);
+	ocp_data &= ~MCU_BORW_EN;
+	ocp_write_2(sc, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
+
+	for (i = 0; i < 1000; i++) {
+		ocp_data = ocp_read_1(sc, MCU_TYPE_PLA, PLA_OOB_CTRL);
+		if (ocp_data & LINK_LIST_READY)
+			break;
+		uether_pause(&sc->sc_ue, hz / 10);
+	}
+
+	ocp_data = ocp_read_2(sc, MCU_TYPE_PLA, PLA_SFF_STS_7);
+	ocp_data |= RE_INIT_LL;
+	ocp_write_2(sc, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
+
+	for (i = 0; i < 1000; i++) {
+		ocp_data = ocp_read_1(sc, MCU_TYPE_PLA, PLA_OOB_CTRL);
+		if (ocp_data & LINK_LIST_READY)
+			break;
+		uether_pause(&sc->sc_ue, hz / 10);
+	}
+
+	rtl8152_nic_reset(sc);
+
+	/* rx share fifo credit full threshold */
+	ocp_write_4(sc, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_NORMAL);
+
+		ocp_write_4(sc, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1,
+				RXFIFO_THR2_FULL);
+		ocp_write_4(sc, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2,
+				RXFIFO_THR3_FULL);
+	//if (tp->udev->speed == USB_SPEED_FULL ||
+	//    tp->udev->speed == USB_SPEED_LOW) {
+	//	/* rx share fifo credit near full threshold */
+	//	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1,
+	//			RXFIFO_THR2_FULL);
+	//	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2,
+	//			RXFIFO_THR3_FULL);
+	//} else {
+	//	/* rx share fifo credit near full threshold */
+	//	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1,
+	//			RXFIFO_THR2_HIGH);
+	//	ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2,
+	//			RXFIFO_THR3_HIGH);
+	//}
+
+	/* TX share fifo free credit full threshold */
+	ocp_write_4(sc, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, TXFIFO_THR_NORMAL);
+
+	ocp_write_1(sc, MCU_TYPE_USB, USB_TX_AGG, TX_AGG_MAX_THRESHOLD);
+	ocp_write_4(sc, MCU_TYPE_USB, USB_RX_BUF_TH, RX_THR_HIGH);
+	ocp_write_4(sc, MCU_TYPE_USB, USB_TX_DMA,
+			TEST_MODE_DISABLE | TX_SIZE_ADJUST1);
+
+	//rtl_rx_vlan_en(sc, tp->netdev->features & NETIF_F_HW_VLAN_CTAG_RX);
+
+	ocp_write_2(sc, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS);
+
+	ocp_data = ocp_read_2(sc, MCU_TYPE_PLA, PLA_TCR0);
+	ocp_data |= TCR0_AUTO_FIFO;
+	ocp_write_2(sc, MCU_TYPE_PLA, PLA_TCR0, ocp_data);
+}
+
+static void
+r8152b_enter_oob(struct rtl_softc *sc)
+{
+	printf("[foo] %s\n", __func__);
+	uint32_t ocp_data;
+	int i;
+
+	ocp_data = ocp_read_1(sc, MCU_TYPE_PLA, PLA_OOB_CTRL);
+	ocp_data &= ~NOW_IS_OOB;
+	ocp_write_1(sc, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
+
+	ocp_write_4(sc, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_OOB);
+	ocp_write_4(sc, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1, RXFIFO_THR2_OOB);
+	ocp_write_4(sc, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2, RXFIFO_THR3_OOB);
+
+	rtl_disable(sc);
+
+	for (i = 0; i < 1000; i++) {
+		ocp_data = ocp_read_1(sc, MCU_TYPE_PLA, PLA_OOB_CTRL);
+		if (ocp_data & LINK_LIST_READY)
+			break;
+		uether_pause(&sc->sc_ue, hz / 10);
+	}
+
+	ocp_data = ocp_read_2(sc, MCU_TYPE_PLA, PLA_SFF_STS_7);
+	ocp_data |= RE_INIT_LL;
+	ocp_write_2(sc, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data);
+
+	for (i = 0; i < 1000; i++) {
+		ocp_data = ocp_read_1(sc, MCU_TYPE_PLA, PLA_OOB_CTRL);
+		if (ocp_data & LINK_LIST_READY)
+			break;
+		uether_pause(&sc->sc_ue, hz / 10);
+	}
+
+	ocp_write_2(sc, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS);
+
+	rtl_rx_vlan_en(sc, true);
+
+	ocp_data = ocp_read_2(sc, MCU_TYPE_PLA, PAL_BDC_CR);
+	ocp_data |= ALDPS_PROXY_MODE;
+	ocp_write_2(sc, MCU_TYPE_PLA, PAL_BDC_CR, ocp_data);
+
+	ocp_data = ocp_read_1(sc, MCU_TYPE_PLA, PLA_OOB_CTRL);
+	ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB;
+	ocp_write_1(sc, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data);
+
+	rxdy_gated_en(sc, false);
+
+	ocp_data = ocp_read_4(sc, MCU_TYPE_PLA, PLA_RCR);
+	ocp_data |= RCR_APM | RCR_AM | RCR_AB;
+	ocp_write_4(sc, MCU_TYPE_PLA, PLA_RCR, ocp_data);
+}
+
+static void
+rtl8152_up(struct rtl_softc *sc)
+{
+	printf("[foo] %s\n", __func__);
+	r8152b_disable_aldps(sc);
+	r8152b_exit_oob(sc);
+	r8152b_enable_aldps(sc);
+}
+
+static void
+rtl8152_down(struct rtl_softc *sc)
+{
+	printf("[foo] %s\n", __func__);
+	r8152_power_cut_en(sc, false);
+	r8152b_disable_aldps(sc);
+	r8152b_enter_oob(sc);
+	r8152b_enable_aldps(sc);
+}
+
+static inline void
+r8152_mmd_indirect(struct rtl_softc *sc, uint16_t dev, uint16_t reg)
+{
+	printf("[foo] %s\n", __func__);
+	ocp_reg_write(sc, OCP_EEE_AR, FUN_ADDR | dev);
+	ocp_reg_write(sc, OCP_EEE_DATA, reg);
+	ocp_reg_write(sc, OCP_EEE_AR, FUN_DATA | dev);
+}
+
+static uint16_t
+r8152_mmd_read(struct rtl_softc *sc, uint16_t dev, uint16_t reg)
+{
+	printf("[foo] %s\n", __func__);
+	uint16_t data;
+
+	r8152_mmd_indirect(sc, dev, reg);
+	data = ocp_reg_read(sc, OCP_EEE_DATA);
+	ocp_reg_write(sc, OCP_EEE_AR, 0x0000);
+
+	return data;
+}
+
+static void
+r8152_mmd_write(struct rtl_softc *sc, uint16_t dev, uint16_t reg, uint16_t data)
+{
+	printf("[foo] %s\n", __func__);
+	r8152_mmd_indirect(sc, dev, reg);
+	ocp_reg_write(sc, OCP_EEE_DATA, data);
+	ocp_reg_write(sc, OCP_EEE_AR, 0x0000);
+}
+
+static void
+r8152_eee_en(struct rtl_softc *sc, bool enable)
+{
+	printf("[foo] %s\n", __func__);
+	uint16_t config1, config2, config3;
+	uint32_t ocp_data;
+
+	ocp_data = ocp_read_4(sc, MCU_TYPE_PLA, PLA_EEE_CR);
+	config1 = ocp_reg_read(sc, OCP_EEE_CONFIG1) & ~sd_rise_time_mask;
+	config2 = ocp_reg_read(sc, OCP_EEE_CONFIG2);
+	config3 = ocp_reg_read(sc, OCP_EEE_CONFIG3) & ~fast_snr_mask;
+
+	if (enable) {
+		ocp_data |= EEE_RX_EN | EEE_TX_EN;
+		config1 |= EEE_10_CAP | EEE_NWAY_EN | TX_QUIET_EN | RX_QUIET_EN;
+		//TODO: config1 |= sd_rise_time(1);
+		config2 |= RG_DACQUIET_EN | RG_LDVQUIET_EN;
+		//TODO: config3 |= fast_snr(42);
+	} else {
+		ocp_data &= ~(EEE_RX_EN | EEE_TX_EN);
+		config1 &= ~(EEE_10_CAP | EEE_NWAY_EN | TX_QUIET_EN |
+			     RX_QUIET_EN);
+		//TODO: config1 |= sd_rise_time(7);
+		config2 &= ~(RG_DACQUIET_EN | RG_LDVQUIET_EN);
+		//TODO: config3 |= fast_snr(511);
+	}
+
+	ocp_write_2(sc, MCU_TYPE_PLA, PLA_EEE_CR, ocp_data);
+	ocp_reg_write(sc, OCP_EEE_CONFIG1, config1);
+	ocp_reg_write(sc, OCP_EEE_CONFIG2, config2);
+	ocp_reg_write(sc, OCP_EEE_CONFIG3, config3);
+}
+
+static void
+r8152b_enable_eee(struct rtl_softc *sc)
+{
+	printf("[foo] %s\n", __func__);
+	#define MDIO_MMD_AN             7       /* Auto-Negotiation */
+	#define MDIO_AN_EEE_ADV         60      /* EEE advertisement */
+	#define MDIO_EEE_100TX          0x0002  /* Advertise 100TX EEE cap */
+	r8152_eee_en(sc, true);
+	r8152_mmd_write(sc, MDIO_MMD_AN, MDIO_AN_EEE_ADV, MDIO_EEE_100TX);
+}
+
+static void
+r8152b_enable_fc(struct rtl_softc *sc)
+{
+	uint16_t anar;
+
+	anar = r8152_mdio_read(sc, MII_ANAR);
+	anar |= ANAR_FC | ANAR_X_PAUSE_ASYM;
+	r8152_mdio_write(sc, MII_ANAR, anar);
+}
+
+static void
+rtl_tally_reset(struct rtl_softc *sc)
+{
+	printf("[foo] %s\n", __func__);
+	uint32_t ocp_data;
+
+	ocp_data = ocp_read_2(sc, MCU_TYPE_PLA, PLA_RSTTALLY);
+	ocp_data |= TALLY_RESET;
+	ocp_write_2(sc, MCU_TYPE_PLA, PLA_RSTTALLY, ocp_data);
+}
+
+
+static void
+rtl_init(struct usb_ether *ue)
+{
+	printf("[foo] %s\n", __func__);
+	struct rtl_softc *sc = uether_getsc(ue);
+	struct ifnet *ifp = uether_getifp(ue);
+	uint32_t ocp_data;
+
+	RTL_LOCK_ASSERT(sc, MA_OWNED);
+
+	/*
+	 * Cancel pending I/O
+	 */
+	//rtl_stop(ue);
+
+	/* Load the promiscuous & multicast filter */
+	rtl_setpromisc_and_multi(ue);
+
+	/*
+	 * Set the initial TX and RX configuration.
+	 */
+	r8152b_disable_aldps(sc);
+
+	if (sc->version == RTL_VER_01) {
+		ocp_data = ocp_read_2(sc, MCU_TYPE_PLA, PLA_LED_FEATURE);
+		ocp_data &= ~LED_MODE_MASK;
+		ocp_write_2(sc, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data);
+	}
+
+	/*
+	 * Enable RX and TX 
+	 */
+	r8152_power_cut_en(sc, false);
+
+	ocp_data = ocp_read_2(sc, MCU_TYPE_PLA, PLA_PHY_PWR);
+	ocp_data |= TX_10M_IDLE_EN | PFM_PWM_SWITCH;
+	ocp_write_2(sc, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data);
+
+	ocp_data = ocp_read_4(sc, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL);
+	ocp_data &= ~MCU_CLK_RATIO_MASK;
+	ocp_data |= MCU_CLK_RATIO | D3_CLK_GATED_EN;
+	ocp_write_4(sc, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL, ocp_data);
+
+	ocp_data = GPHY_STS_MSK | SPEED_DOWN_MSK |
+		   SPDWN_RXDV_MSK | SPDWN_LINKCHG_MSK;
+	ocp_write_4(sc, MCU_TYPE_PLA, PLA_GPHY_INTR_IMR, ocp_data);
+
+	//r8152b_enable_eee(sc);
+	r8152b_enable_aldps(sc);
+	r8152b_enable_fc(sc);
+	rtl_tally_reset(sc);
+
+	/* enable rx aggregation */
+	ocp_data = ocp_read_2(sc, MCU_TYPE_USB, USB_USB_CTRL);
+	ocp_data &= ~RX_AGG_DISABLE;
+	ocp_write_2(sc, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
+
+	ifp->if_drv_flags |= IFF_DRV_RUNNING;
+
+	rtl8152_up(sc);
+
+	rtl_start(ue);
+}
+
+/*
+ * Set media options.
+ */
+static int
+rtl_ifmedia_upd(struct ifnet *ifp)
+{
+	printf("[foo] %s\n", __func__);
+	struct rtl_softc *sc = ifp->if_softc;
+	struct mii_data *mii = GET_MII(sc);
+	struct mii_softc *miisc;
+	int error;
+
+	RTL_LOCK_ASSERT(sc, MA_OWNED);
+
+        sc->sc_flags &= ~RTL_FLAG_LINK;
+	LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
+		PHY_RESET(miisc);
+	error = mii_mediachg(mii);
+	return (error);
+}
+
+/*
+ * Report current media status.
+ */
+static void
+rtl_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+	printf("[foo] %s\n", __func__);
+	struct rtl_softc *sc = ifp->if_softc;
+	struct mii_data *mii = GET_MII(sc);
+
+	RTL_LOCK(sc);
+	mii_pollstat(mii);
+	ifmr->ifm_active = mii->mii_media_active;
+	ifmr->ifm_status = mii->mii_media_status;
+	RTL_UNLOCK(sc);
+}
+
+static void
+rtl_start(struct usb_ether *ue)
+{
+	printf("[foo] %s\n", __func__);
+	struct rtl_softc *sc = uether_getsc(ue);
+
+	/*
+	 * start the USB transfers, if not already started:
+	 */
+	usbd_transfer_start(sc->sc_xfer[RTL_INTR_DT_RD]);
+	usbd_transfer_start(sc->sc_xfer[RTL_BULK_DT_RD]);
+	usbd_transfer_start(sc->sc_xfer[RTL_BULK_DT_WR]);
+}
+
+static void
+rtl_stop(struct usb_ether *ue)
+{
+	printf("[foo] %s\n", __func__);
+	struct rtl_softc *sc = uether_getsc(ue);
+	struct ifnet *ifp = uether_getifp(ue);
+
+	RTL_LOCK_ASSERT(sc, MA_OWNED);
+
+	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
+	sc->sc_flags &= ~RTL_FLAG_LINK;
+
+	/*
+	 * stop all the transfers, if not already stopped:
+	 */
+	usbd_transfer_stop(sc->sc_xfer[RTL_BULK_DT_WR]);
+	usbd_transfer_stop(sc->sc_xfer[RTL_BULK_DT_RD]);
+	usbd_transfer_stop(sc->sc_xfer[RTL_INTR_DT_RD]);
+
+	rtl8152_down(sc);
+
+	rtl_reset(sc);
+}
Index: /freebsd-rtl-driver/if_rtlreg.h
===================================================================
--- /freebsd-rtl-driver/if_rtlreg.h	(revision 384)
+++ /freebsd-rtl-driver/if_rtlreg.h	(revision 384)
@@ -0,0 +1,686 @@
+/*-
+ * Copyright (c) 2010, 2011 Rick van der Zwet <info@rickvanderzwet.nl>
+ *
+ * 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) 2001-2003, Shunsuke Akiyama <akiyama@FreeBSD.org>.
+ * 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: release/10.1.0/sys/dev/usb/net/if_rtlreg.h 215335 2010-11-15 06:04:25Z kevlo $
+ */
+
+#define	RTL_CONFIG_IDX		0	/* config number 1 */
+#define	RTL_IFACE_IDX		0
+
+#define	RTL_INTR_PKTLEN		0x8
+
+#define	RTL_TIMEOUT		50
+#define	RTL_MIN_FRAMELEN	60
+
+/* Registers. */
+#define	RTL_IDR0		0x0120
+#define	RTL_IDR1		0x0121
+#define	RTL_IDR2		0x0122
+#define	RTL_IDR3		0x0123
+#define	RTL_IDR4		0x0124
+#define	RTL_IDR5		0x0125
+
+#define	RTL_MAR0		0x0126
+#define	RTL_MAR1		0x0127
+#define	RTL_MAR2		0x0128
+#define	RTL_MAR3		0x0129
+#define	RTL_MAR4		0x012A
+#define	RTL_MAR5		0x012B
+#define	RTL_MAR6		0x012C
+#define	RTL_MAR7		0x012D
+
+#define	RTL_CR			0x012E	/* B, R/W */
+#define	RTL_CR_SOFT_RST		0x10
+#define	RTL_CR_RE		0x08
+#define	RTL_CR_TE		0x04
+#define	RTL_CR_EP3CLREN		0x02
+
+#define	RTL_TCR			0x012F	/* B, R/W */
+#define	RTL_TCR_TXRR1		0x80
+#define	RTL_TCR_TXRR0		0x40
+#define	RTL_TCR_IFG1		0x10
+#define	RTL_TCR_IFG0		0x08
+#define	RTL_TCR_NOCRC		0x01
+#define	RTL_TCR_CONFIG		(RTL_TCR_TXRR1 | RTL_TCR_TXRR0 | 	\
+				    RTL_TCR_IFG1 | RTL_TCR_IFG0)
+
+#define	RTL_RCR			0x0130	/* W, R/W */
+#define	RTL_RCR_TAIL		0x80
+#define	RTL_RCR_AER		0x40
+#define	RTL_RCR_AR		0x20
+#define	RTL_RCR_AM		0x10
+#define	RTL_RCR_AB		0x08
+#define	RTL_RCR_AD		0x04
+#define	RTL_RCR_AAM		0x02
+#define	RTL_RCR_AAP		0x01
+#define	RTL_RCR_CONFIG		(RTL_RCR_TAIL | RTL_RCR_AD)
+
+#define	RTL_TSR			0x0132
+#define	RTL_RSR			0x0133
+#define	RTL_CON0		0x0135
+#define	RTL_CON1		0x0136
+#define	RTL_MSR			0x0137
+#define	RTL_PHYADD		0x0138
+#define	RTL_PHYDAT		0x0139
+
+#define	RTL_PHYCNT		0x013B	/* B, R/W */
+#define	RTL_PHYCNT_PHYOWN	0x40
+#define	RTL_PHYCNT_RWCR		0x20
+
+#define	RTL_GPPC		0x013D
+#define	RTL_WAKECNT		0x013E
+
+#define	RTL_BMCR		0x0140
+#define	RTL_BMCR_SPD_SET	0x2000
+#define	RTL_BMCR_DUPLEX		0x0100
+
+#define	RTL_BMSR		0x0142
+
+#define	RTL_ANAR		0x0144	/* W, R/W */
+#define	RTL_ANAR_PAUSE		0x0400
+
+#define	RTL_ANLP		0x0146	/* W, R/O */
+#define	RTL_ANLP_PAUSE		0x0400
+
+#define	RTL_AER			0x0148
+
+#define	RTL_NWAYT		0x014A
+#define	RTL_CSCR		0x014C
+
+#define	RTL_CRC0		0x014E
+#define	RTL_CRC1		0x0150
+#define	RTL_CRC2		0x0152
+#define	RTL_CRC3		0x0154
+#define	RTL_CRC4		0x0156
+
+#define	RTL_BYTEMASK0		0x0158
+#define	RTL_BYTEMASK1		0x0160
+#define	RTL_BYTEMASK2		0x0168
+#define	RTL_BYTEMASK3		0x0170
+#define	RTL_BYTEMASK4		0x0178
+
+#define	RTL_PHY1		0x0180
+#define	RTL_PHY2		0x0184
+
+#define	RTL_TW1			0x0186
+
+#define	RTL_REG_MIN		0x0120
+#define	RTL_REG_MAX		0x0189
+
+/* EEPROM address declarations. */
+#define	RTL_EEPROM_BASE		0x1200
+#define	RTL_EEPROM_IDR0		(RTL_EEPROM_BASE + 0x02)
+#define	RTL_EEPROM_IDR1		(RTL_EEPROM_BASE + 0x03)
+#define	RTL_EEPROM_IDR2		(RTL_EEPROM_BASE + 0x03)
+#define	RTL_EEPROM_IDR3		(RTL_EEPROM_BASE + 0x03)
+#define	RTL_EEPROM_IDR4		(RTL_EEPROM_BASE + 0x03)
+#define	RTL_EEPROM_IDR5		(RTL_EEPROM_BASE + 0x03)
+#define	RTL_EEPROM_INTERVAL	(RTL_EEPROM_BASE + 0x17)
+
+#define	RTL_RXSTAT_VALID	(0x01 << 12)
+#define	RTL_RXSTAT_RUNT		(0x02 << 12)
+#define	RTL_RXSTAT_PMATCH	(0x04 << 12)
+#define	RTL_RXSTAT_MCAST	(0x08 << 12)
+
+/* New entries (imported from r8152.c) */
+#define R8152_PHY_ID		32
+
+#define PLA_IDR			0xc000
+#define PLA_RCR			0xc010
+#define PLA_RMS			0xc016
+#define PLA_RXFIFO_CTRL0	0xc0a0
+#define PLA_RXFIFO_CTRL1	0xc0a4
+#define PLA_RXFIFO_CTRL2	0xc0a8
+#define PLA_FMC			0xc0b4
+#define PLA_CFG_WOL		0xc0b6
+#define PLA_TEREDO_CFG		0xc0bc
+#define PLA_MAR			0xcd00
+#define PLA_BACKUP		0xd000
+#define PAL_BDC_CR		0xd1a0
+#define PLA_TEREDO_TIMER	0xd2cc
+#define PLA_REALWOW_TIMER	0xd2e8
+#define PLA_LEDSEL		0xdd90
+#define PLA_LED_FEATURE		0xdd92
+#define PLA_PHYAR		0xde00
+#define PLA_BOOT_CTRL		0xe004
+#define PLA_GPHY_INTR_IMR	0xe022
+#define PLA_EEE_CR		0xe040
+#define PLA_EEEP_CR		0xe080
+#define PLA_MAC_PWR_CTRL	0xe0c0
+#define PLA_MAC_PWR_CTRL2	0xe0ca
+#define PLA_MAC_PWR_CTRL3	0xe0cc
+#define PLA_MAC_PWR_CTRL4	0xe0ce
+#define PLA_WDT6_CTRL		0xe428
+#define PLA_TCR0		0xe610
+#define PLA_TCR1		0xe612
+#define PLA_MTPS		0xe615
+#define PLA_TXFIFO_CTRL		0xe618
+#define PLA_RSTTALLY		0xe800
+#define PLA_CR			0xe813
+#define PLA_CRWECR		0xe81c
+#define PLA_CONFIG12		0xe81e	/* CONFIG1, CONFIG2 */
+#define PLA_CONFIG34		0xe820	/* CONFIG3, CONFIG4 */
+#define PLA_CONFIG5		0xe822
+#define PLA_PHY_PWR		0xe84c
+#define PLA_OOB_CTRL		0xe84f
+#define PLA_CPCR		0xe854
+#define PLA_MISC_0		0xe858
+#define PLA_MISC_1		0xe85a
+#define PLA_OCP_GPHY_BASE	0xe86c
+#define PLA_TALLYCNT		0xe890
+#define PLA_SFF_STS_7		0xe8de
+#define PLA_PHYSTATUS		0xe908
+#define PLA_BP_BA		0xfc26
+#define PLA_BP_0		0xfc28
+#define PLA_BP_1		0xfc2a
+#define PLA_BP_2		0xfc2c
+#define PLA_BP_3		0xfc2e
+#define PLA_BP_4		0xfc30
+#define PLA_BP_5		0xfc32
+#define PLA_BP_6		0xfc34
+#define PLA_BP_7		0xfc36
+#define PLA_BP_EN		0xfc38
+
+#define USB_U2P3_CTRL		0xb460
+#define USB_DEV_STAT		0xb808
+#define USB_USB_CTRL		0xd406
+#define USB_PHY_CTRL		0xd408
+#define USB_TX_AGG		0xd40a
+#define USB_RX_BUF_TH		0xd40c
+#define USB_USB_TIMER		0xd428
+#define USB_RX_EARLY_AGG	0xd42c
+#define USB_PM_CTRL_STATUS	0xd432
+#define USB_TX_DMA		0xd434
+#define USB_TOLERANCE		0xd490
+#define USB_LPM_CTRL		0xd41a
+#define USB_UPS_CTRL		0xd800
+#define USB_MISC_0		0xd81a
+#define USB_POWER_CUT		0xd80a
+#define USB_AFE_CTRL2		0xd824
+#define USB_WDT11_CTRL		0xe43c
+#define USB_BP_BA		0xfc26
+#define USB_BP_0		0xfc28
+#define USB_BP_1		0xfc2a
+#define USB_BP_2		0xfc2c
+#define USB_BP_3		0xfc2e
+#define USB_BP_4		0xfc30
+#define USB_BP_5		0xfc32
+#define USB_BP_6		0xfc34
+#define USB_BP_7		0xfc36
+#define USB_BP_EN		0xfc38
+
+/* OCP Registers */
+#define OCP_ALDPS_CONFIG	0x2010
+#define OCP_EEE_CONFIG1		0x2080
+#define OCP_EEE_CONFIG2		0x2092
+#define OCP_EEE_CONFIG3		0x2094
+#define OCP_BASE_MII		0xa400
+#define OCP_EEE_AR		0xa41a
+#define OCP_EEE_DATA		0xa41c
+#define OCP_PHY_STATUS		0xa420
+#define OCP_POWER_CFG		0xa430
+#define OCP_EEE_CFG		0xa432
+#define OCP_SRAM_ADDR		0xa436
+#define OCP_SRAM_DATA		0xa438
+#define OCP_DOWN_SPEED		0xa442
+#define OCP_EEE_ABLE		0xa5c4
+#define OCP_EEE_ADV		0xa5d0
+#define OCP_EEE_LPABLE		0xa5d2
+#define OCP_ADC_CFG		0xbc06
+
+/* SRAM Register */
+#define SRAM_LPF_CFG		0x8012
+#define SRAM_10M_AMP1		0x8080
+#define SRAM_10M_AMP2		0x8082
+#define SRAM_IMPEDANCE		0x8084
+
+/* PLA_RCR */
+#define RCR_AAP			0x00000001
+#define RCR_APM			0x00000002
+#define RCR_AM			0x00000004
+#define RCR_AB			0x00000008
+#define RCR_ACPT_ALL		(RCR_AAP | RCR_APM | RCR_AM | RCR_AB)
+
+/* PLA_RXFIFO_CTRL0 */
+#define RXFIFO_THR1_NORMAL	0x00080002
+#define RXFIFO_THR1_OOB		0x01800003
+
+/* PLA_RXFIFO_CTRL1 */
+#define RXFIFO_THR2_FULL	0x00000060
+#define RXFIFO_THR2_HIGH	0x00000038
+#define RXFIFO_THR2_OOB		0x0000004a
+#define RXFIFO_THR2_NORMAL	0x00a0
+
+/* PLA_RXFIFO_CTRL2 */
+#define RXFIFO_THR3_FULL	0x00000078
+#define RXFIFO_THR3_HIGH	0x00000048
+#define RXFIFO_THR3_OOB		0x0000005a
+#define RXFIFO_THR3_NORMAL	0x0110
+
+/* PLA_TXFIFO_CTRL */
+#define TXFIFO_THR_NORMAL	0x00400008
+#define TXFIFO_THR_NORMAL2	0x01000008
+
+/* PLA_FMC */
+#define FMC_FCR_MCU_EN		0x0001
+
+/* PLA_EEEP_CR */
+#define EEEP_CR_EEEP_TX		0x0002
+
+/* PLA_WDT6_CTRL */
+#define WDT6_SET_MODE		0x0010
+
+/* PLA_TCR0 */
+#define TCR0_TX_EMPTY		0x0800
+#define TCR0_AUTO_FIFO		0x0080
+
+/* PLA_TCR1 */
+#define VERSION_MASK		0x7cf0
+
+/* PLA_MTPS */
+#define MTPS_JUMBO		(12 * 1024 / 64)
+#define MTPS_DEFAULT		(6 * 1024 / 64)
+
+/* PLA_RSTTALLY */
+#define TALLY_RESET		0x0001
+
+/* PLA_CR */
+#define CR_RST			0x10
+#define CR_RE			0x08
+#define CR_TE			0x04
+
+/* PLA_CRWECR */
+#define CRWECR_NORAML		0x00
+#define CRWECR_CONFIG		0xc0
+
+/* PLA_OOB_CTRL */
+#define NOW_IS_OOB		0x80
+#define TXFIFO_EMPTY		0x20
+#define RXFIFO_EMPTY		0x10
+#define LINK_LIST_READY		0x02
+#define DIS_MCU_CLROOB		0x01
+#define FIFO_EMPTY		(TXFIFO_EMPTY | RXFIFO_EMPTY)
+
+/* PLA_MISC_1 */
+#define RXDY_GATED_EN		0x0008
+
+/* PLA_SFF_STS_7 */
+#define RE_INIT_LL		0x8000
+#define MCU_BORW_EN		0x4000
+
+/* PLA_CPCR */
+#define CPCR_RX_VLAN		0x0040
+
+/* PLA_CFG_WOL */
+#define MAGIC_EN		0x0001
+
+/* PLA_TEREDO_CFG */
+#define TEREDO_SEL		0x8000
+#define TEREDO_WAKE_MASK	0x7f00
+#define TEREDO_RS_EVENT_MASK	0x00fe
+#define OOB_TEREDO_EN		0x0001
+
+/* PAL_BDC_CR */
+#define ALDPS_PROXY_MODE	0x0001
+
+/* PLA_CONFIG34 */
+#define LINK_ON_WAKE_EN		0x0010
+#define LINK_OFF_WAKE_EN	0x0008
+
+/* PLA_CONFIG5 */
+#define BWF_EN			0x0040
+#define MWF_EN			0x0020
+#define UWF_EN			0x0010
+#define LAN_WAKE_EN		0x0002
+
+/* PLA_LED_FEATURE */
+#define LED_MODE_MASK		0x0700
+
+/* PLA_PHY_PWR */
+#define TX_10M_IDLE_EN		0x0080
+#define PFM_PWM_SWITCH		0x0040
+
+/* PLA_MAC_PWR_CTRL */
+#define D3_CLK_GATED_EN		0x00004000
+#define MCU_CLK_RATIO		0x07010f07
+#define MCU_CLK_RATIO_MASK	0x0f0f0f0f
+#define ALDPS_SPDWN_RATIO	0x0f87
+
+/* PLA_MAC_PWR_CTRL2 */
+#define EEE_SPDWN_RATIO		0x8007
+
+/* PLA_MAC_PWR_CTRL3 */
+#define PKT_AVAIL_SPDWN_EN	0x0100
+#define SUSPEND_SPDWN_EN	0x0004
+#define U1U2_SPDWN_EN		0x0002
+#define L1_SPDWN_EN		0x0001
+
+/* PLA_MAC_PWR_CTRL4 */
+#define PWRSAVE_SPDWN_EN	0x1000
+#define RXDV_SPDWN_EN		0x0800
+#define TX10MIDLE_EN		0x0100
+#define TP100_SPDWN_EN		0x0020
+#define TP500_SPDWN_EN		0x0010
+#define TP1000_SPDWN_EN		0x0008
+#define EEE_SPDWN_EN		0x0001
+
+/* PLA_GPHY_INTR_IMR */
+#define GPHY_STS_MSK		0x0001
+#define SPEED_DOWN_MSK		0x0002
+#define SPDWN_RXDV_MSK		0x0004
+#define SPDWN_LINKCHG_MSK	0x0008
+
+/* PLA_PHYAR */
+#define PHYAR_FLAG		0x80000000
+
+/* PLA_EEE_CR */
+#define EEE_RX_EN		0x0001
+#define EEE_TX_EN		0x0002
+
+/* PLA_BOOT_CTRL */
+#define AUTOLOAD_DONE		0x0002
+
+/* USB_DEV_STAT */
+#define STAT_SPEED_MASK		0x0006
+#define STAT_SPEED_HIGH		0x0000
+#define STAT_SPEED_FULL		0x0002
+
+/* USB_TX_AGG */
+#define TX_AGG_MAX_THRESHOLD	0x03
+
+/* USB_RX_BUF_TH */
+#define RX_THR_SUPPER		0x0c350180
+#define RX_THR_HIGH		0x7a120180
+#define RX_THR_SLOW		0xffff0180
+
+/* USB_TX_DMA */
+#define TEST_MODE_DISABLE	0x00000001
+#define TX_SIZE_ADJUST1		0x00000100
+
+/* USB_UPS_CTRL */
+#define POWER_CUT		0x0100
+
+/* USB_PM_CTRL_STATUS */
+#define RESUME_INDICATE		0x0001
+
+/* USB_USB_CTRL */
+#define RX_AGG_DISABLE		0x0010
+
+/* USB_U2P3_CTRL */
+#define U2P3_ENABLE		0x0001
+
+/* USB_POWER_CUT */
+#define PWR_EN			0x0001
+#define PHASE2_EN		0x0008
+
+/* USB_MISC_0 */
+#define PCUT_STATUS		0x0001
+
+/* USB_RX_EARLY_AGG */
+#define EARLY_AGG_SUPPER	0x0e832981
+#define EARLY_AGG_HIGH		0x0e837a12
+#define EARLY_AGG_SLOW		0x0e83ffff
+
+/* USB_WDT11_CTRL */
+#define TIMER11_EN		0x0001
+
+/* USB_LPM_CTRL */
+#define LPM_TIMER_MASK		0x0c
+#define LPM_TIMER_500MS		0x04	/* 500 ms */
+#define LPM_TIMER_500US		0x0c	/* 500 us */
+
+/* USB_AFE_CTRL2 */
+#define SEN_VAL_MASK		0xf800
+#define SEN_VAL_NORMAL		0xa000
+#define SEL_RXIDLE		0x0100
+
+/* OCP_ALDPS_CONFIG */
+#define ENPWRSAVE		0x8000
+#define ENPDNPS			0x0200
+#define LINKENA			0x0100
+#define DIS_SDSAVE		0x0010
+
+/* OCP_PHY_STATUS */
+#define PHY_STAT_MASK		0x0007
+#define PHY_STAT_LAN_ON		3
+#define PHY_STAT_PWRDN		5
+
+/* OCP_POWER_CFG */
+#define EEE_CLKDIV_EN		0x8000
+#define EN_ALDPS		0x0004
+#define EN_10M_PLLOFF		0x0001
+
+/* OCP_EEE_CONFIG1 */
+#define RG_TXLPI_MSK_HFDUP	0x8000
+#define RG_MATCLR_EN		0x4000
+#define EEE_10_CAP		0x2000
+#define EEE_NWAY_EN		0x1000
+#define TX_QUIET_EN		0x0200
+#define RX_QUIET_EN		0x0100
+#define sd_rise_time_mask	0x0070
+#define sd_rise_time(x)		(min(x, 7) << 4)	/* bit 4 ~ 6 */
+#define RG_RXLPI_MSK_HFDUP	0x0008
+#define SDFALLTIME		0x0007	/* bit 0 ~ 2 */
+
+/* OCP_EEE_CONFIG2 */
+#define RG_LPIHYS_NUM		0x7000	/* bit 12 ~ 15 */
+#define RG_DACQUIET_EN		0x0400
+#define RG_LDVQUIET_EN		0x0200
+#define RG_CKRSEL		0x0020
+#define RG_EEEPRG_EN		0x0010
+
+/* OCP_EEE_CONFIG3 */
+#define fast_snr_mask		0xff80
+#define fast_snr(x)		(min(x, 0x1ff) << 7)	/* bit 7 ~ 15 */
+#define RG_LFS_SEL		0x0060	/* bit 6 ~ 5 */
+#define MSK_PH			0x0006	/* bit 0 ~ 3 */
+
+/* OCP_EEE_AR */
+/* bit[15:14] function */
+#define FUN_ADDR		0x0000
+#define FUN_DATA		0x4000
+/* bit[4:0] device addr */
+
+/* OCP_EEE_CFG */
+#define CTAP_SHORT_EN		0x0040
+#define EEE10_EN		0x0010
+
+/* OCP_DOWN_SPEED */
+#define EN_10M_BGOFF		0x0080
+
+/* OCP_ADC_CFG */
+#define CKADSEL_L		0x0100
+#define ADC_EN			0x0080
+#define EN_EMI_L		0x0040
+
+/* SRAM_LPF_CFG */
+#define LPF_AUTO_TUNE		0x8000
+
+/* SRAM_10M_AMP1 */
+#define GDAC_IB_UPALL		0x0008
+
+/* SRAM_10M_AMP2 */
+#define AMP_DN			0x0200
+
+/* SRAM_IMPEDANCE */
+#define RX_DRIVING_MASK		0x6000
+
+enum rtl_register_content {
+	_1000bps	= 0x10,
+	_100bps		= 0x08,
+	_10bps		= 0x04,
+	LINK_STATUS	= 0x02,
+	FULL_DUP	= 0x01,
+};
+
+#define RTL8152_MAX_TX		4
+#define RTL8152_MAX_RX		10
+#define INTBUFSIZE		2
+#define CRC_SIZE		4
+#define TX_ALIGN		4
+#define RX_ALIGN		8
+
+#define INTR_LINK		0x0004
+
+#define RTL8152_REQT_READ	0xc0
+#define RTL8152_REQT_WRITE	0x40
+#define RTL8152_REQ_GET_REGS	0x05
+#define RTL8152_REQ_SET_REGS	0x05
+
+#define BYTE_EN_DWORD		0xff
+#define BYTE_EN_WORD		0x33
+#define BYTE_EN_BYTE		0x11
+#define BYTE_EN_SIX_BYTES	0x3f
+#define BYTE_EN_START_MASK	0x0f
+#define BYTE_EN_END_MASK	0xf0
+
+#define VLAN_ETH_FRAME_LEN	1518    /* Max. octets in frame sans FCS */
+#define VLAN_HLEN		4       /* The additional bytes (on top of the Ethernet header) that VLAN requires.*/
+
+#define RTL8153_MAX_PACKET	9216 /* 9K */
+#define RTL8153_MAX_MTU		(RTL8153_MAX_PACKET - VLAN_ETH_HLEN - VLAN_HLEN)
+#define RTL8152_RMS		(VLAN_ETH_FRAME_LEN + VLAN_HLEN)
+#define RTL8153_RMS		RTL8153_MAX_PACKET
+#define RTL8152_TX_TIMEOUT	(5 * HZ)
+
+#define MCU_TYPE_PLA		0x0100
+#define MCU_TYPE_USB		0x0000
+
+#define BYTE_EN_DWORD		0xff
+#define BYTE_EN_WORD		0x33
+#define BYTE_EN_BYTE		0x11
+#define BYTE_EN_SIX_BYTES	0x3f
+#define BYTE_EN_START_MASK	0x0f
+#define BYTE_EN_END_MASK	0xf0
+/* End new entries */
+
+
+#define	GET_MII(sc)		uether_getmii(&(sc)->sc_ue)
+
+struct rtl_intrpkt {
+	uint8_t	rtl_tsr;
+	uint8_t	rtl_rsr;
+	uint8_t	rtl_gep_msr;
+	uint8_t	rtl_waksr;
+	uint8_t	rtl_txok_cnt;
+	uint8_t	rtl_rxlost_cnt;
+	uint8_t	rtl_crcerr_cnt;
+	uint8_t	rtl_col_cnt;
+} __packed;
+
+struct rx_desc {
+	uint32_t opts1;
+#define RX_LEN_MASK			0x7fff
+
+	uint32_t opts2;
+#define RD_UDP_CS			(1 << 23)
+#define RD_TCP_CS			(1 << 22)
+#define RD_IPV6_CS			(1 << 20)
+#define RD_IPV4_CS			(1 << 19)
+
+	uint32_t opts3;
+#define IPF				(1 << 23) /* IP checksum fail */
+#define UDPF				(1 << 22) /* UDP checksum fail */
+#define TCPF				(1 << 21) /* TCP checksum fail */
+#define RX_VLAN_TAG			(1 << 16)
+
+	uint32_t opts4;
+	uint32_t opts5;
+	uint32_t opts6;
+};
+
+struct tx_desc {
+	uint32_t opts1;
+#define TX_FS			(1 << 31) /* First segment of a packet */
+#define TX_LS			(1 << 30) /* Final segment of a packet */
+#define GTSENDV4		(1 << 28)
+#define GTSENDV6		(1 << 27)
+#define GTTCPHO_SHIFT		18
+#define GTTCPHO_MAX		0x7fU
+#define TX_LEN_MAX		0x3ffffU
+
+	uint32_t opts2;
+#define UDP_CS			(1 << 31) /* Calculate UDP/IP checksum */
+#define TCP_CS			(1 << 30) /* Calculate TCP/IP checksum */
+#define IPV4_CS			(1 << 29) /* Calculate IPv4 checksum */
+#define IPV6_CS			(1 << 28) /* Calculate IPv6 checksum */
+#define MSS_SHIFT		17
+#define MSS_MAX			0x7ffU
+#define TCPHO_SHIFT		17
+#define TCPHO_MAX		0x7ffU
+#define TX_VLAN_TAG			(1 << 16)
+};
+
+
+enum {
+	RTL_BULK_DT_RD,
+	RTL_BULK_DT_WR,
+	RTL_INTR_DT_RD,
+	RTL_N_TRANSFER,
+};
+
+enum {
+	RTL_VER_UNKNOWN,
+	RTL_VER_01,
+	RTL_VER_02,
+	RTL_VER_03,
+	RTL_VER_04,
+	RTL_VER_05,
+	RTL_VER_MAX
+};
+
+struct rtl_softc {
+	struct usb_ether	sc_ue;
+	struct mtx		sc_mtx;
+	struct usb_xfer	*sc_xfer[RTL_N_TRANSFER];
+
+	//TODO: If this the right place for this variable?
+	uint16_t		ocp_base;
+	uint16_t		version;
+	uint32_t		saved_wolopts;
+	
+	int			sc_flags;
+#define	RTL_FLAG_LINK		0x0001
+};
+
+#define	RTL_LOCK(_sc)		mtx_lock(&(_sc)->sc_mtx)
+#define	RTL_UNLOCK(_sc)		mtx_unlock(&(_sc)->sc_mtx)
+#define	RTL_LOCK_ASSERT(_sc, t)	mtx_assert(&(_sc)->sc_mtx, t)
