📄 usb_standard_requests.c
字号:
//-----------------------------------------------------------------------------
// USB_Standard_Requests.c
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Implementation details and suggestions
//-----------------------------------------------------------------------------
//
// [HALT and STALL handling on interrupt and bulk EPs]
// HALT is set to one by
// - Hardware (firmware) condition
// - SetFeature( ENDPOINT_HALT )
//
// HALT is reset to zero by
// - SetConfiguration(), SetInterface()
// - ClearFeature(ENDPOINT_HALT), if the hardware (firmware) condition meets
//
// GetStatus( ENDPOINT ) returns the HALT state of the EP.
// STALL is always returned by the EP while the EP is in HALT.
// Isochronous EP doesn't support HALT/STALL
//
// This implementaion fully supports this HALT scheme, exept for Hardware HALT
//
// [Data toggle handling on interrupt and bulk EPs]
// - Set to DATA0 on Set_Configuration and Set_Interface
// - Set to DATA0 on ClearFeature( ENDPOINT_HALT )
//
// This implementaion fully supports this data toggle scheme
//
// [Bus-powered/Self-powered]
// USB device can switch the actual power source on the fly.
// bmAttributes of the config descriptor shows the default power source.
// D6: 0 = pure bus-powered device
// 1 = pure self-powered or switchable device.
// bMaxPower of the config descriptor indicates power requirement from the bus in mA / 2
// pure bus-powered and switchable device has to set this value to other than 0
// when this value is less than or equal to 50 (=100mA), enumeration will always success
// but when more than 50, enumeration may fail
// GetStatus( DEVICE ) returns the current power source
// D0: 0 = bus-powered / 1 = self-powered.
//
// This implementaion gives a pure bus-powered device
//
// [Suspend/Resume and Remote wakeup]
// This sequence differs according to OS
// Windows
// Non remote wakeup device, System hibernates
// Suspend bus (stop SOF) - System standby (PC) - Suspend interrupt (device)
// ...
// bus reset - System wake up (PC) - (no Suspend interrupt)
// start enumeration again
//
// Remote wakeup device
// SetFeature( DEVICE_REMOTE_WAKEUP )
// Suspend bus (stop SOF) - System standby (PC) - Suspend interrupt (device)
// ...
// Resume bus (start SOF) - System wake up (PC) - Resume interrupt (device)
// ClearFeature( DEVICE_REMOTE_WAKEUP )
//
// MacOSX
// Non remote wakeup device
// Suspend bus (stop SOF) - System sleep (Mac) - Suspend interrupt (device)
// ...
// Resume bus (start SOF) - System wake up (Mac) - Resume interrupt (device)
// GetStatus( ENDPOINT ) (MSC) - depends on the class
//
// Remote wakeup device
// SetFeature( DEVICE_REMOTE_WAKEUP ) - at the end of enumeration
// ...
// Suspend bus (stop SOF) - System sleep (Mac) - Suspend interrupt (device)
// ...
// Resume bus (start SOF) - System wake up (Mac) - Resume interrupt (device)
//
// Linux
// Linux seems not yet to establish suspend well
//
// This implementation gives non-remote-wakeup device
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------
#include "USB_Type.h"
#include "USB_Configuration.h"
#include "USB_Register.h"
#include "USB_Descriptor.h"
#include "USB_ISR.h"
#include "USB_CDC_UART.h"
#include "USB_Main.h"
#include "USB_Standard_Requests.h"
//-----------------------------------------------------------------------------
// Global Variables
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Static Variables in this file
//-----------------------------------------------------------------------------
// These are response packets used for communication with host
static BYTE code ONES_PACKET[2] = {0x01, 0x00};
static BYTE code ZERO_PACKET[2] = {0x00, 0x00};
//-----------------------------------------------------------------------------
// Local function prototypes
//-----------------------------------------------------------------------------
static void Get_Status(void);
static void Clear_Feature(void);
static void Set_Feature(void);
static void Set_Address(void);
static void Get_Descriptor(void);
static void Get_Configuration(void);
static void Set_Configuration(void);
static void Get_Interface(void);
static void Set_Interface(void);
static bit Set_Halt( BYTE endpoint, BYTE status );
//-----------------------------------------------------------------------------
// configuration conditions
//-----------------------------------------------------------------------------
#if (defined USE_EP1_OUT) && !(defined ENABLE_EP1_OUT_ISO)
#define USE_EP1_OUT_STATUS
#endif
#if (defined USE_EP2_OUT) && !(defined ENABLE_EP2_OUT_ISO)
#define USE_EP2_OUT_STATUS
#endif
#if (defined USE_EP3_OUT) && !(defined ENABLE_EP3_OUT_ISO)
#define USE_EP3_OUT_STATUS
#endif
#if (defined USE_EP1_IN) && !(defined ENABLE_EP1_IN_ISO)
#define USE_EP1_IN_STATUS
#endif
#if (defined USE_EP2_IN) && !(defined ENABLE_EP2_IN_ISO)
#define USE_EP2_IN_STATUS
#endif
#if (defined USE_EP3_IN) && !(defined ENABLE_EP3_IN_ISO)
#define USE_EP3_IN_STATUS
#endif
//-----------------------------------------------------------------------------
// SDCC suport
//-----------------------------------------------------------------------------
#if defined SDCC
#pragma nooverlay
#endif // SDCC
//-----------------------------------------------------------------------------
// Standard device request dispatcher
//-----------------------------------------------------------------------------
void Standard_Device_Request( void )
{
switch(Setup.bRequest)
{
case GET_STATUS: Get_Status(); break;
case CLEAR_FEATURE: Clear_Feature(); break;
case SET_FEATURE: Set_Feature(); break;
case SET_ADDRESS: Set_Address(); break;
case GET_DESCRIPTOR: Get_Descriptor(); break;
case GET_CONFIGURATION: Get_Configuration(); break;
case SET_CONFIGURATION: Set_Configuration(); break;
case GET_INTERFACE: Get_Interface(); break;
// case SET_INTERFACE: Set_Interface(); break;
case STD_REQ_RESERVE1:
case STD_REQ_RESERVE2:
case SET_DESCRIPTOR:
case SET_INTERFACE:
case SYNCH_FRAME:
default: break;
}
}
//-----------------------------------------------------------------------------
// Support Subroutines
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Get_Status
//-----------------------------------------------------------------------------
//
// Get_Status( DEVICE ) : returns the current state of
// a) bus-powered/self-powered
// b) remote wakeup enabled/disabled
// Get_Status( INTERFACE ) : returns always 0x00
// Get_Status( ENDPOINT ) : returns current state of EP HALT
//
//-----------------------------------------------------------------------------
static void Get_Status(void)
{
bit aStatus;
// Valid when wValue equals to zero, and wLength (data length) equals to 2
if ( (Setup.wValue.i == 0) && (Setup.wLength.i == 2) )
{
// Determine if recipient was device, interface, or EP
switch( Setup.bmRequestType )
{
case IN_DEVICE: // If recipient was device
if ( Setup.wIndex.i == 0 ) // Valid when wIndex equals to zero
{
// send 0x00, indicating bus power and no remote wake-up supported
DataPtr = (BYTE*)&ZERO_PACKET;
setup_handled = TRUE;
}
break;
case IN_INTERFACE: // See if recipient was interface
// Valid if device is configured and existing interface index
if ( (USB_State == DEV_CONFIGURED) && (Setup.wIndex.i < DSC_NUM_INTERFACE) )
{
// Status packet always returns 0x00
DataPtr = (BYTE*)&ZERO_PACKET;
setup_handled = TRUE;
}
break;
case IN_ENDPOINT: // See if recipient was an endpoint
// Make sure device is configured and index msb = 0x00
if ((USB_State == DEV_CONFIGURED) && (Setup.wIndex.c[MSB] == 0) )
{
aStatus = EP_IDLE;
switch ( Setup.wIndex.c[LSB] )
{
#ifdef USE_EP1_OUT_STATUS
case EP1_OUT: aStatus = Ep_StatusOUT1; setup_handled = TRUE; break;
#endif
#ifdef USE_EP2_OUT_STATUS
case EP2_OUT: aStatus = Ep_StatusOUT2; setup_handled = TRUE; break;
#endif
#ifdef USE_EP3_OUT_STATUS
case EP3_OUT: aStatus = Ep_StatusOUT3; setup_handled = TRUE; break;
#endif
#ifdef USE_EP1_IN_STATUS
case EP1_IN: aStatus = Ep_StatusIN1; setup_handled = TRUE; break;
#endif
#ifdef USE_EP2_IN_STATUS
case EP2_IN: aStatus = Ep_StatusIN2; setup_handled = TRUE; break;
#endif
#ifdef USE_EP3_IN_STATUS
case EP3_IN: aStatus = Ep_StatusIN3; setup_handled = TRUE; break;
#endif
default: break;
}
if (aStatus == EP_HALT)
{
// If endpoint is halted, return 0x01,0x00
DataPtr = (BYTE*)&ONES_PACKET;
} else {
// Otherwise return 0x00,0x00 to indicate endpoint active
DataPtr = (BYTE*)&ZERO_PACKET;
}
}
break;
default:
break;
}
}
if ( setup_handled )
{
// Set serviced Setup Packet, Endpoint 0 intransmit mode,
Ep_Status0 = EP_TX;
DataSize = 2;
}
}
//-----------------------------------------------------------------------------
// Set_Halt
//-----------------------------------------------------------------------------
//
// Helper routine to set/reset HALT on the EP
// endpoint: Endopoint address, (EP1_OUT, EP1_IN, etc) defined in USB_Descriptor.h
// status: EP_IDLE / EP_HALT
//
// Set/Reset HALT flag to the specified EP
// Enable/disable STALL on the EP
// Clear the data toggle
//
//-----------------------------------------------------------------------------
static bit Set_Halt( BYTE endpoint, BYTE status )
{
BYTE controlReg;
switch ( endpoint ) {
#ifdef USE_EP1_OUT_STATUS
case EP1_OUT: Ep_StatusOUT1 = status; break;
#endif
#ifdef USE_EP2_OUT_STATUS
case EP2_OUT: Ep_StatusOUT2 = status; break;
#endif
#ifdef USE_EP3_OUT_STATUS
case EP3_OUT: Ep_StatusOUT3 = status; break;
#endif
#ifdef USE_EP1_IN_STATUS
case EP1_IN: Ep_StatusIN1 = status; break;
#endif
#ifdef USE_EP2_IN_STATUS
case EP2_IN: Ep_StatusIN2 = status; break;
#endif
#ifdef USE_EP3_IN_STATUS
case EP3_IN: Ep_StatusIN3 = status; break;
#endif
default: return FALSE;
}
POLL_WRITE_BYTE (INDEX, endpoint & 0x7F); // Set endpoint index masking IN/OUT bit
if ( endpoint & 0x80 ) { // IN endpoints
if ( status == EP_IDLE )
controlReg = (rbInCLRDT | rbInFLUSH); // clear data toggle, SDSTL, STSTL
else
controlReg = (rbInCLRDT | rbInSDSTL | rbInFLUSH); // send STALL
POLL_WRITE_BYTE( EINCSRL, controlReg );
#if (defined ENABLE_EP1_IN_DOUBLE_BUF) || (defined ENABLE_EP2_IN_DOUBLE_BUF) || (defined ENABLE_EP3_IN_DOUBLE_BUF)
{ // clear double buffer
BYTE eincsrl;
do { // wait until FLUSH complete
POLL_READ_BYTE( EINCSRL, eincsrl );
} while ( eincsrl & rbInFLUSH );
if ( eincsrl & rbInFIFONE ) { // clear double buffer
POLL_WRITE_BYTE( EINCSRL, controlReg );
}
}
#endif
} else { // OUT endpoints
if ( status == EP_IDLE )
controlReg = (rbOutCLRDT | rbOutFLUSH); // clear data toggle, SDSTL, STSTL
else
controlReg = (rbOutCLRDT | rbOutSDSTL | rbOutFLUSH); // send STALL
POLL_WRITE_BYTE( EOUTCSRL, controlReg );
#if (defined ENABLE_EP1_OUT_DOUBLE_BUF) || (defined ENABLE_EP2_OUT_DOUBLE_BUF) || (defined ENABLE_EP3_OUT_DOUBLE_BUF)
{ // clear double buffer
BYTE eoutcsrl;
do { // wait until FLUSH complete
POLL_READ_BYTE( EOUTCSRL, eoutcsrl );
} while ( eoutcsrl & rbOutFLUSH );
POLL_WRITE_BYTE( EOUTCSRL, controlReg );// clear double buffer
}
#endif
}
// initialize USB-related variables
// because the FIFO is flushed
if ( endpoint == EP1_IN )
IN1_FIFO_empty = TRUE;
if ( endpoint == EP2_IN )
IN2_FIFO_empty = TRUE;
if ( endpoint == EP3_IN )
IN2_FIFO_empty = TRUE;
if ( endpoint == EP1_OUT )
OUT1_FIFO_loaded = FALSE;
if ( endpoint == EP2_OUT )
OUT2_FIFO_loaded = FALSE;
if ( endpoint == EP3_OUT )
OUT3_FIFO_loaded = FALSE;
return TRUE;
}
//-----------------------------------------------------------------------------
// Clear_Feature
//-----------------------------------------------------------------------------
//
// Clear_Feature( DEVICE_REMOTE_WAKEUP ): disable remote wakeup
// Clear_Feature( ENDPOINT_HALT ) : clear HALT satate of the EP
//
//-----------------------------------------------------------------------------
static void Clear_Feature()
{
if ( (USB_State == DEV_CONFIGURED) // Make sure device is configured
&& (Setup.wLength.i == 0) ) // and data length set to zero.
{
switch( Setup.bmRequestType )
{
case OUT_DEVICE: // for device, if remote wakeup is valid
if ( (Setup.wValue.i == DEVICE_REMOTE_WAKEUP)
&& (Setup.wIndex.i == 0) )
{
// disable remote wakeup here
setup_handled = TRUE;
}
break;
case OUT_ENDPOINT: // for endpoint, if endpoint halt is valid
if ( (Setup.wValue.i == ENDPOINT_HALT)
&& (Setup.wIndex.c[MSB] == 0) )
{
if ( Set_Halt( Setup.wIndex.c[LSB], EP_IDLE ) )
setup_handled = TRUE;
}
break;
default:
break;
}
}
}
//-----------------------------------------------------------------------------
// Set_Feature
//-----------------------------------------------------------------------------
//
// Set_Feature( DEVICE_REMOTE_WAKEUP ) : enable remote wakeup
// Set_Feature( ENDPOINT_HALT ) : set HALT satate to the EP
//
//-----------------------------------------------------------------------------
static void Set_Feature(void)
{
if ( (USB_State == DEV_CONFIGURED) // Make sure device is configured
&& (Setup.wLength.i == 0) ) // and data length set to zero.
{
switch( Setup.bmRequestType )
{
case OUT_DEVICE: // for device, if remote wakeup is valid
if ( (Setup.wValue.i == DEVICE_REMOTE_WAKEUP)
&& (Setup.wIndex.i == 0) )
{
// enable remote wakeup here
setup_handled = TRUE;
}
break;
case OUT_ENDPOINT: // for endpoint, if endpoint halt is valid
if ( (Setup.wValue.i == ENDPOINT_HALT)
&& (Setup.wIndex.c[MSB] == 0) )
{
if ( Set_Halt( Setup.wIndex.c[LSB], EP_HALT ) )
setup_handled = TRUE;
}
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -