主机环境:Windows 7 SP1
开发环境:MDK5.14
目标板:STM32F103C8T6
开发库:STM32F1Cube库和STM32_USB_Device_Library
现在分析USB器件库核心文件的最后一个文件usbd_ctlreq,该文件提供了标准请求的处理,跟USB2.0协议的第九章节紧密关联。在Setup阶段根据bmRequest字段的内容分为:设备请求、接口请求、端点请求。并根据不同的请求调用不同的函数体,USB2.0协议中定义的标清请求有以下几种
通过第一个竖栏可以看出同一个请求代码可以对应多个接收者,例如CLEAR_FEATURE请求可以是设备请求也可以是接口请求,同样也可以是端点请求。对应的各个请求代码,如下
在usbd_def.h文件中可以找到与之对应的定义,如下:
#define USB_REQ_GET_STATUS 0x00
#define USB_REQ_CLEAR_FEATURE 0x01
#define USB_REQ_SET_FEATURE 0x03
#define USB_REQ_SET_ADDRESS 0x05
#define USB_REQ_GET_DESCRIPTOR 0x06
#define USB_REQ_SET_DESCRIPTOR 0x07
#define USB_REQ_GET_CONFIGURATION 0x08
#define USB_REQ_SET_CONFIGURATION 0x09
#define USB_REQ_GET_INTERFACE 0x0A
#define USB_REQ_SET_INTERFACE 0x0B
#define USB_REQ_SYNCH_FRAME 0x0C
首先看一下标准设备请求的处理,
/**
* @brief USBD_StdDevReq
* Handle standard usb device requests
* @param pdev: device instance
* @param req: usb request
* @retval status
*/
USBD_StatusTypeDef USBD_StdDevReq (USBD_HandleTypeDef *pdev , USBD_SetupReqTypedef *req)
{
USBD_StatusTypeDef ret = USBD_OK;
switch (req->bRequest)
{
case USB_REQ_GET_DESCRIPTOR:
USBD_GetDescriptor (pdev, req) ;
break;
case USB_REQ_SET_ADDRESS:
USBD_SetAddress(pdev, req);
break;
case USB_REQ_SET_CONFIGURATION:
USBD_SetConfig (pdev , req);
break;
case USB_REQ_GET_CONFIGURATION:
USBD_GetConfig (pdev , req);
break;
case USB_REQ_GET_STATUS:
USBD_GetStatus (pdev , req);
break;
case USB_REQ_SET_FEATURE:
USBD_SetFeature (pdev , req);
break;
case USB_REQ_CLEAR_FEATURE:
USBD_ClrFeature (pdev , req);
break;
default:
USBD_CtlError(pdev , req);
break;
}
return ret;
}
符合标准的设备请求通过Table 9-3可以看出一共有8种,这里只处理了7种,SET_DESCRIPTOR是没有处理的,当请求不是这7种请求的任何一种时通过USBD_CtlError()函数回应给USB主机一个STALL表明请求错误发生。首先看第一个请求获取描述符请求的处理,如下:
/**
* @brief USBD_GetDescriptor
* Handle Get Descriptor requests
* @param pdev: device instance
* @param req: usb request
* @retval status
*/
static void USBD_GetDescriptor(USBD_HandleTypeDef *pdev ,
USBD_SetupReqTypedef *req)
{
uint16_t len;
uint8_t *pbuf;
switch (req->wValue >> 8)
{
#if (USBD_LPM_ENABLED == 1)
case USB_DESC_TYPE_BOS:
pbuf = pdev->pDesc->GetBOSDescriptor(pdev->dev_speed, &len);
break;
#endif
case USB_DESC_TYPE_DEVICE:
pbuf = pdev->pDesc->GetDeviceDescriptor(pdev->dev_speed, &len);
break;
case USB_DESC_TYPE_CONFIGURATION:
if(pdev->dev_speed == USBD_SPEED_HIGH )
{
pbuf = (uint8_t *)pdev->pClass->GetHSConfigDescriptor(&len);
pbuf[1] = USB_DESC_TYPE_CONFIGURATION;
}
else
{
pbuf = (uint8_t *)pdev->pClass->GetFSConfigDescriptor(&len);
pbuf[1] = USB_DESC_TYPE_CONFIGURATION;
}
break;
case USB_DESC_TYPE_STRING:
switch ((uint8_t)(req->wValue))
{
case USBD_IDX_LANGID_STR:
pbuf = pdev->pDesc->GetLangIDStrDescriptor(pdev->dev_speed, &len);
break;
case USBD_IDX_MFC_STR:
pbuf = pdev->pDesc->GetManufacturerStrDescriptor(pdev->dev_speed, &len);
break;
case USBD_IDX_PRODUCT_STR:
pbuf = pdev->pDesc->GetProductStrDescriptor(pdev->dev_speed, &len);
break;
case USBD_IDX_SERIAL_STR:
pbuf = pdev->pDesc->GetSerialStrDescriptor(pdev->dev_speed, &len);
break;
case USBD_IDX_CONFIG_STR:
pbuf = pdev->pDesc->GetConfigurationStrDescriptor(pdev->dev_speed, &len);
break;
case USBD_IDX_INTERFACE_STR:
pbuf = pdev->pDesc->GetInterfaceStrDescriptor(pdev->dev_speed, &len);
break;
default:
#if (USBD_SUPPORT_USER_STRING == 1)
pbuf = pdev->pClass->GetUsrStrDescriptor(pdev, (req->wValue) , &len);
break;
#else
USBD_CtlError(pdev , req);
return;
#endif
}
break;
case USB_DESC_TYPE_DEVICE_QUALIFIER:
if(pdev->dev_speed == USBD_SPEED_HIGH )
{
pbuf = (uint8_t *)pdev->pClass->GetDeviceQualifierDescriptor(&len);
break;
}
else
{
USBD_CtlError(pdev , req);
return;
}
case USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION:
if(pdev->dev_speed == USBD_SPEED_HIGH )
{
pbuf = (uint8_t *)pdev->pClass->GetOtherSpeedConfigDescriptor(&len);
pbuf[1] = USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION;
break;
}
else
{
USBD_CtlError(pdev , req);
return;
}
default:
USBD_CtlError(pdev , req);
return;
}
if((len != 0)&& (req->wLength != 0))
{
len = MIN(len , req->wLength);
USBD_CtlSendData (pdev,
pbuf,
len);
}
}
也是一大串switch-case语句,这样的代码虽然多但容易分析,在GET_DESCRIPTOR请求中,根据Table 9-3可知wValue字段的含义是描述符类型和描述符索引,在USB2.0协议的9.4.3章节中可以看到wValue的高字节标记了描述符的类型,wValue的低字节标记了描述符的索引。在USBD_GetDescriptor()函数中首先是检测描述符类型,第一个分支是设备描述符,通过pdev句柄的pDesc指针下的GetDeviceDescriptor指针调用所需要的函数即我们之前分析过的usbd_desc.c文件中的对应函数。第二个分支是获取配置描述符,这个是通过设备类指针获取的,放在后面分析,且这里分出了高速和全速模式。接着一个大分支是获取字符串描述符,这里就需要用到wValue的低字节描述符索引来细分各个字符串描述符,获取字符串描述符的处理跟获
『本文转载自网络,版权归原作者所有,如有侵权请联系删除』