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;
}