/** ****************************************************************************** * @file usbd_core.c * @author MCD Application Team * @version V2.4.1 * @date 19-June-2015 * @brief This file provides all the USBD core functions. ****************************************************************************** * @attention * *

© COPYRIGHT 2015 STMicroelectronics

* * 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" #include "usbd_descriptors.h" #include "upstream_statemachine.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*/ pdev->pClass = NULL; pdev->pClassData = 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); pdev->usbCoreStatus = USB_STATUS_STOP; return USBD_OK; } /** * @brief USBD_DeInit * Re-Initialize th device library * @param pdev: device instance * @retval status: status */ USBD_ClassTypeDef* 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); /* Deinitialize low level driver */ USBD_LL_DeInit(pdev); return pdev->pClass; // 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; USBD_FS_DeviceDesc[USBD_PID_LOBYTE_OFFSET] = LOBYTE(pclass->USBDevPid); USBD_FS_DeviceDesc[USBD_PID_HIBYTE_OFFSET] = HIBYTE(pclass->USBDevPid); 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); pdev->usbCoreStatus = USB_STATUS_START; pdev->dev_state = USBD_STATE_DEFAULT; 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); pdev->usbCoreStatus = USB_STATUS_STOP; return USBD_OK; } /** * @brief USBD_RunTestMode * Launch test mode process * @param pdev: device instance * @retval status */ USBD_StatusTypeDef USBD_RunTestMode (USBD_HandleTypeDef *pdev) { UNUSED(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_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 & 0x1F) { 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; } return USBD_OK; } /** * @brief USBD_DataOutStage * Handle data OUT stage * @param pdev: device instance * @param epnum: endpoint index * @retval status */ USBD_StatusTypeDef USBD_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, pep->rem_length); } 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_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); } else { //We sent less data than host was expecting? /* 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; } 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_Reset * Handle Reset event * @param pdev: device instance * @retval status */ USBD_StatusTypeDef USBD_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_SetSpeed * Handle Reset event * @param pdev: device instance * @retval status */ USBD_StatusTypeDef USBD_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_Suspend(USBD_HandleTypeDef *pdev) { if ((pdev->dev_state > USBD_STATE_DEFAULT) && (pdev->dev_state < USBD_STATE_SUSPENDED)) { pdev->dev_old_state = pdev->dev_state; pdev->dev_state = USBD_STATE_SUSPENDED; Upstream_StateMachine_Suspend(); } return USBD_OK; } /** * @brief USBD_Resume * Handle Resume event * @param pdev: device instance * @retval status */ USBD_StatusTypeDef USBD_Resume(USBD_HandleTypeDef *pdev) { pdev->dev_state = pdev->dev_old_state; if (pdev->dev_old_state > USBD_STATE_DEFAULT) { Upstream_StateMachine_CheckResume(); } return USBD_OK; } /** * @brief USBD_SOF * Handle SOF event * @param pdev: device instance * @retval status */ USBD_StatusTypeDef USBD_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_IsoINIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum) { UNUSED(pdev); return USBD_OK; } /** * @brief USBD_IsoOUTIncomplete * Handle iso out incomplete event * @param pdev: device instance * @retval status */ USBD_StatusTypeDef USBD_IsoOUTIncomplete(USBD_HandleTypeDef *pdev, uint8_t epnum) { UNUSED(pdev); return USBD_OK; } /** * @brief USBD_DevConnected * Handle device connection event * @param pdev: device instance * @retval status */ USBD_StatusTypeDef USBD_DevConnected(USBD_HandleTypeDef *pdev) { UNUSED(pdev); return USBD_OK; } /** * @brief USBD_DevDisconnected * Handle device disconnection event * @param pdev: device instance * @retval status */ USBD_StatusTypeDef USBD_DevDisconnected(USBD_HandleTypeDef *pdev) { /* Free Class Resources */ pdev->dev_state = USBD_STATE_DEFAULT; pdev->pClass->DeInit(pdev, pdev->dev_config); return USBD_OK; } USBD_StatusTypeDef USBD_BufferFreed(USBD_HandleTypeDef *pdev) { if(pdev->pClass->FreeDataBuffer != NULL) { pdev->pClass->FreeDataBuffer(pdev); } return USBD_OK; } /** * @} */ /** * @} */ /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/