📄 usb_lib.c
字号:
/**************** (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 + -