2055 lines
51 KiB
C
2055 lines
51 KiB
C
|
||
/*++
|
||
|
||
Copyright (c) 1990-2000 Microsoft Corporation All Rights Reserved
|
||
|
||
Module Name:
|
||
|
||
processor.c
|
||
|
||
Abstract:
|
||
|
||
Device driver to control the processor device.
|
||
|
||
|
||
Environment:
|
||
|
||
Kernel mode
|
||
|
||
|
||
Revision History:
|
||
|
||
Eliyas Yakub Oct 6, 1998
|
||
Jake Oshins March 5, 2000
|
||
Stole Eliyas' toaster code and made a processor
|
||
driver out of it.
|
||
|
||
--*/
|
||
#include "processor.h"
|
||
#include <initguid.h>
|
||
|
||
GLOBALS Globals;
|
||
FADT HalpFixedAcpiDescTable;
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text (INIT, DriverEntry)
|
||
#pragma alloc_text (PAGE, ProcessorAddDevice)
|
||
#pragma alloc_text (PAGE, ProcessorDispatchPnp)
|
||
#pragma alloc_text (PAGE, ProcessorReadWrite)
|
||
#pragma alloc_text (PAGE, ProcessorCreateClose)
|
||
#pragma alloc_text (PAGE, ProcessorDispatchIoctl)
|
||
#pragma alloc_text (PAGE, ProcessorStartDevice)
|
||
#pragma alloc_text (PAGE, ProcessorUnload)
|
||
#pragma alloc_text (PAGE, ProcessorCanRemoveDevice)
|
||
#pragma alloc_text (PAGE, ProcessorReturnResources)
|
||
#pragma alloc_text (PAGE, ProcessorSendIrpSynchronously)
|
||
#pragma alloc_text (PAGE, RegisterStateHandlers)
|
||
#endif
|
||
|
||
NTSTATUS
|
||
DriverEntry (
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PUNICODE_STRING RegistryPath
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Installable driver initialization entry point.
|
||
This entry point is called directly by the I/O system.
|
||
|
||
Arguments:
|
||
|
||
DriverObject - pointer to the driver object
|
||
|
||
RegistryPath - pointer to a unicode string representing the path,
|
||
to driver-specific key in the registry.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS if successful,
|
||
STATUS_UNSUCCESSFUL otherwise.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
OBJECT_ATTRIBUTES objAttributes;
|
||
UNICODE_STRING callbackName;
|
||
PCALLBACK_OBJECT callback;
|
||
FADT *fadt;
|
||
|
||
#if MAX_DEBUG
|
||
TurnOnFullDebugSpew();
|
||
#endif
|
||
|
||
DebugPrint((INFO, "Built: %s %s\n", __DATE__, __TIME__));
|
||
DebugEnter();
|
||
|
||
|
||
//
|
||
// Get Global Processor Flags
|
||
//
|
||
|
||
GetRegistryDwordValue(PROCESSOR_PARAMETERS_REG_PATH,
|
||
PROCESSOR_GLOBAL_FLAGS_REG_KEY,
|
||
&Globals.HackFlags);
|
||
|
||
|
||
//
|
||
// Save the RegistryPath.
|
||
//
|
||
|
||
Globals.DriverObject = DriverObject;
|
||
Globals.RegistryPath.MaximumLength = RegistryPath->Length + sizeof(UNICODE_NULL);
|
||
Globals.RegistryPath.Length = RegistryPath->Length;
|
||
Globals.RegistryPath.Buffer = ExAllocatePoolWithTag(PagedPool,
|
||
Globals.RegistryPath.MaximumLength,
|
||
PROCESSOR_POOL_TAG);
|
||
|
||
if (!Globals.RegistryPath.Buffer) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
RtlCopyUnicodeString(&Globals.RegistryPath, RegistryPath);
|
||
|
||
DriverObject->MajorFunction[IRP_MJ_PNP] = ProcessorDispatchPnp;
|
||
DriverObject->MajorFunction[IRP_MJ_POWER] = ProcessorDispatchPower;
|
||
DriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL] = ProcessorDispatchIoctl;
|
||
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = ProcessorSystemControl;
|
||
DriverObject->DriverExtension->AddDevice = ProcessorAddDevice;
|
||
DriverObject->DriverUnload = ProcessorUnload;
|
||
|
||
|
||
//
|
||
// Register callback that tells us to make
|
||
// anything we need for sleeping non-pageable.
|
||
//
|
||
|
||
RtlInitUnicodeString(&callbackName, L"\\Callback\\PowerState");
|
||
|
||
InitializeObjectAttributes(&objAttributes,
|
||
&callbackName,
|
||
OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
|
||
NULL,
|
||
NULL);
|
||
|
||
ExCreateCallback(&callback,
|
||
&objAttributes,
|
||
FALSE,
|
||
TRUE);
|
||
|
||
Globals.CallbackRegistration = ExRegisterCallback(callback,
|
||
ProcessorPowerStateCallback,
|
||
NULL);
|
||
|
||
|
||
//
|
||
// copy fadt
|
||
//
|
||
|
||
fadt = (FADT*) GetAcpiTable(FADT_SIGNATURE);
|
||
|
||
if (fadt) {
|
||
|
||
RtlCopyMemory(&HalpFixedAcpiDescTable, fadt, fadt->Header.Length);
|
||
ExFreePool(fadt);
|
||
|
||
} else {
|
||
|
||
DebugAssert(!"GetAcpiTable(FACP) Failed!");
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// Parse MAPIC tables, store processor information in Globals
|
||
//
|
||
|
||
status = ProcessMultipleApicDescTable(&Globals.ProcInfo);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// no MAPIC table, then we are a single proc machine.
|
||
//
|
||
|
||
Globals.ProcInfo.ActiveProcessors = 1;
|
||
Globals.ProcInfo.TotalProcessors = 1;
|
||
|
||
}
|
||
|
||
|
||
if (Globals.ProcInfo.ActiveProcessors == 1) {
|
||
Globals.SingleProcessorProfile = TRUE;
|
||
}
|
||
|
||
|
||
//
|
||
// Call family specific driver
|
||
//
|
||
|
||
InitializeDriver(&Globals.RegistryPath);
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
NTSTATUS
|
||
ProcessorAddDevice (
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PDEVICE_OBJECT PhysicalDeviceObject
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The Plug & Play subsystem is handing us a brand new PDO, for which we
|
||
(by means of INF registration) have been asked to provide a driver.
|
||
|
||
We need to determine if we need to be in the driver stack for the device.
|
||
Create a function device object to attach to the stack
|
||
Initialize that device object
|
||
Return status success.
|
||
|
||
Remember: We can NOT actually send ANY non-pnp IRPS to the given driver
|
||
stack, UNTIL we have received an IRP_MN_START_DEVICE.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - pointer to a device object.
|
||
|
||
PhysicalDeviceObject - pointer to a device object created by the
|
||
underlying bus driver.
|
||
|
||
Return Value:
|
||
|
||
NT status code.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
PDEVICE_OBJECT deviceObject = NULL;
|
||
PFDO_DATA fdoData;
|
||
POWER_STATE powerState;
|
||
|
||
DebugEnter();
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Create a function device object.
|
||
//
|
||
|
||
status = IoCreateDevice(DriverObject,
|
||
sizeof(FDO_DATA),
|
||
NULL, // No Name
|
||
FILE_DEVICE_UNKNOWN,
|
||
FILE_DEVICE_SECURE_OPEN,
|
||
FALSE,
|
||
&deviceObject);
|
||
|
||
|
||
if (!NT_SUCCESS (status)) {
|
||
|
||
//
|
||
// returning failure here prevents the entire stack from functioning,
|
||
// but most likely the rest of the stack will not be able to create
|
||
// device objects either, so it is still OK.
|
||
//
|
||
|
||
goto ProcessorAddDeviceExit;
|
||
}
|
||
|
||
RtlZeroMemory(deviceObject->DeviceExtension, sizeof(FDO_DATA));
|
||
DebugPrint((TRACE, " pdo=0x%x, new fdo=0x%x\n",
|
||
PhysicalDeviceObject,
|
||
deviceObject));
|
||
|
||
//
|
||
// Initialize the device extension.
|
||
//
|
||
|
||
fdoData = (PFDO_DATA) deviceObject->DeviceExtension;
|
||
|
||
//
|
||
// Set the initial state of the FDO
|
||
//
|
||
|
||
INITIALIZE_PNP_STATE(fdoData);
|
||
|
||
fdoData->UnderlyingPDO = PhysicalDeviceObject;
|
||
|
||
//
|
||
// We will hold all requests until we are started.
|
||
// On W2K we will not get any I/O until the entire device
|
||
// is started. On Win9x this may be required.
|
||
//
|
||
|
||
fdoData->QueueState = HoldRequests;
|
||
|
||
fdoData->Self = deviceObject;
|
||
fdoData->NextLowerDriver = NULL;
|
||
|
||
InitializeListHead(&fdoData->NewRequestsQueue);
|
||
KeInitializeSpinLock(&fdoData->QueueLock);
|
||
|
||
//
|
||
// Initialize the remove event to Not-Signaled
|
||
//
|
||
|
||
KeInitializeEvent(&fdoData->RemoveEvent, SynchronizationEvent, FALSE);
|
||
|
||
//
|
||
// Initialize the stop event to Signaled:
|
||
// there are no Irps that prevent the device from being
|
||
// stopped. This event will be set when the OutstandingIO
|
||
// will become 1.
|
||
//
|
||
|
||
KeInitializeEvent(&fdoData->StopEvent, SynchronizationEvent, TRUE);
|
||
|
||
fdoData->OutstandingIO = 1; // biased to 1. Transition to zero during
|
||
// remove device means IO is finished.
|
||
// Transition to 1 means the device can be
|
||
// stopped.
|
||
|
||
//
|
||
// Initialize the structures that protect the performance states.
|
||
//
|
||
|
||
KeInitializeEvent(&fdoData->PerfStateLock, SynchronizationEvent, TRUE);
|
||
|
||
deviceObject->Flags |= DO_POWER_PAGABLE;
|
||
deviceObject->Flags |= DO_BUFFERED_IO;
|
||
|
||
|
||
//
|
||
// Typically, the function driver for a device is its
|
||
// power policy owner, although for some devices another
|
||
// driver or system component may assume this role.
|
||
// Set the initial power state of the device, if known, by calling
|
||
// PoSetPowerState.
|
||
//
|
||
|
||
fdoData->DevicePowerState = PowerDeviceD0;
|
||
fdoData->SystemPowerState = PowerSystemWorking;
|
||
|
||
powerState.DeviceState = PowerDeviceD0;
|
||
PoSetPowerState ( deviceObject, DevicePowerState, powerState );
|
||
|
||
|
||
//
|
||
// Attach our driver to the device stack.
|
||
// The return value of IoAttachDeviceToDeviceStack is the top of the
|
||
// attachment chain. This is where all the IRPs should be routed.
|
||
//
|
||
|
||
fdoData->NextLowerDriver = IoAttachDeviceToDeviceStack(deviceObject,
|
||
PhysicalDeviceObject);
|
||
if (!fdoData->NextLowerDriver) {
|
||
|
||
IoDeleteDevice(deviceObject);
|
||
status = STATUS_NO_SUCH_DEVICE;
|
||
goto ProcessorAddDeviceExit;
|
||
}
|
||
|
||
//
|
||
// Pick up ACPI interfaces.
|
||
//
|
||
|
||
status = AcquireAcpiInterfaces(fdoData);
|
||
|
||
if (!NT_SUCCESS (status)) {
|
||
DebugPrint((ERROR, "AddDevice: AcquireAcpiInterfaces failed (%x)\n", status));
|
||
IoDetachDevice(fdoData->NextLowerDriver);
|
||
IoDeleteDevice (deviceObject);
|
||
goto ProcessorAddDeviceExit;
|
||
}
|
||
|
||
|
||
//
|
||
// Initialize our saved state.
|
||
//
|
||
|
||
fdoData->SavedState = (ULONG)-1;
|
||
|
||
|
||
//
|
||
// Clear the DO_DEVICE_INITIALIZING flag.
|
||
// Note: Do not clear this flag until the driver has set the
|
||
// device power state and the power DO flags.
|
||
//
|
||
|
||
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
||
|
||
ProcessorAddDeviceExit:
|
||
|
||
DebugExitStatus(status);
|
||
return status;
|
||
}
|
||
NTSTATUS
|
||
ProcessorDispatchPnp (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The plug and play dispatch routines.
|
||
|
||
Most of these requests the driver will completely ignore.
|
||
In all cases it must pass on the IRP to the lower driver.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - pointer to a device object.
|
||
|
||
Irp - pointer to an I/O Request Packet.
|
||
|
||
Return Value:
|
||
|
||
NT status code
|
||
|
||
--*/
|
||
{
|
||
PFDO_DATA fdoData;
|
||
PIO_STACK_LOCATION stack;
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
PDEVICE_CAPABILITIES deviceCapabilities;
|
||
ULONG requestCount;
|
||
PPNP_DEVICE_STATE deviceState;
|
||
|
||
|
||
DebugEnter();
|
||
PAGED_CODE();
|
||
|
||
fdoData = (PFDO_DATA) DeviceObject->DeviceExtension;
|
||
|
||
stack = IoGetCurrentIrpStackLocation (Irp);
|
||
|
||
DebugPrint((TRACE, "FDO %s\n",
|
||
PnPMinorFunctionString(stack->MinorFunction)));
|
||
|
||
if (Deleted == fdoData->DevicePnPState) {
|
||
|
||
//
|
||
// Since the device is removed, we will not hold any IRPs.
|
||
// We just fail it.
|
||
//
|
||
Irp->IoStatus.Status = STATUS_DELETE_PENDING;
|
||
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
||
return STATUS_DELETE_PENDING;
|
||
}
|
||
|
||
ProcessorIoIncrement (fdoData);
|
||
switch (stack->MinorFunction) {
|
||
case IRP_MN_START_DEVICE:
|
||
|
||
//
|
||
// The device is starting.
|
||
//
|
||
// We cannot touch the device (send it any non pnp irps) until a
|
||
// start device has been passed down to the lower drivers.
|
||
// First pass the IRP down.
|
||
//
|
||
|
||
status = ProcessorSendIrpSynchronously(fdoData->NextLowerDriver, Irp);
|
||
if (NT_SUCCESS (status)) {
|
||
//
|
||
// Lower drivers have finished their start operation, so now
|
||
// we can finish ours.
|
||
//
|
||
status = ProcessorStartDevice (fdoData, Irp);
|
||
}
|
||
|
||
//
|
||
// We must now complete the IRP, since we stopped it in the
|
||
// completion routine with MORE_PROCESSING_REQUIRED.
|
||
//
|
||
break;
|
||
|
||
|
||
case IRP_MN_QUERY_STOP_DEVICE:
|
||
|
||
//
|
||
// Processors cannot be stopped.
|
||
//
|
||
|
||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||
break;
|
||
|
||
case IRP_MN_CANCEL_STOP_DEVICE:
|
||
|
||
//
|
||
// Send this IRP down and wait for it to come back.
|
||
// Set the QueueState flag to AllowRequests,
|
||
// and process all the previously queued up IRPs.
|
||
//
|
||
|
||
//
|
||
// First check to see whether you have received cancel-stop
|
||
// without first receiving a query-stop. This could happen if someone
|
||
// above us fails a query-stop and passes down the subsequent
|
||
// cancel-stop.
|
||
//
|
||
|
||
status = ProcessorSendIrpSynchronously(fdoData->NextLowerDriver,Irp);
|
||
if(NT_SUCCESS(status)) {
|
||
|
||
if(StopPending == fdoData->DevicePnPState) {
|
||
|
||
fdoData->QueueState = AllowRequests;
|
||
|
||
RESTORE_PREVIOUS_PNP_STATE(fdoData);
|
||
|
||
ASSERT(fdoData->DevicePnPState == Started);
|
||
//
|
||
// Process the queued requests
|
||
//
|
||
|
||
ProcessorProcessQueuedRequests(fdoData);
|
||
}
|
||
}
|
||
|
||
break;
|
||
|
||
case IRP_MN_STOP_DEVICE:
|
||
|
||
//
|
||
// We should never get here.
|
||
//
|
||
|
||
ASSERTMSG("Processors don't stop. Fatal error!", FALSE);
|
||
return STATUS_INVALID_DEVICE_REQUEST;
|
||
|
||
case IRP_MN_QUERY_REMOVE_DEVICE:
|
||
|
||
//
|
||
// If we can allow removal of the device, we should set the QueueState
|
||
// to HoldRequests so further requests will be queued. This is required
|
||
// so that we can process queued up requests in cancel-remove just in
|
||
// case somebody else in the stack fails the query-remove.
|
||
//
|
||
|
||
status = ProcessorCanRemoveDevice(DeviceObject, Irp);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// Now prepare to hold the new ones (eventually we might
|
||
// get a IRP_MN_CANCEL_REMOVE_DEVICE) and we need to
|
||
// process the queued requests then.
|
||
//
|
||
|
||
fdoData->QueueState = HoldRequests;
|
||
|
||
SET_NEW_PNP_STATE(fdoData, RemovePending);
|
||
|
||
DebugPrint((TRACE, "Query - remove holding requests...\n"));
|
||
|
||
ProcessorIoDecrement(fdoData);
|
||
|
||
//
|
||
// Wait for all the requests to be completed
|
||
//
|
||
|
||
KeWaitForSingleObject(
|
||
&fdoData->StopEvent,
|
||
Executive, // Waiting for reason of a driver
|
||
KernelMode, // Waiting in kernel mode
|
||
FALSE, // No alert
|
||
NULL); // No timeout
|
||
|
||
|
||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
IoSkipCurrentIrpStackLocation (Irp);
|
||
|
||
status = IoCallDriver (fdoData->NextLowerDriver, Irp);
|
||
return status;
|
||
}
|
||
break;
|
||
|
||
case IRP_MN_CANCEL_REMOVE_DEVICE:
|
||
|
||
//
|
||
// We need to reset the QueueState flag to ProcessRequest,
|
||
// since the device resume its normal activities.
|
||
//
|
||
|
||
//
|
||
// First check to see whether you have received cancel-remove
|
||
// without first receiving a query-remove. This could happen if
|
||
// someone above us fails a query-remove and passes down the
|
||
// subsequent cancel-remove.
|
||
//
|
||
|
||
if(RemovePending == fdoData->DevicePnPState)
|
||
{
|
||
|
||
status = ProcessorSendIrpSynchronously(fdoData->NextLowerDriver,Irp);
|
||
|
||
if(NT_SUCCESS(status))
|
||
{
|
||
fdoData->QueueState = AllowRequests;
|
||
|
||
RESTORE_PREVIOUS_PNP_STATE(fdoData);
|
||
|
||
//
|
||
// Process the queued requests that arrived between
|
||
// QUERY_REMOVE and CANCEL_REMOVE.
|
||
//
|
||
|
||
ProcessorProcessQueuedRequests(fdoData);
|
||
} else {
|
||
//
|
||
// Nobody can fail this IRP. This is a fatal error.
|
||
//
|
||
ASSERTMSG("Cancel remove failed. Fatal error!", FALSE);
|
||
DebugPrint((TRACE, "Failure status = 0x%x\n", status));
|
||
}
|
||
}
|
||
else {
|
||
status = ProcessorSendIrpSynchronously(fdoData->NextLowerDriver,Irp);
|
||
}
|
||
|
||
break;
|
||
|
||
case IRP_MN_SURPRISE_REMOVAL:
|
||
{
|
||
PVOID parameterArray[4] = {0};
|
||
UCHAR buffer[] = "Processor driver does not support IRP_MN_SURPRISE_REMOVAL\n";
|
||
|
||
//
|
||
// Processors cannot be gracefully yanked from a running
|
||
// system.
|
||
//
|
||
|
||
KeBugCheckEx(FATAL_UNHANDLED_HARD_ERROR,
|
||
0x10000,
|
||
(ULONG_PTR) parameterArray,
|
||
(ULONG_PTR) buffer,
|
||
(ULONG_PTR) NULL);
|
||
|
||
return STATUS_INVALID_DEVICE_REQUEST;
|
||
}
|
||
|
||
|
||
case IRP_MN_REMOVE_DEVICE:
|
||
|
||
//
|
||
// For now, we can't remove processors.
|
||
//
|
||
|
||
status = ProcessorSendIrpSynchronously(fdoData->NextLowerDriver,Irp);
|
||
if (!NT_SUCCESS(status)) {
|
||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||
}
|
||
break;
|
||
|
||
#if 0
|
||
//
|
||
// The Plug & Play system has dictated the removal of this device. We
|
||
// have no choice but to detach and delete the device object.
|
||
// (If we wanted to express an interest in preventing this removal,
|
||
// we should have failed the query remove IRP).
|
||
//
|
||
|
||
|
||
if(SurpriseRemovePending != fdoData->DevicePnPState)
|
||
{
|
||
//
|
||
// This means we are here after query-remove.
|
||
// So first stop the device, disable the interface,
|
||
// return resources, and fail all the pending request,.
|
||
//
|
||
|
||
fdoData->QueueState = FailRequests;
|
||
|
||
//
|
||
// Fail all the pending request. Since the QueueState is FailRequests
|
||
// ProcessorProcessQueuedRequests will simply flush the queue,
|
||
// completing each IRP with STATUS_DELETE_PENDING
|
||
//
|
||
|
||
ProcessorProcessQueuedRequests(fdoData);
|
||
|
||
// //
|
||
// // Disable the Interface
|
||
// //
|
||
//
|
||
// status = IoSetDeviceInterfaceState(&fdoData->InterfaceName, FALSE);
|
||
//
|
||
// if (!NT_SUCCESS (status)) {
|
||
// DebugPrint((0,
|
||
// "IoSetDeviceInterfaceState failed: 0x%x\n", status));
|
||
// }
|
||
|
||
//
|
||
// Return hardware resources.
|
||
//
|
||
|
||
ProcessorReturnResources(DeviceObject);
|
||
|
||
}
|
||
|
||
SET_NEW_PNP_STATE(fdoData, Deleted);
|
||
|
||
//
|
||
// Drop ACPI interfaces.
|
||
//
|
||
|
||
status = ReleaseAcpiInterfaces(fdoData);
|
||
ASSERT(NT_SUCCESS(status));
|
||
|
||
#if 0
|
||
//
|
||
// Inform WMI to remove this DeviceObject from its
|
||
// list of providers.
|
||
//
|
||
|
||
ProcessorWmiDeRegistration(fdoData);
|
||
#endif
|
||
|
||
//
|
||
// We need two decrements here, one for the increment in
|
||
// ProcessorPnpDispatch, the other for the 1-biased value of
|
||
// OutstandingIO. Also, we need to wait that all the requests
|
||
// are served.
|
||
//
|
||
|
||
requestCount = ProcessorIoDecrement (fdoData);
|
||
|
||
//
|
||
// The requestCount is a least one here (is 1-biased)
|
||
//
|
||
ASSERT(requestCount > 0);
|
||
|
||
requestCount = ProcessorIoDecrement (fdoData);
|
||
|
||
KeWaitForSingleObject (
|
||
&fdoData->RemoveEvent,
|
||
Executive,
|
||
KernelMode,
|
||
FALSE,
|
||
NULL);
|
||
|
||
|
||
//
|
||
// Send on the remove IRP.
|
||
// We need to send the remove down the stack before we detach,
|
||
// but we don't need to wait for the completion of this operation
|
||
// (and to register a completion routine).
|
||
//
|
||
|
||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
IoSkipCurrentIrpStackLocation (Irp);
|
||
status = IoCallDriver (fdoData->NextLowerDriver, Irp);
|
||
|
||
//
|
||
// Detach the FDO from the device stack
|
||
//
|
||
IoDetachDevice (fdoData->NextLowerDriver);
|
||
|
||
/// //
|
||
/// // Free up interface memory
|
||
/// //
|
||
///
|
||
/// RtlFreeUnicodeString(&fdoData->InterfaceName);
|
||
IoDeleteDevice (fdoData->Self);
|
||
|
||
return status;
|
||
#endif
|
||
|
||
case IRP_MN_QUERY_CAPABILITIES:
|
||
|
||
status = ProcessorSendIrpSynchronously(fdoData->NextLowerDriver, Irp);
|
||
break;
|
||
|
||
case IRP_MN_QUERY_PNP_DEVICE_STATE:
|
||
|
||
//
|
||
// Pass the IRP down because the modification to the Irp is done
|
||
// on the way up.
|
||
//
|
||
|
||
status = ProcessorSendIrpSynchronously(fdoData->NextLowerDriver, Irp);
|
||
break;
|
||
|
||
default:
|
||
|
||
//
|
||
// Pass down all the unhandled Irps.
|
||
//
|
||
|
||
IoSkipCurrentIrpStackLocation (Irp);
|
||
status = IoCallDriver (fdoData->NextLowerDriver, Irp);
|
||
ProcessorIoDecrement(fdoData);
|
||
|
||
return status;
|
||
}
|
||
|
||
Irp->IoStatus.Status = status;
|
||
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
||
|
||
ProcessorIoDecrement(fdoData);
|
||
|
||
return status;
|
||
}
|
||
NTSTATUS
|
||
ProcessorDispatchPnpComplete (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PVOID Context
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
The lower-level drivers completed the pnp IRP.
|
||
Signal this to whoever registered us.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - pointer to a device object.
|
||
|
||
Irp - pointer to an I/O Request Packet.
|
||
|
||
Context - pointer to the event to be signaled.
|
||
Return Value:
|
||
|
||
NT status code
|
||
|
||
|
||
--*/
|
||
{
|
||
|
||
PKEVENT event = (PKEVENT) Context;
|
||
|
||
DebugEnter();
|
||
UNREFERENCED_PARAMETER(DeviceObject);
|
||
|
||
//
|
||
// Wait for lower drivers to be done with the Irp.
|
||
// Important thing to note here is when you allocate
|
||
// the memory for an event in the stack you must do a
|
||
// KernelMode wait instead of UserMode to prevent
|
||
// the stack from getting paged out.
|
||
//
|
||
|
||
KeSetEvent(event, IO_NO_INCREMENT, FALSE);
|
||
|
||
//
|
||
// Take the IRP back so that we can continue using it during
|
||
// the dispatch routine.
|
||
// NB: The dispatch routine will have to call IoCompleteRequest
|
||
//
|
||
|
||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||
}
|
||
NTSTATUS
|
||
ProcessorReadWrite (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Performs read/write to the Processor device.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - pointer to a device object.
|
||
|
||
Irp - pointer to an I/O Request Packet.
|
||
|
||
Return Value:
|
||
|
||
NT status code
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
PFDO_DATA fdoData;
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
|
||
DebugEnter();
|
||
PAGED_CODE();
|
||
|
||
fdoData = (PFDO_DATA) DeviceObject->DeviceExtension;
|
||
|
||
if (HoldRequests == fdoData->QueueState) {
|
||
|
||
status = ProcessorQueueRequest(fdoData, Irp);
|
||
return status;
|
||
}
|
||
|
||
ProcessorIoIncrement (fdoData);
|
||
|
||
//
|
||
// Perform read/write operation here
|
||
//
|
||
|
||
Irp->IoStatus.Information = 0; // fill in the correct length
|
||
Irp->IoStatus.Status = status;
|
||
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
||
|
||
ProcessorIoDecrement(fdoData);
|
||
|
||
return STATUS_SUCCESS;
|
||
|
||
}
|
||
NTSTATUS
|
||
ProcessorCreateClose (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Dispatch routine to handle Create/Close on the
|
||
Processor device.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - pointer to a device object.
|
||
|
||
Irp - pointer to an I/O Request Packet.
|
||
|
||
Return Value:
|
||
|
||
NT status code
|
||
|
||
--*/
|
||
{
|
||
PFDO_DATA fdoData;
|
||
NTSTATUS status;
|
||
PIO_STACK_LOCATION irpStack;
|
||
|
||
DebugEnter();
|
||
PAGED_CODE();
|
||
|
||
fdoData = (PFDO_DATA) DeviceObject->DeviceExtension;
|
||
|
||
//
|
||
// Since we don't access the hardware to process
|
||
// these two requests, we don't have to worry about
|
||
// about the current device state and whether or not
|
||
// to queue this request.
|
||
//
|
||
|
||
ProcessorIoIncrement (fdoData);
|
||
|
||
status = STATUS_SUCCESS;
|
||
irpStack = IoGetCurrentIrpStackLocation (Irp);
|
||
|
||
switch (irpStack->MajorFunction) {
|
||
case IRP_MJ_CREATE:
|
||
|
||
DebugPrint((TRACE, "Create \n"));
|
||
break;
|
||
|
||
case IRP_MJ_CLOSE:
|
||
DebugPrint((TRACE, "Close \n"));
|
||
break;
|
||
|
||
}
|
||
|
||
Irp->IoStatus.Information = 0;
|
||
Irp->IoStatus.Status = status;
|
||
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
||
|
||
ProcessorIoDecrement(fdoData);
|
||
|
||
|
||
return status;
|
||
}
|
||
NTSTATUS
|
||
ProcessorDispatchIoctl (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Handle user mode DeviceIoControl requests.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - pointer to a device object.
|
||
|
||
Irp - pointer to an I/O Request Packet.
|
||
|
||
Return Value:
|
||
|
||
NT status code
|
||
|
||
--*/
|
||
{
|
||
PIO_STACK_LOCATION irpStack;
|
||
NTSTATUS status= STATUS_SUCCESS;
|
||
PFDO_DATA fdoData;
|
||
|
||
DebugEnter();
|
||
PAGED_CODE();
|
||
|
||
fdoData = (PFDO_DATA) DeviceObject->DeviceExtension;
|
||
|
||
if (HoldRequests == fdoData->QueueState) {
|
||
|
||
status = ProcessorQueueRequest(fdoData, Irp);
|
||
return status;
|
||
}
|
||
|
||
ProcessorIoIncrement (fdoData);
|
||
|
||
irpStack = IoGetCurrentIrpStackLocation (Irp);
|
||
|
||
switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
|
||
default:
|
||
status = STATUS_INVALID_DEVICE_REQUEST;
|
||
}
|
||
|
||
Irp->IoStatus.Status = status;
|
||
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
||
ProcessorIoDecrement(fdoData);
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
ProcessorStartDevice (
|
||
IN PFDO_DATA FdoData,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Performs whatever initialization is needed to setup the
|
||
device, namely connecting to an interrupt,
|
||
setting up a DMA channel or mapping any I/O port resources.
|
||
|
||
Arguments:
|
||
|
||
Irp - pointer to an I/O Request Packet.
|
||
|
||
FdoData - pointer to a FDO_DATA structure
|
||
|
||
Return Value:
|
||
|
||
NT status code
|
||
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status = STATUS_SUCCESS;
|
||
PPROCESSOR_OBJECT_INFO objInfo;
|
||
|
||
DebugEnter();
|
||
PAGED_CODE();
|
||
|
||
FdoData->PerfStates = NULL;
|
||
|
||
//
|
||
// Set Processor Device's Friendly Name
|
||
//
|
||
|
||
SetProcessorFriendlyName(FdoData);
|
||
|
||
|
||
//
|
||
// Query the ACPI driver to get the info from the ACPI
|
||
// processor object.
|
||
//
|
||
|
||
status = AcpiEvaluateProcessorObject(FdoData, &objInfo);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
DebugPrint((TRACE, "Failed to get processor information from ACPI\n"));
|
||
return status;
|
||
}
|
||
|
||
RtlCopyMemory(&FdoData->ProcObjInfo, objInfo, sizeof(PROCESSOR_OBJECT_INFO));
|
||
ExFreePool(objInfo);
|
||
|
||
AcquireProcessorPerfStateLock(FdoData);
|
||
|
||
//
|
||
// Build up a notion of available C-states by looking first for
|
||
// ACPI 1.0 C-states and then for ACPI 2.0 C-states.
|
||
//
|
||
|
||
#ifdef _X86_
|
||
|
||
//
|
||
// Acpi 1.0 CStates
|
||
//
|
||
|
||
status = InitializeAcpi1Cstates(FdoData);
|
||
|
||
if (!NT_SUCCESS(status) &&
|
||
!((status == STATUS_NOT_FOUND) ||
|
||
(status == STATUS_OBJECT_NAME_NOT_FOUND))) {
|
||
DebugPrint((WARN, "Failed to initialize ACPI 1.0 C-states\n"));
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// Acpi 1.0 TStates
|
||
//
|
||
|
||
status = InitializeAcpi1TStates(FdoData);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
DebugPrint((WARN, "Failed to initialize ACPI 1.0 T-states\n"));
|
||
return status;
|
||
}
|
||
|
||
|
||
//
|
||
// Acpi 2.0 CStates
|
||
//
|
||
|
||
status = InitializeAcpi2Cstates(FdoData);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
|
||
//
|
||
// Notify the BIOS that we are taking control
|
||
//
|
||
|
||
AssumeCStateControl();
|
||
|
||
} else if ((status != STATUS_NOT_FOUND) &&
|
||
(status != STATUS_OBJECT_NAME_NOT_FOUND)) {
|
||
|
||
DebugPrint((INFO, "Failed to initialize ACPI 2.0 C-states\n"));
|
||
return status;
|
||
|
||
}
|
||
|
||
//
|
||
// Acpi 2.0 PStates/TStates or Legacy PStates/TStates
|
||
//
|
||
|
||
status = InitializeAcpi2PStates(FdoData);
|
||
|
||
if (status == STATUS_NOT_SUPPORTED) {
|
||
|
||
//
|
||
// We found an Acpi 2.0 interface, but it wasn't one we supported,
|
||
// ie Function Fixed Hardware. We need to re-init our Acpi 1.0
|
||
// throttle states.
|
||
//
|
||
|
||
status = InitializeAcpi1TStates(FdoData);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
DebugPrint((WARN, "Failed to initialize ACPI 1.0 T-states\n"));
|
||
return status;
|
||
}
|
||
|
||
}
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
status = InitializeNonAcpiPerformanceStates(FdoData);
|
||
}
|
||
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
DebugPrint((WARN, "This processor doesn't support voltage transitions\n"));
|
||
status = STATUS_SUCCESS;
|
||
}
|
||
|
||
//
|
||
// if we found Perf States, then register with WMI
|
||
//
|
||
|
||
if (FdoData->PerfStates) {
|
||
|
||
//
|
||
// Register with WMI.
|
||
//
|
||
|
||
status = ProcessorWmiRegistration(FdoData);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
DebugPrint((ERROR, "IoWMIRegistrationControl() failed! rc=0x%x\n", status));
|
||
}
|
||
}
|
||
|
||
|
||
status = RegisterStateHandlers(FdoData);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
DebugPrint((ERROR, "Failed to register C-states\n"));
|
||
return status;
|
||
}
|
||
#endif
|
||
|
||
ReleaseProcessorPerfStateLock(FdoData);
|
||
|
||
//
|
||
// Set PnP state flag
|
||
//
|
||
|
||
SET_NEW_PNP_STATE(FdoData, Started);
|
||
|
||
//
|
||
// Mark the device as active and not holding IRPs
|
||
//
|
||
|
||
FdoData->QueueState = AllowRequests;
|
||
|
||
//
|
||
// The last thing to do is to process the pending IRPs.
|
||
//
|
||
|
||
ProcessorProcessQueuedRequests(FdoData);
|
||
|
||
return status;
|
||
}
|
||
NTSTATUS
|
||
ProcessorCleanup (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The dispatch routine for cleanup: we need to walk the Irp queue and
|
||
to cancel all the requests for which the file object is the same with
|
||
the one in the Irp.
|
||
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - pointer to a device object.
|
||
|
||
Irp - pointer to an I/O Request Packet.
|
||
|
||
Return Value:
|
||
|
||
NT status code
|
||
|
||
--*/
|
||
{
|
||
PFDO_DATA fdoData;
|
||
KIRQL oldIrql;
|
||
LIST_ENTRY cleanupList;
|
||
PLIST_ENTRY thisEntry, nextEntry, listHead;
|
||
PIRP pendingIrp;
|
||
PIO_STACK_LOCATION pendingIrpStack, irpStack;
|
||
|
||
|
||
DebugEnter();
|
||
|
||
fdoData = (PFDO_DATA) DeviceObject->DeviceExtension;
|
||
ProcessorIoIncrement (fdoData);
|
||
|
||
irpStack = IoGetCurrentIrpStackLocation(Irp);
|
||
|
||
InitializeListHead(&cleanupList);
|
||
|
||
//
|
||
// We must acquire queue lock first.
|
||
//
|
||
|
||
KeAcquireSpinLock(&fdoData->QueueLock, &oldIrql);
|
||
|
||
//
|
||
// Walk through the list and remove all the IRPs
|
||
// that belong to the input irp's fileobject.
|
||
//
|
||
|
||
listHead = &fdoData->NewRequestsQueue;
|
||
for(thisEntry = listHead->Flink,nextEntry = thisEntry->Flink;
|
||
thisEntry != listHead;
|
||
thisEntry = nextEntry,nextEntry = thisEntry->Flink)
|
||
{
|
||
|
||
pendingIrp = CONTAINING_RECORD(thisEntry, IRP,
|
||
Tail.Overlay.ListEntry);
|
||
pendingIrpStack = IoGetCurrentIrpStackLocation(pendingIrp);
|
||
|
||
if (irpStack->FileObject == pendingIrpStack->FileObject)
|
||
{
|
||
RemoveEntryList(thisEntry);
|
||
|
||
//
|
||
// Set the cancel routine to NULL
|
||
//
|
||
if(NULL == IoSetCancelRoutine (pendingIrp, NULL))
|
||
{
|
||
//
|
||
// The cancel routine has run but it must be waiting to hold
|
||
// the queue lock. It will cancel the IRP as soon as we
|
||
// drop the lock outside this loop. We will initialize
|
||
// the IRP's listEntry so that the cancel routine wouldn't barf
|
||
// when it tries to remove the IRP from the queue, and
|
||
// leave the this IRP alone.
|
||
//
|
||
InitializeListHead(thisEntry);
|
||
} else {
|
||
//
|
||
// Cancel routine is not called and will never be
|
||
// called. So we queue the IRP in the cleanupList
|
||
// and cancel it after dropping the lock
|
||
//
|
||
InsertTailList(&cleanupList, thisEntry);
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Release the spin lock.
|
||
//
|
||
|
||
KeReleaseSpinLock(&fdoData->QueueLock, oldIrql);
|
||
|
||
//
|
||
// Walk through the cleanup list and cancel all
|
||
// the Irps.
|
||
//
|
||
|
||
while(!IsListEmpty(&cleanupList))
|
||
{
|
||
//
|
||
// Complete the IRP
|
||
//
|
||
|
||
thisEntry = RemoveHeadList(&cleanupList);
|
||
pendingIrp = CONTAINING_RECORD(thisEntry, IRP,
|
||
Tail.Overlay.ListEntry);
|
||
//
|
||
// You must clear the cancel routine before completing the IRP.
|
||
//
|
||
|
||
IoSetCancelRoutine (pendingIrp, NULL);
|
||
pendingIrp->IoStatus.Information = 0;
|
||
pendingIrp->IoStatus.Status = STATUS_CANCELLED;
|
||
IoCompleteRequest(pendingIrp, IO_NO_INCREMENT);
|
||
}
|
||
|
||
Irp->IoStatus.Information = 0;
|
||
Irp->IoStatus.Status = STATUS_SUCCESS;
|
||
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
||
ProcessorIoDecrement (fdoData);
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
VOID
|
||
ProcessorUnload (
|
||
IN PDRIVER_OBJECT DriverObject
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Free all the resources allocated in DriverEntry.
|
||
|
||
Arguments:
|
||
|
||
DriverObject - pointer to a driver object.
|
||
|
||
Return Value:
|
||
|
||
VOID.
|
||
|
||
--*/
|
||
{
|
||
DebugEnter();
|
||
PAGED_CODE();
|
||
|
||
// toddcar - 1/21/2001 - ISSUE
|
||
// need to finish support of unloading processor driver, also
|
||
// need to implement mechanism to call family specific driver
|
||
// code to allow them to free their resources
|
||
//
|
||
|
||
//
|
||
// The device object(s) should be NULL now
|
||
// (since we unload, all the devices objects associated with this
|
||
// driver must be deleted.
|
||
//
|
||
|
||
DebugAssert(DriverObject->DeviceObject == NULL);
|
||
|
||
//
|
||
// We should not be unloaded until all the devices we control
|
||
// have been removed from our queue.
|
||
//
|
||
|
||
if (Globals.RegistryPath.Buffer) {
|
||
ExFreePool(Globals.RegistryPath.Buffer);
|
||
}
|
||
|
||
DebugAssert(Globals.CallbackRegistration);
|
||
ExUnregisterCallback(Globals.CallbackRegistration);
|
||
|
||
return;
|
||
}
|
||
|
||
NTSTATUS
|
||
ProcessorQueueRequest (
|
||
IN OUT PFDO_DATA FdoData,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Queues the Irp in the device queue. This routine will be called whenever
|
||
the device receives IRP_MN_QUERY_STOP_DEVICE or IRP_MN_QUERY_REMOVE_DEVICE
|
||
|
||
Arguments:
|
||
|
||
FdoData - pointer to the device's extension.
|
||
|
||
Irp - the request to be queued.
|
||
|
||
Return Value:
|
||
|
||
NT status code.
|
||
|
||
--*/
|
||
{
|
||
|
||
KIRQL oldIrql;
|
||
NTSTATUS status = STATUS_PENDING;
|
||
|
||
DebugEnter();
|
||
|
||
//
|
||
// Check whether we are allowed to queue requests.
|
||
//
|
||
|
||
ASSERT(HoldRequests == FdoData->QueueState);
|
||
|
||
KeAcquireSpinLock(&FdoData->QueueLock, &oldIrql);
|
||
|
||
InsertTailList(&FdoData->NewRequestsQueue,
|
||
&Irp->Tail.Overlay.ListEntry);
|
||
|
||
IoMarkIrpPending(Irp);
|
||
|
||
//
|
||
// Set the cancel routine
|
||
//
|
||
|
||
IoSetCancelRoutine (Irp, ProcessorCancelQueued);
|
||
|
||
KeReleaseSpinLock(&FdoData->QueueLock, oldIrql);
|
||
|
||
return status;
|
||
}
|
||
|
||
VOID
|
||
ProcessorProcessQueuedRequests (
|
||
IN OUT PFDO_DATA FdoData
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Removes and processes the entries in the queue. If this routine is called
|
||
when processing IRP_MN_CANCEL_STOP_DEVICE, IRP_MN_CANCEL_REMOVE_DEVICE
|
||
or IRP_MN_START_DEVICE, the requests are passed to the next lower driver.
|
||
If the routine is called when IRP_MN_REMOVE_DEVICE is received, the IRPs
|
||
are completed with STATUS_DELETE_PENDING.
|
||
|
||
|
||
Arguments:
|
||
|
||
FdoData - pointer to the device's extension (where is the held IRPs queue).
|
||
|
||
|
||
Return Value:
|
||
|
||
VOID.
|
||
|
||
--*/
|
||
{
|
||
|
||
KIRQL oldIrql;
|
||
PIRP nextIrp, cancelledIrp;
|
||
PLIST_ENTRY listEntry;
|
||
LIST_ENTRY cancelledIrpList;
|
||
|
||
DebugEnter();
|
||
|
||
InitializeListHead(&cancelledIrpList);
|
||
|
||
//
|
||
// We need to dequeue all the entries in the queue, reset the cancel
|
||
// routine for each of them and then process then:
|
||
// - if the device is active, we will send them down
|
||
// - else we will complete them with STATUS_DELETE_PENDING
|
||
//
|
||
|
||
for(;;)
|
||
{
|
||
//
|
||
// Acquire the queue lock before manipulating the list entries.
|
||
//
|
||
KeAcquireSpinLock(&FdoData->QueueLock, &oldIrql);
|
||
|
||
if(IsListEmpty(&FdoData->NewRequestsQueue))
|
||
{
|
||
KeReleaseSpinLock(&FdoData->QueueLock, oldIrql);
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Remove a request from the queue.
|
||
//
|
||
listEntry = RemoveHeadList(&FdoData->NewRequestsQueue);
|
||
|
||
nextIrp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
|
||
|
||
//
|
||
// Check to see if it's cancelled.
|
||
//
|
||
if (nextIrp->Cancel)
|
||
{
|
||
if(IoSetCancelRoutine (nextIrp, NULL))
|
||
{
|
||
//
|
||
// This IRP was just cancelled but the cancel routine
|
||
// hasn't been called yet. So it's safe to cancel the IRP,
|
||
// Let's queue the IRP in the cancelledIrp list and complete
|
||
// them after releasing the lock. This is to ensure that
|
||
// we don't call out of the driver while holding a lock.
|
||
//
|
||
|
||
InsertTailList(&cancelledIrpList, listEntry);
|
||
} else {
|
||
//
|
||
// The cancel routine has run but it must be waiting to hold
|
||
// the queue lock. It will cancel the IRP as soon as we
|
||
// drop the lock. So initialize the IRPs
|
||
// listEntry so that the cancel routine wouldn't barf
|
||
// when it tries to remove the IRP from the queue.
|
||
//
|
||
InitializeListHead(listEntry);
|
||
}
|
||
|
||
KeReleaseSpinLock(&FdoData->QueueLock, oldIrql);
|
||
}
|
||
else
|
||
{
|
||
IoSetCancelRoutine (nextIrp, NULL);
|
||
|
||
//
|
||
// Release the lock before we call out of the driver
|
||
//
|
||
|
||
KeReleaseSpinLock(&FdoData->QueueLock, oldIrql);
|
||
|
||
if (FailRequests == FdoData->QueueState) {
|
||
//
|
||
// The device was removed, we need to fail the request
|
||
//
|
||
nextIrp->IoStatus.Information = 0;
|
||
nextIrp->IoStatus.Status = STATUS_DELETE_PENDING;
|
||
IoCompleteRequest (nextIrp, IO_NO_INCREMENT);
|
||
|
||
} else {
|
||
//
|
||
// Process the IRP. Depending on the type of the
|
||
// IRP either we pass it down or complete it here.
|
||
//
|
||
ProcessorIoIncrement (FdoData);
|
||
|
||
IoSkipCurrentIrpStackLocation (nextIrp);
|
||
IoCallDriver (FdoData->NextLowerDriver, nextIrp);
|
||
|
||
ProcessorIoDecrement(FdoData);
|
||
}
|
||
|
||
}
|
||
}// end of loop
|
||
|
||
//
|
||
// Walk through the cancelledIrp list and cancel all
|
||
// the Irps.
|
||
//
|
||
|
||
while(!IsListEmpty(&cancelledIrpList))
|
||
{
|
||
//
|
||
// Complete the IRP
|
||
//
|
||
|
||
PLIST_ENTRY listItem = RemoveHeadList(&cancelledIrpList);
|
||
cancelledIrp = CONTAINING_RECORD(listItem, IRP, Tail.Overlay.ListEntry);
|
||
cancelledIrp->IoStatus.Information = 0;
|
||
cancelledIrp->IoStatus.Status = STATUS_CANCELLED;
|
||
IoCompleteRequest(cancelledIrp, IO_NO_INCREMENT);
|
||
}
|
||
|
||
return;
|
||
|
||
}
|
||
VOID
|
||
ProcessorCancelQueued (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The cancel routine. It will remove the IRP from the queue
|
||
and will complete it. The cancel spin lock is already acquired
|
||
when this routine is called.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - pointer to the device object.
|
||
|
||
Irp - pointer to the IRP to be cancelled.
|
||
|
||
|
||
Return Value:
|
||
|
||
VOID.
|
||
|
||
--*/
|
||
{
|
||
PFDO_DATA fdoData = DeviceObject->DeviceExtension;
|
||
KIRQL oldIrql = Irp->CancelIrql;
|
||
|
||
DebugEnter();
|
||
|
||
//
|
||
// Release the cancel spinlock
|
||
//
|
||
|
||
IoReleaseCancelSpinLock( Irp->CancelIrql);
|
||
|
||
//
|
||
// Acquire the local spinlock
|
||
//
|
||
|
||
KeAcquireSpinLockAtDpcLevel(&fdoData->QueueLock);
|
||
|
||
|
||
//
|
||
// Remove the cancelled IRP from queue and
|
||
// release the queue lock.
|
||
//
|
||
RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
|
||
|
||
KeReleaseSpinLock(&fdoData->QueueLock, oldIrql);
|
||
|
||
//
|
||
// Complete the request with STATUS_CANCELLED.
|
||
//
|
||
|
||
Irp->IoStatus.Status = STATUS_CANCELLED;
|
||
Irp->IoStatus.Information = 0;
|
||
IoCompleteRequest (Irp, IO_NO_INCREMENT);
|
||
|
||
return;
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
ProcessorCanRemoveDevice (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine determines whether the device can be safely removed. In our
|
||
particular case, we'll assume we can always remove the device.
|
||
A device shouldn't be removed if, for example, it has open handles or
|
||
removing the device could result in losing data (plus the reasons
|
||
mentioned at ProcessorCanStopDevice). The PnP manager on Windows 2000 fails
|
||
on its own any attempt to remove, if there any open handles to the device.
|
||
However on Win9x, the driver must keep count of open handles and fail
|
||
query_remove if there are any open handles.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - pointer to the device object.
|
||
|
||
Irp - pointer to the current IRP.
|
||
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS if the device can be safely removed, an appropriate
|
||
NT Status if not.
|
||
|
||
--*/
|
||
{
|
||
UNREFERENCED_PARAMETER(DeviceObject);
|
||
UNREFERENCED_PARAMETER(Irp);
|
||
|
||
DebugEnter();
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// As we implement hot-plug processors, this will have to change.
|
||
//
|
||
|
||
return STATUS_INVALID_DEVICE_REQUEST;
|
||
}
|
||
|
||
NTSTATUS
|
||
ProcessorReturnResources (
|
||
IN PDEVICE_OBJECT DeviceObject
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine returns all the resources acquired during
|
||
device startup.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - pointer to the device object.
|
||
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS if the device can be safely removed, an appropriate
|
||
NT Status if not.
|
||
|
||
--*/
|
||
{
|
||
UNREFERENCED_PARAMETER(DeviceObject);
|
||
|
||
DebugEnter();
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Disconnect from the interrupt and unmap any I/O ports
|
||
// that are mapped in StartDevice.
|
||
//
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
NTSTATUS
|
||
ProcessorSendIrpSynchronously (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Sends the Irp down the stack and waits for it to complete.
|
||
|
||
Arguments:
|
||
DeviceObject - pointer to the device object.
|
||
|
||
Irp - pointer to the current IRP.
|
||
|
||
NotImplementedIsValid -
|
||
|
||
Return Value:
|
||
|
||
NT status code
|
||
|
||
--*/
|
||
{
|
||
KEVENT event;
|
||
NTSTATUS status;
|
||
|
||
DebugEnter();
|
||
PAGED_CODE();
|
||
|
||
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
||
|
||
IoCopyCurrentIrpStackLocationToNext(Irp);
|
||
|
||
IoSetCompletionRoutine(Irp,
|
||
ProcessorDispatchPnpComplete,
|
||
&event,
|
||
TRUE,
|
||
TRUE,
|
||
TRUE
|
||
);
|
||
|
||
status = IoCallDriver(DeviceObject, Irp);
|
||
|
||
//
|
||
// Wait for lower drivers to be done with the Irp.
|
||
// Important thing to note here is when you allocate
|
||
// memory for an event in the stack you must do a
|
||
// KernelMode wait instead of UserMode to prevent
|
||
// the stack from getting paged out.
|
||
//
|
||
//
|
||
|
||
if (status == STATUS_PENDING) {
|
||
KeWaitForSingleObject(&event,
|
||
Executive,
|
||
KernelMode,
|
||
FALSE,
|
||
NULL
|
||
);
|
||
status = Irp->IoStatus.Status;
|
||
}
|
||
|
||
return status;
|
||
}
|
||
LONG
|
||
ProcessorIoIncrement (
|
||
IN OUT PFDO_DATA FdoData
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine increments the number of requests the device receives
|
||
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - pointer to the device object.
|
||
|
||
Return Value:
|
||
|
||
The value of OutstandingIO field in the device extension.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
LONG result;
|
||
|
||
//DebugEnter();
|
||
|
||
result = InterlockedIncrement(&FdoData->OutstandingIO);
|
||
ASSERT(result > 0);
|
||
|
||
//
|
||
// Need to clear StopEvent (when OutstandingIO bumps from 1 to 2)
|
||
//
|
||
if (result == 2) {
|
||
//
|
||
// We need to clear the event
|
||
//
|
||
KeClearEvent(&FdoData->StopEvent);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
LONG
|
||
ProcessorIoDecrement (
|
||
IN OUT PFDO_DATA FdoData
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine decrements as it complete the request it receives
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - pointer to the device object.
|
||
|
||
Return Value:
|
||
|
||
The value of OutstandingIO field in the device extension.
|
||
|
||
|
||
--*/
|
||
{
|
||
LONG result;
|
||
|
||
//DebugEnter();
|
||
|
||
result = InterlockedDecrement(&FdoData->OutstandingIO);
|
||
ASSERT(result >= 0);
|
||
|
||
if (result == 1) {
|
||
//
|
||
// Set the stop event. Note that when this happens
|
||
// (i.e. a transition from 2 to 1), the type of requests we
|
||
// want to be processed are already held instead of being
|
||
// passed away, so that we can't "miss" a request that
|
||
// will appear between the decrement and the moment when
|
||
// the value is actually used.
|
||
//
|
||
|
||
KeSetEvent (&FdoData->StopEvent,
|
||
IO_NO_INCREMENT,
|
||
FALSE);
|
||
|
||
}
|
||
|
||
if (result == 0) {
|
||
|
||
//
|
||
// The count is 1-biased, so it can be zero only if an
|
||
// extra decrement is done when a remove Irp is received
|
||
//
|
||
|
||
ASSERT(Deleted == FdoData->DevicePnPState);
|
||
|
||
//
|
||
// Set the remove event, so the device object can be deleted
|
||
//
|
||
|
||
KeSetEvent (&FdoData->RemoveEvent,
|
||
IO_NO_INCREMENT,
|
||
FALSE);
|
||
|
||
}
|
||
|
||
|
||
return result;
|
||
}
|
||
|
||
NTSTATUS
|
||
RegisterStateHandlers (
|
||
IN PFDO_DATA DeviceExtension
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine calls the kernel with C-states and P-states.
|
||
|
||
Arguments:
|
||
|
||
DeviceExtension
|
||
|
||
Return Value:
|
||
|
||
status
|
||
|
||
--*/
|
||
{
|
||
PPROCESSOR_STATE_HANDLER2 procStates;
|
||
NTSTATUS status;
|
||
ULONG i, bufSize;
|
||
|
||
DebugEnter();
|
||
PAGED_CODE();
|
||
|
||
bufSize = sizeof(PROCESSOR_STATE_HANDLER2) +
|
||
(sizeof(PROCESSOR_PERF_LEVEL) *
|
||
(DeviceExtension->PerfStates ?
|
||
(DeviceExtension->PerfStates->Count - 1) : 0));
|
||
|
||
procStates = ExAllocatePoolWithTag(NonPagedPool,
|
||
bufSize,
|
||
PROCESSOR_POOL_TAG);
|
||
|
||
if (!procStates) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
RtlZeroMemory(procStates, bufSize);
|
||
|
||
procStates->NumIdleHandlers = DeviceExtension->CStates->Count;
|
||
DebugAssert(procStates->NumIdleHandlers <= MAX_IDLE_HANDLERS);
|
||
|
||
|
||
for (i = 0; i < procStates->NumIdleHandlers; i++) {
|
||
|
||
procStates->IdleHandler[i].HardwareLatency = DeviceExtension->CStates->State[i].Latency;
|
||
procStates->IdleHandler[i].Handler = DeviceExtension->CStates->State[i].IdleHandler;
|
||
}
|
||
|
||
#ifdef _X86_
|
||
|
||
if (DeviceExtension->PerfStates) {
|
||
|
||
procStates->SetPerfLevel = DeviceExtension->PerfStates->TransitionFunction;
|
||
procStates->HardwareLatency = DeviceExtension->PerfStates->TransitionLatency;
|
||
procStates->NumPerfStates = (UCHAR) DeviceExtension->PerfStates->Count;
|
||
|
||
for (i = 0; i < procStates->NumPerfStates; i++) {
|
||
|
||
procStates->PerfLevel[i].PercentFrequency = (UCHAR) DeviceExtension->PerfStates->State[i].PercentFrequency;
|
||
procStates->PerfLevel[i].Flags = (USHORT) DeviceExtension->PerfStates->State[i].Flags;
|
||
}
|
||
}
|
||
|
||
#endif
|
||
|
||
DumpProcessorStateHandler2Info(procStates);
|
||
|
||
status = ZwPowerInformation(ProcessorStateHandler2,
|
||
procStates,
|
||
bufSize,
|
||
NULL,
|
||
0);
|
||
|
||
ExFreePool(procStates);
|
||
return status;
|
||
}
|
||
#if DBG
|
||
VOID
|
||
DumpProcessorPerfStates (
|
||
PPROCESSOR_PERFORMANCE_STATES PerfStates
|
||
)
|
||
{
|
||
ULONG x;
|
||
|
||
DebugPrint((TRACE, "Processor Performance States (0x%p)\n", PerfStates));
|
||
DebugPrint((TRACE, " TransitionFunction: 0x%p\n", PerfStates->TransitionFunction));
|
||
DebugPrint((TRACE, " Highest Latency: %u us\n", PerfStates->TransitionLatency));
|
||
DebugPrint((TRACE, "\n"));
|
||
DebugPrint((TRACE, " State\tFrequency\t\tPower Consumption\n"));
|
||
DebugPrint((TRACE, " -----\t---------\t\t-----------------\n"));
|
||
|
||
for (x=0; x < PerfStates->Count; x++) {
|
||
|
||
DebugPrint((TRACE, " %u:\t\t%u mhz (%u%%)\t\tFlags: 0x%x\n",
|
||
x,
|
||
PerfStates->State[x].Frequency,
|
||
PerfStates->State[x].PercentFrequency,
|
||
PerfStates->State[x].Flags));
|
||
}
|
||
|
||
DebugPrint((TRACE, "\n"));
|
||
|
||
}
|
||
VOID
|
||
DumpProcessorStateHandler2Info (
|
||
PPROCESSOR_STATE_HANDLER2 StateInfo
|
||
)
|
||
{
|
||
ULONG x;
|
||
|
||
DebugPrint((TRACE, "Processor State Handler Info (0x%p)\n", StateInfo));
|
||
DebugPrint((TRACE, " NumIdleHandlers: %u\n", StateInfo->NumIdleHandlers));
|
||
|
||
for (x=0; x < MAX_IDLE_HANDLERS; x++) {
|
||
|
||
DebugPrint((TRACE, " Idle Handler #%u\n", x));
|
||
DebugPrint((TRACE, " HardwareLatency: %u\n", StateInfo->IdleHandler[x].HardwareLatency));
|
||
DebugPrint((TRACE, " Handler: 0x%p\n", StateInfo->IdleHandler[x].Handler));
|
||
|
||
}
|
||
|
||
DebugPrint((TRACE, " SetPerfLevel: 0x%p\n", StateInfo->SetPerfLevel));
|
||
DebugPrint((TRACE, " HardwareLatency: %u\n", StateInfo->HardwareLatency));
|
||
DebugPrint((TRACE, " NumPerfStates: %u\n", StateInfo->NumPerfStates));
|
||
|
||
for (x=0; x < StateInfo->NumPerfStates; x++) {
|
||
|
||
DebugPrint((TRACE, " Perf State #%u:\n", x));
|
||
DebugPrint((TRACE, " PercentFrequency: %u\n", StateInfo->PerfLevel[x].PercentFrequency));
|
||
DebugPrint((TRACE, " Flags: %u\n", StateInfo->PerfLevel[x].Flags));
|
||
|
||
}
|
||
|
||
DebugPrint((TRACE, "\n"));
|
||
}
|
||
#endif
|