USB主机通过描述符一级级的得到从机的信息,STM32的USB代码是通过Device_Property实现的。
一个USB设备只有一个设备描述符--N个配置描述符 -----N个接口描述符--------N个端点描述符。
USB主机读取描述符合集时,一种方式是先读取前面9个字节的配置描述符,这样就得到整个合集的长度,然后再全部读回合集;另一种方式是直接读整段数据。
HID描述符和接口描述符似乎是从这段数据中判断出来的,并没有像其他描述符有直接的接口函数获取。
对于HID描述符和报表描述符,程序是通过结构Device_Property中的Class_Data_Setup来获取的。Class_Data_Setup是处理类所有有Data阶段的请求过程。 Class_Data_Setup()响应所有的特殊请求,并根据请求填写ENDPOINT_INFO。
如果是IN标记, wLength 和 wOffset就会赋值总传输字节和起始位置;如果是OUT标记,rLength 和 rOffset就会赋值预期的总字节数和缓冲区中的起始位置。
注意:
由于GET_CONFIGURATION和GET_INTERFACE 与类高度相关,因此将在此处检查和处理它们。
RESULT usbClassDataSetup(uint8_t RequestNo)
{
uint8_t *(*CopyRoutine)(uint16_t);
CopyRoutine = NULL;
if ((RequestNo == GET_DESCRIPTOR)
&& (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT))
&& (pInformation->USBwIndex0 == 0))
{
if (pInformation->USBwValue1 == HID_REPORT_DESCRIPTOR_TYPE)
{
CopyRoutine = hidGetReportDescriptor;
}
else if (pInformation->USBwValue1 == HID_DESCRIPTOR_TYPE)
{
CopyRoutine = hidGetHIDDescriptor;
}
} /* End of GET_DESCRIPTOR */
/*** GET_PROTOCOL ***/
else if ((Type_Recipient == (CLASS_REQUEST | INTERFACE_RECIPIENT))
&& RequestNo == HID_GET_PROTOCOL)
{
CopyRoutine = hidGetProtocolValue;
}
if (CopyRoutine == NULL)
{
return USB_UNSUPPORT;
}
pInformation->Ctrl_Info.CopyData = CopyRoutine;
pInformation->Ctrl_Info.Usb_wOffset = 0;
(*CopyRoutine)(0);
return USB_SUCCESS;
}