[KMDF 1.9] how to send request to usbtarget with WdfFileObject context

Hello all,
I’m a beginner in KMDF device development.
I try to understand the best way for send request to usbTarget from a file object context.
I create 2 device interfaces for each smartcard reader slot (reference String = SLOT_0, SLOT_1).

// DeviceContext Structure
deviceContext
{
USB_DEVICE_DESCRIPTOR UsbDeviceDescriptor;
PUSB_CONFIGURATION_DESCRIPTOR UsbConfigurationDescriptor;
WDFUSBDEVICE WdfUsbTargetDevice;
WDFUSBINTERFACE UsbInterface;
WDFQUEUE IoctlQueue;
}

// FileSlotContext Structure
fileContext // Used for each device interface
{
SMARTCARD_EXTENSION smartcardExtension;
ULONG slotNumber;
UNICODE_STRING slotName; // stored for define the device interface opened
WDFDEVICE Device;
BOOLEAN alreadyOpen;
}

NTSTATUS EvtDeviceAdd( IN WDFDRIVER Driver,
IN PWDFDEVICE_INIT DeviceInit)
{

RtlInitUnicodeString(&DeviceName0, L"SLOT_0");
RtlInitUnicodeString(&DeviceName1, L"SLOT_1");

WDF_FILEOBJECT_CONFIG_INIT(
&fileobjectConfig,
DeviceFileCreate, // Create
DeviceEvtFileClose, // Close
EvtFileCleanup // Cleanup
);

WDF_OBJECT_ATTRIBUTES_INIT(&fileObjectAttributes);

fileObjectAttributes.SynchronizationScope = WdfSynchronizationScopeDevice;

WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&fileObjectAttributes, FILE_SLOT_CONTEXT);
WdfDeviceInitSetFileObjectConfig(
DeviceInit,
&fileobjectConfig,
&fileObjectAttributes //WDF_NO_OBJECT_ATTRIBUTES
);

WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, DEVICE_CONTEXT);

status = WdfDeviceCreate(&DeviceInit, &attributes, &device);

if (!NT_SUCCESS(status)) {

KdPrint((" EvtDeviceAdd - WdfDeviceCreate FAILED ( status = 0x%X)\n", status));

return status;
}

// KL 07-02-2011
if (status == STATUS_SUCCESS) {

WdfControlFinishInitializing(
device
);

//deviceObject = WdfDeviceWdmGetDeviceObject(device);
}

pDevContext = GetDeviceContext(device);

pDevContext->wdfDevice = device;
pDevContext->FDO = WdfDeviceWdmGetDeviceObject(device);
pDevContext->PDO = WdfDeviceWdmGetPhysicalDevice(device);

status = WdfDeviceCreateDeviceInterface(
device,
&SmartCardReaderGuid,
&DeviceName0
);

if (!NT_SUCCESS(status)) {
KdPrint((“1) WdfDeviceCreateDeviceInterface failed 0x%X\n”, status));
return status;
}

status = WdfDeviceCreateDeviceInterface(
device,
&SmartCardReaderGuid,
&DeviceName1
);

if (!NT_SUCCESS(status)) {
KdPrint((“2) WdfDeviceCreateDeviceInterface failed 0x%X\n”, status));
return status;
}
//
// Create a parallel queue for dispatching ioctl requests.
//

WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig,WdfIoQueueDispatchSequential); // KL 17-02-2011 WdfIoQueueDispatchParallel);

ioQueueConfig.EvtIoDeviceControl = EvtIoDeviceControl;

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

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

status = WdfDeviceConfigureRequestDispatching(
device,
pDevContext->IoctlQueue,
WdfRequestTypeDeviceControl
);

if (!NT_SUCCESS(status)) {
KdPrint((“WdfDeviceConfigureRequestDispatching failed 0x%X\n”, status));
return status;
}

KdPrint((“<<<=== EvtDeviceAdd \n\n”));

return status;
}

