⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 usb_standard_requests.c

📁 USB CDC using C8051F320/340, virtual COM port thru usb connection
💻 C
📖 第 1 页 / 共 2 页
字号:
//-----------------------------------------------------------------------------
// 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 + -