Question Regarding Multiple Device Interfaces

I have a driver that allows multiple Device Interfaces so that My driver can distinguish which USB endpoint to read on.

I have created 2 additional Device Interfaces so that our application can access either of the endpoints to do a read.

I call WdfDeviceCreateDeviceInterface For to create the SymbolicLinks.

I have basically modified the BulkUsb sample to meet my needs.

I have added a parallel queue that handles the read request and then when I receive the ReadRequest, I forward the Request to Each Sequential Queue that I have created for Reading Each of the Endpoints. All of this seems to work fine. Also, the Parallel queue is using the Framework Dispatching and the other queues are getting handled by routing the request WdfRequestForwardToIoQueue when the request from the parallel queue comes in and a decision has been made on which Sequential queue it needs to go to. I make this decision using WdfFileObjectGetFileName().

However when I use the same Handle in the Application that I have used for the CreateFile on one of the aforementioned interfaces, to do a Write It appears that the write request is getting handled by the Read Parallel Queue. It just starts pouring out data like their are tons of Read Requests being Issued.

However, If I create a seperate handle for the Write, I don’t see any issues. Also, I kept the same Sequential Queue to handle the write request and I am letting the framework handle write Dispatching.

My question is what is it I am missing here. It seems like the Write Request should always be routed to the proper queue.

I probably am misunderstanding something simple since I am new to the framework and it has been years since i have done Kernel Drivers.

If you are creating multiple device interfaces are you specifying a ReferenceString along with the GUID? If not, there is no way for you to determine which interface is being opened. Instead of comparing against the file name (which by the way is only valid during the create path) whenever you get a request to process, determine which interface is being opened during EvtDeviceFileCreate, record that in your WDFFILEOBJECT and then use that remembered state whenever you process a request. Furthermore, you can store WDFFILEOBJECT specific WDFQUEUEs under the context on the WDFFILEOBJECT and just use the WDFQUEUE value in the context when dispatching requests to subqueues instead of determining which queue to send to for each request.

d

Yes, I am storing the Reference String along with the GUID.

I didn’t realize that EvtDeviceFileCreate got called on each Read/Write request. I thought it was only called on CreateFile(). So, you are saying each Read request will call EvtDeviceFileCreate and I can determine which Interface was called at that time. I can then store a pointer to the Queue in the WDFFILEOBJECT and Just have the ReadDispatch Request Forward the Request automatically to that Queue.

Is my understanding of what you said correct?

Can you be more specific on how store additional data on the WDFFILEOBJECT?

Oh and Thanks for your help.

I see. I add it to the Object Attributes instead of Using WDF_NO_OBJECT_ATTRIBUTES.

Yes, when calling WdfDeviceInitSetFileObjectConfig. In reponse to your earlier email, EvtDeviceFileCreate is only called in the CreateFile path when the handle is being opened. What I am trying to say is that instead of figuring out what to do during the processing of a read / write / ioctl request is that you figure out what to do a priori in EvtDeviceFileCreate, store your decision in the context for the WDFFILEOBJECT and then just use the WDFFILEOBJECT context to blindly tell you what to do during request processing.

d

I got that part working, but I am still seeing the same problem. I think there must be something wrong with the queues. It runs for a little while and then It goes Crazy Processing requests on the parallel queue. The application is stopped and I still see my EvtDeviceReadFile being called 100’s of times.

Is it OK to have 4 queues as Follow:

1 Parallel Queue that processes the main Read Request and uses the Framework Dispatching. Messages from this queue get forwarded to 2 sequential Queues. Each of these processes a seperate IN endpoint.

1 Sequential Queue for processing the Write Requests that also Uses the Framework Dispatching.

Or, Do I need to do the Write Request the same way as the read request and Create a Main Parallel Queue that Forwards the Request To a sequential queue? This doesn’t seem necessary since I only have one interface doing Writes.

I haven’t quite narrowed down the root cause of this issue, but I suspect that this is related to the write Request Coming in Using the same handle in the Application.

