822 lines
32 KiB
C
822 lines
32 KiB
C
/*
|
|
* Copyright 2018,2020,2022 NXP
|
|
* All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include "lwip/opt.h"
|
|
#include "lwip/def.h"
|
|
#include "lwip/mem.h"
|
|
#include "lwip/pbuf.h"
|
|
#include "lwip/stats.h"
|
|
#include "lwip/snmp.h"
|
|
#include "lwip/ethip6.h"
|
|
#include "netif/etharp.h"
|
|
#include "netif/ppp/pppoe.h"
|
|
#include "lwip/igmp.h"
|
|
#include "lwip/mld6.h"
|
|
|
|
#if USE_RTOS && defined(SDK_OS_FREE_RTOS)
|
|
#include "FreeRTOS.h"
|
|
#include "event_groups.h"
|
|
#endif
|
|
|
|
#include "usb_host_config.h"
|
|
#include "usb_host.h"
|
|
#include "usb_host_cdc_rndis.h"
|
|
#include "usb_host_cdc.h"
|
|
|
|
#include "board.h"
|
|
|
|
#include "usb_ethernetif.h"
|
|
|
|
#include "board.h"
|
|
|
|
#if ((!USB_HOST_CONFIG_KHCI) && (!USB_HOST_CONFIG_EHCI) && (!USB_HOST_CONFIG_OHCI) && (!USB_HOST_CONFIG_IP3516HS))
|
|
#error Please enable USB_HOST_CONFIG_KHCI, USB_HOST_CONFIG_EHCI, USB_HOST_CONFIG_OHCI, or USB_HOST_CONFIG_IP3516HS in file usb_host_config.
|
|
#endif
|
|
|
|
/*******************************************************************************
|
|
* Definitions
|
|
******************************************************************************/
|
|
|
|
/*******************************************************************************
|
|
* Prototypes
|
|
******************************************************************************/
|
|
extern void USB_HostClockInit(void);
|
|
extern void USB_HostIsrEnable(void);
|
|
extern void USB_HostTaskFn(void *param);
|
|
/*******************************************************************************
|
|
* Variables
|
|
******************************************************************************/
|
|
#define IFNAME0 'N'
|
|
#define IFNAME1 'X'
|
|
/*each g_RndisInstance should have its own's buffer*/
|
|
USB_DMA_NONINIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) uint8_t g_SendMessage[RNDIS_CONTROL_MESSAGE];
|
|
USB_DMA_NONINIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) uint8_t g_GetMessage[RNDIS_CONTROL_MESSAGE];
|
|
/*used for send/recv data from/to device rndis, the message length should be the sum of max frame packet size and usb rndis header*/
|
|
USB_DMA_NONINIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) uint8_t g_OutPutBuffer[RNDIS_DATA_MESSAGE];
|
|
USB_DMA_NONINIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) uint8_t g_InPutBuffer[RNDIS_DATA_MESSAGE];
|
|
|
|
usb_host_rndis_instance_struct_t g_RndisInstance = {0};
|
|
|
|
usb_host_handle g_HostHandle;
|
|
|
|
|
|
/*******************************************************************************
|
|
* Code
|
|
******************************************************************************/
|
|
/*!
|
|
* @brief host cdc data transfer callback.
|
|
*
|
|
* This function is used as callback function for bulk in transfer .
|
|
*
|
|
* @param param the host cdc instance pointer.
|
|
* @param data data buffer pointer.
|
|
* @param dataLength data length.
|
|
* @status transfer result status.
|
|
*/
|
|
|
|
void USB_HostCdcRndisDataInCallback(void *param, uint8_t *data, uint32_t dataLength, usb_status_t status)
|
|
{
|
|
usb_host_rndis_instance_struct_t * rndisInstance = (usb_host_rndis_instance_struct_t *)param;
|
|
struct netif *netif = (struct netif *)rndisInstance->netif;
|
|
if (status != kStatus_USB_Success)
|
|
{
|
|
if (status == kStatus_USB_TransferCancel)
|
|
{
|
|
/*usb_echo("cdc transfer cancel\r\n");*/
|
|
}
|
|
else
|
|
{
|
|
/**usb_echo("cdc in transfer retry\r\n");*/
|
|
}
|
|
rndisInstance->runState = kUSB_HostCdcRndisRunDataReceive;
|
|
}
|
|
else
|
|
{
|
|
|
|
struct pbuf *pbuf;
|
|
if((dataLength > 0) && (NULL != data))
|
|
{
|
|
|
|
rndis_packet_msg_struct_t *temp = (rndis_packet_msg_struct_t *)data;
|
|
pbuf= pbuf_alloc(PBUF_RAW, temp->dataLength, PBUF_POOL);
|
|
if (pbuf)
|
|
{
|
|
|
|
temp->dataBuffer[temp->dataLength] = 0;
|
|
pbuf->tot_len = temp->dataLength;
|
|
pbuf->len = temp->dataLength;
|
|
|
|
uint8_t *p = (uint8_t*)(&temp->dataOffset);
|
|
memcpy(pbuf->payload, (p + temp->dataOffset), temp->dataLength);
|
|
/*in special case, when polling out packet, in packet maybe finihsed, the in packet will be not be handled*/
|
|
if (!rndisInstance->pollingInSending)
|
|
{
|
|
netif->input(pbuf, netif);
|
|
}
|
|
}
|
|
|
|
}
|
|
rndisInstance->runState = kUSB_HostCdcRndisRunDataReceive;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*!
|
|
* @brief host cdc data transfer callback.
|
|
*
|
|
* This function is used as callback function for bulk out transfer .
|
|
*
|
|
* @param param the host cdc instance pointer.
|
|
* @param data data buffer pointer.
|
|
* @param dataLength data length.
|
|
* @status transfer result status.
|
|
*/
|
|
void USB_HostCdcRndisDataOutCallback(void *param, uint8_t *data, uint32_t dataLength, usb_status_t status)
|
|
{
|
|
usb_host_rndis_instance_struct_t *rndisInstance = (usb_host_rndis_instance_struct_t *)param;
|
|
if (status != kStatus_USB_Success)
|
|
{
|
|
if (status == kStatus_USB_TransferCancel)
|
|
{
|
|
usb_echo("cdc transfer cancel\r\n");
|
|
}
|
|
else
|
|
{
|
|
/*usb_echo("cdc out transfer error\r\n");*/
|
|
}
|
|
}
|
|
rndisInstance->dataSend = 0U;
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
err_t USB_EthernetIfOutPut(struct netif *netif, struct pbuf *p)
|
|
{
|
|
err_t status;
|
|
usb_host_rndis_instance_struct_t * rndisInstance = (usb_host_rndis_instance_struct_t *)netif->state;
|
|
status = ERR_OK;
|
|
if (rndisInstance->attach)
|
|
{
|
|
if(p->tot_len == p->len)
|
|
{
|
|
uint32_t total;
|
|
total = p->tot_len;
|
|
uint32_t transferDone = 0;
|
|
|
|
while (total)
|
|
{
|
|
rndisInstance->pollingInSending = 1;
|
|
if(rndisInstance->dataSend)
|
|
{
|
|
/*discard current data if send flag is not cleared*/
|
|
return ERR_BUF;
|
|
}
|
|
rndisInstance->pollingInSending = 0;
|
|
|
|
rndisInstance->dataSend = 1;
|
|
if(total <= RNDIS_FRAME_MAX_FRAMELEN)
|
|
{
|
|
|
|
USB_HostRndisSendDataMsg(rndisInstance->classHandle, rndisInstance->outPutBuffer, RNDIS_FRAME_MAX_FRAMELEN, 0, 0, 0, 0, 0, ((uint8_t*)p->payload + transferDone),total,
|
|
USB_HostCdcRndisDataOutCallback, rndisInstance);
|
|
transferDone += total;
|
|
total = 0U;
|
|
|
|
}
|
|
else
|
|
{
|
|
USB_HostRndisSendDataMsg(rndisInstance->classHandle, rndisInstance->outPutBuffer, RNDIS_FRAME_MAX_FRAMELEN, 0, 0, 0, 0, 0, ((uint8_t*)p->payload + transferDone),RNDIS_FRAME_MAX_FRAMELEN,
|
|
USB_HostCdcRndisDataOutCallback, rndisInstance);
|
|
transferDone += RNDIS_FRAME_MAX_FRAMELEN;
|
|
total -= RNDIS_FRAME_MAX_FRAMELEN;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (p->tot_len < RNDIS_FRAME_MAX_FRAMELEN)
|
|
{
|
|
u16_t uCopied = pbuf_copy_partial(p, rndisInstance->outPutBuffer, p->tot_len, 0);
|
|
LWIP_ASSERT("uCopied != p->tot_len", uCopied == p->tot_len);
|
|
|
|
rndisInstance->pollingInSending = 1;
|
|
while(rndisInstance->dataSend)
|
|
{
|
|
|
|
USB_HostTaskFn(g_HostHandle);
|
|
}
|
|
rndisInstance->pollingInSending = 0;
|
|
USB_HostRndisSendDataMsg(rndisInstance->classHandle, rndisInstance->outPutBuffer, RNDIS_FRAME_MAX_FRAMELEN, 0, 0, 0, 0, 0, ((uint8_t*)&g_OutPutBuffer[0]),p->tot_len,
|
|
USB_HostCdcRndisDataOutCallback, rndisInstance);
|
|
|
|
}
|
|
else
|
|
{
|
|
/*TO DO*/
|
|
return ERR_BUF;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
status = ERR_CONN;
|
|
usb_echo("USB Rndis device is not attached\r\n");
|
|
}
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
* @brief host callback function.
|
|
*
|
|
* device attach/detach callback function.
|
|
*
|
|
* @param deviceHandle device handle.
|
|
* @param configurationHandle attached device's configuration descriptor information.
|
|
* @param event_code callback event code, please reference to enumeration host_event_t.
|
|
*
|
|
* @retval kStatus_USB_Success The host is initialized successfully.
|
|
* @retval kStatus_USB_NotSupported The application don't support the configuration.
|
|
*/
|
|
usb_status_t USB_HostEvent(usb_device_handle deviceHandle,
|
|
usb_host_configuration_handle configurationHandle,
|
|
uint32_t event_code)
|
|
{
|
|
usb_status_t status;
|
|
status = kStatus_USB_Success;
|
|
|
|
switch (event_code)
|
|
{
|
|
case kUSB_HostEventAttach:
|
|
status = USB_HostCdcRndisEvent(deviceHandle, configurationHandle, event_code);
|
|
break;
|
|
case kUSB_HostEventNotSupported:
|
|
status = USB_HostCdcRndisEvent(deviceHandle, configurationHandle, event_code);
|
|
usb_echo("device not supported.\r\n");
|
|
break;
|
|
|
|
case kUSB_HostEventEnumerationDone:
|
|
status = USB_HostCdcRndisEvent(deviceHandle, configurationHandle, event_code);
|
|
break;
|
|
|
|
case kUSB_HostEventDetach:
|
|
status = USB_HostCdcRndisEvent(deviceHandle, configurationHandle, event_code);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
|
|
static void USB_HostApplicationInit(uint8_t controllerId, struct netif *netif)
|
|
|
|
{
|
|
|
|
usb_status_t status = kStatus_USB_Success;
|
|
|
|
USB_HostClockInit();
|
|
|
|
|
|
status = USB_HostInit(controllerId, &g_HostHandle, USB_HostEvent);
|
|
if (status != kStatus_USB_Success)
|
|
{
|
|
usb_echo("host init error\r\n");
|
|
return;
|
|
}
|
|
USB_HostIsrEnable();
|
|
usb_echo(" host init.\r\n");
|
|
netif->state = (void *)&g_RndisInstance;
|
|
g_RndisInstance.netif = (void*)netif;
|
|
g_RndisInstance.hostHandle = g_HostHandle;
|
|
g_RndisInstance.sendMessage = &g_SendMessage[0];
|
|
g_RndisInstance.getMessage = &g_GetMessage[0];
|
|
g_RndisInstance.outPutBuffer = &g_OutPutBuffer[0];
|
|
g_RndisInstance.inPutBuffer = &g_InPutBuffer[0];
|
|
while (!g_RndisInstance.attach)
|
|
{
|
|
USB_HostTaskFn(g_RndisInstance.hostHandle);
|
|
USB_HosCdcRndisTask(&g_RndisInstance);
|
|
}
|
|
}
|
|
|
|
err_t USB_EthernetIfInIt(struct netif *netif)
|
|
{
|
|
err_t status;
|
|
status = ERR_IF;
|
|
netif->name[0] = IFNAME0;
|
|
netif->name[1] = IFNAME1;
|
|
#if LWIP_IPV4
|
|
netif->output = etharp_output;
|
|
#endif
|
|
netif->linkoutput = USB_EthernetIfOutPut;
|
|
/* set MAC hardware address length */
|
|
netif->hwaddr_len = ETH_HWADDR_LEN;
|
|
ethernetifConfig_t *config;
|
|
if(netif->state)
|
|
{
|
|
config = (ethernetifConfig_t *)netif->state;
|
|
|
|
USB_HostApplicationInit(config->controllerId, netif);
|
|
/*USB enet card is ready*/
|
|
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
|
|
status = ERR_OK;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
/*!
|
|
* @brief host cdc interrupt transfer callback.
|
|
*
|
|
* This function is used as callback function for interrupt transfer . Interrupt transfer is used to implement
|
|
* asynchronous notification of UART status as pstn sepc. This callback suppose the device will return SerialState
|
|
* notification. If there is need to suppose other notification ,please refer pstn spec 6.5 and cdc spec6.3.
|
|
* @param param the host cdc instance pointer.
|
|
* @param data data buffer pointer.
|
|
* @param dataLength data length.
|
|
* @status transfer result status.
|
|
*/
|
|
void USB_HostCdcRndisInterruptCallback(void *param, uint8_t *data, uint32_t dataLength, usb_status_t status)
|
|
{
|
|
/*usb_host_cdc_acm_state_struct_t *state = (usb_host_cdc_acm_state_struct_t *)data;*/
|
|
usb_host_rndis_instance_struct_t *rndisInstance = (usb_host_rndis_instance_struct_t *)param;
|
|
|
|
if (status != kStatus_USB_Success)
|
|
{
|
|
if (status == kStatus_USB_TransferCancel)
|
|
{
|
|
usb_echo("cdc transfer cancel\r\n");
|
|
}
|
|
else
|
|
{
|
|
usb_echo("cdc control transfer error\r\n");
|
|
}
|
|
}
|
|
else
|
|
{ /*more information about SerialState ,please pstn spec 6.5.4 */
|
|
/* usb_echo("get serial state value = %d\r\n", state->bmstate);*/
|
|
rndisInstance->responseAvailable = 1;
|
|
rndisInstance->interruptRunState = kUSB_HostCdcRndisRunInterruptRecvDone;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
* @brief host cdc rndis control transfer callback.
|
|
*
|
|
* This function is used as callback function for control transfer .
|
|
*
|
|
* @param param the host cdc rndis instance pointer.
|
|
* @param data data buffer pointer.
|
|
* @param dataLength data length.
|
|
* @status transfer result status.
|
|
*/
|
|
void USB_HostCdcRndisControlCallback(void *param, uint8_t *data, uint32_t dataLength, usb_status_t status)
|
|
{
|
|
usb_host_rndis_instance_struct_t *rndisInstance = (usb_host_rndis_instance_struct_t *)param;
|
|
|
|
struct netif *netif = (struct netif *)rndisInstance->netif;
|
|
if (status != kStatus_USB_Success)
|
|
{
|
|
usb_echo("data transfer error = %d\r\n",status);
|
|
return;
|
|
}
|
|
|
|
if (rndisInstance->runWaitState == kUSB_HostCdcRndisRunWaitSetControlInterface)
|
|
{
|
|
rndisInstance->runState = kUSB_HostCdcRndisRunSetControlInterfaceDone;
|
|
}
|
|
else if (rndisInstance->runWaitState == kUSB_HostCdcRndisRunWaitSetDataInterface)
|
|
{
|
|
rndisInstance->runState = kUSB_HostCdcRndisRunSetDataInterfaceDone;
|
|
}
|
|
else if (rndisInstance->runWaitState == kUSB_HostCdcRndisRunWaitInitMsg)
|
|
{
|
|
rndisInstance->runState = kUSB_HostCdcRndisRunWaitInitMsgDone;
|
|
}
|
|
else if (rndisInstance->runWaitState == kUSB_HostCdcRndisRunWaitMaxmumFrame)
|
|
{
|
|
rndisInstance->runState = kUSB_HostCdcRndisRunWaitMaxmumFrameDone;
|
|
}
|
|
else if (rndisInstance->runWaitState == kUSB_HostCdcRndisRunWaitGetMACAddress)
|
|
{
|
|
rndisInstance->runState = kUSB_HostCdcRndisRunWaitGetMACAddressDone;
|
|
}
|
|
else if (rndisInstance->runWaitState == kUSB_HostCdcRndisRunWaitSetMsg)
|
|
{
|
|
rndisInstance->runState = kUSB_HostCdcRndisRunWaitSetMsgDone;
|
|
}
|
|
else if (rndisInstance->runWaitState == kUSB_HostCdcRndisRunWaitGetEncapsulatedCommand)
|
|
{
|
|
rndisInstance->runState = kUSB_HostCdcRndisRunGetEncapsulatedResponseDone;
|
|
if (rndisInstance->previousRunState == kUSB_HostCdcRndisRunWaitInitMsgDone)
|
|
{
|
|
rndisInstance->runState = kUSB_HostCdcRndisRunWaitMaxmumFrame;
|
|
|
|
}
|
|
else if (rndisInstance->previousRunState == kUSB_HostCdcRndisRunWaitMaxmumFrameDone)
|
|
{
|
|
rndisInstance->runState = kUSB_HostCdcRndisRunWaitGetMACAddress;
|
|
|
|
rndis_query_cmplt_struct_t * msg = (rndis_query_cmplt_struct_t *)data;
|
|
if(REMOTE_NDIS_QUERY_CMPLT == msg->messageType)
|
|
{
|
|
netif->mtu = USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(((uint8_t*)&msg->requestID + msg->informationBufferOffset));
|
|
}
|
|
else
|
|
{
|
|
/*set default value if device doesn't send query complete message*/
|
|
netif->mtu = 1500U;
|
|
}
|
|
}
|
|
else if (rndisInstance->previousRunState == kUSB_HostCdcRndisRunWaitGetMACAddressDone)
|
|
{
|
|
rndisInstance->runState = kUSB_HostCdcRndisRunWaitSetMsg;
|
|
rndis_query_cmplt_struct_t * msg = (rndis_query_cmplt_struct_t *)data;
|
|
|
|
netif->hwaddr_len = NETIF_MAX_HWADDR_LEN;
|
|
|
|
memcpy(netif->hwaddr,(((uint8_t*)&msg->requestID + msg->informationBufferOffset)), NETIF_MAX_HWADDR_LEN);
|
|
}
|
|
else if (rndisInstance->previousRunState == kUSB_HostCdcRndisRunWaitSetMsgDone)
|
|
{
|
|
rndisInstance->runState = kUSB_HostCdcRndisRunGetState;
|
|
}
|
|
rndisInstance->previousRunState = kUSB_HostCdcRndisRunIdle;
|
|
}
|
|
else
|
|
{
|
|
}
|
|
}
|
|
|
|
|
|
/*!
|
|
* @brief host rndis task function.
|
|
*
|
|
* This function implements the host cdc action, it is used to create task.
|
|
*
|
|
* @param param the host rndis instance pointer.
|
|
*/
|
|
void USB_HosCdcRndisTask(void *param)
|
|
{
|
|
|
|
usb_status_t status = kStatus_USB_Success;
|
|
usb_host_rndis_instance_struct_t *rndisInstance = (usb_host_rndis_instance_struct_t *)param;
|
|
uint32_t filtertype;
|
|
struct netif *netif ;
|
|
/* device state changes */
|
|
if (rndisInstance->deviceState != rndisInstance->previousState)
|
|
{
|
|
rndisInstance->previousState = rndisInstance->deviceState;
|
|
switch (rndisInstance->deviceState)
|
|
{
|
|
case kStatus_DEV_Idle:
|
|
break;
|
|
case kStatus_DEV_Attached:
|
|
rndisInstance->runState = kUSB_HostCdcRndisRunSetControlInterface;
|
|
status = USB_HostCdcInit(rndisInstance->deviceHandle, &rndisInstance->classHandle);
|
|
usb_echo("rndis device attached\r\n");
|
|
break;
|
|
case kStatus_DEV_Detached:
|
|
rndisInstance->deviceState = kStatus_DEV_Idle;
|
|
rndisInstance->runState = kUSB_HostCdcRndisRunIdle;
|
|
USB_HostCdcDeinit(rndisInstance->deviceHandle, rndisInstance->classHandle);
|
|
rndisInstance->dataInterfaceHandle = NULL;
|
|
rndisInstance->classHandle = NULL;
|
|
rndisInstance->controlInterfaceHandle = NULL;
|
|
rndisInstance->deviceHandle = NULL;
|
|
rndisInstance->interruptRunState = kUSB_HostCdcRndisRunIdle;
|
|
usb_echo("rndis device detached\r\n");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* run state */
|
|
switch (rndisInstance->runState)
|
|
{
|
|
case kUSB_HostCdcRndisRunIdle:
|
|
break;
|
|
case kUSB_HostCdcRndisRunSetControlInterface:
|
|
rndisInstance->runWaitState = kUSB_HostCdcRndisRunWaitSetControlInterface;
|
|
rndisInstance->runState = kUSB_HostCdcRndisRunIdle;
|
|
if (USB_HostCdcSetControlInterface(rndisInstance->classHandle, rndisInstance->controlInterfaceHandle, 0,
|
|
USB_HostCdcRndisControlCallback, rndisInstance) != kStatus_USB_Success)
|
|
{
|
|
usb_echo("set control interface error\r\n");
|
|
}
|
|
break;
|
|
case kUSB_HostCdcRndisRunSetControlInterfaceDone:
|
|
rndisInstance->runWaitState = kUSB_HostCdcRndisRunWaitSetDataInterface;
|
|
rndisInstance->runState = kUSB_HostCdcRndisRunIdle;
|
|
if (USB_HostCdcSetDataInterface(rndisInstance->classHandle, rndisInstance->dataInterfaceHandle, 0,
|
|
USB_HostCdcRndisControlCallback,rndisInstance) != kStatus_USB_Success)
|
|
{
|
|
usb_echo("set data interface error\r\n");
|
|
}
|
|
break;
|
|
case kUSB_HostCdcRndisRunSetDataInterfaceDone:
|
|
rndisInstance->runWaitState = kUSB_HostCdcRndisRunWaitInitMsg;
|
|
rndisInstance->runState = kUSB_HostCdcRndisRunIdle;
|
|
if(USB_HostRndisInitMsg(rndisInstance->classHandle,rndisInstance->sendMessage, RNDIS_CONTROL_MESSAGE,
|
|
USB_HostCdcRndisControlCallback, rndisInstance))
|
|
{
|
|
usb_echo("Error in Init message\r\n");
|
|
}
|
|
break;
|
|
case kUSB_HostCdcRndisRunWaitInitMsgDone:
|
|
|
|
if (rndisInstance->interruptRunState == kUSB_HostCdcRndisRunIdle)
|
|
{
|
|
rndisInstance->interruptRunState = kUSB_HostCdcRndisRunInterruptRecvPrime;
|
|
if (USB_HostCdcInterruptRecv(rndisInstance->classHandle, (uint8_t *)&rndisInstance->state,
|
|
RNDIS_RESPONSE_AVAILABLE, USB_HostCdcRndisInterruptCallback,
|
|
rndisInstance) != kStatus_USB_Success)
|
|
{
|
|
usb_echo("Error in USB_HostCdcInterruptRecv: %x\r\n", status);
|
|
}
|
|
}
|
|
else if (rndisInstance->interruptRunState == kUSB_HostCdcRndisRunInterruptRecvDone)
|
|
{
|
|
rndisInstance->interruptRunState = kUSB_HostCdcRndisRunIdle;
|
|
/*remember the previous set encapsulated command*/
|
|
rndisInstance->previousRunState = kUSB_HostCdcRndisRunWaitInitMsgDone;
|
|
rndisInstance->runWaitState = kUSB_HostCdcRndisRunWaitGetEncapsulatedCommand;
|
|
rndisInstance->runState = kUSB_HostCdcRndisRunIdle;
|
|
|
|
if(USB_HostCdcGetEncapsulatedResponse(rndisInstance->classHandle, rndisInstance->getMessage,
|
|
RNDIS_CONTROL_MESSAGE, USB_HostCdcRndisControlCallback, rndisInstance))
|
|
{
|
|
usb_echo("Error in Init message\r\n");
|
|
}
|
|
}
|
|
break;
|
|
case kUSB_HostCdcRndisRunWaitMaxmumFrame:
|
|
rndisInstance->previousRunState = kUSB_HostCdcRndisRunWaitMaxmumFrame;
|
|
rndisInstance->runWaitState = kUSB_HostCdcRndisRunWaitMaxmumFrame;
|
|
rndisInstance->runState = kUSB_HostCdcRndisRunIdle;
|
|
|
|
if(USB_HostRndisQueryMsg(rndisInstance->classHandle, OID_GEN_MAXIMUM_FRAME_SIZE, rndisInstance->sendMessage,
|
|
RNDIS_CONTROL_MESSAGE, 0, 0, NULL, USB_HostCdcRndisControlCallback, rndisInstance))
|
|
{
|
|
usb_echo("Error in Init message\r\n");
|
|
}
|
|
break;
|
|
|
|
case kUSB_HostCdcRndisRunWaitMaxmumFrameDone:
|
|
|
|
if (rndisInstance->interruptRunState == kUSB_HostCdcRndisRunIdle)
|
|
{
|
|
rndisInstance->interruptRunState = kUSB_HostCdcRndisRunInterruptRecvPrime;
|
|
if (USB_HostCdcInterruptRecv(rndisInstance->classHandle, (uint8_t *)&rndisInstance->state,
|
|
RNDIS_RESPONSE_AVAILABLE, USB_HostCdcRndisInterruptCallback,
|
|
rndisInstance) != kStatus_USB_Success)
|
|
{
|
|
usb_echo("Error in USB_HostCdcInterruptRecv: %x\r\n", status);
|
|
}
|
|
}
|
|
else if (rndisInstance->interruptRunState == kUSB_HostCdcRndisRunInterruptRecvDone)
|
|
{
|
|
rndisInstance->interruptRunState = kUSB_HostCdcRndisRunIdle;
|
|
rndisInstance->previousRunState = kUSB_HostCdcRndisRunWaitMaxmumFrameDone;
|
|
rndisInstance->runWaitState = kUSB_HostCdcRndisRunWaitGetEncapsulatedCommand;
|
|
rndisInstance->runState = kUSB_HostCdcRndisRunIdle;
|
|
|
|
if(USB_HostCdcGetEncapsulatedResponse(rndisInstance->classHandle, rndisInstance->getMessage,
|
|
RNDIS_CONTROL_MESSAGE, USB_HostCdcRndisControlCallback, rndisInstance))
|
|
{
|
|
usb_echo("Error in Init message\r\n");
|
|
}
|
|
}
|
|
break;
|
|
case kUSB_HostCdcRndisRunWaitGetMACAddress:
|
|
rndisInstance->previousRunState = kUSB_HostCdcRndisRunWaitGetMACAddress;
|
|
rndisInstance->runWaitState = kUSB_HostCdcRndisRunWaitGetMACAddress;
|
|
rndisInstance->runState = kUSB_HostCdcRndisRunIdle;
|
|
|
|
if(USB_HostRndisQueryMsg(rndisInstance->classHandle, OID_802_3_CURRENT_ADDRESS,rndisInstance->sendMessage,
|
|
RNDIS_CONTROL_MESSAGE, 0, 0, NULL, USB_HostCdcRndisControlCallback, rndisInstance))
|
|
{
|
|
usb_echo("Error in Init message\r\n");
|
|
}
|
|
break;
|
|
|
|
case kUSB_HostCdcRndisRunWaitGetMACAddressDone:
|
|
if (rndisInstance->interruptRunState == kUSB_HostCdcRndisRunIdle)
|
|
{
|
|
rndisInstance->interruptRunState = kUSB_HostCdcRndisRunInterruptRecvPrime;
|
|
rndisInstance->interruptRunState = kUSB_HostCdcRndisRunInterruptRecvPrime;
|
|
if (USB_HostCdcInterruptRecv(rndisInstance->classHandle, (uint8_t *)&rndisInstance->state,
|
|
RNDIS_RESPONSE_AVAILABLE, USB_HostCdcRndisInterruptCallback,
|
|
rndisInstance) != kStatus_USB_Success)
|
|
{
|
|
usb_echo("Error in USB_HostCdcInterruptRecv: %x\r\n", status);
|
|
}
|
|
|
|
}
|
|
else if (rndisInstance->interruptRunState == kUSB_HostCdcRndisRunInterruptRecvDone)
|
|
{
|
|
rndisInstance->interruptRunState = kUSB_HostCdcRndisRunIdle;
|
|
rndisInstance->responseAvailable = 0;
|
|
rndisInstance->previousRunState = kUSB_HostCdcRndisRunWaitGetMACAddressDone;
|
|
rndisInstance->runWaitState = kUSB_HostCdcRndisRunWaitGetEncapsulatedCommand;
|
|
rndisInstance->runState = kUSB_HostCdcRndisRunIdle;
|
|
|
|
if(USB_HostCdcGetEncapsulatedResponse(rndisInstance->classHandle, rndisInstance->getMessage,
|
|
RNDIS_CONTROL_MESSAGE, USB_HostCdcRndisControlCallback, rndisInstance))
|
|
{
|
|
usb_echo("Error in Init message\r\n");
|
|
}
|
|
}
|
|
break;
|
|
case kUSB_HostCdcRndisRunWaitSetMsg:
|
|
rndisInstance->previousRunState = kUSB_HostCdcRndisRunWaitSetMsg;
|
|
rndisInstance->runWaitState = kUSB_HostCdcRndisRunWaitSetMsg;
|
|
rndisInstance->runState = kUSB_HostCdcRndisRunIdle;
|
|
filtertype = NDIS_PACKET_TYPE_DIRECTED;
|
|
if(USB_HostRndisSetMsg(rndisInstance->classHandle, OID_GEN_CURRENT_PACKET_FILTER, rndisInstance->sendMessage, RNDIS_CONTROL_MESSAGE, 20U, (sizeof(filtertype)),&filtertype,
|
|
USB_HostCdcRndisControlCallback, rndisInstance))
|
|
{
|
|
usb_echo("Error in set message\r\n");
|
|
}
|
|
break;
|
|
case kUSB_HostCdcRndisRunWaitSetMsgDone:
|
|
if (rndisInstance->interruptRunState == kUSB_HostCdcRndisRunIdle)
|
|
{
|
|
rndisInstance->interruptRunState = kUSB_HostCdcRndisRunInterruptRecvPrime;
|
|
rndisInstance->interruptRunState = kUSB_HostCdcRndisRunInterruptRecvPrime;
|
|
if (USB_HostCdcInterruptRecv(rndisInstance->classHandle, (uint8_t *)&rndisInstance->state,
|
|
RNDIS_RESPONSE_AVAILABLE, USB_HostCdcRndisInterruptCallback,
|
|
rndisInstance) != kStatus_USB_Success)
|
|
{
|
|
usb_echo("Error in USB_HostCdcInterruptRecv: %x\r\n", status);
|
|
}
|
|
}
|
|
else if (rndisInstance->interruptRunState == kUSB_HostCdcRndisRunInterruptRecvDone)
|
|
{
|
|
rndisInstance->responseAvailable = 0;
|
|
rndisInstance->previousRunState = kUSB_HostCdcRndisRunWaitSetMsgDone;
|
|
rndisInstance->runWaitState = kUSB_HostCdcRndisRunWaitGetEncapsulatedCommand;
|
|
rndisInstance->runState = kUSB_HostCdcRndisRunIdle;
|
|
|
|
if(USB_HostCdcGetEncapsulatedResponse(rndisInstance->classHandle, rndisInstance->getMessage,
|
|
RNDIS_CONTROL_MESSAGE, USB_HostCdcRndisControlCallback, rndisInstance))
|
|
{
|
|
usb_echo("Error in Init message\r\n");
|
|
}
|
|
}
|
|
break;
|
|
case kUSB_HostCdcRndisRunGetState:
|
|
rndisInstance->attach = 1;
|
|
rndisInstance->dataSend = 0;
|
|
netif = (struct netif *)rndisInstance->netif;
|
|
netif_set_link_up(netif);
|
|
case kUSB_HostCdcRndisRunDataReceive:
|
|
rndisInstance->runState = kUSB_HostCdcRndisRunIdle;
|
|
USB_HostRndisRecvDataMsg(rndisInstance->classHandle, rndisInstance->inPutBuffer, RNDIS_DATA_MESSAGE,
|
|
USB_HostCdcRndisDataInCallback, rndisInstance);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
usb_status_t USB_HostCdcRndisEvent(usb_device_handle deviceHandle,
|
|
usb_host_configuration_handle configurationHandle,
|
|
uint32_t event_code)
|
|
{
|
|
usb_status_t status;
|
|
uint8_t id;
|
|
usb_host_configuration_t *configuration;
|
|
uint8_t interface_index;
|
|
usb_host_interface_t *hostInterface;
|
|
uint32_t info_value = 0U;
|
|
struct netif *netif;
|
|
status = kStatus_USB_Success;
|
|
|
|
switch (event_code)
|
|
{
|
|
case kUSB_HostEventAttach:
|
|
/* judge whether is configurationHandle supported */
|
|
configuration = (usb_host_configuration_t *)configurationHandle;
|
|
|
|
for (interface_index = 0; interface_index < configuration->interfaceCount; ++interface_index)
|
|
{
|
|
hostInterface = &configuration->interfaceList[interface_index];
|
|
id = hostInterface->interfaceDesc->bInterfaceClass;
|
|
if (id != USB_HOST_CDC_RNDIS_CLASS_CODE)
|
|
{
|
|
continue;
|
|
}
|
|
id = hostInterface->interfaceDesc->bInterfaceSubClass;
|
|
if (id != USB_HOST_CDC_RNDIS_SUBCLASS_CODE)
|
|
{
|
|
continue;
|
|
}
|
|
id = hostInterface->interfaceDesc->bInterfaceProtocol;
|
|
if (id != USB_HOST_CDC_RNDIS_PROTOCOL_CODE)
|
|
{
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
/* the interface is supported by the application */
|
|
g_RndisInstance.controlInterfaceHandle = hostInterface;
|
|
|
|
}
|
|
}
|
|
for (interface_index = 0; interface_index < configuration->interfaceCount; ++interface_index)
|
|
{
|
|
hostInterface = &configuration->interfaceList[interface_index];
|
|
id = hostInterface->interfaceDesc->bInterfaceClass;
|
|
|
|
if (id != USB_HOST_CDC_DATA_CLASS_CODE)
|
|
{
|
|
continue;
|
|
}
|
|
id = hostInterface->interfaceDesc->bInterfaceSubClass;
|
|
if (id != USB_HOST_CDC_DATA_SUBCLASS_CODE)
|
|
{
|
|
continue;
|
|
}
|
|
id = hostInterface->interfaceDesc->bInterfaceProtocol;
|
|
if (id != USB_HOST_CDC_DATA_PROTOCOL_CODE)
|
|
{
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
g_RndisInstance.dataInterfaceHandle = hostInterface;
|
|
|
|
}
|
|
}
|
|
g_RndisInstance.deviceHandle = deviceHandle;
|
|
if ((NULL != g_RndisInstance.dataInterfaceHandle) && (NULL != g_RndisInstance.controlInterfaceHandle))
|
|
{
|
|
status = kStatus_USB_Success;
|
|
}
|
|
else
|
|
{
|
|
status = kStatus_USB_NotSupported;
|
|
}
|
|
break;
|
|
|
|
case kUSB_HostEventNotSupported:
|
|
usb_echo(" the usb tethering featue is not enabled, please turn on usb tethering in mobile phone\r\n ");
|
|
break;
|
|
|
|
case kUSB_HostEventEnumerationDone:
|
|
if (g_RndisInstance.deviceState == kStatus_DEV_Idle)
|
|
{
|
|
if ((g_RndisInstance.deviceHandle != NULL) && (g_RndisInstance.dataInterfaceHandle != NULL) && (g_RndisInstance.controlInterfaceHandle != NULL))
|
|
{
|
|
g_RndisInstance.deviceState = kStatus_DEV_Attached;
|
|
|
|
USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDevicePID, &info_value);
|
|
usb_echo("device cdc attached:\r\npid=0x%x", info_value);
|
|
USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceVID, &info_value);
|
|
usb_echo("vid=0x%x ", info_value);
|
|
USB_HostHelperGetPeripheralInformation(deviceHandle, kUSB_HostGetDeviceAddress, &info_value);
|
|
usb_echo("address=%d\r\n", info_value);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
usb_echo("not idle rndis instance\r\n");
|
|
}
|
|
break;
|
|
|
|
case kUSB_HostEventDetach:
|
|
if (g_RndisInstance.deviceState != kStatus_DEV_Idle)
|
|
{
|
|
|
|
g_RndisInstance.attach = 0;
|
|
g_RndisInstance.dataSend = 0;
|
|
netif = (struct netif *)g_RndisInstance.netif;
|
|
netif_set_link_down(netif);
|
|
g_RndisInstance.deviceState = kStatus_DEV_Detached;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
void usb_ethernetif_input(struct netif *netif)
|
|
{
|
|
usb_host_rndis_instance_struct_t * rndisInstance = (usb_host_rndis_instance_struct_t *)netif->state;
|
|
USB_HostTaskFn(rndisInstance->hostHandle);
|
|
USB_HosCdcRndisTask(rndisInstance);
|
|
}
|