ISR(usb_general_interrupt, AVR32_USBB_IRQ_GROUP, USB_INT_LEVEL) #endif { #ifdef FREERTOS_USED portBASE_TYPE task_woken = pdFALSE; #endif uint8_t i; /* avoid Cppcheck Warning */ UNUSED(i); // ---------- DEVICE/HOST events management ------------------------------------ #if USB_DEVICE_FEATURE == true && USB_HOST_FEATURE == true // ID pin change detection if (Is_usb_id_transition() && Is_usb_id_interrupt_enabled()) { g_usb_mode = (Is_usb_id_device()) ? USB_MODE_DEVICE : USB_MODE_HOST; Usb_ack_id_transition(); if (g_usb_mode != g_old_usb_mode) // Basic debounce { // Previously in device mode, check if disconnection was detected if (g_old_usb_mode == USB_MODE_DEVICE) { if (usb_connected) { // Device mode diconnection actions usb_connected = false; usb_configuration_nb = 0; Usb_vbus_off_action(); } } // Previously in host mode, check if disconnection was detected else if (Is_host_attached()) { // Host mode diconnection actions device_state = DEVICE_UNATTACHED; Host_device_disconnection_action(); } LOG_STR(log_pin_id_changed); Usb_send_event((Is_usb_device()) ? EVT_USB_DEVICE_FUNCTION : EVT_USB_HOST_FUNCTION); Usb_id_transition_action(); //! @todo ID pin hot state change!!! // Preliminary management: HARDWARE RESET!!! #if ID_PIN_CHANGE_GENERATE_RESET == ENABLE // Hot ID transition generates CPU reset Usb_disable(); Usb_disable_otg_pad(); #ifdef FREERTOS_USED // Release the semaphore in order to start a new device/host task taskENTER_CRITICAL(); xSemaphoreGiveFromISR(usb_tsk_semphr, &task_woken); taskEXIT_CRITICAL(); #else #if defined(CPU_RESET_CALLBACK) CPU_RESET_CALLBACK(); #endif Reset_CPU(); #endif #endif g_old_usb_mode = g_usb_mode; // Store current USB mode, for mode change detection } } #endif // End DEVICE/HOST FEATURE MODE // ---------- DEVICE events management ----------------------------------------- #if USB_DEVICE_FEATURE == true #if USB_HOST_FEATURE == true // If both device and host features are enabled, check if device mode is engaged // (accessing the USB registers of a non-engaged mode, even with load operations, // may corrupt USB FIFO data). if (Is_usb_device()) #endif { // VBus state detection if (Is_usb_vbus_transition() && Is_usb_vbus_interrupt_enabled()) { Usb_ack_vbus_transition(); if (Is_usb_vbus_high()) { usb_start_device(); Usb_send_event(EVT_USB_POWERED); Usb_vbus_on_action(); } else { Usb_unfreeze_clock(); Usb_detach(); usb_connected = false; usb_configuration_nb = 0; Usb_send_event(EVT_USB_UNPOWERED); Usb_vbus_off_action(); #ifdef FREERTOS_USED // Release the semaphore in order to start a new device/host task taskENTER_CRITICAL(); xSemaphoreGiveFromISR(usb_tsk_semphr, &task_woken); taskEXIT_CRITICAL(); #endif } } // Device Start-of-Frame received if (Is_usb_sof() && Is_usb_sof_interrupt_enabled()) { Usb_ack_sof(); Usb_sof_action(); } // Device Suspend event (no more USB activity detected) if (Is_usb_suspend() && Is_usb_suspend_interrupt_enabled()) { Usb_ack_suspend(); Usb_enable_wake_up_interrupt(); (void)Is_usb_wake_up_interrupt_enabled(); Usb_freeze_clock(); Usb_send_event(EVT_USB_SUSPEND); Usb_suspend_action(); } // Wake-up event (USB activity detected): Used to resume if (Is_usb_wake_up() && Is_usb_wake_up_interrupt_enabled()) { Usb_unfreeze_clock(); (void)Is_usb_clock_frozen(); Usb_ack_wake_up(); Usb_disable_wake_up_interrupt(); Usb_wake_up_action(); Usb_send_event(EVT_USB_WAKE_UP); } // Resume state bus detection if (Is_usb_resume() && Is_usb_resume_interrupt_enabled()) { Usb_disable_wake_up_interrupt(); Usb_ack_resume(); Usb_disable_resume_interrupt(); Usb_resume_action(); Usb_send_event(EVT_USB_RESUME); } // USB bus reset detection if (Is_usb_reset() && Is_usb_reset_interrupt_enabled()) { Usb_ack_reset(); usb_init_device(); Usb_reset_action(); Usb_send_event(EVT_USB_RESET); } } #endif // End DEVICE FEATURE MODE // ---------- HOST events management ------------------------------------------- #if USB_HOST_FEATURE == true #if USB_DEVICE_FEATURE == true // If both device and host features are enabled, check if host mode is engaged // (accessing the USB registers of a non-engaged mode, even with load operations, // may corrupt USB FIFO data). else #endif { // The device has been disconnected if (Is_host_device_disconnection() && Is_host_device_disconnection_interrupt_enabled()) { host_disable_all_pipes(); Host_ack_device_disconnection(); #if USB_HOST_PIPE_INTERRUPT_TRANSFER == ENABLE reset_it_pipe_str(); #endif #ifdef HOST_VBUS_LOW_TIMEOUT cpu_set_timeout(HOST_VBUS_LOW_TIMEOUT, &timer_vbus_low); device_state = DEVICE_VBUS_LOW; #else device_state = DEVICE_UNATTACHED; #endif LOG_STR(log_device_disconnected); Usb_send_event(EVT_HOST_DISCONNECTION); Host_device_disconnection_action(); #ifdef FREERTOS_USED // Release the semaphore in order to start a new device/host task taskENTER_CRITICAL(); xSemaphoreGiveFromISR(usb_tsk_semphr, &task_woken); taskEXIT_CRITICAL(); #endif } // Device connection if (Is_host_device_connection() && Is_host_device_connection_interrupt_enabled()) { Host_ack_device_connection(); host_disable_all_pipes(); Usb_send_event(EVT_HOST_CONNECTION); Host_device_connection_action(); } // Host Start-of-Frame has been sent if (Is_host_sof() && Is_host_sof_interrupt_enabled()) { Host_ack_sof(); Usb_send_event(EVT_HOST_SOF); private_sof_counter++; // Delay time-out management for interrupt tranfer mode in host mode #if USB_HOST_PIPE_INTERRUPT_TRANSFER == ENABLE && TIMEOUT_DELAY_ENABLE == ENABLE if (private_sof_counter >= 250) // Count 250 ms (SOF @ 1 ms) { private_sof_counter = 0; for (i = 0; i < MAX_PEP_NB; i++) { if (it_pipe_str[i].enable && ++it_pipe_str[i].timeout > TIMEOUT_DELAY && Host_get_pipe_type(i) != TYPE_INTERRUPT) { it_pipe_str[i].enable = false; it_pipe_str[i].status = PIPE_DELAY_TIMEOUT; Host_reset_pipe(i); if (!is_any_interrupt_pipe_active() && !g_sav_int_sof_enable) // If no more transfer is armed { Host_disable_sof_interrupt(); } it_pipe_str[i].handler(PIPE_DELAY_TIMEOUT, it_pipe_str[i].nb_byte_processed); } } } #endif Host_sof_action(); } // Host Wake-up has been received if (Is_host_hwup() && Is_host_hwup_interrupt_enabled()) { // CAUTION: HWUP can be cleared only when USB clock is active (not frozen)! //! @todo Implement this on the silicon version //Pll_start_auto(); // First Restart the PLL for USB operation //Wait_pll_ready(); // Make sure PLL is locked Usb_unfreeze_clock(); // Enable clock on USB interface (void)Is_usb_clock_frozen(); // Make sure USB interface clock is enabled Host_disable_hwup_interrupt(); // Wake-up interrupt should be disabled as host is now awoken! Host_ack_hwup(); // Clear HWUP interrupt flag Usb_send_event(EVT_HOST_HWUP); // Send software event Host_hwup_action(); // Map custom action } Host_int_action(); while ((i = Host_get_interrupt_pipe_number()) < MAX_PEP_NB) { if (Is_host_in_received(i) && Is_host_in_received_interrupt_enabled(i)) { Host_freeze_pipe(i); Host_disable_in_received_interrupt(i); } } #if defined(USB_HIGH_SPEED_SUPPORT) && USB_HIGH_SPEED_SUPPORT == true && \ defined(PIPE_AUDIO_IN) // Workaround - freeze the IN audio pipe if (Is_host_in_received(PIPE_AUDIO_IN)) { extern void workaround_freeze_iso_in(void); workaround_freeze_iso_in(); } #endif // USB_HIGH_SPEED_SUPPORT == true #if USB_HOST_PIPE_INTERRUPT_TRANSFER == ENABLE // Host pipe interrupts while ((i = Host_get_interrupt_pipe_number()) < MAX_PEP_NB) usb_pipe_interrupt(i); #endif } #endif // End HOST FEATURE MODE #ifdef FREERTOS_USED return task_woken; #endif }
__interrupt #endif static void usb_general_interrupt(void) #endif { #ifdef FREERTOS_USED portBASE_TYPE task_woken = pdFALSE; #endif #if USB_HOST_FEATURE == true && USB_HOST_PIPE_INTERRUPT_TRANSFER == ENABLE U8 i; #endif // ---------- DEVICE/HOST events management ------------------------------------ #if USB_DEVICE_FEATURE == true && USB_HOST_FEATURE == true // ID pin change detection if (Is_usb_id_transition() && Is_usb_id_interrupt_enabled()) { g_usb_mode = (Is_usb_id_device()) ? USB_MODE_DEVICE : USB_MODE_HOST; Usb_ack_id_transition(); if (g_usb_mode != g_old_usb_mode) // Basic debounce { // Previously in device mode, check if disconnection was detected if (g_old_usb_mode == USB_MODE_DEVICE) { if (usb_connected) { // Device mode disconnection actions usb_connected = false; usb_configuration_nb = 0; Usb_vbus_off_action(); } } // Previously in host mode, check if disconnection was detected else if (Is_host_attached()) { // Host mode disconnection actions device_state = DEVICE_UNATTACHED; Host_device_disconnection_action(); } //LOG_STR(log_pin_id_changed); if (Is_usb_id_device() == USB_MODE_DEVICE) { LOG_STR(log_pin_id_changed_to_device); } else { LOG_STR(log_pin_id_changed_to_host); } Usb_send_event((Is_usb_device()) ? EVT_USB_DEVICE_FUNCTION : EVT_USB_HOST_FUNCTION); Usb_id_transition_action(); // Easier to recover from ID signal de-bounce and ID pin transitions by shutting down the USB and resetting state machine to re-init #if ID_PIN_CHANGE_SHUTDOWN_USB == ENABLE Usb_disable(); Usb_disable_otg_pad(); extern void UsbResetStateMachine(void); UsbResetStateMachine(); #ifdef FREERTOS_USED // Release the semaphore in order to start a new device/host task taskENTER_CRITICAL(); xSemaphoreGiveFromISR(usb_tsk_semphr, &task_woken); taskEXIT_CRITICAL(); #endif #endif #if ID_PIN_CHANGE_GENERATE_RESET == ENABLE Reset_CPU(); #endif } } #endif // End DEVICE/HOST FEATURE MODE // ---------- DEVICE events management ----------------------------------------- #if USB_DEVICE_FEATURE == true #if USB_HOST_FEATURE == true // If both device and host features are enabled, check if device mode is engaged // (accessing the USB registers of a non-engaged mode, even with load operations, // may corrupt USB FIFO data). if (Is_usb_device()) #endif { // VBus state detection if (Is_usb_vbus_transition() && Is_usb_vbus_interrupt_enabled()) { Usb_ack_vbus_transition(); if (Is_usb_vbus_high()) { usb_start_device(); Usb_send_event(EVT_USB_POWERED); Usb_vbus_on_action(); } else { Usb_unfreeze_clock(); Usb_detach(); usb_connected = false; usb_configuration_nb = 0; Usb_send_event(EVT_USB_UNPOWERED); Usb_vbus_off_action(); #ifdef FREERTOS_USED // Release the semaphore in order to start a new device/host task taskENTER_CRITICAL(); xSemaphoreGiveFromISR(usb_tsk_semphr, &task_woken); taskEXIT_CRITICAL(); #endif } } // Device Start-of-Frame received if (Is_usb_sof() && Is_usb_sof_interrupt_enabled()) { Usb_ack_sof(); Usb_sof_action(); } // Device Suspend event (no more USB activity detected) if (Is_usb_suspend() && Is_usb_suspend_interrupt_enabled()) { Usb_ack_suspend(); Usb_enable_wake_up_interrupt(); (void)Is_usb_wake_up_interrupt_enabled(); Usb_freeze_clock(); Usb_send_event(EVT_USB_SUSPEND); Usb_suspend_action(); } // Wake-up event (USB activity detected): Used to resume if (Is_usb_wake_up() && Is_usb_wake_up_interrupt_enabled()) { Usb_unfreeze_clock(); (void)Is_usb_clock_frozen(); Usb_ack_wake_up(); Usb_disable_wake_up_interrupt(); Usb_wake_up_action(); Usb_send_event(EVT_USB_WAKE_UP); } // Resume state bus detection if (Is_usb_resume() && Is_usb_resume_interrupt_enabled()) { Usb_disable_wake_up_interrupt(); Usb_ack_resume(); Usb_disable_resume_interrupt(); Usb_resume_action(); Usb_send_event(EVT_USB_RESUME); } // USB bus reset detection if (Is_usb_reset() && Is_usb_reset_interrupt_enabled()) { Usb_ack_reset(); usb_init_device(); Usb_reset_action(); Usb_send_event(EVT_USB_RESET); } } #endif // End DEVICE FEATURE MODE // ---------- HOST events management ------------------------------------------- #if USB_HOST_FEATURE == true #if USB_DEVICE_FEATURE == true // If both device and host features are enabled, check if host mode is engaged // (accessing the USB registers of a non-engaged mode, even with load operations, // may corrupt USB FIFO data). else #endif { // The device has been disconnected if (Is_host_device_disconnection() && Is_host_device_disconnection_interrupt_enabled()) { host_disable_all_pipes(); Host_ack_device_disconnection(); #if USB_HOST_PIPE_INTERRUPT_TRANSFER == ENABLE reset_it_pipe_str(); #endif device_state = DEVICE_UNATTACHED; LOG_STR(log_device_disconnected); Usb_send_event(EVT_HOST_DISCONNECTION); Host_device_disconnection_action(); #ifdef FREERTOS_USED // Release the semaphore in order to start a new device/host task taskENTER_CRITICAL(); xSemaphoreGiveFromISR(usb_tsk_semphr, &task_woken); taskEXIT_CRITICAL(); #endif } // Device connection if (Is_host_device_connection() && Is_host_device_connection_interrupt_enabled()) { Host_ack_device_connection(); host_disable_all_pipes(); Host_device_connection_action(); } // Host Start-of-Frame has been sent if (Is_host_sof() && Is_host_sof_interrupt_enabled()) { Host_ack_sof(); Usb_send_event(EVT_HOST_SOF); #if (USB_HIGH_SPEED_SUPPORT==true) if( Is_usb_full_speed_mode() ) { private_sof_counter++; }else{ private_sof_counter_HS++; if( 0 == (private_sof_counter_HS%8) ) { private_sof_counter++; } } #else private_sof_counter++; #endif // Delay time-out management for interrupt transfer mode in host mode #if USB_HOST_PIPE_INTERRUPT_TRANSFER == ENABLE && TIMEOUT_DELAY_ENABLE == ENABLE if (private_sof_counter >= 250) // Count 250 ms (SOF @ 1 ms) { private_sof_counter = 0; for (i = 0; i < MAX_PEP_NB; i++) { if (it_pipe_str[i].enable && ++it_pipe_str[i].timeout > TIMEOUT_DELAY && Host_get_pipe_type(i) != TYPE_INTERRUPT) { it_pipe_str[i].enable = false; it_pipe_str[i].status = PIPE_DELAY_TIMEOUT; Host_reset_pipe(i); if (!is_any_interrupt_pipe_active() && !g_sav_int_sof_enable) // If no more transfer is armed { Host_disable_sof_interrupt(); } it_pipe_str[i].handler(PIPE_DELAY_TIMEOUT, it_pipe_str[i].nb_byte_processed); } } } #endif Host_sof_action(); } // Host Wake-up has been received if (Is_host_hwup() && Is_host_hwup_interrupt_enabled()) { // CAUTION: HWUP can be cleared only when USB clock is active (not frozen)! //! @todo Implement this on the silicon version //Pll_start_auto(); // First Restart the PLL for USB operation //Wait_pll_ready(); // Make sure PLL is locked Usb_unfreeze_clock(); // Enable clock on USB interface (void)Is_usb_clock_frozen(); // Make sure USB interface clock is enabled Host_disable_hwup_interrupt(); // Wake-up interrupt should be disabled as host is now awoken! Host_ack_hwup(); // Clear HWUP interrupt flag Usb_send_event(EVT_HOST_HWUP); // Send software event Host_hwup_action(); // Map custom action } #if USB_HOST_PIPE_INTERRUPT_TRANSFER == ENABLE // Host pipe interrupts while ((i = Host_get_interrupt_pipe_number()) < MAX_PEP_NB) usb_pipe_interrupt(i); #endif } #endif // End HOST FEATURE MODE #ifdef FREERTOS_USED return task_woken; #endif }
void usb_host_task(void) #endif { #define DEVICE_DEFAULT_MAX_ERROR_COUNT 2 static uint8_t device_default_error_count; #ifdef HOST_VBUS_LOW_TIMEOUT extern t_cpu_time timer_vbus_low; #endif static bool sav_int_sof_enable; uint8_t pipe; #ifdef FREERTOS_USED portTickType xLastWakeTime; xLastWakeTime = xTaskGetTickCount(); while (true) { vTaskDelayUntil(&xLastWakeTime, configTSK_USB_HST_PERIOD); #endif // FREERTOS_USED switch (device_state) { #ifdef HOST_VBUS_LOW_TIMEOUT case DEVICE_VBUS_LOW: Usb_disable_vbus(); if (cpu_is_timeout(&timer_vbus_low)) usb_host_task_init(); break; #endif //------------------------------------------------------ // DEVICE_UNATTACHED state // // - Default init state // - Try to give device power supply // case DEVICE_UNATTACHED: device_default_error_count = 0; nb_interface_supported = 0; Host_clear_device_status(); // Reset device status Usb_clear_all_event(); // Clear all software events Host_disable_sof(); host_disable_all_pipes(); Usb_enable_vbus(); // Give at least device power supply! // If VBus OK, wait for device connection if (Is_usb_vbus_high()) device_state = DEVICE_ATTACHED; break; //------------------------------------------------------ // DEVICE_ATTACHED state // // - VBus is on // - Try to detect device connection // case DEVICE_ATTACHED: if (Is_host_device_connection() || Is_usb_event(EVT_HOST_CONNECTION) ) // Device pull-up detected { device_attached_retry: if( Is_usb_event(EVT_HOST_CONNECTION) ) { Usb_ack_event(EVT_HOST_CONNECTION); } Usb_ack_bconnection_error_interrupt(); Usb_ack_vbus_error_interrupt(); Host_ack_device_connection(); Host_clear_device_status(); // Reset device status cpu_irq_disable(); Host_disable_device_disconnection_interrupt(); Host_send_reset(); // First USB reset (void)Is_host_sending_reset(); cpu_irq_enable(); Usb_ack_event(EVT_HOST_SOF); // Active wait for end of reset send while (Is_host_sending_reset()) { // The USB macro does not signal the end of reset when a disconnection occurs if (Is_host_device_disconnection()) { // Stop sending USB reset Host_stop_sending_reset(); } } Host_ack_reset_sent(); Host_enable_sof(); // Start SOF generation Host_enable_sof_interrupt(); // SOF will be detected under interrupt if (!Is_host_device_disconnection()) { // Workaround for some buggy devices with powerless pull-up // usually low-speed where data line rises slowly and can be interpreted as disconnection for (sof_cnt = 0; sof_cnt < 0xFFFF; sof_cnt++) // Basic time-out counter { // If we detect SOF, device is still alive and connected, just clear false disconnect flag if (Is_usb_event(EVT_HOST_SOF) && Is_host_device_disconnection()) { Host_ack_device_connection(); Host_ack_device_disconnection(); break; } } } Host_enable_device_disconnection_interrupt(); sof_cnt = 0; while (sof_cnt < 100) // Wait 100 ms after USB reset { if (Is_usb_event(EVT_HOST_SOF)) Usb_ack_event(EVT_HOST_SOF), sof_cnt++; // Count SOFs if (Is_host_emergency_exit() || Is_usb_bconnection_error_interrupt()) goto device_attached_error; } device_state = DEVICE_POWERED; LOG_STR(log_device_connected); Host_device_connection_action(); sof_cnt = 0; } device_attached_error: // Device connection error, or VBus pb -> Retry the connection process from the beginning if (Is_usb_bconnection_error_interrupt() || Is_usb_vbus_error_interrupt() || Is_usb_vbus_low()) { if (device_state != DEVICE_VBUS_LOW) device_state = DEVICE_UNATTACHED; Usb_ack_bconnection_error_interrupt(); Usb_ack_vbus_error_interrupt(); Host_disable_sof(); } break; //------------------------------------------------------ // DEVICE_POWERED state // // - Device connection (attach) has been detected, // - Wait 100 ms and configure default control pipe // case DEVICE_POWERED: if (Is_usb_event(EVT_HOST_SOF)) { Usb_ack_event(EVT_HOST_SOF); if (sof_cnt++ >= 100) // Wait 100 ms { Host_enable_pipe(P_CONTROL); (void)Host_configure_pipe(P_CONTROL, 0, EP_CONTROL, TYPE_CONTROL, TOKEN_SETUP, 8, SINGLE_BANK); device_state = DEVICE_DEFAULT; } } break; //------------------------------------------------------ // DEVICE_DEFAULT state // // - Get device descriptor // - Reconfigure control pipe according to device control endpoint // - Assign device address // case DEVICE_DEFAULT: // Get first device descriptor if (host_get_device_descriptor_incomplete() == CONTROL_GOOD) { sof_cnt = 0; while (sof_cnt < 20) // Wait 20 ms before USB reset (special buggy devices...) { if (Is_usb_event(EVT_HOST_SOF)) Usb_ack_event(EVT_HOST_SOF), sof_cnt++; if (Is_host_emergency_exit() || Is_usb_bconnection_error_interrupt()) break; } cpu_irq_disable(); Host_disable_device_disconnection_interrupt(); Host_send_reset(); // First USB reset (void)Is_host_sending_reset(); cpu_irq_enable(); Usb_ack_event(EVT_HOST_SOF); // Active wait for end of reset send while (Is_host_sending_reset()) { // The USB macro does not signal the end of reset when a disconnection occurs if (Is_host_device_disconnection()) { // Stop sending USB reset Host_stop_sending_reset(); } } Host_ack_reset_sent(); if (!Is_host_device_disconnection()) { // Workaround for some buggy devices with powerless pull-up // usually low-speed where data line rises slowly and can be interpreted as disconnection for (sof_cnt = 0; sof_cnt < 0xFFFF; sof_cnt++) // Basic time-out counter { // If we detect SOF, device is still alive and connected, just clear false disconnect flag if (Is_usb_event(EVT_HOST_SOF) && Is_host_device_disconnection()) { Host_ack_device_connection(); Host_ack_device_disconnection(); break; } } } Host_enable_device_disconnection_interrupt(); sof_cnt = 0; while (sof_cnt < 200) // Wait 200 ms after USB reset { if (Is_usb_event(EVT_HOST_SOF)) Usb_ack_event(EVT_HOST_SOF), sof_cnt++; if (Is_host_emergency_exit() || Is_usb_bconnection_error_interrupt()) break; } Host_disable_pipe(P_CONTROL); Host_unallocate_memory(P_CONTROL); Host_enable_pipe(P_CONTROL); // Reconfigure the control pipe according to the device control endpoint (void)Host_configure_pipe(P_CONTROL, 0, EP_CONTROL, TYPE_CONTROL, TOKEN_SETUP, data_stage[OFFSET_FIELD_MAXPACKETSIZE], SINGLE_BANK); // Give an absolute device address if (host_set_address(DEVICE_ADDRESS) == CONTROL_GOOD) { for (pipe = 0; pipe < MAX_PEP_NB; pipe++) Host_configure_address(pipe, DEVICE_ADDRESS); device_state = DEVICE_ADDRESSED; } else if (device_state != DEVICE_VBUS_LOW) device_state = DEVICE_ERROR; } else { if (device_state != DEVICE_VBUS_LOW) { if (++device_default_error_count > DEVICE_DEFAULT_MAX_ERROR_COUNT) device_state = DEVICE_ERROR; else { Host_disable_sof(); Host_disable_pipe(P_CONTROL); Host_unallocate_memory(P_CONTROL); device_state = DEVICE_ATTACHED; goto device_attached_retry; } } Usb_ack_bconnection_error_interrupt(); Usb_ack_vbus_error_interrupt(); Host_disable_sof(); } break; //------------------------------------------------------ // DEVICE_ADDRESSED state // // - Check if VID PID is in supported list // case DEVICE_ADDRESSED: if (host_get_device_descriptor() == CONTROL_GOOD) { // Detect if the device connected belongs to the supported devices table if (host_check_VID_PID()) { Host_set_device_supported(); Host_device_supported_action(); device_state = DEVICE_CONFIGURED; } else { #if HOST_STRICT_VID_PID_TABLE == ENABLE device_state = DEVICE_ERROR; LOG_STR(log_unsupported_device); #else device_state = DEVICE_CONFIGURED; #endif Host_device_not_supported_action(); } } else if (device_state != DEVICE_VBUS_LOW) device_state = DEVICE_ERROR; // Can not get device descriptor break; //------------------------------------------------------ // DEVICE_CONFIGURED state // // - Configure pipes for the supported interface // - Send Set_configuration() request // - Go to full operating mode (device ready) // case DEVICE_CONFIGURED: { uint8_t configuration_index = 0; if (host_get_configuration_descriptor(configuration_index) == CONTROL_GOOD) { if (host_check_class()) // Class support OK? { #if HOST_AUTO_CFG_ENDPOINT == DISABLE User_configure_endpoint(); // User call here instead of autoconfig Host_set_configured(); // Assumes config is OK with user config #endif if (Is_host_configured()) { if (host_set_configuration(data_stage[OFFSET_FIELD_CONFIGURATION_NB]) == CONTROL_GOOD) // Send Set_configuration { // Device and host are now fully configured // go to DEVICE_READY normal operation device_state = DEVICE_READY; // Monitor device disconnection under interrupt Host_enable_device_disconnection_interrupt(); // If user host application requires SOF interrupt event // Keep SOF interrupt enabled, otherwise disable this interrupt #if HOST_CONTINUOUS_SOF_INTERRUPT == DISABLE cpu_irq_disable(); Host_disable_sof_interrupt(); (void)Is_host_sof_interrupt_enabled(); cpu_irq_enable(); #endif Host_new_device_connection_action(); cpu_irq_enable(); LOG_STR(log_device_enumerated); } else if (device_state != DEVICE_VBUS_LOW) device_state = DEVICE_ERROR; // Problem during Set_configuration request... } } else // Device class not supported... { device_state = DEVICE_UNSUPPORTED; LOG_STR(log_unsupported_device); Host_device_class_not_supported_action(); } } else if (device_state != DEVICE_VBUS_LOW) device_state = DEVICE_ERROR; // Can not get configuration descriptors... } break; //------------------------------------------------------ // DEVICE_READY state // // - Full standard operating mode // - Nothing to do... // case DEVICE_READY: // Host full standard operating mode! break; //------------------------------------------------------ // DEVICE_UNSUPPORTED state // case DEVICE_UNSUPPORTED: break; //------------------------------------------------------ // DEVICE_ERROR state // // - Error state // - Do custom action call (probably go to default mode...) // case DEVICE_ERROR: //! @todo #if HOST_ERROR_RESTART == ENABLE device_state = DEVICE_UNATTACHED; #endif Host_device_error_action(); break; //------------------------------------------------------ // DEVICE_SUSPENDED state // // - Host application request to suspend the device activity // - State machine comes here thanks to Host_request_suspend() // case DEVICE_SUSPENDED: if (Is_device_supports_remote_wakeup()) // If the connected device supports remote wake-up { host_set_feature_remote_wakeup(); // Enable this feature... } LOG_STR(log_usb_suspended); sav_int_sof_enable = Is_host_sof_interrupt_enabled(); //Save current SOF interrupt enable state cpu_irq_disable(); Host_disable_sof_interrupt(); (void)Is_host_sof_interrupt_enabled(); cpu_irq_enable(); Host_ack_sof(); Host_disable_sof(); // Stop SOF generation, this generates the suspend state Host_ack_hwup(); Host_enable_hwup_interrupt(); // Enable host wake-up interrupt // (this is the unique USB interrupt able to wake up the CPU core from power-down mode) (void)Is_host_hwup_interrupt_enabled(); // Make sure host wake-up interrupt is enabled Usb_freeze_clock(); //! @todo Implement this on the silicon version //Stop_pll(); Host_suspend_action(); // Custom action here! (e.g. go to power-save mode...) device_state = DEVICE_WAIT_RESUME; // Wait for device resume event break; //------------------------------------------------------ // DEVICE_WAIT_RESUME state // // Wait in this state till: // - the host receives an upstream resume from the device // - or the host software request the device to resume // case DEVICE_WAIT_RESUME: if (Is_usb_event(EVT_HOST_HWUP) || Is_host_request_resume()) // Remote wake-up has been detected // or local resume request has been received { if (Is_host_request_resume()) // Not a remote wake-up, but a host application request { // CAUTION: HWUP can be cleared only when USB clock is active //! @todo Implement this on the silicon version //Pll_start_auto(); // First Restart the PLL for USB operation //Wait_pll_ready(); // Make sure PLL is locked Usb_unfreeze_clock(); // Enable clock on USB interface (void)Is_usb_clock_frozen(); // Make sure USB interface clock is enabled cpu_irq_disable(); Host_disable_hwup_interrupt(); // Wake-up interrupt should be disabled as host is now awoken! (void)Is_host_hwup_interrupt_enabled(); cpu_irq_enable(); Host_ack_hwup(); // Clear HWUP interrupt flag } Host_enable_sof(); Host_send_resume(); // Send downstream resume while (!Is_host_down_stream_resume()); // Wait for downstream resume sent Host_ack_remote_wakeup(); // Ack remote wake-up reception Host_ack_request_resume(); // Ack software request Host_ack_down_stream_resume(); // Ack downstream resume sent Usb_ack_event(EVT_HOST_HWUP); // Ack software event if (sav_int_sof_enable) Host_enable_sof_interrupt(); // Restore SOF interrupt enable state before suspend device_state = DEVICE_READY; // Come back to full operating mode LOG_STR(log_usb_resumed); } break; //------------------------------------------------------ // default state // // - Default case: ERROR // - Go to DEVICE_UNATTACHED state // default: device_state = DEVICE_UNATTACHED; break; } #ifdef FREERTOS_USED } #endif }