VOID
DeviceFileCreate (
IN WDFDEVICE Device,
IN WDFREQUEST Request,
IN WDFFILEOBJECT FileObject
)
{

RtlInitUnicodeString(&DeviceName0, L"\SLOT_0");
RtlInitUnicodeString(&DeviceName1, L"\SLOT_1");

fdoData = GetDeviceContext(Device);
slotContext = GetFileSlotContext(FileObject);
deviceName = WdfFileObjectGetFileName(WdfRequestGetFileObject(Request));

if (RtlCompareUnicodeString(deviceName, &DeviceName0, TRUE) == 0x0)
{
slotContext->slotNumber = 0;

if(!slotContext->alreadyOpen)
{

KdPrint( (" DeviceFileCreate __ SLOT_0 - FIRST CREATE\n"));
slotContext->Device = Device;
status = RegisterWithSmcLib(slotContext);

if(!NT_SUCCESS (status)){
// return status;
KdPrint( (" DeviceFileCreate - RegisterWithSmcLib- failed - status = 0x%X\n", status));
return;
}

slotContext->alreadyOpen = TRUE;

WdfRequestComplete(Request, STATUS_SUCCESS);

}
}
else
{
slotContext->slotNumber = 1;

if(!slotContext->alreadyOpen)
{

KdPrint( (" DeviceFileCreate __ SLOT_1 - FIRST CREATE\n"));
slotContext->Device = Device;
status = RegisterWithSmcLib(slotContext);

if(!NT_SUCCESS (status)){
// return status;
KdPrint( (" DeviceFileCreate - RegisterWithSmcLib- failed - status = 0x%X\n", status));
return;
}

slotContext->alreadyOpen = TRUE;

WdfRequestComplete(Request, STATUS_SUCCESS);

}
}
KdPrint( (“<<<=== DeviceFileCreate \n\n”));

return;
}

// Function used for register smartcardExtension from fileContext with different slot number
NTSTATUS
RegisterWithSmcLib (PFILE_SLOT_CONTEXT fileSlotContext)
{

// Callback used for smartcard statement
SmartCardExtension->ReaderFunction[RDF_CARD_POWER] =
Slot_ScardPower;

SmartCardExtension->VendorAttr.UnitNo = fileSlotContext->slotNumber;

status = SmartcardInitialize(SmartCardExtension);

if (status != STATUS_SUCCESS) {

SmartcardLogError(
WdfDriverWdmGetDriverObject(WdfGetDriver()),
STATUS_INSUFFICIENT_RESOURCES,
NULL,
0
);
return status;

}

// Function normally used for power on the inserted smartcard , it’s necessary to send some bytes to USB target for read/Write information of the smartcard
NTSTATUS Slot_ScardPower (PSMARTCARD_EXTENSION SmartcardExtension)
{
switch(SmartcardExtension->MinorIoControlCode)
{
case SCARD_WARM_RESET :
KdPrint((“SCARD_WARM_RESET\n”));
status = ccid_powerOn(SmartcardExtension,
&dataOutLength,
dataOut);
break;
default :
KdPrint((“Something else\n”));
status = STATUS_UNSUCCESSFUL;
}

KdPrint((" <<<=== Slot_ScardPower \n\n"));

return status;
}

ccid_powerOn(SmartcardExtension,
&dataOutLength,
dataOut)
{
// Would like to send information to usbTarget from fileContext
}

Now I have a big problem for understand how to proceed for “dialog” with the usbTargetDevice stored in the deviceContext.

I thought to add a queue in the fileContext with an objectAttributes that contains the usbTarget stored in deviceContext.

But I’m not sure if it’s the best way.

Some could help me please, because I really see no way for resolve this problem.

Thanks in advance,

Best regards,

(Just figured I’d give you a heads-up: I don’t know about other folks on the list, but you’ve posted too much code here for ME to read and not enough of a problem description. If you can explain what you’re trying to do and the problem you’re having doing it in English, I’ll be happy to help. I realize this is hard for folks who are not native speakers of English, but I spend much of the day trying to decipher long sequences of unfamiliar buggy code (sometimes my own), and I’m just not that likely to read another long sequence on the list on the chance that I might figure out what problem you need help with.)

Peter
OSR

Thanks Peter for your reply.

I must develop a driver for a smartcard reader usb multi slot ( 3 slot ).
The reader have just one usb interface with 3 endPoint ( IN,Out,Interrupt)
In first, I have used the OSRFXUSB sample for design the usb architecture (pipeRead/Write/Interrupt) stored in the deviceExtension context.
And called 3 times WdfDeviceCreateDeviceInterface with 3 different names.

My goal is to develop just one .sys file for work with this reader.

Doron suggest me to use device interface for each slot, so I have created a callBack for deviceFileCreate
I have created a file Context that contains all information for each slot ( slotNumber, deviceName, smartcard reader capabilities, mandatory smartcard callback for smclib.lib ).

Now the card detection process :
If I insert a card to the reader, I receive an interrupt and read interruptPipe buffer ( 4 bytes ) in the completion routine.
These 4 bytes define the slot where the card has been inserted.
for example :
0x50, 0x03, 0x0, 0x0 = card inserted to slot 0
0x50, 0x0C, 0x0, 0x0 = card inserted to slot 1
0x50, 0x30, 0x0, 0x0 = card inserted to slot 2

When I receive this buffer, I extract the second byte and with it’s value I can distinguish what is the slot used.

if ( buf[1] == 0x3)
// update card state of the fileSlotContext concerned ( First device interface slot 0)
else if ( buf[1] == 0xC)
// update card state of the fileSlotContext concerned ( Second device interface slot 1)
else if ( buf[1] == 0x30)
// update card state of the fileSlotContext concerned ( Third device interface slot 2)

For memorize the wdfFileObject attached to each slot I use temporarly an array of PFILE_CONTEXT.
But after I’m going to replace it by a wdfCollection.

All this work fine, now when I insert a card in one of the 3 slot, I can inform the slot concerned.

For summarize :
I can inform the fileContext when I receive an USB interrupt.

[USB INTERRUPT] [FILE CONTEXT per SLOT]
1 50,03 >>>>>> Update cardState of Slot0
2) Send

