Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

4936 lines
143 KiB

/*++
Copyright (c) 1993 Microsoft Corporation
Module Name:
sphw.c
Abstract:
Hardware detection and confirmation routines for text setup.
Author:
Ted Miller (tedm) 1-October-1993
Revision History:
--*/
#include "spprecmp.h"
#pragma hdrstop
extern BOOLEAN HandleLineContinueChars;
VOID
SpHardwareConfirmInteract(
IN PVOID SifHandle
);
VOID
SpConfirmScsiInteract(
IN PVOID SifHandle,
IN PWSTR SourceDevicePath,
IN PWSTR DirectoryOnSourceDevice
);
BOOLEAN
SpSelectHwItem(
IN PVOID SifHandle,
IN PWSTR NonlocalizedComponentName,
IN PWSTR OemSectionName, OPTIONAL
IN ULONG SelectHwScreenId,
IN ULONG SelectOemHwScreenId,
IN ULONG AllowedFileTypes,
IN ULONG RequiredFileTypes,
IN OUT PHARDWARE_COMPONENT HwComp
);
VOID
SpScanHardwareDescription(
IN PWSTR DesiredKeyName
);
VOID
SpDetectComputer(
IN PVOID SifHandle
);
VOID
SpDetectVideo(
IN PVOID SifHandle
);
VOID
SpDetectKeyboard(
IN PVOID SifHandle
);
VOID
SpDetectMouse(
IN PVOID SifHandle
);
VOID
SpDetectLayout(
IN PVOID SifHandle
);
VOID
SpDetectScsi(
IN PVOID SifHandle,
IN PWSTR SourceDevicePath,
IN PWSTR DirectoryOnSourceDevice
);
VOID
SpDetermineComponent(
IN PVOID SifHandle,
OUT PHARDWARE_COMPONENT HwComp,
IN PWSTR HardwareDescriptionKeyName,
IN PWSTR FallbackIdentifier,
IN PWSTR ComponentName
);
BOOLEAN
SpOemDiskette(
IN PVOID SifHandle,
IN PWSTR SectionName,
IN ULONG SelectOemHwScreenId,
IN ULONG AllowedFileTypes,
IN ULONG RequiredFileTypes,
IN OUT PHARDWARE_COMPONENT HwComp,
IN ULONG ErrorId
);
BOOLEAN
SpOemInfSelection(
IN PVOID TxtsetupOem,
IN PWSTR NonlocalizedComponentName,
IN PWSTR SelectedId,
IN PWSTR ItemDescription,
IN ULONG AllowedFileTypes,
IN ULONG RequiredFileTypes,
OUT PHARDWARE_COMPONENT HwComp,
IN ULONG ErrorId
);
VOID
SpFreeLocatedIdStrings(
VOID
);
VOID
SpScanHardwareDescriptionWorker(
IN HANDLE KeyHandle,
IN PWSTR KeyName,
IN PWSTR DesiredKeyName
);
BOOLEAN
SpScanMapSection(
IN PVOID SifHandle,
OUT PHARDWARE_COMPONENT HwComp,
IN PWSTR ComponentName,
IN PWSTR IdString
);
VOID
SpInitHwComponent(
OUT PHARDWARE_COMPONENT HwComp,
IN PWSTR IdString,
IN PWSTR Description,
IN BOOLEAN ThirdPartyOption,
IN ULONG FileTypeBits,
IN PWSTR BaseDllName,
IN BOOLEAN MigratedDriver
);
VOID
SpInitHwComponentFile(
OUT PHARDWARE_COMPONENT_FILE HwCompFile,
IN PWSTR Filename,
IN HwFileType FileType,
IN PWSTR ConfigName,
IN PWSTR DiskDescription,
IN PWSTR DiskTagFile,
IN PWSTR Directory,
IN PWSTR ArcDeviceName
);
VOID
SpInitHwComponentRegVal(
OUT PHARDWARE_COMPONENT_REGISTRY HwCompReg,
IN PWSTR KeyName,
IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID Buffer,
IN ULONG BufferSize
);
VOID
SpFreeHwComponentFile(
IN OUT PHARDWARE_COMPONENT_FILE *HwCompFile
);
VOID
SpFreeHwComponentReg(
IN OUT PHARDWARE_COMPONENT_REGISTRY *HwCompReg
);
PHARDWARE_COMPONENT_REGISTRY
SpInterpretOemRegistryData(
IN PVOID SifHandle,
IN PWSTR SectionName,
IN ULONG Line,
IN ULONG ValueType,
IN PWSTR KeyName,
IN PWSTR ValueName
);
VOID
SpGetDriverValuesForLoad(
IN PVOID SifHandle,
IN PWSTR ComponentSectionName,
IN PWSTR ComponentLoadSectionName,
IN PWSTR Shortname,
OUT PWSTR *Filename,
OUT PWSTR *MediaDesignator,
OUT PWSTR *Description OPTIONAL
);
//
// These two globals track a table that gets built as the
// hardware description in the registry is scanned for a
// particular hardware component. See SpScanHardwareDescription().
//
PWSTR *IdStringArray;
ULONG IdStringCount;
//
// Array of ulongs that are the message ids for screens that
// prompt the user to select a type of a component from the
// list below.
//
ULONG SelectHwScreens[HwComponentMax] = { SP_SCRN_SELECT_COMPUTER,
SP_SCRN_SELECT_DISPLAY,
SP_SCRN_SELECT_KEYBOARD,
SP_SCRN_SELECT_LAYOUT,
SP_SCRN_SELECT_MOUSE
};
//
// Array of ulongs that are the message ids for screens that
// prompt the user to select an option from an oem disk for
// a component from the list below.
//
ULONG SelectOemHwScreens[HwComponentMax] = { SP_SCRN_SELECT_OEM_COMPUTER,
SP_SCRN_SELECT_OEM_DISPLAY,
SP_SCRN_SELECT_OEM_KEYBOARD,
SP_SCRN_SELECT_OEM_LAYOUT,
SP_SCRN_SELECT_OEM_MOUSE
};
ULONG UnknownHwScreens[HwComponentMax] = { SP_SCRN_UNKNOWN_COMPUTER,
SP_SCRN_UNKNOWN_DISPLAY,
SP_SCRN_UNKNOWN_KEYBOARD,
SP_SCRN_UNKNOWN_LAYOUT,
SP_SCRN_UNKNOWN_MOUSE
};
//
// These are the names of the components. This is array is not localized
// because it is used only to index hardware-related sections in the
// setup information file.
//
PWSTR NonlocalizedComponentNames[HwComponentMax] = { L"Computer",
L"Display",
L"Keyboard",
L"Keyboard Layout",
L"Mouse"
};
//
// The following is the name of the SCSI section in txtsetup.sif.
// On amd64/x86 machines, this is one of SCSI.ISA, SCSI.EISA, or SCSI.MCA.
// On other machines, this is just SCSI.
//
PWSTR ScsiSectionName;
PWSTR ScsiLoadSectionName;
PWSTR FileTypeNames[HwFileMax+1] = { L"Driver",
L"Port",
L"Class",
L"Inf",
L"Dll",
L"Detect",
L"Hal",
L"Catalog",
NULL
};
PWSTR RegistryTypeNames[HwRegistryMax+1] = { L"REG_DWORD",
L"REG_BINARY",
L"REG_SZ",
L"REG_EXPAND_SZ",
L"REG_MULTI_SZ",
NULL
};
ULONG RegistryValueTypeMap[HwRegistryMax] = { REG_DWORD,
REG_BINARY,
REG_SZ,
REG_EXPAND_SZ,
REG_MULTI_SZ
};
PHARDWARE_COMPONENT HardwareComponents[HwComponentMax] = { NULL,NULL,NULL,NULL,NULL };
PHARDWARE_COMPONENT ScsiHardware;
PHARDWARE_COMPONENT BootBusExtenders;
PHARDWARE_COMPONENT BusExtenders;
PHARDWARE_COMPONENT InputDevicesSupport;
PHARDWARE_COMPONENT PreinstallHardwareComponents[HwComponentMax] = { NULL,NULL,NULL,NULL,NULL };
PHARDWARE_COMPONENT PreinstallScsiHardware = NULL;
PHARDWARE_COMPONENT UnsupportedScsiHardwareToDisable = NULL;
PWSTR PreinstallSectionNames[HwComponentMax] = { WINNT_U_COMPUTERTYPE_W,
WINNT_OEMDISPLAYDRIVERS_W,
WINNT_OEMKEYBOARDDRIVERS_W,
WINNT_U_KEYBOARDLAYOUT_W,
WINNT_OEMPOINTERDRIVERS_W
};
#define MAX_SCSI_MINIPORT_COUNT 5
ULONG LoadedScsiMiniportCount;
//
// This array lists the type of files allowed for each component type.
// For example, detect files are allowed for computer and driver files are
// allowed for all component types. Keep in sync with HwComponentType enum!
//
ULONG AllowedFileTypes[HwComponentMax] = {
// Computer
FILETYPE(HwFileDriver) | FILETYPE(HwFilePort) | FILETYPE(HwFileClass)
| FILETYPE(HwFileInf) | FILETYPE(HwFileDll) | FILETYPE(HwFileDetect)
| FILETYPE(HwFileHal) | FILETYPE(HwFileCatalog),
// Display
FILETYPE(HwFileDriver) | FILETYPE(HwFilePort) | FILETYPE(HwFileInf)
| FILETYPE(HwFileDll) | FILETYPE(HwFileCatalog),
// Keyboard
FILETYPE(HwFileDriver) | FILETYPE(HwFilePort) | FILETYPE(HwFileClass)
| FILETYPE(HwFileInf) | FILETYPE(HwFileDll) | FILETYPE(HwFileCatalog),
// Layout
FILETYPE(HwFileDll) | FILETYPE(HwFileInf),
// Mouse
FILETYPE(HwFileDriver) | FILETYPE(HwFilePort) | FILETYPE(HwFileClass)
| FILETYPE(HwFileInf) | FILETYPE(HwFileDll) | FILETYPE(HwFileCatalog)
};
#define SCSI_ALLOWED_FILETYPES (FILETYPE(HwFileDriver) | FILETYPE(HwFilePort) | FILETYPE(HwFileInf) | FILETYPE(HwFileCatalog))
//
// This array lists the type of files required for each component type.
// For example, a hal is required for computer. Keep in sync with
// HwComponentType enum!
//
ULONG RequiredFileTypes[HwComponentMax] = {
// Computer
FILETYPE(HwFileHal),
// Display
FILETYPE(HwFileDriver) | FILETYPE(HwFileDll),
// Keyboard
FILETYPE(HwFileDriver),
// Layout
FILETYPE(HwFileDll),
// Mouse
FILETYPE(HwFileDriver)
};
#define SCSI_REQUIRED_FILETYPES FILETYPE(HwFileDriver)
#define MAP_SECTION_NAME_PREFIX L"Map."
#define HARDWARE_MENU_SIZE HwComponentMax
#define MICROSOFT_BUS_MOUSE_NAME L"MICROSOFT BUS MOUSE"
FloppyDriveType
SpGetFloppyDriveType(
IN ULONG FloppyOrdinal
)
/*++
Routine Description:
Inspect a floppy disk drive attempting to classify it as a
5.25 or 3.5" drive, hi or low density. For 5.25" disks,
1.2MB drives are high density; smaller drives are low-density.
For 3.5" drives, 1.44, 2.88, or 20.8MB is high density, smaller
drives are low density.
Any other drive types are unrecognized and result in
FloppyTypeNone being returned.
Arguments:
FloppyOrdinal - supplies ordinal number of floppy (0=A:, etc).
Return Value:
Value from the FloppyDriveType enum indicating which type the drive is.
FloppyTypeNone if we couldn't determine this information.
--*/
{
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING UnicodeString;
HANDLE Handle;
WCHAR OpenPath[64];
DISK_GEOMETRY DiskGeom[25];
ULONG_PTR MediaTypeCount;
static FloppyDriveType CachedTypes[2] = { -1,-1 };
FloppyDriveType FloppyType;
//
// If we have already determined this for this drive,
// return the cached info.
//
if((FloppyOrdinal < ELEMENT_COUNT(CachedTypes))
&& (CachedTypes[FloppyOrdinal] != -1))
{
return(CachedTypes[FloppyOrdinal]);
}
//
// Assume the floppy doesn't exist or we can't tell what type it is.
//
FloppyType = FloppyTypeNone;
swprintf(OpenPath,L"\\device\\floppy%u",FloppyOrdinal);
INIT_OBJA(&ObjectAttributes,&UnicodeString,OpenPath);
Status = ZwCreateFile(
&Handle,
SYNCHRONIZE | FILE_READ_ATTRIBUTES,
&ObjectAttributes,
&IoStatusBlock,
NULL, // allocation size
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_VALID_FLAGS, // full sharing
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL, // no EAs
0
);
if(NT_SUCCESS(Status)) {
//
// Get supported media types.
//
Status = ZwDeviceIoControlFile(
Handle,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_DISK_GET_MEDIA_TYPES,
NULL,
0,
DiskGeom,
sizeof(DiskGeom)
);
if(NT_SUCCESS(Status)) {
ASSERT((IoStatusBlock.Information % sizeof(DISK_GEOMETRY)) == 0);
if(MediaTypeCount = IoStatusBlock.Information / sizeof(DISK_GEOMETRY)) {
//
// Highest capacity media type is last entry.
//
switch(DiskGeom[MediaTypeCount-1].MediaType) {
case F5_1Pt23_1024: //NEC98
if (!IsNEC_98) {
break;
}
// trough down to set FloppyType525High on NEC98
case F5_1Pt2_512:
FloppyType = FloppyType525High;
break;
case F3_1Pt23_1024: //NEC98
if (!IsNEC_98) {
break;
}
// trough down to set FloppyType35High on NEC98
case F3_1Pt44_512:
case F3_2Pt88_512:
case F3_20Pt8_512:
FloppyType = FloppyType35High;
break;
case F3_720_512:
FloppyType = FloppyType35Low;
break;
case F5_360_512:
case F5_320_512:
case F5_320_1024:
case F5_180_512:
case F5_160_512:
FloppyType = FloppyType525Low;
break;
case F3_120M_512:
FloppyType = FloppyType35High120MB;
break;
}
} else {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: no media types for %ws!\n",OpenPath));
}
} else {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to get media types for %ws (%lx)\n",OpenPath,Status));
}
ZwClose(Handle);
} else {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: %ws does not exist (%lx)\n",OpenPath,Status));
}
//
// Save the value.
//
if(FloppyOrdinal < ELEMENT_COUNT(CachedTypes)) {
CachedTypes[FloppyOrdinal] = FloppyType;
}
return(FloppyType);
}
VOID
SpConfirmScsiMiniports(
IN PVOID SifHandle,
IN PWSTR SourceDevicePath,
IN PWSTR DirectoryOnSourceDevice
)
{
CLEAR_CLIENT_SCREEN();
SpDisplayStatusText(SP_STAT_PLEASE_WAIT,DEFAULT_STATUS_ATTRIBUTE);
//
// Start with scsi.
//
SpDetectScsi(SifHandle,SourceDevicePath,DirectoryOnSourceDevice);
SpConfirmScsiInteract(SifHandle,SourceDevicePath,DirectoryOnSourceDevice);
}
VOID
SpConfirmHardware(
IN PVOID SifHandle
)
{
ULONG i;
BOOLEAN AllConfirmed,FirstPass,NeedConfirm;
PWSTR p;
CLEAR_CLIENT_SCREEN();
SpDisplayStatusText(SP_STAT_PLEASE_WAIT,DEFAULT_STATUS_ATTRIBUTE);
//
// Determine the computer type.
//
SpDetectComputer(SifHandle);
//
// Determine the video type.
//
SpDetectVideo(SifHandle);
//
// Determine the keyboard type.
//
SpDetectKeyboard(SifHandle);
//
// Determine the mouse.
//
SpDetectMouse(SifHandle);
//
// Determine the keyboard layout.
//
SpDetectLayout(SifHandle);
//
// If we have upgrade, we don't need to know what display, keyboard,
// layout, mouse we have. We just need the computer type and that
// is 100% accurate. So we can skip the hardware confirmation dialog
//
if(NTUpgrade == UpgradeFull) {
return;
}
//
// Handle locale-specific keyboard stuff for Far East.
//
SplangSelectKeyboard(
UnattendedOperation,
UnattendedSifHandle,
NTUpgrade,
SifHandle,
HardwareComponents
);
//
// See whether this is an unattended setup.
//
NeedConfirm = FALSE;
if(UnattendedOperation) {
NeedConfirm = FALSE;
if( !PreInstall ) {
//
// If this is not an OEM pre-install, then check if we need
// to confirm the hardware
//
p = SpGetSectionKeyIndex(
UnattendedSifHandle,
SIF_UNATTENDED,
SIF_CONFIRMHW,
0
);
if(p && !_wcsicmp(p,L"yes")) {
NeedConfirm = TRUE;
}
} else {
return;
}
}
FirstPass = TRUE;
do {
//
// See if we know what everything is.
//
AllConfirmed = TRUE;
for(i=0; i<HwComponentMax; i++) {
if(HardwareComponents[i]->Description == NULL) {
AllConfirmed = FALSE;
break;
}
}
//
// If we don't know what everything is, put up a warning.
//
if(FirstPass) {
if(CustomSetup && NeedConfirm) {
AllConfirmed = FALSE;
}
FirstPass = FALSE;
} else if(!AllConfirmed) {
SpDisplayScreen(UnknownHwScreens[i],4,HEADER_HEIGHT+2);
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_ENTER_EQUALS_CONTINUE,0);
SpInputDrain();
while(SpInputGetKeypress() != ASCI_CR) ;
}
//
// If this is a custom setup or we don't know what
// a piece of hardware is, present the confirmation screen
// to the user.
//
if(!AllConfirmed) {
SpHardwareConfirmInteract(SifHandle);
}
} while(!AllConfirmed);
}
VOID
SpHardwareConfirmInteract(
IN PVOID SifHandle
)
{
PWSTR szUnknown,szListMatches;
PWSTR p;
ULONG MenuLeftX,MenuTopY;
ULONG LongestLength,len;
PWSTR MenuItems[HARDWARE_MENU_SIZE];
PVOID Menu;
ULONG KeyPressed;
ULONG_PTR Selection;
ULONG ValidKeys[3] = { KEY_F3,ASCI_CR,0 };
BOOLEAN Done;
ULONG i;
WCHAR c;
//
// Fetch 'unknown' and 'the above list matches my computer' from the resources.
//
SpFormatMessage(TemporaryBuffer,sizeof(TemporaryBuffer),SP_TEXT_UNKNOWN);
szUnknown = SpDupStringW(TemporaryBuffer);
SpFormatMessage(TemporaryBuffer,sizeof(TemporaryBuffer),SP_TEXT_LIST_MATCHES);
szListMatches = SpDupStringW(TemporaryBuffer);
for(Done=FALSE; !Done; ) {
//
// Part 1 of the screen.
//
SpDisplayScreen(SP_SCRN_HW_CONFIRM_1,3,HEADER_HEIGHT+1);
//
// Remember top line of the menu.
//
MenuTopY = NextMessageTopLine + 2;
//
// Part 2 of the screen.
//
SpContinueScreen(SP_SCRN_HW_CONFIRM_2,3,2,FALSE,DEFAULT_ATTRIBUTE);
//
// To determine where the left margin of the menu is, we'll load
// the second part of the screen and look for the first semicolon.
//
SpFormatMessage(TemporaryBuffer,sizeof(TemporaryBuffer),SP_SCRN_HW_CONFIRM_2);
p = wcschr(TemporaryBuffer,L':');
ASSERT(p);
if(p) {
c = *p;
*p = 0;
MenuLeftX = SplangGetColumnCount(TemporaryBuffer) + 5;
*p = c;
} else {
MenuLeftX = 23;
}
//
// Build up menu items.
//
LongestLength = SplangGetColumnCount(szListMatches);
for(i=0; i<HARDWARE_MENU_SIZE; i++) {
MenuItems[i] = HardwareComponents[i]->Description
? HardwareComponents[i]->Description
: szUnknown;
if((len=SplangGetColumnCount(MenuItems[i])) > LongestLength) {
LongestLength = len;
}
}
Menu = SpMnCreate(MenuLeftX,MenuTopY,LongestLength,HARDWARE_MENU_SIZE+2);
ASSERT(Menu);
//
// Silently fail, if we cannot create the menu
//
if (!Menu) {
Done = TRUE;
continue;
}
//
// Add all the items to the menu, plus one unselectable spacer and
// the 'the list matches' item.
//
for(i=0; i<HARDWARE_MENU_SIZE; i++) {
BOOLEAN ItemSelectable;
#if defined(_IA64_)
ItemSelectable = TRUE; // in softsdv the mouse + keyboard are
// unknown; we need to select them.
#else
ItemSelectable = ( (i != HwComponentKeyboard) &&
(i != HwComponentMouse) );
#endif
SpMnAddItem(Menu,
MenuItems[i],
MenuLeftX,
LongestLength,
ItemSelectable,
ItemSelectable ? i : 0);
}
SpMnAddItem(Menu,L"",MenuLeftX,LongestLength,FALSE,0);
SpMnAddItem(Menu,szListMatches,MenuLeftX,LongestLength,TRUE,(ULONG_PTR)(-1));
//
// Display the status text.
//
SpDisplayStatusOptions(
DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_ENTER_EQUALS_SELECT,
SP_STAT_F3_EQUALS_EXIT,
0
);
//
// Display the menu and await a selection.
//
SpMnDisplay(Menu,
(ULONG_PTR)(-1),
FALSE,
ValidKeys,
NULL,
NULL,
NULL,
&KeyPressed,
&Selection);
SpMnDestroy(Menu);
switch(KeyPressed) {
case KEY_F3:
SpConfirmExit();
break;
case ASCI_CR:
//
// Selection was made.
//
if(Selection == (ULONG_PTR)(-1)) {
Done = TRUE;
} else {
ASSERT(Selection < HwComponentMax);
//
// Allow user to make alternate selection for this component.
//
SpSelectHwItem(
SifHandle,
NonlocalizedComponentNames[Selection],
NULL, // use component name as section name
SelectHwScreens[Selection],
SelectOemHwScreens[Selection],
AllowedFileTypes[Selection],
RequiredFileTypes[Selection],
HardwareComponents[Selection]
);
}
break;
default:
// should never get here!
ASSERT(0);
break;
}
}
SpMemFree(szUnknown);
SpMemFree(szListMatches);
}
BOOLEAN
SpSelectHwItem(
IN PVOID SifHandle,
IN PWSTR NonlocalizedComponentName,
IN PWSTR OemSectionName, OPTIONAL
IN ULONG SelectHwScreenId,
IN ULONG SelectOemHwScreenId,
IN ULONG AllowedFileTypes,
IN ULONG RequiredFileTypes,
IN OUT PHARDWARE_COMPONENT HwComp
)
/*++
Routine Description:
Allow the user to make selection from a list of choices for a component.
The list comes from a section in the setup information file named
for the component. For example, [Display].
The descriptions in that section will be placed into a menu to make
up the selections. Also added to the menu will be a choice for 'other'
which the user can choose if he has a third-party driver diskette.
If a third-party option is the currently selected option, then that
option will also be on the menu and will be the default.
If the user selects 'other' then prompt for a driver diskette.
Arguments:
SifHandle - supplies handle to open setup information file.
NonlocalizedComponentName - supplies name of component to be used
as the name of a section in the sif file for the component.
OemSectionName - supplies name of a section that will contain the
options for the component in txtsetup.oem. This may be different
than NonloclizedComponentName -- for example, the componentname
string might be "SCSI.MCA" but the OemSectionName would be "SCSI."
SelectHwScreenId - supplies message id of the screen prompting the user
to select an option for this component.
SelectOemHwScreenId - supplies message id of the screen prompting the
user to select an option on an oem screen for this component
(ie, the screen the user gets when he selects 'other' hw type
and inserts an oem floppy).
AllowedFileTypes - supplies a mask indicating which types of files are
allowed for this component. Used to validate the oem selection
if the user chooses the 'other' hardware type and inserts an oem floppy.
RequiredFileTypes - supplies a mask indicating which types of files are
required for this component. Used to validate the oem selection
if the user chooses the 'other' hardware type and inserts an oem floppy.
HwComp - hardware component structure to be filled in with information
about the user's selection.
Return Value:
TRUE if the selected hardware item has been changed by the user's action.
FALSE otherwise.
--*/
{
ULONG LineCount,Line;
PVOID Menu;
ULONG MenuTopY,MenuHeight,MenuWidth;
PWSTR Description;
ULONG_PTR Selection;
PWSTR szOtherHardware;
ULONG OtherOption;
ULONG_PTR OriginalSelection = (ULONG_PTR)(-1);
ULONG ValidKeys[4] = { KEY_F3,ASCI_CR,ASCI_ESC,0 };
ULONG Keypress;
BOOLEAN Done;
BOOLEAN rc = FALSE;
PWSTR Id,Descr;
//
// Fetch the 'other hardware' string from resources.
//
SpFormatMessage(TemporaryBuffer,sizeof(TemporaryBuffer),SP_TEXT_OTHER_HARDWARE);
szOtherHardware = SpDupStringW(TemporaryBuffer);
for(Done=FALSE; !Done; ) {
//
// Display the selection prompt screen.
//
SpDisplayScreen(SelectHwScreenId,5,HEADER_HEIGHT+1);
MenuTopY = NextMessageTopLine + 2;
MenuHeight = VideoVars.ScreenHeight - MenuTopY - 3;
MenuWidth = VideoVars.ScreenWidth - 6;
//
// Create a menu.
//
Menu = SpMnCreate(3,MenuTopY,MenuWidth,MenuHeight);
ASSERT(Menu);
//
// Assume unknown option.
//
Selection = (ULONG_PTR)(-1);
//
// Build a list of options containing the options in our box
// and the currently selected oem option (if any).
//
LineCount = SpCountLinesInSection(SifHandle,NonlocalizedComponentName);
for(Line=0; Line<LineCount; Line++) {
//
// Get the description from the current line and add it to the menu.
//
Description = SpGetSectionLineIndex(
SifHandle,
NonlocalizedComponentName,
Line,
INDEX_DESCRIPTION
);
if(!Description) {
SpFatalSifError(SifHandle,NonlocalizedComponentName,NULL,Line,INDEX_DESCRIPTION);
}
SpMnAddItem(Menu,Description,3,VideoVars.ScreenWidth-6,TRUE,Line);
//
// See if this is the currently selected item.
//
if(HwComp->Description && !wcscmp(HwComp->Description,Description)) {
Selection = Line;
}
}
//
// If there is an oem option, add its description and make it the default.
//
if(HwComp->ThirdPartyOptionSelected) {
SpMnAddItem(Menu,HwComp->Description,3,VideoVars.ScreenWidth-6,TRUE,Line);
Selection = Line++;
}
//
// Add 'other to the list and make it the defualt if the current type is
// 'other' and there is no third-party option.
// Note that we don't allow oem keyboard layouts any more.
//
if(HwComp == HardwareComponents[HwComponentLayout]) {
if(Selection == (ULONG_PTR)(-1)) {
Selection = 0;
}
OtherOption = (ULONG)(-1);
} else {
SpMnAddItem(Menu,szOtherHardware,3,VideoVars.ScreenWidth-6,TRUE,Line);
if((Selection == (ULONG_PTR)(-1))
|| (!HwComp->ThirdPartyOptionSelected && !HwComp->IdString))
{
Selection = Line;
}
OtherOption = Line;
}
if(OriginalSelection == (ULONG_PTR)(-1)) {
OriginalSelection = Selection;
}
//
// Display the status text options.
//
SpDisplayStatusOptions(
DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_ENTER_EQUALS_SELECT,
SP_STAT_F3_EQUALS_EXIT,
SP_STAT_ESC_EQUALS_CANCEL,
0
);
//
// Display the menu.
//
SpMnDisplay(
Menu,
Selection,
TRUE,
ValidKeys,
NULL,
NULL,
NULL,
&Keypress,
&Selection
);
//
// Fetch the description text before we free the menu structure.
//
Descr = SpMnGetTextDup(Menu,Selection);
SpMnDestroy(Menu);
switch(Keypress) {
case ASCI_CR:
if(Selection == OtherOption) {
//
// User selected 'other' -- prompt for a diskette, etc.
//
rc = SpOemDiskette(
SifHandle,
OemSectionName ? OemSectionName : NonlocalizedComponentName,
SelectOemHwScreenId,
AllowedFileTypes,
RequiredFileTypes,
HwComp,
SP_SCRN_OEM_INF_ERROR
);
} else if(Selection == OriginalSelection) {
//
// User chose same thinbg that was selected before.
//
rc = FALSE;
} else {
//
// User chose a non-oem option. Update structures accordingly
// and forget any previously selected oem option.
//
Id = SpGetKeyName(SifHandle,NonlocalizedComponentName,(ULONG)Selection);
if(!Id) {
SpFatalSifError(SifHandle,NonlocalizedComponentName,NULL,(ULONG)Selection,(ULONG)(-1));
}
ASSERT(Descr);
SpFreeHwComponentFile(&HwComp->Files);
SpInitHwComponent(HwComp,Id,Descr,FALSE,0,NULL,FALSE);
rc = TRUE;
}
Done = TRUE;
break;
case ASCI_ESC:
Done = TRUE;
break;
case KEY_F3:
SpConfirmExit();
break;
default:
// shouldn't ever get here!
ASSERT(0);
break;
}
SpMemFree(Descr);
}
SpMemFree(szOtherHardware);
return(rc);
}
VOID
SpOemInfError(
IN ULONG ErrorScreenId,
IN ULONG SubErrorId,
IN PWSTR SectionName,
IN ULONG LineNumber,
IN PWSTR Description
)
{
WCHAR SubError[512];
//
// Line numbers are 0-based. Want to display to user as 1-based.
//
LineNumber++;
//
// Fetch/format the suberror.
//
SpFormatMessage(SubError,sizeof(SubError),SubErrorId,SectionName,LineNumber,Description);
//
// Display the error screen.
//
SpStartScreen(
ErrorScreenId,
3,
HEADER_HEIGHT+1,
FALSE,
FALSE,
DEFAULT_ATTRIBUTE,
SubError
);
if( !PreInstall ) {
//
// Display status options: enter to continue.
//
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_ENTER_EQUALS_CONTINUE,0);
//
// Wait for the user to press enter.
//
SpInputDrain();
while(SpInputGetKeypress() != ASCI_CR) ;
} else {
//
// If this is an OEM pre-install then treat the error as a fatal one.
// Display status options: F3 to exit.
//
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_F3_EQUALS_EXIT,0);
//
// Wait for the user to press enter.
//
SpInputDrain();
while(SpInputGetKeypress() != KEY_F3) ;
SpDone(0,FALSE,TRUE);
}
}
BOOLEAN
SpOemDiskette(
IN PVOID SifHandle,
IN PWSTR SectionName,
IN ULONG SelectOemHwScreenId,
IN ULONG AllowedFileTypes,
IN ULONG RequiredFileTypes,
IN OUT PHARDWARE_COMPONENT HwComp,
IN ULONG ErrorId
)
{
PWSTR szDiskName;
BOOLEAN b;
ULONG ErrorLine;
NTSTATUS Status;
PVOID TxtsetupOem;
ULONG Count;
ULONG Line;
ULONG_PTR DefaultSelection,Selection;
PWSTR DefSelId;
PVOID Menu;
ULONG MenuTopY,MenuHeight,MenuWidth;
BOOLEAN rc;
ULONG ValidKeys[3] = { ASCI_CR, ASCI_ESC, 0 };
ULONG Key;
PWSTR szDefaults = TXTSETUP_OEM_DEFAULTS_U;
PWSTR szDevicePath = 0;
//
// Assume failure.
//
rc = FALSE;
//
// Always want to prompt for the disk in A:.
// First, make sure there is an A:!
//
if(SpGetFloppyDriveType(0) == FloppyTypeNone) {
SpDisplayScreen(SP_SCRN_NO_FLOPPY_FOR_OEM_DISK,3,HEADER_HEIGHT+1);
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_ENTER_EQUALS_CONTINUE,0);
SpInputDrain();
while(SpInputGetKeypress() != ASCI_CR) ;
goto sod0;
}
//
// Fetch the generic oem disk name.
//
SpFormatMessage(TemporaryBuffer,sizeof(TemporaryBuffer),SP_TEXT_OEM_DISK_NAME);
szDiskName = SpDupStringW(TemporaryBuffer);
//
// Prompt for the disk -- ignore what may be in the drive already,
// and allow escape.
//
szDevicePath = SpDupStringW(L"\\device\\floppy0");
if (szDevicePath) {
b = SpPromptForDisk(
szDiskName,
szDevicePath,
TXTSETUP_OEM_FILENAME_U,
TRUE,
TRUE,
FALSE,
NULL
);
SpMemFree(szDevicePath);
} else {
b = FALSE;
}
SpMemFree(szDiskName);
//
// If the user pressed escape at the disk prompt, bail out now.
//
if(!b) {
goto sod0;
}
//
// Load txtsetup.oem.
//
HandleLineContinueChars = FALSE;
Status = SpLoadSetupTextFile(
L"\\device\\floppy0\\" TXTSETUP_OEM_FILENAME_U,
NULL,
0,
&TxtsetupOem,
&ErrorLine,
TRUE,
FALSE
);
HandleLineContinueChars = TRUE;
if(!NT_SUCCESS(Status)) {
if(Status == STATUS_UNSUCCESSFUL) {
SpOemInfError(ErrorId,SP_TEXT_OEM_INF_ERROR_A,NULL,ErrorLine,NULL);
} else {
SpOemInfError(ErrorId,SP_TEXT_OEM_INF_ERROR_0,NULL,0,NULL);
}
goto sod0;
}
//
// Determine if this inf file is relevent to the device class the user
// is selecting. If there is a section called 'display' 'keyboard' etc
// as appropriate for DeviceClass, then we're in business.
//
Count = SpCountLinesInSection(TxtsetupOem,SectionName);
if(!Count) {
SpOemInfError(ErrorId,SP_TEXT_OEM_INF_ERROR_1,SectionName,0,NULL);
goto sod1;
}
//
// Get the id of the default choice.
//
DefaultSelection = 0;
DefSelId = SpGetSectionKeyIndex(TxtsetupOem,szDefaults,SectionName,OINDEX_DEFAULT);
if(DefSelId == NULL) {
DefSelId = L"";
}
//
// Display the prompt screen, calculate where the menu goes,
// and create a menu.
//
SpDisplayScreen(SelectOemHwScreenId,5,HEADER_HEIGHT+1);
MenuTopY = NextMessageTopLine + 2;
MenuHeight = VideoVars.ScreenHeight - MenuTopY - 3;
MenuWidth = VideoVars.ScreenWidth - 6;
Menu = SpMnCreate(3,MenuTopY,MenuWidth,MenuHeight);
//
// Build a menu from the choices in the oem inf file section.
//
for(Line=0; Line<Count; Line++) {
PWSTR p,Descr;
Descr = SpGetSectionLineIndex(TxtsetupOem,SectionName,Line,OINDEX_DESCRIPTION);
if(Descr == NULL) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpOemDiskette: no description on line %u in [%ws]",Line,SectionName));
SpOemInfError(ErrorId,SP_TEXT_OEM_INF_ERROR_2,SectionName,Line,NULL);
goto sod2;
}
SpMnAddItem(Menu,Descr,3,MenuWidth,TRUE,Line);
// determine if this is the default selection.
if(p = SpGetKeyName(TxtsetupOem,SectionName,Line)) {
if(!_wcsicmp(p,DefSelId)) {
DefaultSelection = Line;
}
} else {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpOemDiskette: no key on line %u of section %ws",Line,SectionName));
SpOemInfError(ErrorId,SP_TEXT_OEM_INF_ERROR_2,SectionName,Line,NULL);
goto sod2;
}
}
//
// Display options in status bar: enter = select, escape = cancel.
//
SpDisplayStatusOptions(
DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_ENTER_EQUALS_SELECT,
SP_STAT_ESC_EQUALS_CANCEL,
0
);
//
// Display the menu and await a selection.
//
SpMnDisplay(Menu,
DefaultSelection,
TRUE,
ValidKeys,
NULL,
NULL,
NULL,
&Key,
&Selection);
if(Key == ASCI_CR) {
PWSTR Id = SpGetKeyName(TxtsetupOem,SectionName,(ULONG)Selection);
PWSTR p;
//
// We already checked this once for non-null (above).
//
ASSERT(Id);
rc = SpOemInfSelection(
TxtsetupOem,
SectionName,
Id,
p = SpMnGetTextDup(Menu,Selection),
AllowedFileTypes,
RequiredFileTypes,
HwComp,
ErrorId
);
SpMemFree(p);
} else {
ASSERT(Key == ASCI_ESC);
// just fall through and return false.
}
sod2:
SpMnDestroy(Menu);
sod1:
SpFreeTextFile(TxtsetupOem);
sod0:
return(rc);
}
BOOLEAN
SpOemInfSelection(
IN PVOID TxtsetupOem,
IN PWSTR NonlocalizedComponentName,
IN PWSTR SelectedId,
IN PWSTR ItemDescription,
IN ULONG AllowedFileTypes,
IN ULONG RequiredFileTypes,
OUT PHARDWARE_COMPONENT HwComp,
IN ULONG ErrorId
)
{
PWSTR FilesSectionName,ConfigSectionName;
ULONG Line,Count,Line2,Count2;
BOOLEAN rc = FALSE;
PHARDWARE_COMPONENT_FILE FileList = NULL;
PHARDWARE_COMPONENT_REGISTRY RegList = NULL;
ULONG FileTypeBits = 0;
PWSTR szDisks = TXTSETUP_OEM_DISKS_U;
//
// Iterate through the files section, remembering info about the
// files to be copied in support of the selection.
//
FilesSectionName = SpMemAlloc(
((wcslen(NonlocalizedComponentName)+wcslen(SelectedId)+1)*sizeof(WCHAR))
+ sizeof(L"Files.")
);
wcscpy(FilesSectionName,L"Files.");
wcscat(FilesSectionName,NonlocalizedComponentName);
wcscat(FilesSectionName,L".");
wcscat(FilesSectionName,SelectedId);
Count = SpCountLinesInSection(TxtsetupOem,FilesSectionName);
if(Count == 0) {
SpOemInfError(ErrorId,SP_TEXT_OEM_INF_ERROR_3,FilesSectionName,0,NULL);
goto sod0;
}
for(Line=0; Line<Count; Line++) {
PWSTR Disk,Filename,Filetype,Tagfile,Description,Directory,ConfigName;
HwFileType filetype;
PHARDWARE_COMPONENT_FILE FileStruct;
//
// Get the disk specification, filename, and filetype from the line.
//
Disk = SpGetSectionLineIndex(TxtsetupOem,FilesSectionName,Line,OINDEX_DISKSPEC);
Filename = SpGetSectionLineIndex(TxtsetupOem,FilesSectionName,Line,OINDEX_FILENAME);
Filetype = SpGetKeyName(TxtsetupOem,FilesSectionName,Line);
if(!Disk || !Filename || !Filetype) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpOemInfSelection: Disk=%ws, Filename=%ws, Filetype=%ws",
Disk ? Disk : L"(null)",
Filename ? Filename : L"(null)",
Filetype ? Filetype : L"(null)"
));
SpOemInfError(ErrorId,SP_TEXT_OEM_INF_ERROR_2,FilesSectionName,Line,NULL);
SpFreeHwComponentFile(&FileList);
goto sod0;
}
//
// Parse the filetype.
//
filetype = SpFindStringInTable(FileTypeNames,Filetype);
if(filetype == HwFileMax) {
SpOemInfError(ErrorId,SP_TEXT_OEM_INF_ERROR_4,FilesSectionName,Line,NULL);
SpFreeHwComponentFile(&FileList);
goto sod0;
}
//
// Fetch the name of the section containing configuration information.
// Required if file is of type port, class, or driver.
//
if((filetype == HwFilePort) || (filetype == HwFileClass) || (filetype == HwFileDriver)) {
ConfigName = SpGetSectionLineIndex(TxtsetupOem,FilesSectionName,Line,OINDEX_CONFIGNAME);
if(ConfigName == NULL) {
SpOemInfError(ErrorId,SP_TEXT_OEM_INF_ERROR_8,FilesSectionName,Line,NULL);
SpFreeHwComponentFile(&FileList);
goto sod0;
}
} else {
ConfigName = NULL;
}
//
// Using the disk specification, look up the tagfile, description,
// and directory for the disk.
//
Tagfile = SpGetSectionKeyIndex(TxtsetupOem,szDisks,Disk,OINDEX_TAGFILE);
Description = SpGetSectionKeyIndex(TxtsetupOem,szDisks,Disk,OINDEX_DISKDESCR);
Directory = SpGetSectionKeyIndex(TxtsetupOem,szDisks,Disk,OINDEX_DIRECTORY);
if((Directory == NULL) || !wcscmp(Directory,L"\\")) {
Directory = L"";
}
if(!Tagfile || !Description) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpOemInfSelection: Tagfile=%ws, Description=%ws",
Tagfile ? Tagfile : L"(null)",
Description ? Description : L"(null)"
));
SpOemInfError(ErrorId,SP_TEXT_OEM_INF_ERROR_5,FilesSectionName,Line,NULL);
SpFreeHwComponentFile(&FileList);
goto sod0;
}
FileStruct = SpMemAlloc(sizeof(HARDWARE_COMPONENT_FILE));
RtlZeroMemory(FileStruct,sizeof(HARDWARE_COMPONENT_FILE));
SpInitHwComponentFile(
FileStruct,
Filename,
filetype,
ConfigName,
Description,
Tagfile,
Directory,
NULL
);
FileStruct->Next = FileList;
FileList = FileStruct;
if((filetype == HwFilePort) || (filetype == HwFileDriver)) {
SET_FILETYPE_PRESENT(FileTypeBits,HwFilePort);
SET_FILETYPE_PRESENT(FileTypeBits,HwFileDriver);
} else {
SET_FILETYPE_PRESENT(FileTypeBits,filetype);
}
//
// Now go look in the [Config.<ConfigName>] section for registry
// information that is to be set for this driver file.
//
if(ConfigName) {
ConfigSectionName = SpMemAlloc((wcslen(ConfigName)*sizeof(WCHAR)) + sizeof(L"Config."));
wcscpy(ConfigSectionName,L"Config.");
wcscat(ConfigSectionName,ConfigName);
Count2 = SpCountLinesInSection(TxtsetupOem,ConfigSectionName);
for(Line2=0; Line2<Count2; Line2++) {
PWSTR KeyName,ValueName,ValueType;
PHARDWARE_COMPONENT_REGISTRY Reg;
HwRegistryType valuetype;
//
// Fetch KeyName, ValueName, and ValueType from the line.
//
KeyName = SpGetSectionLineIndex(TxtsetupOem,ConfigSectionName,Line2,OINDEX_KEYNAME);
ValueName = SpGetSectionLineIndex(TxtsetupOem,ConfigSectionName,Line2,OINDEX_VALUENAME);
ValueType = SpGetSectionLineIndex(TxtsetupOem,ConfigSectionName,Line2,OINDEX_VALUETYPE);
if(!KeyName || !ValueName || !ValueType) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: SpOemInfSelection: KeyName=%ws, ValueName=%ws, ValueType=%ws",
KeyName ? KeyName : L"(null)",
ValueName ? ValueName : L"(null)",
ValueType ? ValueType : L"(null)"
));
SpOemInfError(ErrorId,SP_TEXT_OEM_INF_ERROR_2,ConfigSectionName,Line2,NULL);
SpFreeHwComponentReg(&RegList);
SpFreeHwComponentFile(&FileList);
goto sod0;
}
//
// Parse the value type and associated values.
//
valuetype = SpFindStringInTable(RegistryTypeNames,ValueType);
if(valuetype == HwRegistryMax) {
SpOemInfError(ErrorId,SP_TEXT_OEM_INF_ERROR_6,ConfigSectionName,Line2,NULL);
SpFreeHwComponentFile(&FileList);
SpFreeHwComponentReg(&RegList);
goto sod0;
}
valuetype = RegistryValueTypeMap[valuetype];
Reg = SpInterpretOemRegistryData(
TxtsetupOem,
ConfigSectionName,
Line2,
valuetype,
KeyName,
ValueName
);
if(Reg) {
Reg->Next = RegList;
RegList = Reg;
} else {
SpOemInfError(ErrorId,SP_TEXT_OEM_INF_ERROR_7,ConfigSectionName,Line2,NULL);
SpFreeHwComponentReg(&RegList);
SpFreeHwComponentFile(&FileList);
goto sod0;
}
}
FileStruct->RegistryValueList = RegList;
RegList = NULL;
SpMemFree(ConfigSectionName);
}
}
//
// Check to see whether only files of the allowed types for this component
// have been specified.
//
if((AllowedFileTypes | FileTypeBits) != AllowedFileTypes) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SppOemInfSelection: allowed files: %lx, what we've got: %lx",AllowedFileTypes,FileTypeBits));
SpOemInfError(ErrorId,SP_TEXT_OEM_INF_ERROR_9,FilesSectionName,0,NULL);
SpFreeHwComponentFile(&FileList);
goto sod0;
}
//
// Check to see whether files were specified for each required type.
//
if((RequiredFileTypes & FileTypeBits) != RequiredFileTypes) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SppOemInfSelection: required files: %lx, what we've got: %lx",RequiredFileTypes,FileTypeBits));
SpOemInfError(ErrorId,SP_TEXT_OEM_INF_ERROR_9,FilesSectionName,0,NULL);
SpFreeHwComponentFile(&FileList);
goto sod0;
}
//
// Everything is OK so we can place the information we have gathered
// into the main structure for the device class.
//
SpFreeHwComponentFile(&HwComp->Files);
SpInitHwComponent(HwComp,SelectedId,ItemDescription,TRUE,FileTypeBits,NULL,FALSE);
HwComp->Files = FileList;
rc = TRUE;
//
// Clean up and exit.
//
sod0:
SpMemFree(FilesSectionName);
return(rc);
}
VOID
SpDetectComputer(
IN PVOID SifHandle
)
{
PHARDWARE_COMPONENT pHw = HardwareComponents[HwComponentComputer];
PWSTR Description;
//
// Setupldr *must* have given us this information.
//
ASSERT(pHw);
ASSERT(pHw->Next == NULL);
//
// If the computer is a third-aprty type, the desscription
// should already be there.
//
if(pHw->ThirdPartyOptionSelected) {
ASSERT(pHw->Description);
} else {
//
// Description might already be there if the user chose
// a type we support, during setupldr phase.
//
if(pHw->Description) {
SpMemFree(pHw->Description);
}
//
// Look up the description.
//
Description = SpGetSectionKeyIndex(
SifHandle,
NonlocalizedComponentNames[HwComponentComputer],
pHw->IdString,
INDEX_DESCRIPTION
);
if(!Description) {
SpFatalSifError(
SifHandle,
NonlocalizedComponentNames[HwComponentComputer],
pHw->IdString,
0,
INDEX_DESCRIPTION
);
}
pHw->Description = SpDupStringW(Description);
}
}
VOID
SpDetectVideo(
IN PVOID SifHandle
)
{
PHARDWARE_COMPONENT VideoDevice;
VideoDevice = HardwareComponents[HwComponentDisplay];
//
// Just use what setupldr detected but we'll have to go
// fetch the description for non-oem video types.
//
if(!VideoDevice->ThirdPartyOptionSelected && !VideoDevice->Description) {
VideoDevice->Description = SpGetSectionKeyIndex(
SifHandle,
NonlocalizedComponentNames[HwComponentDisplay],
VideoDevice->IdString,
INDEX_DESCRIPTION
);
if(VideoDevice->Description) {
VideoDevice->Description = SpDupStringW(VideoDevice->Description);
} else {
SpFatalSifError(
SifHandle,
NonlocalizedComponentNames[HwComponentDisplay],
VideoDevice->IdString,
0,
INDEX_DESCRIPTION
);
}
}
//
// There should be only one video device.
//
ASSERT(VideoDevice->Next == NULL);
}
VOID
SpDetectKeyboard(
IN PVOID SifHandle
)
{
#if 0
PHARDWARE_COMPONENT KeyboardDevice;
KeyboardDevice = HardwareComponents[HwComponentKeyboard];
//
// If setupldr did any keyboard detection, ignore it
// unless it's a third-party option.
//
if(KeyboardDevice && KeyboardDevice->ThirdPartyOptionSelected) {
//
// There should be only one keyboard device.
//
ASSERT(KeyboardDevice->Next == NULL);
} else {
//
// Free the keyboard device if there is one.
//
if(KeyboardDevice) {
SpFreeHwComponent(&KeyboardDevice,TRUE);
}
KeyboardDevice = SpMemAlloc(sizeof(HARDWARE_COMPONENT));
RtlZeroMemory(KeyboardDevice,sizeof(HARDWARE_COMPONENT));
SpDetermineComponent(
SifHandle,
KeyboardDevice,
L"KeyboardPeripheral",
NULL,
L"Keyboard"
);
HardwareComponents[HwComponentKeyboard] = KeyboardDevice;
}
#endif
PHARDWARE_COMPONENT KeyboardDevice, p;
PWSTR ComponentName;
PWSTR Key;
PWSTR Description;
#if 0
for( KeyboardDevice = HardwareComponents[HwComponentKeyboard];
KeyboardDevice != NULL;
KeyboardDevice = KeyboardDevice->Next ) {
//
// Free the keyboard device if there is one.
//
if(KeyboardDevice) {
SpFreeHwComponent(&KeyboardDevice,TRUE);
}
}
#endif
KeyboardDevice = HardwareComponents[HwComponentKeyboard];
//
// Free the keyboard device if there is one.
//
if(KeyboardDevice) {
SpFreeHwComponent(&KeyboardDevice,TRUE);
}
ComponentName = NonlocalizedComponentNames[HwComponentKeyboard];
KeyboardDevice = NULL;
p = NULL;
if( UsbKeyboardDetected ) {
Key = SpDupStringW( L"kbdhid" );
if (Key) {
Description = SpGetSectionKeyIndex(SifHandle,ComponentName,Key,INDEX_DESCRIPTION);
} else {
Description = NULL;
Key = L"kbdhid";
}
if(!Description) {
SpFatalSifError(SifHandle,ComponentName,Key,0,INDEX_DESCRIPTION);
}
p = SpMemAlloc(sizeof(HARDWARE_COMPONENT));
RtlZeroMemory(p,sizeof(HARDWARE_COMPONENT));
SpInitHwComponent(p,Key,Description,FALSE,0,NULL,FALSE);
KeyboardDevice = p;
}
else if (StdKeyboardDetected) {
Key = SpDupStringW( L"STANDARD" );
if (Key) {
Description = SpGetSectionKeyIndex(SifHandle,ComponentName,Key,INDEX_DESCRIPTION);
} else {
Description = NULL;
Key = L"STANDARD";
}
if(!Description) {
SpFatalSifError(SifHandle,ComponentName,Key,0,INDEX_DESCRIPTION);
}
p = SpMemAlloc(sizeof(HARDWARE_COMPONENT));
RtlZeroMemory(p,sizeof(HARDWARE_COMPONENT));
SpInitHwComponent(p,Key,Description,FALSE,0,NULL,FALSE);
KeyboardDevice = p;
} else {
p = SpMemAlloc(sizeof(HARDWARE_COMPONENT));
if (p) {
RtlZeroMemory(p,sizeof(HARDWARE_COMPONENT));
SpDetermineComponent(
SifHandle,
p,
L"KeyboardPeripheral",
L"NO KEYBOARD",
L"Keyboard"
);
KeyboardDevice = p;
}
}
ASSERT(KeyboardDevice);
HardwareComponents[HwComponentKeyboard] = KeyboardDevice;
}
VOID
SpDetectLayout(
IN PVOID SifHandle
)
{
PHARDWARE_COMPONENT KeyboardLayout;
PWSTR IdString,Description;
KeyboardLayout = HardwareComponents[HwComponentLayout];
//
// Setupldr never chooses a layout.
//
ASSERT(KeyboardLayout == NULL);
KeyboardLayout = SpMemAlloc(sizeof(HARDWARE_COMPONENT));
RtlZeroMemory(KeyboardLayout,sizeof(HARDWARE_COMPONENT));
HardwareComponents[HwComponentLayout] = KeyboardLayout;
//
// Look up the default layout in the setup information file.
//
IdString = SpGetSectionKeyIndex(SifHandle,SIF_NLS,SIF_DEFAULTLAYOUT,0);
if(!IdString) {
SpFatalSifError(SifHandle,SIF_NLS,SIF_DEFAULTLAYOUT,0,0);
}
Description = SpGetSectionKeyIndex(
SifHandle,
NonlocalizedComponentNames[HwComponentLayout],
IdString,
INDEX_DESCRIPTION
);
if(!Description) {
SpFatalSifError(
SifHandle,
NonlocalizedComponentNames[HwComponentLayout],
IdString,
0,
INDEX_DESCRIPTION
);
}
//
// Initialize the hardware component strucutre for the layout.
//
SpInitHwComponent(KeyboardLayout,IdString,Description,FALSE,0,NULL,FALSE);
}
VOID
SpDetectMouse(
IN PVOID SifHandle
)
{
#if 0
PHARDWARE_COMPONENT MouseDevice;
//
// Setupldr does not do any mouse detection.
//
ASSERT(HardwareComponents[HwComponentMouse] == NULL);
MouseDevice = SpMemAlloc(sizeof(HARDWARE_COMPONENT));
RtlZeroMemory(MouseDevice,sizeof(HARDWARE_COMPONENT));
SpDetermineComponent(
SifHandle,
MouseDevice,
L"PointerPeripheral",
L"NO MOUSE",
L"Mouse"
);
HardwareComponents[HwComponentMouse] = MouseDevice;
#endif
PHARDWARE_COMPONENT MouseDevice, p;
PWSTR ComponentName;
PWSTR Key;
PWSTR Description;
ComponentName = NonlocalizedComponentNames[HwComponentMouse];
MouseDevice = NULL;
p = NULL;
//
// If a mouse was detected (through pnp), then add the mouse to the list
//
// none = "No Mouse or Other Pointing Device",files.none,""
// mouhid = "USB Mouse",files.mouhid,mouhid
// msser = "Microsoft Serial Mouse",files.sermouse,sermouse
// ps2 = "Mouse Port Mouse",files.i8042,i8042prt
// sermouse = "Serial Mouse",files.sermouse,sermouse
//
if( UsbMouseDetected ) {
Key = SpDupStringW( L"mouhid" );
if (Key) {
Description = SpGetSectionKeyIndex(SifHandle,ComponentName,Key,INDEX_DESCRIPTION);
} else {
Description = NULL;
Key = L"mouhid";
}
if(!Description) {
SpFatalSifError(SifHandle,ComponentName,Key,0,INDEX_DESCRIPTION);
}
p = SpMemAlloc(sizeof(HARDWARE_COMPONENT));
RtlZeroMemory(p,sizeof(HARDWARE_COMPONENT));
SpInitHwComponent(p,Key,Description,FALSE,0,NULL,FALSE);
MouseDevice = p;
} else if( SerMouseDetected ) {
Key = SpDupStringW( L"msser" );
if (Key) {
Description = SpGetSectionKeyIndex(SifHandle,ComponentName,Key,INDEX_DESCRIPTION);
} else {
Description = NULL;
Key = L"msser";
}
if(!Description) {
SpFatalSifError(SifHandle,ComponentName,Key,0,INDEX_DESCRIPTION);
}
p = SpMemAlloc(sizeof(HARDWARE_COMPONENT));
RtlZeroMemory(p,sizeof(HARDWARE_COMPONENT));
SpInitHwComponent(p,Key,Description,FALSE,0,NULL,FALSE);
p->Next = MouseDevice;
MouseDevice = p;
}
#if defined(_AMD64_) || defined(_IA64_)
else if( PS2MouseDetected ) {
Key = SpDupStringW( L"ps2" );
if (Key) {
Description = SpGetSectionKeyIndex(SifHandle,ComponentName,Key,INDEX_DESCRIPTION);
} else {
Description = NULL;
Key = L"ps2";
}
if(!Description) {
SpFatalSifError(SifHandle,ComponentName,Key,0,INDEX_DESCRIPTION);
}
p = SpMemAlloc(sizeof(HARDWARE_COMPONENT));
RtlZeroMemory(p,sizeof(HARDWARE_COMPONENT));
SpInitHwComponent(p,Key,Description,FALSE,0,NULL,FALSE);
p->Next = MouseDevice;
MouseDevice = p;
}
else
#endif // defined(_AMD64_) || defined (_IA64_)
{
//
// Now look for a mouse detected by NTDETECT.
//
p = SpMemAlloc(sizeof(HARDWARE_COMPONENT));
RtlZeroMemory(p,sizeof(HARDWARE_COMPONENT));
SpDetermineComponent(
SifHandle,
p,
L"PointerPeripheral",
L"NO MOUSE",
L"Mouse"
);
if( MouseDevice == NULL ) {
//
// If we did not any mice through pnp, then add whatever we found through NTDETECT
// (even "No Mouse"), to the mice list.
//
MouseDevice = p;
} else {
//
// Add the mouse detected through NTDETECT, if any
//
if( _wcsicmp( p->IdString, L"none" ) != 0 ) {
p->Next = MouseDevice;
MouseDevice = p;
}
}
}
ASSERT(MouseDevice);
HardwareComponents[HwComponentMouse] = MouseDevice;
}
VOID
SpDetermineComponent(
IN PVOID SifHandle,
OUT PHARDWARE_COMPONENT HwComp,
IN PWSTR HardwareDescriptionKeyName,
IN PWSTR FallbackIdentifier,
IN PWSTR ComponentName
)
/*++
Routine Description:
Make an initial determination about the type of a hardware component
(ie, perform a hardware 'detection').
The detection is performed by scanning the hardware configuration tree
for a key representing a particular hardware component, and attempting
to match its identifier string with a set of known identifier strings
(stored in the setup information file).
Arguments:
SifHandle - supplies handle for main setup information file.
HwComp - a hardware component structure that is filled in with information
about the component we find.
HardwareDescriptionKeyName - supplies the name of the key in the hardware
description (ie, the firmware configuration tree).
FallbackIdentifier - supplies the id string to use if we cannot detect
the hardware type for the component. For example, if we can't find
a PointerPeripheral (mouse), this might be "NO MOUSE."
ComponentName - supplies name of the component. This name is not translated.
Return Value:
TRUE if a match was found, FALSE otherwise.
--*/
{
PWSTR IdString;
//
// Scan the firmware configuration tree.
//
SpScanHardwareDescription(HardwareDescriptionKeyName);
if (IdStringCount && (0 == _wcsicmp(HardwareDescriptionKeyName, L"PointerPeripheral"))) {
//
// Skip the Microsoft Bus Mouse device
//
ULONG Index;
for (Index = 0; Index < IdStringCount; Index++) {
if (IdStringArray[Index] && _wcsicmp(IdStringArray[Index], MICROSOFT_BUS_MOUSE_NAME)) {
if (Index) {
PWSTR FirstId = IdStringArray[0];
IdStringArray[0] = IdStringArray[Index];
IdStringArray[Index] = FirstId;
}
break;
}
}
if (Index >= IdStringCount) {
IdStringCount = 0;
}
}
//
// Pick off the first identifier found. If no such node
// was found, then use the fallback identifier.
//
IdString = IdStringCount ? IdStringArray[0] : FallbackIdentifier;
//
// Now go scan the map section in the sif file to see whether we
// recognize the hardware described by this particular id string.
//
SpScanMapSection(SifHandle,HwComp,ComponentName,IdString);
SpFreeLocatedIdStrings();
}
BOOLEAN
SpScanMapSection(
IN PVOID SifHandle,
OUT PHARDWARE_COMPONENT HwComp,
IN PWSTR ComponentName,
IN PWSTR IdString
)
/*++
Routine Description:
Scan a 'map' section in the main sif file. A 'map' section is used to
map values seen as id strings in the firmware configuration tree t0
'shortnames' -- ie, key values that represent a particular component type.
A map section has the form, for example,
[Map.Display]
g300 = *G300
g364 = *G364
vxl = *VXL
where the values on the RHS represent possible values for the DisplayController
node in the hardware description. The values on the LHS are the keys to be used
throughout the rest of setup to represent the type of video present in the machine.
If an entry starts with a * then it need only appear as a substring of the
id string found in the firmware configuration tree; otherwise the entry and
the id string must match exactly.
There is then a section like
[Display]
g300 = "Integrated Video Controller (G300)",...
g364 = "Integrated Video Controller (G364)",...
vxl = "Integrated Jaguar Video",...
that gives additional information about the video type, like a description, etc.
This routine scans the map section for a match of a given id string found in
the firmware tree, looks up additional information about the component if a match
is found, and fills in a hardware component structure.
Arguments:
SifHandle - supplies handle for main setup information file.
HwComp - a hardware component structure that is filled in with information
about the component we find, if a match is found.
ComponentName - supplies name of the component. This name is not translated.
IdString - supplies the id string located in a key in the
firmware configuration tree.
Return Value:
TRUE if a match was found, FALSE otherwise.
--*/
{
PWSTR MapSectionName;
ULONG LineCount;
ULONG Line;
BOOLEAN b;
PWSTR Value;
PWSTR Key,Description;
if(IdString == NULL) {
IdString = L"";
}
//
// Form the name of the map section.
//
MapSectionName = SpMemAlloc((wcslen(ComponentName)*sizeof(WCHAR)) + sizeof(MAP_SECTION_NAME_PREFIX));
wcscpy(MapSectionName,MAP_SECTION_NAME_PREFIX);
wcscat(MapSectionName,ComponentName);
LineCount = SpCountLinesInSection(SifHandle,MapSectionName);
if(!LineCount) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Warning: no lines in [%ws]\n",MapSectionName));
SpMemFree(MapSectionName);
return(FALSE);
}
//
// We have a section like
//
// [Map.Display]
// vga = "VGA"
// xga = *XGA
//
// We look at each line in the section, seeing if the IdString found in the
// firmware configuration tree matches the value on the right hand side.
// If so, then we expect to find a line like, for example
//
// [Display]
// xga = "IBM XGA or XGA2"
//
for(Line=0; Line<LineCount; Line++) {
Value = SpGetSectionLineIndex(SifHandle,MapSectionName,Line,INDEX_MAP_FWID);
if(!Value) {
SpFatalSifError(SifHandle,MapSectionName,NULL,Line,INDEX_MAP_FWID);
return FALSE;
}
if(*Value == L'*') {
b = (BOOLEAN)(wcsstr(IdString,Value+1) != NULL);
} else {
b = (BOOLEAN)(wcscmp(IdString,Value) == 0);
}
if(b) {
//
// We've got a match.
//
if((Key = SpGetKeyName(SifHandle,MapSectionName,Line)) == NULL) {
SpFatalSifError(SifHandle,MapSectionName,NULL,Line,(ULONG)(-1));
}
Description = SpGetSectionKeyIndex(SifHandle,ComponentName,Key,INDEX_DESCRIPTION);
if(!Description) {
SpFatalSifError(SifHandle,ComponentName,Key,0,INDEX_DESCRIPTION);
}
SpInitHwComponent(HwComp,Key,Description,FALSE,0,NULL,FALSE);
SpMemFree(MapSectionName);
return(TRUE);
}
}
SpMemFree(MapSectionName);
return(FALSE);
}
VOID
SpScanHardwareDescription(
IN PWSTR DesiredKeyName
)
/*++
Routine Description:
Scan the hardware tree looking for subkeys of a key whose name
matches a given value.
Keys in the hardware tree do not match nodes in the arc configuration
tree exactly. In the arc configuration tree, each node has 3 attributes:
a class, a type, and a key (not the same as a registry key; an arc key
is more like an instance number or ordinal). In the TN tree, the instances
are themselves made subkeys. So something like scsi(0)disk(0)rdisk(0)
in the arc space ends up looking like
HKEY_LOCAL_MACHINE
HARDWARE
DESCRIPTION
System
ScsiAdapter
0
DiskController
0
DiskPeripheral
0
in the nt hardware description tree.
This is why we need to look for subkeys on a desired node in the arc tree --
we assume that the subkeys of, say, a PointerPeripheral key in the registry
are named "0" "1" etc and contain the ARC configuration data and id string.
Id strings in keys we locate are added to a global table, in the variables
IdStringCount and IdStringArray. The caller must free these resources by
calling SpFreeLocatedIdStrings.
Arguments:
Return Value:
--*/
{
NTSTATUS Status;
OBJECT_ATTRIBUTES Obja;
UNICODE_STRING UnicodeString;
HANDLE hKey;
//
// Initialize some globals that allow us to track identifier strings
// of devices we have located.
//
IdStringCount = 0;
IdStringArray = SpMemAlloc(0);
//
// Open the root of the hardware description tree.
//
INIT_OBJA(&Obja,&UnicodeString,L"\\Registry\\Machine\\Hardware\\Description\\System");
Status = ZwOpenKey(&hKey,KEY_READ,&Obja);
if(!NT_SUCCESS(Status)) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to open hardware description (%lx)\n",Status));
return;
}
//
// Scan the tree.
//
SpScanHardwareDescriptionWorker(hKey,L"System",DesiredKeyName);
ZwClose(hKey);
}
VOID
SpScanHardwareDescriptionWorker(
IN HANDLE KeyHandle,
IN PWSTR KeyName,
IN PWSTR DesiredKeyName
)
/*++
Routine Description:
Recursive worker routine used to do a depth-first traveral of a registry
tree rooted at a given key.
Arguments:
KeyHandle - handle for a registry tree.
KeyName - name of the key for which KeyHandle is an open handle.
This is one component long -- ie, no path separator characters appear.
DesiredKeyName - supplies the name of the key we are looking for.
Return Value:
--*/
{
ULONG SubKeyIndex;
ULONG ResultLength;
PKEY_BASIC_INFORMATION KeyInfo;
PKEY_VALUE_PARTIAL_INFORMATION ValInfo;
HANDLE hSubkey;
NTSTATUS Status;
UNICODE_STRING UnicodeString;
OBJECT_ATTRIBUTES Obja;
PWSTR SubkeyName;
KeyInfo = (PKEY_BASIC_INFORMATION)TemporaryBuffer;
ValInfo = (PKEY_VALUE_PARTIAL_INFORMATION)TemporaryBuffer;
//
// Enumerate all subkeys of the current key.
//
for( SubKeyIndex=0;
NT_SUCCESS(
ZwEnumerateKey(
KeyHandle,
SubKeyIndex,
KeyBasicInformation,
TemporaryBuffer,
sizeof(TemporaryBuffer),
&ResultLength
)
);
SubKeyIndex++ )
{
//
// Zero-terminate the subkey name just in case.
//
KeyInfo->Name[KeyInfo->NameLength/sizeof(WCHAR)] = 0;
//
// Make a duplicate of the subkey name because the name is
// in TemporaryBuffer, which might get clobbered by recursive
// calls to this routine.
//
SubkeyName = SpDupStringW(KeyInfo->Name);
if (SubkeyName) {
//
// Open this subkey.
//
INIT_OBJA(&Obja,&UnicodeString,SubkeyName);
Obja.RootDirectory = KeyHandle;
Status = ZwOpenKey(&hSubkey,KEY_READ,&Obja);
if(NT_SUCCESS(Status)) {
//
// See if the current key's name matches the type we're looking for.
//
if(!_wcsicmp(KeyName,DesiredKeyName)) {
RtlInitUnicodeString(&UnicodeString,L"Identifier");
//
// Get the identifier string,
//
Status = ZwQueryValueKey(
hSubkey,
&UnicodeString,
KeyValuePartialInformation,
TemporaryBuffer,
sizeof(TemporaryBuffer),
&ResultLength
);
if(NT_SUCCESS(Status)) {
//
// Zero-terminate the id string value just in case.
// The data is a wstring, so there shouldn't be
// any alignment problems.
//
*(PWCHAR)(ValInfo->Data + ValInfo->DataLength) = 0;
//
// Now we have the identifier string -- save it.
//
IdStringArray = SpMemRealloc(
IdStringArray,
(IdStringCount+1) * sizeof(PWSTR)
);
IdStringArray[IdStringCount++] = SpDupStringW((PWSTR)ValInfo->Data);
} else {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: Unable to get identifier string in %ws\\%ws (%lx)\n",
KeyName,
SubkeyName,
Status
));
}
} else {
//
// Enumerate this subkey's subkeys.
//
SpScanHardwareDescriptionWorker(hSubkey,SubkeyName,DesiredKeyName);
}
ZwClose(hSubkey);
} else {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: Warning: unable to open key %ws\\%ws (%lx)\n",
KeyName,SubkeyName,Status));
}
SpMemFree(SubkeyName);
}
}
}
VOID
SpFreeLocatedIdStrings(
VOID
)
{
ULONG i;
ASSERT(IdStringArray);
for(i=0; i<IdStringCount; i++) {
SpMemFree(IdStringArray[i]);
}
SpMemFree(IdStringArray);
IdStringArray = NULL;
IdStringCount = 0;
}
PHARDWARE_COMPONENT
SpSetupldrHwToHwDevice(
IN PDETECTED_DEVICE SetupldrHw
)
{
PHARDWARE_COMPONENT HwComp,HwCompPrev,HwCompFirst=NULL;
PHARDWARE_COMPONENT_FILE HwCompFile,HwCompFilePrev;
PHARDWARE_COMPONENT_REGISTRY HwCompReg,HwCompRegPrev;
PDETECTED_DEVICE_FILE SetupldrFile;
PDETECTED_DEVICE_REGISTRY SetupldrReg;
PWSTR s1,s2,s3,s4,s5;
PVOID Buffer;
ULONG BufferSize;
if (SetupldrHw==NULL) {
return(NULL);
}
HwCompPrev = NULL;
for( ; SetupldrHw; SetupldrHw=SetupldrHw->Next) {
//
// Fetch and convert the two strings from the detected device structure.
//
s1 = SpToUnicode(SetupldrHw->IdString);
#ifdef UNICODE_SETUPLDR
// cast this to avoid having to drag in tchar.h, etc.
s2 = (PWSTR)SetupldrHw->Description;
#else
s2 = SetupldrHw->Description ? SpToUnicode(SetupldrHw->Description) : NULL;
#endif
s3 = SpToUnicode(SetupldrHw->BaseDllName);
//
// Create a new hardware component structure.
//
HwComp = SpMemAlloc(sizeof(HARDWARE_COMPONENT));
RtlZeroMemory(HwComp,sizeof(HARDWARE_COMPONENT));
//
// Initialize the component structure.
//
SpInitHwComponent(
HwComp,
s1,
s2,
SetupldrHw->ThirdPartyOptionSelected,
SetupldrHw->FileTypeBits,
s3,
SetupldrHw->MigratedDriver
);
//
// Link the component structure into the list.
//
if(HwCompPrev) {
HwCompPrev->Next = HwComp;
} else {
HwCompFirst = HwComp;
}
HwCompPrev = HwComp;
//
// Free the unicode strings.
//
SpMemFree(s1);
#ifndef UNICODE_SETUPLDR
if(s2) {
SpMemFree(s2);
}
#endif
SpMemFree(s3);
//
// Create new entries for each of the hardware component's files.
//
HwCompFilePrev = NULL;
for(SetupldrFile=SetupldrHw->Files; SetupldrFile; SetupldrFile=SetupldrFile->Next) {
//
// We can't convert the ARC device name to NT device name since may may not have
// the ARC <-> NT name map fully initialized yet
//
PWSTR ArcDeviceName = SetupldrFile->ArcDeviceName ?
SpToUnicode(SetupldrFile->ArcDeviceName) : NULL;
//
// Fetch and convert the 5 strings from the detected device file structure.
//
s1 = SpToUnicode(SetupldrFile->Filename);
#ifdef UNICODE_SETUPLDR
// cast this to avoid having to drag in tchar.h, etc.
s2 = (PWSTR)SetupldrFile->DiskDescription;
#else
s2 = SpToUnicode(SetupldrFile->DiskDescription);
#endif
s3 = SpToUnicode(SetupldrFile->DiskTagfile);
s4 = SpToUnicode(SetupldrFile->Directory);
if (SetupldrFile->ConfigName != NULL) {
s5 = SpToUnicode(SetupldrFile->ConfigName);
} else {
s5 = NULL;
}
//
// Create a new hardware component file structure.
//
HwCompFile = SpMemAlloc(sizeof(HARDWARE_COMPONENT_FILE));
//
// Initialize the component file structure.
//
SpInitHwComponentFile(HwCompFile,
s1,
SetupldrFile->FileType,
s5,
s2,
s3,
s4,
ArcDeviceName
);
//
// Link the component file structure into the list.
//
if(HwCompFilePrev) {
HwCompFilePrev->Next = HwCompFile;
} else {
HwComp->Files = HwCompFile;
}
HwCompFilePrev = HwCompFile;
//
// Free the unicode strings.
//
SpMemFree(s1);
#ifndef UNICODE_SETUPLDR
SpMemFree(s2);
#endif
SpMemFree(s3);
SpMemFree(s4);
if (s5 != NULL) {
SpMemFree(s5);
}
if (ArcDeviceName) {
SpMemFree(ArcDeviceName);
}
//
// Create new entries for each registry value structure for this file.
//
HwCompRegPrev = NULL;
for( SetupldrReg=SetupldrFile->RegistryValueList;
SetupldrReg;
SetupldrReg=SetupldrReg->Next)
{
//
// Make a duplicate of the buffer.
// Special case REG_SZ, REG_EXPAND_SZ and REG_MULTI_SZ values because
// we need to convert then to unicode.
//
if(SetupldrReg->ValueType == REG_SZ || SetupldrReg->ValueType == REG_EXPAND_SZ) {
Buffer = SpToUnicode(SetupldrReg->Buffer);
BufferSize = (wcslen(Buffer) + 1) * sizeof(WCHAR);
} else {
if(SetupldrReg->ValueType == REG_MULTI_SZ) {
PUCHAR p;
ULONG len;
//
// Determine the size of the buffer needed to hold the unicode
// equivalent of the multi_sz. Assume all characters are
// single-byte and thus the size exactly doubles.
//
for(BufferSize=sizeof(WCHAR),p=SetupldrReg->Buffer; *p; ) {
len = strlen(p) + 1;
BufferSize += len * sizeof(WCHAR);
p += len;
}
Buffer = SpMemAlloc(BufferSize);
//
// Convert each string in the multi_sz to unicode
// and place in the resulting unicode multi_sz.
//
for(s1=Buffer,p=SetupldrReg->Buffer; *p; ) {
s2 = SpToUnicode(p);
wcscpy(s1,s2);
SpMemFree(s2);
p += strlen(p) + 1;
s1 += wcslen(s1) + 1;
}
//
// Final terminating nul in the multi_sz.
//
*s1++ = 0;
//
// Reallocate the buffer. If some of the characters
// were double-byte, the buffer will be smaller than
// the maximum size we allocated above.
//
BufferSize = (ULONG)((PUCHAR)s1 - (PUCHAR)Buffer);
Buffer = SpMemRealloc(Buffer,BufferSize);
} else {
BufferSize = SetupldrReg->BufferSize;
Buffer = SpMemAlloc(BufferSize);
ASSERT(Buffer);
RtlMoveMemory(Buffer,SetupldrReg->Buffer,BufferSize);
}
}
//
// Fetch and convert the 2 strings from the detected device
// registry value structure.
//
s1 = SpToUnicode(SetupldrReg->KeyName);
s2 = SpToUnicode(SetupldrReg->ValueName);
//
// Create a new registry value structure.
//
HwCompReg = SpMemAlloc(sizeof(HARDWARE_COMPONENT_REGISTRY));
//
// Initialize the component registry value structure.
//
SpInitHwComponentRegVal(
HwCompReg,
s1,
s2,
SetupldrReg->ValueType,
Buffer,
BufferSize
);
//
// Link the component registry value structure into the list.
//
if(HwCompRegPrev) {
HwCompRegPrev->Next = HwCompReg;
} else {
HwCompFile->RegistryValueList = HwCompReg;
}
HwCompRegPrev = HwCompReg;
//
// Free the unicode strings.
//
SpMemFree(s1);
SpMemFree(s2);
}
}
}
return(HwCompFirst);
}
VOID
SpInitHwComponent(
OUT PHARDWARE_COMPONENT HwComp,
IN PWSTR IdString,
IN PWSTR Description,
IN BOOLEAN ThirdPartyOption,
IN ULONG FileTypeBits,
IN PWSTR BaseDllName,
IN BOOLEAN MigratedDriver
)
/*++
Routine Description:
Initialize the fields of a HARDWARE_COMPONENT structure.
Before initializing the fields, ther IdString and Description
strings are freed if they are present in the given hardware
component structure.
All string values are duplicated by this routine so the caller
may free them without worrying about ruining the hardware component
structure.
Arguments:
IdString - supplies a nul-terminated unicode string for the
IdString field of the structure. May be NULL.
Description - supplies a nul-terminated unicode string for the
Description field pf the structure. May be NULL.
ThirdPartyOption - supplies value of the ThirdPartyOptionSelected
field of the strcture.
FileTypeBits - supplies value for the FileTypeBits field
of the structure.
Return Value:
None.
--*/
{
if(HwComp->IdString) {
SpMemFree(HwComp->IdString);
}
if(HwComp->Description) {
SpMemFree(HwComp->Description);
}
if(HwComp->BaseDllName) {
SpMemFree(HwComp->BaseDllName);
}
RtlZeroMemory(HwComp,sizeof(HARDWARE_COMPONENT));
if(IdString) {
HwComp->IdString = SpDupStringW(IdString);
}
if(Description) {
HwComp->Description = SpDupStringW(Description);
}
if(BaseDllName) {
HwComp->BaseDllName = SpDupStringW(BaseDllName);
}
HwComp->ThirdPartyOptionSelected = ThirdPartyOption;
HwComp->FileTypeBits = FileTypeBits;
HwComp->MigratedDriver = MigratedDriver;
}
VOID
SpFreeHwComponent(
IN OUT PHARDWARE_COMPONENT *HwComp,
IN BOOLEAN FreeAllInList
)
{
PHARDWARE_COMPONENT hwComp,Next;
for(hwComp = *HwComp; hwComp; hwComp=(FreeAllInList ? Next : NULL)) {
SpFreeHwComponentFile(&hwComp->Files);
if(hwComp->IdString) {
SpMemFree(hwComp->IdString);
}
if(hwComp->Description) {
SpMemFree(hwComp->Description);
}
if(hwComp->BaseDllName) {
SpMemFree(hwComp->BaseDllName);
}
Next = hwComp->Next;
SpMemFree(hwComp);
}
*HwComp = NULL;
}
VOID
SpFreeHwComponentFile(
IN OUT PHARDWARE_COMPONENT_FILE *HwCompFile
)
/*++
Routine Description:
Free a hardware component file list and all resources used by it,
including any registry value structures associated with the file
and resources used by such structgures.
Arguments:
HwCompFile - supplies pointer to pointer to the first hardware
component file structure in a linked list.
Return Value:
None. HwCompFile is filled in with NULL to prevent the caller
from retaining a 'dangling' pointer to memory that has been freed.
--*/
{
PHARDWARE_COMPONENT_FILE hwCompFile,NextFile;
for(hwCompFile = *HwCompFile ; hwCompFile; hwCompFile=NextFile) {
if(hwCompFile->Filename) {
SpMemFree(hwCompFile->Filename);
}
if(hwCompFile->ConfigName) {
SpMemFree(hwCompFile->ConfigName);
}
if(hwCompFile->DiskDescription) {
SpMemFree(hwCompFile->DiskDescription);
}
if(hwCompFile->DiskTagFile) {
SpMemFree(hwCompFile->DiskTagFile);
}
if(hwCompFile->Directory) {
SpMemFree(hwCompFile->Directory);
}
//
// Free registry values as well.
//
SpFreeHwComponentReg(&hwCompFile->RegistryValueList);
NextFile = hwCompFile->Next;
SpMemFree(hwCompFile);
}
*HwCompFile = NULL;
}
VOID
SpInitHwComponentFile(
OUT PHARDWARE_COMPONENT_FILE HwCompFile,
IN PWSTR Filename,
IN HwFileType FileType,
IN PWSTR ConfigName,
IN PWSTR DiskDescription,
IN PWSTR DiskTagFile,
IN PWSTR Directory,
IN PWSTR ArcDeviceName
)
/*++
Routine Description:
Initialize the fields of a HARDWARE_COMPONENT_FILE structure.
All string values are duplicated by this routine so the caller
may free them without worrying about ruining the
hardware component file structure.
Arguments:
Filename - supplies a nul-terminated unicode string for the
Filename field of the structure. May be NULL.
FileType - supplies value for the FileType field of the structure.
ConfigName - supplies a nul-terminated unicode string for the
ConfigName field of the structure. May be NULL.
DiskDescription - supplies a nul-terminated unicode string for the
DiskDescription field of the structure. May be NULL.
DiskTagFile - supplies a nul-terminated unicode string for the
DiskTagFile field of the structure. May be NULL.
Directory - supplies a nul-terminated unicode string for the
Directory field of the structure. May be NULL.
ArcDeviceName - supplies the arc device name where the file
resides.
Return Value:
None.
--*/
{
RtlZeroMemory(HwCompFile,sizeof(HARDWARE_COMPONENT_FILE));
if(Filename) {
HwCompFile->Filename = SpDupStringW(Filename);
}
HwCompFile->FileType = FileType;
if(ConfigName) {
HwCompFile->ConfigName = SpDupStringW(ConfigName);
}
if(DiskDescription) {
HwCompFile->DiskDescription = SpDupStringW(DiskDescription);
}
if(DiskTagFile) {
HwCompFile->DiskTagFile = SpDupStringW(DiskTagFile);
}
if(Directory) {
HwCompFile->Directory = SpDupStringW(Directory);
}
if (ArcDeviceName) {
HwCompFile->ArcDeviceName = SpDupStringW(ArcDeviceName);
}
}
VOID
SpFreeHwComponentReg(
IN OUT PHARDWARE_COMPONENT_REGISTRY *HwCompReg
)
/*++
Routine Description:
Free a hardware component registry value list and all resources
used by it.
Arguments:
HwCompReg - supplies pointer to pointer to the first hardware
component registry value structure in a linked list.
Return Value:
None. HwCompReg is filled in with NULL to prevent the caller
from retaining a 'dangling' pointer to memory that has been freed.
--*/
{
PHARDWARE_COMPONENT_REGISTRY hwCompReg,NextReg;
for(hwCompReg = *HwCompReg ; hwCompReg; hwCompReg=NextReg) {
if(hwCompReg->KeyName) {
SpMemFree(hwCompReg->KeyName);
}
if(hwCompReg->ValueName) {
SpMemFree(hwCompReg->ValueName);
}
if(hwCompReg->Buffer) {
SpMemFree(hwCompReg->Buffer);
}
NextReg = hwCompReg->Next;
SpMemFree(hwCompReg);
}
*HwCompReg = NULL;
}
VOID
SpInitHwComponentRegVal(
OUT PHARDWARE_COMPONENT_REGISTRY HwCompReg,
IN PWSTR KeyName,
IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID Buffer,
IN ULONG BufferSize
)
/*++
Routine Description:
Initialize the fields of a HARDWARE_COMPONENT_REGISTRY structure.
All string values are duplicated by this routine so the caller
may free them without worrying about ruining the
hardware component file structure.
Arguments:
KeyName - supplies a nul-terminated unicode string for the
KeyName field of the structure. May be NULL.
ValueName - supplies a nul-terminated unicode string for the
ValueName field of the structure. May be NULL.
ValueType - supplies value for the ValueType field of the structure.
Buffer - supplies value for the Buffer field of the structure.
BufferSize - supplies value for the BufferSize field of the structure.
Return Value:
None.
--*/
{
RtlZeroMemory(HwCompReg,sizeof(HARDWARE_COMPONENT_REGISTRY));
if(KeyName) {
HwCompReg->KeyName = SpDupStringW(KeyName);
}
if(ValueName) {
HwCompReg->ValueName = SpDupStringW(ValueName);
}
HwCompReg->ValueType = ValueType;
HwCompReg->Buffer = Buffer;
HwCompReg->BufferSize = BufferSize;
}
PHARDWARE_COMPONENT_REGISTRY
SpInterpretOemRegistryData(
IN PVOID SifHandle,
IN PWSTR SectionName,
IN ULONG Line,
IN ULONG ValueType,
IN PWSTR KeyName,
IN PWSTR ValueName
)
{
PHARDWARE_COMPONENT_REGISTRY Reg;
PWSTR Value;
unsigned i,len;
ULONG Dword;
ULONG BufferSize;
PVOID Buffer = NULL;
PWSTR BufferWstr;
WCHAR str[3];
//
// Perform appropriate action based on the type
//
switch(ValueType) {
case REG_DWORD:
Value = SpGetSectionLineIndex(SifHandle,SectionName,Line,OINDEX_FIRSTVALUE);
if(Value == NULL) {
goto x1;
}
//
// Make sure it's really a hex number
//
len = wcslen(Value);
if(len > 8) {
goto x1;
}
for(i=0; i<len; i++) {
if(!SpIsXDigit(Value[i])) {
goto x1;
}
}
//
// convert it from unicode to a hex number
//
Dword = (ULONG)SpStringToLong(Value,NULL,16);
//
// Allocate a 4-byte buffer and store the dword in it
//
Buffer = SpMemAlloc(BufferSize = sizeof(ULONG));
*(PULONG)Buffer = Dword;
break;
case REG_SZ:
case REG_EXPAND_SZ:
Value = SpGetSectionLineIndex(SifHandle,SectionName,Line,OINDEX_FIRSTVALUE);
if(Value == NULL) {
goto x1;
}
//
// Allocate a buffer of appropriate size for the string
//
Buffer = SpDupStringW(Value);
BufferSize = (wcslen(Value)+1) * sizeof(WCHAR);
break;
case REG_BINARY:
Value = SpGetSectionLineIndex(SifHandle,SectionName,Line,OINDEX_FIRSTVALUE);
if(Value == NULL) {
goto x1;
}
//
// Figure out how many byte values are specified
//
len = wcslen(Value);
if(len & 1) {
goto x1; // odd # of characters
}
//
// Allocate a buffer to hold the byte values
//
Buffer = SpMemAlloc(BufferSize = len / 2);
//
// For each digit pair, convert to a hex number and store in the
// buffer
//
str[2] = 0;
for(i=0; i<len; i+=2) {
//
// SpIsXDigit evaluates args more than once so break out assignments.
//
str[0] = SpToUpper(Value[i]);
str[1] = SpToUpper(Value[i+1]);
if(!SpIsXDigit(str[0]) || !SpIsXDigit(str[1])) {
goto x1;
}
((PUCHAR)Buffer)[i/2] = (UCHAR)SpStringToLong(str,NULL,16);
}
break;
case REG_MULTI_SZ:
//
// Calculate size of the buffer needed to hold all specified strings
//
for(BufferSize=sizeof(WCHAR),i=0;
Value = SpGetSectionLineIndex(SifHandle,SectionName,Line,OINDEX_FIRSTVALUE+i);
i++)
{
BufferSize += (wcslen(Value)+1) * sizeof(WCHAR);
}
//
// Allocate a buffer of appropriate size
//
Buffer = SpMemAlloc(BufferSize);
BufferWstr = Buffer;
//
// Store each string in the buffer, converting to wide char format
// in the process
//
for(i=0;
Value = SpGetSectionLineIndex(SifHandle,SectionName,Line,OINDEX_FIRSTVALUE+i);
i++)
{
wcscpy(BufferWstr,Value);
BufferWstr += wcslen(Value) + 1;
}
//
// Place final terminating widechar nul in the buffer
//
*BufferWstr = 0;
break;
default:
x1:
//
// Error - bad type specified or maybe we detected bad data values
// and jumped here
//
if(Buffer) {
SpMemFree(Buffer);
}
return(NULL);
}
Reg = SpMemAlloc(sizeof(HARDWARE_COMPONENT_REGISTRY));
SpInitHwComponentRegVal(Reg,KeyName,ValueName,ValueType,Buffer,BufferSize);
return(Reg);
}
VOID
SpDetectScsi(
IN PVOID SifHandle,
IN PWSTR SourceDevicePath,
IN PWSTR DirectoryOnSourceDevice
)
{
BOOLEAN DetectScsi;
BOOLEAN b;
ULONG DriverLoadCount;
ULONG d;
NTSTATUS Status;
PWSTR DriverDescription,DriverFilename;
PWSTR DriverShortname,DiskDesignator;
PHARDWARE_COMPONENT scsi,Prev;
PWSTR PreviousDiskDesignator;
//
// Determine the name of the scsi section.
// This is a remnant from the time when we had separate
// lists for isa, eisa, and mca machines.
//
ScsiSectionName = SpDupStringW(L"SCSI");
ScsiLoadSectionName = SpDupStringW(L"SCSI.Load");
LoadedScsiMiniportCount = 0;
//
// If scsi drivers have already been loaded, assume setupldr
// did the detection and skip the scsi confirmation screen.
//
if(SetupParameters.LoadedScsi) {
DetectScsi = FALSE;
//
// Fill in descriptions, ignoring what setupldr may have put in
// the device descriptor.
//
for(scsi=ScsiHardware; scsi; scsi=scsi->Next) {
if(scsi->ThirdPartyOptionSelected) {
ASSERT(scsi->Description);
if(!scsi->Description) {
}
} else if(scsi->MigratedDriver) {
if(scsi->Description) {
SpMemFree(scsi->Description);
}
SpFormatMessage( TemporaryBuffer,
sizeof(TemporaryBuffer),
SP_TEXT_MIGRATED_DRIVER,
scsi->BaseDllName );
scsi->Description = SpDupStringW( TemporaryBuffer );
} else {
if(scsi->Description) {
SpMemFree(scsi->Description);
}
scsi->Description = SpGetSectionKeyIndex(
SifHandle,
ScsiSectionName,
scsi->IdString,
INDEX_DESCRIPTION
);
if(!scsi->Description) {
SpFatalSifError(SifHandle,ScsiSectionName,scsi->IdString,0,INDEX_DESCRIPTION);
}
}
}
} else {
//
// Scsi drivers have not been loaded.
// Assume we need to perform detection and confirmation here.
//
//
// If this is a custom setup, ask the user if he wants to skip detection.
// We do this because loading some miniports can whack the hardware such
// that the machine hangs.
//
if(CustomSetup) {
ULONG ValidKeys[3] = { KEY_F3,ASCI_CR,0 };
ULONG Mnemonics[2] = { MnemonicSkipDetection,0 };
do {
SpDisplayScreen(SP_SCRN_CONFIRM_SCSI_DETECT,3,HEADER_HEIGHT+1);
SpDisplayStatusOptions(
DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_F3_EQUALS_EXIT,
SP_STAT_ENTER_EQUALS_CONTINUE,
SP_STAT_S_EQUALS_SKIP_DETECTION,
0
);
switch(SpWaitValidKey(ValidKeys,NULL,Mnemonics)) {
case KEY_F3:
SpConfirmExit();
b = TRUE;
break;
case ASCI_CR:
DetectScsi = TRUE;
b = FALSE;
break;
default:
//
// Must be MnemonicSkipDetection.
//
DetectScsi = FALSE;
b = FALSE;
break;
}
} while(b);
} else {
//
// Express Setup; always detect scsi.
//
DetectScsi = TRUE;
}
}
//
// If we are supposed to detect scsi, do that here.
// We will 'detect' scsi by loading scsi miniport drivers.
//
if(DetectScsi) {
ASSERT(ScsiHardware == NULL);
CLEAR_CLIENT_SCREEN();
//
// Determine the number of drivers to be loaded.
//
PreviousDiskDesignator = L"";
Prev = NULL;
DriverLoadCount = SpCountLinesInSection(SifHandle,ScsiLoadSectionName);
for(d=0; (d<DriverLoadCount) && (LoadedScsiMiniportCount < MAX_SCSI_MINIPORT_COUNT); d++) {
PWSTR p;
//
// Determine whether we are really supposed to load this driver.
//
if((p = SpGetSectionLineIndex(SifHandle,ScsiLoadSectionName,d,2)) && !_wcsicmp(p,L"noload")) {
continue;
}
//
// Get the driver shortname.
//
DriverShortname = SpGetKeyName(SifHandle,ScsiLoadSectionName,d);
if(!DriverShortname) {
SpFatalSifError(SifHandle,ScsiLoadSectionName,NULL,d,(ULONG)(-1));
}
//
// Get parameters used to load the driver.
//
SpGetDriverValuesForLoad(
SifHandle,
ScsiSectionName,
ScsiLoadSectionName,
DriverShortname,
&DriverFilename,
&DiskDesignator,
&DriverDescription
);
//
// Prompt for the disk containing the driver.
//
retryload:
if(_wcsicmp(DiskDesignator,PreviousDiskDesignator)) {
ULONG i;
SpPromptForSetupMedia(
SifHandle,
DiskDesignator,
SourceDevicePath
);
//
// Redraw the found list.
//
CLEAR_CLIENT_SCREEN();
for(i=0,scsi=ScsiHardware; scsi; scsi=scsi->Next,i++) {
SpDisplayFormattedMessage(
SP_TEXT_FOUND_ADAPTER,
FALSE,
FALSE,
DEFAULT_ATTRIBUTE,
4,
HEADER_HEIGHT+4+i,
scsi->Description
);
}
PreviousDiskDesignator = DiskDesignator;
}
//
// Attempt to load the driver.
//
Status = SpLoadDeviceDriver(
DriverDescription,
SourceDevicePath,
DirectoryOnSourceDevice,
DriverFilename
);
//
// If the driver loaded, remember it.
//
if(NT_SUCCESS(Status)) {
SpDisplayFormattedMessage(
SP_TEXT_FOUND_ADAPTER,
FALSE,
FALSE,
DEFAULT_ATTRIBUTE,
4,
HEADER_HEIGHT+4+LoadedScsiMiniportCount,
DriverDescription
);
LoadedScsiMiniportCount++;
scsi = SpMemAlloc(sizeof(HARDWARE_COMPONENT));
RtlZeroMemory(scsi,sizeof(HARDWARE_COMPONENT));
SpInitHwComponent(scsi,DriverShortname,DriverDescription,FALSE,0,NULL,FALSE);
//
// Link the hardware description into the list.
//
if(Prev) {
Prev->Next = scsi;
} else {
ScsiHardware = scsi;
}
Prev = scsi;
} else {
if(Status == STATUS_NO_MEDIA_IN_DEVICE) {
PreviousDiskDesignator = L"";
goto retryload;
}
}
}
} else {
//
// Count the number of loaded miniport drivers.
//
for(scsi=ScsiHardware; scsi; scsi=scsi->Next) {
LoadedScsiMiniportCount++;
}
}
}
VOID
SpConfirmScsiInteract(
IN PVOID SifHandle,
IN PWSTR SourceDevicePath,
IN PWSTR DirectoryOnSourceDevice
)
{
ULONG ValidKeys[3] = { ASCI_CR, KEY_F3, 0 };
ULONG Mnemonics[2] = { MnemonicScsiAdapters,0 };
ULONG ListTopY;
PHARDWARE_COMPONENT scsi;
ULONG i;
BOOLEAN ScsiConfirmed;
BOOLEAN b;
BOOLEAN AddDriver;
NTSTATUS Status;
#define SCSI_LIST_LEFT_X 7
//
// In unattended mode, we might skip this
// depending on the unattended script.
//
if(UnattendedOperation) {
if( !PreInstall ) {
PWSTR p;
p = SpGetSectionKeyIndex(
UnattendedSifHandle,
SIF_UNATTENDED,
SIF_CONFIRMHW,
0
);
//
// If not specified or specified and not "yes"
// then return.
//
if(!p || _wcsicmp(p,L"yes")) {
return;
}
} else {
return;
}
} else if (LoadedScsiMiniportCount) {
return;
}
ScsiConfirmed = FALSE;
do {
//
// First part of the screen.
//
SpDisplayScreen(SP_SCRN_SCSI_LIST_1,3,HEADER_HEIGHT+1);
//
// Remember where the first part of the screen ends.
//
ListTopY = NextMessageTopLine + 2;
//
// Second part of the screen.
//
SpContinueScreen(
SP_SCRN_SCSI_LIST_2,
3,
MAX_SCSI_MINIPORT_COUNT+6,
FALSE,
DEFAULT_ATTRIBUTE
);
//
// Display each loaded miniport driver description.
//
if(ScsiHardware) {
for(i=0,scsi=ScsiHardware; scsi; scsi=scsi->Next,i++) {
if(i == MAX_SCSI_MINIPORT_COUNT) {
SpvidDisplayString(
L"...",
DEFAULT_ATTRIBUTE,
SCSI_LIST_LEFT_X,
ListTopY+i
);
break;
}
SpvidDisplayString(
scsi->Description,
DEFAULT_ATTRIBUTE,
SCSI_LIST_LEFT_X,
ListTopY+i
);
}
} else {
SpDisplayFormattedMessage(
SP_TEXT_ANGLED_NONE,
FALSE,
FALSE,
DEFAULT_ATTRIBUTE,
SCSI_LIST_LEFT_X,
ListTopY
);
}
//
// display status text options.
//
SpDisplayStatusOptions(
DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_S_EQUALS_SCSI_ADAPTER,
SP_STAT_ENTER_EQUALS_CONTINUE,
SP_STAT_F3_EQUALS_EXIT,
0
);
//
// Wait for the user to press a valid key.
//
switch(SpWaitValidKey(ValidKeys,NULL,Mnemonics)) {
case ASCI_CR:
ScsiConfirmed = TRUE;
break;
case KEY_F3:
SpConfirmExit();
break;
default:
//
// Must be s=specify additional adapter.
//
AddDriver = FALSE;
scsi = SpMemAlloc(sizeof(HARDWARE_COMPONENT));
RtlZeroMemory(scsi,sizeof(HARDWARE_COMPONENT));
b = SpSelectHwItem(
SifHandle,
ScsiSectionName,
L"Scsi",
SP_SCRN_SELECT_SCSI,
SP_SCRN_SELECT_OEM_SCSI,
SCSI_ALLOWED_FILETYPES,
SCSI_REQUIRED_FILETYPES,
scsi
);
if(b) {
//
// User made a selection. Determine whether that scsi adapter
// is already on the list for instllation.
//
PHARDWARE_COMPONENT p;
b = FALSE;
for(p=ScsiHardware; p; p=p->Next) {
if((p->ThirdPartyOptionSelected == scsi->ThirdPartyOptionSelected)
&& !_wcsicmp(p->IdString,scsi->IdString))
{
b = TRUE;
break;
}
}
if(b) {
//
// The driver is already loaded -- silently ignore the user's selection.
//
#if 0
//
// This driver is already loaded -- tell the user.
//
SpDisplayScreen(SP_SCRN_SCSI_ALREADY_LOADED,3,HEADER_HEIGHT+1);
SpDisplayStatusOptions(
DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_ENTER_EQUALS_CONTINUE,
0
);
SpInputDrain();
while(SpInputGetKeypress() != ASCI_CR) ;
#endif
} else {
PWSTR DiskDevicePath;
PWSTR DirectoryOnDisk;
PWSTR DriverFilename;
PWSTR Media;
//
// The driver is not loaded. Atempt to load it.
//
if(scsi->ThirdPartyOptionSelected) {
PHARDWARE_COMPONENT_FILE fil;
//
// Locate the first file of type driver or port.
//
for(fil=scsi->Files; fil; fil=fil->Next) {
if((fil->FileType == HwFileDriver) || (fil->FileType == HwFilePort)) {
DirectoryOnDisk = fil->Directory;
DriverFilename = fil->Filename;
break;
}
}
DiskDevicePath = L"\\device\\floppy0";
} else {
DiskDevicePath = SourceDevicePath;
DirectoryOnDisk = DirectoryOnSourceDevice;
SpGetDriverValuesForLoad(
SifHandle,
ScsiSectionName,
ScsiLoadSectionName,
scsi->IdString,
&DriverFilename,
&Media,
NULL
);
SpPromptForSetupMedia(
SifHandle,
Media,
DiskDevicePath
);
}
CLEAR_CLIENT_SCREEN();
Status = SpLoadDeviceDriver(
scsi->Description,
DiskDevicePath,
DirectoryOnDisk,
DriverFilename
);
//
// If the driver did not load, tell the user.
//
if(NT_SUCCESS(Status)) {
AddDriver = TRUE;
} else {
SpDisplayScreen(SP_SCRN_SCSI_DIDNT_LOAD,3,HEADER_HEIGHT+1);
SpDisplayStatusOptions(
DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_ENTER_EQUALS_CONTINUE,
0
);
SpInputDrain();
while(SpInputGetKeypress() != ASCI_CR) ;
}
}
}
if(AddDriver) {
if(ScsiHardware) {
PHARDWARE_COMPONENT p = ScsiHardware;
while(p->Next) {
p = p->Next;
}
p->Next = scsi;
} else {
ScsiHardware = scsi;
}
LoadedScsiMiniportCount++;
} else {
SpFreeHwComponent(&scsi,TRUE);
}
break;
}
} while(!ScsiConfirmed);
}
VOID
SpGetDriverValuesForLoad(
IN PVOID SifHandle,
IN PWSTR ComponentSectionName,
IN PWSTR ComponentLoadSectionName,
IN PWSTR Shortname,
OUT PWSTR *Filename,
OUT PWSTR *MediaDesignator,
OUT PWSTR *Description OPTIONAL
)
{
PWSTR description,mediaDesignator,filename;
//
// Get the filename associated with this load option.
//
filename = SpGetSectionKeyIndex(SifHandle,ComponentLoadSectionName,Shortname,0);
if(!filename) {
SpFatalSifError(SifHandle,ComponentLoadSectionName,Shortname,0,0);
}
//
// Look up the description in the component section.
//
description = SpGetSectionKeyIndex(
SifHandle,
ComponentSectionName,
Shortname,
INDEX_DESCRIPTION
);
if(!description) {
SpFatalSifError(SifHandle,ComponentSectionName,Shortname,0,INDEX_DESCRIPTION);
}
//
// Look up the media designator. If we are loading the driver for use
// during setup, we want to get it from the setup boot media.
//
mediaDesignator = SpLookUpValueForFile(SifHandle,filename,INDEX_WHICHBOOTMEDIA,TRUE);
//
// Pass information back to caller.
//
*Filename = filename;
*MediaDesignator = mediaDesignator;
if(Description) {
*Description = description;
}
}
BOOLEAN
SpInstallingMp(
VOID
)
{
PWSTR ComputerId;
ULONG ComputerIdLen;
ComputerId = HardwareComponents[HwComponentComputer]->IdString;
ComputerIdLen = wcslen(ComputerId);
//
// If _up is specified use the up kernel. Otherwise use the mp kernel.
//
if((ComputerIdLen >= 3) && !_wcsicmp(ComputerId+ComputerIdLen-3,L"_mp")) {
return(TRUE);
}
return(FALSE);
}
PHARDWARE_COMPONENT
SpGetPreinstallComponentInfo(
IN HANDLE MasterSifHandle,
IN BOOLEAN OemComponent,
IN PWSTR ComponentName,
IN PWSTR Description,
IN ULONG AllowedFileTypes,
IN ULONG RequiredFileTypes
)
/*++
Routine Description:
Initialize a structure that contains the information about a
component to be pre-installed.
Arguments:
MasterSifHandle - Handle to txtsetup.sif.
OemComponent - Flag that indicates if the component to be pre-installed
is an OEM or retail component.
ComponentName - Name of the component whose information will be retrieved
(Computer, Display, Keyboard, Keyboard Layout and Mouse ).
AllowedFileTypes -
RequiredFileTypes -
Return Value:
Returns a pointer to an initialized HARDWARE_COMPONENT structure.
--*/
{
PHARDWARE_COMPONENT TempHwComponent;
PWSTR IdString;
ULONG ValidKeys[2] = { KEY_F3,0 };
TempHwComponent = SpMemAlloc(sizeof(HARDWARE_COMPONENT));
RtlZeroMemory(TempHwComponent,sizeof(HARDWARE_COMPONENT));
if( !OemComponent ) {
//
// Pre-install a retail component
//
IdString = SpGetKeyNameByValue( MasterSifHandle,
ComponentName,
Description );
if( IdString == NULL ) {
//
// This is a fatal error
//
SpStartScreen( SP_SCRN_OEM_PREINSTALL_VALUE_NOT_FOUND,
3,
HEADER_HEIGHT+3,
FALSE,
FALSE,
DEFAULT_ATTRIBUTE,
Description,
ComponentName);
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_F3_EQUALS_EXIT,0);
SpWaitValidKey(ValidKeys,NULL,NULL);
SpDone(0,FALSE,TRUE);
return NULL; // for prefix
}
SpInitHwComponent(TempHwComponent,IdString,Description,FALSE,0,NULL,FALSE);
} else {
//
// Pre-install an OEM component
//
IdString = SpGetKeyNameByValue( PreinstallOemSifHandle,
ComponentName,
Description );
if( IdString == NULL ) {
//
// Put a fatal error message indicating that txtsetup.oem
// is needed but that it couldn't be loaded. Note that the
// that SpOemInfError() will not return.
//
SpOemInfError(SP_SCRN_OEM_PREINSTALL_INF_ERROR,
SP_TEXT_OEM_INF_ERROR_B,
ComponentName,
0,
Description);
// SpDone(0,FALSE,TRUE);
}
if( !SpOemInfSelection( PreinstallOemSifHandle,
ComponentName,
IdString,
Description,
AllowedFileTypes,
RequiredFileTypes,
TempHwComponent,
SP_SCRN_OEM_PREINSTALL_INF_ERROR ) ) {
//
// This case shoud never occur, becase in case of error,
// SpOemInfSelection will not return.
//
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpOemInfSelection() in pre-install mode failed \n" ));
ASSERT(FALSE);
// SpDone(0,FALSE,TRUE);
}
}
return( TempHwComponent );
}
VOID
SpInitializePreinstallList(
IN HANDLE MasterSifHandle,
IN PWSTR SetupSourceDevicePath,
IN PWSTR OemPreinstallSourcePath
)
/*++
Routine Description:
Initialize the structures that contains the information about the
components to be pre-installed.
Arguments:
MasterSifHandle - Handle to txtsetup.sif.
SetupSourceDevicePath - Path to the device that contains the source media.
OemDirectoryOnSourceDevice - Directory on the media where the OEM
components are loacted.
Return Value:
NONE.
--*/
{
PWSTR TxtsetupOemPath;
PWSTR p;
PWSTR OemTag = L"OEM";
BOOLEAN OemComponent;
NTSTATUS Status;
PHARDWARE_COMPONENT TempHwComponent;
PWSTR IdString;
PWSTR Description;
ULONG ErrorLine;
ULONG i,j;
#if defined(_AMD64_) || defined(_X86_)
PWSTR r, s;
#endif // defined(_AMD64_) || defined(_X86_)
#if defined(_AMD64_) || defined(_X86_)
//
// First, we need to check if the directory '\$' exists on the root.
// if it does, we need to move it to (\$win_nt$.~ls\$OEM$).
// This will happen only when winnt.exe (DOS) was used in the installation
// process.
// Winnt.exe copies the $OEM$ to the '\$', in order to avoid hitting the
// DOS limitiation for the length of a path (maximum of 64 characters).
//
wcscpy(TemporaryBuffer, SetupSourceDevicePath);
SpConcatenatePaths( TemporaryBuffer, WINNT_OEM_DEST_DIR_W );
r = SpDupStringW(TemporaryBuffer);
if (r) {
if( SpFileExists( r, TRUE ) ) {
wcscpy(TemporaryBuffer, SetupSourceDevicePath);
SpConcatenatePaths( TemporaryBuffer, PreinstallOemSourcePath );
s = wcsrchr( TemporaryBuffer, (WCHAR)'\\' );
if( s != NULL ) {
*s = (WCHAR)'\0';
}
s = SpDupStringW(TemporaryBuffer);
if (s) {
Status = SpMoveFileOrDirectory( r, s );
SpMemFree( s );
} else {
Status = STATUS_NO_MEMORY;
}
if( !NT_SUCCESS( Status ) ) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
"SETUP: Unable to move directory %ws to %ws. Status = %lx \n",
r, s, Status ));
}
}
SpMemFree( r );
}
#endif // defined(_AMD64_) || defined(_X86_)
//
// Attempt to load txtsetup.oem
//
wcscpy( TemporaryBuffer, SetupSourceDevicePath );
SpConcatenatePaths( TemporaryBuffer, OemPreinstallSourcePath );
SpConcatenatePaths( TemporaryBuffer, L"txtsetup.oem" );
TxtsetupOemPath = SpDupStringW( TemporaryBuffer );
CLEAR_CLIENT_SCREEN();
HandleLineContinueChars = FALSE;
Status = SpLoadSetupTextFile(
TxtsetupOemPath,
NULL, // No image already in memory
0, // Image size is empty
&PreinstallOemSifHandle,
&ErrorLine,
TRUE,
FALSE
);
HandleLineContinueChars = TRUE;
if(!NT_SUCCESS(Status)) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to read txtsetup.oem. Status = %lx \n", Status ));
PreinstallOemSifHandle = NULL;
if(Status == STATUS_UNSUCCESSFUL) {
//
// Put an fatal error. On pre-install mode, the function will
// never come back.
//
SpOemInfError(SP_SCRN_OEM_PREINSTALL_INF_ERROR,SP_TEXT_OEM_INF_ERROR_A,NULL,ErrorLine,NULL);
return;
} else {
//
// Unable to load txtsetup.oem. Don't put an error message yet.
// Wait until we know that the file is needed.
//
}
}
for( j = 0; j < HwComponentMax; j++ ) {
PreinstallHardwareComponents[j] = NULL;
if( ( j == HwComponentComputer ) || ( j == HwComponentLayout ) ) {
Description = SpGetSectionKeyIndex(UnattendedSifHandle,
SIF_UNATTENDED,
PreinstallSectionNames[j],
0);
if( Description != NULL ) {
if( j != HwComponentLayout ) {
p = SpGetSectionKeyIndex(UnattendedSifHandle,
SIF_UNATTENDED,
PreinstallSectionNames[j],
1);
OemComponent = (p != NULL) && (_wcsicmp(p, OemTag) == 0);
if( OemComponent && ( PreinstallOemSifHandle == NULL ) ) {
//
// Put a fatal error message indicating that txtsetup.oem
// is needed but that it couldn't be loaded. Note that the
// SpOemInfError() will not return.
//
SpOemInfError(SP_SCRN_OEM_PREINSTALL_INF_ERROR,SP_TEXT_OEM_INF_ERROR_A,NULL,0,NULL);
// return;
}
} else {
OemComponent = FALSE;
}
PreinstallHardwareComponents[j] =
SpGetPreinstallComponentInfo( MasterSifHandle,
OemComponent,
NonlocalizedComponentNames[j],
Description,
AllowedFileTypes[j],
RequiredFileTypes[j] );
}
} else {
for( i = 0;
Description = SpGetKeyName( UnattendedSifHandle,
PreinstallSectionNames[j],
i );
i++ ) {
p = SpGetSectionKeyIndex(UnattendedSifHandle,
PreinstallSectionNames[j],
Description,
0);
OemComponent = (p != NULL) && (_wcsicmp(p, OemTag) == 0);
if( OemComponent && ( PreinstallOemSifHandle == NULL ) ) {
//
// Put a fatal error message indicating that txtsetup.oem
// is needed but that it couldn't be loaded. Note that the
// SpOemInfError() will not return.
//
SpOemInfError(SP_SCRN_OEM_PREINSTALL_INF_ERROR,SP_TEXT_OEM_INF_ERROR_A,NULL,0,NULL);
// return;
}
TempHwComponent =
SpGetPreinstallComponentInfo( MasterSifHandle,
OemComponent,
NonlocalizedComponentNames[j],
Description,
AllowedFileTypes[j],
RequiredFileTypes[j] );
TempHwComponent->Next = PreinstallHardwareComponents[j];
PreinstallHardwareComponents[j] = TempHwComponent;
}
}
}
//
// Note that there is no need to get the information about the scsi
// drivers to pre-install, ScsiHardware already contains the correct
// information.
//
// #if 0
for( i = 0;
Description = SpGetKeyName( UnattendedSifHandle,
WINNT_OEMSCSIDRIVERS_W,
i );
i++ ) {
p = SpGetSectionKeyIndex(UnattendedSifHandle,
WINNT_OEMSCSIDRIVERS_W,
Description,
0);
OemComponent = (p != NULL) && (_wcsicmp(p, OemTag) == 0);
if( OemComponent && ( PreinstallOemSifHandle == NULL ) ) {
//
// Put a fatal error message indicating that txtsetup.oem
// is needed but that it couldn't be loaded. Note that the
// SpOemInfError() will not return.
//
SpOemInfError(SP_SCRN_OEM_PREINSTALL_INF_ERROR,SP_TEXT_OEM_INF_ERROR_A,NULL,0,NULL);
// return;
}
TempHwComponent =
SpGetPreinstallComponentInfo( MasterSifHandle,
OemComponent,
L"SCSI",
Description,
SCSI_ALLOWED_FILETYPES,
SCSI_REQUIRED_FILETYPES );
TempHwComponent->Next = PreinstallScsiHardware;
PreinstallScsiHardware = TempHwComponent;
}
// #endif
}
PSETUP_PNP_HARDWARE_ID
SpSetupldrPnpDatabaseToSetupPnpDatabase(
IN PPNP_HARDWARE_ID AnsiHardwareIdDatabase
)
{
PPNP_HARDWARE_ID TempAnsiId;
PSETUP_PNP_HARDWARE_ID TempUnicodeId;
PSETUP_PNP_HARDWARE_ID UnicodeHardwareIdDatabase;
#if 0
ULONG Index;
#endif
UnicodeHardwareIdDatabase = NULL;
for( TempAnsiId = AnsiHardwareIdDatabase; TempAnsiId != NULL; TempAnsiId = TempAnsiId->Next ) {
TempUnicodeId = SpMemAlloc( sizeof( SETUP_PNP_HARDWARE_ID ) );
ASSERT(TempUnicodeId);
RtlZeroMemory( TempUnicodeId, sizeof(SETUP_PNP_HARDWARE_ID ) );
TempUnicodeId->Id = SpToUnicode( TempAnsiId->Id );
ASSERT(TempUnicodeId->Id);
TempUnicodeId->DriverName = SpToUnicode( TempAnsiId->DriverName );
ASSERT(TempUnicodeId->DriverName);
if( TempAnsiId->ClassGuid != NULL ) {
TempUnicodeId->ClassGuid = SpToUnicode( TempAnsiId->ClassGuid );
} else {
TempUnicodeId->ClassGuid = NULL;
}
TempUnicodeId->Next = UnicodeHardwareIdDatabase;
UnicodeHardwareIdDatabase = TempUnicodeId;
}
#if 0
for( TempUnicodeId = UnicodeHardwareIdDatabase, Index = 0;
TempUnicodeId != NULL;
TempUnicodeId = TempUnicodeId->Next, Index++ ) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Index = %d, Id = %ls, DriverName = %ls, ClassGUID = %ls \n", Index, TempUnicodeId->Id, TempUnicodeId->DriverName, ((TempUnicodeId->ClassGuid)? TempUnicodeId->ClassGuid : none)));
}
#endif
return( UnicodeHardwareIdDatabase );
}
BOOLEAN
SpSelectSectionItem(
IN PVOID SifHandle,
IN PWSTR SectionName,
IN ULONG SelectScreenId,
IN ULONG DefaultSelection OPTIONAL,
OUT PULONG SelectedOption
)
/*++
Routine Description:
Allow the user to make selection from a list of choices for a component.
The list comes from a section in the setup information file named
for the component. For example, [Display].
The descriptions in that section will be placed into a menu to make
up the selections.
Arguments:
SifHandle - supplies handle to open setup information file.
SectionName - supplies name of section to be used.
SelectHwScreenId - supplies message id of the screen prompting the user
to select an option for this section.
DefaultSelection - Item index, which should be highlighted as the default
choice when the menu is shown
SelectedOption - Returns the selected option
Return Value:
TRUE if a valid option is selected, otherwise FALSE
--*/
{
BOOLEAN Result;
ULONG LineCount,Line;
PVOID Menu;
ULONG MenuTopY,MenuHeight,MenuWidth;
PWSTR Description;
ULONG_PTR Selection;
ULONG ValidKeys[4] = {ASCI_CR, ASCI_ESC, 0};
ULONG Keypress;
//
// Display the selection prompt screen.
//
SpDisplayScreen(SelectScreenId, 5, HEADER_HEIGHT+1);
MenuTopY = NextMessageTopLine + 2;
MenuHeight = VideoVars.ScreenHeight - MenuTopY - 3;
MenuWidth = VideoVars.ScreenWidth - 6;
//
// Create a menu.
//
Menu = SpMnCreate(3, MenuTopY, MenuWidth, MenuHeight);
Result = (Menu != NULL);
//
// Assume unknown option.
//
Selection = (ULONG_PTR)(-1);
//
// Build a list of options containing the options in our box
//
LineCount = SpCountLinesInSection(SifHandle, SectionName);
for(Line=0; (Line < LineCount) && Result; Line++) {
//
// Get the description from the current line and add it to the menu.
//
Description = SpGetSectionLineIndex(
SifHandle,
SectionName,
Line,
INDEX_DESCRIPTION
);
if(!Description) {
Result = FALSE;
break;
}
SpMnAddItem(Menu, Description, 3, VideoVars.ScreenWidth-6, TRUE, Line);
//
// See if this is the currently selected item.
//
if((DefaultSelection != -1) && (DefaultSelection == Line)) {
Selection = Line;
}
}
if (Result) {
if(Selection == (ULONG_PTR)(-1)) {
Selection = 0;
}
//
// Display the status text options.
//
SpDisplayStatusOptions(
(UCHAR)(ATT_FG_BLACK | ATT_BG_WHITE),
SP_STAT_ENTER_EQUALS_SELECT,
SP_STAT_ESC_EQUALS_CANCEL,
0
);
//
// Display the menu.
//
SpMnDisplay(Menu,
Selection,
TRUE,
ValidKeys,
NULL,
NULL,
NULL,
&Keypress,
&Selection);
//
// Destroy the menu
//
SpMnDestroy(Menu);
switch(Keypress) {
case ASCI_CR:
Result = TRUE;
*SelectedOption = (ULONG)Selection;
break;
case ASCI_ESC:
Result = FALSE;
if (DefaultSelection != -1)
*SelectedOption = (ULONG)Selection;
break;
default:
Result = FALSE;
break;
}
}
return Result;
}
NTSTATUS
SpInitVirtualOemDevices(
IN PSETUP_LOADER_BLOCK SetupLoaderBlock,
OUT PVIRTUAL_OEM_SOURCE_DEVICE *SourceDevices
)
/*++
Routine Description:
Iterates through the virtual OEM source devices which loader
created and converts them into VIRTUAL_OEM_SOURCE_DEVICE list.
Also creates the required registry entries for each device
under RAM disk's parameters key.
Arguments:
SetupLoaderBlock - Setup loader block constructed by setupldr.
SourceDevice - Place holder for receiving the pointer to
head of the linked list of VIRTUAL_OEM_SOURCE_DEVICEs.
Return Value:
Appropriate NTSTATUS code
--*/
{
NTSTATUS Status = STATUS_INVALID_PARAMETER;
if (SetupLoaderBlock && SourceDevices) {
Status = STATUS_SUCCESS;
//
// Setupldr would have constructed its own version
// of the virtual OEM source devices
//
if (SetupLoaderBlock->OemSourceDevices) {
PVIRTUAL_OEM_SOURCE_DEVICE DeviceList = NULL;
PDETECTED_OEM_SOURCE_DEVICE CurrDevice = SetupLoaderBlock->OemSourceDevices;
ULONG DeviceCount = 0;
//
// Replicate the device list
//
while (CurrDevice) {
PVIRTUAL_OEM_SOURCE_DEVICE NewDevice;
NewDevice = SpMemAlloc(sizeof(VIRTUAL_OEM_SOURCE_DEVICE));
if (!NewDevice) {
Status = STATUS_NO_MEMORY;
break;
}
RtlZeroMemory(NewDevice, sizeof(VIRTUAL_OEM_SOURCE_DEVICE));
NewDevice->ArcDeviceName = SpToUnicode(CurrDevice->ArcDeviceName);
#if defined(_AMD64_) || defined(_X86_)
//
// NOTE : Loader allocated "LoaderFirmwarePermanent" memory
// so that memory manager while initializing doesn't
// reclaim this memory. This also helps us to avoid
// double copy -- i.e. this is the only location
// where we read the device contents into memory and
// this memory is valid through out the textmode setup so
// just reuse the memory.
//
NewDevice->ImageBase = CurrDevice->ImageBase;
#else
//
// NOTE : 05/13/2001 : LoaderFirmwarePermanent doesn't seem to work on non
// x86 platforsm (particularly IA64). Till this issue is resolved
// we have to allocate paged pool memory and replicate the disk
// image in loader heap tracked by "CurrDevice->ImageBase".
//
NewDevice->ImageBase = SpMemAlloc((SIZE_T)(CurrDevice->ImageSize));
if (NewDevice->ImageBase) {
memcpy(NewDevice->ImageBase,
CurrDevice->ImageBase,
(SIZE_T)(CurrDevice->ImageSize));
} else {
Status = STATUS_NO_MEMORY; // ran out of memory
break;
}
#endif // defined(_AMD64_) || defined(_X86_)
NewDevice->ImageSize = CurrDevice->ImageSize;
NewDevice->DeviceId = DeviceCount++;
//
// Insert the node at the head of the list
//
if (!DeviceList) {
DeviceList = NewDevice;
} else {
NewDevice->Next = DeviceList;
DeviceList = NewDevice;
}
CurrDevice = CurrDevice->Next;
}
//
// Sanity check
//
if (NT_SUCCESS(Status) && !DeviceList) {
Status = STATUS_UNSUCCESSFUL;
}
//
// Setup the parameters for the RAM disk driver
// to create appropriate device objects as
// needed by us
//
if (NT_SUCCESS(Status) && DeviceList) {
WCHAR KeyName[MAX_PATH];
UNICODE_STRING RamDiskDriverName;
OBJECT_ATTRIBUTES ObjectAttrs;
HANDLE RamDiskDriverHandle = NULL;
//
// Create the service key
//
swprintf(KeyName,
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\%ws",
RAMDISK_DRIVER_NAME
);
INIT_OBJA(&ObjectAttrs, &RamDiskDriverName, KeyName);
Status = ZwCreateKey(&RamDiskDriverHandle,
KEY_ALL_ACCESS,
&ObjectAttrs,
0,
NULL,
REG_OPTION_NON_VOLATILE,
NULL);
if (NT_SUCCESS(Status)) {
UNICODE_STRING ParamName;
OBJECT_ATTRIBUTES ParamAttrs;
HANDLE ParamHandle = NULL;
//
// Create the parameters key
//
INIT_OBJA(&ParamAttrs, &ParamName, L"Parameters");
ParamAttrs.RootDirectory = RamDiskDriverHandle;
Status = ZwCreateKey(&ParamHandle,
KEY_ALL_ACCESS,
&ParamAttrs,
0,
NULL,
REG_OPTION_NON_VOLATILE,
NULL);
if (NT_SUCCESS(Status)) {
WCHAR ValueStr[MAX_PATH];
PVIRTUAL_OEM_SOURCE_DEVICE CurrDevice = DeviceList;
//
// Create the regsitry values indicating the virtual
// devices for the Ram drive
//
while (CurrDevice) {
UNICODE_STRING ValueName;
BYTE Value[MAX_PATH * 2];
PBYTE ValuePtr = (PBYTE)Value;
ULONG ValueSize;
ULONGLONG ImageBase = (ULONGLONG)(ULONG_PTR)(CurrDevice->ImageBase);
ULONG ImageSize = (ULONG)(CurrDevice->ImageSize);
swprintf(ValueStr,
L"%ws%d",
MS_RAMDISK_DRIVER_PARAM,
CurrDevice->DeviceId);
memcpy(ValuePtr, &ImageBase, sizeof(ULONGLONG));
ValuePtr += sizeof(ULONGLONG);
memcpy(ValuePtr, &ImageSize, sizeof(ULONG));
ValuePtr += sizeof(ULONG);
ValueSize = (ULONG)(ULONG_PTR)(ValuePtr - Value);
RtlInitUnicodeString(&ValueName, ValueStr);
Status = ZwSetValueKey(ParamHandle,
&ValueName,
0,
REG_BINARY,
Value,
ValueSize);
if (!NT_SUCCESS(Status)) {
break;
}
//
// process next device
//
CurrDevice = CurrDevice->Next;
}
ZwClose(ParamHandle);
}
ZwClose(RamDiskDriverHandle);
}
}
//
// Initialize the return value only if we are successful
//
if (NT_SUCCESS(Status)) {
*SourceDevices = DeviceList;
}
} else {
*SourceDevices = NULL;
}
}
return Status;
}