1161 lines
32 KiB
C
1161 lines
32 KiB
C
/*++
|
||
|
||
Copyright (c) 1997 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
init.c
|
||
|
||
Abstract:
|
||
|
||
Common initialization routine for the AGP filter driver
|
||
|
||
Author:
|
||
|
||
John Vert (jvert) 10/22/1997
|
||
|
||
Revision History:
|
||
|
||
Elliot Shmukler (elliots) 3/24/1999 - Added support for "favored" memory
|
||
ranges for AGP physical memory allocation,
|
||
fixed some bugs.
|
||
|
||
--*/
|
||
#include "agplib.h"
|
||
|
||
//
|
||
// Local function prototypes
|
||
//
|
||
NTSTATUS
|
||
AgpAddDevice(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PDEVICE_OBJECT PhysicalDeviceObject
|
||
);
|
||
|
||
NTSTATUS
|
||
AgpBuildHackTable(
|
||
IN OUT PAGP_HACK_TABLE_ENTRY *AgpHackTable,
|
||
IN HANDLE HackTableKey
|
||
);
|
||
|
||
NTSTATUS
|
||
DriverEntry(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PUNICODE_STRING RegistryPath
|
||
);
|
||
|
||
VOID
|
||
AgpDriverUnload(
|
||
IN PDRIVER_OBJECT DriverObject
|
||
);
|
||
|
||
VOID
|
||
AgpInitFavoredMemoryRanges(
|
||
IN PTARGET_EXTENSION Extension);
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, AgpAddDevice)
|
||
#pragma alloc_text(PAGE, DriverEntry)
|
||
#pragma alloc_text(PAGE, AgpDriverUnload)
|
||
#pragma alloc_text(PAGE, AgpAttachDeviceRelations)
|
||
#pragma alloc_text(INIT, AgpBuildHackTable)
|
||
#pragma alloc_text(PAGE, AgpInitFavoredMemoryRanges)
|
||
#endif
|
||
|
||
ULONG AgpLogLevel = 0;
|
||
ULONG AgpStopLevel = 0;
|
||
PDRIVER_OBJECT AgpDriver;
|
||
GLOBALS Globals;
|
||
|
||
//
|
||
// Table of hacks for broken hardware read from the registry at init
|
||
//
|
||
PAGP_HACK_TABLE_ENTRY AgpDeviceHackTable = NULL;
|
||
PAGP_HACK_TABLE_ENTRY AgpGlobalHackTable = NULL;
|
||
|
||
#define HACKFMT_VENDORDEV (sizeof(L"VVVVDDDD") - sizeof(UNICODE_NULL))
|
||
#define HACKFMT_VENDORDEVREVISION (sizeof(L"VVVVDDDDRR") - sizeof(UNICODE_NULL))
|
||
#define HACKFMT_SUBSYSTEM (sizeof(L"VVVVDDDDSSSSssss") - sizeof(UNICODE_NULL))
|
||
#define HACKFMT_SUBSYSTEMREVISION (sizeof(L"VVVVDDDDSSSSssssRR") - sizeof(UNICODE_NULL))
|
||
#define HACKFMT_MAX_LENGTH HACKFMT_SUBSYSTEMREVISION
|
||
|
||
#define HACKFMT_DEVICE_OFFSET 4
|
||
#define HACKFMT_SUBVENDOR_OFFSET 8
|
||
#define HACKFMT_SUBSYSTEM_OFFSET 12
|
||
|
||
NTSTATUS
|
||
AgpAddDevice(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PDEVICE_OBJECT PhysicalDeviceObject
|
||
)
|
||
{
|
||
NTSTATUS Status;
|
||
PDEVICE_OBJECT Device;
|
||
PTARGET_EXTENSION Extension;
|
||
UCHAR CapabilityID;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Create our device
|
||
//
|
||
Status = IoCreateDevice(DriverObject,
|
||
sizeof(TARGET_EXTENSION) + AgpExtensionSize - sizeof(ULONGLONG),
|
||
NULL,
|
||
FILE_DEVICE_BUS_EXTENDER,
|
||
FILE_DEVICE_SECURE_OPEN, // Not really necessary in our case as we don't support create
|
||
FALSE,
|
||
&Device);
|
||
if (!NT_SUCCESS(Status)) {
|
||
AGPLOG(AGP_CRITICAL,("AgpAddDevice: IoCreateDevice failed %08lx\n",Status));
|
||
return(Status);
|
||
}
|
||
|
||
//
|
||
// Initialize the device extension
|
||
//
|
||
Extension = Device->DeviceExtension;
|
||
Extension->CommonExtension.Type = AgpTargetFilter;
|
||
Extension->CommonExtension.Deleted = FALSE;
|
||
Extension->CommonExtension.Signature = TARGET_SIG;
|
||
|
||
#if (WINVER > 0x501)
|
||
Status =
|
||
ApQueryAgpTargetBusInterface(PhysicalDeviceObject,
|
||
&Extension->CommonExtension.BusInterface,
|
||
&CapabilityID);
|
||
#else
|
||
Status = STATUS_NOT_IMPLEMENTED;
|
||
#endif // (WINVER > 0x501)
|
||
|
||
//
|
||
// Perhaps this OS doesn't support the new AGP_TARGET_BUS_INTERFACE, then
|
||
// we can still support the target bridge without using HalGet/SetBusData
|
||
// we just have to do a bit more work, and probe to see if there is an AGP
|
||
// target capability on this bridge device
|
||
//
|
||
#ifndef AGP_INTERFACE_TEST
|
||
if (!NT_SUCCESS(Status)) {
|
||
Status = ApQueryBusInterface(PhysicalDeviceObject,
|
||
&Extension->CommonExtension.BusInterface);
|
||
if (NT_SUCCESS(Status)) {
|
||
PCI_AGP_CAPABILITY TargetCap;
|
||
|
||
//
|
||
// Look for the target bride capability
|
||
//
|
||
Status = AgpLibGetTargetCapability(GET_AGP_CONTEXT(Extension),
|
||
&TargetCap);
|
||
if (NT_SUCCESS(Status)) {
|
||
CapabilityID = TargetCap.Header.CapabilityID;
|
||
|
||
//
|
||
// For our UAGP35 driver to work on older OS, we will
|
||
// attempt to override the bus interface with
|
||
// HalGet/SetBusData functions that access the host, if
|
||
// we can find an AGP capability there, otherwise we
|
||
// will leave well enough alone so other drivers will
|
||
// continue to get the same behavior they've always had,
|
||
// namely bus interface still munges whatever, and lib
|
||
// behavior defaults to traditional/non-bridge w/respect
|
||
// to resource handling
|
||
//
|
||
} else {
|
||
BUS_INTERFACE_STANDARD BusInterfaceSave;
|
||
|
||
CapabilityID = PCI_CAPABILITY_ID_AGP;
|
||
|
||
#if (WINVER < 0x502)
|
||
//
|
||
// Save the bus interface
|
||
//
|
||
BusInterfaceSave.SetBusData =
|
||
Extension->CommonExtension.BusInterface.SetBusData;
|
||
BusInterfaceSave.GetBusData =
|
||
Extension->CommonExtension.BusInterface.GetBusData;
|
||
Extension->CommonExtension.BusInterface.SetBusData =
|
||
ApLegacySetBusData;
|
||
Extension->CommonExtension.BusInterface.GetBusData =
|
||
ApLegacyGetBusData;
|
||
|
||
Status = AgpLibGetTargetCapability(GET_AGP_CONTEXT(Extension),
|
||
&TargetCap);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
Extension->CommonExtension.BusInterface.SetBusData =
|
||
BusInterfaceSave.SetBusData;
|
||
Extension->CommonExtension.BusInterface.GetBusData =
|
||
BusInterfaceSave.GetBusData;
|
||
}
|
||
#endif // (WINVER < 0x502)
|
||
|
||
Status = STATUS_SUCCESS; // We do have a bus interface
|
||
}
|
||
}
|
||
}
|
||
#endif // AGP_INTERFACE_TEST
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
|
||
AGPLOG(AGP_CRITICAL,
|
||
("AgpAddDevice: query for bus interface failed %08lx\n", Status));
|
||
IoDeleteDevice(Device);
|
||
return(STATUS_NO_SUCH_DEVICE);
|
||
}
|
||
Extension->ChildDevice = NULL;
|
||
Extension->Resources = NULL;
|
||
Extension->ResourcesTranslated = NULL;
|
||
Extension->FavoredMemory.NumRanges = 0;
|
||
Extension->FavoredMemory.Ranges = NULL;
|
||
Extension->GartBase.QuadPart = 0;
|
||
Extension->GartLengthInPages = 0;
|
||
Extension->Agp3BridgeResourceIndex = JUNK_INDEX;
|
||
|
||
if (CapabilityID == PCI_CAPABILITY_ID_AGP_TARGET) {
|
||
Extension->StartTarget = Agp3StartTargetBridge;
|
||
Extension->FilterResourceRquirements =
|
||
Agp3FilterResourceRequirementsBridge;
|
||
} else {
|
||
ASSERT(CapabilityID == PCI_CAPABILITY_ID_AGP);
|
||
Extension->StartTarget = AgpStartTargetHost;
|
||
Extension->FilterResourceRquirements =
|
||
AgpFilterResourceRequirementsHost;
|
||
}
|
||
|
||
Extension->Lock = ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), 'MFgA');
|
||
if (Extension->Lock == NULL) {
|
||
AGPLOG(AGP_CRITICAL,
|
||
("AgpAddDevice: allocation of fast mutext failed\n"));
|
||
RELEASE_BUS_INTERFACE(Extension);
|
||
IoDeleteDevice(Device);
|
||
return(STATUS_INSUFFICIENT_RESOURCES);
|
||
}
|
||
ExInitializeFastMutex(Extension->Lock);
|
||
|
||
//
|
||
// Attach to the supplied PDO
|
||
//
|
||
Extension->CommonExtension.AttachedDevice = IoAttachDeviceToDeviceStack(Device, PhysicalDeviceObject);
|
||
if (Extension->CommonExtension.AttachedDevice == NULL) {
|
||
//
|
||
// The attach failed.
|
||
//
|
||
AGPLOG(AGP_CRITICAL,
|
||
("AgpAddDevice: IoAttachDeviceToDeviceStack from %08lx to %08lx failed\n",
|
||
Device,
|
||
PhysicalDeviceObject));
|
||
RELEASE_BUS_INTERFACE(Extension);
|
||
IoDeleteDevice(Device);
|
||
return(STATUS_INSUFFICIENT_RESOURCES);
|
||
}
|
||
|
||
//
|
||
// Figure out our favored memory ranges
|
||
//
|
||
|
||
AgpInitFavoredMemoryRanges(Extension);
|
||
|
||
//
|
||
// Finally call the chipset-specific code for target initialization
|
||
//
|
||
Status = AgpInitializeTarget(GET_AGP_CONTEXT(Extension));
|
||
if (!NT_SUCCESS(Status)) {
|
||
AGPLOG(AGP_CRITICAL,
|
||
("AgpAttachDeviceRelations: AgpInitializeTarget on device %08lx failed %08lx\n",
|
||
Device,
|
||
Status));
|
||
IoDetachDevice(Extension->CommonExtension.AttachedDevice);
|
||
RELEASE_BUS_INTERFACE(Extension);
|
||
IoDeleteDevice(Device);
|
||
return(Status);
|
||
}
|
||
|
||
Extension->PDO = PhysicalDeviceObject;
|
||
Extension->Self = Device;
|
||
|
||
Status = AgpWmiRegistration(Extension);
|
||
if (!NT_SUCCESS(Status)) {
|
||
AGPLOG(AGP_CRITICAL, ("AgpWmiRegistration failed %08lx\n", Status));
|
||
IoDetachDevice(Extension->CommonExtension.AttachedDevice);
|
||
RELEASE_BUS_INTERFACE(Extension);
|
||
IoDeleteDevice(Device);
|
||
return Status;
|
||
}
|
||
|
||
Device->Flags &= ~DO_DEVICE_INITIALIZING;
|
||
|
||
return(STATUS_SUCCESS);
|
||
|
||
}
|
||
|
||
NTSTATUS
|
||
AgpBuildHackTable(
|
||
IN OUT PAGP_HACK_TABLE_ENTRY *AgpHackTable,
|
||
IN HANDLE HackTableKey
|
||
)
|
||
{
|
||
|
||
NTSTATUS status;
|
||
PKEY_FULL_INFORMATION keyInfo = NULL;
|
||
ULONG hackCount, size, index;
|
||
USHORT temp;
|
||
PAGP_HACK_TABLE_ENTRY entry;
|
||
ULONGLONG data;
|
||
PKEY_VALUE_FULL_INFORMATION valueInfo = NULL;
|
||
ULONG valueInfoSize = sizeof(KEY_VALUE_FULL_INFORMATION)
|
||
+ HACKFMT_MAX_LENGTH +
|
||
+ sizeof(ULONGLONG);
|
||
|
||
//
|
||
// Get the key info so we know how many hack values there are.
|
||
// This does not change during system initialization.
|
||
//
|
||
|
||
status = ZwQueryKey(HackTableKey,
|
||
KeyFullInformation,
|
||
NULL,
|
||
0,
|
||
&size
|
||
);
|
||
|
||
if (status != STATUS_BUFFER_TOO_SMALL) {
|
||
ASSERT(!NT_SUCCESS(status));
|
||
goto cleanup;
|
||
}
|
||
|
||
ASSERT(size > 0);
|
||
|
||
keyInfo = ExAllocatePool(PagedPool, size);
|
||
|
||
if (!keyInfo) {
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto cleanup;
|
||
}
|
||
|
||
status = ZwQueryKey(HackTableKey,
|
||
KeyFullInformation,
|
||
keyInfo,
|
||
size,
|
||
&size
|
||
);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
goto cleanup;
|
||
}
|
||
|
||
hackCount = keyInfo->Values;
|
||
|
||
ExFreePool(keyInfo);
|
||
keyInfo = NULL;
|
||
|
||
//
|
||
// Allocate and initialize the hack table
|
||
//
|
||
|
||
*AgpHackTable = ExAllocatePool(NonPagedPool,
|
||
(hackCount + 1) * sizeof(AGP_HACK_TABLE_ENTRY)
|
||
);
|
||
|
||
if (!*AgpHackTable) {
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto cleanup;
|
||
}
|
||
|
||
|
||
//
|
||
// Allocate a valueInfo buffer big enough for the biggest valid
|
||
// format and a ULONGLONG worth of data.
|
||
//
|
||
|
||
valueInfo = ExAllocatePool(PagedPool, valueInfoSize);
|
||
|
||
if (!valueInfo) {
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto cleanup;
|
||
}
|
||
|
||
entry = *AgpHackTable;
|
||
|
||
for (index = 0; index < hackCount; index++) {
|
||
|
||
status = ZwEnumerateValueKey(HackTableKey,
|
||
index,
|
||
KeyValueFullInformation,
|
||
valueInfo,
|
||
valueInfoSize,
|
||
&size
|
||
);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL) {
|
||
//
|
||
// All out data is of fixed length and the buffer is big enough
|
||
// so this can't be for us.
|
||
//
|
||
|
||
continue;
|
||
} else {
|
||
goto cleanup;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Get pointer to the data if its of the right type
|
||
//
|
||
|
||
if ((valueInfo->Type == REG_BINARY) &&
|
||
(valueInfo->DataLength == sizeof(ULONGLONG))) {
|
||
data = *(ULONGLONG UNALIGNED *)(((PUCHAR)valueInfo) + valueInfo->DataOffset);
|
||
} else {
|
||
//
|
||
// We only deal in ULONGLONGs
|
||
//
|
||
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Now see if the name is formatted like we expect it to be:
|
||
// VVVVDDDD
|
||
// VVVVDDDDRR
|
||
// VVVVDDDDSSSSssss
|
||
// VVVVDDDDSSSSssssRR
|
||
|
||
if ((valueInfo->NameLength != HACKFMT_VENDORDEV) &&
|
||
(valueInfo->NameLength != HACKFMT_VENDORDEVREVISION) &&
|
||
(valueInfo->NameLength != HACKFMT_SUBSYSTEM) &&
|
||
(valueInfo->NameLength != HACKFMT_SUBSYSTEMREVISION)) {
|
||
|
||
//
|
||
// This isn't ours
|
||
//
|
||
|
||
AGPLOG(
|
||
AGP_CRITICAL,
|
||
("Skipping hack entry with invalid length name\n"
|
||
));
|
||
|
||
continue;
|
||
}
|
||
|
||
|
||
//
|
||
// This looks plausable - try to parse it and fill in a hack table
|
||
// entry
|
||
//
|
||
|
||
RtlZeroMemory(entry, sizeof(AGP_HACK_TABLE_ENTRY));
|
||
|
||
//
|
||
// Look for DeviceID and VendorID (VVVVDDDD)
|
||
//
|
||
|
||
if (!AgpStringToUSHORT(valueInfo->Name, &entry->VendorID)) {
|
||
continue;
|
||
}
|
||
|
||
if (!AgpStringToUSHORT(valueInfo->Name + HACKFMT_DEVICE_OFFSET,
|
||
&entry->DeviceID)) {
|
||
continue;
|
||
}
|
||
|
||
|
||
//
|
||
// Look for SubsystemVendorID/SubSystemID (SSSSssss)
|
||
//
|
||
|
||
if ((valueInfo->NameLength == HACKFMT_SUBSYSTEM) ||
|
||
(valueInfo->NameLength == HACKFMT_SUBSYSTEMREVISION)) {
|
||
|
||
if (!AgpStringToUSHORT(valueInfo->Name + HACKFMT_SUBVENDOR_OFFSET,
|
||
&entry->SubVendorID)) {
|
||
continue;
|
||
}
|
||
|
||
if (!AgpStringToUSHORT(valueInfo->Name + HACKFMT_SUBSYSTEM_OFFSET,
|
||
&entry->SubSystemID)) {
|
||
continue;
|
||
}
|
||
|
||
entry->Flags |= AGP_HACK_FLAG_SUBSYSTEM;
|
||
}
|
||
|
||
//
|
||
// Look for RevisionID (RR)
|
||
//
|
||
|
||
if ((valueInfo->NameLength == HACKFMT_VENDORDEVREVISION) ||
|
||
(valueInfo->NameLength == HACKFMT_SUBSYSTEMREVISION)) {
|
||
if (AgpStringToUSHORT(valueInfo->Name +
|
||
(valueInfo->NameLength/sizeof(WCHAR) - 4), &temp)) {
|
||
entry->RevisionID = temp & 0xFF;
|
||
entry->Flags |= AGP_HACK_FLAG_REVISION;
|
||
} else {
|
||
continue;
|
||
}
|
||
}
|
||
|
||
ASSERT(entry->VendorID != 0xFFFF);
|
||
|
||
//
|
||
// Fill in the entry
|
||
//
|
||
|
||
entry->DeviceFlags = data;
|
||
|
||
AGPLOG(
|
||
AGP_CRITICAL,
|
||
("Adding Hack entry for Vendor:0x%04x Device:0x%04x ",
|
||
entry->VendorID, entry->DeviceID
|
||
));
|
||
|
||
if (entry->Flags & AGP_HACK_FLAG_SUBSYSTEM) {
|
||
AGPLOG(
|
||
AGP_CRITICAL,
|
||
("SybSys:0x%04x SubVendor:0x%04x ",
|
||
entry->SubSystemID, entry->SubVendorID
|
||
));
|
||
}
|
||
|
||
if (entry->Flags & AGP_HACK_FLAG_REVISION) {
|
||
AGPLOG(
|
||
AGP_CRITICAL,
|
||
("Revision:0x%02x",
|
||
(ULONG) entry->RevisionID
|
||
));
|
||
}
|
||
|
||
AGPLOG(
|
||
AGP_CRITICAL,
|
||
(" = 0x%I64x\n",
|
||
entry->DeviceFlags
|
||
));
|
||
|
||
entry++;
|
||
}
|
||
|
||
ASSERT(entry < (*AgpHackTable + hackCount + 1));
|
||
|
||
//
|
||
// Terminate the table with an invalid VendorID
|
||
//
|
||
|
||
entry->VendorID = 0xFFFF;
|
||
|
||
ExFreePool(valueInfo);
|
||
|
||
return STATUS_SUCCESS;
|
||
|
||
cleanup:
|
||
|
||
ASSERT(!NT_SUCCESS(status));
|
||
|
||
if (keyInfo) {
|
||
ExFreePool(keyInfo);
|
||
}
|
||
|
||
if (valueInfo) {
|
||
ExFreePool(valueInfo);
|
||
}
|
||
|
||
if (*AgpHackTable) {
|
||
ExFreePool(*AgpHackTable);
|
||
*AgpHackTable = NULL;
|
||
}
|
||
|
||
return status;
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
AgpInitFavoredMemoryRanges(
|
||
IN PTARGET_EXTENSION Extension)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Determines the optimum memory ranges for AGP physical memory
|
||
allocation by calling the ACPI BANK method provided by the
|
||
AGP northbridge in order to determine which physical memory
|
||
ranges are decoded by that northbridge.
|
||
|
||
Initializes the FavoredMemory sturcture in the target extension
|
||
with the proper ranges.
|
||
|
||
If this routine fails, then the FavoredMemory structure
|
||
is left untouched in its initialized state (i.e. no favored memory
|
||
ranges found).
|
||
|
||
Arguments:
|
||
|
||
Extension - The target extension.
|
||
|
||
|
||
Return Value:
|
||
|
||
NONE. Upon failure,
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE_OBJECT LowerPdo;
|
||
IO_STATUS_BLOCK IoStatus;
|
||
PIRP Irp;
|
||
KEVENT event;
|
||
NTSTATUS Status;
|
||
ACPI_EVAL_INPUT_BUFFER inputBuffer;
|
||
UCHAR ResultBuffer[sizeof(ACPI_EVAL_OUTPUT_BUFFER) + MAX_MBAT_SIZE];
|
||
PACPI_EVAL_OUTPUT_BUFFER outputBuffer;
|
||
PACPI_METHOD_ARGUMENT MethodArg;
|
||
PMBAT Mbat;
|
||
UCHAR i;
|
||
USHORT j;
|
||
PHYSICAL_ADDRESS MaxMemory;
|
||
|
||
//
|
||
// Maximum memory address for limiting AGP memory to below 4GB
|
||
//
|
||
|
||
MAX_MEM(MaxMemory.QuadPart);
|
||
|
||
//
|
||
// Get an event to wait on
|
||
//
|
||
|
||
KeInitializeEvent(&event, NotificationEvent, FALSE);
|
||
|
||
// Get a PDO where we will send the request IRP.
|
||
|
||
LowerPdo = Extension->CommonExtension.AttachedDevice;
|
||
|
||
//
|
||
// Initialize the input parameters and the output buffer.
|
||
//
|
||
RtlZeroMemory( &inputBuffer, sizeof(ACPI_EVAL_INPUT_BUFFER) );
|
||
inputBuffer.MethodNameAsUlong = CM_BANK_METHOD;
|
||
inputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
|
||
outputBuffer = (PACPI_EVAL_OUTPUT_BUFFER)ResultBuffer;
|
||
|
||
//
|
||
// Build the request to call the BANK method.
|
||
//
|
||
Irp = IoBuildDeviceIoControlRequest(
|
||
IOCTL_ACPI_EVAL_METHOD,
|
||
LowerPdo,
|
||
&inputBuffer,
|
||
sizeof(ACPI_EVAL_INPUT_BUFFER),
|
||
outputBuffer,
|
||
sizeof(ResultBuffer),
|
||
FALSE,
|
||
&event,
|
||
&IoStatus
|
||
);
|
||
|
||
if (!Irp)
|
||
{
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Send to the ACPI driver
|
||
//
|
||
Status = IoCallDriver ( LowerPdo, Irp);
|
||
if (Status == STATUS_PENDING)
|
||
{
|
||
KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL);
|
||
Status = IoStatus.Status;
|
||
}
|
||
|
||
if (NT_SUCCESS(Status))
|
||
{
|
||
AGPLOG(AGP_NOISE, ("AGPLIB: ACPI BANK Method Executed.\n"));
|
||
|
||
//
|
||
// Sanity check method results
|
||
//
|
||
|
||
MethodArg = outputBuffer->Argument;
|
||
if ((outputBuffer->Signature == ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE) &&
|
||
(MethodArg->DataLength >= sizeof(MBAT)) &&
|
||
(MethodArg->Type == ACPI_METHOD_ARGUMENT_BUFFER))
|
||
{
|
||
|
||
AGPLOG(AGP_NOISE, ("AGPLIB: MBAT appears valid.\n"));
|
||
|
||
//
|
||
// Grab the MBAT and see if we can parse it
|
||
//
|
||
|
||
Mbat = (PMBAT)MethodArg->Data;
|
||
|
||
if (Mbat->TableVersion == MBAT_VERSION) {
|
||
AGPLOG(AGP_NOISE, ("AGPLIB: Parsing MBAT.\n"));
|
||
|
||
//
|
||
// Calculate the number of favored ranges mentioned
|
||
// in the MBAT
|
||
//
|
||
|
||
i=Mbat->ValidEntryBitmap;
|
||
while(i)
|
||
{
|
||
Extension->FavoredMemory.NumRanges++;
|
||
i = i & (i-1);
|
||
}
|
||
|
||
AGPLOG(AGP_NOISE, ("AGPLIB: %u favored ranges found.\n",
|
||
Extension->FavoredMemory.NumRanges));
|
||
|
||
if(Extension->FavoredMemory.NumRanges == 0) return;
|
||
|
||
//
|
||
// Allocate the favored memory range structure in our device
|
||
// extension
|
||
//
|
||
|
||
Extension->FavoredMemory.Ranges =
|
||
ExAllocatePool(NonPagedPool, sizeof(AGP_MEMORY_RANGE) *
|
||
Extension->FavoredMemory.NumRanges);
|
||
|
||
if (Extension->FavoredMemory.Ranges == NULL) {
|
||
Extension->FavoredMemory.NumRanges = 0;
|
||
return;
|
||
}
|
||
|
||
|
||
//
|
||
// Initialize the favored memory ranges in our extension
|
||
// based upon the MBAT
|
||
//
|
||
|
||
i=0;
|
||
j=0;
|
||
while(Mbat->ValidEntryBitmap)
|
||
{
|
||
if (Mbat->ValidEntryBitmap & 1)
|
||
{
|
||
if (Mbat->DecodeRange[i].Lower.QuadPart > MaxMemory.QuadPart) {
|
||
// This range is invalid since its lower address is above
|
||
// the highest allowable address
|
||
|
||
AGPLOG(AGP_NOISE, ("AGPLIB: Invalid MBAT Range ==> %I64x - %I64x\n",
|
||
Mbat->DecodeRange[i].Lower.QuadPart,
|
||
Mbat->DecodeRange[i].Upper.QuadPart));
|
||
|
||
// Pretend like this range never existed ...
|
||
//
|
||
|
||
Extension->FavoredMemory.NumRanges--;
|
||
|
||
}
|
||
else
|
||
{
|
||
|
||
// This is a valid range.
|
||
|
||
Extension->FavoredMemory.Ranges[j].Lower.QuadPart =
|
||
Mbat->DecodeRange[i].Lower.QuadPart;
|
||
Extension->FavoredMemory.Ranges[j].Upper.QuadPart =
|
||
Mbat->DecodeRange[i].Upper.QuadPart;
|
||
|
||
|
||
AGPLOG(AGP_NOISE, ("AGPLIB: MBAT Range ==> %I64x - %I64x\n",
|
||
Mbat->DecodeRange[i].Lower.QuadPart,
|
||
Mbat->DecodeRange[i].Upper.QuadPart));
|
||
|
||
if(Extension->FavoredMemory.Ranges[j].Upper.QuadPart >
|
||
MaxMemory.QuadPart)
|
||
{
|
||
AGPLOG(AGP_NOISE, ("AGPLIB: Adjusting range to fit within maximum allowable address.\n"));
|
||
Extension->FavoredMemory.Ranges[j].Upper.QuadPart =
|
||
MaxMemory.QuadPart;
|
||
}
|
||
|
||
j++;
|
||
}
|
||
}
|
||
Mbat->ValidEntryBitmap >>= 1;
|
||
i++;
|
||
}
|
||
|
||
} else {
|
||
|
||
AGPLOG(AGP_WARNING, ("AGPLIB: Unknown MBAT version.\n"));
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
}
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
DriverEntry(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PUNICODE_STRING RegistryPath
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Entrypoint needed to initialize the AGP filter.
|
||
|
||
Arguments:
|
||
|
||
DriverObject - Pointer to the driver object created by the system.
|
||
|
||
RegistryPath - Pointer to the unicode registry service path.
|
||
|
||
Return Value:
|
||
|
||
NT status.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
HANDLE serviceKey, paramsKey;
|
||
UNICODE_STRING UnicodeString;
|
||
OBJECT_ATTRIBUTES attributes;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Save the RegistryPath for WMI
|
||
//
|
||
Globals.RegistryPath.MaximumLength =
|
||
RegistryPath->Length + sizeof(UNICODE_NULL);
|
||
|
||
Globals.RegistryPath.Length = RegistryPath->Length;
|
||
|
||
Globals.RegistryPath.Buffer =
|
||
ExAllocatePoolWithTag(PagedPool,
|
||
Globals.RegistryPath.MaximumLength,
|
||
'GpgA'
|
||
);
|
||
|
||
if (!Globals.RegistryPath.Buffer) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
RtlCopyUnicodeString(&Globals.RegistryPath, RegistryPath);
|
||
|
||
AgpDriver = DriverObject;
|
||
|
||
DriverObject->DriverExtension->AddDevice = AgpAddDevice;
|
||
DriverObject->DriverUnload = AgpDriverUnload;
|
||
|
||
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = AgpDispatchDeviceControl;
|
||
DriverObject->MajorFunction[IRP_MJ_PNP] = AgpDispatchPnp;
|
||
DriverObject->MajorFunction[IRP_MJ_POWER] = AgpDispatchPower;
|
||
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = AgpDispatchWmi;
|
||
|
||
RtlInitUnicodeString(&UnicodeString,
|
||
L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\"
|
||
L"Control");
|
||
|
||
//
|
||
// Open the global hack key and retrieve the gloabl hack table
|
||
//
|
||
InitializeObjectAttributes(&attributes,
|
||
&UnicodeString,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
Status = ZwOpenKey(&serviceKey,
|
||
KEY_READ,
|
||
&attributes
|
||
);
|
||
|
||
//
|
||
// We must succeed here, there are devices that can freeze a system,
|
||
// and something is really wrong if we can't access these values
|
||
//
|
||
if (!NT_SUCCESS(Status)) {
|
||
return Status;
|
||
}
|
||
|
||
AgpOpenKey(L"AGP", serviceKey, ¶msKey, &Status);
|
||
|
||
ZwClose(serviceKey);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
return Status;
|
||
}
|
||
|
||
Status = AgpBuildHackTable(&AgpGlobalHackTable, paramsKey);
|
||
|
||
ZwClose(paramsKey);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// Open our service key and retrieve any platform hack(s)
|
||
//
|
||
InitializeObjectAttributes(&attributes,
|
||
RegistryPath,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
Status = ZwOpenKey(&serviceKey,
|
||
KEY_READ,
|
||
&attributes
|
||
);
|
||
|
||
//
|
||
// Maybe their chipset is so burly, it doesn't require any hacks!
|
||
//
|
||
if (!NT_SUCCESS(Status)) {
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
AgpOpenKey(L"Parameters", serviceKey, ¶msKey, &Status);
|
||
|
||
ZwClose(serviceKey);
|
||
|
||
//
|
||
// Don't care
|
||
//
|
||
if (!NT_SUCCESS(Status)) {
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
//
|
||
// Again, disregard status
|
||
//
|
||
AgpBuildHackTable(&AgpDeviceHackTable, paramsKey);
|
||
|
||
ZwClose(paramsKey);
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
AgpDriverUnload(
|
||
IN PDRIVER_OBJECT DriverObject
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Entrypoint used to unload the AGP driver
|
||
|
||
Arguments:
|
||
|
||
DriverObject - Pointer to the driver object created by the system
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
if (AgpDeviceHackTable != NULL) {
|
||
ExFreePool(AgpDeviceHackTable);
|
||
AgpDeviceHackTable = NULL;
|
||
}
|
||
|
||
if (AgpGlobalHackTable != NULL) {
|
||
ExFreePool(AgpGlobalHackTable);
|
||
AgpGlobalHackTable = NULL;
|
||
}
|
||
|
||
if (Globals.RegistryPath.Buffer != NULL) {
|
||
ExFreePool(Globals.RegistryPath.Buffer);
|
||
Globals.RegistryPath.Buffer = NULL;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
AgpAttachDeviceRelations(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PTARGET_EXTENSION Extension
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Completion routine for BusRelations IRP_MN_QUERY_DEVICE_RELATIONS irps sent
|
||
to the PCI-PCI bridge PDO. In order to handle QUERY_INTERFACE irps sent
|
||
from the AGP device, we must attach to its PDO. That means we attach to
|
||
all the child PDOs of the PCI-PCI bridge.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Supplies the device object
|
||
|
||
Irp - Supplies the IRP_MN_QUERY_DEVICE_RELATIONS irp
|
||
|
||
Extension - Supplies the AGP device extension.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
PDEVICE_RELATIONS Relations;
|
||
ULONG i;
|
||
PDEVICE_OBJECT NewDevice;
|
||
PMASTER_EXTENSION NewExtension;
|
||
AGP_CRITICAL_ROUTINE_CONTEXT routineContext;
|
||
#if DBG
|
||
ULONG MasterCount=0;
|
||
#endif
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// If we have already attached, don't do it again.
|
||
//
|
||
if (Extension->ChildDevice != NULL) {
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
Relations = (PDEVICE_RELATIONS)Irp->IoStatus.Information;
|
||
//
|
||
// If somebody completed the IRP with success, but never
|
||
// filled in the Relations field, then assume there are
|
||
// no children and we don't have to do anything.
|
||
//
|
||
if (Relations == NULL) {
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
for (i=0; i<Relations->Count; i++) {
|
||
|
||
//
|
||
// Create a device object to attach to this PDO.
|
||
//
|
||
Status = IoCreateDevice(AgpDriver,
|
||
sizeof(MASTER_EXTENSION),
|
||
NULL,
|
||
FILE_DEVICE_BUS_EXTENDER,
|
||
0,
|
||
FALSE,
|
||
&NewDevice);
|
||
if (!NT_SUCCESS(Status)) {
|
||
AGPLOG(AGP_CRITICAL,("AgpAttachDeviceRelations: IoCreateDevice failed %08lx\n",Status));
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Initialize the device extension
|
||
//
|
||
|
||
NewExtension = NewDevice->DeviceExtension;
|
||
NewExtension->CommonExtension.Deleted = FALSE;
|
||
NewExtension->CommonExtension.Type = AgpMasterFilter;
|
||
NewExtension->CommonExtension.Signature = MASTER_SIG;
|
||
Status = ApQueryBusInterface(Relations->Objects[i], &NewExtension->CommonExtension.BusInterface);
|
||
if (!NT_SUCCESS(Status)) {
|
||
AGPLOG(AGP_CRITICAL,
|
||
("AgpAttachDeviceRelations: query for bus interface failed %08lx\n", Status));
|
||
IoDeleteDevice(NewDevice);
|
||
continue;
|
||
}
|
||
NewExtension->Target = Extension;
|
||
NewExtension->InterfaceCount = 0;
|
||
NewExtension->ReservedPages = 0;
|
||
NewExtension->StopPending = FALSE;
|
||
NewExtension->RemovePending = FALSE;
|
||
NewExtension->DisableCount = 1; // biased so that we don't give anything out
|
||
// until we see the IRP_MN_START
|
||
Extension->ChildDevice = NewExtension;
|
||
|
||
//
|
||
// Attach to the specified device
|
||
//
|
||
NewExtension->CommonExtension.AttachedDevice = IoAttachDeviceToDeviceStack(NewDevice, Relations->Objects[i]);
|
||
if (NewExtension->CommonExtension.AttachedDevice == NULL) {
|
||
//
|
||
// The attach failed. Not really fatal, AGP just won't work for that device.
|
||
//
|
||
AGPLOG(AGP_CRITICAL,
|
||
("AgpAttachDeviceRelations: IoAttachDeviceToDeviceStack from %08lx to %08lx failed\n",
|
||
NewDevice,
|
||
Relations->Objects[i]));
|
||
RELEASE_BUS_INTERFACE(NewExtension);
|
||
IoDeleteDevice(NewDevice);
|
||
Extension->ChildDevice = NULL;
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Propagate the PDO's requirements
|
||
//
|
||
NewDevice->StackSize = NewExtension->CommonExtension.AttachedDevice->StackSize + 1;
|
||
NewDevice->AlignmentRequirement = NewExtension->CommonExtension.AttachedDevice->AlignmentRequirement;
|
||
if (NewExtension->CommonExtension.AttachedDevice->Flags & DO_POWER_PAGABLE) {
|
||
NewDevice->Flags |= DO_POWER_PAGABLE;
|
||
}
|
||
|
||
//
|
||
// Finally call the chipset-specific code for master initialization
|
||
//
|
||
routineContext.Gate = 1;
|
||
routineContext.Barrier = 1;
|
||
routineContext.Routine = (PCRITICALROUTINE)AgpInitializeMaster;
|
||
routineContext.Extension = GET_AGP_CONTEXT(Extension);
|
||
routineContext.Context = &NewExtension->Capabilities;
|
||
#if (WINVER < 0x502) || defined(AGP_DEBUG_MASTER_INIT)
|
||
Status = AgpInitializeMaster(GET_AGP_CONTEXT(Extension),
|
||
&NewExtension->Capabilities);
|
||
#else
|
||
Status = (NTSTATUS)KeIpiGenericCall(AgpExecuteCriticalSystemRoutine,
|
||
(ULONG_PTR)&routineContext
|
||
);
|
||
#endif
|
||
if (!NT_SUCCESS(Status)) {
|
||
AGPLOG(AGP_CRITICAL,
|
||
("AgpAttachDeviceRelations: AgpInitializeMaster on device %08lx failed %08lx\n",
|
||
NewDevice,
|
||
Status));
|
||
IoDetachDevice(NewExtension->CommonExtension.AttachedDevice);
|
||
RELEASE_BUS_INTERFACE(NewExtension);
|
||
IoDeleteDevice(NewDevice);
|
||
Extension->ChildDevice = NULL;
|
||
continue;
|
||
}
|
||
NewDevice->Flags &= ~DO_DEVICE_INITIALIZING;
|
||
|
||
//
|
||
// We can't do this if DBG because looping through here to catch/ASSERT
|
||
// multiple AGP masters will *always* screw up our target context
|
||
//
|
||
#if 0
|
||
//
|
||
// Check to make sure there is only one AGP master on the bus. There can be more
|
||
// than one device (multifunction device) but only one must have AGP capabilities
|
||
//
|
||
MasterCount++;
|
||
ASSERT(MasterCount == 1);
|
||
#else
|
||
break;
|
||
#endif
|
||
|
||
}
|
||
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|
||
|
||
|