My bigbig problem, is after this step.
When I inform the fileContext concerned, I must send 10 bytes to the usb target for powerOn the card and receive somes bytes.

First of all, I’m beginner and even with the wdf books, I didn’t find a clear architecture that represent this use case.

I don’t know what is needed for create a communication between deviceContext and fileContext.

I suppose this can be possible, but I’m not sure if my architecture is correct or not.
maybe with an ioTarget pointer stored in the fileContext during deviceFileCreate callback ?

I’m lost in all these means :frowning:

I hope to have been more clear,

Thanks in advance,

Best regards,

Moulefrite

Each file slot context can reference back to the wdfusbdevice and wdfusbpipes. If you need to serialize the sending of the io across all of the slots, you would need some state management, otherwise just write to the device when you need to

d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@hotmail.com
Sent: Saturday, February 19, 2011 10:14 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] [KMDF 1.9] how to send request to usbtarget with WdfFileObject context

Thanks Peter for your reply.

I must develop a driver for a smartcard reader usb multi slot ( 3 slot ).
The reader have just one usb interface with 3 endPoint ( IN,Out,Interrupt) In first, I have used the OSRFXUSB sample for design the usb architecture (pipeRead/Write/Interrupt) stored in the deviceExtension context.
And called 3 times WdfDeviceCreateDeviceInterface with 3 different names.

My goal is to develop just one .sys file for work with this reader.

Doron suggest me to use device interface for each slot, so I have created a callBack for deviceFileCreate I have created a file Context that contains all information for each slot ( slotNumber, deviceName, smartcard reader capabilities, mandatory smartcard callback for smclib.lib ).

Now the card detection process :
If I insert a card to the reader, I receive an interrupt and read interruptPipe buffer ( 4 bytes ) in the completion routine.
These 4 bytes define the slot where the card has been inserted.
for example :
0x50, 0x03, 0x0, 0x0 = card inserted to slot 0 0x50, 0x0C, 0x0, 0x0 = card inserted to slot 1 0x50, 0x30, 0x0, 0x0 = card inserted to slot 2

When I receive this buffer, I extract the second byte and with it’s value I can distinguish what is the slot used.

if ( buf[1] == 0x3)
// update card state of the fileSlotContext concerned ( First device interface slot 0) else if ( buf[1] == 0xC)
// update card state of the fileSlotContext concerned ( Second device interface slot 1) else if ( buf[1] == 0x30)
// update card state of the fileSlotContext concerned ( Third device interface slot 2)

