📄 usb_core.c
字号:
/******************** (C) COPYRIGHT 2006 STMicroelectronics ********************
* File Name : usb_core.c
* Author : MCD Application Team
* Date First Issued : 03/10/2006 : V0.1
* Description : Standard protocol processing (USB v2.0)
********************************************************************************
* History:
* 03/10/2006 : V0.1
********************************************************************************
* THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*******************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include "USB_lib.h"
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#define ValBit(VAR,Place) (VAR & (1<<Place))
#define SetBit(VAR,Place) ( VAR |= (1<<Place) )
#define ClrBit(VAR,Place) ( VAR &= ((1<<Place)^255) )
BYTE *Standard_GetStatus(WORD Length);
RESULT Standard_ClearFeature(void);
extern BYTE* test;
#define Send0LengthData() { \
_SetEPTxCount(ENDP0, 0); \
vSetEPTxStatus(EP_TX_VALID); \
}
/* cells saving status during interrupt servicing */
WORD SaveRState;
WORD SaveTState;
BYTE EXTRA=0;
#define vSetEPRxStatus(st) (SaveRState = st)
#define vSetEPTxStatus(st) (SaveTState = st)
#define USB_StatusIn() Send0LengthData()
#define USB_StatusOut() vSetEPRxStatus(EP_RX_VALID)
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
NAME: Standard_GetConfiguration
INPUT: Length - How many bytes are needed
OUTPUT: If "Length" is 0, return the length of configuration value
If "Length" is not 0, return the data buffer address
RETURN: Return 0, if the request is invalid when "Length" is 0
Return "Buffer" if the "Length" is not 0
DESCRIPTION:
Return the current configuration variable address
NOTICE:
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
BYTE *Standard_GetConfiguration(WORD Length)
{
if (Length == 0)
return (BYTE *)sizeof(pInformation->Current_Configuration);
return (BYTE *)&pInformation->Current_Configuration;
} /* Standard_GetConfiguration */
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
NAME: Standard_SetConfiguration
INPUT:
OUTPUT:
RETURN: Return USB_SUCCESS, if the request is performed
Return UNSUPPORT, if the request is invalid
DESCRIPTION:
This routine is called to set the configuration value
Then each class should configure device themself
NOTICE: this routine can support 127 configurations
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
RESULT Standard_SetConfiguration(void)
{
if (pInformation->USBwValue0 <= Device_Table.Total_Configuration && pInformation->USBwValue1==0
&& pInformation->USBwIndex==0) //call Back usb spec 2.0
{
pInformation->Current_Configuration = pInformation->USBwValue0;
return USB_SUCCESS;
}
else
return UNSUPPORT;
} /* Standard_SetConfiguration */
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
NAME: Standard_GetInterface
INPUT: Length - How many bytes are needed
OUTPUT: If "Length" is 0, return the length of interface value
If "Length" is not 0, return the data buffer address
RETURN: Return 0, if the request is invalid when "Length" is 0
Return "Buffer" if the "Length" is not 0
DESCRIPTION:
Return the Alternate Setting of the current interface
NOTICE: Every Interface can Support 128 Alternate Settings
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
BYTE *Standard_GetInterface(WORD Length)
{
if (Length == 0)
return (BYTE *)sizeof(pInformation->Current_AlternateSetting);
return (BYTE *)&pInformation->Current_AlternateSetting;
} /* Standard_GetInterface */
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
NAME: Standard_SetInterface
INPUT:
OUTPUT:
RETURN: Return USB_SUCCESS, if the request is performed
Return UNSUPPORT, if the request is invalid
DESCRIPTION:
This routine is called to set the interface
Then each class should configure the interface them self
NOTICE: The number of supported interfaces should be specified by the user.
The maximum number of supported Interface is 128
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
RESULT Standard_SetInterface(void)
{
DEVICE_INFO *pInfo = pInformation;
DEVICE_PROP *pProp = pProperty;
RESULT Re;
//test if the specified Interface and Alternate Setting are supportted by the application Firmware
Re = (*pProp->Class_Get_Interface_Setting)(pInfo->USBwIndex0,pInfo->USBwValue0);
if(pInfo->Current_Configuration==0 )
return UNSUPPORT;
else
{
if (Re!= USB_SUCCESS || pInfo->USBwIndex1!=0 || pInfo->USBwValue1!=0)
return UNSUPPORT;
else if ( Re == USB_SUCCESS)
{
pInfo->Current_Interface = pInfo->USBwIndex0;
pInfo->Current_AlternateSetting = pInfo->USBwValue0;
return USB_SUCCESS;
}
else return UNSUPPORT;
}
} /* Standard_SetInterface */
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
NAME: Standard_GetStatus
INPUT: Length - How many bytes are needed
OUTPUT: If "Length" is 0, return the length of status data
If "Length" is not 0, return number of bytes have been copied
RETURN: Return 0, if the request is at end of data block,
or is invalid when "Length" is 0
DESCRIPTION:
Copy the device request data to "StatusInfo buffer"
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
WORD_BYTE StatusInfo;
#define StatusInfo0 StatusInfo.bw.bb1 /* Reverse bb0 & bb1 */
#define StatusInfo1 StatusInfo.bw.bb0
BYTE *Standard_GetStatus(WORD Length)
{
DEVICE_INFO *pInfo = pInformation;
if (Length == 0)
return (BYTE *)2;
StatusInfo.w = 0;
/* Reset Status Information */
if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)) {/*Get Device Status */
BYTE Feature = pInfo->Current_Feature;
if (ValBit(Feature, 5))
SetBit(StatusInfo0, 1); /* Remote Wakeup enabled */
if (ValBit(Feature, 7))
ClrBit(StatusInfo0, 0); /* Bus-powered */
else if (ValBit(Feature, 6))
SetBit(StatusInfo0, 0); /* Self-powered */
}
else if (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT))/*Interface Status*/
return (BYTE *)&StatusInfo;
else if (Type_Recipient == (STANDARD_REQUEST | ENDPOINT_RECIPIENT)) {/*Get EndPoint Status*/
BYTE Related_Endpoint;
BYTE wIndex0 = pInfo->USBwIndex0;
Related_Endpoint = (wIndex0 & 0x0f);
if (ValBit(wIndex0, 7)) {
/* IN endpoint */
if (_GetTxStallStatus( Related_Endpoint ))
SetBit(StatusInfo0, 0); /* IN Endpoint stalled */
}
else {
/* OUT endpoint */
if (_GetRxStallStatus( Related_Endpoint ))
SetBit(StatusInfo0, 0); /* OUT Endpoint stalled */
}
}
else
return NULL;
return (BYTE *)&StatusInfo;
} /* Standard_GetStatus */
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
NAME: Standard_ClearFeature
INPUT:
OUTPUT: none
DESCRIPTION:
Clear or disable a specific feature
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
RESULT Standard_ClearFeature(void)
{
DEVICE_INFO *pInfo = pInformation;
BYTE Type_Rec = Type_Recipient;
WORD Status;
if ( Type_Rec == (STANDARD_REQUEST | DEVICE_RECIPIENT) ) {/*Device Clear Feature*/
ClrBit(pInfo->Current_Feature, 5);
return USB_SUCCESS;
}
else if ( Type_Rec == (STANDARD_REQUEST | ENDPOINT_RECIPIENT) ) {/*EndPoint Clear Feature*/
DEVICE* pDev;
BYTE Related_Endpoint;
BYTE wIndex0;
BYTE rEP;
if (pInfo->USBwValue != ENDPOINT_STALL || pInfo->USBwIndex1!=0)
return UNSUPPORT;
pDev = &Device_Table;
wIndex0 = pInfo->USBwIndex0;
rEP = wIndex0 & ~0x80;
Related_Endpoint = ENDP0 + rEP;
if (ValBit(pInfo->USBwIndex0, 7)) Status =_GetEPTxStatus(Related_Endpoint);// get Status of endpoint & stall the request if
// the related_ENdpoint is Disabled
else Status =_GetEPRxStatus(Related_Endpoint);
if (rEP >= pDev->Total_Endpoint || Status==0 || pInfo->Current_Configuration==0)
return UNSUPPORT;
if (wIndex0 & 0x80) { /* IN endpoint */
if (_GetTxStallStatus(Related_Endpoint ))
_SetEPTxStatus(Related_Endpoint, EP_TX_NAK);
}
else { /* OUT endpoint */
if (_GetRxStallStatus(Related_Endpoint)){
if (Related_Endpoint == ENDP0) {
/* After clear the STALL, enable the default endpoint receiver */
SetEPRxCount(Related_Endpoint, STD_MAXPACKETSIZE);
_SetEPRxStatus(Related_Endpoint, EP_RX_VALID);
}
else
_SetEPRxStatus(Related_Endpoint, EP_RX_NAK);
}
}
return USB_SUCCESS;
}
return UNSUPPORT;
} /* Standard_ClearFeature */
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
NAME: Standard_SetEndPointFeature
INPUT:
OUTPUT: none
DESCRIPTION:
Set or enable a specific feature of EndPoint
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
RESULT Standard_SetEndPointFeature(void)
{
DEVICE_INFO *pInfo = pInformation;
BYTE wIndex0;
BYTE Related_Endpoint;
BYTE rEP;
WORD Status;
wIndex0 = pInfo->USBwIndex0;
rEP = wIndex0 & ~0x80;
Related_Endpoint = ENDP0 + rEP;
if (ValBit(pInfo->USBwIndex0, 7)) Status =_GetEPTxStatus(Related_Endpoint);// get Status of endpoint & stall the request if
// the related_ENdpoint is Disabled
else Status =_GetEPRxStatus(Related_Endpoint);
if (Related_Endpoint >= Device_Table.Total_Endpoint || pInfo->USBwValue !=0 || Status==0 ||
pInfo->Current_Configuration==0 /*&& Related_Endpoint!=ENDP0)*/)
return UNSUPPORT;
else {
if (wIndex0 & 0x80) { /* IN endpoint */
_SetEPTxStatus(Related_Endpoint, EP_TX_STALL);
}
else { /* OUT endpoint */
_SetEPRxStatus(Related_Endpoint, EP_RX_STALL);
}
}
return USB_SUCCESS;
} /*Standard_SetEndPointFeature */
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
NAME: Standard_SetDeviceFeature
INPUT:
OUTPUT: none
DESCRIPTION:
Set or enable a specific feature of Device
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
RESULT Standard_SetDeviceFeature(void)
{
SetBit(pInformation->Current_Feature, 5);
return USB_SUCCESS;
} /*Standard_SetDeviceFeature */
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
NAME: Standard_GetDescriptorData
Standard_GetStringDescriptor
INPUT: Length - Length of the data in this transfer
pDesc - A pointer points to descriptor struct
The structure gives the initial address
of the descriptor and its original size
OUTPUT: Address of a part of the descriptor pointed by the Usb_wOffset
The buffer pointed by this address contains at least Length bytes
DESCRIPTION:
These 2 routines only used for the descriptors resident in ROM or RAM
pDesc can be in either ROM or RAM
Standard_GetStringDescriptor is used for transfer string descriptor
The purpose of these 2 routines is to have a versatile way to response
descriptors request. It allows user to generate certain descriptors
with software or read descriptors from external storage part by part.
*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
BYTE *Standard_GetStringDescriptor(WORD Length, ONE_DESCRIPTOR *pDesc)
{
int len, offset, wOffset;
wOffset = pInformation->Ctrl_Info.Usb_wOffset;
if (Length == 0) {
offset = 0;
do {
len = (int)*(pDesc->Descriptor + offset);
if (wOffset >= 0 && wOffset < len) {
len -= wOffset;
if (len > 0)
return (BYTE*)len;
break;
}
wOffset -= len;
offset += len;
} while (offset < pDesc->Descriptor_Size);
return 0;
}
return pDesc->Descriptor + wOffset;
}/* Standard_GetStringDescriptor */
/*============================================================================*/
/*============================================================================*/
BYTE *Standard_GetDescriptorData(WORD Length, ONE_DESCRIPTOR *pDesc)
{
int len, wOffset;
wOffset = pInformation->Ctrl_Info.Usb_wOffset;
if (Length == 0) {
len = pDesc->Descriptor_Size - wOffset;
if (len <= 0)
return 0;
return (BYTE *)len;
}
return pDesc->Descriptor + wOffset;
} /* Standard_GetDescriptorData */
/*-----------------------------------------------------------------------------
ROUTINE NAME : DataStageOut
INPUT/OUTPUT : None
DESCRIPTION : Data stage of a Control Write Transfer
-----------------------------------------------------------------------------*/
void DataStageOut()
{
ENDPOINT_INFO *pEPinfo = &pInformation->Ctrl_Info;
WORD save_rLength;
save_rLength = pEPinfo->Usb_rLength;
if (pEPinfo->CopyData && save_rLength) {
BYTE *Buffer;
WORD Length;
BYTE *Source;
Length = pEPinfo->PacketSize;
if (Length > save_rLength)
Length = save_rLength;
Buffer = (*pEPinfo->CopyData)(Length);
pEPinfo->Usb_rLength -= Length;
pEPinfo->Usb_rOffset += Length;
Source = PMAAddr + (BYTE *)(_GetEPRxAddr(ENDP0)*2); /* *2 for 32 bits addr */
while (Length) {
*Buffer++ = *Source++;
Length--;
if(Length == 0) break; /* odd counter */
*Buffer++ = *Source++;
Length--;
Source++;Source++; /* skip 2 bytes for 32 bit addressing */
}
}
if(pEPinfo->Usb_rLength !=0){
vSetEPRxStatus(EP_RX_VALID);/* reenable for next data reception */
_SetEPTxCount(ENDP0, 0);
vSetEPTxStatus(EP_TX_VALID);/* Expect the host to abort the data OUT stage */
}
/* Set the next State*/
if (pEPinfo->Usb_rLength >= pEPinfo->PacketSize)
pInformation->ControlState = OUT_DATA;
else
{
if (pEPinfo->Usb_rLength >0)
pInformation->ControlState = LAST_OUT_DATA;
else if (pEPinfo->Usb_rLength == 0)
{
pInformation->ControlState = WAIT_STATUS_IN;
USB_StatusIn();
}
}
} /* DataStageOut */
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -