void USB_Host_ResetDevice(void) { bool BusSuspended = USB_Host_IsBusSuspended(); USB_INT_Disable(USB_INT_DDISCI); USB_Host_WaitMS(20); USB_Host_ResetBus(); while (!(USB_Host_IsResetBusDone())); USB_INT_Clear(USB_INT_HSOFI); USB_Host_ResumeBus(); for (uint8_t MSRem = 10; MSRem != 0; MSRem--) { /* Workaround for powerless-pullup devices. After a USB bus reset, all disconnection interrupts are supressed while a USB frame is looked for - if it is found within 10ms, the device is still present. */ if (USB_INT_HasOccurred(USB_INT_HSOFI)) { USB_INT_Clear(USB_INT_DDISCI); break; } _delay_ms(1); } if (BusSuspended) USB_Host_SuspendBus(); USB_INT_Enable(USB_INT_DDISCI); }
uint8_t USB_Host_SendControlRequest(void* const BufferPtr) { bool BusSuspended = USB_Host_IsBusSuspended(); uint8_t ReturnStatus = USB_Host_SendControlRequest_PRV(BufferPtr); Pipe_Freeze(); if (BusSuspended) USB_Host_SuspendBus(); Pipe_ResetPipe(PIPE_CONTROLPIPE); return ReturnStatus; }
uint8_t USB_Host_WaitMS(uint8_t MS) { bool BusSuspended = USB_Host_IsBusSuspended(); uint8_t ErrorCode = HOST_WAITERROR_Successful; USB_INT_Clear(USB_INT_HSOFI); USB_Host_ResumeBus(); while (MS) { if (USB_INT_HasOccurred(USB_INT_HSOFI)) { USB_INT_Clear(USB_INT_HSOFI); MS--; } if ((USB_IsConnected == false) || (USB_CurrentMode == USB_MODE_DEVICE)) { ErrorCode = HOST_WAITERROR_DeviceDisconnect; break; } if (Pipe_IsError() == true) { Pipe_ClearError(); ErrorCode = HOST_WAITERROR_PipeError; break; } if (Pipe_IsStalled() == true) { Pipe_ClearStall(); ErrorCode = HOST_WAITERROR_SetupStalled; break; } } if (BusSuspended) USB_Host_SuspendBus(); return ErrorCode; }
uint8_t USB_Host_SendControlRequest(void* const BufferPtr) { uint8_t* DataStream = (uint8_t*)BufferPtr; bool BusSuspended = USB_Host_IsBusSuspended(); uint8_t ReturnStatus = HOST_SENDCONTROL_Successful; uint16_t DataLen = USB_ControlRequest.wLength; USB_Host_ResumeBus(); if ((ReturnStatus = USB_Host_WaitMS(1)) != HOST_WAITERROR_Successful) goto End_Of_Control_Send; Pipe_SetPipeToken(PIPE_TOKEN_SETUP); Pipe_ClearError(); Pipe_Unfreeze(); Pipe_Write_8(USB_ControlRequest.bmRequestType); Pipe_Write_8(USB_ControlRequest.bRequest); Pipe_Write_16_LE(USB_ControlRequest.wValue); Pipe_Write_16_LE(USB_ControlRequest.wIndex); Pipe_Write_16_LE(USB_ControlRequest.wLength); Pipe_ClearSETUP(); if ((ReturnStatus = USB_Host_WaitForIOS(USB_HOST_WAITFOR_SetupSent)) != HOST_SENDCONTROL_Successful) goto End_Of_Control_Send; Pipe_Freeze(); if ((ReturnStatus = USB_Host_WaitMS(1)) != HOST_WAITERROR_Successful) goto End_Of_Control_Send; if ((USB_ControlRequest.bmRequestType & CONTROL_REQTYPE_DIRECTION) == REQDIR_DEVICETOHOST) { Pipe_SetPipeToken(PIPE_TOKEN_IN); if (DataStream != NULL) { while (DataLen) { Pipe_Unfreeze(); if ((ReturnStatus = USB_Host_WaitForIOS(USB_HOST_WAITFOR_InReceived)) != HOST_SENDCONTROL_Successful) goto End_Of_Control_Send; if (!(Pipe_BytesInPipe())) DataLen = 0; while (Pipe_BytesInPipe() && DataLen) { *(DataStream++) = Pipe_Read_8(); DataLen--; } Pipe_Freeze(); Pipe_ClearIN(); } } Pipe_SetPipeToken(PIPE_TOKEN_OUT); Pipe_Unfreeze(); if ((ReturnStatus = USB_Host_WaitForIOS(USB_HOST_WAITFOR_OutReady)) != HOST_SENDCONTROL_Successful) goto End_Of_Control_Send; Pipe_ClearOUT(); if ((ReturnStatus = USB_Host_WaitForIOS(USB_HOST_WAITFOR_OutReady)) != HOST_SENDCONTROL_Successful) goto End_Of_Control_Send; } else { if (DataStream != NULL) { Pipe_SetPipeToken(PIPE_TOKEN_OUT); Pipe_Unfreeze(); while (DataLen) { if ((ReturnStatus = USB_Host_WaitForIOS(USB_HOST_WAITFOR_OutReady)) != HOST_SENDCONTROL_Successful) goto End_Of_Control_Send; while (DataLen && (Pipe_BytesInPipe() < USB_Host_ControlPipeSize)) { Pipe_Write_8(*(DataStream++)); DataLen--; } Pipe_ClearOUT(); } if ((ReturnStatus = USB_Host_WaitForIOS(USB_HOST_WAITFOR_OutReady)) != HOST_SENDCONTROL_Successful) goto End_Of_Control_Send; Pipe_Freeze(); } Pipe_SetPipeToken(PIPE_TOKEN_IN); Pipe_Unfreeze(); if ((ReturnStatus = USB_Host_WaitForIOS(USB_HOST_WAITFOR_InReceived)) != HOST_SENDCONTROL_Successful) goto End_Of_Control_Send; Pipe_ClearIN(); } End_Of_Control_Send: Pipe_Freeze(); if (BusSuspended) USB_Host_SuspendBus(); Pipe_ResetPipe(PIPE_CONTROLPIPE); return ReturnStatus; }
void USB_Host_ProcessNextHostState(void) { uint8_t ErrorCode = HOST_ENUMERROR_NoError; uint8_t SubErrorCode = HOST_ENUMERROR_NoError; static uint16_t WaitMSRemaining; static uint8_t PostWaitState; switch (USB_HostState) { case HOST_STATE_WaitForDevice: if (WaitMSRemaining) { if ((SubErrorCode = USB_Host_WaitMS(1)) != HOST_WAITERROR_Successful) { USB_HostState = PostWaitState; ErrorCode = HOST_ENUMERROR_WaitStage; break; } if (!(--WaitMSRemaining)) USB_HostState = PostWaitState; } break; case HOST_STATE_Powered: WaitMSRemaining = HOST_DEVICE_SETTLE_DELAY_MS; USB_HostState = HOST_STATE_Powered_WaitForDeviceSettle; break; case HOST_STATE_Powered_WaitForDeviceSettle: if (WaitMSRemaining--) { _delay_ms(1); break; } else { USB_Host_VBUS_Manual_Off(); USB_OTGPAD_On(); USB_Host_VBUS_Auto_Enable(); USB_Host_VBUS_Auto_On(); USB_HostState = HOST_STATE_Powered_WaitForConnect; } break; case HOST_STATE_Powered_WaitForConnect: if (USB_INT_HasOccurred(USB_INT_DCONNI)) { USB_INT_Clear(USB_INT_DCONNI); USB_INT_Clear(USB_INT_DDISCI); USB_INT_Clear(USB_INT_VBERRI); USB_INT_Enable(USB_INT_VBERRI); USB_Host_ResumeBus(); Pipe_ClearPipes(); HOST_TASK_NONBLOCK_WAIT(100, HOST_STATE_Powered_DoReset); } break; case HOST_STATE_Powered_DoReset: USB_Host_ResetDevice(); HOST_TASK_NONBLOCK_WAIT(200, HOST_STATE_Powered_ConfigPipe); break; case HOST_STATE_Powered_ConfigPipe: Pipe_ConfigurePipe(PIPE_CONTROLPIPE, EP_TYPE_CONTROL, PIPE_TOKEN_SETUP, ENDPOINT_CONTROLEP, PIPE_CONTROLPIPE_DEFAULT_SIZE, PIPE_BANK_SINGLE); if (!(Pipe_IsConfigured())) { ErrorCode = HOST_ENUMERROR_PipeConfigError; SubErrorCode = 0; break; } USB_HostState = HOST_STATE_Default; break; case HOST_STATE_Default: USB_ControlRequest = (USB_Request_Header_t) { .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_STANDARD | REQREC_DEVICE), .bRequest = REQ_GetDescriptor, .wValue = (DTYPE_Device << 8), .wIndex = 0, .wLength = 8, }; uint8_t DataBuffer[8]; if ((SubErrorCode = USB_Host_SendControlRequest(DataBuffer)) != HOST_SENDCONTROL_Successful) { ErrorCode = HOST_ENUMERROR_ControlError; break; } USB_ControlPipeSize = DataBuffer[offsetof(USB_Descriptor_Device_t, Endpoint0Size)]; USB_Host_ResetDevice(); HOST_TASK_NONBLOCK_WAIT(200, HOST_STATE_Default_PostReset); break; case HOST_STATE_Default_PostReset: Pipe_ConfigurePipe(PIPE_CONTROLPIPE, EP_TYPE_CONTROL, PIPE_TOKEN_SETUP, ENDPOINT_CONTROLEP, USB_ControlPipeSize, PIPE_BANK_SINGLE); if (!(Pipe_IsConfigured())) { ErrorCode = HOST_ENUMERROR_PipeConfigError; SubErrorCode = 0; break; } USB_ControlRequest = (USB_Request_Header_t) { .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_STANDARD | REQREC_DEVICE), .bRequest = REQ_SetAddress, .wValue = USB_HOST_DEVICEADDRESS, .wIndex = 0, .wLength = 0, }; if ((SubErrorCode = USB_Host_SendControlRequest(NULL)) != HOST_SENDCONTROL_Successful) { ErrorCode = HOST_ENUMERROR_ControlError; break; } HOST_TASK_NONBLOCK_WAIT(100, HOST_STATE_Default_PostAddressSet); break; case HOST_STATE_Default_PostAddressSet: USB_Host_SetDeviceAddress(USB_HOST_DEVICEADDRESS); EVENT_USB_Host_DeviceEnumerationComplete(); USB_HostState = HOST_STATE_Addressed; break; } if ((ErrorCode != HOST_ENUMERROR_NoError) && (USB_HostState != HOST_STATE_Unattached)) { EVENT_USB_Host_DeviceEnumerationFailed(ErrorCode, SubErrorCode); USB_Host_VBUS_Auto_Off(); EVENT_USB_Host_DeviceUnattached(); USB_ResetInterface(); } } uint8_t USB_Host_WaitMS(uint8_t MS) { bool BusSuspended = USB_Host_IsBusSuspended(); uint8_t ErrorCode = HOST_WAITERROR_Successful; bool HSOFIEnabled = USB_INT_IsEnabled(USB_INT_HSOFI); USB_INT_Disable(USB_INT_HSOFI); USB_INT_Clear(USB_INT_HSOFI); USB_Host_ResumeBus(); while (MS) { if (USB_INT_HasOccurred(USB_INT_HSOFI)) { USB_INT_Clear(USB_INT_HSOFI); MS--; } if ((USB_HostState == HOST_STATE_Unattached) || (USB_CurrentMode != USB_MODE_Host)) { ErrorCode = HOST_WAITERROR_DeviceDisconnect; break; } if (Pipe_IsError() == true) { Pipe_ClearError(); ErrorCode = HOST_WAITERROR_PipeError; break; } if (Pipe_IsStalled() == true) { Pipe_ClearStall(); ErrorCode = HOST_WAITERROR_SetupStalled; break; } } if (BusSuspended) USB_Host_SuspendBus(); if (HSOFIEnabled) USB_INT_Enable(USB_INT_HSOFI); return ErrorCode; } static void USB_Host_ResetDevice(void) { bool BusSuspended = USB_Host_IsBusSuspended(); USB_INT_Disable(USB_INT_DDISCI); USB_Host_ResetBus(); while (!(USB_Host_IsBusResetComplete())); USB_Host_ResumeBus(); bool HSOFIEnabled = USB_INT_IsEnabled(USB_INT_HSOFI); USB_INT_Disable(USB_INT_HSOFI); USB_INT_Clear(USB_INT_HSOFI); for (uint8_t MSRem = 10; MSRem != 0; MSRem--) { /* Workaround for powerless-pull-up devices. After a USB bus reset, all disconnection interrupts are suppressed while a USB frame is looked for - if it is found within 10ms, the device is still present. */ if (USB_INT_HasOccurred(USB_INT_HSOFI)) { USB_INT_Clear(USB_INT_HSOFI); USB_INT_Clear(USB_INT_DDISCI); break; } _delay_ms(1); } if (HSOFIEnabled) USB_INT_Enable(USB_INT_HSOFI); if (BusSuspended) USB_Host_SuspendBus(); USB_INT_Enable(USB_INT_DDISCI); }