;        page    80,132
;        title   CP/DOS Load Base Device Drivers  ***  IBM CONFIDENTIAL  ***
;       name    devlbdd
SCCSID  equ     "@(#)devlbdd.asm        6.15 92/03/13"
;                 IBM/Microsoft Confidential
;
;           Copyright (c) IBM Corporation  1987, 1990
;           Copyright (c) Microsoft Corp.  1987, 1990
;                     All Rights Reserved


; Source File Name:     DEVLBDD.ASM
;
; Descriptive Name:     CP-DOS Load Base Device Drivers
;
; Function:     This module contains routines which load a base device driver
;               from a file on the boot device.
;
; Notes:        - All code in this file is new
;
; Dependencies: - This code uses SIFS to open and read in the file. Therefore,
;                 all SIFS dependencies must be met.
;
; Restrictions: - The following is a list of deviations from the bi-modal
;                 device driver architecture for BASE DEVICE DRIVERS.
;                 1. No relocation items are allowed.
;                 2. The init command is CMDInitBase (see devsym.inc).
;                 3. All devices MUST initialize.
;                 4. The code segment must be movable AFTER initialization.
;
; Entry Points: InitBaseDDs
;
; External References:
;               InternalError
;               SYIAbort
;               syiDisplayMessage
;               SYISaveMessage
;               SYISaveMessageID
;               VirtToPhys
;
; Module Heirarchy:
;               InitBaseDDs
;                 BaseDevInit
;                   InitDeviceRes
;                   InitDisk
;                   InitKbd
;                 BaseDevLoad
;                   InternalError
;
; Revision History:
; ID    Date     Description
; ----  -------- ------------------------------------------------------------
; D1357 9/3/91   DCR 1357 Suppress boot messages
;148754 3/15/96  Interim PNP Solution
;150691 4/8/9    Command Line for Resource.sys - Snoop Level from AltF1
;147968 5/11/96  RJM Change FSD and DD system owners to use HMTEs
;---------------------------------------------------------------------------
INCL_ERRORS   EQU  1
.386p

.xlist
include dosseg.inc
include basemaca.inc
include fnoinit.inc
include osmaca.inc
include struc.inc
include mhandle.inc
include mi.inc
include ldrvars.inc
include ldrxport.inc
include devsym.inc
include dpb.inc
include bpb.inc
include inicfg.inc
include inisms.inc
include basemid.inc
include dskinit.inc
include config.inc
include doshlp.inc
include sicg.inc
include bseerr.inc
include infoseg.inc                      ;  @PAA04757 for SIS_BootDrv
.list
CPUMode 386

        ModName  , FNO_DEVLBDD_ASM

LOADINGBASELIST   EQU  0    ;OK for BaseDevLoad to check IPL_DEPENDENT FLAG
LOADINGBASEDEV    EQU  1    ;BaseDevLoad should assume IPL_INDEPENDENT
MSGLINE_NO1       EQU  29   ;Line number for the progress indicator-logo ON
MSGLINE_NO2       EQU  12   ;Line number for the progress indicator-no logo on
MSG_LENGTH        EQU  80   ; length of message text

ReferInitGlobal CFG_ProtectOnly,BYTE
ReferInitGlobal Config_Sys_Data,WORD
ReferInitGlobal pszzBaseVDDs,DWORD
ReferInitGlobal command_string,BYTE
ReferGlobal     SISData,BYTE            ;@PAA04757A - for SIS_BootDrv
ReferGlobal     OEMdev,DWORD            ;Pointer to device chain
ReferGlobal     ABIOS_present,BYTE
ReferGlobal     BClock,DWORD            ;Pointer to clock device
ReferGlobal     ConInpDev,DWORD         ;Pointer to console input device
ReferGlobal     ConOutDev,DWORD         ;Pointer to console output device
ReferGlobal     iDevCall,BYTE           ;see DEV.ASM
ReferGlobal     MaxSec,WORD
ReferGlobal     NumIO,BYTE              ;Number of physical drives
ReferGlobal     NumIORipl,BYTE          ;Number of RIPL drives
ReferGlobal     LstDPBDrv,BYTE
ReferGlobal     DevConfigTbl,BYTE
ReferGlobal     DHF, DWORD               ;DosHlp lookup table
ReferGlobal     LoadDevDrv,BYTE
ReferGlobal     _twodiskboot,WORD        ;150800
ReferInitGlobal sicg_packet_3_d,BYTE
ReferInitGlobal AltFxKeyPressed,BYTE
;147968 ReferGlobal     _LDRDDOwner,WORD      
ReferFlat       dologo,BYTE             ; Screen state (if set logobitmap on)

EXTRN           RealModeIC:near
EXTRN           ProtModeIC:near

EXTRNFAR        InitDeviceRes           ;see DEV.ASM
EXTRNFAR        RMNotifyWork            ;see DEV.ASM
EXTRNFAR        VirtToPhys
EXTRNFAR        w_loadmodule
EXTRNFAR        w_ldrDirtyWorker
EXTRNFAR        FreeDriveLetter     ;99999
EXTRNFAR        AllocateDriveLetter ;99999
EXTRN32         _LDRFreeModule

extrn           InitDisk:near
extrn           InitKbd:near
extrn           InitPRT:near
extrn           SYIAbort:near
extrn           syiSwapDiskette:near           ;149691
extrn           syiDisplayMessage:near
extrn           SYISaveMessage:near
extrn           SYISaveMessageID:near
extrn           SetDPBRemovFlag:near
extrn           sicgf3:far
extrn           sicgf5:far
extrn           syiInitInt13Thread:near                                  ;@xxxx


INITDATA segment
MissingDD         SMT     <MSG_SYSINIT_SFILE_NOT_FND,1>
MissingDD_var1    dd      ?
InvalidDD         SMT     <MSG_SYSINIT_SDRVR_INVAL,1>
InvalidDD_var1    dd      ?
SDRVInitFail      SMT     <MSG_SYSINIT_SDRVR_FAIL,1>
SDRVInitFail_v1   dd      ?
UDRVInitFail      SMT     <MSG_SYSINIT_UDRVR_FAIL,3>
UDRVInitFail_v1   dd      line_number
UDRVInitFail_v2   dd      command
UDRVInitFail_v3   dd      ?

line_number     db     6 dup(0)       ; CONFIG.SYS line number
command         db     "BASEDEV=",0   ; command name

PUBLIC          MsgLoading
PUBLIC          MsgLoadingLen
PUBLIC          MsgDoneLoading
PUBLIC          MsgDoneLoadingLen

MsgLoading      db      "Loading ",72 dup(0)    ;message
MsgLoadingLen   dw      8
MsgDoneLoading  db      "Installed ",70 dup(0)  ;message 2
MsgDoneLoadingLen       dw 10

                public CurrentDev
CurrentDev      dd      0

BASEDEVOrderlist db  ".SNP"                     ; 148754
                 db  ".SYS"
                 db  ".BID"
                 db  ".VSD"
                 db  ".TSD"
                 db  ".ADD"
                 db  ".I13"
                 db  ".FLT"
                 db  ".DMD"
                 dd  0


DPBArea          dd      ?
UseCfgSys        dw      0   ; 148754
SwappedDiskette  db 0        ; 149691

; Resource Manager Command Line Parameters
PUBLIC	RMSysCmdLine						; 150691
RMSysCmdLine	 db	"/SL:N",0,0  				; 150691
RESOURCESYS	 db	"RESOURCE.SYS",0                        ; 150691

INITDATA ends


INITBSS segment
basedd_objbuffer       db 200 dup(?)
INITBSS ends


        FARCODE INIT
INITCODE segment


