camera usb driver based on microsoft ddk's bulkusb,but have some question.

Hi:

I have built a bulk usb driver based on BulkUsb,and change the BULKUSB_MAX_TRANSFER_SIZE=2014208 bytes. I am developing it for a bulk communication with my camera device.

I have Implemented that driver for 2014208 bytes size.my driver usually run
well,but when the driver is timeout ,in this case,the driver return tranfer size is zero.? who can tell me why?

in order to confirm my question,I reduce the send size of hardware , at this time,the application program timeout everytime. and the driver return tranfer size is zero bytes.for example,my application send a buffer to device hardware,the size is 2014208 bytes,but the maxinum data of the device hardware is less than 2014208,for example,is 1440254.at this time, my application program receive zero bytes dada,but in my opinion, the size must be 1440254.who can tell me why?

the third question : my application program use readfile function to read data of usb pipe,but everytime it return False,and find GetLastError() =ERROR_IO_PENDING,then use GetOverlappedResult ,find the transfer size is right(=2014208).

the fouth question : some time when WAIT_TIMEOUT,and at this time ,the transfer size is zero bytes.

who can tell me why? I am look forward to hearing from you .thank you very much indeed.

stone

my application program is:

DWORD USB_Read(HANDLE handle, // Input
PVOID pData, // Output :image buff
DWORD dwLen, // Input :a frame image size
PDWORD pLength, // Output: receives the number of bytes read
DWORD dwMilliseconds) // Input: the time of timeout
{

BOOL bResult;
DWORD nBytesRead;
OVERLAPPED gOverlapped;
DWORD dwResult;

dwResult = E_FALSE;

// set up overlapped structure fields
gOverlapped.Internal = 0;
gOverlapped.InternalHigh = 0;
gOverlapped.Offset = 0;
gOverlapped.OffsetHigh = 0;
gOverlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

if(pLength != NULL)
{
*pLength = 0;
}

// attempt an asynchronous read operation
bResult = ReadFile(handle,pData,dwLen,&nBytesRead,&gOverlapped);
if(!bResult)
{
// deal with the error code
switch (GetLastError())
{
case ERROR_HANDLE_EOF:
{
// we have reached the end of the file
// during the call to ReadFile
break;
}
case ERROR_IO_PENDING:
{
// asynchronous i/o is still in progress
switch(WaitForSingleObject(gOverlapped.hEvent, dwMilliseconds))
{
case WAIT_OBJECT_0:
// check on the results of the asynchronous read
// and update the nBytesRead…
bResult = GetOverlappedResult(handle, &gOverlapped,
&nBytesRead, FALSE);
if(bResult)
{
if(pLength != NULL)
*pLength = nBytesRead;
dwResult = E_OK;
}
break;
case WAIT_TIMEOUT:
bResult = GetOverlappedResult(handle, &gOverlapped,&nBytesRead, FALSE);
if(bResult)
{
if(pLength != NULL)
{
*pLength = nBytesRead;
}
}
CancelIo(handle);
break;
default:
CancelIo(handle);
break;
}
break;
}
default:
CancelIo(handle);
break;
}
}
else
{
if(pLength != NULL)
*pLength = nBytesRead;
TRACE(" have data %d\n",nBytesRead);
dwResult = E_OK;
}

ResetEvent(gOverlapped.hEvent);
CloseHandle(gOverlapped.hEvent);
return dwResult;
}

my driver is based on ddk’s bulkusb,the Dispatch routine for read and write is:

