Jelajahi Sumber

Update hcd-ehci, dcd-dwc2 and examples.

1. Add some example Msh commands.
2. Fix device enumeration on EXT hub.
3. Re-file some templates.
4. Extend end-point number of dwc2 device driver.
5. Re-file rndis_host implementation includes
   a. rt_mutex_take in ISR
   b. 2rd pmsg is unaligned issue.
   c. destroy u0 ethernet resource after removing dongle.
Wayne Lin 2 tahun lalu
induk
melakukan
dd1f1d3ba8

+ 3 - 0
SConscript

@@ -97,6 +97,7 @@ if GetDepend(['PKG_CHERRYUSB_HOST']):
         src += Glob('class/msc/usbh_msc.c')
     if GetDepend(['PKG_CHERRYUSB_HOST_RNDIS']):
         src += Glob('class/wireless/usbh_rndis.c')
+        src += Glob('third_party/rt-thread-4.1.1/rndis_host/rndis_host.c')
 
     if GetDepend(['PKG_CHERRYUSB_HOST_DWC2']):
         src += Glob('port/dwc2/usb_hc_dwc2.c')
@@ -119,6 +120,8 @@ if GetDepend(['PKG_CHERRYUSB_HOST']):
         src += Glob('class/vendor/cp201x/usbh_cp210x.c')
         src += Glob('third_party/rt-thread-4.1.1/dfs/drv_usbh_cp210x_rtt.c')
 
+src += Glob('third_party/rt-thread-4.1.1/msh_cmd.c')
+
 group = DefineGroup('CherryUSB', src, depend = ['PKG_USING_CHERRYUSB'], CPPPATH = path, CPPDEFINES = CPPDEFINES)
 
 Return('group')

+ 3 - 1
class/hub/usbh_hub.c

