USB Read Problem

Hi,
I have a problem with USB. I can’t read from the device. Once I send the IRP, I do not get any response from the underlying device. The IRP completion routine never gets called.

I checked with the USBlyzer and it clearly states that the IRP gets stuck at usbhci after passing through usbhub.

I have a windows server 2003 SDK. It contains the BulkUsb sample. That sample works perfectly. Here is the code for it: -

fdoData->BulkUrb = (PURB)ExAllocatePoolWithTag( NonPagedPool, (SIZE_T)sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), USBDRV_POOL_TAG );
RtlZeroMemory( fdoData->BulkUrb, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER) );

fdoData->ReadBuffer = ExAllocatePoolWithTag( NonPagedPool, 64, USBDRV_POOL_TAG );
UsbBuildInterruptOrBulkTransferRequest( fdoData->BulkUrb,
(USHORT)sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
fdoData->InPipe->PipeHandle,
fdoData->ReadBuffer,
NULL,
64,
USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
NULL );

// Allocate IRP
fdoData->BulkIrp = IoAllocateIrp( fdoData->TopOfStackDeviceObject->StackSize + 1, FALSE );

// Set URB in the IRP
IoSetNextIrpStackLocation( fdoData->BulkIrp );
IoGetCurrentIrpStackLocation( fdoData->BulkIrp )->DeviceObject = DeviceObject;

// Get next IRP stack location
nextStack = IoGetNextIrpStackLocation( fdoData->BulkIrp );

// Setup next stack parameters
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
nextStack->Parameters.Others.Argument1 = fdoData->BulkUrb;
nextStack->Parameters.Others.Argument2 = NULL;

// Set the IRP completion routine
IoSetCompletionRoutine( fdoData->BulkIrp,
(PIO_COMPLETION_ROUTINE)IsoReadIrpCompletionRoutine,
NULL,
TRUE,
TRUE,
TRUE );

// Pass down the IRP down to the next lower device
IoCallDriver( fdoData->TopOfStackDeviceObject, fdoData->BulkIrp );

Also, I know that I should use KDMF but i have to use WDM.

Any help will be highly appreciated.

Regards.

xxxxx@prescott-instruments.com wrote:

I have a problem with USB. I can’t read from the device. Once I send the IRP, I do not get any response from the underlying device. The IRP completion routine never gets called.

Could it be IoCallDriver is returning immediately with an error? That’s
where parameter errors are diagnosed.

I checked with the USBlyzer and it clearly states that the IRP gets stuck at usbhci after passing through usbhub.

I have a windows server 2003 SDK. It contains the BulkUsb sample. That sample works perfectly. Here is the code for it: -

Why would you show us code that works, instead of showing us the code
that fails?


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

Thanks for the reply.

Could it be IoCallDriver is returning immediately with an error? That’s where parameter errors are diagnosed.

IoCallDriver just returns STATUS_PENDING. No error thats the problem.

Why would you show us code that works, instead of showing us the code that fails?

Sorry for that. Actually, i.e. the code that does not work. Typing mistake.

One more thing, I just want to add. Before doing the read operation on the device, i cancelled the Idle request and put the device power to D0 state. Also, the device does not support wait wake.

xxxxx@prescott-instruments.com wrote:

Sorry for that. Actually, i.e. the code that does not work. Typing mistake.

One more thing, I just want to add. Before doing the read operation on the device, i cancelled the Idle request and put the device power to D0 state. Also, the device does not support wait wake.

How did you do that? Did you get a notification that you had moved to D0?

This line is unnecessary, and possibly dangerous:

IoSetNextIrpStackLocation( fdoData->BulkIrp );


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

Have you run this under the driver verifier?

Hi,
I have a problem with USB. I can’t read from the device. Once I send the
IRP, I do not get any response from the underlying device. The IRP
completion routine never gets called.

I checked with the USBlyzer and it clearly states that the IRP gets stuck
at usbhci after passing through usbhub.

I have a windows server 2003 SDK. It contains the BulkUsb sample. That
sample works perfectly. Here is the code for it: -

fdoData->BulkUrb = (PURB)ExAllocatePoolWithTag( NonPagedPool,
(SIZE_T)sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER), USBDRV_POOL_TAG );
RtlZeroMemory( fdoData->BulkUrb, sizeof(struct
_URB_BULK_OR_INTERRUPT_TRANSFER) );

