Read file returning ERROR_IO_PENDING, Not getting Read Request in my Driver?

Hey guys,

Sorry for what might be a trivial question for some of you. I’m using a coworkers USB library to write and read from a composite HID that I have written a custom driver for. In my driver I have a continuous reader set up to read incoming touch data from the device which I package into mouse and keyboard reports that are sent to the OS. Up until this point I hadn’t supported user I/O with the device but I am now trying to implement it. I’ve succeeded in adding support for write requests - I receive a IOCTL_HID_WRITE_REPORT code in my EvtInternalDeviceControl function and use WdfUsbTargetPipeWriteSynchronously to copy the user data over to the device (I tried some other methods to write the data to the device but nothing worked until I used that method). Writing works just fine, the problem I’m having occurs when I try and read.

So, in order to perform a read on this chip I need to write a read request packet to the device and then the device will respond with the data requested. When a user calls our write function from user space I receive the read request packet successfully from user space (in the user buffer of the IRP passed to EvtInternalDeviceControl) and copy the packet to the device. Once I do this, I do receive the response from the device in my continuous reader completion routine. The problem is that when I call the read function from our usb library (just a wrapper for readfile) to try and get the actual data back to user space, I never receive any IOCTL_HID_READ_REPORT code in my driver or anything and readfile always returns ERROR_IO_PENDING. Since I never get a read request in my driver I am unsure how to copy the data received from the device back to user space or support read requests at all. The problem has to do with the overlapped read but I can’t do anything if I never receive the request in my driver. I call GetLastError() when the read routine fails and it returns ERROR_IO_INCOMPLETE. Can anyone point me in the right direction here? I’d really appreciate it. Here’s the code for our read function:

BOOL ReadFromDevice(MY_DEVICE *pDevice, DWORD dwCollIndex, LPVOID pMessage, DWORD dwNumBytes, DWORD *pdwBytesRead)
{
BOOL bReadSuccess = FALSE;
BOOL bOverlapped = FALSE;

if(dwCollIndex >= pDevice->bCollectionNum)
{//collection does not exist for this device
return FALSE;
}
if(dwNumBytes < pDevice->Collection[dwCollIndex].dwInReportByteLength)
{//not enough space in buffer
return FALSE;
}
if(!ReadFile(pDevice->Collection[dwCollIndex].hHidDevice,
pMessage,
dwNumBytes,
pdwBytesRead,
&pDevice->Collection[dwCollIndex].OverlappedRead))
{//ReadFile returned FALSE
DWORD dwLastError = ::GetLastError();
if(dwLastError == ERROR_IO_PENDING)
{
WaitForSingleObject(pGhMtDevice->Collection[dwCollIndex].OverlappedRead.hEvent, TIMEOUT_READ);

BOOL bSuccess = GetOverlappedResult(pDevice->Collection[dwCollIndex].hHidDevice,
&pDevice->Collection[dwCollIndex].OverlappedRead,
pdwBytesRead,
FALSE);

if(bSuccess)
{
//GetOverlappedResult does not appear to be returning the correct number
// of bytes received (rather: wMaxPacketSize?).
if(*pdwBytesRead != pDevice->Collection[dwCollIndex].dwInReportByteLength)
{
*pdwBytesRead = pDevice->Collection[dwCollIndex].dwInReportByteLength;
}
bReadSuccess = TRUE;
}
}
}
else
{//read returned immediately
bReadSuccess = TRUE;
}
ResetEvent(pDevice->Collection[dwCollIndex].OverlappedRead.hEvent);
return(bReadSuccess);
}

How did you configure your WDFQUEUE? If sequential, the read could be waiting for the current io to complete. !wdfkd.wdfqueue can tell you if the read is sitting in the pending list.

d
-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@gmail.com
Sent: Thursday, February 26, 2015 12:51 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] Read file returning ERROR_IO_PENDING, Not getting Read Request in my Driver?

Hey guys,

