mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-22 23:48:12 +00:00
579 lines
12 KiB
C
579 lines
12 KiB
C
/**
|
|
******************************************************************************
|
|
* @file usbd_core.c
|
|
* @author MCD Application Team
|
|
* @version V2.4.2
|
|
* @date 11-December-2015
|
|
* @brief This file provides all the USBD core functions.
|
|
******************************************************************************
|
|
* @attention
|
|
*
|
|
* <h2><center>© COPYRIGHT 2015 STMicroelectronics</center></h2>
|
|
*
|
|
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
|
|
* You may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at:
|
|
*
|
|
* http://www.st.com/software_license_agreement_liberty_v2
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
******************************************************************************
|
|
*/
|
|
|
|
/* Includes ------------------------------------------------------------------*/
|
|
#include "usbd_core.h"
|
|
|
|
/** @addtogroup STM32_USBD_DEVICE_LIBRARY
|
|
* @{
|
|
*/
|
|
|
|
|
|
/** @defgroup USBD_CORE
|
|
* @brief usbd core module
|
|
* @{
|
|
*/
|
|
|
|
/** @defgroup USBD_CORE_Private_TypesDefinitions
|
|
* @{
|
|
*/
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
|
|
/** @defgroup USBD_CORE_Private_Defines
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
|
|
/** @defgroup USBD_CORE_Private_Macros
|
|
* @{
|
|
*/
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
|
|
|
|
|
|
/** @defgroup USBD_CORE_Private_FunctionPrototypes
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/** @defgroup USBD_CORE_Private_Variables
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/** @defgroup USBD_CORE_Private_Functions
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* @brief USBD_Init
|
|
* Initializes the device stack and load the class driver
|
|
* @param pdev: device instance
|
|
* @param pdesc: Descriptor structure address
|
|
* @param id: Low level core index
|
|
* @retval None
|
|
*/
|
|
USBD_StatusTypeDef USBD_Init(USBD_HandleTypeDef *pdev, USBD_DescriptorsTypeDef *pdesc, uint8_t id)
|
|
{
|
|
/* Check whether the USB Host handle is valid */
|
|
if(pdev == NULL)
|
|
{
|
|
USBD_ErrLog("Invalid Device handle");
|
|
return USBD_FAIL;
|
|
}
|
|
|
|
/* Unlink previous class*/
|
|
if(pdev->pClass != NULL)
|
|
{
|
|
pdev->pClass = NULL;
|
|
}
|
|
|
|
/* Assign USBD Descriptors */
|
|
if(pdesc != NULL)
|
|
{
|
|
pdev->pDesc = pdesc;
|
|
}
|
|
|
|
/* Set Device initial State */
|
|
pdev->dev_state = USBD_STATE_DEFAULT;
|
|
pdev->id = id;
|
|
/* Initialize low level driver */
|
|
USBD_LL_Init(pdev);
|
|
|
|
return USBD_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief USBD_DeInit
|
|
* Re-Initialize th device library
|
|
* @param pdev: device instance
|
|
* @retval status: status
|
|
*/
|
|
USBD_StatusTypeDef USBD_DeInit(USBD_HandleTypeDef *pdev)
|
|
{
|
|
/* Set Default State */
|
|
pdev->dev_state = USBD_STATE_DEFAULT;
|
|
|
|
/* Free Class Resources */
|
|
pdev->pClass->DeInit(pdev, pdev->dev_config);
|
|
|
|
/* Stop the low level driver */
|
|
USBD_LL_Stop(pdev);
|
|
|
|
/* Initialize low level driver */
|
|
USBD_LL_DeInit(pdev);
|
|
|
|
return USBD_OK;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief USBD_RegisterClass
|
|
* Link class driver to Device Core.
|
|
* @param pDevice : Device Handle
|
|
* @param pclass: Class handle
|
|
* @retval USBD Status
|
|
*/
|
|
USBD_StatusTypeDef USBD_RegisterClass(USBD_HandleTypeDef *pdev, USBD_ClassTypeDef *pclass)
|
|
{
|
|
USBD_StatusTypeDef status = USBD_OK;
|
|
if(pclass != 0)
|
|
{
|
|
/* link the class to the USB Device handle */
|
|
pdev->pClass = pclass;
|
|
status = USBD_OK;
|
|
}
|
|
else
|
|
{
|
|
USBD_ErrLog("Invalid Class handle");
|
|
status = USBD_FAIL;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* @brief USBD_Start
|
|
* Start the USB Device Core.
|
|
* @param pdev: Device Handle
|
|
* @retval USBD Status
|
|
*/
|
|
USBD_StatusTypeDef USBD_Start (USBD_HandleTypeDef *pdev)
|
|
{
|
|
|
|
/* Start the low level driver */
|
|
USBD_LL_Start(pdev);
|
|
|
|
return USBD_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief USBD_Stop
|
|
* Stop the USB Device Core.
|
|
* @param pdev: Device Handle
|
|
* @retval USBD Status
|
|
*/
|
|
USBD_StatusTypeDef USBD_Stop (USBD_HandleTypeDef *pdev)
|
|
{
|
|
/* Free Class Resources */
|
|
pdev->pClass->DeInit(pdev, pdev->dev_config);
|
|
|
|
/* Stop the low level driver */
|
|
USBD_LL_Stop(pdev);
|
|
|
|
return USBD_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief USBD_RunTestMode
|
|
* Launch test mode process
|
|
* @param pdev: device instance
|
|
* @retval status
|
|
*/
|
|
USBD_StatusTypeDef USBD_RunTestMode (USBD_HandleTypeDef *pdev)
|
|
{
|
|
return USBD_OK;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief USBD_SetClassConfig
|
|
* Configure device and start the interface
|
|
* @param pdev: device instance
|
|
* @param cfgidx: configuration index
|
|
* @retval status
|
|
*/
|
|
|
|
USBD_StatusTypeDef USBD_SetClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
|
|
{
|
|
USBD_StatusTypeDef ret = USBD_FAIL;
|
|
|
|
if(pdev->pClass != NULL)
|
|
{
|
|
/* Set configuration and Start the Class*/
|
|
if(pdev->pClass->Init(pdev, cfgidx) == 0)
|
|
{
|
|
ret = USBD_OK;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief USBD_ClrClassConfig
|
|
* Clear current configuration
|
|
* @param pdev: device instance
|
|
* @param cfgidx: configuration index
|
|
* @retval status: USBD_StatusTypeDef
|
|
*/
|
|
USBD_StatusTypeDef USBD_ClrClassConfig(USBD_HandleTypeDef *pdev, uint8_t cfgidx)
|
|
{
|
|
/* Clear configuration and De-initialize the Class process*/
|
|
pdev->pClass->DeInit(pdev, cfgidx);
|
|
return USBD_OK;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief USBD_SetupStage
|
|
* Handle the setup stage
|
|
* @param pdev: device instance
|
|
* @retval status
|
|
*/
|
|
USBD_StatusTypeDef USBD_LL_SetupStage(USBD_HandleTypeDef *pdev, uint8_t *psetup)
|
|
{
|
|
|
|
USBD_ParseSetupRequest(&pdev->request, psetup);
|
|
|
|
pdev->ep0_state = USBD_EP0_SETUP;
|
|
pdev->ep0_data_len = pdev->request.wLength;
|
|
|
|
switch (pdev->request.bmRequest & USB_REQ_TYPE_MASK)
|
|
{
|
|
case USB_REQ_TYPE_STANDARD:
|
|
case USB_REQ_TYPE_CLASS:
|
|
switch (pdev->request.bmRequest & USB_REQ_RECIPIENT_MASK)
|
|
{
|
|
case USB_REQ_RECIPIENT_DEVICE:
|
|
USBD_StdDevReq(pdev, &pdev->request);
|
|
break;
|
|
case USB_REQ_RECIPIENT_INTERFACE:
|
|
USBD_StdItfReq(pdev, &pdev->request);
|
|
break;
|
|
case USB_REQ_RECIPIENT_ENDPOINT:
|
|
USBD_StdEPReq(pdev, &pdev->request);
|
|
break;
|
|
default:
|
|
USBD_LL_StallEP(pdev, pdev->request.bmRequest & 0x80);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case USB_REQ_TYPE_VENDOR:
|
|
if (pdev->dev_state == USBD_STATE_CONFIGURED || pdev->dev_state == USBD_STATE_ADDRESSED) {
|
|
if (pdev->pClass->Setup != NULL)
|
|
pdev->pClass->Setup(pdev, &pdev->request);
|
|
} else {
|
|
USBD_CtlError(pdev, &pdev->request);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return USBD_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief USBD_DataOutStage
|
|
* Handle data OUT stage
|
|
* @param pdev: device instance
|
|
* @param epnum: endpoint index
|
|
* @retval status
|
|
*/
|
|
USBD_StatusTypeDef USBD_LL_DataOutStage(USBD_HandleTypeDef *pdev , uint8_t epnum, uint8_t *pdata)
|
|
{
|
|
USBD_EndpointTypeDef *pep;
|
|
|
|
if(epnum == 0)
|
|
{
|
|
pep = &pdev->ep_out[0];
|
|
|
|
if ( pdev->ep0_state == USBD_EP0_DATA_OUT)
|
|
{
|
|
if(pep->rem_length > pep->maxpacket)
|
|
{
|
|
pep->rem_length -= pep->maxpacket;
|
|
|
|
USBD_CtlContinueRx (pdev,
|
|
pdata,
|
|
MIN(pep->rem_length ,pep->maxpacket));
|
|
}
|
|
else
|
|
{
|
|
if((pdev->pClass->EP0_RxReady != NULL)&&
|
|
(pdev->dev_state == USBD_STATE_CONFIGURED))
|
|
{
|
|
pdev->pClass->EP0_RxReady(pdev);
|
|
}
|
|
USBD_CtlSendStatus(pdev);
|
|
}
|
|
}
|
|
}
|
|
else if((pdev->pClass->DataOut != NULL)&&
|
|
(pdev->dev_state == USBD_STATE_CONFIGURED))
|
|
{
|
|
pdev->pClass->DataOut(pdev, epnum);
|
|
}
|
|
return USBD_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief USBD_DataInStage
|
|
* Handle data in stage
|
|
* @param pdev: device instance
|
|
* @param epnum: endpoint index
|
|
* @retval status
|
|
*/
|
|
USBD_StatusTypeDef USBD_LL_DataInStage(USBD_HandleTypeDef *pdev ,uint8_t epnum, uint8_t *pdata)
|
|
{
|
|
USBD_EndpointTypeDef *pep;
|
|
|
|
if(epnum == 0)
|
|
{
|
|
pep = &pdev->ep_in[0];
|
|
|
|
if ( pdev->ep0_state == USBD_EP0_DATA_IN)
|
|
{
|
|
if(pep->rem_length > pep->maxpacket)
|
|
{
|
|
pep->rem_length -= pep->maxpacket;
|
|
|
|
USBD_CtlContinueSendData (pdev,
|
|
pdata,
|
|
pep->rem_length);
|
|
|
|
/* Prepare endpoint for premature end of transfer */
|
|
USBD_LL_PrepareReceive (pdev,
|
|
0,
|
|
NULL,
|
|
0);
|
|
}
|
|
else
|
|
{ /* last packet is MPS multiple, so send ZLP packet */
|
|
if((pep->total_length % pep->maxpacket == 0) &&
|
|
(pep->total_length >= pep->maxpacket) &&
|
|
(pep->total_length < pdev->ep0_data_len ))
|
|
{
|
|
|
|
USBD_CtlContinueSendData(pdev , NULL, 0);
|
|
pdev->ep0_data_len = 0;
|
|
|
|
/* Prepare endpoint for premature end of transfer */
|
|
USBD_LL_PrepareReceive (pdev,
|
|
0,
|
|
NULL,
|
|
0);
|
|
}
|
|
else
|
|
{
|
|
if((pdev->pClass->EP0_TxSent != NULL)&&
|
|
(pdev->dev_state == USBD_STATE_CONFIGURED))
|
|
{
|
|
pdev->pClass->EP0_TxSent(pdev);
|
|
}
|
|
USBD_CtlReceiveStatus(pdev);
|
|
}
|
|
}
|
|
}
|
|
if (pdev->dev_test_mode == 1)
|
|
{
|
|
USBD_RunTestMode(pdev);
|
|
pdev->dev_test_mode = 0;
|
|
}
|
|
}
|
|
else if((pdev->pClass->DataIn != NULL)&&
|
|
(pdev->dev_state == USBD_STATE_CONFIGURED))
|
|
{
|
|
pdev->pClass->DataIn(pdev, epnum);
|
|
}
|
|
return USBD_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief USBD_LL_Reset
|
|
* Handle Reset event
|
|
* @param pdev: device instance
|
|
* @retval status
|
|
*/
|
|
|
|
USBD_StatusTypeDef USBD_LL_Reset(USBD_HandleTypeDef *pdev)
|
|
{
|
|
/* Open EP0 OUT */
|
|
USBD_LL_OpenEP(pdev,
|
|
0x00,
|
|
USBD_EP_TYPE_CTRL,
|
|
USB_MAX_EP0_SIZE);
|
|
|
|
pdev->ep_out[0].maxpacket = USB_MAX_EP0_SIZE;
|
|
|
|
/* Open EP0 IN */
|
|
USBD_LL_OpenEP(pdev,
|
|
0x80,
|
|
USBD_EP_TYPE_CTRL,
|
|
USB_MAX_EP0_SIZE);
|
|
|
|
pdev->ep_in[0].maxpacket = USB_MAX_EP0_SIZE;
|
|
/* Upon Reset call user call back */
|
|
pdev->dev_state = USBD_STATE_DEFAULT;
|
|
|
|
if (pdev->pClassData)
|
|
pdev->pClass->DeInit(pdev, pdev->dev_config);
|
|
|
|
|
|
return USBD_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
* @brief USBD_LL_Reset
|
|
* Handle Reset event
|
|
* @param pdev: device instance
|
|
* @retval status
|
|
*/
|
|
USBD_StatusTypeDef USBD_LL_SetSpeed(USBD_HandleTypeDef *pdev, USBD_SpeedTypeDef speed)
|
|
{
|
|
pdev->dev_speed = speed;
|
|
return USBD_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief USBD_Suspend
|
|
* Handle Suspend event
|
|
* @param pdev: device instance
|
|
* @retval status
|
|
*/
|
|
|
|
USBD_StatusTypeDef USBD_LL_Suspend(USBD_HandleTypeDef *pdev)
|
|
{
|
|
pdev->dev_old_state = pdev->dev_state;
|
|
pdev->dev_state = USBD_STATE_SUSPENDED;
|
|
return USBD_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief USBD_Resume
|
|
* Handle Resume event
|
|
* @param pdev: device instance
|
|
* @retval status
|
|
*/
|
|
|
|
USBD_StatusTypeDef USBD_LL_Resume(USBD_HandleTypeDef *pdev)
|
|
{
|
|
pdev->dev_state = pdev->dev_old_state;
|
|
return USBD_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief USBD_SOF
|
|
* Handle SOF event
|
|
* @param pdev: device instance
|
|
* @retval status
|
|
*/
|
|
|
|
USBD_StatusTypeDef USBD_LL_SOF(USBD_HandleTypeDef *pdev)
|
|
{
|
|
if(pdev->dev_state == USBD_STATE_CONFIGURED)
|
|
{
|
|
if(pdev->pClass->SOF != NULL)
|
|
{
|
|
pdev->pClass->SOF(pdev);
|
|
}
|
|
}
|
|
return USBD_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief USBD_IsoINIncomplete
|
|
* Handle iso in incomplete event
|
|
* @param pdev: device instance
|
|
* @retval status
|
|
*/
|
|
USBD_StatusTypeDef USBD_LL_IsoINIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum)
|
|
{
|
|
return USBD_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief USBD_IsoOUTIncomplete
|
|
* Handle iso out incomplete event
|
|
* @param pdev: device instance
|
|
* @retval status
|
|
*/
|
|
USBD_StatusTypeDef USBD_LL_IsoOUTIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum)
|
|
{
|
|
return USBD_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief USBD_DevConnected
|
|
* Handle device connection event
|
|
* @param pdev: device instance
|
|
* @retval status
|
|
*/
|
|
USBD_StatusTypeDef USBD_LL_DevConnected(USBD_HandleTypeDef *pdev)
|
|
{
|
|
return USBD_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief USBD_DevDisconnected
|
|
* Handle device disconnection event
|
|
* @param pdev: device instance
|
|
* @retval status
|
|
*/
|
|
USBD_StatusTypeDef USBD_LL_DevDisconnected(USBD_HandleTypeDef *pdev)
|
|
{
|
|
/* Free Class Resources */
|
|
pdev->dev_state = USBD_STATE_DEFAULT;
|
|
pdev->pClass->DeInit(pdev, pdev->dev_config);
|
|
|
|
return USBD_OK;
|
|
}
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
|
|