Question regarding obtaining HID input reports

Hello,

I am struggling with obtaining HID Input Reports in my driver.

I am following the HID Injector architecture.

I receive my input report on my PDO read request queue.
I forward this request to a manual queue.
I obtain the request from the manual queue.
I then use following to retrieve the read report data:

  • WdfRequestRetrieveOutputMemory
  • WdfMemoryGetBuffer

I would have expected the buffer to contain the report ID that was requested and the remainder 0’s.

However, the report ID is always zero.

I use an application to test this input report which does the following:

  • Allocates a buffer sufficiently large enough to house the report ID + data.
  • Zero out that buffer.
  • Write the report ID to the 1st byte in the buffer.
  • Perform a ReadFile.

Is my approach proper?

My HID report is a very simple one with 1 report that returns 1 byte.

// Report 8 - Read 1 byte
0x05, 0x0B,	//	USAGE_PAGE (Telephony Devices)	
0x09, 0x01,	//	USAGE (Phone)					
0xA1, 0x00,	//	COLLECTION (Physical)			
0x85, 0x08,	//	  REPORT_ID (8)					
0x15, 0x00,	//	  LOGICAL_MINIMUM (0)			
0x25, 0x01,	//	  LOGICAL_MAXIMUM (1)			
0x09, 0x2F,	//	  USAGE (Phone Mute)			
0x75, 0x01,	//	  REPORT_SIZE (1)				
0x95, 0x01,	//	  REPORT_COUNT (1)				
0x81, 0x02,	//	  INPUT (Data,Var,Abs)			
0x09, 0x20,	//	  USAGE (Hook Switch)			
0x09, 0x21,	//	  USAGE (Flash)					
0x75, 0x01,	//	  REPORT_SIZE (1)				
0x95, 0x02,	//	  REPORT_COUNT (2)				
0x81, 0x02,	//	  INPUT (Data,Var,Abs)			
0x95, 0x05,	//	  REPORT_COUNT (5)				
0x81, 0x01,	//	  INPUT (Cnst,Ary,Abs)			
0xC0		//	END_COLLECTION

IIRC there is an optimization in the HID stack that will only write the report ID to the first byte if the device has multiple reports in the descriptor.

That was my experience as well.

Thanks for the reply.

I updated the HID report descriptor to include 5 Input & 8 Output reports.

My results are the same.

I’ve included below the full report descriptor:

// Report 1 - Read 1 byte
0x05, 0x0C,	//	USAGE_PAGE (Consumer Devices)	
0x09, 0x01,	//	USAGE (Consumer Control)		
0xA1, 0x00,	//	COLLECTION (Physical)			
0x85, 0x01,	//	  REPORT_ID (1)					
0x15, 0x00,	//	  LOGICAL_MINIMUM (0)			
0x25, 0x01,	//	  LOGICAL_MAXIMUM (1)			
0x09, 0xEA,	//	  USAGE (Volume Down)			
0x09, 0xE9,	//	  USAGE (Volume Up)				
0x75, 0x01,	//	  REPORT_SIZE (1)				
0x95, 0x02,	//	  REPORT_COUNT (2)				
0x81, 0x06,	//	  INPUT (Data,Var,Rel)			
0x95, 0x06,	//	  REPORT_COUNT (6)				
0x81, 0x01,	//	  INPUT (Cnst,Ary,Abs)			

// Report 2 - Read 2 bytes
0x85, 0x02, //	  REPORT_ID (2)					
0x05, 0x0C,	//	  USAGE_PAGE (Consumer Devices)	
0x09, 0x00,	//	  USAGE (Unassigned)			
0x95, 0x10,	//	  REPORT_COUNT (16)				
0x81, 0x02,	//	  INPUT (Data,Var,Abs)			

// Report 4 - Write 36 bytes
0x85, 0x04,	//	  REPORT_ID (4)
0x09, 0x00,	//	  USAGE (Unassigned)			
0x75, 0x08,	//	  REPORT_SIZE (8)				
0x95, 0x24,	//	  REPORT_COUNT (36)				
0x91, 0x00,	//	  OUTPUT (Data,Ary,Abs)			

// Report 5 - Read 32 bytes
0x85, 0x05,	//	  REPORT_ID (5)
0x09, 0x00,	//	  USAGE (Unassigned)			
0x95, 0x20,	//	  REPORT_COUNT (32)				
0x81, 0x02,	//	  INPUT (Data,Var,Abs)			

// Report 6 - Write 36 bytes
0x85, 0x06,	//	  REPORT_ID (6)
0x09, 0x00,	//	  USAGE (Unassigned)			
0x95, 0x24,	//	  REPORT_COUNT (36)				
0x91, 0x02,	//	  OUTPUT (Data,Var,Abs)			

