/** * Post-processes a command given the case identified during the * pre-processing step. * Depending on the case, one of the following actions can be done: * - Bulk IN endpoint is stalled * - Bulk OUT endpoint is stalled * - CSW status set to phase error * \param pMsdDriver Pointer to a MSDDriver instance * \return If the device is halted */ static unsigned char MSDD_PostProcessCommand(MSDDriver *pMsdDriver) { MSDCommandState *commandState = &(pMsdDriver->commandState); MSCsw *csw = &(commandState->csw); unsigned char haltStatus = 0; /* STALL Bulk IN endpoint ? */ if ((commandState->postprocess & MSDD_CASE_STALL_IN) != 0) { TRACE_INFO_WP("StallIn "); //MSDD_Halt(MSDD_CASE_STALL_IN); USBD_Halt(commandState->pipeIN); haltStatus = 1; } /* STALL Bulk OUT endpoint ? */ if ((commandState->postprocess & MSDD_CASE_STALL_OUT) != 0) { TRACE_INFO_WP("StallOut "); //MSDD_Halt(MSDD_CASE_STALL_OUT); USBD_Halt(commandState->pipeOUT); haltStatus = 1; } /* Set CSW status code to phase error ? */ if ((commandState->postprocess & MSDD_CASE_PHASE_ERROR) != 0) { TRACE_INFO_WP("PhaseErr "); csw->bCSWStatus = MSD_CSW_PHASE_ERROR; } return haltStatus; }
//----------------------------------------------------------------------------- /// HALT Specified USB pipe. /// \param stallCASE Case of the stall condition (Bulk In/Out/Both). //----------------------------------------------------------------------------- void MSDD_Halt(unsigned int stallCASE) { if (stallCASE & MSDD_CASE_STALL_OUT) { USBD_Halt(MSDDriverDescriptors_BULKOUT); } if (stallCASE & MSDD_CASE_STALL_IN) { USBD_Halt(MSDDriverDescriptors_BULKIN); } }
//------------------------------------------------------------------------------ /// Handles the given request if it is standard, otherwise STALLs it. /// \param pDriver Pointer to a USBDDriver instance. /// \param pRequest Pointer to a USBGenericRequest instance. //------------------------------------------------------------------------------ void USBDDriver_RequestHandler( USBDDriver *pDriver, const USBGenericRequest *pRequest) { unsigned char cfgnum; unsigned char infnum; unsigned char eptnum; unsigned char setting; unsigned char type; unsigned char indexDesc; unsigned int length; unsigned int address; TRACE_INFO_WP("Std "); // Check request code switch (USBGenericRequest_GetRequest(pRequest)) { case USBGenericRequest_GETDESCRIPTOR: TRACE_INFO_WP("gDesc "); // Send the requested descriptor type = USBGetDescriptorRequest_GetDescriptorType(pRequest); indexDesc = USBGetDescriptorRequest_GetDescriptorIndex(pRequest); length = USBGenericRequest_GetLength(pRequest); GetDescriptor(pDriver, type, indexDesc, length); break; case USBGenericRequest_SETADDRESS: TRACE_INFO_WP("sAddr "); // Sends a zero-length packet and then set the device address address = USBSetAddressRequest_GetAddress(pRequest); USBD_Write(0, 0, 0, (TransferCallback) USBD_SetAddress, (void *) address); break; case USBGenericRequest_SETCONFIGURATION: TRACE_INFO_WP("sCfg "); // Set the requested configuration cfgnum = USBSetConfigurationRequest_GetConfiguration(pRequest); SetConfiguration(pDriver, cfgnum); break; case USBGenericRequest_GETCONFIGURATION: TRACE_INFO_WP("gCfg "); // Send the current configuration number GetConfiguration(pDriver); break; case USBGenericRequest_GETSTATUS: TRACE_INFO_WP("gSta "); // Check who is the recipient switch (USBGenericRequest_GetRecipient(pRequest)) { case USBGenericRequest_DEVICE: TRACE_INFO_WP("Dev "); // Send the device status GetDeviceStatus(pDriver); break; case USBGenericRequest_ENDPOINT: TRACE_INFO_WP("Ept "); // Send the endpoint status eptnum = USBGenericRequest_GetEndpointNumber(pRequest); GetEndpointStatus(eptnum); break; default: TRACE_WARNING( "USBDDriver_RequestHandler: Unknown recipient (%d)\n\r", USBGenericRequest_GetRecipient(pRequest)); USBD_Stall(0); } break; case USBGenericRequest_CLEARFEATURE: TRACE_INFO_WP("cFeat "); // Check which is the requested feature switch (USBFeatureRequest_GetFeatureSelector(pRequest)) { case USBFeatureRequest_ENDPOINTHALT: TRACE_INFO_WP("Hlt "); // Unhalt endpoint and send a zero-length packet USBD_Unhalt(USBGenericRequest_GetEndpointNumber(pRequest)); USBD_Write(0, 0, 0, 0, 0); break; case USBFeatureRequest_DEVICEREMOTEWAKEUP: TRACE_INFO_WP("RmWU "); // Disable remote wake-up and send a zero-length packet pDriver->isRemoteWakeUpEnabled = 0; USBD_Write(0, 0, 0, 0, 0); break; default: TRACE_WARNING( "USBDDriver_RequestHandler: Unknown feature selector (%d)\n\r", USBFeatureRequest_GetFeatureSelector(pRequest)); USBD_Stall(0); } break; case USBGenericRequest_SETFEATURE: TRACE_INFO_WP("sFeat "); // Check which is the selected feature switch (USBFeatureRequest_GetFeatureSelector(pRequest)) { case USBFeatureRequest_DEVICEREMOTEWAKEUP: TRACE_INFO_WP("RmWU "); // Enable remote wake-up and send a ZLP pDriver->isRemoteWakeUpEnabled = 1; USBD_Write(0, 0, 0, 0, 0); break; case USBFeatureRequest_ENDPOINTHALT: TRACE_INFO_WP("Halt "); // Halt endpoint USBD_Halt(USBGenericRequest_GetEndpointNumber(pRequest)); USBD_Write(0, 0, 0, 0, 0); break; #if defined(CHIP_USB_UDPHS) || defined(CHIP_USB_OTGHS) case USBFeatureRequest_TESTMODE: // 7.1.20 Test Mode Support if ((USBGenericRequest_GetType(pRequest) == USBGenericRequest_DEVICE) && ((USBGenericRequest_GetIndex(pRequest) & 0x000F) == 0)) { // Handle test request USBDDriver_Test(USBFeatureRequest_GetTestSelector(pRequest)); } else { USBD_Stall(0); } break; #endif #if defined(CHIP_USB_OTGHS) case USBFeatureRequest_OTG_B_HNP_ENABLE: TRACE_INFO_WP("OTG_B_HNP_ENABLE "); otg_features_supported |= 1<<USBFeatureRequest_OTG_B_HNP_ENABLE; USBD_Write(0, 0, 0, 0, 0); break; case USBFeatureRequest_OTG_A_HNP_SUPPORT: TRACE_INFO_WP("OTG_A_HNP_SUPPORT "); otg_features_supported |= 1<<USBFeatureRequest_OTG_A_HNP_SUPPORT; USBD_Write(0, 0, 0, 0, 0); break; case USBFeatureRequest_OTG_A_ALT_HNP_SUPPORT: TRACE_INFO_WP("OTG_A_ALT_HNP_SUPPORT "); otg_features_supported |= 1<<USBFeatureRequest_OTG_A_ALT_HNP_SUPPORT; USBD_Write(0, 0, 0, 0, 0); break; #endif default: TRACE_WARNING( "USBDDriver_RequestHandler: Unknown feature selector (%d)\n\r", USBFeatureRequest_GetFeatureSelector(pRequest)); USBD_Stall(0); } break; case USBGenericRequest_SETINTERFACE: TRACE_INFO_WP("sInterface "); infnum = USBInterfaceRequest_GetInterface(pRequest); setting = USBInterfaceRequest_GetAlternateSetting(pRequest); SetInterface(pDriver, infnum, setting); break; case USBGenericRequest_GETINTERFACE: TRACE_INFO_WP("gInterface "); infnum = USBInterfaceRequest_GetInterface(pRequest); GetInterface(pDriver, infnum); break; default: TRACE_WARNING( "USBDDriver_RequestHandler: Unknown request code (%d)\n\r", USBGenericRequest_GetRequest(pRequest)); USBD_Stall(0); } }
/** * Handles the given request if it is standard, otherwise STALLs it. * \param pDriver Pointer to a USBDDriver instance. * \param pRequest Pointer to a USBGenericRequest instance. */ void USBDDriver_RequestHandler( USBDDriver *pDriver, const USBGenericRequest *pRequest) { uint8_t cfgnum; uint8_t infnum; uint8_t eptnum; uint8_t setting; uint8_t type; uint8_t indexDesc; uint32_t length; uint32_t address; TRACE_INFO_WP("Std "); /* Check request code */ switch (USBGenericRequest_GetRequest(pRequest)) { case USBGenericRequest_GETDESCRIPTOR: TRACE_INFO_WP("gDesc "); /* Send the requested descriptor */ type = USBGetDescriptorRequest_GetDescriptorType(pRequest); indexDesc = USBGetDescriptorRequest_GetDescriptorIndex(pRequest); length = USBGenericRequest_GetLength(pRequest); GetDescriptor(pDriver, type, indexDesc, length); break; case USBGenericRequest_SETADDRESS: TRACE_INFO_WP("sAddr "); /* Sends a zero-length packet and then set the device address */ address = USBSetAddressRequest_GetAddress(pRequest); USBD_Write(0, 0, 0, (TransferCallback) USBD_SetAddress, (void *) address); break; case USBGenericRequest_SETCONFIGURATION: TRACE_INFO_WP("sCfg "); /* Set the requested configuration */ cfgnum = USBSetConfigurationRequest_GetConfiguration(pRequest); SetConfiguration(pDriver, cfgnum); break; case USBGenericRequest_GETCONFIGURATION: TRACE_INFO_WP("gCfg "); /* Send the current configuration number */ GetConfiguration(pDriver); break; case USBGenericRequest_GETSTATUS: TRACE_INFO_WP("gSta "); /* Check who is the recipient */ switch (USBGenericRequest_GetRecipient(pRequest)) { case USBGenericRequest_DEVICE: TRACE_INFO_WP("Dev "); /* Send the device status */ GetDeviceStatus(pDriver); break; case USBGenericRequest_ENDPOINT: TRACE_INFO_WP("Ept "); /* Send the endpoint status */ eptnum = USBGenericRequest_GetEndpointNumber(pRequest); GetEndpointStatus(eptnum); break; default: TRACE_WARNING( "USBDDriver_RequestHandler: Unknown recipient (%d)\n\r", USBGenericRequest_GetRecipient(pRequest)); USBD_Stall(0); } break; case USBGenericRequest_CLEARFEATURE: TRACE_INFO_WP("cFeat "); /* Check which is the requested feature */ switch (USBFeatureRequest_GetFeatureSelector(pRequest)) { case USBFeatureRequest_ENDPOINTHALT: TRACE_INFO_WP("Hlt "); /* Unhalt endpoint and send a zero-length packet */ USBD_Unhalt(USBGenericRequest_GetEndpointNumber(pRequest)); USBD_Write(0, 0, 0, 0, 0); break; case USBFeatureRequest_DEVICEREMOTEWAKEUP: TRACE_INFO_WP("RmWU "); /* Disable remote wake-up and send a zero-length packet */ pDriver->isRemoteWakeUpEnabled = 0; USBD_Write(0, 0, 0, 0, 0); break; default: TRACE_WARNING( "USBDDriver_RequestHandler: Unknown feature selector (%d)\n\r", USBFeatureRequest_GetFeatureSelector(pRequest)); USBD_Stall(0); } break; case USBGenericRequest_SETFEATURE: TRACE_INFO_WP("sFeat "); /* Check which is the selected feature */ switch (USBFeatureRequest_GetFeatureSelector(pRequest)) { case USBFeatureRequest_DEVICEREMOTEWAKEUP: TRACE_INFO_WP("RmWU "); /* Enable remote wake-up and send a ZLP */ pDriver->isRemoteWakeUpEnabled = 1; USBD_Write(0, 0, 0, 0, 0); break; case USBFeatureRequest_ENDPOINTHALT: TRACE_INFO_WP("Halt "); /* Halt endpoint */ USBD_Halt(USBGenericRequest_GetEndpointNumber(pRequest)); USBD_Write(0, 0, 0, 0, 0); break; case USBFeatureRequest_OTG_B_HNP_ENABLE: TRACE_INFO_WP("OTG_B_HNP_ENABLE "); pDriver->otg_features_supported |= 1<<USBFeatureRequest_OTG_B_HNP_ENABLE; USBD_Write(0, 0, 0, 0, 0); break; case USBFeatureRequest_OTG_A_HNP_SUPPORT: TRACE_INFO_WP("OTG_A_HNP_SUPPORT "); pDriver->otg_features_supported |= 1<<USBFeatureRequest_OTG_A_HNP_SUPPORT; USBD_Write(0, 0, 0, 0, 0); break; case USBFeatureRequest_OTG_A_ALT_HNP_SUPPORT: TRACE_INFO_WP("OTG_A_ALT_HNP_SUPPORT "); pDriver->otg_features_supported |= 1<<USBFeatureRequest_OTG_A_ALT_HNP_SUPPORT; USBD_Write(0, 0, 0, 0, 0); break; default: TRACE_WARNING( "USBDDriver_RequestHandler: Unknown feature selector (%d)\n\r", USBFeatureRequest_GetFeatureSelector(pRequest)); USBD_Stall(0); } break; case USBGenericRequest_SETINTERFACE: TRACE_INFO_WP("sInterface "); infnum = USBInterfaceRequest_GetInterface(pRequest); setting = USBInterfaceRequest_GetAlternateSetting(pRequest); SetInterface(pDriver, infnum, setting); break; case USBGenericRequest_GETINTERFACE: TRACE_INFO_WP("gInterface "); infnum = USBInterfaceRequest_GetInterface(pRequest); GetInterface(pDriver, infnum); break; default: TRACE_WARNING( "USBDDriver_RequestHandler: Unknown request code (%d)\n\r", USBGenericRequest_GetRequest(pRequest)); USBD_Stall(0); } }
/** * State machine for the MSD %device driver * \param pMsdDriver Pointer to a MSDDriver instance */ void MSDD_StateMachine(MSDDriver * pMsdDriver) { MSDCommandState *commandState = &(pMsdDriver->commandState); MSCbw *cbw = &(commandState->cbw); MSCsw *csw = &(commandState->csw); MSDTransfer *transfer = &(commandState->transfer); unsigned char status; /* Identify current driver state */ switch (pMsdDriver->state) { /*---------------------- */ case MSDD_STATE_READ_CBW: /*---------------------- */ /* Start the CBW read operation */ transfer->semaphore = 0; #if 1 status = USBD_Read(commandState->pipeOUT, cbw, MSD_CBW_SIZE, (TransferCallback) MSDDriver_Callback, (void *) transfer); #else status = MSDD_Read(cbw, MSD_CBW_SIZE, (TransferCallback) MSDDriver_Callback, (void *) transfer); #endif /* Check operation result code */ if (status == USBD_STATUS_SUCCESS) { /* If the command was successful, wait for transfer */ pMsdDriver->state = MSDD_STATE_WAIT_CBW; } break; /*---------------------- */ case MSDD_STATE_WAIT_CBW: /*---------------------- */ /* Check transfer semaphore */ if (transfer->semaphore > 0) { /* Take semaphore and terminate transfer */ transfer->semaphore--; /* Check if transfer was successful */ if (transfer->status == USBD_STATUS_SUCCESS) { TRACE_INFO_WP("\n\r------------------------------\n\r"); /* Process received command */ pMsdDriver->state = MSDD_STATE_PROCESS_CBW; } else if (transfer->status == USBD_STATUS_RESET) { TRACE_INFO("MSDD_StateMachine: EP resetted\n\r"); pMsdDriver->state = MSDD_STATE_READ_CBW; } else { TRACE_WARNING( "MSDD_StateMachine: Failed to read CBW\n\r"); pMsdDriver->state = MSDD_STATE_READ_CBW; } } break; /*------------------------- */ case MSDD_STATE_PROCESS_CBW: /*------------------------- */ /* Check if this is a new command */ if (commandState->state == 0) { /* Copy the CBW tag */ csw->dCSWTag = cbw->dCBWTag; /* Check that the CBW is 31 bytes long */ if ((transfer->transferred != MSD_CBW_SIZE) || (transfer->remaining != 0)) { TRACE_WARNING( "MSDD_StateMachine: Invalid CBW (len %d)\n\r", (int)transfer->transferred); /* Wait for a reset recovery */ pMsdDriver->waitResetRecovery = 1; /* Halt the Bulk-IN and Bulk-OUT pipes */ //MSDD_Halt(MSDD_CASE_STALL_OUT | MSDD_CASE_STALL_IN); USBD_Halt(commandState->pipeIN); USBD_Halt(commandState->pipeOUT); csw->bCSWStatus = MSD_CSW_COMMAND_FAILED; pMsdDriver->state = MSDD_STATE_READ_CBW; } /* Check the CBW Signature */ else if (cbw->dCBWSignature != MSD_CBW_SIGNATURE) { TRACE_WARNING( "MSD_BOTStateMachine: Invalid CBW (Bad signature)\n\r"); /* Wait for a reset recovery */ pMsdDriver->waitResetRecovery = 1; /* Halt the Bulk-IN and Bulk-OUT pipes */ //MSDD_Halt(MSDD_CASE_STALL_OUT | MSDD_CASE_STALL_IN); USBD_Halt(commandState->pipeIN); USBD_Halt(commandState->pipeOUT); csw->bCSWStatus = MSD_CSW_COMMAND_FAILED; pMsdDriver->state = MSDD_STATE_READ_CBW; } else { /* Pre-process command */ MSDD_PreProcessCommand(pMsdDriver); } } /* Process command */ if (csw->bCSWStatus == MSDD_STATUS_SUCCESS) { if (MSDD_ProcessCommand(pMsdDriver)) { /* Post-process command if it is finished */ if (MSDD_PostProcessCommand(pMsdDriver)) { TRACE_INFO_WP("WaitHALT "); pMsdDriver->state = MSDD_STATE_WAIT_HALT; } else { pMsdDriver->state = MSDD_STATE_SEND_CSW; } } TRACE_INFO_WP("\n\r"); } break; /*---------------------- */ case MSDD_STATE_SEND_CSW: /*---------------------- */ /* Set signature */ csw->dCSWSignature = MSD_CSW_SIGNATURE; /* Start the CSW write operation */ #if 1 status = USBD_Write(commandState->pipeIN, csw, MSD_CSW_SIZE, (TransferCallback) MSDDriver_Callback, (void *) transfer); #else status = MSDD_Write(csw, MSD_CSW_SIZE, (TransferCallback) MSDDriver_Callback, (void *) transfer); #endif /* Check operation result code */ if (status == USBD_STATUS_SUCCESS) { TRACE_INFO_WP("SendCSW "); /* Wait for end of transfer */ pMsdDriver->state = MSDD_STATE_WAIT_CSW; } break; /*---------------------- */ case MSDD_STATE_WAIT_CSW: /*---------------------- */ /* Check transfer semaphore */ if (transfer->semaphore > 0) { /* Take semaphore and terminate transfer */ transfer->semaphore--; /* Check if transfer was successful */ if (transfer->status == USBD_STATUS_RESET) { TRACE_INFO("MSDD_StateMachine: EP resetted\n\r"); } else if (transfer->status == USBD_STATUS_ABORTED) { TRACE_WARNING( "MSDD_StateMachine: Failed to send CSW\n\r"); } else { TRACE_INFO_WP("ok"); } /* Read new CBW */ pMsdDriver->state = MSDD_STATE_READ_CBW; } break; /*---------------------- */ case MSDD_STATE_WAIT_HALT: /*---------------------- */ //if (MSDD_IsHalted() == 0) { if (!USBD_IsHalted(commandState->pipeIN)) { pMsdDriver->state = MSDD_STATE_SEND_CSW; } break; } }