?? usbfx2lk_io.cpp
字號:
///////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright 2005 OSR Open Systems Resources, Inc.
// All Rights Reserved
//
// This sofware is supplied for instructional purposes only.
//
// OSR Open Systems Resources, Inc. (OSR) expressly disclaims any warranty
// for this software. THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION,
// THE IMPLIED WARRANTIES OF MECHANTABILITY OR FITNESS FOR A PARTICULAR
// PURPOSE. THE ENTIRE RISK ARISING FROM THE USE OF THIS SOFTWARE REMAINS
// WITH YOU. OSR's entire liability and your exclusive remedy shall not
// exceed the price paid for this material. In no event shall OSR or its
// suppliers be liable for any damages whatsoever (including, without
// limitation, damages for loss of business profit, business interruption,
// loss of business information, or any other pecuniary loss) arising out
// of the use or inability to use this software, even if OSR has been
// advised of the possibility of such damages. Because some states/
// jurisdictions do not allow the exclusion or limitation of liability for
// consequential or incidental damages, the above limitation may not apply
// to you.
//
// OSR Open Systems Resources, Inc.
// 105 Route 101A Suite 19
// Amherst, NH 03031 (603) 595-6500 FAX: (603) 595-6503
// email bugs to: bugs@osr.com
//
//
// MODULE:
//
// USBFx2LK_io.cpp
//
// ABSTRACT:
//
// This file contains the routines that handle IRP_MJ_READ and
// IRP_MJ_WRITE processing for the OSR USB FX2 Learning Kit Device
//
// AUTHOR(S):
//
// OSR Open Systems Resources, Inc.
//
///////////////////////////////////////////////////////////////////////////////
#include "usbfx2lk.h"
#ifdef WPP_TRACING
//
// Include the necessary tmh file - this is
// just a matter of course if you're using WPP tracing.
//
extern "C" {
#include "usbfx2lk_io.tmh"
}
#endif
//
// Forward Definitions
//
NTSTATUS UsbFx2LkReadCompletionRoutine(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context);
NTSTATUS UsbFx2LkWriteCompletionRoutine(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context);
VOID IssueUsbReadRequest(IN PDEVICE_OBJECT DeviceObject,IN PVOID Context);
VOID IssueUsbWriteRequest(IN PDEVICE_OBJECT DeviceObject,IN PVOID Context);
///////////////////////////////////////////////////////////////////////////////
//
// ProcessNextIrpInQueue
//
// This routine processes the Next Irp in the Io Queue, if we are in a state
// to process Irps. If not, the Irps will remain in the queue until the state
// of the device changes to either a state where the Irps can be processed or where
// the Irps will be removed from the queue.
//
// INPUTS:
//
// DevExt - Address of our Device Extension.
//
// OUTPUTS:
//
// None
//
// RETURNS:
//
// None
//
// IRQL:
//
// IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// User Context
//
// NOTES:
//
///////////////////////////////////////////////////////////////////////////////
VOID ProcessNextIrpInQueue(PUSBFX2LK_EXT DevExt)
{
KIRQL oldIrql;
PIRP irp;
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_READWRITE, ("ProcessNextIrpInQueue Entered...\n"));
//
// Check the state of the device. If we not processing irps
// we will just return.
//
KeAcquireSpinLock(&DevExt->IoStateLock,&oldIrql);
if(DevExt->DevicePnPState >= STATE_ALL_ABOVE_QUEUE) {
KeReleaseSpinLock(&DevExt->IoStateLock,oldIrql);
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_READWRITE,
("ProcessNextIrpInQueue: Exit Queuing Irps, Not Processing\n"));
return;
}
KeReleaseSpinLock(&DevExt->IoStateLock,oldIrql);
//
// See if the device is currently suspended. If it
// is, this routine will attempt to asynchronously power
// the device back up and will return TRUE. In that
// case, the power up code will restart our queues and
// we can simply exit here. However, if this routine
// returns FALSE the device is already powered up
// and we can attempt to start the next IRP in
// the queue.
//
if (!SSPowerDeviceIfSuspendedAsync(DevExt)) {
//
// Attempt to remove an IRP from the Queue.
//
irp = IoCsqRemoveNextIrp(&DevExt->CancelSafeIoQueue,NULL);
//
// See if we got an IRP. If not, then we exit.
//
if(!irp) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_READWRITE,
("ProcessNextIrpInQueue Exit No Irps in Queue\n"));
return;
}
//
// Got an IRP, submit it to the Device Below us.
//
(VOID)IoCallDriver(DevExt->DeviceToSendIrpsTo,irp);
}
OsrTracePrint(TRACE_LEVEL_VERBOSE,OSRDBG_READWRITE, ("ProcessNextIrpInQueue Exit...\n"));
return;
}
///////////////////////////////////////////////////////////////////////////////
//
// UsbFx2LkRead
//
// This routine is called by the IO Manager to process a IRP_MJ_READ
// Irp.
//
//
// INPUTS:
//
// DeviceObject - One of our Device Objects.
// Irp - The Irp to process.
//
// OUTPUTS:
//
// None
//
// RETURNS:
//
// STATUS_PENDING, or an ERROR.
//
// IRQL:
//
// IRQL == PASSIVE_LEVEL
//
// CONTEXT:
//
// User Context
//
// NOTES:
//
// READ requests are always serviced by the bulk input pipe
//
///////////////////////////////////////////////////////////////////////////////
NTSTATUS UsbFx2LkRead(PDEVICE_OBJECT DeviceObject,PIRP Irp)
{
PUSBFX2LK_EXT devExt = (PUSBFX2LK_EXT)DeviceObject->DeviceExtension;
PIO_STACK_LOCATION ioStack = IoGetCurrentIrpStackLocation(Irp);
KIRQL oldIrql;
PUSBFX2LK_IO_CONTEXT pFx2Context = NULL;
NTSTATUS status;
PMDL pMdl = NULL;
ULONG totalLength = 0;
ULONG urbFlags = 0;
PUCHAR virtualAddress = 0;
ULONG stageLength = 0;
PURB urb = NULL;
PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(Irp);
//
// We should never be here and not at PASSIVE_LEVEL
//
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
//
// Major issue is we haven't setup our bulk input pipe yet
//
ASSERT(devExt->BulkInPipe);
OsrTracePrint(TRACE_LEVEL_INFORMATION,OSRDBG_READWRITE, ("UsbFx2LkRead Entered...\n"));
//
// Increment the number of outstanding IOs queued to the device.
//
OsrIncrementOutstandingIoCount(devExt,__FILE__,__LINE__);
//
// See what sort of state we're in.
//
KeAcquireSpinLock(&devExt->IoStateLock,&oldIrql);
if (devExt->DevicePnPState < STATE_ALL_BELOW_FAIL) {
KeReleaseSpinLock(&devExt->IoStateLock,oldIrql);
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_READWRITE,
("UsbFx2LkRead: Failing request due to Pnp State! Current PnP state - %s\n",
OsrPrintState(devExt)));
status = STATUS_INVALID_DEVICE_STATE;
goto UsbFx2LkRead_Exit;
}
KeReleaseSpinLock(&devExt->IoStateLock,oldIrql);
//
// We do not support zero length operations in this driver
//
if(!ioStack->Parameters.Read.Length || !Irp->MdlAddress) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_READWRITE,
("UsbFx2LkRead: Invalid Parameters to READ \n"));
status = STATUS_INVALID_PARAMETER;
goto UsbFx2LkRead_Exit;
}
//
// Get the total length of the transfer we are asked to perform.
//
totalLength = ioStack->Parameters.Read.Length;
//
// See if the transfer length is greater than the maximum packet
// size of the pipe * the amount of buffering that the firmware
// provides. If the transfer is too large, we will reject it here
// without further processing
//
if(totalLength >
(ULONG)(devExt->BulkInPipe->PipeInformation.MaximumPacketSize * \
USBFX2LK_BULK_TRANSFER_FW_BUFFERING)) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_READWRITE,
("UsbFx2LkRead: Length exceeds %d\n",
devExt->BulkInPipe->PipeInformation.MaximumPacketSize * USBFX2LK_BULK_TRANSFER_FW_BUFFERING));
status = STATUS_INVALID_PARAMETER;
goto UsbFx2LkRead_Exit;
}
//
// Allocate a USBFX2 I/O context. This is a driver specific
// structure that we'll use to contain all the necessary
// information about this particular request while we
// own that request
//
pFx2Context = (PUSBFX2LK_IO_CONTEXT) ExAllocatePoolWithTag(NonPagedPool,sizeof(USBFX2LK_IO_CONTEXT),'ciuO');
if(pFx2Context == NULL) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_READWRITE,
("UsbFx2LkRead: Failed to allocate IO Context\n"));
status = STATUS_INSUFFICIENT_RESOURCES;
goto UsbFx2LkRead_Exit;
}
//
// Get the user's base virtual address from the MDL. This
// will be used as a cookie to indicate what area of the
// user's data buffer we are currently copying data into
//
virtualAddress = (PUCHAR) MmGetMdlVirtualAddress(Irp->MdlAddress);
//
// the transfer request is for totalLength. We can perform a maximum of
// the bulk input pipe's PipeInformation.MaximumPacketSize in each stage.
//
pFx2Context->MaxmimumStageSize = devExt->BulkInPipe->PipeInformation.MaximumPacketSize;
if(totalLength > devExt->BulkInPipe->PipeInformation.MaximumPacketSize) {
//
// Total length is bigger that we can send, so we will break up
// the transfer into smaller pieces.
//
stageLength = pFx2Context->MaxmimumStageSize;
} else {
//
// We can send this packet in one transfer.
//
stageLength = totalLength;
}
//
// We asked the I/O manager to supply reads and writes from user
// mode components in the form of MDLs by setting the DO_DIRECT_IO
// bit in our device object during AddDevice. This will result in
// the I/O manager sending our driver MDLs that describe the entire
// length of the user's buffer for the entire operation.
//
// However, we may need to split this single user transfer up
// into multiple "stages" so that we don't send our device
// I/O operations that exceed the maximum supported single
// transfer size. To do this, we will build what are called
// "partial MDLs" that describe only the portion of the user's
// data buffer that we will be transferring at each individual
// stage.
//
// The first step in building partial MDLs will be allocating
// a new MDL that is large enough to describe the passed in MDL.
//
pMdl = IoAllocateMdl((PVOID)virtualAddress,
totalLength,
FALSE,
FALSE,
NULL);
if(pMdl == NULL) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_READWRITE,("UsbFx2LkRead: Failed to Allocate Mdl\n"));
status = STATUS_INSUFFICIENT_RESOURCES;
ExFreePool(pFx2Context);
goto UsbFx2LkRead_Exit;
}
//
// Now, build a partial MDL out of the newly allocated
// MDL. This will map the first stageLength bytes of
// the MDL in the IRP into the newly allocated MDL
//
IoBuildPartialMdl(Irp->MdlAddress,
pMdl,
(PVOID)virtualAddress,
stageLength);
//
// Allocate an URB to be used for the transfer.
//
urb = (PURB) ExAllocatePoolWithTag(NonPagedPool,sizeof(URB),'bruO');
if(urb == NULL) {
OsrTracePrint(TRACE_LEVEL_ERROR,OSRDBG_READWRITE,("UsbFx2LkRead: Failed to allocate URB\n"));
status = STATUS_INSUFFICIENT_RESOURCES;
ExFreePool(pFx2Context);
IoFreeMdl(pMdl);
goto UsbFx2LkRead_Exit;
}
//
// Build the Transfer URB.
//
//
// Indicate that this is a read function and that we will allow short
// transfers of data.
//
urbFlags = USBD_SHORT_TRANSFER_OK | USBD_TRANSFER_DIRECTION_IN;
UsbBuildInterruptOrBulkTransferRequest(
urb,
sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
devExt->BulkInPipe->PipeInformation.PipeHandle,
NULL,
pMdl,
stageLength,
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -