BulkInPipe Read Request -> 0xc0000001

xxxxx@alumni.tu-berlin.de wrote:

…From my point of view my original question on the NTSTATUS 0xc0000001 message in case of a read request can be answered that if the microcontroller of the usb device sends continuously data into the bulkin pipe then the host has to offer a continues reader because otherwise it would generate the error message 0xc0000001.

No, that’s not correct. Remember that USB is entirely host-driven. A
device cannot send data on its own. The device is never given a chance
to send any data unless the host controller asks it to, and the host
controller will never ask the device to send unless it has a read
request waiting.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

You have a race condition. What happens when WdfIoQueueRetrieveNextRequest fails and immediately right afterwards you receive a user mode request for bulk in data? Do you drop the data on the floor in the cont reader completion routine?

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@alumni.tu-berlin.de
Sent: Wednesday, May 1, 2013 10:58 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] BulkInPipe Read Request -> 0xc0000001

Hi,
just for the case that someone is interested in code examples on how to get data from a continuous reader into the user space ? here are the relevant routines (attached). From my point of view my original question on the NTSTATUS 0xc0000001 message in case of a read request can be answered that if the microcontroller of the usb device sends continuously data into the bulkin pipe then the host has to offer a continues reader because otherwise it would generate the error message 0xc0000001.
Best Regards,
Matthias

//WDFQUEUE BulkinReadRequestsQueue;//must be included into the device context structure
// WDFUSBPIPE UsbInterruptPipe; //must be included into the device context structure

//EvtDevicePrepareHardware
WdfUsbTargetPipeSetNoMaximumPacketSizeCheck(devCtx->UsbBulkInPipe);
WDF_USB_CONTINUOUS_READER_CONFIG_INIT(&BulkinConfig,
&UsbPipeReadComplete,
devCtx,
1024*sizeof(BYTE)); // <- this has to be multiple times larger than the expected packet size ? I expected 200 bytes and got only in the case of 1024 bytes a call of the BulkInContireader completion routine

BulkinConfig.EvtUsbTargetPipeReadersFailed = (PFN_WDF_USB_READERS_FAILED) UsbPipeReadFailed;
BulkinConfig.NumPendingReads = 2; // this is by default = 0;
status = WdfUsbTargetPipeConfigContinuousReader(
devCtx->UsbBulkInPipe,
&BulkinConfig);
if(!NT_SUCCESS(status))
{
KdPrint((__DRIVER_NAME
“WdfUsbTargetPipeConfigContinuousReader failed with status 0x%08x\n”, status));
return status;
} else KdPrint((__DRIVER_NAME
“WdfUsbTargetPipeConfigContinuousReader ready \n”));

//CreateQueue
WDF_IO_QUEUE_CONFIG_INIT(&ioQConfig,
WdfIoQueueDispatchManual); // this is the ?manual queue? Tim was speaking about

status = WdfIoQueueCreate(Device,
&ioQConfig,
WDF_NO_OBJECT_ATTRIBUTES,
&Context->BulkinReadRequestsQueue);
if(!NT_SUCCESS(status))
{
KdPrint((__DRIVER_NAME
“WdfIoQueueCreate for manual queue failed with status 0x%08x\n”, status));
return status;
}

//IOCTL routine which is called from user space via DeviceIoControl
VOID
IoCtlGetUSBBulkinData(
IN WDFQUEUE Queue,
IN WDFREQUEST Request,
IN size_t OutputBufferLength,
IN size_t InputBufferLength
)

{

NTSTATUS status = STATUS_SUCCESS;
PDEVICE_CONTEXT devCtx = NULL;
UNREFERENCED_PARAMETER(InputBufferLength);
UNREFERENCED_PARAMETER(OutputBufferLength);

devCtx = GetDeviceContext(WdfIoQueueGetDevice(Queue));
status = WdfRequestForwardToIoQueue(Request,
devCtx->BulkinReadRequestsQueue); //this pushes a IO request into the quese that contains appropriate buffer space that were set DeviceIoControl inside the user space

if(!NT_SUCCESS(status))
{
KdPrint((__DRIVER_NAME
“WdfRequestForwardToIoQueue failed with code 0x%08x.\n”, status));
WdfRequestComplete(Request, status);
}
Else KdPrint((__DRIVER_NAME
“Request fired.\n”));

};

