您好!
我已经设法修改了 tivaware usblib、以便成功响应 Microsoft 的操作系统字符串描述符-这是一种非标准的描述符类型。 下面显示了这个 USB 交易交换的屏幕截图。 此描述符交换由 Data0设置数据包中的 EE 表示。
此描述符交换看起来与所有标准描述符交换完全匹配。 请参阅下面的标准设计。
现在、我遇到的问题是、在 windows 发送一个 OS 字符串描述符后、它会发送一个兼容的 ID 描述符。 我以相同的方式对该描述符请求进行响应、响应会失败。 我一直在测试修改 usblib 以进行响应的不同方式、它们似乎都以如下所示的相同方式失败。
我在协议分析器上遇到的错误说明"Invalid PID sequence"、并详细说明"已观察到无效的数据包序列"。
我已经尝试使用以下函数进行响应、但运气不好。 不过、我确实看到"in"数据包的 Data1具有正确的数据。 我正在尝试发送以下描述符响应。
const uint8_t g_pui8MicrosoftCompatibleIDFeatureDesc[] = //uint8_t g_pui8MicrosoftCompatibleIDFeatureDesc[] = { 0x28, 0x00, 0x00, 0x00, // Desc Length 0x00, 0x01, // Version '1.0' 0x04, 0x00, // Compatibility ID descriptor index 0x0004 0x01, // Number of Sections 0x00, 0x00, 0x00, 0x00, // RESERVED 0x00, 0x00, 0x00, // RESERVED 0x00, // Interface Number (Interface #0) 0x01, // RESERVED 0x57, 0x49, 0x4E, 0x55, // (8 bytes) Compatibility ID "WINUSB\0\0" 0x53, 0x42, 0x00, 0x00, // 0x00, 0x00, 0x00, 0x00, // (8 bytes) Sub-Compatible ID (UNUSED) 0x00, 0x00, 0x00, 0x00, // 0x00, 0x00, 0x00, 0x00, // (6 bytes) RESERVED 0x00, 0x00, // };
使用此函数:
USBDCDSendDataEP0(0, g_pui8MicrosoftCompatibleIDFeatureDesc, 40);
目前为了测试、我还尝试了以下方法进行回应。
// // Need to ACK the data on end point 0 without setting last data as there // will be a data phase. // MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, false); // // // Return the externally specified MS OS string descriptor. // g_psDCDInst[0].pui8EP0Data = (uint8_t *)g_pui8MicrosoftCompatibleIDFeatureDesc; // // The total size of a string descriptor is in byte 0. // g_psDCDInst[0].ui32EP0DataRemain = g_pui8MicrosoftCompatibleIDFeatureDesc[0]; // // Save the total size of the data sent. // g_psDCDInst[0].ui32OUTDataSize = g_pui8MicrosoftCompatibleIDFeatureDesc[0]; USBDEP0StateTx(0);
这些代码片段可在 usbdenum.c 文件的以下函数中找到。
//***************************************************************************** // // This internal function reads a request data packet and dispatches it to // either a standard request handler or the registered device request // callback depending upon the request type. // // \return None. // //***************************************************************************** static void USBDReadAndDispatchRequest(uint32_t ui32Index) { uint32_t ui32Size; tUSBRequest *psRequest; // // Cast the buffer to a request structure. // psRequest = (tUSBRequest *)g_pui8DataBufferIn; // // Set the buffer size. // ui32Size = EP0_MAX_PACKET_SIZE; // // Get the data from the USB controller end point 0. // MAP_USBEndpointDataGet(USB0_BASE, USB_EP_0, g_pui8DataBufferIn, &ui32Size); // // If there was a null setup packet then just return. // if(!ui32Size) { return; } // // See if this is a standard request or not. // if((psRequest->bmRequestType & USB_RTYPE_TYPE_M) != USB_RTYPE_STANDARD) { // // Since this is not a standard request, see if there is // an external handler present. // if(g_ppsDevInfo[0]->psCallbacks->pfnRequestHandler) { // !!RV!! maybe pass entire g_psDCDInst instead of just pvCBData to // get access to EP0 stuff. - doesn't work due to casting but can // add the main g_... pointer to pvCBData, but usbdbulk.c doesn't // know about g_psDCDInst data type so can't use it. //g_psDCDInst[0].pvCBData = (void*)g_psDCDInst; //g_ppsDevInfo[0]->psCallbacks->pfnRequestHandler( // g_psDCDInst[0].pvCBData, // psRequest); //USBDCDSendDataEP0(0, g_pui8MicrosoftCompatibleIDFeatureDesc, 40); //USBDCDStallEP0(0); // // Need to ACK the data on end point 0 without setting last data as there // will be a data phase. // MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, false); // // // Return the externally specified MS OS string descriptor. // g_psDCDInst[0].pui8EP0Data = (uint8_t *)g_pui8MicrosoftCompatibleIDFeatureDesc; // // The total size of a string descriptor is in byte 0. // g_psDCDInst[0].ui32EP0DataRemain = g_pui8MicrosoftCompatibleIDFeatureDesc[0]; // // Save the total size of the data sent. // g_psDCDInst[0].ui32OUTDataSize = g_pui8MicrosoftCompatibleIDFeatureDesc[0]; USBDEP0StateTx(0); } else { // // If there is no handler then stall this request. // USBDCDStallEP0(0); } } else { // // Assure that the jump table is not out of bounds. // if((psRequest->bRequest < (sizeof(g_psUSBDStdRequests) / sizeof(tStdRequest))) && (g_psUSBDStdRequests[psRequest->bRequest] != 0)) { // // Jump table to the appropriate handler. // g_psUSBDStdRequests[psRequest->bRequest](&g_psDCDInst[0], psRequest); } else { // // If there is no handler then stall this request. // USBDCDStallEP0(0); } } }
我还尝试过使用处理程序/回调方法、但由于这不起作用、我正在简化这种情况、将我需要用来直接响应此描述符的代码添加到非标准描述符的调度处理程序功能调用区域。 有人知道为什么这些数据包/PID 序列不符合处理描述符请求的这些(目前粗略的)代码模块的顺序吗?
对于以下代码、处理操作系统描述符(第一个)似乎很奇怪。 您可以看到、我在这里添加了一条 if 语句、来查找0xEE 值并在底部的字符串处理程序情况中响应该描述符。
//***************************************************************************** // // This function handles the GET_DESCRIPTOR standard USB request. // // \param pvInstance is the USB device controller instance data. // \param psUSBRequest holds the data for this request. // // This function will return most of the descriptors requested by the host // controller. The descriptor specified by \e // pvInstance->psInfo->pui8DeviceDescriptor will be returned when the device // descriptor is requested. If a request for a specific configuration // descriptor is made, then the appropriate descriptor from the \e // g_pConfigDescriptors will be returned. When a request for a string // descriptor is made, the appropriate string from the // \e pvInstance->psInfo->pStringDescriptors will be returned. If the // \e pvInstance->psInfo->psCallbacks->GetDescriptor is specified it will be // called to handle the request. In this case it must call the // USBDCDSendDataEP0() function to send the data to the host controller. If // the callback is not specified, and the descriptor request is not for a // device, configuration, or string descriptor then this function will stall // the request to indicate that the request was not supported by the device. // // \return None. // //***************************************************************************** static void USBDGetDescriptor(void *pvInstance, tUSBRequest *psUSBRequest) { bool bConfig; tDCDInstance *psUSBControl; tDeviceInfo *psDevice; const tConfigHeader *psConfig; const tDeviceDescriptor *psDeviceDesc; uint8_t ui8Index; int32_t i32Index; ASSERT(psUSBRequest != 0); ASSERT(pvInstance != 0); // // Create the device information pointer. // psUSBControl = (tDCDInstance *)pvInstance; psDevice = g_ppsDevInfo[0]; // // Need to ACK the data on end point 0 without setting last data as there // will be a data phase. // MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, false); // // Assume we are not sending the configuration descriptor until we // determine otherwise. // bConfig = false; // // Which descriptor are we being asked for? // switch(psUSBRequest->wValue >> 8) { // // This request was for a device descriptor. // case USB_DTYPE_DEVICE: { // // Return the externally provided device descriptor. // psUSBControl->pui8EP0Data = (uint8_t *)psDevice->pui8DeviceDescriptor; // // The size of the device descriptor is in the first byte. // psUSBControl->ui32EP0DataRemain = psDevice->pui8DeviceDescriptor[0]; break; } // // This request was for a configuration descriptor. // case USB_DTYPE_CONFIGURATION: { // // Which configuration are we being asked for? // ui8Index = (uint8_t)(psUSBRequest->wValue & 0xFF); // // Is this valid? // psDeviceDesc = (const tDeviceDescriptor *)psDevice->pui8DeviceDescriptor; if(ui8Index >= psDeviceDesc->bNumConfigurations) { // // This is an invalid configuration index. Stall EP0 to // indicate a request error. // USBDCDStallEP0(0); psUSBControl->pui8EP0Data = 0; psUSBControl->ui32EP0DataRemain = 0; } else { // // Return the externally specified configuration descriptor. // psConfig = psDevice->ppsConfigDescriptors[ui8Index]; // // Start by sending data from the beginning of the first // descriptor. // psUSBControl->ui8ConfigSection = 0; psUSBControl->ui16SectionOffset = 0; psUSBControl->pui8EP0Data = (uint8_t *)psConfig->psSections[0]->pui8Data; // // Determine the total size of the configuration descriptor // by counting the sizes of the sections comprising it. // psUSBControl->ui32EP0DataRemain = USBDCDConfigDescGetSize(psConfig); // // Remember that we need to send the configuration descriptor // and which descriptor we need to send. // psUSBControl->ui8ConfigIndex = ui8Index; bConfig = true; } break; } // // This request was for a string descriptor. // case USB_DTYPE_STRING: { // // Determine the correct descriptor index based on the requested // language ID and index. // i32Index = USBDStringIndexFromRequest(psUSBRequest->wIndex, psUSBRequest->wValue & 0xFF); // // If the mapping function returned -1 then stall the request to // indicate that the request was not valid. // if(i32Index == -1) { USBDCDStallEP0(0); break; } // // !!RV!! // Check for microsoft OS string descriptor and if found // handle. Break immediatley after handling. // if(i32Index == 0xEE) { // // // Return the externally specified MS OS string descriptor. // psUSBControl->pui8EP0Data = (uint8_t *)g_pui8MicrosoftOSString; // // The total size of a string descriptor is in byte 0. // psUSBControl->ui32EP0DataRemain = g_pui8MicrosoftOSString[0]; //USBDCDStallEP0(0); break; } // // // Return the externally specified configuration descriptor. // psUSBControl->pui8EP0Data = (uint8_t *)psDevice->ppui8StringDescriptors[i32Index]; // // The total size of a string descriptor is in byte 0. // psUSBControl->ui32EP0DataRemain = psDevice->ppui8StringDescriptors[i32Index][0]; break; } // // Any other request is not handled by the default enumeration handler // so see if it needs to be passed on to another handler. // default: { // // If there is a handler for requests that are not handled then // call it. // if(psDevice->psCallbacks->pfnGetDescriptor) { psDevice->psCallbacks->pfnGetDescriptor(g_psDCDInst[0].pvCBData, psUSBRequest); } else { // // Whatever this was this handler does not understand it so // just stall the request. // USBDCDStallEP0(0); } return; } } // // If this request has data to send, then send it. // if(psUSBControl->pui8EP0Data) { // // If there is more data to send than is requested then just // send the requested amount of data. // if(psUSBControl->ui32EP0DataRemain > psUSBRequest->wLength) { psUSBControl->ui32EP0DataRemain = psUSBRequest->wLength; } // // Now in the transmit data state. Be careful to call the correct // function since we need to handle the configuration descriptor // differently from the others. // if(!bConfig) { USBDEP0StateTx(0); } else { USBDEP0StateTxConfig(0); } } }
所以我在此停留、试图调试这一非标准描述符处理不起作用的问题。 即使是 TI 的文档也说第一个函数应该能够处理这种"我认为"。
非常感谢任何帮助!