Hi there
I got a problem with my usb driver. It uses a system thread which continuously creates IRP’s and calls the underlaying usb driver. There are always three outstanding Interrupt IN transfer requests. So the system polls my device as it should be. No problem, everything works fine until my system is under heavy load (and especially the device defines a polling interval of 4ms or less). In this case I got fragmentet, invalid data from the underlaying driver again and again. The lower the polling intervall is, the more data is invalid. Mostly it contains some data from the next transfer which will complete after the current one. I don’t have a clue what the problem is. On a low-powered notebook up to every 10th (or more) transfer contains invalid data. On my highend 2Core PC only a few transfers are fragmentet and invalid.
Within the completion routine the driver stores the data into a buffer. The usermode application accesses this buffer through an DeviceIoControll request. Every access to buffer is protected by a SpinLook.
So I is there maybe a timing / synchronization problem?!?
Btw: My Usb-Transfer-Logger application (I think it’s filter driver lays under my driver) also sees the fragmented data as my drivers receives it.
May someone has an idea? Thank you!
Patric
CODE:
VOID
ThreadInterruptTransfer (
IN PVOID pDeviceExtension )
{
PURB urb;
PIRP irp;
LONG counter;
NTSTATUS ntStatus;
PDEVICE_EXTENSION deviceExtension;
PIO_STACK_LOCATION pNextStack;
IO_STATUS_BLOCK ioStatus;
LONG DATAPACK_SIZE;
CHAR buffer[sizeof(DataPackS)][CONCURRENT_INTERUPT_TRANSFERS];
DATAPACK_SIZE = sizeof(DataPackS);
deviceExtension = pDeviceExtension;
KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
KeInitializeSemaphore(&deviceExtension->InterruptTransferSemaphore, CONCURRENT_INTERUPT_TRANSFERS, CONCURRENT_INTERUPT_TRANSFERS);
counter = 0;
while(!deviceExtension->bShutdownInterruptTransferThread)
{
KeWaitForSingleObject(&deviceExtension->InterruptTransferSemaphore,
Executive, KernelMode, TRUE, NULL);
if(deviceExtension->bShutdownInterruptTransferThread)
break;
ntStatus = SubmitInterruptReadIRP(deviceExtension->TopOfStackDeviceObject,&buffer[0][counter],DATAPACK_SIZE,deviceExtension);
counter = (++counter) % (CONCURRENT_INTERUPT_TRANSFERS);
}
PsTerminateSystemThread(STATUS_SUCCESS);
}
NTSTATUS
SubmitInterruptReadIRP(
PDEVICE_OBJECT TopOfDeviceStack,
PVOID WriteBuffer,
ULONG NumBytes,
PDEVICE_EXTENSION deviceExtension
)
{
NTSTATUS ntStatus;
PURB urb;
NTSTATUS status;
PIRP irp;
LARGE_INTEGER startingOffset;
KEVENT event;
PIO_STACK_LOCATION nextStack;
PBULKUSB_RW_CONTEXT rwContext;
rwContext = NULL;
startingOffset.QuadPart = (LONGLONG) 0;
irp = IoAllocateIrp( TopOfDeviceStack->StackSize, FALSE );
if (NULL == irp) {
return STATUS_INSUFFICIENT_RESOURCES;
}
irp->AssociatedIrp.SystemBuffer = WriteBuffer;
irp->MdlAddress = NULL;
urb = ExAllocatePool(NonPagedPool,
sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER));
if(urb == NULL) {
BulkUsb_DbgPrint(1, (“Failed to alloc mem for urb\n”));
return STATUS_INSUFFICIENT_RESOURCES;
}
UsbBuildInterruptOrBulkTransferRequest(
urb,
sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
deviceExtension->InterruptPipeHandle,
irp->AssociatedIrp.SystemBuffer,
irp->MdlAddress,
NumBytes,
USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK,
NULL);
rwContext = ExAllocatePool(NonPagedPool,
sizeof(BULKUSB_RW_CONTEXT));
if(rwContext == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
rwContext->Urb = urb;
rwContext->Mdl = irp->MdlAddress;
rwContext->Length = NumBytes;
rwContext->Numxfer = 0;
rwContext->VirtualAddress = NULL;
rwContext->DeviceExtension = deviceExtension;
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,
InterruptCompletion,
rwContext,
TRUE,
TRUE,
TRUE);
ntStatus = IoCallDriver(TopOfDeviceStack, irp);
return STATUS_SUCCESS;
}
NTSTATUS
InterruptCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
NTSTATUS status;
PVOID buffer;
PMDL mdl, nextMdl;
KIRQL oldIrql;
PDEVICE_EXTENSION deviceExtension;
PBULKUSB_RW_CONTEXT rwContext;
LARGE_INTEGER timeout;
rwContext = Context;
deviceExtension = rwContext->DeviceExtension;
if(NT_SUCCESS(Irp->IoStatus.Status))
{
buffer = Irp->AssociatedIrp.SystemBuffer;
KeAcquireSpinLock(&deviceExtension->InterruptTransferBufferSpinLock, &oldIrql);
CarSmUsbFifoInsertData(deviceExtension->InterruptTransferBuffer, (unsigned char*)(buffer), sizeof(DataPackS));
KeReleaseSpinLock(&deviceExtension->InterruptTransferBufferSpinLock, oldIrql);
}
ExFreePool(rwContext->Urb);
ExFreePool(rwContext);
BulkUsb_DbgPrint(3, (“IoFreeIrp - Interrupt Transfer Completed\n”));
RemoveOutstandingInterruptTransferIrp(deviceExtension, Irp);
IoFreeIrp(Irp);
try {
KeReleaseSemaphore(&deviceExtension->InterruptTransferSemaphore,
0,
1,
FALSE);
} except (STATUS_SEMAPHORE_LIMIT_EXCEEDED) {}
return STATUS_MORE_PROCESSING_REQUIRED;
}