4013 lines
122 KiB
C
4013 lines
122 KiB
C
/*++
|
||
|
||
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>
|
||
|
||
#ifdef i386
|
||
#include <bldrx86.h>
|
||
#endif
|
||
|
||
#if DBG
|
||
|
||
#define DIAGOUT(x) SlPrint x
|
||
|
||
#else
|
||
|
||
#define DIAGOUT(x)
|
||
|
||
#endif
|
||
|
||
BOOLEAN PromptOemHal=FALSE;
|
||
BOOLEAN PromptOemScsi=FALSE;
|
||
BOOLEAN PromptOemVideo=FALSE;
|
||
PVOID PreInstallOemInfHandle = NULL;
|
||
|
||
//
|
||
// Floppy disks which need to be treated as
|
||
// as virtual floppies
|
||
//
|
||
const static ULONG VirtualFloppyStart = 1;
|
||
const static ULONG MinimumFloppiesToScan = 2;
|
||
|
||
|
||
#ifdef ARCI386
|
||
BOOLEAN PromptOemKeyboard=FALSE;
|
||
#endif
|
||
|
||
PCHAR FloppyDiskPath;
|
||
ULONG FloppyNumber=0;
|
||
ULONG IsSuperFloppy=0;
|
||
|
||
extern PCHAR BootPath;
|
||
extern PCHAR BootDevice;
|
||
extern ULONG BootDeviceId;
|
||
extern PVOID InfFile;
|
||
|
||
typedef struct _MENU_ITEM_DATA {
|
||
PVOID InfFile;
|
||
PCHAR SectionName;
|
||
ULONG Index;
|
||
PTCHAR 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 POEM_SOURCE_DEVICE OemSourceDevice,
|
||
IN PCHAR ComponentName,
|
||
IN OEMFILETYPE ComponentType,
|
||
IN ULONG MenuHeaderId,
|
||
OUT PDETECTED_DEVICE DetectedDevice,
|
||
OUT PVOID * ImageBase,
|
||
OUT OPTIONAL PCHAR * ImageName,
|
||
OUT OPTIONAL PTCHAR * DriverDescription,
|
||
IN BOOLEAN AllowUserSelection,
|
||
IN PTCHAR PreInstallComponentDescription,
|
||
OUT PPNP_HARDWARE_ID* HardwareIdDatabase,
|
||
IN PCHAR DriverDir,
|
||
IN BOOLEAN InsertDevice
|
||
);
|
||
|
||
BOOLEAN
|
||
SlpSelectHardware(
|
||
IN POEM_SOURCE_DEVICE SourceDevice,
|
||
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 PTCHAR * DriverDescription,
|
||
IN BOOLEAN AllowUserSelection,
|
||
IN PTCHAR PreInstallComponentDescription,
|
||
IN BOOLEAN PreInstallOemComponent,
|
||
OUT PPNP_HARDWARE_ID* HardwareIdDatabase
|
||
);
|
||
|
||
BOOLEAN
|
||
SlpOemInfSelection(
|
||
IN POEM_SOURCE_DEVICE OemSourceDevice,
|
||
IN PVOID OemInfHandle,
|
||
IN PCHAR ComponentName,
|
||
IN PCHAR SelectedId,
|
||
IN PTCHAR ItemDescription,
|
||
OUT PDETECTED_DEVICE Device,
|
||
OUT PPNP_HARDWARE_ID* HardwareIdDatabase,
|
||
IN PCHAR DriverDir
|
||
);
|
||
|
||
VOID
|
||
SlpInitDetectedDevice(
|
||
IN PDETECTED_DEVICE Device,
|
||
IN PCHAR IdString,
|
||
IN PTCHAR 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
|
||
);
|
||
|
||
BOOLEAN
|
||
SuperFloppyCallback(
|
||
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", "catalog"
|
||
};
|
||
|
||
//
|
||
// 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(
|
||
IN POEM_SOURCE_DEVICE ScsiSourceDevice,
|
||
IN BOOLEAN AllowUserSelection,
|
||
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:
|
||
|
||
ScsiSourceDevice - The OEM_SOURCE_DEVICE from which the the drivers need to
|
||
be loaded.
|
||
|
||
AllowUserSelection - Whether user can interact while selecting the driver
|
||
from txtsetup.oem driver list.
|
||
|
||
pOemScsiInfo - Returns a linked list containing info about any third-party scsi
|
||
drivers selected.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
|
||
{
|
||
PVOID OemScsiBase;
|
||
PTCHAR MessageString, ScsiDescription, MnemonicText;
|
||
PCHAR OemScsiName;
|
||
BOOLEAN Success, bFirstTime = TRUE, bRepaint;
|
||
ULONG x, y1, y2, ScsiDriverCount, NumToSkip;
|
||
ULONG c;
|
||
TCHAR Mnemonic;
|
||
POEMSCSIINFO NewOemScsi, CurOemScsi;
|
||
PDETECTED_DEVICE ScsiDevice;
|
||
ULONG OemScsiDriverCount = 0;
|
||
PPREINSTALL_DRIVER_INFO CurrentDriver;
|
||
|
||
CurrentDriver = PreinstallDriverList;
|
||
|
||
*pOemScsiInfo = CurOemScsi = NULL;
|
||
|
||
MnemonicText = BlFindMessage(SL_SCSI_SELECT_MNEMONIC);
|
||
Mnemonic = (TCHAR)_totupper(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, OemScsiDriverCount = 0, ScsiDevice = BlLoaderBlock->SetupLoaderBlock->ScsiDevices;
|
||
ScsiDevice;
|
||
ScsiDevice = ScsiDevice->Next) {
|
||
ScsiDriverCount++;
|
||
if( ScsiDevice->ThirdPartyOptionSelected ) {
|
||
OemScsiDriverCount++;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Display each loaded OEM miniport driver description.
|
||
//
|
||
if(OemScsiDriverCount) {
|
||
|
||
if(OemScsiDriverCount > MAX_SCSI_MINIPORT_COUNT) {
|
||
NumToSkip = ScsiDriverCount - (OemScsiDriverCount - MAX_SCSI_MINIPORT_COUNT);
|
||
//
|
||
// Display ellipses to indicate that top entries have scrolled out of view
|
||
//
|
||
SlGenericMessageBox(0,
|
||
NULL,
|
||
TEXT("..."),
|
||
&x,
|
||
&y1,
|
||
&y2,
|
||
FALSE
|
||
);
|
||
|
||
y1 = y2 + 1;
|
||
|
||
} else {
|
||
NumToSkip = ScsiDriverCount - OemScsiDriverCount;
|
||
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(ScsiSourceDevice,
|
||
"SCSI",
|
||
OEMSCSI,
|
||
LoaderBootDriver,
|
||
SL_PROMPT_SCSI,
|
||
SL_PROMPT_OEM_SCSI,
|
||
NULL,
|
||
&OemScsiBase,
|
||
&OemScsiName,
|
||
&ScsiDescription,
|
||
AllowUserSelection,
|
||
(AllowUserSelection)? NULL : CurrentDriver->DriverDescription,
|
||
(BOOLEAN)((AllowUserSelection)? FALSE : CurrentDriver->OemDriver),
|
||
&BlLoaderBlock->SetupLoaderBlock->HardwareIdDatabase);
|
||
|
||
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;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
SlLoadOemScsiDriversUnattended(
|
||
IN POEM_SOURCE_DEVICE OemSourceDevice,
|
||
IN PVOID InfHandle,
|
||
IN PCHAR ParamsSectionName,
|
||
IN PCHAR RootDirKeyName,
|
||
IN PCHAR BootDriversKeyName,
|
||
IN POEMSCSIINFO* ScsiInfo,
|
||
OUT PPNP_HARDWARE_ID* HardwareIdDatabase
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Loads the boot drivers (SCSI miniport only) specified in inf file
|
||
in an unattended fashion
|
||
|
||
Arguments:
|
||
|
||
OemSourceDevice - The OEM_SOURCE_DEVICE which contains the scsi
|
||
mass storage drivers that need to be loaded.
|
||
|
||
InfHandle - Handle to inf file (e.g. winnt.sif)
|
||
|
||
ParamsSectionName - The section name which contains the boot driver
|
||
keys and values.
|
||
|
||
RootDirKeyName - The key name whose value points to the root directory
|
||
under which all the different directories are present
|
||
|
||
BootDriversKeyName - The key name which consits of multiple values of
|
||
one level subdirectory name which are present under
|
||
the specified root directory.
|
||
|
||
ScsiInfo - Returns a linked list containing info about any third-party scsi
|
||
drivers loaded.
|
||
|
||
HardwareIdDatabase - Hardware Ids of the device which the loaded driver supports
|
||
|
||
Return Value:
|
||
|
||
TRUE, if successful otherwise FALSE
|
||
|
||
--*/
|
||
{
|
||
BOOLEAN LoadResult = FALSE;
|
||
|
||
if (InfHandle) {
|
||
POEMSCSIINFO CurrOemScsi = NULL;
|
||
ULONG Index = 0;
|
||
PCHAR DriverDir = SlGetSectionKeyIndex(InfHandle,
|
||
ParamsSectionName,
|
||
BootDriversKeyName,
|
||
Index);
|
||
PCHAR DriverRoot = SlGetSectionKeyIndex(InfHandle,
|
||
ParamsSectionName,
|
||
RootDirKeyName,
|
||
0);
|
||
ULONG RootLength = DriverRoot ? strlen(DriverRoot) : 0;
|
||
|
||
//
|
||
// DriverRoot and DriverDir need to have valid values
|
||
// in specified ParamsSectionName
|
||
//
|
||
LoadResult = (DriverDir && DriverRoot);
|
||
|
||
while (DriverDir && LoadResult) {
|
||
CHAR FullDriverDir[256];
|
||
DETECTED_DEVICE DetectedDevice = {0};
|
||
PVOID ImageBase = NULL;
|
||
PCHAR ImageName = NULL;
|
||
PTCHAR DriverDescription = NULL;
|
||
|
||
//
|
||
// Create the full path of the driver directory relative
|
||
// to the boot directory
|
||
//
|
||
if (RootLength) {
|
||
strcpy(FullDriverDir, DriverRoot);
|
||
strcat(FullDriverDir, "\\");
|
||
} else {
|
||
FullDriverDir[0] = 0;
|
||
}
|
||
|
||
strcat(FullDriverDir, DriverDir);
|
||
|
||
//
|
||
// Load the driver and related files, in an unattended manner
|
||
//
|
||
LoadResult = SlpOemDiskette(OemSourceDevice,
|
||
"SCSI",
|
||
OEMSCSI,
|
||
0,
|
||
&DetectedDevice,
|
||
&ImageBase,
|
||
&ImageName,
|
||
&DriverDescription,
|
||
FALSE,
|
||
NULL,
|
||
HardwareIdDatabase,
|
||
FullDriverDir,
|
||
TRUE);
|
||
|
||
if (LoadResult) {
|
||
//
|
||
// If the load was successful, then create and add the information
|
||
// ScsiInfo
|
||
//
|
||
if (ImageBase && ScsiInfo) {
|
||
POEMSCSIINFO NewScsi = (POEMSCSIINFO)BlAllocateHeap(sizeof(OEMSCSIINFO));
|
||
|
||
if (!NewScsi) {
|
||
SlNoMemoryError();
|
||
}
|
||
|
||
RtlZeroMemory(NewScsi, sizeof(OEMSCSIINFO));
|
||
NewScsi->ScsiBase = ImageBase;
|
||
NewScsi->ScsiName = ImageName;
|
||
|
||
if (CurrOemScsi) {
|
||
CurrOemScsi->Next = NewScsi;
|
||
} else {
|
||
*ScsiInfo = NewScsi;
|
||
}
|
||
|
||
CurrOemScsi = NewScsi;
|
||
}
|
||
|
||
//
|
||
// Get the next driver directory to process
|
||
//
|
||
Index++;
|
||
DriverDir = SlGetSectionKeyIndex(InfHandle,
|
||
ParamsSectionName,
|
||
BootDriversKeyName,
|
||
Index);
|
||
}
|
||
}
|
||
}
|
||
|
||
return LoadResult;
|
||
}
|
||
|
||
|
||
VOID
|
||
SlPromptOemHal(
|
||
IN POEM_SOURCE_DEVICE HalSourceDevice,
|
||
IN BOOLEAN AllowUserSelection,
|
||
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:
|
||
|
||
HalSourceDevice - The OEM_SOURCE_DEVICE which contains the HAL that needs
|
||
to be loaded.
|
||
|
||
AllowUserSelection - Indicates whether user can interact while selecting the
|
||
OEM hal from the list specified in txtsetup.oem.
|
||
|
||
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;
|
||
|
||
do {
|
||
Success = SlpSelectHardware(HalSourceDevice,
|
||
"Computer",
|
||
OEMHAL,
|
||
LoaderHalCode,
|
||
SL_PROMPT_HAL,
|
||
SL_PROMPT_OEM_HAL,
|
||
&BlLoaderBlock->SetupLoaderBlock->ComputerDevice,
|
||
HalBase,
|
||
HalName,
|
||
NULL,
|
||
AllowUserSelection,
|
||
ComputerType,
|
||
OemHal,
|
||
&BlLoaderBlock->SetupLoaderBlock->HardwareIdDatabase);
|
||
|
||
} while ( !Success );
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
SlPromptOemVideo(
|
||
IN POEM_SOURCE_DEVICE VideoSourceDevice,
|
||
IN BOOLEAN AllowUserSelection,
|
||
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:
|
||
|
||
VideoSourceDevice - The OEM_SOURCE_DEVICE which contains the video driver that
|
||
needs to be loaded.
|
||
|
||
AllowUserSelection - Indicates whether user can interact while selecting the
|
||
driver from the list specified in txtsetup.oem.
|
||
|
||
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(VideoSourceDevice,
|
||
"display",
|
||
OEMOTHER,
|
||
LoaderBootDriver,
|
||
SL_PROMPT_VIDEO,
|
||
SL_PROMPT_OEM_VIDEO,
|
||
&BlLoaderBlock->SetupLoaderBlock->VideoDevice,
|
||
VideoBase,
|
||
VideoName,
|
||
NULL,
|
||
AllowUserSelection,
|
||
NULL,
|
||
FALSE,
|
||
&BlLoaderBlock->SetupLoaderBlock->HardwareIdDatabase);
|
||
|
||
} while ( !Success );
|
||
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
SlpSelectHardware(
|
||
IN POEM_SOURCE_DEVICE SourceDevice,
|
||
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 PTCHAR *DriverDescription,
|
||
IN BOOLEAN AllowUserSelection,
|
||
IN PTCHAR PreInstallComponentDescription,
|
||
IN BOOLEAN PreInstallOemComponent,
|
||
OUT PPNP_HARDWARE_ID* HardwareIdDatabase
|
||
)
|
||
|
||
/*++
|
||
|
||
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:
|
||
|
||
SourceDevice - The device which contains the driver/hal that needs to
|
||
be loaded.
|
||
|
||
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 = 0;
|
||
TCHAR OtherSelectionName[80];
|
||
PTCHAR p;
|
||
ULONG c, i;
|
||
PCHAR AdapterName;
|
||
CHAR Buffer[80];
|
||
PCHAR FileName;
|
||
PTCHAR FileDescription;
|
||
ARC_STATUS Status;
|
||
BOOLEAN b;
|
||
ULONG Ordinal;
|
||
SCSI_INSERT_STATUS sis;
|
||
|
||
if( AllowUserSelection ) {
|
||
if(ComponentType != OEMSCSI) {
|
||
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"
|
||
//
|
||
_tcsncpy(OtherSelectionName,
|
||
BlFindMessage(SL_TEXT_OTHER_DRIVER),
|
||
80
|
||
);
|
||
OtherSelectionName[79] = TEXT('\0');
|
||
//
|
||
// Use text up to the first CR or LF.
|
||
//
|
||
for(p = OtherSelectionName; *p; p++) {
|
||
if((*p == TEXT('\n')) || (*p == TEXT('\r'))) {
|
||
*p = TEXT('\0');
|
||
break;
|
||
}
|
||
}
|
||
|
||
OtherSelection = SlAddMenuItem(Menu,
|
||
OtherSelectionName,
|
||
(PVOID)-1,
|
||
0);
|
||
|
||
//
|
||
// Default is "other"
|
||
//
|
||
Selection = OtherSelection;
|
||
} else {
|
||
//
|
||
// For SCSI devices we don't display any list of drivers for the user to choose.
|
||
// We just prompt for the OEM disk, this is because we always load all SCSI drivers
|
||
// in the NT product, due to pnp requirements.
|
||
//
|
||
//
|
||
// 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,
|
||
SlCopyStringAT(ComponentName),
|
||
TEXT("txtsetup.sif"));
|
||
goto SelectionAbort;
|
||
}
|
||
|
||
Selection = SlGetSectionKeyOrdinal( InfFile,
|
||
ComponentName,
|
||
q );
|
||
}
|
||
}
|
||
|
||
//
|
||
// Allow the user to interact with the menu
|
||
//
|
||
while (1) {
|
||
if( AllowUserSelection ) {
|
||
SlClearClientArea();
|
||
p = BlFindMessage(SL_SELECT_DRIVER_PROMPT);
|
||
if (p) {
|
||
SlWriteStatusText(p);
|
||
}
|
||
|
||
if(ComponentType != OEMSCSI) {
|
||
c = SlDisplayMenu(MenuHeaderId,
|
||
Menu,
|
||
&Selection);
|
||
} else {
|
||
//
|
||
// For SCSI devices, we don't display any list of driver for the user to chose
|
||
//
|
||
c = ASCI_CR;
|
||
}
|
||
} 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(SourceDevice,
|
||
ComponentName,
|
||
ComponentType,
|
||
OemMenuHeaderId,
|
||
DetectedDevice,
|
||
ImageBase,
|
||
ImageName,
|
||
DriverDescription,
|
||
AllowUserSelection,
|
||
PreInstallComponentDescription,
|
||
HardwareIdDatabase,
|
||
NULL,
|
||
TRUE);
|
||
|
||
|
||
SlClearClientArea();
|
||
SlWriteStatusText(TEXT(""));
|
||
return(b);
|
||
|
||
} else {
|
||
//
|
||
// User selected a built-in. Go ahead and load
|
||
// it here.
|
||
//
|
||
|
||
if(ComponentType == OEMHAL) {
|
||
//
|
||
// We are looking for a HAL. If we're doing a remote
|
||
// boot, look in the [Hal] section. Otherwise, look in
|
||
// the [Hal.Load] section. (Local setup has a separate
|
||
// section to minimize the number of HAL binaries that
|
||
// need to be on the boot floppies.)
|
||
//
|
||
strcpy(Buffer, BlBootingFromNet ? "Hal" : "Hal.Load");
|
||
} else {
|
||
sprintf(Buffer, "%s.Load", ComponentName );
|
||
}
|
||
|
||
AdapterName = SlGetKeyName(InfFile,
|
||
ComponentName,
|
||
Selection
|
||
);
|
||
if(AdapterName==NULL) {
|
||
SlFatalError(SL_BAD_INF_FILE, TEXT("txtsetup.sif"), ENODEV);
|
||
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 {
|
||
#ifdef UNICODE
|
||
FileDescription = SlGetIniValueW(
|
||
#else
|
||
FileDescription = SlGetIniValue(
|
||
#endif
|
||
InfFile,
|
||
ComponentName,
|
||
AdapterName,
|
||
NULL);
|
||
}
|
||
|
||
if(FileName==NULL) {
|
||
SlFatalError(SL_BAD_INF_FILE, TEXT("txtsetup.sif"), EBADF);
|
||
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, TEXT("txtsetup.sif"), EINVAL);
|
||
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(_stricmp(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);
|
||
|
||
#ifdef i386
|
||
retryhal:
|
||
#endif
|
||
BlOutputLoadMessage(BootDevice, FileName, FileDescription);
|
||
Status = BlLoadImage(BootDeviceId,
|
||
LoaderHalCode,
|
||
Buffer,
|
||
TARGET_IMAGE,
|
||
ImageBase
|
||
);
|
||
#ifdef i386
|
||
//
|
||
// If the HAL didn't fit in the preferred range, reset the range to
|
||
// all of memory and try again.
|
||
//
|
||
if ((Status == ENOMEM) &&
|
||
((BlUsableBase != 0) ||
|
||
(BlUsableLimit != _16MB))) {
|
||
BlUsableBase = 0;
|
||
BlUsableLimit = _16MB;
|
||
|
||
goto retryhal;
|
||
}
|
||
#endif
|
||
} else {
|
||
*ImageBase = NULL;
|
||
Status = ESUCCESS;
|
||
}
|
||
}
|
||
|
||
if (Status != ESUCCESS) {
|
||
SlMessageBox(SL_FILE_LOAD_FAILED,Buffer,Status);
|
||
goto SelectionAbort;
|
||
}
|
||
|
||
SlClearClientArea();
|
||
SlWriteStatusText(TEXT(""));
|
||
return(TRUE);
|
||
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
SelectionAbort:
|
||
SlClearClientArea();
|
||
SlWriteStatusText(TEXT(""));
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
ARC_STATUS
|
||
SlGetDriverTimeStampFromFile(
|
||
IN ULONG DeviceId,
|
||
IN PCHAR DriverPath,
|
||
OUT PULONG TimeDateStamp
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Gets the driver's link time stamp from the the image
|
||
header.
|
||
|
||
Arguments:
|
||
|
||
DeviceId : Device on which the driver file resides (e.g. floppy)
|
||
|
||
DriverPath : Full qualified path of the driver file
|
||
|
||
TimeDateStamp : Place holder to return the image header time stamp
|
||
|
||
Return Value:
|
||
|
||
ESUCCESS if successful, otherwise appropriate error code.
|
||
|
||
--*/
|
||
{
|
||
ARC_STATUS Status = EINVAL;
|
||
|
||
if (DriverPath && TimeDateStamp) {
|
||
UCHAR UBuffer[SECTOR_SIZE * 2 + 256] = {0};
|
||
UCHAR *Buffer = ALIGN_BUFFER(UBuffer);
|
||
ULONG FileId = 0;
|
||
|
||
//
|
||
// open the file
|
||
//
|
||
Status = BlOpen(DeviceId, DriverPath, ArcOpenReadOnly, &FileId);
|
||
|
||
if (Status == ESUCCESS) {
|
||
ULONG BytesToRead = SECTOR_SIZE * 2;
|
||
ULONG BytesRead = 0;
|
||
|
||
//
|
||
// read the first two sectors of the file
|
||
//
|
||
Status = BlRead(FileId, Buffer, BytesToRead, &BytesRead);
|
||
|
||
if ((Status == ESUCCESS) && (BytesToRead == BytesRead)) {
|
||
PIMAGE_NT_HEADERS ImgHdr = RtlImageNtHeader(Buffer);
|
||
Status = EINVAL;
|
||
|
||
if (ImgHdr) {
|
||
*TimeDateStamp = ImgHdr->FileHeader.TimeDateStamp;
|
||
Status = ESUCCESS;
|
||
}
|
||
}
|
||
|
||
BlClose(FileId);
|
||
}
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
BOOLEAN
|
||
SlRemoveInboxDriver(
|
||
IN PCHAR DriverToRemove
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Removes the given driver name from list of the
|
||
SCSI miniport devices that need to be loaded as default
|
||
boot driver.
|
||
|
||
Arguments:
|
||
|
||
DriverToRemove : Driver base name, that needs to be removed
|
||
|
||
Return Value:
|
||
|
||
TRUE, if the driver was found and removed otherwise FALSE
|
||
|
||
--*/
|
||
{
|
||
BOOLEAN Result = FALSE;
|
||
|
||
if (DriverToRemove) {
|
||
PDETECTED_DEVICE NodePtr = BlLoaderBlock->SetupLoaderBlock->ScsiDevices;
|
||
PDETECTED_DEVICE PrevNode = NULL;
|
||
|
||
while (NodePtr) {
|
||
if (NodePtr->BaseDllName && !_stricmp(NodePtr->BaseDllName, DriverToRemove))
|
||
break;
|
||
|
||
PrevNode = NodePtr;
|
||
NodePtr = NodePtr->Next;
|
||
}
|
||
|
||
if (NodePtr) {
|
||
if (PrevNode) {
|
||
PrevNode->Next = NodePtr->Next;
|
||
Result = TRUE;
|
||
} else {
|
||
if (NodePtr == BlLoaderBlock->SetupLoaderBlock->ScsiDevices) {
|
||
BlLoaderBlock->SetupLoaderBlock->ScsiDevices = NULL;
|
||
Result = TRUE;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return Result;
|
||
}
|
||
|
||
ARC_STATUS
|
||
SlConstructDriverPath(
|
||
IN PDETECTED_DEVICE Device,
|
||
IN PCHAR DefaultPath,
|
||
OUT PCHAR FullPath
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Constructs a fully qualified driver path given the device node.
|
||
|
||
Arguments:
|
||
|
||
Device : The device for which the path needs to be created.
|
||
|
||
Defaultpath : Directory path to use, if device does not has file list.
|
||
|
||
FullPath : Placeholder to return the constructed path
|
||
|
||
Return Value:
|
||
|
||
ESUCCESS if path is constructed, otherwise a proper error code.
|
||
|
||
--*/
|
||
{
|
||
ARC_STATUS Status = EINVAL;
|
||
|
||
if (Device && FullPath) {
|
||
PDETECTED_DEVICE_FILE Node = Device->Files;
|
||
|
||
//
|
||
// locate the driver file
|
||
//
|
||
while (Node) {
|
||
HwFileType FileType = Node->FileType;
|
||
|
||
if((FileType == HwFilePort) || (FileType == HwFileClass) ||
|
||
(FileType == HwFileDriver) || (FileType == HwFileHal)) {
|
||
break;
|
||
}
|
||
|
||
Node = Node->Next;
|
||
}
|
||
|
||
if (Node && Node->Filename) {
|
||
*FullPath = '\0';
|
||
|
||
if (Node->Directory)
|
||
strcat(FullPath, Node->Directory);
|
||
|
||
//
|
||
// append separator only if directory-name does not have
|
||
// trailing separator or the the filename does
|
||
// not have a leading separator
|
||
//
|
||
if ((Node->Filename[0] != '\\') && (*FullPath) &&
|
||
(FullPath[strlen(FullPath) - 1] != '\\')) {
|
||
strcat(FullPath, "\\");
|
||
}
|
||
|
||
strcat(FullPath, Node->Filename);
|
||
Status = ESUCCESS;
|
||
} else {
|
||
if (DefaultPath && Device->BaseDllName) {
|
||
//
|
||
// default path has a valid trailing separator
|
||
//
|
||
strcpy(FullPath, DefaultPath);
|
||
strcat(FullPath, Device->BaseDllName);
|
||
Status = ESUCCESS;
|
||
}
|
||
}
|
||
|
||
if (Status != ESUCCESS)
|
||
*FullPath = '\0';
|
||
}
|
||
|
||
|
||
return Status;
|
||
}
|
||
|
||
VERSION_COMP_RESULT
|
||
SlCompareDriverVersion(
|
||
IN ULONG InboxDeviceId,
|
||
IN PDETECTED_DEVICE InboxDriver,
|
||
IN ULONG OemDeviceId,
|
||
IN PDETECTED_DEVICE OemDriver
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Compares the version of an inbox driver and oem driver
|
||
based on the link date-time stamp present in the image
|
||
header.
|
||
|
||
Arguments:
|
||
|
||
InboxDeviceId : Boot device ID
|
||
|
||
InboxDriver : Device containing inbox driver details
|
||
|
||
OemDeviceId : Oem device ID (either floppy or boot device)
|
||
|
||
OemDriver : Device containing OEM driver details
|
||
|
||
Return Value:
|
||
|
||
VersionErr if not able to get version information for the
|
||
drivers, otherwise one of the following appropriately :
|
||
VersionSame, VersionOemNew, VersionInboxNew
|
||
|
||
--*/
|
||
{
|
||
VERSION_COMP_RESULT Result = VersionError;
|
||
|
||
if (InboxDriver && OemDriver) {
|
||
CHAR FullPath[256];
|
||
ULONG InboxDateTime = 0, OemDateTime = 0;
|
||
ARC_STATUS Status;
|
||
|
||
Status = SlConstructDriverPath(InboxDriver, BootPath, FullPath);
|
||
|
||
if (Status == ESUCCESS) {
|
||
Status = SlGetDriverTimeStampFromFile(InboxDeviceId,
|
||
FullPath, &InboxDateTime);
|
||
|
||
if (Status == ESUCCESS) {
|
||
Status = SlConstructDriverPath(OemDriver, NULL, FullPath);
|
||
|
||
if (Status == ESUCCESS) {
|
||
Status = SlGetDriverTimeStampFromFile(OemDeviceId,
|
||
FullPath, &OemDateTime);
|
||
}
|
||
}
|
||
}
|
||
|
||
if ((Status == ESUCCESS) && InboxDateTime && OemDateTime) {
|
||
if (InboxDateTime != OemDateTime) {
|
||
Result = (InboxDateTime > OemDateTime) ?
|
||
VersionInboxNew : VersionOemNew;
|
||
} else {
|
||
Result = VersionSame;
|
||
}
|
||
}
|
||
}
|
||
|
||
return Result;
|
||
}
|
||
|
||
BOOLEAN
|
||
SlConfirmInboxDriverReplacement(
|
||
IN PTCHAR DriverName,
|
||
IN PTCHAR AdditionalInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Puts up a dialog box on the screen giving information about
|
||
the same inbox driver and oem driver being loaded, asking
|
||
for user selection i.e. either OEM or INBOX driver.
|
||
|
||
Arguments:
|
||
|
||
DriverName : Driver name which is same for inbox and OEM
|
||
|
||
AdditionalInfo : Which driver is newer i.e. either OEM or
|
||
Inbox or nothing if could not determine which driver is
|
||
newer.
|
||
|
||
Return Value:
|
||
|
||
TRUE if the user selected to replace default driver with OEM
|
||
driver, otherwise return FALSE indicating that user wants
|
||
to use inbox driver.
|
||
|
||
--*/
|
||
{
|
||
ULONG KeyPressed = 0;
|
||
PTCHAR MnemonicText = BlFindMessage(SL_SCSI_SELECT_MNEMONIC);
|
||
ULONG Mnemonic = MnemonicText ? toupper(MnemonicText[0]) : 'S';
|
||
|
||
if (AdditionalInfo) {
|
||
ULONG Len = _tcslen(AdditionalInfo);
|
||
|
||
if ((Len >= 2) && (AdditionalInfo[Len-2] == TEXT('\r')) &&
|
||
(AdditionalInfo[Len-1] == TEXT('\n'))) {
|
||
AdditionalInfo[Len-2] = TEXT('\0');
|
||
}
|
||
}
|
||
|
||
if (DriverName) {
|
||
SlClearClientArea();
|
||
SlDisplayMessageBox(SL_OEM_DRIVERINFO, AdditionalInfo, DriverName);
|
||
SlWriteStatusText(BlFindMessage(SL_CONFIRM_OEMDRIVER));
|
||
|
||
do {
|
||
KeyPressed = SlGetChar();
|
||
KeyPressed = toupper(KeyPressed);
|
||
}
|
||
while ((KeyPressed != ASCI_CR) && (KeyPressed != Mnemonic));
|
||
|
||
SlClearClientArea();
|
||
SlWriteStatusText(TEXT(""));
|
||
}
|
||
|
||
return (KeyPressed == Mnemonic);
|
||
}
|
||
|
||
PDETECTED_DEVICE
|
||
SlCheckForInboxDriver(
|
||
IN PCHAR DriverToCheck
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Searches the inbox SCSI miniport list to see if a driver
|
||
of the given name exists.
|
||
|
||
Arguments:
|
||
|
||
DriverToCheck : Base driver name to look for, in the list
|
||
|
||
Return Value:
|
||
|
||
Pointer to device node containing driver information, if the
|
||
given driver name is found, otherwise NULL
|
||
|
||
--*/
|
||
{
|
||
PDETECTED_DEVICE NodePtr = NULL;
|
||
|
||
if (DriverToCheck) {
|
||
NodePtr = BlLoaderBlock->SetupLoaderBlock->ScsiDevices;
|
||
|
||
while (NodePtr) {
|
||
if (NodePtr->BaseDllName && !_stricmp(NodePtr->BaseDllName, DriverToCheck)) {
|
||
break;
|
||
}
|
||
|
||
NodePtr = NodePtr->Next;
|
||
}
|
||
}
|
||
|
||
return NodePtr;
|
||
}
|
||
|
||
|
||
|
||
BOOLEAN
|
||
SlpOemDiskette(
|
||
IN POEM_SOURCE_DEVICE OemSourceDevice,
|
||
IN PCHAR ComponentName,
|
||
IN OEMFILETYPE ComponentType,
|
||
IN ULONG MenuHeaderId,
|
||
OUT OPTIONAL PDETECTED_DEVICE DetectedDevice,
|
||
OUT PVOID *ImageBase,
|
||
OUT OPTIONAL PCHAR *ImageName,
|
||
OUT OPTIONAL PTCHAR *DriverDescription,
|
||
IN BOOLEAN AllowUserSelection,
|
||
IN PTCHAR PreInstallComponentDescription,
|
||
OUT PPNP_HARDWARE_ID* HardwareIdDatabase,
|
||
IN PCHAR DriverDir,
|
||
IN BOOLEAN InsertDevice
|
||
)
|
||
|
||
/*++
|
||
|
||
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:
|
||
|
||
OemSourceDevice - The device which contains the driver/hal that
|
||
needs to be loaded.
|
||
|
||
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.
|
||
|
||
HardwareIdDatabase - The hardware IDs what were loaded for the particular
|
||
driver.
|
||
|
||
DriverDir - The driver directory which has the dynamic update driver. The
|
||
path is relative to the boot directory. This value indicates
|
||
that the driver to be loaded is dyamic update boot driver.
|
||
|
||
InsertDevice - Indicates whether to insert the device into the detected
|
||
device list or not. Currently only valid for SCSI mass storage device
|
||
drivers.
|
||
|
||
Return Value:
|
||
|
||
TRUE if the user made a choice, FALSE if the user cancelled/error occurred.
|
||
|
||
--*/
|
||
|
||
{
|
||
static CHAR LoadDeviceName[128];
|
||
ULONG LoadDeviceId = -1;
|
||
PVOID OemInfHandle = NULL;
|
||
ULONG Error;
|
||
ARC_STATUS Status;
|
||
ULONG Count;
|
||
ULONG DefaultSelection;
|
||
PTCHAR DefaultSelText = NULL;
|
||
PCHAR p;
|
||
PSL_MENU Menu;
|
||
ULONG c;
|
||
PMENU_ITEM_DATA Data;
|
||
PDETECTED_DEVICE_FILE FileStruct;
|
||
BOOLEAN bDriverLoaded;
|
||
HwFileType filetype;
|
||
PDETECTED_DEVICE prev, cur;
|
||
static CHAR FullDriverPath[256];
|
||
ULONG DirectoryLength;
|
||
BOOLEAN SeparatorNeeded;
|
||
static CHAR FilePath[256];
|
||
PCHAR OemComponentId = NULL;
|
||
PTCHAR OemComponentDescription;
|
||
DETECTED_DEVICE TempDevice;
|
||
static TCHAR ScratchBuffer[256] = {0};
|
||
PDETECTED_DEVICE InboxDevice;
|
||
BOOLEAN DynamicUpdate = FALSE;
|
||
BOOLEAN Preinstallation = FALSE;
|
||
BOOLEAN DeviceOpened = FALSE;
|
||
|
||
//
|
||
// If source device is specified, then probe it and
|
||
// extract some required state information
|
||
//
|
||
if (OemSourceDevice) {
|
||
if (SL_OEM_SOURCE_DEVICE_TYPE(OemSourceDevice,
|
||
SL_OEM_SOURCE_DEVICE_TYPE_DYN_UPDATE)) {
|
||
DynamicUpdate = TRUE;
|
||
}
|
||
|
||
if (SL_OEM_SOURCE_DEVICE_TYPE(OemSourceDevice,
|
||
SL_OEM_SOURCE_DEVICE_TYPE_PREINSTALL)) {
|
||
Preinstallation = TRUE;
|
||
}
|
||
|
||
//
|
||
// Is the inf already opened ?
|
||
//
|
||
if (!DynamicUpdate && OemSourceDevice->InfHandle &&
|
||
!SL_OEM_SOURCE_DEVICE_STATE(OemSourceDevice,
|
||
SL_OEM_SOURCE_DEVICE_PROCESSED)) {
|
||
OemInfHandle = OemSourceDevice->InfHandle;
|
||
}
|
||
|
||
LoadDeviceId = OemSourceDevice->DeviceId;
|
||
}
|
||
|
||
if (AllowUserSelection) {
|
||
SlClearClientArea();
|
||
}
|
||
|
||
if (AllowUserSelection) {
|
||
//
|
||
// Only try to detect floppy 0 if no source device
|
||
// specified
|
||
//
|
||
if (OemSourceDevice) {
|
||
strcpy(LoadDeviceName, OemSourceDevice->ArcDeviceName);
|
||
LoadDeviceId = OemSourceDevice->DeviceId;
|
||
} else {
|
||
//
|
||
// Compute the name of the A: drive
|
||
//
|
||
if (!SlpFindFloppy(0, LoadDeviceName)) {
|
||
ULONG UserInput;
|
||
|
||
//
|
||
// No floppy drive available, bail out.
|
||
//
|
||
SlClearClientArea();
|
||
SlDisplayMessageBox(SL_NO_FLOPPY_DRIVE);
|
||
|
||
do {
|
||
UserInput = SlGetChar();
|
||
}
|
||
while ((UserInput != ASCI_ESC) && (UserInput != SL_KEY_F3));
|
||
|
||
if (UserInput == SL_KEY_F3) {
|
||
ArcRestart();
|
||
}
|
||
|
||
SlClearClientArea();
|
||
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Open the device if its not already done
|
||
//
|
||
if (LoadDeviceId == -1) {
|
||
//
|
||
// Prompt for the disk.
|
||
//
|
||
while(1) {
|
||
if (!SlPromptForDisk(BlFindMessage(SL_OEM_DISK_PROMPT), TRUE)) {
|
||
return(FALSE);
|
||
}
|
||
|
||
Status = ArcOpen(LoadDeviceName, ArcOpenReadOnly, &LoadDeviceId);
|
||
|
||
if(Status == ESUCCESS) {
|
||
DeviceOpened = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Load the OEM INF file
|
||
//
|
||
if( AllowUserSelection ) {
|
||
*FilePath = *FullDriverPath = '\0';
|
||
} else {
|
||
PCHAR p;
|
||
|
||
if (DynamicUpdate || Preinstallation) {
|
||
strcpy(FilePath, BootPath);
|
||
} else {
|
||
*FilePath = '\0';
|
||
}
|
||
|
||
if (DynamicUpdate && DriverDir) {
|
||
//
|
||
// In case of dynamic update boot drivers
|
||
// the path to txtsetup.oem needs to be fully
|
||
// qualified from the boot directory
|
||
//
|
||
strcat(FilePath, DriverDir);
|
||
}
|
||
|
||
if (PreInstall) {
|
||
#if defined(_X86_)
|
||
if ( BlBootingFromNet ) {
|
||
#endif
|
||
//
|
||
// On RISC platforms and on x86 remote boot clients,
|
||
// remove the platform specific directory from the path.
|
||
//
|
||
p = (FilePath + strlen(FilePath) - 1);
|
||
|
||
if( *p == '\\' ) {
|
||
*p = '\0';
|
||
}
|
||
|
||
p = strrchr(FilePath, '\\');
|
||
|
||
*(p+1) = '\0';
|
||
#if defined(_X86_)
|
||
}
|
||
#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
|
||
// but on remote boot clients, the path is going to be:
|
||
// \device\lanmanredirector\server\reminst\setup\language\images\build\$OEM$\TEXTMODE
|
||
//
|
||
strcat(
|
||
FilePath,
|
||
#if defined(_X86_)
|
||
BlBootingFromNet ? WINNT_OEM_TEXTMODE_DIR_A : WINNT_OEM_DIR_A
|
||
#else
|
||
WINNT_OEM_TEXTMODE_DIR_A
|
||
#endif
|
||
);
|
||
}
|
||
|
||
//
|
||
// Save the path to the directory that contains txtsetup.oem.
|
||
// It will be used later on, when we load the driver.
|
||
//
|
||
strcpy(FullDriverPath, FilePath);
|
||
strcat(FilePath, "\\");
|
||
}
|
||
|
||
//
|
||
// Now form the path to txtsetup.oem
|
||
//
|
||
strcat(FilePath, "txtsetup.oem");
|
||
|
||
//
|
||
// Note : Reload the txtsetup.oem again in dynamic update boot driver case
|
||
// since for each driver the txtsetup.oem is different in its own
|
||
// downloaded directory
|
||
//
|
||
if (!OemInfHandle) {
|
||
if (DriverDir || AllowUserSelection || (PreInstallOemInfHandle == NULL)) {
|
||
Status = SlInitIniFile(NULL,
|
||
LoadDeviceId,
|
||
FilePath,
|
||
&OemInfHandle,
|
||
NULL,
|
||
NULL,
|
||
&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 (!PreInstallComponentDescription) {
|
||
if(p = SlGetSectionKeyIndex(OemInfHandle, "Defaults",ComponentName, 0)) {
|
||
#ifdef UNICODE
|
||
DefaultSelText = SlGetSectionKeyIndexW(
|
||
#else
|
||
DefaultSelText = SlGetSectionKeyIndex(
|
||
#endif
|
||
OemInfHandle,
|
||
ComponentName,
|
||
p,
|
||
0);
|
||
|
||
//
|
||
// Save away the component id
|
||
//
|
||
OemComponentId = p;
|
||
} else {
|
||
DefaultSelText = NULL;
|
||
}
|
||
} else {
|
||
DefaultSelText = PreInstallComponentDescription;
|
||
}
|
||
|
||
//
|
||
// In case of dynamic update drivers, if the defaults is not set then
|
||
// use the first entry in the section as the default !!!
|
||
//
|
||
if (DynamicUpdate && !AllowUserSelection && !DefaultSelText) {
|
||
OemComponentId = SlGetKeyName(
|
||
OemInfHandle,
|
||
ComponentName,
|
||
0);
|
||
}
|
||
|
||
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 (!DetectedDevice) {
|
||
RtlZeroMemory(&TempDevice, sizeof(DETECTED_DEVICE));
|
||
DetectedDevice = &TempDevice;
|
||
}
|
||
|
||
//
|
||
// We create a new device using SlInsertScsiDevice(...) only if we load
|
||
// the requested SCSI miniport successfully
|
||
//
|
||
if (ComponentType == OEMSCSI) {
|
||
DetectedDevice->Ordinal= (ULONG)-1;
|
||
}
|
||
|
||
if( AllowUserSelection ) {
|
||
Data = SlGetMenuItem(Menu, DefaultSelection);
|
||
OemComponentId = Data->Identifier;
|
||
OemComponentDescription = Data->Description;
|
||
} else {
|
||
if (PreInstallComponentDescription) {
|
||
OemComponentId = SlPreInstallGetComponentName( OemInfHandle,
|
||
ComponentName,
|
||
PreInstallComponentDescription );
|
||
if( OemComponentId == NULL ) {
|
||
SlFatalError(SL_BAD_UNATTENDED_SCRIPT_FILE,
|
||
PreInstallComponentDescription,
|
||
SlCopyStringAT(ComponentName),
|
||
"txtsetup.oem");
|
||
|
||
}
|
||
|
||
OemComponentDescription = PreInstallComponentDescription;
|
||
} else {
|
||
#ifdef UNICODE
|
||
OemComponentDescription = SlGetSectionKeyIndexW(
|
||
OemInfHandle,
|
||
ComponentName,
|
||
OemComponentId,
|
||
0);
|
||
#else
|
||
OemComponentDescription = SlGetSectionKeyIndex(
|
||
OemInfHandle,
|
||
ComponentName,
|
||
OemComponentId,
|
||
0);
|
||
#endif
|
||
}
|
||
}
|
||
|
||
|
||
if(SlpOemInfSelection(OemSourceDevice,
|
||
OemInfHandle,
|
||
ComponentName,
|
||
OemComponentId,
|
||
OemComponentDescription,
|
||
DetectedDevice,
|
||
HardwareIdDatabase,
|
||
FullDriverPath)) {
|
||
//
|
||
// 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)) {
|
||
ULONG DirLength;
|
||
|
||
BlOutputLoadMessage(
|
||
LoadDeviceName,
|
||
FileStruct->Filename,
|
||
OemComponentDescription // Data->Description
|
||
);
|
||
|
||
|
||
//
|
||
// Reconstruct the FullDriverPath
|
||
//
|
||
strcpy(FullDriverPath, FileStruct->Directory);
|
||
DirLength = strlen(FullDriverPath);
|
||
|
||
if (DirLength && (FullDriverPath[DirLength - 1] != '\\')) {
|
||
strcat(FullDriverPath, "\\");
|
||
}
|
||
|
||
strcat(FullDriverPath, FileStruct->Filename);
|
||
|
||
if (ComponentType == OEMSCSI) {
|
||
PTCHAR FmtStr = 0;
|
||
|
||
//
|
||
// Verify that we don't have an in-box driver
|
||
//
|
||
InboxDevice = SlCheckForInboxDriver(FileStruct->Filename);
|
||
|
||
if (InboxDevice) {
|
||
VERSION_COMP_RESULT VerResult;
|
||
PTCHAR AdditionalInfo;
|
||
PTCHAR DriverName = OemComponentDescription;
|
||
#ifdef UNICODE
|
||
WCHAR FileNameW[100];
|
||
#endif
|
||
|
||
if(DriverName == NULL) {
|
||
#ifdef UNICODE
|
||
UNICODE_STRING uString;
|
||
ANSI_STRING aString;
|
||
RtlInitAnsiString(&aString, FileStruct->Filename);
|
||
uString.Buffer = FileNameW;
|
||
uString.MaximumLength = sizeof(FileNameW);
|
||
RtlAnsiStringToUnicodeString(&uString, &aString, FALSE);
|
||
//
|
||
// the converted string is NULL-terminated
|
||
//
|
||
DriverName = FileNameW;
|
||
#else
|
||
DriverName = FileStruct->Filename;
|
||
#endif
|
||
}
|
||
|
||
//
|
||
// Compare the drivers version's using link time stamp
|
||
//
|
||
VerResult = SlCompareDriverVersion(
|
||
BootDeviceId,
|
||
InboxDevice,
|
||
LoadDeviceId,
|
||
DetectedDevice
|
||
);
|
||
|
||
//
|
||
// Show additional message to the user about the driver
|
||
// version mismatch
|
||
//
|
||
switch (VerResult) {
|
||
case VersionOemNew:
|
||
AdditionalInfo = BlFindMessage(SL_OEMDRIVER_NEW);
|
||
break;
|
||
|
||
case VersionInboxNew:
|
||
AdditionalInfo = BlFindMessage(SL_INBOXDRIVER_NEW);
|
||
break;
|
||
|
||
default:
|
||
AdditionalInfo = TEXT("");
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Show the message and get confirmation from user
|
||
// only in attended case. In case of dynamic update
|
||
// boot drivers just use the inbox driver itself
|
||
//
|
||
if (AllowUserSelection &&
|
||
SlConfirmInboxDriverReplacement(DriverName,
|
||
AdditionalInfo)) {
|
||
//
|
||
// Remove the driver node from inbox SCSI miniport
|
||
// list
|
||
//
|
||
SlRemoveInboxDriver(FileStruct->Filename);
|
||
} else {
|
||
//
|
||
// User selected to use inbox driver
|
||
//
|
||
if (AllowUserSelection) {
|
||
|
||
if (DeviceOpened) {
|
||
ArcClose(LoadDeviceId);
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
if (DynamicUpdate) {
|
||
//
|
||
// NOTE: Use the inbox driver instead
|
||
// of dynamic update driver
|
||
//
|
||
return TRUE;
|
||
}
|
||
|
||
//
|
||
// If user already loaded another third party
|
||
// driver then honor that
|
||
//
|
||
if (InboxDevice->ThirdPartyOptionSelected) {
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// NOTE : For other autoload features we
|
||
// use the OEM driver, instead of inbox
|
||
// driver to make auto load feature
|
||
// meaningful.
|
||
}
|
||
}
|
||
|
||
//
|
||
// Inform the user that the driver is being loaded
|
||
//
|
||
FmtStr = BlFindMessage(SL_FILE_LOAD_MESSAGE);
|
||
|
||
if (FmtStr && !WinPEBoot) {
|
||
PTSTR pFileName;
|
||
#ifdef UNICODE
|
||
WCHAR FileNameW[64];
|
||
ANSI_STRING aString;
|
||
UNICODE_STRING uString;
|
||
|
||
RtlInitString( &aString, FileStruct->Filename );
|
||
uString.Buffer = FileNameW;
|
||
uString.MaximumLength = sizeof(FileNameW);
|
||
RtlAnsiStringToUnicodeString( &uString, &aString, FALSE );
|
||
|
||
pFileName = FileNameW;
|
||
|
||
#else
|
||
pFileName = FileStruct->Filename;
|
||
|
||
#endif
|
||
_stprintf(ScratchBuffer, FmtStr, pFileName);
|
||
SlWriteStatusText(ScratchBuffer);
|
||
}
|
||
}
|
||
|
||
Status = BlLoadImage(LoadDeviceId,
|
||
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 (DeviceOpened) {
|
||
ArcClose(LoadDeviceId);
|
||
}
|
||
|
||
return FALSE;
|
||
} else {
|
||
SlFatalError(SL_FILE_LOAD_FAILED, SlCopyStringAT(FullDriverPath), Status);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (DeviceOpened) {
|
||
ArcClose(LoadDeviceId);
|
||
}
|
||
|
||
if(bDriverLoaded) {
|
||
if ((ComponentType == OEMSCSI) && InsertDevice) {
|
||
PDETECTED_DEVICE NewScsiDevice = NULL;
|
||
|
||
//
|
||
// Insert the device in SCSI miniport list
|
||
//
|
||
if(SlInsertScsiDevice((ULONG)-1, &NewScsiDevice) == ScsiInsertError) {
|
||
SlNoMemoryError();
|
||
}
|
||
|
||
//
|
||
// update the node information we just created
|
||
//
|
||
*NewScsiDevice = *DetectedDevice;
|
||
}
|
||
|
||
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__
|
||
);
|
||
|
||
//
|
||
// Treat the invalid txtsetup.oem files cases as
|
||
// user cancellation
|
||
//
|
||
goto OemLoadFailed;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
OemLoadFailed:
|
||
|
||
if (DeviceOpened){
|
||
ArcClose(LoadDeviceId);
|
||
}
|
||
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;
|
||
PTCHAR 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;
|
||
|
||
#ifdef UNICODE
|
||
Description = SlGetSectionLineIndexW(
|
||
#else
|
||
Description = SlGetSectionLineIndex(
|
||
#endif
|
||
InfHandle,
|
||
SectionName,
|
||
i,
|
||
0);
|
||
if (Description==NULL) {
|
||
Description=TEXT("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;
|
||
FloppyDiskPath[0] = '\0';
|
||
|
||
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
|
||
SlpIsOnlySuperFloppy(
|
||
void
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Determines if we only have ATAPI super floppies
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
TRUE - only super floppies
|
||
|
||
FALSE - > 0 regular floppies
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
BlSearchConfigTree(BlLoaderBlock->ConfigurationRoot,
|
||
PeripheralClass,
|
||
FloppyDiskPeripheral,
|
||
0,
|
||
SuperFloppyCallback);
|
||
|
||
return(IsSuperFloppy == FloppyNumber);
|
||
|
||
}
|
||
|
||
BOOLEAN
|
||
SuperFloppyCallback(
|
||
IN PCONFIGURATION_COMPONENT_DATA Component
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Callback routine called by SlpIsOnlySuper to find if we only have ATAPI floppy
|
||
drives 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;
|
||
PCM_FLOPPY_DEVICE_DATA FloppyData;
|
||
PCM_PARTIAL_RESOURCE_LIST DescriptorList;
|
||
|
||
if(Component->ComponentEntry.Type==FloppyDiskPeripheral) {
|
||
//
|
||
// A floppy disk peripheral was found.
|
||
//
|
||
|
||
FloppyNumber++;
|
||
|
||
//
|
||
// Crack the CM descriptors. This is a reversal of the storage from
|
||
// ..\detect\i386\diskc.c. The data is in the 2nd, not the 1st descriptor
|
||
//
|
||
DescriptorList = (PCM_PARTIAL_RESOURCE_LIST)Component->ConfigurationData;
|
||
FloppyData = (PCM_FLOPPY_DEVICE_DATA)(DescriptorList +1);
|
||
|
||
if (FloppyData->MaxDensity & 0x80000000) {
|
||
//
|
||
// Is it a special removeable ATAPI device?
|
||
//
|
||
IsSuperFloppy++;
|
||
}
|
||
}
|
||
|
||
return(TRUE); // keep searching
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
SlpReplicatePnpHardwareIds(
|
||
IN PPNP_HARDWARE_ID ExistingIds,
|
||
OUT PPNP_HARDWARE_ID *NewIds
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Replicates the input PNP_HARDWARE_ID list.
|
||
|
||
Arguments:
|
||
|
||
ExistingIds - The input PNP_HARDWARE_ID list
|
||
|
||
NewIds - Placeholder for the the new replicated hardware
|
||
ID linked list.
|
||
|
||
Return Value:
|
||
|
||
TRUE if successful, otherwise FALSE.
|
||
|
||
--*/
|
||
{
|
||
BOOLEAN Result = FALSE;
|
||
|
||
if (ExistingIds && NewIds) {
|
||
PPNP_HARDWARE_ID SrcNode = ExistingIds;
|
||
PPNP_HARDWARE_ID HeadNode = NULL;
|
||
PPNP_HARDWARE_ID PrevNode = NULL;
|
||
PPNP_HARDWARE_ID CurrNode = NULL;
|
||
|
||
do {
|
||
CurrNode = BlAllocateHeap(sizeof(PNP_HARDWARE_ID));
|
||
|
||
if (CurrNode) {
|
||
*CurrNode = *SrcNode;
|
||
CurrNode->Next = NULL;
|
||
|
||
if (!HeadNode) {
|
||
HeadNode = CurrNode;
|
||
}
|
||
|
||
if (PrevNode) {
|
||
PrevNode->Next = CurrNode;
|
||
}
|
||
|
||
PrevNode = CurrNode;
|
||
SrcNode = SrcNode->Next;
|
||
}
|
||
}
|
||
while (SrcNode && CurrNode);
|
||
|
||
if (CurrNode) {
|
||
Result = TRUE;
|
||
*NewIds = HeadNode;
|
||
}
|
||
}
|
||
|
||
return Result;
|
||
}
|
||
|
||
|
||
|
||
BOOLEAN
|
||
SlpOemInfSelection(
|
||
IN POEM_SOURCE_DEVICE OemSourceDevice,
|
||
IN PVOID OemInfHandle,
|
||
IN PCHAR ComponentName,
|
||
IN PCHAR SelectedId,
|
||
IN PTCHAR ItemDescription,
|
||
OUT PDETECTED_DEVICE Device,
|
||
OUT PPNP_HARDWARE_ID* HardwareIdDatabase,
|
||
IN PCHAR DriverDir
|
||
)
|
||
{
|
||
PCHAR FilesSectionName,ConfigSectionName,HardwareIdsSectionName;
|
||
ULONG Line,Count,Line2,Count2;
|
||
BOOLEAN rc = FALSE;
|
||
PDETECTED_DEVICE_FILE FileList = NULL, FileListTail;
|
||
PDETECTED_DEVICE_REGISTRY RegList = NULL, RegListTail;
|
||
PPNP_HARDWARE_ID IdList = NULL, IdListTail;
|
||
PPNP_HARDWARE_ID PrivateIdList = NULL;
|
||
ULONG FileTypeBits = 0;
|
||
|
||
//
|
||
// Validate the parameters
|
||
//
|
||
if (!ComponentName || !SelectedId) {
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// 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);
|
||
if (!FilesSectionName) {
|
||
return FALSE; // out of memory
|
||
}
|
||
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,Directory,ConfigName;
|
||
PTCHAR Description;
|
||
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) {
|
||
#ifdef UNICODE
|
||
DIAGOUT((
|
||
TEXT("SlpOemDiskette: Disk=%S, Filename=%S, Filetype=%S"),
|
||
Disk ? Disk : "(null)",
|
||
Filename ? Filename : "(null)",
|
||
Filetype ? Filetype : "(null)"));
|
||
#else
|
||
DIAGOUT((
|
||
TEXT("SlpOemDiskette: Disk=%s, Filename=%s, Filetype=%s"),
|
||
Disk ? Disk : "(null)",
|
||
Filename ? Filename : "(null)",
|
||
Filetype ? Filetype : "(null)"));
|
||
#endif
|
||
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);
|
||
|
||
#ifdef UNICODE
|
||
Description = SlGetSectionKeyIndexW(
|
||
#else
|
||
Description = SlGetSectionKeyIndex(
|
||
#endif
|
||
OemInfHandle,
|
||
"Disks",
|
||
Disk,
|
||
OINDEX_DISKDESCR);
|
||
|
||
Directory = SlGetSectionKeyIndex(OemInfHandle,"Disks",Disk,OINDEX_DIRECTORY);
|
||
if((Directory == NULL) || !strcmp(Directory,"\\")) {
|
||
Directory = SlCopyStringA("");
|
||
}
|
||
|
||
if(!Tagfile || !Description) {
|
||
DIAGOUT((
|
||
TEXT("SppOemDiskette: Tagfile=%s, Description=%s"),
|
||
Tagfile ? Tagfile : "(null)",
|
||
Description ? Description : TEXT("(null)")));
|
||
// SppOemInfError(ErrorMsg,&SptOemInfErr5,Line+1,FilesSectionName);
|
||
goto sod0;
|
||
}
|
||
|
||
FileStruct = BlAllocateHeap(sizeof(DETECTED_DEVICE_FILE));
|
||
memset(FileStruct, 0, sizeof(DETECTED_DEVICE_FILE));
|
||
|
||
//
|
||
// Use the fully qualified path, for dynamic update drivers
|
||
// if any
|
||
//
|
||
if (DriverDir && DriverDir[0]) {
|
||
PCHAR FullDir = BlAllocateHeap(256);
|
||
|
||
if (FullDir) {
|
||
*FullDir = '\0';
|
||
|
||
//
|
||
// Do we need a starting '\' ?
|
||
//
|
||
if (DriverDir[0] != '\\') {
|
||
strcat(FullDir, "\\");
|
||
}
|
||
|
||
strcat(FullDir, DriverDir);
|
||
|
||
//
|
||
// Do we need to append another '\' between
|
||
// the paths ?
|
||
//
|
||
if ((FullDir[strlen(FullDir) - 1] != '\\') &&
|
||
(*Directory != '\\')) {
|
||
strcat(FullDir, "\\");
|
||
}
|
||
|
||
strcat(FullDir, Directory);
|
||
|
||
//
|
||
// Do we need a terminating '\'?
|
||
//
|
||
if (FullDir[strlen(FullDir) - 1] != '\\') {
|
||
strcat(FullDir, "\\");
|
||
}
|
||
|
||
Directory = FullDir;
|
||
} else {
|
||
return FALSE; // ran out of memory
|
||
}
|
||
}
|
||
|
||
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);
|
||
}
|
||
|
||
//
|
||
// If this is a dynamic update driver, then mark the
|
||
// the device file type bits to indicate this. Textmode
|
||
// setup needs this to construct a valid source path.
|
||
//
|
||
if (OemSourceDevice &&
|
||
SL_OEM_SOURCE_DEVICE_TYPE(OemSourceDevice, SL_OEM_SOURCE_DEVICE_TYPE_DYN_UPDATE)){
|
||
SET_FILETYPE_PRESENT(FileTypeBits, HwFileDynUpdt);
|
||
}
|
||
|
||
//
|
||
// 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((
|
||
TEXT("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;
|
||
}
|
||
|
||
//
|
||
// Save away the arc device name also
|
||
//
|
||
if (OemSourceDevice && OemSourceDevice->ArcDeviceName) {
|
||
FileStruct->ArcDeviceName = SlCopyStringA(OemSourceDevice->ArcDeviceName);
|
||
} else {
|
||
FileStruct->ArcDeviceName = NULL;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Get the hardware ids if such a section exist
|
||
//
|
||
HardwareIdsSectionName = BlAllocateHeap(strlen(ComponentName) + strlen(SelectedId) + sizeof("HardwareIds.") + 1);
|
||
strcpy(HardwareIdsSectionName,"HardwareIds.");
|
||
strcat(HardwareIdsSectionName,ComponentName);
|
||
strcat(HardwareIdsSectionName,".");
|
||
strcat(HardwareIdsSectionName,SelectedId);
|
||
Count = SlCountLinesInSection(OemInfHandle,HardwareIdsSectionName);
|
||
if(Count == (ULONG)(-1)) {
|
||
//
|
||
// If the section doesn't exist, the assume it is empty
|
||
//
|
||
Count = 0;
|
||
}
|
||
IdList = IdListTail = NULL;
|
||
for(Line=0; Line<Count; Line++) {
|
||
PCHAR Id;
|
||
PCHAR DriverName;
|
||
PCHAR ClassGuid;
|
||
PPNP_HARDWARE_ID TempIdElement;
|
||
|
||
Id = SlGetSectionLineIndex(OemInfHandle,HardwareIdsSectionName,Line,OINDEX_HW_ID);
|
||
DriverName = SlGetSectionLineIndex(OemInfHandle,HardwareIdsSectionName,Line,OINDEX_DRIVER_NAME);
|
||
ClassGuid = SlGetSectionLineIndex(OemInfHandle,HardwareIdsSectionName,Line,OINDEX_CLASS_GUID);
|
||
if( !Id || !DriverName ) {
|
||
SlMessageBox(SL_BAD_INF_SECTION,HardwareIdsSectionName);
|
||
goto sod0;
|
||
}
|
||
TempIdElement = BlAllocateHeap(sizeof(PNP_HARDWARE_ID));
|
||
if(IdListTail == NULL) {
|
||
IdListTail = TempIdElement;
|
||
}
|
||
TempIdElement->Id = Id;
|
||
TempIdElement->DriverName = DriverName;
|
||
TempIdElement->ClassGuid = ClassGuid;
|
||
TempIdElement->Next = IdList;
|
||
IdList = TempIdElement;
|
||
}
|
||
|
||
if( IdList != NULL ) {
|
||
//
|
||
// Replicate the PNP hardware Id list
|
||
//
|
||
if (!SlpReplicatePnpHardwareIds(IdList, &PrivateIdList)) {
|
||
goto sod0; // ran out of memory
|
||
}
|
||
|
||
IdListTail->Next = *HardwareIdDatabase;
|
||
*HardwareIdDatabase = IdList;
|
||
}
|
||
|
||
//
|
||
// 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;
|
||
Device->HardwareIds = PrivateIdList;
|
||
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(_stricmp(StringTable[i],String) == 0) {
|
||
return(i);
|
||
}
|
||
}
|
||
|
||
return(i);
|
||
}
|
||
|
||
|
||
VOID
|
||
SlpInitDetectedDevice(
|
||
IN PDETECTED_DEVICE Device,
|
||
IN PCHAR IdString,
|
||
IN PTCHAR 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);
|
||
if (Buffer == NULL) {
|
||
goto x1;
|
||
}
|
||
|
||
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 PTCHAR 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;
|
||
PTCHAR SearchName;
|
||
|
||
//
|
||
// If this is not an OEM component, then enumerate the entries in the
|
||
// section in txtsetup.sif
|
||
//
|
||
for (i=0;;i++) {
|
||
#ifdef UNICODE
|
||
SearchName = SlGetSectionLineIndexW(
|
||
#else
|
||
SearchName = SlGetSectionLineIndex(
|
||
#endif
|
||
Inf,
|
||
SectionName,
|
||
i,
|
||
0 );
|
||
if (SearchName==NULL) {
|
||
//
|
||
// we have enumerated the entire section without finding a
|
||
// match, return failure.
|
||
//
|
||
return(NULL);
|
||
}
|
||
|
||
if (_tcsicmp(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));
|
||
}
|
||
|
||
|
||
ARC_STATUS
|
||
SlLoadWinPESection(
|
||
IN POEM_SOURCE_DEVICE OemSourceDevice,
|
||
IN PVOID OemInfHandle,
|
||
IN PCSTR OemSectionName,
|
||
IN PVOID InboxInfHandle,
|
||
IN PCSTR InboxSectionName,
|
||
IN BOOLEAN IsScsiSection,
|
||
IN POEMSCSIINFO* ScsiInfo, OPTIONAL
|
||
OUT PPNP_HARDWARE_ID* HardwareIdDatabase OPTIONAL
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Loads the oem drivers from the specified section in the
|
||
given OEM file name
|
||
|
||
Arguments:
|
||
|
||
OemSourceDevice : The device that has the drivers that need to
|
||
be loaded for WinPE.
|
||
|
||
OemInfHandle : Handle to the oem inf file
|
||
|
||
OemSectionName : The section name that needs to be loaded.
|
||
|
||
InboxInfHandle : The original setup inf handle (txtsetup.sif)
|
||
|
||
InboxSectionName : The section name, whose drivers are to be loaded
|
||
|
||
IsScsiSection : Indicates whether the driver being loaded is SCSI
|
||
miniport or not.
|
||
|
||
ScsiInfo - Returns a linked list containing info about any third-party scsi
|
||
drivers loaded.
|
||
|
||
HardwareIdDatabase - Hardware Ids of the device which the loaded driver supports
|
||
|
||
Return Value:
|
||
|
||
Appropriate ARC_STATUS
|
||
|
||
--*/
|
||
{
|
||
ARC_STATUS Status = EINVAL;
|
||
|
||
if (OemSourceDevice && OemInfHandle && OemSectionName && InboxInfHandle && InboxSectionName) {
|
||
CHAR Buffer[128];
|
||
ULONG EntryCount;
|
||
BOOLEAN Append = TRUE;
|
||
PCHAR SectionName = Buffer;
|
||
ULONG InsertIndex = 0;
|
||
|
||
Status = ESUCCESS;
|
||
|
||
strcpy(SectionName, OemSectionName);
|
||
strcat(SectionName, WINPE_REPLACE_SUFFIX_A);
|
||
|
||
//
|
||
// check if there is a .replace section
|
||
//
|
||
EntryCount = SlCountLinesInSection(OemInfHandle,
|
||
SectionName);
|
||
|
||
if (EntryCount && (EntryCount != (-1))) {
|
||
Append = FALSE;
|
||
} else {
|
||
//
|
||
// check if there is a .append section
|
||
//
|
||
strcpy(SectionName, OemSectionName);
|
||
strcat(SectionName, WINPE_APPEND_SUFFIX_A);
|
||
|
||
EntryCount = SlCountLinesInSection(OemInfHandle,
|
||
SectionName);
|
||
}
|
||
|
||
//
|
||
// if append was requested then load the inbox
|
||
// drivers first
|
||
//
|
||
if (Append) {
|
||
Status = SlLoadSection(InboxInfHandle,
|
||
InboxSectionName,
|
||
IsScsiSection,
|
||
TRUE,
|
||
&InsertIndex);
|
||
}
|
||
|
||
//
|
||
// load the non-pnp oem drivers if any
|
||
//
|
||
if ((Status == ESUCCESS) && EntryCount && (EntryCount != (-1))) {
|
||
Status = SlLoadSection(OemInfHandle,
|
||
SectionName,
|
||
IsScsiSection,
|
||
FALSE,
|
||
&InsertIndex);
|
||
}
|
||
|
||
//
|
||
// load the pnp oem drivers
|
||
//
|
||
if (IsScsiSection && ScsiInfo && HardwareIdDatabase) {
|
||
EntryCount = SlCountLinesInSection(OemInfHandle,
|
||
WINPE_OEMDRIVER_PARAMS_A);
|
||
|
||
//
|
||
// Try to load the driver only if present
|
||
//
|
||
if (EntryCount && (EntryCount != (-1))) {
|
||
BOOLEAN Result;
|
||
ULONG OldDeviceType = OemSourceDevice->DeviceType;
|
||
|
||
//
|
||
// We mark the device type as dynupdate device type
|
||
// so that the fully qualified driver root directory is
|
||
// used while loading MSDs
|
||
//
|
||
SL_OEM_SET_SOURCE_DEVICE_TYPE(OemSourceDevice,
|
||
(SL_OEM_SOURCE_DEVICE_TYPE_LOCAL |
|
||
SL_OEM_SOURCE_DEVICE_TYPE_FIXED |
|
||
SL_OEM_SOURCE_DEVICE_TYPE_DYN_UPDATE));
|
||
|
||
Result = SlLoadOemScsiDriversUnattended(OemSourceDevice,
|
||
OemInfHandle,
|
||
WINPE_OEMDRIVER_PARAMS_A,
|
||
WINPE_OEMDRIVER_ROOTDIR_A,
|
||
WINPE_OEMDRIVER_DIRS_A,
|
||
ScsiInfo,
|
||
HardwareIdDatabase);
|
||
|
||
//
|
||
// Restore the old device type
|
||
//
|
||
SL_OEM_SET_SOURCE_DEVICE_TYPE(OemSourceDevice,
|
||
OldDeviceType);
|
||
|
||
if (!Result) {
|
||
Status = EINVAL;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
ARC_STATUS
|
||
SlInitOemSourceDevices(
|
||
OUT POEM_SOURCE_DEVICE *OemSourceDevices,
|
||
OUT POEM_SOURCE_DEVICE *DefaultSourceDevice
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine scans the devices to figure out which
|
||
are the OEM source devices and creates a list of
|
||
such devices.
|
||
|
||
Arguments:
|
||
|
||
OemSourceDevices - Place holder for receiving the
|
||
linked list of OEM source devices.
|
||
|
||
DefaultSourceDevice - Place holder for the OEM source
|
||
device which will be used as the default device
|
||
while trying to load OEM drivers / HAL -- generally
|
||
floppy(0).
|
||
|
||
Return Value:
|
||
|
||
Returns the appropriate ARC_STATUS error code.
|
||
|
||
--*/
|
||
{
|
||
ARC_STATUS Status = EINVAL;
|
||
|
||
if (OemSourceDevices && DefaultSourceDevice) {
|
||
ULONG FloppyCount = 0;
|
||
ULONG Index = 0;
|
||
CHAR ArcDeviceName[128];
|
||
POEM_SOURCE_DEVICE OemDevices = NULL;
|
||
|
||
ArcDeviceName[0] = '\0';
|
||
Status = ESUCCESS;
|
||
|
||
//
|
||
// We may not find any devices
|
||
//
|
||
*OemSourceDevices = *DefaultSourceDevice = NULL;
|
||
|
||
//
|
||
// Iterate through all the floppy drives and make them
|
||
// oem source devices
|
||
//
|
||
|
||
while (ESUCCESS == Status) {
|
||
POEM_SOURCE_DEVICE NewDevice;
|
||
|
||
//
|
||
// Scan for atleast minimum number for floppies
|
||
//
|
||
if (!SlpFindFloppy(Index, ArcDeviceName)) {
|
||
if ((Index + 1) < MinimumFloppiesToScan) {
|
||
Index++;
|
||
|
||
continue;
|
||
} else {
|
||
break;
|
||
}
|
||
}
|
||
|
||
NewDevice = BlAllocateHeap(sizeof(OEM_SOURCE_DEVICE));
|
||
|
||
if (!NewDevice) {
|
||
Status = ENOMEM;
|
||
} else {
|
||
ARC_STATUS OpenStatus;
|
||
ULONG DeviceId;
|
||
ULONG DeviceType = (SL_OEM_SOURCE_DEVICE_TYPE_LOCAL |
|
||
SL_OEM_SOURCE_DEVICE_TYPE_REMOVABLE);
|
||
|
||
memset(NewDevice, 0, sizeof(OEM_SOURCE_DEVICE));
|
||
strcpy(NewDevice->ArcDeviceName, ArcDeviceName);
|
||
|
||
//
|
||
// Assume we are not going to use device id
|
||
//
|
||
NewDevice->DeviceId = -1;
|
||
|
||
//
|
||
// Treat all the floppy drives which are greater than 0
|
||
// as virtual floppy drives
|
||
//
|
||
if (Index >= VirtualFloppyStart) {
|
||
DeviceType |= SL_OEM_SOURCE_DEVICE_TYPE_VIRTUAL;
|
||
}
|
||
|
||
//
|
||
// Currently we only use local removable media for
|
||
// OEM drivers
|
||
//
|
||
SL_OEM_SET_SOURCE_DEVICE_TYPE(NewDevice, DeviceType);
|
||
|
||
SL_OEM_SET_SOURCE_DEVICE_STATE(NewDevice,
|
||
SL_OEM_SOURCE_DEVICE_NOT_PROCESSED);
|
||
|
||
OpenStatus = ArcOpen(ArcDeviceName,
|
||
ArcOpenReadOnly,
|
||
&DeviceId);
|
||
|
||
if (ESUCCESS == OpenStatus) {
|
||
CHAR InfPath[128];
|
||
ULONG FileId;
|
||
ULONG MediaType = SL_OEM_SOURCE_MEDIA_PRESENT;
|
||
|
||
strcpy(InfPath, "\\");
|
||
strcat(InfPath, TXTSETUP_OEM_FILENAME);
|
||
|
||
//
|
||
// Verify if the file is present
|
||
//
|
||
OpenStatus = BlOpen(DeviceId,
|
||
InfPath,
|
||
ArcOpenReadOnly,
|
||
&FileId);
|
||
|
||
if (ESUCCESS == OpenStatus) {
|
||
PVOID InfHandle = NULL;
|
||
ULONG ErrorLine = 0;
|
||
|
||
//
|
||
// We don't need file handle any more
|
||
//
|
||
BlClose(FileId);
|
||
|
||
//
|
||
// Open and parse the txtsetup.oem file
|
||
//
|
||
OpenStatus = SlInitIniFile(NULL,
|
||
DeviceId,
|
||
InfPath,
|
||
&InfHandle,
|
||
NULL,
|
||
0,
|
||
&ErrorLine);
|
||
|
||
if (ESUCCESS == OpenStatus) {
|
||
PCHAR StrValue;
|
||
|
||
MediaType |= SL_OEM_SOURCE_MEDIA_HAS_DRIVERS;
|
||
NewDevice->InfHandle = InfHandle;
|
||
NewDevice->DeviceId = DeviceId;
|
||
|
||
StrValue = SlGetSectionKeyIndex(InfHandle,
|
||
TXTSETUP_OEM_DEFAULTS,
|
||
TXTSETUP_OEM_DEFAULTS_COMPUTER,
|
||
0);
|
||
|
||
if (StrValue) {
|
||
MediaType |= (SL_OEM_SOURCE_MEDIA_HAS_DEFAULT |
|
||
SL_OEM_SOURCE_MEDIA_HAS_HAL);
|
||
}
|
||
|
||
StrValue = SlGetSectionKeyIndex(InfHandle,
|
||
TXTSETUP_OEM_DEFAULTS,
|
||
TXTSETUP_OEM_DEFAULTS_SCSI,
|
||
0);
|
||
|
||
if (StrValue) {
|
||
MediaType |= (SL_OEM_SOURCE_MEDIA_HAS_DEFAULT |
|
||
SL_OEM_SOURCE_MEDIA_HAS_MSD);
|
||
}
|
||
} else {
|
||
//
|
||
// Inform the user about the error & abort ?
|
||
//
|
||
MediaType |= SL_OEM_SOURCE_MEDIA_NO_DRIVERS;
|
||
}
|
||
|
||
//
|
||
// close the device if not needed
|
||
//
|
||
if (NewDevice->DeviceId != DeviceId) {
|
||
ArcClose(DeviceId);
|
||
}
|
||
|
||
//
|
||
// Mark the device state as scanned
|
||
//
|
||
SL_OEM_SET_SOURCE_DEVICE_STATE(NewDevice,
|
||
SL_OEM_SOURCE_DEVICE_SCANNED);
|
||
}
|
||
|
||
SL_OEM_SET_SOURCE_MEDIA_TYPE(NewDevice,
|
||
MediaType);
|
||
} else {
|
||
SL_OEM_SET_SOURCE_MEDIA_TYPE(NewDevice,
|
||
SL_OEM_SOURCE_MEDIA_ABSENT);
|
||
}
|
||
|
||
//
|
||
// insert the new device at the head of the linked list
|
||
//
|
||
if (!OemDevices) {
|
||
OemDevices = NewDevice;
|
||
} else {
|
||
NewDevice->Next = OemDevices;
|
||
OemDevices = NewDevice;
|
||
}
|
||
|
||
//
|
||
// Currently floppy0 is the default OEM source device
|
||
//
|
||
if (Index == 0) {
|
||
*DefaultSourceDevice = NewDevice;
|
||
}
|
||
|
||
//
|
||
// Process next floppy drive
|
||
//
|
||
Index++;
|
||
ArcDeviceName[0] = '\0';
|
||
}
|
||
}
|
||
|
||
if (ESUCCESS == Status) {
|
||
*OemSourceDevices = OemDevices;
|
||
}
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
ARC_STATUS
|
||
SlLoadOemScsiDriversFromOemSources(
|
||
IN POEM_SOURCE_DEVICE OemSourceDevices,
|
||
IN OUT PPNP_HARDWARE_ID *HardwareIds,
|
||
OUT POEMSCSIINFO *OemScsiInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Goes through each of the OEM source device and loads the
|
||
default drivers, if any.
|
||
|
||
Arguments:
|
||
|
||
OemSourceDevices - List of OEM source devices.
|
||
|
||
HardwareIds - List of all the hardware IDs of the devices which
|
||
are controlled by the drivers which were loaded.
|
||
|
||
OemScsiInfo - Placeholder for receiving the list OEMSCSIINFO
|
||
list, which has the driver base and driver name for each
|
||
driver loaded.
|
||
|
||
Return Value:
|
||
|
||
Returns the appropriate ARC_STATUS error code.
|
||
|
||
--*/
|
||
{
|
||
ARC_STATUS Status = EINVAL;
|
||
|
||
if (OemSourceDevices && OemScsiInfo) {
|
||
POEM_SOURCE_DEVICE CurrDevice = OemSourceDevices;
|
||
POEMSCSIINFO DeviceOemScsiInfo = NULL;
|
||
POEMSCSIINFO LastOemScsiNode = NULL;
|
||
|
||
Status = ESUCCESS;
|
||
|
||
while (CurrDevice) {
|
||
//
|
||
// Only process those devices which are not processed yet
|
||
// and which are not dynamic update source devices
|
||
//
|
||
if (!SL_OEM_SOURCE_DEVICE_STATE(CurrDevice,
|
||
SL_OEM_SOURCE_DEVICE_PROCESSED) &&
|
||
!SL_OEM_SOURCE_DEVICE_TYPE(CurrDevice,
|
||
SL_OEM_SOURCE_DEVICE_TYPE_DYN_UPDATE)) {
|
||
|
||
//
|
||
// Does the device has MSD with default entry ?
|
||
//
|
||
if (SL_OEM_SOURCE_MEDIA_TYPE(CurrDevice,
|
||
SL_OEM_SOURCE_MEDIA_HAS_DRIVERS) &&
|
||
SL_OEM_SOURCE_MEDIA_TYPE(CurrDevice,
|
||
SL_OEM_SOURCE_MEDIA_HAS_DEFAULT) &&
|
||
SL_OEM_SOURCE_MEDIA_TYPE(CurrDevice,
|
||
SL_OEM_SOURCE_MEDIA_HAS_MSD)) {
|
||
|
||
PPNP_HARDWARE_ID HardwareIdDatabase = NULL;
|
||
POEMSCSIINFO CurrentOemScsiInfo = NULL;
|
||
DETECTED_DEVICE DetectedDevice = {0};
|
||
PVOID ImageBase = NULL;
|
||
PCHAR ImageName = NULL;
|
||
PTCHAR DriverDescription = NULL;
|
||
BOOLEAN LoadResult;
|
||
|
||
//
|
||
// Load the driver and related files, in an unattended manner
|
||
//
|
||
LoadResult = SlpOemDiskette(CurrDevice,
|
||
"SCSI",
|
||
OEMSCSI,
|
||
0,
|
||
&DetectedDevice,
|
||
&ImageBase,
|
||
&ImageName,
|
||
&DriverDescription,
|
||
FALSE,
|
||
NULL,
|
||
&HardwareIdDatabase,
|
||
NULL,
|
||
TRUE);
|
||
|
||
if (LoadResult) {
|
||
CurrentOemScsiInfo = BlAllocateHeap(sizeof(OEMSCSIINFO));
|
||
|
||
if (CurrentOemScsiInfo) {
|
||
memset(CurrentOemScsiInfo, 0, sizeof(OEMSCSIINFO));
|
||
CurrentOemScsiInfo->ScsiBase = ImageBase;
|
||
CurrentOemScsiInfo->ScsiName = ImageName;
|
||
|
||
//
|
||
// Insert the ids into main hardware Id database
|
||
//
|
||
if (HardwareIdDatabase) {
|
||
while (HardwareIdDatabase->Next) {
|
||
HardwareIdDatabase = HardwareIdDatabase->Next;
|
||
}
|
||
|
||
HardwareIdDatabase->Next = *HardwareIds;
|
||
*HardwareIds = HardwareIdDatabase;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Mark the oem source device state, as processed
|
||
//
|
||
SL_OEM_SET_SOURCE_DEVICE_STATE(CurrDevice,
|
||
SL_OEM_SOURCE_DEVICE_PROCESSED);
|
||
} else {
|
||
//
|
||
// Make the oem source device state as skipped so that
|
||
// we don't create virtual oem source device for it
|
||
//
|
||
SL_OEM_SET_SOURCE_DEVICE_STATE(CurrDevice,
|
||
SL_OEM_SOURCE_DEVICE_SKIPPED);
|
||
}
|
||
|
||
if (CurrentOemScsiInfo) {
|
||
//
|
||
// Initialize head if necessary
|
||
//
|
||
if (!DeviceOemScsiInfo) {
|
||
DeviceOemScsiInfo = CurrentOemScsiInfo;
|
||
}
|
||
|
||
//
|
||
// Merge the current linked list with the
|
||
// full OEM source device linked list
|
||
//
|
||
if (LastOemScsiNode) {
|
||
LastOemScsiNode->Next = CurrentOemScsiInfo;
|
||
} else {
|
||
LastOemScsiNode = CurrentOemScsiInfo;
|
||
}
|
||
|
||
//
|
||
// NOTE : We need to maintain the linked list
|
||
// in the order the drivers were loaded so
|
||
// search for the last node in the current list
|
||
// and keep last node pointer around for the
|
||
// merge for next iteration.
|
||
//
|
||
while (LastOemScsiNode->Next) {
|
||
LastOemScsiNode = LastOemScsiNode->Next;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
CurrDevice = CurrDevice->Next;
|
||
}
|
||
|
||
//
|
||
// Initialize the return argument irrespective of
|
||
// status code since we might have loaded some drivers
|
||
// and would like to use it anyway
|
||
//
|
||
*OemScsiInfo = DeviceOemScsiInfo;
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
ARC_STATUS
|
||
SlInitVirtualOemSourceDevices(
|
||
IN PSETUP_LOADER_BLOCK SetupLoaderBlock,
|
||
IN POEM_SOURCE_DEVICE OemSourceDevices
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Goes through each of the OEM source devices and creates
|
||
another linked list of virtual OEM source devices.
|
||
|
||
This list is put in the loader block for setupdd.sys
|
||
to inform the RAM disk driver to create virtual devices
|
||
under NT to read drivers of this device.
|
||
|
||
NOTE : Currently we allocate memory for the whole virtual
|
||
device and replicate its contents into the allocated memory.
|
||
We do this because we don't want OEMs to write separate
|
||
NT driver to read from the virtual device under NT.
|
||
We also limit the size of each virtual device to be 3MB
|
||
at the max.
|
||
|
||
Arguments:
|
||
|
||
SetupLoaderBlock - Setup loader block
|
||
|
||
OemSourceDevices - The list of OEM source devices identified
|
||
by the setupldr.
|
||
|
||
Return Value:
|
||
|
||
Returns the appropriate ARC_STATUS error code.
|
||
|
||
--*/
|
||
{
|
||
ARC_STATUS Status = EINVAL;
|
||
|
||
if (SetupLoaderBlock && OemSourceDevices) {
|
||
PDETECTED_OEM_SOURCE_DEVICE OemVirtualDevices = NULL;
|
||
PDETECTED_OEM_SOURCE_DEVICE NewVirtualDevice = NULL;
|
||
POEM_SOURCE_DEVICE CurrentDevice = OemSourceDevices;
|
||
|
||
Status = ESUCCESS;
|
||
|
||
while (CurrentDevice) {
|
||
//
|
||
// Process only those devices which are virtual
|
||
// and have drivers in them and which were not skipped
|
||
//
|
||
if (SL_OEM_SOURCE_DEVICE_TYPE(CurrentDevice,
|
||
SL_OEM_SOURCE_DEVICE_TYPE_VIRTUAL) &&
|
||
SL_OEM_SOURCE_MEDIA_TYPE(CurrentDevice,
|
||
SL_OEM_SOURCE_MEDIA_HAS_DRIVERS) &&
|
||
!SL_OEM_SOURCE_DEVICE_STATE(CurrentDevice,
|
||
SL_OEM_SOURCE_DEVICE_SKIPPED)) {
|
||
|
||
ULONGLONG ImageSize = 0;
|
||
PVOID ImageBase = NULL;
|
||
ULONG DeviceId = -1;
|
||
FILE_INFORMATION FileInfo = {0};
|
||
LARGE_INTEGER Start = {0};
|
||
|
||
//
|
||
// Open the device, only if needed
|
||
//
|
||
if (CurrentDevice->DeviceId == -1) {
|
||
Status = ArcOpen(CurrentDevice->ArcDeviceName,
|
||
ArcOpenReadOnly,
|
||
&DeviceId);
|
||
} else {
|
||
DeviceId = CurrentDevice->DeviceId;
|
||
}
|
||
|
||
if (Status != ESUCCESS) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Rewind the device
|
||
//
|
||
Status = ArcSeek(DeviceId, &Start, SeekAbsolute);
|
||
|
||
if (Status != ESUCCESS) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Get the device size
|
||
//
|
||
Status = ArcGetFileInformation(DeviceId,
|
||
&FileInfo);
|
||
|
||
if (Status != ESUCCESS) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// NOTE : At the max we only allow 3MB per
|
||
// virtual device (should be only one device
|
||
// in most of the cases)
|
||
//
|
||
if (FileInfo.EndingAddress.QuadPart > 0x300000) {
|
||
Status = E2BIG;
|
||
} else {
|
||
ULONG PageCount = 0;
|
||
ULONG HeapPage = 0;
|
||
|
||
//
|
||
// Allocate the memory for the disk image
|
||
//
|
||
ImageSize = FileInfo.EndingAddress.QuadPart;
|
||
|
||
#ifdef _X86_
|
||
//
|
||
// NOTE : Allocate "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.
|
||
//
|
||
// If we didn't allocate loader firmware permanent memory
|
||
// then setupdd.sys would have to allocate paged pool memory
|
||
// and replicate the contents from the loader block during
|
||
// initialization.
|
||
//
|
||
Status = BlAllocateDescriptor(
|
||
LoaderFirmwarePermanent,
|
||
0,
|
||
(ULONG)(ROUND_TO_PAGES(ImageSize) >> PAGE_SHIFT),
|
||
(PULONG)&HeapPage);
|
||
|
||
if (Status == ESUCCESS) {
|
||
ImageBase = (PVOID)(KSEG0_BASE | (HeapPage << PAGE_SHIFT));
|
||
}
|
||
|
||
#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 memory from regular heap and we have to
|
||
// replicate the memory in setupdd!SpInitialize0(..)
|
||
//
|
||
ImageBase = BlAllocateHeap((ULONG)ImageSize);
|
||
|
||
if (!ImageBase) {
|
||
Status = ENOMEM;
|
||
}
|
||
#endif
|
||
|
||
if (Status != ESUCCESS) {
|
||
break;
|
||
}
|
||
|
||
if (ImageBase) {
|
||
ULONG BytesRead = 0;
|
||
|
||
RtlZeroMemory(ImageBase, (ULONG)ImageSize);
|
||
|
||
//
|
||
// Read the whole device image in a single call
|
||
//
|
||
Status = ArcRead(DeviceId,
|
||
ImageBase,
|
||
(ULONG)ImageSize,
|
||
&BytesRead);
|
||
|
||
//
|
||
// NOTE : The approximate device size may
|
||
// be bigger than the media size. So if we
|
||
// read atleast some bytes then we assume
|
||
// we are fine.
|
||
//
|
||
if ((BytesRead > 0) && (Status != ESUCCESS)) {
|
||
Status = ESUCCESS;
|
||
}
|
||
} else {
|
||
Status = ENOMEM;
|
||
}
|
||
}
|
||
|
||
if (Status != ESUCCESS) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Create a new virtual device node and put it in the
|
||
// list of virtual devices
|
||
//
|
||
NewVirtualDevice = BlAllocateHeap(sizeof(DETECTED_OEM_SOURCE_DEVICE));
|
||
|
||
RtlZeroMemory(NewVirtualDevice, sizeof(DETECTED_OEM_SOURCE_DEVICE));
|
||
|
||
if (NewVirtualDevice == NULL) {
|
||
Status = ENOMEM;
|
||
|
||
break;
|
||
}
|
||
|
||
NewVirtualDevice->ArcDeviceName = SlCopyStringA(CurrentDevice->ArcDeviceName);
|
||
NewVirtualDevice->ImageBase = ImageBase;
|
||
NewVirtualDevice->ImageSize = ImageSize;
|
||
|
||
DbgPrint("SETUPLDR: Virtual Device => %s (base:%p, size:%d)\n",
|
||
NewVirtualDevice->ArcDeviceName,
|
||
ImageBase,
|
||
(ULONG)ImageSize);
|
||
|
||
//
|
||
// Add the new device at the head of the linked list
|
||
//
|
||
if (!OemVirtualDevices) {
|
||
OemVirtualDevices = NewVirtualDevice;
|
||
} else {
|
||
NewVirtualDevice->Next = OemVirtualDevices;
|
||
OemVirtualDevices = NewVirtualDevice;
|
||
}
|
||
}
|
||
|
||
//
|
||
// go on to next OEM source device
|
||
//
|
||
CurrentDevice = CurrentDevice->Next;
|
||
}
|
||
|
||
if (Status == ESUCCESS) {
|
||
SetupLoaderBlock->OemSourceDevices = OemVirtualDevices;
|
||
}
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|