WTF is fdoData? NEVER give a code sample in which the variable
declarations do not appear! We are left to guess what fdoData might be,
but in the absence of seeing its declaration and initialization, we have
no idea what is going on here!

And, I might add, there may be many different places the declaration of
fdoData might appear, and only one, or at most two, of them would be
correct usage.

I think you missed an absolutely critical test here. How can you use the
result of ExAllocatePoolWithTag without knowing if the pointer is valid?
Where do deal with completing the incoming IRP with
STATUS_INSUFFICIENT_RESOURCES? You have made this error fairly
consistently, failing to test the return values of DDI calls that can
fail. This is unacceptable practice.

fdoData->ReadBuffer = ExAllocatePoolWithTag( NonPagedPool, 64,
USBDRV_POOL_TAG );

Another case of failing to test the result

UsbBuildInterruptOrBulkTransferRequest( fdoData->BulkUrb,
(USHORT)sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
fdoData->InPipe->PipeHandle,
fdoData->ReadBuffer,
NULL,
64,
USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
NULL );

// Allocate IRP
fdoData->BulkIrp = IoAllocateIrp(
fdoData->TopOfStackDeviceObject->StackSize + 1, FALSE );

Another case of failing to check the return value. RTFM. If the
documentation says a function can return a NULL pointer, then you MUST,
REPEAT MUST, check for a valid return. Failure to do this will result in
a BSOD. Note that you are responsible for freeing up any allocations that
you have already done.

// Set URB in the IRP
IoSetNextIrpStackLocation( fdoData->BulkIrp );
IoGetCurrentIrpStackLocation( fdoData->BulkIrp )->DeviceObject =
DeviceObject;

I think you should use a few more variables here. Generally, if you
writesomething of the form f(…)->field, you had better be certain that
the function f will ALWAYS, WITHOUT EXCEPTION, return a valid pointer. My
memory is that you cannot execute IoGetCurrenIrpStackLocation on a
newly-allocated IRP, and the documentation suggests that this is rarely
used. IoGetNextIrpStackLocation should be used on a newly-allocated IRP.

// Get next IRP stack location
nextStack = IoGetNextIrpStackLocation( fdoData->BulkIrp );

// Setup next stack parameters
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
nextStack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_INTERNAL_USB_SUBMIT_URB;
nextStack->Parameters.Others.Argument1 = fdoData->BulkUrb;
nextStack->Parameters.Others.Argument2 = NULL;

// Set the IRP completion routine
IoSetCompletionRoutine( fdoData->BulkIrp,
(PIO_COMPLETION_ROUTINE)IsoReadIrpCompletionRoutine,
NULL,
TRUE,
TRUE,
TRUE );

// Pass down the IRP down to the next lower device
> IoCallDriver( fdoData->TopOfStackDeviceObject, fdoData->BulkIrp );

You said at some point this returns STATUS_PENDING, and how could you
possibly know this? You do not check the value, you don’t even store it
or process it. So what happens when the driver below you returns an error
code? Note that if the result is not STATUS_PENDING, or fails the
NT_ERROR predicate, you will have to engage in “graceful recovery” here.

Also, you have given this example completely out of context. When is this
code called? Where do we see the function definition? Answer: we don’t
know fro this piece of code where it is executed. We don’t see what its
caller expects.

One thing you must internalize is the notion of “graceful recovery”. This
means that if anything goes wrong, the incoming IRP is completed with a
proper error status, and NOTHING you allocated along the way remains
allocated. It also means that if this code is in the dequeue routine,
then it must ensure that the next IRP in the queue is dequeued, or your
driver will go into a persistent vegetative state. And in your completion
routine, ditto; if the IRP you sent down failed, you have to clean up
everything, and complete the original IRP.

Also, I know that I should use KDMF but i have to use WDM.

Any help will be highly appreciated.

Regards.


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

Hi Tim,

> One more thing, I just want to add. Before doing the read operation on the
device, i cancelled the Idle request and put the device power to D0 state. Also,
the device does not support wait wake.

How did you do that? Did you get a notification that you had moved to D0?

In the IRP_MJ_CREATE dispatch routine, I cancelled the idle request Irp which I submitted it to underlying device object when the device was idle. In the Idle Irp completion routine, I changed the device power state to D0.

I created a dialog box with a button on it. Whenever user clicks the button, it sends a device I/O control to the device object. The device object creates an Irp with associated non-paged buffer and bulk IN endpoint pipe handle. Then after building the URB, I send the request to the underlying device object.

