;       SCCSID = @(#)iniproc2.asm       6.26 92/03/26
        page    78,132
        title   iniproc2, System Initialization Process - Part 2


SCCSID  equ     "@(#)iniproc2.asm       6.26 92/03/26"

;                 IBM Confidential
;
;           Copyright (c) IBM Corporation  1987, 1994
;                     All Rights Reserved

;
; SOURCE FILE NAME: Iniproc2
;
; DESCRIPTIVE NAME: System Initialization Process - Part 2
;
; FUNCTION: To complete initialization of the CP/DOS system
;
; NOTES:
;   DEPENDENCIES: None
;   RESTRICTIONS: None
;
; ENTRY POINTS:
;             syiInstallDeviceDrivers - Install all
;                                  user specified device drivers
;             syiInitEnvironment - Initialize the SysInit
;                                  Environment with SET information.
;             syiStartDaemonProcess - Start all user specified
;                                  asynchronous processes (except PM apps)
;             syi2StartDaemonProcess - Start all user specified      80080
;                                  asynchronous processes (PM apps)
;             syiStartShell - Start the protected mode shell
;             syiStartDOSMode - Start DOS mode
;
; EXTERNAL REFERENCES:
;                DosExecPgm      - Start a program
;                DosLoadModule   - Load a module
;                SICG            - Perform initialization function
;                syiAbortR3 - Display a fatal error message
;                syiDisplayMessageR3 - Display an error message
;*                                                             *
;* REVISIONS:                                                  *
;*                                                             *
;*   -  001     2/22/91   Mark Rogalski,   IBM                 *
;*      CP20 DCR 1329  Add DOS=UMB  and DEVICEHIGH support     *
;*                                                             *
;*   -  002     3/22/91   Mark Rogalski,   IBM                 *
;*      CP20 DCR 1329  Add DOS=HIGH support                    *
;*                                                             *
;*   -  003     5/08/91   Edd Doutre,                          *
;*      B720443 Added error detection for VDDs                 *
;*                                                             *
;*   -  004     5/13/91   Edd Doutre for Allen Wynn,           *
;*      B722160 Added error detection for Block DD's           *
;*                                                             *
;*   -  005     5/22/91   Russ Berkoff,            ,           *
;*      B723129 Fix divide fault in syiInitializeDeviceDriver  *
;*                                                             *
;***********************************************************************;BN011;
; 19Jun91 - G.L.Fulk                                                    ;BN011;
; Add support for a DOS ONLY "FILES=" statement in CONFIG.SYS.          ;BN011;
;***********************************************************************;BN011;
;*                                                             *
;*   -  006     8/21/91   Stacey Barnes,           ,           *
;*      B723649 DWORD alignment of sicg_pktA caused            *
;*              sicg_packet_a_d to be ordered differently.     *
;*              This broke the VDM Manager when it displayed   *
;*              errors in loading VDDs.                        *
;*   - 007      10/31/91  Allen Wynn                           *
;*     AA04380  abort boot if MINIFSD and not HPFS ifs         *
;*              (rather than any ifs)                          *
;*   - 008      02/09/94  Catherine E. Bundy                   *
;*              call sysinit call gate function 18 to free     *
;*              device driver through ldrfreemodule rather     *
;*              then dosfreemodule                             *
;*   - @83390   09May1994 D.Azzarito                           *
;*              Support "forced" Autocheck on FAT drives       *
;*   - @75220   31May1994 M.Monahan                            *
;*              Added dynamic libpath feature support          *
;*   - 90474    07/22/94   ACW  Add UNILOCK support            *
;*   - 98072    13Sep94  D.Azzarito - Don't CHKDSK twice if    *
;*              the drive is dirty and FORCE specified.        *
;*   - 147968   5/11/96  RJM Change FSD and DD system owners   *
;*              to use HMTEs                                   *
;***************************************************************

        subttl  Data Structures
        page
        .xlist
        .xcref
        .sall
        include basemid.inc           ; Message IDs
        include utilmd11.inc          ; #73958 added new error msg. M. Violante
        include utilmd17.inc          ; MSG_REPLACEMENT_STRING
        include devsym.inc            ; Device driver packets
        include basemaca.inc          ; CP/DOS macros
        include fnoinit.inc
        include osmaca.inc            ; CP/DOS macros
        include dosseg.inc            ; CP/DOS segments
        INCL_ERRORS equ 1             ; for bseerr.inc
        include bseerr.inc            ; error codes
        include infoseg.inc           ; System Information Segment
        include inicfg.inc            ; CONFIG.SYS data packets
        include inisms.inc            ; SysInit Message Segment
        include mi.inc
        include sicg.inc              ; SICG packets
        include struc.inc             ; Structured assembler macros
        include fsc.inc               ; for FSD loading
        include ldrvars.inc           ; EQUates for EXT_DEVICE, EXT_FSD
        include curdir.inc            ; Include MAXPATHLEN
        include tkexport.inc
        include ldrxport.inc
        include vmowner.inc
        INCL_DOSSESMGR equ 1          ; #73958 added PM control.    M. Violante
        include bsedos.inc            ; #73958 added PM control.    M. Violante
        include inialtf1.inc
        .list
        .cref
.386p

        ModName  , FNO_INIPROC2_ASM

        ReferGlobal     DevHlp,DWORD
        ReferGlobal     LoadDevDrv,BYTE
        ReferGlobal     ProtOnlySystem,BYTE
        ReferGlobal     SISData
;147968        ReferGlobal     _LDRDDOwner,WORD
;147968        ReferGlobal     _LDRFSDOwner,WORD
        ReferGlobal     mFSD_FLAG,BYTE
        ReferGlobal     ACHK_FLAG,BYTE
        ReferGlobal     pMiniFSD,DWORD
        ReferGlobal     initfatchkdsk,BYTE  ; init chkdsk of fat boot partition ;### AC DCR 1520
        ReferGlobal     FatDirtyBit,BYTE    ; init chkdsk of fat boot partition ;### AC DCR 1520
        ReferGlobal     _DDInitTime,BYTE
        ReferGlobal     syiGlobalFlags,DWORD

        ReferGDT        GDT_DOS16LDRDIRTYWORKER,WORD

        ReferFlat       _pPTDACur

        ReferInitGlobal error_messages_displayed,byte         ; #73958 M. Violante
        ReferInitGlobal CFG_AutoCheck,BYTE                    ;### AC DCR 1520
        ReferInitGlobal CFG_Break,BYTE
        ReferInitGlobal CFG_Dos_Flags,BYTE                    ;BN002
        ReferInitGlobal CFG_FCBCount,WORD
        ReferInitGlobal CFG_FCBKeep,WORD
        ReferInitGlobal CFG_FILESCount,WORD                             ;BN011;
        ReferInitGlobal CFG_LastDrive,BYTE
        ReferInitGlobal CFG_ProtectOnly,BYTE
        ReferInitGlobal CFG_RMSize,WORD
        ReferInitGlobal Config_Sys_Data,WORD
        ReferInitGlobal fscInitTemplate,BYTE
        ReferInitGlobal mFSD_Handle,WORD
        ReferInitGlobal pDosOpen,DWORD
        ReferInitGlobal pDosMove,DWORD
        ReferInitGlobal pDosDelete,DWORD
        ReferInitGlobal pDosRead,DWORD
        ReferInitGlobal pDosWrite,DWORD
        ReferInitGlobal pDosClose,DWORD
        ReferInitGlobal pDosAllocSeg,DWORD
        ReferInitGlobal pDosCreateThread,DWORD
        ReferInitGlobal pDosExecPgm,DWORD
        ReferInitGlobal pDosPutMessage,DWORD
        ReferInitGlobal pDosIQAppType,DWORD
        ReferInitGlobal pDosSemWait,DWORD            ;80080
        ReferInitGlobal pDosSMSysInitSem,dword       ;80080
        ReferInitGlobal pDosLoadModule,DWORD
;        ReferInitGlobal pDosLogMode,DWORD  Removed by CP20 DCR 1152
        ReferInitGlobal pDosReallocSeg,DWORD
        ReferInitGlobal pSICG,DWORD
        ReferInitGlobal syiEnvironSelector,WORD
        ReferInitGlobal open_action,WORD
        ReferInitGlobal AltFxKeyPressed,BYTE
        ReferInitGlobal AltF1Flags,BYTE
        ReferInitGlobal AltF1Parm,BYTE           ;Feature 74378
        ReferInitGlobal AltF1CmdParms,BYTE       ;Feature 74378
        ReferInitGlobal AltF1xCmdParms,BYTE      ;Feature 74378
        ReferInitGlobal AltF1SecCmdParms,BYTE    ; @SEC
        ReferInitGlobal sicg_packet_1A,byte
        ReferInitGlobal sicg_packet_1A_d,byte

        ReferInitGlobal CFG_ReserveDriveLetter,BYTE    ;99999
        ReferGlobal     NumIO,BYTE                     ;99999
        ReferGlobal     NumIOReserveDriveLetter,BYTE   ;99999
        ReferGlobal     ReserveDriveLetterStart,BYTE   ;99999

        extrn   InitFSCTemplateR3:near
        extrn   syiAbortR3:near
        extrn   syiDisplayMessageR3:near
        extrn   syiPauseOnErrorR3:near
        extrn   syiCheckFatDrive:near
        extrn   message_buffer:byte      ; "borrow" a buffer to read/write to
ifdef TRYBUY
        extrn   _RunningLocked:near     ;UniLock
        extrn   _VerifyDDLoaded:near    ;UniLock
        extrn   _LockProblem:near       ;UniLock
        extrn   _StartLockProgram:near  ;UniLock
endif


INITDATA segment

usExeType       dw         0

;       SICG packet to complete Device Manager initialization

sicg_packet_0   dw         SICGFUN0

;       SICG packet to initialize a device driver
;
;       NOTE: This packet is used for functions 3, 4, 5, 6 and 8
;
;       For function 8 (complete FSD install.), only sicg_devhndl in
;       sicg_packet_3_d is used.

public sicg_packet_3_d          ; this is now used for basedd's also
sicg_packet_3   dw         ?
sicg_packet_3_d sicg_pkt3  <>

;       SICG packet to complete device driver initialization

sicg_packet_7   dw         SICGFUN7
sicg_packet_7_d sicg_pkt7  <>

;       SICG packet for use with fscCheck and fscAdd (see fsc.asm)

sicg_packet_9   dw         SICGFUN9
sicg_packet_9_d sicg_pkt9  <>

;       SICG packet to create the 3.x Box

sicg_packet_a   dw         SICGFUNA
; @006  B723649
sicg_packet_a_d sicg_pktA  <,,,cbInitMessageLen,vdmmInitMessageBuf,usInitErrorCode,hsemVDMMInitMessageBufferEmpty,hsemVDMMInitErrorHandlerBusy> ;BC011;

;       SICG packet to deinstall a character device driver

sicg_packet_b   dw         SICGFUNB
sicg_packet_b_d sicg_pktB  <>

;       SICG packet to receive a failure code from VDMMInit
;       this packet handles subfunctions 1 2 and 3
sicg_packet_c   dw         SICGFUNC
sicg_packet_c_d sicg_pktC  <1>

;       SICG packet to add char device entry into table

sicg_packet_11  dw         SICGFUN11
sicg_packet_11_d sicg_pkt11 <>

sicg_packet_12  dw         SICGFUN12

;-----  Data structures defining messages issued -----

;       IFS= statement is missing from config.sys when booting from an
;       IFS partition

tbl_no_ifs_stmt       SMT     <MSG_SYSINIT_NO_IFS_STMT,0>

;       User specified program or device driver file is missing

tbl_user_file_missing SMT     <MSG_SYSINIT_UFILE_NOT_FND,3>
                      SMT_Var <line_number>
                      SMT_Var <command>
                      SMT_Var <object_name>

tbl_dd_missing        equ     tbl_user_file_missing
tbl_run_missing       equ     tbl_user_file_missing
tbl_shell_missing     equ     tbl_user_file_missing

tbl_rshell_missing    SMT     <MSG_SYSINIT_UFILE_NOT_FND,3>
                      SMT_Var <line_number>
                      SMT_Var <command>
                      SMT_Var <file_specification>

;       User specified program or device driver is too big

tbl_user_file_too_big SMT     <MSG_SYSINIT_UFILE_NO_MEM,3>
                      SMT_Var <line_number>
                      SMT_Var <command>
                      SMT_Var <file_specification>

tbl_dd_too_big        equ     tbl_user_file_too_big
tbl_rshell_too_big    equ     tbl_user_file_too_big
tbl_run_too_big       equ     tbl_user_file_too_big
tbl_shell_too_big     equ     tbl_user_file_too_big


;       User specified device driver is invalid

tbl_user_dd_invalid   SMT     <MSG_SYSINIT_UDRVR_INVAL,3>
                      SMT_Var <line_number>
                      SMT_Var <command>
                      SMT_Var <file_specification>

;       User specified device driver did not install

tbl_dd_not_installed  SMT     <MSG_SYSINIT_UDRVR_FAIL,3>
                      SMT_Var <line_number>
                      SMT_Var <command>
                      SMT_Var <file_specification>

tbl_cant_load_dd      equ     tbl_user_dd_invalid
tbl_invalid_dd        equ     tbl_user_dd_invalid

;       User specified program is non-executable

tbl_ufile_cant_exec   SMT     <MSG_SYSINIT_UEXEC_FAIL,3>
                      SMT_Var <line_number>
                      SMT_Var <command>
                      SMT_Var <object_name>

tbl_run_cant_exec     equ     tbl_ufile_cant_exec
tbl_shell_cant_exec   equ     tbl_ufile_cant_exec

tbl_rshell_cant_exec  SMT     <MSG_SYSINIT_UEXEC_FAIL,3>
                      SMT_Var <line_number>
                      SMT_Var <command>
                      SMT_Var <file_specification>

;       User specified program requires Presentation Manager
; defects 73958 - M. Violante

tbl_user_file_pm      SMT     <MSG_OS2STUB_PM,0>

;       System program is missing

tbl_sys_file_missing  SMT     <MSG_SYSINIT_SFILE_NOT_FND,1>
                      SMT_Var <object_name>

tbl_dshell_missing    equ     tbl_sys_file_missing

;       System program is too big

tbl_sys_file_too_big  SMT     <MSG_SYSINIT_SFILE_NO_MEM,1>
                      SMT_Var <file_specification>

tbl_dshell_too_big    SMT     <MSG_SYSINIT_SFILE_NO_MEM,1>
                      SMT_Var <shell_exe>

;       System program is non-executable

tbl_sys_cant_exec     SMT     <MSG_SYSINIT_SEXEC_FAIL,1>
                      SMT_Var <object_name>

tbl_dshell_cant_exec  equ     tbl_sys_cant_exec

;       Not enough memory to create DOS mode

tbl_3x_too_big        SMT     <MSG_SYSINIT_DOS_NO_MEM,0>

;       Can't create DOS mode

tbl_cannot_create_3x  SMT     <MSG_SYSINIT_DOS_FAIL,1>
                      SMT_Var <error_string>

;       A base VDD failed to install
tbl_sdrvr_fail        SMT     <MSG_SYSINIT_SDRVR_FAIL,1>
                      SMT_Var <vdmmInitMessageBuf>

;       A user (installable) VDD failed to install
tbl_udrvr_fail        SMT     <MSG_SYSINIT_UDRVR_FAIL,3>
                      SMT_Var <line_number>
                      SMT_Var <command>
                      SMT_Var <vdmmInitMessageBuf>

;       A VDD could not be loaded (either base or user-installable)

tbl_vdd_invalid       SMT       <MSG_SYSINIT_UDRVR_INVAL,3> ; SYS1719
                      SMT_Var <line_number>
                      SMT_Var <command>
                      SMT_Var <vdmmInitMessageBuf>

;       DOS mode device driver modified system storage

tbl_arena_trashed     SMT     <MSG_SYSINIT_DOS_MODIFIED,2>
                      SMT_Var <line_number>
                      SMT_Var <file_specification>

;       DOS mode device driver executed an INT 21

tbl_bad_dos_dd        SMT     <MSG_SYSINIT_BAD_DOS_DD,3>
                      SMT_Var <line_number>
                      SMT_Var <command>
                      SMT_Var <file_specification>

;       DOS mode was not created

tbl_dos_not_started   SMT     <MSG_SYSINIT_DOS_STOPPED,0>
tbl_could_not_reserve  SMT    <MSG_SYSINIT_DRV_RESERVE,1>
                      SMT_Var <CFG_ReserveDriveLetter>

;       Error in SET statement

tbl_invalid_parm      SMT     <MSG_SYSINIT_INVAL_PARM,3>
tbl_invalid_parm_line SMT_Var <>
tbl_invalid_parm_name SMT_Var <>
tbl_invalid_parm_token SMT_Var <>

;       Progrress Indicator for DD loading (F2 Key processing)

tbl_load_DDriver        SMT     <MSG_REPLACEMENT_STRING, 1>
tbl_load_DDName         SMT_Var <file_specification>

;       Parameter list for syiStartProgram

Start_Parms           struc
Start_FileSpec        dd      ?       ; address of file specification
Start_Command         dd      ?       ; address of command line
Start_Required        dw      0       ; 0 = program is optional
                                      ; 1 = program is required for
                                      ;     system operation
Start_Async           dw      1       ; 1 = program is in parent's session
                                      ; 4 = program is detached
                                      ; 0 = program run synchronously
Start_Missing         dw      ?       ; offset of file not found message
Start_Too_Big         dw      ?       ; offset of program too big msg
Start_Cant_Exec       dw      ?       ; offset of exec failure message
Start_Parms           ends

fatmsgbuff            db  ' ',0Dh, 0Ah

;       Start parameter list for RUN= command

start_daemon_parms    Start_Parms <,,0,4,tbl_run_missing,tbl_run_too_big,tbl_run_cant_exec>

;       Start parameter list for CALL= command

start_call_parms      Start_Parms <,,0,0,tbl_run_missing,tbl_run_too_big,tbl_run_cant_exec>

;  Removed by CP20 DCR 1152
;       Start parameter list for LOGDAEM.EXE
;
;start_log_parms       Start_Parms <LogDaem_exe,?,0,,tbl_run_missing,tbl_run_too_big,tbl_run_cant_exec>

;       Start parameter list for PROTSHELL= command

start_shell_parms     Start_Parms <,,1,,tbl_shell_missing,tbl_shell_too_big,tbl_shell_cant_exec>

;       Start parameter list for default PROTSHELL

start_dshell_parms    Start_Parms <shell_exe,cmd_exe,1,,tbl_dshell_missing,tbl_dshell_too_big,tbl_dshell_cant_exec>

;       Start parameter list for FAT Chkdsk

start_chkdsk_parms    Start_Parms <chkdsk,chkdsk_args,0,0,tbl_dshell_missing,tbl_dshell_too_big,tbl_dshell_cant_exec> ;### AC DCR 1520

ascii_table     db     '0123456789ABCDEF' ; translation table used to
                                          ; convert hex to ASCII

e3xbox_string   db  '3XBOX='          ; environment variable for 3.x Box
len_3xbox_string equ $-e3xbox_string

shell_exe       db     'PMSHELL.EXE',0 ; default protected mode shell name
cmd_exe         db     'CMD.EXE',0     ; default parameters
chkdsk          db     'CHKDSK.COM',0      ;
ifdef TRYBUY
hKbdCalls       db     'KBDCALLS',0    ;UniLock
hVioCalls       db     'VIOCALLS',0    ;UniLock
hDosCalls       db     'DOSCALL1',0    ;UniLock
endif

chkdsk_args     db     'C:/N',0     ; chkdsk arguments                     ;### AC DCR 1520

;  Removed by CP20 DCR 1152
;LogDaem_exe     db     'LOGDAEM.EXE',0      ;Log Daemon name

driver_string   db     'Driver '      ; block device driver name (for
                                      ;    messages

b10             db     10             ; used for decimal conversion

blank           equ    ' '            ; blank character
tab             equ    09h            ; tab character

ConfigSys        db     '\CONFIG.SYS',0
Config001        db     '\CONFIG.001',0
len_Config001    equ    ($-Config001)-1
OS2Ini           db     '\OS2\OS2.INI',0
OS2001           db     '\OS2\OS2.001',0
len_OS2001       equ    ($-OS2001)-1
OS2sysIni        db     '\OS2\OS2SYS.INI',0
OS2sys001        db     '\OS2\OS2SYS.001',0
len_OS2sys001    equ    ($-OS2sys001)-1
StartupCMD       db     '\STARTUP.CMD',0
Startup001       db     '\STARTUP.001',0
len_Startup001   equ    ($-Startup001)-1

GoodConfigSys    db     '\OS2\INSTALL\CONFIG.SYS',0
GoodOS2Ini       db     '\OS2\INSTALL\OS2.INI',0
GoodOS2SysIni    db     '\OS2\INSTALL\OS2SYS.INI',0

;75220 support extended libpaths
BeginLibpath     db     'BEGINLIBPATH',0
EndLibpath       db     'ENDLIBPATH',0

;59527 SVGADataFile     db     '\OS2\SVGADATA.PMI',0

INITDATA ends


INITBSS segment

;       Semaphores and communications region for VDMMInit to tell
;       syiReceiveVDMErrors that a nonfatal error occurred

        public hsemSICGThreadDead
        public hsemVDMMInitMessageBufferEmpty
        public hsemVDMMInitErrorHandlerBusy
        public fVDMMInitComplete

cbInitMessageLen                equ 80 ; size of message buffer below

hsemSICGThreadDead              dd 0  ;
hsemVDMMInitMessageBufferEmpty  dd 0  ; these 3   semaphores are described
hsemVDMMInitErrorHandlerBusy    dd 0  ; in SICG.ASM function 0Ch
usInitErrorCode                 dw ?  ; nonfatal error code
vdmmInitMessageBuf              db cbInitMessageLen dup(?) ; message buffer
fVDMMInitComplete               dw 0  ; has VDMMInit finished?

;       Miscellaneous data fields

pDevHlp               dd  ?           ; address of Device Helper router
DDPacket              Packet <>       ; initialization packet
null_argument   db     0              ; null argument string

    public command_string
command_string  db     1024 dup(?)    ; command line for DosExecPgm

line_number     db     6 dup(0)       ; CONFIG.SYS line number
command         db     MAXPATHLEN dup(?)     ; command name
file_specification db  1024 dup(?)    ; file specification

dd_name_string  db     10 dup(?)      ; device driver name

error_string    db     5 dup(0)       ; error code string

Environ_String_Max equ 1024
Environ_Buffer  db Environ_String_Max+1 dup(?)  ; buffer to hold parsed environment string
Environ_Keyword_Length dw ?             ; the length of the environment variable
Environ_Argument_Length dw ?            ; the length of the entire environment string

environment_string db  1024 dup(0)      ; environment string to be added for execpgm

object_name     db     MAXPATHLEN dup(0)      ; name of failing module
object_name_len equ    $-object_name

source_handle   dw  0           ; handle for source file
target_handle   dw  0           ; handle for source file

bytes_read      dw  0           ; number of bytes read

ShowErrorMsg    db  0         ; Show error message if Device driver fails init?
ifdef TRYBUY
LockedDDLoaded  db  0         ;UniLock   Locked Device driver loaded
endif

INITBSS ends

;       Structure of a double word

double_word     struc
lsw             dw     ?              ; least significant word
msw             dw     ?              ; most significant word
double_word     ends

        FARCODE INITR3
.386p
INITR3CODE segment
        assume  ds:DOSINITDATA,es:nothing


; SUBROUTINE NAME: syiInstallDeviceDrivers
;
; DESCRIPTIVE NAME: Install device drivers
;
; FUNCTION:      To load and initialize all user specified
;                device drivers and file system drivers.
;
; NOTES:         This is an internal subroutine within syiProcess
;
; ENTRY POINT: syiInstallDeviceDrivers
;    LINKAGE:    Call (near) from syiProcess
;
; INPUT:         Config_Sys_Data contains the selector for the
;                                CONFIG.SYS data segment
;                (DS) -> DOSINITDATA
;
; EXIT-NORMAL: Return to caller (no values returned)
;
; EXIT-ERROR:    None
;
; EFFECTS:       All registers are preserved
;
; INTERNAL REFERENCES:
;    ROUTINES: syiInstallDeviceDriver - Install device driver
;                syiInstallFileSysDriver - Install FS driver
;
; EXTERNAL REFERENCES:
;    ROUTINES: SICG              - Perform initialization function
;
;
; Procedure syiInstallDeviceDrivers(CONFIG.SYS data)
;
; For each DEVICE/FSD packet
;   if FSD packet
;     Call syiInstallFileSysDriver(file specification,parameters)
;       to load and initialise the file system driver
;     Check to see if this was HPFS
;   else                                /* it is a DEVICE packet
;     Call syiInstallDeviceDriver(file specification,parameters)
;       to load and initialize the device driver
;   Call syiPauseOnErrorR3 to display "press Enter key to continue" if an
;       error message was displayed
; Next statement
;
; Call SICG(0) to complete Device Manager initialization
;
; Return
;
; End syiInstallDeviceDrivers

Procedure syiInstallDeviceDrivers
    assume ds:DOSINITDATA, es:nothing, fs:nothing, gs:nothing, ss:nothing
        SaveReg <ds,es>
        pusha

        LocalVar HPFS_IFS_Present,BYTE
ifdef TRYBUY
        LocalVar pDOSCALLS,DWORD       ;UniLock    Order must be preserved!!
        LocalVar pKBDCALLS,DWORD       ;UniLock    Order must be preserved!!
        LocalVar pVIOCALLS,DWORD       ;UniLock    Order must be preserved!!
endif
        EnterProc
        mov     HPFS_IFS_Present,0

;       Pick up the address of the Device Helper router

        DosContext es
        mov     ax,DevHlp.msw
        mov     pDevHlp.msw,ax
        mov     ax,DevHlp.lsw
        mov     pDevHlp.lsw,ax
        mov     al,CFG_ReserveDriveLetter   ;99999 start
        .if     <al eq 0ffh>           ; was ReserveDriveLetter specified?
             mov    al, NumIO          ; no, use NumIO as starting place.
        .else
             mov    ah,NumIO           ; Check NumIO
             .if    <ah a al>         ; Did BASEDEVS encroach on reserve letter?
                  add     CFG_ReserveDriveLetter,"A" ; make it ASCII
                  push    si
                  mov  si,offset tbl_could_not_reserve
                  call syiDisplayMessageR3
                  pop     si
                  sub     CFG_ReserveDriveLetter,"A" ;unmake ASCII
                  mov    al,NumIO      ; encroachment, reset to start at NumIO
             .else                     ;else all is well
                inc     al             ; start after reserved drive letter
             .endif
        .endif
        mov     NumIOReserveDriveLetter,al
        mov     ReserveDriveLetterStart,al        ;99999 end
        assume  es:nothing

; BLINK thread should already be running here

;       Loop through all the DEVICE/FSD data packets

        mov     es,Config_Sys_Data
        mov     si,es:[0].CFG_Device.CFG_Head
        .while  <nonzero si> near

          mov   dx,es:[si].CFG_Next
          mov   bl,es:[si].CFG_Type

;         Save the CONFIG.SYS file line number and the name of the
;         device driver file for any error messages    B720443 Edd

          call  syiCopyConfigSysData            ; @003 Edd

          .if <bl eq EXT_DEVICE> near
            push  es
            push  es:[si].CFG_FileSpec
            push  ds
            push  offset DOSINITDATA:usExeType
            call  pDosIQAppType
            .if   <zero ax> or
            .if   <ax eq ERROR_INVALID_EXE_SIGNATURE> near
              mov   cx,[usExeType]
              .if <ax eq ERROR_INVALID_EXE_SIGNATURE> or
              test  cx,QAT_DOSEXE       ; if old device, put on RM device list
              .if   <nz>
                xor   ax,ax
                mov   di,es:[0].CFG_RMDevice.CFG_Tail
                .if   <zero di>
                  mov  es:[0].CFG_RMDevice.CFG_Head,si
                .else
                  mov  es:[di].CFG_Next,si
                .endif
                mov   es:[si].CFG_Next,0
                mov   es:[0].CFG_RMDevice.CFG_Tail,si
              .else
                mov   word ptr es:[si].CFG_Size,-1   ;do not allow size value  BN001
                mov   word ptr es:[si].CFG_Size+2,-1 ;even if specified        BN001
                and   cx,QAT_VDD or QAT_32BIT or QAT_PDD or QAT_DYNLINK
                cmp   cx,QAT_VDD or QAT_32BIT or QAT_DYNLINK
                                        ; VDD's should have QAT_VDD and
                .if <z>                 ; QAT_32BIT bits set.
                                        ; If VDD, put on VDD device list
                  mov   di,es:[0].CFG_VDDDevice.CFG_Tail
                  .if   <zero di>
                    mov   es:[0].CFG_VDDDevice.CFG_Head,si
                  .else
                    mov   es:[di].CFG_Next,si
                  .endif
                  mov   es:[si].CFG_Next,0
                  mov   es:[0].CFG_VDDDevice.CFG_Tail,si
                .else
                  cmp  cx,QAT_DYNLINK
                  .if <z> or
                  cmp  cx,QAT_PDD or QAT_32BIT or QAT_DYNLINK
                  .if <z>
                    inc  ax           ; set "do install dd/filesys" flag
                  .else
                    ; @003 B720443 Edd added invalid (V)DD msg call here
                    push  si
                    test  cx,QAT_VDD  ; none of the above, something wrong?
                    .if <nz>
                       ; a VDD failed to load, invalid bits...
                       mov  si,offset tbl_vdd_invalid
                    .else
                       ; a DD failed to load, invalid bits...
                       mov  si,offset tbl_invalid_dd
                    .endif
                     call syiDisplayMessageR3
                     pop  si
                    ; @003 B720443 ends
                  .endif
                .endif
              .endif
            .endif
          .else
            mov ax,1                    ; IFS, (ax) != 0
          .endif

;         Install the specified device/filesys driver

          .if <nonzero ax>              ; if not RM or VDD device

;;;;;;;;; Progress Indicator for device Driver Installs

              .if <AltFxKeyPressed  e 2>
                  push  si
                  mov   si, offset  tbl_load_DDriver
                  call  syiDisplayMessageR3
                  pop   si
              .endif

            .if <bl eq EXT_DEVICE>
              call  syiInstallDeviceDriver
            .else
              call  syiInstallFileSysDriver
              ;start of changes for @007
              SaveReg <es,di,bx,ax>
              xor   bx,bx
              mov   di,es:[si].CFG_FileSpec      ;es:di -> filename
              mov   eax,es:[di+bx]
              .while <al ne 0>          ;while not end of filename
                  .if   <al eq 'H'> or
                  .if   <al eq 'h'>
                      .if <ah eq 'P'> or
                      .if <ah eq 'p'>
                          shr  eax,16
                         .if   <al eq 'F'> or
                         .if   <al eq 'f'>
                             .if <ah eq 'S'> or
                             .if <ah eq 's'>
                                 mov   al,es:[di+bx+4]
                                .if <al eq '.'>
                                 mov   HPFS_IFS_Present,1 ; HPFS ifs statement
                                .endif
                             .endif
                         .endif
                      .endif
                  .endif
                  .if <HPFS_IFS_Present eq 1> ;found HPFS ifs statment
                      xor   ax,ax             ; so exit
                  .else
                      inc   bx
                      mov   eax,es:[di+bx]
                  .endif
              .endwhile
              RestoreReg <ax,bx,di,es>
              ;end of changes for @007
            .endif
          .endif
          call  syiPauseOnErrorR3
          mov   si,dx
        .endwhile
ifdef TRYBUY
    ;UniLock   Call to build protected DD
    ;UniLock   If needed, dummy up CFG packet (or re-use one since we're finished)
    ;UniLock   load DS, ES:SI (SI?) and call syiInstallDeviceDriver
    ;UniLock   verify that it loaded OK.
    ;UniLock
    ;UniLock

    ;UniLock   already in DosContext, no need to switch

        DosContext   es                     ;
        mov   cx,SISData.SIS_BootDrv        ;get the boot drive from
        add   cl,'A' - 1                    ;the system infoseg, make alpha
        cmp   cl,'C'                        ; C: drive or above
        jge   oktrylock                     ; do the checking
        jmp   nolock                        ; no checking for booted from diskette

oktrylock:
        DosInitContext <DS>, bx

        ;Setup pKBDCALLS, pDOSCALLS, etc
        mov   pKBDCALLSh,DS
        mov   pKBDCALLSl,offset hKbdCalls
        mov   pVIOCALLSh,DS
        mov   pVIOCALLSl,offset hVioCalls
        mov   pDOSCALLSh,DS
        mov   pDOSCALLSl,offset hDosCalls

        push  DS
        push  offset file_specification
        push  DS
        push  offset dd_name_string
        push  SS
        lea   ax, pVIOCALLS
        push  AX
;        push  offset pVIOCALLS
        push  03
        call _RunningLocked
        .if <ax eq 2>
           mov    [LockedDDLoaded],1
           mov     es,Config_Sys_Data
           mov     si,es:[0].CFG_Device.CFG_Head

           push    es                         ; Save pointer to CFG Packet
           push    si                         ;

           mov   di,es:[si].CFG_FileSpec      ;es:di -> filename
           DosInitContext <DS>, bx
           mov     si,offset file_specification
           .repeat
             lodsb                            ;Copy from file_specification
             stosb                            ; to CFG_FileSpec
           .until  <al eq 0>

           pop     si                         ; Restore pointer to CFG Packet
           pop     es                         ;

           ; Dummy up first CFG_Device packet (see inicfg.inc)

           mov     es:[si].CFG_Type,EXT_DEVICE
           mov     word ptr es:[si].CFG_Size,-1   ;do not allow size value
           mov     word ptr es:[si].CFG_Size+2,-1 ;even if specified
           mov     word ptr es:[si].CFG_Next,0
           mov     word ptr es:[si].CFG_LineNumber,0
           mov     ax,ds
           shl     eax,16
           mov     ax,offset file_specification
           mov     dword ptr es:[si].CFG_Command,eax

           call  syiInstallDeviceDriver

           push  DS
           push  offset dd_name_string
           call _VerifyDDLoaded
           .if <ax eq 0>
              jmp lockProblem
           .endif
        .elseif <ax eq 1>
lockProblem:
           ;;Fail boot
           call _LockProblem
        .else
           ;;Continue normally
           mov    [LockedDDLoaded],0
        .endif
nolock:                                 ; no locking

endif
        DosContext   es                 ; Check to see if booting an ifs (partition)
        .if <es:mFSD_FLAG ne FALSE> and ; and if an ifs statement was present
        .if <HPFS_IFS_Present eq 0>     ; if no ifs statement then halt system
            DosInitContext   ds         ; with message to add ifs to config.sys
            mov   si,offset tbl_no_ifs_stmt
            call  syiAbortR3
        .endif

;       Signal end of device driver init time

        mov     _DDInitTime,0    ; Warning, this is R3 code modifying R0 data

;       Call the ldr to signal completion of all PDD and IFS init. As we have
;       to go through a R0 call gate here, this is a call to ldrDirtyWorker
;       with function code 2.
        xor     ax,ax
        inc     ax
        inc     ax
        push    ax             ; function code = 2
        xor     ax,ax
        push    ax             ; pass NULL pointer
        push    ax
        db      9ah            ; call GDT call gate for 16-bit worker
        dw      0,GDT_DOS16LDRDIRTYWORKER

;       Now that all device drivers have been installed, call the
;       Device Manager to complete its initialization

        push    ds
        push    offset DOSINITDATA:sicg_packet_0
        call    pSICG


;       Return to caller

        LeaveProc

        popa
        RestoreReg <es,ds>
        ret

EndProc syiInstallDeviceDrivers


;
; SUBROUTINE NAME: syiInstallDeviceDriver
;
; DESCRIPTIVE NAME: Install a device driver
;
; FUNCTION:      To load and initialize a device driver
;
; NOTES:         This is an internal subroutine within
;                  syiInstallDeviceDrivers
;
; ENTRY POINT: syiInstallDeviceDriver
;    LINKAGE:    Call (near)
;
; INPUT:         ES:SI = address of DEVICE= data packet
;                (DS) -> DOSINITDATA
;
; EXIT-NORMAL: Return to caller (no values returned)
;
; EXIT-ERROR:    None
;
; EFFECTS:       All registers are preserved
;
; INTERNAL REFERENCES:
;    ROUTINES: syiLoadDeviceFileSysDriver
;                syiDisplayMessageR3 - Display an error message
;                syiInitializeDeviceDriver - Initialize a
;                                  device driver
;
; EXTERNAL REFERENCES:
;    ROUTINES:
;                SICG            - Perform initialization function
;
;
; Procedure syiInstallDeviceDriver(CONFIG.SYS data packet)
;
; Call syiLoadDeviceFileSysDriver
; If the load was not successful
;   Return
;
; Call SICG(3,handle,device header,initial device number,
;     protected mode CS,protected mode DS,real mode CS,real mode DS)
;     to see if this is a valid device driver and lock its segments
;
; If the module is not a device driver
;   Call syiDisplayMessageR3(device driver file invalid)
; else
;   pick up the address of the device header and the first device
;       number from the SICG packet
;   number of drivers = 0
;   indicate no device drivers were successfully installed
;
;   For each device header in the device header chain
;     put real and protected mode CS and DS values into device header
;   Next device header
;
;   For each device header in the device header chain
;     increment driver number
;     Call syiInitializeDeviceDriver(device header,
;         driver number)
;     If device driver was successfully installed
;       indicate a device driver was installed
;     endif
;   Next device header
;
;   If a device driver was installed successfully
;     Call SICG(5,device header,end code,end data) to resize
;       the first data and first code segments and to set DPL to 0
;       for all the permamnent segments
;   else
;     Call syiDisplayMessageR3(no device drivers installed)
;   endif
; endif
;
; Call pSICG(18,handle) to free the device driver module
;
; Return
;
; End syiInstallDeviceDriver
;

Procedure syiInstallDeviceDriver
    assume ds:DOSINITDATA, es:nothing, fs:nothing, gs:nothing, ss:nothing

        LocalVar installed,BYTE
        LocalVar pakt,WORD

        EnterProc
        SaveReg <ds,es>
        pusha

        mov     pakt,si
        call    syiLoadDeviceFileSysDriver
        jnc     short sid00
        jmp     exit_install_device_driver

;       Check that the loaded module is really a device driver, find
;       the device driver header, CS and DS selectors, and initial
;       block device drive number, and lock the segments

sid00:
;
; RAR - Put RM load notification here
;
        push    di
        mov     di,pakt
        add     di,CFG_FileSpec         ;ES:SI has base packet address
        mov     di,es:[di]              ;get pointer
        mov     ax,60h        ;AX   =Notify RM of DD Load
        call    RMNotifyR3    ;ES:DI=ASCIIZ module name
        pop     di


        mov     sicg_packet_3,SICGFUN3
        push    ds                    ; address of packet
        push    offset DOSINITDATA:sicg_packet_3
        call    pSICG
        .if     <nonzero ax>

;         The module is not a valid device driver - inform the user

          mov   si,offset tbl_invalid_dd
          call  syiDisplayMessageR3

;         Free the module

;         call function 18 to free device driver through ldrfreemodule
;         instead of dosfreemodule  77939 ceb

          mov   sicg_packet_3,SICGFUN18                         ;ceb 77939
          push  ds                    ; address of packet       ;ceb 77939
          push  offset DOSINITDATA:sicg_packet_3                ;ceb 77939
          call  pSICG                                           ;ceb 77939
;          push    sicg_packet_3_d.sicg_devhndl ; module handle ;ceb 77939
;          call    pDosFreeModule                               ;ceb 77939
;
; RAR - Put RM unload notification here
;
        mov     ax,61h        ;AX   =Notify RM of DD unload
        call    RMNotifyR3    ;ES:DI=ASCIIZ module name

          jmp     exit_install_device_driver

        .endif

;       The device driver is valid - install it

        mov     installed,0           ; indicate no device drivers were
                                      ;    installed

;       Fill in the CS and DS values for each device header in the chain

        SaveReg <es>
        les     di,sicg_packet_3_d.sicg_devhdr
        mov     ax,sicg_packet_3_d.sicg_protcs ; ring 0 CS selector
        mov     bx,sicg_packet_3_d.sicg_protds ; ring 0 DS selector
        mov     cx,sicg_packet_3_d.sicg_realcs ; real CS segment
        mov     dx,sicg_packet_3_d.sicg_realds ; real DS segment
        .while  <di ne -1>
          mov   es:[di].SDevProtCS,ax          ; put the CS and DS
          mov   es:[di].SDevProtDS,bx          ;   values into each
          mov   es:[di].SDevRealCS,cx          ;   DD header in the
          mov   es:[di].SDevRealDS,dx          ;   chain
          mov   es:[di].SDevNext.msw,es        ; fix up the link field
          mov   di,es:[di].SDevNext.lsw
        .endwhile
        RestoreReg <es>

;       Initialize each device driver in the module

        xor     ax,ax                 ; set device driver number to 0
        mov     ShowErrorMsg,al       ; Set to "don't show message"
        .repeat
          inc   ax                    ; increment device driver number
          call  syiInitializeDeviceDriver ; initialize the DD
          .if   nc                    ; was the DD initialized?
            mov installed,1           ; yes, indicate a DD was installed
          .endif
        .until  <sicg_packet_3_d.sicg_devhdr.lsw eq -1>

        .if     <installed ne 0>      ; was a DD installed?

;         At least one device driver was installed - keep the device
;         driver module, resize the first data and code segments and
;         set DPL = 0 for all permanent segments.

          mov   sicg_packet_3,SICGFUN5
          push  ds                    ; address of packet
          push  offset DOSINITDATA:sicg_packet_3
          call  pSICG

;
; RAR - Put RM install notification here
;
          mov   ax,62h        ;AX   =Notify RM of DD install
          call  RMNotifyR3    ;ES:DI=ASCIIZ module name

        .else
;         Free the module

;         call function 18 to free device driver through ldrfreemodule
;         instead of dosfreemodule  77939 ceb

          mov   sicg_packet_3,SICGFUN18                         ;ceb 77939
          push  ds                    ; address of packet       ;ceb 77939
          push  offset DOSINITDATA:sicg_packet_3                ;ceb 77939
          call  pSICG                                           ;ceb 77939
;          push    sicg_packet_3_d.sicg_devhndl ; module handle ;ceb 77939
;          call    pDosFreeModule                               ;ceb 77939

;
; RAR - Put RM unload notification here
;
          mov   ax,61h        ;AX   =Notify RM of DD unload
          call  RMNotifyR3    ;ES:DI=ASCIIZ module name

          .if <ShowErrorMsg ne 0>   ; not Quiet init failure?

;            No device drivers were installed - inform the user and
;            throw away the module.

             mov   si,offset tbl_dd_not_installed
             call  syiDisplayMessageR3

          .endif
        .endif

;       Return to caller

exit_install_device_driver:
;       Call the ldr to signal completion of this PDD init routine. As we have
;       to go through a R0 call gate here, this is a call to ldrDirtyWorker
;       with function code 1.                                         ;63985
                                                                      ;63985
        pushf                                                         ;63985
        xor     ax,ax                                                 ;63985
        inc     ax                                                    ;63985
        push    ax             ; function code = 1                    ;63985
        xor     ax,ax                                                 ;63985
        push    ax             ; pass NULL pointer                    ;63985
        push    ax                                                    ;63985
        db      9ah            ; call GDT call gate for 16-bit worker ;63985
        dw      0,GDT_DOS16LDRDIRTYWORKER                             ;63985
        popf                                                          ;63985

        popa
        RestoreReg <es,ds>
        LeaveProc
        ret

EndProc syiInstallDeviceDriver


;
; SUBROUTINE NAME: syiInstallFileSysDriver
;
; DESCRIPTIVE NAME: Install a File System driver
;
; FUNCTION:      To load and initialize a File System driver
;
; NOTES:         This is an internal subroutine within
;                  syiInstallDeviceDrivers
;
; ENTRY POINT: syiInstallFileSysDriver
;    LINKAGE:    Call (near)
;
; INPUT:         ES:SI = address of FSD= data packet
;                (DS) -> DOSINITDATA
;
; EXIT-NORMAL: Return to caller (no values returned)
;
; EXIT-ERROR:    None
;
; EFFECTS:       All registers are preserved
;
; INTERNAL REFERENCES:
;    ROUTINES: syiLoadDeviceFileSysDriver
;
; EXTERNAL REFERENCES:
;    ROUTINES:
;                DosGetProcAddr  - Get address to a procedure
;                SICG            - Perform initialization function
;
;
; Procedure syiInstallFileSysDriver(CONFIG.SYS data packet)
;
; Call syiLoadDeviceFileSysDriver
;     to load the file system device driver
; If error
;   Return
;
; For each name in fscNameList table
;   Call pDosGetProcAddr
;   If DosGetProcAddr returned error
;     Call syiDisplayMessageR3(FileSys driver file invalid)
;     Call pSICG(18)
;     Return
;   endif
; Next name
;
; Call SICG (9,SICG_FSCCHECK)
;     to make sure that the FSC is ok for this FSD
; If error
;   syiDisplayMessageR3(FileSys driver file invalid)
;   Call pSICG(18)
;   Return
; endif
;
; Call FS_INIT(parameter string from FSD= in config.sys)
; If error
;   syiDisplayMessageR3(FileSys driver file invalid)
;   Call pSICG(18)
;   Return
; endif
;
; If a Mini FSD is present
;
;   Call SICG(12)
;     to terminate the Mini FSD
;
;   Call SICG(9,SICG_FSCREPLACE)
;     to replace the mini-FSD's FSC with this FSD's FSC
;
; Else
;
;   Call SICG(9,SICG_FSCADD)
;     to add ths FSD's FSC to the FSC segment
; Endif
;
; If successful
;   Call SICG(8,device header) to set DPL = 0 for all the segments in
;       the FSD module
; else
;   Call syiDisplayMessageR3(FileSys driver init failed)
; endif
;
; Call pSICG(18)
;     to free the device driver module
;
; Return
;
; End syiInstallFileSysDriver
;

Procedure syiInstallFileSysDriver
    assume ds:DOSINITDATA, es:nothing, fs:nothing, gs:nothing, ss:nothing

        SaveReg <ds,es>
        pusha

        call    syiLoadDeviceFileSysDriver
        jnc     short sif00
        jmp     exit_install_filesys_driver
sif00:
        mov     ax,sicg_packet_3_d.sicg_devhndl
        mov     cx,3

        call    InitFSCTemplateR3
        jnc     sif01
        jmp     error_install_filesys_driver

;       Confirm that the FSC for this FSD doesn't contain any intolerable
;       errors, so that we can go ahead and init it.
sif01:
        mov     sicg_packet_9,SICGFUN9
        mov     sicg_packet_9_d.si9_funcnum,SICG_FSCCHECK ; perform fscCheck
        push    ds                    ; address of packet
        push    offset DOSINITDATA:sicg_packet_9
        call    pSICG
        DosContext      ds
        .if <mFSD_FLAG ne FALSE> near
          .if     <ax ne ERROR_ALREADY_EXISTS>
            jmp   error_install_boot_filesys_driver
          .endif

;         ES:SI -> config.sys data packet
;         (DS) -> DOSINITDATA
;
;         Call the init routine for this FSD.


          mov     ax,es:[si].CFG_Parameters
          .if     <nonzero ax>
            push    es
          .else
            push    ax
          .endif
          push    ax
          DosInitContext  ds            ; Gain addressability to pDevHlp
          push    pDevHlp.msw
          push    pDevHlp.lsw           ; Push pointer to DevHelp call-gate
          DosContext    ds
          mov     ax,offset pMiniFSD    ; DS:AX -> pMiniFSD
          push    ds
          push    ax
          DosInitContext  ds
          mov     si,offset DOSINITDATA:fscInitTemplate
          call    dword ptr ds:[si].FS_INIT
          SaveReg <ax>
;move fsd selectors to ring 0
          SaveReg <ds>
          mov     sicg_packet_3,SICGFUN8
          push    ds                    ; address of packet
          push    offset DOSINITDATA:sicg_packet_3
          call    pSICG
          RestoreReg <ds>
;terminate mini_fsd
          push    ds
          push    offset DOSINITDATA:sicg_packet_12
          call    pSICG
          .if <nonzero ax>
            jmp   error_install_boot_filesys_driver
          .endif

;         call function 18 to free mini_fsd through ldrfreemodule
;         instead of dosfreemodule  77939 ceb

          mov     ax,sicg_packet_3_d.sicg_devhndl ; ceb 77939 save devhandle
          push    ax
          mov     ax,mFSD_Handle                  ; ceb 77939 store fsd handle
          mov     sicg_packet_3_d.sicg_devhndl,ax ; ceb 77939 in packet
          mov     sicg_packet_3,SICGFUN18         ; ceb 77939
          push    ds                              ; ceb 77939 address of packet
          push  offset DOSINITDATA:sicg_packet_3  ; ceb 77939
          call    pSICG                           ; ceb 77939
;          call  pDosFreeModule                   ; ceb 77939
          pop     ax                              ; ceb 77939
          mov     [sicg_packet_3_d].sicg_devhndl,ax ; ceb 77939 restore packet
          DosContext      ds

          mov   ds:mFSD_FLAG,FALSE
          DosInitContext  ds
          RestoreReg    <ax>
          .if <nonzero ax>
            jmp   short error_install_boot_filesys_driver
          .endif

  ;       Add this FSD's FSC to the FSC segment.

          mov     sicg_packet_9,SICGFUN9
          mov     sicg_packet_9_d.si9_funcnum,SICG_FSCREPLACE ; perform fscAdd
          push    ds                    ; address of packet
          push    offset DOSINITDATA:sicg_packet_9
          call    pSICG
          .if     <nonzero ax>
            jmp   short error_install_boot_filesys_driver
          .endif
        .else
          .if     <nonzero ax>
            jmp   error_install_filesys_driver
          .endif

;         ES:SI -> config.sys data packet
;
;         Call the init routine for this FSD.

          mov     ax,es:[si].CFG_Parameters
          .if     <nonzero ax>
            push    es
          .else
            push    ax
          .endif
          push    ax
          DosInitContext  ds            ; Gain addressability to pDevHlp
          push    pDevHlp.msw
          push    pDevHlp.lsw           ; Push pointer to DevHelp call-gate
          push    0
          push    0
          mov     si,offset fscInitTemplate
          call    dword ptr ds:[si].FS_INIT
          .if <nonzero ax>
            jmp   short error_install_filesys_driver
          .endif

  ;       Add this FSD's FSC to the FSC segment.

          mov     sicg_packet_9,SICGFUN9
          mov     sicg_packet_9_d.si9_funcnum,SICG_FSCADD ; perform fscAdd
          push    ds                    ; address of packet
          push    offset DOSINITDATA:sicg_packet_9
          call    pSICG
          .if     <nonzero ax>
            jmp   short error_install_filesys_driver
          .endif
;move fsd selectors to ring 0
        mov     sicg_packet_3,SICGFUN8
        push    ds                    ; address of packet
        push    offset DOSINITDATA:sicg_packet_3
        call    pSICG
        .endif

        jmp     short exit_install_filesys_driver

error_install_boot_filesys_driver:
       DosInitContext   ds
       mov   si,offset tbl_invalid_dd
       call  syiAbortR3

error_install_filesys_driver:
       DosInitContext   ds
       mov   si,offset tbl_invalid_dd
       call  syiDisplayMessageR3

;       Free the module

free_filesys_driver:

;       call function 18 to free device driver through ldrfreemodule
;       instead of dosfreemodule  77939 ceb

        mov   sicg_packet_3,SICGFUN18                         ;ceb 77939
        push  ds                    ; address of packet       ;ceb 77939
        push  offset DOSINITDATA:sicg_packet_3                ;ceb 77939
        call  pSICG                                           ;ceb 77939
;        push    sicg_packet_3_d.sicg_devhndl ; module handle ;ceb 77939
;        call    pDosFreeModule                               ;ceb 77939

;       Return to caller

exit_install_filesys_driver:

;       Call the ldr to signal completion of this IFS init routine. As we have
;       to go through a R0 call gate here, this is a call to ldrDirtyWorker
;       with function code 1.

        xor     ax,ax
        inc     ax
        push    ax             ; function code = 1
        xor     ax,ax
        push    ax             ; pass NULL pointer
        push    ax
        db      9ah            ; call GDT call gate for 16-bit worker
        dw      0,GDT_DOS16LDRDIRTYWORKER

        popa
        RestoreReg <es,ds>
        ret

EndProc syiInstallFileSysDriver


;
; SUBROUTINE NAME: syiLoadDeviceFileSysDriver
;
; DESCRIPTIVE NAME: Load a Device or a FileSystem driver
;
; FUNCTION:      To load a Device or a FileSystem driver
;
; NOTES:         This is an internal subroutine within
;                  syiInstallDeviceDrivers
;
; ENTRY POINT: syiLoadDeviceFileSysDriver
;    LINKAGE:    Call (near)
;
; INPUT:         ES:SI = address of DEVICE/FSD data packet
;                (DS) -> DOSINITDATA
;
; EXIT-NORMAL: CF = 0
;
; EXIT-ERROR:    CF = 1
;
; EFFECTS:       All registers are preserved
;
; INTERNAL REFERENCES:
;    ROUTINES: syiCopyConfigSysData - Copy line number,
;                                  command, and file spec from
;                                  CONFIG.SYS data packet
;                syiDisplayMessageR3 - Display an error message
;
; EXTERNAL REFERENCES:
;    ROUTINES:
;                DosLoadModule   - Load a module
;
;
; Procedure syiLoadDeviceFileSysDriver(CONFIG.SYS data packet)
;
; Call syiCopyConfigSysData(CONFIG.SYS packet) to save the
;    line number and file specification for any error messages
;
; Call DosLoadModule(file specification,handle) to load the
;    device/filesys driver
;
; If the module could not be loaded
;   Case error code of
;     Error_file_not_found:
;     Error_path_not_found:
;       message ID = device driver file not found
;     Error_bad_format:
;     Error_invalid_exe_signature:
;       if (TYPE_DEVICE)
;         message ID = 0
;         add this device driver to the list of DOS mode device drivers
;       else
;         message ID = unable to load driver
;       endif
;     Error_not_enough_memory:
;       message ID = insufficient memory for device driver
;     else
;       message ID = unable to load device driver
;   endcase
;   Call syiDisplayMessageR3(message ID)
;   stc
; endif
;
; Return
;
; End syiLoadDeviceFileSysDriver
;

Procedure syiLoadDeviceFileSysDriver
    assume ds:DOSINITDATA, es:nothing, fs:nothing, gs:nothing, ss:nothing

        SaveReg <ds,es>
        pusha

;       Save the CONFIG.SYS file line number and the name of the device
;       driver file for any error messages

        call    syiCopyConfigSysData

        mov     bl,es:[si].CFG_Type   ; (BL) = EXT_DEVICE or EXT_FSD
        SaveReg <es>
        DosContext es
        mov     LoadDevDrv,bl         ; tell DOSLOADMODULE load type
        RestoreReg <es>
        assume  es:nothing

        push    ds                    ; address of object name buffer
        push    offset object_name
        push    object_name_len       ; length of object name buffer
        push    es                    ; address of file specification
        push    es:[si].CFG_FileSpec
        push    ds                    ; address of module handle
        mov     ax,offset sicg_packet_3_d.sicg_devhndl
        push    ax
        call    pDosLoadModule

;       If the module could not be loaded, display an error message
;       or add the module to the list of DOS mode device drivers

        .if     <nonzero ax>
          .if   <ax eq ERROR_FILE_NOT_FOUND> or
          .if   <ax eq ERROR_PATH_NOT_FOUND>
            mov si,offset tbl_dd_missing
          .elseif <ax eq ERROR_BAD_FORMAT> or
          .if   <ax eq ERROR_INVALID_EXE_SIGNATURE>
            mov si,offset tbl_cant_load_dd
          .elseif <ax eq ERROR_NOT_ENOUGH_MEMORY>
            mov si,offset tbl_dd_too_big
          .else
            mov si,offset tbl_cant_load_dd
          .endif
          .if   <nonzero si>
            call syiDisplayMessageR3
          .endif
          stc
        .else                           ; load worked
          DosContext ds,ax
;147968          cmp   es:[si].CFG_Type,EXT_FSD
;147968          je    short ldfd20
;147968          cmp   [_LDRDDOwner],MAXDDOWNER
;147968          jae   short ldfd30            ; avoid overflowing DD owner counter
;147968          inc   [_LDRDDOwner]
;147968          jmp   short ldfd30
;147968ldfd20:
;147968          cmp   [_LDRFSDOwner],MAXFSDOWNER
;147968          jae   short ldfd30            ; avoid overflowing FSD owner counter
;147968          inc   [_LDRFSDOwner]
;147968ldfd30:
          clc
        .endif

        popa
        RestoreReg <es,ds>
    assume ds:nothing, es:nothing
        ret
EndProc syiLoadDeviceFileSysDriver


;
; SUBROUTINE NAME: syiInitializeDeviceDriver
;
; DESCRIPTIVE NAME: Initialize a device driver
;
; FUNCTION:      To initialize a device driver
;
; NOTES:         This is an internal subroutine within
;                  syiInstallDeviceDriver
;
; ENTRY POINT: syiInitializeDeviceDriver
;    LINKAGE:    Call (near)
;
; INPUT:         ES:SI = address of DEVICE= data packet
;                AX    = device driver number
;                sicg_packet_3 contains:
;                        address of device driver header
;                        first device number for block device
;
; EXIT-NORMAL: CF = 0
;              ShowErrorMsg unchanged
;                sicg_packet_3 contains:
;                        address of next device driver header
;                        size of code and data segments
;
; EXIT-ERROR:    CF = 1
;                If DD returned ERROR_I24_QUIET_INIT_FAIL
;                  Then ShowErrorMsg remains unchanged.
;                If any error other than ERROR_I24_QUIET_INIT_FAIL occurs
;                  Then ShowErrorMsg set to 1.
;
;
; EFFECTS:       All registers are preserved
;
; INTERNAL REFERENCES:
;    ROUTINES: syiConstructCommandLine - Construct the
;                                  device driver command line
;
; EXTERNAL REFERENCES:
;    ROUTINES:
;                SICG            - Perform initializtion function
;
;
; Procedure syiInitializeDeviceDriver(device driver header,
;     data packet)
;
; If this is a character device
;   device name string = device name from header
;   Call SICG(8,attributes,device name) to deinstall an old
;       device driver with the same name
;   If the deinstall request was rejected
;     Return(initialization failed)
;   endif
; else
;   device name string = 'Driver n' (where n is the device driver number)
; endif
;
; Call syiConstructCommandLine(data packet) to construct the
;     command line string
; Call device driver strategy routine(length,cmd=init,status=0,
;     Device Helper address,parameter string,initial drive number)
;     to initialize the device driver
;
; If (status=error) or (end code=0 and end data=0) or
;     (block device and number of units=0)
;   Return(initialization failed)
; endif
;
; If this is a block device
;   If a BPB vector was supplied
;     Call SICG(7,device header,BPB vector,number of units)
;         to build the DPBs for this device
;     If the build DPB request failed
;       Return(initialization failed)
;     endif
;   endif
;   add number of units to initial device number
; endif
;
; Call SICG(4,device header) to add the device driver to device driver chain
; save code and data segment sizes
;
; Return(initialization succeeded)
;
; End syiInitializeDeviceDriver

Procedure syiInitializeDeviceDriver,near
    assume ds:DOSINITDATA, es:nothing, fs:nothing, gs:nothing, ss:nothing

        LocalVar strategy_routine,DWORD
        LocalVar success,BYTE
        LocalVar character_device,BYTE

        EnterProc
        SaveReg <ds,es>
        pusha

;       See what kind of device driver this is

        SaveReg <es>
        les     di,sicg_packet_3_d.sicg_devhdr
        .if     <bit es:[di].SDevAtt and DEV_CHAR_DEV>

;         This is a character device

          mov   character_device,1

;         Copy the device name from the device header

          SaveReg <ds,es,si,di>       ; copy the device name and
          push  es                    ;   insert a null byte at the end
          push  ds                    ;   to make it into an ASCIIZ
          pop   es                    ;   string for error messages
          pop   ds
          lea   si,[di].SDevName
          mov   di,offset dd_name_string
          mov   cx,8
          rep   movsb
          xor   al,al
          stosb
          RestoreReg <di,si,es,ds>

;         Try to deinstall an older device driver with the same name

          mov   ax,es:[di].SDevAtt                ; DD attributes
          mov   sicg_packet_b_d.siB_Attributes,ax
          mov   sicg_packet_b_d.siB_Name.msw,es   ; DD name
          lea   ax,es:[di].SDevName
          mov   sicg_packet_b_d.siB_Name.lsw,ax
          push  ds                                ; address of packet
          push  offset DOSINITDATA:sicg_packet_b
          call  pSICG
          .if   <nonzero ax>

;           The older device driver refused to be deinstalled -
;           inform the user that the new device driver cannot be
;           installed

            RestoreReg <es>
            les di,sicg_packet_3_d.sicg_devhdr ; point to the next device
            mov di,es:[di].SDevNext.lsw        ; driver header
            mov sicg_packet_3_d.sicg_devhdr.lsw,di
            DosInitContext   ds
            mov ShowErrorMsg, 1       ; Display error message
            stc                       ; indicate failure
            jmp  exit_initialize_device_driver
          .endif
        .else

;         This is a block device

          mov   character_device,0

;         Make sure a drive letter is available         @004a B722160

          push    es
          DosContext es                           ; Address DOSGROUP
          mov     al,es:NumIOReserveDriveLetter   ; Get current number of units

          mov     ah,'Z' - 'A' + 1
          .if     <al nb ah>                      ; Too many units?
            pop     es
            pop     es                            ;From SaveReg above
            les     di,sicg_packet_3_d.sicg_devhdr ; point to the next device
            mov     di,es:[di].SDevNext.lsw        ; driver header
            mov     sicg_packet_3_d.sicg_devhdr.lsw,di
            DosInitContext   ds
            mov ShowErrorMsg, 1       ; Display error message
            stc                                    ; indicate failure
            jmp      exit_initialize_device_driver
          .endif
          pop     es

;         Set the device name string to 'Driver n'

          SaveReg <es,si,di>          ; copy 'Driver ' to device name
          push  ds                    ;   string
          pop   es
          mov   si,offset driver_string
          mov   di,offset dd_name_string
          mov   cx,7
          rep   movsb

          xor   ah,ah                 ;                 @005a B723129
          div   b10                   ; convert device driver number
          add   ax,'00'               ;   to ASCII, append it to the
          .if   <al ne '0'>           ;   device name string, and
            stosb                     ;   add a null byte at the end
          .endif                      ;   to make it into an ASCIIZ
          mov   al,ah                 ;   string
          xor   ah,ah
          stosw
          RestoreReg <di,si,es>
        .endif

;       Pick up the address of the device driver's Strategy Routine
;       entry point

        mov     ax,sicg_packet_3_d.sicg_devcs ; CS = ring 3 CS
        mov     strategy_routine.msw,ax
        mov     ax,es:[di].SDevStrat          ; IP = entry offset
        mov     strategy_routine.lsw,ax
        RestoreReg <es>

;       Call the device driver at its Strategy Routine entry point

        mov     DDPacket.PktLen,PktHeadSize+LENInit     ; length of packet
        mov     DDPacket.PktCmd,CMDInit
        mov     DDPacket.PktStatus,0       ; status = 0
        mov     ax,pDevHlp.msw             ; CS:IP for Device Helper
        mov     DDPacket.InitDevHlp.msw,ax ;       router
        mov     ax,pDevHlp.lsw
        mov     DDPacket.InitDevHlp.lsw,ax
        call    syiConstructCommandLine
        mov     DDPacket.InitpBPB.msw,ds   ; command line
        mov     DDPacket.InitpBPB.lsw,offset command_string
        mov     al,sicg_packet_3_d.sicg_drvno ; first drive number
        mov     DDPacket.Initdrv,al

        SaveReg <es,ds>
        pusha
        push    ds                    ; ES:BX = address of initialization
        pop     es                    ;         packet
        mov     bx,offset DDPacket
        mov     ds,sicg_packet_3_d.sicg_devhdr.msw ; DS = address
                                      ;   of data segment
        call    strategy_routine
        popa
        RestoreReg <ds,es>

;       See if the device driver was initialized successfully

;       The initialization fails if any of the following are true:
;         1. the error bit is set in the status field of the INIT packet
;         2. both the end code and end data offsets are zero
;         3. the number of units for a block device is zero
;         4. the DPBs for a block device cannot be allocated

        mov     success,1             ; indicate success
        .if     <bit DDPacket.PktStatus and STERR> or
        mov     ax,DDPacket.InitEcode
        or      ax,DDPacket.InitEdata
        .if     z or
        .if     <character_device eq 0> and
        .if     <DDPacket.InitcUnit eq 0>
            mov   success,0             ; indicate failure
        .endif

        .if     <success eq 1>
            .if     <character_device eq 0>

;         Build the DPBs for this block device driver

                .if   <DDPacket.InitpBPB.msw ne 0>
                    mov ax,sicg_packet_3_d.sicg_devhdr.msw ; address of the
                    mov sicg_packet_7_d.si7_devhdr.msw,ax  ;   DD header
                    mov ax,sicg_packet_3_d.sicg_devhdr.lsw
                    mov sicg_packet_7_d.si7_devhdr.lsw,ax
                    mov ax,DDPacket.InitpBPB.msw           ; address of the
                    mov sicg_packet_7_d.si7_bpbvec.msw,ax  ;   BPB vector
                    mov ax,DDPacket.InitpBPB.lsw
                    mov sicg_packet_7_d.si7_bpbvec.lsw,ax
                    mov al,DDPacket.InitcUnit              ; number of units
                    mov sicg_packet_7_d.si7_nunits,al
                    mov sicg_packet_7_d.si7_unit,0
                    push ds
                    push offset DOSINITDATA:sicg_packet_7
                    call pSICG
                    .if <nonzero ax>
                        mov success,0
                    .else
                        mov al,DDPacket.InitcUnit
                        add sicg_packet_3_d.sicg_drvno,al
                    .endif
                .endif

            .else       ; It was a character device
;
; Make entry for the device in the character device table
; We get the address of the device header and pass it on the the routine.
; We use the Ring 0 GDT selectors for the segment since we want them to be
; around forever.
;
                push ds
                mov     di,sicg_packet_3_d.sicg_devhdr.lsw
                mov     sicg_packet_11_d.si11_devhdr.lsw,DI
                mov     di,sicg_packet_3_d.sicg_protds
                mov     sicg_packet_11_d.si11_devhdr.msw,DI
                push    offset DOSINITDATA:sicg_packet_11
                call    pSICG
                .if <c>
                    mov     success,0
                .endif

            .endif
        .endif

        .if     <success eq 0>
            les   di,sicg_packet_3_d.sicg_devhdr ; point to the next device
            mov   di,es:[di].SDevNext.lsw        ; driver header
            mov   sicg_packet_3_d.sicg_devhdr.lsw,di
            mov   cx,DDPacket.PktStatus
            and cx,0ffH
            .if <cx ne ERROR_I24_QUIET_INIT_FAIL>
               mov ShowErrorMsg, 1       ; Display error message
            .endif
            stc                         ; indicate failure
            jmp   exit_initialize_device_driver
        .endif

;       Save the address of the next device driver header

        les     di,sicg_packet_3_d.sicg_devhdr
        mov     di,es:[di].SDevNext.lsw

;       Add the device driver to the device driver chain

        mov     sicg_packet_3,SICGFUN4
        push    ds
        push    offset DOSINITDATA:sicg_packet_3
        call     pSICG

;       Save code and data segment sizes and the address of the next
;       device driver header

        mov     ax,DDPacket.InitEcode
        mov     sicg_packet_3_d.sicg_ecode,ax
        mov     ax,DDPacket.InitEdata
        mov     sicg_packet_3_d.sicg_edata,ax
        mov     sicg_packet_3_d.sicg_devhdr.lsw,di
        clc                           ; indicate success

;       Return to caller

exit_initialize_device_driver:

;       Call the ldr to signal completion of this PDD init routine. As we have
;       to go through a R0 call gate here, this is a call to ldrDirtyWorker
;       with function code 1.
; move this call to syiinstalldevicedriver so PDD with more than 1 header work
; with the os2ver lie code
;63985  pushf
;63985  xor     ax,ax
;63985  inc     ax
;63985  push    ax             ; function code = 1
;63985  xor     ax,ax
;63985  push    ax             ; pass NULL pointer
;63985  push    ax
;63985  db      9ah            ; call GDT call gate for 16-bit worker
;63985  dw      0,GDT_DOS16LDRDIRTYWORKER
;63985  popf

        popa
        RestoreReg <es,ds>
        LeaveProc
        ret

EndProc syiInitializeDeviceDriver,NoCheck



;
; SUBROUTINE NAME: syiStartDOSMode
;
; DESCRIPTIVE NAME: Start DOS mode
;
; FUNCTION:      To create DOS mode, load the DOS mode device
;                drivers, and start the DOS mode command interpreter
;
; NOTES:         This is an internal subroutine within syiProcess
;
; ENTRY POINT: syiStartDOSMode
;    LINKAGE:    Call (near) from syiProcess
;
; INPUT:         Config_Sys_Data = selector for CONFIG.SYS data
;                                  segment
;
; EXIT-NORMAL: Return to caller (no values returned)
;
; EXIT-ERROR:    None
;
; EFFECTS:       All registers are preserved
;
; INTERNAL REFERENCES:
;    ROUTINES: syiCopyConfigSysData - Copy line number
;                                  command, and file spec from
;                                  CONFIG.SYS data packet
;                syiDisplayMessageR3 - Display an error message
;                syiInstallDOSModeDeviceDrivers - Install
;                                  all DOS mode device drivers
;                syiReceiveVDMMErrors - Thread which displays
;                                  nonfatal errors generated by
;                                  VDMMInit
;
; EXTERNAL REFERENCES:
;    ROUTINES:
;                SICG            - Perform an initialization function
;
;
; Procedure syiStartDOSMode(CONFIG.SYS data)
;
; If PROTECTONLY=YES was not specified
;
; Call SICG(10) to create the 3.x Box
; If PROTECTONLY=YES was not specified and the 3.x Box could not
;     be created
;   indicate DOS mode initialization failed
;   Call syiDisplayMessageR3(not enough memory for DOS mode)
; endif
;
; If DOS mode initialization failed
;   indicate this is an OS/2 mode only system
;   Call syiDisplayMessageR3(DOS mode not started)
; endif
;
; Return
;
; End syiStartDOSMode

Procedure syiStartDOSMode,near
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing
        SaveReg <ds,es>
        pusha

        DosInitContext <ds>,ax
        mov     es,Config_Sys_Data
   assume   es:nothing

;       Check the DOS mode device drivers when ProtectOnly=yes

        mov     si,es:[0].CFG_RMDevice.CFG_Head
        .while  <nonzero si>

;         Save the CONFIG.SYS file line number and the name of the
;         device driver file for any error messages

          call  syiCopyConfigSysData
          .if   <CFG_ProtectOnly ne 0>

;           There is no 3.x Box - inform the user about the bad
;           device driver

            push si
            mov  si,offset tbl_invalid_dd
            call syiDisplayMessageR3
            pop  si
          .endif
          mov   si,es:[si].CFG_Next
        .endwhile

;       If protectonly=no, initialize MVDM

        .if <CFG_ProtectOnly eq 0> near

;         create a temporary thread which receives requests to display
;         a message on the text screen
;
;         create space for one local variable
          push ax
          mov bp,sp

;         allocate a small stack segment for it
;         NOTE: This segment is never freed.  We trust that when
;               initialization is complete then all allocated
;               memory will be freed automagically.

          push 2048                   ; 2K should be more than enough
          push ss
          push bp
          push 0
          call pDosAllocSeg
          .if <nonzero ax> or near    ; failure, return error      ;BN002

;         Subfunction 1 (see SICG.ASM, function 0Ch)
          push  ds
          push  offset DOSINITDATA:sicg_packet_c
          call  pSICG

;         Fire up its thread

          push cs
          push offset syiReceiveVDMMErrors ; function to run

          push ss                     ; stack gets thread id
          push bp

          push [bp]
          push 2046                   ; top of thread's stack

          call pDosCreateThread

          .if <nonzero ax> or         ; failure, return error

;         Subfunction 2 (see SICG.ASM, function 0Ch)
          inc sicg_packet_c_d
          push  ds
          push  offset DOSINITDATA:sicg_packet_c
          call  pSICG

;         The service thread is now ready to receive error messages.
;         Now we can start initializing VDMM proper.

          mov   ax,CFG_RMSize         ; move parameters to SICG packet
          mov   sicg_packet_a_d.siA_rmsize,ax
          mov   ax,CFG_FCBCount
          mov   sicg_packet_a_d.siA_fcbcnt,ax
          mov   ax,CFG_FCBKeep
          mov   sicg_packet_a_d.siA_fcbkeep,ax
          mov   ax,CFG_FILESCount                                       ;BN011;
          mov   sicg_packet_a_d.siA_filescount,ax                       ;BN011;
          mov   al,CFG_Break
          mov   sicg_packet_a_d.siA_break,al
          mov   al,CFG_Dos_Flags                   ;BN002
          mov   sicg_packet_a_d.siA_Dos_Flags,al   ;BN002
          mov   al,CFG_ProtectOnly
          and   al,1                  ; isolate PROTECTONLY=YES bit
          mov   sicg_packet_a_d.siA_protonly,al
          mov   ax,es:[0].CFG_RMDevice.CFG_Head
          mov   sicg_packet_a_d.siA_RMDevice.Offst,ax
          mov   sicg_packet_a_d.siA_RMDevice.Segmt,es
          mov   ax,es:[0].CFG_VDDDevice.CFG_Head
          mov   sicg_packet_a_d.siA_VDDDevice.Offst,ax
          mov   sicg_packet_a_d.siA_VDDDevice.Segmt,es
          mov   ax,es:[0].CFG_Shell.CFG_Tail
          mov   sicg_packet_a_d.siA_Shell.Offst,ax
          mov   sicg_packet_a_d.siA_Shell.Segmt,es
          mov   al,[CFG_LastDrive]
          mov   sicg_packet_a_d.siA_lastdrive,al
          push  ds
          push  offset DOSINITDATA:sicg_packet_a
          call  pSICG

;         See if MVDM was initialized correctly

          .if <nonzero ax>

;           MVDM could not be initialized - display the appropriate
;           error message

            mov   CFG_ProtectOnly,3     ; indicate DOS mode failed
            .if <ax eq ERROR_NOT_ENOUGH_MEMORY>
              mov si,offset tbl_3x_too_big      ; DOS mode memory is too small
            .elseif <ax eq ERROR_INIT_ROUTINE_FAILED>
              mov si,offset tbl_sdrvr_fail      ; a base VDD failed to install
            .elseif <ax eq ERROR_EXE_MARKED_INVALID> or
                .if <ax eq ERROR_BAD_EXE_FORMAT>
              mov si,offset tbl_vdd_invalid     ; a base VDD failed to load
            .else
              call  syiConvertErrorCode ; something else is wrong
              mov si,offset tbl_cannot_create_3x
            .endif
            call   syiDisplayMessageR3
          .endif
          pop ax                      ; clean up the stack
        .endif

;       Now kill the thread we created to service error messages
        inc fVDMMInitComplete

;       Subfunction 3 (see SICG.ASM, function 0Ch)
        inc sicg_packet_c_d
        push ds
        push ds
        push offset DOSINITDATA:sicg_packet_c
        call pSICG
        pop ds

;       If DOS mode initialization failed for any reason, inform the
;       user

        .if     <CFG_ProtectOnly eq 3>
          DosContext <es>

          mov   ProtOnlySystem,1      ; indicate OS/2 mode only system
          mov   SISData.SIS_ProtMdOnly,1
       assume  es:nothing
          mov   si,offset tbl_dos_not_started ; tell the user DOS mode failed
          call  syiDisplayMessageR3
        .endif

;       Return to caller

        popa
        RestoreReg <es,ds>
        ret
EndProc syiStartDOSMode


; SUBROUTINE NAME: syiReceiveVDMMErrors
;
; DESCRIPTIVE NAME: Handle nonfatal errors generated by VDMMInit
;
; FUNCTION:      To display informative messages when nonfatal errors
;                are generated by VDMMInit, such as the failure of
;                user-installable VDDs to install.
;
; NOTES:         This is an internal subroutine within
;                syiStartDOSMode
;
; ENTRY POINT: syiReceiveVDMMErrors
;    LINKAGE:    Created as a thread by syiStartDOSMode
;
; INPUT:         None.
;
; EXIT-NORMAL: Thread kills itself.
;
; EXIT-ERROR:    None
;
; INTERNAL REFERENCES:
;    ROUTINES: syiDisplayMessageR3 - Display an error message
;
; EXTERNAL REFERENCES:
;    ROUTINES:
;                SICG            - Perform an initialization function
;
;
; Procedure syiReceiveVDMMErrors
;
; Do forever
;     Wait for a message to be received from VDMMInit (SICG)
;     Convert the error number to a message
;     Display the message (syiDisplayMessageR3)
; Enddo
;
; End syiReceiveVDMMErrors
;
Procedure syiReceiveVDMMErrors,,local
    assume ds:DOSINITDATA, es:nothing, fs:nothing, gs:nothing, ss:nothing
    push 0
    push SICGFUNC
    mov  bp,sp

    .repeat
      push ds
      push ss
      push bp
      call [pSICG]
      pop  ds

      mov  ax,[usInitErrorCode]     ; What happened?

      .if <ax eq ERROR_INIT_ROUTINE_FAILED>
        mov si,offset tbl_udrvr_fail        ; a user VDD failed to install
      .else                                 ; should never get here?
        mov si,offset tbl_vdd_invalid       ; a user VDD failed to load
      .endif
      call syiDisplayMessageR3

    .loop

EndProc syiReceiveVDMMErrors


;
; SUBROUTINE NAME: syiConvertErrorCode
;
; DESCRIPTIVE NAME: Convert error code to ASCII
;
; FUNCTION:      To convert an error code to a printable ASCIIZ
;                string
;
; NOTES:         This is an internal subroutine within syiProcess
;
; ENTRY POINT: syiConvertErrorCode
;    LINKAGE:    Call (near)
;
; INPUT:         AX = error code
;
; EXIT-NORMAL: error_string = ASCIIZ string
;
; EXIT-ERROR:    None
;
; EFFECTS:       All registers are preserved
;
; INTERNAL REFERENCES:
;    ROUTINES: None
;
; EXTERNAL REFERENCES:
;    ROUTINES: None
;
;
; Procedure syiConvertErrorCode(error code)
;
; For I=1 to 4
;   convert the Ith nibble of error code to ASCII and store it in the
;       string
; Next I
;
; Return
;
; End syiConvertErrorCode

Procedure syiConvertErrorCode,near
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing

        SaveReg <ds,es>
        pusha

;       Convert each nibble of the error code to ASCII

        push    ds                    ; ES:DI points to error code string
        pop     es
        mov     di,offset error_string
        mov     bx,offset ascii_table ; DS:BX points to translation table
        mov     cx,4                  ; convert 4 nibbles

        .repeat
          rol   ax,4                  ; shift next nibble to AL
          SaveReg <ax>
          and   al,0fh                ; isolate the nibble
          xlat                        ; translate it to ASCII
          stosb                       ; store it in the error string
          RestoreReg <ax>
        .loop

;       Return to caller

        popa
        RestoreReg <es,ds>
        ret

EndProc syiConvertErrorCode


;
; SUBROUTINE NAME: syiStartDaemonProcesses
;
; DESCRIPTIVE NAME: Start deamon processes
;
; FUNCTION:      To start all user specified daemon proceses
;
; NOTES:         This is an internal subroutine within syiProcess
;
; ENTRY POINT: syiStartDaemonProcesses
;    LINKAGE:    Call (near) from syiProcess
;
; INPUT:         Config_Sys_Data = selector for CONFIG.SYS data
;                                  segment
;
; EXIT-NORMAL: Return to caller (no values returned)
;
; EXIT-ERROR:    None
;
; EFFECTS:       All registers are preserved
;
; INTERNAL REFERENCES:
;    ROUTINES: syiCopyConfigSysData - Copy line number
;                                  command, and file spec from
;                                  CONFIG.SYS data packet
;              syiStartProgram      - Start an asynchronous
;                                  program
;
; EXTERNAL REFERENCES:
;    ROUTINES: None
;
;
; Procedure syiStartDaemonProcesses(CONFIG.SYS data)

; @PEN - LOG=  function removed by CP20 DCR 1152
; X If LOG= specified in CONFIG.SYS
; X    Call DosLogMode(init,CFG_Log)
; X    Call syiCopyConfigSysData(CONFIG.SYS packet) to save the
; X        line number and file specification for any error messages
; X    Call pDosIQAppType
; X    If Program is not a PM
; X      Call syiStartProgram(log daemon,command line)
; X    If exec successful
; X      Call DosLogMode(synchronize)
; X    Else
; X      Call DosLogMode(terminate)
; X    Endif
; X  Else
; X    Call DosLogMode(terminate)
; X  Endif
;
; For each CALL= or RUN= statement in the CONFIG.SYS data segment
;   Call syiCopyConfigSysData(CONFIG.SYS packet) to save the
;       line number and file specification for any error messages
;   Call pDosIQAppType(file specification,command line)
;   If Program is not a PM
;      Call syiStartProgram(file specification,command line)
; Next statement
;
; Return
;
; End syiStartDaemonProcesses

Procedure syiStartDaemonProcesses,near
    assume ds:DOSINITDATA, es:nothing, fs:nothing, gs:nothing, ss:nothing

        SaveReg <ds,es>
        pusha
ifdef TRYBUY
        mov    al,[LockedDDLoaded]              ;UniLock
        .if <al ne 0>    ;If running locked     ;UniLock
            call   _StartLockProgram            ;UniLock
        .endif                                  ;UniLock
endif

;       Removed LOG= processing with CP20 DCR 1152 @PEN

;       Load each program specified on a RUN= statement

        mov     es,Config_Sys_Data
        mov     di,es:[0].CFG_Run.CFG_Head
        .while  <nonzero di> near

          mov   si,di                 ; copy the line number and file
          call  syiCopyConfigSysData ; specification

          .if   <es:[di].CFG_Type eq CFG_Type_Call>
            ;do this so BVHVGA will be linked (and not unlinked)
            push    ax                    ; save AX
            push    ds                    ; save ds
            DosInitContext <ds>,ax
            push    00000001b             ; open flag
            push    0000000000000011b     ; open flag
            push    ds                    ; address of file name
            push    offset DOSINITDATA:fatmsgbuff
            call    pDosPutMessage
            pop     ds                    ;restore ds
            pop     ax                    ;restore AX

            mov   si,offset start_call_parms ; point to CALL= start parm list
          .else
            mov   si,offset start_daemon_parms ; point to RUN= start parm list
          .endif

          mov   ds:[si].Start_FileSpec.msw,es ; point to file
          mov   ax,es:[di].CFG_FileSpec       ; specification
          mov   ds:[si].Start_FileSpec.lsw,ax

          mov   ax,es:[di].CFG_Parameters ; point to command line
          .if   <nonzero ax>
            mov ds:[si].Start_Command.msw,es
          .else
            mov ds:[si].Start_Command.msw,ax
          .endif
          mov   ds:[si].Start_Command.lsw,ax

; begin defects #73958 - M. Violante
          push  es
          push  es:[di].CFG_FileSpec
          push  ds
          push  offset DOSINITDATA:usExeType
          call  pDosIQAppType
          .if   <ax eq ERROR_INVALID_EXE_SIGNATURE> near
            mov  si,offset tbl_run_cant_exec
            call syiDisplayMessageR3
          .else
            mov  cx,[usExeType]
            ;Top order bits may be set, just check CL
            ;don't worry about bit 3, it's for FAPI apps, PM apps can't be fapi
            .if   <cl eq FAPPTYP_WINDOWAPI> near  ; PM or SSF_TYPE_PM?
              ; If CALL=, display error, otherwise just delay
              ; the start until we call syi2StartDaemonProcesses
              .if   <es:[di].CFG_Type eq CFG_Type_Call> ;80080
                mov  si,offset tbl_user_file_pm
                call syiDisplayMessageR3

;               display  "PRESS ERROR TO CONTINUE"  message
                mov   [error_messages_displayed],1
                call  syiPauseOnErrorR3
              .else                                       ;80080
                mov   es:[di].CFG_Type,CFG_Type_Delay_Run ;80080
                push  ds
                DosContext ds
                or    syiGlobalFlags,SYI_PM_PROG_TO_RUN ;turn on early wait bit
                ASSUME  ds:nothing
                pop   ds
              .endif                                      ;80080
            .else
              call  syiStartProgram               ; start the program
            .endif
          .endif
; end defects #73958 - M. Violante

          mov   di,es:[di].CFG_Next
        .endwhile

;       Return to caller

        popa
        RestoreReg <es,ds>
        ret

EndProc syiStartDaemonProcesses


;Start 80080 changes
;
; SUBROUTINE NAME: syi2StartDaemonProcesses
;
; DESCRIPTIVE NAME: Start deamon processes
;
; FUNCTION:      To start all user specified PM daemon proceses
;
; NOTES:         This is an internal subroutine within syiProcess
;
; ENTRY POINT: syi2startDaemonProcesses
;    LINKAGE:    Call (near) from syiProcess
;
; INPUT:         Config_Sys_Data = selector for CONFIG.SYS data
;                                  segment
;
; EXIT-NORMAL: Return to caller (no values returned)
;
; EXIT-ERROR:    None
;
; EFFECTS:       All registers are preserved
;
; INTERNAL REFERENCES:
;    ROUTINES: syiCopyConfigSysData - Copy line number
;                                  command, and file spec from
;                                  CONFIG.SYS data packet
;              syiStartProgram      - Start an asynchronous
;                                       PM program
;
; EXTERNAL REFERENCES:
;    ROUTINES: None
;
;
; Procedure syi2StartDaemonProcesses(CONFIG.SYS data)
;
; Wait for PM to come up
; For each CALL= or RUN= statement in the CONFIG.SYS data segment
;   If delayed RUN= statement
;     Call syiStartProgram(file specification,command line)
; Next statement
;
; Return
;
; End syi2StartDaemonProcesses

Procedure syi2StartDaemonProcesses,near
    assume ds:DOSINITDATA, es:nothing, fs:nothing, gs:nothing, ss:nothing

        SaveReg <ds,es>

;Wait for PM to start
        DosContext <ds>,ax
        mov     eax,syiGlobalFlags
        and     eax,SYI_PM_PROG_TO_RUN
        .if     <nonzero eax>        ; Did we find RUN= PM program
           pusha
           DosInitContext <es>,ax
           push    [pDosSMSysInitSem]
           push    -1
           push    -1
           call    pDosSemWait
           .if     <nonzero ax>
             Panic <"Error semwaiting on DosSMSysInitSem">
           .endif

           DosInitContext <ds>,ax

;          Load each program specified on a RUN= statement who's processing
;          was delayed in syistartdaemonprocesses.

           assume  es:nothing
           mov     es,Config_Sys_Data
           mov     di,es:[0].CFG_Run.CFG_Head
           .while  <nonzero di> near
             .if   <es:[di].CFG_Type eq CFG_Type_Delay_Run>
               mov   si,offset start_daemon_parms ; point to RUN= start parm list

               mov   ds:[si].Start_FileSpec.msw,es ; point to file
               mov   ax,es:[di].CFG_FileSpec       ; specification
               mov   ds:[si].Start_FileSpec.lsw,ax

               mov   ax,es:[di].CFG_Parameters ; point to command line
               .if   <nonzero ax>
                 mov ds:[si].Start_Command.msw,es
               .else
                 mov ds:[si].Start_Command.msw,ax
               .endif
               mov   ds:[si].Start_Command.lsw,ax

               ;Don't need to call pDosIQAppType here, we already
               ;called it and did checks in syiStartDaemonProcesses
               call  syiStartProgram               ; start the program
             .endif
             mov   di,es:[di].CFG_Next
           .endwhile
           popa
        .endif
;       Return to caller

        RestoreReg <es,ds>
        ret

EndProc syi2StartDaemonProcesses
;End 80080 changes


;
; SUBROUTINE NAME: syiStartShell
;
; DESCRIPTIVE NAME: Start protected mode shell
;
; FUNCTION:      To start the protected mode shell
;
; NOTES:         This is an internal subroutine within syiProcess
;
; ENTRY POINT: syiStartShell
;    LINKAGE:    Call (near) from syiProcess
;
; INPUT:         Config_Sys_Data = selector for CONFIG.SYS data
;                                  segment
;
; EXIT-NORMAL: Return to caller (no values returned)
;
; EXIT-ERROR:    None
;
; EFFECTS:       All registers are preserved
;
; INTERNAL REFERENCES:
;    ROUTINES: syiCopyConfigSysData - Copy line number
;                                  command, and file spec from
;                                  CONFIG.SYS data packet
;                syiStartProgram - Start an asynchronous program
;
; EXTERNAL REFERENCES:
;    ROUTINES: None
;
;
; Procedure syiStartShell(CONFIG.SYS data)
;
; If PROTSHELL= was specified
;   Call syiCopyConfigSysData(CONFIG.SYS packet) to save the
;       line number and file specification for any error messages
;   copy the shell name and command line
; else
;   set the shell name to 'SHELL.EXE'
;   set the command line to 'CMD.EXE'
; endif
;
; Call syiStartProgram(shell name,command line,message IDs)
;     to start the protected mode shell
;
; Return
;
; End syiStartShell

Procedure syiStartShell,near
    assume ds:DOSINITDATA, es:nothing, fs:nothing, gs:nothing, ss:nothing

        SaveReg <ds,es>
        pusha

;       Find the shell name and the command line

        mov     es,Config_Sys_Data
        mov     di,es:[0].CFG_ProtShell.CFG_Tail
        .if     <zero di>             ; was PROTSHELL= specified?
          mov   si,offset start_dshell_parms ; no, point to default shell start
                                      ;     parameters
        .else                         ;
          mov   si,di                 ; yes, save line number and file
          call  syiCopyConfigSysData ; specification
          mov   si,offset start_shell_parms  ; point to shell start parameters

          mov   ds:[si].Start_FileSpec.msw,es ; point to file
          mov   ax,es:[di].CFG_FileSpec       ; specification
          mov   ds:[si].Start_FileSpec.lsw,ax

          mov   ax,es:[di].CFG_Parameters ; point to command line
          .if   <nonzero ax>
            mov ds:[si].Start_Command.msw,es
          .else
            mov ds:[si].Start_Command.msw,ax
          .endif
          mov   ds:[si].Start_Command.lsw,ax
        .endif

;       Start the protected mode shell

        call    syiStartProgram

;       Return to caller

        popa
        RestoreReg <es,ds>
        ret

EndProc syiStartShell


;
; SUBROUTINE NAME: syiStartProgram
;
; DESCRIPTIVE NAME: Start a/synchronous program
;
; FUNCTION:      To start a program as a process
;
; NOTES:         This is an internal subroutine within syiProcess
;
; ENTRY POINT: syiStartProgram
;    LINKAGE:    Call (near)
;
; INPUT:         DS:SI = Address of parameter list containing:
;                  Start_FileSpec = address of file specification
;                  Start_Command  = address of command arguments
;                  Start_Async    = execution flags
;                  Start_Required = 0 = program is optional
;                                   1 = program is required
;                  Start_Missing  = offset of file missing message
;                  Start_Too_Big  = offset of program too big msg
;                  Start_Cant_Exec= offset of exec failure message
;
; EXIT-NORMAL: CF = 0
;
; EXIT-ERROR:    CF = 1
;
; EFFECTS:       All registers are preserved
;
; INTERNAL REFERENCES:
;    ROUTINES: syiAbortR3 - Display a fatal error message
;                syiDisplayMessageR3 - Display an error message
;
; EXTERNAL REFERENCES:
;    ROUTINES:
;                DosExecPgm      - Start a program
;
;
; Procedure syiStartProgram(file specification,command arguments,
;                                 message IDs)
;
; construct the command line by concatenating the file specification
;    and the command arguments
;
; Call DosExecPgm(file specification,command line,a/synch)
;     to start the program
; If the program was started
;   Return(success)
; endif
;
; Case return code of
;   Error_file_not_found:
;   Error_path_not_found:
;     message ID = file not found message
;   Error_not_enough_memory:
;     message ID = program too big message
;   else
;     message ID = EXEC failure message
; endcase
;
; If the program is required for system operation
;   Call syiAbortR3(message ID) to display the message and halt
; else
;   Call syiDisplayMessageR3(message ID) to display the message
; endif
;
; Return(error)
;
; End syiStartProgram

Procedure syiStartProgram,near
    assume ds:DOSINITDATA, es:nothing, fs:nothing, gs:nothing, ss:nothing

        LocalVar process_id,WORD

        EnterProc
        SaveReg <ds,es>
        pusha

;       Build up the command line string by concatenating the
;       file specification string and the command argument string

;       Copy the file specification to the command line string

        SaveReg <ds,si>
        push    ds
        pop     es
        lds     si,ds:[si].Start_FileSpec
        mov     di,offset command_string
        .repeat
          lodsb
          stosb
        .until  <al eq 0>
        RestoreReg <si,ds>

;       Copy the command arguments (if any) to the command line string

        .if     <ds:[si].Start_Command.msw ne 0> ; are there any arguments?
          SaveReg <ds,si>
          lds   si,ds:[si].Start_Command
          .repeat
            lodsb
            stosb
          .until <al eq 0>
          RestoreReg <si,ds>
        .endif

        stosb                         ; terminate the command line

;       Start the program
;       Call DosExecPgm(file spec,command line,environment,a/synchronous)

        push    ds                    ; address of object name buffer
        push    offset object_name
        push    object_name_len       ; length of object name buffer
        push    ds:[si].Start_Async   ; execution flags
        push    ds                    ; address of command line
        push    offset DOSINITDATA:command_string
        push    0                     ; inherit the sysinit environment
        push    0
        push    ss                    ; address of process ID word
        lea     ax,process_id
        push    ax
        push    ds:[si].Start_FileSpec.msw ; address of file name
        push    ds:[si].Start_FileSpec.lsw
        call    pDosExecPgm           ; execute the program

;       If the DosExecPgm failed, inform the user

        .if     <nonzero ax>          ; this will clear the carry flag
          mov   bx,ds:[si].Start_Required
          .if   <ax eq ERROR_FILE_NOT_FOUND> or
          .if   <ax eq ERROR_PATH_NOT_FOUND>
            mov si,ds:[si].Start_Missing
          .elseif <ax eq ERROR_NOT_ENOUGH_MEMORY>
            mov si,ds:[si].Start_Too_Big
          .else
            mov si,ds:[si].Start_Cant_Exec
          .endif

          .if   <nonzero bx>          ; is this program required?
            call syiAbortR3      ; yes, display the message and halt
          .else
            call syiDisplayMessageR3 ; no, display the message
          .endif
          stc                         ; indicate error
        .endif

;       Return to caller

        popa
        RestoreReg <es,ds>
        LeaveProc
        ret

EndProc syiStartProgram


;
; SUBROUTINE NAME: syiCopyConfigSysData
;
; DESCRIPTIVE NAME: Copy CONFIG.SYS common data
;
; FUNCTION:      To copy the ASCIIZ string which contains the
;                line number, the ASCIIZ string which contains the
;                command, and the ASCIIZ string which contains
;                the file specification from the CONFIG.SYS data
;                packet
;
; NOTES:         This is an internal subroutine within syiProcess
;
; ENTRY POINT: syiCopyConfigSysData
;    LINKAGE:    Call (near)
;
; INPUT:         ES:SI = Address of CONFIG.SYS data packet
;                (DS) -> DOSINITDATA
;
; EXIT-NORMAL: line_number contains the line number string
;                command contains the command name
;                file_specification contains the file specification
;
; EXIT-ERROR:    None
;
; EFFECTS:       All registers are preserved
;
; INTERNAL REFERENCES:
;    ROUTINES: None
;
; EXTERNAL REFERENCES:
;    ROUTINES: None
;
;
; Procedure syiCopyConfigSysData(CONFIG.SYS data packet)
;
; copy the line number from the data packet
; copy the command from the data packet
; copy the file specification from the data packet
;
; Return
;
; End syiCopyConfigSysData

Procedure syiCopyConfigSysData,near
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing

        SaveReg <ds,es>
        pusha

;       Copy the line number from the data packet

        push    ds                    ; DS:SI = address of line number
        push    es                    ;         string in CONFIG.SYS
        pop     ds                    ;         data packet
        pop     es                    ; (ES) -> DOSINITDATA
        SaveReg <si>
        lea     si,ds:[si].CFG_LineNumber

        mov     di,offset line_number ; ES:DI = address of line_number

        .repeat                       ; copy the string (until the
          lodsb                       ;   terminating null is found)
          stosb
        .until  <al eq 0>
        RestoreReg <si>

;       Copy the command from the data packet

        SaveReg <ds,si>
        lds     si,ds:[si].CFG_Command; DS:SI = address of command name

        mov     di,offset command      ; ES:DI = address of command

        .repeat                       ; copy the string (until the
          lodsb                       ;   terminating null is found)
          stosb
        .until  <al eq 0>
        RestoreReg <si,ds>

;       Copy the file specification from the data packet

        mov     si,ds:[si].CFG_FileSpec ; DS:SI = address of file
                                      ;         specification string
                                      ;         in CONFIG.SYS data
                                      ;         packet

        mov     di,offset file_specification ; ES:DI -> file_specification

        .repeat                       ; copy the string (until the
          lodsb                       ;   terminating null is found)
          stosb
        .until  <al eq 0>

;       Return to caller

        popa
        RestoreReg <es,ds>
        ret

EndProc syiCopyConfigSysData


;
; SUBROUTINE NAME: syiConstructCommandLine
;
; DESCRIPTIVE NAME: Construct command line
;
; FUNCTION:      To concatenate the file specification and argument
;                string into a single string
;
; NOTES:         This is an internal subroutine within syiProcess
;
; ENTRY POINT: syiConstructCommandLine
;    LINKAGE:    Call (near)
;
; INPUT:         ES:SI = Address of CONFIG.SYS data packet
;
; EXIT-NORMAL: command_string contains the command line string
;
; EXIT-ERROR:    None
;
; EFFECTS:       All registers are preserved
;
; INTERNAL REFERENCES:
;    ROUTINES: None
;
; EXTERNAL REFERENCES:
;    ROUTINES: None
;
;
; Procedure syiConstructCommandLine(CONFIG.SYS data packet)
;
; copy the file specification from the data packet
; If an argument string was specified
;   copy the argument string from the data packet
; endif
;
; Return
;
; End syiConstructCommandLine

Procedure syiConstructCommandLine,near
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing

        SaveReg <ds,es>
        pusha

;       Copy the file specification from the data packet

        push    ds                    ; DS:SI = address of file specification
        push    es                    ;         string in CONFIG.SYS
        pop     ds                    ;         data packet
        pop     es
        SaveReg <si>
        mov     si,ds:[si].CFG_FileSpec

        mov     di,offset command_string ; ES:DI -> command_string

        .repeat                       ; copy the string (until the
          lodsb                       ;   terminating null is found)
          .leave <al eq 0>
          stosb
        .until
        RestoreReg <si>

;       Copy the argument string from the data packet

        mov     si,ds:[si].CFG_Parameters
        .if     <nonzero si>
          .repeat                     ; copy the string (until the
            lodsb                     ;   terminating null is found)
            .leave <al eq 0>
            stosb
          .until
        .endif

;       Terminate the string with a null byte

        stosb

;       Return to caller

        popa
        RestoreReg <es,ds>
        ret

EndProc syiConstructCommandLine


;
; SUBROUTINE NAME: syiInitEnvironment
;
; DESCRIPTIVE NAME: Initialize Sysinit Environment
;
; FUNCTION:      To fill in the SysInit environment with the strings
;                specified by the SET commands in CONFIG.SYS
;
; NOTES:         This is an internal subroutine within syiProcess
;
; ENTRY POINT: syiInitEnvironment
;    LINKAGE:    Call (near)
;
; INPUT:         syiEnvironSelector => SysInit environment
;
; EXIT-NORMAL: The environment is fillen in with the SET strings
;
; EXIT-ERROR:    None
;
; EFFECTS:       All registers are preserved
;
; INTERNAL REFERENCES:
;    ROUTINES:
;                syiModifyEnvironment - Add an environment var
;                syiDisplayMessageR3 - Display error messages
;
; EXTERNAL REFERENCES:
;    ROUTINES: None
;
;
; Procedure syiInitEnvironment()
;
; Get the head of the SET packet list
; While packets exist
;     Get the string to be added to the environment
;     Add it to the environment (call syiModifyEnvironment)
;     If an error occured (c)
;         Issue invalid parameter message.
;     Endif
;     Get the next packet
; Endwhile
;

Procedure syiInitEnvironment
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing
        push    ds                              ;Save all registers
        push    es
        pusha

        DosInitContext ds
        mov     ds,Config_Sys_Data
        assume  ds:nothing
        mov     bx,ds:[0].CFG_Set.CFG_Head      ;Get the head of the SET
                                                ;statemtment list

        .while <nonzero bx>                     ;While packets exist
            mov     si,ds:[bx].CFG_EnvStr       ;DS:SI -> environment string
            call    syiModifyEnvironment        ;Add string to environment
            .if     c                           ;If an error occured
                DosInitContext es
                                                    ;Fill in the message table
                                                    ;   with the appropriate
                                                    ;   fill-in items
                lea     ax,ds:[bx].CFG_LineNumber       ;Fill in the line number
                mov     tbl_invalid_parm_line.lsw,ax
                mov     tbl_invalid_parm_line.msw,ds
                mov     ax,ds:[bx].CFG_Command.lsw      ;Fill in the CONFIG.SYS statement name
                mov     tbl_invalid_parm_name.lsw,ax
                mov     ax,ds:[bx].CFG_Command.msw
                mov     tbl_invalid_parm_name.msw,ax
                mov     ax,ds:[bx].CFG_EnvStr           ;Fill in the invalid token
                mov     tbl_invalid_parm_token.lsw,ax
                mov     tbl_invalid_parm_token.msw,ds
                push    ds
                DosInitContext ds
                mov     si,offset tbl_invalid_parm ;DS:SI -> message table
                call    syiDisplayMessageR3    ;Issue the error message
                pop     ds
                assume  ds:nothing
            .endif
            mov     bx,ds:[bx].CFG_Next         ;DS:BX -> next SET packet
        .endwhile

        popa                                    ;Restore all registers
        pop     es
        pop     ds
        ret
EndProc syiInitEnvironment



;
; SUBROUTINE NAME: syiModifyEnvironment
;
; DESCRIPTIVE NAME: Modify the Sysinit Environment
;
; FUNCTION:      To add or modify a string in the SysInit environment
;
; NOTES:         This is an internal subroutine within syiProcess
;
; ENTRY POINT: syiModifyEnvironment
;    LINKAGE:    Call (near)
;
; INPUT:         syiEnvironSelector => SysInit environment
;                DS:SI => String to add to environment
;
; EXIT-NORMAL: Carry clear
;                The environment is fillen in with the given string
;
; EXIT-ERROR:    Carry set
;
; EFFECTS:       All registers except AX are preserved
;
; INTERNAL REFERENCES:
;    ROUTINES: None
;
; EXTERNAL REFERENCES:
;    ROUTINES:
;                pDosReallocSeg - reallocate segment
;
;
; Procedure syiModifyEnvironment (string)
;
; Parse and validate the string (call syiParseEnvironmentString)
; If no error
;     Call syiExcludeExtLIBPATH to handle it if it is an Extended LIBPATH setting
;     If it wasn't an extended libpath
;         Scan the environment for the variable (call syiScanEnvironment)
;         If a match was found
;             Remove the string (call syiRemoveEnvironmentString)
;         Endif
;         If the environment argument is not null
;             Add the string to the environment (call syiAddEnvironmentString)
;         Endif
;     Endif
; Endif

Procedure syiModifyEnvironment
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing
    LocalVar Potential_Match WORD
        EnterProc
        push    ds                              ;Save the used registers
        push    es
        DosInitContext es

; Parse and validate the passed string

        call    syiParseEnvironmentString ;Parse the environment string

        .if     nc near                         ;If the string is valid
            push    si
            push    di

; Check for Extended Libpaths
            mov     Potential_Match,0
            call syiExcludeExtLIBPATH                  ;Go set the extended libpath

            .if <Potential_Match eq -1>             ;If it wasn't an extended LIBPATH

; Scan the environment for a matching keyword

                mov     ds,syiEnvironSelector           ;DS:SI -> beginning of environment
                xor     si,si
                call    syiScanEnvironment      ;Scan the environment for the string

; The current environment has been scanned.  If a matching keyword has been
; found, then Potential_Match points to it and SI points to the environment beyond.
; If not, Potential_Match is -1 and SI points to the end of the environment.

; Remove old string from environment (if appropiate)

                .if <Potential_Match ne -1>             ;If a match was found
                    push    ds
                    pop     es
                    assume  es:nothing                      ;DS:SI -> past matched string
                    mov     di,Potential_Match              ;ES:DI -> at matched string
                    call    syiRemoveEnvironmentString ;Remove the string
                .endif                                  ;Endif

; Now add the string to the environment (if appropriate).

                DosInitContext ds
                mov     es,syiEnvironSelector
                assume  es:nothing
                call    syiAddEnvironmentString  ;Add string to the environment

                clc                                     ;Indicate no error
            .else                               ;else was extended libpath
                clc                             ;clear the carry
            .endif                              ;endif carry from procextlibpath
            pop     di                          ;Restore registers
            pop     si
        .endif                              ;Endif parse succeeded
        pop     es
        pop     ds
        LeaveProc
        ret
EndProc syiModifyEnvironment




;
; SUBROUTINE NAME: syiParseEnvironmentString
;
; DESCRIPTIVE NAME: Parse and environment string
;
; FUNCTION:      To parse and modify a string for the environment
;
; NOTES:         This is an internal subroutine within syiProcess
;
;                The string must consist of a non-null environment
;                variable name, an equal sign, and an optional
;                envrionment variable value (text).  Leading white
;                space is stripped off the variable name.  Imbedded
;                white space is left intact.  The variable name is
;                folded to upper case without regard for DBCS.  The
;                remainder of the string is not modified.
;
;                There is a mirror routine, syiR0ParseEnvironmentString
;                in inidin2.asm for use while still at ring 0.  Changes
;                to this routine should be reflected there.
;
; ENTRY POINT: syiParseEnvironmentString
;    LINKAGE:    Call (near)
;
; INPUT:         ES addresses DOSINITDATA
;                DS:SI => String to add to environment
;
; EXIT-NORMAL: Carry clear
;                The string is parsed into the environment buffer
;                Environ_Keyword_Length = length of keyword
;                Environ_Argument_Length = length of entire string
;
; EXIT-ERROR:    Carry set
;
; EFFECTS:       All registers except AX are preserved
;
; INTERNAL REFERENCES:
;    ROUTINES: None
;
; EXTERNAL REFERENCES:
;    ROUTINES: None
;
;
; Procedure syiParseEnvironmentString (string)
;
; Strip of leading white space
; Repeat
;     Get a character
;     If end of string then set carry and abort loop
;     If leading "=" then set carry and abort loop
;     If string is too long for buffer then set carry and abort loop
;     Upshift character
;     Store character in buffer
;     Keep count of string length
; Until "=" encountered
; Repeat
;     If string is too long for buffer then set carry and abort loop
;     Copy character to buffer
;     Keep count of string length
; Until end of string encountered
;

Procedure syiParseEnvironmentString
    assume ds:nothing, es:DOSINITDATA, fs:nothing, gs:nothing, ss:nothing

        push    si
        push    di

        mov     di,offset Environ_Buffer        ;Address the parsing buffer
        mov     Environ_Keyword_Length,0        ;Initialize keyword length to 0
        cld

; Strip of leading white space
        .repeat                                 ;Repeat
            lodsb                                   ;Consume a character
        .until <al ne ' '> and                  ;Until non-white space encountered
        .until <al ne 09h>
        dec     si                              ;Backup because we have gone too far

; Parse environment variable into buffer.
        .repeat                                 ;Repeat
            lodsb                                   ;Get a character

            .if <zero al>                           ;If null (premature end of string)
                stc                                     ;Set carry (this is an error)
                .leave                                  ;Abort the loop
            .endif                                  ;Endif

            .if <al eq '='> and                     ;If char is an equal sign (end of keyword) and
            .if <Environ_Keyword_Length eq 0>       ;If keyword is null (no keyword)
                stc                                     ;Set carry (this is an error)
                .leave                                  ;Abort the loop
            .endif                                  ;Endif

                                                    ;If the buffer is full (keyword too long)
            .if <Environ_Keyword_Length ae Environ_String_Max>
                stc                                     ;Set carry (this is an error)
                .leave                                  ;Abort the loop
            .endif                                  ;Endif

            .if <al ae 'a'> and                     ;If char is lowercase
            .if <al be 'z'>
                add     al,'A'-'a'                      ;Upshift it
            .endif                                  ;Endif

            stosb                                   ;Store the char in the buffer
            inc     Environ_Keyword_Length          ;Update the keyword length
        .until <al eq '='>                      ;Until equal sign encountered

;Get the remainder of the environment string
        .if     nc                              ;If no error was encountered
            mov     ax,Environ_Keyword_Length       ;Initialize string length to keyword length
            mov     Environ_Argument_Length,ax

            .repeat                                 ;Repeat
                                                        ;If no room in buffer
                .if <Environ_Argument_Length ae Environ_String_Max>
                    stc                                     ;Set carry (this is an error)
                    .leave                                  ;Abort the loop
                .endif                                  ;Endif
                lodsb                                   ;Copy character to buffer
                stosb
                inc     Environ_Argument_Length         ;Update string length
            .until <zero al>                        ;Until end of string
        .endif                                  ;Endif

        pop     di
        pop     si
        ret
EndProc syiParseEnvironmentString



;
; SUBROUTINE NAME: syiScanEnvironment
;
; DESCRIPTIVE NAME: Scan the Sysinit Environment
;
; FUNCTION:      To scan the SysInit environment for a given variable
;
; NOTES:         This is an internal subroutine within syiProcess
;
; ENTRY POINT: syiScanEnvironment
;    LINKAGE:    Call (near)
;
; INPUT:         DS:SI -> beginning of environment
;                ES addresses DOSINITDATA
;                Environment_Buffer holds parsed string
;                BP is correct to address Potential_Match
;
; EXIT-NORMAL: If match found:
;                    Potential_Match -> matching string
;                    SI -> next string in environment
;                If no match found:
;                    Potential_Match = -1
;                    SI -> end of environment
;
; EXIT-ERROR:    none
;
; EFFECTS:       All registers except AX are preserved
;
; INTERNAL REFERENCES:
;    ROUTINES: None
;
; EXTERNAL REFERENCES:
;    ROUTINES: None
;
;
; Procedure syiScanEnvironment(string)
;
; Initialize Potential_Match to "not found"
; Get first character of environment
; While strings exist in the environment
;     Remember string as a potential match
;     Repeat
;         If characters differ then set Potential_Match to "false" and exit loop
;         If character is "=" then we have a match -- exit loop
;         Get next character in environment
;     Forever
;     Scan to the end of the environment string
;     If a match was found, exit while loop
; Endwhile
;

Procedure syiScanEnvironment
    assume ds:nothing, es:DOSINITDATA, fs:nothing, gs:nothing, ss:nothing
        push    di
        mov     Potential_Match,-1              ;Initialize Potential_Match to "not found"
        lodsb                                   ;Get the first character

        .while <nonzero al>                     ;While strings in the envrionment exist
            mov     Potential_Match,si              ;The current string is a potential match
            dec     Potential_Match                 ;But we have read the first character so back up
            mov     di,offset Environ_Buffer   ;Compare environment keywords
            .repeat                                 ;Repeat
                scasb                                   ;Compare characters
                .if ne                                  ;If they are different
                    mov     Potential_Match,-1              ;We do not have a match
                    .leave                                  ;Abort this loop
                .endif                                  ;Endif
                .leave <al eq '='>                      ;If char is an equal sign then we have a match
                                                        ;   and exit this loop
                lodsb                                   ;Get next character
            .until                                  ;Forever

            ;This environment variable either does or does not match.
            ;Now we simply scan to the end of the string
            .while <nonzero al>                     ;While characters in the string
                lodsb                                   ;Consume a character
            .endwhile                               ;Endwhile

            .leave <Potential_Match ne -1>          ;Leave if the string matched
            lodsb                                   ;Get the next character
        .endwhile                               ;EndWhile
        pop     di
        ret
EndProc syiScanEnvironment

;
; SUBROUTINE NAME: syiExcludeExtLIBPATH
;
; DESCRIPTIVE NAME: Exclude the External LIBPATH settings, they
;                   are set while still in ring 0 in inidin2.asm
;
; FUNCTION:      If it is a BeginLIPBATH or EndLIBPATH variable set
;                Potential Match to 0 so the caller will not create
;                an environment variable of that name.
;
; NOTES:         This is an internal subroutine within syiProcess
;
; ENTRY POINT: syiExcludeExtLIBPATH
;    LINKAGE:    Call (near)
;
; INPUT:
;                ES addresses DOSINITDATA
;                Environment_Buffer holds parsed string
;                BP is correct to address Potential_Match
;                  and Potential_Match is 0
;
; EXIT-NORMAL: Carry Clear
;
; EXIT-ERROR:  Carry Set
;
; EFFECTS:       ESI, EDI, EAX can be modified, all others preserved
;
; INTERNAL REFERENCES:
;    ROUTINES: None
;
; EXTERNAL REFERENCES:
;    ROUTINES: None
;
;
; Procedure syiExcludeExtLIBPATH(string)
;
; Compare the Environ_Buffer Keywork to BeginLIBPATH
; Assume we will match BeginLIBATH
; If they do not match
;   Set Potential Match to -1
;
; If Potential Match is -1
;   Assume we will match EndLIBPATH
;   Set Potential Match back to 0
;   Compare the Environ_Buffer Keywork to EndLIBPATH
;   If they do not match
;     Set Potential Match to -1
;
;

Procedure syiExcludeExtLIBPATH
    assume ds:nothing, es:DOSINITDATA, fs:nothing, gs:nothing, ss:nothing

    push    cx
    push    ds
    DosInitContext ds                  ;Set DS  so DS:SI will
                                       ; be able to point to program variables

    mov     si,offset BeginLibpath
    mov     di,offset Environ_Buffer   ;Compare environment keywords
    mov     cx,1                       ;Assume we will match on begin libpath
    lodsb                              ;Get the first character
    .repeat                                 ;Repeat
        scasb                                   ;Compare characters
        .if ne                                  ;If they are different
            mov     Potential_Match,-1              ;We do not have a match
            .leave                                  ;Abort this loop
        .endif                                  ;Endif
        .leave <al eq 0 >                       ;If char is a null we have a match
                                                ;   and exit this loop
        lodsb                                   ;Get next character
    .until                                  ;Forever
    .if <Potential_Match eq -1>             ;If a match was not found
        mov     si,offset EndLibpath
        mov     di,offset Environ_Buffer    ;Compare environment keywords
        mov     Potential_Match,0           ;Reset Potential_Match
        mov     cx,2                        ;Assume we will match on end libpath
        lodsb                               ;Get the first character
        .repeat                                 ;Repeat
            scasb                                   ;Compare characters
            .if ne                                  ;If they are different
                mov     Potential_Match,-1              ;We do not have a match
                .leave                                  ;Abort this loop
            .endif                                  ;Endif
            lodsb                                   ;Get next character
            .leave <al eq 0 >                       ;If char is a null we have a match
                                                    ;   and exit this loop
        .until                                  ;Forever
    .endif



    pop     ds
    pop     cx
    ret
EndProc syiExcludeExtLIBPATH



;
; SUBROUTINE NAME: syiRemoveEnvironmentString
;
; DESCRIPTIVE NAME: Remove a string from the environment
;
; FUNCTION:      To remove a string from the SysInit environment
;
; NOTES:         This is an internal subroutine within syiProcess
;
; ENTRY POINT: syiRemoveEnvironmentString
;    LINKAGE:    Call (near)
;
; INPUT:         ES:DI -> String to be removed
;                DS:SI -> The next string in the environment
;
; EXIT-NORMAL: SI -> the end of the environment
;                The environment string is removed
;
; EXIT-ERROR:    none
;
; EFFECTS:       All registers except AX are preserved
;
; INTERNAL REFERENCES:
;    ROUTINES: None
;
; EXTERNAL REFERENCES:
;    ROUTINES:
;                pDosReallocSeg - reallocate segment
;
;
; Procedure syiRemoveEnvironmentString (string)
;
; For each string after the string to be removed
;     Move string down to shrink environment
; Reallocate environment to new size
;

Procedure syiRemoveEnvironmentString
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing
        push    di
        ;Move subsequent environment strings down over the matching string
        .repeat                                 ;Repeat
            lodsb                                   ;Move a character
            stosb
            .leave <zero al>                        ;If zero (end of environment), leave
            .repeat                                 ;Repeat (move one string)
                lodsb                                   ;Move a character
                stosb
            .until <zero al>                        ;Until zero (end of a string)
        .until                                  ;Forever
        mov     si,di                           ;SI -> end of environment

        ;Reallocate (shrink) environment to size in SI
        mov     ax,si
        .if <ax b 2>                            ;Minimum size is 2 bytes
            mov     ax,2
        .endif
        push    ax
        push    ds
        DosInitContext ds
        call    pDosReallocSeg                  ;Reallocate
        .if <nonzero ax>                        ;We cannot handle a realloc failure
            Panic <"IniProc2: Environment shrink failed">
        .endif
        pop     di
        ret
EndProc syiRemoveEnvironmentString



;
; SUBROUTINE NAME: syiAddEnvironmentString
;
; DESCRIPTIVE NAME: Add a string to the Sysinit Environment
;
; FUNCTION:      To add a string to the SysInit environment
;
; NOTES:         This is an internal subroutine within syiProcess
;
; ENTRY POINT: syiAddEnvironmentString
;    LINKAGE:    Call (near)
;
; INPUT:         DS addresses DOSINITDATA
;                ES addresses the environment
;                SI -> end of the environment
;
; EXIT-NORMAL: The string is added to the environment
;
; EXIT-ERROR:    none
;
; EFFECTS:       All registers except AX are preserved
;
; INTERNAL REFERENCES:
;    ROUTINES: None
;
; EXTERNAL REFERENCES:
;    ROUTINES:
;                pDosReallocSeg - reallocate segment
;
;
; Procedure syiAddEnvironmentString (string)
;
; If argument for environment variable is not null
;     Reallocate environment to accomodate string
;     Copy string to end of environment
; Endif
;
Procedure syiAddEnvironmentString
    assume ds:DOSINITDATA, es:nothing, fs:nothing, gs:nothing, ss:nothing
        push    cx
        push    si
        push    di

        mov     ax,Environ_Keyword_Length       ;If an argument was given
        inc     ax                              ; (keyword length = string length)
        .if     <ax b Environ_Argument_Length>  ; taking trailing null into account
            mov     ax,si                           ;Reallocate environment to hold string
            add     ax,Environ_Argument_Length
            push    ax
            push    es
            call    pDosReallocSeg                  ;Realloc
            .if <nonzero ax>                        ;We cannot handle a realloc failure
                Panic <"IniProc2: Environment expand failed">
            .endif

            ;add the string to the environment
            mov     di,si                           ;ES:DI -> end of environment
            dec     di
            mov     si,offset Environ_Buffer        ;DS:SI -> string to add
            mov     cx,Environ_Argument_Length      ;CX = length of string
            rep     movsb                           ;Copy string to environment
            xor     al,al                           ;Mark end of env with null
            stosb
        .endif
        pop     di
        pop     si
        pop     cx
        ret
EndProc syiAddEnvironmentString

;
; SUBROUTINE NAME: syiFATAutoCheck
;
; DESCRIPTIVE NAME: RUN Chkdsk on dirty fat partitions
;
; FUNCTION:      Runs chkdsk on dirty fat partitions that are the boot
;                or user chosen drive partitions.
;
; NOTES:         This is an internal subroutine within syiProcess
;
; ENTRY POINT: syiFATAutoCheck
;    LINKAGE:    Call (near) from syiProcess
;
; INPUT:         Config_Sys_Data = selector for CONFIG.SYS data
;                                  segment
;
; EXIT-NORMAL: Return to caller (no values returned)
;
; EXIT-ERROR:    None
;
; EFFECTS:       All registers are preserved
;
; INTERNAL REFERENCES:
;    ROUTINES: syiCopyConfigSysData - Copy line number
;                                  command, and file spec from
;                                  CONFIG.SYS data packet
;                syiStartProgram         - Start an asynchronous
;                                  program
;
; EXTERNAL REFERENCES:
;    ROUTINES: None
;
;
; Procedure syiFATAutoCheck(CONFIG.SYS data)

;   Call syiCopyConfigSysData(CONFIG.SYS packet) to save the
;       line number and file specification for any error messages
;   Call syiStartProgram(file specification,command line)
;
; Return
;
; End syiFATAutoCheck

Procedure syiFATAutoCheck,near
    assume ds:DOSINITDATA, es:nothing, fs:nothing, gs:nothing, ss:nothing

        SaveReg <ds,es>
        pusha

        LocalVar BootChkdsk,BYTE         ; Results from boot drive     @83390
        LocalVar ForceChkdsk,BYTE        ; Flag - do we FORCE chkdsk?  @83390
        EnterProc                                                    ; @83390

        DosContext es
        mov     cx,SISData.SIS_BootDrv   ; get the boot drive from
        add     cl,'A' - 1               ; the system infoseg

        mov     initfatchkdsk,1          ; If trying to chkdsk a fat boot partition
        .if <es:ACHK_FLAG e FALSE> and   ; If not run chkdsk on fat boot partition
        .if <cl a 'B'> and
        .if <cl be 'Z'>
           mov     al, cl
           call    syiCheckFatDrive      ; See if volume is fat and dirty
           mov     BootChkdsk, ah        ; save state of boot drive    @83390
           .if <ah eq 1>                 ; ah = 1 run chkdsk
              push    ax                 ; save AX
              push    00000001b          ; open flag
              push    0000000000000011b  ; open flag
              push    ds                 ; address of file name
              push    offset DOSINITDATA:fatmsgbuff
              call    pDosPutMessage
              pop     ax                 ; restore AX

              lea     si,chkdsk_args     ; Load address of chkdsk arguments
              mov     ds:[si], cl        ; Move the boot drive into position
              mov     si,offset start_chkdsk_parms  ; point to chkdsk start parameters
              push    cx
              push    bp                 ; save frame                   @83390
              call    syiStartProgram    ; start the program
              pop     bp                 ; restore frame                @83390
              pop     cx
           .endif
        .endif
        mov     es,Config_Sys_Data

;          mov   si,di                   ; copy the line number and file
;          call  syiCopyConfigSysData    ; specification
        xor     bx,bx                    ; Zero out CFG_AutoCheck index
sfa00:                                   ; get next Autocheck drive     @83390
        .while <CFG_AutoCheck[bx] ne 0>  ; Check for end or no autocheck
           mov     al, CFG_AutoCheck[bx] ; Get drive letter
           test    al, 20h               ; check FORCE flag (lowercase) @83390
           .if <nz>                      ; yep, force this drive        @83390
              mov     ForceChkdsk,1      ; turn on FORCE flag           @83390
              and     al, 0DFh           ; fix the drive case           @83390
           .else                         ; not FORCE                    @83390
              mov     ForceChkdsk,0      ; turn off FORCE flag          @83390
           .endif                        ; end FORCE                    @83390
           .if <al e cl>                 ; If user specified boot drive @83390
              .if <ForceChkdsk e 0> or   ; if no force for boot drive   @83390
              .if <BootChkdsk e 1>       ; or we already checked it     @98072
                 inc     bx              ; grab the next drive letter
                 jmp     sfa00           ; (no iterate in this STRUC)   @83390
              .endif
           .endif
           call    syiCheckFatDrive      ; See if volume is fat and dirty
           .if <ah e 1> or               ;ah=1 run chkdsk               @83390
           .if <ah e 0> and              ;ah=0 FAT drive AND            @83390
           .if <ForceChkdsk ne 0>        ; force is ON                  @83390
              push    ax                 ; save AX
              push    00000001b          ; open flag
              push    0000000000000011b  ; open flag
              push    ds                 ; address of file name
              push    offset DOSINITDATA:fatmsgbuff
              call    pDosPutMessage
              pop     ax                 ;restore AX

              lea     si,chkdsk_args     ; Load address of chkdsk arguments
              mov     ds:[si], al        ; Move drive letter into position.
              mov     si,offset start_chkdsk_parms  ; point to chkdsk start parameters
              push    cx                 ; Save boot drive letter
              push    bp                 ; save frame                   @83390
              call    syiStartProgram    ; start the program
              pop     bp                 ; restore frame                @83390
              pop     cx                 ; Restore drive letter
           .endif
           inc     bx                    ; Increment index
        .endwhile

;       Return to caller
        DosContext es
        mov     initfatchkdsk,0          ; If trying to chkdsk a fat boot partition

        LeaveProc                                                    ; @83390
        popa
        RestoreReg <es,ds>
        ret

EndProc syiFATAutoCheck


;;;;;;;;;;;;;;;;;; Start of Feature 74378 changes ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; SUBROUTINE NAME: syiStartAltF1Process
;
; DESCRIPTIVE NAME: Start process specified by Alt-F1
;
; FUNCTION:
;
; NOTES:         This is an internal subroutine within syiProcess
;
; ENTRY POINT: syiStartAltF1Process
;    LINKAGE:    Call (near) from syiProcess
;
; INPUT:         AltF1Parm set
;
;
; EXIT-NORMAL: Return to caller (no values returned)
;
; EXIT-ERROR:    None
;
; EFFECTS:       All registers are preserved
;
; INTERNAL REFERENCES:
;
; EXTERNAL REFERENCES:
;    ROUTINES: None
;
;
Procedure syiStartAltF1Process,near
    assume ds:DOSINITDATA, es:nothing, fs:nothing, gs:nothing, ss:nothing

        SaveReg <ds,es>
        pusha
;       int     3
        mov  al,AltFxKeyPressed
        .if <al eq 1>                            ; Alt-F1 key pressed?

              ;do this so BVHVGA will be linked (and not unlinked)
              DosInitContext <ds>,ax

              push    00000001b             ; open flag
              push    0000000000000011b     ; open flag
              push    ds                    ; address of file name
              push    offset DOSINITDATA:fatmsgbuff
              call    pDosPutMessage

              mov   si,offset start_call_parms ; point to CALL= start parm list

              mov   ax,ds
              mov   ds:[si].Start_Command.msw,ax  ; (in InitData)

;;;;;;;;      DosContext <es>,ax
              mov   ds:[si].Start_FileSpec.msw,ax ; point to file

              mov   ax, offset cmd_exe
              mov   ds:[si].Start_FileSpec.lsw,ax

              mov   al,AltF1Flags
              test  al,ALTF1_USE_ALTF1xCMD
              jz    short safp_use_altf1

              mov   ax, offset AltF1xCmdParms ; point to command line
              jmp   short safp_start

safp_use_altf1:
              test  al,ALTF1_NO_ALTF1CMD     ; Does ALTF1.CMD exist?
              jnz   short safp_norun_altf1   ;  No, so don't run it!

              test  al,ALTF1_USE_ALTF1SEC    ; Security hooks installed? @SEC
              jnz   short safp_use_secf1     ;  Yes. Use ALTF1SEC.CMD.   @SEC

              mov   ax, offset AltF1CmdParms ; point to command line
              jmp   short safp_start         ; @SEC

safp_use_secf1:                                                        ; @SEC
              mov   ax, offset AltF1SecCmdParms ; point to command line  @SEC

safp_start:
              mov   ds:[si].Start_Command.lsw,ax                       ; @SEC

              call  syiStartProgram ; start the program

              ;If C was pressed, we must reboot
              mov     al,AltF1Parm
              .if     <al eq "C">
                  mov     sicg_packet_3,SICGFUN19    ; Reboot function
                  push    ds
                  push    offset DOSINITDATA:sicg_packet_3
                  call    pSICG
              .endif


safp_norun_altf1:
              ;??????????????????????????????????????????????????
              ;?????
              ;????? Add new msg if error on return about ALTF1_CMD
              ;?????     not being able to run.
              ;?????
              ;?????     if <c>
              ;?????        print out message that ALTF1_CMD processing
              ;?????        didn't run.
              ;?????     endif
              ;?????
              ;??????????????????????????????????????????????????

        .endif

;       Return to caller

        popa
        RestoreReg <es,ds>
        ret

EndProc syiStartAltF1Process

;;;;;;;;;;;;;;;;;;;; End of Feature 74378 changes ;;;;;;;;;;;;;;;;;;;;;;;;;;;;


;
; Subroutine Name:      RMNotifyR3
;
; Function:    Notify ResourceManager of a device driver event
;         AX=event       40=BASEDEV LOAD          60=DEVICE LOAD
;                        41=BASEDEV FAIL          61=DEVICE FAIL
;                        42=BASEDEV INSTALLED     62=DEVICE INSTALLED
;      ES:DI=ASCIIZ Module name (if 40 or 60)
;
Procedure RMNotifyR3
assume          ds:nothing,es:nothing,ss:nothing
        EnterProc      <>               ;allocate the local variables
        push    ds

        DosInitContext <DS>, bx
        mov     sicg_packet_1A_d.sicg_1A_func,ax
        mov     sicg_packet_1A_d.sicg_1A_off,di
        mov     sicg_packet_1A_d.sicg_1A_sel,es

        push    ds
        push    offset DOSINITDATA:sicg_packet_1A
        call    pSICG

rmnovr: pop     ds
        LeaveProc                       ;deallocate the local variables
        ret
EndProc RMNotifyR3


INITR3CODE ends

        end
