📄 usb_host_task.c
字号:
/**
* @file usb_host_task.c,v
*
* Copyright (c) 2004 Atmel.
*
* Please read file license.txt for copyright notice.
*
* @brief This file manages the USB Host controller, the host enumeration process
* and suspend resume host requests.
*
* This task dos not belongs to the scheduler tasks but is called directly from the general usb_task
*
* @version 1.19 at90usb128-usbkey-demo-3enum-host-mouse-1_0_4 $Id: usb_host_task.c,v 1.19 2006/10/13 13:34:12 rletendu Exp $
*
*
* @todo
* @bug
*/
//_____ I N C L U D E S ___________________________________________________
#include "config.h"
#include "conf_usb.h"
#include "modules/usb/usb_task.h"
#include "usb_host_task.h"
#include "lib_mcu/usb/usb_drv.h"
#include "lib_mcu/pll/pll_drv.h"
#include "modules/usb/host_chap9/usb_host_enum.h"
#if (USB_HOST_FEATURE == DISABLED)
#warning trying to compile a file used with the USB HOST without USB_HOST_FEATURE enabled
#endif
#if (USB_HOST_FEATURE == ENABLED)
#ifndef DEVICE_ADDRESS
#error DEVICE_ADDRESS should be defined somewhere in config files (conf_usb.h)
#endif
#ifndef SIZEOF_DATA_STAGE
#error SIZEOF_DATA_STAGE should be defined in conf_usb.h
#endif
#ifndef HOST_CONTINUOUS_SOF_INTERRUPT
#error HOST_CONTINUOUS_SOF_INTERRUPT should be defined as ENABLE or DISABLE in conf_usb.h
#endif
#ifndef USB_HOST_PIPE_INTERRUPT_TRANSFER
#error USB_HOST_PIPE_INTERRUPT_TRANSFER should be defined as ENABLE or DISABLE in conf_usb.h
#endif
#ifndef Usb_id_transition_action
#define Usb_id_transition_action()
#endif
#ifndef Host_device_disconnection_action
#define Host_device_disconnection_action()
#endif
#ifndef Host_device_connection_action
#define Host_device_connection_action()
#endif
#ifndef Host_sof_action
#define Host_sof_action()
#endif
#ifndef Host_suspend_action
#define Host_suspend_action()
#endif
#ifndef Host_hwup_action
#define Host_hwup_action()
#endif
#ifndef Host_device_not_supported_action
#define Host_device_not_supported_action()
#endif
#ifndef Host_device_class_not_supported_action
#define Host_device_class_not_supported_action()
#endif
#ifndef Host_device_supported_action
#define Host_device_supported_action()
#endif
#ifndef Host_device_error_action
#define Host_device_error_action()
#endif
//_____ M A C R O S ________________________________________________________
#ifndef LOG_STR_CODE
#define LOG_STR_CODE(str)
#else
U8 code log_device_connected[]="Device Connection";
U8 code log_device_enumerated[]="Device Enumerated";
U8 code log_device_unsupported[]="Unsupported Device";
U8 code log_going_to_suspend[]="Usb suspend";
U8 code log_usb_resumed[]="Usb resumed";
#endif
//_____ D E F I N I T I O N S ______________________________________________
//_____ D E C L A R A T I O N S ____________________________________________
#if (USB_HOST_PIPE_INTERRUPT_TRANSFER == ENABLE)
volatile S_pipe_int it_pipe_str[MAX_EP_NB];
volatile U8 pipe_nb_save;
U8 g_sav_int_sof_enable;
#endif
//!
//! Public : U8 device_state
//! Its value represent the current state of the
//! device connected to the usb host controller
//! Value can be:
//! - DEVICE_ATTACHED
//! - DEVICE_POWERED
//! - DEVICE_SUSPENDED
//! - DEVICE_DEFAULT
//! - DEVICE_ADDRESSED
//! - DEVICE_CONFIGURED
//! - DEVICE_ERROR
//! - DEVICE_UNATTACHED
//! - DEVICE_READY
//! - DEVICE_WAIT_RESUME
//! - DEVICE_DISCONNECTED
//! - DEVICE_DISCONNECTED_ACK
//!/
U8 device_state;
//! For control requests management over pipe 0
S_usb_setup_data usb_request;
//!
//! Public : U8 data_stage[SIZEOF_DATA_STAGE];
//! Internal RAM buffer for USB data stage content
//! This buffer is required to setup host enumeration process
//! Its contains the device descriptors received.
//! Depending on the device descriptors lenght, its size can be optimized
//! with the SIZEOF_DATA_STAGE define of conf_usb.h file
//!
//!/
U8 data_stage[SIZEOF_DATA_STAGE];
U8 device_status;
U8 request_resume;
U8 force_enumeration=FALSE;
static U16 c; // As internal host start of frame counter
U8 new_device_connected=0;
/**
* @brief This function initializes the USB controller in host mode and
* the associated variables.
*
* This function enables the USB controller for host mode operation.
*
* @param none
*
* @return none
*
*/
void usb_host_task_init(void)
{
Pll_start_auto();
Wait_pll_ready();
Usb_disable();
Usb_enable();
Usb_unfreeze_clock();
Usb_attach();
Usb_enable_uvcon_pin();
Usb_select_host();
Usb_disable_vbus_hw_control(); // Force Vbus generation without timeout
Host_enable_device_disconnection_interrupt();
device_state=DEVICE_UNATTACHED;
}
/**
* @brief Entry point of the USB host management
*
* The aim is to manage the device target connection and enumeration
* depending on the device_state, the function performs the required operations
* to get the device enumerated and configured
* Once the device is operationnal, the device_state value is DEVICE_READY
* This state should be tested by the host task application before performing
* any applicative requests to the device.
*
* @param none
*
* @return none
*
* \image html host_task.gif
*/
void usb_host_task(void)
{
switch (device_state)
{
//------------------------------------------------------
// DEVICE_UNATTACHED state
//
// - Default init state
// - Try to give device power supply
//
case DEVICE_UNATTACHED:
for (c=0;c<MAX_EP_NB;c++) {ep_table[c]=0;}// Reset PIPE lookup table with device EP addr
nb_interface_supported=0;
Host_clear_device_supported(); // Reset Device status
Host_clear_configured();
Host_clear_device_ready();
Usb_clear_all_event(); // Clear all software events
new_device_connected=0;
#if (SOFTWARE_VBUS_CTRL==ENABLE)
if( Is_usb_bconnection_error_interrupt()||Is_usb_vbus_error_interrupt())
{
Usb_ack_bconnection_error_interrupt();
Usb_ack_vbus_error_interrupt();
Host_clear_vbus_request();
}
Usb_disable_vbus_pad();
Usb_enable_manual_vbus();
if(Is_usb_srp_interrupt())
{
Usb_ack_srp_interrupt();
Usb_enable_vbus_pad();
Usb_enable_vbus();
device_state=DEVICE_ATTACHED;
}
#else
Usb_enable_vbus(); // Give at least device power supply!!!
if(Is_usb_vbus_high())
{ device_state=DEVICE_ATTACHED; } // If VBUS ok goto to device connection expectation
#endif
break;
//------------------------------------------------------
// DEVICE_ATTACHED state
//
// - Vbus is on
// - Try to detected device connection
//
case DEVICE_ATTACHED :
if (Is_device_connection() || (force_enumeration==TRUE)) // Device pull-up detected
{
Host_ack_device_connection();
for (c=0;c<MAX_EP_NB;c++) {ep_table[c]=0;}// Reset PIPE lookup table with device EP addr
nb_interface_supported=0;
Host_clear_device_supported(); // Reset Device status
Host_clear_configured();
Host_clear_device_ready();
Usb_clear_all_event(); // Clear all software events
new_device_connected=0;
force_enumeration=FALSE;
// Now device is connected, enable disconnection interrupt
Host_enable_device_disconnection_interrupt();
Enable_interrupt();
// Reset device status
Host_clear_device_supported();
Host_clear_configured();
Host_clear_device_ready();
Host_enable_sof(); // Start Start Of Frame generation
Host_enable_sof_interrupt(); // SOF will be detected under interrupt
c = 0;
while (c<100) // wait 100ms before USB reset
{
if (Is_usb_event(EVT_HOST_SOF)) { Usb_ack_event(EVT_HOST_SOF); c++; }// Count Start Of frame
if (Is_host_emergency_exit() || Is_usb_bconnection_error_interrupt()) {goto device_attached_error;}
}
Host_disable_device_disconnection_interrupt();
Host_send_reset(); // First USB reset
Usb_ack_event(EVT_HOST_SOF);
while (Is_host_reset()); // Active wait of end of reset send
Host_ack_reset();
//Workaround for some bugly devices with powerless pull up
//usually low speed where data line rise slowly and can be interpretaded as disconnection
for(c=0;c!=0xFFFF;c++) // Basic Timeout counter
{
if(Is_usb_event(EVT_HOST_SOF)) //If we detect SOF, device is still alive and connected, just clear false disconnect flag
{
if(Is_device_disconnection())
{
Host_ack_device_connection();
Host_ack_device_disconnection();
break;
}
}
}
Host_enable_device_disconnection_interrupt();
c = 0;
while (c<100) // wait 100ms after USB reset
{
if (Is_usb_event(EVT_HOST_SOF)) { Usb_ack_event(EVT_HOST_SOF); c++; }// Count Start Of frame
if (Is_host_emergency_exit() || Is_usb_bconnection_error_interrupt()) {goto device_attached_error;}
}
device_state = DEVICE_POWERED;
c=0;
}
device_attached_error:
// Device connection error, or vbus pb -> Retry the connection process from the begining
if( Is_usb_bconnection_error_interrupt()||Is_usb_vbus_error_interrupt()||Is_usb_vbus_low())
{
Usb_ack_bconnection_error_interrupt();
Usb_enable_vbus_hw_control();
device_state=DEVICE_UNATTACHED;
Usb_disable_vbus();
Usb_disable_vbus_pad();
Usb_enable_vbus_pad();
Usb_ack_vbus_error_interrupt();
Usb_enable_vbus();
Usb_disable_vbus_hw_control();
Host_disable_sof();
}
break;
//------------------------------------------------------
// DEVICE_POWERED state
//
// - Device connection (attach) as been detected,
// - Wait 100ms and configure default control pipe
//
case DEVICE_POWERED :
LOG_STR_CODE(log_device_connected);
Host_device_connection_action();
if (Is_usb_event(EVT_HOST_SOF))
{
Usb_ack_event(EVT_HOST_SOF);
if (c++ >= 100) // Wait 100ms
{
device_state = DEVICE_DEFAULT;
Host_select_pipe(PIPE_CONTROL);
Host_enable_pipe();
host_configure_pipe(PIPE_CONTROL, \
TYPE_CONTROL, \
TOKEN_SETUP, \
EP_CONTROL, \
SIZE_8, \
ONE_BANK, \
0 );
device_state = DEVICE_DEFAULT;
}
}
break;
//------------------------------------------------------
// DEVICE_DEFAULT state
//
// - Get device descriptor
// - Reconfigure Pipe 0 according to Device EP0
// - Attribute device address
//
case DEVICE_DEFAULT :
// Get first device descriptor
if( CONTROL_GOOD == host_get_device_descriptor_uncomplete())
{
c = 0;
while(c<20) // wait 20ms before USB reset (special buggly devices...)
{
if (Is_usb_event(EVT_HOST_SOF)) { Usb_ack_event(EVT_HOST_SOF); c++; }
if (Is_host_emergency_exit() || Is_usb_bconnection_error_interrupt()) {break;}
}
Host_disable_device_disconnection_interrupt();
Host_send_reset(); // First USB reset
Usb_ack_event(EVT_HOST_SOF);
while (Is_host_reset()); // Active wait of end of reset send
Host_ack_reset();
//Workaround for some bugly devices with powerless pull up
//usually low speed where data line rise slowly and can be interpretaded as disconnection
for(c=0;c!=0xFFFF;c++) // Basic Timeout counter
{
if(Is_usb_event(EVT_HOST_SOF)) //If we detect SOF, device is still alive and connected, just clear false disconnect flag
{
if(Is_device_disconnection())
{
Host_ack_device_connection();
Host_ack_device_disconnection();
break;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -