Hi,

Here is a patch adding CoreChip RD9700 support to udav(4).

The chip is used by USB-Ethernet dongles for Android gadget, they are
sold at eBay with cheap price tag (under 5.00 USD).

RD9700 is bad DM9601 copy.

The description of these dongles says "USB 2.0 10/100Mbps" but
actually they work with USB 1.1 (full-speed) and 10Mbps half-duplex.

They have no serial EEPROM, no different MAC address. I have two
dongles and they have same address (00:e0:4c:53:44:58) and Windows'
driver sets 00:01:0a:XX:XX:XX (XX:XX:XX is different).

RD9700 does not have MII-PHY so the patch simply bypasses MII related
routine.

The performance is poor, receive is extremely slow.

At RD9700's bulk-in pipe, sometimes there is no Zero-Length-Packet
(ZLP) to show the end of USB transaction. The device uses one Ethernet
frame as one USB transaction, so no ZLP makes dropping frame. There is
no remedy for this problem.

Comments or ok?

Regards,
-- 
SASANO Takayoshi <u...@mx5.nisiq.net>

Index: if_udav.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/if_udav.c,v
retrieving revision 1.64
diff -u -p -r1.64 if_udav.c
--- if_udav.c   15 Nov 2013 10:17:39 -0000      1.64
+++ if_udav.c   21 Jan 2014 21:06:30 -0000
@@ -109,6 +109,7 @@ void udav_txeof(struct usbd_xfer *, void
 void udav_rxeof(struct usbd_xfer *, void *, usbd_status);
 void udav_tick(void *);
 void udav_tick_task(void *);
+void udav_tick_task_rd9700(void *);
 int udav_ioctl(struct ifnet *, u_long, caddr_t);
 void udav_stop_task(struct udav_softc *);
 void udav_stop(struct ifnet *, int);
@@ -155,6 +156,7 @@ static const struct udav_type {
        struct usb_devno udav_dev;
        u_int16_t udav_flags;
 #define UDAV_EXT_PHY   0x0001
+#define UDAV_RD9700    0x0002
 } udav_devs [] = {
        {{ USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB_TXC }, 0 },
        {{ USB_VENDOR_DAVICOM, USB_PRODUCT_DAVICOM_DM9601 }, 0 },
@@ -164,7 +166,8 @@ static const struct udav_type {
        {{ USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_ZT6688 }, 0 },
        {{ USB_VENDOR_SHANTOU, USB_PRODUCT_SHANTOU_ADM8515 }, 0 },
        {{ USB_VENDOR_UNKNOWN4, USB_PRODUCT_UNKNOWN4_DM9601 }, 0 },
-       {{ USB_VENDOR_UNKNOWN6, USB_PRODUCT_UNKNOWN6_DM9601 }, 0 }
+       {{ USB_VENDOR_UNKNOWN6, USB_PRODUCT_UNKNOWN6_DM9601 }, 0 },
+       {{ USB_VENDOR_UNKNOWN4, USB_PRODUCT_UNKNOWN4_RD9700 }, UDAV_RD9700 },
 };
 #define udav_lookup(v, p) ((struct udav_type *)usb_lookup(udav_devs, v, p))
 
@@ -202,6 +205,7 @@ udav_attach(struct device *parent, struc
        printf("%s: ", devname);
 
        sc->sc_udev = dev;
+       sc->sc_flags = udav_lookup(uaa->vendor, uaa->product)->udav_flags;
 
        /* Move the device into the configured state. */
        err = usbd_set_config_no(dev, UDAV_CONFIG_NO, 1);
@@ -210,8 +214,8 @@ udav_attach(struct device *parent, struc
                goto bad;
        }
 
-       usb_init_task(&sc->sc_tick_task, udav_tick_task, sc,
-           USB_TASK_TYPE_GENERIC);
+       usb_init_task(&sc->sc_tick_task, (sc->sc_flags & UDAV_RD9700) ?
+           udav_tick_task_rd9700 : udav_tick_task, sc, USB_TASK_TYPE_GENERIC);
        rw_init(&sc->sc_mii_lock, "udavmii");
        usb_init_task(&sc->sc_stop_task, (void (*)(void *)) udav_stop_task, sc,
            USB_TASK_TYPE_GENERIC);
@@ -224,7 +228,6 @@ udav_attach(struct device *parent, struc
        }
 
        sc->sc_ctl_iface = iface;
-       sc->sc_flags = udav_lookup(uaa->vendor, uaa->product)->udav_flags;
 
        /* get interface descriptor */
        id = usbd_get_interface_descriptor(sc->sc_ctl_iface);
@@ -294,12 +297,20 @@ udav_attach(struct device *parent, struc
        mii->mii_flags = MIIF_AUTOTSLEEP;
        ifmedia_init(&mii->mii_media, 0,
                     udav_ifmedia_change, udav_ifmedia_status);
-       mii_attach(self, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, 0);
-       if (LIST_FIRST(&mii->mii_phys) == NULL) {
+       if (sc->sc_flags & UDAV_RD9700) {
+               /* no MII-PHY */
                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);
+       } else {
+               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);
+       }
 
        /* attach the interface */
        if_attach(ifp);
@@ -342,7 +353,8 @@ udav_detach(struct device *self, int fla
        if (ifp->if_flags & IFF_RUNNING)
                udav_stop(GET_IFP(sc), 1);
 
-       mii_detach(&sc->sc_mii, MII_PHY_ANY, MII_OFFSET_ANY);
+       if (!(sc->sc_flags & UDAV_RD9700))
+               mii_detach(&sc->sc_mii, MII_PHY_ANY, MII_OFFSET_ANY);
        ifmedia_delete_instance(&sc->sc_mii.mii_media, IFM_INST_ANY);
        if (ifp->if_softc != NULL) {
                ether_ifdetach(ifp);
@@ -650,7 +662,8 @@ udav_init(struct ifnet *ifp)
        UDAV_SETBIT(sc, UDAV_GPCR, UDAV_GPCR_GEP_CNTL0);
        UDAV_CLRBIT(sc, UDAV_GPR, UDAV_GPR_GEPIO0);
 
-       mii_mediachg(mii);
+       if (!(sc->sc_flags & UDAV_RD9700))
+               mii_mediachg(mii);
 
        if (sc->sc_pipe_tx == NULL || sc->sc_pipe_rx == NULL) {
                if (udav_openpipes(sc)) {
@@ -1345,6 +1358,10 @@ udav_ifmedia_change(struct ifnet *ifp)
                return (0);
 
        sc->sc_link = 0;
+
+       if (sc->sc_flags & UDAV_RD9700)
+               return (0);
+
        if (mii->mii_instance) {
                struct mii_softc *miisc;
                for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL;
@@ -1373,6 +1390,13 @@ udav_ifmedia_status(struct ifnet *ifp, s
                return;
        }
 
+       if (sc->sc_flags & UDAV_RD9700) {
+               ifmr->ifm_active = IFM_ETHER | IFM_10_T;
+               ifmr->ifm_status = IFM_AVALID;
+               if (sc->sc_link) ifmr->ifm_status |= IFM_ACTIVE;
+               return;
+       }
+
        mii_pollstat(mii);
        ifmr->ifm_active = mii->mii_media_active;
        ifmr->ifm_status = mii->mii_media_status;
@@ -1427,6 +1451,42 @@ udav_tick_task(void *xsc)
                if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
                           udav_start(ifp);
        }
+
+       timeout_add_sec(&sc->sc_stat_ch, 1);
+
+       splx(s);
+}
+
+void
+udav_tick_task_rd9700(void *xsc)
+{
+       struct udav_softc *sc = xsc;
+       struct ifnet *ifp;
+       int s;
+
+       if (sc == NULL)
+               return;
+
+       DPRINTFN(0xff, ("%s: %s: enter\n", sc->sc_dev.dv_xname,
+                       __func__));
+
+       if (usbd_is_dying(sc->sc_udev))
+               return;
+
+       ifp = GET_IFP(sc);
+
+       s = splnet();
+
+       if (udav_csr_read1(sc, UDAV_NSR) & UDAV_NSR_LINKST) {
+               if (!sc->sc_link) {
+                       DPRINTF(("%s: %s: got link\n",
+                                sc->sc_dev.dv_xname, __func__));
+                       sc->sc_link++;
+                       if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
+                                  udav_start(ifp);
+               }
+       } else
+               sc->sc_link = 0;
 
        timeout_add_sec(&sc->sc_stat_ch, 1);
 
Index: if_udavreg.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/if_udavreg.h,v
retrieving revision 1.13
diff -u -p -r1.13 if_udavreg.h
--- if_udavreg.h        15 Apr 2013 09:23:01 -0000      1.13
+++ if_udavreg.h        21 Jan 2014 21:06:30 -0000
@@ -60,6 +60,16 @@
 #define         UDAV_NCR_LBK0          (1<<1) /* Lookback Mode */
 #define         UDAV_NCR_RST           (1<<0) /* Software reset */
 
+#define        UDAV_NSR                0x01 /* Network Status Register */
+#define         UDAV_NSR_SPEED         (1<<7) /* Media Speed (Int. PHY) */
+#define         UDAV_NSR_LINKST        (1<<6) /* Link Status (Int. PHY) */
+#define         UDAV_NSR_WAKEST        (1<<5) /* Wakeup Status */ 
+#define         UDAV_NSR_TXFULL        (1<<4) /* TX FIFO Full */
+#define         UDAV_NSR_TX2END        (1<<3) /* TX Packet 2 Complete Status */
+#define         UDAV_NSR_TX1END        (1<<2) /* TX Packet 1 Complete Status */
+#define         UDAV_NSR_RXOV          (1<<1) /* RX FIFO Overflow */
+#define         UDAV_NSR_RXRDY         (1<<0) /* RX Packet Ready */
+
 #define        UDAV_RCR                0x05 /* RX Control Register */
 #define         UDAV_RCR_WTDIS         (1<<6) /* Watchdog Timer Disable */
 #define         UDAV_RCR_DIS_LONG      (1<<5) /* Discard Long Packet(over 
1522Byte) */
Index: usbdevs
===================================================================
RCS file: /cvs/src/sys/dev/usb/usbdevs,v
retrieving revision 1.621
diff -u -p -r1.621 usbdevs
--- usbdevs     8 Jan 2014 21:15:29 -0000       1.621
+++ usbdevs     21 Jan 2014 21:06:32 -0000
@@ -4137,6 +4137,7 @@ product UNKNOWN3 ZD1211B  0x1233 ZD1211B
 
 /* Unknown vendor 4 */
 product UNKNOWN4 DM9601                0x8101 DM9601
+product UNKNOWN4 RD9700                0x9700 RD9700
 
 /* Unknown vendor 5 */
 product UNKNOWN5 NF_RIC                0x0001  NF RIC
Index: usbdevs.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/usbdevs.h,v
retrieving revision 1.632
diff -u -p -r1.632 usbdevs.h
--- usbdevs.h   8 Jan 2014 21:16:38 -0000       1.632
+++ usbdevs.h   21 Jan 2014 21:06:34 -0000
@@ -1,4 +1,4 @@
-/*     $OpenBSD: usbdevs.h,v 1.632 2014/01/08 21:16:38 jcs Exp $       */
+/*     $OpenBSD$       */
 
 /*
  * THIS FILE IS AUTOMATICALLY GENERATED.  DO NOT EDIT.
@@ -4144,6 +4144,7 @@
 
 /* Unknown vendor 4 */
 #define        USB_PRODUCT_UNKNOWN4_DM9601     0x8101          /* DM9601 */
+#define        USB_PRODUCT_UNKNOWN4_RD9700     0x9700          /* RD9700 */
 
 /* Unknown vendor 5 */
 #define        USB_PRODUCT_UNKNOWN5_NF_RIC     0x0001          /* NF RIC */
Index: usbdevs_data.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/usbdevs_data.h,v
retrieving revision 1.626
diff -u -p -r1.626 usbdevs_data.h
--- usbdevs_data.h      8 Jan 2014 21:16:38 -0000       1.626
+++ usbdevs_data.h      21 Jan 2014 21:06:36 -0000
@@ -1,4 +1,4 @@
-/*     $OpenBSD: usbdevs_data.h,v 1.626 2014/01/08 21:16:38 jcs Exp $  */
+/*     $OpenBSD$       */
 
 /*
  * THIS FILE IS AUTOMATICALLY GENERATED.  DO NOT EDIT.
@@ -10504,6 +10504,10 @@ const struct usb_known_product usb_known
        {
            USB_VENDOR_UNKNOWN4, USB_PRODUCT_UNKNOWN4_DM9601,
            "DM9601",
+       },
+       {
+           USB_VENDOR_UNKNOWN4, USB_PRODUCT_UNKNOWN4_RD9700,
+           "RD9700",
        },
        {
            USB_VENDOR_UNKNOWN5, USB_PRODUCT_UNKNOWN5_NF_RIC,

Reply via email to