1476 lines
49 KiB
C
1476 lines
49 KiB
C
/*++
|
||
|
||
Copyright (c) 1995-2000 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
bus.c
|
||
|
||
Abstract:
|
||
|
||
|
||
Author:
|
||
|
||
Shie-Lin Tzong (shielint) July-26-1995
|
||
|
||
Environment:
|
||
|
||
Kernel mode only.
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "busp.h"
|
||
#include "pnpisa.h"
|
||
|
||
#if ISOLATE_CARDS
|
||
|
||
BOOLEAN
|
||
PipIsDeviceInstanceInstalled(
|
||
IN HANDLE Handle,
|
||
IN PUNICODE_STRING DeviceInstanceName
|
||
);
|
||
|
||
VOID
|
||
PipInitializeDeviceInfo (
|
||
IN OUT PDEVICE_INFORMATION deviceInfo,
|
||
IN PCARD_INFORMATION cardinfo,
|
||
IN USHORT index
|
||
);
|
||
|
||
NTSTATUS
|
||
PipGetInstalledLogConf(
|
||
IN HANDLE EnumHandle,
|
||
IN PDEVICE_INFORMATION DeviceInfo,
|
||
OUT PHANDLE LogConfHandle
|
||
);
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE,PipCreateReadDataPort)
|
||
#pragma alloc_text(PAGE,PipStartReadDataPort)
|
||
#pragma alloc_text(PAGE,PipStartAndSelectRdp)
|
||
#pragma alloc_text(PAGE,PipCheckBus)
|
||
#pragma alloc_text(PAGE,PipIsDeviceInstanceInstalled)
|
||
#pragma alloc_text(PAGE,PipGetInstalledLogConf)
|
||
#pragma alloc_text(PAGE,PipInitializeDeviceInfo)
|
||
#endif
|
||
|
||
VOID
|
||
PipVerifyCards(
|
||
IN OUT ULONG *CardsExpected
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine checks to see how many cards can be found using the
|
||
current RDP resources.
|
||
|
||
Arguments:
|
||
|
||
CardsExpected - Pointer to ULONG in which to store the number of
|
||
cards found and minimally verified.
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
ULONG j, cardsDetected = 0;
|
||
NTSTATUS status;
|
||
|
||
ASSERT(PipState == PiSSleep);
|
||
if (*CardsExpected == 0) {
|
||
return;
|
||
}
|
||
|
||
for (j = 1; j <= *CardsExpected; j++) {
|
||
ULONG noDevices, dataLength;
|
||
PUCHAR cardData;
|
||
|
||
PipConfig((UCHAR)j);
|
||
status = PipReadCardResourceData (
|
||
&noDevices,
|
||
&cardData,
|
||
&dataLength);
|
||
if (!NT_SUCCESS(status)) {
|
||
continue;
|
||
} else {
|
||
ExFreePool(cardData);
|
||
cardsDetected++;
|
||
}
|
||
}
|
||
*CardsExpected = cardsDetected;
|
||
}
|
||
|
||
NTSTATUS
|
||
PipStartAndSelectRdp(
|
||
PDEVICE_INFORMATION DeviceInfo,
|
||
PPI_BUS_EXTENSION BusExtension,
|
||
PDEVICE_OBJECT DeviceObject,
|
||
PCM_RESOURCE_LIST StartResources
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine selects an RDP and trims down the resources to just the RDP.
|
||
|
||
Arguments:
|
||
|
||
DeviceInfo - device extension for RDP
|
||
BusExtension - device extension for BUS object
|
||
DeviceObject - device object for RDP
|
||
StartResources - the start resources we received in the RDP start irp
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS = Current resources are fine but need trimming
|
||
|
||
anything else - current resources failed in some way
|
||
|
||
--*/
|
||
{
|
||
ULONG i, j, CardsFound, LastMapped = -1;
|
||
NTSTATUS status;
|
||
|
||
// Already tested for null start resources, and start resource list too small
|
||
|
||
status = PipMapAddressAndCmdPort(BusExtension);
|
||
if (!NT_SUCCESS(status)) {
|
||
DebugPrint((DEBUG_ERROR, "failed to map the address and command ports\n"));
|
||
return status;
|
||
}
|
||
|
||
for (i = 2, j = 0; i < StartResources->List->PartialResourceList.Count; i++, j++) {
|
||
|
||
PipReadDataPortRanges[j].CardsFound = 0;
|
||
// RDP possibilities that we didn't get.
|
||
if (StartResources->List->PartialResourceList.PartialDescriptors[i].u.Port.Length == 0) {
|
||
continue;
|
||
}
|
||
|
||
status = PipMapReadDataPort(
|
||
BusExtension,
|
||
StartResources->List->PartialResourceList.PartialDescriptors[i].u.Port.Start,
|
||
StartResources->List->PartialResourceList.PartialDescriptors[i].u.Port.Length
|
||
);
|
||
if (!NT_SUCCESS(status))
|
||
{
|
||
DebugPrint((DEBUG_ERROR, "failed to map RDP range\n"));
|
||
continue;
|
||
}
|
||
|
||
LastMapped = i;
|
||
|
||
PipIsolateCards(&CardsFound);
|
||
DebugPrint((DEBUG_STATE, "Found %d cards at RDP %x\n", CardsFound, BusExtension->ReadDataPort));
|
||
|
||
#if 0
|
||
PipVerifyCards(&CardsFound);
|
||
DebugPrint((DEBUG_STATE, "Found %d cards at RDP %x, verified OK\n", CardsFound, BusExtension->ReadDataPort));
|
||
#endif
|
||
|
||
PipReadDataPortRanges[j].CardsFound = CardsFound;
|
||
|
||
PipWaitForKey();
|
||
}
|
||
|
||
if (LastMapped == -1) { // never mapped a RDP successfully
|
||
PipCleanupAcquiredResources(BusExtension);
|
||
return STATUS_CONFLICTING_ADDRESSES;
|
||
}
|
||
|
||
//
|
||
// Establish that we want trimmed resource requirements and that
|
||
// we're still processing the RDP.
|
||
//
|
||
ASSERT((DeviceInfo->Flags & DF_PROCESSING_RDP) == 0);
|
||
DeviceInfo->Flags |= DF_PROCESSING_RDP|DF_REQ_TRIMMED;
|
||
|
||
//
|
||
// Release unwanted resources.
|
||
//
|
||
PipCleanupAcquiredResources(BusExtension);
|
||
|
||
IoInvalidateDeviceState(DeviceObject);
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
PipStartReadDataPort(
|
||
PDEVICE_INFORMATION DeviceInfo,
|
||
PPI_BUS_EXTENSION BusExtension,
|
||
PDEVICE_OBJECT DeviceObject,
|
||
PCM_RESOURCE_LIST StartResources
|
||
)
|
||
{
|
||
NTSTATUS status;
|
||
ULONG i, CardsFound;
|
||
|
||
if (StartResources == NULL) {
|
||
DebugPrint((DEBUG_ERROR, "Start RDP with no resources?\n"));
|
||
ASSERT(0);
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
if (StartResources->List->PartialResourceList.Count < 2) {
|
||
DebugPrint((DEBUG_ERROR, "Start RDP with insufficient resources?\n"));
|
||
ASSERT(0);
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
if (StartResources->List->PartialResourceList.Count > 3) {
|
||
return PipStartAndSelectRdp(
|
||
DeviceInfo,
|
||
BusExtension,
|
||
DeviceObject,
|
||
StartResources
|
||
);
|
||
}
|
||
|
||
DebugPrint((DEBUG_STATE|DEBUG_PNP,
|
||
"Starting RDP as port %x\n",
|
||
StartResources->List->PartialResourceList.PartialDescriptors[2].u.Port.Start.LowPart + 3));
|
||
|
||
status = PipMapAddressAndCmdPort(BusExtension);
|
||
if (!NT_SUCCESS(status)) {
|
||
DebugPrint((DEBUG_ERROR, "failed to map the address and command ports\n"));
|
||
return status;
|
||
}
|
||
|
||
status = PipMapReadDataPort(
|
||
BusExtension,
|
||
StartResources->List->PartialResourceList.PartialDescriptors[2].u.Port.Start,
|
||
StartResources->List->PartialResourceList.PartialDescriptors[2].u.Port.Length
|
||
);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
// BUGBUG probably have to free something
|
||
DebugPrint((DEBUG_ERROR, "failed to map RDP range\n"));
|
||
return status;
|
||
}
|
||
|
||
PipIsolateCards(&CardsFound);
|
||
DebugPrint((DEBUG_STATE, "Found %d cards at RDP %x, WaitForKey\n", CardsFound, BusExtension->ReadDataPort));
|
||
|
||
#if 0
|
||
PipVerifyCards(&CardsFound);
|
||
DebugPrint((DEBUG_STATE, "Found %d cards are OK at RDP %x, WaitForKey\n", CardsFound, BusExtension->ReadDataPort));
|
||
#endif
|
||
|
||
DeviceInfo->Flags &= ~DF_PROCESSING_RDP;
|
||
DeviceInfo->Flags |= DF_ACTIVATED;
|
||
|
||
PipWaitForKey();
|
||
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
PipCreateReadDataPortBootResources(
|
||
IN PDEVICE_INFORMATION DeviceInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine creates the CM_RESOURCE_LIST reported as a partial
|
||
boot config for the RDP. This ensures that the RDP start isn't
|
||
deferred excessively.
|
||
|
||
Arguments:
|
||
|
||
DeviceInfo - device extension for PDO
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS
|
||
|
||
STATUS_INSUFFICIENT_RESOURCES
|
||
|
||
--*/
|
||
{
|
||
PCM_RESOURCE_LIST bootResources;
|
||
PCM_PARTIAL_RESOURCE_LIST partialResList;
|
||
PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDesc;
|
||
ULONG bootResourcesSize, i;
|
||
|
||
bootResourcesSize = sizeof(CM_RESOURCE_LIST) +
|
||
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
|
||
|
||
bootResources = ExAllocatePool(PagedPool,
|
||
bootResourcesSize);
|
||
if (bootResources == NULL) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
RtlZeroMemory(bootResources, bootResourcesSize);
|
||
|
||
bootResources->Count = 1;
|
||
partialResList = (PCM_PARTIAL_RESOURCE_LIST)&bootResources->List[0].PartialResourceList;
|
||
partialResList->Version = 0;
|
||
partialResList->Revision = 0x3000;
|
||
partialResList->Count = 2;
|
||
partialDesc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)&partialResList->PartialDescriptors[0];
|
||
|
||
for (i = 0; i < 2; i++) {
|
||
partialDesc->Type = CmResourceTypePort;
|
||
partialDesc->ShareDisposition = CmResourceShareDeviceExclusive;
|
||
partialDesc->Flags = CM_RESOURCE_PORT_IO;
|
||
if (i == 0) {
|
||
partialDesc->u.Port.Start.LowPart = COMMAND_PORT;
|
||
}
|
||
else {
|
||
partialDesc->u.Port.Start.LowPart = ADDRESS_PORT;
|
||
}
|
||
partialDesc->Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
|
||
partialDesc->u.Port.Length = 1;
|
||
partialDesc++;
|
||
}
|
||
DeviceInfo->BootResources = bootResources;
|
||
DeviceInfo->BootResourcesLength = bootResourcesSize;
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
PipCreateReadDataPort(
|
||
PPI_BUS_EXTENSION BusExtension
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine isolates all the PNP ISA cards.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
Always return STATUS_UNSUCCESSFUL.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
PUCHAR readDataPort = NULL;
|
||
PDEVICE_INFORMATION deviceInfo;
|
||
PDEVICE_OBJECT pdo;
|
||
|
||
status = IoCreateDevice(PipDriverObject,
|
||
sizeof(PDEVICE_INFORMATION),
|
||
NULL,
|
||
FILE_DEVICE_BUS_EXTENDER,
|
||
FILE_AUTOGENERATED_DEVICE_NAME,
|
||
FALSE,
|
||
&pdo);
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
return status;
|
||
}
|
||
|
||
// Create a physical device object to represent this logical function
|
||
//
|
||
deviceInfo = ExAllocatePoolWithTag(NonPagedPool,
|
||
sizeof(DEVICE_INFORMATION),
|
||
'iPnP');
|
||
if (!deviceInfo) {
|
||
DebugPrint((DEBUG_ERROR, "PnpIsa:failed to allocate DEVICEINFO structure\n"));
|
||
IoDeleteDevice(pdo);
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
PipInitializeDeviceInfo (deviceInfo,NULL,0);
|
||
|
||
status = PipCreateReadDataPortBootResources(deviceInfo);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
deviceInfo->PhysicalDeviceObject = pdo;
|
||
|
||
//
|
||
// Mark this node as the special read data port node
|
||
//
|
||
deviceInfo->Flags |= DF_ENUMERATED|DF_READ_DATA_PORT;
|
||
deviceInfo->Flags &= ~DF_NOT_FUNCTIONING;
|
||
deviceInfo->PhysicalDeviceObject->DeviceExtension = (PVOID)deviceInfo;
|
||
deviceInfo->ParentDeviceExtension = BusExtension;
|
||
|
||
PipRDPNode = deviceInfo;
|
||
|
||
PipLockDeviceDatabase();
|
||
PushEntryList (&BusExtension->DeviceList,
|
||
&deviceInfo->DeviceList
|
||
);
|
||
PipUnlockDeviceDatabase();
|
||
|
||
deviceInfo->PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
||
} else {
|
||
IoDeleteDevice(pdo);
|
||
ExFreePool(deviceInfo);
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// PipCheckBus and PipMinimalCheckBus enumerate the ISAPNP cards present.
|
||
//
|
||
// PipMinimalCheckBus is used on return from hibernation to avoid
|
||
// having to make everything referenced by PipCheckBus non-pageable.
|
||
//
|
||
// Conventions:
|
||
// * Cards are marked dead by setting their CSN to 0.
|
||
// * Cards are marked potentially missing by setting their CSN to -1.
|
||
// Cards that are found later in the routines have their CSNs
|
||
// properly set, any remaining cards get their CSN set to 0.
|
||
// * Logical devices of dead cards have the DF_NOT_FUNCTIONING flag set.
|
||
//
|
||
|
||
BOOLEAN
|
||
PipMinimalCheckBus (
|
||
IN PPI_BUS_EXTENSION BusExtension
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine enumerates the ISAPNP cards on return from hibernate.
|
||
It is a subset of PipCheckBus and assumes that PipCheckBus will be
|
||
run shortly thereafter. It deals with cards that disappear after
|
||
hibernate or new cards that have appeared. It's primary task is
|
||
to put cards where they used to be before the hibernate.
|
||
|
||
Arguments:
|
||
|
||
BusExtension - FDO extension
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
PDEVICE_INFORMATION deviceInfo;
|
||
PCARD_INFORMATION cardInfo;
|
||
PSINGLE_LIST_ENTRY cardLink, deviceLink;
|
||
ULONG dataLength, noDevices, logicalDevice, FoundCSNs, i;
|
||
NTSTATUS status;
|
||
USHORT csn;
|
||
PUCHAR cardData;
|
||
BOOLEAN needsFullRescan = FALSE;
|
||
|
||
DebugPrint((DEBUG_POWER | DEBUG_ISOLATE,
|
||
"Minimal check bus for restore: %d CSNs expected\n",
|
||
BusExtension->NumberCSNs
|
||
));
|
||
|
||
DebugPrint((DEBUG_POWER, "reset csns in extensions\n"));
|
||
|
||
// forget any previously issued CSNs
|
||
cardLink = BusExtension->CardList.Next;
|
||
while (cardLink) {
|
||
cardInfo = CONTAINING_RECORD (cardLink, CARD_INFORMATION, CardList);
|
||
if (cardInfo->CardSelectNumber != 0) {
|
||
cardInfo->CardSelectNumber = (USHORT) -1;
|
||
}
|
||
cardLink = cardInfo->CardList.Next;
|
||
}
|
||
|
||
//
|
||
// Perform Pnp isolation process. This will assign card select number for each
|
||
// Pnp Isa card isolated by the system. All the isolated cards will be left in
|
||
// isolation state.
|
||
//
|
||
|
||
if (PipReadDataPort && PipCommandPort && PipAddressPort) {
|
||
|
||
PipIsolateCards(&FoundCSNs);
|
||
|
||
DebugPrint((DEBUG_POWER | DEBUG_ISOLATE,
|
||
"Minimal check bus for restore: %d cards found\n",
|
||
FoundCSNs));
|
||
} else {
|
||
//
|
||
// If we can't enumerate (no resources) stop now
|
||
//
|
||
DebugPrint((DEBUG_POWER | DEBUG_ISOLATE,
|
||
"Minimal check bus failed, no resources\n"));
|
||
PipWaitForKey();
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// For each card selected build CardInformation and DeviceInformation structures.
|
||
//
|
||
// PipLFSRInitiation(); BUG?
|
||
|
||
for (csn = 1; csn <= FoundCSNs; csn++) {
|
||
|
||
PipConfig((UCHAR)csn);
|
||
status = PipReadCardResourceData (
|
||
&noDevices,
|
||
&cardData,
|
||
&dataLength);
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
DebugPrint((DEBUG_ERROR | DEBUG_POWER, "CSN %d gives bad resource data\n", csn));
|
||
continue;
|
||
}
|
||
|
||
cardInfo = PipIsCardEnumeratedAlready(BusExtension, cardData, dataLength);
|
||
if (!cardInfo) {
|
||
DebugPrint((DEBUG_ERROR | DEBUG_POWER,
|
||
"No match for card CSN %d, turning off\n", csn));
|
||
for (i = 0; i < noDevices; i++) {
|
||
PipSelectDevice((UCHAR) i);
|
||
PipDeactivateDevice();
|
||
}
|
||
needsFullRescan = TRUE;
|
||
continue;
|
||
}
|
||
|
||
cardInfo->CardSelectNumber = csn;
|
||
|
||
for (deviceLink = cardInfo->LogicalDeviceList.Next; deviceLink;
|
||
deviceLink = deviceInfo->LogicalDeviceList.Next) {
|
||
|
||
deviceInfo = CONTAINING_RECORD (deviceLink, DEVICE_INFORMATION, LogicalDeviceList);
|
||
if (deviceInfo->Flags & DF_NOT_FUNCTIONING) {
|
||
continue;
|
||
}
|
||
|
||
PipSelectDevice((UCHAR)deviceInfo->LogicalDeviceNumber);
|
||
if ((deviceInfo->DevicePowerState == PowerDeviceD0) &&
|
||
(deviceInfo->Flags & DF_ACTIVATED))
|
||
{
|
||
DebugPrint((DEBUG_POWER, "CSN %d/LDN %d was never powered off\n",
|
||
(ULONG) deviceInfo->LogicalDeviceNumber,
|
||
(ULONG) csn));
|
||
PipDeactivateDevice();
|
||
(VOID) PipSetDeviceResources(deviceInfo,
|
||
deviceInfo->AllocatedResources);
|
||
PipActivateDevice();
|
||
} else {
|
||
PipDeactivateDevice();
|
||
}
|
||
}
|
||
}
|
||
|
||
cardLink = BusExtension->CardList.Next;
|
||
while (cardLink) {
|
||
cardInfo = CONTAINING_RECORD (cardLink, CARD_INFORMATION, CardList);
|
||
if (cardInfo->CardSelectNumber == (USHORT)-1) {
|
||
DebugPrint((DEBUG_ERROR, "Marked a card as DEAD, logical devices\n"));
|
||
cardInfo->CardSelectNumber = (USHORT)0; // Mark it is no longer present
|
||
deviceLink = cardInfo->LogicalDeviceList.Next;
|
||
while (deviceLink) {
|
||
deviceInfo = CONTAINING_RECORD (deviceLink, DEVICE_INFORMATION, LogicalDeviceList);
|
||
deviceInfo->Flags |= DF_NOT_FUNCTIONING;
|
||
deviceLink = deviceInfo->LogicalDeviceList.Next;
|
||
}
|
||
needsFullRescan = TRUE;
|
||
}
|
||
cardLink = cardInfo->CardList.Next;
|
||
}
|
||
|
||
PipWaitForKey();
|
||
|
||
return needsFullRescan;
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
PipCheckBus (
|
||
IN PPI_BUS_EXTENSION BusExtension
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The function enumerates the bus specified by BusExtension
|
||
|
||
Arguments:
|
||
|
||
BusExtension - supplies a pointer to the BusExtension structure of the bus
|
||
to be enumerated.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
ULONG objectSize, noDevices;
|
||
OBJECT_ATTRIBUTES objectAttributes;
|
||
PUCHAR cardData;
|
||
ULONG dataLength;
|
||
USHORT csn, i, detectedCsn = 0, irqReqFlags, irqBootFlags;
|
||
PDEVICE_INFORMATION deviceInfo;
|
||
PCARD_INFORMATION cardInfo;
|
||
UCHAR tmp;
|
||
PSINGLE_LIST_ENTRY link;
|
||
ULONG dumpData;
|
||
UNICODE_STRING unicodeString;
|
||
HANDLE logConfHandle, enumHandle = NULL;
|
||
PKEY_VALUE_FULL_INFORMATION keyValueInformation;
|
||
PCM_RESOURCE_LIST cmResource;
|
||
BOOLEAN conflictDetected,requireEdge;
|
||
ULONG dummy, bootFlags = 0;
|
||
|
||
PSINGLE_LIST_ENTRY deviceLink;
|
||
PSINGLE_LIST_ENTRY cardLink;
|
||
|
||
// mark all cards as 'maybe missing'
|
||
|
||
cardLink = BusExtension->CardList.Next;
|
||
while (cardLink) {
|
||
cardInfo = CONTAINING_RECORD (cardLink, CARD_INFORMATION, CardList);
|
||
if (cardInfo->CardSelectNumber != (USHORT)0) {
|
||
cardInfo->CardSelectNumber = (USHORT)-1;
|
||
}
|
||
cardLink = cardInfo->CardList.Next;
|
||
}
|
||
|
||
//
|
||
// Clear DF_ENUMERTED flag for all the devices.
|
||
//
|
||
|
||
deviceLink = BusExtension->DeviceList.Next;
|
||
while (deviceLink) {
|
||
deviceInfo = CONTAINING_RECORD (deviceLink, DEVICE_INFORMATION, DeviceList);
|
||
if (!(deviceInfo->Flags & DF_READ_DATA_PORT)) {
|
||
deviceInfo ->Flags &= ~DF_ENUMERATED;
|
||
}
|
||
deviceLink = deviceInfo->DeviceList.Next;
|
||
}
|
||
|
||
//
|
||
// Perform Pnp isolation process. This will assign card select number for each
|
||
// Pnp Isa card isolated by the system. All the isolated cards will be left in
|
||
// isolation state.
|
||
//
|
||
|
||
if (PipReadDataPort && PipCommandPort && PipAddressPort) {
|
||
DebugPrint((DEBUG_PNP, "QueryDeviceRelations checking the BUS\n"));
|
||
PipIsolateCards(&BusExtension->NumberCSNs);
|
||
} else {
|
||
//
|
||
// If we can't enumerate (no resources) stop now
|
||
//
|
||
DebugPrint((DEBUG_PNP, "QueryDeviceRelations: No RDP\n"));
|
||
return;
|
||
}
|
||
|
||
DebugPrint((DEBUG_PNP, "CheckBus found %d cards\n",
|
||
BusExtension->NumberCSNs));
|
||
#if NT4_DRIVER_COMPAT
|
||
|
||
//
|
||
// If there is no PnpISA card, we are done.
|
||
// Oterwise, open HKLM\System\CCS\ENUM\PNPISA.
|
||
//
|
||
|
||
if (BusExtension->NumberCSNs != 0) {
|
||
|
||
RtlInitUnicodeString(
|
||
&unicodeString,
|
||
L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM");
|
||
status = PipOpenRegistryKey(&enumHandle,
|
||
NULL,
|
||
&unicodeString,
|
||
KEY_ALL_ACCESS,
|
||
FALSE
|
||
);
|
||
if (!NT_SUCCESS(status)) {
|
||
dumpData = status;
|
||
PipLogError(PNPISA_OPEN_CURRENTCONTROLSET_ENUM_FAILED,
|
||
PNPISA_CHECKDEVICE_1,
|
||
status,
|
||
&dumpData,
|
||
1,
|
||
0,
|
||
NULL
|
||
);
|
||
|
||
DebugPrint((DEBUG_ERROR, "PnPIsa: Unable to open HKLM\\SYSTEM\\CCS\\ENUM"));
|
||
return;
|
||
}
|
||
}
|
||
|
||
#endif // NT4_DRIVER_COMPAT
|
||
|
||
//
|
||
// For each card selected build CardInformation and DeviceInformation structures.
|
||
//
|
||
|
||
for (csn = 1; csn <= BusExtension->NumberCSNs; csn++) {
|
||
|
||
PipConfig((UCHAR)csn);
|
||
status = PipReadCardResourceData (
|
||
&noDevices,
|
||
&cardData,
|
||
&dataLength);
|
||
if (!NT_SUCCESS(status)) {
|
||
//
|
||
// card will marked 'not functioning' later
|
||
//
|
||
DebugPrint((DEBUG_ERROR, "PnpIsaCheckBus: Found a card which gives bad resource data\n"));
|
||
continue;
|
||
}
|
||
|
||
detectedCsn++;
|
||
|
||
cardInfo = PipIsCardEnumeratedAlready(BusExtension, cardData, dataLength);
|
||
|
||
if (!cardInfo) {
|
||
|
||
//
|
||
// Allocate and initialize card information and its associate device
|
||
// information structures.
|
||
//
|
||
|
||
cardInfo = (PCARD_INFORMATION)ExAllocatePoolWithTag(
|
||
NonPagedPool,
|
||
sizeof(CARD_INFORMATION),
|
||
'iPnP');
|
||
if (!cardInfo) {
|
||
dumpData = sizeof(CARD_INFORMATION);
|
||
PipLogError(PNPISA_INSUFFICIENT_POOL,
|
||
PNPISA_CHECKBUS_1,
|
||
STATUS_INSUFFICIENT_RESOURCES,
|
||
&dumpData,
|
||
1,
|
||
0,
|
||
NULL
|
||
);
|
||
|
||
ExFreePool(cardData);
|
||
DebugPrint((DEBUG_ERROR, "PnpIsaCheckBus: failed to allocate CARD_INFO structure\n"));
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Initialize card information structure
|
||
//
|
||
|
||
RtlZeroMemory(cardInfo, sizeof(CARD_INFORMATION));
|
||
cardInfo->CardSelectNumber = csn;
|
||
cardInfo->NumberLogicalDevices = noDevices;
|
||
cardInfo->CardData = cardData;
|
||
cardInfo->CardDataLength = dataLength;
|
||
cardInfo->CardFlags = PipGetCardFlags(cardInfo);
|
||
|
||
PushEntryList (&BusExtension->CardList,
|
||
&cardInfo->CardList
|
||
);
|
||
DebugPrint ((DEBUG_ISOLATE, "adding one pnp card %x\n",
|
||
cardInfo));
|
||
|
||
//
|
||
// For each logical device supported by the card build its DEVICE_INFORMATION
|
||
// structures.
|
||
//
|
||
|
||
cardData += sizeof(SERIAL_IDENTIFIER);
|
||
dataLength -= sizeof(SERIAL_IDENTIFIER);
|
||
PipFindNextLogicalDeviceTag(&cardData, &dataLength);
|
||
|
||
//
|
||
// Select card
|
||
//
|
||
|
||
for (i = 0; i < noDevices; i++) { // logical device number starts from 0
|
||
|
||
//
|
||
// Create and initialize device tracking structure (Device_Information.)
|
||
//
|
||
|
||
deviceInfo = (PDEVICE_INFORMATION) ExAllocatePoolWithTag(
|
||
NonPagedPool,
|
||
sizeof(DEVICE_INFORMATION),
|
||
'iPnP');
|
||
if (!deviceInfo) {
|
||
dumpData = sizeof(DEVICE_INFORMATION);
|
||
PipLogError(PNPISA_INSUFFICIENT_POOL,
|
||
PNPISA_CHECKBUS_2,
|
||
STATUS_INSUFFICIENT_RESOURCES,
|
||
&dumpData,
|
||
1,
|
||
0,
|
||
NULL
|
||
);
|
||
|
||
DebugPrint((DEBUG_ERROR, "PnpIsa:failed to allocate DEVICEINFO structure\n"));
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// This sets card data to point to the next device.
|
||
//
|
||
PipInitializeDeviceInfo (deviceInfo,cardInfo,i);
|
||
|
||
deviceInfo->ParentDeviceExtension = BusExtension;
|
||
|
||
//
|
||
// cardData is UPDATED by this routine to the next logical device.
|
||
//
|
||
deviceInfo->DeviceData = cardData;
|
||
if (cardData) {
|
||
deviceInfo->DeviceDataLength = PipFindNextLogicalDeviceTag(&cardData, &dataLength);
|
||
} else {
|
||
deviceInfo->DeviceDataLength = 0;
|
||
ASSERT(deviceInfo->DeviceDataLength != 0);
|
||
continue;
|
||
}
|
||
|
||
ASSERT(deviceInfo->DeviceDataLength != 0);
|
||
|
||
//
|
||
// The PNP ISA spec lets the device specify IRQ
|
||
// settings that don't actually work, and some that
|
||
// work rarely. And some devices just get it wrong.
|
||
//
|
||
// IRQ edge/level interpretation strategy:
|
||
//
|
||
// * Extract the irq requirements from the tags on a
|
||
// per device basis.
|
||
// * Extract the boot config, note edge/level settings
|
||
// * Trust the boot config over requirements. When in
|
||
// doubt, assume edge.
|
||
// * Fix boot config and requirements to reflect the
|
||
// edge/level settings we've decided upon.
|
||
// * Ignore the high/low settings in the requirements
|
||
// and in the boot config. Only support high- // edge
|
||
// and low-level.
|
||
//
|
||
|
||
// Determine whether requirements specify edge or
|
||
// level triggered interrupts. Unfortunately, we
|
||
// don't build the IO_REQUIREMENTS_LIST until later,
|
||
// so just examine the tags.
|
||
|
||
irqReqFlags = PipIrqLevelRequirementsFromDeviceData(
|
||
deviceInfo->DeviceData,
|
||
deviceInfo->DeviceDataLength
|
||
);
|
||
|
||
DebugPrint((DEBUG_IRQ, "Irqs for CSN %d/LDN %d are %s\n",
|
||
deviceInfo->CardInformation->CardSelectNumber,
|
||
deviceInfo->LogicalDeviceNumber,
|
||
(irqReqFlags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE) ? "level" : "edge"));
|
||
|
||
//
|
||
// Select the logical device, disable its io range check
|
||
// and read its boot config before disabling it.
|
||
//
|
||
|
||
PipSelectDevice((UCHAR)i);
|
||
if (!(deviceInfo->CardInformation->CardFlags & CF_IGNORE_BOOTCONFIG)) {
|
||
status = PipReadDeviceResources (
|
||
0,
|
||
deviceInfo->DeviceData,
|
||
deviceInfo->CardInformation->CardFlags,
|
||
&deviceInfo->BootResources,
|
||
&deviceInfo->BootResourcesLength,
|
||
&irqBootFlags
|
||
);
|
||
if (!NT_SUCCESS(status)) {
|
||
deviceInfo->BootResources = NULL;
|
||
deviceInfo->BootResourcesLength = 0;
|
||
|
||
// If we had a boot config on this boot,
|
||
// extract saved irqBootFlags that we saved earlier.
|
||
status = PipGetBootIrqFlags(deviceInfo, &irqBootFlags);
|
||
if (!NT_SUCCESS(status)) {
|
||
// if we have no boot config, and no saved
|
||
// boot config from earlier this boot then
|
||
// we are going to take a shot in the dark
|
||
// and declare it edge. Experience has
|
||
// shown that if you actually believe
|
||
// resource requirements of level w/o
|
||
// confirmation from the BIOS, then you
|
||
// die horribly. Very very few cards
|
||
// actually do level and do it right.
|
||
|
||
irqBootFlags = CM_RESOURCE_INTERRUPT_LATCHED;
|
||
(VOID) PipSaveBootIrqFlags(deviceInfo, irqBootFlags);
|
||
}
|
||
} else {
|
||
// save irqBootFlags in case the RDP gets
|
||
// removed and our boot config is lost.
|
||
(VOID) PipSaveBootIrqFlags(deviceInfo, irqBootFlags);
|
||
}
|
||
|
||
DebugPrint((DEBUG_IRQ, "Irqs (boot config) for CSN %d/LDN %d are %s\n",
|
||
deviceInfo->CardInformation->CardSelectNumber,
|
||
deviceInfo->LogicalDeviceNumber,
|
||
(irqBootFlags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE) ? "level" : "edge"));
|
||
} else {
|
||
// when in doubt....
|
||
irqBootFlags = CM_RESOURCE_INTERRUPT_LATCHED;
|
||
}
|
||
|
||
if (irqBootFlags != irqReqFlags) {
|
||
DebugPrint((DEBUG_IRQ, "Req and Boot config disagree on irq type, favoring boot config"));
|
||
irqReqFlags = irqBootFlags;
|
||
}
|
||
|
||
// override flags in case a card *MUST* be configured
|
||
// one way and the above code fails to do this.
|
||
if (deviceInfo->CardInformation->CardFlags == CF_FORCE_LEVEL) {
|
||
irqReqFlags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
|
||
} else if (deviceInfo->CardInformation->CardFlags == CF_FORCE_EDGE) {
|
||
irqReqFlags = CM_RESOURCE_INTERRUPT_LATCHED;
|
||
}
|
||
|
||
if (deviceInfo->BootResources) {
|
||
// apply irq level/edge decision to boot config
|
||
PipFixBootConfigIrqs(deviceInfo->BootResources,
|
||
irqReqFlags);
|
||
(VOID) PipSaveBootResources(deviceInfo);
|
||
cmResource = deviceInfo->BootResources;
|
||
} else {
|
||
status = PipGetSavedBootResources(deviceInfo, &cmResource);
|
||
if (!NT_SUCCESS(status)) {
|
||
cmResource = NULL;
|
||
}
|
||
}
|
||
|
||
#if 0
|
||
PipWriteAddress(IO_RANGE_CHECK_PORT);
|
||
tmp = PipReadData();
|
||
tmp &= ~2;
|
||
PipWriteAddress(IO_RANGE_CHECK_PORT);
|
||
PipWriteData(tmp);
|
||
#endif
|
||
PipDeactivateDevice();
|
||
|
||
PipQueryDeviceResourceRequirements (
|
||
deviceInfo,
|
||
0, // Bus Number
|
||
0, // Slot number??
|
||
cmResource,
|
||
irqReqFlags,
|
||
&deviceInfo->ResourceRequirements,
|
||
&dumpData
|
||
);
|
||
|
||
if (cmResource && !deviceInfo->BootResources) {
|
||
ExFreePool(cmResource);
|
||
cmResource = NULL;
|
||
}
|
||
|
||
//
|
||
// Create a physical device object to represent this logical function
|
||
//
|
||
status = IoCreateDevice( PipDriverObject,
|
||
sizeof(PDEVICE_INFORMATION),
|
||
NULL,
|
||
FILE_DEVICE_BUS_EXTENDER,
|
||
FILE_AUTOGENERATED_DEVICE_NAME,
|
||
FALSE,
|
||
&deviceInfo->PhysicalDeviceObject);
|
||
if (NT_SUCCESS(status)) {
|
||
deviceInfo->Flags |= DF_ENUMERATED;
|
||
deviceInfo->Flags &= ~DF_NOT_FUNCTIONING;
|
||
deviceInfo->PhysicalDeviceObject->DeviceExtension = (PVOID)deviceInfo;
|
||
//
|
||
// Add it to the logical device list of the pnp isa card.
|
||
//
|
||
|
||
PushEntryList (&cardInfo->LogicalDeviceList,
|
||
&deviceInfo->LogicalDeviceList
|
||
);
|
||
|
||
//
|
||
// Add it to the list of devices for this bus
|
||
//
|
||
|
||
PushEntryList (&BusExtension->DeviceList,
|
||
&deviceInfo->DeviceList
|
||
);
|
||
|
||
#if NT4_DRIVER_COMPAT
|
||
|
||
//
|
||
// Check should we enable this device. If the device has
|
||
// Service setup and ForcedConfig then enable the device.
|
||
//
|
||
|
||
logConfHandle = NULL;
|
||
status = PipGetInstalledLogConf(enumHandle,
|
||
deviceInfo,
|
||
&logConfHandle);
|
||
if (NT_SUCCESS(status)) {
|
||
//
|
||
// Read the boot config selected by user and activate the device.
|
||
// First check if ForcedConfig is set. If not, check BootConfig.
|
||
//
|
||
|
||
status = PipGetRegistryValue(logConfHandle,
|
||
L"ForcedConfig",
|
||
&keyValueInformation);
|
||
if (NT_SUCCESS(status)) {
|
||
if ((keyValueInformation->Type == REG_RESOURCE_LIST) &&
|
||
(keyValueInformation->DataLength != 0)) {
|
||
cmResource = (PCM_RESOURCE_LIST)
|
||
KEY_VALUE_DATA(keyValueInformation);
|
||
//
|
||
// Act as if force config
|
||
// reflected the level/edge
|
||
// decision we made based on
|
||
// the boot config and
|
||
// resource requirements.
|
||
//
|
||
|
||
PipFixBootConfigIrqs(cmResource,
|
||
irqReqFlags);
|
||
|
||
conflictDetected = FALSE;
|
||
|
||
//
|
||
// Before activating the device, make sure no one is using
|
||
// the resources.
|
||
//
|
||
|
||
status = IoReportResourceForDetection(
|
||
PipDriverObject,
|
||
NULL,
|
||
0,
|
||
deviceInfo->PhysicalDeviceObject,
|
||
cmResource,
|
||
keyValueInformation->DataLength,
|
||
&conflictDetected
|
||
);
|
||
if (NT_SUCCESS(status) && (conflictDetected == FALSE)) {
|
||
|
||
//
|
||
// Set resources and activate the device.
|
||
//
|
||
|
||
status = PipSetDeviceResources (deviceInfo, cmResource);
|
||
if (NT_SUCCESS(status)) {
|
||
PipActivateDevice();
|
||
deviceInfo->Flags |= DF_ACTIVATED;
|
||
deviceInfo->Flags &= ~DF_REMOVED;
|
||
|
||
//
|
||
// Write ForcedConfig to AllocConfig
|
||
//
|
||
|
||
RtlInitUnicodeString(&unicodeString, L"AllocConfig");
|
||
ZwSetValueKey(logConfHandle,
|
||
&unicodeString,
|
||
0,
|
||
REG_RESOURCE_LIST,
|
||
cmResource,
|
||
keyValueInformation->DataLength
|
||
);
|
||
|
||
//
|
||
// Make ForcedConfig our new BootConfig.
|
||
//
|
||
|
||
if (deviceInfo->BootResources) {
|
||
ExFreePool(deviceInfo->BootResources);
|
||
deviceInfo->BootResourcesLength = 0;
|
||
deviceInfo->BootResources = NULL;
|
||
}
|
||
deviceInfo->BootResources = (PCM_RESOURCE_LIST) ExAllocatePool (
|
||
PagedPool, keyValueInformation->DataLength);
|
||
if (deviceInfo->BootResources) {
|
||
deviceInfo->BootResourcesLength = keyValueInformation->DataLength;
|
||
RtlMoveMemory(deviceInfo->BootResources,
|
||
cmResource,
|
||
deviceInfo->BootResourcesLength
|
||
);
|
||
}
|
||
deviceInfo->DevicePowerState = PowerDeviceD0;
|
||
deviceInfo->LogConfHandle = logConfHandle;
|
||
}
|
||
|
||
//
|
||
// Release the resources. If someone else gets the resources
|
||
// before us, then ....
|
||
//
|
||
|
||
dummy = 0;
|
||
IoReportResourceForDetection(
|
||
PipDriverObject,
|
||
NULL,
|
||
0,
|
||
deviceInfo->PhysicalDeviceObject,
|
||
(PCM_RESOURCE_LIST) &dummy,
|
||
sizeof(dummy),
|
||
&conflictDetected
|
||
);
|
||
}
|
||
}
|
||
ExFreePool(keyValueInformation);
|
||
}
|
||
if (deviceInfo->LogConfHandle == NULL) {
|
||
ZwClose(logConfHandle);
|
||
}
|
||
}
|
||
#endif
|
||
deviceInfo->PhysicalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
|
||
} else {
|
||
// NTRAID#20181
|
||
// Still leaking the DeviceInfo structure
|
||
// and it's contents if IoCreateDevice failed.
|
||
}
|
||
}
|
||
} else {
|
||
|
||
//
|
||
// The card has been enumerated and setup. We only need to change the CSN.
|
||
//
|
||
|
||
cardInfo->CardSelectNumber = csn;
|
||
ExFreePool(cardData);
|
||
|
||
//
|
||
// Set DF_ENUMERATED flag on all the logical devices on the isapnp card.
|
||
//
|
||
|
||
deviceLink = cardInfo->LogicalDeviceList.Next;
|
||
while (deviceLink) {
|
||
deviceInfo = CONTAINING_RECORD (deviceLink, DEVICE_INFORMATION, LogicalDeviceList);
|
||
if (!(deviceInfo->Flags & DF_NOT_FUNCTIONING)) {
|
||
deviceInfo->Flags |= DF_ENUMERATED;
|
||
}
|
||
// what did this accomplish?
|
||
if ((deviceInfo->DevicePowerState == PowerDeviceD0) &&
|
||
(deviceInfo->Flags & DF_ACTIVATED)) {
|
||
PipSelectDevice((UCHAR)deviceInfo->LogicalDeviceNumber);
|
||
PipActivateDevice();
|
||
}
|
||
deviceLink = deviceInfo->LogicalDeviceList.Next;
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Go through the card link list for cards that we didn't find this time.
|
||
//
|
||
|
||
cardLink = BusExtension->CardList.Next;
|
||
while (cardLink) {
|
||
cardInfo = CONTAINING_RECORD (cardLink, CARD_INFORMATION, CardList);
|
||
if (cardInfo->CardSelectNumber == (USHORT)-1) {
|
||
DebugPrint((DEBUG_ERROR, "Marked a card as DEAD, logical devices\n"));
|
||
cardInfo->CardSelectNumber = (USHORT)0; // Mark it is no longer present
|
||
deviceLink = cardInfo->LogicalDeviceList.Next;
|
||
while (deviceLink) {
|
||
deviceInfo = CONTAINING_RECORD (deviceLink, DEVICE_INFORMATION, LogicalDeviceList);
|
||
deviceInfo->Flags |= DF_NOT_FUNCTIONING;
|
||
deviceInfo->Flags &= ~DF_ENUMERATED;
|
||
deviceLink = deviceInfo->LogicalDeviceList.Next;
|
||
}
|
||
}
|
||
cardLink = cardInfo->CardList.Next;
|
||
}
|
||
|
||
#if NT4_DRIVER_COMPAT
|
||
if (enumHandle) {
|
||
ZwClose(enumHandle);
|
||
}
|
||
#endif
|
||
//
|
||
// Finaly put all cards into wait for key state.
|
||
//
|
||
|
||
DebugPrint((DEBUG_STATE, "All cards ready\n"));
|
||
PipWaitForKey();
|
||
|
||
BusExtension->NumberCSNs = detectedCsn;
|
||
}
|
||
|
||
BOOLEAN
|
||
PipIsDeviceInstanceInstalled(
|
||
IN HANDLE Handle,
|
||
IN PUNICODE_STRING DeviceInstanceName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine checks if the device instance is installed.
|
||
|
||
Arguments:
|
||
|
||
Handle - Supplies a handle to the device instanace key to be checked.
|
||
|
||
DeviceInstanceName - supplies a pointer to a UNICODE_STRING which specifies
|
||
the path of the device instance to be checked.
|
||
|
||
Returns:
|
||
|
||
A BOOLEAN value.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS status;
|
||
ULONG deviceFlags;
|
||
PKEY_VALUE_FULL_INFORMATION keyValueInformation;
|
||
BOOLEAN installed;
|
||
UNICODE_STRING serviceName, unicodeString;
|
||
HANDLE handle, handlex;
|
||
ULONG dumpData;
|
||
|
||
//
|
||
// Check if the "Service=" value entry initialized. If no, its driver
|
||
// is not installed yet.
|
||
//
|
||
status = PipGetRegistryValue(Handle,
|
||
L"Service",
|
||
&keyValueInformation);
|
||
if (NT_SUCCESS(status)) {
|
||
if ((keyValueInformation->Type == REG_SZ) &&
|
||
(keyValueInformation->DataLength != 0)) {
|
||
serviceName.Buffer = (PWSTR)((PCHAR)keyValueInformation +
|
||
keyValueInformation->DataOffset);
|
||
serviceName.MaximumLength = serviceName.Length = (USHORT)keyValueInformation->DataLength;
|
||
if (serviceName.Buffer[(keyValueInformation->DataLength / sizeof(WCHAR)) - 1] == UNICODE_NULL) {
|
||
serviceName.Length -= sizeof(WCHAR);
|
||
}
|
||
|
||
//
|
||
// try open the service key to make sure it is a valid key
|
||
//
|
||
|
||
RtlInitUnicodeString(
|
||
&unicodeString,
|
||
L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\SERVICES");
|
||
status = PipOpenRegistryKey(&handle,
|
||
NULL,
|
||
&unicodeString,
|
||
KEY_READ,
|
||
FALSE
|
||
);
|
||
if (!NT_SUCCESS(status)) {
|
||
dumpData = status;
|
||
PipLogError(PNPISA_OPEN_CURRENTCONTROLSET_SERVICE_FAILED,
|
||
PNPISA_CHECKINSTALLED_1,
|
||
status,
|
||
&dumpData,
|
||
1,
|
||
0,
|
||
NULL
|
||
);
|
||
|
||
DebugPrint((DEBUG_ERROR, "PnPIsaCheckDeviceInstalled: Can not open CCS\\SERVICES key"));
|
||
ExFreePool(keyValueInformation);
|
||
return FALSE;
|
||
}
|
||
|
||
status = PipOpenRegistryKey(&handlex,
|
||
handle,
|
||
&serviceName,
|
||
KEY_READ,
|
||
FALSE
|
||
);
|
||
ZwClose (handle);
|
||
if (!NT_SUCCESS(status)) {
|
||
dumpData = status;
|
||
PipLogError(PNPISA_OPEN_CURRENTCONTROLSET_SERVICE_DRIVER_FAILED,
|
||
PNPISA_CHECKINSTALLED_2,
|
||
status,
|
||
&dumpData,
|
||
1,
|
||
serviceName.Length,
|
||
serviceName.Buffer
|
||
);
|
||
|
||
DebugPrint((DEBUG_ERROR, "PnPIsaCheckDeviceInstalled: Can not open CCS\\SERVICES key"));
|
||
ExFreePool(keyValueInformation);
|
||
return FALSE;
|
||
}
|
||
ZwClose(handlex);
|
||
}
|
||
ExFreePool(keyValueInformation);
|
||
} else {
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// Check if the device instance has been disabled.
|
||
// First check global flag: CONFIGFLAG and then CSCONFIGFLAG.
|
||
//
|
||
|
||
deviceFlags = 0;
|
||
status = PipGetRegistryValue(Handle,
|
||
L"ConfigFlags",
|
||
&keyValueInformation);
|
||
if (NT_SUCCESS(status)) {
|
||
if ((keyValueInformation->Type == REG_DWORD) &&
|
||
(keyValueInformation->DataLength >= sizeof(ULONG))) {
|
||
deviceFlags = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
|
||
}
|
||
ExFreePool(keyValueInformation);
|
||
}
|
||
|
||
if (!(deviceFlags & CONFIGFLAG_DISABLED)) {
|
||
deviceFlags = 0;
|
||
status = PipGetDeviceInstanceCsConfigFlags(
|
||
DeviceInstanceName,
|
||
&deviceFlags
|
||
);
|
||
if (NT_SUCCESS(status)) {
|
||
if ((deviceFlags & CSCONFIGFLAG_DISABLED) ||
|
||
(deviceFlags & CSCONFIGFLAG_DO_NOT_CREATE)) {
|
||
deviceFlags = CONFIGFLAG_DISABLED;
|
||
} else {
|
||
deviceFlags = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
installed = TRUE;
|
||
if (deviceFlags & CONFIGFLAG_DISABLED) {
|
||
installed = FALSE;
|
||
}
|
||
|
||
return installed;
|
||
}
|
||
|
||
VOID
|
||
PipInitializeDeviceInfo (PDEVICE_INFORMATION deviceInfo,
|
||
PCARD_INFORMATION cardInfo,
|
||
USHORT index
|
||
)
|
||
{
|
||
ULONG dataLength;
|
||
|
||
RtlZeroMemory (deviceInfo,sizeof (DEVICE_INFORMATION));
|
||
deviceInfo->Flags = DF_NOT_FUNCTIONING;
|
||
deviceInfo->CardInformation = cardInfo;
|
||
deviceInfo->LogicalDeviceNumber = index;
|
||
deviceInfo->DevicePowerState = PowerDeviceD0;
|
||
}
|
||
|
||
|
||
#if NT4_DRIVER_COMPAT
|
||
|
||
NTSTATUS
|
||
PipGetInstalledLogConf(
|
||
IN HANDLE EnumHandle,
|
||
IN PDEVICE_INFORMATION DeviceInfo,
|
||
OUT PHANDLE LogConfHandle
|
||
)
|
||
{
|
||
HANDLE deviceIdHandle = NULL, uniqueIdHandle = NULL, confHandle = NULL;
|
||
PWCHAR deviceId = NULL, uniqueId = NULL, buffer;
|
||
UNICODE_STRING unicodeString;
|
||
NTSTATUS status;
|
||
USHORT length;
|
||
|
||
status = PipQueryDeviceId(DeviceInfo, &deviceId, 0);
|
||
if (!NT_SUCCESS(status)) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
RtlInitUnicodeString(&unicodeString, deviceId);
|
||
status = PipOpenRegistryKey(&deviceIdHandle,
|
||
EnumHandle,
|
||
&unicodeString,
|
||
KEY_READ,
|
||
FALSE
|
||
);
|
||
if (!NT_SUCCESS(status)) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
status = PipQueryDeviceUniqueId(DeviceInfo, &uniqueId);
|
||
if (!NT_SUCCESS(status)) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
|
||
//
|
||
// Open this registry path under HKLM\CCS\System\Enum
|
||
//
|
||
|
||
RtlInitUnicodeString(&unicodeString, uniqueId);
|
||
status = PipOpenRegistryKey(&uniqueIdHandle,
|
||
deviceIdHandle,
|
||
&unicodeString,
|
||
KEY_READ,
|
||
FALSE
|
||
);
|
||
if (!NT_SUCCESS(status)) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
RtlInitUnicodeString(&unicodeString, L"LogConf");
|
||
status = PipOpenRegistryKey(&confHandle,
|
||
uniqueIdHandle,
|
||
&unicodeString,
|
||
KEY_READ,
|
||
FALSE
|
||
);
|
||
if (!NT_SUCCESS(status)) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
// allocate enough space for "deviceid\uniqueid<unicode null>"
|
||
length = (wcslen(uniqueId) + wcslen(deviceId)) * sizeof(WCHAR) +
|
||
sizeof(WCHAR) + sizeof(WCHAR);
|
||
buffer = ExAllocatePool(PagedPool, length);
|
||
if (buffer == NULL) {
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto Cleanup;
|
||
}
|
||
|
||
swprintf(buffer, L"%s\\%s", deviceId, uniqueId);
|
||
RtlInitUnicodeString(&unicodeString, buffer);
|
||
|
||
if (PipIsDeviceInstanceInstalled(uniqueIdHandle, &unicodeString)) {
|
||
status = STATUS_SUCCESS;
|
||
*LogConfHandle = confHandle;
|
||
} else {
|
||
status = STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
ExFreePool(buffer);
|
||
|
||
Cleanup:
|
||
if (uniqueIdHandle) {
|
||
ZwClose(uniqueIdHandle);
|
||
}
|
||
|
||
if (uniqueId) {
|
||
ExFreePool(uniqueId);
|
||
}
|
||
|
||
if (deviceIdHandle) {
|
||
ZwClose(deviceIdHandle);
|
||
}
|
||
|
||
if (deviceId) {
|
||
ExFreePool(deviceId);
|
||
}
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
*LogConfHandle = NULL;
|
||
if (confHandle) {
|
||
ZwClose(confHandle);
|
||
}
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
#endif
|
||
|
||
#endif
|