Пример #1
0
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
}
Пример #2
0
__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
}
Пример #3
0
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
}