我的驱动程序里面关键有两个函数StartIO和OnReadWriteComplete,read和write的入口函数里面只是做了些错误检查,然后都是调用StartIO函数。
VOID StartIo(PDEVICE_OBJECT fdo, PIRP Irp)
{
//KdPrint(("[ StartIo] start"));
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
NTSTATUS status = IoAcquireRemoveLock(&pdx->RemoveLock, Irp);
if (!NT_SUCCESS(status))
{
CompleteRequest(Irp, status, 0);
KdPrint(("[ .StartIo] end - !NT_STATUS(status)"));
return;
}
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
BOOLEAN read = stack->MajorFunction == IRP_MJ_READ;
if (read)
KdPrint(("[StartIo] Read Operation"));
else
KdPrint(("[StartIo] Write Operation"));
USBD_PIPE_HANDLE hpipe = read ? pdx->hinpipe : pdx->houtpipe;
PRWCONTEXT ctx = (PRWCONTEXT) ExAllocatePool(NonPagedPool, sizeof(RWCONTEXT));
if (!ctx)
{
KdPrint((DRIVERNAME " - Can't allocate memory for context structure\n"));
StartNextPacket(&pdx->dqReadWrite, fdo);
CompleteRequest(Irp, STATUS_INSUFFICIENT_RESOURCES, 0);
IoReleaseRemoveLock(&pdx->RemoveLock, Irp);
return;
}
RtlZeroMemory(ctx, sizeof(RWCONTEXT));
ULONG length = Irp->MdlAddress ? MmGetMdlByteCount(Irp->MdlAddress) : 0;
KdPrint(("[StartIo] - Length %d\n", length));
if (!length && !read && FALSE) // zero-length write
{
....//零长度写,没有执行过
return;
}
if (!length) // zero-length read
{
.... //零长度读,没有执行过
return;
}
ULONG_PTR va = (ULONG_PTR) MmGetMdlVirtualAddress(Irp->MdlAddress);
ULONG urbflags = USBD_SHORT_TRANSFER_OK |
(read ? USBD_TRANSFER_DIRECTION_IN : USBD_TRANSFER_DIRECTION_OUT);
ULONG seglen= length;
if (seglen > pdx->maxtransfer)
{
seglen = pdx->maxtransfer;
KdPrint((DRIVERNAME " - Read/write of %d bytes will be done in segments of %d\n",
length,
seglen));
}
//---------------------------------------------------------------------------
// Allocate an MDL for each segment of the transfer. The parameters are chosen so
// that the MDL will have room for a maximum-sized buffer in the worst case where
// it starts just before a page boundary. (Note that the virtual address argument to
// IoAllocateMdl is not actually used as an address.)
//---------------------------------------------------------------------------
PMDL mdl = IoAllocateMdl((PVOID) (PAGE_SIZE - 1), seglen, FALSE, FALSE, NULL);
if (!mdl) // can't allocate MDL
{
KdPrint((DRIVERNAME " - Can't allocate memory for MDL\n"));
ExFreePool(ctx);
StartNextPacket(&pdx->dqReadWrite, fdo);
CompleteRequest(Irp, STATUS_INSUFFICIENT_RESOURCES, 0);
IoReleaseRemoveLock(&pdx->RemoveLock, Irp);
}
//---------------------------------------------------------------------------
// Initialize the (partial) MDL to describe the first segment's subset of the user buffer.
//---------------------------------------------------------------------------
IoBuildPartialMdl(Irp->MdlAddress, mdl, (PVOID) va, seglen);
//---------------------------------------------------------------------------
// Reader Peter Diaconesco ran across an apparent bug in the Win2K version of
// UHCD.SYS. Under heavy load conditions, UHCD was bug-checking because its
// internal call to MmGetSystemAddressForMdl was apparently returning NULL
// (even though it's not supposed to). We can prevent that problem by mapping
// the pages in the following "safe" manner:
//---------------------------------------------------------------------------
if (!GenericGetSystemAddressForMdl(mdl)) // can't map transfer segment
{
KdPrint((DRIVERNAME " - Can't map memory for read or write\n"));
ExFreePool(ctx);
StartNextPacket(&pdx->dqReadWrite, fdo);
CompleteRequest(Irp, STATUS_INSUFFICIENT_RESOURCES, 0);
IoReleaseRemoveLock(&pdx->RemoveLock, Irp);
return;
}
UsbBuildInterruptOrBulkTransferRequest(ctx,
sizeof(_URB_BULK_OR_INTERRUPT_TRANSFER),
hpipe,
NULL,
mdl,
seglen,
urbflags,
NULL);
//---------------------------------------------------------------------------
// Set context structure parameters to pick up where we just left off
//---------------------------------------------------------------------------
ctx->va = va + seglen;
ctx->length = length - seglen;
ctx->mdl = mdl;
ctx->numxfer = 0;
//---------------------------------------------------------------------------
// Use the original Read or Write IRP as a container for the URB
//---------------------------------------------------------------------------
stack = IoGetNextIrpStackLocation(Irp);
stack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
stack->Parameters.Others.Argument1 = (PVOID) (PURB) ctx;
stack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
//KdPrint((" \n TransferBufferMDL: %x \n", ctx->UrbBulkOrInterruptTransfer.TransferBufferMDL));
IoSetCompletionRoutine(Irp,
(PIO_COMPLETION_ROUTINE) OnReadWriteComplete,
(PVOID)ctx,
TRUE,
TRUE,
TRUE);
IoCallDriver(pdx->LowerDeviceObject, Irp);
//KdPrint(("[ .StartIo] end"));
} //end:StartIo