TSTATUS
BulkUsb_DispatchReadWrite(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++

Routine Description:

Dispatch routine for read and write.
This routine creates a BULKUSB_RW_CONTEXT for a read/write.
This read/write is performed in stages of BULKUSB_MAX_TRANSFER_SIZE.
once a stage of transfer is complete, then the irp is circulated again,
until the requested length of tranfer is performed.

Arguments:

DeviceObject - pointer to device object
Irp - I/O request packet

Return Value:

NT status value

–*/
{
PMDL mdl;
PURB urb;
ULONG totalLength;
ULONG stageLength;
ULONG urbFlags;
BOOLEAN read;
NTSTATUS ntStatus;
ULONG_PTR virtualAddress;
PFILE_OBJECT fileObject;
PDEVICE_EXTENSION deviceExtension;
PIO_STACK_LOCATION irpStack;
PIO_STACK_LOCATION nextStack;
PBULKUSB_RW_CONTEXT rwContext;
PUSBD_PIPE_INFORMATION pipeInformation;

//
// initialize variables
//

urb = NULL;
mdl = NULL;
rwContext = NULL;
totalLength = 0;
irpStack = IoGetCurrentIrpStackLocation(Irp);
fileObject = irpStack->FileObject;
read = (irpStack->MajorFunction == IRP_MJ_READ) ? TRUE : FALSE;
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;

BulkUsb_DbgPrint(3, (“BulkUsb_DispatchReadWrite - begins\n”));

if(deviceExtension->DeviceState != Working) {

BulkUsb_DbgPrint(1, (“Invalid device state\n”));

ntStatus = STATUS_INVALID_DEVICE_STATE;
goto BulkUsb_DispatchReadWrite_Exit;
}

//
// It is true that the client driver cancelled the selective suspend
// request in the dispatch routine for create Irps.
// But there is no guarantee that it has indeed completed.
// so wait on the NoIdleReqPendEvent and proceed only if this event
// is signalled.
//
BulkUsb_DbgPrint(3, (“Waiting on the IdleReqPendEvent\n”));

//
// make sure that the selective suspend request has been completed.
//

if(deviceExtension->SSEnable) {

KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent, //
Executive,
KernelMode,
FALSE,
NULL);
}

if(fileObject && fileObject->FsContext) {

pipeInformation = fileObject->FsContext;

if(UsbdPipeTypeBulk != pipeInformation->PipeType) {

BulkUsb_DbgPrint(1, (“Usbd pipe type is not bulk\n”));

ntStatus = STATUS_INVALID_HANDLE;
goto BulkUsb_DispatchReadWrite_Exit;
}
}
else {

BulkUsb_DbgPrint(1, (“Invalid handle\n”));

ntStatus = STATUS_INVALID_HANDLE;
goto BulkUsb_DispatchReadWrite_Exit;
}

rwContext = (PBULKUSB_RW_CONTEXT)
ExAllocatePool(NonPagedPool,
sizeof(BULKUSB_RW_CONTEXT));

if(rwContext == NULL) {

BulkUsb_DbgPrint(1, (“Failed to alloc mem for rwContext\n”));

ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto BulkUsb_DispatchReadWrite_Exit;
}

if(Irp->MdlAddress) {

totalLength = MmGetMdlByteCount(Irp->MdlAddress);
}

if(totalLength > BULKUSB_TEST_BOARD_TRANSFER_BUFFER_SIZE) {

BulkUsb_DbgPrint(1, (“Transfer length > circular buffer\n”));

ntStatus = STATUS_INVALID_PARAMETER;

ExFreePool(rwContext);

goto BulkUsb_DispatchReadWrite_Exit;
}

if(totalLength == 0) {

BulkUsb_DbgPrint(1, (“Transfer data length = 0\n”));

ntStatus = STATUS_SUCCESS;

ExFreePool(rwContext);

goto BulkUsb_DispatchReadWrite_Exit;
}

urbFlags = USBD_SHORT_TRANSFER_OK;

virtualAddress = (ULONG_PTR) MmGetMdlVirtualAddress(Irp->MdlAddress);

if(read) {

urbFlags |= USBD_TRANSFER_DIRECTION_IN;
BulkUsb_DbgPrint(3, (“Read operation\n”));
}
else {

urbFlags |= USBD_TRANSFER_DIRECTION_OUT;
BulkUsb_DbgPrint(3, (“Write operation\n”));
}

//
// the transfer request is for totalLength.
// we can perform a max of BULKUSB_MAX_TRANSFER_SIZE
// in each stage.
//
if(totalLength > BULKUSB_MAX_TRANSFER_SIZE) {

stageLength = BULKUSB_MAX_TRANSFER_SIZE;
}
else {

stageLength = totalLength;
}

mdl = IoAllocateMdl((PVOID) virtualAddress,
totalLength,
FALSE,
FALSE,
NULL);

if(mdl == NULL) {

BulkUsb_DbgPrint(1, (“Failed to alloc mem for mdl\n”));

ntStatus = STATUS_INSUFFICIENT_RESOURCES;

ExFreePool(rwContext);

goto BulkUsb_DispatchReadWrite_Exit;
}

//
// map the portion of user-buffer described by an mdl to another mdl

IoBuildPartialMdl(Irp->MdlAddress,
mdl,
(PVOID) virtualAddress,
stageLength);

urb = ExAllocatePool(NonPagedPool,
sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER));

if(urb == NULL) {

BulkUsb_DbgPrint(1, (“Failed to alloc mem for urb\n”));

ntStatus = STATUS_INSUFFICIENT_RESOURCES;

ExFreePool(rwContext);
IoFreeMdl(mdl);

goto BulkUsb_DispatchReadWrite_Exit;
}

UsbBuildInterruptOrBulkTransferRequest(
urb,
sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
pipeInformation->PipeHandle,
NULL,
mdl,
stageLength,
urbFlags,
NULL);

//
// set BULKUSB_RW_CONTEXT parameters.

rwContext->Urb = urb;
rwContext->Mdl = mdl;
rwContext->Length = totalLength - stageLength;
rwContext->Numxfer = 0;
rwContext->VirtualAddress = virtualAddress + stageLength;
rwContext->DeviceExtension = deviceExtension;

//
// use the original read/write irp as an internal device control irp

nextStack = IoGetNextIrpStackLocation(Irp);
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
nextStack->Parameters.Others.Argument1 = (PVOID) urb;
nextStack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_INTERNAL_USB_SUBMIT_URB;

IoSetCompletionRoutine(Irp,
(PIO_COMPLETION_ROUTINE)BulkUsb_ReadWriteCompletion,
rwContext,
TRUE,
TRUE,
TRUE);

//
// since we return STATUS_PENDING call IoMarkIrpPending.
// This is the boiler plate code.
// This may cause extra overhead of an APC for the Irp completion
// but this is the correct thing to do.
//

IoMarkIrpPending(Irp);

BulkUsb_DbgPrint(3, (“BulkUsb_DispatchReadWrite::”));
BulkUsb_IoIncrement(deviceExtension);

ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject,
Irp);

if(!NT_SUCCESS(ntStatus)) {

BulkUsb_DbgPrint(1, (“IoCallDriver fails with status %X\n”, ntStatus));

//
// if the device was yanked out, then the pipeInformation
// field is invalid.
// similarly if the request was cancelled, then we need not
// invoked reset pipe/device.
//
if((ntStatus != STATUS_CANCELLED) &&
(ntStatus != STATUS_DEVICE_NOT_CONNECTED)) {

ntStatus = BulkUsb_ResetPipe(DeviceObject,
pipeInformation);

if(!NT_SUCCESS(ntStatus)) {

BulkUsb_DbgPrint(1, (“BulkUsb_ResetPipe failed\n”));

ntStatus = BulkUsb_ResetDevice(DeviceObject);
}
}
else {

BulkUsb_DbgPrint(3, ("ntStatus is STATUS_CANCELLED or "
“STATUS_DEVICE_NOT_CONNECTED\n”));
}
}

//
// we return STATUS_PENDING and not the status returned by the lower layer.
//
return STATUS_PENDING;

BulkUsb_DispatchReadWrite_Exit:

Irp->IoStatus.Status = ntStatus;
Irp->IoStatus.Information = 0;

IoCompleteRequest(Irp, IO_NO_INCREMENT);

BulkUsb_DbgPrint(3, (“BulkUsb_DispatchReadWrite - ends\n”));

return ntStatus;
}

NTSTATUS
BulkUsb_ReadWriteCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++

Routine Description:

This is the completion routine for reads/writes
If the irp completes with success, we check if we
need to recirculate this irp for another stage of
transfer. In this case return STATUS_MORE_PROCESSING_REQUIRED.
if the irp completes in error, free all memory allocs and
return the status.

Arguments:

DeviceObject - pointer to device object
Irp - I/O request packet
Context - context passed to the completion routine.

Return Value:

NT status value