The reason I think this is because I have written a test application that creates 3 handles from CreateFile(). 2 reads and 1 write and everything works fine. I have ran overnight without incident.

However, in our main application that this is being written for, I only have 2 handles. The main one does the Reads and Writes and the other does the reading using the additional interface.

It is like it goes crazy receiving Read Requests on the third endpoint. My suspicion is that I am not doing something correct on the queues.

this seems like an OK setup. perhaps the init code might help. also when things go “crazy”, break in on your read dispatch routine and see what the callstack is (and post it), it might give us a clue. Also, another thing to try is !wdfkd.wdfdevicequeues and then !wdfqueue on the read queue to see how many requests are pending

d

Thanks for the help. It is not an issue. I was fooled by how fast the requests were being sent down and bound and determined to find something wrong. I was using traceview to monitor and it was way behind in logging events since so many events were being logged.

test

Doran,

I was wrong. The issue did not go away. This is rather lengthy and I have tried to provide the things you asked for when I get into this state.

I took out the thread that reads on the other Endpoint and I am seeing EvtDeviceFileCreate get called multiple times with the other Symbolic Link (ie my other interface).

I am doing WdfRequestGetFileObject() and WdfFileObjectGetFileName() and thene doing a RtlCompareUnicodeString and it is matching the String that tells me to read from the other interface. Something really strange is happening because I have the code commented out that does create file to \…\My2ndInterface. I do see some potential issue in the application code that is calling CancelIO and then Closing the Handle. But, this is being done on the other interface.

My app runs for a few minutes and then I start seeing tons of requests come in on the other interface.

Another note. We have an FPGA that is Constantly Sending data to the USB Device via the Slave Fifo Interface. This happens to be on the endpoint that I am seeing all the requests on. This should not matter since I am not even opening a handle on this interface right now.

Is it possible that I am not handling the Cleanup Correctly or something. At any rate, I don’t see how it can be sending requests down to the driver that matches the exact symoblic link string for my interface.

Here is the Call Stack when I see EvtDeviceFileCreate get called on the interface that I am not doing a create file on:

1: kd> k
ChildEBP RetAddr
a0a2b9ac ba45d1bb LxNextGenUsbDriver!GetCreateFileInterface+0x8a [c:\dev\lxr\version_3.0\source\hardware\drivers\nextgenusbdriver\device.c @ 729]
a0a2b9dc a06a5071 LxNextGenUsbDriver!LxEvtDeviceFileCreate+0x3b [c:\dev\lxr\version_3.0\source\hardware\drivers\nextgenusbdriver\device.c @ 632]
WARNING: Stack unwind information not available. Following frames may be wrong.
a0a2b9f8 a06a5dbd Wdf01000+0x3b071
a0a2ba34 a06a5e95 Wdf01000+0x3bdbd
a0a2ba50 a069c272 Wdf01000+0x3be95
a0a2ba5c 804eef95 Wdf01000+0x32272
a0a2ba6c 80581ed6 nt!IopfCallDriver+0x31
a0a2bb4c 805bdd14 nt!IopParseDevice+0xa58
a0a2bbc4 805ba39c nt!ObpLookupObjectName+0x53c
a0a2bc18 80574e53 nt!ObOpenObjectByName+0xea
a0a2bc94 805757ca nt!IopCreateFile+0x407
a0a2bcf0 80577e94 nt!IoCreateFile+0x8e
a0a2bd30 8054078c nt!NtCreateFile+0x30
a0a2bd30 7c90eb94 nt!KiFastCallEntry+0xfc
045bf024 7c90d68e ntdll!KiFastSystemCallRet
045bf028 7c810916 ntdll!NtCreateFile+0xc
045bf0c0 041d496c 0x7c810916
045bf26c 041f9fe0 0x41d496c
045bf3e0 041d8bfa 0x41f9fe0
045bf90c 041fc6ce 0x41d8bfa

Here is the stack upon entering EvtIoRead and after

