Files
CherryUSB/third_party/FreeRTOS-10.4/rndis_host/rndis_host.c
Zhihong Chen d4ba2eef57 osal: add USB_OSAL_WAITING_FOREVER for Semaphore and Queue use
- add USB_OSAL_WAITING_FOREVER for Semaphore and Queue use

Signed-off-by: Zhihong Chen <zhihong.chen@hpmicro.com>
2023-10-12 14:38:13 +08:00

287 lines
8.5 KiB
C

/* FreeRTOS kernel includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "timers.h"
#include <stdio.h>
#include "board.h"
#include "netif/etharp.h"
#include "lwip/init.h"
#include "lwip/tcp.h"
#include "lwip/tcpip.h"
#include "lwip/netif.h"
#include "lwip/pbuf.h"
#include "lwip/icmp.h"
#include "lwip/udp.h"
#include "lwip/opt.h"
#include "lwip/arch.h"
#include "lwip/api.h"
#include "lwip/inet.h"
#include "lwip/dhcp.h"
#include "lwip/prot/dhcp.h"
#include <lwip/ip.h>
#include <lwip/netdb.h>
#include <lwip/sockets.h>
#include "usbh_core.h"
#include "usbh_rndis.h"
#include "rndis_protocol.h"
/* Macro Definition */
/*--------------- Tasks Priority -------------*/
#define RNDIS_RECV_DATA_TASK_PRIO (tskIDLE_PRIORITY + 6)
#define RNDIS_ETH_BUFFER_LEN (sizeof(rndis_data_packet_t) + 1514 + 42)
#define RNDIS_RXETH_BUFFER_LEN (RNDIS_ETH_BUFFER_LEN * 3)
/* Static Variable Definition*/
static struct usbh_rndis *s_rndis_class_ptr;
static struct netif netif_data;
static ip4_addr_t ipaddr;
static ip4_addr_t netmask;
static ip4_addr_t gateway;
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;
SemaphoreHandle_t mutex_sem_handle;
SemaphoreHandle_t sig_sem_handle;
TimerHandle_t timer_handle;
TaskHandle_t data_recv_task_handle;
/* Static Function Declaration */
static void rndis_dev_keepalive_timeout(void *pdata);
static err_t netif_init_cb(struct netif *netif);
static err_t linkoutput_fn(struct netif *netif, struct pbuf *p);
static int usbh_rndis_eth_tx(struct pbuf *p);
static int rndis_msg_data_send(struct usbh_rndis *rndis_class, uint8_t *buffer, int nbytes);
static void lwip_rx_handle(void *pdata);
extern 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)
{
struct netif *netif = &netif_data;
s_rndis_class_ptr = rndis_class;
rx_buf_ptr = rx_buffer;
/* Create tcp_ip stack thread */
tcpip_init(NULL, NULL);
netif->hwaddr_len = 6;
memcpy(netif->hwaddr, rndis_class->mac, 6);
IP4_ADDR(&ipaddr, 0, 0, 0, 0);
IP4_ADDR(&netmask, 0, 0, 0, 0);
IP4_ADDR(&gateway, 0, 0, 0, 0);
netif = netif_add(netif, &ipaddr, &netmask, &gateway, NULL, netif_init_cb, tcpip_input);
netif_set_default(netif);
netif_set_up(netif);
mutex_sem_handle = xSemaphoreCreateMutex();
if (NULL == mutex_sem_handle) {
printf("mutex semaphore creat faile!\r\n");
for (;;) {
;
}
}
sig_sem_handle = xSemaphoreCreateCounting(1, 0);
if (NULL == sig_sem_handle) {
printf("Rndis sig semaphore creat faile!\r\n");
for (;;) {
;
}
}
timer_handle =
xTimerCreate((const char *)NULL, (TickType_t)5000, (UBaseType_t)pdTRUE, (void *const)1, (TimerCallbackFunction_t)rndis_dev_keepalive_timeout);
if (NULL != timer_handle) {
xTimerStart(timer_handle, 0);
} else {
printf("timer creation failed!.\n");
for (;;) {
;
}
}
if (xTaskCreate(lwip_rx_handle, "rndis_lwip_rx", configMINIMAL_STACK_SIZE + 2048U, rndis_class, RNDIS_RECV_DATA_TASK_PRIO, &data_recv_task_handle) !=
pdPASS) {
printf("rndis_lwip_rx Task creation failed!.\n");
for (;;) {
;
}
}
}
void usbh_rndis_stop(struct usbh_rndis *rndis_class)
{
vTaskDelete(data_recv_task_handle);
xTimerStop(timer_handle, 0);
xTimerDelete(timer_handle, 0);
vSemaphoreDelete(mutex_sem_handle);
vSemaphoreDelete(sig_sem_handle);
netif_remove(&netif_data);
printf("rndis dev stop!\n");
}
static void rndis_dev_keepalive_timeout(void *pdata)
{
int ret;
xSemaphoreTake(mutex_sem_handle, portMAX_DELAY);
ret = usbh_rndis_keepalive(s_rndis_class_ptr);
xSemaphoreGive(mutex_sem_handle);
if (ret < 0) {
printf("rndis dev keepalive timeout!\n");
}
}
static void lwip_rx_handle(void *pdata)
{
err_t err;
int ret = 0;
struct pbuf *p;
rndis_data_packet_t *pmsg;
int pmg_offset;
int payload_offset;
struct usbh_rndis *rndis_class = (struct usbh_rndis *)pdata;
rx_buf_ptr = rx_buffer;
while (1) {
pmg_offset = 0;
payload_offset = 0;
ret = usbh_rndis_bulk_in_transfer(rndis_class, rx_buf_ptr, RNDIS_RXETH_BUFFER_LEN, USB_OSAL_WAITING_FOREVER);
if (ret <= 0) {
vTaskDelay(1);
continue;
}
while (ret > 0) {
pmsg = (rndis_data_packet_t *)(rx_buf_ptr + pmg_offset);
if (pmsg->MessageType == REMOTE_NDIS_PACKET_MSG) {
/* allocate buffer */
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);
payload_offset += q->len;
}
/* entry point to the LwIP stack */
err = netif_data.input(p, &netif_data);
if (err != ERR_OK) {
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
pbuf_free(p);
}
pmg_offset += pmsg->MessageLength;
ret -= pmsg->MessageLength;
}
}
}
}
}
static err_t netif_init_cb(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->state = NULL;
netif->name[0] = 'E';
netif->name[1] = 'X';
netif->linkoutput = linkoutput_fn;
netif->output = etharp_output;
return ERR_OK;
}
static err_t linkoutput_fn(struct netif *netif, struct pbuf *p)
{
int ret;
ret = usbh_rndis_eth_tx(p);
if (-EBUSY == ret) {
ret = ERR_BUF;
}
return ret;
}
static int usbh_rndis_eth_tx(struct pbuf *p)
{
struct pbuf *q;
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;
break;
} else {
s_rndis_class_ptr->link_status = false;
}
vTaskDelay(1000);
}
return 0;
}
assert((p->tot_len + sizeof(rndis_data_packet_t)) < sizeof(tx_buffer));
if (p->tot_len > sizeof(tx_buffer)) {
printf("RNDIS MTU is:%d, but the send packet size is %d\r\n", sizeof(tx_buffer), p->tot_len);
p->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) + p->tot_len;
hdr->DataOffset = sizeof(rndis_data_packet_t) - sizeof(rndis_generic_msg_t);
hdr->DataLength = p->tot_len;
buffer = (uint8_t *)(tx_buffer + sizeof(rndis_data_packet_t));
for (q = p; q != NULL; q = q->next) {
memcpy(buffer, q->payload, q->len);
buffer += q->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);
}
static int rndis_msg_data_send(struct usbh_rndis *rndis_class, uint8_t *buffer,
int nbytes)
{
int ret = ERR_OK;
int len = 0;
xSemaphoreTake(mutex_sem_handle, portMAX_DELAY);
len = usbh_rndis_bulk_out_transfer(rndis_class, buffer, nbytes, 5000);
xSemaphoreGive(mutex_sem_handle);
if (len != nbytes) {
printf("rndis msg send fail\r\n");
ret = -EBUSY;
}
return ret;
}