/** * @brief USBH_Process * Background process of the USB Core. * @param phost: Host Handle * @retval USBH Status */ USBH_StatusTypeDef USBH_Process(USBH_HandleTypeDef *phost) { __IO USBH_StatusTypeDef status = USBH_FAIL; uint8_t idx = 0; switch (phost->gState) { case HOST_IDLE : if (phost->device.is_connected) { /* Wait for 200 ms after connection */ phost->gState = HOST_DEV_WAIT_FOR_ATTACHMENT; USBH_Delay(200); USBH_LL_ResetPort(phost); #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_PORT_EVENT, 0); #endif } break; case HOST_DEV_WAIT_FOR_ATTACHMENT: break; case HOST_DEV_ATTACHED : USBH_UsrLog("USB Device Attached"); /* Wait for 100 ms after Reset */ USBH_Delay(100); phost->device.speed = USBH_LL_GetSpeed(phost); phost->gState = HOST_ENUMERATION; phost->Control.pipe_out = USBH_AllocPipe (phost, 0x00); phost->Control.pipe_in = USBH_AllocPipe (phost, 0x80); /* Open Control pipes */ USBH_OpenPipe (phost, phost->Control.pipe_in, 0x80, phost->device.address, phost->device.speed, USBH_EP_CONTROL, phost->Control.pipe_size); /* Open Control pipes */ USBH_OpenPipe (phost, phost->Control.pipe_out, 0x00, phost->device.address, phost->device.speed, USBH_EP_CONTROL, phost->Control.pipe_size); #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_PORT_EVENT, 0); #endif break; case HOST_ENUMERATION: /* Check for enumeration status */ if ( USBH_HandleEnum(phost) == USBH_OK) { /* The function shall return USBH_OK when full enumeration is complete */ USBH_UsrLog ("Enumeration done."); phost->device.current_interface = 0; if(phost->device.DevDesc.bNumConfigurations == 1) { USBH_UsrLog ("This device has only 1 configuration."); phost->gState = HOST_SET_CONFIGURATION; } else { phost->gState = HOST_INPUT; } } break; case HOST_INPUT: { /* user callback for end of device basic enumeration */ if(phost->pUser != NULL) { phost->pUser(phost, HOST_USER_SELECT_CONFIGURATION); phost->gState = HOST_SET_CONFIGURATION; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0); #endif } } break; case HOST_SET_CONFIGURATION: /* set configuration */ if (USBH_SetCfg(phost, phost->device.CfgDesc.bConfigurationValue) == USBH_OK) { phost->gState = HOST_CHECK_CLASS; USBH_UsrLog ("Default configuration set."); } break; case HOST_CHECK_CLASS: if(phost->ClassNumber == 0) { USBH_UsrLog ("No Class has been registered."); } else { phost->pActiveClass = NULL; for (idx = 0; idx < USBH_MAX_NUM_SUPPORTED_CLASS ; idx ++) { if(phost->pClass[idx]->ClassCode == phost->device.CfgDesc.Itf_Desc[0].bInterfaceClass) { phost->pActiveClass = phost->pClass[idx]; } } if(phost->pActiveClass != NULL) { if(phost->pActiveClass->Init(phost)== USBH_OK) { phost->gState = HOST_CLASS_REQUEST; USBH_UsrLog ("%s class started.", phost->pActiveClass->Name); /* Inform user that a class has been activated */ phost->pUser(phost, HOST_USER_CLASS_SELECTED); } else { phost->gState = HOST_ABORT_STATE; USBH_UsrLog ("Device not supporting %s class.", phost->pActiveClass->Name); } } else { phost->gState = HOST_ABORT_STATE; USBH_UsrLog ("No registered class for this device."); } } #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0); #endif break; case HOST_CLASS_REQUEST: /* process class standard control requests state machine */ if(phost->pActiveClass != NULL) { status = phost->pActiveClass->Requests(phost); if(status == USBH_OK) { phost->gState = HOST_CLASS; } } else { phost->gState = HOST_ABORT_STATE; USBH_ErrLog ("Invalid Class Driver."); #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0); #endif } break; case HOST_CLASS: /* process class state machine */ if(phost->pActiveClass != NULL) { phost->pActiveClass->BgndProcess(phost); } break; case HOST_DEV_DISCONNECTED : DeInitStateMachine(phost); /* Re-Initilaize Host for new Enumeration */ if(phost->pActiveClass != NULL) { phost->pActiveClass->DeInit(phost); phost->pActiveClass = NULL; } break; case HOST_ABORT_STATE: default : break; } return USBH_OK; }
/** * @brief USBH_HandleEnum * This function includes the complete enumeration process * @param pdev: Selected device * @retval USBH_Status */ static USBH_Status USBH_HandleEnum(USB_OTG_CORE_HANDLE *pdev, USBH_HOST *phost) { USBH_Status Status = USBH_BUSY; uint8_t Local_Buffer[64]; switch (phost->EnumState) { case ENUM_IDLE: /* Get Device Desc for only 1st 8 bytes : To get EP0 MaxPacketSize */ if ( USBH_Get_DevDesc(pdev , phost, 8) == USBH_OK) { phost->Control.ep0size = phost->device_prop.Dev_Desc.bMaxPacketSize; /* Issue Reset */ HCD_ResetPort(pdev); phost->EnumState = ENUM_GET_FULL_DEV_DESC; /* modify control channels configuration for MaxPacket size */ USBH_Modify_Channel (pdev, phost->Control.hc_num_out, 0, 0, 0, phost->Control.ep0size); USBH_Modify_Channel (pdev, phost->Control.hc_num_in, 0, 0, 0, phost->Control.ep0size); } break; case ENUM_GET_FULL_DEV_DESC: /* Get FULL Device Desc */ if ( USBH_Get_DevDesc(pdev, phost, USB_DEVICE_DESC_SIZE)\ == USBH_OK) { /* user callback for device descriptor available */ phost->usr_cb->DeviceDescAvailable(&phost->device_prop.Dev_Desc); phost->EnumState = ENUM_SET_ADDR; } break; case ENUM_SET_ADDR: /* set address */ if ( USBH_SetAddress(pdev, phost, USBH_DEVICE_ADDRESS) == USBH_OK) { USB_OTG_BSP_mDelay(2); phost->device_prop.address = USBH_DEVICE_ADDRESS; /* user callback for device address assigned */ phost->usr_cb->DeviceAddressAssigned(); phost->EnumState = ENUM_GET_CFG_DESC; /* modify control channels to update device address */ USBH_Modify_Channel (pdev, phost->Control.hc_num_in, phost->device_prop.address, 0, 0, 0); USBH_Modify_Channel (pdev, phost->Control.hc_num_out, phost->device_prop.address, 0, 0, 0); } break; case ENUM_GET_CFG_DESC: /* get standard configuration descriptor */ if ( USBH_Get_CfgDesc(pdev, phost, USB_CONFIGURATION_DESC_SIZE) == USBH_OK) { phost->EnumState = ENUM_GET_FULL_CFG_DESC; } break; case ENUM_GET_FULL_CFG_DESC: /* get FULL config descriptor (config, interface, endpoints) */ if (USBH_Get_CfgDesc(pdev, phost, phost->device_prop.Cfg_Desc.wTotalLength) == USBH_OK) { /* User callback for configuration descriptors available */ phost->usr_cb->ConfigurationDescAvailable(&phost->device_prop.Cfg_Desc, phost->device_prop.Itf_Desc, phost->device_prop.Ep_Desc[0]); phost->EnumState = ENUM_GET_MFC_STRING_DESC; } break; case ENUM_GET_MFC_STRING_DESC: if (phost->device_prop.Dev_Desc.iManufacturer != 0) { /* Check that Manufacturer String is available */ if ( USBH_Get_StringDesc(pdev, phost, phost->device_prop.Dev_Desc.iManufacturer, Local_Buffer , 0xff) == USBH_OK) { /* User callback for Manufacturing string */ phost->usr_cb->ManufacturerString(Local_Buffer); phost->EnumState = ENUM_GET_PRODUCT_STRING_DESC; } } else { phost->usr_cb->ManufacturerString("N/A"); phost->EnumState = ENUM_GET_PRODUCT_STRING_DESC; } break; case ENUM_GET_PRODUCT_STRING_DESC: if (phost->device_prop.Dev_Desc.iProduct != 0) { /* Check that Product string is available */ if ( USBH_Get_StringDesc(pdev, phost, phost->device_prop.Dev_Desc.iProduct, Local_Buffer, 0xff) == USBH_OK) { /* User callback for Product string */ phost->usr_cb->ProductString(Local_Buffer); phost->EnumState = ENUM_GET_SERIALNUM_STRING_DESC; } } else { phost->usr_cb->ProductString("N/A"); phost->EnumState = ENUM_GET_SERIALNUM_STRING_DESC; } break; case ENUM_GET_SERIALNUM_STRING_DESC: if (phost->device_prop.Dev_Desc.iSerialNumber != 0) { /* Check that Serial number string is available */ if ( USBH_Get_StringDesc(pdev, phost, phost->device_prop.Dev_Desc.iSerialNumber, Local_Buffer, 0xff) == USBH_OK) { /* User callback for Serial number string */ phost->usr_cb->SerialNumString(Local_Buffer); phost->EnumState = ENUM_SET_CONFIGURATION; } } else { phost->usr_cb->SerialNumString("N/A"); phost->EnumState = ENUM_SET_CONFIGURATION; } break; case ENUM_SET_CONFIGURATION: /* set configuration (default config) */ if (USBH_SetCfg(pdev, phost, phost->device_prop.Cfg_Desc.bConfigurationValue) == USBH_OK) { phost->EnumState = ENUM_DEV_CONFIGURED; } break; case ENUM_DEV_CONFIGURED: /* user callback for enumeration done */ Status = USBH_OK; break; default: break; } return Status; }
/** * @brief USBH_Process * Background process of the USB Core. * @param phost: Host Handle * @retval USBH Status */ USBH_StatusTypeDef USBH_Process(USBH_HandleTypeDef *phost) { __IO USBH_StatusTypeDef status = USBH_FAIL; int reset_core = 0; uint8_t idx = 0, j; if (mapped_port_state(phost) == PORT_UP) { if (!phost->device.is_attached) { phost->gState = HOST_DEV_DISCONNECTED; } else if (phost->requestCoreReset) { phost->gState = HOST_DEV_DISCONNECTED; reset_core = 1; } } switch (phost->gState) { case HOST_IDLE : if (phost->device.is_connected) { /* Wait for 200 ms after connection */ USBH_UsrLog("."); USBH_UsrLog("."); USBH_UsrLog("."); USBH_UsrLog("Connected, delay %dms before port reset", USBH_CONNECT_DELAY); USBH_Delay(USBH_CONNECT_DELAY); /* TODO QUICK FIX: making sure Global Int is enabled, may be disabled by * unpaired port down event in hcd, ridiculous bug */ USBH_LL_Start(phost); USBH_LL_ResetPort(phost); phost->gState = HOST_DEV_WAIT_FOR_ATTACHMENT; phost->gStateTimer = HAL_GetTick(); #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_PORT_EVENT, 0); #endif } break; case HOST_DEV_WAIT_FOR_ATTACHMENT: if (!phost->device.is_connected) { // phost->device.is_connected = 0; phost->gState = HOST_IDLE; } else if (phost->device.is_attached) { phost->gState = HOST_DEV_ATTACHED; } else if (HAL_GetTick() - phost->gStateTimer > 1000) { // phost->device.is_connected = 0; phost->gState = HOST_IDLE; } break; case HOST_DEV_ATTACHED : if (!phost->device.is_connected) { // phost->device.is_connected = 0; phost->gState = HOST_IDLE; } USBH_UsrLog("USB Device Attached"); /* Wait for 100 ms after Reset */ USBH_Delay(100); phost->device.speed = USBH_LL_GetSpeed(phost); phost->gState = HOST_ENUMERATION; phost->Control.pipe_out = USBH_AllocPipe (phost, 0x00); phost->Control.pipe_in = USBH_AllocPipe (phost, 0x80); /* Open Control pipes */ USBH_OpenPipe (phost, phost->Control.pipe_in, 0x80, phost->device.address, phost->device.speed, USBH_EP_CONTROL, phost->Control.pipe_size); /* Open Control pipes */ USBH_OpenPipe (phost, phost->Control.pipe_out, 0x00, phost->device.address, phost->device.speed, USBH_EP_CONTROL, phost->Control.pipe_size); /* do this here, instead in interrupt context **/ if (phost->pUser != NULL) { phost->pUser(phost, HOST_USER_CONNECTION); } #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_PORT_EVENT, 0); #endif break; case HOST_ENUMERATION: /* Check for enumeration status */ if ( USBH_HandleEnum(phost) == USBH_OK) { /* The function shall return USBH_OK when full enumeration is complete */ USBH_UsrLog ("Enumeration done."); USBH_Print_DeviceDescriptor(phost); phost->device.current_interface = 0; if(phost->device.DevDesc.bNumConfigurations == 1) { USBH_UsrLog ("This device has only 1 configuration."); phost->gState = HOST_SET_CONFIGURATION; } else { phost->gState = HOST_INPUT; } } break; case HOST_INPUT: { /* user callback for end of device basic enumeration */ if(phost->pUser != NULL) { phost->pUser(phost, HOST_USER_SELECT_CONFIGURATION); phost->gState = HOST_SET_CONFIGURATION; #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0); #endif } } break; case HOST_SET_CONFIGURATION: /* set configuration */ if (USBH_SetCfg(phost, phost->device.CfgDesc.bConfigurationValue) == USBH_OK) { phost->gState = HOST_CHECK_CLASS; USBH_UsrLog ("Default configuration set."); } break; case HOST_CHECK_CLASS: if(phost->ClassNumber == 0) { USBH_UsrLog ("No Class has been registered."); phost->AbortReason = ABORT_NOCLASS_REGISTERED; phost->gState = HOST_ABORT_STATE; } else { phost->pActiveClass = NULL; // for (idx = 0; idx < USBH_MAX_NUM_SUPPORTED_CLASS ; idx ++) for (idx = 0; idx < phost->ClassNumber; idx++) { // search all interfaces, not only interface 0 for (j = 0; j < phost->device.CfgDesc.bNumInterfaces; j++) { if (phost->pClass[idx]->ClassCode == phost->device.CfgDesc.Itf_Desc[j].bInterfaceClass) { phost->pActiveClass = phost->pClass[idx]; USBH_UsrLog( "Registered %s class with code 0x%02x matches interface #%d", phost->pClass[idx]->Name, phost->pClass[idx]->ClassCode, j); break; } } if (phost->pActiveClass != NULL) break; } if(phost->pActiveClass != NULL) { if(phost->pActiveClass->Init(phost)== USBH_OK) { phost->gState = HOST_CLASS_REQUEST; USBH_UsrLog ("%s class started.", phost->pActiveClass->Name); /* Inform user that a class has been activated */ phost->pUser(phost, HOST_USER_CLASS_SELECTED); } else { phost->AbortReason = ABORT_CLASSINIT_FAIL; phost->gState = HOST_ABORT_STATE; USBH_UsrLog ("Device not supporting %s class.", phost->pActiveClass->Name); phost->pActiveClass = NULL; } } else { phost->AbortReason = ABORT_NOCLASS_MATCH; phost->gState = HOST_ABORT_STATE; USBH_UsrLog ("No registered class for this device."); } } #if (USBH_USE_OS == 1) osMessagePut ( phost->os_event, USBH_STATE_CHANGED_EVENT, 0); #endif break; case HOST_CLASS_REQUEST: /* process class standard control requests state machine */ if(phost->pActiveClass != NULL) { /* as long as pActiveClass is set, this state is */ status = phost->pActiveClass->Requests(phost); if(status == USBH_OK) { phost->gState = HOST_CLASS; } else if (status == USBH_FAIL || status == USBH_NOT_SUPPORTED) { phost->pActiveClass->DeInit(phost); phost->pActiveClass = NULL; phost->AbortReason = ABORT_CLASSREQUEST_FAIL; phost->gState = HOST_ABORT_STATE; USBH_ErrLog("Class Request fail.") } }