1: kd> k
ChildEBP RetAddr
b9c86bd0 a09e5071 LxNextGenUsbDriver!LxEvtIoRead+0xb5 [c:\dev\lxr\version_3.0\source\hardware\drivers\nextgenusbdriver\bulkrwr.c @ 75]
WARNING: Stack unwind information not available. Following frames may be wrong.
b9c86bec a09e7b20 Wdf01000+0x3b071
b9c86c14 a09e9929 Wdf01000+0x3db20
b9c86c30 a09eabe0 Wdf01000+0x3f929
b9c86c4c a09ecbb1 Wdf01000+0x40be0
b9c86c70 a09dc272 Wdf01000+0x42bb1
b9c86c7c 804eef95 Wdf01000+0x32272
b9c86c8c 8057e69c nt!IopfCallDriver+0x31
b9c86ca0 8057b77d nt!IopSynchronousServiceTail+0x60
b9c86d38 8054078c nt!NtReadFile+0x55d
b9c86d38 7c90eb94 nt!KiFastCallEntry+0xfc
04cbed4c 0410a7e0 0x7c90eb94
04cbfed4 04109ee3 0x410a7e0
04cbffb4 7c80b683 0x4109ee3
04cbffec 00000000 0x7c80b683

None of these debugger commands are working or I am doing something wrong.

1: kd> !wdfkd.wdfdevicequeues 0x77dd0408
Could not retrieve !FxObjectsInfoCount
c0000005 Exception in wdfkd.wdfdevicequeues debugger extension.
PC: 00fa550f VA: 00000000 R/W: 0 Parameter: 0001003f

1: kd> !wdfqueue 0x78355fb0
Could not retrieve !FxObjectsInfoCount
c0000005 Exception in wdfkd.wdfqueue debugger extension.
PC: 00fa550f VA: 00000000 R/W: 0 Parameter: 0001003f

Here is my LxEvtDeviceAdd Source (I assume this is the init code you were asking about). I can provide other source if you need it.

NTSTATUS
LxEvtDeviceAdd(
IN WDFDRIVER Driver,
IN PWDFDEVICE_INIT DeviceInit
)
/*++
Routine Description:

EvtDeviceAdd is called by the framework in response to AddDevice
call from the PnP manager. We create and initialize a device object to
represent a new instance of the device. All the software resources
should be allocated in this callback.

Arguments:

Driver - Handle to a framework driver object created in DriverEntry

DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure.

Return Value:

NTSTATUS

–*/
{
WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks;
WDF_OBJECT_ATTRIBUTES attributes;
NTSTATUS status;
WDFDEVICE device;
WDF_DEVICE_PNP_CAPABILITIES pnpCaps;
WDF_IO_QUEUE_CONFIG ioQueueConfig;
PDEVICE_CONTEXT pDevContext;
WDFQUEUE queue;
WDF_FILEOBJECT_CONFIG deviceConfig;
DECLARE_CONST_UNICODE_STRING(LX_STATUS_INTERFACE,LX_STATUS_INTERFACE_STRING);
DECLARE_CONST_UNICODE_STRING(LX_BEAD_DATA_INTERFACE,LX_BEAD_DATA_INTERFACE_STRING);

UNREFERENCED_PARAMETER(Driver);

TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP,“–> LxEvtDeviceAdd routine\n”);

//
// Initialize the pnpPowerCallbacks structure. Callback events for PNP
// and Power are specified here. If you don’t supply any callbacks,
// the Framework will take appropriate default actions based on whether
// DeviceInit is initialized to be an FDO, a PDO or a filter device
// object.
//

WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);
//
// For usb devices, PrepareHardware callback is the to place select the
// interface and configure the device.
//
pnpPowerCallbacks.EvtDevicePrepareHardware = LxEvtDevicePrepareHardware;

WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks);

WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoBuffered);

//
// Need to setup the Callback for File Object Create Configuration
// This will allow us to setup the appropriate interface that the Device has been
// configured for.
//
WDF_FILEOBJECT_CONFIG_INIT(&deviceConfig,
LxEvtDeviceFileCreate,
WDF_NO_EVENT_CALLBACK, // No Close callback function
LxEvtFileCleanup); // Cleanup callback function

WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes,
FILE_OBJECT_CONTEXT);

WdfDeviceInitSetFileObjectConfig(DeviceInit,
&deviceConfig,
&attributes);

//
// Now specify the size of device extension where we track per device
// context.DeviceInit is completely initialized. So call the framework
// to create the device and attach it to the lower stack.
//
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_CONTEXT);

status = WdfDeviceCreate(&DeviceInit, &attributes, &device);
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
“WdfDeviceCreate failed with Status code %!STATUS!\n”, status);
return status;
}

//
// Get the DeviceObject context by using accessor function specified in
// the WDF_DECLARE_CONTEXT_TYPE_WITH_NAME macro for DEVICE_CONTEXT.
//
pDevContext = GetDeviceContext(device);

//
// Tell the framework to set the SurpriseRemovalOK in the DeviceCaps so
// that you don’t get the popup in usermode (on Win2K) when you surprise
// remove the device.
//
WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnpCaps);
pnpCaps.SurpriseRemovalOK = WdfTrue;

WdfDeviceSetPnpCapabilities(device, &pnpCaps);

//
// Create a parallel default queue and register an event callback to
// receive ioctl requests. We will create separate queues for
// handling read and write requests. All other requests will be
// completed with error status automatically by the framework.
//
WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig,
WdfIoQueueDispatchParallel);

ioQueueConfig.EvtIoDeviceControl = LxEvtIoDeviceControl;

status = WdfIoQueueCreate(device,
&ioQueueConfig,
WDF_NO_OBJECT_ATTRIBUTES,
&queue);// pointer to default queue
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
“WdfIoQueueCreate failed %!STATUS!\n”, status);
return status;
}

//
// We will create a separate Parallel queue and configure it
// to receive read requests. We also need to register a EvtIoStop
// handler so that we can acknowledge requests that are pending
// at the target driver. This is the Main Queue for Processing read
// requests from the Application Layer. When EvtDeviceFileCreate is
// received (ie, when the Application Opens the file Handle to this device
// typically using CreateFile() API), We will determine which Symbolic
// link Opened the Driver and LxStatusDataInterface or LxBeadDataInterface.
// We will store a pointer to this queue in the WDFFILEOBJECT so that when the
// read request is generated, we can simply forware the request to the Appropriate
// Sequential Queue. This is how we handle doing reads on Multiple Endpoints.
// This queue will also be configured for Framework Dispatching.
//
//

WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig, WdfIoQueueDispatchParallel);

ioQueueConfig.EvtIoRead = LxEvtIoRead;
ioQueueConfig.EvtIoStop = LxEvtIoStop;

status = WdfIoQueueCreate(
device,
&ioQueueConfig,
WDF_NO_OBJECT_ATTRIBUTES,
&queue // queue handle
);

if (!NT_SUCCESS (status))
{
TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
“WdfIoQueueCreate failed 0x%x\n”, status);
return status;
}

status = WdfDeviceConfigureRequestDispatching(
device,
queue,
WdfRequestTypeRead);

if(!NT_SUCCESS (status))
{
ASSERT(NT_SUCCESS(status));
TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
“WdfDeviceConfigureRequestDispatching failed 0x%x\n”, status);
return status;
}

//
//We Will Create the First of the 2 Sequential Queues that will handle
//the read requests on each endpoint. This will handle the BeadDataInterface on
//EP6 IN. This queue is fed by the Parallel queue above and no Framework
//Dispatching will be configured.
//
WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig, WdfIoQueueDispatchSequential);

ioQueueConfig.EvtIoRead = LxEvtIoReadBeadData;
ioQueueConfig.EvtIoStop = LxEvtIoStop;

status = WdfIoQueueCreate(
device,
&ioQueueConfig,
WDF_NO_OBJECT_ATTRIBUTES,
&pDevContext->BeadDataQueue // queue handle
);

if (!NT_SUCCESS (status))
{
TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
“WdfIoQueueCreate Bead Data Queue failed 0x%x\n”, status);
return status;
}

//
//We Will Create the Second of the 2 Sequential Queues that will handle
//the read requests on each endpoint. This queue will handle the LxStatusDataInterface on
//EP2 IN. This queue is fed by the Parallel queue above and no Framework Dispatching will
//be configured.
//
WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig, WdfIoQueueDispatchSequential);

ioQueueConfig.EvtIoRead = LxEvtIoReadStatusData;
ioQueueConfig.EvtIoStop = LxEvtIoStop;

status = WdfIoQueueCreate(
device,
&ioQueueConfig,
WDF_NO_OBJECT_ATTRIBUTES,
&pDevContext->StatusDataQueue // queue handle
);

if (!NT_SUCCESS (status))
{
TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
“WdfIoQueueCreate Status Data Queue failed 0x%x\n”, status);
return status;
}

//
// We will create another sequential queue and configure it
// to receive write requests. This will handle all the Write requests
// on EP4 OUT.
//
WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig, WdfIoQueueDispatchSequential);

ioQueueConfig.EvtIoWrite = LxEvtIoWrite;
ioQueueConfig.EvtIoStop = LxEvtIoStop;

status = WdfIoQueueCreate(
device,
&ioQueueConfig,
WDF_NO_OBJECT_ATTRIBUTES,
&queue // queue handle
);

if (!NT_SUCCESS (status))
{
TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
“WdfIoQueueCreate failed 0x%x\n”, status);
return status;
}

status = WdfDeviceConfigureRequestDispatching(
device,
queue,
WdfRequestTypeWrite);

if(!NT_SUCCESS (status))
{
ASSERT(NT_SUCCESS(status));
TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
“WdfDeviceConfigureRequestDispatching failed 0x%x\n”, status);
return status;
}

//
// Register a device interface so that app can find our device and talk to it.
//
status = WdfDeviceCreateDeviceInterface(device,
(LPGUID) &GUID_CLASS_LX_DETECTOR,
&LX_STATUS_INTERFACE);// Reference String

if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
“WdfDeviceCreateDeviceInterface failed %!STATUS!\n”, status);
return status;
}

//
// Register a device interface so that app can find our device and talk to it.
//
status = WdfDeviceCreateDeviceInterface(device,
(LPGUID) &GUID_CLASS_LX_DETECTOR,
&LX_BEAD_DATA_INTERFACE);// Reference String
if (!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_ERROR, DBG_PNP,
“WdfDeviceCreateDeviceInterface failed %!STATUS!\n”, status);
return status;
}

TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, “<– LxEvtDeviceAdd\n”);

return status;
}

Here is the LxEvtIoRead Code: (Note that it does much more than necessary, because I needed to break into the
code when I started getting requests on the BeadDataInterface.)

