FYI: The control device is just used for side band communication with my filter.
I don’t specify any hardware, compat id for the control device itself anywhere, if I understand your question correctly.
Should I set these on the filter itself? If yes, where? In code using or in INF file? If yes, what are the API functions should I use? I know there’s WdfPdoInitAddCompatibleID() to set the compat id, what about setting hardware ID?
The ids would be listed in device manager in the properties dialog for the device
d
debt from my phone
-----Original Message-----
From: xxxxx@hotmail.com
Sent: Thursday, July 07, 2011 6:44 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] INF File Driver Installation
What is the hardware and compact ids for the ?'ed unknown device ?
When I create the control device I:
- WdfControlDeviceInitAllocate( …, SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RW_RES_R);
- WdfDeviceInitAssignName( …, “\Device\VJoy0”);
- WdfDeviceCreate();
- WdfDeviceCreateSymbolicLink( …, “\DosDevices\VJoy0”);
I don’t set anything else on it, I use purely the approach as in kbfilter WDM sample.
In device manager for this device, under ‘General’ tab only ‘Location’ shows info that this device is on my VJoy device everything else displays as ‘Unknown’.
NTDEV is sponsored by OSR
For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars
To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer
Here ya go Doron:
View by connection (as it appears in dev. manager):
Virtual Joystick Device -+
|
|–> Unknown Device (?)
Virtual Joystick Device:
Hardware Ids: HID\VID_1234&PID_ABCD&REV_001
Compatible Ids: (none)
Unknown Device :
Hardware Ids: (none)
Compatible Ids: (none)
The unknown device, what is this supposed to be my TLC or my control device?
xxxxx@hotmail.com wrote:
Here ya go Doron:
View by connection (as it appears in dev. manager):
Virtual Joystick Device -+
|
|–> Unknown Device (?)Virtual Joystick Device:
Hardware Ids: HID\VID_1234&PID_ABCD&REV_001
Compatible Ids: (none)Unknown Device :
Hardware Ids: (none)
Compatible Ids: (none)The unknown device, what is this supposed to be my TLC or my control device?
How are you exposing your control device? Are you creating it like a
bus driver? If you create a PnP child device as a bus driver, then this
is exactly what you would expect. If you just create a control device
PDO, it should not appear in Device Manager.
–
Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.
No, the control device is purely legacy non-Plug and Play device that can be opened by user mode apps via symbolic link. The control device a has a default queue to handle DeviceIoControl from user.
It is created when my filter is created (EvtDeviceAdd) and I store the handle to the control device in my filter’s device context. The control device is destroyed when my filter is destroyed.
It is created verbatim like in the general\toaster\kmdf\filter\sideband\filter.c\FilterCreateControlDevice method.
The only difference in my filter device and the one in the sample is that I have one control device per filter where as the toaster filter creates one global control device for all filters.
> If you just create a control device
PDO, it should not appear in Device Manager.
That’s what I am thinking. I think the ‘Unknown Device’ is my TLC as enumerated by the HID class driver.
Most likely that is the best guess of what is happening. To me, this would mean your hid descriptor might be wonky or some other interfacing between you and hidclass is wrong
d
debt from my phone
-----Original Message-----
From: xxxxx@hotmail.com
Sent: Thursday, July 07, 2011 11:48 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] INF File Driver Installation
If you just create a control device
PDO, it should not appear in Device Manager.
That’s what I am thinking. I think the ‘Unknown Device’ is my TLC as enumerated by the HID class driver.
NTDEV is sponsored by OSR
For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars
To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer
OK, I will spend this weekend troubleshooting. I will verify all the HID related code.
Fun, fun, fun, and I had plans for my sunny weekend
I have looked at my driver code for hours and can’t absolutely find a problem. Everything looks fine.
Sorry guys but I need a bit more help from you guys, at least please answer these questions so I know what to look for (it is difficult to troubleshoot something without knowing details):
I read somewhere that I should implement WdfDeviceInitAssignWdmIrpPreprocessCallback(IRP_MN_QUERY_ID). Is the the cause of my TLC appearing as unknown device?
In my filters’ VJoyEvtInternalDeviceControl I handle HID class driver passed requests.
The requests with Io Control Codes I did NOT handle (I return STATUS_NOT_SUPPORTED and complete the request with that status) are as follows:
IOCTL_HID_SET_FEATURE, IOCTL_HID_GET_FEATURE, IOCTL_HID_WRITE_REPORT,IOCTL_HID_GET_INPUT_REPORT, IOCTL_HID_SET_OUTPUT_REPORT, IOCTL_HID_GET_STRING,IOCTL_HID_ACTIVATE_DEVICE,IOCTL_HID_DEACTIVATE_DEVICE
The driver trace indicates to me that when the driver is loaded, HID class does not pass any of these requests to me so they are not implemented.
I did though implemented these (and I can see Kernel trace from my driver for these):
IOCTL_HID_GET_DEVICE_DESCRIPTOR, IOCTL_HID_GET_DEVICE_ATTRIBUTES, IOCTL_HID_GET_REPORT_DESCRIPTOR, IOCTL_HID_READ_REPORT
One more thing, maybe my INF file, it is missing something or should I look for to make sure it is there …
xxxxx@hotmail.com wrote:
I have looked at my driver code for hours and can’t absolutely find a problem. Everything looks fine.
Sorry guys but I need a bit more help from you guys, at least please answer these questions so I know what to look for (it is difficult to troubleshoot something without knowing details):
Yes, which is why we can only make guesses. You have far more details
than we do.
I read somewhere that I should implement WdfDeviceInitAssignWdmIrpPreprocessCallback(IRP_MN_QUERY_ID). Is the the cause of my TLC appearing as unknown device?
No. The HID class driver reads your HID descriptors and creates a PDO
for each of them. Your driver is not handling the IRP_MN_QUERY_ID call
– the HID class driver does.
What is your top-level collection? What type of device are you advertising?
I did though implemented these (and I can see Kernel trace from my driver for these):
IOCTL_HID_GET_DEVICE_DESCRIPTOR, IOCTL_HID_GET_DEVICE_ATTRIBUTES, IOCTL_HID_GET_REPORT_DESCRIPTOR, IOCTL_HID_READ_REPORT
And are you actually doing the right things when you get these requests?
–
Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.
First, I want to thank you for continous help Tim & Doron. Below are my answers to your questions:
Yes, which is why we can only make guesses. You have far more details
than we do.
I understand, and yes I have all the code but the code looks correct (my only suspicion was the HID Report descriptor itself but I generated it from DT tool; I even replaced mine with one that comes from the samples in the DT tool.
To ensure that your eyes are looking at exactly what my eyes are I will start pasting critical snippets from my driver.
What is your top-level collection? What type of device are you advertising?
I am advertising a joystick via my TLC. My TLC is ‘Application’. Here’s the entire descriptor (generated by DT):
// Setup:
// 32 buttons (1-bit/button state)
// 9 axis (2 bytes/axis)
CONST HID_REPORT_DESCRIPTOR g_defaultReportDescriptor[58] = {
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x04, // USAGE (Joystick)
0xa1, 0x01, // COLLECTION (Application)
0xa1, 0x00, // COLLECTION (Physical)
0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM (Button 1)
0x29, 0x20, // USAGE_MAXIMUM (Button 32)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x95, 0x20, // REPORT_COUNT (32)
0x75, 0x01, // REPORT_SIZE (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x30, // USAGE (X)
0x09, 0x31, // USAGE (Y)
0x09, 0x32, // USAGE (Z)
0x09, 0x33, // USAGE (Rx)
0x09, 0x34, // USAGE (Ry)
0x09, 0x35, // USAGE (Rz)
0x09, 0x36, // USAGE (Slider)
0x09, 0x37, // USAGE (Dial)
0x09, 0x38, // USAGE (Wheel)
0x16, 0x01, 0x80, // LOGICAL_MINIMUM (-32767)
0x26, 0xff, 0x7f, // LOGICAL_MAXIMUM (32767)
0x95, 0x09, // REPORT_COUNT (9)
0x75, 0x10, // REPORT_SIZE (16)
0x81, 0x02, // INPUT (Data,Var,Abs)
0xc0, // END_COLLECTION
0xc0 // END_COLLECTION
};
And are you actually doing the right things when you get these requests?
Yea, I actually looked various samples and it is pretty straight forward. I check all status codes from my calls and all succeed,- I have outputs traces from my Kernel driver to DebugView. That’s why I am puzzled and don’t know what to do next.
Here’s the code for the critical requests:
GetHidDescriptor (IOCTL_HID_GET_DEVICE_DESCRIPTOR)
Uses:
CONST HID_DESCRIPTOR g_defaultHidDescriptor = {
0x09, // length of HID descriptor
0x21, // descriptor type == HID 0x21
0x0100, // hid spec release
0x00, // country code == Not Specified
0x01, // number of HID class descriptors
{
0x22, // descriptor type
sizeof(g_defaultReportDescriptor) // total length of report descriptor
}
};
//Simply copies memory to Requests’ memory.
WDFMEMORY memory;
status = WdfRequestRetrieveOutputMemory(Request, &memory);
status = WdfMemoryCopyFromBuffer(memory, 0, (PVOID) &g_defaultHidDescriptor, bytesToCopy);
WdfRequestSetInformation(…);
GetReportDescriptor (IOCTL_HID_GET_REPORT_DESCRIPTOR)
//Simply copies memory to Requests’ memory.
status = WdfRequestRetrieveOutputMemory(Request, &memory);
bytesToCopy = g_defaultHidDescriptor.DescriptorList[0].wReportLength;
status = WdfMemoryCopyFromBuffer(memory, 0, (PVOID) g_defaultReportDescriptor, bytesToCopy);
WdfRequestSetInformation(…);
GetDeviceAttributes (IOCTL_HID_GET_DEVICE_ATTRIBUTES)
status = WdfRequestRetrieveOutputBuffer(Request, sizeof(HID_DEVICE_ATTRIBUTES), &pDeviceAttributes, NULL);
pDeviceAttributes->Size = sizeof(HID_DEVICE_ATTRIBUTES);
pDeviceAttributes->VendorID = VENDOR_ID;
pDeviceAttributes->ProductID = PRODUCT_ID;
pDeviceAttributes->VersionNumber = VERSION_NO;
WdfRequestSetInformation(…);
Here’s my driver’s trace from DebugView:
VJoy Driver V1.0 – Compiled Jul 8 2011 00:03:38
VJoyEvtDeviceAdd Entry
Creating Control Device, Ctl Dev No 1
Control Device created, with symbolic name ‘\DosDevices\VJoy1’
VJoyEvtDeviceAdd Exit = 0x0
IOCTL_HID_GET_DEVICE_DESCRIPTOR, Queue:0x7E0F81F8, Request:0x7E6D1A20
VJoyGetHidDescriptor Entry
VJoyGetHidDescriptor Exit = 0x0
IOCTL_HID_GET_DEVICE_ATTRIBUTES, Queue:0x7E0F81F8, Request:0x7E6D1A20
VJoyGetDeviceAttributes Entry
VJoyGetDeviceAttributes Exit = 0x0
IOCTL_HID_GET_REPORT_DESCRIPTOR, Queue:0x7E0F81F8, Request:0x7E6D1A20
VJoyGetReportDescriptor Entry
VJoyGetReportDescriptor Exit = 0x0
IOCTL_HID_READ_REPORT, Queue:0x7E0F81F8, Request:0x7E6D1A20
IOCTL_HID_READ_REPORT, Queue:0x7E0F81F8, Request:0x7E0C9A60
FYI:
There’s one guy who also wrote vjoy driver on sourceforge, I took his driver compiled it and installed it with devcon, same problem. But, he has this installer that he also releases to install the driver and guess what, when using the installer the problem goes away and the TLC appears under his vjoy driver as hid game compliant device.
xxxxx@hotmail.com wrote:
> And are you actually doing the right things when you get these requests?
Yea, I actually looked various samples and it is pretty straight forward. I check all status codes from my calls and all succeed,- I have outputs traces from my Kernel driver to DebugView. That’s why I am puzzled and don’t know what to do next.Here’s the code for the critical requests:
GetHidDescriptor (IOCTL_HID_GET_DEVICE_DESCRIPTOR)
Uses:
CONST HID_DESCRIPTOR g_defaultHidDescriptor = {
0x09, // length of HID descriptor
0x21, // descriptor type == HID 0x21
0x0100, // hid spec release
0x00, // country code == Not Specified
0x01, // number of HID class descriptors
{
0x22, // descriptor type
sizeof(g_defaultReportDescriptor) // total length of report descriptor
}
};//Simply copies memory to Requests’ memory.
WDFMEMORY memory;
status = WdfRequestRetrieveOutputMemory(Request, &memory);
status = WdfMemoryCopyFromBuffer(memory, 0, (PVOID) &g_defaultHidDescriptor, bytesToCopy);
WdfRequestSetInformation(…);
But you have eliminated almost all of the code that is interesting. The
“information” setting is a key place to make a mistake. Does it really
look like this?
bytesToCopy = sizeof(g_defaultHidDescriptor);
WdfRequestRetrieveOutputMemory( Request, &memory );
WdfMemoryCopyFromBuffer( memory, 0, (PVOID)&g_defaultHidDescriptor,
bytesToCopy )
WdfRequestSetInformation( Request, bytesToCopy );
And where do you actually complete the request?
–
Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.
>Does it really look like this?
Almost. Satisfying the descriptor requests (HID, report) is just memory copying. My filter responds to internal io control (VJoyEvtInternalDeviceControl) from the HID class and calls each function respectively. If you need more let me know and I’ll be happy to provide.
Here are complete function implementations:
VOID
VJoyEvtInternalDeviceControl(
IN WDFQUEUE Queue,
IN WDFREQUEST Request,
IN size_t OutputBufferLength,
IN size_t InputBufferLength,
IN ULONG IoControlCode)
{
NTSTATUS status = STATUS_SUCCESS;
WDFDEVICE device;
PDEVICE_CONTEXT pDevContext = NULL;
UNREFERENCED_PARAMETER(OutputBufferLength);
UNREFERENCED_PARAMETER(InputBufferLength);
device = WdfIoQueueGetDevice(Queue);
pDevContext = GetDeviceContext(device);
DbgPrint(“%s, Queue:0x%p, Request:0x%p\n”,
DbgHidInternalIoctlString(IoControlCode),
Queue,
Request);
//
// Please note that HIDCLASS provides the buffer in the Irp->UserBuffer
// field irrespective of the ioctl buffer type. However, framework is very
// strict about type checking. You cannot get Irp->UserBuffer by using
// WdfRequestRetrieveOutputMemory if the ioctl is not a METHOD_NEITHER
// internal ioctl. So depending on the ioctl code, we will either
// use retreive function or escape to WDM to get the UserBuffer.
//
switch(IoControlCode) {
case IOCTL_HID_GET_DEVICE_DESCRIPTOR:
//
// Retrieves the device’s HID descriptor.
//
status = VJoyGetHidDescriptor(device, Request);
break;
case IOCTL_HID_GET_DEVICE_ATTRIBUTES:
//
//Retrieves a device’s attributes in a HID_DEVICE_ATTRIBUTES structure.
//
status = VJoyGetDeviceAttributes(Request);
break;
case IOCTL_HID_GET_REPORT_DESCRIPTOR:
//
//Obtains the report descriptor for the HID device.
//
status = VJoyGetReportDescriptor(device, Request);
break;
case IOCTL_HID_READ_REPORT:
//
// Returns a report from the device into a class driver-supplied buffer.
// For now queue the request to the manual queue. The request will
// be retrived and completd by the raw PDO as it receives DeviceIoControl
//
status = WdfRequestForwardToIoQueue(Request, pDevContext->ReadReportMsgQueue);
if(!NT_SUCCESS(status)){
DbgPrint(“WdfRequestForwardToIoQueue failed with status: 0x%x\n”, status);
WdfRequestComplete(Request, status);
}
return;
//
// This feature is only supported on WinXp and later. Compiling in W2K
// build environment will fail without this conditional preprocessor statement.
//
#if (OSVER(NTDDI_VERSION) > NTDDI_WIN2K)
case IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST:
DbgPrint(“IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST\n”);
status = STATUS_NOT_SUPPORTED;
break;
#endif // (OSVER(NTDDI_VERSION) > NTDDI_WIN2K)
case IOCTL_HID_SET_FEATURE:
DbgPrint(“IOCTL_HID_SET_FEATURE\n”);
//status = VJoySetFeature(Request);
WdfRequestComplete(Request, status);
return;
case IOCTL_HID_GET_FEATURE:
DbgPrint(“IOCTL_HID_GET_FEATURE\n”);
case IOCTL_HID_WRITE_REPORT:
DbgPrint(“IOCTL_HID_WRITE_REPORT\n”);
case IOCTL_HID_GET_INPUT_REPORT:
DbgPrint(“IOCTL_HID_GET_INPUT_REPORT\n”);
status = STATUS_NOT_SUPPORTED;
break;
case IOCTL_HID_SET_OUTPUT_REPORT:
DbgPrint(“IOCTL_HID_SET_OUTPUT_REPORT\n”);
status = STATUS_NOT_SUPPORTED;
break;
case IOCTL_HID_GET_STRING:
case IOCTL_HID_ACTIVATE_DEVICE:
case IOCTL_HID_DEACTIVATE_DEVICE:
default:
status = STATUS_NOT_SUPPORTED;
break;
}
WdfRequestComplete(Request, status);
return;
}
NTSTATUS
VJoyGetHidDescriptor(
IN WDFDEVICE Device,
IN WDFREQUEST Request)
{
NTSTATUS status = STATUS_SUCCESS;
size_t bytesToCopy = 0;
WDFMEMORY memory;
UNREFERENCED_PARAMETER(Device);
DbgPrint(“VJoyGetHidDescriptor Entry\n”);
status = WdfRequestRetrieveOutputMemory(Request, &memory);
if (!NT_SUCCESS(status)) {
DbgPrint(“WdfRequestRetrieveOutputMemory failed 0x%x\n”, status);
return status;
}
//
// Use hardcoded “HID Descriptor”
//
bytesToCopy = g_defaultHidDescriptor.bLength;
if (bytesToCopy == 0) {
status = STATUS_INVALID_DEVICE_STATE;
DbgPrint(“g_defaultHidDescriptor is zero, 0x%x\n”, status);
return status;
}
status = WdfMemoryCopyFromBuffer(memory, 0, (PVOID) &g_defaultHidDescriptor, bytesToCopy);
if (!NT_SUCCESS(status)) {
DbgPrint(“WdfMemoryCopyFromBuffer failed 0x%x\n”, status);
return status;
}
//
// Report how many bytes were copied
//
WdfRequestSetInformation(Request, bytesToCopy);
DbgPrint(“VJoyGetHidDescriptor Exit = 0x%x\n”, status);
return status;
}
NTSTATUS
VJoyGetReportDescriptor(
IN WDFDEVICE Device,
IN WDFREQUEST Request)
{
NTSTATUS status = STATUS_SUCCESS;
ULONG_PTR bytesToCopy;
WDFMEMORY memory;
UNREFERENCED_PARAMETER(Device);
DbgPrint(“VJoyGetReportDescriptor Entry\n”);
status = WdfRequestRetrieveOutputMemory(Request, &memory);
if (!NT_SUCCESS(status)) {
DbgPrint(“WdfRequestRetrieveOutputMemory failed 0x%x\n”, status);
return status;
}
//
// Use hardcoded “Report Descriptor” that was generated using “HID Descriptor Tool”
//
bytesToCopy = g_defaultHidDescriptor.DescriptorList[0].wReportLength;
if (bytesToCopy == 0) {
status = STATUS_INVALID_DEVICE_STATE;
DbgPrint(“g_defaultHidDescriptor’s report length is zero, 0x%x\n”, status);
return status;
}
status = WdfMemoryCopyFromBuffer(memory, 0, (PVOID) g_defaultReportDescriptor, bytesToCopy);
if (!NT_SUCCESS(status)) {
DbgPrint(“WdfMemoryCopyFromBuffer failed 0x%x\n”, status);
return status;
}
//
// Report how many bytes were copied
//
WdfRequestSetInformation(Request, bytesToCopy);
DbgPrint(“VJoyGetReportDescriptor Exit = 0x%x\n”, status);
return status;
}
NTSTATUS
VJoyGetDeviceAttributes(IN WDFREQUEST Request)
{
NTSTATUS status = STATUS_SUCCESS;
PHID_DEVICE_ATTRIBUTES pDeviceAttributes = NULL;
DbgPrint(“VJoyGetDeviceAttributes Entry\n”);
status = WdfRequestRetrieveOutputBuffer(Request, sizeof(HID_DEVICE_ATTRIBUTES), &pDeviceAttributes, NULL);
if (!NT_SUCCESS(status))
{
DbgPrint(“WdfRequestRetrieveOutputBuffer failed 0x%x\n”, status);
return status;
}
//
// Set USB device descriptor
//
pDeviceAttributes->Size = sizeof(HID_DEVICE_ATTRIBUTES);
pDeviceAttributes->VendorID = VENDOR_ID;
pDeviceAttributes->ProductID = PRODUCT_ID;
pDeviceAttributes->VersionNumber = VERSION_NO;
//
// Report how many bytes were copied
//
WdfRequestSetInformation(Request, sizeof(HID_DEVICE_ATTRIBUTES));
DbgPrint(“VJoyGetDeviceAttributes Exit = 0x%x\n”, status);
return status;
}
**** Issue Resolved! Question raised.
Tim wrote:
No. The HID class driver reads your HID descriptors and creates a PDO
for each of them. Your driver is not handling the IRP_MN_QUERY_ID call
– the HID class driver does.
That’s fine, but it does incorrectly!
Tim, and/or Doron:
As you know I have been having problems seeing my TLC appear in dev. manager on WinXP under my VJoy device.
I have resolved the problem by implementing IRP_MN_QUERY_ID in my driver and the problem went away, my TLC appeared in dev. manager under my device.
Apparently, the root enumerator would put some null values in response to IRP_MN_QUERY_ID -> to prevent this I overrode the behaviour by responding to IRP_MN_QUERY_ID.
My question is, on WinXP, why is this happening, why is the root enumerator handling the request incorrectly for my device? Is that a bug in Windows XP (I haven’t tested yet on Vista/Win7)?
FYI:
In my response to IRP_MN_QUERY_ID I handled the BusQueryHardwareIDs query and supplied hardware IDs myself.
Actually, it’s a known issue I forgot to bring up. Sorry
d
debt from my phone
-----Original Message-----
From: xxxxx@hotmail.com
Sent: Saturday, July 16, 2011 8:57 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] INF File Driver Installation
FYI:
In my response to IRP_MN_QUERY_ID I handled the BusQueryHardwareIDs query and supplied hardware IDs myself.
NTDEV is sponsored by OSR
For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars
To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer
No problem. Thx for your response.