📄 ocrwblk.c
字号:
/*++
Copyright (c) 1997-1998 Microsoft Corporation
Module Name:
OcrwBulk.c
Abstract:
Bulk USB device driver for Intel 82930 USB test board
Read/write io test code
Environment:
kernel mode only
Notes:
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
PURPOSE.
Copyright (c) 1997-1998 Microsoft Corporation. All Rights Reserved.
Revision History:
11/17/97 : created
--*/
#include "wdm.h"
#include "stdarg.h"
#include "stdio.h"
#define DRIVER
#include "usbdi.h"
#include "usbdlib.h"
#include "Blk82930.h"
NTSTATUS
BulkUsb_SingleUrbReadWrite(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN BOOLEAN Read
)
/*++
Routine Description:
This routine is called by BulkUsb_StagedReadWrite() for transfers that
are smaller than deviceExtension->MaximumTransferSize and therefore don't
need to be broken up into chunks
Arguments:
DeviceObject - pointer to our FDO ( Functional Device Object )
Irp - pointer to the IRP_MJ_READ or IRP_MJ_WRITE
Read - TRUE for read, FALSE for write
Return Value:
NT status code
--*/
{
int totalLength = 0;
NTSTATUS ntStatus;
ULONG siz;
PURB urb;
PFILE_OBJECT fileObject;
PIO_STACK_LOCATION irpStack, nextStack;
PUSBD_PIPE_INFORMATION pipeHandle = NULL;
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
BULKUSB_KdPrint ( DBGLVL_HIGH, (" Enter BulkUsb_SingleUrbReadWrite\n"));
// We should have already checked this in BulkUsb_StagedReadWrite();
BULKUSB_ASSERT( BulkUsb_CanAcceptIoRequests( DeviceObject ) );
Irp->IoStatus.Information = 0;
siz = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER);
irpStack = IoGetCurrentIrpStackLocation (Irp);
fileObject = irpStack->FileObject;
pipeHandle = fileObject->FsContext;
if (!pipeHandle)
{
ntStatus = STATUS_INVALID_HANDLE;
BULKUSB_KdPrint ( DBGLVL_DEFAULT, ("BulkUsb_SingleUrbReadWrite() Rejecting on invalid pipeHandle 0x%x decimal %d\n",pipeHandle, pipeHandle ));
Irp->IoStatus.Status = ntStatus;
IoCompleteRequest (Irp, IO_NO_INCREMENT );
return ntStatus;
}
BULKUSB_ASSERT( UsbdPipeTypeBulk == pipeHandle->PipeType );
if ( Irp->MdlAddress ) { // could be NULL for 0-len request
totalLength = MmGetMdlByteCount(Irp->MdlAddress);
}
// Build our URB for USBD
urb = BulkUsb_BuildAsyncRequest(DeviceObject,
Irp,
pipeHandle,
Read);
if ( !urb ) {
BULKUSB_KdPrint ( DBGLVL_DEFAULT, ("BulkUsb_SingleUrbReadWrite()failed to alloc urb\n" ));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
Irp->IoStatus.Status = ntStatus;
IoCompleteRequest (Irp, IO_NO_INCREMENT );
return ntStatus;
}
deviceExtension->BaseUrb = urb; // save pointer to URb we alloced for this xfer; we free in completion routine
//
// Now that we have created the urb, we will send a
// request to the USB device object.
//
//
// Call the class driver to perform the operation.
// IoGetNextIrpStackLocation gives a higher level driver access to the next-lower
// driver's I/O stack location in an IRP so the caller can set it up for the lower driver.
nextStack = IoGetNextIrpStackLocation(Irp);
BULKUSB_ASSERT(nextStack != NULL);
//
// pass the URB to the USB driver stack
//
nextStack->Parameters.Others.Argument1 = urb;
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
nextStack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_INTERNAL_USB_SUBMIT_URB;
IoSetCompletionRoutine(
Irp, // irp to use
BulkUsb_SimpleReadWrite_Complete, // routine to call when irp is done
DeviceObject, // we pass our FDO as context to pass routine
TRUE, // call on success
TRUE, // call on error
TRUE); // call on cancel
//
// Call IoCallDriver to send the irp to the usb port.
//
BULKUSB_KdPrint ( DBGLVL_HIGH, (" BulkUsb_SingleUrbReadWrite about to IoCallDriver\n"));
BulkUsb_IncrementIoCount(DeviceObject);
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp );
BULKUSB_KdPrint ( DBGLVL_HIGH, (" BulkUsb_SingleUrbReadWrite after IoCallDriver status (pending) 0x%x\n", ntStatus));
//
// The USB driver should always return STATUS_PENDING when
// it receives an irp with major function code IRP_MJ_WRITE or IRP_MJ_READ.
//
ASSERT( ntStatus == STATUS_PENDING);
BULKUSB_KdPrint ( DBGLVL_HIGH, (" Exit BulkUsb_SingleUrbReadWrite\n"));
return ntStatus;
}
NTSTATUS
BulkUsb_StagedReadWrite(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN BOOLEAN Read
)
/*++
Routine Description:
This routine is called by BulkUsb_Read() for IRP_MJ_READ.
This routine is called by BulkUsb_Write() for IRP_MJ_WRITE.
Breaks up a read or write in to specified sized chunks,
as specified by deviceExtension->MaximumTransferSize
Arguments:
DeviceObject - pointer to our FDO ( Functional Device Object )
Irp - pointer to the IRP_MJ_READ or IRP_MJ_WRITE
Read - TRUE for read, FALSE for write
Return Value:
NT status code
--*/
{
NTSTATUS ntStatus = STATUS_SUCCESS;
NTSTATUS resetPipeStatus;
PFILE_OBJECT fileObject;
PIO_STACK_LOCATION irpStack, nextStack;
PURB urb;
PIRP irp;
PMDL mdl;
PVOID va;
CHAR stackSize;
KIRQL OldIrql;
BOOLEAN fRes;
NTSTATUS waitStatus;
ULONG i, nIrps = 0, totalLength = 0, totalIrpsNeeded, used;
PUSBD_PIPE_INFORMATION pipeHandle = NULL;
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PUCHAR pCon = NULL;
ULONG ChunkSize = deviceExtension->MaximumTransferSize;
ULONG arraySize;
PBULKUSB_RW_CONTEXT context = NULL;
BULKUSB_KdPrint ( DBGLVL_DEFAULT, ("enter BulkUsb_StagedReadWrite()\n"));
Irp->IoStatus.Information = 0;
// Can't accept a new io request if:
// 1) device is removed,
// 2) has never been started,
// 3) is stopped,
// 4) has a remove request pending,
// 5) has a stop device pending
if ( !BulkUsb_CanAcceptIoRequests( DeviceObject ) ) {
ntStatus = STATUS_DELETE_PENDING;
Irp->IoStatus.Status = ntStatus;
BULKUSB_KdPrint ( DBGLVL_DEFAULT, ("BulkUsb_StagedReadWrite() can't accept requests, returning STATUS_INSUFFICIENT_RESOURCES\n"));
IoCompleteRequest (Irp, IO_NO_INCREMENT );
return ntStatus;
}
if ( Irp->MdlAddress ) { // could be NULL for 0-len request
totalLength = MmGetMdlByteCount(Irp->MdlAddress);
}
BULKUSB_KdPrint ( DBGLVL_HIGH, ("BulkUsb_StagedReadWrite() totalLength = decimal %d, Irp->MdlAddress = 0x%x\n",totalLength, Irp->MdlAddress ));
if ( totalLength <= deviceExtension->MaximumTransferSize ) {
// for short or zero-len transfers, no need to do the staging; do it in a single request
return BulkUsb_SingleUrbReadWrite( DeviceObject, Irp, Read );
}
irpStack = IoGetCurrentIrpStackLocation (Irp);
fileObject = irpStack->FileObject;
pipeHandle = fileObject->FsContext;
if (!pipeHandle)
{
ntStatus = STATUS_INVALID_HANDLE;
BULKUSB_KdPrint ( DBGLVL_DEFAULT, ("BulkUsb_StagedReadWrite() Rejecting on invalid pipeHandle 0x%x decimal %d\n",pipeHandle, pipeHandle ));
Irp->IoStatus.Status = ntStatus;
IoCompleteRequest (Irp, IO_NO_INCREMENT );
return ntStatus;
}
//
// submit the request to USB
//
BULKUSB_ASSERT( UsbdPipeTypeBulk == pipeHandle->PipeType );
BULKUSB_ASSERT( NULL != Irp->MdlAddress );
BULKUSB_ASSERT(totalLength > deviceExtension->MaximumTransferSize );
// more memory than is on our test device?
if ( totalLength > BULKUSB_TEST_BOARD_TRANSFER_BUFFER_SIZE )
{
ntStatus = STATUS_INVALID_PARAMETER;
BULKUSB_KdPrint ( DBGLVL_DEFAULT, ("BulkUsb_StagedReadWrite() Rejecting on too large request 0x%x decimal %d\n",totalLength, totalLength ));
Irp->IoStatus.Status = ntStatus;
IoCompleteRequest (Irp, IO_NO_INCREMENT );
return ntStatus;
}
// calculate total # of staged irps that will be needed
totalIrpsNeeded = totalLength / deviceExtension->MaximumTransferSize ;
if ( totalLength % deviceExtension->MaximumTransferSize )
totalIrpsNeeded++;
BULKUSB_ASSERT( !deviceExtension->PendingIoIrps ); // this should have been cleaned up last time
BULKUSB_ASSERT( !deviceExtension->BaseIrp ); // this should have been cleaned up last time
used = 0;
// alloc one extra for termination
arraySize = ( totalIrpsNeeded +1 ) * sizeof(BULKUSB_RW_CONTEXT);
// allocate space for an array of BULKUSB_RW_CONTEXT structs for the staged irps
deviceExtension->PendingIoIrps = BULKUSB_ExAllocatePool(NonPagedPool, arraySize );
if ( !deviceExtension->PendingIoIrps ) {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
BULKUSB_KdPrint ( DBGLVL_DEFAULT, ("BulkUsb_StagedReadWrite() !deviceExtension->PendingIoIrps STATUS_INSUFFICIENT_RESOURCES\n"));
Irp->IoStatus.Status = ntStatus;
IoCompleteRequest (Irp, IO_NO_INCREMENT );
return ntStatus;
}
RtlZeroMemory(deviceExtension->PendingIoIrps, arraySize );
// init ptr to 1st BULKUSB_RW_CONTEXT struct in array
pCon = (PUCHAR) deviceExtension->PendingIoIrps;
deviceExtension->BaseIrp = Irp; // this is the original user's irp
deviceExtension->StagedBytesTransferred = 0;
deviceExtension->StagedPendingIrpCount = totalIrpsNeeded;
// we need to build a series of irps & urbs to represent
// this request.
while (NT_SUCCESS(ntStatus) ) {
context = (PBULKUSB_RW_CONTEXT) pCon;
irp = NULL;
urb = NULL;
mdl = NULL;
if ( !BulkUsb_CanAcceptIoRequests( DeviceObject ) ) {
// got sudden remove! ( i.e. plug was yanked )
ntStatus = STATUS_DELETE_PENDING;
Irp->IoStatus.Status = ntStatus;
BULKUSB_KdPrint ( DBGLVL_MAXIMUM, ("BulkUsb_StagedReadWrite() got sudden remove, breaking out of URB-building loop\n"));
break;
}
stackSize = (CCHAR)(deviceExtension->TopOfStackDeviceObject->StackSize + 1);
irp = IoAllocateIrp(stackSize, FALSE);
// Get the virtual address for the buffer described by
// our original input Irp's MDL.
va = MmGetMdlVirtualAddress(Irp->MdlAddress);
if (irp) {
// Each new Irp will 'see' the entire buffer, but map it's IO location
// to a single ChunkSize section within it via IoBuildPartialMdl()
mdl = IoAllocateMdl(va,
totalLength,
FALSE,
FALSE,
irp);
}
if (mdl) {
// see if we're done yet
if( ( used + ChunkSize ) > totalLength ) {
// make sure to truncate last transfer if neccy
ChunkSize = totalLength - used;
}
// Map the sub-area of the full user buffer this staged Irp will be using for IO
IoBuildPartialMdl(Irp->MdlAddress, // Points to an MDL describing the original buffer,
// of which a subrange is to be mapped
mdl, // our allocated target mdl
(PUCHAR)va + used, // base virtual address of area to be mapped
ChunkSize); // size of area to be mapped
used+=ChunkSize;
urb = BulkUsb_BuildAsyncRequest(DeviceObject,
irp,
pipeHandle,
Read);
}
if (urb && irp && mdl) {
context->Urb = urb;
context->DeviceObject = DeviceObject;
context->Irp = irp;
context->Mdl = mdl;
nIrps++;
// IoGetNextIrpStackLocation gives a higher level driver access to the next-lower
// driver's I/O stack location in an IRP so the caller can set it up for the lower driver.
nextStack = IoGetNextIrpStackLocation(irp);
BULKUSB_ASSERT(nextStack != NULL);
BULKUSB_ASSERT(DeviceObject->StackSize>1);
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
nextStack->Parameters.Others.Argument1 = urb;
nextStack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_INTERNAL_USB_SUBMIT_URB;
IoSetCompletionRoutine(irp,
BulkUsb_AsyncReadWrite_Complete,
context, // pass the context array element to completion routine
TRUE, // invoke on success
TRUE, // invoke on error
TRUE); // invoke on cancellation of the Irp
BULKUSB_KdPrint ( DBGLVL_MAXIMUM, ("BulkUsb_StagedReadWrite() created staged irp #%d %x\n", nIrps, irp));
// We keep an array of all pending read/write Irps; we may have to cancel
// them explicitly on sudden device removal or other error
(( PBULKUSB_RW_CONTEXT) pCon)->Irp = irp;
BulkUsb_IncrementIoCount(DeviceObject);
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject,
(( PBULKUSB_RW_CONTEXT) pCon)->Irp);
} else {
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
BULKUSB_KdPrint ( DBGLVL_DEFAULT, ("BulkUsb_StagedReadWrite() Dumped from irp loop on failed Irp or urb allocate\n"));
break;
}
if (used >= totalLength) {
break; // we're done
}
// point to next BULKUSB_RW_CONTEXT struct
pCon += sizeof(BULKUSB_RW_CONTEXT);
} // end while
Irp->IoStatus.Status = ntStatus;
if (!NT_SUCCESS(ntStatus)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -