usb_core.c这个c文件是个庞大的文件,主要是定义了usb2.0的标注协议处理函数。
下面是这个文件的所有函数:
/*******************************************************************************
* Function Name : Standard_GetConfiguration.
* Description : 返回当前配置变量的地址
* Input : Length -需要的字节 How many bytes are needed.
* Output : None.
* Return : 如果'Length'值为0时,请求无效,返回1。长度不为0时,返回配置变量的地址
* Readme : 当配置值与摸个配置描述符中的配置编号一致时,表示选中该配置
*******************************************************************************/
uint8_t *Standard_GetConfiguration(uint16_t Length);
/*******************************************************************************
* Function Name : Standard_SetConfiguration.
* Description : 该函数用于设置配置值,主机发送该请求后,usb设备要配置自己的设备值
* Input : None.
* Output : None.
* Return : 当该请求被执行了,返回USB_SUCCESS
* 当请求无效时,然会USB_UNSUPPORT
*******************************************************************************/
RESULT Standard_SetConfiguration(void);
/*******************************************************************************
* Function Name : Standard_GetInterface.
* Description : 返回当前接口的备用接口
* Input : Length -需要的字节数
* Output : None.
* Return : 当'Length'的值为0,请求无效,返回0,当长度不为0,返回备用接口的地址
*******************************************************************************/
uint8_t *Standard_GetInterface(uint16_t Length);
/*******************************************************************************
* Function Name : Standard_GetStatus.
* Description : 拷贝设备请求数据到"StatusInfo buffer".
* Input : - Length -需要的字节数
* Output : None.
* Return : 如果请求在数据块的末端,或则当'Length'为0是,请求无效,则返回0
*******************************************************************************/
uint8_t *Standard_GetStatus(uint16_t Length);
/*******************************************************************************
* Function Name : Standard_ClearFeature.
* Description : 清除或禁止某个指定的特性
* Input : None.
* Output : None.
* Return : 当请求被执行,返回Return USB_SUCCESS,如果请求无效,返回USB_UNSUPPORT
*******************************************************************************/
RESULT Standard_ClearFeature(void);
/*******************************************************************************
* Function Name : Standard_SetEndPointFeature
* Description : 设置或使能端点的指定的特性
* Input : None.
* Output : None.
* Return : 如果请求被执行,返回USB_SUCCESS,如果请求无效,则返回USB_UNSUPPORT
*******************************************************************************/
RESULT Standard_SetEndPointFeature(void);
/*******************************************************************************
* Function Name : Standard_SetDeviceFeature.
* Description : 设置或使能设备指定的特性
* Input : None.
* Output : None.
* Return : 如果请求被执行,返回USB_SUCCESS,如果请求无效,则返回USB_UNSUPPORT
*******************************************************************************/
RESULT Standard_SetDeviceFeature(void);
/*******************************************************************************
* Function Name : Standard_GetDescriptorData.
* Description : Standard_GetDescriptorData用于描述符的传输.
* : 这个函数用于驻留在flash或RAM里的描述符pDesc可以自相Flash或RAM
* 这个函数的目的是具有不同的方式去响应描述符请求。
* 它允许用户通过软件生成的某些描述符或则读取外部存储设备的描述符部分.
* Input : Length - 这次传输的的数据长度
* pDesc - 指向描述符结构体的指针
* Output : None.
* Return : 返回usb_wOffset指向的描述符部分的地址。这个地址指向的缓冲包含最起码Length个字节
*******************************************************************************/
uint8_t *Standard_GetDescriptorData(uint16_t Length, ONE_DESCRIPTOR *pDesc);
/*******************************************************************************
* Function Name : DataStageOut.
* Description : 数据阶段的控制写传输
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
void DataStageOut(void);
/*******************************************************************************
* Function Name : DataStageIn.
* Description : 数据阶段的控制读传输
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
void DataStageIn(void);
/*******************************************************************************
* Function Name : NoData_Setup0.
* Description : 处理没有数据阶段的建立请求
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
void NoData_Setup0(void);
/*******************************************************************************
* Function Name : Data_Setup0.
* Description : 处理有数据阶段的建立请求
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
void Data_Setup0(void);
/*******************************************************************************
* Function Name : Setup0_Process
* Description : 建立阶段的数据处理Get the device request data and dispatch to individual process.
* Input : None.
* Output : None.
* Return : Post0_Process.
*******************************************************************************/
uint8_t Setup0_Process(void);
/*******************************************************************************
* Function Name : In0_Process
* Description : 处理默认端点的所有IN令牌包
* Input : None.
* Output : None.
* Return : Post0_Process.
*******************************************************************************/
uint8_t In0_Process(void);
/*******************************************************************************
* Function Name : Out0_Process
* Description : 处理默认端点上的所有OUT令牌包
* Input : None.
* Output : None.
* Return : Post0_Process.
*******************************************************************************/
uint8_t Out0_Process(void);
/*******************************************************************************
* Function Name : Post0_Process
* Description : 为防止错误,停止端点0Stall the Endpoint 0 in case of error.
* Input : None.
* Output : None.
* Return : 如果控制状态是PAUSE,返回0;如果不是返回1
*******************************************************************************/
uint8_t Post0_Process(void);
/*******************************************************************************
* Function Name : SetDeviceAddress.
* Description : 设置设备和所有使用过的端点地址
* Input : Val:设备地址
* Output : None.
* Return : None.
*******************************************************************************/
void SetDeviceAddress(uint8_t Val);
/*******************************************************************************
* Function Name : NOP_Process
* Description : 没有处理函数
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
void NOP_Process(void);
这里简单地介绍几类函数。
首先要将的是关于USB特性(Feature)和状态的函数,这些函数包括:Standard_SetEndPointFeature();Standard_SetDeviceFeature;Standard_ClearFeature();Standard_GetStatus();这四个函数。
先讲讲
USB的Feature。对于USB的设备来说,特性就是否支持远程唤醒;如果是 对于USb的端点来说,端点是否有效(打开)就是端点的特性。
在
Standard_SetDeviceFeature函数中就是设置usb支持远程唤醒。
/*******************************************************************************
* Function Name : Standard_SetDeviceFeature.
* Description : 设置或使能设备指定的特性
* Input : None.
* Output : None.
* Return : 如果请求被执行,返回USB_SUCCESS,如果请求无效,则返回USB_UNSUPPORT
*******************************************************************************/
RESULT Standard_SetDeviceFeature(void)
{
SetBit(pInformation->Current_Feature, 5); //置位Current_Feature的D5,即支持远程唤醒
pUser_Standard_Requests->User_SetDeviceFeature(); //调用User_SetDeviceFeature(),该函数在usb_prop.c中注册
return USB_SUCCESS;
}
在
Standard_SetEndPointFeature()函数中就是停止(STALL)输入端点或则输出端点。
RESULT Standard_SetEndPointFeature(void)
{
uint32_t wIndex0;
uint32_t Related_Endpoint;
uint32_t rEP;
uint32_t Status;
wIndex0 = pInformation->USBwIndex0; //获取端点的地址
rEP = wIndex0 & ~0x80; //提取端点号
Related_Endpoint = ENDP0 + rEP; //端点号
if (ValBit(pInformation->USBwIndex0, 7)) //输入端口
{
/* get Status of endpoint & stall the request if the related_ENdpoint
is Disabled*/
Status = _GetEPTxStatus(Related_Endpoint); //获取端点的发送状态
}
else //输出端口
{
Status = _GetEPRxStatus(Related_Endpoint); //获取端点的接收状态
}
if (Related_Endpoint >= Device_Table.Total_Endpoint //端点号小于总的已用端点数
|| pInformation->USBwValue != 0 || Status == 0 //USBwValue域不为0(规定为0),端点的状态为0(端点关闭)
|| pInformation->Current_Configuration == 0) //当前的配置值为0
{
return USB_UNSUPPORT; //返回USB_UNSUPPORT
}
else
{
if (wIndex0 & 0x80) //输入端口
{
/* IN endpoint */
_SetEPTxStatus(Related_Endpoint, EP_TX_STALL); //设置端口的发送状态为停止
}
else //输出端口
{
/* OUT endpoint */
_SetEPRxStatus(Related_Endpoint, EP_RX_STALL); //设置端口的接收地址为停止
}
}
pUser_Standard_Requests->User_SetEndPointFeature(); //调用User_SetEndPointFeature()函数,该函数在usb_prop.c中注册
return USB_SUCCESS;
}
至于
Standard_ClearFeature()函数就是清楚USB特性。对于设备来说,设置不支持远程唤醒;对于端点来说是设置输入端点或则输出端点有效(VALID)。
/*******************************************************************************
* Function Name : Standard_ClearFeature.
* Description : 清除或禁止某个指定的特性
* Input : None.
* Output : None.
* Return : 当请求被执行,返回Return USB_SUCCESS,如果请求无效,返回USB_UNSUPPORT
*******************************************************************************/
RESULT Standard_ClearFeature(void)
{
uint32_t Type_Rec = Type_Recipient;
uint32_t Status;
if (Type_Rec == (STANDARD_REQUEST | DEVICE_RECIPIENT)) //标准请求,请求的接收者是设备
{/*Device Clear Feature*/
ClrBit(pInformation->Current_Feature, 5); //清除Current_Feature的D5,表示不支持远程唤醒
return USB_SUCCESS; //返回USB_SUCCESS
}
else if (Type_Rec == (STANDARD_REQUEST | ENDPOINT_RECIPIENT)) //标准请求,请求的接收者是端点
{/*EndPoint Clear Feature*/
DEVICE* pDev;
uint32_t Related_Endpoint;
uint32_t wIndex0;
uint32_t rEP;
if ((pInformation->USBwValue != ENDPOINT_STALL) //端点没有挂起
|| (pInformation->USBwIndex1 != 0)) //USBwIndex1不为0(USBwIndex1必须为0)
{
return USB_UNSUPPORT; //返回USB_UNSUPPORT
}
pDev = &Device_Table;
wIndex0 = pInformation->USBwIndex0; //wIndex获取端点地址
rEP = wIndex0 & ~0x80; //rEP存放端点号
Related_Endpoint = ENDP0 + rEP; //端点号
if (ValBit(pInformation->USBwIndex0, 7)) //输入端点
{
/*Get Status of endpoint & stall the request if the related_ENdpoint
is Disabled*/
Status = _GetEPTxStatus(Related_Endpoint); //获取端点的发送状态
}
else //输出端点
{
Status = _GetEPRxStatus(Related_Endpoint); //获取端点的接收状态
}
if ((rEP >= pDev->Total_Endpoint) || (Status == 0) //端点号大于总的已使用的端点数,状态为0(端点关闭)
|| (pInformation->Current_Configuration == 0)) //或则当前的配置子为0
{
return USB_UNSUPPORT; //返回USB_UNSUPPORT
}
if (wIndex0 & 0x80) //输入端点
{
/* IN endpoint */
if (_GetTxStallStatus(Related_Endpoint )) //如果端点发送状态为停止(STALL)
{
#ifndef STM32F10X_CL
ClearDTOG_TX(Related_Endpoint);
#endif /* STM32F10X_CL */
SetEPTxStatus(Related_Endpoint, EP_TX_VALID); //设置端点发送状态有效(VALID)
}
}
else //输出端点
{
/* OUT endpoint */
if (_GetRxStallStatus(Related_Endpoint)) //如果端点接收状态为停止(STALl)
{
if (Related_Endpoint == ENDP0) //如果端点号为端点0
{
/* After clear the STALL, enable the default endpoint receiver */
SetEPRxCount(Related_Endpoint, Device_Property.MaxPacketSize);//设置端点的接收数据包长度
_SetEPRxStatus(Related_Endpoint, EP_RX_VALID); //设置端点有效
}
else //如果不是端点0
{
#ifndef STM32F10X_CL
ClearDTOG_RX(Related_Endpoint);
#endif /* STM32F10X_CL */
_SetEPRxStatus(Related_Endpoint, EP_RX_VALID); //直接设置端点有效
}
}
}
pUser_Standard_Requests->User_ClearFeature(); //调用User_ClearFeature()函数,该函数在usb_prop.c中定义
return USB_SUCCESS;
}
return USB_UNSUPPORT;
}
使用Standard_GetStatus()这个函数来获得USB的状态,对于设备来说,获取状态就是要查看是否支持远程唤醒和是否自供电这两个状态。对于端点来说当让就是端点的状态了,收VALID,STALl还是其他状态。
/*******************************************************************************
* Function Name : Standard_GetStatus.
* Description : 拷贝设备请求数据到"StatusInfo buffer".
* Input : - Length -需要的字节数
* Output : None.
* Return : 如果请求在数据块的末端,或则当'Length'为0是,请求无效,则返回0
*******************************************************************************/
uint8_t *Standard_GetStatus(uint16_t Length)
{
if (Length == 0) //Length为0
{
pInformation->Ctrl_Info.Usb_wLength = 2; //设置需要传输的字节数为2,因为状态信息为2个字节
return 0;
}
/* Reset Status Information */ //清空状态信息值
StatusInfo.w = 0;
if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))//标准请求,请求的接收者是设备
{
/*Get Device Status */
uint8_t Feature = pInformation->Current_Feature;//获取设备的特性值
if (ValBit(Feature, 5)) //如果特性Feature的D5为1,即特性支持远程唤醒
{
SetBit(StatusInfo0, 1); //置位StatusInfo0状态信息的D1,表示支持远程唤醒
}
else //如果特性Feature的D5为0,及表示不支持远程唤醒
{
ClrBit(StatusInfo0, 1); //复位StatusInfo0状态信息的D1,表示不支持远程唤醒
}
if (ValBit(Feature, 6)) //如果特性Feature的D6为1,表示是自供电的
{
SetBit(StatusInfo0, 0); //置为StatusInfo0状态信息的D0,表示自供电
}
else //如果特性Feature的D6为0,表示是总线供电的
{
ClrBit(StatusInfo0, 0); //复位StatusInfo0状态信息的D0,表示总线供电
}
}
else if (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT))//标准请求,请求的接收者是接口
{
return (uint8_t *)&StatusInfo; //直接返回状态信息数据
}
else if (Type_Recipient == (STANDARD_REQUEST | ENDPOINT_RECIPIENT))//标准请求,请求的接受者是端点
{
uint8_t Related_Endpoint;
uint8_t wIndex0 = pInformation->USBwIndex0; //获取端点的地址
Related_Endpoint = (wIndex0 & 0x0f); //获取wIndex0的低4位D0~D3,这4位为端点号,D7表示传输方向
if (ValBit(wIndex0, 7)) //如果wIndex0的最高位D7为1,表示是输入端点,这里的输入是相对于主机而言的
{
if (_GetTxStallStatus(Related_Endpoint)) //如果端点的发送状态为停止(STALL)
{
SetBit(StatusInfo0, 0); //设置StatusInfo0状态信息的D0为1,表示发送停止状态
}
}
else //如果wIndex0的最高位D7为0,表示是输出端点
{
if (_GetRxStallStatus(Related_Endpoint)) //如果端点接收状态为停止
{
SetBit(StatusInfo0, 0); //设置StatusInfo0状态信息的D0为1,表示接收停止状态
}
}
} //其他情况,返回NULL
else
{
return NULL;
}
pUser_Standard_Requests->User_GetStatus(); //调用User_GetStatus函数,该函数在usb_prop.c中注册
return (uint8_t *)&StatusInfo; //返回状态信息
}
接下去的一类函数是设置/获取配置值和接口值等,这些函数包括:Standard_GetConfiguration();Standard_SetConfiguration();Standard_GetInterface();Standard_SetInterface();Standard_GetDescriptorData();
先将Get的相关函数分析下:
/*******************************************************************************
* Function Name : Standard_GetConfiguration.
* Description : 返回当前配置变量的地址
* Input : Length -需要的字节 How many bytes are needed.
* Output : None.
* Return : 如果'Length'值为0时,请求无效,返回1。长度不为0时,返回配置变量的地址
* Readme : 当配置值与摸个配置描述符中的配置编号一致时,表示选中该配置
*******************************************************************************/
uint8_t *Standard_GetConfiguration(uint16_t Length)
{
if (Length == 0) //长度为0
{
pInformation->Ctrl_Info.Usb_wLength =
sizeof(pInformation->Current_Configuration); //端点通讯的数据长度为1个字节,因为Current_Configuration为1字节
return 0; //返回0,表示请求无效
}
pUser_Standard_Requests->User_GetConfiguration(); //调用User_GetConfiguration函数,该函数在usb_prop.c中注册
return (uint8_t *)&pInformation->Current_Configuration;//返回当前的配置是的地址
}
/*******************************************************************************
* Function Name : Standard_GetInterface.
* Description : 返回当前接口的备用接口
* Input : Length -需要的字节数
* Output : None.
* Return : 当'Length'的值为0,请求无效,返回0,当长度不为0,返回备用接口的地址
*******************************************************************************/
uint8_t *Standard_GetInterface(uint16_t Length)
{
if (Length == 0) //长度为0
{
pInformation->Ctrl_Info.Usb_wLength = //设置端点通讯的长度为1字节
sizeof(pInformation->Current_AlternateSetting);
return 0;
}
pUser_Standard_Requests->User_GetInterface(); //调用User_GetInterface函数,该函数在usb_prop.c中注册
return (uint8_t *)&pInformation->Current_AlternateSetting; //返回备用接口值的地址
}
我们可以对比下上面两个get函数,函数结构上都类似,起始获取配置或接口值都只要返回DEVICE_INFO *pInformation里的对应的值就可以了。
接下去是两个Set函数:
/*******************************************************************************
* Function Name : Standard_SetConfiguration.
* Description : 该函数用于设置配置值,主机发送该请求后,usb设备要配置自己的设备值
* Input : None.
* Output : None.
* Return : 当该请求被执行了,返回USB_SUCCESS
* 当请求无效时,然会USB_UNSUPPORT
*******************************************************************************/
RESULT Standard_SetConfiguration(void)
{
if ((pInformation->USBwValue0 <= //当配置值(即设备的编号)小于已使用的端点编号
Device_Table.Total_Configuration) && (pInformation->USBwValue1 == 0)//USBwValue是16bit,低8字节表示配置值,高8bit为0
&& (pInformation->USBwIndex == 0)) /*call Back usb spec 2.0*/ //USBwIndex域用不到,固定为0
{
pInformation->Current_Configuration = pInformation->USBwValue0; //Current_Configuration设置成要设置的配置值
pUser_Standard_Requests->User_SetConfiguration(); //调用User_SetConfiguration函数,该函数在usb_prop.c中注册
return USB_SUCCESS;
}
else
{
return USB_UNSUPPORT;
}
}
/*******************************************************************************
* Function Name : Standard_SetInterface.
* Description : 该函数用于设置接口值,主机该请求后,usn设备设置自己的接口值
* Input : None.
* Output : None.
* Return : 当请求被执行,返回USB_SUCCESS,当请求无效,返回USB_UNSUPPORT
*******************************************************************************/
RESULT Standard_SetInterface(void)
{
RESULT Re;
/*测试应用程序是否支持被选中的接口和备用接口,成功返回SUCCESS*/
Re = (*pProperty->Class_Get_Interface_Setting)(pInformation->USBwIndex0, pInformation->USBwValue0);
if (pInformation->Current_Configuration != 0) //有不为0的配置值,如果配置值为0.则会让设备进入设置地址状态
{
if ((Re != USB_SUCCESS) || (pInformation->USBwIndex1 != 0) //应用程序不支持,或16bit接口号的高8位不为0,或wValue的值不为0
|| (pInformation->USBwValue1 != 0))
{
return USB_UNSUPPORT; //返回USB_UNSUPPORT
} //如果应用程序支持接口
else if (Re == USB_SUCCESS)
{ //调用User_SetInterface(),该函数在usb_prop.c里定义
pUser_Standard_Requests->User_SetInterface();
pInformation->Current_Interface = pInformation->USBwIndex0;//设置当前的接口值
pInformation->Current_AlternateSetting = pInformation->USBwValue0; //设置当前的备用接口,一般情况下设置为0
return USB_SUCCESS;
}
}
return USB_UNSUPPORT;
}
设置配置值或接口值的函数解析USB主机发送过来的标准请求数据,对于设置配置请求
USBwValue0存放着配置值;对于设置接口请求
USBwIndex0
就存放着接口值。
还有Standard_GetDescriptorData();是获取描述符的函数;
/*******************************************************************************
* Function Name : DataStageOut.
* Description : 数据阶段的控制写传输
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
void DataStageOut(void)
{
ENDPOINT_INFO *pEPinfo = &pInformation->Ctrl_Info;
uint32_t save_rLength;
save_rLength = pEPinfo->Usb_rLength; //获取要传输的长度
if (pEPinfo->CopyData && save_rLength) //缓冲区中有数据,且要传输的数据长度大于0
{
uint8_t *Buffer;
uint32_t Length;
Length = pEPinfo->PacketSize; //端点缓冲区总的数据长度
if (Length > save_rLength) //要发送的数据长度小于总的数据长度
{
Length = save_rLength; //Length等于要传输的数据长度
}
Buffer = (*pEPinfo->CopyData)(Length); //获取数据缓冲的地址
pEPinfo->Usb_rLength -= Length; //计算剩余的长度
pEPinfo->Usb_rOffset += Length; //调整偏移量
#ifdef STM32F10X_CL
PCD_EP_Read(ENDP0, Buffer, Length);
#else
PMAToUserBufferCopy(Buffer, GetEPRxAddr(ENDP0), Length);//从要发送的数据缓冲区Buffer拷贝Length数据到PMA缓冲区中
#endif /* STM32F10X_CL */
}
if (pEPinfo->Usb_rLength != 0) //如果还有剩余的数据
{
vSetEPRxStatus(EP_RX_VALID); //重新设置端点接收(相对主机而言)状态有效
SetEPTxCount(ENDP0, 0); //设置端点发送状态计数为0
vSetEPTxStatus(EP_TX_VALID); //设置发送状态有效,好让主机可以中断数据输出阶段
}
/* Set the next State*/
if (pEPinfo->Usb_rLength >= pEPinfo->PacketSize) //如果要传输的长度大于端点的缓冲大小
{
pInformation->ControlState = OUT_DATA; //说明还处于OUT_DATA数据阶段
}
else //如果要传输的长度小于端点的缓冲大小
{
if (pEPinfo->Usb_rLength > 0) //且还有剩余数据
{
pInformation->ControlState = LAST_OUT_DATA; //说明这是最后要传输的数据了。
}
else if (pEPinfo->Usb_rLength == 0) //如果已经没哟要传输的数据了
{
pInformation->ControlState = WAIT_STATUS_IN; //进入WAIT_STATUS_IN状态
USB_StatusIn();
}
}
}
/*******************************************************************************
* Function Name : DataStageIn.
* Description : 数据阶段的控制读传输
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
void DataStageIn(void)
{
ENDPOINT_INFO *pEPinfo = &pInformation->Ctrl_Info; //pEPinfo获取端点信息
uint32_t save_wLength = pEPinfo->Usb_wLength; //save_wLength为要接收的数据长度
uint32_t ControlState = pInformation->ControlState; //ControlState获取当前设备的控制状态
uint8_t *DataBuffer;
uint32_t Length;
if ((save_wLength == 0) && (ControlState == LAST_IN_DATA))//如果没有要接收的数据,且控制状态为LAST_IN_DATA最后数据状态
{
if(Data_Mul_MaxPacketSize == TRUE) //如果要接收的数据长度是最大数据长度的整数倍,且小于数据缓冲区的大小
{
Send0LengthData(); //说明没有数据可以接收了,重新使能TX
ControlState = LAST_IN_DATA; //此时控制的状态为LAST_IN_DATA
Data_Mul_MaxPacketSize = FALSE; //Data_Mul_MaxPacketSize标志为FALSE
}
else
{
ControlState = WAIT_STATUS_OUT; //没有可接收的的数据了,此时进入WAIT_STATUS_OUT状态
#ifdef STM32F10X_CL
PCD_EP_Read (ENDP0, 0, 0);
#endif /* STM32F10X_CL */
#ifndef STM32F10X_CL
vSetEPTxStatus(EP_TX_STALL); //设置端点发送(相对于主机而言)状态为停止状态
#endif /* STM32F10X_CL */
}
goto Expect_Status_Out; //程序跳转到Expect_Status_Out处
}
Length = pEPinfo->PacketSize; //获取整个数据包的长度
ControlState = (save_wLength <= Length) ? LAST_IN_DATA : IN_DATA; //要接收的数据长度小于等于数据包长度,则是LAST_IN_DATA状态,否则是IN_DATA状态
if (Length > save_wLength) //总的数据包的长度大于要接收的数据长度
{
Length = save_wLength; //Length等于要接收的数据长度
}
DataBuffer = (*pEPinfo->CopyData)(Length); //获取数据缓冲区的地址
#ifdef STM32F10X_CL
PCD_EP_Write (ENDP0, DataBuffer, Length);
#else
UserToPMABufferCopy(DataBuffer, GetEPTxAddr(ENDP0), Length);//从PMA缓冲区中拷贝Length个字节到DataBuffer地址去
#endif /* STM32F10X_CL */
SetEPTxCount(ENDP0, Length); //设置端点的发送(相对主机而言)状态计数值为Length,即接收到Length个数据
pEPinfo->Usb_wLength -= Length; //剩下的数据
pEPinfo->Usb_wOffset += Length; //调整偏移量
vSetEPTxStatus(EP_TX_VALID); //设置端点的发送状态有效,即可以继续接收数据
USB_StatusOut(); //设置端点接收(对主机而言)状态有效,好让主机可以中断的数据读阶段
Expect_Status_Out:
pInformation->ControlState = ControlState;
}
/*******************************************************************************
* Function Name : NoData_Setup0.
* Description : 处理没有数据阶段的建立请求
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
void NoData_Setup0(void)
{
RESULT Result = USB_UNSUPPORT;
uint32_t RequestNo = pInformation->USBbRequest; //获取请求代码
uint32_t ControlState;
if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT)) //标准请求,请求的接收者是设备
{
/* Device Request*/
/* SET_CONFIGURATION*/
if (RequestNo == SET_CONFIGURATION) //收到设置配置请求
{
Result = Standard_SetConfiguration(); //设置配置值
}
/*SET ADDRESS*/
else if (RequestNo == SET_ADDRESS) //收到设置地址请求,wValue存放地址,wIndex必须为0,wLength必须为0
{
if ((pInformation->USBwValue0 > 127) || (pInformation->USBwValue1 != 0)//设备地址没有在0~127
|| (pInformation->USBwIndex != 0) //wValue没有为0
|| (pInformation->Current_Configuration != 0)) //当前的配置值不为0,说明usb已经枚举过了
/* Device Address should be 127 or less*/
{
ControlState = STALLED; //有如上不正确情况,设置控制状态为停止状态
goto exit_NoData_Setup0;
}
else
{
Result = USB_SUCCESS; //Result赋予USB_SUCCESS
#ifdef STM32F10X_CL
SetDeviceAddress(pInformation->USBwValue0); //设置设备的地址
#endif /* STM32F10X_CL */
}
}
/*SET FEATURE for Device*/
else if (RequestNo == SET_FEATURE) //如果是设置特性请求
{
if ((pInformation->USBwValue0 == DEVICE_REMOTE_WAKEUP) \
&& (pInformation->USBwIndex == 0)) //如要设置的是使能远程唤醒并且wIndex域为0
{
Result = Standard_SetDeviceFeature(); //设置设备的特性
}
else
{
Result = USB_UNSUPPORT; //否则Result赋予USB_UNSUPPORT
}
}
/*Clear FEATURE for Device */
else if (RequestNo == CLEAR_FEATURE) //如果是清除特性请求
{
if (pInformation->USBwValue0 == DEVICE_REMOTE_WAKEUP //如过要清除的是远程唤醒特性
&& pInformation->USBwIndex == 0 //且wIndex域为0
&& ValBit(pInformation->Current_Feature, 5)) //且当前设备的特性有远程唤醒特性
{
Result = Standard_ClearFeature(); //则清除远程唤醒特性
}
else
{
Result = USB_UNSUPPORT; //否则Result赋予USB_UNSUPPORT
}
}
}
/* Interface Request*/
else if (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT))//标准请求,且请求的接收者是接口
{
/*SET INTERFACE*/
if (RequestNo == SET_INTERFACE) //如果是设置接口请求
{
Result = Standard_SetInterface(); //设置接口值
}
}
/* EndPoint Request*/
else if (Type_Recipient == (STANDARD_REQUEST | ENDPOINT_RECIPIENT))//标准请求,且请求的接收者是端点
{
/*CLEAR FEATURE for EndPoint*/
if (RequestNo == CLEAR_FEATURE) //如果是清除特性请求
{
Result = Standard_ClearFeature(); //清除端点的特性
}
/* SET FEATURE for EndPoint*/
else if (RequestNo == SET_FEATURE) //如果是设置特性请求
{
Result = Standard_SetEndPointFeature(); //设置端点的特性
}
}
else //不是标准请求或其他USB协议之外的一些请求
{
Result = USB_UNSUPPORT;
}
if (Result != USB_SUCCESS) //如果处理请求不成功
{
Result = (*pProperty->Class_NoData_Setup)(RequestNo); //看看是不是特殊类请求
if (Result == USB_NOT_READY) //如果USB忙,即上个请求还没有处理完
{
ControlState = PAUSE; //设置状态为暂停
goto exit_NoData_Setup0; //程序跳到exit_NoData_Setup0处
}
}
if (Result != USB_SUCCESS) //如果不是特殊类请求
{
ControlState = STALLED; //设置状态为停止状态
goto exit_NoData_Setup0; //程序跳到exit_NoData_Setup0处
}
ControlState = WAIT_STATUS_IN; //进入WAIT_STATUS_IN状态
USB_StatusIn(); //这里其实是设置端点发送(相对于主机来说)状态有效,好接收状态阶段的数据
exit_NoData_Setup0:
pInformation->ControlState = ControlState; //设置当前的状态
return;
}
/*******************************************************************************
* Function Name : Data_Setup0.
* Description : 处理有数据阶段的建立请求
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
void Data_Setup0(void)
{
uint8_t *(*CopyRoutine)(uint16_t);
RESULT Result;
uint32_t Request_No = pInformation->USBbRequest; //获取请求代号
uint32_t Related_Endpoint, Reserved;
uint32_t wOffset, Status;
CopyRoutine = NULL;
wOffset = 0;
/*GET DESCRIPTOR*/
if (Request_No == GET_DESCRIPTOR) //如果是获取描述符的请求,获取描述符的接收者只能是设备
{
if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))//标准请求,且请求的接收者是设备
{
uint8_t wValue1 = pInformation->USBwValue1; //USBwValue0表示索引号,USBwValue1表示描述符的类型编号
if (wValue1 == DEVICE_DESCRIPTOR) //如果是设别描述符
{
CopyRoutine = pProperty->GetDeviceDescriptor; //获取设备描述符
}
else if (wValue1 == CONFIG_DESCRIPTOR) //如果是配置描述符
{
CopyRoutine = pProperty->GetConfigDescriptor; //获取配置描述符
}
else if (wValue1 == STRING_DESCRIPTOR) //如果是字符串描述符
{
CopyRoutine = pProperty->GetStringDescriptor; //获取字符串描述符
} /* End of GET_DESCRIPTOR */
}
}
/*GET STATUS*/
else if ((Request_No == GET_STATUS) && (pInformation->USBwValue == 0)//如果是获取状态请求,且wValue域为0
&& (pInformation->USBwLength == 0x0002)
&& (pInformation->USBwIndex1 == 0))
{
/* GET STATUS for Device*/
if ((Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))//标准请求,请求的接受者是设备
&& (pInformation->USBwIndex == 0)) //且wIndex域为0
{
CopyRoutine = Standard_GetStatus; //函数指针指向Standard_GetStatus函数
}
/* GET STATUS for Interface*/
else if (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT))//标准请求,且请求的接收者是接口
{
if (((*pProperty->Class_Get_Interface_Setting)(pInformation->USBwIndex0, 0) == USB_SUCCESS)//测试接口和备用接口是否支持
&& (pInformation->Current_Configuration != 0)) //且当前的配置值不为0
{
CopyRoutine = Standard_GetStatus; //函数指针指向Standard_GetStatus函数
}
}
/* GET STATUS for EndPoint*/
else if (Type_Recipient == (STANDARD_REQUEST | ENDPOINT_RECIPIENT))//标准请求,且请求的接收者是端点
{
Related_Endpoint = (pInformation->USBwIndex0 & 0x0f); //获取端点号,D0~D3表示端点号
Reserved = pInformation->USBwIndex0 & 0x70; //获取保留值,D4~D6是保留值,必须为0
if (ValBit(pInformation->USBwIndex0, 7)) //如果D7为1,表示是输入
{
/*Get Status of endpoint & stall the request if the related_ENdpoint
is Disabled*/
Status = _GetEPTxStatus(Related_Endpoint); //获取该端点的发送状态
}
else
{
Status = _GetEPRxStatus(Related_Endpoint); //获取该端点的接收状态
}
if ((Related_Endpoint < Device_Table.Total_Endpoint) && (Reserved == 0)//端点号小于总端点数,保留值正确
&& (Status != 0)) //且端点有效
{
CopyRoutine = Standard_GetStatus; //函数指针指向Standard_GetStatus函数
}
}
}
/*GET CONFIGURATION*/
else if (Request_No == GET_CONFIGURATION) //如果是获取配置请求
{
if (Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))//标准请求,且请求的接收者是设备
{
CopyRoutine = Standard_GetConfiguration; //函数指针指向Standard_GetConfiguration函数
}
}
/*GET INTERFACE*/
else if (Request_No == GET_INTERFACE) //如果是获取接口请求
{
if ((Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT))//标准请求,且请求的接收者是接口
&& (pInformation->Current_Configuration != 0) && (pInformation->USBwValue == 0)//当前的配置值不为0,wValue域的值为0
&& (pInformation->USBwIndex1 == 0) && (pInformation->USBwLength == 0x0001) //wIndex1域的值为0,并且数据长度为1
&& ((*pProperty->Class_Get_Interface_Setting)(pInformation->USBwIndex0, 0) == USB_SUCCESS))//支持接口和备用接口
{
CopyRoutine = Standard_GetInterface; //函数指针指向Standard_GetInterface函数
}
}
if (CopyRoutine) //该函数指针不为空
{
pInformation->Ctrl_Info.Usb_wOffset = wOffset; //设置偏移量
pInformation->Ctrl_Info.CopyData = CopyRoutine; //注册处理函数
/* sb in the original the cast to word was directly */
/* now the cast is made step by step */
(*CopyRoutine)(0); //执行该函数
Result = USB_SUCCESS;
}
else //该函数指针为空
{
Result = (*pProperty->Class_Data_Setup)(pInformation->USBbRequest);//说明不是标准请求,则是特殊类请求,调用Class_Data_Setup函数
if (Result == USB_NOT_READY) //如果USB忙,表示处理上一次请求
{
pInformation->ControlState = PAUSE; //设置状态为暂停
return;
}
}
if (pInformation->Ctrl_Info.Usb_wLength == 0xFFFF) //如果要发送的数据长度为0xffff
{
/* Data is not ready, wait it */
pInformation->ControlState = PAUSE; //设置状态为暂停
return;
}
if ((Result == USB_UNSUPPORT) || (pInformation->Ctrl_Info.Usb_wLength == 0))//如果没有检测到USB或没有要传输的数据
{
/* Unsupported request */
pInformation->ControlState = STALLED; //设置控制状态为停止
return;
}
if (ValBit(pInformation->USBbmRequestType, 7)) //如果是输入状态,即设备到主机
{
/* Device ==> Host */
__IO uint32_t wLength = pInformation->USBwLength; //获取数据过程要传输的字节数
/* Restrict the data length to be the one host asks for */
if (pInformation->Ctrl_Info.Usb_wLength > wLength) //如果要发送的数据长度大于主机要求的数据长度
{
pInformation->Ctrl_Info.Usb_wLength = wLength; //则发送主机要求的数据长度
}
else if (pInformation->Ctrl_Info.Usb_wLength < pInformation->USBwLength)//如果要发送的数据长度小于主机要求的数据长度
{
if (pInformation->Ctrl_Info.Usb_wLength < pProperty->MaxPacketSize)//如果要发送的数据长度小于最大数据包长度
{ //Data_Mul_MaxPacketSize赋0
Data_Mul_MaxPacketSize = FALSE;
}
else if ((pInformation->Ctrl_Info.Usb_wLength % pProperty->MaxPacketSize) == 0)//如果要发送的数据包是最大数据包的整数倍
{
Data_Mul_MaxPacketSize = TRUE; //Data_Mul_MaxPacketSize置1
}
}
pInformation->Ctrl_Info.PacketSize = pProperty->MaxPacketSize;//端点数据包的长度设置为最大数据包长度
DataStageIn(); //调用数据阶段控制写函数
}
else //如果是输出状态,即主机到设备
{
pInformation->ControlState = OUT_DATA; //设置控制的状态为OUT_DATA
vSetEPRxStatus(EP_RX_VALID); //设置端点接收装塔斯有效以下次接收数据
}
return;
}
/*******************************************************************************
* Function Name : Setup0_Process
* Description : 建立阶段的数据处理Get the device request data and dispatch to individual process.
* Input : None.
* Output : None.
* Return : Post0_Process.
*******************************************************************************/
uint8_t Setup0_Process(void)
{
union
{
uint8_t* b;
uint16_t* w;
} pBuf;
#ifdef STM32F10X_CL
USB_OTG_EP *ep;
uint16_t offset = 0;
ep = PCD_GetOutEP(ENDP0);
pBuf.b = ep->xfer_buff;
#else
uint16_t offset = 1;
pBuf.b = PMAAddr + (uint8_t *)(_GetEPRxAddr(ENDP0) * 2); //获取接收端点的缓冲区地址
#endif /* STM32F10X_CL */
if (pInformation->ControlState != PAUSE) //控制状态不是暂停
{
/*为什么USBbmRequestType和USBbRequest两个域在一个32位的地址中?*/
pInformation->USBbmRequestType = *pBuf.b++; //获取一个字节的bmRequestType
pInformation->USBbRequest = *pBuf.b++; //获取一个字节的bRequest */
pBuf.w += offset; //因为STM32是32位处理器,所以地址也是32位的,所以跳过后16位
pInformation->USBwValue = ByteSwap(*pBuf.w++); //获取2字节的wValue值并该成小端模式
pBuf.w += offset; //因为STM32是32位处理器,所以地址也是32位的,所以跳过后16位
pInformation->USBwIndex = ByteSwap(*pBuf.w++); //获取2字节的wIndex值并修改成小端模式
pBuf.w += offset; //因为STM32是32位处理器,所以地址也是32位的,所以跳过后16位
pInformation->USBwLength = *pBuf.w; //获取2字节的wLength
}
pInformation->ControlState = SETTING_UP; //设置控制的状态为建立状态SETTING_UP
if (pInformation->USBwLength == 0)
{
/* Setup with no data stage */
NoData_Setup0(); //处理没有数据阶段的建立请求
}
else
{
/* Setup with data stage */
Data_Setup0(); //处理有数据阶段的建立请求
}
return Post0_Process();
}
/*******************************************************************************
* Function Name : In0_Process
* Description : 处理默认端点的所有IN令牌包
* Input : None.
* Output : None.
* Return : Post0_Process.
*******************************************************************************/
uint8_t In0_Process(void)
{
uint32_t ControlState = pInformation->ControlState;
if ((ControlState == IN_DATA) || (ControlState == LAST_IN_DATA)) //状态在IN_DATA或LAST_IN_DATA
{
DataStageIn(); //处理控制写传输
/* ControlState may be changed outside the function */
ControlState = pInformation->ControlState; //获取处理后的状态
}
else if (ControlState == WAIT_STATUS_IN) //状态在WAIT_STATUS_IN
{
if ((pInformation->USBbRequest == SET_ADDRESS) && //设置地址请求
(Type_Recipient == (STANDARD_REQUEST | DEVICE_RECIPIENT))) //标准请求,请求的接收者是设备
{
SetDeviceAddress(pInformation->USBwValue0); //设置USB设备地址
pUser_Standard_Requests->User_SetDeviceAddress(); //调用User_SetDeviceAddress函数,注册地址信息
}
(*pProperty->Process_Status_IN)(); //调用Process_Status_IN()处理IN令牌包
ControlState = STALLED; //设置状态为停止
}
else //状态不是WAIT_STATUS_IN
{
ControlState = STALLED; //设置状态为停止
}
pInformation->ControlState = ControlState; //获取处理后的控制状态
return Post0_Process();
}
/*******************************************************************************
* Function Name : Out0_Process
* Description : 处理默认端点上的所有OUT令牌包
* Input : None.
* Output : None.
* Return : Post0_Process.
*******************************************************************************/
uint8_t Out0_Process(void)
{
uint32_t ControlState = pInformation->ControlState; //获取控制状态
if ((ControlState == IN_DATA) || (ControlState == LAST_IN_DATA)) //如果是IN_DATA或LAST_IN_DATA状态
{
/* host aborts the transfer before finish */
ControlState = STALLED; //设置状态为停止
}
else if ((ControlState == OUT_DATA) || (ControlState == LAST_OUT_DATA))//如果是OUT_DATA或LAST_OUT_DATA
{
DataStageOut(); //处理控制写传输
ControlState = pInformation->ControlState; //获取处理后的控制状态
}
else if (ControlState == WAIT_STATUS_OUT) //如果控制状态是WAIT_STATUS_OUT
{
(*pProperty->Process_Status_OUT)(); //调用Process_Status_OUT()处理OUT令牌包
#ifndef STM32F10X_CL
ControlState = STALLED; //然后设置状态为停止状态
#endif /* STM32F10X_CL */
}
/* Unexpect state, STALL the endpoint */
else
{
ControlState = STALLED;
}
pInformation->ControlState = ControlState; //获取处理后的控制状态
return Post0_Process();
}
/*******************************************************************************
* Function Name : Post0_Process
* Description : 为防止错误,停止端点0Stall the Endpoint 0 in case of error.
* Input : None.
* Output : None.
* Return : 如果控制状态是PAUSE,返回0;如果不是返回1
*******************************************************************************/
uint8_t Post0_Process(void)
{
#ifdef STM32F10X_CL
USB_OTG_EP *ep;
#endif /* STM32F10X_CL */
SetEPRxCount(ENDP0, Device_Property.MaxPacketSize); //设置端点0的接收计数值为最大包长度
if (pInformation->ControlState == STALLED) //如果当前控制状态是停止状态
{
vSetEPRxStatus(EP_RX_STALL); //设置端点接收状态为停止
vSetEPTxStatus(EP_TX_STALL); //设置端点发送状态为停止
}
#ifdef STM32F10X_CL
else if ((pInformation->ControlState == OUT_DATA) || //如果控制是OUT_DATA或WAIT_STATUS_OUT
(pInformation->ControlState == WAIT_STATUS_OUT))
{
ep = PCD_GetInEP(0);
ep->is_in = 0;
OTGD_FS_EP0StartXfer(ep);
vSetEPTxStatus(EP_TX_VALID);
}
else if ((pInformation->ControlState == IN_DATA) || //如果控制是OUT_DATA或WAIT_STATUS_OUT
(pInformation->ControlState == WAIT_STATUS_IN))
{
ep = PCD_GetInEP(0);
ep->is_in = 1;
OTGD_FS_EP0StartXfer(ep);
}
#endif /* STM32F10X_CL */
return (pInformation->ControlState == PAUSE);
}
/*******************************************************************************
* Function Name : SetDeviceAddress.
* Description : 设置设备和所有使用过的端点地址
* Input : Val:设备地址
* Output : None.
* Return : None.
*******************************************************************************/
void SetDeviceAddress(uint8_t Val)
{
#ifdef STM32F10X_CL
PCD_EP_SetAddress ((uint8_t)Val);
#else
uint32_t i;
uint32_t nEP = Device_Table.Total_Endpoint; //获取所有已使用的端点数
/* set address in every used endpoint */
for (i = 0; i < nEP; i++)
{
_SetEPAddress((uint8_t)i, (uint8_t)i); //设置这些端点的地址
} /* for */
_SetDADDR(Val | DADDR_EF); //设置设备的地址,并且将EF位置位,使能USB模块位
#endif /* STM32F10X_CL */
}
/*******************************************************************************
* Function Name : NOP_Process
* Description : 没有处理函数
* Input : None.
* Output : None.
* Return : None.
*******************************************************************************/
void NOP_Process(void)
{
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)