[KMDF] problem WDFRequest PDO->FDO

Hello Everybody,

I have a problem for a driver development.
I try to develop a driver for smartcard reader USB.
I have never developed in KMDF and I have some problem for understand his function.

I have merged the sample OSRFXUsb ( for USB Interrupt Part for PDO) and the pscr sample ( for smartcard reader part for FDO).

My problem is for sending WDFRequest to the FDO.
I have implemented like presented the evtIoDeviceControl, but problem this callback is never called.

For my understanding, it’s necessary to implement a child Device for initialize a smartcard reader ? Or It’s possible to add all attributes in same deviceContext ?

typedef struct _DEVICE_CONTEXT {

WDFDEVICE device;
WDFDRIVER driver;
ULONG deviceInstanceNbr;
WDFINTERRUPT Interrupt;
SMARTCARD_EXTENSION SmartcardExtension;

WDFQUEUE NotificationQueue;
WDFQUEUE IoctlQueue;

USB_DEVICE_DESCRIPTOR usbDeviceDescriptor;
PUSB_CONFIGURATION_DESCRIPTOR usbConfigurationDescriptor;

WDFUSBDEVICE UsbDevice;

WDFUSBINTERFACE UsbInterface;

WDFUSBPIPE BulkReadPipe;

WDFUSBPIPE BulkWritePipe;

WDFUSBPIPE InterruptPipe;

WDFQUEUE InterruptMsgQueue;

ULONG UsbDeviceTraits;

} DEVICE_CONTEXT, *PDEVICE_CONTEXT;

NTSTATUS
busEvtDeviceAdd(
IN WDFDRIVER Driver,
IN PWDFDEVICE_INIT DeviceInit
)
{
NTSTATUS status;
WDFDEVICE device;
PDEVICE_CONTEXT pDevContext;

GUID activity;
WDF_DEVICE_PNP_CAPABILITIES pnpCaps;
WDF_FILEOBJECT_CONFIG fileConfig; // KL 26-11-2010
WDF_IO_QUEUE_CONFIG ioQueueConfig;
WDF_INTERRUPT_CONFIG interruptConfig;
WDF_OBJECT_ATTRIBUTES attributes;
WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks;
WDFQUEUE queue;

DECLARE_CONST_UNICODE_STRING(symbolikNameSlot0, SLOT_SYMBOLIK_NAME_0);
DECLARE_CONST_UNICODE_STRING(symbolikNameSlot1, SLOT_SYMBOLIK_NAME_1);
DECLARE_CONST_UNICODE_STRING(symbolikNameSlot2, SLOT_SYMBOLIK_NAME_2);

UNREFERENCED_PARAMETER(Driver);

PAGED_CODE();

WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_SMARTCARD);

// WdfDeviceInitSetExclusive(DeviceInit, TRUE);

WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);
pnpPowerCallbacks.EvtDevicePrepareHardware = busEvtDevicePrepareHardware;
pnpPowerCallbacks.EvtDeviceReleaseHardware = busEvtDeviceReleaseHardware;

pnpPowerCallbacks.EvtDeviceD0Entry = busEvtDeviceD0Entry;
pnpPowerCallbacks.EvtDeviceD0Exit = busEvtDeviceD0Exit;

WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks);

WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoBuffered); // KL 01-12-2010
//WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoDirect);

WDF_FILEOBJECT_CONFIG_INIT(
&fileConfig,
busEvtDeviceFileCreate,
busEvtFileClose,
WDF_NO_EVENT_CALLBACK // not interested in Cleanup
);

WdfDeviceInitSetFileObjectConfig(DeviceInit,
&fileConfig,
WDF_NO_OBJECT_ATTRIBUTES);

WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_CONTEXT);

status = WdfDeviceCreate(&DeviceInit, &attributes, &device);
if (!NT_SUCCESS(status)) {
BulkUsb_DebugPrint(1, (“WdfDeviceCreate failed status = 0x%x\n”, status));
return status;
}

attributes.ParentObject = device;

pDevContext = GetDeviceContext(device);

pDevContext->driver = Driver; // KL 02-12-2010
pDevContext->device= device;

WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnpCaps);
pnpCaps.SurpriseRemovalOK = WdfTrue;
WdfDeviceSetPnpCapabilities(device, &pnpCaps);

WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig,
WdfIoQueueDispatchParallel);

ioQueueConfig.EvtIoDeviceControl = EvtIoDeviceControl;
//ioQueueConfig.EvtIoInternalDeviceControl = EvtIoDeviceInternalControl;

status = WdfIoQueueCreate(device,
&ioQueueConfig,
&attributes,// WDF_NO_OBJECT_ATTRIBUTES,
&queue);// pointer to default queue

if (!NT_SUCCESS(status)) {
BulkUsb_DebugPrint(1, (“busEvtDeviceAdd - WdfIoQueueCreate failed 0x%X \n”, status));

return status;
}

WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig, WdfIoQueueDispatchSequential);

ioQueueConfig.EvtIoRead = usbEvtIoRead;
ioQueueConfig.EvtIoStop = usbEvtIoStop;

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

if (!NT_SUCCESS (status)) {
BulkUsb_DebugPrint(1, (“busEvtDeviceAdd - WdfIoQueueCreate failed %!STATUS!\n”, status));

return status;
}

status = WdfDeviceConfigureRequestDispatching(
device,
queue,
WdfRequestTypeRead);

if(!NT_SUCCESS (status)){
ASSERT(NT_SUCCESS(status));
BulkUsb_DebugPrint(1, (“busEvtDeviceAdd - WdfDeviceConfigureRequestDispatching failed %!STATUS!\n”, status));
//goto Error;
return status;
}

//
// We will create another sequential queue and configure it
// to receive write requests.
//
WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig, WdfIoQueueDispatchSequential);

ioQueueConfig.EvtIoWrite = usbEvtIoWrite;
ioQueueConfig.EvtIoStop = usbEvtIoStop;

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

if (!NT_SUCCESS (status)) {
BulkUsb_DebugPrint(1, (“busEvtDeviceAdd - WdfIoQueueCreate failed %!STATUS!\n”, status));
//goto Error;
return status;
}

status = WdfDeviceConfigureRequestDispatching(
device,
queue,
WdfRequestTypeWrite);

if(!NT_SUCCESS (status)){
ASSERT(NT_SUCCESS(status));
BulkUsb_DebugPrint(1, (“busEvtDeviceAdd - WdfDeviceConfigureRequestDispatching failed %!STATUS!\n”, status));
//goto Error;
return status;
}

WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig, WdfIoQueueDispatchManual);

ioQueueConfig.PowerManaged = WdfFalse;

ioQueueConfig.EvtIoCanceledOnQueue = slotEvtIoCanceledOnQueue;

status = WdfIoQueueCreate (
device,
&ioQueueConfig,
WDF_NO_OBJECT_ATTRIBUTES,
&pDevContext->NotificationQueue
);

if(!NT_SUCCESS (status)){
BulkUsb_DebugPrint(1, (“busEvtDeviceAdd - WdfIoQueueCreate failed %!STATUS!\n”, status));
return status;
}

ioQueueConfig.PowerManaged = WdfFalse;

status = WdfIoQueueCreate(device,
&ioQueueConfig,
WDF_NO_OBJECT_ATTRIBUTES,
&pDevContext->InterruptMsgQueue
);

if (!NT_SUCCESS(status)) {
BulkUsb_DebugPrint(1, (“busEvtDeviceAdd - WdfIoQueueCreate failed %!STATUS!\n”, status));
return status;
}

//
// Register with smartcard libarary.
//
status = slotRegisterWithSmcLib(pDevContext);
if (!NT_SUCCESS (status)) {
BulkUsb_DebugPrint(1, (" slotRegisterWithSmcLib failed status = 0x%x \n", status));
return status;
}

