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