You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
325 lines
7.5 KiB
325 lines
7.5 KiB
/*++
|
|
|
|
Copyright (c) 1996-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
utils.c
|
|
|
|
Abstract:
|
|
|
|
This module contains assorted utility functions for PCI.SYS.
|
|
|
|
Author:
|
|
|
|
Peter Johnston (peterj) 20-Nov-1996
|
|
|
|
Revision History:
|
|
|
|
Eric Nelson (enelson) 20-Mar-2000 - kidnap registry function
|
|
|
|
--*/
|
|
|
|
#include "agplib.h"
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, AgpOpenKey)
|
|
#pragma alloc_text(PAGE, AgpStringToUSHORT)
|
|
#endif
|
|
|
|
|
|
ULONGLONG
|
|
AgpGetDeviceFlags(
|
|
IN PAGP_HACK_TABLE_ENTRY AgpHackTable,
|
|
IN USHORT VendorID,
|
|
IN USHORT DeviceID,
|
|
IN USHORT SubVendorID,
|
|
IN USHORT SubSystemID,
|
|
IN UCHAR RevisionID
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
|
|
Look in the registry for any flags for this VendorId/DeviceId.
|
|
|
|
Arguments:
|
|
|
|
VendorId PCI Vendor ID (16 bits) of the manufacturer of the
|
|
device.
|
|
|
|
DeviceId PCI Device ID (16 bits) of the device.
|
|
|
|
SubVendorID PCI SubVendorID representing the manufacturer of the
|
|
subsystem
|
|
|
|
SubSystemID PCI SubSystemID representing subsystem
|
|
|
|
RevisionID PCI Revision denoting the revision of the device
|
|
|
|
Return Value:
|
|
|
|
64 bit flags value or 0 if not found.
|
|
|
|
--*/
|
|
{
|
|
PAGP_HACK_TABLE_ENTRY current;
|
|
ULONGLONG hackFlags = 0;
|
|
ULONG match, bestMatch = 0;
|
|
|
|
if (AgpHackTable == NULL) {
|
|
return hackFlags;
|
|
}
|
|
|
|
//
|
|
// We want to do a best-case match:
|
|
// VVVVDDDDSSSSssssRR
|
|
// VVVVDDDDSSSSssss
|
|
// VVVVDDDDRR
|
|
// VVVVDDDD
|
|
//
|
|
// List is currently unsorted, so keep updating current best match.
|
|
//
|
|
|
|
for (current = AgpHackTable; current->VendorID != 0xFFFF; current++) {
|
|
match = 0;
|
|
|
|
//
|
|
// Must at least match vendor/dev
|
|
//
|
|
|
|
if ((current->DeviceID != DeviceID) ||
|
|
(current->VendorID != VendorID)) {
|
|
continue;
|
|
}
|
|
|
|
match = 1;
|
|
|
|
//
|
|
// If this entry specifies a revision, check that it is consistent.
|
|
//
|
|
|
|
if (current->Flags & AGP_HACK_FLAG_REVISION) {
|
|
if (current->RevisionID == RevisionID) {
|
|
match += 2;
|
|
} else {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If this entry specifies subsystems, check that they are consistent
|
|
//
|
|
|
|
if (current->Flags & AGP_HACK_FLAG_SUBSYSTEM) {
|
|
if (current->SubVendorID == SubVendorID &&
|
|
current->SubSystemID == SubSystemID) {
|
|
match += 4;
|
|
} else {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (match > bestMatch) {
|
|
bestMatch = match;
|
|
hackFlags = current->DeviceFlags;
|
|
}
|
|
}
|
|
|
|
return hackFlags;
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
AgpOpenKey(
|
|
IN PWSTR KeyName,
|
|
IN HANDLE ParentHandle,
|
|
OUT PHANDLE Handle,
|
|
OUT PNTSTATUS Status
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
|
|
Open a registry key.
|
|
|
|
Arguments:
|
|
|
|
KeyName Name of the key to be opened.
|
|
ParentHandle Pointer to the parent handle (OPTIONAL)
|
|
Handle Pointer to a handle to recieve the opened key.
|
|
|
|
Return Value:
|
|
|
|
TRUE is key successfully opened, FALSE otherwise.
|
|
|
|
--*/
|
|
{
|
|
UNICODE_STRING nameString;
|
|
OBJECT_ATTRIBUTES nameAttributes;
|
|
NTSTATUS localStatus;
|
|
|
|
PAGED_CODE();
|
|
|
|
RtlInitUnicodeString(&nameString, KeyName);
|
|
|
|
InitializeObjectAttributes(&nameAttributes,
|
|
&nameString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
ParentHandle,
|
|
(PSECURITY_DESCRIPTOR)NULL
|
|
);
|
|
localStatus = ZwOpenKey(Handle,
|
|
KEY_READ,
|
|
&nameAttributes
|
|
);
|
|
|
|
if (Status != NULL) {
|
|
|
|
//
|
|
// Caller wants underlying status.
|
|
//
|
|
|
|
*Status = localStatus;
|
|
}
|
|
|
|
//
|
|
// Return status converted to a boolean, TRUE if
|
|
// successful.
|
|
//
|
|
|
|
return NT_SUCCESS(localStatus);
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
AgpStringToUSHORT(
|
|
IN PWCHAR String,
|
|
OUT PUSHORT Result
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
|
|
Takes a 4 character hexidecimal sting and converts it into a USHORT.
|
|
|
|
Arguments:
|
|
|
|
String - the string
|
|
|
|
Result - the USHORT
|
|
|
|
Return Value:
|
|
|
|
TRUE is success, FASLE otherwise
|
|
|
|
--*/
|
|
{
|
|
ULONG count;
|
|
USHORT number = 0;
|
|
PWCHAR current;
|
|
|
|
current = String;
|
|
|
|
for (count = 0; count < 4; count++) {
|
|
|
|
number <<= 4;
|
|
|
|
if (*current >= L'0' && *current <= L'9') {
|
|
number |= *current - L'0';
|
|
} else if (*current >= L'A' && *current <= L'F') {
|
|
number |= *current + 10 - L'A';
|
|
} else if (*current >= L'a' && *current <= L'f') {
|
|
number |= *current + 10 - L'a';
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
|
|
current++;
|
|
}
|
|
|
|
*Result = number;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
ULONG_PTR
|
|
AgpExecuteCriticalSystemRoutine(
|
|
IN ULONG_PTR Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called in the context of KeIpiGenericCall, which
|
|
executes it on all processors. It is used to execute
|
|
a critical routine which needs all processors synchronized, such
|
|
as probing the BARs of a device that could not otherwise be turned off.
|
|
Only one context parameter is allowed in this routine, so it must
|
|
contain both the routine to execute and any context that routine
|
|
requires.
|
|
|
|
When this routine is entered, it is guaranteed that all processors will
|
|
already have been targeted with an IPI, and will be running at IPI_LEVEL.
|
|
All processors will either be running this routine, or will be about to
|
|
enter the routine. No arbitrary threads can possibly be running. No
|
|
devices can interrupt the execution of this routine, since IPI_LEVEL is
|
|
above all device IRQLs.
|
|
|
|
Because this routine runs at IPI_LEVEL, no debug prints, asserts or other
|
|
debugging can occur in this function without hanging MP machines.
|
|
|
|
Arguments:
|
|
|
|
Context - the context passed into the call to KeIpiGenericCall.
|
|
It contains the critical routine to execute, any context required
|
|
in that routine and a gate and a barrier to ensure that the critical
|
|
routine is executed on only one processor, even though this function
|
|
is executed on all processors.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS, or error
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
PAGP_CRITICAL_ROUTINE_CONTEXT routineContext =
|
|
(PAGP_CRITICAL_ROUTINE_CONTEXT)Context;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// The Gate parameter in the routineContext is preinitialized
|
|
// to 1, meaning that the first processor to reach this point
|
|
// in the routine will decrement it to 0, and succeed the if
|
|
// statement.
|
|
//
|
|
if (InterlockedDecrement(&routineContext->Gate) == 0) {
|
|
|
|
//
|
|
// This is only executed on one processor.
|
|
//
|
|
Status = (NTSTATUS)routineContext->Routine(routineContext->Extension,
|
|
routineContext->Context
|
|
);
|
|
|
|
//
|
|
// Free other processors.
|
|
//
|
|
routineContext->Barrier = 0;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Wait for gated function to complete.
|
|
//
|
|
do {
|
|
} while (routineContext->Barrier != 0);
|
|
}
|
|
|
|
return Status;
|
|
}
|