Author Topic: Win8 HID: different policies? different stack?  (Read 14417 times)

grantb5

  • Member
  • ***
  • Posts: 34
Win8 HID: different policies? different stack?
« on: April 26, 2013, 12:40:39 pm »
I have an HID device that has worked for years on various OS's with no issues. It is a standard keyboard class device that also has a simple output report allowing me to send data back to the keyboard class device. I send data to the device using Win32 API HidD_SetFeature().  Works great.

As of Win8 the OS has decided that it wants to stop sending this data. Typically it will work once, then subsequent calls fail. If I move the device to a new USB port then again the first one works, but next ones fail. 

Now if (instead) I install the device with Driver Signature Enforcement off, then it always works. So something has changed at Microsoft regarding this type of access. Am I left having to provide a signed inf/cat for my device even though it's using built-in OS drivers?  If this route even possible?


Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: Win8 HID: different policies? different stack?
« Reply #1 on: April 28, 2013, 03:17:42 pm »
I don't know of any change but that doesn't mean there isn't one.

For Feature reports, open the handle without requesting Read or Write access. (You're probably doing that already.)

If needed, you could add a second, generic HID (not a keyboard) to the keyboard's firmware using a new top-level collection:

http://msdn.microsoft.com/en-us/library/windows/hardware/ff543475%28v=vs.85%29.aspx

grantb5

  • Member
  • ***
  • Posts: 34
Re: Win8 HID: different policies? different stack?
« Reply #2 on: April 29, 2013, 11:14:08 am »
Yes, I'm doing this right now:

Code: [Select]
DeviceHandle = CreateFile(detailData->DevicePath,
                                0, //GENERIC_READ|GENERIC_WRITE,   <-- Using feature report instead.
                                FILE_SHARE_READ|FILE_SHARE_WRITE,
                                (LPSECURITY_ATTRIBUTES)NULL,
                                OPEN_EXISTING,
                                0,
                                NULL);

but I have yet to move my toolchain over to a Win8 machine to see what else I can find out. In this case it's a write-only operation, so I could theoretically eliminate the FILE_SHARE_READ in case that helps ... not sure why it would.

I just find it curious that if I install the device with Driver Signature Enforcement off that it works no problem. And also the strange way it fails with ports being unusable one-by-one.  

Anyway, I did find one other bloke complaining about "similar" things (Win8 being different):
http://answers.flyppdevportal.com/categories/metro/tailoringapps.aspx?ID=5b063d36-5b13-465f-bab1-d190165c4d39

Finally, one wonders if this might be the reason someone at Microsoft changed the way this whole thing works:
"Data exfiltration using a USB keyboard " http://ob-security.info/?p=590

GB


« Last Edit: April 29, 2013, 11:16:07 am by grantb5 »

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: Win8 HID: different policies? different stack?
« Reply #3 on: April 29, 2013, 12:13:44 pm »
Interesting finds!

grantb5

  • Member
  • ***
  • Posts: 34
Re: Win8 HID: different policies? different stack?
« Reply #4 on: April 29, 2013, 04:30:39 pm »
Well now I have two ports, side-by-side.... one works, one doesn't. Both open handles (as shown above) no problem and I added an HidP_GetCaps() func to see if there was anything to learn there. Nothing I can see different between runs on each port. In both cases the Input and Output Report Length values are zero. Also in both cases the Feature Report Length is nuts (21938 bytes) even though my report is 5 bytes. Here is the relevant part of the HID report.

Code: [Select]
  0x09, 0x03,       // Usage (vendor defined)   
    0x75, 0x08,       // Report size (8 bits)     
    0x95, 0x05,       // Report count (5 fields) 
    0xB1, 0x02,       // NEW Feature Report (Data, Variable, Absolute)

I send a byte (for instance) doing this:

Code: [Select]
#define  REPORT_LENGTH_B  6

UCHAR OutputReport[REPORT_LENGTH_B];
bool  bResult;

OutputReport[0] = 0;                // Report #
OutputReport[1] = 1;                // Length
OutputReport[2] = byte;             // Embedded command byte 0.
OutputReport[3] = 0;                // Embedded command byte 1.
OutputReport[4] = 0;                // Embedded command byte 2.
OutputReport[5] = 0;                // Embedded command byte 3.

bResult = HidD_SetFeature(DeviceHandle, OutputReport, REPORT_LENGTH_B);

Not sure what to look at next. Anyway, in summary, the above works when the device is plugged into one port, but not the other.  Obviously it find the device regardless of where it's plugged in and opens a good handle.  It's just the SetFeature chokes on one port and not the other.  And as I mentioned before, this code has worked without issue since at least XP, maybe even 2000.

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: Win8 HID: different policies? different stack?
« Reply #5 on: April 29, 2013, 05:05:44 pm »
If it enumerates as a system keyboard, it should probably have a typical keyboard Input report defined even if your device never sends keypress data.

HidP_GetCaps seems to indicate a problem reading the report descriptor. If you post the report descriptor, someone might see something.

grantb5

  • Member
  • ***
  • Posts: 34
Re: Win8 HID: different policies? different stack?
« Reply #6 on: April 29, 2013, 05:11:36 pm »
There are two actually, one for the "keyboard" and another for the "multimedia" keys.

Code: [Select]
/*
.------------------------------------------------------------------------------
| Keyboard report descriptor (size=63)
`------------------------------------------------------------------------------
*/
const char Hid1ReportDescriptor[] =
{
 0x05, 0x01,       // Usage Page (Generic Desktop)
 0x09, 0x06,       // Usage (Keyboard)
 0xA1, 0x01,       // Collection (Application)

 0x05, 0x07,       //   Usage Page (Key Codes)
 0x19, 0xE0,       //   Usage Minimun (224)
 0x29, 0xE7,       //   Usage Maximum (231)
 0x15, 0x00,       //   Logical Minimum (0)
 0x25, 0x01,       //   Logical Maximum (1)
 0x75, 0x01,       //   Report Size (1 byte)
 0x95, 0x08,       //   Report Count (8 bits)
 0x81, 0x02,       //   Input (Data, Variable, Absolute) - Modifier Bytes

 0x95, 0x01,       //   Report Count (1)
 0x75, 0x08,       //   Report Size (8)
 0x81, 0x01,       //   Input (Constant) - Reserved Byte

 0x95, 0x05,       //   Report Count (5)
 0x75, 0x01,       //   Report Size (1)
 0x05, 0x08,       //   Usage Page (Page# for LEDs)
 0x19, 0x01,       //   Usage Minimum (1)
 0x29, 0x05,       //   Usage Maximum (5)
 0x91, 0x02,       //   Output (Data, Variable, Absolute) - LEDs (5 bits)

 0x95, 0x01,       //   Report Count (1)
 0x75, 0x03,       //   Report Size (3 bits)
 0x91, 0x01,       //   Output (Constant) - LED byte padding (3 bits)

 0x95, 0x06,       //   Report Count (6 bytes)
 0x75, 0x08,       //   Report Size (8 bits)
 0x15, 0x00,       //   Logical Minimum (0)
 0x25, 0x93,       //   Logical Maximum (147)  Added F14-F24, Intl, Lang.
 0x05, 0x07,       //   Usage Page (Key Codes)
 0x19, 0x00,       //   Usage Minimum (0)
 0x29, 0x93,       //   Usage Maximum (147)   Added F14-F24, Intl, Lang.
 0x81, 0x00,       //   Input (Data, Array) - Key data (6 bytes)

    0x09, 0x03,       // Usage (vendor defined)
    0x75, 0x08,       // Report size (8 bits)     
    0x95, 0x05,       // Report count (5 fields)
    0xB1, 0x02,       // NEW Feature Report (Data, Variable, Absolute)
 
 0xC0              // End Collection
};


/*
.------------------------------------------------------------------------------
| Vendor defined HID report descriptor (size=23)   
`------------------------------------------------------------------------------
*/
const char Hid2ReportDescriptor[] = 
{
 0x05, 0x0C,       // usage page (Consumer Page)
 0x09, 0x01,       // usage (Consumer Control)
 0xA1, 0x01,       // collection (application)

 0x85, 0x01,       // REPORT_ID (1)
 0x19, 0x00,       // USAGE_MINIMUM (Unassigned)
 0x2A, 0x2A, 0x02, // USAGE_MAXIMUM (WWW Faves)  Set to our max val.
 0x15, 0x00,       // LOGICAL_MINIMUM (0)
 0x26, 0x2A, 0x02, // LOGICAL_MAXIMUM (554)           Set to our max val.
 0x95, 0x01,       // REPORT_COUNT (1)
 0x75, 0x10,       // REPORT_SIZE (16)
 0x81, 0x00,       // NEW INPUT REPORT (Data,Array,Absolute)

 0xC0              // end collection
};


Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: Win8 HID: different policies? different stack?
« Reply #7 on: April 29, 2013, 10:03:57 pm »
When it fails, does the host try to send the report? If not, what is the error? If yes, how does the device respond?

grantb5

  • Member
  • ***
  • Posts: 34
Re: Win8 HID: different policies? different stack?
« Reply #8 on: April 30, 2013, 12:01:43 pm »
I'm not seeing anything on the USB when it fails. That is, no attempt to Set Feature Report shows up on the bus.  The function returns false (failure) and the error code from get last error is 1.  The unit still operates in the "traditional" manner (input report). In that I can send key data from the device to the PC. That never fails. Only going the other way do I have an issue.

I found that if I uninstall the device using USBDeview (run as administrator), then replug, it will typically work again for a while.  I'm not sure what USBDeview is doing, but it's more comprehensive than device manager as far as purging goes. I attempted to duplicate this functionality in my own software utility, but I don't have a compiler that generates 64-bit code so I could never make my own "purger". Not that it's the ideal situation anyway.

---

PS. USBDeview is from www.nirsoft.net . I'm using v2.18 and I've set up a batch file that removes my device from the command line.

Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: Win8 HID: different policies? different stack?
« Reply #9 on: April 30, 2013, 12:45:27 pm »
Error code 1 is ERROR_INVALID_FUNCTION.

If the Capabilities structure thinks the Feature report is 21938 bytes and you're trying to send 5 bytes, that might be why it's not trying to send the report.

But why does it say 21938 bytes? And why does it work sometimes? A protocol analyzer would show the transactions where the device sends the report descriptor and might show something. I don't see anything wrong with the report descriptor you posted.

grantb5

  • Member
  • ***
  • Posts: 34
Re: Win8 HID: different policies? different stack?
« Reply #10 on: April 30, 2013, 01:01:52 pm »
Welcome to my hell ;-)  ... and thanks for showing an ongoing interest in my situation.