VOID
LxEvtIoRead(
IN WDFQUEUE Queue,
IN WDFREQUEST Request,
IN size_t Length
)
/*++

Routine Description:

Called by the framework when it receives Read or Write requests.

Arguments:

Queue - Default queue handle
Request - Handle to the read/write request
Lenght - Length of the data buffer associated with the request.
The default property of the queue is to not dispatch
zero lenght read & write requests to the driver and
complete is with status success. So we will never get
a zero length request.

Return Value:

–*/
{
WDFUSBPIPE pipe;
NTSTATUS status;
WDFMEMORY reqMemory;
PDEVICE_CONTEXT pDeviceContext;
PUNICODE_STRING fileName;
LX_ENUM_FILE_CREATE_INTERFACE eCreateFileInterface;
PFILE_OBJECT_CONTEXT fileContext;
WDFFILEOBJECT fileObject;
WDFDEVICE Device;

Device = WdfIoQueueGetDevice(Queue);
pDeviceContext = GetDeviceContext(Device);
fileObject = WdfRequestGetFileObject(Request);

if (fileObject != NULL)
{
fileContext = GetFileObjectContext(fileObject);

if (fileContext != NULL)
{
if (fileContext->pDataQueue == NULL)
{
TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, “–>LxEvtIoRead fileContext->pDataQueue is NULL\n”);
status = STATUS_INVALID_DEVICE_REQUEST;
}
else if (fileContext->pDataQueue == &pDeviceContext->BeadDataQueue)
{
TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, “LxEvtIoRead Forwarding Request to Bead Data QUEUE”);
//Forward the Request to the Appropriate Queue that Was Setup on the Device
//context during the call to EvtDeviceFileCreate.
status = WdfRequestForwardToIoQueue(Request,*(fileContext->pDataQueue));
if(!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, “–>LxEvtIoRead WdfRequestForwardToIoQueue failed on eStatusInterface: Error =0x%x\n”, status);
WdfRequestCompleteWithInformation(Request, status, 0);
}
else
{
status = STATUS_PENDING;
}
}
else if (fileContext->pDataQueue == &pDeviceContext->StatusDataQueue)
{
TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, “LxEvtIoRead Forwarding Request to Status Data QUEUE”);
//Forward the Request to the Appropriate Queue that Was Setup on the Device
//context during the call to EvtDeviceFileCreate.
status = WdfRequestForwardToIoQueue(Request,*(fileContext->pDataQueue));
if(!NT_SUCCESS(status))
{
TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, “–>LxEvtIoRead WdfRequestForwardToIoQueue failed on eStatusInterface: Error =0x%x\n”, status);
WdfRequestCompleteWithInformation(Request, status, 0);
}
else
{
status = STATUS_PENDING;
}
}
else
{
TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, “–>LxEvtIoRead fileContext->pDataQueue is UNKNOWN\n”);
status = STATUS_INVALID_DEVICE_REQUEST;
}
}
else
{
TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, “–>LxEvtIoRead GetFileObjectContext failed.”);
status = STATUS_INVALID_DEVICE_REQUEST;
}
}
else
{
TraceEvents(TRACE_LEVEL_VERBOSE, DBG_READ, “–>LxEvtIoRead WdfRequestGetFileObject failed.”);
status = STATUS_INVALID_DEVICE_REQUEST;
}

if (status != STATUS_PENDING) {
//
// complete now if not pending
//
WdfRequestCompleteWithInformation(Request, status, 0);
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_READ, “<– LxEvtIoRead Exiting: Error =0x%x\n”, status);
}

TraceEvents(TRACE_LEVEL_INFORMATION, DBG_READ, “<– LxEvtIoRead Exiting\n”);

return;
}

For the debugger wdfkd commands to work, you need to have kmdf symbols loaded. for v1.5, point to the public sym server (and make sure you are using WDK build 6000 bits). For prev versions, you get the symbols from the install overlay

d

I am using version 1.1 and I am pointing to the symbols directory from the install overlay.
I also did this.
0: kd> ld wdf01000
Symbols already loaded for Wdf01000

But, I still can’t seem to get any debugging info from !wdfkd.*.

I also see this: *** ERROR: Module load completed but symbols could not be loaded for Wdf01000.sys

I am pretty sure CancelIO is triggering whatever is happening if that helps.

What is the output of

!lmi wdf01000

?

Thx
d

CancelIo in and of itself won’t re-present requests to your driver, it will just invoke the appropriate cancel routine you may have set on the request. On the other hand, look at the application and what it does when async i/o completes. Does it properly handle the i/o completing with failure and perhaps resending I/O whenever async I/O completes without regard to the status that the I/O completed with? The callstacks you sent in your previous message all indicate i/o activity from a user mode application, I would really focus your efforts in debugging your app.

d