Sorry for what might be a trivial question for some of you. I’m using a coworkers USB library to write and read from a composite HID that I have written a custom driver for. In my driver I have a continuous reader set up to read incoming touch data from the device which I package into mouse and keyboard reports that are sent to the OS. Up until this point I hadn’t supported user I/O with the device but I am now trying to implement it. I’ve succeeded in adding support for write requests - I receive a IOCTL_HID_WRITE_REPORT code in my EvtInternalDeviceControl function and use WdfUsbTargetPipeWriteSynchronously to copy the user data over to the device (I tried some other methods to write the data to the device but nothing worked until I used that method). Writing works just fine, the problem I’m having occurs when I try and read.

So, in order to perform a read on this chip I need to write a read request packet to the device and then the device will respond with the data requested. When a user calls our write function from user space I receive the read request packet successfully from user space (in the user buffer of the IRP passed to EvtInternalDeviceControl) and copy the packet to the device. Once I do this, I do receive the response from the device in my continuous reader completion routine. The problem is that when I call the read function from our usb library (just a wrapper for readfile) to try and get the actual data back to user space, I never receive any IOCTL_HID_READ_REPORT code in my driver or anything and readfile always returns ERROR_IO_PENDING. Since I never get a read request in my driver I am unsure how to copy the data received from the device back to user space or support read requests at all. The problem has to do with the overlapped read but I can’t do anything if I never receive the request in my driver. I call GetLastError() when the read routine fails and it returns ERROR_IO_INCOMPLETE. Can anyone point me in the right direction here? I’d really appreciate it. Here’s the code for our read function:

BOOL ReadFromDevice(MY_DEVICE *pDevice, DWORD dwCollIndex, LPVOID pMessage, DWORD dwNumBytes, DWORD *pdwBytesRead) {
BOOL bReadSuccess = FALSE;
BOOL bOverlapped = FALSE;

if(dwCollIndex >= pDevice->bCollectionNum)
{//collection does not exist for this device
return FALSE;
}
if(dwNumBytes < pDevice->Collection[dwCollIndex].dwInReportByteLength)
{//not enough space in buffer
return FALSE;
}
if(!ReadFile(pDevice->Collection[dwCollIndex].hHidDevice,
pMessage,
dwNumBytes,
pdwBytesRead,
&pDevice->Collection[dwCollIndex].OverlappedRead))
{//ReadFile returned FALSE
DWORD dwLastError = ::GetLastError();
if(dwLastError == ERROR_IO_PENDING)
{
WaitForSingleObject(pGhMtDevice->Collection[dwCollIndex].OverlappedRead.hEvent, TIMEOUT_READ);

BOOL bSuccess = GetOverlappedResult(pDevice->Collection[dwCollIndex].hHidDevice,
&pDevice->Collection[dwCollIndex].OverlappedRead,
pdwBytesRead,
FALSE);

if(bSuccess)
{
//GetOverlappedResult does not appear to be returning the correct number
// of bytes received (rather: wMaxPacketSize?).
if(*pdwBytesRead != pDevice->Collection[dwCollIndex].dwInReportByteLength)
{
*pdwBytesRead = pDevice->Collection[dwCollIndex].dwInReportByteLength;
}
bReadSuccess = TRUE;
}
}
}
else
{//read returned immediately
bReadSuccess = TRUE;
}
ResetEvent(pDevice->Collection[dwCollIndex].OverlappedRead.hEvent);
return(bReadSuccess);
}


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

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