status = WdfDeviceCreateDeviceInterface(device,
(LPGUID) &GUID_DEVINTERFACE_KL,
//(LPGUID) &GUID_BUS_DEVINTERFACE_KL_0,
NULL); //&symbolikNameSlot0);// Reference String
if (!NT_SUCCESS(status)) {
//KdPrint((“WdfDeviceCreateDeviceInterface failed 0x%x\n”, status));
BulkUsb_DebugPrint(1, (“0) WdfDeviceCreateDeviceInterface failed status = 0x%x \n”, status));
return status;
}

BulkUsb_DebugPrint(1, (" <<<=== busEvtDeviceAdd - SUCCESS = status = 0x%X\n", status));

return status;
}

NTSTATUS
busEvtDeviceD0Entry(
WDFDEVICE Device,
WDF_POWER_DEVICE_STATE PreviousState
)
{
PDEVICE_CONTEXT pDeviceContext;
NTSTATUS status = STATUS_SUCCESS;
PSMARTCARD_EXTENSION SmartcardExtension;
UCHAR state;
WDF_INTERRUPT_INFO interruptInfo;

pDeviceContext = GetDeviceContext(Device);

BulkUsb_DebugPrint(1, (" ===>>> busEvtDeviceD0Entry\n\n"));

status = WdfIoTargetStart(WdfUsbTargetPipeGetIoTarget(pDeviceContext->InterruptPipe));

BulkUsb_DebugPrint(1, (“busEvtDeviceD0Entry - WdfIoTargetStart - [status = 0x%X]\n”, status));

SmartcardExtension = (PSMARTCARD_EXTENSION) &pDeviceContext->SmartcardExtension;

SmartcardExtension->ReaderExtension->StatusFileSelected = FALSE;
state = CBGetCardState(SmartcardExtension);

// save the current power state of the reader
SmartcardExtension->ReaderExtension->ReaderPowerState = PowerReaderWorking;

if (PreviousState != WdfPowerDeviceD3Final) {
//
// The device is resuming from a suspended state.
//
CBUpdateCardState(SmartcardExtension, state, TRUE);
} else {
//
// The device is starting up for the first time.
//
CBUpdateCardState(SmartcardExtension, state, FALSE);
}

BulkUsb_DebugPrint(1, (" <<<=== busEvtDeviceD0Entry\n"));

return status;
}