@@ -299,7 +299,9 @@ static void hub_int_complete_callback(void *arg, int nbytes)
 {
     struct usbh_hub *hub = (struct usbh_hub *)arg;
 
-    if (nbytes > 0) {
+    // >=0 can pass device enumeration on EXT hub.
+    if (nbytes >= 0)
+    {
         usbh_hub_thread_wakeup(hub);
     }
 }

+ 2 - 2
demo/cdc_acm_template.c

@@ -171,8 +171,8 @@ struct usbd_endpoint cdc_in_ep = {
     .ep_cb = usbd_cdc_acm_bulk_in
 };
 
-struct usbd_interface intf0;
-struct usbd_interface intf1;
+static struct usbd_interface intf0;
+static struct usbd_interface intf1;
 
 void cdc_acm_init(void)
 {

+ 26 - 23
demo/cdc_rndis_template.c

@@ -102,12 +102,33 @@ static const uint8_t cdc_descriptor[] = {
 };
 
 const uint8_t mac[6] = { 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
+/*Static IP ADDRESS: IP_ADDR0.IP_ADDR1.IP_ADDR2.IP_ADDR3 */
+#define IP_ADDR0 (uint8_t)192
+#define IP_ADDR1 (uint8_t)168
+#define IP_ADDR2 (uint8_t)123
+#define IP_ADDR3 (uint8_t)100
+
+/*NETMASK*/
+#define NETMASK_ADDR0 (uint8_t)255
+#define NETMASK_ADDR1 (uint8_t)255
+#define NETMASK_ADDR2 (uint8_t)255
+#define NETMASK_ADDR3 (uint8_t)0
+
+/*Gateway Address*/
+#define GW_ADDR0 (uint8_t)192
+#define GW_ADDR1 (uint8_t)168
+#define GW_ADDR2 (uint8_t)123
+#define GW_ADDR3 (uint8_t)1
 
 #ifdef RT_USING_LWIP
 #include <rtthread.h>
 #include <rtdevice.h>
 #include <netif/ethernetif.h>
 
+const ip_addr_t ipaddr = IPADDR4_INIT_BYTES(IP_ADDR0, IP_ADDR1, IP_ADDR2, IP_ADDR3);
+const ip_addr_t netmask = IPADDR4_INIT_BYTES(NETMASK_ADDR0, NETMASK_ADDR1, NETMASK_ADDR2, NETMASK_ADDR3);
+const ip_addr_t gateway = IPADDR4_INIT_BYTES(GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3);
+
 struct eth_device rndis_dev;
 
 static rt_err_t rt_usbd_rndis_control(rt_device_t dev, int cmd, void *args)
@@ -161,33 +182,15 @@ void rt_usbd_rndis_init(void)
 #include "lwip/netif.h"
 #include "lwip/pbuf.h"
 
-/*Static IP ADDRESS: IP_ADDR0.IP_ADDR1.IP_ADDR2.IP_ADDR3 */
-#define IP_ADDR0      (uint8_t)192
-#define IP_ADDR1      (uint8_t)168
-#define IP_ADDR2      (uint8_t)123
-#define IP_ADDR3      (uint8_t)100
-
-/*NETMASK*/
-#define NETMASK_ADDR0 (uint8_t)255
-#define NETMASK_ADDR1 (uint8_t)255
-#define NETMASK_ADDR2 (uint8_t)255
-#define NETMASK_ADDR3 (uint8_t)0
-
-/*Gateway Address*/
-#define GW_ADDR0      (uint8_t)192
-#define GW_ADDR1      (uint8_t)168
-#define GW_ADDR2      (uint8_t)123
-#define GW_ADDR3      (uint8_t)1
-
-static struct netif rndis_netif; //network interface
-
 const ip_addr_t ipaddr = IPADDR4_INIT_BYTES(IP_ADDR0, IP_ADDR1, IP_ADDR2, IP_ADDR3);
 const ip_addr_t netmask = IPADDR4_INIT_BYTES(NETMASK_ADDR0, NETMASK_ADDR1, NETMASK_ADDR2, NETMASK_ADDR3);
 const ip_addr_t gateway = IPADDR4_INIT_BYTES(GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3);
 
+static struct netif rndis_netif; //network interface
+
 /* Network interface name */
-#define IFNAME0       'E'
-#define IFNAME1       'X'
+#define IFNAME0 'E'
+#define IFNAME1 'X'
 
 err_t linkoutput_fn(struct netif *netif, struct pbuf *p)
 {
@@ -203,7 +206,7 @@ err_t linkoutput_fn(struct netif *netif, struct pbuf *p)
 err_t rndisif_init(struct netif *netif)
 {
     LWIP_ASSERT("netif != NULL", (netif != NULL));
-    
+
     netif->mtu = 1500;
     netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP | NETIF_FLAG_UP;
     netif->state = NULL;

+ 1 - 1
demo/hid_keyboard_template.c

@@ -226,7 +226,7 @@ void hid_keyboard_init(void)
 
 USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t write_buffer[64];
 
-void hid_keyboard_test(uint8_t busid)
+void hid_keyboard_test(void)
 {
     const uint8_t sendbuffer[8] = { 0x00, 0x00, HID_KBD_USAGE_A, 0x00, 0x00, 0x00, 0x00, 0x00 };
 

+ 14 - 9
demo/hid_mouse_template.c

@@ -256,15 +256,20 @@ void hid_mouse_init(void)
   */
 void hid_mouse_test(void)
 {
-    /*!< move mouse pointer */
-    mouse_cfg.x += 10;
-    mouse_cfg.y = 0;
+    int counter = 0;
+    while (counter < 1000) {
+        /*!< move mouse pointer */
+        mouse_cfg.x += 40;
+        mouse_cfg.y += 0;
 
-    int ret = usbd_ep_start_write(HID_INT_EP, (uint8_t *)&mouse_cfg, 4);
-    if (ret < 0) {
-        return;
-    }
-    hid_state = HID_STATE_BUSY;
-    while (hid_state == HID_STATE_BUSY) {
+        int ret = usbd_ep_start_write(HID_INT_EP, (uint8_t *)&mouse_cfg, 4);
+        if (ret < 0) {
+            return;
+        }
+        hid_state = HID_STATE_BUSY;
+        while (hid_state == HID_STATE_BUSY) {
+        }
+
+        counter++;
     }
 }

+ 3 - 3
demo/msc_ram_template.c

@@ -132,19 +132,19 @@ BLOCK_TYPE mass_block[BLOCK_COUNT];
 
 void usbd_msc_get_cap(uint8_t lun, uint32_t *block_num, uint16_t *block_size)
 {
-    *block_num = 1000; //Pretend having so many buffer,not has actually.
+    *block_num = BLOCK_COUNT; //Pretend having so many buffer,not has actually.
     *block_size = BLOCK_SIZE;
 }
 int usbd_msc_sector_read(uint32_t sector, uint8_t *buffer, uint32_t length)
 {
-    if (sector < 10)
+    if (sector < BLOCK_COUNT)
         memcpy(buffer, mass_block[sector].BlockSpace, length);
     return 0;
 }
 
 int usbd_msc_sector_write(uint32_t sector, uint8_t *buffer, uint32_t length)
 {
-    if (sector < 10)
+    if (sector < BLOCK_COUNT)
         memcpy(mass_block[sector].BlockSpace, buffer, length);
     return 0;
 }

+ 22 - 4
port/dwc2/usb_dc_dwc2.c

@@ -325,14 +325,17 @@ static void dwc2_set_turnaroundtime(uint32_t hclk, uint8_t speed)
         UsbTrd = USBD_DEFAULT_TRDT_VALUE;
     }
 
+    USB_OTG_GLB->GUSBCFG |= USB_OTG_GUSBCFG_TOCAL;
+
     USB_OTG_GLB->GUSBCFG &= ~USB_OTG_GUSBCFG_TRDT;
-    USB_OTG_GLB->GUSBCFG |= (uint32_t)((UsbTrd << 10) & USB_OTG_GUSBCFG_TRDT);
+    USB_OTG_GLB->GUSBCFG |= (uint32_t)((UsbTrd << USB_OTG_GUSBCFG_TRDT_Pos) & USB_OTG_GUSBCFG_TRDT);
 }
 
 static void dwc2_set_txfifo(uint8_t fifo, uint16_t size)
 {
     uint8_t i;
     uint32_t Tx_Offset;
+    uint32_t Tx_Size;
 
     /*  TXn min size = 16 words. (n  : Transmit FIFO index)
       When a TxFIFO is not used, the Configuration should be as follows:
@@ -348,6 +351,7 @@ static void dwc2_set_txfifo(uint8_t fifo, uint16_t size)
 
     if (fifo == 0U) {
         USB_OTG_GLB->DIEPTXF0_HNPTXFSIZ = ((uint32_t)size << 16) | Tx_Offset;
+        Tx_Size = USB_OTG_GLB->DIEPTXF0_HNPTXFSIZ;
     } else {
         Tx_Offset += (USB_OTG_GLB->DIEPTXF0_HNPTXFSIZ) >> 16;
         for (i = 0U; i < (fifo - 1U); i++) {
@@ -356,7 +360,11 @@ static void dwc2_set_txfifo(uint8_t fifo, uint16_t size)
 
         /* Multiply Tx_Size by 2 to get higher performance */
         USB_OTG_GLB->DIEPTXF[fifo - 1U] = ((uint32_t)size << 16) | Tx_Offset;
+
+        Tx_Size = USB_OTG_GLB->DIEPTXF[fifo - 1U];
     }
+
+    USB_LOG_INFO("fifo-%02d size:%04d %08x\n", fifo, size, Tx_Size);
 }
 
 static uint8_t dwc2_get_devspeed(void)
@@ -665,8 +673,9 @@ int usb_dc_init(void)
         }
     }
 
-    USB_OTG_GLB->GAHBCFG |= USB_OTG_GAHBCFG_HBSTLEN_2;
-    USB_OTG_GLB->GAHBCFG |= USB_OTG_GAHBCFG_DMAEN;
+    USB_OTG_DEV->DCFG &= ~USB_OTG_DCFG_DESCDMA;
+    USB_OTG_GLB->GAHBCFG |= (USB_OTG_GAHBCFG_DMAEN | USB_OTG_GAHBCFG_HBSTLEN_2);
+
 #else
     USB_OTG_GLB->GINTMSK |= USB_OTG_GINTMSK_RXFLVLM;
 #endif
@@ -688,6 +697,15 @@ int usb_dc_init(void)
 #endif
 #if USB_NUM_BIDIR_ENDPOINTS > 5
     dwc2_set_txfifo(5, CONFIG_USB_DWC2_TX5_FIFO_SIZE / 4);
+#endif
+#if USB_NUM_BIDIR_ENDPOINTS > 6
+    dwc2_set_txfifo(6, CONFIG_USB_DWC2_TX6_FIFO_SIZE / 4);
+#endif
+#if USB_NUM_BIDIR_ENDPOINTS > 7
+    dwc2_set_txfifo(7, CONFIG_USB_DWC2_TX7_FIFO_SIZE / 4);
+#endif
+#if USB_NUM_BIDIR_ENDPOINTS > 8
+    dwc2_set_txfifo(8, CONFIG_USB_DWC2_TX8_FIFO_SIZE / 4);
 #endif
     USB_OTG_GLB->GAHBCFG |= USB_OTG_GAHBCFG_GINT;
     USB_OTG_DEV->DCTL &= ~USB_OTG_DCTL_SDIS;
@@ -821,7 +839,7 @@ int usbd_ep_close(const uint8_t ep)
             /* Clear and unmask endpoint disabled interrupt */
             USB_OTG_INEP(ep_idx)->DIEPINT |= USB_OTG_DIEPINT_EPDISD;
         }
-        
+
         USB_OTG_DEV->DEACHMSK &= ~(USB_OTG_DAINTMSK_IEPM & (uint32_t)(1UL << (ep_idx & 0x07)));
         USB_OTG_DEV->DAINTMSK &= ~(USB_OTG_DAINTMSK_IEPM & (uint32_t)(1UL << (ep_idx & 0x07)));
         USB_OTG_INEP(ep_idx)->DIEPCTL = 0;

+ 4 - 0
port/dwc2/usb_dwc2_reg.h

@@ -241,6 +241,10 @@ typedef struct
 #define USB_OTG_DCFG_ERRATIM_Msk                 (0x1UL << USB_OTG_DCFG_ERRATIM_Pos) /*!< 0x00008000 */
 #define USB_OTG_DCFG_ERRATIM                     USB_OTG_DCFG_ERRATIM_Msk        /*!< Erratic error interrupt mask */
 
+#define USB_OTG_DCFG_DESCDMA_Pos                 (23U)
+#define USB_OTG_DCFG_DESCDMA_Msk                 (0x1UL << USB_OTG_DCFG_DESCDMA_Pos)
+#define USB_OTG_DCFG_DESCDMA                     USB_OTG_DCFG_DESCDMA_Msk
+
 #define USB_OTG_DCFG_PERSCHIVL_Pos               (24U)
 #define USB_OTG_DCFG_PERSCHIVL_Msk               (0x3UL << USB_OTG_DCFG_PERSCHIVL_Pos) /*!< 0x03000000 */
 #define USB_OTG_DCFG_PERSCHIVL                   USB_OTG_DCFG_PERSCHIVL_Msk    /*!< Periodic scheduling interval */

+ 1 - 1
port/ehci/usb_hc_ehci.c

@@ -1151,7 +1151,7 @@ int usbh_submit_urb(struct usbh_urb *urb)
 
     pipe = urb->pipe;
 
-    if (!pipe->inuse || !(EHCI_HCOR->portsc[0] & EHCI_PORTSC_CCS) || !pipe->hport->connected) {
+    if (!pipe->inuse /*|| !(EHCI_HCOR->portsc[pipe->hport->port-1] & EHCI_PORTSC_CCS)*/ || !pipe->hport->connected) {
         return -ENODEV;
     }
 

+ 4 - 3
third_party/rt-thread-4.1.1/dfs/udisk.c

@@ -15,6 +15,7 @@
 #include "usbh_msc.h"
 
 #define MAX_PARTITION_COUNT 5
+#define CONFIG_DFS_MOUNT_POINT "/"
 
 struct ustor_data {
     struct dfs_partition part;
@@ -251,7 +252,7 @@ rt_err_t rt_udisk_run(struct usbh_msc *msc_class)
 
             stor_r->dev_cnt++;
 
-            if (dfs_mount(stor_r->dev[i].parent.name, "/", "elm", 0, 0) == 0) {
+            if (dfs_mount(stor_r->dev[i].parent.name, CONFIG_DFS_MOUNT_POINT, "elm", 0, 0) == 0) {
                 rt_kprintf("udisk part %d mount successfully\n", i);
             } else {
                 rt_kprintf("udisk part %d mount failed\n", i);
@@ -285,7 +286,7 @@ rt_err_t rt_udisk_run(struct usbh_msc *msc_class)
                 rt_device_register(&stor_r->dev[0], dname, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE | RT_DEVICE_FLAG_STANDALONE);
 
                 stor_r->dev_cnt++;
-                if (dfs_mount(stor_r->dev[0].parent.name, "/", "elm", 0, 0) == 0) {
+                if (dfs_mount(stor_r->dev[0].parent.name, CONFIG_DFS_MOUNT_POINT, "elm", 0, 0) == 0) {
                     rt_kprintf("Mount FAT on Udisk successful.\n");
                 } else {
                     rt_kprintf("Mount FAT on Udisk failed.\n");
@@ -325,7 +326,7 @@ rt_err_t rt_udisk_stop(struct usbh_msc *msc_class)
         data = (struct ustor_data *)dev->user_data;
 
         /* unmount filesystem */
-        dfs_unmount("/");
+        dfs_unmount(CONFIG_DFS_MOUNT_POINT);
 
         /* delete semaphore */
         rt_sem_delete(data->part.lock);

+ 84 - 0
third_party/rt-thread-4.1.1/msh_cmd.c

@@ -0,0 +1,84 @@
+/**************************************************************************/ /**
+*
+* @copyright (C) 2019 Nuvoton Technology Corp. All rights reserved.
+*
+* SPDX-License-Identifier: Apache-2.0
+*
+* Change Logs:
+* Date            Author       Notes
+* 2023-8-9        Wayne        First version
+*
+******************************************************************************/
+
+#include <rtthread.h>
+
+#if defined(PKG_USING_CHERRYUSB)
+
+#if defined(PKG_CHERRYUSB_DEVICE_CDC_TEMPLATE)
+void cdc_acm_init(void);
+MSH_CMD_EXPORT(cdc_acm_init, start cdc_acm_init);
+#endif
+
+#if defined(PKG_CHERRYUSB_DEVICE_HID_MOUSE_TEMPLATE)
+void hid_mouse_init(void);
+void hid_mouse_test(void);
+
+MSH_CMD_EXPORT(hid_mouse_init, start hid_mouse_init);
+MSH_CMD_EXPORT(hid_mouse_test, start hid_mouse_test);
+#endif
+
+#if defined(PKG_CHERRYUSB_DEVICE_HID_KEYBOARD_TEMPLATE)
+void hid_keyboard_init(void);
+void hid_keyboard_test(void);
+
+MSH_CMD_EXPORT(hid_keyboard_init, start hid_keyboard_init);
+MSH_CMD_EXPORT(hid_keyboard_test, start hid_keyboard_test);
+#endif
+
+#if defined(PKG_CHERRYUSB_DEVICE_MSC_TEMPLATE)
+void msc_ram_init(void);
+MSH_CMD_EXPORT(msc_ram_init, start msc_ram_init);
+#endif
+
+#if defined(PKG_CHERRYUSB_DEVICE_RNDIS_TEMPLATE)
+void cdc_rndis_init(void);
+MSH_CMD_EXPORT(cdc_rndis_init, start cdc_rndis_init);
+#endif
+
+#if defined(PKG_CHERRYUSB_DEVICE_VIDEO_TEMPLATE)
+void video_init(void);
+void video_test(void);
+
+MSH_CMD_EXPORT(video_init, start video_init);
+MSH_CMD_EXPORT(video_test, start video_test);
+#endif
+
+#if defined(PKG_CHERRYUSB_DEVICE_AUDIO_V1_TEMPLATE)
+void audio_v1_init(void);
+void audio_v1_test(void);
+
+MSH_CMD_EXPORT(audio_v1_init, start audio_v1_init);
+MSH_CMD_EXPORT(audio_v1_test, start audio_v1_test);
+#endif
+
+#if defined(PKG_CHERRYUSB_DEVICE_AUDIO_V2_TEMPLATE)
+void audio_v2_init(void);
+void audio_v2_test(void);
+
+MSH_CMD_EXPORT(audio_v2_init, start audio_v2_init);
+MSH_CMD_EXPORT(audio_v2_test, start audio_v2_test);
+#endif
+
+#if defined(PKG_CHERRYUSB_HOST)
+void usbh_class_test(void);
+MSH_CMD_EXPORT(usbh_class_test, start usbh_class_test);
+
+int lsusb(int argc, char **argv);
+MSH_CMD_EXPORT(lsusb, start lsusb);
+
+int usbh_initialize(void);
+//INIT_APP_EXPORT(usbh_initialize);
+MSH_CMD_EXPORT(usbh_initialize, start usbh_initialize);
+#endif
+
+#endif

+ 77 - 62
third_party/rt-thread-4.1.1/rndis_host/rndis_host.c

@@ -8,12 +8,13 @@
 #include <netdev.h>
 
 /* define the rdnis device state*/
-#define RNDIS_BUS_UNINITIALIZED     0
-#define RNDIS_BUS_INITIALIZED       1
-#define RNDIS_INITIALIZED           2
-#define RNDIS_DATA_INITIALIZED      3
+#define RNDIS_BUS_UNINITIALIZED 0
+#define RNDIS_BUS_INITIALIZED   1
+#define RNDIS_INITIALIZED       2
+#define RNDIS_DATA_INITIALIZED  3
 
-#define USB_ETH_MTU               1500 + 14
+#define USB_ETH_MTU             (1500 + 14)
+#define RNDIS_THREAD_STACK_SIZE (4096)
 
 #define RNDIS_NET_DEV_NAME "u0"
 #define MAX_ADDR_LEN       6
@@ -27,8 +28,7 @@ struct usbh_user_rndis {
     void *user_data;
 };
 
-struct rndis_packet_msg
-{
+struct rndis_packet_msg {
     rt_uint32_t MessageType;
     rt_uint32_t MessageLength;
     rt_uint32_t DataOffset;
@@ -65,12 +65,12 @@ struct rt_rndis_eth {
 
     rt_uint32_t rndis_state;
     rt_thread_t rndis_recv;
-    rt_timer_t keepalive_timer;
+    rt_thread_t keepalive_timer;
 };
 typedef struct rt_rndis_eth *rt_rndis_eth_t;
 
-struct usbh_user_rndis *g_user_rndis;
-USB_NOCACHE_RAM_SECTION struct rt_rndis_eth usbh_rndis_eth_device;
+struct usbh_user_rndis *g_user_rndis = RT_NULL;
+USB_NOCACHE_RAM_SECTION struct rt_rndis_eth usbh_rndis_eth_device = { 0 };
 
 void hex_data_print(const char *name, const rt_uint8_t *buf, rt_size_t size)
 {
@@ -139,7 +139,7 @@ static rt_err_t rt_rndis_msg_data_send(struct usbh_user_rndis *rndis_class, rt_u
     ret = usbh_rndis_bulk_out_transfer(rndis_class->rndis_class, buffer, nbytes, 5000);
     rt_mutex_release(usbh_rndis_eth_device.rndis_mutex);
     if (ret != nbytes) {
-        rt_kprintf("rndis msg send fial\r\n");
+        rt_kprintf("rndis msg send fail(%d %d)\r\n", ret, nbytes);
     }
     return ret;
 }
@@ -187,55 +187,62 @@ static rt_err_t rt_rndis_keepalive_msg(struct usbh_user_rndis *rndis_class)
  */
 void rt_usbh_rndis_data_recv_entry(void *pdata)
 {
-    int ret = 0;
     struct usbh_user_rndis *rndis_class = (struct usbh_user_rndis *)pdata;
-    rt_rndis_eth_t device = RT_NULL;
-    device = (rt_rndis_eth_t)rndis_class->user_data;
-    err_t err;
-    struct pbuf *p;
-    rndis_data_packet_t *pmsg;
-    int pmg_offset;
-    int payload_offset;
-
-    if ((pdata == RT_NULL) || (rndis_class == RT_NULL) ||
-        (device == RT_NULL)) {
-        return;
-    }
+    rt_rndis_eth_t device = (rt_rndis_eth_t)rndis_class->user_data;
+    rndis_data_packet_t sRndisDataPkt;
 
-    device->rx_buf_ptr = device->rx_buffer;
+    //device->rx_buf_ptr = device->rx_buffer;
 
     while (1) {
-        pmg_offset = 0;
-        payload_offset = 0;
+        int ret = 0;
+        int pmg_offset = 0;
+        int payload_offset = 0;
         ret = usbh_rndis_bulk_in_transfer(rndis_class->rndis_class, device->rx_buf_ptr, RNDIS_ETH_BUFFER_LEN, RT_WAITING_FOREVER);
         if (ret <= 0) {
             rt_thread_mdelay(1);
             continue;
         }
+
         while (ret > 0) {
-            pmsg = (rndis_data_packet_t *)(device->rx_buf_ptr + pmg_offset);
+            rndis_data_packet_t *pmsg = (rndis_data_packet_t *)(device->rx_buf_ptr + pmg_offset);
+            if (pmg_offset & 0x3) {
+                /* Not word-aligned case */
+                //rt_kprintf("pmsg@%08x Not word-aligned case\n", pmsg);
+
+                rt_memcpy(&sRndisDataPkt, pmsg, sizeof(rndis_data_packet_t));
+                pmsg = &sRndisDataPkt;
+            }
+
             if (pmsg->MessageType == REMOTE_NDIS_PACKET_MSG) {
                 /* allocate buffer */
-                p = pbuf_alloc(PBUF_RAW, pmsg->DataLength, PBUF_POOL);
+                struct pbuf *p = pbuf_alloc(PBUF_RAW, pmsg->DataLength, PBUF_POOL);
                 if (p != NULL) {
                     struct pbuf *q;
                     for (q = p; q != NULL; q = q->next) {
-                        /* Copy the received frame into buffer from memory pointed by the current ETHERNET DMA Rx descriptor */
-                        memcpy(q->payload, ((uint8_t *)(&pmsg->DataOffset) + pmsg->DataOffset + payload_offset), q->len);
+                        void *src = (void *)(device->rx_buf_ptr + pmg_offset + (2 * sizeof(uint32_t)) + pmsg->DataOffset + payload_offset);
+
+                        rt_memcpy(q->payload,
+                                  src,
+                                  q->len);
+
                         payload_offset += q->len;
                     }
                     /* entry point to the LwIP stack */
                     /* notify to upper layer */
-                    if(device->parent.netif->input(p, device->parent.netif)!= ERR_OK )
-                    {
+
+                    if (device->parent.netif->input(p, device->parent.netif) != ERR_OK) {
                         LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: Input error\n"));
                         pbuf_free(p);
                         p = NULL;
                     }
-                    pmg_offset += pmsg->MessageLength;
-                    ret -= pmsg->MessageLength;
                 }
+            } else {
+                rt_kprintf("pmsg->MessageType=%d\n", pmsg->MessageType);
+                break;
             }
+
+            pmg_offset += pmsg->MessageLength;
+            ret -= pmsg->MessageLength;
         }
     }
 }
@@ -243,15 +250,14 @@ void rt_usbh_rndis_data_recv_entry(void *pdata)
 void rt_rndis_dev_keepalive_timeout(void *pdata)
 {
     struct usbh_user_rndis *rndis_class = (struct usbh_user_rndis *)pdata;
-    static rt_uint32_t keepalive_error = 0;
 
-    if (rndis_class == RT_NULL) {
-        return;
-    }
+    while (1) {
+        rt_thread_mdelay(RT_TICK_PER_SECOND * RNDIS_DEV_KEEPALIVE_TIMEOUT / 1000);
 
-    rt_mutex_take(usbh_rndis_eth_device.rndis_mutex, RT_WAITING_FOREVER);
-    rt_rndis_keepalive_msg(rndis_class);
-    rt_mutex_release(usbh_rndis_eth_device.rndis_mutex);
+        rt_mutex_take(usbh_rndis_eth_device.rndis_mutex, RT_WAITING_FOREVER);
+        rt_rndis_keepalive_msg(rndis_class);
+        rt_mutex_release(usbh_rndis_eth_device.rndis_mutex);
+    }
 }
 
 /**
@@ -274,22 +280,24 @@ rt_err_t rt_rndis_run(struct usbh_user_rndis *rndis_class)
      to reset the device, or to tear down the data and control channels*/
     usbh_rndis_eth_device.rndis_state = RNDIS_INITIALIZED;
 
-    usbh_rndis_eth_device.keepalive_timer = rt_timer_create("keeplive", rt_rndis_dev_keepalive_timeout,
-                                                            rndis_class,
-                                                            RT_TICK_PER_SECOND * RNDIS_DEV_KEEPALIVE_TIMEOUT / 1000,
-                                                            RT_TIMER_FLAG_PERIODIC | RT_TIMER_FLAG_SOFT_TIMER);
+    usbh_rndis_eth_device.keepalive_timer = rt_thread_create("keeplive",
+                                                             (void (*)(void *parameter))rt_rndis_dev_keepalive_timeout,
+                                                             rndis_class,
+                                                             RNDIS_THREAD_STACK_SIZE,
+                                                             5,
+                                                             20);
 
     if (usbh_rndis_eth_device.keepalive_timer == RT_NULL) {
         ret = -RT_ENOMEM;
         goto __exit;
     }
-    rt_timer_start(usbh_rndis_eth_device.keepalive_timer);
+
     rndis_class->user_data = (struct rt_device *)&usbh_rndis_eth_device;
 
-    usbh_rndis_eth_device.rndis_recv = rt_thread_create("rndis",
+    usbh_rndis_eth_device.rndis_recv = rt_thread_create("rndis_recv",
                                                         (void (*)(void *parameter))rt_usbh_rndis_data_recv_entry,
                                                         rndis_class,
-                                                        1024 + 512,
+                                                        RNDIS_THREAD_STACK_SIZE,
                                                         5,
                                                         20);
 
@@ -301,8 +309,6 @@ rt_err_t rt_rndis_run(struct usbh_user_rndis *rndis_class)
     /*the LINK SPEED is 100Mbps*/
     usbh_rndis_eth_device.rndis_speed = rndis_class->rndis_class->link_speed;
 
-    eth_device_linkchange(&usbh_rndis_eth_device.parent, rndis_class->rndis_class->link_status);
-
     for (j = 0; j < MAX_ADDR_LEN; j++) {
         usbh_rndis_eth_device.dev_addr[j] = rndis_class->rndis_class->mac[j];
     }
@@ -316,6 +322,8 @@ __exit:
         it can exchange REMOTE_NDIS_PACKET_MSG messages for network data transfer with the device on the data channel*/
         usbh_rndis_eth_device.rndis_state = RNDIS_DATA_INITIALIZED;
         rt_thread_startup(usbh_rndis_eth_device.rndis_recv);
+        rt_thread_startup(usbh_rndis_eth_device.keepalive_timer);
+
         RNDIS_DEV_PRINTF("rndis dev start!\n");
         usbh_rndis_eth_device.rndis_class = rndis_class;
 
@@ -332,8 +340,10 @@ void usbh_rndis_run(struct usbh_rndis *rndis_class)
     RT_ASSERT(g_user_rndis != RT_NULL);
     g_user_rndis->rndis_class = rndis_class;
     if (rt_rndis_run(g_user_rndis) == RT_EOK) {
+        /* Allocate ethernet resource. */
         eth_device_init(&usbh_rndis_eth_device.parent, RNDIS_NET_DEV_NAME);
-        eth_device_linkchange(&usbh_rndis_eth_device.parent, RT_FALSE);
+        //eth_device_linkchange(&usbh_rndis_eth_device.parent, RT_FALSE);
+        eth_device_linkchange(&usbh_rndis_eth_device.parent, RT_TRUE);
     }
 }
 
@@ -348,16 +358,17 @@ rt_err_t rt_rndis_stop(struct usbh_user_rndis *rndis_class)
         info->rndis_recv = RT_NULL;
     }
     eth_device_linkchange(&usbh_rndis_eth_device.parent, RT_FALSE);
+
+    /* Destroy ethernet resource. */
+    eth_device_deinit(&usbh_rndis_eth_device.parent);
+
     usbh_rndis_eth_device.rndis_class = RT_NULL;
 
     /*disable the other thread etx call the rt_timer_start(rndis->keepalive_timer) cause the RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer)*/
-    rt_mutex_take(usbh_rndis_eth_device.rndis_mutex, RT_WAITING_FOREVER);
     if (info->keepalive_timer) {
-        rt_timer_stop(info->keepalive_timer);
-        rt_timer_delete(info->keepalive_timer);
+        rt_thread_delete(info->keepalive_timer);
         info->keepalive_timer = RT_NULL;
     }
-    rt_mutex_release(usbh_rndis_eth_device.rndis_mutex);
 
     info->rndis_state = RNDIS_BUS_UNINITIALIZED;
 
@@ -370,6 +381,7 @@ void usbh_rndis_stop(struct usbh_rndis *rndis_class)
     RT_ASSERT(g_user_rndis != RT_NULL);
     rt_rndis_stop(g_user_rndis);
     usb_free(g_user_rndis);
+    g_user_rndis = RT_NULL;
 }
 /**
  * This function rndis eth device.
@@ -428,7 +440,6 @@ static rt_err_t rt_rndis_eth_control(rt_device_t dev, int cmd, void *args)
 
 /* ethernet device interface */
 
-
 /* transmit packet. */
 extern int usbh_rndis_query_msg_transfer(struct usbh_rndis *rndis_class,
                                          uint32_t oid, uint32_t query_len,
@@ -455,7 +466,7 @@ rt_err_t rt_rndis_eth_tx(rt_device_t dev, struct pbuf *p)
             break;
         }
         RNDIS_DEV_PRINTF("linkdown, drop pkg\r\n");
-        while(recount--) {
+        while (recount--) {
             ret = usbh_rndis_query_msg_transfer(device->rndis_class->rndis_class, OID_GEN_MEDIA_CONNECT_STATUS, sizeof(data), data, &info_len);
             if (ret < 0) {
                 return -EBUSY;
@@ -507,6 +518,7 @@ rt_err_t rt_rndis_eth_tx(rt_device_t dev, struct pbuf *p)
     }
 
     if (device->frame_debug == RT_TRUE) {
+        rt_kprintf("msg @ %08x\n", msg);
         hex_data_print("rndis eth tx", (rt_uint8_t *)msg, msg->MessageLength);
     }
     result = rt_rndis_msg_data_send(device->rndis_class, (rt_uint8_t *)msg, msg->MessageLength);
@@ -527,13 +539,16 @@ const static struct rt_device_ops rndis_device_ops = {
 #endif
 #endif
 
-__WEAK void lowlevel_usb_init(void)
+__WEAK void
+lowlevel_usb_init(void)
 {
-
 }
 
 int usbh_rndis_eth_device_init(void)
 {
+    /* Initialize all data member in usbh_rndis_eth_device */
+    rt_memset(&usbh_rndis_eth_device, 0, sizeof(struct rt_rndis_eth));
+
     /* OUI 00-00-00, only for test. */
     usbh_rndis_eth_device.dev_addr[0] = 0xFF;
     usbh_rndis_eth_device.dev_addr[1] = 0xFF;
@@ -573,9 +588,9 @@ int usbh_rndis_eth_device_init(void)
 
     lowlevel_usb_init();
 
-    return RT_EOK;
+    return 0;
 }
-INIT_APP_EXPORT(usbh_rndis_eth_device_init);
+INIT_DEVICE_EXPORT(usbh_rndis_eth_device_init);
 
 /*********************************************************************************************************
 ** Function name        eth_rndis_frame_debug()