/** ****************************************************************************** * @file usbd_core.c * @author MCD Application Team * @version V1.1.0 * @date 19-March-2012 * @brief This file provides all the USBD core functions. ****************************************************************************** * @attention * *

© COPYRIGHT 2012 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_req.h" #include "usbd_ioreq.h" #include "usb_dcd_int.h" #include "usb_bsp.h" /** @addtogroup STM32_USB_OTG_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 * @{ */ static uint8_t USBD_SetupStage(USB_OTG_CORE_HANDLE *pdev); static uint8_t USBD_DataOutStage(USB_OTG_CORE_HANDLE *pdev , uint8_t epnum); static uint8_t USBD_DataInStage(USB_OTG_CORE_HANDLE *pdev , uint8_t epnum); static uint8_t USBD_SOF(USB_OTG_CORE_HANDLE *pdev); static uint8_t USBD_Reset(USB_OTG_CORE_HANDLE *pdev); static uint8_t USBD_Suspend(USB_OTG_CORE_HANDLE *pdev); static uint8_t USBD_Resume(USB_OTG_CORE_HANDLE *pdev); #ifdef VBUS_SENSING_ENABLED static uint8_t USBD_DevConnected(USB_OTG_CORE_HANDLE *pdev); static uint8_t USBD_DevDisconnected(USB_OTG_CORE_HANDLE *pdev); #endif static uint8_t USBD_IsoINIncomplete(USB_OTG_CORE_HANDLE *pdev); static uint8_t USBD_IsoOUTIncomplete(USB_OTG_CORE_HANDLE *pdev); static uint8_t USBD_RunTestMode (USB_OTG_CORE_HANDLE *pdev) ; /** * @} */ /** @defgroup USBD_CORE_Private_Variables * @{ */ __IO USB_OTG_DCTL_TypeDef SET_TEST_MODE; USBD_DCD_INT_cb_TypeDef USBD_DCD_INT_cb = { USBD_DataOutStage, USBD_DataInStage, USBD_SetupStage, USBD_SOF, USBD_Reset, USBD_Suspend, USBD_Resume, USBD_IsoINIncomplete, USBD_IsoOUTIncomplete, #ifdef VBUS_SENSING_ENABLED USBD_DevConnected, USBD_DevDisconnected, #endif }; USBD_DCD_INT_cb_TypeDef *USBD_DCD_INT_fops = &USBD_DCD_INT_cb; /** * @} */ /** @defgroup USBD_CORE_Private_Functions * @{ */ /** * @brief USBD_Init * Initailizes the device stack and load the class driver * @param pdev: device instance * @param core_address: USB OTG core ID * @param class_cb: Class callback structure address * @param usr_cb: User callback structure address * @retval None */ void USBD_Init(USB_OTG_CORE_HANDLE *pdev, USB_OTG_CORE_ID_TypeDef coreID, USBD_DEVICE *pDevice, USBD_Class_cb_TypeDef *class_cb, USBD_Usr_cb_TypeDef *usr_cb) { /* Hardware Init */ USB_OTG_BSP_Init(pdev); USBD_DeInit(pdev); /*Register class and user callbacks */ pdev->dev.class_cb = class_cb; pdev->dev.usr_cb = usr_cb; pdev->dev.usr_device = pDevice; /* set USB OTG core params */ DCD_Init(pdev , coreID); /* Upon Init call usr callback */ pdev->dev.usr_cb->Init(); /* Enable Interrupts */ USB_OTG_BSP_EnableInterrupt(pdev); } /** * @brief USBD_DeInit * Re-Initialize th device library * @param pdev: device instance * @retval status: status */ USBD_Status USBD_DeInit(USB_OTG_CORE_HANDLE *pdev) { /* Software Init */ return USBD_OK; } /** * @brief USBD_SetupStage * Handle the setup stage * @param pdev: device instance * @retval status */ static uint8_t USBD_SetupStage(USB_OTG_CORE_HANDLE *pdev) { USB_SETUP_REQ req; USBD_ParseSetupRequest(pdev , &req); switch (req.bmRequest & 0x1F) { case USB_REQ_RECIPIENT_DEVICE: USBD_StdDevReq (pdev, &req); break; case USB_REQ_RECIPIENT_INTERFACE: USBD_StdItfReq(pdev, &req); break; case USB_REQ_RECIPIENT_ENDPOINT: USBD_StdEPReq(pdev, &req); break; default: DCD_EP_Stall(pdev , req.bmRequest & 0x80); break; } return USBD_OK; } /** * @brief USBD_DataOutStage * Handle data out stage * @param pdev: device instance * @param epnum: endpoint index * @retval status */ static uint8_t USBD_DataOutStage(USB_OTG_CORE_HANDLE *pdev , uint8_t epnum) { USB_OTG_EP *ep; if(epnum == 0) { ep = &pdev->dev.out_ep[0]; if ( pdev->dev.device_state == USB_OTG_EP0_DATA_OUT) { if(ep->rem_data_len > ep->maxpacket) { ep->rem_data_len -= ep->maxpacket; if(pdev->cfg.dma_enable == 1) { /* in slave mode this, is handled by the RxSTSQLvl ISR */ ep->xfer_buff += ep->maxpacket; } USBD_CtlContinueRx (pdev, ep->xfer_buff, MIN(ep->rem_data_len ,ep->maxpacket)); } else { if((pdev->dev.class_cb->EP0_RxReady != NULL)&& (pdev->dev.device_status == USB_OTG_CONFIGURED)) { pdev->dev.class_cb->EP0_RxReady(pdev); } USBD_CtlSendStatus(pdev); } } } else if((pdev->dev.class_cb->DataOut != NULL)&& (pdev->dev.device_status == USB_OTG_CONFIGURED)) { pdev->dev.class_cb->DataOut(pdev, epnum); } return USBD_OK; } /** * @brief USBD_DataInStage * Handle data in stage * @param pdev: device instance * @param epnum: endpoint index * @retval status */ static uint8_t USBD_DataInStage(USB_OTG_CORE_HANDLE *pdev , uint8_t epnum) { USB_OTG_EP *ep; if(epnum == 0) { ep = &pdev->dev.in_ep[0]; if ( pdev->dev.device_state == USB_OTG_EP0_DATA_IN) { if(ep->rem_data_len > ep->maxpacket) { ep->rem_data_len -= ep->maxpacket; if(pdev->cfg.dma_enable == 1) { /* in slave mode this, is handled by the TxFifoEmpty ISR */ ep->xfer_buff += ep->maxpacket; } USBD_CtlContinueSendData (pdev, ep->xfer_buff, ep->rem_data_len); } else { /* last packet is MPS multiple, so send ZLP packet */ if((ep->total_data_len % ep->maxpacket == 0) && (ep->total_data_len >= ep->maxpacket) && (ep->total_data_len < ep->ctl_data_len )) { USBD_CtlContinueSendData(pdev , NULL, 0); ep->ctl_data_len = 0; } else { if((pdev->dev.class_cb->EP0_TxSent != NULL)&& (pdev->dev.device_status == USB_OTG_CONFIGURED)) { pdev->dev.class_cb->EP0_TxSent(pdev); } USBD_CtlReceiveStatus(pdev); } } } if (pdev->dev.test_mode == 1) { USBD_RunTestMode(pdev); pdev->dev.test_mode = 0; } } else if((pdev->dev.class_cb->DataIn != NULL)&& (pdev->dev.device_status == USB_OTG_CONFIGURED)) { pdev->dev.class_cb->DataIn(pdev, epnum); } return USBD_OK; } /** * @brief USBD_RunTestMode * Launch test mode process * @param pdev: device instance * @retval status */ static uint8_t USBD_RunTestMode (USB_OTG_CORE_HANDLE *pdev) { USB_OTG_WRITE_REG32(&pdev->regs.DREGS->DCTL, SET_TEST_MODE.d32); return USBD_OK; } /** * @brief USBD_Reset * Handle Reset event * @param pdev: device instance * @retval status */ static uint8_t USBD_Reset(USB_OTG_CORE_HANDLE *pdev) { /* Open EP0 OUT */ DCD_EP_Open(pdev, 0x00, USB_OTG_MAX_EP0_SIZE, EP_TYPE_CTRL); /* Open EP0 IN */ DCD_EP_Open(pdev, 0x80, USB_OTG_MAX_EP0_SIZE, EP_TYPE_CTRL); /* Upon Reset call usr call back */ pdev->dev.device_status = USB_OTG_DEFAULT; pdev->dev.usr_cb->DeviceReset(pdev->cfg.speed); return USBD_OK; } /** * @brief USBD_Resume * Handle Resume event * @param pdev: device instance * @retval status */ static uint8_t USBD_Resume(USB_OTG_CORE_HANDLE *pdev) { /* Upon Resume call usr call back */ pdev->dev.usr_cb->DeviceResumed(); pdev->dev.device_status = pdev->dev.device_old_status; pdev->dev.device_status = USB_OTG_CONFIGURED; return USBD_OK; } /** * @brief USBD_Suspend * Handle Suspend event * @param pdev: device instance * @retval status */ static uint8_t USBD_Suspend(USB_OTG_CORE_HANDLE *pdev) { pdev->dev.device_old_status = pdev->dev.device_status; pdev->dev.device_status = USB_OTG_SUSPENDED; /* Upon Resume call usr call back */ pdev->dev.usr_cb->DeviceSuspended(); return USBD_OK; } /** * @brief USBD_SOF * Handle SOF event * @param pdev: device instance * @retval status */ static uint8_t USBD_SOF(USB_OTG_CORE_HANDLE *pdev) { if(pdev->dev.class_cb->SOF) { pdev->dev.class_cb->SOF(pdev); } return USBD_OK; } /** * @brief USBD_SetCfg * Configure device and start the interface * @param pdev: device instance * @param cfgidx: configuration index * @retval status */ USBD_Status USBD_SetCfg(USB_OTG_CORE_HANDLE *pdev, uint8_t cfgidx) { pdev->dev.class_cb->Init(pdev, cfgidx); /* Upon set config call usr call back */ pdev->dev.usr_cb->DeviceConfigured(); return USBD_OK; } /** * @brief USBD_ClrCfg * Clear current configuration * @param pdev: device instance * @param cfgidx: configuration index * @retval status: USBD_Status */ USBD_Status USBD_ClrCfg(USB_OTG_CORE_HANDLE *pdev, uint8_t cfgidx) { pdev->dev.class_cb->DeInit(pdev, cfgidx); return USBD_OK; } /** * @brief USBD_IsoINIncomplete * Handle iso in incomplete event * @param pdev: device instance * @retval status */ static uint8_t USBD_IsoINIncomplete(USB_OTG_CORE_HANDLE *pdev) { pdev->dev.class_cb->IsoINIncomplete(pdev); return USBD_OK; } /** * @brief USBD_IsoOUTIncomplete * Handle iso out incomplete event * @param pdev: device instance * @retval status */ static uint8_t USBD_IsoOUTIncomplete(USB_OTG_CORE_HANDLE *pdev) { pdev->dev.class_cb->IsoOUTIncomplete(pdev); return USBD_OK; } #ifdef VBUS_SENSING_ENABLED /** * @brief USBD_DevConnected * Handle device connection event * @param pdev: device instance * @retval status */ static uint8_t USBD_DevConnected(USB_OTG_CORE_HANDLE *pdev) { pdev->dev.usr_cb->DeviceConnected(); pdev->dev.connection_status = 1; return USBD_OK; } /** * @brief USBD_DevDisconnected * Handle device disconnection event * @param pdev: device instance * @retval status */ static uint8_t USBD_DevDisconnected(USB_OTG_CORE_HANDLE *pdev) { pdev->dev.usr_cb->DeviceDisconnected(); pdev->dev.class_cb->DeInit(pdev, 0); pdev->dev.connection_status = 0; return USBD_OK; } #endif /** * @} */ /** * @} */ /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/