0: kd> !lmi wdf01000
Loaded Module Info: [wdf01000]
Module: Wdf01000
Base Address: a1228000
Image Name: Wdf01000.sys
Machine Type: 332 (I386)
Time Stamp: 444738f2 Thu Apr 20 02:32:02 2006
Size: 77000
CheckSum: 8198b
Characteristics: 102
Debug Data Dirs: Type Size VA Pointer
CODEVIEW 25, 69030, 68230 RSDS - GUID: {5BB58559-87E2-413B-ADCC-FABEE43D76B4}
Age: 1, Pdb: Wdf01000.pdb
Symbol Type: DEFERRED - No error - symbol load deferred
Load Report: no symbols loaded

I will look more into the App as that is what I am doing now. The Funny part is that I don’t see anywhere that requests could be called on on that interface. I have removed all of the places that do A CreateFile on that second interface. Yet, that second interface is what seems to be getting all of the ReadRequests. That is why I had come to the conclusion that it must be something in the Queues of the Driver.

Thanks for your Help and if you have any other ideas, please let me know.

As Soon as I call CancelIO(), I see a flurry of requests coming down to the driver?

Could this be caused from not properly Handling Close and Cleanup? What is required of Close and Cleanup? I am doing Cleanup by flushing the Sequential Queues. But I do not have a Close Handler at All.

Here is what I was doing in Cleanup. But I think it may be ineffective since the requests seem to be coming in on the Parallel Queue that handles EvtIoRead.

This really makes no sense at all Because I am not even Opening or Sending Requests on the other Endpoint. I agree it looks like it is coming down from the application, but Nowhere in the Application am I opening \…\My2ndInterface. I set breakpoints in the app on all the ReadFiles and I still see the requests coming down.

I am only opening \…\My1stInterface and doing reads and writes on this. However as soon as the app calls CancelIO on My1stInterface, I see hundreds of requests on the 2ndInterface.

VOID
LxEvtFileCleanup(
IN WDFFILEOBJECT FileObject
)
/*++

Routine Description:

EvtFileCleanup is called when the handle represented by the FileObject
is closed. This callback is invoked in the context of the thread that
closed the handle.

Arguments:

FileObject - Pointer to fileobject that represents the open handle.

Return Value:

VOID

–*/
{
NTSTATUS NtStatus;
PFILE_OBJECT_CONTEXT fileContext;
PDEVICE_CONTEXT pDeviceContext;
WDFDEVICE Device;
WDFQUEUE* pDataQueue;

fileContext = GetFileObjectContext(FileObject);

if (fileContext->pDataQueue)
{
Device = WdfIoQueueGetDevice(*(fileContext->pDataQueue));
pDeviceContext = GetDeviceContext(Device);

pDataQueue = fileContext->pDataQueue;

TraceEvents(TRACE_LEVEL_ERROR,
DBG_INIT,
“Cleanup: FileObject %p\n”,
FileObject);

if (pDataQueue == &pDeviceContext->BeadDataQueue)
{
WdfIoQueuePurge(pDeviceContext->BeadDataQueue,WDF_NO_EVENT_CALLBACK,WDF_NO_CONTEXT);
WdfIoQueueStart(pDeviceContext->BeadDataQueue);
TraceEvents(TRACE_LEVEL_ERROR,
DBG_INIT,
“LxEvtFileCleanup(): Flushing Bead Data Queue”);

}
else if (pDataQueue == &pDeviceContext->StatusDataQueue)
{
WdfIoQueuePurge(pDeviceContext->StatusDataQueue,WDF_NO_EVENT_CALLBACK,WDF_NO_CONTEXT);
WdfIoQueueStart(pDeviceContext->StatusDataQueue);
TraceEvents(TRACE_LEVEL_ERROR,
DBG_INIT,
“LxEvtFileCleanup(): Flushing Status Data Queue”);

}
}
else
{
TraceEvents(TRACE_LEVEL_ERROR,
DBG_INIT,
“LxEvtFileCleanup(): Called with fileContext->pDataQueue NULL”);
}

}

Another Question I have is when most of the examples create Parallel Queues, I don’t see them calling WdfDeviceConfigureRequestDispatching(). In my case, I am doing this. I then Forward to the Sequential Queues when EvtIoRead is called. Could this be a problem?