Author Topic: Control transfer through Windows HID driver?  (Read 8899 times)

Renate

  • Frequent Contributor
  • ****
  • Posts: 97
Control transfer through Windows HID driver?
« on: March 17, 2020, 10:14:25 am »
There are two generic built-in drivers in Windows, WinUSB and HID.
In WinUSB we have WinUsb_ControlTransfer to send control transfers.
For HID there does not seem to be any way to send a control transfer (from user space).
Ive looked at all the HidD_, HidP_ and even IOCTLs.
Considering that HidD_SetReport uses endpoint zero anyway (in the absence of an out endpoint), this seems like an omission.
Is there anything?
I've even tried WinUsb_Initialize on a HID handle.

The application is using a vendor control message to put a device into bootloader mode without using an out endpoint or even a report.

P.S. I did notice the undocumented DWORD WINAPI HidD_Hello(char *buf, DWORD size)

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: Control transfer through Windows HID driver?
« Reply #1 on: March 17, 2020, 06:19:50 pm »
With device firmware support, hosts can do control transfers with:

HidD_GetInputReport
HidD_SetOutputReport
HidD_GetFeature
HidD_SetFeature

Renate

  • Frequent Contributor
  • ****
  • Posts: 97
Re: Control transfer through Windows HID driver?
« Reply #2 on: March 17, 2020, 07:48:26 pm »
Yes, those are control transfers, but they are not my control transfers.
How do I send {0x40, 0xb0, 0x0000, 0x0000, 0x0000}?

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: Control transfer through Windows HID driver?
« Reply #3 on: March 18, 2020, 12:38:02 pm »
All data to and from HIDs is contained in defined reports.

To send a vendor-defined message to a device, define an Output or Feature report of the desired length and use  HidD_SetOutputReport or HidD_SetFeature to send it. The device must have firmware support to receive the report and take the desired action.

Renate

  • Frequent Contributor
  • ****
  • Posts: 97
Re: Control transfer through Windows HID driver?
« Reply #4 on: March 20, 2020, 08:07:08 pm »
I guess that the long and short of it is that hidusb.sys does not allow custom control transfers.
Of course, you could make this a composite device with an interface bound to WinUSB, then you could WinUsb_ControlTransfer to the same darn control endpoint.

There are other limitations that don't make particular sense too.
Why can't hidusb.sys pass through IOCTL_HID_GET_REPORT_DESCRIPTOR?
You can trivially get the report descriptor in Linux with HIDIOCGRDESCSIZE/HIDIOCGRDESC.

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: Control transfer through Windows HID driver?
« Reply #5 on: March 21, 2020, 09:06:23 pm »
IOCTL_HID_GET_REPORT_DESCRIPTOR - don't know why it wasn't implemented but other APIs, HidP_GetCaps etc., can return report descriptor information.

A HID control transfer can be vendor defined as long as it has a report descriptor that at minimum defines the report length.

Renate

  • Frequent Contributor
  • ****
  • Posts: 97
Re: Control transfer through Windows HID driver?
« Reply #6 on: March 26, 2020, 08:43:08 am »
Well, all the HidP_ stuff works with "preparsed" report descriptors.

Dealing with all this stuff on Windows leads to insanity.
You can go from the top down instead (just an overview, not actual code):
Code: [Select]
SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_HOST_CONTROLLER
DeviceIoControl(IOCTL_USB_GET_ROOT_HUB_NAME
CreateFile
DeviceIoControl(IOCTL_USB_GET_NODE_CONNECTION_INFORMATION
DeviceIoControl(IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION
But even here MS did something annoying that wasn't necessary.
IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION hard-wires the type & request of the setup packet to 0x80 (device in), 0x06.
If they had been looser and allowed 0x81 (interface in), 0x06, 0x2200 we could have gotten report descriptors.
As a matter of fact, on some sloppy devices, I ask for 0x81, 0x06, 0x2200, MS relays that as 0x80 and the device (incorrectly) responds with the report descriptor.
Sheesh.

Not only that, you can't easily correlate a NODE_CONNECTION with a DEVINST.

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: Control transfer through Windows HID driver?
« Reply #7 on: March 26, 2020, 10:29:27 am »
Interesting! I agree with the complaints!

Renate

  • Frequent Contributor
  • ****
  • Posts: 97
Re: Control transfer through Windows HID driver?
« Reply #8 on: April 04, 2020, 11:41:14 am »
Not to beat a dead horse (ok, I am)...

usbview.exe source code seems to always be the point of reference when someone has a USB question for Windows.
I found an ancient copy from 1997-1998 which purportedly gets HID report descriptors.
https://www-user.tu-chemnitz.de/~heha/viewzip.cgi/hs/usbview.zip/src/enum.c
See: LocateHidDesc()

Looking at the code, I see that it tries to unpack that from the configuration descriptor.
Who, when, why did anyone ever put HID report descriptors inside the configuration descriptor?

That whole code is a work in progress. They also discovered that you can't 0x81, 0x06:
Code: [Select]
if (DeviceIoControl(h,IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, // <-- TODO: Search the right IOCTL for this!
Twenty-odd years and still waiting for this to get fixed...

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: Control transfer through Windows HID driver?
« Reply #9 on: April 04, 2020, 09:15:33 pm »
Interesting, thanks for posting!

ulao

  • Frequent Contributor
  • ****
  • Posts: 172
Re: Control transfer through Windows HID driver?
« Reply #10 on: April 29, 2020, 09:01:23 pm »
I had this same issue and got around it by making a polymorphic like descriptor.

                //get data
      0x85, 0x16,                    //   REPORT_ID (22)
      0x96, 0x00, 0x01,              //   REPORT_COUNT (256) one less then rid
      0x09, 0x00,                    //   USAGE (Undefined)
      0xb2, 0x02, 0x01,              //   FEATURE (Data,Var,Abs,Buf)
            
      //send data for anythign 8 or less. Also has support more data via header
      0x85, 0x12,                    //   REPORT_ID (18)
      0x95, 0x08,                    //   REPORT_COUNT (8) 7 + report ID
      0x09, 0x00,                    //   USAGE (Undefined)
      0xb2, 0x02, 0x01,              //   FEATURE (Data,Var,Abs,Buf)

I then can send a byte and received data. When I send data from the PC the first byte tells me what type of data I need.  When returning I can use a length byte.  You could adjust as you need.