–*/
{
ULONG stageLength;
NTSTATUS ntStatus;
PIO_STACK_LOCATION nextStack;
PBULKUSB_RW_CONTEXT rwContext;

//
// initialize variables
//
rwContext = (PBULKUSB_RW_CONTEXT) Context;
ntStatus = Irp->IoStatus.Status;

UNREFERENCED_PARAMETER(DeviceObject);

BulkUsb_DbgPrint(3, (“BulkUsb_ReadWriteCompletion - begins\n”));

//
// successfully performed a stageLength of transfer.
// check if we need to recirculate the irp.
//
if(NT_SUCCESS(ntStatus)) {

if(rwContext) {

rwContext->Numxfer +=
rwContext->Urb->UrbBulkOrInterruptTransfer.TransferBufferLength;

if(rwContext->Length) {

//
// another stage transfer
//
BulkUsb_DbgPrint(3, (“Another stage transfer…\n”));

if(rwContext->Length > BULKUSB_MAX_TRANSFER_SIZE) {

stageLength = BULKUSB_MAX_TRANSFER_SIZE;
}
else {

stageLength = rwContext->Length;
}

IoBuildPartialMdl(Irp->MdlAddress,
rwContext->Mdl,
(PVOID) rwContext->VirtualAddress,
stageLength);

//
// reinitialize the urb
//
rwContext->Urb->UrbBulkOrInterruptTransfer.TransferBufferLength
= stageLength;
rwContext->VirtualAddress += stageLength;
rwContext->Length -= stageLength;

nextStack = IoGetNextIrpStackLocation(Irp);
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
nextStack->Parameters.Others.Argument1 = rwContext->Urb;
nextStack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_INTERNAL_USB_SUBMIT_URB;

IoSetCompletionRoutine(Irp,
BulkUsb_ReadWriteCompletion,
rwContext,
TRUE,
TRUE,
TRUE);

IoCallDriver(rwContext->DeviceExtension->TopOfStackDeviceObject,
Irp);

return STATUS_MORE_PROCESSING_REQUIRED;
}
else {

//
// this is the last transfer
//

Irp->IoStatus.Information = rwContext->Numxfer;
}
}
}
else {

BulkUsb_DbgPrint(1, (“ReadWriteCompletion - failed with status = %X\n”, ntStatus));
}

if(rwContext) {

//
// dump rwContext
//
BulkUsb_DbgPrint(3, (“rwContext->Urb = %X\n”,
rwContext->Urb));
BulkUsb_DbgPrint(3, (“rwContext->Mdl = %X\n”,
rwContext->Mdl));
BulkUsb_DbgPrint(3, (“rwContext->Length = %d\n”,
rwContext->Length));
BulkUsb_DbgPrint(3, (“rwContext->Numxfer = %d\n”,
rwContext->Numxfer));
BulkUsb_DbgPrint(3, (“rwContext->VirtualAddress = %X\n”,
rwContext->VirtualAddress));
BulkUsb_DbgPrint(3, (“rwContext->DeviceExtension = %X\n”,
rwContext->DeviceExtension));

BulkUsb_DbgPrint(3, (“BulkUsb_ReadWriteCompletion::”));
BulkUsb_IoDecrement(rwContext->DeviceExtension);

ExFreePool(rwContext->Urb);
IoFreeMdl(rwContext->Mdl);
ExFreePool(rwContext);
}

BulkUsb_DbgPrint(3, (“BulkUsb_ReadWriteCompletion - ends\n”));

return ntStatus;
}

If you are still using DriverStudio, scrap what you have, and convert it to
KMDF. You will find that if you run Diver verifier on your driver, you will
find several bugs in DriverStudio code that were never fixed and now never
will be unless you fix them yourself. Have you run PreFast on your code? If
you compile it with Win 7 and open a WDK build environment that should
automagically run PreFast for you. Fix the errors and warnings it provides.

My first comment about your app is in regards to your use of an overlapped
structure. The “g” implies to me that it’s global, but using an overlapped
structure also implies asynchronous IO. Are you absolutely sure that you
will never have more than one IO request using that structure? If you cannot
absolutely guarantee that, then using a single global overlapped structure
is a mistake. If you send another read request while a prior one is pending,
you just stepped on the first structure and results are unpredictable. If
you can make a guarantee that no IO request will ever overlap with another
IO request then using a common overlapped structure may work.

Gary G. Little
H (952) 223-1349
C (952) 454-4629
xxxxx@comcast.net

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of zhonghong200@163.com
Sent: Saturday, August 14, 2010 5:03 AM
To: Windows System Software Devs Interest List
Subject: [ntdev] camera usb driver based on microsoft ddk’s bulkusb,but have
some question.

Hi:

I have built a bulk usb driver based on BulkUsb,and change the
BULKUSB_MAX_TRANSFER_SIZE=2014208 bytes. I am developing it for a bulk
communication with my camera device.

I have Implemented that driver for 2014208 bytes size.my driver usually
run well,but when the driver is timeout ,in this case,the driver return
tranfer size is zero.? who can tell me why?

in order to confirm my question,I reduce the send size of hardware , at
this time,the application program timeout everytime. and the driver return
tranfer size is zero bytes.for example,my application send a buffer to
device hardware,the size is 2014208 bytes,but the maxinum data of the device
hardware is less than 2014208,for example,is 1440254.at this time, my
application program receive zero bytes dada,but in my opinion, the size must
be 1440254.who can tell me why?

the third question : my application program use readfile function to read
data of usb pipe,but everytime it return False,and find GetLastError()
=ERROR_IO_PENDING,then use GetOverlappedResult ,find the transfer size is
right(=2014208).

the fouth question : some time when WAIT_TIMEOUT,and at this time ,the
transfer size is zero bytes.

who can tell me why? I am look forward to hearing from you .thank you very
much indeed.

stone

my application program is:

DWORD USB_Read(HANDLE handle, // Input
PVOID pData, // Output :image buff
DWORD dwLen, // Input :a frame image size
PDWORD pLength, // Output: receives the number of
bytes read
DWORD dwMilliseconds) // Input: the time of timeout
{

BOOL bResult;
DWORD nBytesRead;
OVERLAPPED gOverlapped;
DWORD dwResult;

dwResult = E_FALSE;

// set up overlapped structure fields
gOverlapped.Internal = 0;
gOverlapped.InternalHigh = 0;
gOverlapped.Offset = 0;
gOverlapped.OffsetHigh = 0;
gOverlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

if(pLength != NULL)
{
*pLength = 0;
}

// attempt an asynchronous read operation
bResult = ReadFile(handle,pData,dwLen,&nBytesRead,&gOverlapped);
if(!bResult)
{
// deal with the error code
switch (GetLastError())
{
case ERROR_HANDLE_EOF:
{
// we have reached the end of the file
// during the call to ReadFile
break;
}
case ERROR_IO_PENDING:
{
// asynchronous i/o is still in progress

switch(WaitForSingleObject(gOverlapped.hEvent, dwMilliseconds))
{
case WAIT_OBJECT_0:
// check on the results of the
asynchronous read
// and update the nBytesRead…
bResult =
GetOverlappedResult(handle, &gOverlapped,
&nBytesRead, FALSE);
if(bResult)
{
if(pLength != NULL)
*pLength =
nBytesRead;
dwResult = E_OK;
}
break;
case WAIT_TIMEOUT:
bResult =
GetOverlappedResult(handle, &gOverlapped,&nBytesRead, FALSE);
if(bResult)
{
if(pLength != NULL)
{
*pLength =
nBytesRead;
}
}
CancelIo(handle);
break;
default:
CancelIo(handle);
break;
}
break;
}
default:
CancelIo(handle);
break;
}
}
else
{
if(pLength != NULL)
*pLength = nBytesRead;
TRACE(" have data %d\n",nBytesRead);
dwResult = E_OK;
}

ResetEvent(gOverlapped.hEvent);
CloseHandle(gOverlapped.hEvent);
return dwResult;
}

my driver is based on ddk’s bulkusb,the Dispatch routine for read and write
is:

