589 lines
12 KiB
C
589 lines
12 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1998 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
util.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains the code for a serial imaging devices driver
|
|||
|
miscellaneous utility functions
|
|||
|
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Vlad Sadovsky vlads 10-April-1998
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel mode
|
|||
|
|
|||
|
Revision History :
|
|||
|
|
|||
|
vlads 04/10/1998 Created first draft
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "serscan.h"
|
|||
|
#include "serlog.h"
|
|||
|
|
|||
|
#if DBG
|
|||
|
extern ULONG SerScanDebugLevel;
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SerScanSynchCompletionRoutine(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN PKEVENT Event
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is for use with synchronous IRP processing.
|
|||
|
All it does is signal an event, so the driver knows it
|
|||
|
can continue.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DriverObject - Pointer to driver object created by system.
|
|||
|
|
|||
|
Irp - Irp that just completed
|
|||
|
|
|||
|
Event - Event we'll signal to say Irp is done
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
KeSetEvent((PKEVENT) Event, 0, FALSE);
|
|||
|
|
|||
|
return (STATUS_MORE_PROCESSING_REQUIRED);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SerScanCompleteIrp(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN PVOID Context
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is for use with synchronous IRP processing.
|
|||
|
All it does is signal an event, so the driver knows it
|
|||
|
can continue.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DriverObject - Pointer to driver object created by system.
|
|||
|
|
|||
|
Irp - Irp that just completed
|
|||
|
|
|||
|
Event - Event we'll signal to say Irp is done
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
//
|
|||
|
// WORKWORK Do any post IO processing here...
|
|||
|
//
|
|||
|
|
|||
|
if (Irp->PendingReturned) {
|
|||
|
|
|||
|
IoMarkIrpPending (Irp);
|
|||
|
}
|
|||
|
|
|||
|
Status = Irp->IoStatus.Status;
|
|||
|
|
|||
|
return (Status);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SerScanCallParent(
|
|||
|
IN PDEVICE_EXTENSION Extension,
|
|||
|
IN PIRP pIrp,
|
|||
|
IN BOOLEAN Wait,
|
|||
|
IN PIO_COMPLETION_ROUTINE CompletionRoutine
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine will call the next driver in the WDM chain
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Extension - Device Extension.
|
|||
|
|
|||
|
Irp - Irp to call parent with.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PIO_STACK_LOCATION pIrpStack;
|
|||
|
PIO_STACK_LOCATION pNextIrpStack;
|
|||
|
KEVENT Event;
|
|||
|
PVOID Context;
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
|
|||
|
Context = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Prepare to call down to the parent with the I/O Request...
|
|||
|
//
|
|||
|
|
|||
|
pNextIrpStack = IoGetNextIrpStackLocation(pIrp);
|
|||
|
pNextIrpStack->MajorFunction = pIrpStack->MajorFunction;
|
|||
|
pNextIrpStack->MinorFunction = pIrpStack->MinorFunction;
|
|||
|
|
|||
|
RtlCopyMemory(&pNextIrpStack->Parameters,
|
|||
|
&pIrpStack->Parameters,
|
|||
|
sizeof(pIrpStack->Parameters.Others));
|
|||
|
|
|||
|
if (Wait) {
|
|||
|
|
|||
|
KeInitializeEvent(&Event, NotificationEvent, FALSE);
|
|||
|
|
|||
|
CompletionRoutine = SerScanSynchCompletionRoutine;
|
|||
|
Context = (PVOID)&Event;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
IoSetCompletionRoutine(
|
|||
|
pIrp,
|
|||
|
CompletionRoutine,
|
|||
|
Context,
|
|||
|
TRUE,
|
|||
|
TRUE,
|
|||
|
TRUE
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Call down to our parent
|
|||
|
//
|
|||
|
|
|||
|
Status = IoCallDriver(Extension->LowerDevice, pIrp);
|
|||
|
|
|||
|
if (Wait && Status == STATUS_PENDING) {
|
|||
|
|
|||
|
//
|
|||
|
// Still pending, wait for the IRP to complete
|
|||
|
//
|
|||
|
|
|||
|
KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
|
|||
|
|
|||
|
Status = pIrp->IoStatus.Status;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
SerScanLogError(
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PDEVICE_OBJECT DeviceObject OPTIONAL,
|
|||
|
IN PHYSICAL_ADDRESS P1,
|
|||
|
IN PHYSICAL_ADDRESS P2,
|
|||
|
IN ULONG SequenceNumber,
|
|||
|
IN UCHAR MajorFunctionCode,
|
|||
|
IN UCHAR RetryCount,
|
|||
|
IN ULONG UniqueErrorValue,
|
|||
|
IN NTSTATUS FinalStatus,
|
|||
|
IN NTSTATUS SpecificIOStatus
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine allocates an error log entry, copies the supplied data
|
|||
|
to it, and requests that it be written to the error log file.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DriverObject - Supplies a pointer to the driver object for the
|
|||
|
device.
|
|||
|
|
|||
|
DeviceObject - Supplies a pointer to the device object associated
|
|||
|
with the device that had the error, early in
|
|||
|
initialization, one may not yet exist.
|
|||
|
|
|||
|
P1,P2 - Supplies the physical addresses for the controller
|
|||
|
ports involved with the error if they are available
|
|||
|
and puts them through as dump data.
|
|||
|
|
|||
|
SequenceNumber - Supplies a ulong value that is unique to an IRP over
|
|||
|
the life of the irp in this driver - 0 generally
|
|||
|
means an error not associated with an irp.
|
|||
|
|
|||
|
MajorFunctionCode - Supplies the major function code of the irp if there
|
|||
|
is an error associated with it.
|
|||
|
|
|||
|
RetryCount - Supplies the number of times a particular operation
|
|||
|
has been retried.
|
|||
|
|
|||
|
UniqueErrorValue - Supplies a unique long word that identifies the
|
|||
|
particular call to this function.
|
|||
|
|
|||
|
FinalStatus - Supplies the final status given to the irp that was
|
|||
|
associated with this error. If this log entry is
|
|||
|
being made during one of the retries this value
|
|||
|
will be STATUS_SUCCESS.
|
|||
|
|
|||
|
SpecificIOStatus - Supplies the IO status for this particular error.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PIO_ERROR_LOG_PACKET ErrorLogEntry;
|
|||
|
PVOID ObjectToUse;
|
|||
|
SHORT DumpToAllocate;
|
|||
|
|
|||
|
if (ARGUMENT_PRESENT(DeviceObject)) {
|
|||
|
|
|||
|
ObjectToUse = DeviceObject;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
ObjectToUse = DriverObject;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
DumpToAllocate = 0;
|
|||
|
|
|||
|
if (P1.LowPart != 0 || P1.HighPart != 0) {
|
|||
|
DumpToAllocate = (SHORT) sizeof(PHYSICAL_ADDRESS);
|
|||
|
}
|
|||
|
|
|||
|
if (P2.LowPart != 0 || P2.HighPart != 0) {
|
|||
|
DumpToAllocate += (SHORT) sizeof(PHYSICAL_ADDRESS);
|
|||
|
}
|
|||
|
|
|||
|
ErrorLogEntry = IoAllocateErrorLogEntry(ObjectToUse,
|
|||
|
(UCHAR) (sizeof(IO_ERROR_LOG_PACKET) + DumpToAllocate));
|
|||
|
|
|||
|
if (!ErrorLogEntry) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
ErrorLogEntry->ErrorCode = SpecificIOStatus;
|
|||
|
ErrorLogEntry->SequenceNumber = SequenceNumber;
|
|||
|
ErrorLogEntry->MajorFunctionCode = MajorFunctionCode;
|
|||
|
ErrorLogEntry->RetryCount = RetryCount;
|
|||
|
ErrorLogEntry->UniqueErrorValue = UniqueErrorValue;
|
|||
|
ErrorLogEntry->FinalStatus = FinalStatus;
|
|||
|
ErrorLogEntry->DumpDataSize = DumpToAllocate;
|
|||
|
|
|||
|
if (DumpToAllocate) {
|
|||
|
|
|||
|
RtlCopyMemory(ErrorLogEntry->DumpData, &P1, sizeof(PHYSICAL_ADDRESS));
|
|||
|
|
|||
|
if (DumpToAllocate > sizeof(PHYSICAL_ADDRESS)) {
|
|||
|
|
|||
|
RtlCopyMemory(((PUCHAR) ErrorLogEntry->DumpData) +
|
|||
|
sizeof(PHYSICAL_ADDRESS), &P2,
|
|||
|
sizeof(PHYSICAL_ADDRESS));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
IoWriteErrorLogEntry(ErrorLogEntry);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SerScanPassThrough(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DriverObject - Supplies the driver object.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
PDEVICE_EXTENSION Extension = DeviceObject->DeviceExtension;
|
|||
|
PDEVICE_OBJECT AttachedDevice=Extension->AttachedDeviceObject;
|
|||
|
|
|||
|
if (AttachedDevice != NULL) {
|
|||
|
|
|||
|
//IoCopyCurrentIrpStackLocationToNext( Irp );
|
|||
|
|
|||
|
IoSkipCurrentIrpStackLocation(Irp);
|
|||
|
|
|||
|
return IoCallDriver(
|
|||
|
AttachedDevice,
|
|||
|
Irp
|
|||
|
);
|
|||
|
} else {
|
|||
|
|
|||
|
Irp->IoStatus.Status = STATUS_PORT_DISCONNECTED;
|
|||
|
Irp->IoStatus.Information=0L;
|
|||
|
|
|||
|
IoCompleteRequest(
|
|||
|
Irp,
|
|||
|
IO_NO_INCREMENT
|
|||
|
);
|
|||
|
|
|||
|
return STATUS_PORT_DISCONNECTED;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
RemoveReferenceAndCompleteRequest(
|
|||
|
PDEVICE_OBJECT DeviceObject,
|
|||
|
PIRP Irp,
|
|||
|
NTSTATUS StatusToReturn
|
|||
|
)
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
PDEVICE_EXTENSION Extension=(PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|||
|
LONG NewReferenceCount;
|
|||
|
|
|||
|
NewReferenceCount=InterlockedDecrement(&Extension->ReferenceCount);
|
|||
|
|
|||
|
if (NewReferenceCount == 0) {
|
|||
|
//
|
|||
|
// device is being removed, set event
|
|||
|
//
|
|||
|
|
|||
|
KeSetEvent(
|
|||
|
&Extension->RemoveEvent,
|
|||
|
0,
|
|||
|
FALSE
|
|||
|
);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
Irp->IoStatus.Status = StatusToReturn;
|
|||
|
|
|||
|
IoCompleteRequest(
|
|||
|
Irp,
|
|||
|
IO_SERIAL_INCREMENT
|
|||
|
);
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
CheckStateAndAddReference(
|
|||
|
PDEVICE_OBJECT DeviceObject,
|
|||
|
PIRP Irp
|
|||
|
)
|
|||
|
{
|
|||
|
|
|||
|
PDEVICE_EXTENSION Extension=(PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|||
|
KIRQL OldIrql;
|
|||
|
|
|||
|
InterlockedIncrement(&Extension->ReferenceCount);
|
|||
|
|
|||
|
if (Extension->Removing) {
|
|||
|
//
|
|||
|
// driver not accepting requests already
|
|||
|
//
|
|||
|
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|||
|
|
|||
|
if (irpSp->MajorFunction == IRP_MJ_POWER) {
|
|||
|
|
|||
|
PoStartNextPowerIrp(Irp);
|
|||
|
}
|
|||
|
|
|||
|
RemoveReferenceAndCompleteRequest(
|
|||
|
DeviceObject,
|
|||
|
Irp,
|
|||
|
STATUS_UNSUCCESSFUL
|
|||
|
);
|
|||
|
|
|||
|
return STATUS_UNSUCCESSFUL;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//InterlockedIncrement(&Extension->PendingIoCount);
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
RemoveReference(
|
|||
|
PDEVICE_OBJECT DeviceObject
|
|||
|
)
|
|||
|
|
|||
|
{
|
|||
|
PDEVICE_EXTENSION Extension=(PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|||
|
LONG NewReferenceCount;
|
|||
|
|
|||
|
NewReferenceCount=InterlockedDecrement(&Extension->ReferenceCount);
|
|||
|
|
|||
|
if (NewReferenceCount == 0) {
|
|||
|
//
|
|||
|
// device is being removed, set event
|
|||
|
//
|
|||
|
KeSetEvent(
|
|||
|
&Extension->RemoveEvent,
|
|||
|
0,
|
|||
|
FALSE
|
|||
|
);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
WaitForLowerDriverToCompleteIrp(
|
|||
|
PDEVICE_OBJECT TargetDeviceObject,
|
|||
|
PIRP Irp,
|
|||
|
PKEVENT Event
|
|||
|
)
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
KeResetEvent(Event);
|
|||
|
|
|||
|
IoSetCompletionRoutine(
|
|||
|
Irp,
|
|||
|
SerScanSynchCompletionRoutine,
|
|||
|
Event,
|
|||
|
TRUE,
|
|||
|
TRUE,
|
|||
|
TRUE
|
|||
|
);
|
|||
|
|
|||
|
Status = IoCallDriver(TargetDeviceObject, Irp);
|
|||
|
|
|||
|
if (Status == STATUS_PENDING) {
|
|||
|
|
|||
|
KeWaitForSingleObject(
|
|||
|
Event,
|
|||
|
Executive,
|
|||
|
KernelMode,
|
|||
|
FALSE,
|
|||
|
NULL
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
return Irp->IoStatus.Status;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
#ifdef DEAD_CODE
|
|||
|
|
|||
|
VOID
|
|||
|
SSIncrementIoCount(
|
|||
|
IN PDEVICE_OBJECT pDeviceObject
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Performs interlocked increment of pending i/o counter.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Device Object
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
PDEVICE_EXTENSION Extension;
|
|||
|
|
|||
|
Extension = (PDEVICE_EXTENSION)(pDeviceObject -> DeviceExtension);
|
|||
|
|
|||
|
InterlockedIncrement(&Extension -> PendingIoCount);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
LONG
|
|||
|
SSDecrementIoCount(
|
|||
|
IN PDEVICE_OBJECT pDeviceObject
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Performs interlocked decrement of i/o counter and when it eaches zero
|
|||
|
initiates device object destruction
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Device Object
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PDEVICE_EXTENSION Extension;
|
|||
|
LONG ioCount;
|
|||
|
|
|||
|
Extension = (PDEVICE_EXTENSION)(pDeviceObject -> DeviceExtension);
|
|||
|
|
|||
|
ioCount = InterlockedDecrement(&Extension -> PendingIoCount);
|
|||
|
|
|||
|
if (0 == ioCount) {
|
|||
|
KeSetEvent(&Extension -> PendingIoEvent,1,FALSE);
|
|||
|
}
|
|||
|
|
|||
|
return ioCount;
|
|||
|
}
|
|||
|
|
|||
|
#endif
|