Hi all
Thanks again, the last few comments have gone over my head I’m afraid… I have reviewed our SendAwaitUrb code and with the help of the msdn cheat sheets, reworked the function. It seems to work fine but if anyone has any further comments, I’d be pleased to hear them.
Sean
typedef enum {
IRPLOCK_CANCELABLE,
IRPLOCK_CANCEL_STARTED,
IRPLOCK_CANCEL_COMPLETE,
IRPLOCK_COMPLETED
} IRPLOCK;
NTSTATUS SendAwaitUrbOnComplete(PDEVICE_OBJECT pdo, PIRP Irp, PVOID pev)
{
PLONG lock;
lock = (PLONG) pev;
if (InterlockedExchange((PVOID)&lock, IRPLOCK_COMPLETED) == IRPLOCK_CANCEL_STARTED) {
//
// Main line code has got the control of the IRP. It will
// now take the responsibility of completing the IRP.
// Therefore…
return STATUS_MORE_PROCESSING_REQUIRED;
}
return STATUS_CONTINUE_COMPLETION ;
}
NTSTATUS SendAwaitUrb(IN PDEVICE_OBJECT LowerDeviceObject, PURB urb)
{
KEVENT event;
IO_STATUS_BLOCK iostatus={0};
PIRP Irp;
PIO_STACK_LOCATION stack;
NTSTATUS ntStatus;
IRPLOCK lock = IRPLOCK_CANCELABLE;;
KeInitializeEvent(&event, NotificationEvent, FALSE);
Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_USB_SUBMIT_URB, LowerDeviceObject, NULL, 0, NULL, 0, TRUE, &event, &iostatus);
if (!Irp)
{
ser_string(“Unable to allocate IRP for sending URB\n”);
return STATUS_INSUFFICIENT_RESOURCES;
}
IoSetCompletionRoutine(Irp, SendAwaitUrbOnComplete, (PVOID) &event, TRUE, TRUE, TRUE);
stack = IoGetNextIrpStackLocation(Irp);
ASSERT(stack != NULL);
stack->Parameters.Others.Argument1 = (PVOID) urb;
ntStatus = IoCallDriver(LowerDeviceObject, Irp);
if(!NT_SUCCESS(ntStatus))
{
dlDbgPrint(FUNCTION", IoCallDriver failed ntStatus %lx, iostatus.Status %lx, urb->UrbHeader.Status %lx\r\n",ntStatus,iostatus.Status,urb->UrbHeader.Status);
}
if (ntStatus == STATUS_PENDING)
{
LARGE_INTEGER Timeout;
Timeout.QuadPart = -1 * 10000000;
dlDbgPrint(FUNCTION", IoCallDriver returned STATUS_PENDING\r\n");
ASSERT_KEWAIT_IRQL(Timeout.QuadPart);
ntStatus = KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, &Timeout);
if ( ntStatus == STATUS_TIMEOUT)
{
dlDbgPrint(FUNCTION", KeWaitForSingleObject returned STATUS_TIMEOUT\r\n");
if (InterlockedExchange((PVOID)&lock, IRPLOCK_CANCEL_STARTED) == IRPLOCK_CANCELABLE)
{
dlDbgPrint(FUNCTION", lock is IRPLOCK_CANCELABLE, calling IoCancelIrp\r\n");
IoCancelIrp(Irp); // okay in this context
if (InterlockedExchange((PVOID) &lock, IRPLOCK_CANCEL_COMPLETE) == IRPLOCK_COMPLETED)
{
dlDbgPrint(FUNCTION", lock is IRPLOCK_COMPLETED, calling IoCompleteRequest\r\n");
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
}
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
iostatus.Status = ntStatus; // Return STATUS_TIMEOUT
}
else
{
ntStatus = iostatus.Status;
}
if (!NT_SUCCESS(ntStatus))
{
ser_print(FUNCTION", iostatus 0x%08lx\r\n",ntStatus);
}
}
return ntStatus;
}