Afterwards, IoCallDriver just returns STATUS_PENDING. No response for Irp completion.

I have uploaded the etl file on the rapidshare for your reference.

http://rapidshare.com/files/1841611726/usbtrace.etl

Any help will be highly appreciated.

Regards.

> Hi Tim,

>> One more thing, I just want to add. Before doing the read operation on
>> the
device, i cancelled the Idle request and put the device power to D0 state.
Also,
the device does not support wait wake.

> How did you do that? Did you get a notification that you had moved to
> D0?

In the IRP_MJ_CREATE dispatch routine, I cancelled the idle request Irp
which I submitted it to underlying device object when the device was idle.
In the Idle Irp completion routine, I changed the device power state to
D0.

Note that when you say “cancel the IRP” you have no idea if it is canceled
or not. In principle, an IRP which has been sent down can be
not-yet-arrived, active, or already-completed, among many ossibilities.
There are so many race coditions here that it is very scary. I would have
thought that what you would request that power management power the device
up. I would have thought that you would then wait for the IRP_MJ_POWER
telling you that it is in the D0 state. I’m a bit suspicious about
manipulating power state without the power manager being involved. Since
the USB Bus Driver needs to know what the power state of each device iso
it can deal with global power state. Manipulating this outside the
knowledge of the Power Manager sounds dangerous, particularly in light of
the complexity of PnP/Power interactions that WDF handles. It is also not
clear why you send an explicit power-down IRP and hold onto it; I would
have thought the right way to do this would be to request the Power
Manager put the device in the reduced power state, and complete that IRP
when you get the _POWER IRP you would complete that IRP with an apprpriate
indication of success or failure.

I have always thought of power management as an incomprehensible “magic
black box”, because the WDM documentation was not followed by any WDM
example code. One of the major strengths of WDF is to have finally gotten
this right. And while it is still a magic black box, you should not be
attempting to bypass it. I have not looked at te WDF documentation in
detail, but others have and I would expect there to be a documented,
supported technique for requesting a power-state change that someone can
tell you. But to me, your design sounds
suspect-to-possibly-worst-possible design.

I created a dialog box with a button on it. Whenever user clicks the
button, it sends a device I/O control to the device object. The device
object creates an Irp with associated non-paged buffer and bulk IN
endpoint pipe handle. Then after building the URB, I send the request to
the underlying device object.

Afterwards, IoCallDriver just returns STATUS_PENDING. No response for Irp
completion.

I have uploaded the etl file on the rapidshare for your reference.

http://rapidshare.com/files/1841611726/usbtrace.etl

Any help will be highly appreciated.

Regards.


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

This is how I cancel the Idle Irp which I already sent it to the underlying device. Also, PFDODATA pointer is just the device extension only.

VOID
CancelDeviceSuspend(
__in PFDO_DATA fdoData )
{
PIRP Irp;
KIRQL oldIrql;

FuncEntry();

// Acquire the spin lock
KeAcquireSpinLock( &(fdoData->IdleStateLock), &oldIrql );

if( !CanDeviceSuspend( fdoData ) )
{
USB_DBG( Trace, Device, “Device is not Idle” );

Irp = (PIRP)InterlockedExchangePointer( &(fdoData->PendingIdleIrp), NULL );
}

// Release the spin lock
KeReleaseSpinLock( &(fdoData->IdleStateLock), oldIrql );

if( Irp )
{
// This routine has the irp pointer.
// It is safe to call IoCancelIrp because we know that
// the compleiton routine will not free this irp unless…
if( IoCancelIrp( Irp ) )
{
USB_DBG( Trace, Device, “IoCancelIrp returns TRUE” );
}
else
{
USB_DBG( Trace, Device, “IoCancelIrp returns FALSE” );
}

// We decrement the FreeIdleIrpCount from 2 to 1.
// If completion routine runs ahead of us, then this routine
// decrements the FreeIdleIrpCount from 1 to 0 and hence shall
// free the irp.
if( InterlockedDecrement( &(fdoData->FreeIdleIrpCount) ) == 0 )
{
// Free the allocated Idle Irp
IoFreeIrp( Irp );

// Set the Idle pending request event to signaled state
KeSetEvent( &(fdoData->NoIdleRequestPendingEvent), IO_NO_INCREMENT, FALSE );
}
}

FuncExit();
}

This is the Idle Irp Completion routine.

