Windows2003-3790/drivers/serveravailability/saport/io.cpp
2020-09-30 16:53:55 +02:00

409 lines
12 KiB
C++

/*++
Copyright (c) 1991 - 2001 Microsoft Corporation
Module Name:
#### ##### #### ##### #####
## ## ## ## # ## ## ## ##
## ## ## ## ## ## ## ##
## ## ## ## ## ## ## ##
## ## ## ## ##### #####
## ## ## ## ## # ## ##
#### ##### ## #### ## ##
Abstract:
This module contains the code to process basic I/O
requests for read and write IRPs.
Author:
Wesley Witt (wesw) 1-Oct-2001
Environment:
Kernel mode only.
Notes:
--*/
#include "internal.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,SaPortRead)
#pragma alloc_text(PAGE,SaPortWrite)
#endif
NTSTATUS
SaPortWrite(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine is the dispatch point for all writes. The function
calls the miniport specific I/O validation function to verify that
the input parameters are correct. The IRP is then marked as pending
and placed in the device queue for processing.
Arguments:
DeviceObject - The device object for the target device.
Irp - Pointer to an IRP structure that describes the requested I/O operation.
Return Value:
NT status code.
--*/
{
NTSTATUS status;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
DebugPrint(( DeviceExtension->DeviceType, SAPORT_DEBUG_INFO_LEVEL, "SaPortWrite\n" ));
if (!DeviceExtension->IsStarted) {
return CompleteRequest( Irp, STATUS_NO_SUCH_DEVICE, 0 );
}
__try {
//
// Do any device specific verification
//
if (!IS_IRP_INTERNAL( Irp )) {
switch (DeviceExtension->DriverExtension->InitData.DeviceType) {
case SA_DEVICE_DISPLAY:
status = SaDisplayIoValidation( (PDISPLAY_DEVICE_EXTENSION)DeviceExtension, Irp, IrpSp );
break;
case SA_DEVICE_KEYPAD:
status = SaKeypadIoValidation( (PKEYPAD_DEVICE_EXTENSION)DeviceExtension, Irp, IrpSp );
break;
case SA_DEVICE_NVRAM:
status = SaNvramIoValidation( (PNVRAM_DEVICE_EXTENSION)DeviceExtension, Irp, IrpSp );
break;
case SA_DEVICE_WATCHDOG:
status = SaWatchdogIoValidation( (PWATCHDOG_DEVICE_EXTENSION)DeviceExtension, Irp, IrpSp );
break;
}
if (!NT_SUCCESS(status)) {
ERROR_RETURN( DeviceExtension->DeviceType, "I/O validation failed", status );
}
}
IoMarkIrpPending( Irp );
IoStartPacket( DeviceObject, Irp, NULL, SaPortCancelRoutine );
status = STATUS_PENDING;
} __finally {
}
if (status != STATUS_PENDING) {
status = CompleteRequest( Irp, status, Irp->IoStatus.Information );
}
return status;
}
NTSTATUS
SaPortRead(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine is the dispatch point for all reads. The function
calls the miniport specific I/O validation function to verify that
the input parameters are correct. The IRP is then marked as pending
and placed in the device queue for processing.
Arguments:
DeviceObject - The device object for the target device.
Irp - Pointer to an IRP structure that describes the requested I/O operation.
Return Value:
NT status code.
--*/
{
NTSTATUS status;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
DebugPrint(( DeviceExtension->DeviceType, SAPORT_DEBUG_INFO_LEVEL, "SaPortRead\n" ));
if (!DeviceExtension->IsStarted) {
return CompleteRequest( Irp, STATUS_NO_SUCH_DEVICE, 0 );
}
__try {
if (!IS_IRP_INTERNAL( Irp )) {
//
// Do any device specific verification, but
// only if the request is NOT internal
//
switch (DeviceExtension->DriverExtension->InitData.DeviceType) {
case SA_DEVICE_DISPLAY:
status = SaDisplayIoValidation( (PDISPLAY_DEVICE_EXTENSION)DeviceExtension, Irp, IrpSp );
break;
case SA_DEVICE_KEYPAD:
status = SaKeypadIoValidation( (PKEYPAD_DEVICE_EXTENSION)DeviceExtension, Irp, IrpSp );
break;
case SA_DEVICE_NVRAM:
status = SaNvramIoValidation( (PNVRAM_DEVICE_EXTENSION)DeviceExtension, Irp, IrpSp );
break;
case SA_DEVICE_WATCHDOG:
status = SaWatchdogIoValidation( (PWATCHDOG_DEVICE_EXTENSION)DeviceExtension, Irp, IrpSp );
break;
}
if (!NT_SUCCESS(status)) {
ERROR_RETURN( DeviceExtension->DeviceType, "I/O validation failed", status );
}
}
IoMarkIrpPending( Irp );
IoStartPacket( DeviceObject, Irp, NULL, SaPortCancelRoutine );
status = STATUS_PENDING;
} __finally {
}
if (status != STATUS_PENDING) {
status = CompleteRequest( Irp, status, Irp->IoStatus.Information );
}
return status;
}
VOID
SaPortCancelRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine is the dispatch point for all IRP cancellation. Every IRP
that is pending has this function specified as the global cancel routine.
The associated miniport can specify a cancel routine that it uses for I/O
specific processing, specifically for stopping I/O on it's hardware device.
Arguments:
DeviceObject - The device object for the target device.
Irp - Pointer to an IRP structure that describes the requested I/O operation.
Return Value:
None.
--*/
{
PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
if (DeviceObject->CurrentIrp == Irp) {
IoReleaseCancelSpinLock( Irp->CancelIrql );
if (DeviceExtension->InitData->CancelRoutine) {
DeviceExtension->InitData->CancelRoutine( DeviceExtension->MiniPortDeviceExtension, Irp, TRUE );
}
CompleteRequest( Irp, STATUS_CANCELLED, 0 );
IoReleaseRemoveLock( &DeviceExtension->RemoveLock, DeviceExtension->DeviceObject->CurrentIrp );
IoStartNextPacket( DeviceExtension->DeviceObject, TRUE );
} else {
if (KeRemoveEntryDeviceQueue( &DeviceObject->DeviceQueue, &Irp->Tail.Overlay.DeviceQueueEntry )) {
IoReleaseCancelSpinLock( Irp->CancelIrql );
if (DeviceExtension->InitData->CancelRoutine) {
DeviceExtension->InitData->CancelRoutine( DeviceExtension->MiniPortDeviceExtension, Irp, FALSE );
}
CompleteRequest( Irp, STATUS_CANCELLED, 0 );
IoReleaseRemoveLock( &DeviceExtension->RemoveLock, DeviceExtension->DeviceObject->CurrentIrp );
IoStartNextPacket( DeviceExtension->DeviceObject, TRUE );
} else {
IoReleaseCancelSpinLock( Irp->CancelIrql );
}
}
}
BOOLEAN
SaPortStartIoSynchRoutine(
IN PVOID SynchronizeContext
)
/*++
Routine Description:
This routine is called through a call to KeSynchronizeExecution and is used
to synchronize the StartIO calls for a miniport with it's ISR access to any
hardware. This function is currently used for read and write IRPS only and
passes the calls through to the miniport, returning any status code to the
caller of KeSynchronizeExecution.
Arguments:
SynchronizeContext - Void pointer that is really a SAPORT_IOCONTEXT packet.
Return Value:
Always TRUE, the status code is found in IoContext->Status.
--*/
{
PSAPORT_IOCONTEXT IoContext = (PSAPORT_IOCONTEXT)SynchronizeContext;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(IoContext->Irp);
IoContext->Status = IoContext->IoRoutine(
IoContext->MiniPortDeviceExtension,
IoContext->Irp,
IrpSp->FileObject ? IrpSp->FileObject->FsContext : NULL,
IoContext->StartingOffset,
IoContext->IoBuffer,
IoContext->IoLength
);
return TRUE;
}
VOID
SaPortStartIo(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine is the dispatch point for the StartIo call by the I/O manager.
The function simply calls the associated miniport's I/O handler and completes
the IRP if the miniport returns STATUS_PENDING.
Arguments:
DeviceObject - The device object for the target device.
Irp - Pointer to an IRP structure that describes the requested I/O operation.
Return Value:
NT status code.
--*/
{
NTSTATUS Status = STATUS_SUCCESS;
PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
SAPORT_IOCONTEXT IoContext;
__try {
Status = IoAcquireRemoveLock( &DeviceExtension->RemoveLock, Irp );
if (!NT_SUCCESS(Status)) {
ERROR_RETURN( DeviceExtension->DeviceType, "IoAcquireRemoveLock failed", Status );
}
IoContext.IoBuffer = (PUCHAR) MmGetSystemAddressForMdlSafe( Irp->MdlAddress, NormalPagePriority );
if (IoContext.IoBuffer == NULL) {
ERROR_RETURN( DeviceExtension->DeviceType, "MmGetSystemAddressForMdlSafe failed", Status );
}
switch (IrpSp->MajorFunction) {
case IRP_MJ_READ:
IoContext.IoRoutine = DeviceExtension->InitData->Read;
IoContext.IoLength = IrpSp->Parameters.Read.Length;
IoContext.StartingOffset = IrpSp->Parameters.Read.ByteOffset.QuadPart;
break;
case IRP_MJ_WRITE:
IoContext.IoRoutine = DeviceExtension->InitData->Write;
IoContext.IoLength = IrpSp->Parameters.Write.Length;
IoContext.StartingOffset = IrpSp->Parameters.Write.ByteOffset.QuadPart;
break;
default:
IoContext.IoRoutine = NULL;
break;
}
if (IoContext.IoRoutine) {
if (DeviceExtension->InterruptObject) {
IoContext.MiniPortDeviceExtension = DeviceExtension->MiniPortDeviceExtension;
IoContext.Irp = Irp;
KeSynchronizeExecution(
DeviceExtension->InterruptObject,
SaPortStartIoSynchRoutine,
&IoContext
);
Status = IoContext.Status;
} else {
Status = IoContext.IoRoutine(
DeviceExtension->MiniPortDeviceExtension,
Irp,
IrpSp->FileObject ? IrpSp->FileObject->FsContext : NULL,
IoContext.StartingOffset,
IoContext.IoBuffer,
IoContext.IoLength
);
}
} else {
Status = STATUS_NOT_SUPPORTED;
}
} __finally {
}
if (Status != STATUS_SUCCESS && Status != STATUS_PENDING) {
REPORT_ERROR( DeviceExtension->DeviceType, "Miniport I/O routine failed", Status );
}
if (Status == STATUS_SUCCESS || Status != STATUS_PENDING) {
IoReleaseRemoveLock( &DeviceExtension->RemoveLock, Irp );
CompleteRequest( Irp, Status, 0 );
IoStartNextPacket( DeviceExtension->DeviceObject, TRUE );
}
}