+ -

HID 启动跟踪与获取报表描术符失败的问题

问题

今天改了一下代码,就把从线程中取数改成了直接调用,设备就枚举不成功了~~
让人怀疑人生了啊,看来看去没干啥啊,咋就不成功了

本着不放弃的精神,然后抓包分析
发现SetIdle命令返回异常,就查看REACTOS,源代码~~

 Status = Hid_GetDescriptor(DeviceObject,
                                URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE,
                                sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
                                (PVOID *)&HidDeviceExtension->ConfigurationDescriptor,
                                &DescriptorLength,
                                USB_CONFIGURATION_DESCRIPTOR_TYPE,
                                0,
                                0);
     if (!NT_SUCCESS(Status))
     {
         //
         // failed to obtain device descriptor
         //
         DPRINT1("[HIDUSB] failed to get device descriptor %x\n", Status);
         return Status;
     }

     //
     // now parse the descriptors
     //
     InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(HidDeviceExtension->ConfigurationDescriptor,
                                                               HidDeviceExtension->ConfigurationDescriptor,
                                                              -1,
                                                              -1,
                                                               USB_DEVICE_CLASS_HUMAN_INTERFACE,
                                                              -1,
                                                              -1);
  if (HidDescriptor->bLength == sizeof(HID_DESCRIPTOR) && HidDescriptor->bDescriptorType == HID_HID_DESCRIPTOR_TYPE)
     {
         //
         // found
         //
         HidDeviceExtension->HidDescriptor = HidDescriptor;

         //
         // select configuration
         //
         Status = Hid_SelectConfiguration(DeviceObject);

         //
         // done
         //
         DPRINT("[HIDUSB] SelectConfiguration %x\n", Status);

         if (NT_SUCCESS(Status))
         {
             //
             // now set the device idle
             //
             Hid_SetIdle(DeviceObject);

             //
             // get protocol
             //
             Hid_GetProtocol(DeviceObject);
             return Status;
         }
     }

从这个源代码来看,当从配置描述符中解析出HID描述符后,做两件事
1.选择配置描述符。这个没啥说的,USB都要做这程流。
2.当配置选择完成后,需要置IDLE,然后再获取HID Protocol

当时看代码的时候,是忽视一个问题就是,这两个函数的并没有返回值,所以对整个USB的初始化流程有任何影响。
所以自己当时也是2,就跟踪SetIdle,并强行IDLE返回SUCCESS.

        else if (Urb->UrbHeader.Function == URB_FUNCTION_CLASS_INTERFACE)//idle and protocol
        {
            KdPrint(("URB_FUNCTION_CLASS_INTERFACE[%x] %x=%08x\n", URB_FUNCTION_CLASS_INTERFACE,Urb->UrbHeader.Function, STATUS_SUCCESS));
            Irp->IoStatus.Status = STATUS_SUCCESS;
            IoCompleteRequest(Irp, IO_NO_INCREMENT);
            return   STATUS_SUCCESS;
        }

idle定义如下:

 #define USB_SET_IDLE_REQUEST 0xA
 #define USB_GET_PROTOCOL_REQUEST 0x3
(urb)->UrbControlVendorClassRequest.Request = (request);

绕了地整一大圈,发现问题依旧,设备还中启动失败.设备管理器中为code 10,搜索了一下,无果。

转机

太纠结了不是啥好事,最好的排除法就是有个正确的,进行数据对比。
所以拿出大神BUSBOUDD,就和系统驱动抓包对比.

和系统驱动抓包对比,发现SET_IDLE,也返回失败.

Device  Phase  Data                            Description     Cmd.Phase.Ofs(rep)
------  -----  ------------------------------------------------------------------
  20.0  CTL    21 0a 00 00  00 00 00 00              SET IDLE            7.1.0        
  20.0  USTS   c0000004                             stall pid            7.2.0

但是和自己的驱动对比,无错。这说明自己强行返回成功了,但如果又改成

        IoSkipCurrentIrpStackLocation(Irp);
        Status = IoCallDriver(PDODeviceExtension->parent_fdo, Irp);

就要系统驱动的结果一样了
不过,并没有GetProtocol的请求,估计就是windows和Reactos的差别了吧,不纠结了。

问题所在

发现了一个最重大的问题就是获取描述符0X22,失败。
这玩意最终是由类驱动 HidClassFDO_StartDevice -> HidClassFDO_GetDescriptors 实现的。
而且这个IOCTL是发送给接口的。
所以驱动中需要加上

 else if (Urb->UrbHeader.Function == URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE
     || Urb->UrbHeader.Function == URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE)
     {
          if (Urb->UrbControlDescriptorRequest.DescriptorType == 0x22)
          {

          }     
     }

修改代码,发现成功启动设备。而之前失败,是由于 HID CLASS创建的FDO在IRP_MN_START_DEVICE中失败的。


未解决的奇怪问题

在调用SET_IDLE_REQUEST时,下层驱动返回C0000010 STATUS_INVALID_DEVICE_REQUEST,而BUSBOUND返回显示的是另一个值C0000004,至于这个值是不是STATUS_INFO_LENGTH_MISMATCH,现在就不清楚了。

3: kd> dt _URB_CONTROL_VENDOR_OR_CLASS_REQUEST 0xffffb40c`e46d88b0 
bulkusb!_URB_CONTROL_VENDOR_OR_CLASS_REQUEST
   +0x000 Hdr              : _URB_HEADER
   +0x018 Reserved         : (null) 
   +0x020 TransferFlags    : 0
   +0x024 TransferBufferLength : 0
   +0x028 TransferBuffer   : (null) 
   +0x030 TransferBufferMDL : (null) 
   +0x038 UrbLink          : (null) 
   +0x040 hca              : _URB_HCD_AREA
   +0x080 RequestTypeReservedBits : 0x22 '"'
   +0x081 Request          : 0xa ''  //idle
   +0x082 Value            : 0
   +0x084 Index            : 0
   +0x086 Reserved1        : 0
3: kd> dx -id 0,0,ffffb40c9f0cb2c0 -r1 (*((bulkusb!_URB_HEADER *)0xffffb40ce46d88b0))
(*((bulkusb!_URB_HEADER *)0xffffb40ce46d88b0))                 [Type: _URB_HEADER]
    [+0x000] Length           : 0x88 [Type: unsigned short]
    [+0x002] Function         : 0x1b [Type: unsigned short]
    [+0x004] Status           : 0 [Type: long]
    [+0x008] UsbdDeviceHandle : 0x0 [Type: void *]
    [+0x010] UsbdFlags        : 0x0 [Type: unsigned long]
微信公众号
字节流公众号  字节流QQ群:952873936
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

Powered by bytekits.com,汇天下文字,成非凡梦想!!!