TSTATUS
BulkUsb_DispatchReadWrite(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++

Routine Description:

Dispatch routine for read and write.
This routine creates a BULKUSB_RW_CONTEXT for a read/write.
This read/write is performed in stages of BULKUSB_MAX_TRANSFER_SIZE.
once a stage of transfer is complete, then the irp is circulated again,
until the requested length of tranfer is performed.

Arguments:

DeviceObject - pointer to device object
Irp - I/O request packet

Return Value:

NT status value

–*/
{
PMDL mdl;
PURB urb;
ULONG totalLength;
ULONG stageLength;
ULONG urbFlags;
BOOLEAN read;
NTSTATUS ntStatus;
ULONG_PTR virtualAddress;
PFILE_OBJECT fileObject;
PDEVICE_EXTENSION deviceExtension;
PIO_STACK_LOCATION irpStack;
PIO_STACK_LOCATION nextStack;
PBULKUSB_RW_CONTEXT rwContext;
PUSBD_PIPE_INFORMATION pipeInformation;

//
// initialize variables
//

urb = NULL;
mdl = NULL;
rwContext = NULL;
totalLength = 0;
irpStack = IoGetCurrentIrpStackLocation(Irp);
fileObject = irpStack->FileObject;
read = (irpStack->MajorFunction == IRP_MJ_READ) ? TRUE : FALSE;
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;

BulkUsb_DbgPrint(3, (“BulkUsb_DispatchReadWrite - begins\n”));

if(deviceExtension->DeviceState != Working) {

BulkUsb_DbgPrint(1, (“Invalid device state\n”));

ntStatus = STATUS_INVALID_DEVICE_STATE;
goto BulkUsb_DispatchReadWrite_Exit;
}

//
// It is true that the client driver cancelled the selective suspend
// request in the dispatch routine for create Irps.
// But there is no guarantee that it has indeed completed.
// so wait on the NoIdleReqPendEvent and proceed only if this event
// is signalled.
//
BulkUsb_DbgPrint(3, (“Waiting on the IdleReqPendEvent\n”));

//
// make sure that the selective suspend request has been completed.
//

if(deviceExtension->SSEnable) {

KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent, //
Executive,
KernelMode,
FALSE,
NULL);
}

if(fileObject && fileObject->FsContext) {

pipeInformation = fileObject->FsContext;

if(UsbdPipeTypeBulk != pipeInformation->PipeType) {

BulkUsb_DbgPrint(1, (“Usbd pipe type is not bulk\n”));

ntStatus = STATUS_INVALID_HANDLE;
goto BulkUsb_DispatchReadWrite_Exit;
}
}
else {

BulkUsb_DbgPrint(1, (“Invalid handle\n”));

ntStatus = STATUS_INVALID_HANDLE;
goto BulkUsb_DispatchReadWrite_Exit;
}

rwContext = (PBULKUSB_RW_CONTEXT)
ExAllocatePool(NonPagedPool,
sizeof(BULKUSB_RW_CONTEXT));

if(rwContext == NULL) {

BulkUsb_DbgPrint(1, (“Failed to alloc mem for rwContext\n”));

ntStatus = STATUS_INSUFFICIENT_RESOURCES;
goto BulkUsb_DispatchReadWrite_Exit;
}

if(Irp->MdlAddress) {

totalLength = MmGetMdlByteCount(Irp->MdlAddress);
}

if(totalLength > BULKUSB_TEST_BOARD_TRANSFER_BUFFER_SIZE) {

BulkUsb_DbgPrint(1, (“Transfer length > circular buffer\n”));

ntStatus = STATUS_INVALID_PARAMETER;

ExFreePool(rwContext);

goto BulkUsb_DispatchReadWrite_Exit;
}

if(totalLength == 0) {

BulkUsb_DbgPrint(1, (“Transfer data length = 0\n”));

ntStatus = STATUS_SUCCESS;

ExFreePool(rwContext);

goto BulkUsb_DispatchReadWrite_Exit;
}

urbFlags = USBD_SHORT_TRANSFER_OK;

virtualAddress = (ULONG_PTR) MmGetMdlVirtualAddress(Irp->MdlAddress);

if(read) {

urbFlags |= USBD_TRANSFER_DIRECTION_IN;
BulkUsb_DbgPrint(3, (“Read operation\n”));
}
else {

urbFlags |= USBD_TRANSFER_DIRECTION_OUT;
BulkUsb_DbgPrint(3, (“Write operation\n”));
}

//
// the transfer request is for totalLength.
// we can perform a max of BULKUSB_MAX_TRANSFER_SIZE
// in each stage.
//
if(totalLength > BULKUSB_MAX_TRANSFER_SIZE) {

stageLength = BULKUSB_MAX_TRANSFER_SIZE;
}
else {

stageLength = totalLength;
}

mdl = IoAllocateMdl((PVOID) virtualAddress,
totalLength,
FALSE,
FALSE,
NULL);

if(mdl == NULL) {

BulkUsb_DbgPrint(1, (“Failed to alloc mem for mdl\n”));

ntStatus = STATUS_INSUFFICIENT_RESOURCES;

ExFreePool(rwContext);

goto BulkUsb_DispatchReadWrite_Exit;
}

//
// map the portion of user-buffer described by an mdl to another mdl

IoBuildPartialMdl(Irp->MdlAddress,
mdl,
(PVOID) virtualAddress,
stageLength);

urb = ExAllocatePool(NonPagedPool,
sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER));

if(urb == NULL) {

BulkUsb_DbgPrint(1, (“Failed to alloc mem for urb\n”));

ntStatus = STATUS_INSUFFICIENT_RESOURCES;

ExFreePool(rwContext);
IoFreeMdl(mdl);

goto BulkUsb_DispatchReadWrite_Exit;
}

UsbBuildInterruptOrBulkTransferRequest(
urb,
sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
pipeInformation->PipeHandle,
NULL,
mdl,
stageLength,
urbFlags,
NULL);

//
// set BULKUSB_RW_CONTEXT parameters.

rwContext->Urb = urb;
rwContext->Mdl = mdl;
rwContext->Length = totalLength - stageLength;
rwContext->Numxfer = 0;
rwContext->VirtualAddress = virtualAddress + stageLength;
rwContext->DeviceExtension = deviceExtension;

//
// use the original read/write irp as an internal device control irp

nextStack = IoGetNextIrpStackLocation(Irp);
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
nextStack->Parameters.Others.Argument1 = (PVOID) urb;
nextStack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_INTERNAL_USB_SUBMIT_URB;

IoSetCompletionRoutine(Irp,

(PIO_COMPLETION_ROUTINE)BulkUsb_ReadWriteCompletion,
rwContext,
TRUE,
TRUE,
TRUE);