NTSTATUS
slotRegisterWithSmcLib(
PDEVICE_CONTEXT DeviceExtension
)
{
PREADER_EXTENSION ReaderExtension;
PSMARTCARD_EXTENSION SmartcardExtension;
UNICODE_STRING vendorNameU, ifdTypeU;
ANSI_STRING vendorNameA, ifdTypeA;
WDFSTRING vendorNameStr, ifdTypeStr;
NTSTATUS status;
UNICODE_STRING vendor;

PAGED_CODE();

BulkUsb_DebugPrint(1, (" ===>>> slotRegisterWithSmcLib\n"));

vendorNameStr = NULL;
ifdTypeStr = NULL;

RtlZeroMemory(&vendorNameA, sizeof(vendorNameA));
RtlZeroMemory(&ifdTypeA, sizeof(ifdTypeA));

// set up the device extension.
SmartcardExtension = &DeviceExtension->SmartcardExtension;

// allocate the reader extension
ReaderExtension = ExAllocatePoolWithTag(
NonPagedPool,
sizeof( READER_EXTENSION ),
SMARTCARD_POOL_TAG
);

if ( ReaderExtension == NULL ) {
SmartcardLogError(
WdfDriverWdmGetDriverObject(WdfGetDriver()),
SLOT_INSUFFICIENT_RESOURCES,
NULL,
0
);
status = STATUS_INSUFFICIENT_RESOURCES;
return status;
}

RtlZeroMemory( ReaderExtension, sizeof( READER_EXTENSION ));

SmartcardExtension->ReaderExtension = ReaderExtension;

ReaderExtension->CompletionRoutine = CBUpdateCardState;
ReaderExtension->TrackingContext = SmartcardExtension;

// Initialize the RequestInterrupt flag
ReaderExtension->RequestInterrupt = FALSE;

// setup smartcard extension - callback’s
SmartcardExtension->ReaderFunction[RDF_CARD_POWER] = CBCardPower;
SmartcardExtension->ReaderFunction[RDF_TRANSMIT] = CBTransmit;
SmartcardExtension->ReaderFunction[RDF_CARD_TRACKING] = CBCardTracking;
SmartcardExtension->ReaderFunction[RDF_SET_PROTOCOL] = CBSetProtocol;
SmartcardExtension->ReaderFunction[RDF_IOCTL_VENDOR] = slotGenericIOCTL;

// enter correct version of the lib
SmartcardExtension->Version = SMCLIB_VERSION;
SmartcardExtension->SmartcardRequest.BufferSize = MIN_BUFFER_SIZE;
SmartcardExtension->SmartcardReply.BufferSize = MIN_BUFFER_SIZE;

SmartcardExtension->ReaderExtension->ReaderPowerState = PowerReaderWorking;

status = SmartcardInitialize(SmartcardExtension);

if (status != STATUS_SUCCESS) {

BulkUsb_DebugPrint(1, (" slotRegisterWithSmcLib - SmartcardInitialize FAILED - status = 0x%X\n", status));

return status;
}

SmartcardExtension->OsData->DeviceObject =
WdfDeviceWdmGetDeviceObject(DeviceExtension->device);

RtlCopyMemory(
SmartcardExtension->VendorAttr.VendorName.Buffer,
DRIVER_NAME,
sizeof(DRIVER_NAME)
);
SmartcardExtension->VendorAttr.VendorName.Length = sizeof(DRIVER_NAME);

RtlCopyMemory(
SmartcardExtension->VendorAttr.IfdType.Buffer,
IFD_TYPE,
sizeof(IFD_TYPE)
);
SmartcardExtension->VendorAttr.IfdType.Length = sizeof(IFD_TYPE);

BulkUsb_DebugPrint(1, (" <<<=== slotRegisterWithSmcLib\n"));

return status;
}

UCHAR
CBGetCardState(
PSMARTCARD_EXTENSION SmartcardExtension
)
/*++

CBUpdateCardState:
updates the variable CurrentState in SmartcardExtension

Arguments:
SmartcardExtension context of call

Return Value:
STATUS_SUCCESS

–*/
{
PREADER_EXTENSION ReaderExtension = SmartcardExtension->ReaderExtension;

Val = 0x0;

BulkUsb_DebugPrint(1, (" ===>>> CBGetCardState\n"));

// NEED TO SEND WDFREQUEST TO THE PIPE BULKWRITE FOR EXECUTE GET_STATE COMMAND

BulkUsb_DebugPrint(1, (" <<<=== CBGetCardState\n"));

return Val;
}

Thanks in advance,

Best regard,

Kamel

Generic KMDF suggestions:

If not already done so, familiarize yourself with KMDF: http://www.microsoft.com/whdc/driver/wdf/KMDF.mspx

If you want to see all the IRPs sent to your driver, add a pre-process callback. In that callback you will see every IRP. It will make it easy for you to understand if the problem is b/c the IRP was never sent or if there is something wrong with your driver queues configuration.

Make sure to turn on WDM and WDF driver verifier. The link should contain this info too.

Egi.

Thanks Edigio for your help.
I have implemented my usbTarget for bulkInterrupt, bulkIn/Out.
Problem When I create WDFQUEUE for bulkRead/Write in ths bus part ( BusEvtDeviceAdd) and try to implement a function for add request to this Queue, I never have a request executed.
Pipe Interrupt work fine ( extract from osrFxUsb kmdf Sample ),
now I want to use my Queue dedicated for the bulkRead/Write for exchange information from FDO( slot smartcard part).
And I have always the problem for call the EvtDeviceControl function.

Thanks in advance.

Regards,

Kamel