; Subroutine Name:      InitBaseDDs
;
; Descriptive Name:     Load Base Device Drivers
;
; Function:     This routine is called from the device manager to load and
;               initialize the base device drivers.
;
; Notes:        OEMDev MUST be initialized to -1.
;
; Entry Point:  InitBaseDDs in DOSCODE
;     Linkage:  Call (near, protect mode)
;
; Entry:        ax -> DPB segment
;
; Exit-Normal:  nothing
;
; Exit-Error:   none
;
; Effects:      no registers preserved
;
; Internal References:
;   Routines:   InitBaseList
;               InitBASEDEVs
;
; External References:
;   Routines:   none
;
;

Procedure InitBaseDDs,near
assume          ds:nothing,es:nothing,ss:nothing
EnterProc       <>                      ;allocate the local variables

SaveReg         <ax>

call            syiInitInt13Thread                                       ;@xxxx

RestoreReg      <ax>

DosInitContext  ds,si
mov             DPBArea.Segmt,ax        ;init DPB chain
mov             DPBArea.Offst,0

call            InitBaseList            ;load base device drivers from
                                        ; static list
call            OrderBASEDEVs           ;Put BASEDEV= statements in correct
                                        ; load order
call            InitBASEDEVs            ;load base device drivers from
                                        ; config.sys
;       Swap diskettes if we haven't already swapped            ;149691
push     es                                                     ;149691
DosContext  <es>,cx                                             ;149691
push     ds                                                     ;150105
DosInitContext <ds>,cx                                          ;150105
mov  cx,es:_twodiskboot                                         ;150800
.if <nonzero cx>               ; _twodiskboot?                  ;150800
   mov  al,SwappedDiskette      ; Already swapped diskette?     ;149691
   .if <al eq 0>                                                ;149691
      call         syiSwapDiskette ; prompt for next diskette   ;149691
      mov  SwappedDiskette,1                                    ;149691
   .endif                                                       ;149691
.endif                                                          ;149691
pop      ds                                                     ;150105
pop      es                                                     ;149691
ASSUME ES:NOTHING                                               ;149691

LeaveProc                               ;deallocate the local variables
ret
EndProc InitBaseDDs

; Subroutine Name:      InitBaseList
;
; Descriptive Name:     Load Base Device Drivers
;
; Function:     This routine is called from InitBaseDDs to load and
;               initialize the base device drivers.
;
; Notes:        OEMDev MUST be initialized to -1.
;
; Entry Point:  InitBaseList in DOSCODE
;     Linkage:  Call (near, protect mode)
;
; Entry:        nothing
;
; Exit-Normal:  nothing
;
; Exit-Error:   none
;
; Effects:      no registers preserved
;
; Internal References:
;   Routines:   BaseDevInit
;               BaseDevLoad
;
; External References:
;   Routines:   sicgf5
;               LDRFreeModule
;               DosHlpBaseDDList
;
; Pseudo Code:
;       Init the DPB chain
;       Set pointer to first file in base device driver list
;       REPEAT
;         Load the device driver (call BaseDevLoad)
;         IF carry flag indicates not IPL_INDEPENDENT THEN
;            Set pointer to first header in driver
;            REPEAT
;              Initialize the device (call BaseDevInit)
;              Save ending code and data addresses
;              Set pointer to next header in driver
;            UNTIL no more headers
;            Shrink segments (call sicgf5)
;            Link driver into chain
;            Free mte (call LDRFreeModule)
;         ENDIF
;         Set pointer to next file in list
;       UNTIL no more files
;       Return
;

Procedure InitBaseList,near
assume          ds:nothing,es:nothing,ss:nothing
LocalVar        CodeLimit,WORD
LocalVar        DataLimit,WORD
LocalVar        F2Switch,WORD
LocalVar        pCmdLine,DWORD					; 150691
EnterProc       <>                      ;allocate the local variables



DosContext      ds
test            ABIOS_present,-1
.if             <z>
  mov al, BASEDD_AT             ; AT
.else
  mov al, BASEDD_PS2            ; ABIOS PS/2
.endif

call DHF.DosHlpBaseDDList       ; get base device driver list

; es:di now points to buffer list for base device drivers
; es:si now points to buffer list for base virtual device drivers

DosInitContext ds,cx

mov             pszzBaseVDDs.Offst,si     ;save offset of VDD list
mov             pszzBaseVDDs.Segmt,es     ;save selector of VDD list

.while          <<byte ptr es:[di]> ne 0> near
  DosInitContext  ds
  mov             CodeLimit,0             ;clear out the limits
  mov             DataLimit,0
  SaveReg         <di,es>                 ;es:di -> file list
  mov             MissingDD_var1.Offst,di         ;set up for messages
  mov             MissingDD_var1.Segmt,es
  mov             InvalidDD_var1.Offst,di
  mov             InvalidDD_var1.Segmt,es
  mov             SDRVInitFail_v1.Offst,di
  mov             SDRVInitFail_v1.Segmt,es
  mov             UDRVInitFail_v3.Offst,di
  mov             UDRVInitFail_v3.Segmt,es

  mov             cx,LOADINGBASELIST


  .if             <AltFxKeyPressed  e 2>
      mov         ax, 1                    ; message "loading ..."
;     int         3                        ; TESTING
      call         DisplayLoadMsg
  .endif
;                                                               ; 150691
; Check if Command Line for base driver (resource.sys)          ; 150691
; if Command line found, return pointer in pCmdLine             ; 150691
;                                                               ; 150691
  mov		   ax,ss	     				; 150691
  mov		   ds,ax                                        ; 150691
  lea		   si,pCmdLine          ; ds:si = pCmdline      ; 150691
  call 	           CheckCmdLine		; es:di = filename	; 150691

  call             BaseDevLoad             ;load driver
  .if <nc> near                         ;if driver IPL_DEPEND
    assume          ds:nothing
    mov             bx, si                  ;save offset of first header
    xor             si,si                   ;ds:si -> first header
    .repeat
; 150691 xor             bx,bx
; 150691 xor             cx,cx                   ;bx:cx = NULL
      ; Get pointer to the Command Line	(pCmdLine)              ; 150691
      mov	      bx,word ptr ss:[pCmdLine+2] 		; 150691
      mov	      cx,word ptr ss:[pCmdLine]                 ; 150691

      mov             ax,LOADINGBASELIST
      call            BaseDevInit             ;init
      mov             CodeLimit,cx            ;save code limit
      mov             DataLimit,dx            ;save data limit
      mov             si,ds:[si].SDevNext.Offst ;next header
    .until          <si eq -1>
    .if <CodeLimit ne 0> and
    .if <DataLimit ne 0>
       SaveReg         <ds>
       DosInitContext ds
       lea             si,sicg_packet_3_d
       mov             cx,CodeLimit          ;squeeze driver's segments
       mov             dx,DataLimit
       mov             ds:[si].sicg_ecode,cx
       mov             ds:[si].sicg_edata,dx
       call            sicgf5
     ; ;never fails
     ; .if <c>
     ;   DosInitContext ds,si                ;ds:si -> abort message
     ;   mov            si,offset InvalidDD
     ;   call           SYIAbort
     ; .endif
       RestoreReg      <ds>
       DosContext      es                    ;link device into chain
       xor             si,si                 ;ds:si -> first header
       .while          <ds:[si].SDevNext.Offst ne -1>
         mov             si,ds:[si].SDevNext.Offst ;next header
       .endwhile
       mov             ax,OEMdev.Offst       ;link last header to head of chain
       mov             ds:[si].SDevNext.Offst,ax
       mov             ax,OEMdev.Segmt
       mov             ds:[si].SDevNext.Segmt,ax
       mov             OEMdev.Offst,0        ;put first header at head of chain
       mov             OEMdev.Segmt,ds
    .else
       SaveReg         <ds>
       DosInitContext   <ds>
       mov              bx,sicg_packet_3_d.sicg_devhndl
       movzx            ebx,bx
       FlatContext     <ds,es>,ax,noassume
       CCALL32         _LDRFreeModule <ebx,dword ptr TRUE>
       RestoreReg      <ds>
    .endif
  .endif

   pushad
   mov     eax,1
   CALLFAR w_ldrDirtyWorker
   popad

  DosInitContext        ds
  .if             <AltFxKeyPressed  e 2>
      mov         ax, 2                    ; message "Done loading ..."
