I recently picked up a cheap Cherry View based mini-pc and found its onboard
RTL8152 (usb) ethernet wasn't supported, so I ported ure(4) from freebsd.

I'm fairly sure there are some endianness issues, but I can't test on a
big endian platform as this is the only hardware I have.  It also leaves the
chip in some terrible state where it can't be recognised after a reboot,
and you have to remove power before it'll work again.

Aside from those problems, the driver does actually work on amd64 so I'd like
to get it in the tree.


Index: files.usb
===================================================================
RCS file: /cvs/src/sys/dev/usb/files.usb,v
retrieving revision 1.128
diff -u -p -u -p -r1.128 files.usb
--- files.usb   15 Jun 2016 19:39:34 -0000      1.128
+++ files.usb   26 Jun 2016 09:56:29 -0000
@@ -270,6 +270,12 @@ device     url: ether, ifnet, mii
 attach url at uhub
 file   dev/usb/if_url.c                url
 
+# Realtek RTL8152
+device ure: ether, ifnet, mii
+attach ure at uhub
+file   dev/usb/if_ure.c                ure
+
+
 
 # Serial drivers
 # Modems
Index: if_ure.c
===================================================================
RCS file: if_ure.c
diff -N if_ure.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ if_ure.c    26 Jun 2016 09:56:29 -0000
@@ -0,0 +1,1283 @@
+/*-
+ * Copyright (c) 2015 Kevin Lo <[email protected]>
+ * 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.
+ */
+
+#include "bpfilter.h"
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sockio.h>
+#include <sys/rwlock.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/device.h>
+
+#include <machine/bus.h>
+
+#include <net/if.h>
+#include <net/if_media.h>
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include <dev/mii/miivar.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdi_util.h>
+#include <dev/usb/usbdivar.h>
+#include <dev/usb/usbdevs.h>
+
+#include "if_urereg.h"
+
+#ifdef URE_DEBUG
+#define DPRINTF(x)     do { if (uredebug) printf x; } while (0)
+#define DPRINTFN(n,x)  do { if (uredebug >= (n)) printf x; } while (0)
+int    uredebug = 0;
+#else
+#define DPRINTF(x)
+#define DPRINTFN(n,x)
+#endif
+
+
+const struct usb_devno ure_devs[] = {
+       { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8152 }
+};
+
+int    ure_match(struct device *, void *, void *);
+void   ure_attach(struct device *, struct device *, void *);
+int    ure_detach(struct device *, int);
+
+struct cfdriver ure_cd = {
+       NULL, "ure", DV_IFNET
+};
+
+const struct cfattach ure_ca = {
+       sizeof(struct ure_softc), ure_match, ure_attach, ure_detach
+};
+
+int            ure_ctl(struct ure_softc *, uint8_t, uint16_t, uint16_t,
+                   void *, int);
+int            ure_read_mem(struct ure_softc *, uint16_t, uint16_t, void *,
+                   int);
+int            ure_write_mem(struct ure_softc *, uint16_t, uint16_t, void *,
+                   int);
+uint8_t                ure_read_1(struct ure_softc *, uint16_t, uint16_t);
+uint16_t       ure_read_2(struct ure_softc *, uint16_t, uint16_t);
+uint32_t       ure_read_4(struct ure_softc *, uint16_t, uint16_t);
+int            ure_write_1(struct ure_softc *, uint16_t, uint16_t, uint32_t);
+int            ure_write_2(struct ure_softc *, uint16_t, uint16_t, uint32_t);
+int            ure_write_4(struct ure_softc *, uint16_t, uint16_t, uint32_t);
+uint16_t       ure_ocp_reg_read(struct ure_softc *, uint16_t);
+void           ure_ocp_reg_write(struct ure_softc *, uint16_t, uint16_t);
+
+void           ure_init(void *);
+void           ure_stop(struct ure_softc *);
+void           ure_start(struct ifnet *);
+void           ure_reset(struct ure_softc *);
+
+void           ure_miibus_statchg(struct device *);
+int            ure_miibus_readreg(struct device *, int, int);
+void           ure_miibus_writereg(struct device *, int, int, int);
+void           ure_lock_mii(struct ure_softc *);
+void           ure_unlock_mii(struct ure_softc *);
+
+int            ure_encap(struct ure_softc *, struct mbuf *, int);
+void           ure_rxeof(struct usbd_xfer *, void *, usbd_status);
+void           ure_txeof(struct usbd_xfer *, void *, usbd_status);
+int            ure_rx_list_init(struct ure_softc *);
+int            ure_tx_list_init(struct ure_softc *);
+struct mbuf *  ure_newbuf(void);
+
+void           ure_tick_task(void *);
+void           ure_tick(void *);
+
+int            ure_ifmedia_upd(struct ifnet *);
+void           ure_ifmedia_sts(struct ifnet *, struct ifmediareq *);
+int            ure_ioctl(struct ifnet *, u_long, caddr_t);
+void           ure_rtl8152_init(struct ure_softc *);
+void           ure_disable_teredo(struct ure_softc *);
+void           ure_init_fifo(struct ure_softc *);
+
+
+
+int
+ure_ctl(struct ure_softc *sc, uint8_t rw, uint16_t val, uint16_t index,
+    void *buf, int len)
+{
+       usb_device_request_t    req;
+       usbd_status             err;
+
+       if (usbd_is_dying(sc->ure_udev))
+               return 0;
+
+       if (rw == URE_CTL_WRITE)
+               req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
+       else
+               req.bmRequestType = UT_READ_VENDOR_DEVICE;
+       req.bRequest = UR_SET_ADDRESS;
+       USETW(req.wValue, val);
+       USETW(req.wIndex, index);
+       USETW(req.wLength, len);
+
+       DPRINTFN(5, ("ure_ctl: rw %d, val 0x%04hu, index 0x%04hu, len %d\n",
+           rw, val, index, len));
+       err = usbd_do_request(sc->ure_udev, &req, buf);
+       if (err) {
+               DPRINTF(("ure_ctl: error %d\n", err));
+               return -1;
+       }
+
+       return 0;
+}
+
+int
+ure_read_mem(struct ure_softc *sc, uint16_t addr, uint16_t index,
+    void *buf, int len)
+{
+
+       return (ure_ctl(sc, URE_CTL_READ, addr, index, buf, len));
+}
+
+int
+ure_write_mem(struct ure_softc *sc, uint16_t addr, uint16_t index,
+    void *buf, int len)
+{
+
+       return (ure_ctl(sc, URE_CTL_WRITE, addr, index, buf, len));
+}
+
+uint8_t
+ure_read_1(struct ure_softc *sc, uint16_t reg, uint16_t index)
+{
+       uint32_t val;
+       uint8_t temp[4];
+       uint8_t shift;
+
+       shift = (reg & 3) << 3;
+       reg &= ~3;
+       
+       ure_read_mem(sc, reg, index, &temp, 4);
+       val = UGETDW(temp);
+       val >>= shift;
+
+       return (val & 0xff);
+}
+
+uint16_t
+ure_read_2(struct ure_softc *sc, uint16_t reg, uint16_t index)
+{
+       uint32_t val;
+       uint8_t temp[4];
+       uint8_t shift;
+
+       shift = (reg & 2) << 3;
+       reg &= ~3;
+
+       ure_read_mem(sc, reg, index, &temp, 4);
+       val = UGETDW(temp);
+       val >>= shift;
+
+       return (val & 0xffff);
+}
+
+uint32_t
+ure_read_4(struct ure_softc *sc, uint16_t reg, uint16_t index)
+{
+       uint8_t temp[4];
+
+       ure_read_mem(sc, reg, index, &temp, 4);
+       return (UGETDW(temp));
+}
+
+int
+ure_write_1(struct ure_softc *sc, uint16_t reg, uint16_t index, uint32_t val)
+{
+       uint16_t byen;
+       uint8_t temp[4];
+       uint8_t shift;
+
+       byen = URE_BYTE_EN_BYTE;
+       shift = reg & 3;
+       val &= 0xff;
+
+       if (reg & 3) {
+               byen <<= shift;
+               val <<= (shift << 3);
+               reg &= ~3;
+       }
+
+       USETDW(temp, val);
+       return (ure_write_mem(sc, reg, index | byen, &temp, 4));
+}
+
+int
+ure_write_2(struct ure_softc *sc, uint16_t reg, uint16_t index, uint32_t val)
+{
+       uint16_t byen;
+       uint8_t temp[4];
+       uint8_t shift;
+
+       byen = URE_BYTE_EN_WORD;
+       shift = reg & 2;
+       val &= 0xffff;
+
+       if (reg & 2) {
+               byen <<= shift;
+               val <<= (shift << 3);
+               reg &= ~3;
+       }
+
+       USETDW(temp, val);
+       return (ure_write_mem(sc, reg, index | byen, &temp, 4));
+}
+
+int
+ure_write_4(struct ure_softc *sc, uint16_t reg, uint16_t index, uint32_t val)
+{
+       uint8_t temp[4];
+
+       USETDW(temp, val);
+       return (ure_write_mem(sc, reg, index | URE_BYTE_EN_DWORD, &temp, 4));
+}
+
+uint16_t
+ure_ocp_reg_read(struct ure_softc *sc, uint16_t addr)
+{
+       uint16_t reg;
+
+       ure_write_2(sc, URE_PLA_OCP_GPHY_BASE, URE_MCU_TYPE_PLA, addr & 0xf000);
+       reg = (addr & 0x0fff) | 0xb000;
+
+       return (ure_read_2(sc, reg, URE_MCU_TYPE_PLA));
+}
+
+void
+ure_ocp_reg_write(struct ure_softc *sc, uint16_t addr, uint16_t data)
+{
+       uint16_t reg;
+
+       ure_write_2(sc, URE_PLA_OCP_GPHY_BASE, URE_MCU_TYPE_PLA, addr & 0xf000);
+       reg = (addr & 0x0fff) | 0xb000;
+
+       ure_write_2(sc, reg, URE_MCU_TYPE_PLA, data);
+}
+
+int
+ure_miibus_readreg(struct device *dev, int phy, int reg)
+{
+       struct ure_softc        *sc = (void *)dev;
+       uint16_t                val;
+
+       if (usbd_is_dying(sc->ure_udev))
+               return 0;
+
+       if (sc->ure_phyno != phy)
+               return 0;
+
+       ure_lock_mii(sc);
+       val = ure_ocp_reg_read(sc, URE_OCP_BASE_MII + reg * 2);
+       ure_unlock_mii(sc);
+
+       return val;     /* letoh16? */
+}
+
+void
+ure_miibus_writereg(struct device *dev, int phy, int reg, int val)
+{
+       struct ure_softc        *sc = (void *)dev;
+
+       if (sc->ure_phyno != phy)
+               return;
+
+       ure_lock_mii(sc);
+       ure_ocp_reg_write(sc, URE_OCP_BASE_MII + reg * 2, val); /* htole16? */
+       ure_unlock_mii(sc);
+}
+
+void
+ure_miibus_statchg(struct device *dev)
+{
+       struct ure_softc        *sc = (void *)dev;
+       struct mii_data         *mii = &sc->ure_mii;
+       struct ifnet            *ifp = &sc->ure_ac.ac_if;
+
+       if ((ifp->if_flags & IFF_RUNNING) == 0)
+               return;
+
+       sc->ure_flags &= ~URE_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:
+                       sc->ure_flags |= URE_FLAG_LINK;
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+int
+ure_ifmedia_upd(struct ifnet *ifp)
+{
+       struct ure_softc *sc = ifp->if_softc;
+       struct mii_data *mii = &sc->ure_mii;
+       int err;
+
+       sc->ure_flags &= ~URE_FLAG_LINK;
+       if (mii->mii_instance) {
+               struct mii_softc *miisc;
+               LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
+                       PHY_RESET(miisc);
+       }
+
+       err = mii_mediachg(mii);
+       if (err == ENXIO)
+               return 0;
+       else
+               return err;
+}
+
+void
+ure_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+       struct ure_softc *sc = ifp->if_softc;
+       struct mii_data *mii = &sc->ure_mii;
+
+       mii_pollstat(mii);
+       ifmr->ifm_active = mii->mii_media_active;
+       ifmr->ifm_status = mii->mii_media_status;
+}
+
+void
+ure_iff(struct ure_softc *sc)
+{
+       struct ifnet            *ifp = &sc->ure_ac.ac_if;
+       struct ether_multi      *enm;
+       struct ether_multistep  step;
+       uint32_t                hashes[2] = { 0, 0 };
+       uint32_t                hash;
+       uint32_t                rxmode;
+
+       if (usbd_is_dying(sc->ure_udev))
+               return;
+
+       ifp->if_flags &= ~IFF_ALLMULTI;
+       rxmode = ure_read_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA);
+       if (ifp->if_flags & IFF_PROMISC || sc->ure_ac.ac_multirangecnt > 0) {
+               ifp->if_flags |= IFF_ALLMULTI;
+               if (ifp->if_flags & IFF_PROMISC)
+                       rxmode |= URE_RCR_AAP;
+               rxmode |= URE_RCR_AM;
+               hashes[0] = hashes[1] = 0xffffffff;
+       } else {
+               ETHER_FIRST_MULTI(step, &sc->ure_ac, enm);
+               while (enm != NULL) {
+                       hash = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN)
+                           >> 26;
+                       if (hash < 32)
+                               hashes[0] |= (1 << hash);
+                       else
+                               hashes[1] |= (1 << (hash - 32));
+
+                       ETHER_NEXT_MULTI(step, enm);
+               }
+
+               hash = swap32(hashes[0]);
+               hashes[0] = swap32(hashes[1]);
+               hashes[1] = hash;
+               rxmode |= URE_RCR_AM;
+       }
+
+       ure_write_4(sc, URE_PLA_MAR0, URE_MCU_TYPE_PLA, hashes[0]);
+       ure_write_4(sc, URE_PLA_MAR4, URE_MCU_TYPE_PLA, hashes[1]);
+       ure_write_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA, rxmode);
+}
+
+void
+ure_reset(struct ure_softc *sc)
+{
+       int i;
+
+       ure_write_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA, URE_CR_RST);
+
+       for (i = 0; i < URE_TIMEOUT; i++) {
+               if (!(ure_read_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA) &
+                   URE_CR_RST))
+                       break;
+               usbd_delay_ms(sc->ure_udev, 10);
+       }
+       if (i == URE_TIMEOUT)
+               printf("%s: reset never completed\n", sc->ure_dev.dv_xname);
+}
+
+void
+ure_init(void *xsc)
+{
+       struct ure_softc        *sc = xsc;
+       struct ure_chain        *c;
+       struct ifnet            *ifp = &sc->ure_ac.ac_if;
+       uint32_t                rxmode;
+       usbd_status             err;
+       int                     s, i;
+
+       s = splnet();
+
+       /* Cancel pending I/O. */
+       ure_stop(sc);
+
+       ure_reset(sc);
+
+       if (ure_rx_list_init(sc) == ENOBUFS) {
+               printf("%s: rx list init failed\n", sc->ure_dev.dv_xname);
+               splx(s);
+               return;
+       }
+
+       if (ure_tx_list_init(sc) == ENOBUFS) {
+               printf("%s: tx list init failed\n", sc->ure_dev.dv_xname);
+               splx(s);
+               return;
+       }
+
+       /* Set MAC address. */
+       ure_write_mem(sc, URE_PLA_IDR, URE_MCU_TYPE_PLA | URE_BYTE_EN_SIX_BYTES,
+           sc->ure_ac.ac_enaddr, 8);
+
+       /* Reset the packet filter. */
+       ure_write_2(sc, URE_PLA_FMC, URE_MCU_TYPE_PLA,
+           ure_read_2(sc, URE_PLA_FMC, URE_MCU_TYPE_PLA) &
+           ~URE_FMC_FCR_MCU_EN);
+       ure_write_2(sc, URE_PLA_FMC, URE_MCU_TYPE_PLA,
+           ure_read_2(sc, URE_PLA_FMC, URE_MCU_TYPE_PLA) |
+           URE_FMC_FCR_MCU_EN);
+           
+       /* Enable transmit and receive. */
+       ure_write_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA,
+           ure_read_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA) | URE_CR_RE |
+           URE_CR_TE);
+
+       ure_write_2(sc, URE_PLA_MISC_1, URE_MCU_TYPE_PLA,
+           ure_read_2(sc, URE_PLA_MISC_1, URE_MCU_TYPE_PLA) &
+           ~URE_RXDY_GATED_EN);
+
+       /* Set Rx mode. */
+       rxmode = URE_RCR_APM;
+
+       /* If we want promiscuous mode, set the allframes bit. */
+       if (ifp->if_flags & IFF_PROMISC)
+               rxmode |= URE_RCR_AAP;
+
+       if (ifp->if_flags & IFF_BROADCAST)
+               rxmode |= URE_RCR_AB;
+
+       ure_write_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA, rxmode);
+
+       /* Load the multicast filter. */
+       ure_iff(sc);
+
+       /* Open RX and TX pipes. */
+       err = usbd_open_pipe(sc->ure_iface, sc->ure_ed[URE_ENDPT_RX],
+           USBD_EXCLUSIVE_USE, &sc->ure_ep[URE_ENDPT_RX]);
+       if (err) {
+               printf("%s: open rx pipe failed: %s\n",
+                   sc->ure_dev.dv_xname, usbd_errstr(err));
+               splx(s);
+               return;
+       }
+
+       err = usbd_open_pipe(sc->ure_iface, sc->ure_ed[URE_ENDPT_TX],
+           USBD_EXCLUSIVE_USE, &sc->ure_ep[URE_ENDPT_TX]);
+       if (err) {
+               printf("%s: open tx pipe failed: %s\n",
+                   sc->ure_dev.dv_xname, usbd_errstr(err));
+               splx(s);
+               return;
+       }
+
+       /* Start up the receive pipe. */
+       for (i = 0; i < URE_RX_LIST_CNT; i++) {
+               c = &sc->ure_cdata.rx_chain[i];
+               usbd_setup_xfer(c->uc_xfer, sc->ure_ep[URE_ENDPT_RX],
+                   c, c->uc_buf, sc->ure_bufsz,
+                   USBD_SHORT_XFER_OK | USBD_NO_COPY,
+                   USBD_NO_TIMEOUT, ure_rxeof);
+               usbd_transfer(c->uc_xfer);
+       }
+
+       /* Indicate we are up and running. */
+       ifp->if_flags |= IFF_RUNNING;
+       ifq_clr_oactive(&ifp->if_snd);
+
+       timeout_add_sec(&sc->ure_stat_ch, 1);
+
+       splx(s);
+}
+
+void
+ure_start(struct ifnet *ifp)
+{
+       struct ure_softc        *sc = ifp->if_softc;
+       struct mbuf             *m_head = NULL;
+
+       if ((sc->ure_flags & URE_FLAG_LINK) == 0 ||
+           ifq_is_oactive(&ifp->if_snd)) {
+               return;
+       }
+
+       m_head = ifq_deq_begin(&ifp->if_snd);
+       if (m_head == NULL) {
+               return;
+       }
+
+       if (ure_encap(sc, m_head, 0)) {
+               ifq_deq_rollback(&ifp->if_snd, m_head);
+               ifq_set_oactive(&ifp->if_snd);
+               return;
+       }
+       ifq_deq_commit(&ifp->if_snd, m_head);
+
+#if NBPFILTER > 0
+       if (ifp->if_bpf)
+               bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
+#endif
+       ifq_set_oactive(&ifp->if_snd);
+}
+
+void
+ure_tick(void *xsc)
+{
+       struct ure_softc *sc = xsc;
+
+       if (sc == NULL)
+               return;
+
+       if (usbd_is_dying(sc->ure_udev))
+               return;
+
+       usb_add_task(sc->ure_udev, &sc->ure_tick_task);
+}
+
+void
+ure_stop(struct ure_softc *sc)
+{
+       usbd_status             err;
+       struct ifnet            *ifp;
+       int                     i;
+
+       ure_reset(sc);
+
+       ifp = &sc->ure_ac.ac_if;
+       ifp->if_timer = 0;
+       ifp->if_flags &= ~IFF_RUNNING;
+       ifq_clr_oactive(&ifp->if_snd);
+
+       timeout_del(&sc->ure_stat_ch);
+
+       if (sc->ure_ep[URE_ENDPT_RX] != NULL) {
+               usbd_abort_pipe(sc->ure_ep[URE_ENDPT_RX]);
+               err = usbd_close_pipe(sc->ure_ep[URE_ENDPT_RX]);
+               if (err) {
+                       printf("%s: close rx pipe failed: %s\n",
+                           sc->ure_dev.dv_xname, usbd_errstr(err));
+               }
+               sc->ure_ep[URE_ENDPT_RX] = NULL;
+       }
+
+       if (sc->ure_ep[URE_ENDPT_TX] != NULL) {
+               usbd_abort_pipe(sc->ure_ep[URE_ENDPT_TX]);
+               err = usbd_close_pipe(sc->ure_ep[URE_ENDPT_TX]);
+               if (err) {
+                       printf("%s: close tx pipe failed: %s\n",
+                           sc->ure_dev.dv_xname, usbd_errstr(err));
+               }
+               sc->ure_ep[URE_ENDPT_TX] = NULL;
+       }
+
+       for (i = 0; i < URE_RX_LIST_CNT; i++) {
+               if (sc->ure_cdata.rx_chain[i].uc_mbuf != NULL) {
+                       m_freem(sc->ure_cdata.rx_chain[i].uc_mbuf);
+                       sc->ure_cdata.rx_chain[i].uc_mbuf = NULL;
+               }
+               if (sc->ure_cdata.rx_chain[i].uc_xfer != NULL) {
+                       usbd_free_xfer(sc->ure_cdata.rx_chain[i].uc_xfer);
+                       sc->ure_cdata.rx_chain[i].uc_xfer = NULL;
+               }
+       }
+
+       for (i = 0; i < URE_TX_LIST_CNT; i++) {
+               if (sc->ure_cdata.tx_chain[i].uc_mbuf != NULL) {
+                       m_freem(sc->ure_cdata.tx_chain[i].uc_mbuf);
+                       sc->ure_cdata.tx_chain[i].uc_mbuf = NULL;
+               }
+               if (sc->ure_cdata.tx_chain[i].uc_xfer != NULL) {
+                       usbd_free_xfer(sc->ure_cdata.tx_chain[i].uc_xfer);
+                       sc->ure_cdata.tx_chain[i].uc_xfer = NULL;
+               }
+       }
+}
+
+void
+ure_rtl8152_init(struct ure_softc *sc)
+{
+       uint32_t pwrctrl;
+
+       /* Disable ALDPS. */
+       ure_ocp_reg_write(sc, URE_OCP_ALDPS_CONFIG, URE_ENPDNPS | URE_LINKENA |
+           URE_DIS_SDSAVE);
+       usbd_delay_ms(sc->ure_udev, 20);
+
+       if (sc->ure_chip & URE_CHIP_VER_4C00) {
+               ure_write_2(sc, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA,
+                   ure_read_2(sc, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA) &
+                   ~URE_LED_MODE_MASK);
+       }
+
+       ure_write_2(sc, URE_USB_UPS_CTRL, URE_MCU_TYPE_USB,
+           ure_read_2(sc, URE_USB_UPS_CTRL, URE_MCU_TYPE_USB) &
+           ~URE_POWER_CUT);
+       ure_write_2(sc, URE_USB_PM_CTRL_STATUS, URE_MCU_TYPE_USB,
+           ure_read_2(sc, URE_USB_PM_CTRL_STATUS, URE_MCU_TYPE_USB) &
+           ~URE_RESUME_INDICATE);
+
+       ure_write_2(sc, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA,
+           ure_read_2(sc, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA) |
+           URE_TX_10M_IDLE_EN | URE_PFM_PWM_SWITCH);
+       pwrctrl = ure_read_4(sc, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA);
+       pwrctrl &= ~URE_MCU_CLK_RATIO_MASK;
+       pwrctrl |= URE_MCU_CLK_RATIO | URE_D3_CLK_GATED_EN;
+       ure_write_4(sc, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA, pwrctrl);
+       ure_write_2(sc, URE_PLA_GPHY_INTR_IMR, URE_MCU_TYPE_PLA,
+           URE_GPHY_STS_MSK | URE_SPEED_DOWN_MSK | URE_SPDWN_RXDV_MSK |
+           URE_SPDWN_LINKCHG_MSK);
+
+       /* Disable Rx aggregation. */
+       ure_write_2(sc, URE_USB_USB_CTRL, URE_MCU_TYPE_USB,
+           ure_read_2(sc, URE_USB_USB_CTRL, URE_MCU_TYPE_USB) |
+           URE_RX_AGG_DISABLE);
+
+       /* Disable ALDPS. */
+       ure_ocp_reg_write(sc, URE_OCP_ALDPS_CONFIG, URE_ENPDNPS | URE_LINKENA |
+           URE_DIS_SDSAVE);
+       usbd_delay_ms(sc->ure_udev, 20);
+
+       ure_init_fifo(sc);
+
+       ure_write_1(sc, URE_USB_TX_AGG, URE_MCU_TYPE_USB,
+           URE_TX_AGG_MAX_THRESHOLD);
+       ure_write_4(sc, URE_USB_RX_BUF_TH, URE_MCU_TYPE_USB, URE_RX_THR_HIGH);
+       ure_write_4(sc, URE_USB_TX_DMA, URE_MCU_TYPE_USB,
+           URE_TEST_MODE_DISABLE | URE_TX_SIZE_ADJUST1);
+}
+
+void
+ure_disable_teredo(struct ure_softc *sc)
+{
+       ure_write_4(sc, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA,
+           ure_read_4(sc, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA) & 
+           ~(URE_TEREDO_SEL | URE_TEREDO_RS_EVENT_MASK | URE_OOB_TEREDO_EN));
+       ure_write_2(sc, URE_PLA_WDT6_CTRL, URE_MCU_TYPE_PLA,
+           URE_WDT6_SET_MODE);
+       ure_write_2(sc, URE_PLA_REALWOW_TIMER, URE_MCU_TYPE_PLA, 0);
+       ure_write_4(sc, URE_PLA_TEREDO_TIMER, URE_MCU_TYPE_PLA, 0);
+}
+
+void
+ure_init_fifo(struct ure_softc *sc)
+{
+       uint32_t rx_fifo1, rx_fifo2;
+       int i;
+
+       ure_write_2(sc, URE_PLA_MISC_1, URE_MCU_TYPE_PLA,
+           ure_read_2(sc, URE_PLA_MISC_1, URE_MCU_TYPE_PLA) |
+           URE_RXDY_GATED_EN);
+
+       ure_disable_teredo(sc);
+
+       ure_write_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA,
+           ure_read_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA) &
+           ~URE_RCR_ACPT_ALL);
+
+       ure_reset(sc);
+
+       ure_write_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA, 0);
+
+       ure_write_1(sc, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA,
+           ure_read_1(sc, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) &
+           ~URE_NOW_IS_OOB);
+
+       ure_write_2(sc, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA,
+           ure_read_2(sc, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) &
+           ~URE_MCU_BORW_EN);
+       for (i = 0; i < URE_TIMEOUT; i++) {
+               if (ure_read_1(sc, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) &
+                   URE_LINK_LIST_READY)
+                       break;
+               usbd_delay_ms(sc->ure_udev, 10);
+       }
+       if (i == URE_TIMEOUT)
+               printf("%s timeout waiting for OOB control\n",
+                   sc->ure_dev.dv_xname);
+       ure_write_2(sc, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA,
+           ure_read_2(sc, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) |
+           URE_RE_INIT_LL);
+       for (i = 0; i < URE_TIMEOUT; i++) {
+               if (ure_read_1(sc, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) &
+                   URE_LINK_LIST_READY)
+                       break;
+               usbd_delay_ms(sc->ure_udev, 10);
+       }
+       if (i == URE_TIMEOUT)
+               printf("%s: timeout waiting for OOB control\n",
+                   sc->ure_dev.dv_xname);
+
+       ure_write_2(sc, URE_PLA_CPCR, URE_MCU_TYPE_PLA,
+           ure_read_2(sc, URE_PLA_CPCR, URE_MCU_TYPE_PLA) &
+           ~URE_CPCR_RX_VLAN);
+       ure_write_2(sc, URE_PLA_TCR0, URE_MCU_TYPE_PLA,
+           ure_read_2(sc, URE_PLA_TCR0, URE_MCU_TYPE_PLA) |
+           URE_TCR0_AUTO_FIFO);
+
+       /* Configure Rx FIFO threshold and coalescing. */
+       ure_write_4(sc, URE_PLA_RXFIFO_CTRL0, URE_MCU_TYPE_PLA,
+           URE_RXFIFO_THR1_NORMAL);
+       if (sc->ure_udev->speed == USB_SPEED_FULL) {
+               rx_fifo1 = URE_RXFIFO_THR2_FULL;
+               rx_fifo2 = URE_RXFIFO_THR3_FULL;
+       } else {
+               rx_fifo1 = URE_RXFIFO_THR2_HIGH;
+               rx_fifo2 = URE_RXFIFO_THR3_HIGH;
+       }
+       ure_write_4(sc, URE_PLA_RXFIFO_CTRL1, URE_MCU_TYPE_PLA, rx_fifo1);
+       ure_write_4(sc, URE_PLA_RXFIFO_CTRL2, URE_MCU_TYPE_PLA, rx_fifo2);
+
+       /* Configure Tx FIFO threshold. */
+       ure_write_4(sc, URE_PLA_TXFIFO_CTRL, URE_MCU_TYPE_PLA,
+           URE_TXFIFO_THR_NORMAL);
+}
+
+int
+ure_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+       struct ure_softc        *sc = ifp->if_softc;;
+       struct ifreq            *ifr = (struct ifreq *)data;
+       int                     s, error = 0;
+
+       s = splnet();
+
+       switch (cmd) {
+       case SIOCSIFADDR:
+               ifp->if_flags |= IFF_UP;
+               if (!(ifp->if_flags & IFF_RUNNING))
+                       ure_init(sc);
+               break;
+
+       case SIOCSIFFLAGS:
+               if (ifp->if_flags & IFF_UP) {
+                       if (ifp->if_flags & IFF_RUNNING)
+                               error = ENETRESET;
+                       else
+                               ure_init(sc);
+               } else {
+                       if (ifp->if_flags & IFF_RUNNING)
+                               ure_stop(sc);
+               }
+               break;
+
+       case SIOCGIFMEDIA:
+       case SIOCSIFMEDIA:
+               error = ifmedia_ioctl(ifp, ifr, &sc->ure_mii.mii_media, cmd);
+               break;
+
+       default:
+               error = ether_ioctl(ifp, &sc->ure_ac, cmd, data);
+       }
+
+       if (error == ENETRESET) {
+               if (ifp->if_flags & IFF_RUNNING)
+                       ure_iff(sc);
+               error = 0;
+       }
+
+       splx(s);
+
+       return (error);
+}
+
+int
+ure_match(struct device *parent, void *match, void *aux)
+{
+       struct usb_attach_arg *uaa = aux;
+
+       /*
+       if (uaa->configno != URE_CONFIG_IDX) 
+               return UMATCH_NONE;
+       if (uaa->ifaceno != URE_IFACE_IDX)
+               return UMATCH_NONE;
+       */
+       if (uaa->iface == NULL || uaa->configno != 1)
+               return UMATCH_NONE;
+       
+       return (usb_lookup(ure_devs, uaa->vendor, uaa->product) != NULL ?
+           UMATCH_VENDOR_PRODUCT_CONF_IFACE : UMATCH_NONE);
+}
+
+void
+ure_attach(struct device *parent, struct device *self, void *aux)
+{
+       struct ure_softc                *sc = (struct ure_softc *)self;
+       struct usb_attach_arg           *uaa = aux;
+       usb_interface_descriptor_t      *id;
+       usb_endpoint_descriptor_t       *ed;
+       struct mii_data                 *mii;
+       u_char                          eaddr[8]; /* 4byte padded */
+       struct ifnet                    *ifp;
+       int                             i, s;
+       uint16_t                        ver;
+
+       sc->ure_udev = uaa->device;
+       sc->ure_iface = uaa->iface;
+
+       usb_init_task(&sc->ure_tick_task, ure_tick_task, sc,
+           USB_TASK_TYPE_GENERIC);
+       rw_init(&sc->ure_mii_lock, "uremii");
+       usb_init_task(&sc->ure_stop_task, (void (*)(void *))ure_stop, sc,
+           USB_TASK_TYPE_GENERIC);
+
+       id = usbd_get_interface_descriptor(sc->ure_iface);
+
+       sc->ure_bufsz = 16 * 1024;
+
+       for (i = 0; i < id->bNumEndpoints; i++) {
+               ed = usbd_interface2endpoint_descriptor(sc->ure_iface, i);
+               if (!ed) {
+                       printf("%s: couldn't get ep %d\n",
+                           sc->ure_dev.dv_xname, i);
+                       return;
+               }
+               if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
+                   UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
+                       sc->ure_ed[URE_ENDPT_RX] = ed->bEndpointAddress;
+               } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
+                   UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
+                       sc->ure_ed[URE_ENDPT_TX] = ed->bEndpointAddress;
+               }
+       }
+
+       s = splnet();
+
+       sc->ure_phyno = 0;
+       printf("%s: ", sc->ure_dev.dv_xname);
+
+       ver = ure_read_2(sc, URE_PLA_TCR1, URE_MCU_TYPE_PLA) & URE_VERSION_MASK;
+       switch (ver) {
+       case 0x4c00:
+               sc->ure_chip |= URE_CHIP_VER_4C00;
+               ure_read_mem(sc, URE_PLA_IDR, URE_MCU_TYPE_PLA, eaddr,
+                   sizeof(eaddr));
+               printf("ver 4c00");
+               break;
+       case 0x4c10:
+               sc->ure_chip |= URE_CHIP_VER_4C10;
+               ure_read_mem(sc, URE_PLA_BACKUP, URE_MCU_TYPE_PLA, eaddr,
+                   sizeof(eaddr));
+               printf("ver 4c01");
+               break;
+       default:
+               printf(", unknown ver %02x", ver);
+               /* fake addr?  or just fail? */
+               break;
+       }
+
+       printf(", address %s\n", ether_sprintf(eaddr));
+
+       bcopy(eaddr, (char *)&sc->ure_ac.ac_enaddr, ETHER_ADDR_LEN);
+
+       ure_rtl8152_init(sc);
+
+       ifp = &sc->ure_ac.ac_if;
+       ifp->if_softc = sc;
+       strlcpy(ifp->if_xname, sc->ure_dev.dv_xname, IFNAMSIZ);
+       ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+       ifp->if_ioctl = ure_ioctl;
+       ifp->if_start = ure_start;
+       ifp->if_capabilities = 0;
+
+       mii = &sc->ure_mii;
+       mii->mii_ifp = ifp;
+       mii->mii_readreg = ure_miibus_readreg;
+       mii->mii_writereg = ure_miibus_writereg;
+       mii->mii_statchg = ure_miibus_statchg;
+       mii->mii_flags = MIIF_AUTOTSLEEP;
+
+       ifmedia_init(&mii->mii_media, 0, ure_ifmedia_upd, ure_ifmedia_sts);
+       mii_attach(self, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, 0);
+
+       if (LIST_FIRST(&mii->mii_phys) == NULL) {
+               ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_NONE, 0, NULL);
+               ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_NONE);
+       } else
+               ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO);
+
+       if_attach(ifp);
+       ether_ifattach(ifp);
+
+       timeout_set(&sc->ure_stat_ch, ure_tick, sc);
+
+       splx(s);
+}
+
+int
+ure_detach(struct device *self, int flags)
+{
+       struct ure_softc        *sc = (struct ure_softc *)self;
+       struct ifnet            *ifp = &sc->ure_ac.ac_if;
+       int                     s;
+
+       if (timeout_initialized(&sc->ure_stat_ch))
+               timeout_del(&sc->ure_stat_ch);
+
+       if (sc->ure_ep[URE_ENDPT_TX] != NULL)
+               usbd_abort_pipe(sc->ure_ep[URE_ENDPT_TX]);
+       if (sc->ure_ep[URE_ENDPT_RX] != NULL)
+               usbd_abort_pipe(sc->ure_ep[URE_ENDPT_RX]);
+
+       usb_rem_task(sc->ure_udev, &sc->ure_tick_task);
+       usb_rem_task(sc->ure_udev, &sc->ure_stop_task);
+
+       s = splusb();
+
+       if (--sc->ure_refcnt >= 0) {
+               usb_detach_wait(&sc->ure_dev);
+       }
+
+       if (ifp->if_flags & IFF_RUNNING)
+               ure_stop(sc);
+
+       mii_detach(&sc->ure_mii, MII_PHY_ANY, MII_OFFSET_ANY);
+       ifmedia_delete_instance(&sc->ure_mii.mii_media, IFM_INST_ANY);
+       if (ifp->if_softc != NULL) {
+               ether_ifdetach(ifp);
+               if_detach(ifp);
+       }
+
+       splx(s);
+
+       return 0;
+}
+
+void
+ure_tick_task(void *xsc)
+{
+       int                     s;
+       struct ure_softc        *sc = xsc;
+       struct mii_data         *mii;
+
+       if (sc == NULL)
+               return;
+
+       if (usbd_is_dying(sc->ure_udev))
+               return;
+       mii = &sc->ure_mii;
+
+       s = splnet();
+       mii_tick(mii);
+       if ((sc->ure_flags & URE_FLAG_LINK) == 0)
+               ure_miibus_statchg(&sc->ure_dev);
+       timeout_add_sec(&sc->ure_stat_ch, 1);
+       splx(s);
+}
+
+void
+ure_lock_mii(struct ure_softc *sc)
+{
+       sc->ure_refcnt++;
+       rw_enter_write(&sc->ure_mii_lock);
+}
+
+void
+ure_unlock_mii(struct ure_softc *sc)
+{
+       rw_exit_write(&sc->ure_mii_lock);
+       if (--sc->ure_refcnt < 0)
+               usb_detach_wakeup(&sc->ure_dev);
+}
+
+void
+ure_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
+{
+       struct ure_chain        *c = (struct ure_chain *)priv;
+       struct ure_softc        *sc = c->uc_sc;
+       struct ifnet            *ifp = &sc->ure_ac.ac_if;
+       u_char                  *buf = c->uc_buf;
+       uint32_t                total_len;
+       uint16_t                pktlen = 0;
+       struct mbuf_list        ml = MBUF_LIST_INITIALIZER();
+       struct mbuf             *m;
+       int                     s;
+       struct ure_rxpkt        rxhdr;
+       
+       if (usbd_is_dying(sc->ure_udev))
+               return;
+
+       if (!(ifp->if_flags & IFF_RUNNING))
+               return;
+
+       if (status != USBD_NORMAL_COMPLETION) {
+               if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
+                       return;
+               if (usbd_ratecheck(&sc->ure_rx_notice)) {
+                       printf("%s: usb errors on rx: %s\n",
+                               sc->ure_dev.dv_xname, usbd_errstr(status));
+               }
+               if (status == USBD_STALLED)
+                       
usbd_clear_endpoint_stall_async(sc->ure_ep[URE_ENDPT_RX]);
+               goto done;
+       }
+
+       usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
+       DPRINTFN(3, ("received %d bytes\n", total_len));
+
+       do {
+               if (total_len < sizeof(rxhdr)) {
+                       DPRINTF(("too few bytes left for a packet header\n"));
+                       ifp->if_ierrors++;
+                       goto done;
+               }
+
+               buf += pktlen;
+
+               memcpy(&rxhdr, buf, sizeof(rxhdr));
+               total_len -= sizeof(rxhdr);
+
+               pktlen = lemtoh32(&rxhdr.ure_pktlen) & URE_RXPKT_LEN_MASK;
+               DPRINTFN(4, ("next packet is %d bytes\n", pktlen));
+               if (pktlen > total_len) {
+                       DPRINTF(("not enough bytes left for next packet\n"));
+                       ifp->if_ierrors++;
+                       goto done;
+               }
+
+               total_len -= pktlen;
+               buf += sizeof(rxhdr);
+
+               m = ure_newbuf();
+               if (m == NULL) {
+                       DPRINTF(("unable to allocate mbuf for next packet\n"));
+                       ifp->if_ierrors++;
+                       goto done;
+               }
+
+               m->m_pkthdr.len = m->m_len = pktlen;
+               m_adj(m, ETHER_ALIGN);
+
+               memcpy(mtod(m, char *), buf, pktlen);
+               ml_enqueue(&ml, m);
+       } while (total_len > 0);
+
+done:
+       s = splnet();
+       if_input(ifp, &ml);
+       splx(s);
+       memset(c->uc_buf, 0, sc->ure_bufsz);
+
+       usbd_setup_xfer(xfer, sc->ure_ep[URE_ENDPT_RX], c, c->uc_buf,
+           sc->ure_bufsz, USBD_SHORT_XFER_OK | USBD_NO_COPY,
+           USBD_NO_TIMEOUT, ure_rxeof);
+       usbd_transfer(xfer);
+}
+
+
+void
+ure_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
+{
+       struct ure_softc        *sc;
+       struct ure_chain        *c;
+       struct ifnet            *ifp;
+       int                     s;
+
+       c = priv;
+       sc = c->uc_sc;
+       ifp = &sc->ure_ac.ac_if;
+
+       if (usbd_is_dying(sc->ure_udev))
+               return;
+
+       DPRINTFN(2, ("tx completion\n"));
+
+       s = splnet();
+
+       if (status != USBD_NORMAL_COMPLETION) {
+               if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
+                       splx(s);
+                       return;
+               }
+               ifp->if_oerrors++;
+               printf("%s: usb error on tx: %s\n", sc->ure_dev.dv_xname,
+                   usbd_errstr(status));
+               if (status == USBD_STALLED)
+                       
usbd_clear_endpoint_stall_async(sc->ure_ep[URE_ENDPT_TX]);
+               splx(s);
+               return;
+       }
+
+       ifp->if_timer = 0;
+       ifq_clr_oactive(&ifp->if_snd);
+
+       m_freem(c->uc_mbuf);
+       c->uc_mbuf = NULL;
+
+       if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
+               ure_start(ifp);
+
+       ifp->if_opackets++;
+       splx(s);
+       
+}
+
+int
+ure_tx_list_init(struct ure_softc *sc)
+{
+       struct ure_cdata *cd;
+       struct ure_chain *c;
+       int i;
+
+       cd = &sc->ure_cdata;
+       for (i = 0; i < URE_TX_LIST_CNT; i++) {
+               c = &cd->tx_chain[i];
+               c->uc_sc = sc;
+               c->uc_idx = i;
+               c->uc_mbuf = NULL;
+               if (c->uc_xfer == NULL) {
+                       c->uc_xfer = usbd_alloc_xfer(sc->ure_udev);
+                       if (c->uc_xfer == NULL)
+                               return ENOBUFS;
+                       c->uc_buf = usbd_alloc_buffer(c->uc_xfer,
+                           sc->ure_bufsz);
+                       if (c->uc_buf == NULL) {
+                               usbd_free_xfer(c->uc_xfer);
+                               return ENOBUFS;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+int
+ure_rx_list_init(struct ure_softc *sc)
+{
+       struct ure_cdata *cd;
+       struct ure_chain *c;
+       int i;
+
+       cd = &sc->ure_cdata;
+       for (i = 0; i < URE_RX_LIST_CNT; i++) {
+               c = &cd->rx_chain[i];
+               c->uc_sc = sc;
+               c->uc_idx = i;
+               c->uc_mbuf = NULL;
+               if (c->uc_xfer == NULL) {
+                       c->uc_xfer = usbd_alloc_xfer(sc->ure_udev);
+                       if (c->uc_xfer == NULL)
+                               return ENOBUFS;
+                       c->uc_buf = usbd_alloc_buffer(c->uc_xfer,
+                           sc->ure_bufsz);
+                       if (c->uc_buf == NULL) {
+                               usbd_free_xfer(c->uc_xfer);
+                               return ENOBUFS;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+struct mbuf *
+ure_newbuf(void)
+{
+       struct mbuf *m;
+
+       MGETHDR(m, M_DONTWAIT, MT_DATA);
+       if (m == NULL)
+               return NULL;
+
+       MCLGET(m, M_DONTWAIT);
+       if (!(m->m_flags & M_EXT)) {
+               m_freem(m);
+               return NULL;
+       }
+
+       return m;
+}
+
+int
+ure_encap(struct ure_softc *sc, struct mbuf *m, int idx)
+{
+       struct ure_chain        *c;
+       usbd_status             err;
+       struct ure_txpkt        txhdr;
+       uint32_t                frm_len = 0;
+       u_char                  *buf;
+
+       c = &sc->ure_cdata.tx_chain[idx];
+       buf = c->uc_buf;
+
+       /* header */
+       htolem32(&txhdr.ure_pktlen, m->m_pkthdr.len | URE_TXPKT_TX_FS |
+           URE_TXPKT_TX_LS);
+       txhdr.ure_rsvd0 = 0;
+       memcpy(buf, &txhdr, sizeof(txhdr));
+       buf += sizeof(txhdr);
+       frm_len = sizeof(txhdr);
+
+       /* packet */
+       m_copydata(m, 0, m->m_pkthdr.len, buf);
+       frm_len += m->m_pkthdr.len;
+
+       c->uc_mbuf = m;
+
+       DPRINTFN(2, ("tx %d bytes\n", frm_len));
+       usbd_setup_xfer(c->uc_xfer, sc->ure_ep[URE_ENDPT_TX], c, c->uc_buf,
+           frm_len, USBD_FORCE_SHORT_XFER | USBD_NO_COPY, 10000, ure_txeof);
+
+       err = usbd_transfer(c->uc_xfer);
+       if (err != USBD_IN_PROGRESS) {
+               ure_stop(sc);
+               return EIO;
+       }
+
+       sc->ure_cdata.tx_cnt++;
+       return 0;
+}
Index: if_urereg.h
===================================================================
RCS file: if_urereg.h
diff -N if_urereg.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ if_urereg.h 26 Jun 2016 09:56:29 -0000
@@ -0,0 +1,464 @@
+/*-
+ * Copyright (c) 2015 Kevin Lo <[email protected]>
+ * 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$
+ */
+
+#define        URE_CTL_READ            0x01
+#define        URE_CTL_WRITE           0x02
+
+#define        URE_TIMEOUT             1000
+#define        URE_PHY_TIMEOUT         2000
+
+#define        URE_BYTE_EN_DWORD       0xff
+#define        URE_BYTE_EN_WORD        0x33
+#define        URE_BYTE_EN_BYTE        0x11
+#define        URE_BYTE_EN_SIX_BYTES   0x3f
+
+#define        URE_MAX_FRAMELEN        (ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN)
+
+#define        URE_PLA_IDR             0xc000
+#define        URE_PLA_RCR             0xc010
+#define        URE_PLA_RMS             0xc016
+#define        URE_PLA_RXFIFO_CTRL0    0xc0a0
+#define        URE_PLA_RXFIFO_CTRL1    0xc0a4
+#define        URE_PLA_RXFIFO_CTRL2    0xc0a8
+#define        URE_PLA_DMY_REG0        0xc0b0
+#define        URE_PLA_FMC             0xc0b4
+#define        URE_PLA_CFG_WOL         0xc0b6
+#define        URE_PLA_TEREDO_CFG      0xc0bc
+#define        URE_PLA_MAR0            0xcd00
+#define        URE_PLA_MAR4            0xcd04
+#define        URE_PLA_BACKUP          0xd000
+#define        URE_PLA_BDC_CR          0xd1a0
+#define        URE_PLA_TEREDO_TIMER    0xd2cc
+#define        URE_PLA_REALWOW_TIMER   0xd2e8
+#define        URE_PLA_LEDSEL          0xdd90
+#define        URE_PLA_LED_FEATURE     0xdd92
+#define        URE_PLA_PHYAR           0xde00
+#define        URE_PLA_BOOT_CTRL       0xe004
+#define        URE_PLA_GPHY_INTR_IMR   0xe022
+#define        URE_PLA_EEE_CR          0xe040
+#define        URE_PLA_EEEP_CR         0xe080
+#define        URE_PLA_MAC_PWR_CTRL    0xe0c0
+#define        URE_PLA_MAC_PWR_CTRL2   0xe0ca
+#define        URE_PLA_MAC_PWR_CTRL3   0xe0cc
+#define        URE_PLA_MAC_PWR_CTRL4   0xe0ce
+#define        URE_PLA_WDT6_CTRL       0xe428
+#define        URE_PLA_TCR0            0xe610
+#define        URE_PLA_TCR1            0xe612
+#define        URE_PLA_MTPS            0xe615
+#define        URE_PLA_TXFIFO_CTRL     0xe618
+#define        URE_PLA_RSTTELLY        0xe800
+#define        URE_PLA_CR              0xe813
+#define        URE_PLA_CRWECR          0xe81c
+#define        URE_PLA_CONFIG5         0xe822
+#define        URE_PLA_PHY_PWR         0xe84c
+#define        URE_PLA_OOB_CTRL        0xe84f
+#define        URE_PLA_CPCR            0xe854
+#define        URE_PLA_MISC_0          0xe858
+#define        URE_PLA_MISC_1          0xe85a
+#define        URE_PLA_OCP_GPHY_BASE   0xe86c
+#define        URE_PLA_TELLYCNT        0xe890
+#define        URE_PLA_SFF_STS_7       0xe8de
+#define        URE_PLA_PHYSTATUS       0xe908
+
+#define        URE_USB_USB2PHY         0xb41e
+#define        URE_USB_SSPHYLINK2      0xb428
+#define        URE_USB_U2P3_CTRL       0xb460
+#define        URE_USB_CSR_DUMMY1      0xb464
+#define        URE_USB_CSR_DUMMY2      0xb466
+#define        URE_USB_DEV_STAT        0xb808
+#define        URE_USB_CONNECT_TIMER   0xcbf8
+#define        URE_USB_BURST_SIZE      0xcfc0
+#define        URE_USB_USB_CTRL        0xd406
+#define        URE_USB_PHY_CTRL        0xd408
+#define        URE_USB_TX_AGG          0xd40a
+#define        URE_USB_RX_BUF_TH       0xd40c
+#define        URE_USB_USB_TIMER       0xd428
+#define        URE_USB_RX_EARLY_AGG    0xd42c
+#define        URE_USB_PM_CTRL_STATUS  0xd432
+#define        URE_USB_TX_DMA          0xd434
+#define        URE_USB_TOLERANCE       0xd490
+#define        URE_USB_LPM_CTRL        0xd41a
+#define        URE_USB_UPS_CTRL        0xd800
+#define        URE_USB_MISC_0          0xd81a
+#define        URE_USB_POWER_CUT       0xd80a
+#define        URE_USB_AFE_CTRL2       0xd824
+#define        URE_USB_WDT11_CTRL      0xe43c
+
+/* OCP Registers. */
+#define        URE_OCP_ALDPS_CONFIG    0x2010
+#define        URE_OCP_EEE_CONFIG1     0x2080
+#define        URE_OCP_EEE_CONFIG2     0x2092
+#define        URE_OCP_EEE_CONFIG3     0x2094
+#define        URE_OCP_BASE_MII        0xa400
+#define        URE_OCP_EEE_AR          0xa41a
+#define        URE_OCP_EEE_DATA        0xa41c
+#define        URE_OCP_PHY_STATUS      0xa420
+#define        URE_OCP_POWER_CFG       0xa430
+#define        URE_OCP_EEE_CFG         0xa432
+#define        URE_OCP_SRAM_ADDR       0xa436
+#define        URE_OCP_SRAM_DATA       0xa438
+#define        URE_OCP_DOWN_SPEED      0xa442
+#define        URE_OCP_EEE_ABLE        0xa5c4
+#define        URE_OCP_EEE_ADV         0xa5d0
+#define        URE_OCP_EEE_LPABLE      0xa5d2
+#define        URE_OCP_PHY_STATE       0xa708
+#define        URE_OCP_ADC_CFG         0xbc06
+
+/* SRAM Register. */
+#define        URE_SRAM_LPF_CFG        0x8012
+#define        URE_SRAM_10M_AMP1       0x8080
+#define        URE_SRAM_10M_AMP2       0x8082
+#define        URE_SRAM_IMPEDANCE      0x8084
+
+/* PLA_RCR */
+#define        URE_RCR_AAP             0x00000001
+#define        URE_RCR_APM             0x00000002
+#define        URE_RCR_AM              0x00000004
+#define        URE_RCR_AB              0x00000008
+#define        URE_RCR_ACPT_ALL        \
+       (URE_RCR_AAP | URE_RCR_APM | URE_RCR_AM | URE_RCR_AB)
+
+/* PLA_RXFIFO_CTRL0 */
+#define        URE_RXFIFO_THR1_NORMAL  0x00080002
+#define        URE_RXFIFO_THR1_OOB     0x01800003
+
+/* PLA_RXFIFO_CTRL1 */
+#define        URE_RXFIFO_THR2_FULL    0x00000060
+#define        URE_RXFIFO_THR2_HIGH    0x00000038
+#define        URE_RXFIFO_THR2_OOB     0x0000004a
+#define        URE_RXFIFO_THR2_NORMAL  0x00a0
+
+/* PLA_RXFIFO_CTRL2 */
+#define        URE_RXFIFO_THR3_FULL    0x00000078
+#define        URE_RXFIFO_THR3_HIGH    0x00000048
+#define        URE_RXFIFO_THR3_OOB     0x0000005a
+#define        URE_RXFIFO_THR3_NORMAL  0x0110
+
+/* PLA_TXFIFO_CTRL */
+#define        URE_TXFIFO_THR_NORMAL   0x00400008
+#define        URE_TXFIFO_THR_NORMAL2  0x01000008
+
+/* PLA_DMY_REG0 */
+#define        URE_ECM_ALDPS           0x0002
+
+/* PLA_FMC */
+#define        URE_FMC_FCR_MCU_EN      0x0001
+
+/* PLA_EEEP_CR */
+#define        URE_EEEP_CR_EEEP_TX     0x0002
+
+/* PLA_WDT6_CTRL */
+#define        URE_WDT6_SET_MODE       0x001
+
+/* PLA_TCR0 */
+#define        URE_TCR0_TX_EMPTY       0x0800
+#define        URE_TCR0_AUTO_FIFO      0x0080
+
+/* PLA_TCR1 */
+#define        URE_VERSION_MASK        0x7cf0
+
+/* PLA_CR */
+#define        URE_CR_RST              0x10
+#define        URE_CR_RE               0x08
+#define        URE_CR_TE               0x04
+
+/* PLA_CRWECR */
+#define        URE_CRWECR_NORAML       0x00
+#define        URE_CRWECR_CONFIG       0xc0
+
+/* PLA_OOB_CTRL */
+#define        URE_NOW_IS_OOB          0x80    
+#define        URE_TXFIFO_EMPTY        0x20    
+#define        URE_RXFIFO_EMPTY        0x10    
+#define        URE_LINK_LIST_READY     0x02    
+#define        URE_DIS_MCU_CLROOB      0x01    
+#define        URE_FIFO_EMPTY          (URE_TXFIFO_EMPTY | URE_RXFIFO_EMPTY)
+
+/* PLA_MISC_1 */
+#define        URE_RXDY_GATED_EN       0x0008  
+
+/* PLA_SFF_STS_7 */
+#define        URE_RE_INIT_LL          0x8000  
+#define        URE_MCU_BORW_EN         0x4000  
+
+/* PLA_CPCR */
+#define        URE_CPCR_RX_VLAN        0x0040
+
+/* PLA_TEREDO_CFG */
+#define        URE_TEREDO_SEL                  0x8000
+#define        URE_TEREDO_WAKE_MASK            0x7f00
+#define        URE_TEREDO_RS_EVENT_MASK        0x00fe
+#define        URE_OOB_TEREDO_EN               0x0001
+
+/* PAL_BDC_CR */
+#define        URE_ALDPS_PROXY_MODE    0x0001
+
+/* PLA_CONFIG5 */
+#define        URE_LAN_WAKE_EN         0x0002
+
+/* PLA_LED_FEATURE */
+#define        URE_LED_MODE_MASK       0x0700
+
+/* PLA_PHY_PWR */
+#define        URE_TX_10M_IDLE_EN      0x0080
+#define        URE_PFM_PWM_SWITCH      0x0040
+
+/* PLA_MAC_PWR_CTRL */
+#define        URE_D3_CLK_GATED_EN     0x00004000
+#define        URE_MCU_CLK_RATIO       0x07010f07
+#define        URE_MCU_CLK_RATIO_MASK  0x0f0f0f0f
+#define        URE_ALDPS_SPDWN_RATIO   0x0f87
+
+/* PLA_MAC_PWR_CTRL2 */
+#define        URE_EEE_SPDWN_RATIO     0x8007
+
+/* PLA_MAC_PWR_CTRL3 */
+#define        URE_PKT_AVAIL_SPDWN_EN  0x0100
+#define        URE_SUSPEND_SPDWN_EN    0x0004
+#define        URE_U1U2_SPDWN_EN       0x0002
+#define        URE_L1_SPDWN_EN         0x0001
+
+/* PLA_MAC_PWR_CTRL4 */
+#define        URE_PWRSAVE_SPDWN_EN    0x1000
+#define        URE_RXDV_SPDWN_EN       0x0800
+#define        URE_TX10MIDLE_EN        0x0100
+#define        URE_TP100_SPDWN_EN      0x0020
+#define        URE_TP500_SPDWN_EN      0x0010
+#define        URE_TP1000_SPDWN_EN     0x0008
+#define        URE_EEE_SPDWN_EN        0x0001
+
+/* PLA_GPHY_INTR_IMR */
+#define        URE_GPHY_STS_MSK        0x0001
+#define        URE_SPEED_DOWN_MSK      0x0002
+#define        URE_SPDWN_RXDV_MSK      0x0004
+#define        URE_SPDWN_LINKCHG_MSK   0x0008
+
+/* PLA_PHYAR */
+#define        URE_PHYAR_PHYDATA       0x0000ffff
+#define        URE_PHYAR_BUSY          0x80000000
+
+/* PLA_EEE_CR */
+#define        URE_EEE_RX_EN           0x0001
+#define        URE_EEE_TX_EN           0x0002
+
+/* PLA_BOOT_CTRL */
+#define        URE_AUTOLOAD_DONE       0x0002
+
+/* USB_USB2PHY */
+#define        URE_USB2PHY_SUSPEND     0x0001
+#define        URE_USB2PHY_L1          0x0002
+
+/* USB_SSPHYLINK2 */
+#define        URE_PWD_DN_SCALE_MASK   0x3ffe
+#define        URE_PWD_DN_SCALE(x)     ((x) << 1)
+
+/* USB_CSR_DUMMY1 */
+#define        URE_DYNAMIC_BURST       0x0001
+
+/* USB_CSR_DUMMY2 */
+#define        URE_EP4_FULL_FC         0x0001
+
+/* USB_DEV_STAT */
+#define        URE_STAT_SPEED_MASK     0x0006
+#define        URE_STAT_SPEED_HIGH     0x0000
+#define        URE_STAT_SPEED_FULL     0x0001
+
+/* USB_TX_AGG */
+#define        URE_TX_AGG_MAX_THRESHOLD        0x03
+
+/* USB_RX_BUF_TH */
+#define        URE_RX_THR_SUPER        0x0c350180
+#define        URE_RX_THR_HIGH         0x7a120180
+#define        URE_RX_THR_SLOW         0xffff0180
+
+/* USB_TX_DMA */
+#define        URE_TEST_MODE_DISABLE   0x00000001
+#define        URE_TX_SIZE_ADJUST1     0x00000100
+
+/* USB_UPS_CTRL */
+#define        URE_POWER_CUT           0x0100
+
+/* USB_PM_CTRL_STATUS */
+#define        URE_RESUME_INDICATE     0x0001
+
+/* USB_USB_CTRL */
+#define        URE_RX_AGG_DISABLE      0x0010
+#define        URE_RX_ZERO_EN          0x0080
+
+/* USB_U2P3_CTRL */
+#define        URE_U2P3_ENABLE         0x0001
+
+/* USB_POWER_CUT */
+#define        URE_PWR_EN              0x0001
+#define        URE_PHASE2_EN           0x0008
+
+/* USB_MISC_0 */
+#define        URE_PCUT_STATUS         0x0001
+
+/* USB_RX_EARLY_TIMEOUT */
+#define        URE_COALESCE_SUPER      85000U
+#define        URE_COALESCE_HIGH       250000U
+#define        URE_COALESCE_SLOW       524280U
+
+/* USB_WDT11_CTRL */
+#define        URE_TIMER11_EN          0x0001
+
+/* USB_LPM_CTRL */
+#define        URE_FIFO_EMPTY_1FB      0x30
+#define        URE_LPM_TIMER_MASK      0x0c
+#define        URE_LPM_TIMER_500MS     0x04
+#define        URE_LPM_TIMER_500US     0x0c
+#define        URE_ROK_EXIT_LPM        0x02
+
+/* USB_AFE_CTRL2 */
+#define        URE_SEN_VAL_MASK        0xf800
+#define        URE_SEN_VAL_NORMAL      0xa000
+#define        URE_SEL_RXIDLE          0x0100
+
+/* OCP_ALDPS_CONFIG */
+#define        URE_ENPWRSAVE           0x8000  
+#define        URE_ENPDNPS             0x0200  
+#define        URE_LINKENA             0x0100  
+#define        URE_DIS_SDSAVE          0x0010
+
+/* OCP_PHY_STATUS */
+#define        URE_PHY_STAT_MASK       0x0007
+#define        URE_PHY_STAT_LAN_ON     3       
+#define        URE_PHY_STAT_PWRDN      5
+
+/* OCP_POWER_CFG */
+#define        URE_EEE_CLKDIV_EN       0x8000
+#define        URE_EN_ALDPS            0x0004
+#define        URE_EN_10M_PLLOFF       0x0001
+
+/* OCP_EEE_CFG */
+#define        URE_CTAP_SHORT_EN       0x0040
+#define        URE_EEE10_EN            0x0010
+
+/* OCP_DOWN_SPEED */
+#define        URE_EN_10M_BGOFF        0x0080
+
+/* OCP_PHY_STATE */
+#define        URE_TXDIS_STATE         0x01
+#define        URE_ABD_STATE           0x02
+
+/* OCP_ADC_CFG */
+#define        URE_CKADSEL_L           0x0100
+#define        URE_ADC_EN              0x0080
+#define        URE_EN_EMI_L            0x0040
+
+#define        URE_MCU_TYPE_PLA        0x0100
+#define        URE_MCU_TYPE_USB        0x0000
+
+struct ure_intrpkt {
+       uint8_t ure_tsr;
+       uint8_t ure_rsr;
+       uint8_t ure_gep_msr;
+       uint8_t ure_waksr;
+       uint8_t ure_txok_cnt;
+       uint8_t ure_rxlost_cnt;
+       uint8_t ure_crcerr_cnt;
+       uint8_t ure_col_cnt;
+} __packed;
+
+struct ure_rxpkt {
+       uint32_t ure_pktlen;
+#define        URE_RXPKT_LEN_MASK      0x7fff
+       uint32_t ure_rsvd0;
+       uint32_t ure_rsvd1;
+       uint32_t ure_rsvd2;
+       uint32_t ure_rsvd3;
+       uint32_t ure_rsvd4;
+} __packed;
+
+struct ure_txpkt {
+       uint32_t ure_pktlen;
+#define        URE_TXPKT_TX_FS         (1 << 31)
+#define        URE_TXPKT_TX_LS         (1 << 30)
+#define        URE_TXPKT_LEN_MASK      0xffff
+       uint32_t ure_rsvd0;
+} __packed;
+
+#define URE_ENDPT_RX           0
+#define URE_ENDPT_TX           1
+#define URE_ENDPT_MAX          2
+
+#define URE_TX_LIST_CNT                1
+#define URE_RX_LIST_CNT                1
+
+struct ure_chain {
+       struct ure_softc        *uc_sc;
+       struct usbd_xfer        *uc_xfer;
+       char                    *uc_buf;
+       struct mbuf             *uc_mbuf;
+       int                     uc_accum;
+       int                     uc_idx;
+};
+
+struct ure_cdata {
+       struct ure_chain        tx_chain[URE_TX_LIST_CNT];
+       struct ure_chain        rx_chain[URE_RX_LIST_CNT];
+       int                     tx_prod;
+       int                     tx_const;
+       int                     tx_cnt;
+       int                     rx_prod;
+};
+
+struct ure_softc {
+       struct device           ure_dev;
+       struct usbd_device      *ure_udev;
+
+       /* usb */
+       struct usbd_interface   *ure_iface;
+       struct usb_task         ure_tick_task;
+       struct usb_task         ure_stop_task;
+       int                     ure_ed[URE_ENDPT_MAX];
+       struct usbd_pipe        *ure_ep[URE_ENDPT_MAX];
+
+       /* ethernet */
+       struct arpcom           ure_ac;
+       struct mii_data         ure_mii;
+       struct rwlock           ure_mii_lock;
+       int                     ure_refcnt;
+
+       struct ure_cdata        ure_cdata;
+       struct timeout          ure_stat_ch;
+
+       struct timeval          ure_rx_notice;
+       int                     ure_bufsz;
+
+       int                     ure_phyno;
+
+       u_int                   ure_flags;
+#define        URE_FLAG_LINK           0x0001
+
+       u_int                   ure_chip;
+#define        URE_CHIP_VER_4C00       0x01
+#define        URE_CHIP_VER_4C10       0x02
+};
+

Reply via email to