forked from stm/stm32-mw-usb-device
1705 lines
57 KiB
C
1705 lines
57 KiB
C
/**
|
|
******************************************************************************
|
|
* @file usbd_cdc_rndis.c
|
|
* @author MCD Application Team
|
|
* @brief This file provides the high layer firmware functions to manage the
|
|
* following functionalities of the USB CDC_RNDIS Class:
|
|
* - Initialization and Configuration of high and low layer
|
|
* - Enumeration as CDC_RNDIS Device (and enumeration for each implemented memory interface)
|
|
* - OUT/IN data transfer
|
|
* - Command IN transfer (class requests management)
|
|
* - Error management
|
|
*
|
|
******************************************************************************
|
|
* @attention
|
|
*
|
|
* Copyright (c) 2019 STMicroelectronics.
|
|
* All rights reserved.
|
|
*
|
|
* This software is licensed under terms that can be found in the LICENSE file
|
|
* in the root directory of this software component.
|
|
* If no LICENSE file comes with this software, it is provided AS-IS.
|
|
*
|
|
******************************************************************************
|
|
* @verbatim
|
|
*
|
|
* ===================================================================
|
|
* CDC_RNDIS Class Driver Description
|
|
* ===================================================================
|
|
* This driver manages the "Universal Serial Bus Class Definitions for Communications Devices
|
|
* Revision 1.2 November 16, 2007" and the sub-protocol specification of "Universal Serial Bus
|
|
* Communications Class Subclass Specification for PSTN Devices Revision 1.2 February 9, 2007"
|
|
* This driver implements the following aspects of the specification:
|
|
* - Device descriptor management
|
|
* - Configuration descriptor management
|
|
* - Enumeration as CDC device with 2 data endpoints (IN and OUT) and 1 command endpoint (IN)
|
|
* - Requests management (as described in section 6.2 in specification)
|
|
* - Abstract Control Model compliant
|
|
* - Union Functional collection (using 1 IN endpoint for control)
|
|
* - Data interface class
|
|
*
|
|
* These aspects may be enriched or modified for a specific user application.
|
|
*
|
|
* This driver doesn't implement the following aspects of the specification
|
|
* (but it is possible to manage these features with some modifications on this driver):
|
|
* - Any class-specific aspect relative to communication classes should be managed by user application.
|
|
* - All communication classes other than PSTN are not managed
|
|
*
|
|
* @endverbatim
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
|
|
/* Includes ------------------------------------------------------------------*/
|
|
#include "usbd_cdc_rndis.h"
|
|
#include "usbd_ctlreq.h"
|
|
|
|
#ifndef __USBD_CDC_RNDIS_IF_H
|
|
#include "usbd_cdc_rndis_if_template.h"
|
|
#endif /* __USBD_CDC_RNDIS_IF_H */
|
|
/** @addtogroup STM32_USB_DEVICE_LIBRARY
|
|
* @{
|
|
*/
|
|
|
|
|
|
/** @defgroup USBD_CDC_RNDIS
|
|
* @brief usbd core module
|
|
* @{
|
|
*/
|
|
|
|
/** @defgroup USBD_CDC_RNDIS_Private_TypesDefinitions
|
|
* @{
|
|
*/
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
|
|
/** @defgroup USBD_CDC_RNDIS_Private_Defines
|
|
* @{
|
|
*/
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
|
|
/** @defgroup USBD_CDC_RNDIS_Private_Macros
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
|
|
/** @defgroup USBD_CDC_RNDIS_Private_FunctionPrototypes
|
|
* @{
|
|
*/
|
|
|
|
static uint8_t USBD_CDC_RNDIS_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
|
|
static uint8_t USBD_CDC_RNDIS_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx);
|
|
|
|
static uint8_t USBD_CDC_RNDIS_Setup(USBD_HandleTypeDef *pdev,
|
|
USBD_SetupReqTypedef *req);
|
|
|
|
static uint8_t USBD_CDC_RNDIS_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum);
|
|
static uint8_t USBD_CDC_RNDIS_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum);
|
|
static uint8_t USBD_CDC_RNDIS_EP0_RxReady(USBD_HandleTypeDef *pdev);
|
|
#ifndef USE_USBD_COMPOSITE
|
|
static uint8_t *USBD_CDC_RNDIS_GetFSCfgDesc(uint16_t *length);
|
|
static uint8_t *USBD_CDC_RNDIS_GetHSCfgDesc(uint16_t *length);
|
|
static uint8_t *USBD_CDC_RNDIS_GetOtherSpeedCfgDesc(uint16_t *length);
|
|
static uint8_t *USBD_CDC_RNDIS_GetOtherSpeedCfgDesc(uint16_t *length);
|
|
#endif /* USE_USBD_COMPOSITE */
|
|
#if (USBD_SUPPORT_USER_STRING_DESC == 1U)
|
|
static uint8_t *USBD_CDC_RNDIS_USRStringDescriptor(USBD_HandleTypeDef *pdev, uint8_t index, uint16_t *length);
|
|
#endif /* USBD_SUPPORT_USER_STRING_DESC */
|
|
#ifndef USE_USBD_COMPOSITE
|
|
uint8_t *USBD_CDC_RNDIS_GetDeviceQualifierDescriptor(uint16_t *length);
|
|
#endif /* USE_USBD_COMPOSITE */
|
|
|
|
/* CDC_RNDIS Internal messages parsing and construction functions */
|
|
static uint8_t USBD_CDC_RNDIS_MsgParsing(USBD_HandleTypeDef *pdev, uint8_t *RxBuff);
|
|
static uint8_t USBD_CDC_RNDIS_ProcessInitMsg(USBD_HandleTypeDef *pdev, USBD_CDC_RNDIS_InitMsgTypeDef *Msg);
|
|
static uint8_t USBD_CDC_RNDIS_ProcessHaltMsg(USBD_HandleTypeDef *pdev, USBD_CDC_RNDIS_HaltMsgTypeDef *Msg);
|
|
static uint8_t USBD_CDC_RNDIS_ProcessKeepAliveMsg(USBD_HandleTypeDef *pdev, USBD_CDC_RNDIS_KpAliveMsgTypeDef *Msg);
|
|
static uint8_t USBD_CDC_RNDIS_ProcessQueryMsg(USBD_HandleTypeDef *pdev, USBD_CDC_RNDIS_QueryMsgTypeDef *Msg);
|
|
static uint8_t USBD_CDC_RNDIS_ProcessSetMsg(USBD_HandleTypeDef *pdev, USBD_CDC_RNDIS_SetMsgTypeDef *Msg);
|
|
static uint8_t USBD_CDC_RNDIS_ProcessResetMsg(USBD_HandleTypeDef *pdev, USBD_CDC_RNDIS_ResetMsgTypeDef *Msg);
|
|
static uint8_t USBD_CDC_RNDIS_ProcessPacketMsg(USBD_HandleTypeDef *pdev, USBD_CDC_RNDIS_PacketMsgTypeDef *Msg);
|
|
static uint8_t USBD_CDC_RNDIS_ProcessUnsupportedMsg(USBD_HandleTypeDef *pdev, USBD_CDC_RNDIS_CtrlMsgTypeDef *Msg);
|
|
|
|
/* USB Standard Device Descriptor */
|
|
#ifndef USE_USBD_COMPOSITE
|
|
__ALIGN_BEGIN static uint8_t USBD_CDC_RNDIS_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] __ALIGN_END =
|
|
{
|
|
USB_LEN_DEV_QUALIFIER_DESC,
|
|
USB_DESC_TYPE_DEVICE_QUALIFIER,
|
|
0x00,
|
|
0x02,
|
|
0x00,
|
|
0x00,
|
|
0x00,
|
|
0x40,
|
|
0x01,
|
|
0x00,
|
|
};
|
|
#endif /* USE_USBD_COMPOSITE */
|
|
static uint8_t MAC_StrDesc[6] = {CDC_RNDIS_MAC_ADDR0, CDC_RNDIS_MAC_ADDR1, CDC_RNDIS_MAC_ADDR2,
|
|
CDC_RNDIS_MAC_ADDR3, CDC_RNDIS_MAC_ADDR4, CDC_RNDIS_MAC_ADDR5
|
|
};
|
|
|
|
static uint32_t ConnSpeedTab[2] = {CDC_RNDIS_CONNECT_SPEED_UPSTREAM,
|
|
CDC_RNDIS_CONNECT_SPEED_DOWNSTREAM
|
|
};
|
|
|
|
static uint8_t EmptyResponse = 0x00U;
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/** @defgroup USBD_CDC_RNDIS_Private_Variables
|
|
* @{
|
|
*/
|
|
|
|
|
|
/* CDC_RNDIS interface class callbacks structure */
|
|
USBD_ClassTypeDef USBD_CDC_RNDIS =
|
|
{
|
|
USBD_CDC_RNDIS_Init,
|
|
USBD_CDC_RNDIS_DeInit,
|
|
USBD_CDC_RNDIS_Setup,
|
|
NULL, /* EP0_TxSent, */
|
|
USBD_CDC_RNDIS_EP0_RxReady,
|
|
USBD_CDC_RNDIS_DataIn,
|
|
USBD_CDC_RNDIS_DataOut,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
#ifdef USE_USBD_COMPOSITE
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
#else
|
|
USBD_CDC_RNDIS_GetHSCfgDesc,
|
|
USBD_CDC_RNDIS_GetFSCfgDesc,
|
|
USBD_CDC_RNDIS_GetOtherSpeedCfgDesc,
|
|
USBD_CDC_RNDIS_GetDeviceQualifierDescriptor,
|
|
#endif /* USE_USBD_COMPOSITE */
|
|
#if (USBD_SUPPORT_USER_STRING_DESC == 1U)
|
|
USBD_CDC_RNDIS_USRStringDescriptor,
|
|
#endif /* USBD_SUPPORT_USER_STRING_DESC */
|
|
};
|
|
#ifndef USE_USBD_COMPOSITE
|
|
|
|
/* USB CDC device Configuration Descriptor */
|
|
__ALIGN_BEGIN static uint8_t USBD_CDC_RNDIS_CfgDesc[] __ALIGN_END =
|
|
{
|
|
/* Configuration Descriptor */
|
|
0x09, /* bLength: Configuration Descriptor size */
|
|
USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
|
|
LOBYTE(CDC_RNDIS_CONFIG_DESC_SIZ), /* wTotalLength: Total size of the Config descriptor */
|
|
HIBYTE(CDC_RNDIS_CONFIG_DESC_SIZ),
|
|
0x02, /* bNumInterfaces: 2 interfaces */
|
|
0x01, /* bConfigurationValue: Configuration value */
|
|
0x00, /* iConfiguration: Index of string descriptor
|
|
describing the configuration */
|
|
#if (USBD_SELF_POWERED == 1U)
|
|
0xC0, /* bmAttributes: Bus Powered according to user configuration */
|
|
#else
|
|
0x80, /* bmAttributes: Bus Powered according to user configuration */
|
|
#endif /* USBD_SELF_POWERED */
|
|
USBD_MAX_POWER, /* MaxPower (mA) */
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* IAD descriptor */
|
|
0x08, /* bLength */
|
|
0x0B, /* bDescriptorType */
|
|
0x00, /* bFirstInterface */
|
|
0x02, /* bInterfaceCount */
|
|
0xE0, /* bFunctionClass (Wireless Controller) */
|
|
0x01, /* bFunctionSubClass */
|
|
0x03, /* bFunctionProtocol */
|
|
0x00, /* iFunction */
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Interface Descriptor */
|
|
0x09, /* bLength: Interface Descriptor size */
|
|
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: Interface descriptor type */
|
|
CDC_RNDIS_CMD_ITF_NBR, /* bInterfaceNumber: Number of Interface */
|
|
0x00, /* bAlternateSetting: Alternate setting */
|
|
0x01, /* bNumEndpoints: One endpoint used */
|
|
0x02, /* bInterfaceClass: Communication Interface Class */
|
|
0x02, /* bInterfaceSubClass:Abstract Control Model */
|
|
0xFF, /* bInterfaceProtocol: Common AT commands */
|
|
0x00, /* iInterface */
|
|
|
|
/* Header Functional Descriptor */
|
|
0x05, /* bLength: Endpoint Descriptor size */
|
|
0x24, /* bDescriptorType: CS_INTERFACE */
|
|
0x00, /* bDescriptorSubtype: Header functional descriptor */
|
|
0x10, /* bcdCDC: spec release number: 1.20 */
|
|
0x01,
|
|
|
|
/* Call Management Functional Descriptor */
|
|
0x05, /* bFunctionLength */
|
|
0x24, /* bDescriptorType: CS_INTERFACE */
|
|
0x01, /* bDescriptorSubtype: Call Management Func Desc */
|
|
0x00, /* bmCapabilities: D0+D1 */
|
|
CDC_RNDIS_COM_ITF_NBR, /* bDataInterface: 1 */
|
|
|
|
/* ACM Functional Descriptor */
|
|
0x04, /* bFunctionLength */
|
|
0x24, /* bDescriptorType: CS_INTERFACE */
|
|
0x02, /* bDescriptorSubtype: Abstract Control Management desc */
|
|
0x00, /* bmCapabilities */
|
|
|
|
/* Union Functional Descriptor */
|
|
0x05, /* bFunctionLength */
|
|
0x24, /* bDescriptorType: CS_INTERFACE */
|
|
0x06, /* bDescriptorSubtype: Union functional descriptor */
|
|
CDC_RNDIS_CMD_ITF_NBR, /* bMasterInterface: Communication class interface */
|
|
CDC_RNDIS_COM_ITF_NBR, /* bSlaveInterface0: Data Class Interface */
|
|
|
|
/* Notification Endpoint Descriptor */
|
|
0x07, /* bLength: Endpoint Descriptor size */
|
|
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
|
|
CDC_RNDIS_CMD_EP, /* bEndpointAddress */
|
|
0x03, /* bmAttributes: Interrupt */
|
|
LOBYTE(CDC_RNDIS_CMD_PACKET_SIZE), /* wMaxPacketSize */
|
|
HIBYTE(CDC_RNDIS_CMD_PACKET_SIZE),
|
|
CDC_RNDIS_FS_BINTERVAL, /* bInterval */
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
/* Data class interface descriptor */
|
|
0x09, /* bLength: Endpoint Descriptor size */
|
|
USB_DESC_TYPE_INTERFACE, /* bDescriptorType: */
|
|
CDC_RNDIS_COM_ITF_NBR, /* bInterfaceNumber: Number of Interface */
|
|
0x00, /* bAlternateSetting: Alternate setting */
|
|
0x02, /* bNumEndpoints: Two endpoints used */
|
|
0x0A, /* bInterfaceClass: CDC */
|
|
0x00, /* bInterfaceSubClass */
|
|
0x00, /* bInterfaceProtocol */
|
|
0x00, /* iInterface */
|
|
|
|
/* Endpoint OUT Descriptor */
|
|
0x07, /* bLength: Endpoint Descriptor size */
|
|
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
|
|
CDC_RNDIS_OUT_EP, /* bEndpointAddress */
|
|
0x02, /* bmAttributes: Bulk */
|
|
LOBYTE(CDC_RNDIS_DATA_FS_MAX_PACKET_SIZE), /* wMaxPacketSize: */
|
|
HIBYTE(CDC_RNDIS_DATA_FS_MAX_PACKET_SIZE),
|
|
0x00, /* bInterval */
|
|
|
|
/* Endpoint IN Descriptor */
|
|
0x07, /* bLength: Endpoint Descriptor size */
|
|
USB_DESC_TYPE_ENDPOINT, /* bDescriptorType: Endpoint */
|
|
CDC_RNDIS_IN_EP, /* bEndpointAddress */
|
|
0x02, /* bmAttributes: Bulk */
|
|
LOBYTE(CDC_RNDIS_DATA_FS_MAX_PACKET_SIZE), /* wMaxPacketSize */
|
|
HIBYTE(CDC_RNDIS_DATA_FS_MAX_PACKET_SIZE),
|
|
0x00 /* bInterval */
|
|
} ;
|
|
#endif /* USE_USBD_COMPOSITE */
|
|
|
|
static uint8_t RNDISInEpAdd = CDC_RNDIS_IN_EP;
|
|
static uint8_t RNDISOutEpAdd = CDC_RNDIS_OUT_EP;
|
|
static uint8_t RNDISCmdEpAdd = CDC_RNDIS_CMD_EP;
|
|
|
|
static const uint32_t CDC_RNDIS_SupportedOIDs[] =
|
|
{
|
|
OID_GEN_SUPPORTED_LIST,
|
|
OID_GEN_HARDWARE_STATUS,
|
|
OID_GEN_MEDIA_SUPPORTED,
|
|
OID_GEN_MEDIA_IN_USE,
|
|
OID_GEN_MAXIMUM_FRAME_SIZE,
|
|
OID_GEN_LINK_SPEED,
|
|
OID_GEN_TRANSMIT_BLOCK_SIZE,
|
|
OID_GEN_RECEIVE_BLOCK_SIZE,
|
|
OID_GEN_VENDOR_ID,
|
|
OID_GEN_VENDOR_DESCRIPTION,
|
|
OID_GEN_CURRENT_PACKET_FILTER,
|
|
OID_GEN_MAXIMUM_TOTAL_SIZE,
|
|
OID_GEN_MEDIA_CONNECT_STATUS,
|
|
OID_GEN_MAXIMUM_SEND_PACKETS,
|
|
OID_802_3_PERMANENT_ADDRESS,
|
|
OID_802_3_CURRENT_ADDRESS,
|
|
OID_802_3_MULTICAST_LIST,
|
|
OID_802_3_MAXIMUM_LIST_SIZE,
|
|
OID_802_3_RCV_ERROR_ALIGNMENT,
|
|
OID_802_3_XMIT_ONE_COLLISION,
|
|
OID_802_3_XMIT_MORE_COLLISIONS,
|
|
};
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/** @defgroup USBD_CDC_RNDIS_Private_Functions
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* @brief USBD_CDC_RNDIS_Init
|
|
* Initialize the CDC CDC_RNDIS interface
|
|
* @param pdev: device instance
|
|
* @param cfgidx: Configuration index
|
|
* @retval status
|
|
*/
|
|
static uint8_t USBD_CDC_RNDIS_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
|
|
{
|
|
UNUSED(cfgidx);
|
|
USBD_CDC_RNDIS_HandleTypeDef *hcdc;
|
|
|
|
hcdc = (USBD_CDC_RNDIS_HandleTypeDef *)USBD_malloc(sizeof(USBD_CDC_RNDIS_HandleTypeDef));
|
|
|
|
#ifdef USE_USBD_COMPOSITE
|
|
/* Get the Endpoints addresses allocated for this class instance */
|
|
RNDISInEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_IN, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId);
|
|
RNDISOutEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_OUT, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId);
|
|
RNDISCmdEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_IN, USBD_EP_TYPE_INTR, (uint8_t)pdev->classId);
|
|
#endif /* USE_USBD_COMPOSITE */
|
|
|
|
if (hcdc == NULL)
|
|
{
|
|
pdev->pClassDataCmsit[pdev->classId] = NULL;
|
|
return (uint8_t)USBD_EMEM;
|
|
}
|
|
|
|
(void)USBD_memset(hcdc, 0, sizeof(USBD_CDC_RNDIS_HandleTypeDef));
|
|
|
|
pdev->pClassDataCmsit[pdev->classId] = (void *)hcdc;
|
|
pdev->pClassData = pdev->pClassDataCmsit[pdev->classId];
|
|
|
|
if (pdev->dev_speed == USBD_SPEED_HIGH)
|
|
{
|
|
/* Open EP IN */
|
|
(void)USBD_LL_OpenEP(pdev, RNDISInEpAdd, USBD_EP_TYPE_BULK,
|
|
CDC_RNDIS_DATA_HS_IN_PACKET_SIZE);
|
|
|
|
pdev->ep_in[RNDISInEpAdd & 0xFU].is_used = 1U;
|
|
|
|
/* Open EP OUT */
|
|
(void)USBD_LL_OpenEP(pdev, RNDISOutEpAdd, USBD_EP_TYPE_BULK,
|
|
CDC_RNDIS_DATA_HS_OUT_PACKET_SIZE);
|
|
|
|
pdev->ep_out[RNDISOutEpAdd & 0xFU].is_used = 1U;
|
|
|
|
/* Set bInterval for CDC RNDIS CMD Endpoint */
|
|
pdev->ep_in[RNDISCmdEpAdd & 0xFU].bInterval = CDC_RNDIS_HS_BINTERVAL;
|
|
}
|
|
else
|
|
{
|
|
/* Open EP IN */
|
|
(void)USBD_LL_OpenEP(pdev, RNDISInEpAdd, USBD_EP_TYPE_BULK,
|
|
CDC_RNDIS_DATA_FS_IN_PACKET_SIZE);
|
|
|
|
pdev->ep_in[RNDISInEpAdd & 0xFU].is_used = 1U;
|
|
|
|
/* Open EP OUT */
|
|
(void)USBD_LL_OpenEP(pdev, RNDISOutEpAdd, USBD_EP_TYPE_BULK,
|
|
CDC_RNDIS_DATA_FS_OUT_PACKET_SIZE);
|
|
|
|
pdev->ep_out[RNDISOutEpAdd & 0xFU].is_used = 1U;
|
|
|
|
/* Set bInterval for CDC RNDIS CMD Endpoint */
|
|
pdev->ep_in[RNDISCmdEpAdd & 0xFU].bInterval = CDC_RNDIS_FS_BINTERVAL;
|
|
}
|
|
|
|
/* Open Command IN EP */
|
|
(void)USBD_LL_OpenEP(pdev, RNDISCmdEpAdd, USBD_EP_TYPE_INTR, CDC_RNDIS_CMD_PACKET_SIZE);
|
|
pdev->ep_in[RNDISCmdEpAdd & 0xFU].is_used = 1U;
|
|
|
|
hcdc->RxBuffer = NULL;
|
|
|
|
/* Init physical Interface components */
|
|
((USBD_CDC_RNDIS_ItfTypeDef *)pdev->pUserData[pdev->classId])->Init();
|
|
|
|
/* Init the CDC_RNDIS state */
|
|
hcdc->State = CDC_RNDIS_STATE_BUS_INITIALIZED;
|
|
|
|
/* Init Xfer states */
|
|
hcdc->TxState = 0U;
|
|
hcdc->RxState = 0U;
|
|
hcdc->RxLength = 0U;
|
|
hcdc->TxLength = 0U;
|
|
hcdc->LinkStatus = 0U;
|
|
hcdc->NotificationStatus = 0U;
|
|
hcdc->MaxPcktLen = (pdev->dev_speed == USBD_SPEED_HIGH) ? CDC_RNDIS_DATA_HS_MAX_PACKET_SIZE : \
|
|
CDC_RNDIS_DATA_FS_MAX_PACKET_SIZE;
|
|
|
|
if (hcdc->RxBuffer == NULL)
|
|
{
|
|
return (uint8_t)USBD_EMEM;
|
|
}
|
|
|
|
/* Prepare Out endpoint to receive next packet */
|
|
(void)USBD_LL_PrepareReceive(pdev, RNDISOutEpAdd,
|
|
hcdc->RxBuffer, hcdc->MaxPcktLen);
|
|
|
|
return (uint8_t)USBD_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief USBD_CDC_RNDIS_DeInit
|
|
* DeInitialize the CDC layer
|
|
* @param pdev: device instance
|
|
* @param cfgidx: Configuration index
|
|
* @retval status
|
|
*/
|
|
static uint8_t USBD_CDC_RNDIS_DeInit(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
|
|
{
|
|
UNUSED(cfgidx);
|
|
|
|
#ifdef USE_USBD_COMPOSITE
|
|
/* Get the Endpoints addresses allocated for this class instance */
|
|
RNDISInEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_IN, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId);
|
|
RNDISOutEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_OUT, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId);
|
|
RNDISCmdEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_IN, USBD_EP_TYPE_INTR, (uint8_t)pdev->classId);
|
|
#endif /* USE_USBD_COMPOSITE */
|
|
|
|
/* Close EP IN */
|
|
(void)USBD_LL_CloseEP(pdev, RNDISInEpAdd);
|
|
pdev->ep_in[RNDISInEpAdd & 0xFU].is_used = 0U;
|
|
|
|
/* Close EP OUT */
|
|
(void)USBD_LL_CloseEP(pdev, RNDISOutEpAdd);
|
|
pdev->ep_out[RNDISOutEpAdd & 0xFU].is_used = 0U;
|
|
|
|
/* Close Command IN EP */
|
|
(void)USBD_LL_CloseEP(pdev, RNDISCmdEpAdd);
|
|
pdev->ep_in[RNDISCmdEpAdd & 0xFU].is_used = 0U;
|
|
pdev->ep_in[RNDISCmdEpAdd & 0xFU].bInterval = 0U;
|
|
|
|
/* DeInit physical Interface components */
|
|
if (pdev->pClassDataCmsit[pdev->classId] != NULL)
|
|
{
|
|
((USBD_CDC_RNDIS_ItfTypeDef *)pdev->pUserData[pdev->classId])->DeInit();
|
|
USBD_free(pdev->pClassDataCmsit[pdev->classId]);
|
|
pdev->pClassDataCmsit[pdev->classId] = NULL;
|
|
pdev->pClassData = NULL;
|
|
}
|
|
|
|
return (uint8_t)USBD_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief USBD_CDC_RNDIS_Setup
|
|
* Handle the CDC specific requests
|
|
* @param pdev: instance
|
|
* @param req: usb requests
|
|
* @retval status
|
|
*/
|
|
static uint8_t USBD_CDC_RNDIS_Setup(USBD_HandleTypeDef *pdev,
|
|
USBD_SetupReqTypedef *req)
|
|
{
|
|
USBD_CDC_RNDIS_HandleTypeDef *hcdc = (USBD_CDC_RNDIS_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId];
|
|
USBD_CDC_RNDIS_CtrlMsgTypeDef *Msg;
|
|
uint8_t ifalt = 0U;
|
|
uint16_t status_info = 0U;
|
|
USBD_StatusTypeDef ret = USBD_OK;
|
|
|
|
if (hcdc == NULL)
|
|
{
|
|
return (uint8_t)USBD_FAIL;
|
|
}
|
|
|
|
Msg = (USBD_CDC_RNDIS_CtrlMsgTypeDef *)(void *)hcdc->data;
|
|
|
|
switch (req->bmRequest & USB_REQ_TYPE_MASK)
|
|
{
|
|
case USB_REQ_TYPE_CLASS :
|
|
if (req->wLength != 0U)
|
|
{
|
|
/* Control Request Data from Device to Host, send data prepared by device */
|
|
if ((req->bmRequest & 0x80U) != 0U)
|
|
{
|
|
/* Update opcode and length */
|
|
hcdc->CmdOpCode = req->bRequest;
|
|
hcdc->CmdLength = (uint8_t)req->wLength;
|
|
|
|
if (hcdc->CmdOpCode == CDC_RNDIS_GET_ENCAPSULATED_RESPONSE)
|
|
{
|
|
/* Data of Response Message has already been prepared by USBD_CDC_RNDIS_MsgParsing.
|
|
Just check that length is corresponding to right expected value */
|
|
if (req->wLength != Msg->MsgLength)
|
|
{
|
|
}
|
|
}
|
|
|
|
/* Allow application layer to pre-process data or add own processing before sending response */
|
|
((USBD_CDC_RNDIS_ItfTypeDef *)pdev->pUserData[pdev->classId])->Control(req->bRequest,
|
|
(uint8_t *)hcdc->data,
|
|
req->wLength);
|
|
/* Check if Response is ready */
|
|
if (hcdc->ResponseRdy != 0U)
|
|
{
|
|
/* Clear Response Ready flag */
|
|
hcdc->ResponseRdy = 0U;
|
|
|
|
/* Send data on control endpoint */
|
|
(void)USBD_CtlSendData(pdev, (uint8_t *)hcdc->data,
|
|
MIN(CDC_RNDIS_MAX_DATA_SZE, Msg->MsgLength));
|
|
}
|
|
else
|
|
{
|
|
/* CDC_RNDIS Specification says: If for some reason the device receives a GET ENCAPSULATED RESPONSE
|
|
and is unable to respond with a valid data on the Control endpoint,
|
|
then it should return a one-byte packet set to 0x00, rather than
|
|
stalling the Control endpoint */
|
|
(void)USBD_CtlSendData(pdev, &EmptyResponse, 1U);
|
|
}
|
|
}
|
|
/* Control Request Data from Host to Device: Prepare reception of control data stage */
|
|
else
|
|
{
|
|
hcdc->CmdOpCode = req->bRequest;
|
|
hcdc->CmdLength = (uint8_t)MIN(CDC_RNDIS_MAX_INFO_BUFF_SZ, req->wLength);
|
|
|
|
(void)USBD_CtlPrepareRx(pdev, (uint8_t *)hcdc->data, hcdc->CmdLength);
|
|
}
|
|
}
|
|
/* No Data control request: there is no such request for CDC_RNDIS protocol,
|
|
so let application layer manage this case */
|
|
else
|
|
{
|
|
((USBD_CDC_RNDIS_ItfTypeDef *)pdev->pUserData[pdev->classId])->Control(req->bRequest,
|
|
(uint8_t *)req, 0U);
|
|
}
|
|
break;
|
|
|
|
case USB_REQ_TYPE_STANDARD:
|
|
switch (req->bRequest)
|
|
{
|
|
case USB_REQ_GET_STATUS:
|
|
if (pdev->dev_state == USBD_STATE_CONFIGURED)
|
|
{
|
|
(void)USBD_CtlSendData(pdev, (uint8_t *)&status_info, 2U);
|
|
}
|
|
else
|
|
{
|
|
USBD_CtlError(pdev, req);
|
|
ret = USBD_FAIL;
|
|
}
|
|
break;
|
|
|
|
case USB_REQ_GET_INTERFACE:
|
|
if (pdev->dev_state == USBD_STATE_CONFIGURED)
|
|
{
|
|
(void)USBD_CtlSendData(pdev, &ifalt, 1U);
|
|
}
|
|
else
|
|
{
|
|
USBD_CtlError(pdev, req);
|
|
ret = USBD_FAIL;
|
|
}
|
|
break;
|
|
|
|
case USB_REQ_SET_INTERFACE:
|
|
if (pdev->dev_state != USBD_STATE_CONFIGURED)
|
|
{
|
|
USBD_CtlError(pdev, req);
|
|
ret = USBD_FAIL;
|
|
}
|
|
break;
|
|
|
|
case USB_REQ_CLEAR_FEATURE:
|
|
break;
|
|
|
|
default:
|
|
USBD_CtlError(pdev, req);
|
|
ret = USBD_FAIL;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
USBD_CtlError(pdev, req);
|
|
ret = USBD_FAIL;
|
|
break;
|
|
}
|
|
|
|
return (uint8_t)ret;
|
|
}
|
|
|
|
/**
|
|
* @brief USBD_CDC_RNDIS_DataIn
|
|
* Data sent on non-control IN endpoint
|
|
* @param pdev: device instance
|
|
* @param epnum: endpoint number
|
|
* @retval status
|
|
*/
|
|
static uint8_t USBD_CDC_RNDIS_DataIn(USBD_HandleTypeDef *pdev, uint8_t epnum)
|
|
{
|
|
USBD_CDC_RNDIS_HandleTypeDef *hcdc;
|
|
PCD_HandleTypeDef *hpcd = (PCD_HandleTypeDef *)pdev->pData;
|
|
|
|
#ifdef USE_USBD_COMPOSITE
|
|
/* Get the Endpoints addresses allocated for this class instance */
|
|
RNDISInEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_IN, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId);
|
|
#endif /* USE_USBD_COMPOSITE */
|
|
|
|
if (pdev->pClassDataCmsit[pdev->classId] == NULL)
|
|
{
|
|
return (uint8_t)USBD_FAIL;
|
|
}
|
|
|
|
hcdc = (USBD_CDC_RNDIS_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId];
|
|
|
|
if (epnum == (RNDISInEpAdd & 0x7FU))
|
|
{
|
|
if ((pdev->ep_in[epnum & 0xFU].total_length > 0U) &&
|
|
((pdev->ep_in[epnum & 0xFU].total_length % hpcd->IN_ep[epnum & 0xFU].maxpacket) == 0U))
|
|
{
|
|
/* Update the packet total length */
|
|
pdev->ep_in[epnum & 0xFU].total_length = 0U;
|
|
|
|
/* Send ZLP */
|
|
(void)USBD_LL_Transmit(pdev, epnum, NULL, 0U);
|
|
}
|
|
else
|
|
{
|
|
hcdc->TxState = 0U;
|
|
|
|
if (((USBD_CDC_RNDIS_ItfTypeDef *)pdev->pUserData[pdev->classId])->TransmitCplt != NULL)
|
|
{
|
|
((USBD_CDC_RNDIS_ItfTypeDef *)pdev->pUserData[pdev->classId])->TransmitCplt(hcdc->TxBuffer, \
|
|
&hcdc->TxLength, epnum);
|
|
}
|
|
}
|
|
}
|
|
else if (epnum == (RNDISCmdEpAdd & 0x7FU))
|
|
{
|
|
if (hcdc->NotificationStatus != 0U)
|
|
{
|
|
(void)USBD_CDC_RNDIS_SendNotification(pdev, CONNECTION_SPEED_CHANGE,
|
|
0U, (uint8_t *)ConnSpeedTab);
|
|
|
|
hcdc->NotificationStatus = 0U;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return (uint8_t)USBD_FAIL;
|
|
}
|
|
|
|
return (uint8_t)USBD_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief USBD_CDC_RNDIS_DataOut
|
|
* Data received on non-control Out endpoint
|
|
* @param pdev: device instance
|
|
* @param epnum: endpoint number
|
|
* @retval status
|
|
*/
|
|
static uint8_t USBD_CDC_RNDIS_DataOut(USBD_HandleTypeDef *pdev, uint8_t epnum)
|
|
{
|
|
USBD_CDC_RNDIS_HandleTypeDef *hcdc;
|
|
uint32_t CurrPcktLen;
|
|
|
|
#ifdef USE_USBD_COMPOSITE /* Get the Endpoints addresses allocated for this class instance */
|
|
RNDISOutEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_OUT, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId);
|
|
#endif /* USE_USBD_COMPOSITE */
|
|
|
|
if (pdev->pClassDataCmsit[pdev->classId] == NULL)
|
|
{
|
|
return (uint8_t)USBD_FAIL;
|
|
}
|
|
|
|
hcdc = (USBD_CDC_RNDIS_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId];
|
|
|
|
if (epnum == RNDISOutEpAdd)
|
|
{
|
|
/* Get the received data length */
|
|
CurrPcktLen = USBD_LL_GetRxDataSize(pdev, epnum);
|
|
|
|
/* Increment the frame length */
|
|
hcdc->RxLength += CurrPcktLen;
|
|
|
|
/* If the buffer size is less than max packet size: it is the last packet in current frame */
|
|
if ((CurrPcktLen < hcdc->MaxPcktLen) ||
|
|
(hcdc->RxLength >= (CDC_RNDIS_ETH_MAX_SEGSZE + sizeof(USBD_CDC_RNDIS_PacketMsgTypeDef))))
|
|
{
|
|
/* USB data will be immediately processed, this allow next USB traffic being
|
|
NAKed till the end of the application Xfer */
|
|
|
|
/* Call data packet message parsing and processing function */
|
|
(void)USBD_CDC_RNDIS_ProcessPacketMsg(pdev, (USBD_CDC_RNDIS_PacketMsgTypeDef *)(void *)hcdc->RxBuffer);
|
|
}
|
|
else
|
|
{
|
|
/* Prepare Out endpoint to receive next packet in current/new frame */
|
|
(void)USBD_LL_PrepareReceive(pdev, RNDISOutEpAdd,
|
|
(uint8_t *)(hcdc->RxBuffer + hcdc->RxLength),
|
|
hcdc->MaxPcktLen);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return (uint8_t)USBD_FAIL;
|
|
}
|
|
|
|
return (uint8_t)USBD_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief USBD_CDC_RNDIS_EP0_RxReady
|
|
* Handle EP0 Rx Ready event
|
|
* @param pdev: device instance
|
|
* @retval status
|
|
*/
|
|
static uint8_t USBD_CDC_RNDIS_EP0_RxReady(USBD_HandleTypeDef *pdev)
|
|
{
|
|
USBD_CDC_RNDIS_HandleTypeDef *hcdc = (USBD_CDC_RNDIS_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId];
|
|
|
|
if (hcdc == NULL)
|
|
{
|
|
return (uint8_t)USBD_FAIL;
|
|
}
|
|
|
|
if ((pdev->pUserData[pdev->classId] != NULL) && (hcdc->CmdOpCode != 0xFFU))
|
|
{
|
|
/* Check if the received command is SendEncapsulated command */
|
|
if (hcdc->CmdOpCode == CDC_RNDIS_SEND_ENCAPSULATED_COMMAND)
|
|
{
|
|
/* Process Received CDC_RNDIS Control Message */
|
|
(void)USBD_CDC_RNDIS_MsgParsing(pdev, (uint8_t *)(hcdc->data));
|
|
|
|
/* Reset the command opcode for next processing */
|
|
hcdc->CmdOpCode = 0xFFU;
|
|
}
|
|
else
|
|
{
|
|
/* Reset the command opcode for next processing */
|
|
hcdc->CmdOpCode = 0xFFU;
|
|
|
|
/* Ignore the command and return fail */
|
|
return (uint8_t)USBD_FAIL;
|
|
}
|
|
}
|
|
|
|
return (uint8_t)USBD_OK;
|
|
}
|
|
#ifndef USE_USBD_COMPOSITE
|
|
/**
|
|
* @brief USBD_CDC_RNDIS_GetFSCfgDesc
|
|
* Return configuration descriptor
|
|
* @param length : pointer data length
|
|
* @retval pointer to descriptor buffer
|
|
*/
|
|
static uint8_t *USBD_CDC_RNDIS_GetFSCfgDesc(uint16_t *length)
|
|
{
|
|
USBD_EpDescTypeDef *pEpCmdDesc = USBD_GetEpDesc(USBD_CDC_RNDIS_CfgDesc, CDC_RNDIS_CMD_EP);
|
|
USBD_EpDescTypeDef *pEpOutDesc = USBD_GetEpDesc(USBD_CDC_RNDIS_CfgDesc, CDC_RNDIS_OUT_EP);
|
|
USBD_EpDescTypeDef *pEpInDesc = USBD_GetEpDesc(USBD_CDC_RNDIS_CfgDesc, CDC_RNDIS_IN_EP);
|
|
|
|
if (pEpCmdDesc != NULL)
|
|
{
|
|
pEpCmdDesc->bInterval = CDC_RNDIS_FS_BINTERVAL;
|
|
}
|
|
|
|
if (pEpOutDesc != NULL)
|
|
{
|
|
pEpOutDesc->wMaxPacketSize = CDC_RNDIS_DATA_FS_MAX_PACKET_SIZE;
|
|
}
|
|
|
|
if (pEpInDesc != NULL)
|
|
{
|
|
pEpInDesc->wMaxPacketSize = CDC_RNDIS_DATA_FS_MAX_PACKET_SIZE;
|
|
}
|
|
|
|
*length = (uint16_t)(sizeof(USBD_CDC_RNDIS_CfgDesc));
|
|
return USBD_CDC_RNDIS_CfgDesc;
|
|
}
|
|
|
|
/**
|
|
* @brief USBD_CDC_RNDIS_GetHSCfgDesc
|
|
* Return configuration descriptor
|
|
* @param length : pointer data length
|
|
* @retval pointer to descriptor buffer
|
|
*/
|
|
static uint8_t *USBD_CDC_RNDIS_GetHSCfgDesc(uint16_t *length)
|
|
{
|
|
USBD_EpDescTypeDef *pEpCmdDesc = USBD_GetEpDesc(USBD_CDC_RNDIS_CfgDesc, CDC_RNDIS_CMD_EP);
|
|
USBD_EpDescTypeDef *pEpOutDesc = USBD_GetEpDesc(USBD_CDC_RNDIS_CfgDesc, CDC_RNDIS_OUT_EP);
|
|
USBD_EpDescTypeDef *pEpInDesc = USBD_GetEpDesc(USBD_CDC_RNDIS_CfgDesc, CDC_RNDIS_IN_EP);
|
|
|
|
if (pEpCmdDesc != NULL)
|
|
{
|
|
pEpCmdDesc->bInterval = CDC_RNDIS_HS_BINTERVAL;
|
|
}
|
|
|
|
if (pEpOutDesc != NULL)
|
|
{
|
|
pEpOutDesc->wMaxPacketSize = CDC_RNDIS_DATA_HS_MAX_PACKET_SIZE;
|
|
}
|
|
|
|
if (pEpInDesc != NULL)
|
|
{
|
|
pEpInDesc->wMaxPacketSize = CDC_RNDIS_DATA_HS_MAX_PACKET_SIZE;
|
|
}
|
|
|
|
*length = (uint16_t)(sizeof(USBD_CDC_RNDIS_CfgDesc));
|
|
return USBD_CDC_RNDIS_CfgDesc;
|
|
}
|
|
|
|
/**
|
|
* @brief USBD_CDC_RNDIS_GetOtherSpeedCfgDesc
|
|
* Return configuration descriptor
|
|
* @param length : pointer data length
|
|
* @retval pointer to descriptor buffer
|
|
*/
|
|
static uint8_t *USBD_CDC_RNDIS_GetOtherSpeedCfgDesc(uint16_t *length)
|
|
{
|
|
USBD_EpDescTypeDef *pEpCmdDesc = USBD_GetEpDesc(USBD_CDC_RNDIS_CfgDesc, CDC_RNDIS_CMD_EP);
|
|
USBD_EpDescTypeDef *pEpOutDesc = USBD_GetEpDesc(USBD_CDC_RNDIS_CfgDesc, CDC_RNDIS_OUT_EP);
|
|
USBD_EpDescTypeDef *pEpInDesc = USBD_GetEpDesc(USBD_CDC_RNDIS_CfgDesc, CDC_RNDIS_IN_EP);
|
|
|
|
if (pEpCmdDesc != NULL)
|
|
{
|
|
pEpCmdDesc->bInterval = CDC_RNDIS_FS_BINTERVAL;
|
|
}
|
|
|
|
if (pEpOutDesc != NULL)
|
|
{
|
|
pEpOutDesc->wMaxPacketSize = CDC_RNDIS_DATA_FS_MAX_PACKET_SIZE;
|
|
}
|
|
|
|
if (pEpInDesc != NULL)
|
|
{
|
|
pEpInDesc->wMaxPacketSize = CDC_RNDIS_DATA_FS_MAX_PACKET_SIZE;
|
|
}
|
|
|
|
*length = (uint16_t)(sizeof(USBD_CDC_RNDIS_CfgDesc));
|
|
return USBD_CDC_RNDIS_CfgDesc;
|
|
}
|
|
|
|
/**
|
|
* @brief DeviceQualifierDescriptor
|
|
* return Device Qualifier descriptor
|
|
* @param length : pointer data length
|
|
* @retval pointer to descriptor buffer
|
|
*/
|
|
uint8_t *USBD_CDC_RNDIS_GetDeviceQualifierDescriptor(uint16_t *length)
|
|
{
|
|
*length = (uint16_t)(sizeof(USBD_CDC_RNDIS_DeviceQualifierDesc));
|
|
|
|
return USBD_CDC_RNDIS_DeviceQualifierDesc;
|
|
}
|
|
#endif /* USE_USBD_COMPOSITE */
|
|
/**
|
|
* @brief USBD_CDC_RNDIS_RegisterInterface
|
|
* @param pdev: device instance
|
|
* @param fops: CD Interface callback
|
|
* @retval status
|
|
*/
|
|
uint8_t USBD_CDC_RNDIS_RegisterInterface(USBD_HandleTypeDef *pdev,
|
|
USBD_CDC_RNDIS_ItfTypeDef *fops)
|
|
{
|
|
if (fops == NULL)
|
|
{
|
|
return (uint8_t)USBD_FAIL;
|
|
}
|
|
|
|
pdev->pUserData[pdev->classId] = fops;
|
|
|
|
return (uint8_t)USBD_OK;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief USBD_CDC_RNDIS_USRStringDescriptor
|
|
* Manages the transfer of user string descriptors.
|
|
* @param pdev: device instance
|
|
* @param index: descriptor index
|
|
* @param length : pointer data length
|
|
* @retval pointer to the descriptor table or NULL if the descriptor is not supported.
|
|
*/
|
|
#if (USBD_SUPPORT_USER_STRING_DESC == 1U)
|
|
static uint8_t *USBD_CDC_RNDIS_USRStringDescriptor(USBD_HandleTypeDef *pdev, uint8_t index, uint16_t *length)
|
|
{
|
|
static uint8_t USBD_StrDesc[255];
|
|
|
|
/* Check if the requested string interface is supported */
|
|
if (index == CDC_RNDIS_MAC_STRING_INDEX)
|
|
{
|
|
USBD_GetString((uint8_t *)((USBD_CDC_RNDIS_ItfTypeDef *)pdev->pUserData[pdev->classId])->pStrDesc, USBD_StrDesc,
|
|
length);
|
|
return USBD_StrDesc;
|
|
}
|
|
/* Not supported Interface Descriptor index */
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
#endif /* USBD_SUPPORT_USER_STRING_DESC */
|
|
|
|
|
|
/**
|
|
* @brief USBD_CDC_RNDIS_SetTxBuffer
|
|
* @param pdev: device instance
|
|
* @param pbuff: Tx Buffer
|
|
* @param length: Tx Buffer length
|
|
* @param ClassId: The Class ID
|
|
* @retval status
|
|
*/
|
|
#ifdef USE_USBD_COMPOSITE
|
|
uint8_t USBD_CDC_RNDIS_SetTxBuffer(USBD_HandleTypeDef *pdev, uint8_t *pbuff, uint32_t length, uint8_t ClassId)
|
|
{
|
|
USBD_CDC_RNDIS_HandleTypeDef *hcdc = (USBD_CDC_RNDIS_HandleTypeDef *)pdev->pClassDataCmsit[ClassId];
|
|
#else
|
|
uint8_t USBD_CDC_RNDIS_SetTxBuffer(USBD_HandleTypeDef *pdev, uint8_t *pbuff, uint32_t length)
|
|
{
|
|
|
|
USBD_CDC_RNDIS_HandleTypeDef *hcdc = (USBD_CDC_RNDIS_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId];
|
|
#endif /* USE_USBD_COMPOSITE */
|
|
|
|
if (hcdc == NULL)
|
|
{
|
|
return (uint8_t)USBD_FAIL;
|
|
}
|
|
|
|
hcdc->TxBuffer = pbuff;
|
|
hcdc->TxLength = length;
|
|
|
|
return (uint8_t)USBD_OK;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief USBD_CDC_RNDIS_SetRxBuffer
|
|
* @param pdev: device instance
|
|
* @param pbuff: Rx Buffer
|
|
* @retval status
|
|
*/
|
|
uint8_t USBD_CDC_RNDIS_SetRxBuffer(USBD_HandleTypeDef *pdev, uint8_t *pbuff)
|
|
{
|
|
USBD_CDC_RNDIS_HandleTypeDef *hcdc = (USBD_CDC_RNDIS_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId];
|
|
|
|
if (hcdc == NULL)
|
|
{
|
|
return (uint8_t)USBD_FAIL;
|
|
}
|
|
|
|
hcdc->RxBuffer = pbuff;
|
|
|
|
return (uint8_t)USBD_OK;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief USBD_CDC_RNDIS_TransmitPacket
|
|
* Transmit packet on IN endpoint
|
|
* @param pdev: device instance
|
|
* @param ClassId: The Class ID
|
|
* @retval status
|
|
*/
|
|
#ifdef USE_USBD_COMPOSITE
|
|
uint8_t USBD_CDC_RNDIS_TransmitPacket(USBD_HandleTypeDef *pdev, uint8_t ClassId)
|
|
{
|
|
USBD_CDC_RNDIS_HandleTypeDef *hcdc = (USBD_CDC_RNDIS_HandleTypeDef *)pdev->pClassDataCmsit[ClassId];
|
|
#else
|
|
uint8_t USBD_CDC_RNDIS_TransmitPacket(USBD_HandleTypeDef *pdev)
|
|
{
|
|
USBD_CDC_RNDIS_HandleTypeDef *hcdc = (USBD_CDC_RNDIS_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId];
|
|
#endif /* USE_USBD_COMPOSITE */
|
|
|
|
USBD_CDC_RNDIS_PacketMsgTypeDef *PacketMsg;
|
|
USBD_StatusTypeDef ret = USBD_BUSY;
|
|
|
|
#ifdef USE_USBD_COMPOSITE
|
|
/* Get the Endpoints addresses allocated for this class instance */
|
|
RNDISInEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_IN, USBD_EP_TYPE_BULK, ClassId);
|
|
#endif /* USE_USBD_COMPOSITE */
|
|
|
|
if (hcdc == NULL)
|
|
{
|
|
return (uint8_t)USBD_FAIL;
|
|
}
|
|
|
|
PacketMsg = (USBD_CDC_RNDIS_PacketMsgTypeDef *)(void *)hcdc->TxBuffer;
|
|
|
|
if (hcdc->TxState == 0U)
|
|
{
|
|
/* Tx Transfer in progress */
|
|
hcdc->TxState = 1U;
|
|
|
|
/* Format the packet information */
|
|
PacketMsg->MsgType = CDC_RNDIS_PACKET_MSG_ID;
|
|
PacketMsg->MsgLength = hcdc->TxLength;
|
|
PacketMsg->DataOffset = sizeof(USBD_CDC_RNDIS_PacketMsgTypeDef) - CDC_RNDIS_PCKTMSG_DATAOFFSET_OFFSET;
|
|
PacketMsg->DataLength = hcdc->TxLength - sizeof(USBD_CDC_RNDIS_PacketMsgTypeDef);
|
|
PacketMsg->OOBDataOffset = 0U;
|
|
PacketMsg->OOBDataLength = 0U;
|
|
PacketMsg->NumOOBDataElements = 0U;
|
|
PacketMsg->PerPacketInfoOffset = 0U;
|
|
PacketMsg->PerPacketInfoLength = 0U;
|
|
PacketMsg->VcHandle = 0U;
|
|
PacketMsg->Reserved = 0U;
|
|
|
|
/* Update the packet total length */
|
|
pdev->ep_in[RNDISInEpAdd & 0xFU].total_length = hcdc->TxLength;
|
|
|
|
/* Transmit next packet */
|
|
(void)USBD_LL_Transmit(pdev, RNDISInEpAdd, hcdc->TxBuffer, hcdc->TxLength);
|
|
|
|
ret = USBD_OK;
|
|
}
|
|
|
|
return (uint8_t)ret;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief USBD_CDC_RNDIS_ReceivePacket
|
|
* prepare OUT Endpoint for reception
|
|
* @param pdev: device instance
|
|
* @retval status
|
|
*/
|
|
uint8_t USBD_CDC_RNDIS_ReceivePacket(USBD_HandleTypeDef *pdev)
|
|
{
|
|
USBD_CDC_RNDIS_HandleTypeDef *hcdc;
|
|
|
|
#ifdef USE_USBD_COMPOSITE
|
|
/* Get the Endpoints addresses allocated for this class instance */
|
|
RNDISOutEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_OUT, USBD_EP_TYPE_BULK, (uint8_t)pdev->classId);
|
|
#endif /* USE_USBD_COMPOSITE */
|
|
|
|
if (pdev->pClassDataCmsit[pdev->classId] == NULL)
|
|
{
|
|
return (uint8_t)USBD_FAIL;
|
|
}
|
|
|
|
hcdc = (USBD_CDC_RNDIS_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId];
|
|
|
|
/* Prepare Out endpoint to receive next packet */
|
|
(void)USBD_LL_PrepareReceive(pdev, RNDISOutEpAdd,
|
|
hcdc->RxBuffer, hcdc->MaxPcktLen);
|
|
|
|
return (uint8_t)USBD_OK;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief USBD_CDC_RNDIS_SendNotification
|
|
* Transmit Notification packet on CMD IN interrupt endpoint
|
|
* @param pdev: device instance
|
|
* Notif: value of the notification type (from CDC_RNDIS_Notification_TypeDef enumeration list)
|
|
* bVal: value of the notification switch (ie. 0x00 or 0x01 for Network Connection notification)
|
|
* pData: pointer to data buffer (ie. upstream and downstream connection speed values)
|
|
* @retval status
|
|
*/
|
|
uint8_t USBD_CDC_RNDIS_SendNotification(USBD_HandleTypeDef *pdev,
|
|
USBD_CDC_NotifCodeTypeDef Notif,
|
|
uint16_t bVal, uint8_t *pData)
|
|
{
|
|
uint32_t Idx;
|
|
uint16_t ReqSize = 0U;
|
|
USBD_CDC_RNDIS_HandleTypeDef *hcdc = (USBD_CDC_RNDIS_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId];
|
|
USBD_StatusTypeDef ret = USBD_OK;
|
|
|
|
UNUSED(bVal);
|
|
UNUSED(pData);
|
|
|
|
if (hcdc == NULL)
|
|
{
|
|
return (uint8_t)USBD_FAIL;
|
|
}
|
|
|
|
#ifdef USE_USBD_COMPOSITE
|
|
/* Get the Endpoints addresses allocated for this class instance */
|
|
RNDISCmdEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_IN, USBD_EP_TYPE_INTR, (uint8_t)pdev->classId);
|
|
#endif /* USE_USBD_COMPOSITE */
|
|
|
|
/* Initialize the request fields */
|
|
(hcdc->Req).bmRequest = CDC_RNDIS_BMREQUEST_TYPE_RNDIS;
|
|
(hcdc->Req).bRequest = (uint8_t)Notif;
|
|
|
|
switch (Notif)
|
|
{
|
|
case RESPONSE_AVAILABLE:
|
|
(hcdc->Req).wValue = 0U;
|
|
(hcdc->Req).wIndex = CDC_RNDIS_CMD_ITF_NBR;
|
|
(hcdc->Req).wLength = 0U;
|
|
|
|
for (Idx = 0U; Idx < 8U; Idx++)
|
|
{
|
|
(hcdc->Req).data[Idx] = 0U;
|
|
}
|
|
|
|
ReqSize = 8U;
|
|
break;
|
|
|
|
default:
|
|
ret = USBD_FAIL;
|
|
break;
|
|
}
|
|
|
|
/* Transmit notification packet */
|
|
if (ReqSize != 0U)
|
|
{
|
|
(void)USBD_LL_Transmit(pdev, RNDISCmdEpAdd, (uint8_t *)&hcdc->Req, ReqSize);
|
|
}
|
|
|
|
return (uint8_t)ret;
|
|
}
|
|
|
|
|
|
/* ----------------------------- CDC_RNDIS Messages processing functions ----------------------- */
|
|
/**
|
|
* @brief USBD_CDC_RNDIS_MsgParsing
|
|
* Parse received message and process it depending on its nature.
|
|
* @param pdev: USB Device Handle pointer
|
|
* @param RxBuff: Pointer to the message data extracted from SendEncapsulated command
|
|
* @retval status
|
|
*/
|
|
static uint8_t USBD_CDC_RNDIS_MsgParsing(USBD_HandleTypeDef *pdev, uint8_t *RxBuff)
|
|
{
|
|
USBD_CDC_RNDIS_CtrlMsgTypeDef *Msg = (USBD_CDC_RNDIS_CtrlMsgTypeDef *)(void *)RxBuff;
|
|
static uint8_t ret = (uint8_t)USBD_OK;
|
|
|
|
/* Check message type */
|
|
switch (Msg->MsgType)
|
|
{
|
|
/* CDC_RNDIS Initialize message */
|
|
case CDC_RNDIS_INITIALIZE_MSG_ID:
|
|
ret = USBD_CDC_RNDIS_ProcessInitMsg(pdev, (USBD_CDC_RNDIS_InitMsgTypeDef *)(void *)Msg);
|
|
break;
|
|
|
|
/* CDC_RNDIS Halt message */
|
|
case CDC_RNDIS_HALT_MSG_ID:
|
|
ret = USBD_CDC_RNDIS_ProcessHaltMsg(pdev, (USBD_CDC_RNDIS_HaltMsgTypeDef *)(void *)Msg);
|
|
break;
|
|
|
|
/* CDC_RNDIS Query message */
|
|
case CDC_RNDIS_QUERY_MSG_ID:
|
|
ret = USBD_CDC_RNDIS_ProcessQueryMsg(pdev, (USBD_CDC_RNDIS_QueryMsgTypeDef *)(void *)Msg);
|
|
break;
|
|
|
|
/* CDC_RNDIS Set message */
|
|
case CDC_RNDIS_SET_MSG_ID:
|
|
ret = USBD_CDC_RNDIS_ProcessSetMsg(pdev, (USBD_CDC_RNDIS_SetMsgTypeDef *)(void *)Msg);
|
|
break;
|
|
|
|
/* CDC_RNDIS Reset message */
|
|
case CDC_RNDIS_RESET_MSG_ID:
|
|
ret = USBD_CDC_RNDIS_ProcessResetMsg(pdev, (USBD_CDC_RNDIS_ResetMsgTypeDef *)(void *)Msg);
|
|
break;
|
|
|
|
/* CDC_RNDIS Keep-Alive message */
|
|
case CDC_RNDIS_KEEPALIVE_MSG_ID:
|
|
ret = USBD_CDC_RNDIS_ProcessKeepAliveMsg(pdev, (USBD_CDC_RNDIS_KpAliveMsgTypeDef *)(void *)Msg);
|
|
break;
|
|
|
|
/* CDC_RNDIS unsupported message */
|
|
default:
|
|
ret = USBD_CDC_RNDIS_ProcessUnsupportedMsg(pdev, (USBD_CDC_RNDIS_CtrlMsgTypeDef *)(void *)Msg);
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief USBD_CDC_RNDIS_ProcessInitMsg
|
|
* Parse, extract data and check correctness of CDC_RNDIS INIT_MSG command.
|
|
* @param pdev: USB Device Handle pointer
|
|
* @param Msg: Pointer to the message data extracted from SendEncapsulated command
|
|
* @retval status
|
|
*/
|
|
static uint8_t USBD_CDC_RNDIS_ProcessInitMsg(USBD_HandleTypeDef *pdev,
|
|
USBD_CDC_RNDIS_InitMsgTypeDef *Msg)
|
|
{
|
|
/* Get the CDC_RNDIS handle pointer */
|
|
USBD_CDC_RNDIS_HandleTypeDef *hcdc = (USBD_CDC_RNDIS_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId];
|
|
|
|
/* Get and format the Msg input */
|
|
USBD_CDC_RNDIS_InitMsgTypeDef *InitMessage = (USBD_CDC_RNDIS_InitMsgTypeDef *)Msg;
|
|
|
|
/* Use same Msg input buffer as response buffer */
|
|
USBD_CDC_RNDIS_InitCpltMsgTypeDef *InitResponse = (USBD_CDC_RNDIS_InitCpltMsgTypeDef *)(void *)Msg;
|
|
|
|
/* Store the Message Request ID */
|
|
uint32_t ReqId = InitMessage->ReqId;
|
|
|
|
if (hcdc == NULL)
|
|
{
|
|
return (uint8_t)USBD_FAIL;
|
|
}
|
|
|
|
/* Check correctness of the message (MsgType already checked by entry to this function) */
|
|
if ((InitMessage->MsgLength != sizeof(USBD_CDC_RNDIS_InitMsgTypeDef)) || \
|
|
(InitMessage->MajorVersion < CDC_RNDIS_VERSION_MAJOR))
|
|
{
|
|
InitResponse->Status = CDC_RNDIS_STATUS_FAILURE;
|
|
}
|
|
else
|
|
{
|
|
InitResponse->Status = CDC_RNDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
/* Setup the response buffer content */
|
|
InitResponse->MsgType = CDC_RNDIS_INITIALIZE_CMPLT_ID;
|
|
InitResponse->MsgLength = sizeof(USBD_CDC_RNDIS_InitCpltMsgTypeDef);
|
|
InitResponse->ReqId = ReqId;
|
|
InitResponse->MajorVersion = CDC_RNDIS_VERSION_MAJOR;
|
|
InitResponse->MinorVersion = CDC_RNDIS_VERSION_MINOR;
|
|
InitResponse->DeviceFlags = CDC_RNDIS_DF_CONNECTIONLESS;
|
|
InitResponse->Medium = CDC_RNDIS_MEDIUM_802_3;
|
|
InitResponse->MaxPacketsPerTransfer = 1U;
|
|
InitResponse->MaxTransferSize = (sizeof(USBD_CDC_RNDIS_PacketMsgTypeDef) + CDC_RNDIS_ETH_FRAME_SIZE_MAX);
|
|
InitResponse->PacketAlignmentFactor = 2U; /* Not needed as single packet by transfer set */
|
|
InitResponse->AFListOffset = 0U; /* Reserved for connection-oriented devices. Set value to zero. */
|
|
InitResponse->AFListSize = 0U; /* Reserved for connection-oriented devices. Set value to zero. */
|
|
|
|
/* Set CDC_RNDIS state to INITIALIZED */
|
|
hcdc->State = CDC_RNDIS_STATE_INITIALIZED;
|
|
|
|
/* Set Response Ready field in order to send response during next control request */
|
|
hcdc->ResponseRdy = 1U;
|
|
|
|
/* Send Notification on Interrupt EP to inform Host that response is ready */
|
|
(void)USBD_CDC_RNDIS_SendNotification(pdev, RESPONSE_AVAILABLE, 0U, NULL);
|
|
|
|
return (uint8_t)USBD_OK;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief USBD_CDC_RNDIS_ProcessHaltMsg
|
|
* Parse, extract data and check correctness of CDC_RNDIS Halt command.
|
|
* @param pdev: USB Device Handle pointer
|
|
* @param Msg: Pointer to the message data extracted from SendEncapsulated command
|
|
* @retval status
|
|
*/
|
|
static uint8_t USBD_CDC_RNDIS_ProcessHaltMsg(USBD_HandleTypeDef *pdev,
|
|
USBD_CDC_RNDIS_HaltMsgTypeDef *Msg)
|
|
{
|
|
/* Get the CDC_RNDIS handle pointer */
|
|
USBD_CDC_RNDIS_HandleTypeDef *hcdc = (USBD_CDC_RNDIS_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId];
|
|
|
|
if (hcdc == NULL)
|
|
{
|
|
return (uint8_t)USBD_FAIL;
|
|
}
|
|
|
|
/* Set CDC_RNDIS state to INITIALIZED */
|
|
hcdc->State = CDC_RNDIS_STATE_UNINITIALIZED;
|
|
|
|
/* No response required for this message, so no notification (RESPONSE_AVAILABLE) is sent */
|
|
|
|
UNUSED(Msg);
|
|
|
|
return (uint8_t)USBD_OK;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief USBD_CDC_RNDIS_ProcessKeepAliveMsg
|
|
* Parse, extract data and check correctness of CDC_RNDIS KeepAlive command.
|
|
* @param pdev: USB Device Handle pointer
|
|
* @param Msg: Pointer to the message data extracted from SendEncapsulated command
|
|
* @retval status
|
|
*/
|
|
static uint8_t USBD_CDC_RNDIS_ProcessKeepAliveMsg(USBD_HandleTypeDef *pdev,
|
|
USBD_CDC_RNDIS_KpAliveMsgTypeDef *Msg)
|
|
{
|
|
/* Get the CDC_RNDIS handle pointer */
|
|
USBD_CDC_RNDIS_HandleTypeDef *hcdc = (USBD_CDC_RNDIS_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId];
|
|
|
|
/* Use same Msg input buffer as response buffer */
|
|
USBD_CDC_RNDIS_KpAliveCpltMsgTypeDef *InitResponse = (USBD_CDC_RNDIS_KpAliveCpltMsgTypeDef *)(void *)Msg;
|
|
|
|
/* Store the Message Request ID */
|
|
uint32_t ReqId = Msg->ReqId;
|
|
|
|
if (hcdc == NULL)
|
|
{
|
|
return (uint8_t)USBD_FAIL;
|
|
}
|
|
|
|
/* Check correctness of the message (MsgType already checked by entry to this function) */
|
|
if (Msg->MsgLength != sizeof(USBD_CDC_RNDIS_KpAliveMsgTypeDef))
|
|
{
|
|
InitResponse->Status = CDC_RNDIS_STATUS_FAILURE;
|
|
}
|
|
else
|
|
{
|
|
InitResponse->Status = CDC_RNDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
/* Setup the response buffer content */
|
|
InitResponse->MsgType = CDC_RNDIS_KEEPALIVE_CMPLT_ID;
|
|
InitResponse->MsgLength = sizeof(USBD_CDC_RNDIS_KpAliveCpltMsgTypeDef);
|
|
InitResponse->ReqId = ReqId;
|
|
InitResponse->Status = CDC_RNDIS_STATUS_SUCCESS;
|
|
|
|
/* Set Response Ready field in order to send response during next control request */
|
|
hcdc->ResponseRdy = 1U;
|
|
|
|
/* Send Notification on Interrupt EP to inform Host that response is ready */
|
|
(void)USBD_CDC_RNDIS_SendNotification(pdev, RESPONSE_AVAILABLE, 0U, NULL);
|
|
|
|
return (uint8_t)USBD_OK;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief USBD_CDC_RNDIS_ProcessQueryMsg
|
|
* Parse, extract data and check correctness of CDC_RNDIS Query command.
|
|
* @param pdev: USB Device Handle pointer
|
|
* @param Msg: Pointer to the message data extracted from SendEncapsulated command
|
|
* @retval status
|
|
*/
|
|
static uint8_t USBD_CDC_RNDIS_ProcessQueryMsg(USBD_HandleTypeDef *pdev,
|
|
USBD_CDC_RNDIS_QueryMsgTypeDef *Msg)
|
|
{
|
|
/* Get the CDC_RNDIS handle pointer */
|
|
USBD_CDC_RNDIS_HandleTypeDef *hcdc = (USBD_CDC_RNDIS_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId];
|
|
|
|
/* Use same Msg input buffer as response buffer */
|
|
USBD_CDC_RNDIS_QueryCpltMsgTypeDef *QueryResponse = (USBD_CDC_RNDIS_QueryCpltMsgTypeDef *)(void *)Msg;
|
|
|
|
/* Store the Message Request ID */
|
|
uint32_t ReqId = Msg->RequestId;
|
|
|
|
if (hcdc == NULL)
|
|
{
|
|
return (uint8_t)USBD_FAIL;
|
|
}
|
|
|
|
/* Process the OID depending on its code */
|
|
switch (Msg->Oid)
|
|
{
|
|
case OID_GEN_SUPPORTED_LIST:
|
|
QueryResponse->InfoBufLength = sizeof(CDC_RNDIS_SupportedOIDs);
|
|
(void)USBD_memcpy(QueryResponse->InfoBuf, CDC_RNDIS_SupportedOIDs,
|
|
sizeof(CDC_RNDIS_SupportedOIDs));
|
|
|
|
QueryResponse->Status = CDC_RNDIS_STATUS_SUCCESS;
|
|
break;
|
|
|
|
case OID_GEN_HARDWARE_STATUS:
|
|
QueryResponse->InfoBufLength = sizeof(uint32_t);
|
|
QueryResponse->InfoBuf[0] = CDC_RNDIS_HW_STS_READY;
|
|
QueryResponse->Status = CDC_RNDIS_STATUS_SUCCESS;
|
|
break;
|
|
|
|
case OID_GEN_MEDIA_SUPPORTED:
|
|
case OID_GEN_MEDIA_IN_USE:
|
|
QueryResponse->InfoBufLength = sizeof(uint32_t);
|
|
QueryResponse->InfoBuf[0] = CDC_RNDIS_MEDIUM_802_3;
|
|
QueryResponse->Status = CDC_RNDIS_STATUS_SUCCESS;
|
|
break;
|
|
|
|
case OID_GEN_VENDOR_ID:
|
|
QueryResponse->InfoBufLength = sizeof(uint32_t);
|
|
QueryResponse->InfoBuf[0] = USBD_CDC_RNDIS_VID;
|
|
QueryResponse->Status = CDC_RNDIS_STATUS_SUCCESS;
|
|
break;
|
|
|
|
case OID_GEN_MAXIMUM_FRAME_SIZE:
|
|
case OID_GEN_TRANSMIT_BLOCK_SIZE:
|
|
case OID_GEN_RECEIVE_BLOCK_SIZE:
|
|
QueryResponse->InfoBufLength = sizeof(uint32_t);
|
|
QueryResponse->InfoBuf[0] = CDC_RNDIS_ETH_FRAME_SIZE_MAX;
|
|
QueryResponse->Status = CDC_RNDIS_STATUS_SUCCESS;
|
|
break;
|
|
|
|
case OID_GEN_VENDOR_DESCRIPTION:
|
|
QueryResponse->InfoBufLength = (strlen(USBD_CDC_RNDIS_VENDOR_DESC) + 1U);
|
|
(void)USBD_memcpy(QueryResponse->InfoBuf, USBD_CDC_RNDIS_VENDOR_DESC,
|
|
strlen(USBD_CDC_RNDIS_VENDOR_DESC));
|
|
|
|
QueryResponse->Status = CDC_RNDIS_STATUS_SUCCESS;
|
|
break;
|
|
|
|
case OID_GEN_MEDIA_CONNECT_STATUS:
|
|
QueryResponse->InfoBufLength = sizeof(uint32_t);
|
|
QueryResponse->InfoBuf[0] = CDC_RNDIS_MEDIA_STATE_CONNECTED;
|
|
QueryResponse->Status = CDC_RNDIS_STATUS_SUCCESS;
|
|
break;
|
|
|
|
case OID_GEN_MAXIMUM_SEND_PACKETS:
|
|
QueryResponse->InfoBufLength = sizeof(uint32_t);
|
|
QueryResponse->InfoBuf[0] = 1U;
|
|
QueryResponse->Status = CDC_RNDIS_STATUS_SUCCESS;
|
|
break;
|
|
|
|
case OID_GEN_LINK_SPEED:
|
|
QueryResponse->InfoBufLength = sizeof(uint32_t);
|
|
QueryResponse->InfoBuf[0] = USBD_CDC_RNDIS_LINK_SPEED;
|
|
QueryResponse->Status = CDC_RNDIS_STATUS_SUCCESS;
|
|
break;
|
|
|
|
case OID_802_3_PERMANENT_ADDRESS:
|
|
case OID_802_3_CURRENT_ADDRESS:
|
|
QueryResponse->InfoBufLength = 6U;
|
|
(void)USBD_memcpy(QueryResponse->InfoBuf, MAC_StrDesc, 6);
|
|
QueryResponse->Status = CDC_RNDIS_STATUS_SUCCESS;
|
|
break;
|
|
|
|
case OID_802_3_MAXIMUM_LIST_SIZE:
|
|
QueryResponse->InfoBufLength = sizeof(uint32_t);
|
|
QueryResponse->InfoBuf[0] = 1U; /* Only one multicast address supported */
|
|
QueryResponse->Status = CDC_RNDIS_STATUS_SUCCESS;
|
|
break;
|
|
|
|
case OID_GEN_CURRENT_PACKET_FILTER:
|
|
QueryResponse->InfoBufLength = sizeof(uint32_t);
|
|
QueryResponse->InfoBuf[0] = 0xFFFFFFU; /* USBD_CDC_RNDIS_DEVICE.packetFilter */
|
|
QueryResponse->Status = CDC_RNDIS_STATUS_SUCCESS;
|
|
break;
|
|
|
|
case OID_802_3_RCV_ERROR_ALIGNMENT:
|
|
case OID_802_3_XMIT_ONE_COLLISION:
|
|
case OID_802_3_XMIT_MORE_COLLISIONS:
|
|
QueryResponse->InfoBufLength = sizeof(uint32_t);
|
|
QueryResponse->InfoBuf[0] = 0U; /* Unused OIDs, return zero */
|
|
QueryResponse->Status = CDC_RNDIS_STATUS_SUCCESS;
|
|
break;
|
|
|
|
case OID_GEN_MAXIMUM_TOTAL_SIZE:
|
|
QueryResponse->InfoBufLength = sizeof(uint32_t);
|
|
/* Indicate maximum overall buffer (Ethernet frame and CDC_RNDIS header) the adapter can handle */
|
|
QueryResponse->InfoBuf[0] = (CDC_RNDIS_MESSAGE_BUFFER_SIZE + CDC_RNDIS_ETH_FRAME_SIZE_MAX);
|
|
QueryResponse->Status = CDC_RNDIS_STATUS_SUCCESS;
|
|
break;
|
|
|
|
default:
|
|
/* Unknown or unsupported OID */
|
|
QueryResponse->InfoBufLength = 0U;
|
|
QueryResponse->Status = CDC_RNDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
/* Setup the response buffer content */
|
|
QueryResponse->MsgType = CDC_RNDIS_QUERY_CMPLT_ID;
|
|
QueryResponse->MsgLength = QueryResponse->InfoBufLength + 24U;
|
|
QueryResponse->ReqId = ReqId;
|
|
QueryResponse->InfoBufOffset = 16U;
|
|
|
|
/* Set Response Ready field in order to send response during next control request */
|
|
hcdc->ResponseRdy = 1U;
|
|
|
|
/* Send Notification on Interrupt EP to inform Host that response is ready */
|
|
(void)USBD_CDC_RNDIS_SendNotification(pdev, RESPONSE_AVAILABLE, 0U, NULL);
|
|
|
|
return (uint8_t)USBD_OK;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief USBD_CDC_RNDIS_ProcessSetMsg
|
|
* Parse, extract data and check correctness of CDC_RNDIS Set Message command.
|
|
* @param pdev: USB Device Handle pointer
|
|
* @param Msg: Pointer to the message data extracted from SendEncapsulated command
|
|
* @retval status
|
|
*/
|
|
static uint8_t USBD_CDC_RNDIS_ProcessSetMsg(USBD_HandleTypeDef *pdev,
|
|
USBD_CDC_RNDIS_SetMsgTypeDef *Msg)
|
|
{
|
|
/* Get the CDC_RNDIS handle pointer */
|
|
USBD_CDC_RNDIS_HandleTypeDef *hcdc = (USBD_CDC_RNDIS_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId];
|
|
|
|
/* Get and format the Msg input */
|
|
USBD_CDC_RNDIS_SetMsgTypeDef *SetMessage = (USBD_CDC_RNDIS_SetMsgTypeDef *)Msg;
|
|
|
|
/* Use same Msg input buffer as response buffer */
|
|
USBD_CDC_RNDIS_SetCpltMsgTypeDef *SetResponse = (USBD_CDC_RNDIS_SetCpltMsgTypeDef *)(void *)Msg;
|
|
|
|
/* Store the Message Request ID */
|
|
uint32_t ReqId = SetMessage->ReqId;
|
|
|
|
if (hcdc == NULL)
|
|
{
|
|
return (uint8_t)USBD_FAIL;
|
|
}
|
|
|
|
switch (SetMessage->Oid)
|
|
{
|
|
case OID_GEN_CURRENT_PACKET_FILTER:
|
|
/* Setup the packet filter value */
|
|
hcdc->PacketFilter = SetMessage->InfoBuf[0];
|
|
SetResponse->Status = CDC_RNDIS_STATUS_SUCCESS;
|
|
break;
|
|
|
|
case OID_802_3_MULTICAST_LIST:
|
|
/* List of multicast addresses on a miniport adapter */
|
|
SetResponse->Status = CDC_RNDIS_STATUS_SUCCESS;
|
|
break;
|
|
|
|
default:
|
|
/* Report an error */
|
|
SetResponse->Status = CDC_RNDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
/* Prepare response buffer */
|
|
SetResponse->MsgType = CDC_RNDIS_SET_CMPLT_ID;
|
|
SetResponse->MsgLength = sizeof(USBD_CDC_RNDIS_SetCpltMsgTypeDef);
|
|
SetResponse->ReqId = ReqId;
|
|
|
|
/* Set Response Ready field in order to send response during next control request */
|
|
hcdc->ResponseRdy = 1U;
|
|
|
|
/* Send Notification on Interrupt EP to inform Host that response is ready */
|
|
(void)USBD_CDC_RNDIS_SendNotification(pdev, RESPONSE_AVAILABLE, 0U, NULL);
|
|
|
|
return (uint8_t)USBD_OK;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief USBD_CDC_RNDIS_ProcessResetMsg
|
|
* Parse, extract data and check correctness of CDC_RNDIS Set Message command.
|
|
* @param pdev: USB Device Handle pointer
|
|
* @param Msg: Pointer to the message data extracted from SendEncapsulated command
|
|
* @retval status
|
|
*/
|
|
static uint8_t USBD_CDC_RNDIS_ProcessResetMsg(USBD_HandleTypeDef *pdev,
|
|
USBD_CDC_RNDIS_ResetMsgTypeDef *Msg)
|
|
{
|
|
/* Get and format the Msg input */
|
|
USBD_CDC_RNDIS_ResetMsgTypeDef *ResetMessage = (USBD_CDC_RNDIS_ResetMsgTypeDef *)Msg;
|
|
/* Get the CDC_RNDIS handle pointer */
|
|
USBD_CDC_RNDIS_HandleTypeDef *hcdc = (USBD_CDC_RNDIS_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId];
|
|
/* Use same Msg input buffer as response buffer */
|
|
USBD_CDC_RNDIS_ResetCpltMsgTypeDef *ResetResponse = (USBD_CDC_RNDIS_ResetCpltMsgTypeDef *)(void *)Msg;
|
|
|
|
if (hcdc == NULL)
|
|
{
|
|
return (uint8_t)USBD_FAIL;
|
|
}
|
|
|
|
if ((ResetMessage->MsgLength != sizeof(USBD_CDC_RNDIS_ResetMsgTypeDef)) || \
|
|
(ResetMessage->Reserved != 0U))
|
|
{
|
|
ResetResponse->Status = CDC_RNDIS_STATUS_FAILURE;
|
|
}
|
|
else
|
|
{
|
|
ResetResponse->Status = CDC_RNDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
/* Prepare response buffer */
|
|
ResetResponse->MsgType = CDC_RNDIS_RESET_CMPLT_ID;
|
|
ResetResponse->MsgLength = sizeof(USBD_CDC_RNDIS_ResetCpltMsgTypeDef);
|
|
ResetResponse->AddrReset = 0U;
|
|
|
|
/* Set CDC_RNDIS state to INITIALIZED */
|
|
hcdc->State = CDC_RNDIS_STATE_BUS_INITIALIZED;
|
|
hcdc->LinkStatus = 0U;
|
|
|
|
/* Set Response Ready field in order to send response during next control request */
|
|
hcdc->ResponseRdy = 1U;
|
|
|
|
/* Send Notification on Interrupt EP to inform Host that response is ready */
|
|
(void)USBD_CDC_RNDIS_SendNotification(pdev, RESPONSE_AVAILABLE, 0U, NULL);
|
|
|
|
return (uint8_t)USBD_OK;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief USBD_CDC_RNDIS_ProcessPacketMsg
|
|
* Parse, extract data and check correctness of CDC_RNDIS Data Packet.
|
|
* @param pdev: USB Device Handle pointer
|
|
* @param Msg: Pointer to the message data extracted from Packet
|
|
* @retval status
|
|
*/
|
|
static uint8_t USBD_CDC_RNDIS_ProcessPacketMsg(USBD_HandleTypeDef *pdev,
|
|
USBD_CDC_RNDIS_PacketMsgTypeDef *Msg)
|
|
{
|
|
uint32_t tmp1;
|
|
uint32_t tmp2;
|
|
|
|
/* Get the CDC_RNDIS handle pointer */
|
|
USBD_CDC_RNDIS_HandleTypeDef *hcdc = (USBD_CDC_RNDIS_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId];
|
|
|
|
/* Get and format the Msg input */
|
|
USBD_CDC_RNDIS_PacketMsgTypeDef *PacketMsg = (USBD_CDC_RNDIS_PacketMsgTypeDef *)Msg;
|
|
|
|
if (hcdc == NULL)
|
|
{
|
|
return (uint8_t)USBD_FAIL;
|
|
}
|
|
|
|
/* Check correctness of the message */
|
|
if ((PacketMsg->MsgType != CDC_RNDIS_PACKET_MSG_ID))
|
|
{
|
|
return (uint8_t)USBD_FAIL;
|
|
}
|
|
|
|
/* Point to the payload and update the message length */
|
|
|
|
/* Use temporary storage variables to comply with MISRA-C 2012 rule of (+) operand allowed types */
|
|
tmp1 = (uint32_t)PacketMsg;
|
|
tmp2 = (uint32_t)(PacketMsg->DataOffset);
|
|
hcdc->RxBuffer = (uint8_t *)(tmp1 + tmp2 + CDC_RNDIS_PCKTMSG_DATAOFFSET_OFFSET);
|
|
hcdc->RxLength = PacketMsg->DataLength;
|
|
|
|
/* Process data by application */
|
|
((USBD_CDC_RNDIS_ItfTypeDef *)pdev->pUserData[pdev->classId])->Receive(hcdc->RxBuffer, &hcdc->RxLength);
|
|
|
|
return (uint8_t)USBD_OK;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief USBD_CDC_RNDIS_ProcessUnsupportedMsg
|
|
* Parse, extract data and check correctness of CDC_RNDIS KeepAlive command.
|
|
* @param pdev: USB Device Handle pointer
|
|
* @param Msg: Pointer to the message data extracted from SendEncapsulated command
|
|
* @retval status
|
|
*/
|
|
static uint8_t USBD_CDC_RNDIS_ProcessUnsupportedMsg(USBD_HandleTypeDef *pdev,
|
|
USBD_CDC_RNDIS_CtrlMsgTypeDef *Msg)
|
|
{
|
|
/* Get the CDC_RNDIS handle pointer */
|
|
USBD_CDC_RNDIS_HandleTypeDef *hcdc = (USBD_CDC_RNDIS_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId];
|
|
|
|
/* Use same Msg input buffer as response buffer */
|
|
USBD_CDC_RNDIS_StsChangeMsgTypeDef *Response = (USBD_CDC_RNDIS_StsChangeMsgTypeDef *)(void *)Msg;
|
|
|
|
if (hcdc == NULL)
|
|
{
|
|
return (uint8_t)USBD_FAIL;
|
|
}
|
|
|
|
/* Setup the response buffer content */
|
|
Response->MsgType = CDC_RNDIS_INDICATE_STATUS_MSG_ID;
|
|
Response->MsgLength = sizeof(USBD_CDC_RNDIS_StsChangeMsgTypeDef);
|
|
Response->Status = CDC_RNDIS_STATUS_NOT_SUPPORTED;
|
|
Response->StsBufLength = 0U;
|
|
Response->StsBufOffset = 20U;
|
|
|
|
/* Set Response Ready field in order to send response during next control request */
|
|
hcdc->ResponseRdy = 1U;
|
|
|
|
/* Send Notification on Interrupt EP to inform Host that response is ready */
|
|
(void)USBD_CDC_RNDIS_SendNotification(pdev, RESPONSE_AVAILABLE, 0U, NULL);
|
|
|
|
UNUSED(Msg);
|
|
|
|
return (uint8_t)USBD_OK;
|
|
}
|
|
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/**
|
|
* @}
|
|
*/
|