summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsakumisu <[email protected]>2024-05-23 23:14:53 +0800
committersakumisu <[email protected]>2024-05-24 22:49:18 +0800
commit865d2f5d96942222a2af3102cf74519c7287dd6c (patch)
tree6a2c1e9fb5e9e4b7c1e8f15f59b34d419287f0ca
parent3336919e0df469fb0ab18f580ecb3d31fdd6f949 (diff)
refactor(platform): update platform support
-rw-r--r--Kconfig.cherryusb60
-rw-r--r--README.md17
-rw-r--r--README_zh.md15
-rw-r--r--SConscript15
-rw-r--r--class/cdc/usbh_cdc_ecm.c48
-rw-r--r--class/cdc/usbh_cdc_ecm.h10
-rw-r--r--class/cdc/usbh_cdc_ncm.c49
-rw-r--r--class/cdc/usbh_cdc_ncm.h10
-rw-r--r--class/vendor/net/usbh_asix.c71
-rw-r--r--class/vendor/net/usbh_asix.h10
-rw-r--r--class/vendor/net/usbh_rtl8152.c53
-rw-r--r--class/vendor/net/usbh_rtl8152.h10
-rw-r--r--class/wireless/usbh_rndis.c59
-rw-r--r--class/wireless/usbh_rndis.h10
-rw-r--r--platform/README.md14
-rw-r--r--platform/none/usbh_fatfs.c (renamed from third_party/fatfs-0.14/source/port/fatfs_usbh.c)8
-rw-r--r--platform/none/usbh_lwip.c504
-rw-r--r--platform/nuttx/usbh_fs.c189
-rw-r--r--platform/nuttx/usbh_net.c165
-rw-r--r--platform/rtthread/usb_check.c17
-rw-r--r--platform/rtthread/usb_msh.c (renamed from third_party/rt-thread-5.0/usb_msh.c)0
-rw-r--r--platform/rtthread/usbh_dfs.c (renamed from third_party/rt-thread-5.0/dfs_usbh_msc.c)2
-rw-r--r--platform/rtthread/usbh_lwip.c415
-rw-r--r--platform/threadx/.gitkeep0
-rw-r--r--third_party/rt-thread-5.0/usb_check.c43
25 files changed, 1430 insertions, 364 deletions
diff --git a/Kconfig.cherryusb b/Kconfig.cherryusb
index c559fa83..aae7cb00 100644
--- a/Kconfig.cherryusb
+++ b/Kconfig.cherryusb
@@ -197,19 +197,22 @@ if CHERRYUSB
prompt "Enable usb msc driver"
default n
- config CHERRYUSB_HOST_CDC_RNDIS
+ config CHERRYUSB_HOST_CDC_ECM
bool
- prompt "Enable usb rndis driver"
+ prompt "Enable usb cdc ecm driver"
+ select USBHOST_PLATFORM_CDC_ECM
default n
- config CHERRYUSB_HOST_CDC_ECM
+ config CHERRYUSB_HOST_CDC_RNDIS
bool
- prompt "Enable usb cdc ecm driver"
+ prompt "Enable usb rndis driver"
+ select USBHOST_PLATFORM_CDC_RNDIS
default n
config CHERRYUSB_HOST_CDC_NCM
bool
prompt "Enable usb cdc ncm driver"
+ select USBHOST_PLATFORM_CDC_NCM
default n
config CHERRYUSB_HOST_VIDEO
@@ -230,11 +233,13 @@ if CHERRYUSB
config CHERRYUSB_HOST_ASIX
bool
prompt "Enable usb asix driver"
+ select USBHOST_PLATFORM_ASIX
default n
config CHERRYUSB_HOST_RTL8152
bool
prompt "Enable usb rtl8152 driver"
+ select USBHOST_PLATFORM_RTL8152
default n
config CHERRYUSB_HOST_FTDI
@@ -252,6 +257,26 @@ if CHERRYUSB
prompt "Enable usb cp210x driver"
default n
+ config CHERRYUSB_HOST_PL2303
+ bool
+ prompt "Enable usb pl2303 driver"
+ default n
+
+ config USBHOST_PLATFORM_CDC_ECM
+ bool
+
+ config USBHOST_PLATFORM_CDC_RNDIS
+ bool
+
+ config USBHOST_PLATFORM_CDC_NCM
+ bool
+
+ config USBHOST_PLATFORM_ASIX
+ bool
+
+ config USBHOST_PLATFORM_RTL152
+ bool
+
config CHERRYUSB_HOST_TEMPLATE
bool
prompt "Use usb host template"
@@ -270,34 +295,9 @@ if CHERRYUSB
depends on CHERRYUSB_HOST_HID
config TEST_USBH_MSC
int
- prompt "demo for test msc, do not enable because it has used dfs instead"
+ prompt "demo for test msc"
default 0
depends on CHERRYUSB_HOST_MSC
- config TEST_USBH_CDC_ECM
- int
- prompt "demo for test cdc ecm"
- default 0
- depends on CHERRYUSB_HOST_CDC_ECM
- config TEST_USBH_CDC_NCM
- int
- prompt "demo for test cdc ncm"
- default 0
- depends on CHERRYUSB_HOST_CDC_NCM
- config TEST_USBH_RNDIS
- int
- prompt "demo for test cdc rndis"
- default 0
- depends on CHERRYUSB_HOST_CDC_RNDIS
- config TEST_USBH_ASIX
- int
- prompt "demo for test asix"
- default 0
- depends on CHERRYUSB_HOST_ASIX
- config TEST_USBH_RTL8152
- int
- prompt "demo for test rtl8152"
- default 0
- depends on CHERRYUSB_HOST_RTL8152
endif
endif
diff --git a/README.md b/README.md
index 2c3f2900..77daee4b 100644
--- a/README.md
+++ b/README.md
@@ -36,27 +36,14 @@ Taking into account USB performance issues and trying to achieve the theoretical
## Directoy Structure
-```
-.
-├── class
-├── common
-├── core
-├── demo
-├── docs
-├── osal
-├── packet capture
-└── port
-└── tools
-
-```
-
| Directory | Description |
|:-------------:|:---------------------------:|
|class | usb class driver |
|common | usb spec macros and utils |
|core | usb core implementation |
-|demo | different chips demo |
+|demo | usb device and host demo |
|osal | os wrapper |
+|platform | class support for other os |
|docs | doc for guiding |
|port | usb dcd and hcd porting |
|tools | tool url |
diff --git a/README_zh.md b/README_zh.md
index b6b26c1e..a59649e0 100644
--- a/README_zh.md
+++ b/README_zh.md
@@ -36,26 +36,15 @@ CherryUSB 是一个小而美的、可移植性高的、用于嵌入式系统(带
## 目录结构
-```
-.
-├── class
-├── common
-├── core
-├── demo
-├── docs
-├── osal
-└── port
-└── tools
-```
-
| 目录名 | 描述 |
|:-------------:|:-------------------------------:|
|class | usb class 类主从驱动 |
|common | usb spec 定义、常用宏、标准接口定义 |
|core | usb 主从协议栈核心实现 |
-|demo | 示例 |
+|demo | 主从 class demo |
|docs | 文档 |
|osal | os 封装层 |
+|platform | 其他 os 全家桶适配 |
|port | usb 主从需要实现的 porting 接口 |
|tools | 工具链接 |
diff --git a/SConscript b/SConscript
index c4998332..ee49e272 100644
--- a/SConscript
+++ b/SConscript
@@ -191,11 +191,18 @@ if GetDepend(['PKG_CHERRYUSB_HOST']):
if GetDepend(['PKG_CHERRYUSB_HOST_TEMPLATE']):
src += Glob('demo/usb_host.c')
- if GetDepend('RT_USING_DFS'):
- src += Glob('third_party/rt-thread-5.0/dfs_usbh_msc.c')
+ if GetDepend('RT_USING_DFS') and GetDepend(['PKG_CHERRYUSB_HOST_MSC']):
+ src += Glob('platform/rtthread/usbh_dfs.c')
-src += Glob('third_party/rt-thread-5.0/usb_msh.c')
-src += Glob('third_party/rt-thread-5.0/usb_check.c')
+ if GetDepend('PKG_CHERRYUSB_HOST_CDC_ECM') \
+ or GetDepend('PKG_CHERRYUSB_HOST_CDC_RNDIS') \
+ or GetDepend('PKG_CHERRYUSB_HOST_CDC_NCM') \
+ or GetDepend('PKG_CHERRYUSB_HOST_CDC_ASIX') \
+ or GetDepend('PKG_CHERRYUSB_HOST_CDC_RTL8152'):
+ src += Glob('platform/rtthread/usbh_lwip.c')
+
+src += Glob('platform/rtthread/usb_msh.c')
+src += Glob('platform/rtthread/usb_check.c')
group = DefineGroup('CherryUSB', src, depend = ['PKG_USING_CHERRYUSB'], CPPPATH = path, CPPDEFINES = CPPDEFINES)
diff --git a/class/cdc/usbh_cdc_ecm.c b/class/cdc/usbh_cdc_ecm.c
index b115bcf8..5e3ae7bc 100644
--- a/class/cdc/usbh_cdc_ecm.c
+++ b/class/cdc/usbh_cdc_ecm.c
@@ -230,14 +230,6 @@ void usbh_cdc_ecm_rx_thread(void *argument)
{
uint32_t g_cdc_ecm_rx_length;
int ret;
- err_t err;
- struct pbuf *p;
-#if LWIP_TCPIP_CORE_LOCKING_INPUT
- pbuf_type type = PBUF_ROM;
-#else
- pbuf_type type = PBUF_POOL;
-#endif
- struct netif *netif = (struct netif *)argument;
USB_LOG_INFO("Create cdc ecm rx thread\r\n");
// clang-format off
@@ -269,23 +261,9 @@ find_class:
if (g_cdc_ecm_rx_length % USB_GET_MAXPACKETSIZE(g_cdc_ecm_class.bulkin->wMaxPacketSize)) {
USB_LOG_DBG("rxlen:%d\r\n", g_cdc_ecm_rx_length);
- p = pbuf_alloc(PBUF_RAW, g_cdc_ecm_rx_length, type);
- if (p != NULL) {
-#if LWIP_TCPIP_CORE_LOCKING_INPUT
- p->payload = g_cdc_ecm_rx_buffer;
-#else
- memcpy(p->payload, (uint8_t *)g_cdc_ecm_rx_buffer, g_cdc_ecm_rx_length);
-#endif
- g_cdc_ecm_rx_length = 0;
+ usbh_cdc_ecm_eth_input(g_cdc_ecm_rx_buffer, g_cdc_ecm_rx_length);
- err = netif->input(p, netif);
- if (err != ERR_OK) {
- pbuf_free(p);
- }
- } else {
- g_cdc_ecm_rx_length = 0;
- USB_LOG_ERR("No memory to alloc pbuf for cdc ecm rx\r\n");
- }
+ g_cdc_ecm_rx_length = 0;
} else {
/* read continue util read short packet */
if (g_cdc_ecm_rx_length > CONFIG_USBHOST_CDC_ECM_ETH_MAX_SIZE) {
@@ -301,30 +279,20 @@ delete:
// clang-format on
}
-err_t usbh_cdc_ecm_linkoutput(struct netif *netif, struct pbuf *p)
+int usbh_cdc_ecm_eth_output(uint8_t *buf, uint32_t buflen)
{
- int ret;
- struct pbuf *q;
uint8_t *buffer = g_cdc_ecm_tx_buffer;
if (g_cdc_ecm_class.connect_status == false) {
- return ERR_BUF;
- }
-
- for (q = p; q != NULL; q = q->next) {
- memcpy(buffer, q->payload, q->len);
- buffer += q->len;
+ return -USB_ERR_NOTCONN;
}
- USB_LOG_DBG("txlen:%d\r\n", p->tot_len);
+ memcpy(buffer, buf, buflen);
- usbh_bulk_urb_fill(&g_cdc_ecm_class.bulkout_urb, g_cdc_ecm_class.hport, g_cdc_ecm_class.bulkout, g_cdc_ecm_tx_buffer, p->tot_len, USB_OSAL_WAITING_FOREVER, NULL, NULL);
- ret = usbh_submit_urb(&g_cdc_ecm_class.bulkout_urb);
- if (ret < 0) {
- return ERR_BUF;
- }
+ USB_LOG_DBG("txlen:%d\r\n", buflen);
- return ERR_OK;
+ usbh_bulk_urb_fill(&g_cdc_ecm_class.bulkout_urb, g_cdc_ecm_class.hport, g_cdc_ecm_class.bulkout, g_cdc_ecm_tx_buffer, buflen, USB_OSAL_WAITING_FOREVER, NULL, NULL);
+ return usbh_submit_urb(&g_cdc_ecm_class.bulkout_urb);
}
__WEAK void usbh_cdc_ecm_run(struct usbh_cdc_ecm *cdc_ecm_class)
diff --git a/class/cdc/usbh_cdc_ecm.h b/class/cdc/usbh_cdc_ecm.h
index 6066bd05..d965ac88 100644
--- a/class/cdc/usbh_cdc_ecm.h
+++ b/class/cdc/usbh_cdc_ecm.h
@@ -8,9 +8,6 @@
#include "usb_cdc.h"
-#include "lwip/netif.h"
-#include "lwip/pbuf.h"
-
struct usbh_cdc_ecm {
struct usbh_hubport *hport;
struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */
@@ -29,10 +26,6 @@ struct usbh_cdc_ecm {
uint16_t max_segment_size;
uint32_t speed[2];
- ip_addr_t ipaddr;
- ip_addr_t netmask;
- ip_addr_t gateway;
-
void *user_data;
};
@@ -45,7 +38,8 @@ int usbh_cdc_ecm_get_connect_status(struct usbh_cdc_ecm *cdc_ecm_class);
void usbh_cdc_ecm_run(struct usbh_cdc_ecm *cdc_ecm_class);
void usbh_cdc_ecm_stop(struct usbh_cdc_ecm *cdc_ecm_class);
-err_t usbh_cdc_ecm_linkoutput(struct netif *netif, struct pbuf *p);
+int usbh_cdc_ecm_eth_output(uint8_t *buf, uint32_t buflen);
+void usbh_cdc_ecm_eth_input(uint8_t *buf, uint32_t buflen);
void usbh_cdc_ecm_rx_thread(void *argument);
#ifdef __cplusplus
diff --git a/class/cdc/usbh_cdc_ncm.c b/class/cdc/usbh_cdc_ncm.c
index f6e43af3..4f13f791 100644
--- a/class/cdc/usbh_cdc_ncm.c
+++ b/class/cdc/usbh_cdc_ncm.c
@@ -248,14 +248,6 @@ void usbh_cdc_ncm_rx_thread(void *argument)
{
uint32_t g_cdc_ncm_rx_length;
int ret;
- err_t err;
- struct pbuf *p;
-#if LWIP_TCPIP_CORE_LOCKING_INPUT
- pbuf_type type = PBUF_ROM;
-#else
- pbuf_type type = PBUF_POOL;
-#endif
- struct netif *netif = (struct netif *)argument;
USB_LOG_INFO("Create cdc ncm rx thread\r\n");
// clang-format off
@@ -311,20 +303,8 @@ find_class:
if (ndp16_datagram->wDatagramIndex && ndp16_datagram->wDatagramLength) {
USB_LOG_DBG("ndp16_datagram index:%02x, length:%02x\r\n", ndp16_datagram->wDatagramIndex, ndp16_datagram->wDatagramLength);
- p = pbuf_alloc(PBUF_RAW, ndp16_datagram->wDatagramLength, type);
- if (p != NULL) {
-#if LWIP_TCPIP_CORE_LOCKING_INPUT
- p->payload = (uint8_t *)&g_cdc_ncm_rx_buffer[ndp16_datagram->wDatagramIndex];
-#else
- memcpy(p->payload, (uint8_t *)&g_cdc_ncm_rx_buffer[ndp16_datagram->wDatagramIndex], ndp16_datagram->wDatagramLength);
-#endif
- err = netif->input(p, netif);
- if (err != ERR_OK) {
- pbuf_free(p);
- }
- } else {
- USB_LOG_ERR("No memory to alloc pbuf for cdc ncm rx\r\n");
- }
+ uint8_t *buf = (uint8_t *)&g_cdc_ncm_rx_buffer[ndp16_datagram->wDatagramIndex];
+ usbh_cdc_ncm_eth_input(buf, ndp16_datagram->wDatagramLength);
}
}
@@ -344,15 +324,13 @@ delete:
// clang-format on
}
-err_t usbh_cdc_ncm_linkoutput(struct netif *netif, struct pbuf *p)
+int usbh_cdc_ncm_eth_output(uint8_t *buf, uint32_t buflen)
{
- int ret;
- struct pbuf *q;
uint8_t *buffer;
struct cdc_ncm_ndp16_datagram *ndp16_datagram;
if (g_cdc_ncm_class.connect_status == false) {
- return ERR_BUF;
+ return -USB_ERR_NOTCONN;
}
struct cdc_ncm_nth16 *nth16 = (struct cdc_ncm_nth16 *)&g_cdc_ncm_tx_buffer[0];
@@ -360,8 +338,8 @@ err_t usbh_cdc_ncm_linkoutput(struct netif *netif, struct pbuf *p)
nth16->dwSignature = CDC_NCM_NTH16_SIGNATURE;
nth16->wHeaderLength = 12;
nth16->wSequence = g_cdc_ncm_class.bulkout_sequence++;
- nth16->wBlockLength = 16 + 16 + USB_ALIGN_UP(p->tot_len, 4);
- nth16->wNdpIndex = 16 + USB_ALIGN_UP(p->tot_len, 4);
+ nth16->wBlockLength = 16 + 16 + USB_ALIGN_UP(buflen, 4);
+ nth16->wNdpIndex = 16 + USB_ALIGN_UP(buflen, 4);
struct cdc_ncm_ndp16 *ndp16 = (struct cdc_ncm_ndp16 *)&g_cdc_ncm_tx_buffer[nth16->wNdpIndex];
@@ -371,28 +349,19 @@ err_t usbh_cdc_ncm_linkoutput(struct netif *netif, struct pbuf *p)
ndp16_datagram = (struct cdc_ncm_ndp16_datagram *)&g_cdc_ncm_tx_buffer[nth16->wNdpIndex + 8 + 4 * 0];
ndp16_datagram->wDatagramIndex = 16;
- ndp16_datagram->wDatagramLength = p->tot_len;
+ ndp16_datagram->wDatagramLength = buflen;
ndp16_datagram = (struct cdc_ncm_ndp16_datagram *)&g_cdc_ncm_tx_buffer[nth16->wNdpIndex + 8 + 4 * 1];
ndp16_datagram->wDatagramIndex = 0;
ndp16_datagram->wDatagramLength = 0;
buffer = &g_cdc_ncm_tx_buffer[16];
-
- for (q = p; q != NULL; q = q->next) {
- memcpy(buffer, q->payload, q->len);
- buffer += q->len;
- }
+ memcpy(buffer, buf, buflen);
USB_LOG_DBG("txlen:%d\r\n", nth16->wBlockLength);
usbh_bulk_urb_fill(&g_cdc_ncm_class.bulkout_urb, g_cdc_ncm_class.hport, g_cdc_ncm_class.bulkout, g_cdc_ncm_tx_buffer, nth16->wBlockLength, USB_OSAL_WAITING_FOREVER, NULL, NULL);
- ret = usbh_submit_urb(&g_cdc_ncm_class.bulkout_urb);
- if (ret < 0) {
- return ERR_BUF;
- }
-
- return ERR_OK;
+ return usbh_submit_urb(&g_cdc_ncm_class.bulkout_urb);
}
__WEAK void usbh_cdc_ncm_run(struct usbh_cdc_ncm *cdc_ncm_class)
diff --git a/class/cdc/usbh_cdc_ncm.h b/class/cdc/usbh_cdc_ncm.h
index b3cc7d49..5f069401 100644
--- a/class/cdc/usbh_cdc_ncm.h
+++ b/class/cdc/usbh_cdc_ncm.h
@@ -8,9 +8,6 @@
#include "usb_cdc.h"
-#include "lwip/netif.h"
-#include "lwip/pbuf.h"
-
struct usbh_cdc_ncm {
struct usbh_hubport *hport;
struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */
@@ -33,10 +30,6 @@ struct usbh_cdc_ncm {
uint16_t max_segment_size;
uint32_t speed[2];
- ip_addr_t ipaddr;
- ip_addr_t netmask;
- ip_addr_t gateway;
-
void *user_data;
};
@@ -49,7 +42,8 @@ int usbh_cdc_ncm_get_connect_status(struct usbh_cdc_ncm *cdc_ncm_class);
void usbh_cdc_ncm_run(struct usbh_cdc_ncm *cdc_ncm_class);
void usbh_cdc_ncm_stop(struct usbh_cdc_ncm *cdc_ncm_class);
-err_t usbh_cdc_ncm_linkoutput(struct netif *netif, struct pbuf *p);
+int usbh_cdc_ncm_eth_output(uint8_t *buf, uint32_t buflen);
+void usbh_cdc_ncm_eth_input(uint8_t *buf, uint32_t buflen);
void usbh_cdc_ncm_rx_thread(void *argument);
#ifdef __cplusplus
diff --git a/class/vendor/net/usbh_asix.c b/class/vendor/net/usbh_asix.c
index a820f4da..62d78ec3 100644
--- a/class/vendor/net/usbh_asix.c
+++ b/class/vendor/net/usbh_asix.c
@@ -653,16 +653,8 @@ void usbh_asix_rx_thread(void *argument)
{
uint32_t g_asix_rx_length;
int ret;
- err_t err;
uint16_t len;
uint16_t len_crc;
- struct pbuf *p;
-#if LWIP_TCPIP_CORE_LOCKING_INPUT
- pbuf_type type = PBUF_ROM;
-#else
- pbuf_type type = PBUF_POOL;
-#endif
- struct netif *netif = (struct netif *)argument;
USB_LOG_INFO("Create asix rx thread\r\n");
// clang-format off
@@ -702,23 +694,9 @@ find_class:
USB_LOG_DBG("rxlen:%d\r\n", g_asix_rx_length);
- p = pbuf_alloc(PBUF_RAW, len, type);
- if (p != NULL) {
-#if LWIP_TCPIP_CORE_LOCKING_INPUT
- p->payload = (uint8_t *)&g_asix_rx_buffer[4];
-#else
- memcpy(p->payload, (uint8_t *)&g_asix_rx_buffer[4], len);
-#endif
- g_asix_rx_length = 0;
-
- err = netif->input(p, netif);
- if (err != ERR_OK) {
- pbuf_free(p);
- }
- } else {
- g_asix_rx_length = 0;
- USB_LOG_ERR("No memory to alloc pbuf for asix rx\r\n");
- }
+ uint8_t *buf = (uint8_t *)&g_asix_rx_buffer[4];
+ usbh_asix_eth_input(buf, len);
+ g_asix_rx_length = 0;
} else {
if (g_asix_rx_length > CONFIG_USBHOST_ASIX_ETH_MAX_SIZE) {
USB_LOG_ERR("Rx packet is overflow\r\n");
@@ -733,46 +711,37 @@ delete:
// clang-format on
}
-err_t usbh_asix_linkoutput(struct netif *netif, struct pbuf *p)
+int usbh_asix_eth_output(uint8_t *buf, uint32_t buflen)
{
- int ret;
- struct pbuf *q;
uint16_t actual_len;
- uint8_t *buffer = &g_asix_tx_buffer[4];
+ uint8_t *buffer;
if (g_asix_class.connect_status == false) {
- return ERR_BUF;
+ return -USB_ERR_NOTCONN;
}
- for (q = p; q != NULL; q = q->next) {
- memcpy(buffer, q->payload, q->len);
- buffer += q->len;
- }
+ buffer = &g_asix_tx_buffer[4];
+ memcpy(buffer, buf, buflen);
- g_asix_tx_buffer[0] = p->tot_len & 0xff;
- g_asix_tx_buffer[1] = (p->tot_len >> 8) & 0xff;
+ g_asix_tx_buffer[0] = buflen & 0xff;
+ g_asix_tx_buffer[1] = (buflen >> 8) & 0xff;
g_asix_tx_buffer[2] = ~g_asix_tx_buffer[0];
g_asix_tx_buffer[3] = ~g_asix_tx_buffer[1];
- if (!(p->tot_len + 4) % USB_GET_MAXPACKETSIZE(g_asix_class.bulkout->wMaxPacketSize)) {
- USB_LOG_DBG("txlen:%d\r\n", p->tot_len + 8);
- g_asix_tx_buffer[p->tot_len + 4 + 0] = 0x00;
- g_asix_tx_buffer[p->tot_len + 4 + 1] = 0x00;
- g_asix_tx_buffer[p->tot_len + 4 + 2] = 0xff;
- g_asix_tx_buffer[p->tot_len + 4 + 3] = 0xff;
- actual_len = p->tot_len + 8;
+ if (!(buflen + 4) % USB_GET_MAXPACKETSIZE(g_asix_class.bulkout->wMaxPacketSize)) {
+ USB_LOG_DBG("txlen:%d\r\n", buflen + 8);
+ g_asix_tx_buffer[buflen + 4 + 0] = 0x00;
+ g_asix_tx_buffer[buflen + 4 + 1] = 0x00;
+ g_asix_tx_buffer[buflen + 4 + 2] = 0xff;
+ g_asix_tx_buffer[buflen + 4 + 3] = 0xff;
+ actual_len = buflen + 8;
} else {
- USB_LOG_DBG("txlen:%d\r\n", p->tot_len + 4);
- actual_len = p->tot_len + 4;
+ USB_LOG_DBG("txlen:%d\r\n", buflen + 4);
+ actual_len = buflen + 4;
}
usbh_bulk_urb_fill(&g_asix_class.bulkout_urb, g_asix_class.hport, g_asix_class.bulkout, g_asix_tx_buffer, actual_len, USB_OSAL_WAITING_FOREVER, NULL, NULL);
- ret = usbh_submit_urb(&g_asix_class.bulkout_urb);
- if (ret < 0) {
- return ERR_BUF;
- }
-
- return ERR_OK;
+ return usbh_submit_urb(&g_asix_class.bulkout_urb);
}
__WEAK void usbh_asix_run(struct usbh_asix *asix_class)
diff --git a/class/vendor/net/usbh_asix.h b/class/vendor/net/usbh_asix.h
index 0642578b..9f34e570 100644
--- a/class/vendor/net/usbh_asix.h
+++ b/class/vendor/net/usbh_asix.h
@@ -6,9 +6,6 @@
#ifndef USBH_ASIX_H
#define USBH_ASIX_H
-#include "lwip/netif.h"
-#include "lwip/pbuf.h"
-
/* ASIX AX8817X based USB 2.0 Ethernet Devices */
#define AX_CMD_SET_SW_MII 0x06
@@ -156,10 +153,6 @@ struct usbh_asix {
bool connect_status;
uint8_t mac[6];
- ip_addr_t ipaddr;
- ip_addr_t netmask;
- ip_addr_t gateway;
-
void *user_data;
};
@@ -172,8 +165,9 @@ int usbh_asix_get_connect_status(struct usbh_asix *asix_class);
void usbh_asix_run(struct usbh_asix *asix_class);
void usbh_asix_stop(struct usbh_asix *asix_class);
+int usbh_asix_eth_output(uint8_t *buf, uint32_t buflen);
+void usbh_asix_eth_input(uint8_t *buf, uint32_t buflen);
void usbh_asix_rx_thread(void *argument);
-err_t usbh_asix_linkoutput(struct netif *netif, struct pbuf *p);
#ifdef __cplusplus
}
diff --git a/class/vendor/net/usbh_rtl8152.c b/class/vendor/net/usbh_rtl8152.c
index 8def54fb..3bd68a1d 100644
--- a/class/vendor/net/usbh_rtl8152.c
+++ b/class/vendor/net/usbh_rtl8152.c
@@ -2122,16 +2122,8 @@ void usbh_rtl8152_rx_thread(void *argument)
{
uint32_t g_rtl8152_rx_length;
int ret;
- err_t err;
uint16_t len;
uint16_t data_offset;
- struct pbuf *p;
-#if LWIP_TCPIP_CORE_LOCKING_INPUT
- pbuf_type type = PBUF_ROM;
-#else
- pbuf_type type = PBUF_POOL;
-#endif
- struct netif *netif = (struct netif *)argument;
USB_LOG_INFO("Create rtl8152 rx thread\r\n");
// clang-format off
@@ -2181,20 +2173,9 @@ find_class:
USB_LOG_DBG("data_offset:%d, eth len:%d\r\n", data_offset, len);
- p = pbuf_alloc(PBUF_RAW, len, type);
- if (p != NULL) {
-#if LWIP_TCPIP_CORE_LOCKING_INPUT
- p->payload = (uint8_t *)&g_rtl8152_rx_buffer[data_offset + sizeof(struct rx_desc)];
-#else
- memcpy(p->payload, (uint8_t *)&g_rtl8152_rx_buffer[data_offset + sizeof(struct rx_desc)], len);
-#endif
- err = netif->input(p, netif);
- if (err != ERR_OK) {
- pbuf_free(p);
- }
- } else {
- USB_LOG_ERR("No memory to alloc pbuf for rtl8152 rx\r\n");
- }
+ uint8_t *buf = (uint8_t *)&g_rtl8152_rx_buffer[data_offset + sizeof(struct rx_desc)];
+ usbh_rtl8152_eth_input(buf, len);
+
data_offset += (len + sizeof(struct rx_desc));
g_rtl8152_rx_length -= (len + sizeof(struct rx_desc));
@@ -2217,36 +2198,26 @@ delete:
// clang-format on
}
-err_t usbh_rtl8152_linkoutput(struct netif *netif, struct pbuf *p)
+int usbh_rtl8152_eth_output(uint8_t *buf, uint32_t buflen)
{
- int ret;
- struct pbuf *q;
uint8_t *buffer;
- struct tx_desc *tx_desc = (struct tx_desc *)g_rtl8152_tx_buffer;
+ struct tx_desc *tx_desc;
if (g_rtl8152_class.connect_status == false) {
- return ERR_BUF;
+ return -USB_ERR_NOTCONN;
}
- tx_desc->opts1 = p->tot_len | TX_FS | TX_LS;
+ tx_desc = (struct tx_desc *)g_rtl8152_tx_buffer;
+ tx_desc->opts1 = buflen | TX_FS | TX_LS;
tx_desc->opts2 = 0;
buffer = g_rtl8152_tx_buffer + sizeof(struct tx_desc);
+ memcpy(buffer, buf, buflen);
- for (q = p; q != NULL; q = q->next) {
- memcpy(buffer, q->payload, q->len);
- buffer += q->len;
- }
-
- USB_LOG_DBG("txlen:%d\r\n", p->tot_len + sizeof(struct tx_desc));
-
- usbh_bulk_urb_fill(&g_rtl8152_class.bulkout_urb, g_rtl8152_class.hport, g_rtl8152_class.bulkout, g_rtl8152_tx_buffer, p->tot_len + sizeof(struct tx_desc), USB_OSAL_WAITING_FOREVER, NULL, NULL);
- ret = usbh_submit_urb(&g_rtl8152_class.bulkout_urb);
- if (ret < 0) {
- return ERR_BUF;
- }
+ USB_LOG_DBG("txlen:%d\r\n", buflen + sizeof(struct tx_desc));
- return ERR_OK;
+ usbh_bulk_urb_fill(&g_rtl8152_class.bulkout_urb, g_rtl8152_class.hport, g_rtl8152_class.bulkout, g_rtl8152_tx_buffer, buflen + sizeof(struct tx_desc), USB_OSAL_WAITING_FOREVER, NULL, NULL);
+ return usbh_submit_urb(&g_rtl8152_class.bulkout_urb);
}
__WEAK void usbh_rtl8152_run(struct usbh_rtl8152 *rtl8152_class)
diff --git a/class/vendor/net/usbh_rtl8152.h b/class/vendor/net/usbh_rtl8152.h
index 4386ebb7..a9aa7943 100644
--- a/class/vendor/net/usbh_rtl8152.h
+++ b/class/vendor/net/usbh_rtl8152.h
@@ -6,9 +6,6 @@
#ifndef USBH_RTL8152_H
#define USBH_RTL8152_H
-#include "lwip/netif.h"
-#include "lwip/pbuf.h"
-
struct usbh_rtl8152 {
struct usbh_hubport *hport;
struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */
@@ -24,10 +21,6 @@ struct usbh_rtl8152 {
bool connect_status;
uint32_t speed[2];
- ip_addr_t ipaddr;
- ip_addr_t netmask;
- ip_addr_t gateway;
-
uint8_t version;
uint8_t eee_adv;
uint8_t eee_en;
@@ -63,8 +56,9 @@ int usbh_rtl8152_get_connect_status(struct usbh_rtl8152 *rtl8152_class);
void usbh_rtl8152_run(struct usbh_rtl8152 *rtl8152_class);
void usbh_rtl8152_stop(struct usbh_rtl8152 *rtl8152_class);
+int usbh_rtl8152_eth_output(uint8_t *buf, uint32_t buflen);
+void usbh_rtl8152_eth_input(uint8_t *buf, uint32_t buflen);
void usbh_rtl8152_rx_thread(void *argument);
-err_t usbh_rtl8152_linkoutput(struct netif *netif, struct pbuf *p);
#ifdef __cplusplus
}
diff --git a/class/wireless/usbh_rndis.c b/class/wireless/usbh_rndis.c
index ab99855d..969e6e53 100644
--- a/class/wireless/usbh_rndis.c
+++ b/class/wireless/usbh_rndis.c
@@ -425,18 +425,10 @@ static int usbh_rndis_disconnect(struct usbh_hubport *hport, uint8_t intf)
void usbh_rndis_rx_thread(void *argument)
{
uint32_t g_rndis_rx_length;
- uint32_t pmg_offset;
int ret;
- err_t err;
- struct pbuf *p;
+ uint32_t pmg_offset;
rndis_data_packet_t *pmsg;
rndis_data_packet_t temp;
-#if LWIP_TCPIP_CORE_LOCKING_INPUT
- pbuf_type type = PBUF_ROM;
-#else
- pbuf_type type = PBUF_POOL;
-#endif
- struct netif *netif = (struct netif *)argument;
USB_LOG_INFO("Create rndis rx thread\r\n");
// clang-format off
@@ -481,28 +473,15 @@ find_class:
}
if (pmsg->MessageType == REMOTE_NDIS_PACKET_MSG) {
- p = pbuf_alloc(PBUF_RAW, pmsg->DataLength, type);
- if (p != NULL) {
- void *src = (void *)(g_rndis_rx_buffer + pmg_offset + sizeof(rndis_generic_msg_t) + pmsg->DataOffset);
-#if LWIP_TCPIP_CORE_LOCKING_INPUT
- p->payload = src;
-#else
- memcpy(p->payload, src, pmsg->DataLength);
-#endif
- err = netif->input(p, netif);
- if (err != ERR_OK) {
- pbuf_free(p);
- }
- pmg_offset += pmsg->MessageLength;
- g_rndis_rx_length -= pmsg->MessageLength;
+ uint8_t *buf = (uint8_t *)(g_rndis_rx_buffer + pmg_offset + sizeof(rndis_generic_msg_t) + pmsg->DataOffset);
- /* drop the last dummy byte, it is a short packet to tell us we have received a multiple of wMaxPacketSize */
- if (g_rndis_rx_length < 4) {
- g_rndis_rx_length = 0;
- }
- } else {
+ usbh_rndis_eth_input(buf, pmsg->DataLength);
+ pmg_offset += pmsg->MessageLength;
+ g_rndis_rx_length -= pmsg->MessageLength;
+
+ /* drop the last dummy byte, it is a short packet to tell us we have received a multiple of wMaxPacketSize */
+ if (g_rndis_rx_length < 4) {
g_rndis_rx_length = 0;
- USB_LOG_ERR("No memory to alloc pbuf for rndis rx\r\n");
}
} else {
USB_LOG_ERR("offset:%d,remain:%d,total:%d\r\n", pmg_offset, g_rndis_rx_length, total_len);
@@ -525,31 +504,26 @@ delete:
// clang-format on
}
-err_t usbh_rndis_linkoutput(struct netif *netif, struct pbuf *p)
+int usbh_rndis_eth_output(uint8_t *buf, uint32_t buflen)
{
- int ret;
- struct pbuf *q;
uint8_t *buffer;
rndis_data_packet_t *hdr;
uint32_t len;
if (g_rndis_class.connect_status == false) {
- return ERR_BUF;
+ return -USB_ERR_NOTCONN;
}
hdr = (rndis_data_packet_t *)g_rndis_tx_buffer;
memset(hdr, 0, sizeof(rndis_data_packet_t));
hdr->MessageType = REMOTE_NDIS_PACKET_MSG;
- hdr->MessageLength = sizeof(rndis_data_packet_t) + p->tot_len;
+ hdr->MessageLength = sizeof(rndis_data_packet_t) + buflen;
hdr->DataOffset = sizeof(rndis_data_packet_t) - sizeof(rndis_generic_msg_t);
- hdr->DataLength = p->tot_len;
+ hdr->DataLength = buflen;
buffer = (uint8_t *)(g_rndis_tx_buffer + sizeof(rndis_data_packet_t));
- for (q = p; q != NULL; q = q->next) {
- memcpy(buffer, q->payload, q->len);
- buffer += q->len;
- }
+ memcpy(buffer, buf, buflen);
len = hdr->MessageLength;
/* if message length is the multiple of wMaxPacketSize, we should add a short packet to tell device transfer is over. */
@@ -560,12 +534,7 @@ err_t usbh_rndis_linkoutput(struct netif *netif, struct pbuf *p)
USB_LOG_DBG("txlen:%d\r\n", len);
usbh_bulk_urb_fill(&g_rndis_class.bulkout_urb, g_rndis_class.hport, g_rndis_class.bulkout, g_rndis_tx_buffer, len, USB_OSAL_WAITING_FOREVER, NULL, NULL);
- ret = usbh_submit_urb(&g_rndis_class.bulkout_urb);
- if (ret < 0) {
- return ERR_BUF;
- }
-
- return ERR_OK;
+ return usbh_submit_urb(&g_rndis_class.bulkout_urb);
}
__WEAK void usbh_rndis_run(struct usbh_rndis *rndis_class)
diff --git a/class/wireless/usbh_rndis.h b/class/wireless/usbh_rndis.h
index b4e99c3d..be56e400 100644
--- a/class/wireless/usbh_rndis.h
+++ b/class/wireless/usbh_rndis.h
@@ -8,9 +8,6 @@
#include "usb_cdc.h"
-#include "lwip/netif.h"
-#include "lwip/pbuf.h"
-
struct usbh_rndis {
struct usbh_hubport *hport;
struct usb_endpoint_descriptor *bulkin; /* Bulk IN endpoint */
@@ -30,10 +27,6 @@ struct usbh_rndis {
bool connect_status;
uint8_t mac[6];
- ip_addr_t ipaddr;
- ip_addr_t netmask;
- ip_addr_t gateway;
-
void *user_data;
};
@@ -47,7 +40,8 @@ int usbh_rndis_keepalive(struct usbh_rndis *rndis_class);
void usbh_rndis_run(struct usbh_rndis *rndis_class);
void usbh_rndis_stop(struct usbh_rndis *rndis_class);
-err_t usbh_rndis_linkoutput(struct netif *netif, struct pbuf *p);
+int usbh_rndis_eth_output(uint8_t *buf, uint32_t buflen);
+void usbh_rndis_eth_input(uint8_t *buf, uint32_t buflen);
void usbh_rndis_rx_thread(void *argument);
#ifdef __cplusplus
diff --git a/platform/README.md b/platform/README.md
new file mode 100644
index 00000000..a6afc93e
--- /dev/null
+++ b/platform/README.md
@@ -0,0 +1,14 @@
+# Platform Support
+
+This is a platform support for other os with their own components.
+
+| Platform | fs | net | serial |
+|:---------:|:------------:|:------------:|:------------:|
+|none | fatfs | lwip | none |
+|rtthread | dfs | lwip | rt_device |
+|nuttx | nuttx block driver | nuttx net | nuttx char driver|
+|threadx | filex | netx | none |
+
+- **fs** is for usbd_msc and usbh_msc
+- **net** is for cdc_ecm, cdc_rndis, cdc_ncm, asix, rtl8152 and so on.
+- **serial** is for cdc_acm, ch340, ftdi, cp210x, pl2303 and so on. \ No newline at end of file
diff --git a/third_party/fatfs-0.14/source/port/fatfs_usbh.c b/platform/none/usbh_fatfs.c
index feab07e4..ba76c12c 100644
--- a/third_party/fatfs-0.14/source/port/fatfs_usbh.c
+++ b/platform/none/usbh_fatfs.c
@@ -1,3 +1,8 @@
+/*
+ * Copyright (c) 2024, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
#include "ff.h"
#include "diskio.h"
#include "usbh_core.h"
@@ -9,6 +14,7 @@ int USB_disk_status(void)
{
return 0;
}
+
int USB_disk_initialize(void)
{
active_msc_class = (struct usbh_msc *)usbh_find_class_instance("/dev/sda");
@@ -59,4 +65,4 @@ int USB_disk_ioctl(BYTE cmd, void *buff)
}
return result;
-} \ No newline at end of file
+}
diff --git a/platform/none/usbh_lwip.c b/platform/none/usbh_lwip.c
new file mode 100644
index 00000000..f6091378
--- /dev/null
+++ b/platform/none/usbh_lwip.c
@@ -0,0 +1,504 @@
+/*
+ * Copyright (c) 2024, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "netif/etharp.h"
+#include "lwip/netif.h"
+#include "lwip/pbuf.h"
+#include "lwip/tcpip.h"
+#if LWIP_DHCP
+#include "lwip/dhcp.h"
+#include "lwip/prot/dhcp.h"
+#endif
+
+#include "FreeRTOS.h"
+#include "task.h"
+#include "semphr.h"
+#include "timers.h"
+
+#include "usbh_core.h"
+
+#if LWIP_TCPIP_CORE_LOCKING_INPUT !=1
+#warning suggest you to set LWIP_TCPIP_CORE_LOCKING_INPUT to 1, usb handles eth input with own thread
+#endif
+
+#if LWIP_TCPIP_CORE_LOCKING !=1
+#error must set LWIP_TCPIP_CORE_LOCKING to 1
+#endif
+
+#if PBUF_POOL_BUFSIZE < 1600
+#error PBUF_POOL_BUFSIZE must be larger than 1600
+#endif
+
+#define CONFIG_USBHOST_PLATFORM_CDC_ECM
+#define CONFIG_USBHOST_PLATFORM_CDC_RNDIS
+#define CONFIG_USBHOST_PLATFORM_CDC_NCM
+#define CONFIG_USBHOST_PLATFORM_ASIX
+#define CONFIG_USBHOST_PLATFORM_RTL8152
+
+ip_addr_t g_ipaddr;
+ip_addr_t g_netmask;
+ip_addr_t g_gateway;
+
+void usbh_lwip_eth_input_common(struct netif *netif, uint8_t *buf, uint32_t len)
+{
+#if LWIP_TCPIP_CORE_LOCKING_INPUT
+ pbuf_type type = PBUF_REF;
+#else
+ pbuf_type type = PBUF_POOL;
+#endif
+ err_t err;
+ struct pbuf *p;
+
+ p = pbuf_alloc(PBUF_RAW, len, type);
+ if (p != NULL) {
+#if LWIP_TCPIP_CORE_LOCKING_INPUT
+ p->payload = buf;
+#else
+ memcpy(p->payload, buf, len);
+#endif
+ err = netif->input(p, netif);
+ if (err != ERR_OK) {
+ pbuf_free(p);
+ }
+ } else {
+ USB_LOG_ERR("No memory to alloc pbuf\r\n");
+ }
+}
+
+TimerHandle_t dhcp_handle;
+
+static void dhcp_timeout(TimerHandle_t xTimer)
+{
+ struct netif *netif = (struct netif *)pvTimerGetTimerID(xTimer);
+ struct dhcp *dhcp;
+
+ if (netif_is_up(netif)) {
+ dhcp = netif_dhcp_data(netif);
+
+ if (dhcp && (dhcp->state == DHCP_STATE_BOUND)) {
+ USB_LOG_INFO("IPv4 Address : %s\r\n", ipaddr_ntoa(&netif->ip_addr));
+ USB_LOG_INFO("IPv4 Subnet mask : %s\r\n", ipaddr_ntoa(&netif->netmask));
+ USB_LOG_INFO("IPv4 Gateway : %s\r\n\r\n", ipaddr_ntoa(&netif->gw));
+
+ xTimerStop(xTimer, 0);
+ }
+ }
+}
+
+#ifdef CONFIG_USBHOST_PLATFORM_CDC_ECM
+#include "usbh_cdc_ecm.h"
+
+struct netif g_cdc_ecm_netif;
+
+static err_t usbh_cdc_ecm_linkoutput(struct netif *netif, struct pbuf *p)
+{
+ int ret = usbh_cdc_ecm_eth_output(p->payload, p->tot_len);
+ if (ret < 0) {
+ return ERR_BUF;
+ } else {
+ return ERR_OK;
+ }
+}
+
+void usbh_cdc_ecm_eth_input(uint8_t *buf, uint32_t buflen)
+{
+ usbh_lwip_eth_input_common(&g_cdc_ecm_netif, buf, buflen);
+}
+
+static err_t usbh_cdc_ecm_if_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;
+ netif->name[0] = 'E';
+ netif->name[1] = 'X';
+ netif->output = etharp_output;
+ netif->linkoutput = usbh_cdc_ecm_linkoutput;
+ return ERR_OK;
+}
+
+void usbh_cdc_ecm_run(struct usbh_cdc_ecm *cdc_ecm_class)
+{
+ struct netif *netif = &g_cdc_ecm_netif;
+
+ netif->hwaddr_len = 6;
+ memcpy(netif->hwaddr, cdc_ecm_class->mac, 6);
+
+ IP4_ADDR(&g_ipaddr, 0, 0, 0, 0);
+ IP4_ADDR(&g_netmask, 0, 0, 0, 0);
+ IP4_ADDR(&g_gateway, 0, 0, 0, 0);
+
+ netif = netif_add(netif, &g_ipaddr, &g_netmask, &g_gateway, NULL, usbh_cdc_ecm_if_init, tcpip_input);
+ netif_set_default(netif);
+ while (!netif_is_up(netif)) {
+ }
+
+ dhcp_handle = xTimerCreate((const char *)"dhcp", (TickType_t)200, (UBaseType_t)pdTRUE, (void *const)netif, (TimerCallbackFunction_t)dhcp_timeout);
+ if (dhcp_handle == NULL) {
+ USB_LOG_ERR("timer creation failed! \r\n");
+ while (1) {
+ }
+ }
+
+ usb_osal_thread_create("usbh_cdc_ecm_rx", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_cdc_ecm_rx_thread, NULL);
+#if LWIP_DHCP
+ dhcp_start(netif);
+ xTimerStart(dhcp_handle, 0);
+#endif
+}
+
+void usbh_cdc_ecm_stop(struct usbh_cdc_ecm *cdc_ecm_class)
+{
+ struct netif *netif = &g_cdc_ecm_netif;
+#if LWIP_DHCP
+ dhcp_stop(netif);
+ dhcp_cleanup(netif);
+ xTimerStop(dhcp_handle, 0);
+ xTimerDelete(dhcp_handle, 0);
+#endif
+ netif_set_down(netif);
+ netif_remove(netif);
+}
+#endif
+
+#ifdef CONFIG_USBHOST_PLATFORM_CDC_RNDIS
+#include "usbh_rndis.h"
+
+TimerHandle_t timer_handle;
+
+static void rndis_dev_keepalive_timeout(TimerHandle_t xTimer)
+{
+ struct usbh_rndis *rndis_class = (struct usbh_rndis *)pvTimerGetTimerID(xTimer);
+ usbh_rndis_keepalive(rndis_class);
+}
+
+void timer_init(struct usbh_rndis *rndis_class)
+{
+ timer_handle = xTimerCreate((const char *)NULL, (TickType_t)5000, (UBaseType_t)pdTRUE, (void *const)rndis_class, (TimerCallbackFunction_t)rndis_dev_keepalive_timeout);
+ if (NULL != timer_handle) {
+ xTimerStart(timer_handle, 0);
+ } else {
+ USB_LOG_ERR("timer creation failed! \r\n");
+ for (;;) {
+ ;
+ }
+ }
+}
+
+struct netif g_rndis_netif;
+
+static err_t usbh_rndis_linkoutput(struct netif *netif, struct pbuf *p)
+{
+ int ret = usbh_rndis_eth_output(p->payload, p->tot_len);
+ if (ret < 0) {
+ return ERR_BUF;
+ } else {
+ return ERR_OK;
+ }
+}
+
+void usbh_rndis_eth_input(uint8_t *buf, uint32_t buflen)
+{
+ usbh_lwip_eth_input_common(&g_rndis_netif, buf, buflen);
+}
+
+static err_t usbh_rndis_if_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;
+ netif->name[0] = 'E';
+ netif->name[1] = 'X';
+ netif->output = etharp_output;
+ netif->linkoutput = usbh_rndis_linkoutput;
+ return ERR_OK;
+}
+
+void usbh_rndis_run(struct usbh_rndis *rndis_class)
+{
+ struct netif *netif = &g_rndis_netif;
+
+ netif->hwaddr_len = 6;
+ memcpy(netif->hwaddr, rndis_class->mac, 6);
+
+ IP4_ADDR(&g_ipaddr, 0, 0, 0, 0);
+ IP4_ADDR(&g_netmask, 0, 0, 0, 0);
+ IP4_ADDR(&g_gateway, 0, 0, 0, 0);
+
+ netif = netif_add(netif, &g_ipaddr, &g_netmask, &g_gateway, NULL, usbh_rndis_if_init, tcpip_input);
+ netif_set_default(netif);
+ while (!netif_is_up(netif)) {
+ }
+
+ dhcp_handle = xTimerCreate((const char *)"dhcp", (TickType_t)200, (UBaseType_t)pdTRUE, (void *const)netif, (TimerCallbackFunction_t)dhcp_timeout);
+ if (dhcp_handle == NULL) {
+ USB_LOG_ERR("timer creation failed! \r\n");
+ while (1) {
+ }
+ }
+
+ usb_osal_thread_create("usbh_rndis_rx", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_rndis_rx_thread, NULL);
+
+ //timer_init(rndis_class);
+
+#if LWIP_DHCP
+ dhcp_start(netif);
+ xTimerStart(dhcp_handle, 0);
+#endif
+}
+
+void usbh_rndis_stop(struct usbh_rndis *rndis_class)
+{
+ struct netif *netif = &g_rndis_netif;
+#if LWIP_DHCP
+ dhcp_stop(netif);
+ dhcp_cleanup(netif);
+ xTimerStop(dhcp_handle, 0);
+ xTimerDelete(dhcp_handle, 0);
+#endif
+ netif_set_down(netif);
+ netif_remove(netif);
+ // xTimerStop(timer_handle, 0);
+ // xTimerDelete(timer_handle, 0);
+}
+#endif
+
+#ifdef CONFIG_USBHOST_PLATFORM_CDC_NCM
+#include "usbh_cdc_ncm.h"
+
+struct netif g_cdc_ncm_netif;
+
+static err_t usbh_cdc_ncm_linkoutput(struct netif *netif, struct pbuf *p)
+{
+ int ret = usbh_cdc_ncm_eth_output(p->payload, p->tot_len);
+ if (ret < 0) {
+ return ERR_BUF;
+ } else {
+ return ERR_OK;
+ }
+}
+
+void usbh_cdc_ncm_eth_input(uint8_t *buf, uint32_t buflen)
+{
+ usbh_lwip_eth_input_common(&g_cdc_ncm_netif, buf, buflen);
+}
+
+static err_t usbh_cdc_ncm_if_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;
+ netif->name[0] = 'E';
+ netif->name[1] = 'X';
+ netif->output = etharp_output;
+ netif->linkoutput = usbh_cdc_ncm_linkoutput;
+ return ERR_OK;
+}
+
+void usbh_cdc_ncm_run(struct usbh_cdc_ncm *cdc_ncm_class)
+{
+ struct netif *netif = &g_cdc_ncm_netif;
+
+ netif->hwaddr_len = 6;
+ memcpy(netif->hwaddr, cdc_ncm_class->mac, 6);
+
+ IP4_ADDR(&g_ipaddr, 0, 0, 0, 0);
+ IP4_ADDR(&g_netmask, 0, 0, 0, 0);
+ IP4_ADDR(&g_gateway, 0, 0, 0, 0);
+
+ netif = netif_add(netif, &g_ipaddr, &g_netmask, &g_gateway, NULL, usbh_cdc_ncm_if_init, tcpip_input);
+ netif_set_default(netif);
+ while (!netif_is_up(netif)) {
+ }
+
+ dhcp_handle = xTimerCreate((const char *)"dhcp", (TickType_t)200, (UBaseType_t)pdTRUE, (void *const)netif, (TimerCallbackFunction_t)dhcp_timeout);
+ if (dhcp_handle == NULL) {
+ USB_LOG_ERR("timer creation failed! \r\n");
+ while (1) {
+ }
+ }
+
+ usb_osal_thread_create("usbh_cdc_ncm_rx", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_cdc_ncm_rx_thread, NULL);
+#if LWIP_DHCP
+ dhcp_start(netif);
+ xTimerStart(dhcp_handle, 0);
+#endif
+}
+
+void usbh_cdc_ncm_stop(struct usbh_cdc_ncm *cdc_ncm_class)
+{
+ struct netif *netif = &g_cdc_ncm_netif;
+#if LWIP_DHCP
+ dhcp_stop(netif);
+ dhcp_cleanup(netif);
+ xTimerStop(dhcp_handle, 0);
+ xTimerDelete(dhcp_handle, 0);
+#endif
+ netif_set_down(netif);
+ netif_remove(netif);
+}
+#endif
+
+#ifdef CONFIG_USBHOST_PLATFORM_ASIX
+#include "usbh_asix.h"
+
+struct netif g_asix_netif;
+
+static err_t usbh_asix_linkoutput(struct netif *netif, struct pbuf *p)
+{
+ int ret = usbh_asix_eth_output(p->payload, p->tot_len);
+ if (ret < 0) {
+ return ERR_BUF;
+ } else {
+ return ERR_OK;
+ }
+}
+
+void usbh_asix_eth_input(uint8_t *buf, uint32_t buflen)
+{
+ usbh_lwip_eth_input_common(&g_asix_netif, buf, buflen);
+}
+
+static err_t usbh_asix_if_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;
+ netif->name[0] = 'E';
+ netif->name[1] = 'X';
+ netif->output = etharp_output;
+ netif->linkoutput = usbh_asix_linkoutput;
+ return ERR_OK;
+}
+
+void usbh_asix_run(struct usbh_asix *asix_class)
+{
+ struct netif *netif = &g_asix_netif;
+
+ netif->hwaddr_len = 6;
+ memcpy(netif->hwaddr, asix_class->mac, 6);
+
+ IP4_ADDR(&g_ipaddr, 0, 0, 0, 0);
+ IP4_ADDR(&g_netmask, 0, 0, 0, 0);
+ IP4_ADDR(&g_gateway, 0, 0, 0, 0);
+
+ netif = netif_add(netif, &g_ipaddr, &g_netmask, &g_gateway, NULL, usbh_asix_if_init, tcpip_input);
+ netif_set_default(netif);
+ while (!netif_is_up(netif)) {
+ }
+
+ dhcp_handle = xTimerCreate((const char *)"dhcp", (TickType_t)200, (UBaseType_t)pdTRUE, (void *const)netif, (TimerCallbackFunction_t)dhcp_timeout);
+ if (dhcp_handle == NULL) {
+ USB_LOG_ERR("timer creation failed! \r\n");
+ while (1) {
+ }
+ }
+
+ usb_osal_thread_create("usbh_asix_rx", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_asix_rx_thread, NULL);
+#if LWIP_DHCP
+ dhcp_start(netif);
+ xTimerStart(dhcp_handle, 0);
+#endif
+}
+
+void usbh_asix_stop(struct usbh_asix *asix_class)
+{
+ struct netif *netif = &g_asix_netif;
+#if LWIP_DHCP
+ dhcp_stop(netif);
+ dhcp_cleanup(netif);
+ xTimerStop(dhcp_handle, 0);
+ xTimerDelete(dhcp_handle, 0);
+#endif
+ netif_set_down(netif);
+ netif_remove(netif);
+}
+#endif
+
+#ifdef CONFIG_USBHOST_PLATFORM_RTL8152
+#include "usbh_rtl8152.h"
+
+struct netif g_rtl8152_netif;
+
+static err_t usbh_rtl8152_linkoutput(struct netif *netif, struct pbuf *p)
+{
+ int ret = usbh_rtl8152_eth_output(p->payload, p->tot_len);
+ if (ret < 0) {
+ return ERR_BUF;
+ } else {
+ return ERR_OK;
+ }
+}
+
+void usbh_rtl8152_eth_input(uint8_t *buf, uint32_t buflen)
+{
+ usbh_lwip_eth_input_common(&g_rtl8152_netif, buf, buflen);
+}
+
+static err_t usbh_rtl8152_if_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;
+ netif->name[0] = 'E';
+ netif->name[1] = 'X';
+ netif->output = etharp_output;
+ netif->linkoutput = usbh_rtl8152_linkoutput;
+ return ERR_OK;
+}
+
+void usbh_rtl8152_run(struct usbh_rtl8152 *rtl8152_class)
+{
+ struct netif *netif = &g_rtl8152_netif;
+
+ netif->hwaddr_len = 6;
+ memcpy(netif->hwaddr, rtl8152_class->mac, 6);
+
+ IP4_ADDR(&g_ipaddr, 0, 0, 0, 0);
+ IP4_ADDR(&g_netmask, 0, 0, 0, 0);
+ IP4_ADDR(&g_gateway, 0, 0, 0, 0);
+
+ netif = netif_add(netif, &g_ipaddr, &g_netmask, &g_gateway, NULL, usbh_rtl8152_if_init, tcpip_input);
+ netif_set_default(netif);
+ while (!netif_is_up(netif)) {
+ }
+
+ dhcp_handle = xTimerCreate((const char *)"dhcp", (TickType_t)200, (UBaseType_t)pdTRUE, (void *const)netif, (TimerCallbackFunction_t)dhcp_timeout);
+ if (dhcp_handle == NULL) {
+ USB_LOG_ERR("timer creation failed! \r\n");
+ while (1) {
+ }
+ }
+
+ usb_osal_thread_create("usbh_rtl8152_rx", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_rtl8152_rx_thread, NULL);
+#if LWIP_DHCP
+ dhcp_start(netif);
+ xTimerStart(dhcp_handle, 0);
+#endif
+}
+
+void usbh_rtl8152_stop(struct usbh_rtl8152 *rtl8152_class)
+{
+ struct netif *netif = &g_rtl8152_netif;
+#if LWIP_DHCP
+ dhcp_stop(netif);
+ dhcp_cleanup(netif);
+ xTimerStop(dhcp_handle, 0);
+ xTimerDelete(dhcp_handle, 0);
+#endif
+ netif_set_down(netif);
+ netif_remove(netif);
+}
+#endif
diff --git a/platform/nuttx/usbh_fs.c b/platform/nuttx/usbh_fs.c
new file mode 100644
index 00000000..94920323
--- /dev/null
+++ b/platform/nuttx/usbh_fs.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2024, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include <nuttx/config.h>
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/irq.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/signal.h>
+#include <nuttx/arch.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/scsi.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/mutex.h>
+
+#include "usbh_core.h"
+#include "usbh_msc.h"
+
+#ifdef CONFIG_ARCH_CHIP_HPMICRO
+#include "hpm_misc.h"
+#define usbhmsc_phy2sysaddr(a) core_local_mem_to_sys_address(0, a)
+#else
+#define usbhmsc_phy2sysaddr(a) (a)
+#endif
+
+static int usbhost_open(FAR struct inode *inode);
+static int usbhost_close(FAR struct inode *inode);
+static ssize_t usbhost_read(FAR struct inode *inode, unsigned char *buffer,
+ blkcnt_t startsector, unsigned int nsectors);
+static ssize_t usbhost_write(FAR struct inode *inode,
+ FAR const unsigned char *buffer,
+ blkcnt_t startsector, unsigned int nsectors);
+static int usbhost_geometry(FAR struct inode *inode,
+ FAR struct geometry *geometry);
+static int usbhost_ioctl(FAR struct inode *inode, int cmd, unsigned long arg);
+/* Block driver operations. This is the interface exposed to NuttX by the
+ * class that permits it to behave like a block driver.
+ */
+
+static const struct block_operations g_bops = {
+ usbhost_open, /* open */
+ usbhost_close, /* close */
+ usbhost_read, /* read */
+ usbhost_write, /* write */
+ usbhost_geometry, /* geometry */
+ usbhost_ioctl /* ioctl */
+};
+
+static int usbhost_open(FAR struct inode *inode)
+{
+ struct usbh_msc *msc_class;
+
+ DEBUGASSERT(inode->i_private);
+ msc_class = (struct usbh_msc *)inode->i_private;
+
+ if (msc_class->hport && msc_class->hport->connected) {
+ return OK;
+ } else {
+ return -ENODEV;
+ }
+}
+
+static int usbhost_close(FAR struct inode *inode)
+{
+ DEBUGASSERT(inode->i_private);
+ return 0;
+}
+
+static ssize_t usbhost_read(FAR struct inode *inode, unsigned char *buffer,
+ blkcnt_t startsector, unsigned int nsectors)
+{
+ struct usbh_msc *msc_class;
+ int ret;
+
+ DEBUGASSERT(inode->i_private);
+ msc_class = (struct usbh_msc *)inode->i_private;
+
+ if (msc_class->hport && msc_class->hport->connected) {
+ ret = usbh_msc_scsi_read10(msc_class, startsector, (uint8_t *)usbhmsc_phy2sysaddr((uint32_t)buffer), nsectors);
+ if (ret < 0) {
+ return ret;
+ } else {
+#ifdef CONFIG_USBHOST_MSC_DCACHE
+ up_invalidate_dcache((uintptr_t)buffer, (uintptr_t)(buffer + nsectors * msc_class->blocksize));
+#endif
+ return nsectors;
+ }
+ } else {
+ return -ENODEV;
+ }
+}
+
+static ssize_t usbhost_write(FAR struct inode *inode,
+ FAR const unsigned char *buffer,
+ blkcnt_t startsector, unsigned int nsectors)
+{
+ struct usbh_msc *msc_class;
+ int ret;
+
+ DEBUGASSERT(inode->i_private);
+ msc_class = (struct usbh_msc *)inode->i_private;
+
+ if (msc_class->hport && msc_class->hport->connected) {
+#ifdef CONFIG_USBHOST_MSC_DCACHE
+ up_flush_dcache((uintptr_t)buffer, (uintptr_t)(buffer + nsectors * msc_class->blocksize));
+#endif
+ ret = usbh_msc_scsi_write10(msc_class, startsector, (uint8_t *)usbhmsc_phy2sysaddr((uint32_t)buffer), nsectors);
+ if (ret < 0) {
+ return ret;
+ } else {
+ return nsectors;
+ }
+ } else {
+ return -ENODEV;
+ }
+}
+
+static int usbhost_geometry(FAR struct inode *inode,
+ FAR struct geometry *geometry)
+{
+ struct usbh_msc *msc_class;
+
+ DEBUGASSERT(inode->i_private);
+ msc_class = (struct usbh_msc *)inode->i_private;
+
+ if (msc_class->hport && msc_class->hport->connected) {
+ memset(geometry, 0, sizeof(*geometry));
+
+ geometry->geo_available = true;
+ geometry->geo_mediachanged = false;
+ geometry->geo_writeenabled = true;
+ geometry->geo_nsectors = msc_class->blocknum;
+ geometry->geo_sectorsize = msc_class->blocksize;
+
+ uinfo("nsectors: %" PRIdOFF " sectorsize: %" PRIi16 "\n",
+ geometry->geo_nsectors, geometry->geo_sectorsize);
+ return OK;
+ } else {
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int usbhost_ioctl(FAR struct inode *inode, int cmd, unsigned long arg)
+{
+ struct usbh_msc *msc_class;
+
+ DEBUGASSERT(inode->i_private);
+ msc_class = (struct usbh_msc *)inode->i_private;
+
+ if (msc_class->hport && msc_class->hport->connected) {
+ return -ENOTTY;
+ } else {
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+#define DEV_FORMAT "/dev/sd%c"
+
+void usbh_msc_run(struct usbh_msc *msc_class)
+{
+ char devname[32];
+
+ snprintf(devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, msc_class->sdchar);
+
+ register_blockdriver(devname, &g_bops, 0, msc_class);
+}
+
+void usbh_msc_stop(struct usbh_msc *msc_class)
+{
+ char devname[32];
+
+ snprintf(devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, msc_class->sdchar);
+
+ unregister_blockdriver(devname);
+} \ No newline at end of file
diff --git a/platform/nuttx/usbh_net.c b/platform/nuttx/usbh_net.c
new file mode 100644
index 00000000..b034ecc8
--- /dev/null
+++ b/platform/nuttx/usbh_net.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2024, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include <nuttx/config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <semaphore.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/net/ip.h>
+#include <nuttx/net/netdev.h>
+
+#include "usbh_core.h"
+
+#define CONFIG_USBHOST_PLATFORM_CDC_ECM
+#define CONFIG_USBHOST_PLATFORM_CDC_RNDIS
+#define CONFIG_USBHOST_PLATFORM_CDC_NCM
+#define CONFIG_USBHOST_PLATFORM_ASIX
+#define CONFIG_USBHOST_PLATFORM_RTL8152
+
+struct usbh_net {
+ struct net_driver_s netdev;
+ struct work_s txpollwork;
+ bool linkup;
+};
+
+void usbh_net_eth_input_common(struct net_driver_s *dev, uint8_t *buf, size_t len, int (*eth_output)(uint8_t *buf, uint32_t buflen))
+{
+ FAR struct eth_hdr_s *hdr;
+
+ net_lock();
+
+ NETDEV_RXPACKETS(dev);
+
+ /* Any ACK or other response packet generated by the network stack
+ * will always be shorter than the received packet, therefore it is
+ * safe to pass the received frame buffer directly.
+ */
+
+ dev->d_buf = buf;
+ dev->d_len = len;
+
+ hdr = (FAR struct eth_hdr_s *)dev->d_buf;
+#ifdef CONFIG_NET_IPv4
+ if (hdr->type == HTONS(ETHTYPE_IP)) {
+ NETDEV_RXIPV4(dev);
+
+ /* Receive an IPv4 packet from the network device */
+
+ ipv4_input(dev);
+ if (dev->d_len > 0) {
+ /* And send the packet */
+ eth_output(dev->d_buf, dev->d_len);
+ }
+ } else
+#endif
+#ifdef CONFIG_NET_IPv6
+ if (hdr->type == HTONS(ETHTYPE_IP6)) {
+ NETDEV_RXIPV6(dev);
+
+ /* Give the IPv6 packet to the network layer */
+
+ ipv6_input(dev);
+
+ if (dev->d_len > 0) {
+ /* And send the packet */
+ eth_output(dev->d_buf, dev->d_len);
+ }
+ } else
+#endif
+#ifdef CONFIG_NET_ARP
+ if (hdr->type == HTONS(ETHTYPE_ARP)) {
+ NETDEV_RXARP(dev);
+
+ arp_input(dev);
+ if (dev->d_len > 0) {
+ eth_output(dev->d_buf, dev->d_len);
+ }
+ } else
+#endif
+ {
+ NETDEV_RXDROPPED(dev);
+ }
+
+ net_unlock();
+}
+
+#ifdef CONFIG_USBHOST_PLATFORM_CDC_RNDIS
+#include "usbh_rndis.h"
+
+struct usbh_net g_rndis_dev;
+
+static int rndis_ifup(struct net_driver_s *dev)
+{
+ printf("rndis if up\r\n");
+ g_rndis_dev.linkup = true;
+ usb_osal_thread_create("usbh_rndis_rx", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_rndis_rx_thread, NULL);
+ return OK;
+}
+
+static int rndis_ifdown(struct net_driver_s *dev)
+{
+ printf("rndis if down\r\n");
+ g_rndis_dev.linkup = false;
+ return OK;
+}
+
+static int rndis_txpoll(struct net_driver_s *dev)
+{
+ return usbh_rndis_eth_output(g_rndis_dev.netdev.d_buf, g_rndis_dev.netdev.d_len);
+}
+
+static void rndis_txavail_work(void *arg)
+{
+ net_lock();
+
+ if (g_rndis_dev.linkup) {
+ devif_poll(&g_rndis_dev.netdev, rndis_txpoll);
+ } else {
+ }
+
+ net_unlock();
+}
+
+static int rndis_txavail(struct net_driver_s *dev)
+{
+ if (work_available(&g_rndis_dev.txpollwork)) {
+ work_queue(LPWORK, &g_rndis_dev.txpollwork, rndis_txavail_work, NULL, 0);
+ } else {
+ return -1;
+ }
+
+ return OK;
+}
+
+void usbh_rndis_eth_input(uint8_t *buf, uint32_t buflen)
+{
+ usbh_net_eth_input_common(&g_rndis_dev.netdev, buf, buflen, usbh_rndis_eth_output);
+}
+
+void usbh_rndis_run(struct usbh_rndis *rndis_class)
+{
+ memset(&g_rndis_dev.netdev, 0, sizeof(struct net_driver_s));
+
+ g_rndis_dev.netdev.d_ifup = rndis_ifup;
+ g_rndis_dev.netdev.d_ifdown = rndis_ifdown;
+ g_rndis_dev.netdev.d_txavail = rndis_txavail;
+ g_rndis_dev.netdev.d_private = rndis_class;
+
+ for (uint8_t j = 0; j < 6; j++) {
+ g_rndis_dev.netdev.d_mac.ether.ether_addr_octet[j] = rndis_class->mac[j];
+ }
+ netdev_register(&g_rndis_dev.netdev, NET_LL_ETHERNET);
+}
+
+void usbh_rndis_stop(struct usbh_rndis *rndis_class)
+{
+}
+#endif \ No newline at end of file
diff --git a/platform/rtthread/usb_check.c b/platform/rtthread/usb_check.c
new file mode 100644
index 00000000..d4baf03e
--- /dev/null
+++ b/platform/rtthread/usb_check.c
@@ -0,0 +1,17 @@
+#include "rtthread.h"
+
+#ifdef PKG_CHERRYUSB_HOST
+
+#ifndef RT_USING_TIMER_SOFT
+#error must enable RT_USING_TIMER_SOFT to support timer callback in thread
+#endif
+
+#if IDLE_THREAD_STACK_SIZE < 2048
+#error "IDLE_THREAD_STACK_SIZE must be greater than 2048"
+#endif
+
+#if RT_TIMER_THREAD_STACK_SIZE < 2048
+#error "RT_TIMER_THREAD_STACK_SIZE must be greater than 2048"
+#endif
+
+#endif
diff --git a/third_party/rt-thread-5.0/usb_msh.c b/platform/rtthread/usb_msh.c
index db04e059..db04e059 100644
--- a/third_party/rt-thread-5.0/usb_msh.c
+++ b/platform/rtthread/usb_msh.c
diff --git a/third_party/rt-thread-5.0/dfs_usbh_msc.c b/platform/rtthread/usbh_dfs.c
index cdb9e80b..968064a6 100644
--- a/third_party/rt-thread-5.0/dfs_usbh_msc.c
+++ b/platform/rtthread/usbh_dfs.c
@@ -238,4 +238,4 @@ void usbh_msc_stop(struct usbh_msc *msc_class)
dfs_unmount(mount_point);
rt_device_unregister(rt_device_find(name));
-} \ No newline at end of file
+}
diff --git a/platform/rtthread/usbh_lwip.c b/platform/rtthread/usbh_lwip.c
new file mode 100644
index 00000000..2c0c7eaf
--- /dev/null
+++ b/platform/rtthread/usbh_lwip.c
@@ -0,0 +1,415 @@
+/*
+ * Copyright (c) 2024, sakumisu
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "netif/etharp.h"
+#include "lwip/netif.h"
+#include "lwip/pbuf.h"
+#include "lwip/tcpip.h"
+#if LWIP_DHCP
+#include "lwip/dhcp.h"
+#include "lwip/prot/dhcp.h"
+#endif
+
+#include <rtthread.h>
+#include <rtdevice.h>
+#include <netif/ethernetif.h>
+
+#include "usbh_core.h"
+
+#include "lwip/opt.h"
+
+#ifndef RT_USING_LWIP212
+#error must enable RT_USING_LWIP212
+#endif
+
+#ifndef LWIP_NO_RX_THREAD
+#error must enable LWIP_NO_RX_THREAD, we do not use rtthread eth rx thread
+#endif
+
+#ifndef LWIP_NO_TX_THREAD
+#warning suggest you to enable LWIP_NO_TX_THREAD, we do not use rtthread eth tx thread
+#endif
+
+#if LWIP_TCPIP_CORE_LOCKING_INPUT !=1
+#warning suggest you to set LWIP_TCPIP_CORE_LOCKING_INPUT to 1, usb handles eth input with own thread
+#endif
+
+#if LWIP_TCPIP_CORE_LOCKING !=1
+#error must set LWIP_TCPIP_CORE_LOCKING to 1
+#endif
+
+#if PBUF_POOL_BUFSIZE < 1600
+#error PBUF_POOL_BUFSIZE must be larger than 1600
+#endif
+
+// #define CONFIG_USBHOST_PLATFORM_CDC_ECM
+// #define CONFIG_USBHOST_PLATFORM_CDC_RNDIS
+// #define CONFIG_USBHOST_PLATFORM_CDC_NCM
+// #define CONFIG_USBHOST_PLATFORM_ASIX
+// #define CONFIG_USBHOST_PLATFORM_RTL8152
+
+void usbh_lwip_eth_input_common(struct netif *netif, uint8_t *buf, uint32_t len)
+{
+#if LWIP_TCPIP_CORE_LOCKING_INPUT
+ pbuf_type type = PBUF_REF;
+#else
+ pbuf_type type = PBUF_POOL;
+#endif
+ err_t err;
+ struct pbuf *p;
+
+ p = pbuf_alloc(PBUF_RAW, len, type);
+ if (p != NULL) {
+#if LWIP_TCPIP_CORE_LOCKING_INPUT
+ p->payload = buf;
+#else
+ memcpy(p->payload, buf, len);
+#endif
+ err = netif->input(p, netif);
+ if (err != ERR_OK) {
+ pbuf_free(p);
+ }
+ } else {
+ USB_LOG_ERR("No memory to alloc pbuf\r\n");
+ }
+}
+
+#ifdef CONFIG_USBHOST_PLATFORM_CDC_ECM
+#include "usbh_cdc_ecm.h"
+
+static struct eth_device g_cdc_ecm_dev;
+
+static rt_err_t rt_usbh_cdc_ecm_control(rt_device_t dev, int cmd, void *args)
+{
+ struct usbh_cdc_ecm *cdc_ecm_class = (struct usbh_cdc_ecm *)dev->user_data;
+
+ switch (cmd) {
+ case NIOCTL_GADDR:
+
+ /* get mac address */
+ if (args)
+ rt_memcpy(args, cdc_ecm_class->mac, 6);
+ else
+ return -RT_ERROR;
+
+ break;
+
+ default:
+ break;
+ }
+
+ return RT_EOK;
+}
+
+static rt_err_t rt_usbh_cdc_ecm_eth_tx(rt_device_t dev, struct pbuf *p)
+{
+ int ret = usbh_cdc_ecm_eth_output(p->payload, p->tot_len);
+ if (ret < 0) {
+ return -RT_ERROR;
+ } else {
+ return RT_EOK;
+ }
+}
+
+void usbh_cdc_ecm_eth_input(uint8_t *buf, uint32_t buflen)
+{
+ usbh_lwip_eth_input_common(g_cdc_ecm_dev.netif, buf, buflen);
+}
+
+void usbh_cdc_ecm_run(struct usbh_cdc_ecm *cdc_ecm_class)
+{
+ memset(&g_cdc_ecm_dev, 0, sizeof(struct eth_device));
+
+ g_cdc_ecm_dev.parent.control = rt_usbh_cdc_ecm_control;
+ g_cdc_ecm_dev.eth_rx = NULL;
+ g_cdc_ecm_dev.eth_tx = rt_usbh_cdc_ecm_eth_tx;
+ g_cdc_ecm_dev.parent.user_data = cdc_ecm_class;
+
+ eth_device_init(&g_cdc_ecm_dev, "u0");
+ eth_device_linkchange(&g_cdc_ecm_dev, RT_TRUE);
+
+ usb_osal_thread_create("usbh_cdc_ecm_rx", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_cdc_ecm_rx_thread, NULL);
+}
+
+void usbh_cdc_ecm_stop(struct usbh_cdc_ecm *cdc_ecm_class)
+{
+ eth_device_deinit(&g_cdc_ecm_dev);
+}
+#endif
+
+#ifdef CONFIG_USBHOST_PLATFORM_CDC_RNDIS
+#include "usbh_rndis.h"
+
+static struct eth_device g_rndis_dev;
+
+static rt_timer_t keep_timer = RT_NULL;
+
+static void rndis_dev_keepalive_timeout(void *parameter)
+{
+ struct usbh_rndis *rndis_class = (struct usbh_rndis *)parameter;
+ usbh_rndis_keepalive(rndis_class);
+}
+
+static void timer_init(struct usbh_rndis *rndis_class)
+{
+ keep_timer = rt_timer_create("keep",
+ rndis_dev_keepalive_timeout,
+ rndis_class,
+ 5000,
+ RT_TIMER_FLAG_PERIODIC |
+ RT_TIMER_FLAG_SOFT_TIMER);
+
+ rt_timer_start(keep_timer);
+}
+
+static rt_err_t rt_usbh_rndis_control(rt_device_t dev, int cmd, void *args)
+{
+ struct usbh_rndis *rndis_class = (struct usbh_rndis *)dev->user_data;
+
+ switch (cmd) {
+ case NIOCTL_GADDR:
+
+ /* get mac address */
+ if (args)
+ rt_memcpy(args, rndis_class->mac, 6);
+ else
+ return -RT_ERROR;
+
+ break;
+
+ default:
+ break;
+ }
+
+ return RT_EOK;
+}
+
+static rt_err_t rt_usbh_rndis_eth_tx(rt_device_t dev, struct pbuf *p)
+{
+ int ret = usbh_rndis_eth_output(p->payload, p->tot_len);
+ if (ret < 0) {
+ return -RT_ERROR;
+ } else {
+ return RT_EOK;
+ }
+}
+
+void usbh_rndis_eth_input(uint8_t *buf, uint32_t buflen)
+{
+ usbh_lwip_eth_input_common(g_rndis_dev.netif, buf, buflen);
+}
+
+void usbh_rndis_run(struct usbh_rndis *rndis_class)
+{
+ memset(&g_rndis_dev, 0, sizeof(struct eth_device));
+
+ g_rndis_dev.parent.control = rt_usbh_rndis_control;
+ g_rndis_dev.eth_rx = NULL;
+ g_rndis_dev.eth_tx = rt_usbh_rndis_eth_tx;
+ g_rndis_dev.parent.user_data = rndis_class;
+
+ eth_device_init(&g_rndis_dev, "u2");
+ eth_device_linkchange(&g_rndis_dev, RT_TRUE);
+
+ usb_osal_thread_create("usbh_rndis_rx", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_rndis_rx_thread, NULL);
+ //timer_init(rndis_class);
+}
+
+void usbh_rndis_stop(struct usbh_rndis *rndis_class)
+{
+ eth_device_deinit(&g_rndis_dev);
+ // rt_timer_stop(keep_timer);
+ // rt_timer_delete(keep_timer);
+}
+#endif
+
+#ifdef CONFIG_USBHOST_PLATFORM_CDC_NCM
+#include "usbh_cdc_ncm.h"
+
+static struct eth_device g_cdc_ncm_dev;
+
+static rt_err_t rt_usbh_cdc_ncm_control(rt_device_t dev, int cmd, void *args)
+{
+ struct usbh_cdc_ncm *cdc_ncm_class = (struct usbh_cdc_ncm *)dev->user_data;
+
+ switch (cmd) {
+ case NIOCTL_GADDR:
+
+ /* get mac address */
+ if (args)
+ rt_memcpy(args, cdc_ncm_class->mac, 6);
+ else
+ return -RT_ERROR;
+
+ break;
+
+ default:
+ break;
+ }
+
+ return RT_EOK;
+}
+
+static rt_err_t rt_usbh_cdc_ncm_eth_tx(rt_device_t dev, struct pbuf *p)
+{
+ int ret = usbh_cdc_ncm_eth_output(p->payload, p->tot_len);
+ if (ret < 0) {
+ return -RT_ERROR;
+ } else {
+ return RT_EOK;
+ }
+}
+
+void usbh_cdc_ncm_eth_input(uint8_t *buf, uint32_t buflen)
+{
+ usbh_lwip_eth_input_common(g_cdc_ncm_dev.netif, buf, buflen);
+}
+
+void usbh_cdc_ncm_run(struct usbh_cdc_ncm *cdc_ncm_class)
+{
+ memset(&g_cdc_ncm_dev, 0, sizeof(struct eth_device));
+
+ g_cdc_ncm_dev.parent.control = rt_usbh_cdc_ncm_control;
+ g_cdc_ncm_dev.eth_rx = NULL;
+ g_cdc_ncm_dev.eth_tx = rt_usbh_cdc_ncm_eth_tx;
+ g_cdc_ncm_dev.parent.user_data = cdc_ncm_class;
+
+ eth_device_init(&g_cdc_ncm_dev, "u1");
+ eth_device_linkchange(&g_cdc_ncm_dev, RT_TRUE);
+
+ usb_osal_thread_create("usbh_cdc_ncm_rx", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_cdc_ncm_rx_thread, NULL);
+}
+
+void usbh_cdc_ncm_stop(struct usbh_cdc_ncm *cdc_ncm_class)
+{
+ eth_device_deinit(&g_cdc_ncm_dev);
+}
+#endif
+
+#ifdef CONFIG_USBHOST_PLATFORM_ASIX
+#include "usbh_asix.h"
+
+static struct eth_device g_asix_dev;
+
+static rt_err_t rt_usbh_asix_control(rt_device_t dev, int cmd, void *args)
+{
+ struct usbh_asix *asix_class = (struct usbh_asix *)dev->user_data;
+
+ switch (cmd) {
+ case NIOCTL_GADDR:
+
+ /* get mac address */
+ if (args)
+ rt_memcpy(args, asix_class->mac, 6);
+ else
+ return -RT_ERROR;
+
+ break;
+
+ default:
+ break;
+ }
+
+ return RT_EOK;
+}
+
+static rt_err_t rt_usbh_asix_eth_tx(rt_device_t dev, struct pbuf *p)
+{
+ int ret = usbh_asix_eth_output(p->payload, p->tot_len);
+ if (ret < 0) {
+ return -RT_ERROR;
+ } else {
+ return RT_EOK;
+ }
+}
+
+void usbh_asix_eth_input(uint8_t *buf, uint32_t buflen)
+{
+ usbh_lwip_eth_input_common(g_asix_dev.netif, buf, buflen);
+}
+
+void usbh_asix_run(struct usbh_asix *asix_class)
+{
+ memset(&g_asix_dev, 0, sizeof(struct eth_device));
+
+ g_asix_dev.parent.control = rt_usbh_asix_control;
+ g_asix_dev.eth_rx = NULL;
+ g_asix_dev.eth_tx = rt_usbh_asix_eth_tx;
+ g_asix_dev.parent.user_data = asix_class;
+
+ eth_device_init(&g_asix_dev, "u3");
+ eth_device_linkchange(&g_asix_dev, RT_TRUE);
+
+ usb_osal_thread_create("usbh_asix_rx", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_asix_rx_thread, NULL);
+}
+
+void usbh_asix_stop(struct usbh_asix *asix_class)
+{
+ eth_device_deinit(&g_asix_dev);
+}
+#endif
+
+#ifdef CONFIG_USBHOST_PLATFORM_RTL8152
+#include "usbh_rtl8152.h"
+
+static struct eth_device g_rtl8152_dev;
+
+static rt_err_t rt_usbh_rtl8152_control(rt_device_t dev, int cmd, void *args)
+{
+ struct usbh_rtl8152 *rtl8152_class = (struct usbh_rtl8152 *)dev->user_data;
+
+ switch (cmd) {
+ case NIOCTL_GADDR:
+
+ /* get mac address */
+ if (args)
+ rt_memcpy(args, rtl8152_class->mac, 6);
+ else
+ return -RT_ERROR;
+
+ break;
+
+ default:
+ break;
+ }
+
+ return RT_EOK;
+}
+
+static rt_err_t rt_usbh_rtl8152_eth_tx(rt_device_t dev, struct pbuf *p)
+{
+ int ret = usbh_rtl8152_eth_output(p->payload, p->tot_len);
+ if (ret < 0) {
+ return -RT_ERROR;
+ } else {
+ return RT_EOK;
+ }
+}
+
+void usbh_rtl8152_eth_input(uint8_t *buf, uint32_t buflen)
+{
+ usbh_lwip_eth_input_common(g_rtl8152_dev.netif, buf, buflen);
+}
+
+void usbh_rtl8152_run(struct usbh_rtl8152 *rtl8152_class)
+{
+ memset(&g_rtl8152_dev, 0, sizeof(struct eth_device));
+
+ g_rtl8152_dev.parent.control = rt_usbh_rtl8152_control;
+ g_rtl8152_dev.eth_rx = NULL;
+ g_rtl8152_dev.eth_tx = rt_usbh_rtl8152_eth_tx;
+ g_rtl8152_dev.parent.user_data = rtl8152_class;
+
+ eth_device_init(&g_rtl8152_dev, "u4");
+ eth_device_linkchange(&g_rtl8152_dev, RT_TRUE);
+
+ usb_osal_thread_create("usbh_rtl8152_rx", 2048, CONFIG_USBHOST_PSC_PRIO + 1, usbh_rtl8152_rx_thread, NULL);
+}
+
+void usbh_rtl8152_stop(struct usbh_rtl8152 *rtl8152_class)
+{
+ eth_device_deinit(&g_rtl8152_dev);
+}
+#endif
diff --git a/platform/threadx/.gitkeep b/platform/threadx/.gitkeep
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/platform/threadx/.gitkeep
diff --git a/third_party/rt-thread-5.0/usb_check.c b/third_party/rt-thread-5.0/usb_check.c
deleted file mode 100644
index 13d178fb..00000000
--- a/third_party/rt-thread-5.0/usb_check.c
+++ /dev/null
@@ -1,43 +0,0 @@
-#include "rtthread.h"
-
-#ifdef PKG_CHERRYUSB_HOST
-
-#ifndef RT_USING_TIMER_SOFT
-#error must enable RT_USING_TIMER_SOFT to support timer callback in thread
-#endif
-
-#if IDLE_THREAD_STACK_SIZE < 2048
-#error "IDLE_THREAD_STACK_SIZE must be greater than 2048"
-#endif
-
-#if RT_TIMER_THREAD_STACK_SIZE < 2048
-#error "RT_TIMER_THREAD_STACK_SIZE must be greater than 2048"
-#endif
-
-#ifdef RT_USING_LWIP
-
-#include "lwip/opt.h"
-
-#ifndef RT_USING_LWIP212
-#error must enable RT_USING_LWIP212
-#endif
-
-#ifndef LWIP_NO_RX_THREAD
-#error must enable LWIP_NO_RX_THREAD, we do not use rtthread eth rx thread
-#endif
-
-#if LWIP_TCPIP_CORE_LOCKING_INPUT !=1
-#warning suggest you to set LWIP_TCPIP_CORE_LOCKING_INPUT to 1, usb handles eth input with own thread
-#endif
-
-#if LWIP_TCPIP_CORE_LOCKING !=1
-#error must set LWIP_TCPIP_CORE_LOCKING to 1
-#endif
-
-#if PBUF_POOL_BUFSIZE < 1514
-#error PBUF_POOL_BUFSIZE must be larger than 1514
-#endif
-
-#endif
-
-#endif