The default queue (the one that would cause a call to EvtIoInternalDeviceControl) is configured to be parallel. I have another queue that I forward read requests to from EvtIoInternalDeviceControl that is an configured to be manual and is used for interrupt messages (eg the incoming touch data/sending mouse and keyboard reports). This interrupt message queue does not contain the user read request however because I never receive the request in EvtIoInternalDeviceControl and therefore never forward it to that queue. The driver is based on the hidusbfx2 sample if that provides any insight and was originally started by another employee who no longer works here. There is also another queue named ReadRequestQueue that is configured to be manual but I don’t think that this queue is being used because it doesn’t set it’s EvtIoRead field in the queue config structure. Maybe this assumption is incorrect and user sent read requests are being queued in this queue somehow even though there is no callback function set? (One other reason I made the assumption that the read queue is not in use is because when I first was adding write request support I tried to set up a write request queue and despite the fact that I actually DID set that queue’s event callback routine, it never got called and that’s why I ended up handling write requests in EvtIoInternalDeviceControl using WdfUsbTargetPipeWriteSynchronously). Sorry if that answer was overkill, just trying to provide as much info as possible.

Hidusbfx2 is a HID miniport driver IIRC. If correct, you will never see the read. Hidclass will queue it at the PDO layer. IIRC this is what the hid ping pong reads are for. There will always be one or two of these pending and you complete them whenever your device has data (state free, not only after a write, etc)

d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@gmail.com
Sent: Thursday, February 26, 2015 1:37 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Read file returning ERROR_IO_PENDING, Not getting Read Request in my Driver?

The default queue (the one that would cause a call to EvtIoInternalDeviceControl) is configured to be parallel. I have another queue that I forward read requests to from EvtIoInternalDeviceControl that is an configured to be manual and is used for interrupt messages (eg the incoming touch data/sending mouse and keyboard reports). This interrupt message queue does not contain the user read request however because I never receive the request in EvtIoInternalDeviceControl and therefore never forward it to that queue. The driver is based on the hidusbfx2 sample if that provides any insight and was originally started by another employee who no longer works here. There is also another queue named ReadRequestQueue that is configured to be manual but I don’t think that this queue is being used because it doesn’t set it’s EvtIoRead field in the queue config structure. Maybe this assumption is incorrect and user sent read requests are being queued in this queue somehow even though there is no callback function set? (One other reason I made the assumption that the read queue is not in use is because when I first was adding write request support I tried to set up a write request queue and despite the fact that I actually DID set that queue’s event callback routine, it never got called and that’s why I ended up handling write requests in EvtIoInternalDeviceControl using WdfUsbTargetPipeWriteSynchronously). Sorry if that answer was overkill, just trying to provide as much info as possible.


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

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

Yes, that is correct, it is a miniport. Okay, well that would explain why I am not getting the read requests. Can I ask how you found that information? If you are just recalling it and are unsure of where documentation on the topic is then don’t worry about it, it’s just that I’ve been digging through a lot of documentation recently on KMDF development and haven’t seen anything about using HID ping pong reads in a miniport driver so I’m curious as to where it might be. It’s certainly possible I missed something. Either way, is there documentation that you’re aware of that describes how to use the ping pong method? Are they pending in one of the queues I have configured? How does the framework handle them? Sorry if that is asking too much, this is just new to me.

Just something I know from working in the stack a long time ago. The best mention I could find of how the reads work in under a minute was in the umdf sample, https://code.msdn.microsoft.com/windowshardware/WudfVhidmini-Sample-b304f83a

d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@gmail.com
Sent: Thursday, February 26, 2015 2:15 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Read file returning ERROR_IO_PENDING, Not getting Read Request in my Driver?

Yes, that is correct, it is a miniport. Okay, well that would explain why I am not getting the read requests. Can I ask how you found that information? If you are just recalling it and are unsure of where documentation on the topic is then don’t worry about it, it’s just that I’ve been digging through a lot of documentation recently on KMDF development and haven’t seen anything about using HID ping pong reads in a miniport driver so I’m curious as to where it might be. It’s certainly possible I missed something. Either way, is there documentation that you’re aware of that describes how to use the ping pong method? Are they pending in one of the queues I have configured? How does the framework handle them? Sorry if that is asking too much, this is just new to me.


NTDEV is sponsored by OSR

Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev

OSR is HIRING!! See http://www.osr.com/careers

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

Okay, well thank you for your responses, you’ve been helpful