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

📄 usb_lib.c

📁 HID-Ukey底层源码实现(st72651芯片) windows上层驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
/**************** (c) 2000  STMicroelectronics *******************************

NAME:		usb_lib.c
PROJECT:	USB - ST7 FULL SPEED
VERSION:	v 1.0
CREATION:	20/12/2001
AUTHOR:		MICROCONTROLLER DIVISION / ST Rousset

-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
		Functions for handling USB standard request on EP0
-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-

MODIFICATIONS : 

******************************************************************************/

#include "mcu_conf.h"
#include "usb_reg.h"
#include "usb_def.h"
#include "usb_app.h"
#include "usb_libs.h"

#pragma DATA_SEG SHORT USB_RAM0		// Map USB variables into page 0 (short addressing RAM)

//***************************************************************************
//*******  INTERNAL USB Library variables, used only in the USB core  *******
//***************************************************************************
extern unsigned char _Token_OverRun;	// when it's set, stop SETUP process

// USB State Machine value, see _vUSB_StateMachine selector in Usb_def.h
static char _vUSB_StateMachine;	// States of the USB state machine
static char	_vUSB_Report[2];			// Used to report status to host.

//***************************************************************************
//******  Following variables are exported to the outside of the code *******
//***************************************************************************
#ifdef	LARGE_EP0
unsigned short	vUSB_offset;	// Offset of the data stream for data IN stage
unsigned short	vUSB_length;	// Length remain of the data stream for data IN stage
#else
unsigned char	vUSB_offset;	// Offset of the data stream for data IN stage
unsigned char	vUSB_length;	// Length remain of the data stream for data IN stage
#endif
char	*vUSB_DataToSend;		// Data pointer for data IN stage
char	_vUSB_Data_OUT_Len;		// Used to get data length of a data OUT stage

char	vUSB_Configuration;		// Current configurationn value
char	vUSB_Current_Feature;	// D6: Power feature; 1=Self-Power, 0=Bus-Power
								// D5: Remote-wakeup: 1=Support, 0=Not support
								// D1: Remote-wakeup: 1=Enable, 0=Disable
								// Other bits: Reserved as 0

_USB_VSETUP	sUSB_vSetup;		// Internal storage for SETUP package


//************************* CODE SEGMENT ************************************
#pragma CODE_SEG USB_CODE 

#define _USB_SetEP0TxRx(Tx, Rx)	EP0R = (EP0R & 0xCC) | (Rx | (Tx << 4))
#define Non_Standard_Request	{ asm JP	UI.USER_Setup:-1; }

//***************************************************************************
//****************** Const array imported from user space *******************
//***************************************************************************
#pragma INTO_ROM
//extern const ONE_DESCRIPTOR DeviceDescriptor;
extern ONE_DESCRIPTOR DeviceDescriptor;
#pragma INTO_ROM
extern const ONE_DESCRIPTOR ConfigDescriptor[1];
#pragma INTO_ROM
extern const ONE_DESCRIPTOR StringDescriptor[1];


//***************************************************************************
//*******  INTERNAL USB Library functions, used only in the USB core  *******
//***************************************************************************
char _USB_GetEPStatus(char Endpoint);
void _USB_Clr_Feature_EP(void);
void _USB_Set_Feature_EP(void);
void _USB_CopydataIN(void);
char _USB_CopydataOUT(void);

/*-----------------------------------------------------------------------------
ROUTINE NAME : RequestError
INPUT/OUTPUT : None
DESCRIPTION  : Stall next Data or Status Stage.
				Function called when an irrelevant request has been received.
-----------------------------------------------------------------------------*/
void RequestError(void)
{
	// RequestError is called only during enumeration -> STALL EP0 both dir.
	EP0R = 0x11;	// TX Stall, RX Stall (only SETUP token will be ACKed)
	_vUSB_StateMachine = STATE_ERROR;
}

void RequestType_0x00(void);
void RequestType_0x80(void);
void RequestType_0x01(void);
void RequestType_0x81(void);
void RequestType_0x02(void);
void RequestType_0x82(void);

//----------------------------------------------------------------------------
//-------- Table_RequestType is a jump table for dispatching requests --------
//----------------------------------------------------------------------------
#pragma	NO_RETURN
void Table_RequestType(void)
{
	asm {
		JP		RequestType_0x00	// H->D Standard Device
		JP		RequestType_0x80	// D->H Standard Device
		JP		RequestType_0x01	// H->D Standard Interface
		JP		RequestType_0x81	// D->H Standard Interface
		JP		RequestType_0x02	// H->D Standard Endpoint
		JP		RequestType_0x82	// D->H Standard Endpoint
		JP		UI.USER_Setup:-1
		JP		UI.USER_Setup:-1
	}
}