//
// since we return STATUS_PENDING call IoMarkIrpPending.
// This is the boiler plate code.
// This may cause extra overhead of an APC for the Irp completion
// but this is the correct thing to do.
//

IoMarkIrpPending(Irp);

BulkUsb_DbgPrint(3, (“BulkUsb_DispatchReadWrite::”));
BulkUsb_IoIncrement(deviceExtension);

ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject,
Irp);

if(!NT_SUCCESS(ntStatus)) {

BulkUsb_DbgPrint(1, (“IoCallDriver fails with status %X\n”,
ntStatus));

//
// if the device was yanked out, then the pipeInformation
// field is invalid.
// similarly if the request was cancelled, then we need not
// invoked reset pipe/device.
//
if((ntStatus != STATUS_CANCELLED) &&
(ntStatus != STATUS_DEVICE_NOT_CONNECTED)) {

ntStatus = BulkUsb_ResetPipe(DeviceObject,
pipeInformation);

if(!NT_SUCCESS(ntStatus)) {

BulkUsb_DbgPrint(1, (“BulkUsb_ResetPipe failed\n”));

ntStatus = BulkUsb_ResetDevice(DeviceObject);
}
}
else {

BulkUsb_DbgPrint(3, ("ntStatus is STATUS_CANCELLED or "
“STATUS_DEVICE_NOT_CONNECTED\n”));
}
}

//
// we return STATUS_PENDING and not the status returned by the lower
layer.
//
return STATUS_PENDING;

BulkUsb_DispatchReadWrite_Exit:

Irp->IoStatus.Status = ntStatus;
Irp->IoStatus.Information = 0;

IoCompleteRequest(Irp, IO_NO_INCREMENT);

BulkUsb_DbgPrint(3, (“BulkUsb_DispatchReadWrite - ends\n”));

return ntStatus;
}

NTSTATUS
BulkUsb_ReadWriteCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++

Routine Description:

This is the completion routine for reads/writes
If the irp completes with success, we check if we
need to recirculate this irp for another stage of
transfer. In this case return STATUS_MORE_PROCESSING_REQUIRED.
if the irp completes in error, free all memory allocs and
return the status.

Arguments:

DeviceObject - pointer to device object
Irp - I/O request packet
Context - context passed to the completion routine.

Return Value:

NT status value

–*/
{
ULONG stageLength;
NTSTATUS ntStatus;
PIO_STACK_LOCATION nextStack;
PBULKUSB_RW_CONTEXT rwContext;

//
// initialize variables
//
rwContext = (PBULKUSB_RW_CONTEXT) Context;
ntStatus = Irp->IoStatus.Status;

UNREFERENCED_PARAMETER(DeviceObject);

BulkUsb_DbgPrint(3, (“BulkUsb_ReadWriteCompletion - begins\n”));

//
// successfully performed a stageLength of transfer.
// check if we need to recirculate the irp.
//
if(NT_SUCCESS(ntStatus)) {

if(rwContext) {

rwContext->Numxfer +=

rwContext->Urb->UrbBulkOrInterruptTransfer.TransferBufferLength;

if(rwContext->Length) {

//
// another stage transfer
//
BulkUsb_DbgPrint(3, (“Another stage transfer…\n”));

if(rwContext->Length > BULKUSB_MAX_TRANSFER_SIZE) {

stageLength = BULKUSB_MAX_TRANSFER_SIZE;
}
else {

stageLength = rwContext->Length;
}

IoBuildPartialMdl(Irp->MdlAddress,
rwContext->Mdl,
(PVOID) rwContext->VirtualAddress,
stageLength);

//
// reinitialize the urb
//

rwContext->Urb->UrbBulkOrInterruptTransfer.TransferBufferLength

stageLength;
rwContext->VirtualAddress += stageLength;
rwContext->Length -= stageLength;

nextStack = IoGetNextIrpStackLocation(Irp);
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
nextStack->Parameters.Others.Argument1 = rwContext->Urb;
nextStack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_INTERNAL_USB_SUBMIT_URB;

IoSetCompletionRoutine(Irp,
BulkUsb_ReadWriteCompletion,
rwContext,
TRUE,
TRUE,
TRUE);

IoCallDriver(rwContext->DeviceExtension->TopOfStackDeviceObject,
Irp);

return STATUS_MORE_PROCESSING_REQUIRED;
}
else {

//
// this is the last transfer
//

Irp->IoStatus.Information = rwContext->Numxfer;
}
}
}
else {

BulkUsb_DbgPrint(1, (“ReadWriteCompletion - failed with status =
%X\n”, ntStatus));
}

if(rwContext) {

//
// dump rwContext
//
BulkUsb_DbgPrint(3, (“rwContext->Urb = %X\n”,
rwContext->Urb));
BulkUsb_DbgPrint(3, (“rwContext->Mdl = %X\n”,
rwContext->Mdl));
BulkUsb_DbgPrint(3, (“rwContext->Length = %d\n”,
rwContext->Length));
BulkUsb_DbgPrint(3, (“rwContext->Numxfer = %d\n”,
rwContext->Numxfer));
BulkUsb_DbgPrint(3, (“rwContext->VirtualAddress = %X\n”,
rwContext->VirtualAddress));
BulkUsb_DbgPrint(3, (“rwContext->DeviceExtension = %X\n”,
rwContext->DeviceExtension));

BulkUsb_DbgPrint(3, (“BulkUsb_ReadWriteCompletion::”));
BulkUsb_IoDecrement(rwContext->DeviceExtension);

ExFreePool(rwContext->Urb);
IoFreeMdl(rwContext->Mdl);
ExFreePool(rwContext);
}

BulkUsb_DbgPrint(3, (“BulkUsb_ReadWriteCompletion - ends\n”));

return ntStatus;
}


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

