NT4/private/ntos/boot/setup/oemdisk.c
2020-09-30 17:12:29 +02:00

1954 lines
57 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
oemdisk.c
Abstract:
Provides routines for handling OEM disks for video, SCSI miniport, and HAL.
Currently used only on ARC machines.
Author:
John Vert (jvert) 4-Dec-1993
Revision History:
John Vert (jvert) 4-Dec-1993
created
--*/
#include <setupbat.h>
#include "setupldr.h"
#include "stdio.h"
#include <ctype.h>
#if DBG
#define DIAGOUT(x) SlPrint x
#else
#define DIAGOUT(x)
#endif
BOOLEAN PromptOemHal=FALSE;
BOOLEAN PromptOemScsi=FALSE;
BOOLEAN PromptOemVideo=FALSE;
PVOID PreInstallOemInfHandle = NULL;
PCHAR FloppyDiskPath;
extern PCHAR BootPath;
extern ULONG BootDeviceId;
extern PVOID InfFile;
typedef struct _MENU_ITEM_DATA {
PVOID InfFile;
PCHAR SectionName;
ULONG Index;
PCHAR Description;
PCHAR Identifier;
} MENU_ITEM_DATA, *PMENU_ITEM_DATA;
typedef enum _OEMFILETYPE {
OEMSCSI,
OEMHAL,
OEMOTHER
} OEMFILETYPE, *POEMFILETYPE;
//
// Define how many lines of SCSI adapters we can list.
//
#define MAX_SCSI_MINIPORT_COUNT 4
//
// private function prototypes
//
ULONG
SlpAddSectionToMenu(
IN PVOID InfHandle,
IN PCHAR SectionName,
IN PSL_MENU Menu
);
BOOLEAN
SlpOemDiskette(
IN PCHAR ComponentName,
IN OEMFILETYPE ComponentType,
IN ULONG MenuHeaderId,
OUT PDETECTED_DEVICE DetectedDevice,
OUT PVOID *ImageBase,
OUT OPTIONAL PCHAR *ImageName,
OUT OPTIONAL PCHAR *DriverDescription,
IN BOOLEAN AllowUserSelection,
IN PCHAR PreInstallComponentDescription
);
BOOLEAN
SlpSelectHardware(
IN PCHAR ComponentName,
IN OEMFILETYPE ComponentType,
IN TYPE_OF_MEMORY MemoryType,
IN ULONG MenuHeaderId,
IN ULONG OemMenuHeaderId,
OUT PDETECTED_DEVICE DetectedDevice,
OUT PVOID *ImageBase,
OUT OPTIONAL PCHAR *ImageName,
OUT OPTIONAL PCHAR *DriverDescription,
IN BOOLEAN AllowUserSelection,
IN PCHAR PreInstallComponentDescription,
IN BOOLEAN PreInstallOemComponent
);
BOOLEAN
SlpOemInfSelection(
IN PVOID OemInfHandle,
IN PCHAR ComponentName,
IN PCHAR SelectedId,
IN PCHAR ItemDescription,
OUT PDETECTED_DEVICE Device
);
VOID
SlpInitDetectedDevice(
IN PDETECTED_DEVICE Device,
IN PCHAR IdString,
IN PCHAR Description,
IN BOOLEAN ThirdPartyOptionSelected
);
PDETECTED_DEVICE_REGISTRY
SlpInterpretOemRegistryData(
IN PVOID InfHandle,
IN PCHAR SectionName,
IN ULONG Line,
IN HwRegistryType ValueType
);
BOOLEAN
FoundFloppyDiskCallback(
IN PCONFIGURATION_COMPONENT_DATA Component
);
int
SlpFindStringInTable(
IN PCHAR String,
IN PCHAR *StringTable
);
//
// FileTypeNames -- keep in sync with HwFileType enum!
//
PCHAR FileTypeNames[HwFileMax] = { "driver", "port" , "class", "inf",
"dll" , "detect", "hal"
};
//
// RegistryTypeNames -- keep in sync with HwRegistryType enum!
//
PCHAR RegistryTypeNames[HwRegistryMax] = { "REG_DWORD", "REG_BINARY", "REG_SZ",
"REG_EXPAND_SZ", "REG_MULTI_SZ"
};
ULONG RegistryTypeMap[HwRegistryMax] = { REG_DWORD, REG_BINARY, REG_SZ,
REG_EXPAND_SZ, REG_MULTI_SZ
};
VOID
SlPromptOemScsi(
OUT POEMSCSIINFO *pOemScsiInfo
)
/*++
Routine Description:
Provides the user interface and logic for allowing the user to manually select
SCSI adapters from the main INF file or the INF file on an OEM driver disk.
Arguments:
pOemScsiInfo - Returns a linked list containing info about any third-party scsi
drivers selected.
Return Value:
none.
--*/
{
PVOID OemScsiBase;
PCHAR OemScsiName, MessageString, ScsiDescription, MnemonicText;
BOOLEAN Success, bFirstTime = TRUE, bRepaint;
ULONG x, y1, y2, ScsiDriverCount, NumToSkip;
ULONG c;
CHAR Mnemonic;
POEMSCSIINFO NewOemScsi, CurOemScsi;
PDETECTED_DEVICE ScsiDevice;
BOOLEAN AllowUserSelection;
PPREINSTALL_DRIVER_INFO CurrentDriver;
AllowUserSelection = ( !PreInstall || (PreinstallDriverList == NULL) )? TRUE : FALSE;
CurrentDriver = PreinstallDriverList;
*pOemScsiInfo = CurOemScsi = NULL;
MnemonicText = BlFindMessage(SL_SCSI_SELECT_MNEMONIC);
Mnemonic = toupper(MnemonicText[0]);
bRepaint = TRUE;
while(1) {
if( AllowUserSelection ) {
if(bRepaint) {
SlClearClientArea();
if(bFirstTime) {
MessageString = BlFindMessage(SL_SCSI_SELECT_MESSAGE_1);
} else if(Success) {
MessageString = BlFindMessage(SL_SCSI_SELECT_MESSAGE_3);
} else {
MessageString = BlFindMessage(SL_SCSI_SELECT_ERROR);
}
x = 1;
y1 = 4;
SlGenericMessageBox(0, NULL, MessageString, &x, &y1, &y2, FALSE);
y1 = y2 + 1;
x = 4;
//
// Count all currently 'detected' SCSI devices.
//
for(ScsiDriverCount = 0, ScsiDevice = BlLoaderBlock->SetupLoaderBlock->ScsiDevices;
ScsiDevice;
ScsiDriverCount++, ScsiDevice = ScsiDevice->Next);
//
// Display each loaded miniport driver description.
//
if(ScsiDriverCount) {
if(ScsiDriverCount > MAX_SCSI_MINIPORT_COUNT) {
NumToSkip = ScsiDriverCount - MAX_SCSI_MINIPORT_COUNT;
//
// Display ellipses to indicate that top entries have scrolled out of view
//
SlGenericMessageBox(0,
NULL,
"...",
&x,
&y1,
&y2,
FALSE
);
y1 = y2 + 1;
} else {
NumToSkip = 0;
y1++;
}
ScsiDevice = BlLoaderBlock->SetupLoaderBlock->ScsiDevices;
while(NumToSkip && ScsiDevice) {
ScsiDevice = ScsiDevice->Next;
NumToSkip--;
}
while(ScsiDevice) {
SlGenericMessageBox(0,
NULL,
ScsiDevice->Description,
&x,
&y1,
&y2,
FALSE
);
y1 = y2 + 1;
ScsiDevice = ScsiDevice->Next;
}
} else {
y1++;
SlGenericMessageBox(0,
NULL,
BlFindMessage(SL_TEXT_ANGLED_NONE),
&x,
&y1,
&y2,
FALSE
);
y1 = y2 + 1;
}
x = 1;
y1++;
SlGenericMessageBox(0,
NULL,
BlFindMessage(SL_SCSI_SELECT_MESSAGE_2),
&x,
&y1,
&y2,
FALSE
);
SlWriteStatusText(BlFindMessage(SL_SCSI_SELECT_PROMPT));
bRepaint = FALSE;
}
c = SlGetChar();
} else {
c = ( CurrentDriver != NULL )? Mnemonic : ASCI_CR;
}
switch (c) {
case SL_KEY_F3:
SlConfirmExit();
bRepaint = TRUE;
break;
case ASCI_CR:
return;
default:
if(toupper(c) == Mnemonic) {
bFirstTime = FALSE;
bRepaint = TRUE;
Success = SlpSelectHardware("SCSI",
OEMSCSI,
LoaderBootDriver,
SL_PROMPT_SCSI,
SL_PROMPT_OEM_SCSI,
NULL,
&OemScsiBase,
&OemScsiName,
&ScsiDescription,
AllowUserSelection,
(AllowUserSelection)? NULL : CurrentDriver->DriverDescription,
(BOOLEAN)((AllowUserSelection)? FALSE : CurrentDriver->OemDriver)
);
if(!AllowUserSelection) {
CurrentDriver = CurrentDriver->Next;
}
if(Success) {
//
// Check to see if the driver loaded was an OEM SCSI driver. If so,
// then add an OemScsiInfo entry onto the end of our list.
//
if(OemScsiBase) {
NewOemScsi = BlAllocateHeap(sizeof(OEMSCSIINFO));
if(!NewOemScsi) {
SlNoMemoryError();
}
if(CurOemScsi) {
CurOemScsi->Next = NewOemScsi;
} else {
*pOemScsiInfo = NewOemScsi;
}
CurOemScsi = NewOemScsi;
NewOemScsi->ScsiBase = OemScsiBase;
NewOemScsi->ScsiName = OemScsiName;
NewOemScsi->Next = NULL;
}
}
}
}
}
}
VOID
SlPromptOemHal(
OUT PVOID *HalBase,
OUT PCHAR *HalName
)
/*++
Routine Description:
Provides the user interface and logic for allowing the user to manually select
a HAL from the main INF file or the INF file on an OEM driver disk.
Arguments:
HalBase - Returns the address where the HAL was loaded into memory.
HalName - Returns the name of the HAL that was loaded.
Return Value:
ESUCCESS - HAL successfully loaded.
--*/
{
BOOLEAN Success;
BOOLEAN AllowUserSelection;
AllowUserSelection = ( !PreInstall || (ComputerType == NULL) )? TRUE : FALSE;
do {
Success = SlpSelectHardware("Computer",
OEMHAL,
LoaderHalCode,
SL_PROMPT_HAL,
SL_PROMPT_OEM_HAL,
&BlLoaderBlock->SetupLoaderBlock->ComputerDevice,
HalBase,
HalName,
NULL,
AllowUserSelection,
ComputerType,
OemHal
);
} while ( !Success );
}
VOID
SlPromptOemVideo(
OUT PVOID *VideoBase,
OUT PCHAR *VideoName
)
/*++
Routine Description:
Provides the user interface and logic for allowing the user to manually select
a video adapter from the main INF file or the INF file on an OEM driver disk.
Arguments:
VideoBase - Returns the address where the video driver was loaded
VideoName - Returns a pointer to the name of the video driver
Return Value:
None.
--*/
{
BOOLEAN Success;
do {
Success = SlpSelectHardware("display",
OEMOTHER,
LoaderBootDriver,
SL_PROMPT_VIDEO,
SL_PROMPT_OEM_VIDEO,
&BlLoaderBlock->SetupLoaderBlock->VideoDevice,
VideoBase,
VideoName,
NULL,
TRUE,
NULL,
FALSE
);
} while ( !Success );
}
BOOLEAN
SlpSelectHardware(
IN PCHAR ComponentName,
IN OEMFILETYPE ComponentType,
IN TYPE_OF_MEMORY MemoryType,
IN ULONG MenuHeaderId,
IN ULONG OemMenuHeaderId,
OUT OPTIONAL PDETECTED_DEVICE DetectedDevice,
OUT PVOID *ImageBase,
OUT OPTIONAL PCHAR *ImageName,
OUT OPTIONAL PCHAR *DriverDescription,
IN BOOLEAN AllowUserSelection,
IN PCHAR PreInstallComponentDescription,
IN BOOLEAN PreInstallOemComponent
)
/*++
Routine Description:
Present the user with a menu of options for the selected device class.
This menu will consist of options listed in the main inf plus a single
oem option if one is currently selected, plus additional items in the
system partition inf for the component if specified (ARC machines).
When the user makes a selection, forget any previous OEM option (except
for SCSI). If the user selects an option supplied by us, set up the
SELECTED_DEVICE structure and return. Otherwise prompt for a manufacturer-
supplied diskette.
Arguments:
ComponentName - Supplies the name of the component to be presented.
ComponentType - Supplies the type of the component (HAL, SCSI, or Other)
MemoryType - Supplies the type of memory used to load the image.
MenuHeaderId - Supplies the ID of the menu header to be displayed
OemMenuHeaderId - Supplies the ID of the menu header to be displayed
when an OEM selection is to be made.
DetectedDevice - returns the DeviceId of the selected device. If an
OEM diskette is required, the necessary OEM structures will
be allocated and filled in. (This field is ignored for SCSI
components.)
ImageBase - Returns the base of the image that was loaded.
ImageName - Returns the filename of the image.
DriverDescription - If specified, returns the description of the loaded
device.
AllowUserSelection - Indicates whether or not user is allowed to select
a driver. This flag is typically set to FALSE when
pre-installing components defined in unattend.txt.
PreInstallComponentDescription - In the pre-install mode, points to the string
that identifies the component to pre-install.
It is NULL if AllowUserSelction is TRUE.
PreInstallOemComponent - In the pre-install mode, this flag indicates
whether or not the component to pre-install is
an OEM or RETAIL component.
Return Value:
TRUE - Success
FALSE - The user has escaped out of the dialog
--*/
{
PSL_MENU Menu;
LONG Selection;
LONG OtherSelection;
CHAR OtherSelectionName[80];
PCHAR p;
ULONG c, i;
PCHAR AdapterName;
CHAR Buffer[80];
PCHAR FileName;
PCHAR FileDescription;
ARC_STATUS Status;
BOOLEAN b;
ULONG Ordinal;
SCSI_INSERT_STATUS sis;
if( AllowUserSelection ) {
Menu = SlCreateMenu();
if (Menu==NULL) {
SlNoMemoryError();
return(FALSE);
}
//
// Build a list of options containing the drivers we ship and the
// currently selected OEM option (if any).
//
c = SlpAddSectionToMenu(InfFile,
ComponentName,
Menu);
//
// Add selection for "other"
//
strncpy(OtherSelectionName,
BlFindMessage(SL_TEXT_OTHER_DRIVER),
80
);
OtherSelectionName[79] = 0;
//
// Use text up to the first CR or LF.
//
for(p = OtherSelectionName; *p; p++) {
if((*p == '\n') || (*p == '\r')) {
*p = '\0';
break;
}
}
OtherSelection = SlAddMenuItem(Menu,
OtherSelectionName,
(PVOID)-1,
0);
//
// Default is "other"
//
Selection = OtherSelection;
} else {
//
// This is a pre-install. Find out if the component to pre-install
// is RETAIL or OEM.
//
OtherSelection = SlCountLinesInSection( InfFile,
ComponentName );
if( PreInstallOemComponent ) {
//
// Pre-installing an OEM component
//
Selection = OtherSelection;
} else {
//
// Pre-installing a RETAIL component
//
PCHAR q;
q = SlPreInstallGetComponentName( InfFile,
ComponentName,
PreInstallComponentDescription );
if (q==NULL) {
//
// we have enumerated the entire section without finding a
// match, return failure.
//
SlFatalError(SL_BAD_UNATTENDED_SCRIPT_FILE,
PreInstallComponentDescription,
ComponentName,
"txtsetup.sif");
goto SelectionAbort;
}
Selection = SlGetSectionKeyOrdinal( InfFile,
ComponentName,
q );
}
}
//
// Allow the user to interact with the menu
//
while (1) {
if( AllowUserSelection ) {
SlClearClientArea();
SlWriteStatusText(BlFindMessage(SL_SELECT_DRIVER_PROMPT));
c = SlDisplayMenu(MenuHeaderId,
Menu,
&Selection);
} else {
c = ASCI_CR;
}
switch (c) {
case SL_KEY_F3:
SlConfirmExit();
break;
case ASCI_ESC:
goto SelectionAbort;
case ASCI_CR:
if (Selection == OtherSelection) {
//
// User selected "other" Prompt for OEM diskette
//
b = SlpOemDiskette(ComponentName,
ComponentType,
OemMenuHeaderId,
DetectedDevice,
ImageBase,
ImageName,
DriverDescription,
AllowUserSelection,
PreInstallComponentDescription
);
SlClearClientArea();
SlWriteStatusText("");
return(b);
} else {
//
// User selected a built-in. Go ahead and load
// it here.
//
if(ComponentType == OEMHAL) {
//
// then we need to look for [Hal.Load]
//
strcpy(Buffer, "Hal.Load");
} else {
sprintf(Buffer, "%s.Load", ComponentName);
}
AdapterName = SlGetKeyName(InfFile,
ComponentName,
Selection
);
if(AdapterName==NULL) {
SlFatalError(SL_BAD_INF_FILE, "txtsetup.sif");
goto SelectionAbort;
}
FileName = SlGetIniValue(InfFile,
Buffer,
AdapterName,
NULL);
if((FileName==NULL) && (ComponentType == OEMHAL)) {
FileName = SlGetIniValue(InfFile,
"Hal",
AdapterName,
NULL);
FileDescription = SlCopyString(BlFindMessage(SL_HAL_NAME));
} else {
FileDescription = SlGetIniValue(InfFile,
ComponentName,
AdapterName,
NULL);
}
if(FileName==NULL) {
SlFatalError(SL_BAD_INF_FILE, "txtsetup.sif");
goto SelectionAbort;
}
if(ARGUMENT_PRESENT(ImageName)) {
*ImageName = FileName;
}
if(ARGUMENT_PRESENT(DriverDescription)) {
*DriverDescription = FileDescription;
}
//
// If we're doing OEM SCSI, then get a properly-inserted
// DETECTED_DEVICE structure
//
if(ComponentType == OEMSCSI) {
//
// Find this adapter's ordinal within the Scsi.Load section of txtsetup.sif
//
Ordinal = SlGetSectionKeyOrdinal(InfFile, Buffer, AdapterName);
if(Ordinal == (ULONG)-1) {
SlFatalError(SL_BAD_INF_FILE, "txtsetup.sif");
goto SelectionAbort;
}
//
// Create a new detected device entry.
//
if((sis = SlInsertScsiDevice(Ordinal, &DetectedDevice)) == ScsiInsertError) {
SlFriendlyError(ENOMEM, "SCSI detection", __LINE__, __FILE__);
goto SelectionAbort;
}
if(sis == ScsiInsertExisting) {
#if DBG
//
// Sanity check to make sure we're talking about the same driver
//
if(_strcmpi(DetectedDevice->BaseDllName, FileName)) {
SlError(400);
goto SelectionAbort;
}
#endif
}
}
DetectedDevice->IdString = AdapterName;
DetectedDevice->Description = FileDescription;
DetectedDevice->ThirdPartyOptionSelected = FALSE;
DetectedDevice->FileTypeBits = 0;
DetectedDevice->Files = NULL;
DetectedDevice->BaseDllName = FileName;
//
// We only want to load the image if we're not doing SCSI.
//
if(ComponentType != OEMSCSI) {
sprintf(Buffer, "%s%s", BootPath, FileName);
SlGetDisk(FileName);
BlOutputLoadMessage(FileDescription, FileName);
Status = BlLoadImage(BootDeviceId,
LoaderHalCode,
Buffer,
TARGET_IMAGE,
ImageBase
);
} else {
*ImageBase = NULL;
Status = ESUCCESS;
}
}
if (Status != ESUCCESS) {
SlMessageBox(SL_FILE_LOAD_FAILED,Buffer,Status);
goto SelectionAbort;
}
SlClearClientArea();
SlWriteStatusText("");
return(TRUE);
default:
break;
}
}
SelectionAbort:
SlClearClientArea();
SlWriteStatusText("");
return FALSE;
}
BOOLEAN
SlpOemDiskette(
IN PCHAR ComponentName,
IN OEMFILETYPE ComponentType,
IN ULONG MenuHeaderId,
OUT OPTIONAL PDETECTED_DEVICE DetectedDevice,
OUT PVOID *ImageBase,
OUT OPTIONAL PCHAR *ImageName,
OUT OPTIONAL PCHAR *DriverDescription,
IN BOOLEAN AllowUserSelection,
IN PCHAR PreInstallComponentDescription
)
/*++
Routine Description:
Prompt for an oem driver diskette and read the oem text inf file
from it. Present the choices for the device class to the user and
allow him to select one.
Remember information about the selection the user has made.
Arguments:
ComponentName - Supplies name of component to look for.
ComponentType - Supplies the type of the component (HAL, SCSI, or Other)
MenuHeaderId - Supplies ID of menu header to be displayed
DetectedDevice - Returns information about the device seleceted
ImageBase - Returns image base of loaded image
ImageName - Returns filename of loaded image
DriverDescription - If specified, returns description of loaded driver
AllowUserSelection - Indicates whether or not user is allowed to select
a driver. This flag is typically set to FALSE when
pre-installing components defined in unattend.txt.
PreInstallComponentDescription - In the pre-install mode, points to the string
that identifies the component to pre-install.
It is NULL if AllowUserSelction is TRUE.
Return Value:
TRUE if the user made a choice, FALSE if the user cancelled/error occurred.
--*/
{
CHAR FloppyName[80];
ULONG FloppyId;
PVOID OemInfHandle;
ULONG Error;
ARC_STATUS Status;
ULONG Count;
ULONG DefaultSelection;
PCHAR DefaultSelText;
PSL_MENU Menu;
ULONG c;
PMENU_ITEM_DATA Data;
PDETECTED_DEVICE_FILE FileStruct;
BOOLEAN bDriverLoaded;
HwFileType filetype;
PDETECTED_DEVICE prev, cur;
CHAR FullDriverPath[256];
ULONG DirectoryLength;
BOOLEAN SeparatorNeeded;
CHAR OemTextFilePath[256];
PCHAR OemComponentId;
PCHAR OemComponentDescription;
SlClearClientArea();
if( AllowUserSelection ) {
//
// Compute the name of the A: drive
//
if (!SlpFindFloppy(0,FloppyName)) {
//
// No floppy drive available, bail out.
//
SlError(0);
return(FALSE);
}
//
// Prompt for the disk.
//
while(1) {
if (!SlPromptForDisk(BlFindMessage(SL_OEM_DISK_PROMPT), TRUE)) {
return(FALSE);
}
Status = ArcOpen(FloppyName, ArcOpenReadOnly, &FloppyId);
if(Status == ESUCCESS) {
break;
}
}
}
//
// Load the OEM INF file
//
if( AllowUserSelection ) {
strcpy( OemTextFilePath, "" );
strcpy( FullDriverPath, "" );
} else {
#ifndef _X86_
PCHAR p;
#endif
strcpy( OemTextFilePath, BootPath );
#ifndef _X86_
//
// On RISC platforms, remove the platform specific directory
// from the path
//
p = (OemTextFilePath + strlen(OemTextFilePath) - 1);
if( *p == '\\' ) {
*p = '\0';
}
p = strrchr( OemTextFilePath, '\\' );
*(p+1) = '\0';
#endif
//
// Note that on x86 the path to txtsetup.oem is going to be:
// $win_nt$.~bt\$OEM$
// while on non-x86 platforms, the path is going to be:
// $win_nt$.~ls\$OEM$\TEXTMODE
//
strcat( OemTextFilePath,
#ifdef _X86_
WINNT_OEM_DIR
#else
WINNT_OEM_TEXTMODE_DIR
#endif
);
//
// Save the path to the directory that contains txtsetup.oem.
// It will be used later on, when we load the driver.
//
strcpy( FullDriverPath, OemTextFilePath );
strcat( OemTextFilePath, "\\" );
}
//
// Now form the path to txtsetup.oem
//
strcat( OemTextFilePath, "txtsetup.oem" );
if( AllowUserSelection || (PreInstallOemInfHandle == NULL)) {
Status = SlInitIniFile(NULL,
( AllowUserSelection )? FloppyId : BootDeviceId,
OemTextFilePath,
&OemInfHandle,
&Error);
if (Status != ESUCCESS) {
SlFriendlyError(Status, "txtsetup.oem", __LINE__, __FILE__);
goto OemLoadFailed;
}
if( !AllowUserSelection ) {
PreInstallOemInfHandle = OemInfHandle;
}
} else {
OemInfHandle = PreInstallOemInfHandle;
}
Count = SlCountLinesInSection(OemInfHandle, ComponentName);
if(Count == (ULONG)(-1)) {
SlMessageBox(SL_WARNING_SIF_NO_COMPONENT);
goto OemLoadFailed;
}
//
// Get the text of the default choice
//
if( AllowUserSelection ) {
if(DefaultSelText = SlGetSectionKeyIndex(OemInfHandle, "Defaults",ComponentName, 0)) {
DefaultSelText = SlGetSectionKeyIndex(OemInfHandle,ComponentName,DefaultSelText,0);
}
} else {
DefaultSelText = PreInstallComponentDescription;
}
if( AllowUserSelection ) {
//
// Build menu
//
Menu = SlCreateMenu();
if (Menu==NULL) {
SlNoMemoryError();
}
SlpAddSectionToMenu(OemInfHandle,ComponentName,Menu);
//
// Find the index of the default choice
//
if(!DefaultSelText ||
!SlGetMenuItemIndex(Menu,DefaultSelText,&DefaultSelection)) {
DefaultSelection=0;
}
}
//
// Allow the user to interact with the menu
//
while (1) {
if( AllowUserSelection ) {
SlClearClientArea();
SlWriteStatusText(BlFindMessage(SL_SELECT_DRIVER_PROMPT));
c = SlDisplayMenu(MenuHeaderId,
Menu,
&DefaultSelection);
} else {
c = ASCI_CR;
}
switch (c) {
case SL_KEY_F3:
SlConfirmExit();
break;
case ASCI_ESC:
return(FALSE);
break;
case ASCI_CR:
//
// User selected an option, fill in the detected
// device structure with the information from the
// INF file.
//
//
// If this is for OEM SCSI, then we have to get a new (properly-inserted)
// DETECTED_DEVICE structure.
//
if(ComponentType == OEMSCSI) {
if(SlInsertScsiDevice((ULONG)-1, &DetectedDevice) == ScsiInsertError) {
SlNoMemoryError();
}
}
if( AllowUserSelection ) {
Data = SlGetMenuItem(Menu, DefaultSelection);
OemComponentId = Data->Identifier;
OemComponentDescription = Data->Description;
} else {
OemComponentId = SlPreInstallGetComponentName( OemInfHandle,
ComponentName,
PreInstallComponentDescription );
if( OemComponentId == NULL ) {
SlFatalError(SL_BAD_UNATTENDED_SCRIPT_FILE,
PreInstallComponentDescription,
ComponentName,
"txtsetup.oem");
}
OemComponentDescription = PreInstallComponentDescription;
}
if(SlpOemInfSelection(OemInfHandle,
ComponentName,
OemComponentId,
OemComponentDescription,
DetectedDevice))
{
//
// Go load the driver. The correct disk must
// already be in the drive, since we just read
// the INF file off it.
//
// We step down the linked list, and load the first driver we find.
//
for(FileStruct = DetectedDevice->Files, bDriverLoaded = FALSE;
(FileStruct && !bDriverLoaded);
FileStruct = FileStruct->Next) {
filetype = FileStruct->FileType;
if((filetype == HwFilePort) || (filetype == HwFileClass) ||
(filetype == HwFileDriver) || (filetype == HwFileHal)) {
BlOutputLoadMessage(OemComponentDescription, // Data->Description,
FileStruct->Filename);
//
// Allocate a string buffer large enough to hold the full
// path to the file.
//
DirectoryLength = strlen(FileStruct->Directory);
SeparatorNeeded = !(DirectoryLength &&
FileStruct->Directory[DirectoryLength - 1] == '\\');
//
// Note that FullDriverPath is already initialized.
// (This was done right before we loaded txtsetup.oem)
//
strcat(FullDriverPath, FileStruct->Directory);
if(SeparatorNeeded) {
strcat(FullDriverPath, "\\");
}
strcat(FullDriverPath, FileStruct->Filename);
Status = BlLoadImage(( AllowUserSelection )? FloppyId : BootDeviceId,
LoaderHalCode,
FullDriverPath,
TARGET_IMAGE,
ImageBase);
if (Status == ESUCCESS) {
DetectedDevice->BaseDllName = FileStruct->Filename;
if(ARGUMENT_PRESENT(ImageName)) {
*ImageName = FileStruct->Filename;
}
if(ARGUMENT_PRESENT(DriverDescription)) {
*DriverDescription = OemComponentDescription; // Data->Description;
}
bDriverLoaded = TRUE;
} else {
if( !PreInstall ) {
SlFriendlyError(
Status,
FullDriverPath,
__LINE__,
__FILE__
);
//
// If one of the drivers causes an error, then we abort
//
if( AllowUserSelection ) {
ArcClose(FloppyId);
}
//
// We must take the bad driver entry out of the chain in
// the case of SCSI.
//
if(ComponentType == OEMSCSI) {
prev = NULL;
cur = BlLoaderBlock->SetupLoaderBlock->ScsiDevices;
while(cur && (cur != DetectedDevice)) {
prev = cur;
cur = cur->Next;
}
if(cur) { // it better always be non-NULL!
if(prev) {
prev->Next = cur->Next;
} else {
BlLoaderBlock->SetupLoaderBlock->ScsiDevices = cur->Next;
}
}
}
return FALSE;
} else {
SlFatalError(SL_FILE_LOAD_FAILED, FullDriverPath, Status);
}
}
}
}
if( AllowUserSelection ) {
ArcClose(FloppyId);
}
if(bDriverLoaded) {
return TRUE;
} else {
//
// We didn't find any drivers, so inform the user.
//
SlMessageBox(SL_WARNING_SIF_NO_DRIVERS);
break;
}
} else {
SlFriendlyError(
0,
"",
__LINE__,
__FILE__
);
}
break;
}
}
OemLoadFailed:
if( AllowUserSelection ) {
ArcClose(FloppyId);
}
return(FALSE);
}
ULONG
SlpAddSectionToMenu(
IN PVOID InfHandle,
IN PCHAR SectionName,
IN PSL_MENU Menu
)
/*++
Routine Description:
Adds the entries in an INF section to the given menu
Arguments:
InfHandle - Supplies a handle to the INF file
SectionName - Supplies the name of the section.
Menu - Supplies the menu to add the items in the section to.
Return Value:
Number of items added to the menu.
--*/
{
ULONG i;
ULONG LineCount;
PCHAR Description;
PMENU_ITEM_DATA Data;
if (InfHandle==NULL) {
//
// nothing to add
//
return(0);
}
LineCount = SlCountLinesInSection(InfHandle,SectionName);
if(LineCount == (ULONG)(-1)) {
LineCount = 0;
}
for (i=0;i<LineCount;i++) {
Data = BlAllocateHeap(sizeof(MENU_ITEM_DATA));
if (Data==NULL) {
SlError(0);
return(0);
}
Data->InfFile = InfHandle;
Data->SectionName = SectionName;
Data->Index = i;
Description = SlGetSectionLineIndex(InfHandle,
SectionName,
i,
0);
if (Description==NULL) {
Description="BOGUS!";
}
Data->Description = Description;
Data->Identifier = SlGetKeyName(InfHandle,SectionName,i);
SlAddMenuItem(Menu,
Description,
Data,
0);
}
return(LineCount);
}
BOOLEAN
SlpFindFloppy(
IN ULONG Number,
OUT PCHAR ArcName
)
/*++
Routine Description:
Determines the ARC name for a particular floppy drive.
Arguments:
Number - Supplies the floppy drive number
ArcName - Returns the ARC name of the given floppy drive.
Return Value:
TRUE - Drive was found.
FALSE - Drive was not found.
--*/
{
FloppyDiskPath = ArcName;
BlSearchConfigTree(BlLoaderBlock->ConfigurationRoot,
PeripheralClass,
FloppyDiskPeripheral,
Number,
FoundFloppyDiskCallback);
if (ArcName[0]=='\0') {
return(FALSE);
} else {
return(TRUE);
}
}
BOOLEAN
FoundFloppyDiskCallback(
IN PCONFIGURATION_COMPONENT_DATA Component
)
/*++
Routine Description:
Callback routine called by SlpFindFloppy to find a given floppy
drive in the ARC tree.
Check to see whether the parent is disk controller 0.
Arguments:
Component - Supplies the component.
Return Value:
TRUE if search is to continue.
FALSE if search is to stop.
--*/
{
PCONFIGURATION_COMPONENT_DATA ParentComponent;
//
// A floppy disk peripheral was found. If the parent was disk(0),
// we've got a floppy disk drive.
//
if((ParentComponent = Component->Parent)
&& (ParentComponent->ComponentEntry.Type == DiskController))
{
//
// Store the ARC pathname of the floppy
//
BlGetPathnameFromComponent(Component,FloppyDiskPath);
return(FALSE);
}
return(TRUE); // keep searching
}
BOOLEAN
SlpOemInfSelection(
IN PVOID OemInfHandle,
IN PCHAR ComponentName,
IN PCHAR SelectedId,
IN PCHAR ItemDescription,
OUT PDETECTED_DEVICE Device
)
{
PCHAR FilesSectionName,ConfigSectionName;
ULONG Line,Count,Line2,Count2;
BOOLEAN rc = FALSE;
PDETECTED_DEVICE_FILE FileList = NULL, FileListTail;
PDETECTED_DEVICE_REGISTRY RegList = NULL, RegListTail;
ULONG FileTypeBits = 0;
//
// Iterate through the files section, remembering info about the
// files to be copied in support of the selection.
//
FilesSectionName = BlAllocateHeap(strlen(ComponentName) + strlen(SelectedId) + sizeof("Files.") + 1);
strcpy(FilesSectionName,"Files.");
strcat(FilesSectionName,ComponentName);
strcat(FilesSectionName,".");
strcat(FilesSectionName,SelectedId);
Count = SlCountLinesInSection(OemInfHandle,FilesSectionName);
if(Count == (ULONG)(-1)) {
SlMessageBox(SL_BAD_INF_SECTION,FilesSectionName);
goto sod0;
}
for(Line=0; Line<Count; Line++) {
PCHAR Disk,Filename,Filetype,Tagfile,Description,Directory,ConfigName;
HwFileType filetype;
PDETECTED_DEVICE_FILE FileStruct;
//
// Get the disk specification, filename, and filetype from the line.
//
Disk = SlGetSectionLineIndex(OemInfHandle,FilesSectionName,Line,OINDEX_DISKSPEC);
Filename = SlGetSectionLineIndex(OemInfHandle,FilesSectionName,Line,OINDEX_FILENAME);
Filetype = SlGetKeyName(OemInfHandle,FilesSectionName,Line);
if(!Disk || !Filename || !Filetype) {
DIAGOUT(("SlpOemDiskette: Disk=%s, Filename=%s, Filetype=%s",Disk ? Disk : "(null)",Filename ? Filename : "(null)",Filetype ? Filetype : "(null)"));
SlError(Line);
// SppOemInfError(ErrorMsg,&SptOemInfErr2,Line+1,FilesSectionName);
goto sod0;
}
//
// Parse the filetype.
//
filetype = SlpFindStringInTable(Filetype,FileTypeNames);
if(filetype == HwFileMax) {
// SppOemInfError(ErrorMsg,&SptOemInfErr4,Line+1,FilesSectionName);
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 = SlGetSectionLineIndex(OemInfHandle,FilesSectionName,Line,OINDEX_CONFIGNAME);
if(ConfigName == NULL) {
// SppOemInfError(ErrorMsg,&SptOemInfErr8,Line+1,FilesSectionName);
goto sod0;
}
} else {
ConfigName = NULL;
}
//
// Using the disk specification, look up the tagfile, description,
// and directory for the disk.
//
Tagfile = SlGetSectionKeyIndex(OemInfHandle,"Disks",Disk,OINDEX_TAGFILE);
Description = SlGetSectionKeyIndex(OemInfHandle,"Disks",Disk,OINDEX_DISKDESCR);
Directory = SlGetSectionKeyIndex(OemInfHandle,"Disks",Disk,OINDEX_DIRECTORY);
if((Directory == NULL) || !strcmp(Directory,"\\")) {
Directory = SlCopyString("");
}
if(!Tagfile || !Description) {
DIAGOUT(("SppOemDiskette: Tagfile=%s, Description=%s",Tagfile ? Tagfile : "(null)",Description ? Description : "(null)"));
// SppOemInfError(ErrorMsg,&SptOemInfErr5,Line+1,FilesSectionName);
goto sod0;
}
FileStruct = BlAllocateHeap(sizeof(DETECTED_DEVICE_FILE));
FileStruct->Directory = Directory;
FileStruct->Filename = Filename;
FileStruct->DiskDescription = Description;
FileStruct->DiskTagfile = Tagfile;
FileStruct->FileType = filetype;
//
// Insert at tail of list so we preserve the order in the Files section
//
if(FileList) {
FileListTail->Next = FileStruct;
FileListTail = FileStruct;
} else {
FileList = FileListTail = FileStruct;
}
FileStruct->Next = NULL;
if(ConfigName) {
FileStruct->ConfigName = ConfigName;
} else {
FileStruct->ConfigName = NULL;
}
FileStruct->RegistryValueList = NULL;
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 = BlAllocateHeap(strlen(ConfigName) + sizeof("Config."));
strcpy(ConfigSectionName,"Config.");
strcat(ConfigSectionName,ConfigName);
Count2 = SlCountLinesInSection(OemInfHandle,ConfigSectionName);
if(Count2 == (ULONG)(-1)) {
Count2 = 0;
}
for(Line2=0; Line2<Count2; Line2++) {
PCHAR KeyName,ValueName,ValueType;
PDETECTED_DEVICE_REGISTRY Reg;
HwRegistryType valuetype;
//
// Fetch KeyName, ValueName, and ValueType from the line.
//
KeyName = SlGetSectionLineIndex(OemInfHandle,ConfigSectionName,Line2,OINDEX_KEYNAME);
ValueName = SlGetSectionLineIndex(OemInfHandle,ConfigSectionName,Line2,OINDEX_VALUENAME);
ValueType = SlGetSectionLineIndex(OemInfHandle,ConfigSectionName,Line2,OINDEX_VALUETYPE);
if(!KeyName || !ValueName || !ValueType) {
DIAGOUT(("SlpOemDiskette: KeyName=%s, ValueName=%s, ValueType=%s",KeyName ? KeyName : "(null)",ValueName ? ValueName : "(null)",ValueType ? ValueType : "(null)"));
// SppOemInfError(ErrorMsg,&SptOemInfErr2,Line2+1,ConfigSectionName);
goto sod0;
}
//
// Parse the value type and associated values.
//
valuetype = SlpFindStringInTable(ValueType,RegistryTypeNames);
if(valuetype == HwRegistryMax) {
// SppOemInfError(ErrorMsg,&SptOemInfErr6,Line2+1,ConfigSectionName);
goto sod0;
}
Reg = SlpInterpretOemRegistryData(OemInfHandle,ConfigSectionName,Line2,valuetype);
if(Reg) {
Reg->KeyName = KeyName;
Reg->ValueName = ValueName;
//
// Insert at tail of list so as to preserve the order given in the config section
//
if(RegList) {
RegListTail->Next = Reg;
RegListTail = Reg;
} else {
RegList = RegListTail = Reg;
}
Reg->Next = NULL;
} else {
// SppOemInfError(ErrorMsg,&SptOemInfErr7,Line2+1,ConfigSectionName);
goto sod0;
}
}
FileStruct->RegistryValueList = RegList;
RegList = NULL;
}
}
//
// Everything is OK so we can place the information we have gathered
// into the main structure for the device class.
//
SlpInitDetectedDevice( Device,
SelectedId,
ItemDescription,
TRUE
);
Device->Files = FileList;
Device->FileTypeBits = FileTypeBits;
rc = TRUE;
//
// Clean up and exit.
//
sod0:
return(rc);
}
int
SlpFindStringInTable(
IN PCHAR String,
IN PCHAR *StringTable
)
/*++
Routine Description:
Locate a string in an array of strings, returning its index. The search
is not case sensitive.
Arguments:
String - string to locate in the string table.
StringTable - array of strings to search in. The final element of the
array must be NULL so we can tell where the table ends.
Return Value:
Index into the table, or some positive index outside the range of valid
indices for the table if the string is not found.
--*/
{
int i;
for(i=0; StringTable[i]; i++) {
if(_strcmpi(StringTable[i],String) == 0) {
return(i);
}
}
return(i);
}
VOID
SlpInitDetectedDevice(
IN PDETECTED_DEVICE Device,
IN PCHAR IdString,
IN PCHAR Description,
IN BOOLEAN ThirdPartyOptionSelected
)
{
Device->IdString = IdString;
Device->Description = Description;
Device->ThirdPartyOptionSelected = ThirdPartyOptionSelected;
Device->FileTypeBits = 0;
Device->Files = NULL;
}
PDETECTED_DEVICE_REGISTRY
SlpInterpretOemRegistryData(
IN PVOID InfHandle,
IN PCHAR SectionName,
IN ULONG Line,
IN HwRegistryType ValueType
)
{
PDETECTED_DEVICE_REGISTRY Reg;
PCHAR Value;
unsigned i,len;
ULONG Dword;
ULONG BufferSize;
PVOID Buffer = NULL;
PUCHAR BufferUchar;
//
// Perform appropriate action based on the type
//
switch(ValueType) {
case HwRegistryDword:
// case REG_DWORD_LITTLE_ENDIAN:
// case REG_DWORD_BIG_ENDIAN:
Value = SlGetSectionLineIndex(InfHandle,SectionName,Line,OINDEX_FIRSTVALUE);
if(Value == NULL) {
goto x1;
}
//
// Make sure it's really a hex number
//
len = strlen(Value);
if(len > 8) {
goto x1;
}
for(i=0; i<len; i++) {
if(!isxdigit(Value[i])) {
goto x1;
}
}
//
// convert it from ascii to a hex number
//
sscanf(Value,"%lx",&Dword);
#if 0
//
// If big endian, perform appropriate conversion
//
if(VaueType == REG_DWORD_BIG_ENDIAN) {
Dword = ((Dword << 24) & 0xff000000)
| ((Dword << 8) & 0x00ff0000)
| ((Dword >> 8) & 0x0000ff00)
| ((Dword >> 24) & 0x000000ff);
}
#endif
//
// Allocate a 4-byte buffer and store the dword in it
//
Buffer = BlAllocateHeap(BufferSize = sizeof(ULONG));
*(PULONG)Buffer = Dword;
break;
case HwRegistrySz:
case HwRegistryExpandSz:
Value = SlGetSectionLineIndex(InfHandle,SectionName,Line,OINDEX_FIRSTVALUE);
if(Value == NULL) {
goto x1;
}
//
// Allocate a buffer of appropriate size for the string
//
Buffer = BlAllocateHeap(BufferSize = strlen(Value)+1);
strcpy(Buffer, Value);
break;
case HwRegistryBinary:
Value = SlGetSectionLineIndex(InfHandle,SectionName,Line,OINDEX_FIRSTVALUE);
if(Value == NULL) {
goto x1;
}
//
// Figure out how many byte values are specified
//
len = strlen(Value);
if(len & 1) {
goto x1; // odd # of characters
}
//
// Allocate a buffer to hold the byte values
//
Buffer = BlAllocateHeap(BufferSize = len / 2);
BufferUchar = Buffer;
//
// For each digit pair, convert to a hex number and store in the
// buffer
//
for(i=0; i<len; i+=2) {
UCHAR byte;
unsigned j;
//
// Convert the current digit pair to hex
//
for(byte=0,j=i; j<i+2; j++) {
byte <<= 4;
if(isdigit(Value[j])) {
byte |= (UCHAR)Value[j] - (UCHAR)'0';
} else if((Value[j] >= 'a') && (Value[j] <= 'f')) {
byte |= (UCHAR)Value[j] - (UCHAR)'a' + (UCHAR)10;
} else if((Value[j] >= 'A') && (Value[j] <= 'F')) {
byte |= (UCHAR)Value[j] - (UCHAR)'A' + (UCHAR)10;
} else {
goto x1;
}
}
BufferUchar[i/2] = byte;
}
break;
case HwRegistryMultiSz:
//
// Calculate size of the buffer needed to hold all specified strings
//
for(BufferSize=1,i=0;
Value = SlGetSectionLineIndex(InfHandle,SectionName,Line,OINDEX_FIRSTVALUE+i);
i++)
{
BufferSize += strlen(Value)+1;
}
//
// Allocate a buffer of appropriate size
//
Buffer = BlAllocateHeap(BufferSize);
BufferUchar = Buffer;
//
// Store each string in the buffer, converting to wide char format
// in the process
//
for(i=0;
Value = SlGetSectionLineIndex(InfHandle,SectionName,Line,OINDEX_FIRSTVALUE+i);
i++)
{
strcpy(BufferUchar,Value);
BufferUchar += strlen(Value) + 1;
}
//
// Place final terminating nul in the buffer
//
*BufferUchar = 0;
break;
default:
x1:
//
// Error - bad type specified or maybe we detected bad data values
// and jumped here
//
return(NULL);
}
Reg = BlAllocateHeap(sizeof(DETECTED_DEVICE_REGISTRY));
Reg->ValueType = RegistryTypeMap[ValueType];
Reg->Buffer = Buffer;
Reg->BufferSize = BufferSize;
return(Reg);
}
PCHAR
SlPreInstallGetComponentName(
IN PVOID Inf,
IN PCHAR SectionName,
IN PCHAR TargetName
)
/*++
Routine Description:
Determines the canonical short name for a component to be loaded for
this machine.
Arguments:
Inf - Handle to an inf file (retail or OEM).
SectionName - Supplies the name of the section (eg. [Computer])
TargetName - Supplies the ARC string to be matched (eg. "Digital DECpc AXP 150")
Return Value:
NULL - No match was found.
PCHAR - Pointer to the canonical shortname of the component.
--*/
{
ULONG i;
PCHAR SearchName;
//
// If this is not an OEM component, then enumerate the entries in the
// section in txtsetup.sif
//
for (i=0;;i++) {
SearchName = SlGetSectionLineIndex(Inf,
SectionName,
i,
0);
if (SearchName==NULL) {
//
// we have enumerated the entire section without finding a
// match, return failure.
//
return(NULL);
}
if (_stricmp(TargetName, SearchName) == 0) {
//
// we have a match
//
break;
}
}
//
// i is the index into the section of the short machine name
//
return(SlGetKeyName(Inf,
SectionName,
i));
}