/*****************************************************************************
ROUTINE NAME : USB_SETUP_Stage
DESCRIPTION  : This function is called when a SETUP packet is received
               The SETUP packet is copied and dispached to different routine
*****************************************************************************/
void USB_SETUP_Stage(void)
{
	vUSB_DataToSend = NULL;
//	_vUSB_StateMachine 				= SETTING_UP;	// For testing 

	sUSB_vSetup.USBbRequest			= EP0_OUT[1];	// save current bRequest
	sUSB_vSetup.USBbmRequestType 	= EP0_OUT[0];	// save current bmRequestType

	// Copy SETUP packet to sUSB_vSetup and set the sUSB_vSetup.Flag accordingly
	asm {
		CLR		A							// A = sUSB_vSetup.Flag
		LD		X, EP0_OUT:3
		LD		sUSB_vSetup.USBwValue1, X	// Copy high byte of wValue
		JREQ	Cp_wValue0
		OR		A, #NON0_wValue1			// Set flag for high byte of wValue is not 0
Cp_wValue0:
		LD		X, EP0_OUT:2
		LD		sUSB_vSetup.USBwValue0, X	// Copy low byte of wValue
		JREQ	Cp_wIndex1
		OR		A, #NON0_wValue0			// Set flag for low byte of wValue is not 0
Cp_wIndex1:
		LD		X, EP0_OUT:5
		LD		sUSB_vSetup.USBwIndex1, X	// Copy high byte of wIndex
		JREQ	Cp_wIndex0
		OR		A, #NON0_wIndex1			// Set flag for high byte of wIndex is not 0
Cp_wIndex0:
		LD		X, EP0_OUT:4
		LD		sUSB_vSetup.USBwIndex0, X	// Copy low byte of wIndex
		JREQ	Cp_wLength1
		OR		A, #NON0_wIndex0			// Set flag for low byte of wIndex is not 0
Cp_wLength1:
		LD		X, EP0_OUT:7
		LD		sUSB_vSetup.USBwLength1, X	// Copy high byte of wLength
		JREQ	Cp_wLength0
		OR		A, #NON0_wLength1			// Set flag for high byte of wLength is not 0
Cp_wLength0:
		LD		X, EP0_OUT:6
		LD		sUSB_vSetup.USBwLength0, X	// Copy low  byte of wLength
		JREQ	Set_ZeroFlag
		OR		A, #NON0_wLength0			// Set flag for low byte of wLength is not 0
		BCP		A, #NON0_wLength1			// Check if wLength = 1 or 2
		JRNE	Set_ZeroFlag
		CP		X, #2
		JRUGT	Set_ZeroFlag
		JREQ	wLength_is_2
		OR		A, #ONE_wLength				// Set flag for wLength==1
		JRT		Set_ZeroFlag
wLength_is_2:
		OR		A, #TWO_wLength				// Set flag for wLength==2
Set_ZeroFlag:
		LD		sUSB_vSetup.Flag, A
	}

	// Stop the SETUP packet processing if SETUP overrun is detected.
	if (_Token_OverRun)
		return;

	// Preset the machine state for the next step
	if ((sUSB_vSetup.Flag & NON0_wLength) == 0)	// wLength == 0
		_vUSB_StateMachine = WAIT_STATUS_IN;
	else if ((sUSB_vSetup.USBbmRequestType & 0x80) == 0)
		_vUSB_StateMachine = OUT_DATA;	
	else
		_vUSB_StateMachine = IN_DATA;

	// Dispatch requests to the correspond routine
	asm {
		LD		A, sUSB_vSetup.USBbmRequestType
		BCP		A, #0x7C
		JREQ	Standard_Requests
		CALL	UI.USER_Setup:-1			// Non standard requests
		JRT		Post_Requests
Standard_Requests:
		ADD		A, #0x80
		RLC		A
		LD		X, #3
		MUL		X, A
		LD		X, A
		CALL	(Table_RequestType,X)
Post_Requests:
	}

	if ((_vUSB_StateMachine & MACHINESTATE) == IN_DATA) { // IN_DATA or ONE_MORE_IN STATE
		vUSB_offset = 0;
		_USB_CopydataIN();			// Copy data to the endpoint buffer with such request
	}
}