For memorize the wdfFileObject attached to each slot I use temporarly an array of PFILE_CONTEXT.
But after I’m going to replace it by a wdfCollection.

All this work fine, now when I insert a card in one of the 3 slot, I can inform the slot concerned.

For summarize :
I can inform the fileContext when I receive an USB interrupt.

[USB INTERRUPT] [FILE CONTEXT per SLOT]
1 50,03 >>>>>> Update cardState of Slot0
2) Send

My bigbig problem, is after this step.
When I inform the fileContext concerned, I must send 10 bytes to the usb target for powerOn the card and receive somes bytes.

First of all, I’m beginner and even with the wdf books, I didn’t find a clear architecture that represent this use case.

I don’t know what is needed for create a communication between deviceContext and fileContext.

I suppose this can be possible, but I’m not sure if my architecture is correct or not.
maybe with an ioTarget pointer stored in the fileContext during deviceFileCreate callback ?

I’m lost in all these means :frowning:

I hope to have been more clear,

Thanks in advance,

Best regards,

Moulefrite


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

Thanks Doron for your reply,
I have implemented some function for send usb read/Write with a queue for serialize the exchange.

example : this function is attached to a device interface ( called for each slot device interface )
NTSTATUS Slot_ScardPower (PSMARTCARD_EXTENSION SmartcardExtension) // Extract from file context
{
NTSTATUS status = STATUS_SUCCESS;
ULONG dataOutLength;
UCHAR dataOut[BULKUSB_MAX_TRANSFER_SIZE];

KdPrint((" ===>>> Slot_ScardPower \n"));

if((status = SmartcardAcquireRemoveLock(SmartcardExtension)) != STATUS_SUCCESS)
{
SmartcardExtension->IoRequest.Information = 0;
}
else
{
switch(SmartcardExtension->MinorIoControlCode)
{
case SCARD_WARM_RESET :
KdPrint((“SCARD_WARM_RESET\n”));

status = ccid_powerOn(SmartcardExtension,
&dataOutLength,
dataOut);

if(NT_SUCCESS(status))
{
KdPrint((“ccid_powerOn - SUCCESS\n”));
SmartcardExtension->CardCapabilities.ATR.Length = (UCHAR) dataOutLength;
RtlCopyMemory(
SmartcardExtension->CardCapabilities.ATR.Buffer,
dataOut,
dataOutLength);
}
break;
}
}
SmartcardReleaseRemoveLock(SmartcardExtension);
}
KdPrint((" <<<=== Slot_ScardPower \n\n"));

return STATUS_SUCCESS;
}

NTSTATUS
ccid_powerOn(PSMARTCARD_EXTENSION SmartcardExtension,
PULONG lenDataOut,
PUCHAR dataOut)
{
NTSTATUS ntStatus;
KIRQL irql; // KL 17-12-2010

BulkUsb_DebugPrint(3, (“===>>> ccid_powerOn\n”));

ntStatus = busUsbExchange(
GetDeviceContext(WdfWdmDeviceGetWdfDeviceHandle(SmartcardExtension->OsData->DeviceObject)),
SmartcardExtension->ReaderExtension->bSlot,
0x62,
dataOut,
0,
lenDataOut
);
BulkUsb_DebugPrint(3, (“<<<=== ccid_powerOn\n”));

return (ntStatus);
}

NTSTATUS
busUsbExchange(
IN PDEVICE_CONTEXT deviceContext, // KL 17-02-2011
IN UCHAR slotNumber, // KL 19-02-2011
IN UCHAR messageType,
PUCHAR dataBuffer,
IN ULONG dataBufferLen,
PULONG dataOutLength
)
{

status = usbWrite( deviceContext,
length,
bufferTransmit);

if(!NT_SUCCESS(status))
{
BulkUsb_DebugPrint(1, (“busUsbExchange - usb_write FAILED - status = 0x%X\n”, status));
//return
}

status = usbRead( deviceContext,
BULKUSB_MAX_TRANSFER_SIZE,
CCID_MAX_WAIT,
bufferTransmit,
dataOutLength
);

if(!NT_SUCCESS(status))
{
BulkUsb_DebugPrint(1, (“busUsbExchange - usb_read FAILED - status = 0x%X\n”, status));
//return
}
else
{
*dataOutLength = deviceContext->usbBufferReceivedLength;

BulkUsb_DebugPrint(1, (“busUsbExchange - usb_read SUCCESS - dataOutLength = %d\n”, *dataOutLength));

RtlCopyMemory(bufferTransmit,
deviceContext->usbBufferReceived,
*dataOutLength
);

}
return status;
}

