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,