// BulkInContireader completion
VOID
UsbPipeReadComplete(
IN WDFUSBPIPE Pipe,
IN WDFMEMORY Buffer,
IN size_t NumBytesTransfered,
IN WDFCONTEXT Context
)
{
NTSTATUS status = STATUS_SUCCESS;
WDFMEMORY outputMemory = NULL;
BYTE *inBuffer = NULL;
size_t in_size = 0;

PDEVICE_CONTEXT devCtx = Context;
WDFREQUEST Request = NULL;
UNREFERENCED_PARAMETER(Pipe);

// get eventually a request from BulkinReadRequestsQueue ? which would be there if the user mode has previously called IoCtlGetUSBBulkinData via a DeviceIoControl call.

status = WdfIoQueueRetrieveNextRequest(devCtx->BulkinReadRequestsQueue, &Request);
if(NT_SUCCESS(status))
{
KdPrint((__DRIVER_NAME
“Got a Request\n”));
//get the user mode memory
status = WdfRequestRetrieveOutputMemory(Request, &outputMemory);
if(!NT_SUCCESS(status))
{
KdPrint((__DRIVER_NAME
“WdfRequestRetrieveOutputMemory failed with status 0x%08x\n”, status));

} //if
else {

//get the inBuffer pointer for the data packet which was recently send via bulkin

inBuffer = WdfMemoryGetBuffer(Buffer, &in_size);

//check whether the user mode has selected the right buffer size

if(in_size == NumBytesTransfered) {
// copy and paste the data packet from bulkin into the user mode memory
status = WdfMemoryCopyFromBuffer(outputMemory, 0, inBuffer, NumBytesTransfered);
if(!NT_SUCCESS(status))
{
KdPrint((__DRIVER_NAME
“WdfMemoryCopyFromBuffer failed with status 0x%08x\n”, status));

} //if
}// if
else KdPrint((__DRIVER_NAME “in_size != NumBytesTransfered\n”, status));

KdPrint((__DRIVER_NAME “Bytes Copied %d \n”, in_size));

WdfRequestCompleteWithInformation(Request, status, in_size*sizeof(BYTE));
} //else

} //if

return;

// Bulkin Read failed
BOOLEAN
UsbPipeReadFailed(
IN WDFUSBPIPE Pipe,
IN NTSTATUS Status,
IN USBD_STATUS UsbdStatus
)
{
UNREFERENCED_PARAMETER(Pipe);
//send a kd message
KdPrint((__DRIVER_NAME “UsbPipeReadFailed NTSTAUS 0x%08x and USBD Status 0x%08x \n”, Status, UsbdStatus));
return TRUE;
};


NTDEV is sponsored by OSR

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

@Doron
I would feel better with a solution that gets the continuous reader to stop until there is a request inside the manual queue ? this link sounds good: http://msdn.microsoft.com/de-de/library/windows/hardware/ff547415(v=vs.85).aspx. A simpler solution could be to loop WdfIoQueueRetrieveNextRequest until it reports success but for the case the user mode application crashes for some reason the kernel is trapped within an infinite loop.

@Tim: Could also be that it has something to do with the buffer size initially provided by the readfile call from usermode in my first attempt. In my attempts I tried 200, 512 or 1000 bytes but for some reason I didn?t tried 1024. I doubt that it will work with a provided buffer size of 1024 bytes. This is supported by my observation that the continuousreader has called the UsbPipeReadFailed function for the case that:

WDF_USB_CONTINUOUS_READER_CONFIG_INIT(&BulkinConfig,
UsbPipeReadComplete,
devCtx,
200*sizeof(BYTE)); <– after changing this into 1024*sizeof(BYTE) it started to work

No, you want to continuously read the data and handle the case where there are no requests, you simple do this

Declare a lock and ring buffer in your device context

EvtIoControl()
{
GetLock();
If (data in ring buffer) { remove data; remember I have data; }
Else { enqueuerequest(); }
ReleaseLock();

If (I have data) { copy data into request; complete request; }
}

ContReaderComplete()
{
GetLock();
If (dequeuerequest) { // will copy after lock is released }
Else { put data into ring buffer }
ReleaseLock();
If (request has been dequeued) { coy data into request; complete request; }
}

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@alumni.tu-berlin.de
Sent: Wednesday, May 1, 2013 3:31 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] BulkInPipe Read Request -> 0xc0000001

@Doron
I would feel better with a solution that gets the continuous reader to stop until there is a request inside the manual queue ? this link sounds good: http://msdn.microsoft.com/de-de/library/windows/hardware/ff547415(v=vs.85).aspx. A simpler solution could be to loop WdfIoQueueRetrieveNextRequest until it reports success but for the case the user mode application crashes for some reason the kernel is trapped within an infinite loop.

@Tim: Could also be that it has something to do with the buffer size initially provided by the readfile call from usermode in my first attempt. In my attempts I tried 200, 512 or 1000 bytes but for some reason I didn?t tried 1024. I doubt that it will work with a provided buffer size of 1024 bytes. This is supported by my observation that the continuousreader has called the UsbPipeReadFailed function for the case that:

WDF_USB_CONTINUOUS_READER_CONFIG_INIT(&BulkinConfig,
UsbPipeReadComplete,
devCtx,
200*sizeof(BYTE)); <– after changing this into 1024*sizeof(BYTE) it started to work


NTDEV is sponsored by OSR

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

xxxxx@alumni.tu-berlin.de wrote:

I would feel better with a solution that gets the continuous reader to stop until there is a request inside the manual queue ?

That’s a good idea, because an unsatisfied bulk request will retry
continuously until something is sent. That will prevent that part of
the bus from going idle, and is a significant power drain in mobile devices.

@Tim: Could also be that it has something to do with the buffer size initially provided by the readfile call from usermode in my first attempt. In my attempts I tried 200, 512 or 1000 bytes but for some reason I didn?t tried 1024. I doubt that it will work with a provided buffer size of 1024 bytes. This is supported by my observation that the continuousreader has called the UsbPipeReadFailed function for the case that:

WDF_USB_CONTINUOUS_READER_CONFIG_INIT(&BulkinConfig,
UsbPipeReadComplete,
devCtx,
200*sizeof(BYTE)); <– after changing this into 1024*sizeof(BYTE) it started to work

Technically, your reads should all be a multiple of the packet size.
Remember that a USB device is never told how much data you’re
expecting. It merely gets a signal saying “go!”. If you ask for 200
bytes, the host controller schedules enough time for 200 bytes. If the
device sends 512, which it is permitted to do, that is a protocol
violation called “babble”. If it happens to occur at the very end of a
frame, it can cause the hub to shut itself down.

You do know that sizeof(BYTE) is, by definition, 1? Always? BYTE is
typedefed to “unsigned char”, and the C standard requires sizeof(char) be 1.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

@Doron
What about using two or three or maybe n manual queues which all are simultaneously stuffed with identical requests from user mode (the user mode will have n threads each of them calling it?s own queue via DeviceIoControl). The completion routine will then move on to the next queue in the case if the WdfIoQueueRetrieveNextRequest of the first queue fails.

@Tim –>You do know that sizeof(BYTE) is, by definition, 1?
All msdn examples I found use ?sizeof(byte)? instead of ?1? ? but you are right.

That makes no sense whatsoever. Round robining through multiple queues who all hold the same type of request doesn’t make it faster NOR does it close your race condition. It makes your race condition(s) worse by adding more conditions to race on. And your driver doesn’t know which UM thread initiated IO, the driver shouldn’t care if there is 1 thread or 200 threads issuing IO. What I would recommend you do is have one thread issue N simultaneous IOCTLs asynchronously to prime the pump and then when one completes, issue another IOCTL. To be clear, WdfIoQueueRetrieveNextRequest will not fail due to low memory or anything like that, it will fail only because there are no requests to return.

d

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@alumni.tu-berlin.de
Sent: Thursday, May 2, 2013 3:20 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] BulkInPipe Read Request -> 0xc0000001

@Doron
What about using two or three or maybe n manual queues which all are simultaneously stuffed with identical requests from user mode (the user mode will have n threads each of them calling it?s own queue via DeviceIoControl). The completion routine will then move on to the next queue in the case if the WdfIoQueueRetrieveNextRequest of the first queue fails.

@Tim –>You do know that sizeof(BYTE) is, by definition, 1?
All msdn examples I found use ?sizeof(byte)? instead of ?1? ? but you are right.


NTDEV is sponsored by OSR

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