I’m beating my head against the wall on this one. I’ve got a general
purpose USB driver that does staged bulk transfers (similar to the example
in Oney’s book). This works great under Win2k/XP, however when I test under
Win9x/ME the data comes out corrupted. What happens is the first 2MB worth
of transfers (with MaxTransferSize of 4k) work perfectly fine, but after
that every stage of the transfer has a 64 byte “hole” where it is basically
skipping over the buffer. I’ve hooked this all up to a CATC and it looks
like the data is coming across perfectly fine but by the time it gets into
the app, these “holes” have appeared. The only area where things are
handled in 64 byte segments is in the driver beneath me (USBD) where it
breaks up my 4k request into 64 byte packets. I would love to accuse USBD
of causing this problem, but that would seem foolish!
Here’s some relevant code:
#pragma code_seg()
NTSTATUS
BulkReadWrite(
PDEVICE_EXTENSION pDeviceExtension,
PIRP pIrp,
PBULK_TRANSFER_INFO pBulk,
BOOLEAN bRead
)
{
PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation( pIrp );
LONG lTransferLen;
if ( bRead )
lTransferLen = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
else
lTransferLen = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
ASSERT( lTransferLen != 0 );
//
// Set up the block size
//
if ( lTransferLen > MAX_TRANSFER_SIZE )
pBulk->lBlockSize = MAX_TRANSFER_SIZE;
else
pBulk->lBlockSize = lTransferLen;
KdPrint(( “Block size = %d\n”, pBulk->lBlockSize ));
//
// Build up an MDL that is usable for this block
//
PUCHAR pBuff = (PUCHAR) MmGetMdlVirtualAddress( pIrp->MdlAddress );
PMDL pMdl = IoAllocateMdl( (PVOID) pBuff, PAGE_SIZE, FALSE, FALSE,
NULL );
ASSERT( pMdl );
IoBuildPartialMdl( pIrp->MdlAddress, pMdl, (PVOID) pBuff,
pBulk->lBlockSize );
//
// Build up our URB (it has already been allocated)
//
ULONG ulFlags;
if ( bRead )
ulFlags = USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK;
else
ulFlags = USBD_SHORT_TRANSFER_OK;
UsbBuildInterruptOrBulkTransferRequest( pBulk,
sizeof(_URB_BULK_OR_INTERRUPT_TRANSFER),
pBulk->hPipeHandle,
NULL, pMdl,
pBulk->lBlockSize,
ulFlags,
NULL );
//
// Initialize variables and save pointers for later use
//
pBulk->lTotalTransfer = 0;
pBulk->lTransferLeft = lTransferLen;
pBulk->pCurrentBuff = pBuff;
pBulk->pCurrentMdl = pMdl;
KdPrint(( “pBulk->pCurrentBuff = 0x%x\n”, pBulk->pCurrentBuff ));
//
// Send out the URB
//
KdPrint(( “Waiting for Bulk READ…\n” ));
pIrpStack = IoGetNextIrpStackLocation( pIrp );
pIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
pIrpStack->Parameters.Others.Argument1 = (PVOID) (PURB) pBulk;
pIrpStack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_INTERNAL_USB_SUBMIT_URB;
IoSetCompletionRoutine( pIrp, (PIO_COMPLETION_ROUTINE)
BulkCompletionRoutine,
(PVOID) pBulk, TRUE, TRUE, TRUE);
IoCallDriver( pDeviceExtension->pNextDeviceObject, pIrp );
return STATUS_SUCCESS;
}
#pragma code_seg()
NTSTATUS
BulkCompletionRoutine(
PDEVICE_OBJECT pFdo,
PIRP pIrp,
PBULK_TRANSFER_INFO pBulk
)
{
PDEVICE_EXTENSION pDeviceExtension =
(PDEVICE_EXTENSION) pFdo->DeviceExtension;
LONG lActual =
pBulk->UrbBulkOrInterruptTransfer.TransferBufferLength;
KdPrint(( “Completion Rountine: lLeft = %d :: Actual Tranferred =
%d\n”, pBulk->lTransferLeft, lActual ));
//
// Check last transfer for errors
//
NTSTATUS ntStatus= pIrp->IoStatus.Status;
if ( !NT_SUCCESS( ntStatus ) )
{
if ( ntStatus != STATUS_CANCELLED )
{
KdPrint(( “Error sending URB, USBD Status = 0x%x\n”,
URB_STATUS( pBulk ) ));
if ( USBD_HALTED( URB_STATUS( pBulk ) ) )
{
//
// An error has caused this pipe to halt.
We will need
// to reset it in order to continue.
//
KdPrint(( “Resetting Pipe\n” ));
pDeviceExtension->hPipeError =
pBulk->UrbBulkOrInterruptTransfer.PipeHandle;
}
}
//
// Exiting with an error, Clean up
//
ExFreePool( pBulk->pCurrentMdl );
ExFreePool( pBulk );
InterlockedDecrement( &pDeviceExtension->lTransfersPending
);
IoReleaseRemoveLock( &pDeviceExtension->IoRemoveLock, pIrp
);
return ntStatus;
}
//
// Update the counters and pointers
//
pBulk->lTotalTransfer += lActual;
pBulk->lTransferLeft -= lActual;
pBulk->pCurrentBuff += lActual;
//
// Are we done yet?
//
if ( pBulk->lTransferLeft > 0 )
{
if ( pBulk->lTransferLeft > MAX_TRANSFER_SIZE )
pBulk->lBlockSize = MAX_TRANSFER_SIZE;
else
pBulk->lBlockSize = pBulk->lTransferLeft;
KdPrint(( “Next Block size = %d\n”, pBulk->lBlockSize ));
//
// Set up the next URB/IRP pair
//
IoBuildPartialMdl( pIrp->MdlAddress, pBulk->pCurrentMdl,
(PVOID) pBulk->pCurrentBuff, pBulk->lBlockSize );
pBulk->UrbBulkOrInterruptTransfer.TransferBufferLength =
pBulk->lBlockSize;
PIO_STACK_LOCATION pIrpStack = IoGetNextIrpStackLocation(
pIrp );
pIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
pIrpStack->Parameters.Others.Argument1 = (PVOID) (PURB)
pBulk;
pIrpStack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_INTERNAL_USB_SUBMIT_URB;
IoSetCompletionRoutine( pIrp, (PIO_COMPLETION_ROUTINE)
BulkCompletionRoutine,
(PVOID) pBulk, TRUE, TRUE, TRUE);
//
// Send down the URB
//
IoCallDriver( pDeviceExtension->pNextDeviceObject, pIrp );
return STATUS_MORE_PROCESSING_REQUIRED;
}
//
// If we get here, we’re all done. All we have to do is clean
// up our mdl and urb and exit with STATUS_SUCCESS
//
InterlockedDecrement( &pDeviceExtension->lTransfersPending );
pIrp->IoStatus.Information = pBulk->lTotalTransfer;
ExFreePool( pBulk->pCurrentMdl );
ExFreePool( pBulk );
if ( pDeviceExtension->lTransfersPending )
{
KdPrint(( “DEQUE!\n” ));
// TODO: Fix this up
//DeQueueAndStartIrp( pFdo, pDeviceExtension, StartIo );
}
IoReleaseRemoveLock( &pDeviceExtension->IoRemoveLock, pIrp );
return STATUS_SUCCESS;
}
Any ideas anyone??? I’ll take anything at this point!
- Dennis
You are currently subscribed to ntdev as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntdev-$subst(‘Recip.MemberIDChar’)@lists.osr.com