diff --git a/Ubiquitous/XiZi_AIoT/services/drivers/usb/components/class/wireless/rndis_host.c b/Ubiquitous/XiZi_AIoT/services/drivers/usb/components/class/wireless/rndis_host.c index 500bb1415..a38e6ab23 100644 --- a/Ubiquitous/XiZi_AIoT/services/drivers/usb/components/class/wireless/rndis_host.c +++ b/Ubiquitous/XiZi_AIoT/services/drivers/usb/components/class/wireless/rndis_host.c @@ -1 +1,240 @@ +/* FreeRTOS kernel includes. */ + +/************************************************* +File name: rndis_host.c +Description: adopt cherry USB to XiZi AIOT. +Others: CherryUSB v0.10.2/CherryUSB/third_party/FreeRTOS-10.4/rndis_host/rndis_host.c for references + https://github.com/cherry-embedded/CherryUSB/blob/v0.10.2/third_party/FreeRTOS-10.4/rndis_host/rndis_host.c + +History: +1. Date: 2024-07-22 +Author: AIIT XUOS Lab +Modification: Modify rndis_host.c according to + https://github.com/cherry-embedded/CherryUSB/blob/v0.10.2/third_party/FreeRTOS-10.4/rndis_host/rndis_host.c + https://github.com/cherry-embedded/CherryUSB/blob/v0.10.2/third_party/rt-thread-4.1.1/rndis_host/rndis_host_lwip2.1.2.c + and https://github.com/longtengmcu/USB-HOST-driver-4G-rndis-device/components/drivers/usb/usbhost/class/rndis_dev.c (Zhaoshimin). +*************************************************/ +#include +#include "usbh_core.h" #include "usbh_rndis.h" +#include "rndis_protocol.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 USB_ETH_MTU (1500 + 14) +#define RNDIS_THREAD_STACK_SIZE (4096) + +#define NIOCTL_GADDR 0x01 +#define MAX_ADDR_LEN 6 +/* rndis device keepalive time 5000ms*/ +#define RNDIS_DEV_KEEPALIVE_TIMEOUT 5000 +/*should be the usb Integer multiple of maximum packet length N*64*/ +#define RNDIS_ETH_BUFFER_LEN (sizeof(rndis_data_packet_t) + USB_ETH_MTU + 42) +#define RNDIS_RXETH_BUFFER_LEN (RNDIS_ETH_BUFFER_LEN * 5) + +#define RT_TRUE 1 /**< boolean true */ +#define RT_FALSE 0 /**< boolean fails */ + +/* Static Variable Definition*/ +static struct usbh_rndis *s_rndis_class_ptr; + +USB_NOCACHE_RAM_SECTION uint8_t tx_buffer[RNDIS_ETH_BUFFER_LEN]; +USB_NOCACHE_RAM_SECTION uint8_t rx_buffer[RNDIS_RXETH_BUFFER_LEN]; +static uint8_t *rx_buf_ptr; +usb_osal_sem_t mutex_sem_handle; +usb_osal_thread_t timer_handle; +usb_osal_thread_t data_recv_task_handle; + +extern void eth_device_linkchange(bool up); //todo IPC function +extern void eth_device_ready(void *dataptr, size_t len); //todo IPC function + +static void rndis_dev_keepalive_timeout(void *pdata) +{ + int ret; + + while (1) { + usb_osal_msleep(RNDIS_DEV_KEEPALIVE_TIMEOUT); + + usb_osal_sem_take(mutex_sem_handle, USB_OSAL_WAITING_FOREVER); + ret = usbh_rndis_keepalive(s_rndis_class_ptr); + usb_osal_sem_give(mutex_sem_handle); + if (ret < 0) { + printf("rndis dev keepalive timeout!\n"); + } + } +} + +static void usbh_rndis_data_recv_entry(void *pdata) +{ + int ret = 0; + rndis_data_packet_t *pmsg; + int pmg_offset; + int recount = 5; + uint8_t data[4]; + uint32_t info_len = 0; + + struct usbh_rndis *rndis_class = (struct usbh_rndis *)pdata; + rx_buf_ptr = rx_buffer; + + if (!rndis_class->link_status) { + printf("linkdown, drop pkg\r\n"); + while(recount--) { + ret = usbh_rndis_query_msg_transfer(rndis_class, OID_GEN_MEDIA_CONNECT_STATUS, sizeof(data), data, &info_len); + if (ret < 0) { + continue;; + } + if (NDIS_MEDIA_STATE_CONNECTED == data[0]) { + s_rndis_class_ptr->link_status = true; + eth_device_linkchange(RT_TRUE); + printf("linkup, drop pkg\r\n"); + break; + } else { + s_rndis_class_ptr->link_status = false; + eth_device_linkchange(RT_FALSE); + } + usb_osal_msleep(100); + } + } + + while (1) { + pmg_offset = 0; + ret = usbh_rndis_bulk_in_transfer(rndis_class, rx_buf_ptr, RNDIS_RXETH_BUFFER_LEN, USB_OSAL_WAITING_FOREVER); + if (ret <= 0) { + usb_osal_msleep(1); + continue; + } + while (ret > 0) { + pmsg = (rndis_data_packet_t *)(rx_buf_ptr + pmg_offset); + if (pmsg->MessageType == REMOTE_NDIS_PACKET_MSG) { + eth_device_ready((uint8_t *)(&pmsg->DataOffset) + pmsg->DataOffset, pmsg->MessageLength); + pmg_offset += pmsg->MessageLength; + ret -= pmsg->MessageLength; + } + } + } +} + +void usbh_rndis_run(struct usbh_rndis *rndis_class) +{ + s_rndis_class_ptr = rndis_class; + rx_buf_ptr = rx_buffer; + + mutex_sem_handle = usb_osal_sem_create(0); + if (NULL == mutex_sem_handle) { + printf("mutex semaphore creat faile!\r\n"); + return; + } + + timer_handle = usb_osal_thread_create("keepalive", RNDIS_THREAD_STACK_SIZE, 5, rndis_dev_keepalive_timeout, rndis_class); + if (NULL == timer_handle) { + printf("timer creation failed!\n"); + return; + } + + data_recv_task_handle = usb_osal_thread_create("rndis_recv", RNDIS_THREAD_STACK_SIZE, 5, usbh_rndis_data_recv_entry, rndis_class); + if (NULL == data_recv_task_handle) { + printf("rndis_lwip_rx Task creation failed!\n"); + return; + } +} + +void usbh_rndis_stop(struct usbh_rndis *rndis_class) +{ + usb_osal_thread_delete(data_recv_task_handle); + usb_osal_thread_delete(timer_handle); + usb_osal_sem_delete(mutex_sem_handle); + printf("rndis dev stop!\n"); +} + +static int rndis_msg_data_send(struct usbh_rndis *rndis_class, uint8_t *buffer, + int nbytes) +{ + int ret = 0; + int len = 0; + usb_osal_sem_take(mutex_sem_handle, USB_OSAL_WAITING_FOREVER); + len = usbh_rndis_bulk_out_transfer(rndis_class, buffer, nbytes, 5000); + usb_osal_sem_give(mutex_sem_handle); + if (len != nbytes) { + printf("rndis msg send fail\r\n"); + ret = -EBUSY; + } + return ret; +} + +int usbh_rndis_eth_tx(void *dataptr, size_t tot_len) +{ + uint8_t *buffer; + rndis_data_packet_t *hdr; + int ret; + int recount = 5; + uint8_t data[4]; + uint32_t info_len = 0; + + if (!s_rndis_class_ptr->link_status) { + printf("linkdown, drop pkg\r\n"); + while (recount--) { + ret = usbh_rndis_query_msg_transfer(s_rndis_class_ptr, OID_GEN_MEDIA_CONNECT_STATUS, sizeof(data), data, &info_len); + if (ret < 0) { + return -EBUSY; + } + if (NDIS_MEDIA_STATE_CONNECTED == data[0]) { + s_rndis_class_ptr->link_status = true; + eth_device_linkchange(RT_TRUE); + printf("linkup, drop pkg\r\n"); + break; + } else { + s_rndis_class_ptr->link_status = false; + eth_device_linkchange(RT_FALSE); + } + usb_osal_msleep(100); + } + return 0; + } + + USB_ASSERT((tot_len + sizeof(rndis_data_packet_t)) < sizeof(tx_buffer)); + if (tot_len > sizeof(tx_buffer)) { + printf("RNDIS MTU is:%d, but the send packet size is %d\r\n", sizeof(tx_buffer), tot_len); + tot_len = sizeof(tx_buffer); + } + + hdr = (rndis_data_packet_t *)tx_buffer; + memset(hdr, 0, sizeof(rndis_data_packet_t)); + hdr->MessageType = REMOTE_NDIS_PACKET_MSG; + hdr->MessageLength = sizeof(rndis_data_packet_t) + tot_len; + hdr->DataOffset = sizeof(rndis_data_packet_t) - sizeof(rndis_generic_msg_t); + hdr->DataLength = tot_len; + + buffer = (uint8_t *)(tx_buffer + sizeof(rndis_data_packet_t)); + memcpy(buffer, dataptr, tot_len); + + /* send */ + if ((hdr->MessageLength & 0x1FF) == 0) { + /* pad a dummy. */ + hdr->MessageLength += 1; + } + return rndis_msg_data_send(s_rndis_class_ptr, (uint8_t *)tx_buffer, hdr->MessageLength); +} + +int usbh_rndis_eth_control(int cmd, void *args) +{ + switch (cmd) { + case NIOCTL_GADDR: + /* get mac address */ + if (args) { + memcpy(args, s_rndis_class_ptr->mac, MAX_ADDR_LEN); + } else { + return -EINVAL; + } + break; + + default: + break; + } + + return 0; +} + diff --git a/Ubiquitous/XiZi_AIoT/services/drivers/usb/components/class/wireless/usbh_rndis.h b/Ubiquitous/XiZi_AIoT/services/drivers/usb/components/class/wireless/usbh_rndis.h index 1aeac2992..4d0dfaf28 100644 --- a/Ubiquitous/XiZi_AIoT/services/drivers/usb/components/class/wireless/usbh_rndis.h +++ b/Ubiquitous/XiZi_AIoT/services/drivers/usb/components/class/wireless/usbh_rndis.h @@ -50,6 +50,7 @@ int usbh_rndis_bulk_out_transfer(struct usbh_rndis *rndis_class, uint8_t *buffer int usbh_rndis_bulk_in_transfer(struct usbh_rndis *rndis_class, uint8_t *buffer, uint32_t buflen, uint32_t timeout); int usbh_rndis_keepalive(struct usbh_rndis *rndis_class); +int usbh_rndis_query_msg_transfer(struct usbh_rndis *rndis_class, uint32_t oid, uint32_t query_len, uint8_t *info, uint32_t *info_len); void usbh_rndis_run(struct usbh_rndis *rndis_class); void usbh_rndis_stop(struct usbh_rndis *rndis_class); diff --git a/Ubiquitous/XiZi_AIoT/services/drivers/usb/components/osal/usb_osal.h b/Ubiquitous/XiZi_AIoT/services/drivers/usb/components/osal/usb_osal.h index f9510af95..9cc4a7587 100644 --- a/Ubiquitous/XiZi_AIoT/services/drivers/usb/components/osal/usb_osal.h +++ b/Ubiquitous/XiZi_AIoT/services/drivers/usb/components/osal/usb_osal.h @@ -22,6 +22,7 @@ Modification: introduce message queue mechanism. #include #include "usb_config.h" +#define USB_OSAL_WAITING_FOREVER (0xFFFFFFFFU) typedef void *usb_osal_thread_t; typedef void *usb_osal_sem_t;