to Gary Little
thank you for reply,and I am not use driverstudio,I only use microsoft WDM ddk,and based on the ddk’s bulkusb sample. in your answer, you say I have set a grobal overlaped structure,but in my opinion,it is local overlaped. and in my application program,I have only one io request,because I am wait the irp return ,and then send another irp. who can help me?
thank you everybody.

who can give me some advice. thank you

You’ve already got the advice. Don’t use BulkUsb based driver and write
WDF driver, instead. Nobody can remember all the bugs which have to be
fixed to make BulkUsb code reliable. I had to rewrite probably half of
the code and take the decision to use this code as the worst one in my
career. No, I won’t help you with this code because don’t even want to
recall it.

Michal Vodicka
UPEK, Inc.
[xxxxx@upek.com, http://www.upek.com]

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of
zhonghong200@163.com
Sent: Wednesday, August 18, 2010 3:09 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] camera usb driver based on microsoft
ddk’s bulkusb,but have some question.

who can give me some advice. thank you


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

I am a beginner in WDF ,I send the ventro request use UsbBuildVendorRequest and CallUSBD,but in WDF ,what function I can use,thank you.

zhonghong200@163.com wrote:

I have Implemented that driver for 2014208 bytes size.my driver usually run
well,but when the driver is timeout ,in this case,the driver return tranfer size is zero.? who can tell me why?

in order to confirm my question,I reduce the send size of hardware , at this time,the application program timeout everytime. and the driver return tranfer size is zero bytes.for example,my application send a buffer to device hardware,the size is 2014208 bytes,but the maxinum data of the device hardware is less than 2014208,for example,is 1440254.at this time, my application program receive zero bytes dada,but in my opinion, the size must be 1440254.who can tell me why?

Is your device actually sending a short packet for the last packet of
the transfer? When you issue a bulk read for 2,014,208 bytes, that
request will not complete until either all 2,014,208 bytes have been
transferred, or the device sends back a packet of less than 512 bytes.
The FX2, for example, requires special code to force a short packet to
be transferred. The device prefers to hold on to the short buffer until
it fills.

the third question : my application program use readfile function to read data of usb pipe,but everytime it return False,and find GetLastError() =ERROR_IO_PENDING,then use GetOverlappedResult ,find the transfer size is right(=2014208).

And that’s OK, right? GetOverlappedResult will block until the request
completes.


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

to Tim Roberts
thank you for you answer.
in my camera device ,it send each packet with 512 bytes,and I am not send a short packet for the last packet of the transfer.when I issue a bulk read for 2014204 bytes,if the data loss in the transfer process,at this time ,timeout.my question is why i can not receive any data but zero bytes. and in linux system,it can return less than 2014208 bytes.

thank you ,every body

zhonghong200@163.com wrote:

to Tim Roberts
thank you for you answer.
in my camera device ,it send each packet with 512 bytes,and I am not send a short packet for the last packet of the transfer.

It should do so. That’s a design flaw in the device.

when I issue a bulk read for 2014204 bytes,if the data loss in the transfer process,at this time ,timeout.my question is why i can not receive any data but zero bytes. and in linux system,it can return less than 2014208 bytes.

Windows can do the same. Where are you seeing that zero bytes are
returned? How are you handling the timeout? How (exactly) are you
aborting the request? Can you post your completion routine?


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