2344 lines
57 KiB
C
2344 lines
57 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1991-2000 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
misc.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This file contains pnp isa bus extender support routines.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Shie-Lin Tzong (shielint) 27-July-1995
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel mode only.
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
#include "busp.h"
|
|||
|
#include "pnpisa.h"
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
//#pragma alloc_text(PAGE, PipLockDeviceDatabase)
|
|||
|
//#pragma alloc_text(PAGE, PipUnlockDeviceDatabase)
|
|||
|
#pragma alloc_text(PAGE, PipQueryDeviceRelations)
|
|||
|
//#pragma alloc_text(PAGE, PipIsCardEnumeratedAlready)
|
|||
|
#pragma alloc_text(PAGE, PipCleanupAcquiredResources)
|
|||
|
#pragma alloc_text(PAGE, PipMapReadDataPort)
|
|||
|
#pragma alloc_text(PAGE, PipGetMappedAddress)
|
|||
|
#pragma alloc_text(PAGE, PipDecompressEisaId)
|
|||
|
#pragma alloc_text(PAGE, PipLogError)
|
|||
|
#pragma alloc_text(PAGE, PipOpenRegistryKey)
|
|||
|
#pragma alloc_text(PAGE, PipGetRegistryValue)
|
|||
|
#pragma alloc_text(PAGE, PipOpenCurrentHwProfileDeviceInstanceKey)
|
|||
|
#pragma alloc_text(PAGE, PipGetDeviceInstanceCsConfigFlags)
|
|||
|
#pragma alloc_text(PAGE, PipDetermineResourceListSize)
|
|||
|
#pragma alloc_text(PAGE, PipResetGlobals)
|
|||
|
#pragma alloc_text(PAGE, PipMapAddressAndCmdPort)
|
|||
|
#pragma alloc_text(PAGE, PiNeedDeferISABridge)
|
|||
|
#pragma alloc_text(PAGE, PipReleaseDeviceResources)
|
|||
|
#if DBG
|
|||
|
//#pragma alloc_text(PAGE, PipDebugPrint)
|
|||
|
#pragma alloc_text(PAGE, PipDumpIoResourceDescriptor)
|
|||
|
#pragma alloc_text(PAGE, PipDumpIoResourceList)
|
|||
|
#pragma alloc_text(PAGE, PipDumpCmResourceDescriptor)
|
|||
|
#pragma alloc_text(PAGE, PipDumpCmResourceList)
|
|||
|
#endif
|
|||
|
#endif
|
|||
|
|
|||
|
#define IRQFLAGS_VALUE_NAME L"IrqFlags"
|
|||
|
#define BOOTRESOURCES_VALUE_NAME L"BootRes"
|
|||
|
|
|||
|
#if ISOLATE_CARDS
|
|||
|
|
|||
|
UCHAR CurrentCsn = 0;
|
|||
|
UCHAR CurrentDev = 255;
|
|||
|
|
|||
|
VOID
|
|||
|
PipWaitForKey(VOID)
|
|||
|
{
|
|||
|
ASSERT((PipState == PiSConfig) || (PipState == PiSIsolation) || (PipState == PiSSleep));
|
|||
|
PipWriteAddress(CONFIG_CONTROL_PORT);
|
|||
|
PipWriteData(CONTROL_WAIT_FOR_KEY);
|
|||
|
PipReportStateChange(PiSWaitForKey);
|
|||
|
CurrentCsn = 0;
|
|||
|
CurrentDev = 255;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PipConfig(
|
|||
|
IN UCHAR Csn
|
|||
|
)
|
|||
|
{
|
|||
|
ASSERT(Csn);
|
|||
|
ASSERT((PipState == PiSConfig) || (PipState == PiSIsolation) || (PipState == PiSSleep));
|
|||
|
PipWriteAddress(WAKE_CSN_PORT);
|
|||
|
PipWriteData(Csn);
|
|||
|
DebugPrint((DEBUG_STATE, "Wake CSN %u\n", (ULONG) Csn));
|
|||
|
CurrentCsn = Csn;
|
|||
|
CurrentDev = 255;
|
|||
|
PipReportStateChange(PiSConfig);
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PipIsolation(
|
|||
|
VOID
|
|||
|
)
|
|||
|
{
|
|||
|
ASSERT((PipState == PiSConfig) || (PipState == PiSIsolation) || (PipState == PiSSleep));
|
|||
|
PipWriteAddress(WAKE_CSN_PORT);
|
|||
|
PipWriteData(0);
|
|||
|
CurrentCsn = 0;
|
|||
|
CurrentDev = 255;
|
|||
|
DebugPrint((DEBUG_STATE, "Isolate cards w/o CSN\n"));
|
|||
|
PipReportStateChange(PiSIsolation);
|
|||
|
}
|
|||
|
VOID
|
|||
|
PipSleep(
|
|||
|
VOID
|
|||
|
)
|
|||
|
{
|
|||
|
ASSERT((PipState == PiSConfig) || PipState == PiSIsolation);
|
|||
|
PipWriteAddress(WAKE_CSN_PORT);
|
|||
|
PipWriteData(0);
|
|||
|
CurrentCsn = 0;
|
|||
|
CurrentDev = 255;
|
|||
|
DebugPrint((DEBUG_STATE, "Putting all cards to sleep (we think)\n"));
|
|||
|
PipReportStateChange(PiSSleep);
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PipActivateDevice (
|
|||
|
)
|
|||
|
{
|
|||
|
UCHAR tmp;
|
|||
|
|
|||
|
PipWriteAddress(IO_RANGE_CHECK_PORT);
|
|||
|
tmp = PipReadData();
|
|||
|
tmp &= ~2;
|
|||
|
PipWriteAddress(IO_RANGE_CHECK_PORT);
|
|||
|
PipWriteData(tmp);
|
|||
|
PipWriteAddress(ACTIVATE_PORT);
|
|||
|
PipWriteData(1);
|
|||
|
|
|||
|
DebugPrint((DEBUG_STATE, "Activated card CSN %d/LDN %d\n",
|
|||
|
(ULONG) CurrentCsn,
|
|||
|
(ULONG) CurrentDev));
|
|||
|
}
|
|||
|
VOID
|
|||
|
PipDeactivateDevice (
|
|||
|
)
|
|||
|
{
|
|||
|
PipWriteAddress(ACTIVATE_PORT);
|
|||
|
PipWriteData(0);
|
|||
|
|
|||
|
DebugPrint((DEBUG_STATE, "Deactivated card CSN %d/LDN %d\n",
|
|||
|
(ULONG) CurrentCsn,
|
|||
|
(ULONG) CurrentDev));
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PipSelectDevice(
|
|||
|
IN UCHAR Device
|
|||
|
)
|
|||
|
{
|
|||
|
ASSERT(PipState == PiSConfig);
|
|||
|
PipWriteAddress(LOGICAL_DEVICE_PORT);
|
|||
|
PipWriteData(Device);
|
|||
|
|
|||
|
CurrentDev = Device;
|
|||
|
DebugPrint((DEBUG_STATE, "Selected CSN %d/LDN %d\n",
|
|||
|
(ULONG) CurrentCsn,
|
|||
|
(ULONG) Device));
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PipWakeAndSelectDevice(
|
|||
|
IN UCHAR Csn,
|
|||
|
IN UCHAR Device
|
|||
|
)
|
|||
|
{
|
|||
|
PipLFSRInitiation();
|
|||
|
PipConfig(Csn);
|
|||
|
PipSelectDevice(Device);
|
|||
|
}
|
|||
|
|
|||
|
PDEVICE_INFORMATION
|
|||
|
PipReferenceDeviceInformation (
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN BOOLEAN ConfigHardware
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function locks a device node so it won't go away.
|
|||
|
|
|||
|
Note, this function does not lock the whole device node tree.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceNode - Supplies a pointer to the device information node
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PDEVICE_INFORMATION deviceInfo;
|
|||
|
|
|||
|
deviceInfo = (PDEVICE_INFORMATION)DeviceObject->DeviceExtension;
|
|||
|
if (deviceInfo && !(deviceInfo->Flags & DF_DELETED)) {
|
|||
|
|
|||
|
if ((deviceInfo->Flags & DF_NOT_FUNCTIONING) && ConfigHardware) {
|
|||
|
PipDereferenceDeviceInformation(NULL, FALSE);
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
if (!(deviceInfo->Flags & DF_READ_DATA_PORT) && ConfigHardware) {
|
|||
|
PipWakeAndSelectDevice(
|
|||
|
(UCHAR)deviceInfo->CardInformation->CardSelectNumber,
|
|||
|
(UCHAR)deviceInfo->LogicalDeviceNumber);
|
|||
|
}
|
|||
|
|
|||
|
return deviceInfo;
|
|||
|
} else {
|
|||
|
PipDereferenceDeviceInformation(NULL, FALSE);
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PipDereferenceDeviceInformation(
|
|||
|
IN PDEVICE_INFORMATION DeviceInformation, BOOLEAN ConfigedHardware
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function releases the enumeration lock of the specified device node.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceNode - Supplies a pointer to the device node whose lock is to be released.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
//
|
|||
|
// Synchronize the dec and set event operations with IopAcquireEnumerationLock.
|
|||
|
//
|
|||
|
|
|||
|
if (DeviceInformation) {
|
|||
|
|
|||
|
|
|||
|
if (!(DeviceInformation->Flags & DF_READ_DATA_PORT) && ConfigedHardware) {
|
|||
|
if (PipState != PiSWaitForKey) {
|
|||
|
PipWaitForKey();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PipLockDeviceDatabase(
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function locks the whole device node tree. Currently, eject operation
|
|||
|
needs to lock the whole device node tree.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
KeWaitForSingleObject( &PipDeviceTreeLock,
|
|||
|
Executive,
|
|||
|
KernelMode,
|
|||
|
FALSE,
|
|||
|
NULL );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PipUnlockDeviceDatabase (
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function releases the lock of the whole device node tree.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
KeSetEvent( &PipDeviceTreeLock,
|
|||
|
0,
|
|||
|
FALSE );
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PipDeleteDevice (
|
|||
|
PDEVICE_OBJECT DeviceObject
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine
|
|||
|
|
|||
|
Parameters:
|
|||
|
|
|||
|
P1 -
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status code that indicates whether or not the function was successful.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PDEVICE_INFORMATION deviceInfo, devicex, devicep;
|
|||
|
PCARD_INFORMATION cardInfo, cardx, cardp;
|
|||
|
PSINGLE_LIST_ENTRY deviceLink, cardLink;
|
|||
|
NTSTATUS status = STATUS_SUCCESS;
|
|||
|
PPI_BUS_EXTENSION busExtension;
|
|||
|
|
|||
|
deviceInfo = (PDEVICE_INFORMATION)DeviceObject->DeviceExtension;
|
|||
|
|
|||
|
deviceInfo->Flags |= DF_DELETED;
|
|||
|
|
|||
|
//
|
|||
|
// Free the pool
|
|||
|
//
|
|||
|
|
|||
|
if (deviceInfo->ResourceRequirements) {
|
|||
|
ExFreePool(deviceInfo->ResourceRequirements);
|
|||
|
}
|
|||
|
|
|||
|
if (deviceInfo->BootResources) {
|
|||
|
ExFreePool(deviceInfo->BootResources);
|
|||
|
}
|
|||
|
|
|||
|
if (deviceInfo->AllocatedResources) {
|
|||
|
ExFreePool(deviceInfo->AllocatedResources);
|
|||
|
}
|
|||
|
|
|||
|
if (deviceInfo->LogConfHandle) {
|
|||
|
ZwClose(deviceInfo->LogConfHandle);
|
|||
|
deviceInfo->LogConfHandle = NULL;
|
|||
|
}
|
|||
|
|
|||
|
busExtension = deviceInfo->ParentDeviceExtension;
|
|||
|
cardInfo = deviceInfo->CardInformation;
|
|||
|
|
|||
|
PipLockDeviceDatabase();
|
|||
|
|
|||
|
//
|
|||
|
// Remove the device from device list.
|
|||
|
//
|
|||
|
|
|||
|
deviceLink = busExtension->DeviceList.Next;
|
|||
|
devicep = NULL;
|
|||
|
while (deviceLink) {
|
|||
|
devicex = CONTAINING_RECORD (deviceLink, DEVICE_INFORMATION, DeviceList);
|
|||
|
if (devicex == deviceInfo) {
|
|||
|
break;
|
|||
|
}
|
|||
|
devicep = devicex;
|
|||
|
deviceLink = devicex->DeviceList.Next;
|
|||
|
}
|
|||
|
ASSERT(devicex == deviceInfo);
|
|||
|
if (devicep == NULL) {
|
|||
|
busExtension->DeviceList.Next = deviceInfo->DeviceList.Next;
|
|||
|
} else {
|
|||
|
devicep->DeviceList.Next = deviceInfo->DeviceList.Next;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Remove the device from logical device list of the card
|
|||
|
//
|
|||
|
|
|||
|
deviceLink = cardInfo->LogicalDeviceList.Next;
|
|||
|
devicep = NULL;
|
|||
|
while (deviceLink) {
|
|||
|
devicex = CONTAINING_RECORD (deviceLink, DEVICE_INFORMATION, LogicalDeviceList);
|
|||
|
if (devicex == deviceInfo) {
|
|||
|
break;
|
|||
|
}
|
|||
|
devicep = devicex;
|
|||
|
deviceLink = devicex->LogicalDeviceList.Next;
|
|||
|
}
|
|||
|
ASSERT(devicex == deviceInfo);
|
|||
|
if (devicep == NULL) {
|
|||
|
cardInfo->LogicalDeviceList.Next = deviceInfo->LogicalDeviceList.Next;
|
|||
|
} else {
|
|||
|
devicep->LogicalDeviceList.Next = deviceInfo->LogicalDeviceList.Next;
|
|||
|
}
|
|||
|
|
|||
|
cardInfo->NumberLogicalDevices--;
|
|||
|
|
|||
|
//
|
|||
|
// All the devices are gone. That means the card is removed.
|
|||
|
// Next remove the isapnp card structure.
|
|||
|
//
|
|||
|
|
|||
|
if (cardInfo->NumberLogicalDevices == 0) {
|
|||
|
ASSERT(cardInfo->LogicalDeviceList.Next == NULL);
|
|||
|
cardLink = busExtension->CardList.Next;
|
|||
|
cardp = NULL;
|
|||
|
while (cardLink) {
|
|||
|
cardx = CONTAINING_RECORD (cardLink, CARD_INFORMATION, CardList);
|
|||
|
if (cardx == cardInfo) {
|
|||
|
break;
|
|||
|
}
|
|||
|
cardp = cardx;
|
|||
|
cardLink = cardx->CardList.Next;
|
|||
|
}
|
|||
|
ASSERT(cardx == cardInfo);
|
|||
|
if (cardp == NULL) {
|
|||
|
busExtension->CardList.Next = cardInfo->CardList.Next;
|
|||
|
} else {
|
|||
|
cardp->CardList.Next = cardInfo->CardList.Next;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
PipUnlockDeviceDatabase();
|
|||
|
|
|||
|
//
|
|||
|
// Remove the card information structure after releasing spin lock.
|
|||
|
//
|
|||
|
|
|||
|
if (cardInfo->NumberLogicalDevices == 0) {
|
|||
|
if (cardInfo->CardData) {
|
|||
|
ExFreePool(cardInfo->CardData);
|
|||
|
}
|
|||
|
ExFreePool(cardInfo);
|
|||
|
}
|
|||
|
|
|||
|
IoDeleteDevice(DeviceObject);
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PipQueryDeviceRelations (
|
|||
|
PPI_BUS_EXTENSION BusExtension,
|
|||
|
PDEVICE_RELATIONS *DeviceRelations,
|
|||
|
BOOLEAN Removal
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine
|
|||
|
|
|||
|
Parameters:
|
|||
|
|
|||
|
P1 -
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status code that indicates whether or not the function was successful.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PDEVICE_INFORMATION deviceInfo;
|
|||
|
PSINGLE_LIST_ENTRY deviceLink;
|
|||
|
NTSTATUS status = STATUS_SUCCESS;
|
|||
|
PDEVICE_OBJECT *devicePtr;
|
|||
|
ULONG count = 0;
|
|||
|
PDEVICE_RELATIONS deviceRelations;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
*DeviceRelations = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Go through the card link list to match the card data
|
|||
|
//
|
|||
|
|
|||
|
deviceLink = BusExtension->DeviceList.Next;
|
|||
|
while (deviceLink) {
|
|||
|
deviceInfo = CONTAINING_RECORD (deviceLink, DEVICE_INFORMATION, DeviceList);
|
|||
|
//
|
|||
|
// if it's the RDP ignore it for removal relations
|
|||
|
//
|
|||
|
if ((deviceInfo->Flags & DF_ENUMERATED) &&
|
|||
|
(!(deviceInfo->Flags & DF_READ_DATA_PORT) || !Removal)) {
|
|||
|
count++;
|
|||
|
} else {
|
|||
|
|
|||
|
DebugPrint((DEBUG_PNP, "PipQueryDeviceRelations skipping a node, Flags: %x\n",deviceInfo->Flags));
|
|||
|
}
|
|||
|
deviceLink = deviceInfo->DeviceList.Next;
|
|||
|
}
|
|||
|
if (count != 0) {
|
|||
|
deviceRelations = (PDEVICE_RELATIONS) ExAllocatePool(
|
|||
|
PagedPool,
|
|||
|
sizeof(DEVICE_RELATIONS) + (count - 1) * sizeof(PDEVICE_OBJECT));
|
|||
|
if (deviceRelations) {
|
|||
|
deviceRelations->Count = count;
|
|||
|
deviceLink = BusExtension->DeviceList.Next;
|
|||
|
devicePtr = deviceRelations->Objects;
|
|||
|
while (deviceLink) {
|
|||
|
deviceInfo = CONTAINING_RECORD (deviceLink, DEVICE_INFORMATION, DeviceList);
|
|||
|
|
|||
|
if ((deviceInfo->Flags & DF_ENUMERATED) &&
|
|||
|
(!(deviceInfo->Flags & DF_READ_DATA_PORT) || !(Removal))) {
|
|||
|
ObReferenceObject(deviceInfo->PhysicalDeviceObject);
|
|||
|
*devicePtr = deviceInfo->PhysicalDeviceObject;
|
|||
|
devicePtr++;
|
|||
|
}
|
|||
|
deviceLink = deviceInfo->DeviceList.Next;
|
|||
|
}
|
|||
|
*DeviceRelations = deviceRelations;
|
|||
|
} else {
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
}
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
PCARD_INFORMATION
|
|||
|
PipIsCardEnumeratedAlready(
|
|||
|
IN PPI_BUS_EXTENSION BusExtension,
|
|||
|
IN PUCHAR CardData,
|
|||
|
IN ULONG DataLength
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine finds the card information structure which contains the same CardData.
|
|||
|
|
|||
|
Parameters:
|
|||
|
|
|||
|
CardData - Supplies a pointer to the CardData
|
|||
|
|
|||
|
DataLength - The length of the CardData
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
A pointer to the CARD_INFORMATION structure if found.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PCARD_INFORMATION cardInfo;
|
|||
|
PSINGLE_LIST_ENTRY cardLink;
|
|||
|
PSERIAL_IDENTIFIER serialId1, serialId2 = (PSERIAL_IDENTIFIER)CardData;
|
|||
|
|
|||
|
//
|
|||
|
// Go through the card link list to match the card data
|
|||
|
//
|
|||
|
|
|||
|
cardLink = BusExtension->CardList.Next;
|
|||
|
while (cardLink) {
|
|||
|
cardInfo = CONTAINING_RECORD (cardLink, CARD_INFORMATION, CardList);
|
|||
|
if (cardInfo->CardSelectNumber != 0) { // if == 0, card is no longer present
|
|||
|
serialId1 = (PSERIAL_IDENTIFIER)cardInfo->CardData;
|
|||
|
ASSERT(serialId1 && serialId2);
|
|||
|
if (serialId1->VenderId == serialId2->VenderId &&
|
|||
|
serialId1->SerialNumber == serialId2->SerialNumber) {
|
|||
|
return cardInfo;
|
|||
|
}
|
|||
|
}
|
|||
|
cardLink = cardInfo->CardList.Next; // Get the next addr before releasing pool
|
|||
|
}
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PipCleanupAcquiredResources (
|
|||
|
PPI_BUS_EXTENSION BusExtension
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine cleans up the resources assigned to the readdata, command and address
|
|||
|
ports.
|
|||
|
|
|||
|
Parameters:
|
|||
|
|
|||
|
BusExtension - specifies the isapnp bus to be cleaned up.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// Release address, command and read data port resources.
|
|||
|
//
|
|||
|
|
|||
|
if (BusExtension->CommandPort && BusExtension->CmdPortMapped) {
|
|||
|
MmUnmapIoSpace(BusExtension->CommandPort, 1);
|
|||
|
BusExtension->CmdPortMapped = FALSE;
|
|||
|
}
|
|||
|
BusExtension->CommandPort = NULL;
|
|||
|
|
|||
|
if (BusExtension->AddressPort && BusExtension->AddrPortMapped) {
|
|||
|
MmUnmapIoSpace(BusExtension->AddressPort, 1);
|
|||
|
BusExtension->AddrPortMapped = FALSE;
|
|||
|
}
|
|||
|
BusExtension->AddressPort = NULL;
|
|||
|
|
|||
|
if (BusExtension->ReadDataPort) {
|
|||
|
PipReadDataPort = PipCommandPort = PipAddressPort = NULL;
|
|||
|
}
|
|||
|
if (BusExtension->ReadDataPort && BusExtension->DataPortMapped) {
|
|||
|
MmUnmapIoSpace(BusExtension->ReadDataPort - 3, 4);
|
|||
|
BusExtension->DataPortMapped = FALSE;
|
|||
|
}
|
|||
|
BusExtension->ReadDataPort = NULL;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PipMapReadDataPort (
|
|||
|
IN PPI_BUS_EXTENSION BusExtension,
|
|||
|
IN PHYSICAL_ADDRESS Start,
|
|||
|
IN ULONG Length
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine maps specified port resources.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
BusExtension - Supplies a pointer to the pnp bus extension.
|
|||
|
|
|||
|
BaseAddressLow,
|
|||
|
BaseAddressHi - Supplies the read data port base address range to be mapped.
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS code.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
ULONG size;
|
|||
|
PHYSICAL_ADDRESS physicalAddress;
|
|||
|
ULONG dumpData[3];
|
|||
|
BOOLEAN conflictDetected;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
if (BusExtension->ReadDataPort && BusExtension->DataPortMapped) {
|
|||
|
MmUnmapIoSpace(PipReadDataPort - 3, 4);
|
|||
|
PipReadDataPort = BusExtension->ReadDataPort = NULL;
|
|||
|
BusExtension->DataPortMapped = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
PipReadDataPort = PipGetMappedAddress(
|
|||
|
Isa, // InterfaceType
|
|||
|
0, // BusNumber,
|
|||
|
Start,
|
|||
|
Length,
|
|||
|
CM_RESOURCE_PORT_IO,
|
|||
|
&BusExtension->DataPortMapped
|
|||
|
);
|
|||
|
|
|||
|
DebugPrint((DEBUG_RDP, "PnpIsa:ReadDataPort is at %x\n",PipReadDataPort+3));
|
|||
|
if (PipReadDataPort) {
|
|||
|
PipReadDataPort += 3;
|
|||
|
BusExtension->ReadDataPort = PipReadDataPort;
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
} else {
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
PVOID
|
|||
|
PipGetMappedAddress(
|
|||
|
IN INTERFACE_TYPE BusType,
|
|||
|
IN ULONG BusNumber,
|
|||
|
IN PHYSICAL_ADDRESS IoAddress,
|
|||
|
IN ULONG NumberOfBytes,
|
|||
|
IN ULONG AddressSpace,
|
|||
|
OUT PBOOLEAN MappedAddress
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine maps an IO address to system address space.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
BusType - Supplies the type of bus - eisa, mca, isa...
|
|||
|
|
|||
|
IoBusNumber - Supplies the bus number.
|
|||
|
|
|||
|
IoAddress - Supplies the base device address to be mapped.
|
|||
|
|
|||
|
NumberOfBytes - Supplies the number of bytes for which the address is
|
|||
|
valid.
|
|||
|
|
|||
|
AddressSpace - Supplies whether the address is in io space or memory.
|
|||
|
|
|||
|
MappedAddress - Supplies whether the address was mapped. This only has
|
|||
|
meaning if the address returned is non-null.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The mapped address.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PHYSICAL_ADDRESS cardAddress;
|
|||
|
PVOID address;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
HalTranslateBusAddress(BusType, BusNumber, IoAddress, &AddressSpace,
|
|||
|
&cardAddress);
|
|||
|
|
|||
|
//
|
|||
|
// Map the device base address into the virtual address space
|
|||
|
// if the address is in memory space.
|
|||
|
//
|
|||
|
|
|||
|
if (!AddressSpace) {
|
|||
|
|
|||
|
address = MmMapIoSpace(cardAddress, NumberOfBytes, FALSE);
|
|||
|
*MappedAddress = (address ? TRUE : FALSE);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
address = (PVOID) cardAddress.LowPart;
|
|||
|
*MappedAddress = FALSE;
|
|||
|
}
|
|||
|
|
|||
|
return address;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PipDecompressEisaId(
|
|||
|
IN ULONG CompressedId,
|
|||
|
IN PUCHAR EisaId
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine decompressed compressed Eisa Id and returns the Id to caller
|
|||
|
specified character buffer.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
CompressedId - supplies the compressed Eisa Id.
|
|||
|
|
|||
|
EisaId - supplies a 8-char buffer to receive the decompressed Eisa Id.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
USHORT c1, c2;
|
|||
|
LONG i;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
CompressedId &= 0xffffff7f; // remove the reserved bit (bit 7 of byte 0)
|
|||
|
c1 = c2 = (USHORT)CompressedId;
|
|||
|
c1 = (c1 & 0xff) << 8;
|
|||
|
c2 = (c2 & 0xff00) >> 8;
|
|||
|
c1 |= c2;
|
|||
|
for (i = 2; i >= 0; i--) {
|
|||
|
*(EisaId + i) = (UCHAR)(c1 & 0x1f) + 0x40;
|
|||
|
c1 >>= 5;
|
|||
|
}
|
|||
|
EisaId += 3;
|
|||
|
c1 = c2 = (USHORT)(CompressedId >> 16);
|
|||
|
c1 = (c1 & 0xff) << 8;
|
|||
|
c2 = (c2 & 0xff00) >> 8;
|
|||
|
c1 |= c2;
|
|||
|
sprintf (EisaId, "%04x", c1);
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PipLogError(
|
|||
|
IN NTSTATUS ErrorCode,
|
|||
|
IN ULONG UniqueErrorValue,
|
|||
|
IN NTSTATUS FinalStatus,
|
|||
|
IN PULONG DumpData,
|
|||
|
IN ULONG DumpCount,
|
|||
|
IN USHORT StringLength,
|
|||
|
IN PWCHAR String
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine contains common code to write an error log entry. It is
|
|||
|
called from other routines to avoid duplication of code. This routine
|
|||
|
only allows caller to supply one insertion string to the error log.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ErrorCode - The error code for the error log packet.
|
|||
|
|
|||
|
UniqueErrorValue - The unique error value for the error log packet.
|
|||
|
|
|||
|
FinalStatus - The final status of the operation for the error log packet.
|
|||
|
|
|||
|
DumpData - Pointer to an array of dump data for the error log packet.
|
|||
|
|
|||
|
DumpCount - The number of entries in the dump data array.
|
|||
|
|
|||
|
StringLength - The length of insertion string *NOT* including the NULL terminater.
|
|||
|
|
|||
|
String - The pointer to the insertion string
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PIO_ERROR_LOG_PACKET errorLogEntry;
|
|||
|
ULONG i, size;
|
|||
|
PUCHAR p;
|
|||
|
|
|||
|
size = sizeof(IO_ERROR_LOG_PACKET) + DumpCount * sizeof(ULONG) +
|
|||
|
StringLength + sizeof(UNICODE_NULL) - sizeof(ULONG);
|
|||
|
errorLogEntry = (PIO_ERROR_LOG_PACKET) IoAllocateErrorLogEntry(
|
|||
|
PipDriverObject,
|
|||
|
(UCHAR) size
|
|||
|
);
|
|||
|
if (errorLogEntry != NULL) {
|
|||
|
|
|||
|
RtlZeroMemory(errorLogEntry, size);
|
|||
|
|
|||
|
errorLogEntry->ErrorCode = ErrorCode;
|
|||
|
errorLogEntry->DumpDataSize = (USHORT) (DumpCount * sizeof(ULONG));
|
|||
|
errorLogEntry->UniqueErrorValue = UniqueErrorValue;
|
|||
|
errorLogEntry->FinalStatus = FinalStatus;
|
|||
|
for (i = 0; i < DumpCount; i++)
|
|||
|
errorLogEntry->DumpData[i] = DumpData[i];
|
|||
|
if (String) {
|
|||
|
errorLogEntry->NumberOfStrings = 1;
|
|||
|
errorLogEntry->StringOffset = (USHORT)(sizeof(IO_ERROR_LOG_PACKET) +
|
|||
|
DumpCount * sizeof(ULONG) - sizeof(ULONG));
|
|||
|
p= (PUCHAR)errorLogEntry + errorLogEntry->StringOffset;
|
|||
|
RtlMoveMemory(p, String, StringLength);
|
|||
|
}
|
|||
|
IoWriteErrorLogEntry(errorLogEntry);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PipOpenCurrentHwProfileDeviceInstanceKey(
|
|||
|
OUT PHANDLE Handle,
|
|||
|
IN PUNICODE_STRING DeviceInstanceName,
|
|||
|
IN ACCESS_MASK DesiredAccess
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine sets the csconfig flags for the specified device
|
|||
|
which is specified by the instance number under ServiceKeyName\Enum.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ServiceKeyName - Supplies a pointer to the name of the subkey in the
|
|||
|
system service list (HKEY_LOCAL_MACHINE\CurrentControlSet\Services)
|
|||
|
that caused the driver to load. This is the RegistryPath parameter
|
|||
|
to the DriverEntry routine.
|
|||
|
|
|||
|
Instance - Supplies the instance value under ServiceKeyName\Enum key
|
|||
|
|
|||
|
DesiredAccess - Specifies the desired access that the caller needs to
|
|||
|
the key.
|
|||
|
|
|||
|
Create - Determines if the key is to be created if it does not exist.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
status
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
UNICODE_STRING unicodeString;
|
|||
|
HANDLE profileEnumHandle;
|
|||
|
|
|||
|
//
|
|||
|
// See if we can open the device instance key of current hardware profile
|
|||
|
//
|
|||
|
RtlInitUnicodeString (
|
|||
|
&unicodeString,
|
|||
|
L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\HARDWARE PROFILES\\CURRENT\\SYSTEM\\CURRENTCONTROLSET\\ENUM"
|
|||
|
);
|
|||
|
status = PipOpenRegistryKey(&profileEnumHandle,
|
|||
|
NULL,
|
|||
|
&unicodeString,
|
|||
|
KEY_READ,
|
|||
|
FALSE
|
|||
|
);
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
status = PipOpenRegistryKey(Handle,
|
|||
|
profileEnumHandle,
|
|||
|
DeviceInstanceName,
|
|||
|
DesiredAccess,
|
|||
|
FALSE
|
|||
|
);
|
|||
|
ZwClose(profileEnumHandle);
|
|||
|
}
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PipGetDeviceInstanceCsConfigFlags(
|
|||
|
IN PUNICODE_STRING DeviceInstance,
|
|||
|
OUT PULONG CsConfigFlags
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine retrieves the csconfig flags for the specified device
|
|||
|
which is specified by the instance number under ServiceKeyName\Enum.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ServiceKeyName - Supplies a pointer to the name of the subkey in the
|
|||
|
system service list (HKEY_LOCAL_MACHINE\CurrentControlSet\Services)
|
|||
|
that caused the driver to load.
|
|||
|
|
|||
|
// Instance - Supplies the instance value under ServiceKeyName\Enum key
|
|||
|
//
|
|||
|
CsConfigFlags - Supplies a variable to receive the device's CsConfigFlags
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
status
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
HANDLE handle;
|
|||
|
PKEY_VALUE_FULL_INFORMATION keyValueInformation;
|
|||
|
|
|||
|
*CsConfigFlags = 0;
|
|||
|
|
|||
|
status = PipOpenCurrentHwProfileDeviceInstanceKey(&handle,
|
|||
|
DeviceInstance,
|
|||
|
KEY_READ
|
|||
|
);
|
|||
|
if(NT_SUCCESS(status)) {
|
|||
|
status = PipGetRegistryValue(handle,
|
|||
|
L"CsConfigFlags",
|
|||
|
&keyValueInformation
|
|||
|
);
|
|||
|
if(NT_SUCCESS(status)) {
|
|||
|
if((keyValueInformation->Type == REG_DWORD) &&
|
|||
|
(keyValueInformation->DataLength >= sizeof(ULONG))) {
|
|||
|
*CsConfigFlags = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
|
|||
|
}
|
|||
|
ExFreePool(keyValueInformation);
|
|||
|
}
|
|||
|
ZwClose(handle);
|
|||
|
}
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
ULONG
|
|||
|
PipDetermineResourceListSize(
|
|||
|
IN PCM_RESOURCE_LIST ResourceList
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine determines size of the passed in ResourceList
|
|||
|
structure.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Configuration1 - Supplies a pointer to the resource list.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
size of the resource list structure.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
ULONG totalSize, listSize, descriptorSize, i, j;
|
|||
|
PCM_FULL_RESOURCE_DESCRIPTOR fullResourceDesc;
|
|||
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDescriptor;
|
|||
|
|
|||
|
if (!ResourceList) {
|
|||
|
totalSize = 0;
|
|||
|
} else {
|
|||
|
totalSize = FIELD_OFFSET(CM_RESOURCE_LIST, List);
|
|||
|
fullResourceDesc = &ResourceList->List[0];
|
|||
|
for (i = 0; i < ResourceList->Count; i++) {
|
|||
|
listSize = FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR,
|
|||
|
PartialResourceList) +
|
|||
|
FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST,
|
|||
|
PartialDescriptors);
|
|||
|
partialDescriptor = &fullResourceDesc->PartialResourceList.PartialDescriptors[0];
|
|||
|
for (j = 0; j < fullResourceDesc->PartialResourceList.Count; j++) {
|
|||
|
descriptorSize = sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
|
|||
|
if (partialDescriptor->Type == CmResourceTypeDeviceSpecific) {
|
|||
|
descriptorSize += partialDescriptor->u.DeviceSpecificData.DataSize;
|
|||
|
}
|
|||
|
listSize += descriptorSize;
|
|||
|
partialDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)
|
|||
|
((PUCHAR)partialDescriptor + descriptorSize);
|
|||
|
}
|
|||
|
totalSize += listSize;
|
|||
|
fullResourceDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)
|
|||
|
((PUCHAR)fullResourceDesc + listSize);
|
|||
|
}
|
|||
|
}
|
|||
|
return totalSize;
|
|||
|
}
|
|||
|
NTSTATUS
|
|||
|
PipMapAddressAndCmdPort (
|
|||
|
IN PPI_BUS_EXTENSION BusExtension
|
|||
|
)
|
|||
|
{
|
|||
|
NTSTATUS status = STATUS_SUCCESS;
|
|||
|
ULONG dumpData[3];
|
|||
|
PHYSICAL_ADDRESS physicalAddress;
|
|||
|
//
|
|||
|
// Map port addr to memory addr if necessary.
|
|||
|
//
|
|||
|
|
|||
|
if (PipAddressPort == NULL) {
|
|||
|
physicalAddress.LowPart = ADDRESS_PORT;
|
|||
|
physicalAddress.HighPart = 0;
|
|||
|
BusExtension->AddressPort =
|
|||
|
PipAddressPort = PipGetMappedAddress(
|
|||
|
Isa, // InterfaceType
|
|||
|
0, // BusNumber,
|
|||
|
physicalAddress,
|
|||
|
1,
|
|||
|
CM_RESOURCE_PORT_IO,
|
|||
|
&BusExtension->AddrPortMapped
|
|||
|
);
|
|||
|
if (PipAddressPort == NULL) {
|
|||
|
dumpData[0] = ADDRESS_PORT;
|
|||
|
dumpData[1] = 1;
|
|||
|
dumpData[2] = CM_RESOURCE_PORT_IO;
|
|||
|
PipLogError(PNPISA_REGISTER_NOT_MAPPED,
|
|||
|
PNPISA_ACQUIREPORTRESOURCE_1,
|
|||
|
STATUS_INSUFFICIENT_RESOURCES,
|
|||
|
dumpData,
|
|||
|
3,
|
|||
|
0,
|
|||
|
NULL
|
|||
|
);
|
|||
|
status = STATUS_UNSUCCESSFUL;
|
|||
|
}
|
|||
|
}
|
|||
|
if (PipCommandPort == NULL) {
|
|||
|
physicalAddress.LowPart = COMMAND_PORT;
|
|||
|
physicalAddress.HighPart = 0;
|
|||
|
BusExtension->CommandPort =
|
|||
|
PipCommandPort = PipGetMappedAddress(
|
|||
|
Isa, // InterfaceType
|
|||
|
0, // BusNumber,
|
|||
|
physicalAddress,
|
|||
|
1,
|
|||
|
CM_RESOURCE_PORT_IO,
|
|||
|
&BusExtension->CmdPortMapped
|
|||
|
);
|
|||
|
if (PipCommandPort == NULL) {
|
|||
|
dumpData[0] = COMMAND_PORT;
|
|||
|
dumpData[1] = 1;
|
|||
|
dumpData[2] = CM_RESOURCE_PORT_IO;
|
|||
|
PipLogError(PNPISA_REGISTER_NOT_MAPPED,
|
|||
|
PNPISA_ACQUIREPORTRESOURCE_2,
|
|||
|
STATUS_INSUFFICIENT_RESOURCES,
|
|||
|
dumpData,
|
|||
|
3,
|
|||
|
0,
|
|||
|
NULL
|
|||
|
);
|
|||
|
status = STATUS_UNSUCCESSFUL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
return status;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PipReleaseDeviceResources (
|
|||
|
PDEVICE_INFORMATION DeviceInfo
|
|||
|
)
|
|||
|
{
|
|||
|
UNICODE_STRING unicodeString;
|
|||
|
|
|||
|
// This code is here rather than in the following conditional as
|
|||
|
// this best reflects how the code used to work before this code
|
|||
|
// was moved here from PDO stop/remove/surprise remove.
|
|||
|
if (DeviceInfo->LogConfHandle) {
|
|||
|
RtlInitUnicodeString(&unicodeString, L"AllocConfig");
|
|||
|
ZwDeleteValueKey (DeviceInfo->LogConfHandle, &unicodeString);
|
|||
|
}
|
|||
|
|
|||
|
if (DeviceInfo->AllocatedResources) {
|
|||
|
ExFreePool (DeviceInfo->AllocatedResources);
|
|||
|
DeviceInfo->AllocatedResources=NULL;
|
|||
|
|
|||
|
if (DeviceInfo->LogConfHandle) {
|
|||
|
// As it stands now it we will close the logconf handle if
|
|||
|
// the device gets removed, surprise removed, or stopped.
|
|||
|
// When we get started, we'll try to re-create the
|
|||
|
// AllocConfig value but fail because of the lack of the
|
|||
|
// logconf handle. This is not a change in behavior.
|
|||
|
//
|
|||
|
// The ZwDeleteKey() was definitely bogus though.
|
|||
|
|
|||
|
ZwClose(DeviceInfo->LogConfHandle);
|
|||
|
DeviceInfo->LogConfHandle=NULL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PipReportStateChange(
|
|||
|
PNPISA_STATE State
|
|||
|
)
|
|||
|
{
|
|||
|
DebugPrint((DEBUG_STATE, "State transition: %d to %d\n",
|
|||
|
PipState, State));
|
|||
|
PipState = State;
|
|||
|
}
|
|||
|
|
|||
|
ULONG
|
|||
|
PipGetCardFlags(
|
|||
|
PCARD_INFORMATION CardInfo
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Description:
|
|||
|
|
|||
|
Look in the registry for any flags for this CardId
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
CardId First 4 bytes of ISAPNP config space
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
32 bit flags value from registry or 0 if not found.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
HANDLE serviceHandle, paramHandle;
|
|||
|
NTSTATUS status;
|
|||
|
ULONG flags, returnedLength;
|
|||
|
UNICODE_STRING nameString;
|
|||
|
ANSI_STRING ansiString;
|
|||
|
WCHAR nameBuffer[9];
|
|||
|
UCHAR eisaId[8];
|
|||
|
const PWCHAR paramKey = L"Parameters";
|
|||
|
struct {
|
|||
|
KEY_VALUE_PARTIAL_INFORMATION Header;
|
|||
|
|
|||
|
//
|
|||
|
// The header contains enough space for one UCHAR, pad
|
|||
|
// it out by a ULONG, this will ensure the structure
|
|||
|
// is large enough for at lease the ULONG we need.
|
|||
|
//
|
|||
|
// N.B. Natural alignment will get it out far enough that
|
|||
|
// this ULONG is 4 bytes to many.
|
|||
|
//
|
|||
|
|
|||
|
ULONG Pad;
|
|||
|
} returnedData;
|
|||
|
|
|||
|
|
|||
|
status = PipOpenRegistryKey(&serviceHandle,
|
|||
|
NULL,
|
|||
|
&PipRegistryPath,
|
|||
|
KEY_READ,
|
|||
|
FALSE);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
RtlInitUnicodeString(&nameString, paramKey);
|
|||
|
status = PipOpenRegistryKey(¶mHandle,
|
|||
|
serviceHandle,
|
|||
|
&nameString,
|
|||
|
KEY_READ,
|
|||
|
FALSE);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
ZwClose(serviceHandle);
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
PipDecompressEisaId(
|
|||
|
((PSERIAL_IDENTIFIER) (CardInfo->CardData))->VenderId,
|
|||
|
eisaId
|
|||
|
);
|
|||
|
RtlInitAnsiString(&ansiString, eisaId);
|
|||
|
status = RtlAnsiStringToUnicodeString(&nameString, &ansiString, TRUE);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
ZwClose(paramHandle);
|
|||
|
ZwClose(serviceHandle);
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get the "value" of this value.
|
|||
|
//
|
|||
|
|
|||
|
status = ZwQueryValueKey(
|
|||
|
paramHandle,
|
|||
|
&nameString,
|
|||
|
KeyValuePartialInformation,
|
|||
|
&returnedData,
|
|||
|
sizeof(returnedData),
|
|||
|
&returnedLength
|
|||
|
);
|
|||
|
ZwClose(paramHandle);
|
|||
|
ZwClose(serviceHandle);
|
|||
|
|
|||
|
if (NT_SUCCESS(status) && (returnedData.Header.Type == REG_DWORD) &&
|
|||
|
(returnedData.Header.DataLength == sizeof(ULONG))) {
|
|||
|
flags = *(PULONG)(returnedData.Header.Data);
|
|||
|
DebugPrint((DEBUG_WARN, "Retrieving card flags for %ws: %x\n",
|
|||
|
nameString.Buffer, flags));
|
|||
|
} else {
|
|||
|
flags = 0;
|
|||
|
}
|
|||
|
RtlFreeUnicodeString(&nameString);
|
|||
|
return flags;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PipBuildValueName(
|
|||
|
IN PDEVICE_INFORMATION DeviceInfo,
|
|||
|
IN PWSTR Suffix,
|
|||
|
OUT PWSTR *ValuePath)
|
|||
|
/*++
|
|||
|
|
|||
|
Description:
|
|||
|
|
|||
|
Builds a name describing the device via the device id and unique
|
|||
|
id. Used to store per-device info in our parent's BiosConfig key
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceInfo Pointer to the PDO Extension for this device.
|
|||
|
|
|||
|
Suffix Suffix for value name
|
|||
|
|
|||
|
IrqFlags The edge or level setting of the boot config
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
PWSTR DeviceId = NULL, Instance = NULL;
|
|||
|
PWSTR Buffer, Current;
|
|||
|
ULONG length;
|
|||
|
|
|||
|
status = PipQueryDeviceId(DeviceInfo, &DeviceId, 0);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
goto cleanup;
|
|||
|
}
|
|||
|
|
|||
|
status = PipQueryDeviceUniqueId(DeviceInfo, &Instance);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
goto cleanup;
|
|||
|
}
|
|||
|
|
|||
|
length = (wcslen(DeviceId) + wcslen(Instance) + wcslen(Suffix) + 1) * sizeof(WCHAR);
|
|||
|
|
|||
|
Buffer = ExAllocatePool(PagedPool, length);
|
|||
|
if (Buffer == NULL) {
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
goto cleanup;
|
|||
|
}
|
|||
|
|
|||
|
wcscpy(Buffer, DeviceId);
|
|||
|
wcscat(Buffer, Instance);
|
|||
|
wcscat(Buffer, Suffix);
|
|||
|
|
|||
|
Current = Buffer;
|
|||
|
while (*Current != UNICODE_NULL) {
|
|||
|
if (*Current == L'\\') {
|
|||
|
*Current = L'_';
|
|||
|
}
|
|||
|
Current++;
|
|||
|
}
|
|||
|
|
|||
|
cleanup:
|
|||
|
if (Instance) {
|
|||
|
ExFreePool(Instance);
|
|||
|
}
|
|||
|
|
|||
|
if (DeviceId) {
|
|||
|
ExFreePool(DeviceId);
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
*ValuePath = Buffer;
|
|||
|
} else {
|
|||
|
*ValuePath = NULL;
|
|||
|
}
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PipSaveBootResources(
|
|||
|
IN PDEVICE_INFORMATION DeviceInfo
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Description:
|
|||
|
|
|||
|
This saves the per-boot configuration of a device in the registry
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceInfo Pointer to the PDO Extension for this device.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
OBJECT_ATTRIBUTES attributes;
|
|||
|
UNICODE_STRING unicodeString;
|
|||
|
HANDLE deviceHandle, configHandle;
|
|||
|
PWSTR Buffer = NULL;
|
|||
|
ULONG Flags;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
status = IoOpenDeviceRegistryKey(DeviceInfo->ParentDeviceExtension->PhysicalBusDevice,
|
|||
|
PLUGPLAY_REGKEY_DEVICE,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
&deviceHandle
|
|||
|
);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
goto cleanup;
|
|||
|
}
|
|||
|
|
|||
|
RtlInitUnicodeString(&unicodeString, BIOS_CONFIG_KEY_NAME);
|
|||
|
|
|||
|
InitializeObjectAttributes(&attributes,
|
|||
|
&unicodeString,
|
|||
|
OBJ_KERNEL_HANDLE,
|
|||
|
deviceHandle,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
status = ZwCreateKey(&configHandle,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
&attributes,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
REG_OPTION_VOLATILE,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
ZwClose(deviceHandle);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
goto cleanup;
|
|||
|
}
|
|||
|
|
|||
|
status = PipBuildValueName(DeviceInfo, BOOTRESOURCES_VALUE_NAME,
|
|||
|
&Buffer);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
Buffer = NULL;
|
|||
|
goto cleanup;
|
|||
|
}
|
|||
|
|
|||
|
unicodeString.Buffer = Buffer;
|
|||
|
unicodeString.Length = (wcslen(unicodeString.Buffer) + 1) * sizeof(WCHAR);
|
|||
|
unicodeString.MaximumLength = unicodeString.Length;
|
|||
|
|
|||
|
status = ZwSetValueKey(configHandle,
|
|||
|
&unicodeString,
|
|||
|
0,
|
|||
|
REG_BINARY,
|
|||
|
DeviceInfo->BootResources,
|
|||
|
DeviceInfo->BootResourcesLength
|
|||
|
);
|
|||
|
|
|||
|
ZwClose(configHandle);
|
|||
|
|
|||
|
cleanup:
|
|||
|
if (Buffer != NULL) {
|
|||
|
ExFreePool(Buffer);
|
|||
|
}
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PipSaveBootIrqFlags(
|
|||
|
IN PDEVICE_INFORMATION DeviceInfo,
|
|||
|
IN USHORT IrqFlags
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Description:
|
|||
|
|
|||
|
This saves the per-boot irq configuration of a device in the registry
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceInfo Pointer to the PDO Extension for this device.
|
|||
|
|
|||
|
IrqFlags The edge or level setting of the boot config
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
OBJECT_ATTRIBUTES attributes;
|
|||
|
UNICODE_STRING unicodeString;
|
|||
|
HANDLE deviceHandle, configHandle;
|
|||
|
PWSTR Buffer = NULL;
|
|||
|
ULONG Flags;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
Flags = (ULONG) IrqFlags;
|
|||
|
|
|||
|
status = IoOpenDeviceRegistryKey(DeviceInfo->ParentDeviceExtension->PhysicalBusDevice,
|
|||
|
PLUGPLAY_REGKEY_DEVICE,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
&deviceHandle
|
|||
|
);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
goto cleanup;
|
|||
|
}
|
|||
|
|
|||
|
RtlInitUnicodeString(&unicodeString, BIOS_CONFIG_KEY_NAME);
|
|||
|
|
|||
|
InitializeObjectAttributes(&attributes,
|
|||
|
&unicodeString,
|
|||
|
OBJ_KERNEL_HANDLE,
|
|||
|
deviceHandle,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
status = ZwCreateKey(&configHandle,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
&attributes,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
REG_OPTION_VOLATILE,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
ZwClose(deviceHandle);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
goto cleanup;
|
|||
|
}
|
|||
|
|
|||
|
status = PipBuildValueName(DeviceInfo, IRQFLAGS_VALUE_NAME, &Buffer);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
Buffer = NULL;
|
|||
|
goto cleanup;
|
|||
|
}
|
|||
|
|
|||
|
unicodeString.Buffer = Buffer;
|
|||
|
unicodeString.Length = (wcslen(unicodeString.Buffer) + 1) * sizeof(WCHAR);
|
|||
|
unicodeString.MaximumLength = unicodeString.Length;
|
|||
|
|
|||
|
status = ZwSetValueKey(configHandle,
|
|||
|
&unicodeString,
|
|||
|
0,
|
|||
|
REG_DWORD,
|
|||
|
&Flags,
|
|||
|
sizeof(ULONG)
|
|||
|
);
|
|||
|
|
|||
|
ZwClose(configHandle);
|
|||
|
|
|||
|
cleanup:
|
|||
|
if (Buffer != NULL) {
|
|||
|
ExFreePool(Buffer);
|
|||
|
}
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PipGetSavedBootResources(
|
|||
|
IN PDEVICE_INFORMATION DeviceInfo,
|
|||
|
OUT PCM_RESOURCE_LIST *BootResources
|
|||
|
)
|
|||
|
/*
|
|||
|
|
|||
|
Description:
|
|||
|
|
|||
|
This retrieves the saved boot resources
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceInfo Pointer to the PDO Extension for this device.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
UNICODE_STRING unicodeString;
|
|||
|
NTSTATUS status;
|
|||
|
OBJECT_ATTRIBUTES attributes;
|
|||
|
HANDLE deviceHandle, configHandle;
|
|||
|
PWSTR Buffer = NULL;
|
|||
|
PKEY_VALUE_PARTIAL_INFORMATION info = NULL;
|
|||
|
ULONG resultLength;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
*BootResources = NULL;
|
|||
|
status = IoOpenDeviceRegistryKey(DeviceInfo->ParentDeviceExtension->PhysicalBusDevice,
|
|||
|
PLUGPLAY_REGKEY_DEVICE,
|
|||
|
KEY_READ | KEY_WRITE,
|
|||
|
&deviceHandle
|
|||
|
);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
goto cleanup;
|
|||
|
}
|
|||
|
|
|||
|
RtlInitUnicodeString(&unicodeString, BIOS_CONFIG_KEY_NAME);
|
|||
|
|
|||
|
InitializeObjectAttributes(&attributes,
|
|||
|
&unicodeString,
|
|||
|
OBJ_KERNEL_HANDLE,
|
|||
|
deviceHandle,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
status = ZwOpenKey(&configHandle,
|
|||
|
KEY_READ,
|
|||
|
&attributes
|
|||
|
);
|
|||
|
|
|||
|
ZwClose(deviceHandle);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
goto cleanup;
|
|||
|
}
|
|||
|
|
|||
|
status = PipBuildValueName(DeviceInfo, BOOTRESOURCES_VALUE_NAME, &Buffer);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
ZwClose(configHandle);
|
|||
|
Buffer = NULL;
|
|||
|
goto cleanup;
|
|||
|
}
|
|||
|
|
|||
|
unicodeString.Buffer = Buffer;
|
|||
|
unicodeString.Length = (wcslen(unicodeString.Buffer) + 1) * sizeof(WCHAR);
|
|||
|
unicodeString.MaximumLength = unicodeString.Length;
|
|||
|
|
|||
|
status = ZwQueryValueKey(configHandle,
|
|||
|
&unicodeString,
|
|||
|
KeyValuePartialInformation,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
&resultLength
|
|||
|
);
|
|||
|
if (status != STATUS_BUFFER_OVERFLOW &&
|
|||
|
status != STATUS_BUFFER_TOO_SMALL) {
|
|||
|
ZwClose(configHandle);
|
|||
|
goto cleanup;
|
|||
|
}
|
|||
|
|
|||
|
info = ExAllocatePool(PagedPool, resultLength);
|
|||
|
if (info == NULL) {
|
|||
|
ZwClose(configHandle);
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
goto cleanup;
|
|||
|
}
|
|||
|
|
|||
|
status = ZwQueryValueKey(configHandle,
|
|||
|
&unicodeString,
|
|||
|
KeyValuePartialInformation,
|
|||
|
info,
|
|||
|
resultLength,
|
|||
|
&resultLength
|
|||
|
);
|
|||
|
ZwClose(configHandle);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
DebugPrint((DEBUG_PNP, "Failed to get boot resources from registry for %ws\n", Buffer));
|
|||
|
goto cleanup;
|
|||
|
}
|
|||
|
|
|||
|
*BootResources = ExAllocatePool(PagedPool, info->DataLength);
|
|||
|
if (BootResources) {
|
|||
|
RtlCopyMemory(*BootResources, info->Data, info->DataLength);
|
|||
|
DebugPrint((DEBUG_PNP, "Got boot resources from registry for %ws\n", Buffer));
|
|||
|
} else {
|
|||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
cleanup:
|
|||
|
|
|||
|
if (info != NULL) {
|
|||
|
ExFreePool(info);
|
|||
|
}
|
|||
|
|
|||
|
if (Buffer != NULL) {
|
|||
|
ExFreePool(Buffer);
|
|||
|
}
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PipGetBootIrqFlags(
|
|||
|
IN PDEVICE_INFORMATION DeviceInfo,
|
|||
|
OUT PUSHORT IrqFlags
|
|||
|
)
|
|||
|
/*
|
|||
|
|
|||
|
Description:
|
|||
|
|
|||
|
This retrieves the per-boot irq configuration of a device from the registry
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceInfo Pointer to the PDO Extension for this device.
|
|||
|
|
|||
|
IrqFlags - flags we originally derived from the device's boot
|
|||
|
config on this boot
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Status
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
OBJECT_ATTRIBUTES attributes;
|
|||
|
UNICODE_STRING unicodeString;
|
|||
|
HANDLE deviceHandle, configHandle;
|
|||
|
PWSTR Buffer = NULL;
|
|||
|
CHAR returnBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG) - 1];
|
|||
|
PKEY_VALUE_PARTIAL_INFORMATION info;
|
|||
|
ULONG resultLength;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
status = IoOpenDeviceRegistryKey(DeviceInfo->ParentDeviceExtension->PhysicalBusDevice,
|
|||
|
PLUGPLAY_REGKEY_DEVICE,
|
|||
|
KEY_READ | KEY_WRITE,
|
|||
|
&deviceHandle
|
|||
|
);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
goto cleanup;
|
|||
|
}
|
|||
|
|
|||
|
RtlInitUnicodeString(&unicodeString, BIOS_CONFIG_KEY_NAME);
|
|||
|
|
|||
|
InitializeObjectAttributes(&attributes,
|
|||
|
&unicodeString,
|
|||
|
OBJ_KERNEL_HANDLE,
|
|||
|
deviceHandle,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
status = ZwOpenKey(&configHandle,
|
|||
|
KEY_READ,
|
|||
|
&attributes
|
|||
|
);
|
|||
|
|
|||
|
ZwClose(deviceHandle);
|
|||
|
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
goto cleanup;
|
|||
|
}
|
|||
|
|
|||
|
status = PipBuildValueName(DeviceInfo, IRQFLAGS_VALUE_NAME, &Buffer);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
ZwClose(configHandle);
|
|||
|
Buffer = NULL;
|
|||
|
goto cleanup;
|
|||
|
}
|
|||
|
|
|||
|
unicodeString.Buffer = Buffer;
|
|||
|
unicodeString.Length = (wcslen(unicodeString.Buffer) + 1) * sizeof(WCHAR);
|
|||
|
unicodeString.MaximumLength = unicodeString.Length;
|
|||
|
|
|||
|
status = ZwQueryValueKey(configHandle,
|
|||
|
&unicodeString,
|
|||
|
KeyValuePartialInformation,
|
|||
|
&returnBuffer,
|
|||
|
sizeof(returnBuffer),
|
|||
|
&resultLength
|
|||
|
);
|
|||
|
|
|||
|
ZwClose(configHandle);
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
ULONG Temp;
|
|||
|
|
|||
|
info = (PKEY_VALUE_PARTIAL_INFORMATION) returnBuffer;
|
|||
|
|
|||
|
ASSERT(info->DataLength == sizeof(ULONG));
|
|||
|
|
|||
|
Temp = *((PULONG) info->Data);
|
|||
|
ASSERT(!(Temp & 0xFFFF0000));
|
|||
|
*IrqFlags = (USHORT) Temp;
|
|||
|
|
|||
|
DebugPrint((DEBUG_IRQ, "Got Irq Flags of %d for %ws\n",
|
|||
|
(ULONG) *IrqFlags,
|
|||
|
unicodeString.Buffer));
|
|||
|
} else {
|
|||
|
DebugPrint((DEBUG_IRQ, "Failed to get irq flags for %ws\n",
|
|||
|
unicodeString.Buffer));
|
|||
|
}
|
|||
|
|
|||
|
cleanup:
|
|||
|
|
|||
|
if (Buffer != NULL) {
|
|||
|
ExFreePool(Buffer);
|
|||
|
}
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PipResetGlobals (
|
|||
|
VOID
|
|||
|
)
|
|||
|
{
|
|||
|
PipReadDataPort = PipCommandPort = PipAddressPort = NULL;
|
|||
|
PipRDPNode = NULL;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PipOpenRegistryKey(
|
|||
|
OUT PHANDLE Handle,
|
|||
|
IN HANDLE BaseHandle OPTIONAL,
|
|||
|
IN PUNICODE_STRING KeyName,
|
|||
|
IN ACCESS_MASK DesiredAccess,
|
|||
|
IN BOOLEAN Create
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Opens or creates a VOLATILE registry key using the name passed in based
|
|||
|
at the BaseHandle node.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Handle - Pointer to the handle which will contain the registry key that
|
|||
|
was opened.
|
|||
|
|
|||
|
BaseHandle - Handle to the base path from which the key must be opened.
|
|||
|
|
|||
|
KeyName - Name of the Key that must be opened/created.
|
|||
|
|
|||
|
DesiredAccess - Specifies the desired access that the caller needs to
|
|||
|
the key.
|
|||
|
|
|||
|
Create - Determines if the key is to be created if it does not exist.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The function value is the final status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
OBJECT_ATTRIBUTES objectAttributes;
|
|||
|
ULONG disposition;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the object for the key.
|
|||
|
//
|
|||
|
|
|||
|
InitializeObjectAttributes( &objectAttributes,
|
|||
|
KeyName,
|
|||
|
OBJ_CASE_INSENSITIVE,
|
|||
|
BaseHandle,
|
|||
|
(PSECURITY_DESCRIPTOR) NULL );
|
|||
|
|
|||
|
//
|
|||
|
// Create the key or open it, as appropriate based on the caller's
|
|||
|
// wishes.
|
|||
|
//
|
|||
|
|
|||
|
if (Create) {
|
|||
|
return ZwCreateKey( Handle,
|
|||
|
DesiredAccess,
|
|||
|
&objectAttributes,
|
|||
|
0,
|
|||
|
(PUNICODE_STRING) NULL,
|
|||
|
REG_OPTION_VOLATILE,
|
|||
|
&disposition );
|
|||
|
} else {
|
|||
|
return ZwOpenKey( Handle,
|
|||
|
DesiredAccess,
|
|||
|
&objectAttributes );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PipGetRegistryValue(
|
|||
|
IN HANDLE KeyHandle,
|
|||
|
IN PWSTR ValueName,
|
|||
|
OUT PKEY_VALUE_FULL_INFORMATION *Information
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is invoked to retrieve the data for a registry key's value.
|
|||
|
This is done by querying the value of the key with a zero-length buffer
|
|||
|
to determine the size of the value, and then allocating a buffer and
|
|||
|
actually querying the value into the buffer.
|
|||
|
|
|||
|
It is the responsibility of the caller to free the buffer.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
KeyHandle - Supplies the key handle whose value is to be queried
|
|||
|
|
|||
|
ValueName - Supplies the null-terminated Unicode name of the value.
|
|||
|
|
|||
|
Information - Returns a pointer to the allocated data buffer.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The function value is the final status of the query operation.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
UNICODE_STRING unicodeString;
|
|||
|
NTSTATUS status;
|
|||
|
PKEY_VALUE_FULL_INFORMATION infoBuffer;
|
|||
|
ULONG keyValueLength;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
*Information = NULL;
|
|||
|
RtlInitUnicodeString( &unicodeString, ValueName );
|
|||
|
|
|||
|
//
|
|||
|
// Figure out how big the data value is so that a buffer of the
|
|||
|
// appropriate size can be allocated.
|
|||
|
//
|
|||
|
|
|||
|
status = ZwQueryValueKey( KeyHandle,
|
|||
|
&unicodeString,
|
|||
|
KeyValueFullInformation,
|
|||
|
(PVOID) NULL,
|
|||
|
0,
|
|||
|
&keyValueLength );
|
|||
|
if (status != STATUS_BUFFER_OVERFLOW &&
|
|||
|
status != STATUS_BUFFER_TOO_SMALL) {
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Allocate a buffer large enough to contain the entire key data value.
|
|||
|
//
|
|||
|
|
|||
|
infoBuffer = ExAllocatePool( NonPagedPool, keyValueLength );
|
|||
|
if (!infoBuffer) {
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Query the data for the key value.
|
|||
|
//
|
|||
|
|
|||
|
status = ZwQueryValueKey( KeyHandle,
|
|||
|
&unicodeString,
|
|||
|
KeyValueFullInformation,
|
|||
|
infoBuffer,
|
|||
|
keyValueLength,
|
|||
|
&keyValueLength );
|
|||
|
if (!NT_SUCCESS( status )) {
|
|||
|
ExFreePool( infoBuffer );
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Everything worked, so simply return the address of the allocated
|
|||
|
// buffer to the caller, who is now responsible for freeing it.
|
|||
|
//
|
|||
|
|
|||
|
*Information = infoBuffer;
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
PiNeedDeferISABridge(
|
|||
|
IN PDRIVER_OBJECT DriverObject,
|
|||
|
IN PDEVICE_OBJECT DeviceObject
|
|||
|
)
|
|||
|
{
|
|||
|
BOOLEAN defer=FALSE;
|
|||
|
NTSTATUS status;
|
|||
|
HANDLE hKey;
|
|||
|
ULONG value;
|
|||
|
PKEY_VALUE_FULL_INFORMATION keyValueInformation;
|
|||
|
|
|||
|
|
|||
|
|
|||
|
status = IoOpenDeviceRegistryKey (DeviceObject,PLUGPLAY_REGKEY_DEVICE,KEY_READ,&hKey);
|
|||
|
|
|||
|
if (NT_SUCCESS (status)) {
|
|||
|
status = PipGetRegistryValue (hKey,&BRIDGE_CHECK_KEY,&keyValueInformation);
|
|||
|
|
|||
|
if (NT_SUCCESS (status)) {
|
|||
|
if((keyValueInformation->Type == REG_DWORD) &&
|
|||
|
(keyValueInformation->DataLength >= sizeof(ULONG))) {
|
|||
|
value = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
|
|||
|
//
|
|||
|
// Assume that if the value !0 then the bridge is 'broken'
|
|||
|
//
|
|||
|
defer = (value == 0)?FALSE:TRUE;
|
|||
|
}
|
|||
|
}
|
|||
|
ZwClose(hKey);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return defer;
|
|||
|
}
|
|||
|
|
|||
|
#if DBG
|
|||
|
|
|||
|
VOID
|
|||
|
PipDebugPrintContinue (
|
|||
|
ULONG Level,
|
|||
|
PCCHAR DebugMessage,
|
|||
|
...
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine displays debugging message or causes a break.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Level - supplies debugging levelcode. DEBUG_MESSAGE - displays message only.
|
|||
|
DEBUG_BREAK - displays message and break.
|
|||
|
|
|||
|
DebugMessage - supplies a pointer to the debugging message.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
va_list ap;
|
|||
|
|
|||
|
va_start(ap, DebugMessage);
|
|||
|
|
|||
|
vDbgPrintEx(DPFLTR_ISAPNP_ID,
|
|||
|
Level,
|
|||
|
DebugMessage,
|
|||
|
ap
|
|||
|
);
|
|||
|
|
|||
|
if (Level & DEBUG_BREAK) {
|
|||
|
DbgBreakPoint();
|
|||
|
}
|
|||
|
|
|||
|
va_end(ap);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
PipDebugPrint (
|
|||
|
ULONG Level,
|
|||
|
PCCHAR DebugMessage,
|
|||
|
...
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine displays debugging message or causes a break.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Level - supplies debugging levelcode. DEBUG_MESSAGE - displays message only.
|
|||
|
DEBUG_BREAK - displays message and break.
|
|||
|
|
|||
|
DebugMessage - supplies a pointer to the debugging message.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
va_list ap;
|
|||
|
|
|||
|
va_start(ap, DebugMessage);
|
|||
|
|
|||
|
vDbgPrintExWithPrefix("ISAPNP: ",
|
|||
|
DPFLTR_ISAPNP_ID,
|
|||
|
Level,
|
|||
|
DebugMessage,
|
|||
|
ap
|
|||
|
);
|
|||
|
|
|||
|
if (Level & DEBUG_BREAK) {
|
|||
|
DbgBreakPoint();
|
|||
|
}
|
|||
|
|
|||
|
va_end(ap);
|
|||
|
}
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
PipDumpIoResourceDescriptor (
|
|||
|
IN PUCHAR Indent,
|
|||
|
IN PIO_RESOURCE_DESCRIPTOR Desc
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine processes a IO_RESOURCE_DESCRIPTOR and displays it.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Indent - # char of indentation.
|
|||
|
|
|||
|
Desc - supplies a pointer to the IO_RESOURCE_DESCRIPTOR to be displayed.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
UCHAR c = ' ';
|
|||
|
|
|||
|
if (Desc->Option == IO_RESOURCE_ALTERNATIVE) {
|
|||
|
c = 'A';
|
|||
|
} else if (Desc->Option == IO_RESOURCE_PREFERRED) {
|
|||
|
c = 'P';
|
|||
|
}
|
|||
|
switch (Desc->Type) {
|
|||
|
case CmResourceTypePort:
|
|||
|
DebugPrint ((
|
|||
|
DEBUG_RESOURCE,
|
|||
|
"%sIO %c Min: %x:%08x, Max: %x:%08x, Algn: %x, Len %x\n",
|
|||
|
Indent, c,
|
|||
|
Desc->u.Port.MinimumAddress.HighPart, Desc->u.Port.MinimumAddress.LowPart,
|
|||
|
Desc->u.Port.MaximumAddress.HighPart, Desc->u.Port.MaximumAddress.LowPart,
|
|||
|
Desc->u.Port.Alignment,
|
|||
|
Desc->u.Port.Length
|
|||
|
));
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeMemory:
|
|||
|
DebugPrint ((
|
|||
|
DEBUG_RESOURCE,
|
|||
|
"%sMEM %c Min: %x:%08x, Max: %x:%08x, Algn: %x, Len %x\n",
|
|||
|
Indent, c,
|
|||
|
Desc->u.Memory.MinimumAddress.HighPart, Desc->u.Memory.MinimumAddress.LowPart,
|
|||
|
Desc->u.Memory.MaximumAddress.HighPart, Desc->u.Memory.MaximumAddress.LowPart,
|
|||
|
Desc->u.Memory.Alignment,
|
|||
|
Desc->u.Memory.Length
|
|||
|
));
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeInterrupt:
|
|||
|
DebugPrint ((
|
|||
|
DEBUG_RESOURCE,
|
|||
|
"%sINT %c Min: %x, Max: %x\n",
|
|||
|
Indent, c,
|
|||
|
Desc->u.Interrupt.MinimumVector,
|
|||
|
Desc->u.Interrupt.MaximumVector
|
|||
|
));
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeDma:
|
|||
|
DebugPrint ((
|
|||
|
DEBUG_RESOURCE,
|
|||
|
"%sDMA %c Min: %x, Max: %x\n",
|
|||
|
Indent, c,
|
|||
|
Desc->u.Dma.MinimumChannel,
|
|||
|
Desc->u.Dma.MaximumChannel
|
|||
|
));
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PipDumpIoResourceList (
|
|||
|
IN PIO_RESOURCE_REQUIREMENTS_LIST IoList
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine displays Io resource requirements list.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
IoList - supplies a pointer to the Io resource requirements list to be displayed.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
|
|||
|
|
|||
|
PIO_RESOURCE_LIST resList;
|
|||
|
PIO_RESOURCE_DESCRIPTOR resDesc;
|
|||
|
ULONG listCount, count, i, j;
|
|||
|
|
|||
|
if (IoList == NULL) {
|
|||
|
return;
|
|||
|
}
|
|||
|
DebugPrint((DEBUG_RESOURCE,
|
|||
|
"Pnp Bios IO Resource Requirements List for Slot %x -\n",
|
|||
|
IoList->SlotNumber
|
|||
|
));
|
|||
|
DebugPrint((DEBUG_RESOURCE,
|
|||
|
" List Count = %x, Bus Number = %x\n",
|
|||
|
IoList->AlternativeLists,
|
|||
|
IoList->BusNumber
|
|||
|
));
|
|||
|
listCount = IoList->AlternativeLists;
|
|||
|
resList = &IoList->List[0];
|
|||
|
for (i = 0; i < listCount; i++) {
|
|||
|
DebugPrint((DEBUG_RESOURCE,
|
|||
|
" Version = %x, Revision = %x, Desc count = %x\n",
|
|||
|
resList->Version, resList->Revision, resList->Count
|
|||
|
));
|
|||
|
resDesc = &resList->Descriptors[0];
|
|||
|
count = resList->Count;
|
|||
|
for (j = 0; j < count; j++) {
|
|||
|
PipDumpIoResourceDescriptor(" ", resDesc);
|
|||
|
resDesc++;
|
|||
|
}
|
|||
|
resList = (PIO_RESOURCE_LIST) resDesc;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PipDumpCmResourceDescriptor (
|
|||
|
IN PUCHAR Indent,
|
|||
|
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Desc
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine processes a IO_RESOURCE_DESCRIPTOR and displays it.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Indent - # char of indentation.
|
|||
|
|
|||
|
Desc - supplies a pointer to the IO_RESOURCE_DESCRIPTOR to be displayed.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
switch (Desc->Type) {
|
|||
|
case CmResourceTypePort:
|
|||
|
DebugPrint ((
|
|||
|
DEBUG_RESOURCE,
|
|||
|
"%sIO Start: %x:%08x, Length: %x\n",
|
|||
|
Indent,
|
|||
|
Desc->u.Port.Start.HighPart, Desc->u.Port.Start.LowPart,
|
|||
|
Desc->u.Port.Length
|
|||
|
));
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeMemory:
|
|||
|
DebugPrint ((
|
|||
|
DEBUG_RESOURCE,
|
|||
|
"%sMEM Start: %x:%08x, Length: %x\n",
|
|||
|
Indent,
|
|||
|
Desc->u.Memory.Start.HighPart, Desc->u.Memory.Start.LowPart,
|
|||
|
Desc->u.Memory.Length
|
|||
|
));
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeInterrupt:
|
|||
|
DebugPrint ((
|
|||
|
DEBUG_RESOURCE,
|
|||
|
"%sINT Level: %x, Vector: %x, Affinity: %x\n",
|
|||
|
Indent,
|
|||
|
Desc->u.Interrupt.Level,
|
|||
|
Desc->u.Interrupt.Vector,
|
|||
|
Desc->u.Interrupt.Affinity
|
|||
|
));
|
|||
|
break;
|
|||
|
|
|||
|
case CmResourceTypeDma:
|
|||
|
DebugPrint ((
|
|||
|
DEBUG_RESOURCE,
|
|||
|
"%sDMA Channel: %x, Port: %x\n",
|
|||
|
Indent,
|
|||
|
Desc->u.Dma.Channel,
|
|||
|
Desc->u.Dma.Port
|
|||
|
));
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PipDumpCmResourceList (
|
|||
|
IN PCM_RESOURCE_LIST CmList
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine displays CM resource list.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
CmList - supplies a pointer to CM resource list
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PCM_FULL_RESOURCE_DESCRIPTOR fullDesc;
|
|||
|
PCM_PARTIAL_RESOURCE_LIST partialDesc;
|
|||
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR desc;
|
|||
|
ULONG count, i;
|
|||
|
|
|||
|
if (CmList) {
|
|||
|
fullDesc = &CmList->List[0];
|
|||
|
DebugPrint((DEBUG_RESOURCE,
|
|||
|
"Pnp Bios Cm Resource List -\n"
|
|||
|
));
|
|||
|
DebugPrint((DEBUG_RESOURCE,
|
|||
|
" List Count = %x, Bus Number = %x\n",
|
|||
|
CmList->Count, fullDesc->BusNumber
|
|||
|
));
|
|||
|
partialDesc = &fullDesc->PartialResourceList;
|
|||
|
DebugPrint((DEBUG_RESOURCE,
|
|||
|
" Version = %x, Revision = %x, Desc count = %x\n",
|
|||
|
partialDesc->Version, partialDesc->Revision, partialDesc->Count
|
|||
|
));
|
|||
|
count = partialDesc->Count;
|
|||
|
desc = &partialDesc->PartialDescriptors[0];
|
|||
|
for (i = 0; i < count; i++) {
|
|||
|
PipDumpCmResourceDescriptor(" ", desc);
|
|||
|
desc++;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|