963 lines
34 KiB
C
963 lines
34 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1995 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"
|
|||
|
|
|||
|
//
|
|||
|
// Internal references
|
|||
|
//
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
PipIsDeviceInstanceInstalled(
|
|||
|
IN HANDLE Handle,
|
|||
|
IN PUNICODE_STRING DeviceInstanceName
|
|||
|
);
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text(INIT,PipCheckBus)
|
|||
|
#pragma alloc_text(INIT,PipCheckDevices)
|
|||
|
#pragma alloc_text(INIT,PipDeleteCards)
|
|||
|
#pragma alloc_text(INIT,PipIsDeviceInstanceInstalled)
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
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;
|
|||
|
HANDLE handle;
|
|||
|
PUCHAR cardData;
|
|||
|
ULONG dataLength;
|
|||
|
USHORT csn, i, detectedCsn = 0;
|
|||
|
PDEVICE_INFORMATION deviceInfo;
|
|||
|
PCARD_INFORMATION cardInfo;
|
|||
|
UCHAR tmp;
|
|||
|
PSINGLE_LIST_ENTRY link;
|
|||
|
|
|||
|
//
|
|||
|
// 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 put into
|
|||
|
// wait-for-key state.
|
|||
|
//
|
|||
|
|
|||
|
PipIsolateCards(&BusExtension->NumberCSNs);
|
|||
|
|
|||
|
//
|
|||
|
// send initiation key to put cards into sleep state
|
|||
|
//
|
|||
|
|
|||
|
PipLFSRInitiation ();
|
|||
|
|
|||
|
//
|
|||
|
// For each card selected build CardInformation and DeviceInformation structures.
|
|||
|
//
|
|||
|
|
|||
|
for (csn = 1; csn <= BusExtension->NumberCSNs; csn++) {
|
|||
|
|
|||
|
status = PipReadCardResourceData (
|
|||
|
csn,
|
|||
|
&noDevices,
|
|||
|
&cardData,
|
|||
|
&dataLength);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
detectedCsn++;
|
|||
|
|
|||
|
//
|
|||
|
// Allocate and initialize card information and its associate device
|
|||
|
// information structures.
|
|||
|
//
|
|||
|
|
|||
|
cardInfo = (PCARD_INFORMATION)ExAllocatePoolWithTag(
|
|||
|
NonPagedPool,
|
|||
|
sizeof(CARD_INFORMATION),
|
|||
|
'iPnP');
|
|||
|
if (!cardInfo) {
|
|||
|
ExFreePool(cardData);
|
|||
|
DebugPrint((DEBUG_MESSAGE, "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;
|
|||
|
|
|||
|
PushEntryList (&BusExtension->CardList,
|
|||
|
&cardInfo->CardList
|
|||
|
);
|
|||
|
DebugPrint ((DEBUG_MESSAGE, "PnpIsaCheckBus: adding one pnp card %x\n"));
|
|||
|
|
|||
|
//
|
|||
|
// For each logical device supported by the card build its DEVICE_INFORMATION
|
|||
|
// structures.
|
|||
|
//
|
|||
|
|
|||
|
cardData += sizeof(SERIAL_IDENTIFIER);
|
|||
|
dataLength -= sizeof(SERIAL_IDENTIFIER);
|
|||
|
PipFindNextLogicalDeviceTag(&cardData, &dataLength);
|
|||
|
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) {
|
|||
|
DebugPrint((DEBUG_MESSAGE, "PnpIsa:failed to allocate DEVICEINFO structure\n"));
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
deviceInfo->CardInformation = cardInfo;
|
|||
|
deviceInfo->LogicalDeviceNumber = i;
|
|||
|
deviceInfo->DeviceData = cardData;
|
|||
|
deviceInfo->DeviceDataLength = PipFindNextLogicalDeviceTag(&cardData, &dataLength);
|
|||
|
|
|||
|
//
|
|||
|
// 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
|
|||
|
//
|
|||
|
|
|||
|
BusExtension->NoValidSlots += 1;
|
|||
|
PushEntryList (&BusExtension->DeviceList,
|
|||
|
&deviceInfo->DeviceList
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Select the logical device, disable its io range check
|
|||
|
// (Card is not enabled yet.)
|
|||
|
//
|
|||
|
|
|||
|
PipWriteAddress(LOGICAL_DEVICE_PORT);
|
|||
|
PipWriteData(i);
|
|||
|
PipWriteAddress(IO_RANGE_CHECK_PORT);
|
|||
|
tmp = PipReadData();
|
|||
|
tmp &= ~2;
|
|||
|
PipWriteAddress(IO_RANGE_CHECK_PORT);
|
|||
|
PipWriteData(tmp);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Finaly put all cards into wait for key state.
|
|||
|
//
|
|||
|
|
|||
|
PipWriteAddress(CONFIG_CONTROL_PORT);
|
|||
|
PipWriteData(CONTROL_WAIT_FOR_KEY);
|
|||
|
BusExtension->NumberCSNs = detectedCsn;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PipCheckDevices (
|
|||
|
PUNICODE_STRING RegistryPath,
|
|||
|
PPI_BUS_EXTENSION BusExtension
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The function goes through every pnp device and check if it is *installed*,
|
|||
|
if yes, the device will be enabled. Otherwise, we create a device instance
|
|||
|
key for the device and leave the device disabled.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
RegistryPath - Supplies a pointer to the registry path passed to the driver
|
|||
|
entry.
|
|||
|
|
|||
|
BusExtension - supplies a pointer to the pnp isa bus extension structure.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
PCARD_INFORMATION cardInfo;
|
|||
|
PDEVICE_INFORMATION deviceInfo;
|
|||
|
PSINGLE_LIST_ENTRY cardLink, deviceLink;
|
|||
|
PWCHAR cardId, deviceId, uniqueId, compatibleId, ids;
|
|||
|
WCHAR buffer[128];
|
|||
|
ULONG disposition, tmpValue, length, cardIdLength;
|
|||
|
UNICODE_STRING unicodeDeviceId, unicodeUniqueId, unicodeBusId;
|
|||
|
UNICODE_STRING unicodeDeviceInstance, unicodeString;
|
|||
|
HANDLE handle, busIdHandle, deviceIdHandle, uniqueIdHandle, logConfHandle;
|
|||
|
PKEY_VALUE_FULL_INFORMATION keyValueInformation;
|
|||
|
PCM_RESOURCE_LIST cmResource;
|
|||
|
PIO_RESOURCE_REQUIREMENTS_LIST ioResource;
|
|||
|
UNICODE_STRING madeupInstancePath;
|
|||
|
HANDLE madeupKeyHandle;
|
|||
|
|
|||
|
//
|
|||
|
// If there is no PnpISA card, we are done.
|
|||
|
// Oterwise, open HKLM\System\CCS\ENUM\PNPISA.
|
|||
|
//
|
|||
|
|
|||
|
if (BusExtension->NumberCSNs == 0) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
RtlInitUnicodeString(
|
|||
|
&unicodeString,
|
|||
|
L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\ENUM");
|
|||
|
status = PipOpenRegistryKey(&handle,
|
|||
|
NULL,
|
|||
|
&unicodeString,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
FALSE
|
|||
|
);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
DebugPrint((DEBUG_MESSAGE, "PnPIsa: Unable to open HKLM\\SYSTEM\\CCS\\ENUM"));
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Open/Create PNPISA key under HKLM\CCS\System\Enum
|
|||
|
//
|
|||
|
|
|||
|
RtlInitUnicodeString(&unicodeBusId, L"ISAPNP");
|
|||
|
status = PipOpenRegistryKeyPersist(&busIdHandle,
|
|||
|
handle,
|
|||
|
&unicodeBusId,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
TRUE,
|
|||
|
&disposition
|
|||
|
);
|
|||
|
ZwClose(handle);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
DebugPrint((DEBUG_MESSAGE, "PnPIsa: Unable to open ENUM\\PNPISA"));
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Since this driver always return failure, Pnp manager will clean up the
|
|||
|
// madeup key for this driver. If we detect any pnp isa card and create
|
|||
|
// IsaPnP key. We need to keep the madeup key by deleting its *NewlyCreated*
|
|||
|
// value entry.
|
|||
|
//
|
|||
|
|
|||
|
status = PipServiceInstanceToDeviceInstance (
|
|||
|
RegistryPath,
|
|||
|
0,
|
|||
|
&madeupInstancePath,
|
|||
|
&madeupKeyHandle,
|
|||
|
KEY_ALL_ACCESS
|
|||
|
);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
DebugPrint((DEBUG_MESSAGE, "PnPIsa: Unable to open madeup key"));
|
|||
|
return;
|
|||
|
}
|
|||
|
RtlInitUnicodeString(&unicodeString, L"Control");
|
|||
|
status = PipOpenRegistryKey(&handle,
|
|||
|
madeupKeyHandle,
|
|||
|
&unicodeString,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
FALSE
|
|||
|
);
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
RtlInitUnicodeString(&unicodeString, L"*NewlyCreated*");
|
|||
|
ZwDeleteValueKey(handle, &unicodeString);
|
|||
|
ZwClose(handle);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Go through the card link list to process each of its logical device.
|
|||
|
//
|
|||
|
|
|||
|
for (cardLink = BusExtension->CardList.Next; cardLink; cardLink = cardLink->Next) {
|
|||
|
cardInfo = CONTAINING_RECORD (cardLink, CARD_INFORMATION, CardList);
|
|||
|
|
|||
|
PipGetCardIdentifier((PUCHAR)cardInfo->CardData + NUMBER_CARD_ID_BYTES,
|
|||
|
&cardId,
|
|||
|
&cardIdLength);
|
|||
|
|
|||
|
//
|
|||
|
// For each logical device of the card, check if device instance key installed
|
|||
|
// if yes, we will configure the resource and turn on the device. Otherwise
|
|||
|
// we create a device instance key and store possible configuration and leave
|
|||
|
// the device disabled.
|
|||
|
//
|
|||
|
|
|||
|
for (deviceLink = cardInfo->LogicalDeviceList.Next; deviceLink; deviceLink = deviceLink->Next) {
|
|||
|
deviceInfo = CONTAINING_RECORD (deviceLink,
|
|||
|
DEVICE_INFORMATION,
|
|||
|
LogicalDeviceList);
|
|||
|
|
|||
|
//
|
|||
|
// First, get the device id this will be the device key name
|
|||
|
//
|
|||
|
|
|||
|
status = PipQueryDeviceId(deviceInfo, &deviceId, 0);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
continue;
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Open/create this registry path under HKLM\CCS\System\Enum\PnPIsa
|
|||
|
//
|
|||
|
|
|||
|
RtlInitUnicodeString(
|
|||
|
&unicodeDeviceId,
|
|||
|
deviceId + (unicodeBusId.Length / sizeof(WCHAR)) + 1 );
|
|||
|
status = PipOpenRegistryKeyPersist(&deviceIdHandle,
|
|||
|
busIdHandle,
|
|||
|
&unicodeDeviceId,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
TRUE,
|
|||
|
&disposition
|
|||
|
);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
ExFreePool(deviceId);
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Query the unique id for the device
|
|||
|
//
|
|||
|
|
|||
|
status = PipQueryDeviceUniqueId(deviceInfo, &uniqueId);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
ZwClose(deviceIdHandle);
|
|||
|
ExFreePool(deviceId);
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Open/create this registry device instance path under
|
|||
|
// HKLM\System\Enum\IsaPnp\deviceId
|
|||
|
//
|
|||
|
|
|||
|
RtlInitUnicodeString(&unicodeUniqueId, uniqueId);
|
|||
|
status = PipOpenRegistryKeyPersist(&uniqueIdHandle,
|
|||
|
deviceIdHandle,
|
|||
|
&unicodeUniqueId,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
TRUE,
|
|||
|
&disposition
|
|||
|
);
|
|||
|
ZwClose(deviceIdHandle);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
ExFreePool(deviceId);
|
|||
|
ExFreePool(uniqueId);
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
RtlInitUnicodeString(&unicodeString, L"FoundAtEnum");
|
|||
|
tmpValue = 1;
|
|||
|
ZwSetValueKey(uniqueIdHandle,
|
|||
|
&unicodeString,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_DWORD,
|
|||
|
&tmpValue,
|
|||
|
sizeof(tmpValue)
|
|||
|
);
|
|||
|
|
|||
|
RtlInitUnicodeString(&unicodeString, L"LogConf");
|
|||
|
status = PipOpenRegistryKeyPersist(&logConfHandle,
|
|||
|
uniqueIdHandle,
|
|||
|
&unicodeString,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
TRUE,
|
|||
|
&tmpValue
|
|||
|
);
|
|||
|
if (!NT_SUCCESS(status)) {
|
|||
|
logConfHandle = NULL; // just to make sure
|
|||
|
}
|
|||
|
|
|||
|
swprintf(buffer, L"%s\\%s", deviceId, uniqueId);
|
|||
|
RtlInitUnicodeString(&unicodeDeviceInstance, buffer);
|
|||
|
|
|||
|
if (disposition == REG_CREATED_NEW_KEY) {
|
|||
|
|
|||
|
//
|
|||
|
// Create all the default value entry for the newly created key.
|
|||
|
// DeviceDesc = Card Identifier string
|
|||
|
// BaseDevicePath = PNPISA a default parent
|
|||
|
// Configuration = REG_RESOURCE_LIST
|
|||
|
// ConfigurationVector = REG_RESOUCE_REQUIREMENTS_LIST
|
|||
|
// HardwareID = MULTI_SZ
|
|||
|
// CompatibleIDs = MULTI_SZ
|
|||
|
// ConfigFlags = REG_DWORD CONFIGFLAG_REINSTALL
|
|||
|
// Status = REG_DWORD DN_HAS_PROBLEM
|
|||
|
// Problem = REG_DWORD CM_PROB_REINSTALL
|
|||
|
// Create "Control" volatile subkey.
|
|||
|
//
|
|||
|
|
|||
|
RtlInitUnicodeString(&unicodeString, L"Control");
|
|||
|
PipOpenRegistryKey(&handle,
|
|||
|
uniqueIdHandle,
|
|||
|
&unicodeString,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
TRUE
|
|||
|
);
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
ZwClose(handle);
|
|||
|
}
|
|||
|
|
|||
|
if (cardId) {
|
|||
|
RtlInitUnicodeString(&unicodeString, L"DeviceDesc");
|
|||
|
ZwSetValueKey(uniqueIdHandle,
|
|||
|
&unicodeString,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_SZ,
|
|||
|
cardId,
|
|||
|
cardIdLength
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
RtlInitUnicodeString(&unicodeString, L"BaseDevicePath");
|
|||
|
ZwSetValueKey(uniqueIdHandle,
|
|||
|
&unicodeString,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_SZ,
|
|||
|
madeupInstancePath.Buffer,
|
|||
|
madeupInstancePath.Length + sizeof(UNICODE_NULL)
|
|||
|
);
|
|||
|
|
|||
|
RtlInitUnicodeString(&unicodeString, L"ConfigFlags");
|
|||
|
tmpValue = CONFIGFLAG_REINSTALL;
|
|||
|
ZwSetValueKey(uniqueIdHandle,
|
|||
|
&unicodeString,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_DWORD,
|
|||
|
&tmpValue,
|
|||
|
sizeof(tmpValue)
|
|||
|
);
|
|||
|
|
|||
|
RtlInitUnicodeString(&unicodeString, L"Problem");
|
|||
|
tmpValue = CM_PROB_REINSTALL;
|
|||
|
ZwSetValueKey(uniqueIdHandle,
|
|||
|
&unicodeString,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_DWORD,
|
|||
|
&tmpValue,
|
|||
|
sizeof(tmpValue)
|
|||
|
);
|
|||
|
|
|||
|
RtlInitUnicodeString(&unicodeString, L"StatusFlags");
|
|||
|
tmpValue = DN_HAS_PROBLEM;
|
|||
|
ZwSetValueKey(uniqueIdHandle,
|
|||
|
&unicodeString,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_DWORD,
|
|||
|
&tmpValue,
|
|||
|
sizeof(tmpValue)
|
|||
|
);
|
|||
|
|
|||
|
if (logConfHandle) {
|
|||
|
status = PipQueryDeviceResources (
|
|||
|
deviceInfo,
|
|||
|
0, // BusNumber
|
|||
|
&cmResource,
|
|||
|
&length
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(status) && cmResource) {
|
|||
|
RtlInitUnicodeString(&unicodeString, L"BootConfig");
|
|||
|
ZwSetValueKey(
|
|||
|
logConfHandle,
|
|||
|
&unicodeString,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_RESOURCE_LIST,
|
|||
|
cmResource,
|
|||
|
length
|
|||
|
);
|
|||
|
ExFreePool(cmResource);
|
|||
|
}
|
|||
|
|
|||
|
status = PipQueryDeviceResourceRequirements (
|
|||
|
deviceInfo,
|
|||
|
0, // Bus Number
|
|||
|
0, // Slot number??
|
|||
|
&ioResource,
|
|||
|
&length
|
|||
|
);
|
|||
|
if (NT_SUCCESS(status) && ioResource) {
|
|||
|
RtlInitUnicodeString(&unicodeString, L"BasicConfigVector");
|
|||
|
ZwSetValueKey(logConfHandle,
|
|||
|
&unicodeString,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_RESOURCE_REQUIREMENTS_LIST,
|
|||
|
ioResource,
|
|||
|
length
|
|||
|
);
|
|||
|
ExFreePool(ioResource);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
status = PipGetCompatibleDeviceId(deviceInfo->DeviceData, 0, &compatibleId);
|
|||
|
if (NT_SUCCESS(status) && compatibleId) {
|
|||
|
|
|||
|
//
|
|||
|
// create HardwareId value name. Even though it is a MULTI_SZ,
|
|||
|
// we know there is only one HardwareId for PnpIsa.
|
|||
|
//
|
|||
|
|
|||
|
length = wcslen(compatibleId) * sizeof(WCHAR) + 2 * sizeof(WCHAR);
|
|||
|
ids = (PWCHAR)ExAllocatePool(PagedPool, length);
|
|||
|
if (ids) {
|
|||
|
RtlMoveMemory(ids, compatibleId, length - 2 *sizeof(WCHAR));
|
|||
|
ids[length / sizeof(WCHAR) - 1] = UNICODE_NULL;
|
|||
|
ids[length / sizeof(WCHAR) - 2] = UNICODE_NULL;
|
|||
|
RtlInitUnicodeString(&unicodeString, L"HardwareID");
|
|||
|
ZwSetValueKey(uniqueIdHandle,
|
|||
|
&unicodeString,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_MULTI_SZ,
|
|||
|
ids,
|
|||
|
length
|
|||
|
);
|
|||
|
ExFreePool(ids);
|
|||
|
}
|
|||
|
ExFreePool(compatibleId);
|
|||
|
}
|
|||
|
|
|||
|
ids = (PWCHAR)ExAllocatePool(PagedPool, 0x1000);
|
|||
|
if (ids) {
|
|||
|
PWCHAR p1;
|
|||
|
ULONG i;
|
|||
|
|
|||
|
p1 = ids;
|
|||
|
length = 0;
|
|||
|
for (i = 1; TRUE; i++) {
|
|||
|
status = PipGetCompatibleDeviceId(
|
|||
|
deviceInfo->DeviceData,
|
|||
|
i,
|
|||
|
&compatibleId);
|
|||
|
if (NT_SUCCESS(status) && compatibleId) {
|
|||
|
if ((length + wcslen(compatibleId) * sizeof(WCHAR) + 2 * sizeof(WCHAR))
|
|||
|
<= 0x1000) {
|
|||
|
RtlMoveMemory(p1, compatibleId, wcslen(compatibleId) * sizeof(WCHAR));
|
|||
|
p1 += wcslen(compatibleId);
|
|||
|
*p1 = UNICODE_NULL;
|
|||
|
p1++;
|
|||
|
length += wcslen(compatibleId) * sizeof(WCHAR) + sizeof(WCHAR);
|
|||
|
ExFreePool(compatibleId);
|
|||
|
} else {
|
|||
|
ExFreePool(compatibleId);
|
|||
|
break;
|
|||
|
}
|
|||
|
} else {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
*p1 = UNICODE_NULL;
|
|||
|
length += sizeof(WCHAR);
|
|||
|
RtlInitUnicodeString(&unicodeString, L"CompatibleIDs");
|
|||
|
ZwSetValueKey(uniqueIdHandle,
|
|||
|
&unicodeString,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_MULTI_SZ,
|
|||
|
ids,
|
|||
|
length
|
|||
|
);
|
|||
|
ExFreePool(ids);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Add this device instance key to ENUM\PNPISA AttachedComponents
|
|||
|
// value entry.
|
|||
|
//
|
|||
|
|
|||
|
PipRemoveStringFromValueKey(
|
|||
|
madeupKeyHandle,
|
|||
|
L"AttachedComponents",
|
|||
|
&unicodeDeviceInstance
|
|||
|
);
|
|||
|
PipAppendStringToValueKey(
|
|||
|
madeupKeyHandle,
|
|||
|
L"AttachedComponents",
|
|||
|
&unicodeDeviceInstance,
|
|||
|
TRUE
|
|||
|
);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// The device instance key exists. We need to propagate the ConfigFlag
|
|||
|
// to problem and StatusFlags
|
|||
|
//
|
|||
|
|
|||
|
ULONG configFlags;
|
|||
|
|
|||
|
configFlags = 0;
|
|||
|
status = PipGetRegistryValue(uniqueIdHandle,
|
|||
|
L"ConfigFlags",
|
|||
|
&keyValueInformation);
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
if ((keyValueInformation->Type == REG_DWORD) &&
|
|||
|
(keyValueInformation->DataLength >= sizeof(ULONG))) {
|
|||
|
configFlags = *(PULONG)KEY_VALUE_DATA(keyValueInformation);
|
|||
|
}
|
|||
|
ExFreePool(keyValueInformation);
|
|||
|
}
|
|||
|
if (configFlags & CONFIGFLAG_REINSTALL) {
|
|||
|
|
|||
|
RtlInitUnicodeString(&unicodeString, L"Problem");
|
|||
|
tmpValue = CM_PROB_REINSTALL;
|
|||
|
ZwSetValueKey(uniqueIdHandle,
|
|||
|
&unicodeString,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_DWORD,
|
|||
|
&tmpValue,
|
|||
|
sizeof(tmpValue)
|
|||
|
);
|
|||
|
|
|||
|
RtlInitUnicodeString(&unicodeString, L"StatusFlags");
|
|||
|
tmpValue = DN_HAS_PROBLEM;
|
|||
|
ZwSetValueKey(uniqueIdHandle,
|
|||
|
&unicodeString,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_DWORD,
|
|||
|
&tmpValue,
|
|||
|
sizeof(tmpValue)
|
|||
|
);
|
|||
|
} else {
|
|||
|
|
|||
|
RtlInitUnicodeString(&unicodeString, L"Problem");
|
|||
|
tmpValue = 0;
|
|||
|
ZwSetValueKey(uniqueIdHandle,
|
|||
|
&unicodeString,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_DWORD,
|
|||
|
&tmpValue,
|
|||
|
sizeof(tmpValue)
|
|||
|
);
|
|||
|
|
|||
|
RtlInitUnicodeString(&unicodeString, L"StatusFlags");
|
|||
|
ZwSetValueKey(uniqueIdHandle,
|
|||
|
&unicodeString,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_DWORD,
|
|||
|
&tmpValue,
|
|||
|
sizeof(tmpValue)
|
|||
|
);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// The device instance key exists. we will enabled the device
|
|||
|
// if it is installed.
|
|||
|
//
|
|||
|
|
|||
|
if (logConfHandle && PipIsDeviceInstanceInstalled(uniqueIdHandle, &unicodeDeviceInstance)) {
|
|||
|
|
|||
|
//
|
|||
|
// 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)) {
|
|||
|
status = PipGetRegistryValue(logConfHandle,
|
|||
|
L"BootConfig",
|
|||
|
&keyValueInformation);
|
|||
|
}
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
if ((keyValueInformation->Type == REG_RESOURCE_LIST) &&
|
|||
|
(keyValueInformation->DataLength != 0)) {
|
|||
|
cmResource = (PCM_RESOURCE_LIST)
|
|||
|
KEY_VALUE_DATA(keyValueInformation);
|
|||
|
status = PipSetDeviceResources (deviceInfo, cmResource);
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
RtlInitUnicodeString(&unicodeString, L"AllocConfig");
|
|||
|
ZwSetValueKey(logConfHandle,
|
|||
|
&unicodeString,
|
|||
|
TITLE_INDEX_VALUE,
|
|||
|
REG_RESOURCE_LIST,
|
|||
|
cmResource,
|
|||
|
keyValueInformation->DataLength
|
|||
|
);
|
|||
|
PipSelectLogicalDevice(
|
|||
|
deviceInfo->CardInformation->CardSelectNumber,
|
|||
|
deviceInfo->LogicalDeviceNumber,
|
|||
|
TRUE
|
|||
|
);
|
|||
|
}
|
|||
|
}
|
|||
|
ExFreePool(keyValueInformation);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Clean up
|
|||
|
//
|
|||
|
|
|||
|
ZwClose(logConfHandle);
|
|||
|
ZwClose(uniqueIdHandle);
|
|||
|
ExFreePool(deviceId);
|
|||
|
ExFreePool(uniqueId);
|
|||
|
}
|
|||
|
}
|
|||
|
if (cardId) {
|
|||
|
ExFreePool(cardId);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Clean up
|
|||
|
//
|
|||
|
|
|||
|
ZwClose(madeupKeyHandle);
|
|||
|
ZwClose(busIdHandle);
|
|||
|
ExFreePool(madeupInstancePath.Buffer);
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
PipDeleteCards (
|
|||
|
IN PPI_BUS_EXTENSION BusExtension
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The function goes through card list and deletes all the invalid
|
|||
|
cards and their associated logical devices.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
BusExtension - supplies a pointer to the extension data of desired bus.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PDEVICE_INFORMATION deviceInfo;
|
|||
|
PCARD_INFORMATION cardInfo;
|
|||
|
PDEVICE_HANDLER_OBJECT deviceHandler;
|
|||
|
PSINGLE_LIST_ENTRY *cardLink, *deviceLink ;
|
|||
|
|
|||
|
//
|
|||
|
// Go through the card link list to free all the devices
|
|||
|
// marked as invalid.
|
|||
|
//
|
|||
|
|
|||
|
cardLink = &BusExtension->CardList.Next;
|
|||
|
while (*cardLink) {
|
|||
|
cardInfo = CONTAINING_RECORD (*cardLink, CARD_INFORMATION, CardList);
|
|||
|
|
|||
|
//
|
|||
|
// For each logical device of the card mark it as invalid
|
|||
|
//
|
|||
|
|
|||
|
deviceLink = &cardInfo->LogicalDeviceList.Next;
|
|||
|
while (*deviceLink) {
|
|||
|
deviceInfo = CONTAINING_RECORD (*deviceLink, DEVICE_INFORMATION, LogicalDeviceList);
|
|||
|
BusExtension->NoValidSlots--;
|
|||
|
*deviceLink = (*deviceLink)->Next; // Get the next addr before releasing pool
|
|||
|
ExFreePool(deviceInfo);
|
|||
|
}
|
|||
|
|
|||
|
*cardLink = (*cardLink)->Next; // Get the next addr before releasing pool
|
|||
|
if (cardInfo->CardData) {
|
|||
|
ExFreePool(cardInfo->CardData);
|
|||
|
}
|
|||
|
ExFreePool(cardInfo);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Reset the CSN number, card and device link lists.
|
|||
|
//
|
|||
|
|
|||
|
BusExtension->NumberCSNs = 0;
|
|||
|
BusExtension->CardList.Next = NULL;
|
|||
|
BusExtension->DeviceList.Next = NULL;
|
|||
|
}
|
|||
|
|
|||
|
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;
|
|||
|
|
|||
|
//
|
|||
|
// 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)] == 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)) {
|
|||
|
DebugPrint((DEBUG_MESSAGE, "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)) {
|
|||
|
DebugPrint((DEBUG_MESSAGE, "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;
|
|||
|
}
|
|||
|
|