2133 lines
65 KiB
C
2133 lines
65 KiB
C
|
|
|||
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1994-2000 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
mapper.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains the code that manipulates the ARC firmware
|
|||
|
tree and other elements in the registry.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Bob Rinne (BobRi) 15-Oct-1994
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel mode
|
|||
|
|
|||
|
Revision History :
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "pnpmgrp.h"
|
|||
|
#pragma hdrstop
|
|||
|
|
|||
|
#ifdef POOL_TAGGING
|
|||
|
#undef ExAllocatePool
|
|||
|
#define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,'rpaM')
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// This contains information obtained by checking the firmware
|
|||
|
// tree of the registry
|
|||
|
//
|
|||
|
|
|||
|
typedef struct _FIRMWARE_CONFIGURATION {
|
|||
|
struct _FIRMWARE_CONFIGURATION *Next;
|
|||
|
INTERFACE_TYPE BusType;
|
|||
|
ULONG BusNumber;
|
|||
|
CONFIGURATION_TYPE ControllerType;
|
|||
|
ULONG ControllerNumber;
|
|||
|
CONFIGURATION_TYPE PeripheralType;
|
|||
|
ULONG PeripheralNumber;
|
|||
|
ULONG NumberBases;
|
|||
|
ULONG ResourceDescriptorSize;
|
|||
|
PVOID ResourceDescriptor;
|
|||
|
ULONG IdentifierLength;
|
|||
|
ULONG IdentifierType;
|
|||
|
PVOID Identifier;
|
|||
|
WCHAR const* PnPId;
|
|||
|
BOOLEAN NewlyCreated;
|
|||
|
} FIRMWARE_CONFIGURATION, *PFIRMWARE_CONFIGURATION;
|
|||
|
|
|||
|
//
|
|||
|
// Device extension information
|
|||
|
//
|
|||
|
|
|||
|
typedef struct _DEVICE_EXTENSION {
|
|||
|
PDEVICE_OBJECT DeviceObject;
|
|||
|
PDRIVER_OBJECT DriverObject;
|
|||
|
INTERFACE_TYPE InterfaceType;
|
|||
|
ULONG BusNumber;
|
|||
|
PFIRMWARE_CONFIGURATION FirmwareList;
|
|||
|
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
|
|||
|
//
|
|||
|
// mapping table from firmware to enum
|
|||
|
//
|
|||
|
|
|||
|
typedef struct _FIRMWARE_IDENT_TO_PNP_ID {
|
|||
|
PWCHAR FirmwareName;
|
|||
|
PWCHAR PnPId;
|
|||
|
} FIRMWARE_IDENT_TO_PNP_ID, *PFIRMWARE_IDENT_TO_PNP_ID;
|
|||
|
|
|||
|
//
|
|||
|
// table to hold seed information for a firmware tree entry.
|
|||
|
//
|
|||
|
|
|||
|
#define OPTIONS_NONE 0x00000000
|
|||
|
#define OPTIONS_INSERT_PNP_ID 0x00000001
|
|||
|
#define OPTIONS_INSERT_DEVICEDESC 0x00000002
|
|||
|
#define OPTIONS_INSERT_COMPATIBLE_IDS 0x00000004
|
|||
|
#define OPTIONS_INSERT_PHANTOM_MARKER 0x00000008
|
|||
|
typedef struct _MAPPER_SEED {
|
|||
|
PWCHAR ValueName;
|
|||
|
ULONG ValueType;
|
|||
|
ULONG DwordValueContent;
|
|||
|
ULONG Options;
|
|||
|
} MAPPER_SEED, *PMAPPER_SEED;
|
|||
|
|
|||
|
//
|
|||
|
// table to hold key names and attributes for construction
|
|||
|
// in the root enumerator tree
|
|||
|
//
|
|||
|
|
|||
|
#define KEY_SEED_REQUIRED 0x00000000
|
|||
|
#define KEY_SEED_DEVICE_PARAMETERS 0x00000001
|
|||
|
typedef struct _KEY_SEED {
|
|||
|
PWCHAR KeyName;
|
|||
|
ULONG Attribute;
|
|||
|
ULONG Options;
|
|||
|
} KEY_SEED, *PKEY_SEED;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// All the data here is INIT only
|
|||
|
//
|
|||
|
|
|||
|
#ifdef ALLOC_DATA_PRAGMA
|
|||
|
#pragma const_seg("INITCONST")
|
|||
|
#pragma data_seg("INITDATA")
|
|||
|
#endif
|
|||
|
|
|||
|
DEVICE_EXTENSION MapperDeviceExtension;
|
|||
|
|
|||
|
//
|
|||
|
// This table is used to translate the firmware tree information
|
|||
|
// to the root enumerator PNP id for keyboard devices.
|
|||
|
//
|
|||
|
|
|||
|
const FIRMWARE_IDENT_TO_PNP_ID KeyboardMap[] = {
|
|||
|
L"XT_83KEY", L"*PNP0300",
|
|||
|
L"PCAT_86KEY", L"*PNP0301",
|
|||
|
L"PCXT_84KEY", L"*PNP0302",
|
|||
|
L"XT_84KEY", L"*PNP0302",
|
|||
|
L"101-KEY", L"*PNP0303",
|
|||
|
L"OLI_83KEY", L"*PNP0304",
|
|||
|
L"ATT_301", L"*PNP0304",
|
|||
|
L"OLI_102KEY", L"*PNP0305",
|
|||
|
L"OLI_86KEY", L"*PNP0306",
|
|||
|
L"OLI_A101_102KEY", L"*PNP0309",
|
|||
|
L"ATT_302", L"*PNP030a",
|
|||
|
L"PCAT_ENHANCED", L"*PNP030b",
|
|||
|
L"PC98_106KEY", L"*nEC1300",
|
|||
|
L"PC98_LaptopKEY", L"*nEC1300",
|
|||
|
L"PC98_N106KEY", L"*PNP0303",
|
|||
|
NULL, NULL
|
|||
|
};
|
|||
|
|
|||
|
#define PS2_KEYBOARD_COMPATIBLE_ID L"PS2_KEYBOARD"
|
|||
|
#define PS2_MOUSE_COMPATIBLE_ID L"PS2_MOUSE"
|
|||
|
|
|||
|
//
|
|||
|
// This table is used to translate the firmware tree information
|
|||
|
// to the root enumerator PNP id for pointer devices.
|
|||
|
//
|
|||
|
|
|||
|
const FIRMWARE_IDENT_TO_PNP_ID PointerMap[] = {
|
|||
|
L"PS2 MOUSE", L"*PNP0F0E",
|
|||
|
L"SERIAL MOUSE", L"*PNP0F0C",
|
|||
|
L"MICROSOFT PS2 MOUSE", L"*PNP0F03",
|
|||
|
L"LOGITECH PS2 MOUSE", L"*PNP0F12",
|
|||
|
L"MICROSOFT INPORT MOUSE", L"*PNP0F02",
|
|||
|
L"MICROSOFT SERIAL MOUSE", L"*PNP0F01",
|
|||
|
L"MICROSOFT BALLPOINT SERIAL MOUSE", L"*PNP0F09",
|
|||
|
L"LOGITECH SERIAL MOUSE", L"*PNP0F08",
|
|||
|
L"MICROSOFT BUS MOUSE", L"*PNP0F00",
|
|||
|
L"NEC PC-9800 BUS MOUSE", L"*nEC1F00",
|
|||
|
NULL, NULL
|
|||
|
};
|
|||
|
|
|||
|
//
|
|||
|
// the MapperValueSeed table is a NULL terminated table (i.e. the name
|
|||
|
// pointer is NULL) that contains the list of values and their type
|
|||
|
// for insertion in a newly created root enumerator key.
|
|||
|
//
|
|||
|
|
|||
|
const MAPPER_SEED MapperValueSeed[] = {
|
|||
|
REGSTR_VALUE_HARDWAREID, REG_MULTI_SZ, 0, OPTIONS_INSERT_PNP_ID,
|
|||
|
REGSTR_VALUE_COMPATIBLEIDS, REG_MULTI_SZ, 0, OPTIONS_INSERT_COMPATIBLE_IDS,
|
|||
|
REGSTR_VAL_FIRMWAREIDENTIFIED, REG_DWORD, 1, OPTIONS_NONE,
|
|||
|
REGSTR_VAL_DEVDESC, REG_SZ, 0, OPTIONS_INSERT_DEVICEDESC,
|
|||
|
REGSTR_VAL_PHANTOM, REG_DWORD, 1, OPTIONS_INSERT_PHANTOM_MARKER,
|
|||
|
NULL, 0, 0, 0
|
|||
|
};
|
|||
|
|
|||
|
//
|
|||
|
// the MapperKeySeed table is a NULL terminated table (i.e. the name
|
|||
|
// pointer is NULL) that contains the list of keys to and their
|
|||
|
// attributes (volatile or non-volatile) for keys to be created under
|
|||
|
// a newly created root enumerator key.
|
|||
|
//
|
|||
|
// The preceeding backslash is required on all entries in this table.
|
|||
|
//
|
|||
|
|
|||
|
const KEY_SEED MapperKeySeed[] = {
|
|||
|
L"\\Control", REG_OPTION_VOLATILE, KEY_SEED_REQUIRED,
|
|||
|
L"\\LogConf", REG_OPTION_NON_VOLATILE, KEY_SEED_REQUIRED,
|
|||
|
L"", REG_OPTION_NON_VOLATILE, KEY_SEED_DEVICE_PARAMETERS,
|
|||
|
NULL, 0, 0
|
|||
|
};
|
|||
|
|
|||
|
//
|
|||
|
// SerialId is used as the PNP id for all serial controllers.
|
|||
|
// NOTE: there is no code to detect presense of a 16550.
|
|||
|
//
|
|||
|
|
|||
|
const WCHAR SerialId[] = L"*PNP0501"; // RDR should be two entries. *PNP0501 is 16550
|
|||
|
|
|||
|
//
|
|||
|
// ParallelId is used as the PNP id for all parallel controllers.
|
|||
|
// NOTE: there is no code to detect presense of ECP support.
|
|||
|
//
|
|||
|
|
|||
|
const WCHAR ParallelId[] = L"*PNP0400"; // RDR should be two entries. *PNP0401 is ECP
|
|||
|
|
|||
|
//
|
|||
|
// FloppyId is used as the PNP id for all floppy peripherals.
|
|||
|
//
|
|||
|
|
|||
|
const WCHAR FloppyId[] = L"*PNP0700";
|
|||
|
|
|||
|
//
|
|||
|
// ATAId is here, but not used - there is nothing in the firmware
|
|||
|
// tree for the IDE controller.
|
|||
|
//
|
|||
|
|
|||
|
const WCHAR ATAId[] = L"*PNP0600";
|
|||
|
|
|||
|
//
|
|||
|
// Proto type declarations
|
|||
|
//
|
|||
|
|
|||
|
FIRMWARE_IDENT_TO_PNP_ID const*
|
|||
|
MapperFindIdentMatch(
|
|||
|
FIRMWARE_IDENT_TO_PNP_ID const* IdentTable,
|
|||
|
PWCHAR String
|
|||
|
);
|
|||
|
|
|||
|
WCHAR const*
|
|||
|
MapperTranslatePnPId(
|
|||
|
CONFIGURATION_TYPE PeripheralType,
|
|||
|
PKEY_VALUE_FULL_INFORMATION Identifier
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
MapperPeripheralCallback(
|
|||
|
IN PVOID Context,
|
|||
|
IN PUNICODE_STRING PathName,
|
|||
|
IN INTERFACE_TYPE BusType,
|
|||
|
IN ULONG BusNumber,
|
|||
|
IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
|
|||
|
IN CONFIGURATION_TYPE ControllerType,
|
|||
|
IN ULONG ControllerNumber,
|
|||
|
IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
|
|||
|
IN CONFIGURATION_TYPE PeripheralType,
|
|||
|
IN ULONG PeripheralNumber,
|
|||
|
IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
MapperCallback(
|
|||
|
IN PVOID Context,
|
|||
|
IN PUNICODE_STRING PathName,
|
|||
|
IN INTERFACE_TYPE BusType,
|
|||
|
IN ULONG BusNumber,
|
|||
|
IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
|
|||
|
IN CONFIGURATION_TYPE ControllerType,
|
|||
|
IN ULONG ControllerNumber,
|
|||
|
IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
|
|||
|
IN CONFIGURATION_TYPE PeripheralType,
|
|||
|
IN ULONG PeripheralNumber,
|
|||
|
IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
MapperMarkKey(
|
|||
|
IN HANDLE Handle,
|
|||
|
IN PUNICODE_STRING PathName,
|
|||
|
IN PFIRMWARE_CONFIGURATION FirmwareEntry
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
MapperSeedKey(
|
|||
|
IN HANDLE Handle,
|
|||
|
IN PUNICODE_STRING PathName,
|
|||
|
IN PFIRMWARE_CONFIGURATION FirmwareEntry,
|
|||
|
IN BOOLEAN DeviceIsPhantom
|
|||
|
);
|
|||
|
|
|||
|
PCM_RESOURCE_LIST
|
|||
|
MapperAdjustResourceList (
|
|||
|
IN PCM_RESOURCE_LIST ResourceList,
|
|||
|
IN WCHAR const* PnPId,
|
|||
|
IN OUT PULONG Size
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
ComPortDBAdd(
|
|||
|
IN HANDLE DeviceParamKey,
|
|||
|
IN PWSTR PortName
|
|||
|
);
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text(INIT, MapperFindIdentMatch)
|
|||
|
#pragma alloc_text(INIT, MapperTranslatePnPId)
|
|||
|
#pragma alloc_text(INIT, MapperPeripheralCallback)
|
|||
|
#pragma alloc_text(INIT, MapperCallback)
|
|||
|
#pragma alloc_text(INIT, MapperProcessFirmwareTree)
|
|||
|
#pragma alloc_text(INIT, MapperMarkKey)
|
|||
|
#pragma alloc_text(INIT, MapperSeedKey)
|
|||
|
#pragma alloc_text(INIT, MapperFreeList)
|
|||
|
#pragma alloc_text(INIT, MapperConstructRootEnumTree)
|
|||
|
#pragma alloc_text(INIT, MapperAdjustResourceList)
|
|||
|
#pragma alloc_text(INIT, ComPortDBAdd)
|
|||
|
#pragma alloc_text(INIT, MapperPhantomizeDetectedComPorts)
|
|||
|
#endif
|
|||
|
|
|||
|
FIRMWARE_IDENT_TO_PNP_ID const*
|
|||
|
MapperFindIdentMatch(
|
|||
|
FIRMWARE_IDENT_TO_PNP_ID const* IdentTable,
|
|||
|
PWCHAR String
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Given a table of strings to match, find the match for
|
|||
|
the identifier given.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
A pointer to the ident table entry for the match if found
|
|||
|
NULL if not found.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
FIRMWARE_IDENT_TO_PNP_ID const* entry;
|
|||
|
|
|||
|
entry = IdentTable;
|
|||
|
while (entry->FirmwareName) {
|
|||
|
if (!wcscmp(String, entry->FirmwareName)) {
|
|||
|
return entry;
|
|||
|
}
|
|||
|
entry++;
|
|||
|
}
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
WCHAR const*
|
|||
|
MapperTranslatePnPId(
|
|||
|
CONFIGURATION_TYPE PeripheralType,
|
|||
|
PKEY_VALUE_FULL_INFORMATION Identifier
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Given the peripheral type and a location in the firmware tree
|
|||
|
this routine will determine the PnP Id to be used when constructing
|
|||
|
the root enumeration portion of the registry.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
PeripheralType - the type of item being translated (keyboard, mouse, etc)
|
|||
|
PathName - the registry path name into the firmware tree for
|
|||
|
this device.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
A pointer to the PnP Id string if a map is found.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
FIRMWARE_IDENT_TO_PNP_ID const* identMap;
|
|||
|
PWSTR identifierString = NULL;
|
|||
|
WCHAR const* idStr;
|
|||
|
|
|||
|
if (Identifier) {
|
|||
|
identifierString = (PWSTR)((PUCHAR)Identifier + Identifier->DataOffset);
|
|||
|
IopDbgPrint((IOP_MAPPER_INFO_LEVEL,
|
|||
|
"Mapper: identifier = %ws\n\tType = ",
|
|||
|
identifierString));
|
|||
|
}
|
|||
|
|
|||
|
idStr = NULL;
|
|||
|
switch (PeripheralType) {
|
|||
|
case DiskController:
|
|||
|
IopDbgPrint((IOP_MAPPER_INFO_LEVEL,
|
|||
|
"%s (%d)\n",
|
|||
|
"DiskController",
|
|||
|
PeripheralType));
|
|||
|
idStr = FloppyId;
|
|||
|
break;
|
|||
|
|
|||
|
case SerialController:
|
|||
|
IopDbgPrint((IOP_MAPPER_INFO_LEVEL,
|
|||
|
"%s (%d)\n",
|
|||
|
"SerialController",
|
|||
|
PeripheralType));
|
|||
|
idStr = SerialId;
|
|||
|
break;
|
|||
|
|
|||
|
case ParallelController:
|
|||
|
IopDbgPrint((IOP_MAPPER_INFO_LEVEL,
|
|||
|
"%s (%d)\n",
|
|||
|
"ParallelController",
|
|||
|
PeripheralType));
|
|||
|
idStr = ParallelId;
|
|||
|
break;
|
|||
|
|
|||
|
case PointerController:
|
|||
|
IopDbgPrint((IOP_MAPPER_INFO_LEVEL,
|
|||
|
"%s (%d)\n",
|
|||
|
"PointerController",
|
|||
|
PeripheralType));
|
|||
|
idStr = PointerMap[0].PnPId;
|
|||
|
break;
|
|||
|
|
|||
|
case KeyboardController:
|
|||
|
IopDbgPrint((IOP_MAPPER_INFO_LEVEL,
|
|||
|
"%s (%d)\n",
|
|||
|
"KeyboardController",
|
|||
|
PeripheralType));
|
|||
|
idStr = KeyboardMap[0].PnPId;
|
|||
|
break;
|
|||
|
|
|||
|
case DiskPeripheral:
|
|||
|
IopDbgPrint((IOP_MAPPER_INFO_LEVEL,
|
|||
|
"%s (%d)\n",
|
|||
|
"DiskPeripheral",
|
|||
|
PeripheralType));
|
|||
|
break;
|
|||
|
|
|||
|
case FloppyDiskPeripheral:
|
|||
|
IopDbgPrint((IOP_MAPPER_INFO_LEVEL,
|
|||
|
"%s (%d)\n",
|
|||
|
"FloppyDiskPeripheral",
|
|||
|
PeripheralType));
|
|||
|
idStr = FloppyId;
|
|||
|
break;
|
|||
|
|
|||
|
case PointerPeripheral:
|
|||
|
if (identifierString) {
|
|||
|
identMap = MapperFindIdentMatch(PointerMap, identifierString);
|
|||
|
if (identMap) {
|
|||
|
IopDbgPrint((IOP_MAPPER_INFO_LEVEL,
|
|||
|
"%ws\n",
|
|||
|
identMap->PnPId));
|
|||
|
idStr = identMap->PnPId;
|
|||
|
} else {
|
|||
|
IopDbgPrint((IOP_MAPPER_ERROR_LEVEL,
|
|||
|
"Mapper: No pointer match found\n"));
|
|||
|
}
|
|||
|
} else {
|
|||
|
IopDbgPrint((IOP_MAPPER_ERROR_LEVEL,
|
|||
|
"Mapper: No identifier specified\n"));
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case KeyboardPeripheral:
|
|||
|
if (identifierString) {
|
|||
|
identMap = MapperFindIdentMatch(KeyboardMap, identifierString);
|
|||
|
|
|||
|
if (identMap) {
|
|||
|
IopDbgPrint((IOP_MAPPER_INFO_LEVEL,
|
|||
|
"%ws\n",
|
|||
|
identMap->PnPId));
|
|||
|
idStr = identMap->PnPId;
|
|||
|
} else {
|
|||
|
IopDbgPrint((IOP_MAPPER_ERROR_LEVEL,
|
|||
|
"Mapper: No keyboard match found\n"));
|
|||
|
}
|
|||
|
} else {
|
|||
|
IopDbgPrint((IOP_MAPPER_ERROR_LEVEL,
|
|||
|
"Mapper: No identifier specified\n"));
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
IopDbgPrint((IOP_MAPPER_ERROR_LEVEL,
|
|||
|
"Mapper: Unknown device (%d)\n",
|
|||
|
PeripheralType));
|
|||
|
break;
|
|||
|
}
|
|||
|
return idStr;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
MapperPeripheralCallback(
|
|||
|
IN PVOID Context,
|
|||
|
IN PUNICODE_STRING PathName,
|
|||
|
IN INTERFACE_TYPE BusType,
|
|||
|
IN ULONG BusNumber,
|
|||
|
IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
|
|||
|
IN CONFIGURATION_TYPE ControllerType,
|
|||
|
IN ULONG ControllerNumber,
|
|||
|
IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
|
|||
|
IN CONFIGURATION_TYPE PeripheralType,
|
|||
|
IN ULONG PeripheralNumber,
|
|||
|
IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is used to acquire firmware tree information about
|
|||
|
pointer devices in the system.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Context - Pointer to the device extension.
|
|||
|
PathName - unicode registry path.
|
|||
|
BusType - Internal, Isa, ...
|
|||
|
BusNumber - Which bus if we are on a multibus system.
|
|||
|
BusInformation - Configuration information about the bus. Not Used.
|
|||
|
ControllerType - serial or ata disk.
|
|||
|
ControllerNumber - Which controller if there is more than one
|
|||
|
controller in the system.
|
|||
|
ControllerInformation - Array of pointers to the three pieces of
|
|||
|
registry information.
|
|||
|
PeripheralType - Undefined for this call.
|
|||
|
PeripheralNumber - Undefined for this call.
|
|||
|
PeripheralInformation - Undefined for this call.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS if everything went ok, or STATUS_INSUFFICIENT_RESOURCES
|
|||
|
if it couldn't map the base csr or acquire the device object, or
|
|||
|
all of the resource information couldn't be acquired.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PFIRMWARE_CONFIGURATION firmwareEntry = Context;
|
|||
|
PKEY_VALUE_FULL_INFORMATION information;
|
|||
|
ULONG dataLength;
|
|||
|
PWCHAR ptr;
|
|||
|
PVOID temp;
|
|||
|
|
|||
|
UNREFERENCED_PARAMETER( BusType );
|
|||
|
UNREFERENCED_PARAMETER( BusNumber );
|
|||
|
UNREFERENCED_PARAMETER( BusInformation );
|
|||
|
UNREFERENCED_PARAMETER( ControllerType );
|
|||
|
UNREFERENCED_PARAMETER( ControllerNumber );
|
|||
|
|
|||
|
IopDbgPrint((IOP_MAPPER_INFO_LEVEL,
|
|||
|
"Mapper: peripheral registry location is\n %ws\n",
|
|||
|
PathName->Buffer));
|
|||
|
|
|||
|
if (!ControllerInformation) {
|
|||
|
IopDbgPrint((IOP_MAPPER_VERBOSE_LEVEL,
|
|||
|
"Mapper: No component information\n"));
|
|||
|
}
|
|||
|
if (!PeripheralInformation) {
|
|||
|
IopDbgPrint((IOP_MAPPER_VERBOSE_LEVEL,
|
|||
|
"Mapper: No peripheral information\n"));
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Map the PnP Id for this device.
|
|||
|
//
|
|||
|
|
|||
|
if (PeripheralInformation[IoQueryDeviceIdentifier]) {
|
|||
|
information = PeripheralInformation[IoQueryDeviceIdentifier];
|
|||
|
firmwareEntry->PnPId = MapperTranslatePnPId(PeripheralType, information);
|
|||
|
|
|||
|
if (firmwareEntry->PnPId) {
|
|||
|
//
|
|||
|
// Remember the peripheral's identifier (if it has one, and it's a REG_SZ value)
|
|||
|
// for use as the default PnP device description.
|
|||
|
//
|
|||
|
|
|||
|
if (((dataLength = information->DataLength) > sizeof(WCHAR)) &&
|
|||
|
(information->Type == REG_SZ)) {
|
|||
|
|
|||
|
ptr = (PWCHAR) ((PUCHAR)information + information->DataOffset);
|
|||
|
|
|||
|
if (*ptr) {
|
|||
|
temp = ExAllocatePool(NonPagedPool, dataLength);
|
|||
|
if (temp) {
|
|||
|
|
|||
|
//
|
|||
|
// If there's already an identifier here (from the peripheral's
|
|||
|
// controller) then wipe it out.
|
|||
|
//
|
|||
|
|
|||
|
if(firmwareEntry->Identifier) {
|
|||
|
ExFreePool(firmwareEntry->Identifier);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Move the data
|
|||
|
//
|
|||
|
|
|||
|
firmwareEntry->Identifier = temp;
|
|||
|
firmwareEntry->IdentifierType = information->Type;
|
|||
|
firmwareEntry->IdentifierLength = dataLength;
|
|||
|
RtlCopyMemory(temp, ptr, dataLength);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Save the ordinals for the peripheral type and number
|
|||
|
//
|
|||
|
|
|||
|
firmwareEntry->PeripheralType = PeripheralType;
|
|||
|
firmwareEntry->PeripheralNumber = PeripheralNumber;
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
MapperCallback(
|
|||
|
IN PVOID Context,
|
|||
|
IN PUNICODE_STRING PathName,
|
|||
|
IN INTERFACE_TYPE BusType,
|
|||
|
IN ULONG BusNumber,
|
|||
|
IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
|
|||
|
IN CONFIGURATION_TYPE ControllerType,
|
|||
|
IN ULONG ControllerNumber,
|
|||
|
IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
|
|||
|
IN CONFIGURATION_TYPE PeripheralType,
|
|||
|
IN ULONG PeripheralNumber,
|
|||
|
IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is used to acquire firmware tree information about
|
|||
|
pointer devices in the system.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Context - Pointer to the device extension.
|
|||
|
PathName - unicode registry path.
|
|||
|
BusType - Internal, Isa, ...
|
|||
|
BusNumber - Which bus if we are on a multibus system.
|
|||
|
BusInformation - Configuration information about the bus. Not Used.
|
|||
|
ControllerType - serial or ata disk.
|
|||
|
ControllerNumber - Which controller if there is more than one
|
|||
|
controller in the system.
|
|||
|
ControllerInformation - Array of pointers to the three pieces of
|
|||
|
registry information.
|
|||
|
PeripheralType - Undefined for this call.
|
|||
|
PeripheralNumber - Undefined for this call.
|
|||
|
PeripheralInformation - Undefined for this call.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS if everything went ok, or STATUS_INSUFFICIENT_RESOURCES
|
|||
|
if it couldn't map the base csr or acquire the device object, or
|
|||
|
all of the resource information couldn't be acquired.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PDEVICE_EXTENSION deviceExtension = Context;
|
|||
|
PCM_FULL_RESOURCE_DESCRIPTOR controllerData;
|
|||
|
PKEY_VALUE_FULL_INFORMATION information;
|
|||
|
PFIRMWARE_CONFIGURATION firmwareEntry;
|
|||
|
CONFIGURATION_TYPE peripheralType;
|
|||
|
PUCHAR buffer;
|
|||
|
ULONG dataLength;
|
|||
|
|
|||
|
UNREFERENCED_PARAMETER( BusInformation );
|
|||
|
UNREFERENCED_PARAMETER( PeripheralType );
|
|||
|
UNREFERENCED_PARAMETER( PeripheralNumber );
|
|||
|
UNREFERENCED_PARAMETER( PeripheralInformation );
|
|||
|
|
|||
|
//
|
|||
|
// If entry is found, but there is no information just return
|
|||
|
//
|
|||
|
|
|||
|
information = ControllerInformation[IoQueryDeviceConfigurationData];
|
|||
|
if (information == NULL) {
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
dataLength = information->DataLength;
|
|||
|
if (dataLength == 0) {
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Setup to capture the information from the firmware tree
|
|||
|
//
|
|||
|
|
|||
|
firmwareEntry = ExAllocatePool(NonPagedPool, sizeof(FIRMWARE_CONFIGURATION));
|
|||
|
if (!firmwareEntry) {
|
|||
|
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
RtlZeroMemory(firmwareEntry, sizeof(FIRMWARE_CONFIGURATION));
|
|||
|
|
|||
|
//
|
|||
|
// Save information concerning the controller
|
|||
|
//
|
|||
|
|
|||
|
firmwareEntry->ControllerType = ControllerType;
|
|||
|
firmwareEntry->ControllerNumber = ControllerNumber;
|
|||
|
firmwareEntry->BusNumber = BusNumber;
|
|||
|
firmwareEntry->BusType = BusType;
|
|||
|
|
|||
|
//
|
|||
|
// Save the resource descriptor
|
|||
|
//
|
|||
|
|
|||
|
buffer = firmwareEntry->ResourceDescriptor = ExAllocatePool(NonPagedPool,
|
|||
|
dataLength);
|
|||
|
|
|||
|
if (!buffer) {
|
|||
|
ExFreePool(firmwareEntry);
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Save the configuration information on this controller.
|
|||
|
//
|
|||
|
|
|||
|
controllerData = (PCM_FULL_RESOURCE_DESCRIPTOR)
|
|||
|
((PUCHAR)information + information->DataOffset);
|
|||
|
RtlCopyMemory(buffer, controllerData, dataLength);
|
|||
|
firmwareEntry->ResourceDescriptorSize = dataLength;
|
|||
|
|
|||
|
//
|
|||
|
// If there is a device identifier save it.
|
|||
|
//
|
|||
|
|
|||
|
information = ControllerInformation[IoQueryDeviceIdentifier];
|
|||
|
if (information != NULL) {
|
|||
|
PWCHAR ptr;
|
|||
|
|
|||
|
dataLength = information->DataLength;
|
|||
|
if (dataLength != 0) {
|
|||
|
|
|||
|
ptr = (PWCHAR) ((PUCHAR)information + information->DataOffset);
|
|||
|
if (ControllerType == ParallelController) {
|
|||
|
PWCHAR tmpChar;
|
|||
|
|
|||
|
//
|
|||
|
// Some extra mapping is performed here to
|
|||
|
// translate the firmware names to LPT names.
|
|||
|
//
|
|||
|
|
|||
|
*ptr++ = (WCHAR) 'L';
|
|||
|
*ptr++ = (WCHAR) 'P';
|
|||
|
*ptr++ = (WCHAR) 'T';
|
|||
|
|
|||
|
//
|
|||
|
// Find the number.
|
|||
|
//
|
|||
|
|
|||
|
tmpChar = ptr;
|
|||
|
while (*tmpChar) {
|
|||
|
if ((*tmpChar >= (WCHAR) '0') &&
|
|||
|
(*tmpChar <= (WCHAR) '9')) {
|
|||
|
break;
|
|||
|
}
|
|||
|
tmpChar++;
|
|||
|
}
|
|||
|
|
|||
|
if (*tmpChar) {
|
|||
|
while (*tmpChar) {
|
|||
|
*ptr++ = *tmpChar++;
|
|||
|
}
|
|||
|
*ptr = (WCHAR) 0;
|
|||
|
|
|||
|
//
|
|||
|
// Update the datalength to be 4 wchars and eos and
|
|||
|
// restore the pointer.
|
|||
|
//
|
|||
|
|
|||
|
ptr = (PWCHAR) ((PUCHAR)information + information->DataOffset);
|
|||
|
dataLength = 10;
|
|||
|
} else {
|
|||
|
dataLength = 0;
|
|||
|
IopDbgPrint((IOP_MAPPER_ERROR_LEVEL,
|
|||
|
"Mapper: no parallel port number!\n"));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (dataLength) {
|
|||
|
firmwareEntry->Identifier = ExAllocatePool(NonPagedPool,
|
|||
|
dataLength);
|
|||
|
if (firmwareEntry->Identifier) {
|
|||
|
|
|||
|
//
|
|||
|
// Move the data
|
|||
|
//
|
|||
|
|
|||
|
firmwareEntry->IdentifierType = information->Type;
|
|||
|
firmwareEntry->IdentifierLength = dataLength;
|
|||
|
RtlCopyMemory(firmwareEntry->Identifier, ptr, dataLength);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// For some controllers, search the peripheral information
|
|||
|
//
|
|||
|
|
|||
|
switch (ControllerType) {
|
|||
|
case SerialController:
|
|||
|
case ParallelController:
|
|||
|
//
|
|||
|
// Don't look for a peripheral.
|
|||
|
//
|
|||
|
peripheralType = (CONFIGURATION_TYPE) 0;
|
|||
|
break;
|
|||
|
case DiskController:
|
|||
|
peripheralType = FloppyDiskPeripheral;
|
|||
|
break;
|
|||
|
case KeyboardController:
|
|||
|
peripheralType = KeyboardPeripheral;
|
|||
|
break;
|
|||
|
case PointerController:
|
|||
|
peripheralType = PointerPeripheral;
|
|||
|
break;
|
|||
|
default:
|
|||
|
peripheralType = (CONFIGURATION_TYPE) 0;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
IopDbgPrint((IOP_MAPPER_INFO_LEVEL,
|
|||
|
"Mapper: registry location is\n %ws\n",
|
|||
|
PathName->Buffer));
|
|||
|
|
|||
|
IopDbgPrint((IOP_MAPPER_INFO_LEVEL,
|
|||
|
"Mapper: ControllerInformation[] -\n\tIdent: %x -\n\tData: %x -\n\tInformation: %x\n",
|
|||
|
ControllerInformation[0],
|
|||
|
ControllerInformation[1],
|
|||
|
ControllerInformation[2]));
|
|||
|
|
|||
|
if (peripheralType) {
|
|||
|
IopDbgPrint((IOP_MAPPER_INFO_LEVEL,
|
|||
|
"Mapper: searching for peripheral type %d\n",
|
|||
|
peripheralType));
|
|||
|
|
|||
|
IoQueryDeviceDescription(&BusType,
|
|||
|
&BusNumber,
|
|||
|
&ControllerType,
|
|||
|
&ControllerNumber,
|
|||
|
&peripheralType,
|
|||
|
NULL,
|
|||
|
MapperPeripheralCallback,
|
|||
|
firmwareEntry);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// firmwareEntry->PnPId will be NULL if there are no peripherals of this
|
|||
|
// type in the tree or if the peripheral's description doesn't match one of
|
|||
|
// those in our table.
|
|||
|
//
|
|||
|
// firmwareEntry->PeripheralType will be equal to peripheralType if we found
|
|||
|
// one of the proper type regardless of whether or not it is in the table.
|
|||
|
//
|
|||
|
// So this test just ensures that we fallback to the controller IDs in the
|
|||
|
// case were there is no peripheral entry. If there is a peripheral entry
|
|||
|
// that we don't understand we will suppress the entire node.
|
|||
|
//
|
|||
|
// This prevents creating devices with hw ids of bogus as we were seeing on
|
|||
|
// the SGI x86 ARC machines.
|
|||
|
//
|
|||
|
|
|||
|
if (!firmwareEntry->PnPId && firmwareEntry->PeripheralType == 0) {
|
|||
|
|
|||
|
//
|
|||
|
// Attempt to get PnPId from the controller type.
|
|||
|
//
|
|||
|
|
|||
|
firmwareEntry->PnPId = MapperTranslatePnPId(ControllerType, NULL);
|
|||
|
|
|||
|
if (!firmwareEntry->PnPId) {
|
|||
|
IopDbgPrint((IOP_MAPPER_INFO_LEVEL,
|
|||
|
"Mapper: NO PnP Id for\n ==> %ws\n",
|
|||
|
PathName->Buffer));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
IopDbgPrint((IOP_MAPPER_INFO_LEVEL,
|
|||
|
"Mapper: constructed name %d_%d_%d_%d_%d_%d\n",
|
|||
|
firmwareEntry->BusType,
|
|||
|
firmwareEntry->BusNumber,
|
|||
|
firmwareEntry->ControllerType,
|
|||
|
firmwareEntry->ControllerNumber,
|
|||
|
firmwareEntry->PeripheralType,
|
|||
|
firmwareEntry->PeripheralNumber));
|
|||
|
|
|||
|
if (firmwareEntry->PnPId) {
|
|||
|
|
|||
|
//
|
|||
|
// Link into chain of entries.
|
|||
|
//
|
|||
|
|
|||
|
firmwareEntry->Next = deviceExtension->FirmwareList;
|
|||
|
deviceExtension->FirmwareList = firmwareEntry;
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// No map found - don't remember this entry.
|
|||
|
//
|
|||
|
|
|||
|
ExFreePool(buffer);
|
|||
|
if(firmwareEntry->Identifier) {
|
|||
|
ExFreePool(firmwareEntry->Identifier);
|
|||
|
}
|
|||
|
ExFreePool(firmwareEntry);
|
|||
|
}
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
MapperProcessFirmwareTree(
|
|||
|
IN BOOLEAN OnlyProcessSerialPorts
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Query the information in the firmware tree to know what
|
|||
|
system board devices were located. This will cause a FirmwareList
|
|||
|
to be created on the device extention passed.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
OnlyProcessSerialPorts - if non-zero, then we'll only look at serial ports.
|
|||
|
This is done on ACPI machines where, in general, we don't want to pay
|
|||
|
attention to ntdetect/firmware information (but we have to for serial
|
|||
|
ports so that legacy add-in ISA serial ports and modems are detected
|
|||
|
automatically as in previous versions of NT as well as Win9x).
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
INTERFACE_TYPE interfaceType;
|
|||
|
ULONG index;
|
|||
|
CONFIGURATION_TYPE sc;
|
|||
|
CONFIGURATION_TYPE controllerTypes[] = { PointerController,
|
|||
|
KeyboardController,
|
|||
|
ParallelController,
|
|||
|
DiskController,
|
|||
|
FloppyDiskPeripheral,
|
|||
|
SerialController // must be last
|
|||
|
};
|
|||
|
#define CONTROLLER_TYPES_COUNT (sizeof(controllerTypes) / sizeof(controllerTypes[0]))
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// Locate all firmware controller information and save its resource usage.
|
|||
|
//
|
|||
|
// It's pretty inefficient to be going through all interface types, when we
|
|||
|
// really only care about a very small subset of non-PnP buses (e.g., ISA,
|
|||
|
// EISA, maybe Internal).
|
|||
|
//
|
|||
|
|
|||
|
for (interfaceType = 0; interfaceType < MaximumInterfaceType; interfaceType++) {
|
|||
|
|
|||
|
IopDbgPrint((IOP_MAPPER_VERBOSE_LEVEL,
|
|||
|
"Mapper: searching on interface ===> %d\n",
|
|||
|
interfaceType));
|
|||
|
|
|||
|
if(OnlyProcessSerialPorts) {
|
|||
|
|
|||
|
//
|
|||
|
// Start out at the last element of the array, so we only process
|
|||
|
// SerialControllers.
|
|||
|
//
|
|||
|
|
|||
|
index = CONTROLLER_TYPES_COUNT - 1;
|
|||
|
} else {
|
|||
|
index = 0;
|
|||
|
}
|
|||
|
|
|||
|
for ( ; index < CONTROLLER_TYPES_COUNT; index++) {
|
|||
|
sc = controllerTypes[index];
|
|||
|
|
|||
|
IoQueryDeviceDescription(&interfaceType,
|
|||
|
NULL,
|
|||
|
&sc,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
MapperCallback,
|
|||
|
&MapperDeviceExtension);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
MapperMarkKey(
|
|||
|
IN HANDLE Handle,
|
|||
|
IN PUNICODE_STRING PathName,
|
|||
|
IN PFIRMWARE_CONFIGURATION FirmwareEntry
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Record in the root enum key that the firmware mapper found this entry.
|
|||
|
Migrate configuration information entries.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Handle - handle to the key
|
|||
|
PathName - base path name to this key
|
|||
|
FirmwareEntry - information from the firmware tree.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
OBJECT_ATTRIBUTES objectAttributes;
|
|||
|
PCM_RESOURCE_LIST resourceList;
|
|||
|
UNICODE_STRING unicodeName;
|
|||
|
NTSTATUS status;
|
|||
|
HANDLE subKeyHandle;
|
|||
|
PWCHAR wcptr;
|
|||
|
ULONG disposition;
|
|||
|
ULONG buffer;
|
|||
|
USHORT originalLength;
|
|||
|
|
|||
|
//
|
|||
|
// Mark that this entry was in the firmware tree.
|
|||
|
//
|
|||
|
|
|||
|
buffer = 1;
|
|||
|
PiWstrToUnicodeString(&unicodeName, REGSTR_VAL_FIRMWAREIDENTIFIED);
|
|||
|
|
|||
|
ZwSetValueKey(Handle,
|
|||
|
&unicodeName,
|
|||
|
0,
|
|||
|
REG_DWORD,
|
|||
|
&buffer,
|
|||
|
sizeof(ULONG));
|
|||
|
|
|||
|
//
|
|||
|
// Create the control subkey
|
|||
|
//
|
|||
|
|
|||
|
IopDbgPrint((IOP_MAPPER_INFO_LEVEL,
|
|||
|
"Mapper: marking existing key\n"));
|
|||
|
originalLength = PathName->Length;
|
|||
|
wcptr = (PWCHAR) ((PUCHAR)PathName->Buffer + PathName->Length);
|
|||
|
wcptr++; // locate eos
|
|||
|
|
|||
|
//
|
|||
|
// Build the volatile control key
|
|||
|
//
|
|||
|
|
|||
|
InitializeObjectAttributes(&objectAttributes,
|
|||
|
PathName,
|
|||
|
OBJ_CASE_INSENSITIVE,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
RtlAppendUnicodeToString(PathName, L"\\Control");
|
|||
|
status = ZwCreateKey(&subKeyHandle,
|
|||
|
KEY_READ | KEY_WRITE,
|
|||
|
&objectAttributes,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
REG_OPTION_VOLATILE,
|
|||
|
&disposition);
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
|
|||
|
//
|
|||
|
// Create the found by firmware volatile.
|
|||
|
//
|
|||
|
|
|||
|
buffer = 1;
|
|||
|
PiWstrToUnicodeString(&unicodeName, REGSTR_VAL_FIRMWAREMEMBER);
|
|||
|
|
|||
|
ZwSetValueKey(subKeyHandle,
|
|||
|
&unicodeName,
|
|||
|
0,
|
|||
|
REG_DWORD,
|
|||
|
&buffer,
|
|||
|
sizeof(ULONG));
|
|||
|
ZwClose(subKeyHandle);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// ignore failures
|
|||
|
//
|
|||
|
|
|||
|
IopDbgPrint((IOP_MAPPER_ERROR_LEVEL,
|
|||
|
"Mapper: failed to mark control key %x\n",
|
|||
|
status));
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// if there is a resource descriptor, restore path and open LogConf key.
|
|||
|
//
|
|||
|
|
|||
|
if (FirmwareEntry->ResourceDescriptor) {
|
|||
|
PathName->Length = originalLength;
|
|||
|
*wcptr = (WCHAR) 0;
|
|||
|
|
|||
|
InitializeObjectAttributes(&objectAttributes,
|
|||
|
PathName,
|
|||
|
OBJ_CASE_INSENSITIVE,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
RtlAppendUnicodeToString(PathName, L"\\LogConf");
|
|||
|
status = ZwCreateKey(&subKeyHandle,
|
|||
|
KEY_READ | KEY_WRITE,
|
|||
|
&objectAttributes,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
REG_OPTION_VOLATILE,
|
|||
|
&disposition);
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
ULONG size;
|
|||
|
|
|||
|
//
|
|||
|
// two entries need to be made:
|
|||
|
// BootConfig:REG_RESOURCE_LIST
|
|||
|
// BasicConfigVector:REG_RESOURCE_REQUIREMENTS_LIST
|
|||
|
//
|
|||
|
|
|||
|
size = sizeof(CM_RESOURCE_LIST) -
|
|||
|
sizeof(CM_FULL_RESOURCE_DESCRIPTOR) +
|
|||
|
FirmwareEntry->ResourceDescriptorSize;
|
|||
|
|
|||
|
resourceList = ExAllocatePool(NonPagedPool, size);
|
|||
|
|
|||
|
if (resourceList) {
|
|||
|
|
|||
|
resourceList->Count = 1;
|
|||
|
RtlCopyMemory(&resourceList->List[0],
|
|||
|
FirmwareEntry->ResourceDescriptor,
|
|||
|
FirmwareEntry->ResourceDescriptorSize);
|
|||
|
|
|||
|
resourceList = MapperAdjustResourceList (
|
|||
|
resourceList,
|
|||
|
FirmwareEntry->PnPId,
|
|||
|
&size
|
|||
|
);
|
|||
|
|
|||
|
PiWstrToUnicodeString(&unicodeName,
|
|||
|
L"BootConfig");
|
|||
|
ZwSetValueKey(subKeyHandle,
|
|||
|
&unicodeName,
|
|||
|
0,
|
|||
|
REG_RESOURCE_LIST,
|
|||
|
resourceList,
|
|||
|
size);
|
|||
|
#if 0
|
|||
|
//
|
|||
|
// Now do the resource requirements list.
|
|||
|
//
|
|||
|
|
|||
|
reqList = IopCmResourcesToIoResources(0, resourceList);
|
|||
|
|
|||
|
if (reqList) {
|
|||
|
PiWstrToUnicodeString(&unicodeName,
|
|||
|
L"BasicConfigVector");
|
|||
|
ZwSetValueKey(subKeyHandle,
|
|||
|
&unicodeName,
|
|||
|
0,
|
|||
|
REG_RESOURCE_REQUIREMENTS_LIST,
|
|||
|
reqList,
|
|||
|
reqList->ListSize);
|
|||
|
ExFreePool(reqList);
|
|||
|
}
|
|||
|
#endif
|
|||
|
ExFreePool(resourceList);
|
|||
|
}
|
|||
|
|
|||
|
ZwClose(subKeyHandle);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// ignore errors
|
|||
|
//
|
|||
|
|
|||
|
IopDbgPrint((IOP_MAPPER_ERROR_LEVEL,
|
|||
|
"Mapper: failed to update logconf key %x\n",
|
|||
|
status));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Restore path passed in.
|
|||
|
//
|
|||
|
|
|||
|
PathName->Length = originalLength;
|
|||
|
*wcptr = (WCHAR) 0;
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
MapperSeedKey(
|
|||
|
IN HANDLE Handle,
|
|||
|
IN PUNICODE_STRING PathName,
|
|||
|
IN PFIRMWARE_CONFIGURATION FirmwareEntry,
|
|||
|
IN BOOLEAN DeviceIsPhantom
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine seeds a registry key with enough information
|
|||
|
to get PnP to run the class installer on the devnode.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Handle - handle to the key
|
|||
|
|
|||
|
PathName - base path name to this key
|
|||
|
|
|||
|
FirmwareEntry - information from the firmware tree
|
|||
|
|
|||
|
DeviceIsPhantom - if non-zero, add "Phantom" value entry so the root
|
|||
|
enumerator will skip this device instance (i.e., not turn it into a
|
|||
|
devnode)
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
#define SEED_BUFFER_SIZE (512 * sizeof(WCHAR))
|
|||
|
UNICODE_STRING unicodeName;
|
|||
|
OBJECT_ATTRIBUTES objectAttributes;
|
|||
|
MAPPER_SEED const* valueSeed;
|
|||
|
KEY_SEED const* keySeed;
|
|||
|
NTSTATUS status;
|
|||
|
HANDLE subKeyHandle;
|
|||
|
WCHAR const* pnpid;
|
|||
|
PWCHAR buffer;
|
|||
|
PWCHAR wcptr;
|
|||
|
ULONG disposition;
|
|||
|
ULONG size;
|
|||
|
USHORT originalLength;
|
|||
|
|
|||
|
buffer = ExAllocatePool(NonPagedPool, SEED_BUFFER_SIZE);
|
|||
|
if (!buffer) {
|
|||
|
return;
|
|||
|
}
|
|||
|
RtlZeroMemory(buffer, SEED_BUFFER_SIZE);
|
|||
|
|
|||
|
//
|
|||
|
// Create subkeys.
|
|||
|
//
|
|||
|
|
|||
|
originalLength = PathName->Length;
|
|||
|
wcptr = (PWCHAR) ((PUCHAR)PathName->Buffer + PathName->Length);
|
|||
|
|
|||
|
for (keySeed = MapperKeySeed; keySeed->KeyName; keySeed++) {
|
|||
|
|
|||
|
//
|
|||
|
// Reset the base path for the next key to seed.
|
|||
|
//
|
|||
|
|
|||
|
*wcptr = (WCHAR) 0;
|
|||
|
PathName->Length = originalLength;
|
|||
|
RtlAppendUnicodeToString(PathName, keySeed->KeyName);
|
|||
|
|
|||
|
//
|
|||
|
// Only build a device parameters key if there is something
|
|||
|
// to put in the key (i.e., this is a serial or parallel port).
|
|||
|
//
|
|||
|
|
|||
|
if (keySeed->Options & KEY_SEED_DEVICE_PARAMETERS) {
|
|||
|
if (((FirmwareEntry->ControllerType != SerialController) && (FirmwareEntry->ControllerType != ParallelController)) ||
|
|||
|
!FirmwareEntry->Identifier) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
status = IopOpenDeviceParametersSubkey( &subKeyHandle,
|
|||
|
NULL,
|
|||
|
PathName,
|
|||
|
KEY_READ | KEY_WRITE
|
|||
|
);
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
} else {
|
|||
|
status = STATUS_UNSUCCESSFUL;
|
|||
|
}
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// need to construct this key.
|
|||
|
//
|
|||
|
|
|||
|
InitializeObjectAttributes(&objectAttributes,
|
|||
|
PathName,
|
|||
|
OBJ_CASE_INSENSITIVE,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
status = ZwCreateKey(&subKeyHandle,
|
|||
|
KEY_READ | KEY_WRITE,
|
|||
|
&objectAttributes,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
keySeed->Attribute,
|
|||
|
&disposition);
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
|
|||
|
//
|
|||
|
// Check to see if this is the parameters key and
|
|||
|
// migrate the parameter information.
|
|||
|
//
|
|||
|
|
|||
|
if (keySeed->Options & KEY_SEED_DEVICE_PARAMETERS) {
|
|||
|
|
|||
|
if (FirmwareEntry->ControllerType == SerialController) {
|
|||
|
|
|||
|
ComPortDBAdd(subKeyHandle, (PWSTR)FirmwareEntry->Identifier);
|
|||
|
} else {
|
|||
|
//
|
|||
|
// to get here there must be identifier information
|
|||
|
// in the FirmwareEntry, so that check is not performed.
|
|||
|
//
|
|||
|
// NOTE: this will only happen once - when the key is
|
|||
|
// created -- perhaps this needs to happen on every
|
|||
|
// boot.
|
|||
|
//
|
|||
|
|
|||
|
PiWstrToUnicodeString(&unicodeName,
|
|||
|
L"DosDeviceName");
|
|||
|
ZwSetValueKey(subKeyHandle,
|
|||
|
&unicodeName,
|
|||
|
0,
|
|||
|
FirmwareEntry->IdentifierType,
|
|||
|
FirmwareEntry->Identifier,
|
|||
|
FirmwareEntry->IdentifierLength);
|
|||
|
}
|
|||
|
}
|
|||
|
ZwClose(subKeyHandle);
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// ignore failures
|
|||
|
//
|
|||
|
|
|||
|
IopDbgPrint((IOP_MAPPER_ERROR_LEVEL,
|
|||
|
"Mapper: failed to build control key %x\n",
|
|||
|
status));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Undo the mangling of the path name performed in the loop above.
|
|||
|
//
|
|||
|
|
|||
|
*wcptr = (WCHAR) 0;
|
|||
|
PathName->Length = originalLength;
|
|||
|
|
|||
|
//
|
|||
|
// Create values.
|
|||
|
//
|
|||
|
|
|||
|
pnpid = FirmwareEntry->PnPId;
|
|||
|
for (valueSeed = MapperValueSeed; valueSeed->ValueName; valueSeed++) {
|
|||
|
|
|||
|
if (valueSeed->ValueType == REG_DWORD) {
|
|||
|
|
|||
|
if ((valueSeed->Options == OPTIONS_INSERT_PHANTOM_MARKER) &&
|
|||
|
!DeviceIsPhantom) {
|
|||
|
|
|||
|
//
|
|||
|
// Device isn't a phantom--we don't want to mark it as such.
|
|||
|
//
|
|||
|
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
size = sizeof(ULONG);
|
|||
|
RtlCopyMemory(buffer, &valueSeed->DwordValueContent, size);
|
|||
|
|
|||
|
} else if (valueSeed->Options == OPTIONS_INSERT_PNP_ID) {
|
|||
|
|
|||
|
size = (ULONG)((wcslen(pnpid) + 2) * sizeof(WCHAR)); // eos multi_sz
|
|||
|
if (FirmwareEntry->BusType == Eisa) {
|
|||
|
|
|||
|
//
|
|||
|
// need a mult_sz of EISA\PNPblah *PNPblah
|
|||
|
//
|
|||
|
|
|||
|
RtlZeroMemory(buffer, SEED_BUFFER_SIZE);
|
|||
|
wcptr = (PWCHAR)pnpid;
|
|||
|
wcptr++;
|
|||
|
swprintf(buffer, L"EISA\\%s", wcptr);
|
|||
|
|
|||
|
wcptr = buffer;
|
|||
|
while (*wcptr) {
|
|||
|
wcptr++;
|
|||
|
}
|
|||
|
wcptr++; // step past eos for 1st string
|
|||
|
|
|||
|
RtlCopyMemory(wcptr, pnpid, size);
|
|||
|
|
|||
|
size += (ULONG)((PUCHAR)wcptr - (PUCHAR)buffer);
|
|||
|
} else {
|
|||
|
RtlCopyMemory(buffer, pnpid, size - sizeof(WCHAR));
|
|||
|
buffer[size / sizeof(WCHAR) - 1] = L'\0';
|
|||
|
}
|
|||
|
} else if (valueSeed->Options == OPTIONS_INSERT_COMPATIBLE_IDS) {
|
|||
|
if (FirmwareEntry->PeripheralType == KeyboardPeripheral) {
|
|||
|
size = sizeof(PS2_KEYBOARD_COMPATIBLE_ID);
|
|||
|
RtlCopyMemory(buffer, PS2_KEYBOARD_COMPATIBLE_ID, size);
|
|||
|
} else if (FirmwareEntry->PeripheralType == PointerPeripheral &&
|
|||
|
(wcscmp(pnpid, L"*PNP0F0E") == 0 ||
|
|||
|
wcscmp(pnpid, L"*PNP0F03") == 0 ||
|
|||
|
wcscmp(pnpid, L"*PNP0F12") == 0)) {
|
|||
|
size = sizeof(PS2_MOUSE_COMPATIBLE_ID);
|
|||
|
RtlCopyMemory(buffer, PS2_MOUSE_COMPATIBLE_ID, size);
|
|||
|
} else {
|
|||
|
continue;
|
|||
|
}
|
|||
|
buffer[size / 2] = L'\0'; // 2nd NUL for MULTI_SZ
|
|||
|
size += sizeof(L'\0');
|
|||
|
} else if (valueSeed->Options == OPTIONS_INSERT_DEVICEDESC) {
|
|||
|
size = FirmwareEntry->IdentifierLength;
|
|||
|
RtlCopyMemory(buffer, FirmwareEntry->Identifier, size);
|
|||
|
} else {
|
|||
|
IopDbgPrint((IOP_MAPPER_ERROR_LEVEL, "Mapper: NO VALUE TYPE!\n"));
|
|||
|
ASSERT(FALSE);
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
RtlInitUnicodeString(&unicodeName,
|
|||
|
valueSeed->ValueName);
|
|||
|
ZwSetValueKey(Handle,
|
|||
|
&unicodeName,
|
|||
|
0,
|
|||
|
valueSeed->ValueType,
|
|||
|
buffer,
|
|||
|
size);
|
|||
|
}
|
|||
|
ExFreePool(buffer);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
MapperFreeList(
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine walks through the list of firmware entries
|
|||
|
and frees all allocated memory.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PDEVICE_EXTENSION deviceExtension = &MapperDeviceExtension;
|
|||
|
PFIRMWARE_CONFIGURATION tempEntry;
|
|||
|
PFIRMWARE_CONFIGURATION firmwareEntry;
|
|||
|
|
|||
|
firmwareEntry = deviceExtension->FirmwareList;
|
|||
|
while (firmwareEntry) {
|
|||
|
|
|||
|
//
|
|||
|
// free allocated structures associated with the firmware entry
|
|||
|
//
|
|||
|
|
|||
|
if (firmwareEntry->ResourceDescriptor) {
|
|||
|
ExFreePool(firmwareEntry->ResourceDescriptor);
|
|||
|
}
|
|||
|
if (firmwareEntry->Identifier) {
|
|||
|
ExFreePool(firmwareEntry->Identifier);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// free this entry and move to the next
|
|||
|
//
|
|||
|
|
|||
|
tempEntry = firmwareEntry->Next;
|
|||
|
ExFreePool(firmwareEntry);
|
|||
|
firmwareEntry = tempEntry;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
MapperConstructRootEnumTree(
|
|||
|
IN BOOLEAN CreatePhantomDevices
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine walks through the list of firmware entries
|
|||
|
in the device extension and migrates the information into
|
|||
|
the root enumerator's tree in the registry.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
CreatePhantomDevices - If non-zero, then the device instances are created
|
|||
|
as "phantoms" (i.e., they are marked with the "Phantom" value entry so
|
|||
|
that the root enumerator will ignore them). The only time these device
|
|||
|
instance registry keys will ever turn into real live devnodes is if the
|
|||
|
class installer (in response to DIF_FIRSTTIMESETUP or DIF_DETECT)
|
|||
|
decides that these devices aren't duplicates of any PnP-enumerated
|
|||
|
devnodes, and subsequently registers and installs them.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
#define ENUM_KEY_BUFFER_SIZE (1024 * sizeof(WCHAR))
|
|||
|
#define INSTANCE_BUFFER_SIZE (256 * sizeof(WCHAR))
|
|||
|
UNICODE_STRING enumKey;
|
|||
|
PFIRMWARE_CONFIGURATION firmwareEntry;
|
|||
|
OBJECT_ATTRIBUTES objectAttributes;
|
|||
|
NTSTATUS status;
|
|||
|
BOOLEAN keyPresent;
|
|||
|
PWCHAR registryBase;
|
|||
|
PWCHAR instanceBuffer;
|
|||
|
HANDLE handle;
|
|||
|
ULONG disposition;
|
|||
|
PVOID buffer;
|
|||
|
PDEVICE_EXTENSION DeviceExtension = &MapperDeviceExtension;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// allocate space needed for the registry path into the root
|
|||
|
// enumerator tree. Note, limited size on path length.
|
|||
|
//
|
|||
|
|
|||
|
buffer = ExAllocatePool(NonPagedPool, ENUM_KEY_BUFFER_SIZE);
|
|||
|
|
|||
|
if (!buffer) {
|
|||
|
MapperFreeList();
|
|||
|
IopDbgPrint((IOP_MAPPER_ERROR_LEVEL,
|
|||
|
"Mapper: could not allocate memory for registry update\n"));
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
instanceBuffer = ExAllocatePool(NonPagedPool, INSTANCE_BUFFER_SIZE);
|
|||
|
if (!instanceBuffer) {
|
|||
|
MapperFreeList();
|
|||
|
ExFreePool(buffer);
|
|||
|
IopDbgPrint((IOP_MAPPER_ERROR_LEVEL,
|
|||
|
"Mapper: could not allocate memory for instance buffer\n"));
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
InitializeObjectAttributes(&objectAttributes,
|
|||
|
&enumKey,
|
|||
|
OBJ_CASE_INSENSITIVE,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
|
|||
|
#if UMODETEST
|
|||
|
registryBase = L"\\Registry\\Machine\\System\\TestControlSet\\Enum\\Root\\";
|
|||
|
#else
|
|||
|
registryBase = L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\Root\\";
|
|||
|
#endif
|
|||
|
|
|||
|
firmwareEntry = DeviceExtension->FirmwareList;
|
|||
|
while (firmwareEntry) {
|
|||
|
|
|||
|
//
|
|||
|
// Construct the base for the path for this entry.
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
PiWstrToUnicodeString(&enumKey, NULL);
|
|||
|
enumKey.MaximumLength = ENUM_KEY_BUFFER_SIZE;
|
|||
|
enumKey.Buffer = buffer;
|
|||
|
RtlZeroMemory(buffer, ENUM_KEY_BUFFER_SIZE);
|
|||
|
RtlAppendUnicodeToString(&enumKey, registryBase);
|
|||
|
RtlAppendUnicodeToString(&enumKey, firmwareEntry->PnPId);
|
|||
|
|
|||
|
//
|
|||
|
// Build the pnp Key.
|
|||
|
//
|
|||
|
|
|||
|
status = ZwCreateKey(&handle,
|
|||
|
KEY_READ | KEY_WRITE,
|
|||
|
&objectAttributes,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
REG_OPTION_NON_VOLATILE,
|
|||
|
&disposition);
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
|
|||
|
//
|
|||
|
// Do not need the handle, so close it
|
|||
|
// Remember if the key was present prior to call
|
|||
|
//
|
|||
|
|
|||
|
ZwClose(handle);
|
|||
|
keyPresent = (disposition == REG_OPENED_EXISTING_KEY) ? TRUE : FALSE;
|
|||
|
IopDbgPrint((IOP_MAPPER_INFO_LEVEL,
|
|||
|
"Mapper: Key was %s\n",
|
|||
|
keyPresent ? "Present" : "Created"));
|
|||
|
|
|||
|
//
|
|||
|
// Construct the instance name.
|
|||
|
//
|
|||
|
|
|||
|
RtlZeroMemory(instanceBuffer, INSTANCE_BUFFER_SIZE);
|
|||
|
swprintf(instanceBuffer,
|
|||
|
L"\\%d_%d_%d_%d_%d_%d",
|
|||
|
firmwareEntry->BusType,
|
|||
|
firmwareEntry->BusNumber,
|
|||
|
firmwareEntry->ControllerType,
|
|||
|
firmwareEntry->ControllerNumber,
|
|||
|
firmwareEntry->PeripheralType,
|
|||
|
firmwareEntry->PeripheralNumber);
|
|||
|
RtlAppendUnicodeToString(&enumKey, instanceBuffer);
|
|||
|
|
|||
|
status = ZwCreateKey(&handle,
|
|||
|
KEY_READ | KEY_WRITE,
|
|||
|
&objectAttributes,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
REG_OPTION_NON_VOLATILE,
|
|||
|
&disposition);
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
|
|||
|
if (firmwareEntry->ResourceDescriptor) {
|
|||
|
IopDbgPrint((IOP_MAPPER_INFO_LEVEL,
|
|||
|
"Mapper: firmware entry has resources %x\n",
|
|||
|
firmwareEntry->ResourceDescriptor));
|
|||
|
}
|
|||
|
|
|||
|
if (firmwareEntry->Identifier) {
|
|||
|
IopDbgPrint((IOP_MAPPER_INFO_LEVEL,
|
|||
|
"Mapper: firmware entry has identifier %x\n",
|
|||
|
firmwareEntry->Identifier));
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If the key already exists because it was explicitly migrated
|
|||
|
// during textmode setup, we should still consider it a "new key".
|
|||
|
//
|
|||
|
if (disposition != REG_CREATED_NEW_KEY) {
|
|||
|
PKEY_VALUE_FULL_INFORMATION keyValueInformation;
|
|||
|
UNICODE_STRING unicodeString;
|
|||
|
|
|||
|
status = IopGetRegistryValue(handle,
|
|||
|
REGSTR_VALUE_MIGRATED,
|
|||
|
&keyValueInformation);
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
|
|||
|
if ((keyValueInformation->Type == REG_DWORD) &&
|
|||
|
(keyValueInformation->DataLength == sizeof(ULONG)) &&
|
|||
|
((*(PULONG)KEY_VALUE_DATA(keyValueInformation)) != 0)) {
|
|||
|
disposition = REG_CREATED_NEW_KEY;
|
|||
|
}
|
|||
|
|
|||
|
ExFreePool(keyValueInformation);
|
|||
|
|
|||
|
PiWstrToUnicodeString(&unicodeString, REGSTR_VALUE_MIGRATED);
|
|||
|
ZwDeleteValueKey(handle, &unicodeString);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Only if this is a new entry do we see the key.
|
|||
|
//
|
|||
|
|
|||
|
if (disposition == REG_CREATED_NEW_KEY) {
|
|||
|
|
|||
|
//
|
|||
|
// Remember the fact that the key was newly-created for the
|
|||
|
// PnP BIOS case where we need to come along and "phantomize"
|
|||
|
// all newly-created ntdetect COM ports.
|
|||
|
//
|
|||
|
|
|||
|
firmwareEntry->NewlyCreated = TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// Create enough information to get pnp to
|
|||
|
// install drivers
|
|||
|
//
|
|||
|
|
|||
|
MapperSeedKey(handle,
|
|||
|
&enumKey,
|
|||
|
firmwareEntry,
|
|||
|
CreatePhantomDevices
|
|||
|
);
|
|||
|
}
|
|||
|
MapperMarkKey(handle,
|
|||
|
&enumKey,
|
|||
|
firmwareEntry);
|
|||
|
ZwClose(handle);
|
|||
|
|
|||
|
} else {
|
|||
|
IopDbgPrint((IOP_MAPPER_ERROR_LEVEL,
|
|||
|
"Mapper: create of instance key failed %x\n",
|
|||
|
status));
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
IopDbgPrint((IOP_MAPPER_ERROR_LEVEL,
|
|||
|
"Mapper: create pnp key failed %x\n",
|
|||
|
status));
|
|||
|
}
|
|||
|
|
|||
|
firmwareEntry = firmwareEntry->Next;
|
|||
|
}
|
|||
|
ExFreePool(instanceBuffer);
|
|||
|
}
|
|||
|
|
|||
|
PCM_RESOURCE_LIST
|
|||
|
MapperAdjustResourceList (
|
|||
|
IN PCM_RESOURCE_LIST ResourceList,
|
|||
|
IN WCHAR const* PnPId,
|
|||
|
IN OUT PULONG Size
|
|||
|
)
|
|||
|
{
|
|||
|
PCM_PARTIAL_RESOURCE_LIST partialResourceList;
|
|||
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR problemPartialDescriptors;
|
|||
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDescriptors;
|
|||
|
PCM_RESOURCE_LIST newResourceList;
|
|||
|
ULONG i;
|
|||
|
|
|||
|
newResourceList = ResourceList;
|
|||
|
|
|||
|
#if _X86_
|
|||
|
if (KeI386MachineType == MACHINE_TYPE_EISA) {
|
|||
|
|
|||
|
PCM_FULL_RESOURCE_DESCRIPTOR fullDescriptor;
|
|||
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDescriptor;
|
|||
|
PUCHAR nextDescriptor;
|
|||
|
ULONG j;
|
|||
|
ULONG lastResourceIndex;
|
|||
|
|
|||
|
fullDescriptor = &ResourceList->List[0];
|
|||
|
|
|||
|
for (i = 0; i < ResourceList->Count; i++) {
|
|||
|
|
|||
|
partialResourceList = &fullDescriptor->PartialResourceList;
|
|||
|
|
|||
|
for (j = 0; j < partialResourceList->Count; j++) {
|
|||
|
partialDescriptor = &partialResourceList->PartialDescriptors[j];
|
|||
|
|
|||
|
if (partialDescriptor->Type == CmResourceTypePort) {
|
|||
|
if (partialDescriptor->u.Port.Start.HighPart == 0 &&
|
|||
|
(partialDescriptor->u.Port.Start.LowPart & 0x00000300) == 0) {
|
|||
|
partialDescriptor->Flags |= CM_RESOURCE_PORT_16_BIT_DECODE;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
nextDescriptor = (PUCHAR)fullDescriptor + sizeof(CM_FULL_RESOURCE_DESCRIPTOR);
|
|||
|
|
|||
|
//
|
|||
|
// account for any resource descriptors in addition to the single
|
|||
|
// imbedded one I've already accounted for (if there aren't any,
|
|||
|
// then I'll end up subtracting off the extra imbedded descriptor
|
|||
|
// from the previous step)
|
|||
|
//
|
|||
|
//
|
|||
|
// finally, account for any extra device specific data at the end of
|
|||
|
// the last partial resource descriptor (if any)
|
|||
|
//
|
|||
|
if (partialResourceList->Count > 0) {
|
|||
|
|
|||
|
nextDescriptor += (partialResourceList->Count - 1) *
|
|||
|
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
|
|||
|
|
|||
|
lastResourceIndex = partialResourceList->Count - 1;
|
|||
|
|
|||
|
if (partialResourceList->PartialDescriptors[lastResourceIndex].Type ==
|
|||
|
CmResourceTypeDeviceSpecific) {
|
|||
|
|
|||
|
nextDescriptor += partialResourceList->PartialDescriptors[lastResourceIndex].
|
|||
|
u.DeviceSpecificData.DataSize;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
fullDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)nextDescriptor;
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
if (wcscmp(PnPId, FloppyId) == 0) {
|
|||
|
|
|||
|
if (ResourceList->Count == 1) {
|
|||
|
|
|||
|
partialResourceList = &ResourceList->List->PartialResourceList;
|
|||
|
|
|||
|
partialDescriptors = partialResourceList->PartialDescriptors;
|
|||
|
|
|||
|
//
|
|||
|
// Look for the one and only one 8 byte port resource
|
|||
|
//
|
|||
|
problemPartialDescriptors = NULL;
|
|||
|
for (i=0; i<partialResourceList->Count; i++) {
|
|||
|
|
|||
|
if ((partialDescriptors[i].Type == CmResourceTypePort) &&
|
|||
|
(partialDescriptors[i].u.Port.Length == 8)) {
|
|||
|
|
|||
|
if (problemPartialDescriptors == NULL) {
|
|||
|
|
|||
|
problemPartialDescriptors = partialDescriptors + i;
|
|||
|
} else {
|
|||
|
|
|||
|
problemPartialDescriptors = NULL;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (problemPartialDescriptors) {
|
|||
|
|
|||
|
problemPartialDescriptors->u.Port.Length = 6;
|
|||
|
|
|||
|
newResourceList = ExAllocatePool (
|
|||
|
NonPagedPool,
|
|||
|
*Size + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)
|
|||
|
);
|
|||
|
if (newResourceList) {
|
|||
|
|
|||
|
RtlCopyMemory (
|
|||
|
newResourceList,
|
|||
|
ResourceList,
|
|||
|
*Size
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// pick out the new partial resource descriptor
|
|||
|
//
|
|||
|
partialDescriptors = newResourceList->List->
|
|||
|
PartialResourceList.PartialDescriptors;
|
|||
|
partialDescriptors += newResourceList->List->PartialResourceList.Count;
|
|||
|
|
|||
|
RtlCopyMemory (
|
|||
|
partialDescriptors,
|
|||
|
problemPartialDescriptors,
|
|||
|
sizeof(*partialDescriptors)
|
|||
|
);
|
|||
|
|
|||
|
partialDescriptors->u.Port.Start.QuadPart += 7;
|
|||
|
partialDescriptors->u.Port.Length = 1;
|
|||
|
|
|||
|
//
|
|||
|
// we got one more now
|
|||
|
//
|
|||
|
newResourceList->List->PartialResourceList.Count++;
|
|||
|
*Size += sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
|
|||
|
|
|||
|
ExFreePool (ResourceList);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
newResourceList = ResourceList;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return newResourceList;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
ComPortDBAdd(
|
|||
|
IN HANDLE DeviceParamKey,
|
|||
|
IN PWSTR PortName
|
|||
|
)
|
|||
|
{
|
|||
|
UNICODE_STRING portNameString;
|
|||
|
UNICODE_STRING portPrefixString;
|
|||
|
UNICODE_STRING comDBName;
|
|||
|
UNICODE_STRING valueName;
|
|||
|
PKEY_VALUE_PARTIAL_INFORMATION valueInfo;
|
|||
|
ULONG valueInfoLength;
|
|||
|
ULONG returnedLength;
|
|||
|
HANDLE comDBKey;
|
|||
|
ULONG portNo;
|
|||
|
NTSTATUS status;
|
|||
|
|
|||
|
RtlInitUnicodeString(&portNameString, PortName);
|
|||
|
|
|||
|
if (portNameString.Length > 3 * sizeof(WCHAR)) {
|
|||
|
portNameString.Length = 3 * sizeof(WCHAR);
|
|||
|
}
|
|||
|
|
|||
|
PiWstrToUnicodeString(&portPrefixString, L"COM");
|
|||
|
|
|||
|
if (RtlCompareUnicodeString(&portNameString, &portPrefixString, TRUE) == 0) {
|
|||
|
portNo = _wtol(&PortName[3]);
|
|||
|
|
|||
|
if (portNo > 0 && portNo <= 256) {
|
|||
|
|
|||
|
#if UMODETEST
|
|||
|
PiWstrToUnicodeString(&comDBName, L"\\Registry\\Machine\\System\\TestControlSet\\Control\\COM Name Arbiter");
|
|||
|
#else
|
|||
|
PiWstrToUnicodeString(&comDBName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\COM Name Arbiter");
|
|||
|
#endif
|
|||
|
|
|||
|
status = IopCreateRegistryKeyEx( &comDBKey,
|
|||
|
NULL,
|
|||
|
&comDBName,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
REG_OPTION_NON_VOLATILE,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
|
|||
|
PiWstrToUnicodeString(&valueName, L"ComDB Merge");
|
|||
|
|
|||
|
#define COMPORT_DB_MERGE_SIZE 32 // 256 / 8
|
|||
|
|
|||
|
valueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + COMPORT_DB_MERGE_SIZE;
|
|||
|
valueInfo = ExAllocatePool(PagedPool, valueInfoLength);
|
|||
|
|
|||
|
if (valueInfo != NULL) {
|
|||
|
|
|||
|
status = ZwQueryValueKey( comDBKey,
|
|||
|
&valueName,
|
|||
|
KeyValuePartialInformation,
|
|||
|
valueInfo,
|
|||
|
valueInfoLength,
|
|||
|
&returnedLength);
|
|||
|
|
|||
|
if (status == STATUS_OBJECT_NAME_NOT_FOUND) {
|
|||
|
|
|||
|
valueInfo->Type = REG_BINARY;
|
|||
|
valueInfo->DataLength = COMPORT_DB_MERGE_SIZE;
|
|||
|
RtlZeroMemory(valueInfo->Data, valueInfo->DataLength);
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
portNo--;
|
|||
|
valueInfo->Data[ portNo / 8 ] |= 1 << (portNo % 8);
|
|||
|
|
|||
|
status = ZwSetValueKey( comDBKey,
|
|||
|
&valueName,
|
|||
|
0,
|
|||
|
valueInfo->Type,
|
|||
|
valueInfo->Data,
|
|||
|
valueInfo->DataLength );
|
|||
|
|
|||
|
ASSERT(NT_SUCCESS(status));
|
|||
|
}
|
|||
|
|
|||
|
ExFreePool(valueInfo);
|
|||
|
}
|
|||
|
|
|||
|
ZwClose(comDBKey);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
PiWstrToUnicodeString( &valueName, L"DosDeviceName" );
|
|||
|
|
|||
|
status = ZwSetValueKey( DeviceParamKey,
|
|||
|
&valueName,
|
|||
|
0,
|
|||
|
REG_SZ,
|
|||
|
PortName,
|
|||
|
(ULONG)((wcslen(PortName) + 1) * sizeof(WCHAR)) );
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
MapperPhantomizeDetectedComPorts (
|
|||
|
VOID
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine turns all newly-created firmware/ntdetect COM ports into
|
|||
|
phantoms.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PFIRMWARE_CONFIGURATION firmwareEntry;
|
|||
|
NTSTATUS status;
|
|||
|
PWCHAR registryBase;
|
|||
|
PWCHAR instanceBuffer;
|
|||
|
HANDLE handle;
|
|||
|
PWCHAR buffer;
|
|||
|
PDEVICE_EXTENSION DeviceExtension = &MapperDeviceExtension;
|
|||
|
UNICODE_STRING enumKey;
|
|||
|
OBJECT_ATTRIBUTES objectAttributes;
|
|||
|
UNICODE_STRING unicodeName;
|
|||
|
ULONG regValue;
|
|||
|
|
|||
|
//
|
|||
|
// allocate space needed for the registry path into the root
|
|||
|
// enumerator tree. Note, limited size on path length.
|
|||
|
//
|
|||
|
|
|||
|
buffer = ExAllocatePool(NonPagedPool, ENUM_KEY_BUFFER_SIZE);
|
|||
|
|
|||
|
if (!buffer) {
|
|||
|
IopDbgPrint((IOP_MAPPER_ERROR_LEVEL,
|
|||
|
"Mapper: could not allocate memory for registry update\n"));
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
instanceBuffer = ExAllocatePool(NonPagedPool, INSTANCE_BUFFER_SIZE);
|
|||
|
if (!instanceBuffer) {
|
|||
|
ExFreePool(buffer);
|
|||
|
IopDbgPrint((IOP_MAPPER_ERROR_LEVEL,
|
|||
|
"Mapper: could not allocate memory for instance buffer\n"));
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
InitializeObjectAttributes(&objectAttributes,
|
|||
|
&enumKey,
|
|||
|
OBJ_CASE_INSENSITIVE,
|
|||
|
NULL,
|
|||
|
NULL);
|
|||
|
|
|||
|
#if UMODETEST
|
|||
|
registryBase = L"\\Registry\\Machine\\System\\TestControlSet\\Enum\\Root\\";
|
|||
|
#else
|
|||
|
registryBase = L"\\Registry\\Machine\\System\\CurrentControlSet\\Enum\\Root\\";
|
|||
|
#endif
|
|||
|
|
|||
|
firmwareEntry = DeviceExtension->FirmwareList;
|
|||
|
while (firmwareEntry) {
|
|||
|
|
|||
|
//
|
|||
|
// Construct the base for the path for this entry.
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
if ((firmwareEntry->ControllerType == SerialController) &&
|
|||
|
firmwareEntry->NewlyCreated) {
|
|||
|
|
|||
|
PiWstrToUnicodeString(&enumKey, NULL);
|
|||
|
enumKey.MaximumLength = ENUM_KEY_BUFFER_SIZE;
|
|||
|
enumKey.Buffer = buffer;
|
|||
|
RtlZeroMemory(buffer, ENUM_KEY_BUFFER_SIZE);
|
|||
|
RtlAppendUnicodeToString(&enumKey, registryBase);
|
|||
|
RtlAppendUnicodeToString(&enumKey, firmwareEntry->PnPId);
|
|||
|
|
|||
|
//
|
|||
|
// Construct the instance name.
|
|||
|
//
|
|||
|
|
|||
|
RtlZeroMemory(instanceBuffer, INSTANCE_BUFFER_SIZE);
|
|||
|
swprintf(instanceBuffer,
|
|||
|
L"\\%d_%d_%d_%d_%d_%d",
|
|||
|
firmwareEntry->BusType,
|
|||
|
firmwareEntry->BusNumber,
|
|||
|
firmwareEntry->ControllerType,
|
|||
|
firmwareEntry->ControllerNumber,
|
|||
|
firmwareEntry->PeripheralType,
|
|||
|
firmwareEntry->PeripheralNumber);
|
|||
|
RtlAppendUnicodeToString(&enumKey, instanceBuffer);
|
|||
|
|
|||
|
status = ZwOpenKey(&handle,
|
|||
|
KEY_READ | KEY_WRITE,
|
|||
|
&objectAttributes
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(status)) {
|
|||
|
|
|||
|
PiWstrToUnicodeString(&unicodeName, REGSTR_VAL_PHANTOM);
|
|||
|
regValue = 1;
|
|||
|
ZwSetValueKey(handle,
|
|||
|
&unicodeName,
|
|||
|
0,
|
|||
|
REG_DWORD,
|
|||
|
®Value,
|
|||
|
sizeof(regValue)
|
|||
|
);
|
|||
|
|
|||
|
ZwClose(handle);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
firmwareEntry = firmwareEntry->Next;
|
|||
|
}
|
|||
|
|
|||
|
ExFreePool (buffer);
|
|||
|
ExFreePool (instanceBuffer);
|
|||
|
}
|