NTSTATUS
usbWrite(
IN PDEVICE_CONTEXT deviceContext,
IN ULONG bufferInLen,
IN OUT PUCHAR bufferIn
)
{
NTSTATUS status = STATUS_SUCCESS;
PSMARTCARD_EXTENSION smartcardExtension = NULL;
WDFREQUEST requestWrite;
WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket;
WDF_REQUEST_SEND_OPTIONS sendOptions;
WDF_MEMORY_DESCRIPTOR memDesc;
ULONG bytesTransferred;
PUCHAR responseBuffer = NULL;
WDFMEMORY memory;
WDF_OBJECT_ATTRIBUTES attributes;
WDFMEMORY memHandle;

BulkUsb_DebugPrint(1, (“===>>> usbWrite \n”));

//PAGED_CODE();

smartcardExtension = &deviceContext->SmartCardExtension;

// Initialise la structure d’envoi de la requete
WDF_REQUEST_SEND_OPTIONS_INIT(
&sendOptions,
WDF_REQUEST_SEND_OPTION_SYNCHRONOUS | WDF_REQUEST_SEND_OPTION_TIMEOUT
);

// param?tre un timeOut en cas de probl?me de comm USB
WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(
&sendOptions,
WDF_REL_TIMEOUT_IN_SEC(1)
);

// KL 15-12-2010 d?finit le send d’envoi de la requete ( dispatch sur la bonne pile d’envoi )
WDF_USB_CONTROL_SETUP_PACKET_INIT(&controlSetupPacket,
BmRequestHostToDevice,
BmRequestToDevice,
0, // Request
0, // Value
0); // Index

WDF_OBJECT_ATTRIBUTES_INIT(&attributes);

// cr?ation de la requete qui pointe sur l’objet “USB”
status = WdfRequestCreate(
&attributes,
WdfUsbTargetDeviceGetIoTarget(deviceContext->UsbDevice),
&requestWrite);

if (!NT_SUCCESS(status)){
BulkUsb_DebugPrint(1, (“usbWrite - WdfRequestCreate - FAILED status = 0x%X\n”, status));
return status;
}

WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
attributes.ParentObject = requestWrite; // d?finit la cible de la requete

// initialise la WDFMEMORY avec le buffer ? envoyer vers l’USB
status = WdfMemoryCreatePreallocated(
&attributes,
bufferIn,
bufferInLen,
&memHandle
);

if (!NT_SUCCESS(status)){
BulkUsb_DebugPrint(1, (“usbWrite - WdfMemoryCreate - FAILED status = 0x%X\n”, status));
return status;
}

// construit la requete avec sa cible et la WDFMEMORY contenant la commande ? envoyer
status = WdfUsbTargetDeviceFormatRequestForControlTransfer(
deviceContext->UsbDevice,
requestWrite, // Optional WDFREQUEST
&controlSetupPacket,
memHandle,
NULL);

if(!NT_SUCCESS(status)) {
BulkUsb_DebugPrint(1, (“usbWrite - Failed to format request - 0x%x \n”, status));
return status;
} else {
BulkUsb_DebugPrint(1, (“usbWrite - format request SUCCESS \n”));
}

// Formate implicitement la requete vers la cible de type objet pipe bulkOut
status = WdfUsbTargetPipeFormatRequestForWrite(deviceContext->BulkWritePipe,
requestWrite,
memHandle,
NULL);

if (!NT_SUCCESS(status)) {
BulkUsb_DebugPrint(1, (“usbWrite - WdfUsbTargetPipeFormatRequest failed 0x%x\n”, status));
return status;
}

// d?finit une fonction de completion apr?s execution peu importe le status
WdfRequestSetCompletionRoutine(
requestWrite,
EvtRequestWriteCompletionRoutine,
deviceContext);

// ?mission d’une requete asynchrone sur la cible objet pipe bulkOut
if (WdfRequestSend(requestWrite, WdfUsbTargetPipeGetIoTarget(deviceContext->BulkWritePipe), &sendOptions) == FALSE) {

BulkUsb_DebugPrint(1, (“usbWrite - WdfRequestSend failed\n”));
status = WdfRequestGetStatus(requestWrite);
return status;
}

BulkUsb_DebugPrint(1, (“<<<=== usbWrite - status = 0x%X \n”, status));

return status;
}

