2 ******************************************************************************
4 * @author MCD Application Team
7 * @brief This file implements the functions for the core state machine process
8 * the enumeration and the control transfer process
9 ******************************************************************************
12 * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
13 * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
14 * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
15 * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
16 * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
17 * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
19 * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
20 ******************************************************************************
22 /* Includes ------------------------------------------------------------------*/
24 #include "usbh_ioreq.h"
27 #include "usbh_stdreq.h"
28 #include "usbh_core.h"
31 /** @addtogroup USBH_LIB
35 /** @addtogroup USBH_LIB_CORE
39 /** @defgroup USBH_CORE
40 * @brief TThis file handles the basic enumaration when a device is connected
45 /** @defgroup USBH_CORE_Private_TypesDefinitions
48 void USBH_Disconnect (void *pdev);
49 void USBH_Connect (void *pdev);
51 USB_OTG_hPort_TypeDef USBH_DeviceConnStatus_cb =
65 /** @defgroup USBH_CORE_Private_Defines
73 /** @defgroup USBH_CORE_Private_Macros
81 /** @defgroup USBH_CORE_Private_Variables
89 /** @defgroup USBH_CORE_Private_FunctionPrototypes
92 static USBH_Status USBH_HandleEnum(USB_OTG_CORE_HANDLE *pdev, USBH_HOST *phost);
93 USBH_Status USBH_HandleControl (USB_OTG_CORE_HANDLE *pdev, USBH_HOST *phost);
100 /** @defgroup USBH_CORE_Private_Functions
106 * @brief USBH_Connect
107 * USB Connect callback function from the Interrupt.
108 * @param selected device
111 void USBH_Connect (void *pdev)
113 USB_OTG_CORE_HANDLE *ppdev = pdev;
114 ppdev->host.port_cb->ConnStatus = 1;
115 ppdev->host.port_cb->ConnHandled = 0;
119 * @brief USBH_Disconnect
120 * USB Disconnect callback function from the Interrupt.
121 * @param selected device
125 void USBH_Disconnect (void *pdev)
128 USB_OTG_CORE_HANDLE *ppdev = pdev;
130 /* Make device Not connected flag true */
131 ppdev->host.port_cb->DisconnStatus = 1;
132 ppdev->host.port_cb->DisconnHandled = 0;
137 * Host hardware and stack initializations
138 * @param class_cb: Class callback structure address
139 * @param usr_cb: User callback structure address
142 void USBH_Init(USB_OTG_CORE_HANDLE *pdev,
143 USB_OTG_CORE_ID_TypeDef coreID,
145 USBH_Class_cb_TypeDef *class_cb,
146 USBH_Usr_cb_TypeDef *usr_cb)
150 USB_OTG_BSP_Init(pdev);
152 /* configure GPIO pin used for switching VBUS power */
153 USB_OTG_BSP_ConfigVBUS(0);
156 /* Host de-initializations */
157 USBH_DeInit(pdev, phost);
159 /*Register class and user callbacks */
160 phost->class_cb = class_cb;
161 phost->usr_cb = usr_cb;
162 pdev->host.port_cb = &USBH_DeviceConnStatus_cb;
164 pdev->host.port_cb->ConnStatus = 0;
165 pdev->host.port_cb->DisconnStatus = 0;
168 /* Start the USB OTG core */
169 HCD_Init(pdev , coreID);
171 /* Upon Init call usr call back */
172 phost->usr_cb->Init();
174 /* Enable Interrupts */
175 USB_OTG_BSP_EnableInterrupt(pdev);
182 * @retval status: USBH_Status
184 USBH_Status USBH_DeInit(USB_OTG_CORE_HANDLE *pdev, USBH_HOST *phost)
188 phost->gState = HOST_IDLE;
189 phost->gStateBkp = HOST_IDLE;
190 phost->EnumState = ENUM_IDLE;
191 phost->RequestState = CMD_SEND;
193 phost->Control.state = CTRL_SETUP;
194 phost->Control.ep0size = USB_OTG_MAX_EP0_SIZE;
196 phost->device_prop.address = USBH_DEVICE_ADDRESS_DEFAULT;
197 phost->device_prop.speed = HPRT0_PRTSPD_FULL_SPEED;
199 USBH_Free_Channel (pdev, phost->Control.hc_num_in);
200 USBH_Free_Channel (pdev, phost->Control.hc_num_out);
205 * @brief USBH_Process
206 * USB Host core main state machine process
210 void USBH_Process(USB_OTG_CORE_HANDLE *pdev , USBH_HOST *phost)
212 volatile USBH_Status status = USBH_FAIL;
214 switch (phost->gState)
216 case HOST_ISSUE_CORE_RESET :
218 if ( HCD_ResetPort(pdev) == 0)
220 phost->gState = HOST_IDLE;
226 if (HCD_IsDeviceConnected(pdev))
228 /* Wait for USB Connect Interrupt void USBH_ISR_Connected(void) */
229 USBH_DeAllocate_AllChannel(pdev);
230 phost->gState = HOST_DEV_ATTACHED;
234 case HOST_DEV_ATTACHED :
236 phost->usr_cb->DeviceAttached();
237 pdev->host.port_cb->DisconnStatus = 0;
238 pdev->host.port_cb->ConnHandled = 1;
240 phost->Control.hc_num_out = USBH_Alloc_Channel(pdev, 0x00);
241 phost->Control.hc_num_in = USBH_Alloc_Channel(pdev, 0x80);
243 /* Reset USB Device */
244 if ( HCD_ResetPort(pdev) == 0)
246 phost->usr_cb->ResetDevice();
247 /* Wait for USB USBH_ISR_PrtEnDisableChange()
248 Host is Now ready to start the Enumeration
251 phost->device_prop.speed = HCD_GetCurrentSpeed(pdev);
253 phost->gState = HOST_ENUMERATION;
254 phost->usr_cb->DeviceSpeedDetected(phost->device_prop.speed);
256 /* Open Control pipes */
257 USBH_Open_Channel (pdev,
258 phost->Control.hc_num_in,
259 phost->device_prop.address,
260 phost->device_prop.speed,
262 phost->Control.ep0size);
264 /* Open Control pipes */
265 USBH_Open_Channel (pdev,
266 phost->Control.hc_num_out,
267 phost->device_prop.address,
268 phost->device_prop.speed,
270 phost->Control.ep0size);
274 case HOST_ENUMERATION:
275 /* Check for enumeration status */
276 if ( USBH_HandleEnum(pdev , phost) == USBH_OK)
278 /* The function shall return USBH_OK when full enumeration is complete */
280 /* user callback for end of device basic enumeration */
281 phost->usr_cb->EnumerationDone();
283 phost->gState = HOST_USR_INPUT;
288 /*The function should return user response true to move to class state */
289 if ( phost->usr_cb->UserInput() == USBH_USR_RESP_OK)
291 if((phost->class_cb->Init(pdev, phost))\
294 phost->gState = HOST_CLASS_REQUEST;
299 case HOST_CLASS_REQUEST:
300 /* process class standard contol requests state machine */
301 status = phost->class_cb->Requests(pdev, phost);
303 if(status == USBH_OK)
305 phost->gState = HOST_CLASS;
310 USBH_ErrorHandle(phost, status);
316 /* process class state machine */
317 status = phost->class_cb->Machine(pdev, phost);
318 USBH_ErrorHandle(phost, status);
322 /* process control transfer state machine */
323 USBH_HandleControl(pdev, phost);
329 case HOST_ERROR_STATE:
330 /* Re-Initilaize Host for new Enumeration */
331 USBH_DeInit(pdev, phost);
332 phost->usr_cb->DeInit();
333 phost->class_cb->DeInit(pdev, &phost->device_prop);
340 /* check device disconnection event */
341 if (!(HCD_IsDeviceConnected(pdev)) &&
342 (pdev->host.port_cb->DisconnHandled == 0))
344 /* Manage User disconnect operations*/
345 phost->usr_cb->DeviceDisconnected();
347 pdev->host.port_cb->DisconnHandled = 1; /* Handle to avoid the Re-entry*/
349 /* Re-Initilaize Host for new Enumeration */
350 USBH_DeInit(pdev, phost);
351 phost->usr_cb->DeInit();
352 phost->class_cb->DeInit(pdev, &phost->device_prop);
358 * @brief USBH_ErrorHandle
359 * This function handles the Error on Host side.
360 * @param errType : Type of Error or Busy/OK state
363 void USBH_ErrorHandle(USBH_HOST *phost, USBH_Status errType)
365 /* Error unrecovered or not supported device speed */
366 if ( (errType == USBH_ERROR_SPEED_UNKNOWN) ||
367 (errType == USBH_UNRECOVERED_ERROR) )
369 phost->usr_cb->UnrecoveredError();
370 phost->gState = HOST_ERROR_STATE;
372 /* USB host restart requested from application layer */
373 else if(errType == USBH_APPLY_DEINIT)
375 phost->gState = HOST_ERROR_STATE;
376 /* user callback for initalization */
377 phost->usr_cb->Init();
383 * @brief USBH_HandleEnum
384 * This function includes the complete enumeration process
385 * @param pdev: Selected device
386 * @retval USBH_Status
388 static USBH_Status USBH_HandleEnum(USB_OTG_CORE_HANDLE *pdev, USBH_HOST *phost)
390 USBH_Status Status = USBH_BUSY;
391 uint8_t Local_Buffer[64];
393 switch (phost->EnumState)
396 /* Get Device Desc for only 1st 8 bytes : To get EP0 MaxPacketSize */
397 if ( USBH_Get_DevDesc(pdev , phost, 8) == USBH_OK)
399 phost->Control.ep0size = phost->device_prop.Dev_Desc.bMaxPacketSize;
403 phost->EnumState = ENUM_GET_FULL_DEV_DESC;
405 /* modify control channels configuration for MaxPacket size */
406 USBH_Modify_Channel (pdev,
407 phost->Control.hc_num_out,
411 phost->Control.ep0size);
413 USBH_Modify_Channel (pdev,
414 phost->Control.hc_num_in,
418 phost->Control.ep0size);
422 case ENUM_GET_FULL_DEV_DESC:
423 /* Get FULL Device Desc */
424 if ( USBH_Get_DevDesc(pdev, phost, USB_DEVICE_DESC_SIZE)\
427 /* user callback for device descriptor available */
428 phost->usr_cb->DeviceDescAvailable(&phost->device_prop.Dev_Desc);
429 phost->EnumState = ENUM_SET_ADDR;
435 if ( USBH_SetAddress(pdev, phost, USBH_DEVICE_ADDRESS) == USBH_OK)
437 phost->device_prop.address = USBH_DEVICE_ADDRESS;
439 /* user callback for device address assigned */
440 phost->usr_cb->DeviceAddressAssigned();
441 phost->EnumState = ENUM_GET_CFG_DESC;
443 /* modify control channels to update device address */
444 USBH_Modify_Channel (pdev,
445 phost->Control.hc_num_in,
446 phost->device_prop.address,
451 USBH_Modify_Channel (pdev,
452 phost->Control.hc_num_out,
453 phost->device_prop.address,
460 case ENUM_GET_CFG_DESC:
461 /* get standard configuration descriptor */
462 if ( USBH_Get_CfgDesc(pdev,
464 USB_CONFIGURATION_DESC_SIZE) == USBH_OK)
466 phost->EnumState = ENUM_GET_FULL_CFG_DESC;
470 case ENUM_GET_FULL_CFG_DESC:
471 /* get FULL config descriptor (config, interface, endpoints) */
472 if (USBH_Get_CfgDesc(pdev,
474 phost->device_prop.Cfg_Desc.wTotalLength) == USBH_OK)
476 /* User callback for configuration descriptors available */
477 phost->usr_cb->ConfigurationDescAvailable(&phost->device_prop.Cfg_Desc,
478 phost->device_prop.Itf_Desc,
479 phost->device_prop.Ep_Desc[0]);
481 phost->EnumState = ENUM_GET_MFC_STRING_DESC;
485 case ENUM_GET_MFC_STRING_DESC:
486 if (phost->device_prop.Dev_Desc.iManufacturer != 0)
487 { /* Check that Manufacturer String is available */
489 if ( USBH_Get_StringDesc(pdev,
491 phost->device_prop.Dev_Desc.iManufacturer,
495 /* User callback for Manufacturing string */
496 phost->usr_cb->ManufacturerString(Local_Buffer);
497 phost->EnumState = ENUM_GET_PRODUCT_STRING_DESC;
502 phost->usr_cb->ManufacturerString("N/A");
503 phost->EnumState = ENUM_GET_PRODUCT_STRING_DESC;
507 case ENUM_GET_PRODUCT_STRING_DESC:
508 if (phost->device_prop.Dev_Desc.iProduct != 0)
509 { /* Check that Product string is available */
510 if ( USBH_Get_StringDesc(pdev,
512 phost->device_prop.Dev_Desc.iProduct,
516 /* User callback for Product string */
517 phost->usr_cb->ProductString(Local_Buffer);
518 phost->EnumState = ENUM_GET_SERIALNUM_STRING_DESC;
523 phost->usr_cb->ProductString("N/A");
524 phost->EnumState = ENUM_GET_SERIALNUM_STRING_DESC;
528 case ENUM_GET_SERIALNUM_STRING_DESC:
529 if (phost->device_prop.Dev_Desc.iSerialNumber != 0)
530 { /* Check that Serial number string is available */
531 if ( USBH_Get_StringDesc(pdev,
533 phost->device_prop.Dev_Desc.iSerialNumber,
537 /* User callback for Serial number string */
538 phost->usr_cb->SerialNumString(Local_Buffer);
539 phost->EnumState = ENUM_SET_CONFIGURATION;
544 phost->usr_cb->SerialNumString("N/A");
545 phost->EnumState = ENUM_SET_CONFIGURATION;
549 case ENUM_SET_CONFIGURATION:
550 /* set configuration (default config) */
551 if (USBH_SetCfg(pdev,
553 phost->device_prop.Cfg_Desc.bConfigurationValue) == USBH_OK)
555 phost->EnumState = ENUM_DEV_CONFIGURED;
560 case ENUM_DEV_CONFIGURED:
561 /* user callback for enumeration done */
573 * @brief USBH_HandleControl
574 * Handles the USB control transfer state machine
575 * @param pdev: Selected device
578 USBH_Status USBH_HandleControl (USB_OTG_CORE_HANDLE *pdev, USBH_HOST *phost)
581 static uint16_t timeout = 0;
582 USBH_Status status = USBH_OK;
583 URB_STATE URB_Status = URB_IDLE;
585 phost->Control.status = CTRL_START;
588 switch (phost->Control.state)
591 /* send a SETUP packet */
592 USBH_CtlSendSetup (pdev,
593 phost->Control.setup.d8 ,
594 phost->Control.hc_num_out);
595 phost->Control.state = CTRL_SETUP_WAIT;
598 case CTRL_SETUP_WAIT:
600 URB_Status = HCD_GetURB_State(pdev , phost->Control.hc_num_out);
601 /* case SETUP packet sent successfully */
602 if(URB_Status == URB_DONE)
604 direction = (phost->Control.setup.b.bmRequestType & USB_REQ_DIR_MASK);
606 /* check if there is a data stage */
607 if (phost->Control.setup.b.wLength.w != 0 )
609 timeout = DATA_STAGE_TIMEOUT;
610 if (direction == USB_D2H)
612 /* Data Direction is IN */
613 phost->Control.state = CTRL_DATA_IN;
617 /* Data Direction is OUT */
618 phost->Control.state = CTRL_DATA_OUT;
624 timeout = NODATA_STAGE_TIMEOUT;
626 /* If there is No Data Transfer Stage */
627 if (direction == USB_D2H)
629 /* Data Direction is IN */
630 phost->Control.state = CTRL_STATUS_OUT;
634 /* Data Direction is OUT */
635 phost->Control.state = CTRL_STATUS_IN;
638 /* Set the delay timer to enable timeout for data stage completion */
639 phost->Control.timer = HCD_GetCurrentFrame(pdev);
641 else if(URB_Status == URB_ERROR)
643 phost->Control.state = CTRL_ERROR;
644 phost->Control.status = CTRL_XACTERR;
649 /* Issue an IN token */
650 USBH_CtlReceiveData(pdev,
652 phost->Control.length,
653 phost->Control.hc_num_in);
655 phost->Control.state = CTRL_DATA_IN_WAIT;
658 case CTRL_DATA_IN_WAIT:
660 URB_Status = HCD_GetURB_State(pdev , phost->Control.hc_num_in);
662 /* check is DATA packet transfered successfully */
663 if (URB_Status == URB_DONE)
665 phost->Control.state = CTRL_STATUS_OUT;
668 /* manage error cases*/
669 if (URB_Status == URB_STALL)
671 /* In stall case, return to previous machine state*/
672 phost->gState = phost->gStateBkp;
674 else if (URB_Status == URB_ERROR)
677 phost->Control.state = CTRL_ERROR;
679 else if ((HCD_GetCurrentFrame(pdev)- phost->Control.timer) > timeout)
681 /* timeout for IN transfer */
682 phost->Control.state = CTRL_ERROR;
687 /* Start DATA out transfer (only one DATA packet)*/
689 pdev->host.hc[phost->Control.hc_num_out].toggle_out ^= 1;
691 USBH_CtlSendData (pdev,
693 phost->Control.length ,
694 phost->Control.hc_num_out);
696 phost->Control.state = CTRL_DATA_OUT_WAIT;
699 case CTRL_DATA_OUT_WAIT:
701 URB_Status = HCD_GetURB_State(pdev , phost->Control.hc_num_out);
702 if (URB_Status == URB_DONE)
703 { /* If the Setup Pkt is sent successful, then change the state */
704 phost->Control.state = CTRL_STATUS_IN;
707 /* handle error cases */
708 else if (URB_Status == URB_STALL)
710 /* In stall case, return to previous machine state*/
711 phost->gState = phost->gStateBkp;
713 else if (URB_Status == URB_NOTREADY)
715 /* Nack received from device */
716 phost->Control.state = CTRL_DATA_OUT;
718 else if (URB_Status == URB_ERROR)
721 phost->Control.state = CTRL_ERROR;
727 /* Send 0 bytes out packet */
728 USBH_CtlReceiveData (pdev,
731 phost->Control.hc_num_in);
733 phost->Control.state = CTRL_STATUS_IN_WAIT;
737 case CTRL_STATUS_IN_WAIT:
739 URB_Status = HCD_GetURB_State(pdev , phost->Control.hc_num_in);
741 if ( URB_Status == URB_DONE)
742 { /* Control transfers completed, Exit the State Machine */
743 phost->gState = phost->gStateBkp;
746 else if (URB_Status == URB_ERROR)
748 phost->Control.state = CTRL_ERROR;
751 else if((HCD_GetCurrentFrame(pdev)\
752 - phost->Control.timer) > timeout)
754 phost->Control.state = CTRL_ERROR;
756 else if(URB_Status == URB_STALL)
758 /* Control transfers completed, Exit the State Machine */
759 phost->gState = phost->gStateBkp;
760 phost->Control.status = CTRL_STALL;
761 status = USBH_NOT_SUPPORTED;
765 case CTRL_STATUS_OUT:
766 pdev->host.hc[phost->Control.hc_num_out].toggle_out ^= 1;
767 USBH_CtlSendData (pdev,
770 phost->Control.hc_num_out);
772 phost->Control.state = CTRL_STATUS_OUT_WAIT;
775 case CTRL_STATUS_OUT_WAIT:
777 URB_Status = HCD_GetURB_State(pdev , phost->Control.hc_num_out);
778 if (URB_Status == URB_DONE)
780 phost->gState = phost->gStateBkp;
782 else if (URB_Status == URB_NOTREADY)
784 phost->Control.state = CTRL_STATUS_OUT;
786 else if (URB_Status == URB_ERROR)
788 phost->Control.state = CTRL_ERROR;
794 After a halt condition is encountered or an error is detected by the
795 host, a control endpoint is allowed to recover by accepting the next Setup
796 PID; i.e., recovery actions via some other pipe are not required for control
797 endpoints. For the Default Control Pipe, a device reset will ultimately be
798 required to clear the halt or error condition if the next Setup PID is not
801 if (++ phost->Control.errorcount <= USBH_MAX_ERROR_COUNT)
803 /* Do the transmission again, starting from SETUP Packet */
804 phost->Control.state = CTRL_SETUP;
808 phost->Control.status = CTRL_FAIL;
809 phost->gState = phost->gStateBkp;
838 /******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/