// Report 7 - Read 32 bytes
0x85, 0x07, //	  REPORT_ID (7)
0x09, 0x00,	//	  USAGE (Unassigned)			
0x95, 0x20,	//	  REPORT_COUNT (32)				
0x81, 0x02,	//	  INPUT (Data,Var,Abs)			
0xC0,		//	END_COLLECTION					

// Report 8 - Read 1 byte
0x05, 0x0B,	//	USAGE_PAGE (Telephony Devices)	
0x09, 0x01,	//	USAGE (Phone)					
0xA1, 0x00,	//	COLLECTION (Physical)			
0x85, 0x08,	//	  REPORT_ID (8)					
0x15, 0x00,	//	  LOGICAL_MINIMUM (0)			
0x25, 0x01,	//	  LOGICAL_MAXIMUM (1)			
0x09, 0x2F,	//	  USAGE (Phone Mute)			
0x75, 0x01,	//	  REPORT_SIZE (1)				
0x95, 0x01,	//	  REPORT_COUNT (1)				
0x81, 0x02,	//	  INPUT (Data,Var,Abs)			
0x09, 0x20,	//	  USAGE (Hook Switch)			
0x09, 0x21,	//	  USAGE (Flash)					
0x75, 0x01,	//	  REPORT_SIZE (1)				
0x95, 0x02,	//	  REPORT_COUNT (2)				
0x81, 0x02,	//	  INPUT (Data,Var,Abs)			
0x95, 0x05,	//	  REPORT_COUNT (5)				
0x81, 0x01,	//	  INPUT (Cnst,Ary,Abs)			

// Report 9 - Write 1 byte
0x05, 0x08,	//	  USAGE_PAGE (LEDs)				
0x85, 0x09,	//	  REPORT_ID (9)					
0x09, 0x09,	//	  USAGE (Mute)					
0x95, 0x01,	//	  REPORT_COUNT (1)				
0x91, 0x02,	//	  OUTPUT (Data,Var,Abs)			
0x95, 0x07,	//	  REPORT_COUNT (7)				
0x91, 0x01,	//	  OUTPUT (Cnst,Ary,Abs)			

// Report 23 - Write 1 byte
0x85, 0x17,	//	  REPORT_ID (23)				
0x09, 0x17,	//	  USAGE (Off-Hook)				
0x95, 0x01,	//	  REPORT_COUNT (1)				
0x91, 0x02,	//	  OUTPUT (Data,Var,Abs)			
0x95, 0x07,	//	  REPORT_COUNT (7)				
0x91, 0x01,	//	  OUTPUT (Cnst,Ary,Abs)			

// Report 24 - Write 1 byte
0x85, 0x18,	//	  REPORT_ID (24)				
0x09, 0x18,	//	  USAGE (Ring)					
0x95, 0x01,	//	  REPORT_COUNT (1)				
0x91, 0x02,	//	  OUTPUT (Data,Var,Abs)			
0x95, 0x07,	//	  REPORT_COUNT (7)				
0x91, 0x01,	//	  OUTPUT (Cnst,Ary,Abs)			

// Report 30 - Write 1 byte
0x85, 0x1E,	//	  REPORT_ID (30)				
0x09, 0x1E,	//	  USAGE (Speaker)				
0x95, 0x01,	//	  REPORT_COUNT (1)				
0x91, 0x02,	//	  OUTPUT (Data,Var,Abs)			
0x95, 0x07,	//	  REPORT_COUNT (7)				
0x91, 0x01,	//	  OUTPUT (Cnst,Ary,Abs)			

// Report 32 - Write 1 byte
0x85, 0x20,	//	  REPORT_ID (32)				
0x09, 0x20,	//	  USAGE (Hold)					
0x95, 0x01,	//	  REPORT_COUNT (1)				
0x91, 0x02,	//	  OUTPUT (Data,Var,Abs)			
0x95, 0x07,	//	  REPORT_COUNT (7)				
0x91, 0x01,	//	  OUTPUT (Cnst,Ary,Abs)			

// Report 42 - Write 1 byte
0x85, 0x2A,	//	  REPORT_ID (42)				
0x09, 0x2A,	//	  USAGE (On-Line)				
0x95, 0x01,	//	  REPORT_COUNT (1)				
0x91, 0x02,	//	  OUTPUT (Data,Var,Abs)			
0x95, 0x07,	//	  REPORT_COUNT (7)				
0x91, 0x01,	//	  OUTPUT (Cnst,Ary,Abs)

0xC0		//	END_COLLECTION

I don’t know if this is your case, but IOCTL_HID_READ_REPORT does not include a report ID. It asks you to return the first report that comes available.