;     int         3                        ; TESTING
      call         DisplayLoadMsg
  .endif

  RestoreReg      <es,di>                 ;es:di -> file list
  assume          es:nothing
  xor             al,al                   ;skip file just loaded
  mov             cx,-1
  repne   scasb                         ; find end of File Name
  inc             di                    ; es:di -> next file in list
.endwhile

LeaveProc                               ;deallocate the local variables
ret
EndProc InitBaseList


; SUBROUTINE NAME: InitBASEDEVs
;
; DESCRIPTIVE NAME: Install device drivers specified by BASEDEV keyword
;
; FUNCTION:      To load and initialize all user specified
;                base device drivers
;
; NOTES:
;
; ENTRY POINT: InitBASEDEVs
;    LINKAGE:    Call (near)
;
; INPUT:         Config_Sys_Data contains the selector for the
;                                CONFIG.SYS data segment
;                (DS) -> DOSINITDATA
;
; EXIT-NORMAL:   Nothing
;
; EXIT-ERROR:    None
;
; EFFECTS:       No registers are preserved
;
; INTERNAL REFERENCES:
;    ROUTINES:   BaseDevInit
;                BaseDevLoad
;
; EXTERNAL REFERENCES:
;   Routines:   sicgf5
;               LDRFreeModule
;
;
; Procedure InitBASEDEVs
;
;       Set pointer to first file in CFG_Basedev list
;       REPEAT
;         Load the device driver (call BaseDevLoad)
;         IF carry flag indicates failure
;            Call SYIAbort with MissingDD message
;         ELSE
;            Set pointer to first header in driver
;            REPEAT
;              Initialize the device (call BaseDevInit)
;              Save ending code and data addresses
;              Set pointer to next header in driver
;            UNTIL no more headers
;            Shrink segments (call sicgf5)
;            Link driver into chain
;            Free mte (call LDRFreeModule)
;         ENDIF
;         Set pointer to next file in list
;       UNTIL no more files
;       Return
;

Procedure InitBASEDEVs,near
assume          ds:nothing,es:nothing,ss:nothing
LocalVar        CodeLimit,WORD
LocalVar        DataLimit,WORD
LocalVar        F2Switch,WORD           ;set if F2
LocalVar        pDDCfgStruct,DWORD      ;pointer to config DD struct to loaded ;148754
LocalVar        RMHandle,DWORD          ;a value used by Resource Manager      ;148754
LocalVar        DDLoadType,WORD         ;device driver type for Resource Manager;148754
EnterProc       <>                      ;allocate the local variables

DosInitContext  ds

; es:di now points to buffer list for base device drivers

mov     es,Config_Sys_Data
; 148754 mov     di,es:[0].CFG_Basedev.CFG_Head

; 148754 begin
SaveReg <es>
; set UseCfgSys to 0 = do not use Config.sys, instead use RM
mov     UseCfgSys, 0
; set up for call to RM function 20: Send Initial DD CFG list
lea     ax,es:[0].CFG_RMDevice.CFG_Head
push    es
push    ax
lea     ax,es:[0].CFG_VDDDevice.CFG_Head
push    es
push    ax
lea     ax,es:[0].CFG_Device.CFG_Head
push    es
push    ax
lea     ax,es:[0].CFG_Basedev.CFG_Head
push    es
push    ax

mov     cx,sp   ; save pointer to dev array
mov     di,ss
mov     es,di
mov     di,cx                   ; es:di = pointer to config device ptr array
mov     ax,20h                  ;AX = Pass Resource Manager List of DDs Cfg.sys
CALLFAR          RMNotify
add     sp,16                   ;toss parms on stack
.if < ax ne 100h >              ;if error read config.sys data
  inc     UseCfgSys             ;  Use config.sys, not RM to get DDs
.endif
RestoreReg      <es>

mov     di,es:[0].CFG_Basedev.CFG_Head
.if < UseCfgSys eq 0 >          ;Are we using config.sys?
  mov   es:[0].CFG_Basedev.CFG_Head, 0 ;Create new list
  mov   es:[0].CFG_Basedev.CFG_Tail, 0
  mov   DDLoadType,0            ; Specify a Basedev
  mov   RMHandle,0              ; Start with null handle
  mov   ax,ss
  mov   es,ax
  lea   di,ss:DDLoadType        ; es:di -> parameter pointer for IOCtl
                                ; es:di -> PGETNXTDD
  mov   ds,ax
  lea   si,ss:RMHandle          ; ds:si -> pointer for next dd to load (data)
                                ; ds:si -> PNXTDD
  mov   ax,21h                  ; AX = Ask Resource Manager for a driver
  CALLFAR          RMNotify

  les   di,dword ptr ss:pDDCfgStruct ; get pointer to next DD struc
  mov   eax,es:[di].pKrnlCfgDevice
  .if   < zero eax >            ;Test for a new device to be inserted
    CALLFAR  ConfigDevCreate    ;if null, create a new dev struct
  .else                         ;Otherwise, use existing structure
    les di,es:[di].pKrnlCfgDevice
  .endif

  mov     si,es:[0].CFG_Basedev.CFG_Tail
  .if < si eq 0 >
  ;  Point to head                    ;es:di -> Device Packet to insert
     mov  es:[di].CFG_Prev,0
     mov  es:[di].CFG_Next,0
     mov  es:[0].CFG_Basedev.CFG_Head,di
     mov  es:[0].CFG_Basedev.CFG_Tail,di
  .else                         ;es:di -> New Device Packet to insert
     mov  es:[di].CFG_Prev,si
     mov  es:[di].CFG_Next,0
     mov  es:[si].CFG_Next,di
     mov  es:[0].CFG_Basedev.CFG_Tail,di
  .endif
.endif

; 148754 end

mov     F2Switch, 1                      ; TESTING
DosInitContext  ds

.while          <nonzero di> near
  SaveReg         <es,di>                 ;es:di -> next config.sys data packet
  mov             di,es:[di].CFG_FileSpec ;es:di -> filename
  mov             CodeLimit,0             ;clear out the limits
  mov             DataLimit,0
  DosInitContext  ds
  mov             MissingDD_var1.Offst,di         ;set up for messages
  mov             MissingDD_var1.Segmt,es
  mov             InvalidDD_var1.Offst,di
  mov             InvalidDD_var1.Segmt,es
  mov             SDRVInitFail_v1.Offst,di
  mov             SDRVInitFail_v1.Segmt,es
  mov             UDRVInitFail_v3.Offst,di
  mov             UDRVInitFail_v3.Segmt,es
  mov             cx,LOADINGBASEDEV

  .if             <AltFxKeyPressed  e 2>
      mov         ax, 1                    ; message "loading ..."
;     int         3                        ; TESTING
      call         DisplayLoadMsg
  .endif

;
; RAR - Put RM load notification here (ES:DI=module name)
;
  mov              ax,40h          ;AX   =Notify ResourceManager of DD Load
  CALLFAR          RMNotify                ;ES:DI=ASCIIZ module name

  mov              cx,LOADINGBASEDEV                                    ; 148754
  call             BaseDevLoad             ;load driver
  .if <nc> near                          ;if driver missing
    assume          ds:nothing
    mov             bx, si                  ;save offset of first header
    xor             si,si                   ;ds:si -> first header
    .repeat
      RestoreReg      <di,es>                 ;es:di -> config.sys data packet
      SaveReg         <es,di>                 ; put it back on stack
      call            BaseDevConstructCommandLine
      DosInitContext  ,bx
      lea             cx,command_string       ;bx:cx -> command line parms
      mov             ax,LOADINGBASEDEV
      call            BaseDevInit             ;init
      mov             CodeLimit,cx            ;save code limit
      mov             DataLimit,dx            ;save data limit
      mov             si,ds:[si].SDevNext.Offst ;next header
    .until          <si eq -1>
    .if <CodeLimit ne 0> and
    .if <DataLimit ne 0>
       SaveReg         <ds>
       DosInitContext ds
       lea             si,sicg_packet_3_d
       mov             cx,CodeLimit            ;squeeze driver's segments
       mov             dx,DataLimit
       mov             ds:[si].sicg_ecode,cx
       mov             ds:[si].sicg_edata,dx
       call            sicgf5
    ;  ; never fails
    ;  .if <c>
    ;    DosInitContext ds,si                      ;ds:si -> abort message
    ;    mov            si,offset InvalidDD
    ;    call           SYIAbort
    ;  .endif
       RestoreReg      <ds>
       DosContext      es                      ;link device into chain
       xor             si,si                   ;ds:si -> first header
       .while          <ds:[si].SDevNext.Offst ne -1>
         mov             si,ds:[si].SDevNext.Offst ;next header
       .endwhile
       mov             ax,OEMdev.Offst      ;link last header to head of chain
       mov             ds:[si].SDevNext.Offst,ax
       mov             ax,OEMdev.Segmt
       mov             ds:[si].SDevNext.Segmt,ax
       mov             OEMdev.Offst,0       ;put first header at head of chain
       mov             OEMdev.Segmt,ds

       mov             ax,42h      ;AX   =Notify ResourceManager of DD Installed
       CALLFAR         RMNotify
    .else                       ;only freemodule if clearing DD from memory
;pd    SaveReg         <ds> ;;;pd - don't do this - we are about to free it!
       DosInitContext   <ds>
       mov              bx,sicg_packet_3_d.sicg_devhndl
       movzx            ebx,bx
       FlatContext     <ds,es>,ax,noassume
       CCALL32         _LDRFreeModule <ebx,dword ptr TRUE>
;pd    RestoreReg      <ds> ;;; don't restore a selector we just freed
       mov             ax,41h      ;AX   =Notify ResourceManager of DD Failed
       CALLFAR         RMNotify
   .endif
  .endif
  assume          es:nothing
  RestoreReg      <di,es>               ;es:di ->  config.sys data packet

   pushad
   mov     eax,1
   CALLFAR w_ldrDirtyWorker
   popad

  push            ds
  DosInitContext  ds
  .if             <AltFxKeyPressed  e 2>
      mov         ax, 2                    ; message "Finished ..."
;     int         3                        ; TESTING
      call         DisplayLoadMsg
  .endif
; 148754  pop             ds

; 148754  mov             di,es:[di].CFG_Next   ; get next data packet

;148754 Start Ask RM for a driver
  .if < UseCfgSys ne 0 >
    mov             di,es:[di].CFG_Next   ; get next data packet
  .else
    mov   ax,ss
    mov   es,ax
    lea   di,ss:DDLoadType        ; parameter pointer for IOCtl
    mov   ds,ax
    lea   si,ss:RMHandle          ; ds:si -> pointer for next dd to load (data)
    mov   ax,21h                  ; AX = Ask Resource Manager for a driver
    CALLFAR          RMNotify
    les   di,dword ptr ss:pDDCfgStruct ; get pointer to next DD struc
    .if < di ne 0 >
      mov   eax,es:[di].pKrnlCfgDevice
      .if   < zero eax >            ;Test for a new device to be inserted
        CALLFAR  ConfigDevCreate    ;if null, create a new dev struct
      .else
        les di,es:[di].pKrnlCfgDevice
      .endif

      mov  si,es:[0].CFG_Basedev.CFG_Tail
      mov  es:[di].CFG_Prev,si
      mov  es:[di].CFG_Next,0
      mov  es:[si].CFG_Next,di
      mov  es:[0].CFG_Basedev.CFG_Tail,di
    .endif
  .endif

  pop             ds

;148754 End ask for a driver
.endwhile

LeaveProc                               ;deallocate the local variables
ret
EndProc InitBASEDEVs


;
; Subroutine Name:      BaseDevLoad
;
; Descriptive Name:     Base Device Driver Load
;
; Function:     This routine is called from InitBaseDDs to load a base device
;               driver.
;
; Notes:        - The name of the file to load is specified in the name field
;               of the device header. The file extension will be forced to
;               "sys" and the path is forced to the root directory on the boot
;               device.
;               - The loaded driver's header(s) will be linked into the device
;               chain in place of the existing header. Therefore, the loading
;               of the actual driver will be transparent to the caller.
;
; Entry Point:  BaseDevLoad in DOSCODE
;     Linkage:  Call (near, protect mode)
;
; Entry:        es:di -> file name
;               cx   = LOADINGBASELIST (OK to check for IPL_DEPENDANT flag)
;                    = LOADINGBASEDEV ( assume IPL_DEPENDANT)
;
; Exit-Normal:  ds:si -> loaded driver's first header
;               carry clear = device loaded
;               carry set = device not loaded and ipl independent
;
; Exit-Error:   via InternalError
;
;
; Effects:      no registers preserved
;
; Internal References:
;   Routines:   SYIAbort
;
; External References:
;   Routines:   w_loadmodule   - Load dynamic link library module
;               sicgf3
;
; Pseudo Code:
;       Load the file (call w_loadmodule)
;       If error then
;          IF IPL_INDEPENDENT THEN set carry (indicate IPL_INDEPENDENT)
;          ELSE error THEN abort (call SYIAbort)
;       Endif
;       Get module information (call sicgf3)
;       Stuff selectors in headers
;       Return
;

Procedure BaseDevLoad,near,local
assume          ds:nothing,es:nothing,ss:nothing
; call            LoadFile        ;load the file
; get the size of the file
; Call w_loadmodule to load device driver
;

DosContext      ds,si
mov     ds:LoadDevDrv,EXT_DEVICE          ; tell DOSLOADMODULE device driver
DosInitContext ds,si
mov     si,offset basedd_objbuffer        ; ds:si=address of object name buffer
mov     ax,200                            ; length of object name buffer
;es:di   file spec
SaveReg <cx,es,di,ds>
CALLFAR w_loadmodule                      ;destroys registers
RestoreReg <ds,di,es,cx>
.if <nonzero ax>                                                   ;149691
   SaveReg <es,cx>                                                 ;149691
   DosContext  <es>,cx                                             ;149691
   mov  cx,es:_twodiskboot                                         ;150800
   ;       Swap diskettes if we haven't already swapped            ;149691
   mov  cx,_twodiskboot                                            ;150800
   .if <nonzero cx>                ; _twodiskboot?                 ;150800
      mov  al,SwappedDiskette      ; Already swapped diskette?     ;149691
      .if <al eq 0>                                                ;149691
         call         syiSwapDiskette ; prompt for next diskette   ;149691
         mov  SwappedDiskette,1                                    ;149691
         SaveReg <es,di,ds>            ;Try again                  ;149691
         CALLFAR w_loadmodule          ;destroys registers         ;149691
         RestoreReg <ds,di,es>                                     ;149691
      .endif                                                       ;149691
   .endif                                                          ;149691
   RestoreReg <cx,es>                                              ;149691
   ASSUME ES:NOTHING                                               ;149691
.endif                                                             ;149691
.if     <nonzero ax>                  ; did the loadmodule fail?
  .if <cx eq LOADINGBASELIST>         ; If loading from list, check flags
    xor al,al                         ; target is a NULL
    mov         cx, -1                ; search until found
    repne       scasb                 ; find the NULL
                                      ; we are now pointing at Base Device
                                      ; driver flags
    .if <<byte ptr es:[di]> ae IPL_INDEPEND>; is this device drive IPL-
                                      ; Independent ?
      stc                             ; indicate we have an IPL_INDEPEND Device
                                      ; driver not present
    .else
      DosInitContext  ds,si                       ;ds:si -> abort message
      mov             si,offset MissingDD
      call  SYIAbort
    .endif
  .else              ;else loading BASEDEV from config.sys, so just display msg
      DosInitContext  ds,si                       ;ds:si -> message
      mov             si,offset MissingDD
      call            syiDisplayMessage
      stc
  .endif
.else near
;147968  DosContext    ds                      ;147968
;147968  cmp   [_LDRDDOwner],MAXDDOWNER        ;147968
;147968  jae   short bdl10                     ;147968
;147968  inc   [_LDRDDOwner]                   ;147968 ; increment current DD owner
bdl10:
  DosInitContext ds
  mov     sicg_packet_3_d.sicg_devhndl,bx
  lea     si,sicg_packet_3_d
  push    cx
  call    sicgf3
  pop     cx

  .if <c>
     .if <cx eq LOADINGBASELIST>
        DosInitContext  ds,si                       ;ds:si -> abort message
        mov             si,offset InvalidDD
        call            SYIAbort
     .else
        DosInitContext  ds,si                       ;ds:si -> message
        mov             si,offset InvalidDD
        call            syiDisplayMessage

        SaveReg         <ds>
        DosInitContext   <ds>
        mov              bx,sicg_packet_3_d.sicg_devhndl
        movzx            ebx,bx
        FlatContext     <ds,es>,ax,noassume
        CCALL32         _LDRFreeModule <ebx,dword ptr TRUE>
        RestoreReg      <ds>
        stc
     .endif
  .else
     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.Segmt,es      ; fix up the link field
       mov   di,es:[di].SDevNext.Offst
     .endwhile
     lds     si,sicg_packet_3_d.sicg_devhdr
     clc
  .endif
.endif
ret
EndProc BaseDevLoad

;
; Subroutine Name:      BaseDevInit
;
; Descriptive Name:     Base Device Driver Initialization
;
; Function:     This routine is called from InitBaseDDs to initialize a device
;               driver.
;
; Notes:        none
;
; Entry Point:  BaseDevInit in DOSCODE
;     Linkage:  Call (near, protect mode)
;
; Entry:        ds:si -> device header
;               bx:cx -> command line parameters (NULL if DD is not being
;                           via BASEDEV= statement in CONFIG.SYS)
;               ax    = LOADINGBASELIST or LOADINGBASEDEV
;
; Exit-Normal:  cx = code segment limit
;               dx = data segment limit
;               ds:si -> device header
;
; Exit-Error:   via SYIAbort
;
; Effects:      no registers preserved
;
; Internal References:
;   Routines:   none
;
; External References:
;   Routines:   InitDeviceRes
;               InitDisk
;               InitKbd
;               SYIAbort
;
; Pseudo Code:
;       IF console input driver THEN initialize keyboard (call InitKbd)
;       IF block driver THEN initialize disk (call InitDisk)
;       Initialize device driver (call InitDeviceRes)
;       IF not successful THEN abort (call SYIAbort)
;       IF console input driver THEN register as console input device
;       ELSEIF console output driver THEN register as console output device
;       ELSEIF clock driver THEN register as clock device
;       ELSEIF block driver THEN
;         IF error message ID returned THEN save it (call SYISaveMessageID)
;         FOR each unit supported by the driver
;           Build a DPB for the unit
;           Link the DPB into the DPB chain
;         NEXT unit
;       ENDIF
;       Return
;
Procedure BaseDevInit
    assume ds:nothing,es:nothing,ss:nothing
        LocalVar  CalledFrom,WORD
        EnterProc <>
        mov       CalledFrom,ax

        DosContext      es
        test    ds:[si].SDevAtt,DEV_CHAR_DEV
        .if     <nz>
          mov     ax,ds:[si].SDevAtt
          Dev_FuncLev DEVLEV_3,ax                       ;if level 3 dev driver
          .if     <z>
            test    byte ptr ds:[si].SDevCaps,DEV_PARALLEL ;If parallel port dd
            .if     <nz>
              call  InitPRT                             ;bx:cx -> CFG_PrtBufSize
            .endif
            test    byte ptr ds:[si].SDevCaps,DEV_ADAPTER_DD
            .if     <nz>
              call  InitDisk                            ;bx:cx -> parameter list
            .endif
          .endif
          test    byte ptr ds:[si].SDevAtt,DEV_CIN
          .if     <nz>
            SaveReg         <si,ds,es>
            DosInitContext  ds
            mov     es,Config_Sys_Data
            assume  es:nothing
            mov     si,es:CFG_CodePage.CFG_Tail
            xor     ax,ax
            or      si,si
            .if     <nz>
              mov     ax,es:[si].CFG_nIDs
            .endif
            .if     <CFG_ProtectOnly eq 0>
              or      ah,01h
            .endif
            RestoreReg      <es,ds,si>
            assume  ds:nothing, es:DOSGROUP
            call    InitKbd         ;bx:cx -> parameter list
            .if     <c>
              call    SYISaveMessage
            .endif
          .endif
          test    byte ptr ds:[si].SDevAtt,DEV_CLOCK
          .if     <nz>
            mov     BClock.Offst,si
            mov     BClock.Segmt,ds
            mov     ax,ds:[si].SDevRealDS
            mov     BClock.Segmt+2,ax
          .endif
        .else
          call    InitDisk        ;bx:cx -> parameter list
        .endif
        mov     dx,bx           ;dx:cx -> parameter list

        CALLFAR InitDeviceRes

        test    iDevCall.PktStatus,STERR        ;if not successful
        .if     <nz> or
        .if     <iDevCall.InitEcode eq 0> or
        .if     <iDevCall.InitEdata eq 0>
           mov cx,CalledFrom
           .if <cx eq LOADINGBASEDEV>
              mov cx,iDevCall.PktStatus
              and cx,0ffH
              .if <cx ne ERROR_I24_QUIET_INIT_FAIL>
                 SaveReg <ds,si>
                 DosInitContext ds,si
                 mov     si,offset UDRVInitFail ;ds:si -> message
                 call    syiDisplayMessage
                 RestoreReg <si,ds>
                 mov     iDevCall.InitEcode, 0
                 mov     iDevCall.InitEdata, 0
              .endif
              jmp     dev_init_loop
           .else
             DosInitContext  ds,si                 ;ds:si -> abort message
             mov             si,offset SDRVInitFail
             call            SYIAbort
          .endif
        .endif

        test    ds:[si].SDevAtt,DEV_CHAR_DEV    ; Character device?
        .if     <nz>
          test    byte ptr ds:[si].SDevAtt,DEV_CIN
          .if     <nz>
            mov     ConInpDev.Offst,si
            mov     ConInpDev.Segmt,ds
            mov     ax,ds:[si].SDevRealDS
            mov     ConInpDev.Segmt+2,ax
          .endif
          test    byte ptr ds:[si].SDevAtt,DEV_COUT
          .if     <nz>
            mov     ConOutDev.Offst,si
            mov     ConOutDev.Segmt,ds
            mov     ax,ds:[si].SDevRealDS
            mov     ConOutDev.Segmt+2,ax
          .endif
        .else   near
          mov     cl,iDevCall.InitcUnit
          xor     ch,ch                   ; CX = # units in device
          mov     ds:[si].SDevName,cl     ; Number of units in name field
          or      cx,cx
          jnz     short doinitdpb
          jmp     dev_init_loop           ; no DPBs to build

doinitdpb:  mov     dl,NumIO            ;### PTR B710417
            xor     dh,dh               ;### DX = drive # to start with
;@PAA04757A begins
            cmp       NumIORipl,0
            je        InitDPB
            mov       ax,[SISData].SIS_BootDrv

            cmp       dx, ax            ;ax is Ripl Boot Drive, dx is drive #
                                        ;to start with
            jl        InitDPB           ;Is dl is a drive below Ripl range?
            add       dl, NumIORipl     ;Else, adjust this device header.
InitDPB:
;@PAA04757A ends
            SaveReg <si,ds>
            lds     bx,iDevCall.InitpBPB
            assume  ds:nothing
PerUnit:    mov     si,ds:[bx]              ; DS:SI Points to BPB
            inc     bx
            inc     bx                      ; On to next BPB
            mov     ax,ds:[si].BPSECSZ
            .if     <ax a MaxSec>           ; Have new largest sector size?
              mov     MaxSec,ax               ; Yes, set largest buffer size
            .endif
            push    ds
            DosInitContext DS,di
            les     di,DPBArea              ; Address DPB area
            pop     ds
            assume  es:nothing
            mov     es:[di].dpb_cbSector,ax ; initial # of bytes/sector

            mov     al,ds:[si].BPMEDIA
            mov     es:[di].dpb_media,al    ; Set drive's media byte
;@PAA04757A begins
            push      bx
            push      ds
            DosContext ds
            mov       bl, NumIORipl
            cmp       bl, 0
            je        NoRipl

            mov       ax,ds:[SISData].SIS_BootDrv
            dec       ax                ;dl is zero based, SIS_BootDrv is 1 based
            cmp       dl, al            ;al is Ripl Boot Drive, dx is current drive
            jne       NoRipl            ;dl is a drive below Ripl range
            add       dl, bl            ;adjust the drive number pass the Ripl drives
NoRipl:
            mov       LstDPBDrv,dl      ; save this drive for when we init
                                        ; non-base block device drivers
            pop       ds
            pop       bx
;@PAA04757A ends

            mov     es:[di].dpb_drive,dl    ; Set drive #
            SaveReg <bx>                    ; start 99999
            movzx   ax,dl
            xor     bx,bx                   ; It is a local drive
            CALLFAR AllocateDriveLetter
            RestoreReg <bx>                 ; end 99999
            mov     es:[di].dpb_unit,dh     ; Set unit # within device
            mov     es:[di].dpb_hVPB,0      ; initiallly no volume present
            mov     es:[di].dpb_drive_lock,0 ; No one has the drive locked

            mov     ax,ds:[si].BPRES    ; # reserved sectors = start of fat 1
            mov     es:[di].dpb_first_FAT,ax

            mov     ax,ds                   ; Save DS
            RestoreReg      <ds,si>
            mov     es:[di].dpb_driver_addr.Offst,si
            mov     es:[di].dpb_driver_addr.Segmt,ds
            SaveReg <si,ds>
            push    es
            pop     ds
            mov     si,di                   ; ds:si -> dpb
            SaveReg <ax,bx>
            call    SetDPBRemovFlag         ; determine removability for dpb
            RestoreReg <bx,ds>              ; ds -> bpb
            inc     dh                      ; Advance unit in device
            inc     dl                      ; Advance disk # in system
            DosContext es
            push    ds
            DosInitContext ds
            add     DPBArea.Offst,size dpb    ; Point after new DPB
            pop     ds
            dec     cx                         ;@PAA04757C
            jnz     PerUnit                    ;@PAA04757C
            RestoreReg <ds,si>
            mov     cl,iDevCall.InitcUnit
            add     NumIO,cl                  ; Bump # disks by # being added
dev_init_loop:
        .endif
        mov     cx,iDevCall.InitEcode   ;end (limit) of code segment
        mov     dx,iDevCall.InitEdata   ;end (limit) of data segment
        LeaveProc
        ret
EndProc BaseDevInit

;
; SUBROUTINE NAME: BaseDevConstructCommandLine
;
; 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 DevlBDD
;
; ENTRY POINT: BaseDevConstructCommandLine
;    LINKAGE:    Call (near)
;
; INPUT:         ES:DI = 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 BaseDevConstructCommandLine(CONFIG.SYS data packet)
;
; copy the line number from the data packet into line_number (in case of error)
; 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 BaseDevConstructCommandLine

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

        SaveReg <ds,es,si,di>

;       Copy the file specification from the data packet

        mov     si,di                 ; DS:SI = address of CONFIG.SYS
        push    es                    ;         DATA paket
        pop     ds                    ;

        SaveReg <si>
        lea     si,ds:[si].CFG_LineNumber

        DosInitContext ES,ax
        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>

        mov     di,offset command_string ; ES:DI -> command_string
        mov     bx,di                    ; AX:BX -> command_string

        SaveReg <ax>
        SaveReg <si>
        mov     si,ds:[si].CFG_FileSpec  ;DS:SI -> filespec

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

        .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

        RestoreReg <ax>               ; AX:BX -> command_string

        RestoreReg <di,si,es,ds>
        ret

EndProc BaseDevConstructCommandLine

; Subroutine Name:      OrderBASEDEVs
;
; Descriptive Name:     Sort BASEDEV= statements to get correct load order
;
; Function:     Sort the BASEDEV= statements to put the device drivers
;               in the correct load order, by suffix.
;
;
; Entry Point:  OrderBASEDEVs in DOSCODE
;     Linkage:  Call (near, protect mode)
;
; Entry:        none
;
; Exit-Normal:  none
;
; Exit-Error:   none
;
; Effects:
;
; Internal References:
;   Routines:   RelinkBASEDEVs
;
; External References:
;   Routines:   none
;
;

Procedure OrderBASEDEVs,near
  assume          ds:nothing,es:nothing,ss:nothing
   EnterProc    <>                     ;allocate the local variables
   pusha
   DosInitContext <DS>,ax
   mov     es,Config_Sys_Data
   mov     di,es:[0].CFG_Basedev.CFG_Head  ;es:di ->first BASEDEV entry

   .if     <di eq 0>                   ;if no BASEDEV= entries
      jmp      OBD_x                   ; then leave
   .endif

   lea     si, BASEDEVOrderlist        ;ds:si ->current search prefix

   mov     bx, di                      ;es:bx ->place to insert entry
   mov     eax, ds:[si]

   .while  <eax ne 0>                  ;for each prefix
      push   si
      mov    di,bx                     ;place to start search (no need to
                                       ; look at those already sorted)
      .while   <di ne 0>               ;for each (remaining) BASEDEV= entry
         push   di
         mov    di,es:[di].CFG_FileSpec
         mov    edx,DWORD PTR es:[di]
         call   ToUpperEDX
         ;find suffix (with .), put in EDX
         .while  <dl ne '.'> and       ;stop if found "."
         .while  <dl ne 0>             ;or end of string
            inc    di                  ; get next 4 characters
            mov    edx,DWORD PTR es:[di]
            call   ToUpperEDX
         .endwhile
         pop     di
         .if     <eax eq edx>

             call   RelinkBASEDEVs

         .endif
         mov      di,es:[di].CFG_Next  ;now check next BASEDEV= entry
      .endwhile
      pop    si
      add    si,4
      mov    eax,ds:[si]               ;now check next prefix
   .endwhile

   .if <bx ne 0>                       ;BASEDEV entries left over?
      mov  di,es:[bx].CFG_Prev
      mov  es:[di].CFG_Next,0               ;remove them from the list
      mov  es:[0].CFG_Basedev.CFG_Tail,di   ;reset tail
      mov  di,bx

       mov    InvalidDD_var1.Segmt,es
      .while <nonzero di>                   ;put up error msg for each one
          mov    si, es:[di].CFG_FileSpec
          mov    InvalidDD_var1.Offst,si
          mov    si,offset InvalidDD
          call   syiDisplayMessage

          mov      di,es:[di].CFG_Next  ;now check next BASEDEV= entry
      .endwhile
   .endif

OBD_x:
   popa
   LeaveProc                           ;deallocate the local variables
   ret
EndProc OrderBASEDEVs


; Subroutine Name:      RelinkBASEDEVs
;
; Descriptive Name:     Sort BASEDEV= statements to get correct load order
;
; Function:     Sort the BASEDEV= statements to put the device drivers
;               in the correct load order, by suffix.
;
;
; Entry Point:  RelinkBASEDEVs in DOSCODE
;     Linkage:  Call (near, protect mode)
;
; Entry:        es:di -> entry to be moved
;               es:bx -> place to move entry
;
; Exit-Normal:  list reordered. CFG_Head and CFG_Tail are changed if
;               necessary.  BX changed if necessary.
;
; Exit-Error:   none
;
; Effects:      preserves ES, DI.  Other registers may be changed.
;
; Internal References:
;   Routines:   none
;
; External References:
;   Routines:   none
;
;

Procedure RelinkBASEDEVs,near
  assume          ds:nothing,es:nothing,ss:nothing
   EnterProc    <>                     ;allocate the local variables

   .if <di eq bx>                      ;It's in the right place
       .if <di ne 0>
          mov  bx,es:[di].CFG_Next     ;make BX point to next entry.
       .endif
       jmp RLBD_x
   .endif

 ; Take it out of list, either in middle or at tail.  Never take it from
 ; where bx points, because that's where we'd put it (This includes
 ; bx=CFG_Head).  The "if di eq bx" will catch that condition.

   mov    si,es:[di].CFG_Prev
   mov    cx,es:[di].CFG_Next
   mov    es:[si].CFG_Next,cx          ;make prev entry point around this one
   xchg   si,cx
   .if <si ne 0>                       ;is there a Next entry?
        mov    es:[si].CFG_Prev,cx     ; yes, make it's prev entry point around
   .else                               ; this entry
        mov    es:[0].CFG_Basedev.CFG_Tail,si ; no, adjust tail pointer
   .endif

 ; Add at head or in middle.  Never add at tail because that would be where
 ; we would have removed it from.  The "if di eq bx" will catch that
 ; condition.

   mov    cx,es:[0].CFG_Basedev.CFG_Head
   .if <cx eq bx>                      ;adding at head?
      mov   es:[0].CFG_Basedev.CFG_Head,di  ; reset head
      mov   es:[di].CFG_Prev,0
      mov   es:[di].CFG_Next,bx
      mov   es:[bx].CFG_Prev,di
   .else                               ;adding in middle
      mov   si,es:[bx].CFG_Prev
      mov   es:[di].CFG_Next,bx        ;adjust pointers in this entry
      mov   es:[di].CFG_Prev,si

      mov   es:[bx].CFG_Prev,di        ;make next entry's "prevptr" point here
      mov   es:[si].CFG_Next,di        ;make prev entry's "nextptr" point here
   .endif


RLBD_x:
   LeaveProc                           ;deallocate the local variables
   ret
EndProc RelinkBASEDEVs


;
; Subroutine Name:      RMNotify
;
; Function:    Notify ResourceManager of a device driver event
;         AX=event
;                       20H - Register config.sys basedev list
;                               Passes RM parsed config.sys device structs
;                       21H - Retrieve device driver from Resource Manager
;                               Gets a ASCIIZ string for driver to be loaded
;
;                       40H - Base Device Driver will be loaded
;                               ES:DI - ASCIIZ Module name to be loaded
;                       41H - Base Device Driver failed to load
;                               Passes RM ASCIIZ string in var CurrentDev
;                       42H - Base Device Driver Installed
;                               Passes RM ASCIIZ string in var CurrentDev
;
;                       60H - Device Driver will be loaded
;                               ES:DI - ASCIIZ Module name to be loaded
;                       61H - Device Driver failed to load
;                               Passes RM ASCIIZ string in var CurrentDev
;                       62H - Device Driver Installed
;                               Passes RM ASCIIZ string in var CurrentDev
;
; 148754 reworked routine
Procedure RMNotify,faronly
assume          ds:nothing,es:nothing,ss:nothing
push    ds

.if < ax lt 40h >                       ; divide function numbers
  .if < ax eq 20h >             ; pass RM config list with es:di
    sub   si,si                 ; Send null Data pointer for IOCtl data
    mov   ds,si
  .endif
  CALLFAR RMNotifyWork          ; es:di-> ptr to parms ds:si-> ptr to data pkt
  .if < es:[bx].GIOFunction eq 21h >
    .if < es:[bx].PktStatus eq 100h >
      les   di,dword ptr es:[bx].GIOParaPack
    .endif
  .endif
.else                           ; do function 4xh and 6xh
  DosInitContext <DS>,bx
  SaveReg        <es,di>
  test  ax, 0Fh
  .if < Z >                             ; do function 40h and 60h
    mov     word ptr CurrentDev,di      ; save ASCIIZ of dd to be loaded for later
    mov     word ptr CurrentDev+2,es
  .else                                 ; else do functions 41h,42h,61h,62h
    mov     di,word ptr CurrentDev      ; Get ASCIIZ of dd saved from load notify
    mov     es,word ptr CurrentDev+2
  .endif
  sub   si,si                   ; Send null Data pointer for IOCtl data
  mov   ds,si
  CALLFAR RMNotifyWork          ; es:di-> ptr to parms ds:si-> ptr to data pkt
  RestoreReg    <di,es>
.endif

pop     ds
ret
EndProc RMNotify

;
; Subroutine Name:      Config_Dev_Insert
;
; Function:     Adds a new device driver structure in Config.sys chain
;
; Description:  ...
;               Copies the newly provide structure
;               Adjusts the pointer linkage and string pointers
;               Adjusts the Config_FreePtr
;
; Input:
;               ES:DI   -> points to the device struct to be added
;
;
; Output:
;               ES:DI   -> points to the newly created device struct
;
; 148754 added routine
;
Procedure ConfigDevCreate,faronly
   assume          ds:nothing,es:nothing,ss:nothing

   LocalVar     NewDevPkt,DWORD         ;Address of the new device packet (ES:DI)
   LocalVar     ParmOffset,WORD         ;Length of the ASCIIZ parameter string
   LocalVar     FileSpecOffset,WORD     ;Length of the ASCIIZ file spec string


   EnterProc <es,di>  ; Set up stack frame
   SaveReg      <ds,si>
   DosInitContext  ds
   mov          es,Config_Sys_Data
   lds          si,NewDevPkt            ;get pointer to new dev packet passed by Resource Mgr
;  assert ds:si is not null
   SaveReg      <ds,si>
   lds          si,ds:[si].pConfigFileSpec ;Move in file spec !!!??? should I check for 0?
   mov          di,es:[0].CFG_FreePtr   ;Get free area
   mov          FileSpecOffset,di       ;Save location of file spec
   .repeat                              ;Move ASCIIZ string into config space
     lodsb
     stosb
   .until  <zero al>
   RestoreReg   <si,ds>                 ;ds:si -> new dev packet passed by Resource Mgr
   mov          eax,ds:[si].pConfigParms;get pointer to parms string
   .if < nonzero eax >                  ;Do we have parms?
     SaveReg    <ds,si>
     push       eax
     pop        ds
     pop        si                      ;ds:si -> points to parm string
     mov        ParmOffset,di           ;Save offset of parm string
     .repeat                            ;Move ASCIIZ string into config space
       lodsb
       stosb
     .until  <zero al>
     RestoreReg <si,ds>                 ;ds:si -> new dev packet passed by Resource Mgr
   .else
     mov        ParmOffset,0            ;No Parms
   .endif
   inc          di                      ;Word align the free area
   and          di,not 1
   SaveReg      di                      ;save offset of this device struc for later
   add          di,size CFG_Packet3     ;Insert device packet struc into config space
   mov          ax,es:[0].CFG_FreePtr   ;get initial free pointer
   .if          <di b ax>               ;make sure we do not wrap the segment
     InternalError <Config_GetString Config_Sys_Data segment corrupted>
   .endif
   mov          es:[0].CFG_FreePtr,di   ;Update the free pointer with new device
   RestoreReg   di                      ;es:di -> the new device struc
   mov          eax,dword ptr ds:[si].ConfigLineNumber      ; Copy Line number from Resource Manager
   mov          dword ptr es:[di].CFG_LineNumber,eax
   mov          ax,word ptr ds:[si].ConfigLineNumber+4
   mov          word ptr es:[di].CFG_LineNumber+4,ax
   mov          dword ptr es:[di].CFG_Size,-1   ; do not allow size value
   mov          ax,FileSpecOffset               ; get File Spec Offset
   mov          es:[di].CFG_FileSpec,ax         ; Save it
   mov          ax,ParmOffset                   ; get Parameters Offset
   mov          es:[di].CFG_Parameters,ax       ; Save it
   RestoreReg <si,ds>
   LeaveProc
ret
EndProc ConfigDevCreate


;
; Subroutine Name:      ToUpperEDX
;
; Function:     Convert characters in EDX to upper case.
;
;
;

Procedure ToUpperEDX,near
   assume          ds:nothing,es:nothing,ss:nothing
   push   cx
   mov    cx,4

tu_top:
      .if   <dl ge 'a'> and
      .if   <dl le 'z'>
          sub  dl,'a'
          add  dl,'A'
      .endif
      ror edx,8
   loop tu_top

   pop    cx
   ret
EndProc ToUpperEDX


; 150691 begin
;
; SUBROUTINE NAME: CheckCmdLine
;
; DESCRIPTIVE NAME: Check for command line
;
; FUNCTION:      Get Command Line for Internal Base Device Driver List
;		  Resource.sys /SL:[N,0,1,2,3,4]
;
; NOTES:
;
; ENTRY POINT: CheckCmdLine
;    LINKAGE:    Call (near)
;
; INPUT:	DS:SI = pCmdline	
;               ES:DI = filename
;
; 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 CheckCmdLine,near
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing

        SaveReg <es,di>

;       Copy the file specification from the data packet

        xor     ax,ax		; DS:SI = pCmdline	
	mov	ds:[si+2],ax	; Initialize pCmdLine to Null
	mov	ds:[si],ax
;
; 	Check for match -  RESOURCE.SYS
;
	SaveReg <ds,si>
	cld
        DosInitContext  ds
	lea	si,RESOURCESYS
	mov     cx,-1
	repnz   scasb
	not     cx
	sub     di,cx
	repz    cmpsb
        RestoreReg <si,ds>
	jne	CheckCmdLine_Return
	or	ax,ax
	jnz	CheckCmdLine_Return
;
; 	Match found - RESOURCE.SYS
;	Return the command line
;
	mov	ax, seg RMSysCmdLine
	mov	ds:[si+2],ax
        mov	ax, offset RMSysCmdLine
	mov	ds:[si],ax

;       Return to caller
CheckCmdLine_Return:

        RestoreReg <di,es>
        ret

EndProc CheckCmdLine
; 150691 end


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Subroutine Name       :   DisplayLoadMsg
;
; Input                 :   es:di file name
;                           ax == 1: use MsgLoading
;                           ax == 2: use MsgDoneLoading
; Description           :   The file name in (es:di) is appended to the strings
;                           MsgLoading and MsgDoneLoading at offsets indicated
;                           by Msg(Done)LoadingLen var ; if called with param 1
;                           If Param is 1 then the message MsgLoading is
;                           displayed.
;                           Uses Int 10 write routine to write (in REAL MODE).
;                           For param 2, the message set up earlier is used.
;                           The location on the screen is based of the var
;                           dologo that has been set in bitmap.asm.
;
; Functions called      :   RealModeIC
;                           ProtmodeIC
;                           DHF.DosHlpCallInt10
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Procedure DisplayLoadMsg, near
    LocalVar    LineNumber,DWORD
    EnterProc           <>
    assume              ds:nothing, es:nothing, ss:nothing
    SaveReg     <ebp, ecx, ebx, edx, es, di, ds>

    DosInitContext  ds
    DosContext      fs
    .if <ax e 1>
       mov      si, offset MsgLoading
       mov      cx, MSG_LENGTH
       mov      dx, cx
       sub      cx, MsgLoadingLen       ;length remaining
       add      si, MsgLoadingLen       ;ds:si -> End of message string1
       mov      bx, offset MsgDoneLoading
       sub      dx, MsgDoneLoadingLen
       add      bx, MsgDoneLoadingLen   ;ds:bx -> End of message string2
       xchg     si, di                  ;set up source/dest addresses
;      xchg     es, ds
       push     es                      ; in lieu of xchg ds, es
       push     ds
       pop      es
       pop      ds

;;;;;; Cat the Filename to both messages

      .repeat                           ; es:di ->msg1; ds:si-> DDFileName
         lodsb
         stosb
         mov    es:[bx], al             ;es:[bx] -> msg2
         inc    bx
         dec    cx
         dec    dx
      .until <zero al>

;;;;;; Zero fill the rest of the message strings
         rep stosb                      ;Zero fill Msg1

         mov    di,bx                   ;es:di points to the second msg tail
         mov    cx,dx                   ;set up the length
         rep stosb                      ;Zero fill second message


;;;;;; Setup the Text pointer for INT10 call

       DosInitContext   ds
       mov      bx, offset MsgLoading
    .else
       mov      bx, offset MsgDoneLoading
    .endif
    DosInitContext  es                  ; es:bx ->start of message

; Now set up the line number to display the messages
    FlatContext         gs
    mov         LineNumber, (MSGLINE_NO1*0100h) + 0;
    test        dologo, 0FFh            ; Check for screen size
    jnz         no_logo_msg             ;
    mov         LineNumber, (MSGLINE_NO2*0100h) +0

no_logo_msg:

    NullContext gs                      ;to fix masm err! Uses gs for DosContext
    call        RealModeIC              ;put the cpu in real mode
    mov         cx, MSG_LENGTH -1       ; length of msg string
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;Need fixing
    mov         edx, LineNumber         ; set up the line number/cursor param
    mov         bp, bx                  ; start of message
    mov         ebx, 07h                ; bl-attribute; bh-page
    mov         eax, 1301h              ; ah (13h) function; al(01) move cursor


    DosContext  fs
    call        DHF.DosHlpCallInt10     ;call display routine

    call        ProtModeIC              ;reset mode

    RestoreReg  <ds, di, es, edx, ebx, ecx, ebp >
    LeaveProc
    ret

EndProc  DisplayLoadMsg


INITCODE ends

        end