NTSTATUS
IdleNotificationRequestComplete(
__in PDEVICE_OBJECT DeviceObject,
__in PIRP Irp,
__in_xcount_opt(“varies”) PVOID Context )
{
NTSTATUS status;
PFDO_DATA fdoData;
POWER_STATE powerState;
PIRP idleIrp;
KIRQL oldIrql;
PUSB_IDLE_CALLBACK_INFO idleCallbackInfo;

FuncEntry();

fdoData = (PFDO_DATA)Context;

// Check the Irp completion status
if( !NT_SUCCESS( Irp->IoStatus.Status ) && Irp->IoStatus.Status != STATUS_NOT_SUPPORTED )
{
if( (fdoData->DevicePowerState != PowerDeviceD0) && (Irp->IoStatus.Status != STATUS_POWER_STATE_INVALID) )
{
// Send the power request for state: PowerDeviceD0
powerState.DeviceState = PowerDeviceD0;
status = PoRequestPowerIrp( fdoData->PhysicalDeviceObject,
IRP_MN_SET_POWER,
powerState,
(PREQUEST_POWER_COMPLETE)IdlePoIrpAsyncCompletionRoutine,
NULL,
NULL );

if( !NT_SUCCESS( status ) )
{
USB_DBG( Error, Device, “Error in setting device Power Irp: %X”, status );
}
}
}

// Acquire the spin lock
KeAcquireSpinLock( &(fdoData->IdleStateLock), &oldIrql );

idleIrp = InterlockedExchangePointer( &(fdoData->PendingIdleIrp), NULL );
idleCallbackInfo = InterlockedExchangePointer( &(fdoData->IdleCallbackInfo), NULL );

// Free the memory allocated for idle callback info
ExFreePool( idleCallbackInfo );

// Release the spin lock
KeReleaseSpinLock( &(fdoData->IdleStateLock), oldIrql );

if( idleIrp )
{
// Free the allocated Idle Irp
IoFreeIrp( idleIrp );

// Set the Idle pending request event to signaled state
KeSetEvent( &(fdoData->NoIdleRequestPendingEvent), IO_NO_INCREMENT, FALSE );
}
else
{
// The CancelDeviceSuspend routine has grabbed the Irp from the device
// extension. Now the last one to decrement the FreeIdleIrpCount should
// free the irp.
if( InterlockedDecrement( &(fdoData->FreeIdleIrpCount) ) == 0 )
{
// Free the allocated Idle Irp
IoFreeIrp( idleIrp );

// Set the Idle pending request event to signaled state
KeSetEvent( &(fdoData->NoIdleRequestPendingEvent), IO_NO_INCREMENT, FALSE );
}
}

if( fdoData->SSEnable )
{
// Start the IDLE timer
StartIdleTimer( fdoData );
}

FuncExit();

return STATUS_MORE_PROCESSING_REQUIRED;
}

Well, it is old BulkUsb sample implementation and it is incorrect. Read the rules about cancelling SS. Once the callback was called and the device powered down, you have to send D0 IRP down the stack to awake it.

Creating correct SS implementation is real challenge. BulkUsb sample implementation is wrong in so many aspects that you have to rewrite is almost completely. My advice: forgot about BulkUsb sample and use WDF, instead. It will be less work. If your device is simple enough, you can use existing WinUsb driver and in this case everything you need to do is to write INF for your device. And application using WinUsb interface, of course.

BTW, from this thread I’m not sure your current problem is related to SS. You should use hardware USB analyzer to see what happens on the bus.

Michal

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:bounce-524600-
xxxxx@lists.osr.com] On Behalf Of xxxxx@prescott-instruments.com
Sent: Thursday, January 24, 2013 11:40 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] USB Read Problem

This is how I cancel the Idle Irp which I already sent it to the underlying device.
Also, PFDODATA pointer is just the device extension only.