NTSTATUS
usbRead(
IN PDEVICE_CONTEXT deviceContext,
IN ULONG maxBufferOutLen,
IN ULONG waitTime,
OUT PUCHAR bufferOut,
OUT PULONG bufferOutLen
)
{
NTSTATUS status = STATUS_SUCCESS;
WDF_USB_CONTROL_SETUP_PACKET controlSetupPacket;
WDF_REQUEST_SEND_OPTIONS sendOptions;
WDF_MEMORY_DESCRIPTOR memDesc;
ULONG bytesTransferred;
PUCHAR responseBuffer = NULL;
WDFMEMORY memory;
WDF_OBJECT_ATTRIBUTES attributes;
WDFMEMORY memHandle;
WDFREQUEST requestRead;

BulkUsb_DebugPrint(1, (“===>>> usbRead \n”));

//PAGED_CODE();

WDF_REQUEST_SEND_OPTIONS_INIT(
&sendOptions,
WDF_REQUEST_SEND_OPTION_SYNCHRONOUS | WDF_REQUEST_SEND_OPTION_TIMEOUT
);

WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(
&sendOptions,
WDF_REL_TIMEOUT_IN_SEC(1)
);

// KL 15-12-2010
WDF_USB_CONTROL_SETUP_PACKET_INIT(&controlSetupPacket,
BmRequestDeviceToHost,
BmRequestToDevice,
0, // Request
0, // Value
0); // Index

WDF_OBJECT_ATTRIBUTES_INIT(&attributes);

status = WdfRequestCreate(
&attributes,
WdfUsbTargetDeviceGetIoTarget(deviceContext->UsbDevice),
&requestRead);

if (!NT_SUCCESS(status)){
BulkUsb_DebugPrint(1, (“usbRead - WdfRequestCreate - FAILED status = 0x%X\n”, status));
return status;
}

WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
attributes.ParentObject = requestRead;

status = WdfMemoryCreate(
&attributes,
NonPagedPool,
0,
BULKUSB_MAX_TRANSFER_SIZE,
&memHandle,
NULL
);

if (!NT_SUCCESS(status)){
BulkUsb_DebugPrint(1, (“usbRead - READ - WdfMemoryCreate - FAILED status = 0x%X\n”, status));
return status;
}

status = WdfUsbTargetDeviceFormatRequestForControlTransfer(
deviceContext->UsbDevice,
requestRead, // Optional WDFREQUEST
&controlSetupPacket,
memHandle,
NULL);

if(!NT_SUCCESS(status)) {
BulkUsb_DebugPrint(1, (“usbRead - Failed to format request - 0x%x \n”, status));
} else {
BulkUsb_DebugPrint(1, (“usbRead - format request SUCCESS\n”));
}

status = WdfUsbTargetPipeFormatRequestForRead(deviceContext->BulkReadPipe,
requestRead,
memHandle,
NULL); // Offset

if (!NT_SUCCESS(status)) {
BulkUsb_DebugPrint(1, (“usbRead - WdfUsbTargetPipeFormatRequest failed 0x%x\n”, status));
return status;
}

WdfRequestSetCompletionRoutine(
requestRead,
EvtRequestReadCompletionRoutine,
deviceContext);

//
// Send the request asynchronously.
//
if (WdfRequestSend(requestRead, WdfUsbTargetPipeGetIoTarget(deviceContext->BulkReadPipe), &sendOptions) == FALSE) {

BulkUsb_DebugPrint(1, (“usbRead - WdfRequestSend failed\n”));
status = WdfRequestGetStatus(requestRead);
return status;
}

BulkUsb_DebugPrint(1, (“<<<=== usbRead - status = 0x%X\n”, status));

return status;
}

I hope my mecanism is clear and correct

Thanks for your help,

Best regards,

Moulefrite