/*****************************************************************************
ROUTINE NAME : USB_Data_IN_Stage
DESCRIPTION  : This function is called when a data stage packet is sent
		Copy the next data packet to the endpoint buffer if it is necessary
*****************************************************************************/
void USB_Data_IN_Stage(void)
{
	if (_Token_OverRun)		// Stop the data stage procesing if SETUP overrun is detected
		return;

	switch (_vUSB_StateMachine) {
	case IN_DATA:
		if (vUSB_length == 0)
			_vUSB_StateMachine = WAIT_STATUS_OUT;
		else
			_USB_CopydataIN();
		break;
	case ONE_MORE_IN:
		CNT0TXR = 0;
		break;

	default:
		RequestError();
	}
}

/*****************************************************************************
ROUTINE NAME : USB_Data_OUT_Stage
DESCRIPTION  : This function is called when a data stage packet is received
		Copy the next data packet from the endpoint buffer if it is necessary
*****************************************************************************/
void USB_Data_OUT_Stage(void)
{
	if (_Token_OverRun)		// Stop the data stage procesing if SETUP overrun is detected
		return;

	switch (_vUSB_StateMachine & MACHINESTATE) {
	case OUT_DATA:
//	case ONE_MORE_OUT:
		if (vUSB_length < MAX_PACKET_SIZE)
			_vUSB_StateMachine = WAIT_STATUS_IN;
		if (!_USB_CopydataOUT())
			RequestError();
		break;

	default:
		RequestError();
	}
}

/*****************************************************************************
ROUTINE NAME : USB_Status_IN_Stage
DESCRIPTION  : This function is called when a status IN stage is received
*****************************************************************************/
void USB_Status_IN_Stage(void)
{
	// Successful status stage means a transaction is finished correctly
	// Do not stop the data stage procesing if SETUP overrun is detected

	switch (_vUSB_StateMachine & MACHINESTATE) {
	case ADDRESS2SET:
		DADDR = sUSB_vSetup.USBwValue0;
	/* Following lines are useless because the request is not valid in configured state
		if (DADDR == 0) {				// Device goes to address state
			vUSB_Configuration = 0;
			_EP_RxTx_Flag = 0;			// Clear flag for non-control EPs

			// Call user function to un-configure the device
			USER(USER_Set_Configuration);
		}
	*/
		_vUSB_StateMachine = WAIT_SETUP;
		break;

	case WAIT_STATUS_IN:
	case OUT_DATA:
//	case ONE_MORE_OUT:
		USER(USER_Status_In);			// Inform user function of the event
		_vUSB_StateMachine = WAIT_SETUP;
		break;

	default:
		RequestError();
	}
}

/*****************************************************************************
ROUTINE NAME : USB_Status_OUT_Stage
DESCRIPTION  : This function is called when a status OUT stage is received
*****************************************************************************/
void USB_Status_OUT_Stage(void)
{
	// Successful status stage means a transaction is finished correctly
	// Do not stop the data stage procesing if SETUP overrun is detected

	switch (_vUSB_StateMachine & MACHINESTATE) {
	case WAIT_STATUS_OUT:
	case IN_DATA:
//	case ONE_MORE_IN:
		USER(USER_Status_Out);			// Inform user function of the event
		_vUSB_StateMachine = WAIT_SETUP;
		break;

	default:
		RequestError();
	}
}

/*****************************************************************************
ROUTINE NAME : Change_EP0_State
DESCRIPTION  : The SETUP overrun event is checked after process each token
		and before change the state of EP0. The EP0 state is changed only
		when there is no SETUP overrun. (See usb_int.c & usb_poll.c)
*****************************************************************************/
void Change_EP0_State(void)
{
	char _vUSB_State;

	if (_vUSB_StateMachine == WAIT_SETUP)
		return;

	CNT0RXR = MAX_PACKET_SIZE;
	_vUSB_State = _vUSB_StateMachine & MACHINESTATE;
	if (_vUSB_State == WAIT_STATUS_IN || _vUSB_State == ADDRESS2SET) {
		CNT0TXR = 0;
		_USB_SetEP0TxRx(EP_VALID, EP_STALL);
		return;
	}
	if (_vUSB_State == WAIT_STATUS_OUT) {
		_USB_SetEP0TxRx(EP_STALL, EP_VALID);
		return;
	}
	if (_vUSB_State == IN_DATA) {
		_USB_SetEP0TxRx(EP_VALID, EP_VALID);
		return;
	}
	if (_vUSB_State == OUT_DATA) {
		CNT0TXR = 0;
		_USB_SetEP0TxRx(EP_VALID, EP_VALID);
		return;
	}
	if (_vUSB_State == STATE_ERROR) {
		_USB_SetEP0TxRx(EP_STALL, EP_STALL);
		return;
	}
}