VOID
CancelDeviceSuspend(
__in PFDO_DATA fdoData )
{
PIRP Irp;
KIRQL oldIrql;

FuncEntry();

// Acquire the spin lock
KeAcquireSpinLock( &(fdoData->IdleStateLock), &oldIrql );

if( !CanDeviceSuspend( fdoData ) )
{
USB_DBG( Trace, Device, “Device is not Idle” );

Irp = (PIRP)InterlockedExchangePointer( &(fdoData-
>PendingIdleIrp), NULL );
}

// Release the spin lock
KeReleaseSpinLock( &(fdoData->IdleStateLock), oldIrql );

if( Irp )
{
// This routine has the irp pointer.
// It is safe to call IoCancelIrp because we know that
// the compleiton routine will not free this irp unless…
if( IoCancelIrp( Irp ) )
{
USB_DBG( Trace, Device, “IoCancelIrp returns TRUE” );
}
else
{
USB_DBG( Trace, Device, “IoCancelIrp returns FALSE”
);
}

// We decrement the FreeIdleIrpCount from 2 to 1.
// If completion routine runs ahead of us, then this routine
// decrements the FreeIdleIrpCount from 1 to 0 and hence shall
// free the irp.
if( InterlockedDecrement( &(fdoData->FreeIdleIrpCount) ) == 0
)
{
// Free the allocated Idle Irp
IoFreeIrp( Irp );

// Set the Idle pending request event to signaled state
KeSetEvent( &(fdoData->NoIdleRequestPendingEvent),
IO_NO_INCREMENT, FALSE );
}
}

FuncExit();
}

This is the Idle Irp Completion routine.

NTSTATUS
IdleNotificationRequestComplete(
__in PDEVICE_OBJECT DeviceObject,
__in PIRP Irp,
__in_xcount_opt(“varies”) PVOID Context )
{
NTSTATUS status;
PFDO_DATA fdoData;
POWER_STATE powerState;
PIRP idleIrp;
KIRQL oldIrql;
PUSB_IDLE_CALLBACK_INFO idleCallbackInfo;

FuncEntry();

fdoData = (PFDO_DATA)Context;

// Check the Irp completion status
if( !NT_SUCCESS( Irp->IoStatus.Status ) && Irp->IoStatus.Status !=
STATUS_NOT_SUPPORTED )
{
if( (fdoData->DevicePowerState != PowerDeviceD0) && (Irp-
>IoStatus.Status != STATUS_POWER_STATE_INVALID) )
{
// Send the power request for state: PowerDeviceD0
powerState.DeviceState = PowerDeviceD0;
status = PoRequestPowerIrp( fdoData-
>PhysicalDeviceObject,

IRP_MN_SET_POWER,

powerState,

(PREQUEST_POWER_COMPLETE)IdlePoIrpAsyncCompletionRoutine,

NULL,

NULL );

if( !NT_SUCCESS( status ) )
{
USB_DBG( Error, Device, “Error in setting
device Power Irp: %X”, status );
}
}
}

// Acquire the spin lock
KeAcquireSpinLock( &(fdoData->IdleStateLock), &oldIrql );

idleIrp = InterlockedExchangePointer( &(fdoData->PendingIdleIrp),
NULL );
idleCallbackInfo = InterlockedExchangePointer( &(fdoData-
>IdleCallbackInfo), NULL );

// Free the memory allocated for idle callback info
ExFreePool( idleCallbackInfo );

// Release the spin lock
KeReleaseSpinLock( &(fdoData->IdleStateLock), oldIrql );

if( idleIrp )
{
// Free the allocated Idle Irp
IoFreeIrp( idleIrp );

// Set the Idle pending request event to signaled state
KeSetEvent( &(fdoData->NoIdleRequestPendingEvent),
IO_NO_INCREMENT, FALSE );
}
else
{
// The CancelDeviceSuspend routine has grabbed the Irp from
the device
// extension. Now the last one to decrement the
FreeIdleIrpCount should
// free the irp.
if( InterlockedDecrement( &(fdoData->FreeIdleIrpCount) ) == 0
)
{
// Free the allocated Idle Irp
IoFreeIrp( idleIrp );

// Set the Idle pending request event to signaled state
KeSetEvent( &(fdoData->NoIdleRequestPendingEvent),
IO_NO_INCREMENT, FALSE );
}
}

if( fdoData->SSEnable )
{
// Start the IDLE timer
StartIdleTimer( fdoData );
}

FuncExit();

return STATUS_MORE_PROCESSING_REQUIRED;
}


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

NOTE: The information in this message is intended for the personal and confidential use of the designated recipient(s) named above. To the extent the recipient(s) is/are bound by a non-disclosure agreement, or other agreement that contains an obligation of confidentiality, with AuthenTec, then this message and/or any attachments shall be considered confidential information and subject to the confidentiality terms of that agreement. If the reader of this message is not the intended recipient named above, you are notified that you have received this document in error, and any review, dissemination, distribution or copying of this message is strictly prohibited. If you have received this document in error, please delete the original message and notify the sender immediately.
Thank You!
AuthenTec, Inc. http://www.authentec.com/