Yeah the capabilities returns the same or similar nonsense whether the thing is working or not.  I'm not sure what to say about that. I've never used that function before, I just tossed it in as part of the testing to see if it illuminated the issues. So I've no experience with that function returning meaningful data.

I'm viewing the USB with a Beagle USB 480 so I see nothing happening in the bad case. No transaction attempt. In the good case of course I see the successful transactions.  The device itself contains an OTP micro and there are thousands of them in the field. So I'd rather it not be a device-side issue. ;-) Actually it would be nice if it was a Microsoft issue and that they would fix it. But I realize that's probably a pipe dream.

I'm going to redesigning the next gen of this device over the summer, so perhaps will go with a different interface in the future ... so much for backward compatibility.

For now I can recommend USBdeview as a bandage fix until I figure something else out. I can't believe I'm the only one sending Feature Reports on Win8, so it would be nice to have input from other device builders and their experience at this point.  BTW, I tried changing the report # (byte 0 of the report) from 0 to 1 to see if that helped. Nope.

grantb5

  • Member
  • ***
  • Posts: 34
Re: Win8 HID: different policies? different stack?
« Reply #11 on: April 30, 2013, 01:17:35 pm »
I forgot to mention that the host reads the two Report Descriptors separately (as expected) and I'm not seeing any issues with that in either case.  I could post a screen cap perhaps if I can find a place to host the image...  I also have the Beagle capture files.

grantb5

  • Member
  • ***
  • Posts: 34
Re: Win8 HID: different policies? different stack?
« Reply #12 on: May 09, 2013, 02:30:41 pm »
If needed, you could add a second, generic HID (not a keyboard) to the keyboard's firmware using a new top-level collection:

http://msdn.microsoft.com/en-us/library/windows/hardware/ff543475%28v=vs.85%29.aspx

I will have to look at this going forward. I'm not exactly sure how to implement a device with an additional top-level collection, so if anyone has any examples please let me know.