/*****************************************************************************
ROUTINE NAME : RequestType_0x00
DESCRIPTION  : Standard process for request of (H->D, Standard, Device)
*****************************************************************************/
void RequestType_0x00(void)		// Host->Device, Standard, Device-Recipient
{
//	_vUSB_StateMachine = WAIT_STATUS_IN;	// Expect Status IN after the SETUP Stage

	if ((sUSB_vSetup.Flag & (NON0_wIndex | NON0_wValue1 | NON0_wLength)) != 0)
		goto Req_Error;							// (wIndex | wValue1 | wLength) !=0

	switch (sUSB_vSetup.USBbRequest) {
	case CLEAR_FEATURE:
		if (sUSB_vSetup.USBwValue0 != 1)		// Check the feature selector
			break;
		if (DADDR == 0)							// On default state, to stall the request
			break;
		if ((vUSB_Current_Feature & 0x20) == 0)	// Remote wakeup is not support
			break;

		vUSB_Current_Feature &= ~0x02;			// Disable the remote wakeup feature
		return;

	case SET_FEATURE:
		if (sUSB_vSetup.USBwValue0 != 1)		// Check the feature selector
			break;
		if (DADDR == 0)							// On default state, to stall the request
			break;
		if ((vUSB_Current_Feature & 0x20) == 0)	// Remote wakeup is not support
			break;

		vUSB_Current_Feature |= 0x02;			// Enable the remote wakeup feature
		return;

	case SET_ADDRESS:
		if (sUSB_vSetup.USBwValue0 > 127)		// Check the address range
			break;

		if (vUSB_Configuration)					// Microsoft requires this
			break;								// USB Spec. does not want it

		_vUSB_StateMachine = ADDRESS2SET;
		return;

	case SET_CONFIGURATION:
		if (DADDR == 0)							// On default state, to stall the request
			break;
		if (sUSB_vSetup.USBwValue0 > UI.Num_Configuration)	// Check configure value
			break;

		vUSB_Configuration = sUSB_vSetup.USBwValue0;
		if (vUSB_Configuration == 0)
			_EP_RxTx_Flag = 0;					// Clear flag for non-control EPs

		USER(USER_Set_Configuration);	// if (USER_Set_Configuration() == REQ_SUCCESS)	return;
		asm {
			CP		A, #REQ_SUCCESS
			JRNE	bad_config
			RET
	bad_config:
		}
	}
Req_Error:
	Non_Standard_Request;
}	// End of "Host->Device, Standard, Device-Recipient"

/*****************************************************************************
ROUTINE NAME : RequestType_0x80
DESCRIPTION  : Standard process for request of (D->H, Standard, Device)
*****************************************************************************/
void RequestType_0x80(void)		// Device->Host, Standard, Device-Recipient
{
//	_vUSB_StateMachine = IN_DATA;		// Expect Data IN stage after the SETUP Stage

	switch (sUSB_vSetup.USBbRequest) {
	case GET_CONFIGURATION:
		if (DADDR == 0)					// On default state, to stall the request
			goto Req_Error;
		if (sUSB_vSetup.Flag != (ONE_wLength | NON0_wLength0))
			goto Req_Error;				// (wValue | wIndex) !=0 || wLength != 1

		vUSB_DataToSend = &vUSB_Configuration; 
		vUSB_length = 1;
		return;

	case GET_DESCRIPTOR:
		if ((sUSB_vSetup.Flag & NON0_wIndex) == 0) {
			if (sUSB_vSetup.USBwValue1 == 0x01) {		// Device Descriptor
				if (sUSB_vSetup.Flag & NON0_wValue0)
					goto Req_Error;
				vUSB_DataToSend = DeviceDescriptor.Descriptor;
				vUSB_length = DeviceDescriptor.Size;
			}
			else if (sUSB_vSetup.USBwValue1 == 0x02) {	// Configuration Descriptor
				// Check configuration range and return the correspond configuration descriptor
				if (sUSB_vSetup.USBwValue0 > UI.Num_Configuration)
					goto Req_Error;
				vUSB_DataToSend = ConfigDescriptor[sUSB_vSetup.USBwValue0].Descriptor;
				vUSB_length = ConfigDescriptor[sUSB_vSetup.USBwValue0].Size;
			}
			else if (sUSB_vSetup.USBwValue1 == 0x03) {	// String Descriptor
				if (sUSB_vSetup.Flag & NON0_wValue0)
					goto Req_Error;;
				// Asking for the language ID
				vUSB_DataToSend = StringDescriptor[0].Descriptor;
				vUSB_length = StringDescriptor[0].Size;
				
			}
			else {
		Req_Error:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -