summaryrefslogtreecommitdiffstats
path: root/private/mvdm/softpc.new/bios
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/mvdm/softpc.new/bios
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to '')
-rw-r--r--private/mvdm/softpc.new/bios/biosbop.inc10
-rw-r--r--private/mvdm/softpc.new/bios/biosseg.inc39
-rw-r--r--private/mvdm/softpc.new/bios/biostruc.inc101
-rw-r--r--private/mvdm/softpc.new/bios/devmark.inc24
-rw-r--r--private/mvdm/softpc.new/bios/dosmsg.cmd6
-rw-r--r--private/mvdm/softpc.new/bios/makefile102
-rw-r--r--private/mvdm/softpc.new/bios/msbio.cl362
-rw-r--r--private/mvdm/softpc.new/bios/msbio.cl46
-rw-r--r--private/mvdm/softpc.new/bios/msbio.cl57
-rw-r--r--private/mvdm/softpc.new/bios/msbio.cl610
-rw-r--r--private/mvdm/softpc.new/bios/msbio.lnk3
-rw-r--r--private/mvdm/softpc.new/bios/msbio.skl95
-rw-r--r--private/mvdm/softpc.new/bios/msbio1.asm955
-rw-r--r--private/mvdm/softpc.new/bios/mschar.asm1078
-rw-r--r--private/mvdm/softpc.new/bios/msend.asm52
-rw-r--r--private/mvdm/softpc.new/bios/msequ.inc56
-rw-r--r--private/mvdm/softpc.new/bios/msgroup.inc18
-rw-r--r--private/mvdm/softpc.new/bios/msinit.asm288
-rw-r--r--private/mvdm/softpc.new/bios/msint13.asm214
-rw-r--r--private/mvdm/softpc.new/bios/ntio.symbin0 -> 3892 bytes
-rw-r--r--private/mvdm/softpc.new/bios/spcemm.asm167
-rw-r--r--private/mvdm/softpc.new/bios/spckbd.asm2141
-rw-r--r--private/mvdm/softpc.new/bios/spcmse.asm5412
-rw-r--r--private/mvdm/softpc.new/bios/sysconf.asm3972
-rw-r--r--private/mvdm/softpc.new/bios/sysimes.asm26
-rw-r--r--private/mvdm/softpc.new/bios/sysinit1.asm4007
-rw-r--r--private/mvdm/softpc.new/bios/sysinit2.asm1609
27 files changed, 20460 insertions, 0 deletions
diff --git a/private/mvdm/softpc.new/bios/biosbop.inc b/private/mvdm/softpc.new/bios/biosbop.inc
new file mode 100644
index 000000000..57ca401c1
--- /dev/null
+++ b/private/mvdm/softpc.new/bios/biosbop.inc
@@ -0,0 +1,10 @@
+
+bop MACRO callid
+ db 0c4h,0c4h,callid
+ endm
+
+BIOS_PRINTER_IO equ 17h
+PRNIO_EXECUTE equ -1
+PRNIO_FLUSH equ 0
+PRNIO_OPEN equ 1
+PRNIO_CLOSE equ 2
diff --git a/private/mvdm/softpc.new/bios/biosseg.inc b/private/mvdm/softpc.new/bios/biosseg.inc
new file mode 100644
index 000000000..9e2a54536
--- /dev/null
+++ b/private/mvdm/softpc.new/bios/biosseg.inc
@@ -0,0 +1,39 @@
+; BIOSSEG.INC
+;
+; This file defines the segment structure of the BIOS.
+; It should be included at the beginning of each source file.
+; All further segment declarations in the file can then be done by just
+; by specifying the segment name, with no attribute, class, or align type.
+
+
+datagrp group Bios_Data,Bios_Data_Init
+
+
+Bios_Data segment word public 'Bios_Data'
+Bios_Data ends
+
+Bios_Data_Init segment word public 'Bios_Data_Init'
+Bios_Data_Init ends
+
+Filler segment para public 'Filler'
+Filler ends
+
+Bios_Code segment word public 'Bios_Code'
+Bios_Code ends
+
+Filler2 segment para public 'Filler2'
+Filler2 ends
+
+sysinitgrp group sysinitseg, SpcKbdSeg, SpcMseSeg, SpcEmmSeg
+
+SysInitSeg segment word public 'system_init'
+SysInitSeg ends
+
+SpcKbdSeg segment para public 'SoftpcKeyboard'
+SpcKbdSeg ends
+
+SpcMseSeg segment para public 'SoftpcMouse'
+SpcMseSeg ends
+
+SpcEmmSeg segment para public 'SoftpcEmm'
+SpcEmmSeg ends
diff --git a/private/mvdm/softpc.new/bios/biostruc.inc b/private/mvdm/softpc.new/bios/biostruc.inc
new file mode 100644
index 000000000..5afb16ac9
--- /dev/null
+++ b/private/mvdm/softpc.new/bios/biostruc.inc
@@ -0,0 +1,101 @@
+; rom bios call packet structures
+
+;*******************************
+;system service call ( int 15h )
+;*******************************
+;function ah = 0c0h, return system configuration
+;for pc and pcjr on return:
+; (ah) = 80h
+; (cy) = 1
+;for pcxt, pc portable and pcat on return:
+; (ah) = 86h
+; (cy) = 1
+;for all others:
+; (ah) = 0
+; (cy) = 0
+; (es:bx) = pointer to system descriptor vector in ros
+; system descriptor :
+; dw xxxx length of descriptor in bytes,
+; minimum length = 8
+; db xx model byte
+; 0ffh = pc
+; 0feh = pc/xt, portable
+; 0fdh = pc/jr
+; 0fch = pc/at, 6mhz pc/at,
+; 6mhz pc/at running coprocessor(?),
+; ps/2 model 50, 50 z
+; 0fah = ps/2 model 25, 30
+; 0f9h = pc convertible
+; 0f8h = ps/2 model 80
+; 0f7h = nova
+; 0e0 thru 0efh = reserved
+;
+; db xx secondary model byte
+; 000h = pc1
+; 000h = pc/xt, portable
+; 000h = pc/jr
+; 000h = pc/at
+; 001h = 6mhz pc/at
+; 003h = 6mhz pc/at running coprocessor(?)
+; 004h = ps/2 model 50, 50z
+; 001h = ps/2 model 25
+; 000h = pc convertible
+; 000h = ps/2 model 80
+; 000h = nova
+;
+; db xx bios revision level
+; 00 for first release, subsequent release
+; of code with same model byte and
+; secondary model byte require revison level
+; to increase by one.
+;
+; db xx feature information byte 1
+; x0000000 = 1, bios use dma channel 3
+; = 0, dma channel 3 not used
+;
+; 0x000000 = 1, 2nd interrupt chip present
+; = 0, 2nd interrupt chip not present
+;
+; 00x00000 = 1, real time clock present
+; = 0, real time clock not present
+;
+; 000x0000 = 1, keyboard escape sequence(int15h)
+; called in keyboard interrupt
+; (int 09h).
+; = 0, keyboard escape sequence not
+; called.
+; 0000xxxx reserved
+;
+; db xx feature information byte 2 - reserved
+;
+; db xx feature information byte 2 - reserved
+;
+; db xx feature information byte 2 - reserved
+;
+; db xx feature information byte 2 - reserved
+;
+
+bios_system_descriptor struc
+bios_sd_leng dw ?
+bios_sd_modelbyte db ?
+bios_sd_scnd_modelbyte db ?
+ db ?
+bios_sd_featurebyte1 db ?
+ db 4 dup (?)
+bios_system_descriptor ends
+
+;featurebyte1 bit map equates
+dmachannel3 equ 10000000b
+scndintcontroller equ 01000000b
+realtimeclock equ 00100000b
+keyescapeseq equ 00010000b
+;
+;model byte
+mdl_pc1 equ 0ffh
+mdl_xt equ 0feh
+mdl_jr equ 0fdh
+mdl_at equ 0fch
+mdl_convert equ 0f9h
+
+mdl_ps2_30 equ 0fah
+mdl_ps2_80 equ 0f8h
diff --git a/private/mvdm/softpc.new/bios/devmark.inc b/private/mvdm/softpc.new/bios/devmark.inc
new file mode 100644
index 000000000..4b55e6ad8
--- /dev/null
+++ b/private/mvdm/softpc.new/bios/devmark.inc
@@ -0,0 +1,24 @@
+;structure, equtes for devmark for mem command.
+
+devmark struc
+devmark_id db 0
+devmark_seg dw 0
+devmark_size dw 0
+devmark_dum db 3 dup (?)
+devmark_filename db 8 dup (' ')
+devmark ends
+
+devmark_stk equ 'S'
+devmark_device equ 'D'
+devmark_ifs equ 'I'
+devmark_buf equ 'B'
+devmark_cds equ 'L' ;lastdrive
+devmark_files equ 'F'
+devmark_fcbs equ 'X'
+devmark_inst equ 'T' ;used for sysinit base for install= command.
+
+devmark_spc equ 'Q' ;used for spckbd,spcmse
+
+setbrkdone equ 00000001b
+for_devmark equ 00000010b
+not_for_devmark equ 11111101b
diff --git a/private/mvdm/softpc.new/bios/dosmsg.cmd b/private/mvdm/softpc.new/bios/dosmsg.cmd
new file mode 100644
index 000000000..daa8f6150
--- /dev/null
+++ b/private/mvdm/softpc.new/bios/dosmsg.cmd
@@ -0,0 +1,6 @@
+cd ..\messages
+chmode -r %2
+..\tools\buildidx %2
+chmode +r %2
+cd ..\bios
+..\tools\nosrvbld %1 ..\messages\%2
diff --git a/private/mvdm/softpc.new/bios/makefile b/private/mvdm/softpc.new/bios/makefile
new file mode 100644
index 000000000..b2e879795
--- /dev/null
+++ b/private/mvdm/softpc.new/bios/makefile
@@ -0,0 +1,102 @@
+#************************** makefile for NTIO.SYS ***************************
+
+include ..\..\make.inc
+
+tpath =..\..\tools
+lpath =..\..\..\..\tools.os2
+
+dest =ntio.sys
+
+#
+####################### dependencies begin here. #########################
+#
+
+
+all: $(dest)
+ binplace $(dest)
+ binplace ntio.sym
+
+inc.lst: inc.asm
+
+clean:
+ if exist *.obj del *.obj
+ if exist *.exe del *.exe
+ if exist *.map del *.map
+ if exist *.sym del *.sym
+ if exist msbio.cl? del msbio.cl?
+ if exist ntio.sys del ntio.sys
+
+msbio.cl1: msbio.skl \
+ $(msg)\$(COUNTRY).msg
+
+msbio1.obj msbio1.lst: msbio1.asm $(inc)\msbdata.inc \
+ $(inc)\devsym.inc msequ.inc $(cinc)\vint.inc
+
+mschar.obj mschar.lst: mschar.asm biosbop.inc $(inc)\devsym.inc \
+ $(inc)\ioctl.inc msequ.inc msgroup.inc $(cinc)\vint.inc
+
+
+msend.obj msend.lst: msend.asm
+
+msinit.obj msinit.lst: msinit.asm $(inc)\VERSIONA.inc \
+ $(inc)\dbcs.sw $(inc)\dirent.inc $(inc)\dosmac.inc $(inc)\dosmac.inc \
+ $(inc)\dossym.inc $(inc)\error.inc $(inc)\version.inc biostruc.inc \
+ msequ.inc msgroup.inc $(cinc)\dossvc.inc $(cinc)\vint.inc
+
+msint13.obj msint13.lst: msint13.asm biostruc.inc $(cinc)\vint.inc \
+ msequ.inc msgroup.inc
+
+
+sysconf.obj sysconf.lst: sysconf.asm $(inc)\doscntry.inc \
+ $(inc)\parse.asm $(inc)\psdata.inc $(inc)\smifssym.inc \
+ $(inc)\syscall.inc $(inc)\sysvar.inc $(inc)\version.inc devmark.inc \
+ $(inc)\devsym.inc $(cinc)\dossvc.inc $(cinc)\cmdsvc.inc
+
+sysimes.obj sysimes.lst: sysimes.asm
+
+spckbd.obj spckbd.lst: spckbd.asm $(cinc)\vint.inc
+
+spcmse.obj spcmse.lst: spcmse.asm $(cinc)\vint.inc
+
+spcemm.obj spcemm.lst: spcemm.asm $(cinc)\vint.inc
+
+sysinit1.obj sysinit1.lst: sysinit1.asm $(inc)\VERSIONA.inc \
+ $(inc)\arena.inc $(inc)\buffer.inc $(inc)\cputype.inc \
+ $(cinc)\curdir.inc $(inc)\dbcs.sw $(inc)\dirent.inc $(inc)\dosmac.inc \
+ $(inc)\dossym.inc $(inc)\error.inc $(inc)\exe.inc \
+ $(inc)\pdb.inc $(inc)\sf.inc $(inc)\smifssym.inc $(inc)\syscall.inc \
+ $(inc)\sysvar.inc $(inc)\version.inc biostruc.inc $(cinc)\vint.inc \
+ devmark.inc $(inc)\devsym.inc $(inc)\ioctl.inc $(cinc)\dossvc.inc \
+ $(cinc)\cmdsvc.inc
+
+sysinit2.obj sysinit2.lst: sysinit2.asm $(inc)\copyrigh.inc \
+ $(inc)\doscntry.inc $(inc)\syscall.inc $(inc)\version.inc \
+ devmark.inc $(inc)\devsym.inc $(inc)\ioctl.inc
+
+$(dest): msbio.cl1 msbio1.obj mschar.obj msint13.obj msinit.obj \
+ sysinit1.obj spckbd.obj spcmse.obj spcemm.obj sysconf.obj \
+ sysinit2.obj sysimes.obj msend.obj msbio.lnk
+!IFDEF NTVDM_BASED_BUILD
+ link16 $(link_opts) @msbio.lnk
+!ELSE
+ $(lpath)\link $(link_opts) @msbio.lnk
+!ENDIF
+ mapsym ntio
+!IFDEF NTVDM_BASED_BUILD
+ reloc ntio.exe $(dest) 70
+!ELSE
+ $(tpath)\reloc ntio.exe $(dest) 70
+!ENDIF
+ del ntio.exe
+
+# sudeepb 04-Mar-1991 : NT Message file handling for DOSEm.
+#
+# Many of the above .asm files needed for NTIO.SYS include "message class"
+# files (i.e. msbio.cl3 etc.). These files have the message strings extracted
+# from msbio.skl and internationalized using ..\messages\<COUNTRY>.msg file.
+# The utilities needed for getting these *.cl? files from *.skl and *.msg
+# files are all real mode, hence their building rules are not included in
+# this makefile. Use dosmsg.bat command from 3xbox to build these *.cl? files.
+# syntax for dosmsg.bat is "dosmsg <file>.skl <country>.msg". For example
+# building *.cl> files for bios for usa version, the command will be
+# "dosmsg msbio.skl usa-ms.msg"
diff --git a/private/mvdm/softpc.new/bios/msbio.cl3 b/private/mvdm/softpc.new/bios/msbio.cl3
new file mode 100644
index 000000000..09b8ae4e5
--- /dev/null
+++ b/private/mvdm/softpc.new/bios/msbio.cl3
@@ -0,0 +1,62 @@
+; msbio.cl3
+
+
+;_______________________
+
+BADOPM DB 13,10,"Unrecognized command in CONFIG.SYS"
+
+;_______________________
+
+CRLFM DB 13,10,"$"
+
+;_______________________
+
+BadParm DB 13,10,"Bad command or parameters - $"
+
+;_______________________
+
+BADSIZ_PRE DB 13,10,"Sector size too large in file $"
+
+;_______________________
+
+BADLD_PRE DB 13,10,"Bad or missing $"
+
+;_______________________
+
+BADCOM DB "Command Interpreter",0
+
+;_______________________
+
+BADCOUNTRY DB 13,10,"Invalid country code or code page",13,10,"$"
+
+;_______________________
+
+BADCOUNTRYCOM DB 13,10,"Error in COUNTRY command",13,10,"$"
+
+;_______________________
+
+INSUFMEMORY DB 13,10, "Insufficient memory for COUNTRY.SYS file",13,10,"$"
+
+;_______________________
+
+BADMEM DB 13,10,"Configuration too large for memory",13,10,"$"
+
+;_______________________
+
+BADBLOCK DB 13,10,"Too many block devices",13,10,"$"
+
+;_______________________
+
+BADSTACK DB 13,10,"Invalid STACK parameters",13,10,"$"
+
+;_______________________
+
+BADORDER DB 13,10,"Incorrect order in CONFIG.SYS line ","$"
+
+;_______________________
+
+ERRORCMD DB "Error in CONFIG.SYS line ","$"
+
+;_______________________
+
+toomanydrivesmsg DB "WARNING! Logical drives past Z: exist and will be ignored",13,10,"$"
diff --git a/private/mvdm/softpc.new/bios/msbio.cl4 b/private/mvdm/softpc.new/bios/msbio.cl4
new file mode 100644
index 000000000..546f30ae9
--- /dev/null
+++ b/private/mvdm/softpc.new/bios/msbio.cl4
@@ -0,0 +1,6 @@
+; msbio.cl4
+
+
+;_______________________
+
+Mem_alloc_err DB 13,10,"Memory allocation error ","$"
diff --git a/private/mvdm/softpc.new/bios/msbio.cl5 b/private/mvdm/softpc.new/bios/msbio.cl5
new file mode 100644
index 000000000..ca3ebdece
--- /dev/null
+++ b/private/mvdm/softpc.new/bios/msbio.cl5
@@ -0,0 +1,7 @@
+; msbio.cl5
+
+
+;_______________________
+
+FATAL_MSG DB 0DH,0AH,7,0DH,0AH, "Internal stack overflow",0DH,0AH
+ DB "System halted",0DH,0AH,"$"
diff --git a/private/mvdm/softpc.new/bios/msbio.cl6 b/private/mvdm/softpc.new/bios/msbio.cl6
new file mode 100644
index 000000000..401af43a9
--- /dev/null
+++ b/private/mvdm/softpc.new/bios/msbio.cl6
@@ -0,0 +1,10 @@
+; msbio.cl6
+
+
+;_______________________
+
+DOSLOMSG DB "HMA not available : Loading DOS low",13,10,"$"
+
+;_______________________
+
+FEMSG DB "Fatal Error:Cannot allocate Memory for DOS", 13, 10, "$"
diff --git a/private/mvdm/softpc.new/bios/msbio.lnk b/private/mvdm/softpc.new/bios/msbio.lnk
new file mode 100644
index 000000000..425da9c1b
--- /dev/null
+++ b/private/mvdm/softpc.new/bios/msbio.lnk
@@ -0,0 +1,3 @@
+msbio1+mschar+msint13+spckbd+spcmse+spcemm+
+msinit+sysinit1+sysconf+sysinit2+sysimes+
+msend,ntio.exe,ntio.map;
diff --git a/private/mvdm/softpc.new/bios/msbio.skl b/private/mvdm/softpc.new/bios/msbio.skl
new file mode 100644
index 000000000..3636eba2d
--- /dev/null
+++ b/private/mvdm/softpc.new/bios/msbio.skl
@@ -0,0 +1,95 @@
+;==============================================================================
+;REVISION HISTORY:
+;==============================================================================
+
+;==================
+:class 3
+;==================
+
+; displayed when there is a bad command in CONFIG.SYS. '$' TERMINATED, note
+; that this message includes crlfm!
+
+:def 03 BADOPM DB 13,10,"Unrecognized command in CONFIG.SYS"
+:def 04 CRLFM DB 13,10,'$'
+:def 22 BadParm db 13,10,"Bad command or parameters - $"
+
+;displayed when installed device specifies too large a sector size.'$' terminated.
+; FORM: <BADSIZ_PRE>device name<BADSIZ_POST>
+:def 05 BADSIZ_PRE DB 13,10,"Sector size too large in file $"
+
+;displayed when installed device cannot be found. '$' terminated.
+; FORM: <BADLD_PRE>device name<BADLD_POST>
+:def 06 BADLD_PRE DB 13,10,"Bad or missing $"
+
+;displayed when command interpreter is not found. NUL terminated.
+; FORM: <BADLD_PRE><BADCOM><BADLD_POST>
+:def 07 BADCOM DB "Command Interpreter",0
+
+;displayed when country code, code page combination was not found in country.sys file. '$' terminated.
+; FORM: <BADCOUNTRY>
+:def 08 BADCOUNTRY DB 13,10,"Invalid country code or code page",13,10,"$"
+
+;displayed when code page id is missing or wrong syntax.
+; FORM: <BADCOUNTRYCOM>
+:def 09 BADCOUNTRYCOM DB 13,10,"Error in COUNTRY command",13,10,"$"
+
+;displayed when the memory left is not sufficient to handle COUTRY.SYS file
+; FORM: <INSUFMEMORY>
+:def 10 INSUFMEMORY DB 13,10, "Insufficient memory for COUNTRY.SYS file",13,10,"$"
+
+; displayed when there is insufficient memory. '$' TERMINATED, note
+; that this message includes crlfm!
+:def 11 BADMEM DB 13,10,"Configuration too large for memory",13,10,"$"
+
+; displayed when the attempt is made to install a block device which would
+; have a drive letter > 'Z'
+:def 12 BADBLOCK DB 13,10,"Too many Block Devices",13,10,"$"
+
+; displayed when the attempt is made to install a stack with invalid
+; combinations of # of stacks, stack size.
+:def 13 BADSTACK DB 13,10,"Invalid STACK parameters",13,10,"$"
+
+; - displayed when encountering a command that is not "install=" after
+; we had a "Install=" command.
+; Translation::: Please leave the last blank space at the end of the line
+; as it is.
+:def 14 BADORDER DB 13,10,"Incorrect order in CONFIG.SYS line ","$"
+
+; - displayed when the command failed.
+; Translation::: Please leave the last blank space at the end of the line
+; as it is.
+:def 15 ERRORCMD DB "Error in CONFIG.SYS line ","$"
+
+; displayed when more than 24 fixed disk partitions are found ; M029
+:def 24 toomanydrivesmsg db "WARNING! Drives past Z: exist and will be ignored" ; M029
+
+;==================
+:class 4
+;==================
+;MSBIO SYSINIT
+;Message for SYSINIT_BASE program.
+:def 16 Mem_alloc_err db 13,10,"Memory allocation error","$"
+
+
+;==================
+:class 5
+;==================
+
+; PUBLIC FATAL_MSG
+:def 17 FATAL_MSG DB 0DH,0AH,7,0DH,0AH
+ DB "Internal stack overflow",0DH,0AH
+ DB "System halted",0DH,0AH,"$"
+;
+;==================
+:class 6
+;==================
+
+; - displayed when DOS loads due to non-availability of HMA.
+;
+:def 18 DOSLOMSG DB "HMA not available : Loading DOS low", 13, 10, "$"
+:def 23 FEMSG DB "Fatal Error:Cannot allocate Memory for DOS", 13, 10, "$"
+
+
+;:END
+
+
diff --git a/private/mvdm/softpc.new/bios/msbio1.asm b/private/mvdm/softpc.new/bios/msbio1.asm
new file mode 100644
index 000000000..e115bd0d0
--- /dev/null
+++ b/private/mvdm/softpc.new/bios/msbio1.asm
@@ -0,0 +1,955 @@
+ page ,160
+ title msbio1.asm - Bios_Data definition and device driver entry/exit
+
+;
+;----------------------------------------------------------------------------
+;
+; Modification history
+;
+; 26-Feb-1991 sudeepb Ported for NT DOSEm
+;
+;----------------------------------------------------------------------------
+;
+ include version.inc ; set build flags
+ include biosseg.inc ; define BIOS segments
+
+ include devsym.inc
+ include msequ.inc
+ include vint.inc
+
+
+; Assembly conditional for stack switching
+;
+STACKSW equ 1
+
+Bios_Data segment
+
+ assume cs:Bios_Data
+ public BData_start
+BData_start:
+
+
+ assume ds:nothing,es:nothing
+
+ public hdrv_pat
+hdrv_pat label word ; patched by msinit
+ assume cs:Bios_Data
+
+ extrn init:near ; this is in msinit
+
+ jmp init ; go to initialization code
+
+
+; define some stuff that is also used by msdos.sys from an include file
+
+In_Bios = 0ffffh ; define flag for msbdata.inc
+ include msbdata.inc
+
+
+ public inHMA,xms
+inHMA db 0 ; flag indicates we're running from HMA
+xms dd 0 ; entry point to xms if above is true
+
+ align 4
+
+ public ntvdmstate
+ntvdmstate dd 0
+IF 2
+.errnz ntvdmstate-BData_start-FIXED_NTVDMSTATE_OFFSET
+ENDIF
+
+
+ public ptrsav
+ptrsav dd 0
+
+ public auxbuf
+auxbuf db 0,0,0,0 ;set of 1 byte buffers for com 1,2,3, and 4
+ public zeroseg
+zeroseg dw 0 ; easy way to load segment registers with zero
+
+ public auxnum
+auxnum dw 0 ;which aux device was requested
+
+
+ public res_dev_list
+
+res_dev_list label byte
+ p_attr = chardev+outtilbusy+dev320+IOQUERY+DEVOPCL
+; ** p_attr = chardev+outtilbusy+dev320
+
+ sysdev <auxdev2,8013h,strategy,con_entry,'CON '>
+auxdev2 sysdev <prndev2,8000h,strategy,aux0_entry,'AUX '>
+prndev2 sysdev <timdev,p_attr,strategy,prn0_entry,'PRN '>
+timdev sysdev <com1dev,8008h,strategy,tim_entry,'CLOCK$ '>
+com1dev sysdev <lpt1dev,8000h,strategy,aux0_entry,'COM1 '>
+lpt1dev sysdev <lpt2dev,p_attr,strategy,prn1_entry,"LPT1 ">
+lpt2dev sysdev <lpt3dev,p_attr,strategy,prn2_entry,"LPT2 ">
+lpt3dev sysdev <com2dev,p_attr,strategy,prn3_entry,"LPT3 ">
+com2dev sysdev <com3dev,8000h,strategy,aux1_entry,"COM2 ">
+com3dev sysdev <com4dev,8000h,strategy,aux2_entry,"COM3 ">
+com4dev dw -1,Bios_Data,8000h,strategy,aux3_entry
+ db "COM4 "
+
+
+ public RomVectors
+RomVectors label byte
+ public Old10, Old15, Old19, Old1B
+ db 10h ; M028
+Old10 dd (?) ; M028
+ db 15h
+Old15 dd (?)
+ db 19h
+Old19 dd (?)
+ db 1bh
+Old1B dd (?)
+EndRomVectors equ $
+ public NUMROMVECTORS
+NUMROMVECTORS equ ((EndRomVectors - RomVectors)/5)
+
+ public spc_mse_int10
+spc_mse_int10 dd (?)
+
+ public int29Perf
+int29Perf dd (?)
+
+
+ public keyrd_func
+ public keysts_func
+
+; moved altah to inc\msbdata.inc so it could go in instance table in DOS
+
+keyrd_func db 0 ; default is conventional keyboard read
+keysts_func db 1 ; default is conventional keyboard status check.
+
+ public printdev
+printdev db 0 ; index into above array
+
+ public multrk_flag
+multrk_flag dw 0
+
+; the following variable can be modified via ioctl sub-function 16. in this
+; way, the wait can be set to suit the speed of the particular printer being
+; used. one for each printer device.
+
+ public wait_count
+wait_count dw 4 dup (50h) ; array of retry counts for printer
+
+ public int19sem
+int19sem db 0 ; indicate that all int 19
+ ; initialization is complete
+
+; we assume the following remain contiguous and their order doesn't change
+i19_lst:
+ irp aa,<02,08,09,0a,0b,0c,0d,0e,70,72,73,74,76,77>
+ public int19old&aa
+ db aa&h ; store the number as a byte
+int19old&aa dd -1 ;orignal hardware int. vectors for int 19h.
+ endm
+
+num_i19 = ((offset $) - (offset i19_lst))/5
+
+
+;variables for dynamic relocatable modules
+;these should be stay resident.
+
+ public int6c_ret_addr
+int6c_ret_addr dd ? ; return address from int 6c for p12 machine
+
+;
+; data structures for real-time date and time
+;
+ public bin_date_time
+ public month_table
+ public daycnt2
+ public feb29
+
+bin_date_time:
+ db 0 ; century (19 or 20) or hours (0-23)
+ db 0 ; year in century (0...99) or minutes (0-59)
+ db 0 ; month in year (1...12) or seconds (0-59)
+ db 0 ; day in month (1...31)
+
+month_table:
+ dw 0 ; january
+ dw 31 ; february
+ dw 59
+ dw 90
+ dw 120
+ dw 151
+ dw 181
+ dw 212
+ dw 243
+ dw 273
+ dw 304
+ dw 334 ; december
+daycnt2 dw 0000 ; temp for count of days since 1-1-80
+feb29 db 0 ; february 29 in a leap year flag
+
+
+;************************************************************************
+;* *
+;* entry points into Bios_Code routines. The segment values *
+;* are plugged in by seg_reinit. *
+;* *
+;************************************************************************
+
+ public cdev
+cdev dd chardev_entry
+bcode_i2f dd i2f_handler
+end_BC_entries:
+
+;************************************************************************
+;* *
+;* cbreak - break key handling - simply set altah=3 and iret *
+;* *
+;************************************************************************
+
+ public cbreak
+cbreak proc near
+ assume ds:nothing,es:nothing
+
+ mov altah,3 ;indicate break key set
+
+ public intret ; general purpose iret in the Bios_Data seg
+intret:
+ FIRET
+cbreak endp
+
+;************************************************************************
+;* *
+;* strategy - store es:bx (device driver request packet) *
+;* away at [ptrsav] for next driver function call *
+;* *
+;************************************************************************
+
+ public strategy
+strategy proc far
+ assume ds:nothing,es:nothing
+
+ mov word ptr cs:[ptrsav],bx
+ mov word ptr cs:[ptrsav+2],es
+ ret
+strategy endp
+
+;************************************************************************
+;* *
+;* device driver entry points. these are the initial *
+;* 'interrupt' hooks out of the device driver chain. *
+;* in the case of our resident drivers, they'll just *
+;* stick a fake return address on the stack which *
+;* points to dispatch tables and possibly some unit *
+;* numbers, and then call through a common entry point *
+;* which can take care of a20 switching *
+;* *
+;************************************************************************
+
+con_entry proc near
+ assume ds:nothing,es:nothing
+
+ call cdev_entry ; call into code segment handler
+ dw con_table
+
+con_entry endp
+
+;--------------------------------------------------------------------
+
+prn0_entry proc near
+ assume ds:nothing,es:nothing
+
+ call cdev_entry
+ dw prn_table
+ db 0,0 ; device numbers
+
+prn0_entry endp
+
+;--------------------------------------------------------------------
+
+prn1_entry proc near
+ assume ds:nothing,es:nothing
+
+ call cdev_entry
+ dw prn_table
+ db 0,1
+
+prn1_entry endp
+
+;--------------------------------------------------------------------
+
+prn2_entry proc near
+ assume ds:nothing,es:nothing
+
+ call cdev_entry
+ dw prn_table
+ db 1,2
+
+prn2_entry endp
+
+;--------------------------------------------------------------------
+
+prn3_entry proc near
+ assume ds:nothing,es:nothing
+
+ call cdev_entry
+ dw prn_table
+ db 2,3
+
+prn3_entry endp
+
+;--------------------------------------------------------------------
+
+aux0_entry proc near
+ assume ds:nothing,es:nothing
+
+ call cdev_entry
+ dw aux_table
+ db 0
+
+aux0_entry endp
+
+;--------------------------------------------------------------------
+
+aux1_entry proc near
+ assume ds:nothing,es:nothing
+
+ call cdev_entry
+ dw aux_table
+ db 1
+
+aux1_entry endp
+
+;--------------------------------------------------------------------
+
+aux2_entry proc near
+ assume ds:nothing,es:nothing
+
+ call cdev_entry
+ dw aux_table
+ db 2
+
+aux2_entry endp
+
+;--------------------------------------------------------------------
+
+aux3_entry proc near
+ assume ds:nothing,es:nothing
+
+ call cdev_entry
+ dw aux_table
+ db 3
+
+aux3_entry endp
+
+;--------------------------------------------------------------------
+
+tim_entry proc near
+ assume ds:nothing,es:nothing
+
+ call cdev_entry
+ dw tim_table
+
+tim_entry endp
+
+;--------------------------------------------------------------------
+
+;************************************************************************
+;* *
+;* Ensure A20 is enabled before jumping into code in HMA. *
+;* This code assumes that if Segment of Device request packet is *
+;* DOS DATA segment then the Device request came from DOS & that *
+;* A20 is already on. *
+;* *
+;************************************************************************
+
+cdev_entry proc near
+ assume ds:nothing,es:nothing
+;
+; M064 - BEGIN
+;
+ cmp inHMA, 0
+ je ce_enter_codeseg; optimized for DOS in HMA
+
+ push ax
+ mov ax, DosDataSg
+ cmp word ptr [ptrsav+2], ax
+ pop ax
+ jne not_from_dos ; jump is coded this way to fall thru
+ ; in 99.99% of the cases
+ce_enter_codeseg:
+ jmp cdev
+not_from_dos:
+ call EnsureA20On
+;
+; M064 - END
+;
+ jmp short ce_enter_codeseg
+cdev_entry endp
+
+;************************************************************************
+;* *
+;* outchr - this is our int 29h handler. it writes the *
+;* character in al on the display using int 10h ttywrite *
+;* *
+;************************************************************************
+
+ public outchr
+outchr proc far
+ assume ds:nothing,es:nothing
+
+ push ax
+ push si
+ push di
+ push bp
+ push bx
+ mov ah,0eh ; set command to write a character
+ mov bx,7 ; set foreground color
+ int 10h ; call rom-bios
+ pop bx
+ pop bp
+ pop di
+ pop si
+ pop ax
+ jmp intret
+outchr endp
+
+; M001 - BEGIN
+
+;************************************************************************
+;* *
+;* EnsureA20On - ensure that a20 is enabled if we're running *
+;* in the HMA before interrupt entry points into Bios_Code *
+;* *
+;************************************************************************
+
+HiMem label dword
+ dw 90h
+ dw 0ffffh
+
+LoMem label dword
+ dw 80h
+ dw 0h
+
+EnsureA20On proc near
+ assume ds:nothing,es:nothing
+ call IsA20Off
+ jz ea_enable
+ ret
+
+EnableA20 proc near ; M041
+ea_enable:
+ push ax
+ push bx
+ mov ah,5 ; localenablea20
+ call xms
+ pop bx
+ pop ax
+bie_done:
+ ret
+EnableA20 endp ; M041
+
+EnsureA20On endp
+;
+; M001 - END
+
+; M041 : BEGIN
+;
+;----------------------------------------------------------------------------
+;
+; procedure : IsA20Off
+;
+;----------------------------------------------------------------------------
+;
+IsA20Off proc near
+ push ds
+ push es
+ push cx
+ push si
+ push di
+ lds si, HiMem
+ les di, LoMem
+ mov cx, 8
+ rep cmpsw
+ pop di
+ pop si
+ pop cx
+ pop es
+ pop ds
+ ret
+IsA20Off endp
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : DisableA20
+;
+;----------------------------------------------------------------------------
+;
+DisableA20 proc near
+ push ax
+ push bx
+ mov ah,6 ; localdisable a20
+ call xms
+ pop bx
+ pop ax
+ ret
+DisableA20 endp
+
+; M041 : END
+
+;************************************************************************
+;* *
+;* int19 - bootstrap interrupt -- we must restore a bunch of the *
+;* interrupt vectors before resuming the original int19 code *
+;* *
+;************************************************************************
+
+
+ public int19
+int19 proc far
+ assume ds:nothing,es:nothing
+
+ push cs
+ pop ds
+ assume ds:Bios_Data
+
+ mov es,zeroseg
+
+ mov cx, NUMROMVECTORS ; no. of rom vectors to be restored
+ mov si, offset RomVectors ; point to list of saved vectors
+next_int:
+ lodsb ; get int number
+ cbw ; assume < 128
+ shl ax, 1
+ shl ax, 1 ; int * 4
+ mov di, ax
+ lodsw
+ stosw
+ lodsw
+ stosw ; install the saved vector
+ loop next_int
+
+ cmp byte ptr int19sem,0 ; don't do the others unless we
+ jz doint19 ; set our initialization complete flag
+
+; stacks code has changed these hardware interrupt vectors
+; stkinit in sysinit1 will initialize int19holdxx values.
+
+ mov si,offset i19_lst
+ mov cx,num_i19
+
+i19_restore_loop:
+ lodsb ; get interrupt number
+ cbw ; assume < 128
+ mov di,ax ; save interrupt number
+ lodsw ; get original vector offset
+ mov bx,ax ; save it
+ lodsw ; get original vector segment
+ cmp bx,-1 ; check for 0ffffh (unlikely segment)
+ jz i19_restor_1 ;opt no need to check selector too
+ cmp ax,-1 ;opt 0ffffh is unlikely offset
+ jz i19_restor_1
+
+ add di,di
+ add di,di
+ xchg ax,bx
+ stosw
+ xchg ax,bx
+ stosw ; put the vector back
+
+i19_restor_1:
+ loop i19_restore_loop
+
+doint19:
+ int 19h
+int19 endp
+;
+; M036 - BEGIN
+;
+;
+;----------------------------------------------------------------------------
+;
+; procedure : int15
+;
+; Int15 handler for recognizing ctrl-alt-del seq.
+;
+;----------------------------------------------------------------------------
+;
+DELKEY equ 53h
+ public Int15
+Int15 proc far
+ assume ds:nothing
+ cmp ax, (4fh shl 8) + DELKEY ; del keystroke ?
+ je @f
+ jmp dword ptr Old15
+@@:
+ stc
+ jmp dword ptr Old15
+Int15 endp
+;
+;
+;************************************************************************
+;* *
+;* the int2f handler chains up to Bios_Code through here. *
+;* it returns through one of the three functions that follow. *
+;* notice that we'll assume we're being entered from DOS, so *
+;* that we're guaranteed to be A20 enabled if needed *
+;* *
+;************************************************************************
+
+int_2f proc far
+ assume ds:nothing,es:nothing
+ jmp bcode_i2f
+int_2f endp
+
+
+
+;************************************************************************
+;* *
+;* re_init - called back by sysinit after a bunch of stuff *
+;* is done. presently does nothing. affects no *
+;* registers! *
+;* *
+;************************************************************************
+
+ public re_init
+re_init proc far
+ assume ds:nothing,es:nothing
+ ret
+re_init endp
+
+
+;SR; WIN386 support
+; WIN386 instance data structure
+;
+;
+; Here is a Win386 startup info structure which we set up and to which
+; we return a pointer when Win386 initializes.
+;
+
+public Win386_SI, SI_Version, SI_Next
+
+Win386_SI label byte ; Startup Info for Win386
+SI_Version db 3, 0 ; for Win386 3.0
+SI_Next dd ? ; pointer to next info structure
+ dd 0 ; a field we don't need
+ dd 0 ; another field we don't need
+SI_Instance dw Instance_Table, Bios_Data ; far pointer to instance table
+
+;
+; This table gives Win386 the instance data in the BIOS and ROM-BIOS data
+; areas. Note that the address and size of the hardware stacks must
+; be calculated and inserted at boot time.
+;
+Instance_Table label dword
+ dw 00H, 50H ; print screen status...
+ dw 02 ; ...2 bytes
+ dw 0Eh, 50H ; ROM Basic data...
+ dw 14H ; ...14H bytes
+ dw ALTAH, Bios_Data ; a con device buffer...
+ dw 01 ; ... 1 byte
+IF STACKSW
+public NextStack
+NextStack label dword
+
+; NOTE: If stacks are disabled by STACKS=0,0, the following
+; instance items WILL NOT be filled in by SYSINIT.
+; That's just fine as long as these are the last items
+; in the instance list since the first item is initialized
+; to 0000 at load time.
+
+ dw 0, 0 ; pointer to next stack to be used...
+ dw 02 ; ...2 bytes
+; The next item in the instance table must be filled in at sysinit time
+public IT_StackLoc, IT_StackSize
+IT_StackLoc dd ? ; location of hardware stacks
+IT_StackSize dw ? ; size of hardware stacks
+ENDIF
+ dd 0 ; terminate the instance table
+
+;SR;
+; Flag to indicate whether Win386 is running or not
+;
+public IsWin386
+IsWin386 db 0
+
+;
+;This routine was originally in BIOS_CODE but this causes a lot of problems
+;when we call it including checking of A20. The code being only about
+;30 bytes, we might as well put it in BIOS_DATA
+;
+PUBLIC V86_Crit_SetFocus
+
+V86_Crit_SetFocus PROC FAR
+
+ push di
+ push es
+ push bx
+ push ax
+
+ xor di,di
+ mov es,di
+ mov bx,0015h ;Device ID of DOSMGR device
+ mov ax,1684h ;Get API entry point
+ int 2fh
+ mov ax,es
+ or ax,di
+ jz Skip
+;
+;Here, es:di is address of API routine. Set up stack frame to simulate a call
+;
+ push cs ;push return segment
+ mov ax,OFFSET Skip
+ push ax ;push return offset
+ push es
+ push di ;API far call address
+ mov ax,1 ;SetFocus function number
+ retf ;do the call
+Skip:
+ pop ax
+ pop bx
+ pop es
+ pop di
+ ret
+V86_Crit_SetFocus ENDP
+
+
+
+;
+;End WIN386 support
+;
+
+ public FreeHMAPtr
+ public MoveDOSIntoHMA
+FreeHMAPtr dw -1
+MoveDOSIntoHMA dd sysinitseg:FTryToMovDOSHi
+
+
+;SR;
+; A communication block has been setup between the DOS and the BIOS. All
+;the data starting from SysinitPresent will be part of the data block.
+;Right now, this is the only data being communicated. It can be expanded
+;later to add more stuff
+;
+ public SysinitPresent
+ public DemInfoFlag
+SysinitPresent db 0
+DemInfoFlag db 0
+
+
+; this will be the end of the BIOS data if no hard disks are in system
+
+ public endBIOSData
+endBIOSData label byte
+
+Bios_Data ends
+
+;
+; okay. so much for Bios_Data. Now let's put our device driver
+; entry stuff up into Bios_Code.
+
+Bios_Code segment
+ assume cs:Bios_Code
+
+; ORG a bit past zero to leave room for running in HMA...
+
+ org 30h
+ public BCode_start
+BCode_start:
+
+; device driver entry point tables
+
+ extrn con_table:near
+ extrn tim_table:near
+ extrn prn_table:near
+ extrn aux_table:near
+
+ extrn i2f_handler:far
+
+ public Bios_Data_Word
+Bios_Data_Word dw Bios_Data
+
+;************************************************************************
+;* *
+;* seg_reinit is called with ax = our new code segment value, *
+;* trashes di, cx, es *
+;* *
+;* cas -- should be made disposable! *
+;* *
+;************************************************************************
+
+ public seg_reinit
+seg_reinit proc far
+ assume ds:nothing,es:nothing
+
+ mov es,Bios_Data_Word
+ assume es:Bios_Data
+ mov di,2+offset cdev
+ mov cx,((offset end_BC_entries) - (offset cdev))/4
+
+seg_reinit_1:
+ stosw ; modify Bios_Code entry points
+ inc di
+ inc di
+ loop seg_reinit_1
+ ret
+seg_reinit endp
+
+;************************************************************************
+;* *
+;* chardev_entry - main device driver dispatch routine *
+;* called with a dummy parameter block on the stack *
+;* dw dispatch_table, dw prn/aux numbers (optional) *
+;* *
+;* will eventually take care of doing the transitions in *
+;* out of Bios_Code *
+;* *
+;************************************************************************
+
+chardev_entry proc far
+ assume ds:nothing,es:nothing
+
+ push si
+ push ax
+ push cx
+ push dx
+ push di
+ push bp
+ push ds
+ push es
+ push bx
+ mov bp,sp ; point to stack frame
+ mov si,18[bp] ; get return address (dispatch table)
+ mov ds,Bios_Data_Word ; load ds: -> Bios_Data
+ assume ds:Bios_Data
+ mov ax,word ptr 2[si] ; get the device number if present
+ mov byte ptr [auxnum],al
+ mov byte ptr [printdev],ah
+ mov si,word ptr [si] ; point to the device dispatch table
+
+ les bx,[ptrsav] ;get pointer to i/o packet
+
+ mov al,byte ptr es:[bx].unit ;al = unit code
+ mov ah,byte ptr es:[bx].media ;ah = media descrip
+ mov cx,word ptr es:[bx].count ;cx = count
+ mov dx,word ptr es:[bx].start ;dx = start sector
+
+ xchg di,ax
+ mov al,byte ptr es:[bx].cmd
+ cmp al,cs:[si]
+ jae command_error
+
+ cbw ; note that al <= 15 means ok
+ shl ax,1
+
+ add si,ax
+ xchg ax,di
+
+ les di,dword ptr es:[bx].trans
+
+ cld ; ***** always clear direction
+ call cs:word ptr [si+1] ;go do command
+ assume ds:nothing
+
+ jc already_got_ah_status ; if function returned status, don't
+ mov ah,1 ; load with normal completion
+
+already_got_ah_status:
+ mov ds,Bios_Data_Word ; cas///// note: shouldn't be needed!
+ assume ds:Bios_Data
+ lds bx,[ptrsav]
+ assume ds:nothing
+ mov word ptr [bx].status,ax ;mark operation complete
+
+ pop bx
+ pop es
+ pop ds
+ pop bp
+ pop di
+ pop dx
+ pop cx
+ pop ax
+ pop si
+ add sp,2 ; get rid of fake return address
+
+chardev_entry endp ; fall through into bc_retf
+
+ public bc_retf
+bc_retf proc far
+ assume ds:nothing,es:nothing
+
+ ret
+
+bc_retf endp
+
+
+command_error:
+ call bc_cmderr
+ jmp short already_got_ah_status
+
+;
+;----------------------------------------------------------------------------
+; The following piece of hack is for supporting CP/M compatibility
+; Basically at offset 5 we have a far call into 0:c0. But this does not call
+; 0:c0 directly instead it call f01d:fef0, because it needs to support 'lhld 6'
+; The following hack has to reside at ffff:d0 (= f01d:fef0) if BIOS is loaded
+; high.
+;----------------------------------------------------------------------------
+
+
+; BUGBUG sudeepb 21-May-1991 ; We can save these 30 bytes by moving
+; off_d0 to right place.
+
+ db 1fh dup (?) ; pad to bring offset to 0d0h
+
+if2
+ if ( offset off_d0 - 0d0h )
+ %out CP/M compatibilty broken!!!
+ %out Please re-pos hack to ffff:d0
+ endif
+endif
+
+ public off_d0
+off_d0 db 5 dup (?) ; 5 bytes from 0:c0 will be copied onto here
+ ; which is the CP/M call 5 entry point
+ .errnz (offset off_d0 - 0d0h)
+
+
+;----------------------------------------------------------
+;
+; exit - all routines return through this path
+;
+
+ public bc_cmderr
+bc_cmderr:
+ mov al,3 ;unknown command error
+
+; now zero the count field by subtracting its current value,
+; which is still in cx, from itself.
+
+
+; subtract the number of i/o's NOT YET COMPLETED from total
+; in order to return the number actually complete
+
+
+ public bc_err_cnt
+bc_err_cnt:
+ assume ds:Bios_Data
+ les bx,[ptrsav]
+ assume es:nothing
+ sub es:word ptr [bx].count,cx;# of successful i/o's
+ mov ah,81h ;mark error return
+ stc ; indicate abnormal end
+ ret
+
+Bios_Code ends
+
+
+; the last real segment is sysinitseg
+
+sysinitseg segment
+ assume cs:sysinitseg
+ extrn FTryToMovDOSHi:far
+ public SI_start
+SI_start:
+sysinitseg ends
+
+ end
diff --git a/private/mvdm/softpc.new/bios/mschar.asm b/private/mvdm/softpc.new/bios/mschar.asm
new file mode 100644
index 000000000..069273832
--- /dev/null
+++ b/private/mvdm/softpc.new/bios/mschar.asm
@@ -0,0 +1,1078 @@
+ page ,160
+ title mschar - character and clock devices
+;
+;----------------------------------------------------------------------------
+;
+;
+; 26-Feb-1991 sudeepb Ported for NT DOSEm
+;
+;----------------------------------------------------------------------------
+;
+
+ .xlist
+
+ include version.inc ; set build flags
+ include biosseg.inc ; establish bios segment structure
+
+ include msequ.inc
+ include devsym.inc
+ include ioctl.inc
+ include vint.inc
+
+break macro
+ endm
+
+ include biosbop.inc
+
+ include error.inc
+ .list
+
+ include msgroup.inc ; define Bios_Data segment
+
+
+ extrn ptrsav:dword
+
+ extrn altah:byte
+ extrn keyrd_func:byte
+ extrn keysts_func:byte
+
+ extrn auxnum:word
+ extrn auxbuf:byte
+
+ extrn wait_count:word
+ extrn printdev:byte
+ extrn Old10:dword
+ extrn spc_mse_int10:dword
+ extrn int29Perf:dword
+
+
+; close Bios_Data and open Bios_Code segment
+
+ tocode
+
+ extrn bc_cmderr:near
+ extrn bc_err_cnt:near
+
+MODE_CTRLBRK equ 0ffh ; M013
+
+;************************************************************************
+;* *
+;* device driver dispatch tables *
+;* *
+;* each table starts with a byte which lists the number of *
+;* legal functions, followed by that number of words. Each *
+;* word represents an offset of a routine in Bios_Code which *
+;* handles the function. The functions are terminated with *
+;* a near return. If carry is reset, a 'done' code is returned *
+;* to the caller. If carry is set, the ah/al registers are *
+;* returned as abnormal completion status. Notice that ds *
+;* is assumed to point to the Bios_Data segment throughout. *
+;* *
+;************************************************************************
+
+ public con_table
+con_table:
+ db (((offset con_table_end) - (offset con_table) - 1)/2)
+ dw bc_exvec ; 00 init
+ dw bc_exvec ; 01
+ dw bc_exvec ; 02
+ dw bc_cmderr ; 03
+ dw con_read ; 04
+ dw con_rdnd ; 05
+ dw bc_exvec ; 06
+ dw con_flush ; 07
+ dw con_writ ; 08
+ dw con_writ ; 09
+ dw bc_exvec ; 0a
+con_table_end:
+
+ public prn_table
+prn_table label byte
+ db (((offset prn_table_end) - (offset prn_table) -1)/2)
+ dw bc_exvec ; 00 init
+ dw bc_exvec ; 01
+ dw bc_exvec ; 02
+ dw bc_cmderr ; 03
+ dw prn_input ; 04 indicate zero chars read
+ dw z_bus_exit ; 05 read non-destructive
+ dw bc_exvec ; 06
+ dw bc_exvec ; 07
+ dw prn_writ ; 08
+ dw prn_writ ; 09
+ dw prn_stat ; 0a
+ dw bc_exvec ; 0b
+ dw bc_exvec ; 0c
+ dw prn_open ; 0d
+ dw prn_close ; 0e
+ dw bc_exvec ; 0f
+ dw prn_tilbusy ; 10
+ dw bc_exvec ; 11
+ dw bc_exvec ; 12
+ dw prn_genioctl ; 13
+ dw bc_exvec ; 14
+ dw bc_exvec ; 15
+ dw bc_exvec ; 16
+ dw bc_exvec ; 17
+ dw bc_exvec ; 18
+ dw prn_ioctl_query ; 19
+prn_table_end:
+
+
+
+ public aux_table
+aux_table label byte
+ db (((offset aux_table_end) - (offset aux_table) -1)/2)
+
+ dw bc_exvec ; 00 - init
+ dw bc_exvec ; 01
+ dw bc_exvec ; 02
+ dw bc_cmderr ; 03
+ dw aux_read ; 04 - read
+ dw aux_rdnd ; 05 - read non-destructive
+ dw bc_exvec ; 06
+ dw aux_flsh ; 07
+ dw aux_writ ; 08
+ dw aux_writ ; 09
+ dw aux_wrst ; 0a
+aux_table_end:
+
+
+ public tim_table
+tim_table label byte
+ db (((offset tim_table_end) - (offset tim_table) -1)/2)
+ dw bc_exvec ; 00
+ dw bc_exvec ; 01
+ dw bc_exvec ; 02
+ dw bc_cmderr ; 03
+ dw bc_cmderr ; 04
+ dw z_bus_exit ; 05
+ dw bc_exvec ; 06
+ dw bc_exvec ; 07
+ dw bc_cmderr ; 08
+ dw bc_cmderr ; 09
+tim_table_end:
+
+;************************************************************************
+;* *
+;* con_read - read cx bytes from keyboard into buffer at es:di *
+;* *
+;************************************************************************
+
+con_read proc near
+ assume ds:Bios_Data,es:nothing
+
+ jcxz con_exit
+
+con_loop:
+ call chrin ;get char in al
+ stosb ;store char at es:di
+ loop con_loop
+
+con_exit:
+ clc
+ ret
+con_read endp
+
+;************************************************************************
+;* *
+;* chrin - input single char from keyboard into al *
+;* *
+;* we are going to issue extended keyboard function, if *
+;* supported. the returning value of the extended keystroke *
+;* of the extended keyboard function uses 0e0h in al *
+;* instead of 00 as in the conventional keyboard function. *
+;* this creates a conflict when the user entered real *
+;* greek alpha charater (= 0e0h) to distinguish the extended *
+;* keystroke and the greek alpha. this case will be handled *
+;* in the following manner: *
+;* *
+;* ah = 16h *
+;* int 16h *
+;* if al == 0, then extended code (in ah) *
+;* else if al == 0e0h, then *
+;* if ah <> 0, then extended code (in ah) *
+;* else greek_alpha character. *
+;* *
+;* also, for compatibility reason, if an extended code is *
+;* detected, then we are going to change the value in al *
+;* from 0e0h to 00h. *
+;* *
+;************************************************************************
+
+
+chrin proc near
+ assume ds:Bios_Data,es:nothing
+
+ mov ah,keyrd_func ; set by msinit. 0 or 10h
+ xor al,al
+ xchg al,altah ;get character & zero altah
+
+ or al,al
+ jnz keyret
+
+ int 16h ; do rom bios keyrd function
+
+alt10:
+ or ax,ax ;check for non-key after break
+ jz chrin
+
+ cmp ax,7200h ;check for ctrl-prtsc
+ jnz alt_ext_chk
+
+ mov al,16
+ jmp short keyret
+
+alt_ext_chk:
+
+;**************************************************************
+; if operation was extended function (i.e. keyrd_func != 0) then
+; if character read was 0e0h then
+; if extended byte was zero (i.e. ah == 0) then
+; goto keyret
+; else
+; set al to zero
+; goto alt_save
+; endif
+; endif
+; endif
+
+ cmp byte ptr keyrd_func,0
+ jz not_ext
+ cmp al,0e0h
+ jnz not_ext
+
+ or ah,ah
+ jz keyret
+ifdef DBCS
+ifdef KOREA ; Keyl 1990/11/5
+ cmp ah, 0f0h ; If hangeul code range then
+ jb EngCodeRange1 ; do not modify any value.
+ cmp ah, 0f2h
+ jbe not_ext
+EngCodeRange1:
+endif ; KOREA
+endif ; DBCS
+ xor al,al
+ jmp short alt_save
+
+not_ext:
+
+ or al,al ;special case?
+ jnz keyret
+
+alt_save:
+ mov altah,ah ;store special key
+keyret:
+ ret
+chrin endp
+
+;************************************************************************
+;* *
+;* con_rdnd - keyboard non destructive read, no wait *
+;* *
+;* pc-convertible-type machine: if bit 10 is set by the dos *
+;* in the status word of the request packet, and there is no *
+;* character in the input buffer, the driver issues a system *
+;* wait request to the rom. on return from the rom, it returns *
+;* a 'char-not-found' to the dos. *
+;* *
+;************************************************************************
+
+con_rdnd proc near
+ assume ds:Bios_Data,es:nothing
+
+ mov al,[altah]
+ or al,al
+ jnz rdexit
+
+ mov ah,keysts_func ; keyboard i/o interrupt - get
+ int 16h ; keystroke status (keysts_func)
+ jnz gotchr
+
+;
+; pc-convertible checking is not needed on NTVDM
+; if no key in buff return immediatly with busy status
+;04-Aug-1992 Jonle
+;
+; cmp fhavek09,0
+; jz z_bus_exit ; return with busy status if not k09
+;
+; les bx,[ptrsav]
+; assume es:nothing
+; test es:[bx].status,0400h ; system wait enabled?
+; jz z_bus_exit ; return with busy status if not
+;
+; need to wait for ibm response to request for code
+; on how to use the system wait call.
+;
+; mov ax,4100h ; wait on an external event
+; xor bl,bl ; M055; wait for any event
+; int 15h ; call rom for system wait
+
+z_bus_exit:
+ stc
+ mov ah,3 ; indicate busy status
+ ret
+
+gotchr:
+ or ax,ax
+ jnz notbrk ;check for null after break
+
+ mov ah,keyrd_func ; issue keyboard read function
+ int 16h
+ jmp con_rdnd ;and get a real status
+
+notbrk:
+ cmp ax,7200h ;check for ctrl-prtsc
+ jnz rd_ext_chk
+
+ mov al,'P' and 1fh ; return control p
+ jmp short rdexit
+
+rd_ext_chk:
+ cmp keyrd_func,0 ; extended keyboard function?
+ jz rdexit ; no. normal exit.
+
+ cmp al,0e0h ; extended key value or greek alpha?
+ jne rdexit
+
+ifdef DBCS
+ifdef KOREA
+ cmp ah, 0f0h ; If hangeul code range then
+ jb EngCodeRange ; do not modify any value.
+ cmp ah, 0f2h
+ jbe rdexit ; Keyl 90/11/5
+EngCodeRange:
+endif ; KOREA
+endif ; DBCS
+
+ cmp ah,0 ; scan code exist?
+ jz rdexit ; yes. greek alpha char.
+ mov al,0 ; no. extended key stroke.
+ ; change it for compatibility
+
+rdexit:
+ les bx,[ptrsav]
+ assume es:nothing
+ mov es:[bx].media,al ; *** return keyboard character here
+
+bc_exvec:
+ clc ; indicate normal termination
+ ret
+
+con_rdnd endp
+
+;************************************************************************
+;* *
+;* con_write - console write routine *
+;* *
+;* entry: es:di -> buffer *
+;* cx = count *
+;* *
+;************************************************************************
+
+con_writ proc near
+ assume ds:Bios_Data,es:nothing
+
+ jcxz bc_exvec
+
+ push es
+
+ mov bx,word ptr [int29Perf]
+ mov dx,word ptr [int29Perf+2] ;DX:BX is original INT 29h vector
+ sub ax,ax
+ mov es,ax
+ cmp BX,es:[29h*4+0]
+ jne con_lp1 ; if not the same do single int10s
+ cmp DX,es:[29h*4+2]
+ jne con_lp1 ; if not the same do single int10s
+ mov bx,word ptr [spc_mse_int10]
+ mov dx,word ptr [spc_mse_int10+2] ;DX:BX is original INT 10h vector
+ cmp BX,es:[10h*4+0]
+ jne con_lp1 ; if not the same do single int10s
+ cmp DX,es:[10h*4+2]
+ jne con_lp1 ; if not the same do single int10s
+
+ pop es
+
+ ; Sudeepb 21-Jul-1992: We know that no one has hooked in10 so we
+ ; can optimize it by calling a private in1t10h which takes a full
+ ; string, displays it with the same attribute as present on the
+ ; screen and moves the cursor to the end.
+
+ mov ax,46h ; sounds like a good flag value
+ push ax ; make an iret frame
+ push cs
+ mov ax, offset ret_adr
+ push ax
+ push dx ; dx:bx is pointing to softpc int10 handler
+ push bx ; make the retf frame
+ mov ax,13FFh ; AH = WRITESTRING, AL = subfunction
+ retf
+ret_adr:
+ jmp short cc_ret
+
+con_lp1:
+ pop es
+
+con_lp:
+ mov al,es:[di] ;get char
+ inc di
+ int chrout ;output char
+ loop con_lp ;repeat until all through
+
+cc_ret:
+ clc
+ ret
+con_writ endp
+
+;************************************************************************
+;* *
+;* con_flush - flush out keyboard queue *
+;* *
+;************************************************************************
+
+ public con_flush ; called from msbio2.asm for floppy swapping
+con_flush proc near
+ assume ds:Bios_Data,es:nothing
+
+
+ mov [altah],0 ;clear out holding buffer
+
+; while (charavail()) charread();
+
+flloop:
+ mov ah,1 ; command code for check status
+ int 16h ; call rom-bios keyboard routine
+ jz cc_ret ; return carry clear if none
+
+ xor ah,ah ; if zf is nof set, get character
+ int 16h ; call rom-bios to get character
+ jmp flloop
+
+con_flush endp
+
+;************************************************************************
+;* *
+;* some equates for rom bios printer i/o *
+;* *
+;************************************************************************
+
+; ibm rom status bits (i don't trust them, neither should you)
+; warning!!! the ibm rom does not return just one bit. it returns a
+; whole slew of bits, only one of which is correct.
+
+
+notbusystatus = 10000000b ; not busy
+nopaperstatus = 00100000b ; no more paper
+prnselected = 00010000b ; printer selected
+ioerrstatus = 00001000b ; some kinda error
+timeoutstatus = 00000001b ; time out.
+
+noprinter = 00110000b ; no printer attached
+
+;************************************************************************
+;* *
+;* prn_input - return with no error but zero chars read *
+;* *
+;* enter with cx = number of characters requested *
+;* *
+;************************************************************************
+
+prn_input proc near
+ assume ds:Bios_Data,es:nothing
+
+ call bc_err_cnt ; reset count to zero (sub reqpkt.count,cx)
+ clc ; but return with carry reset for no error
+ ret
+
+prn_input endp
+
+;************************************************************************
+;* *
+;* prn_writ - write cx bytes from es:di to printer device *
+;* *
+;* auxnum has printer number *
+;* *
+;************************************************************************
+
+prn_writ proc near
+ assume ds:Bios_Data,es:nothing
+
+ jcxz prn_done ;no chars to output
+
+prn_loop:
+ mov bx,2 ;retry count
+
+prn_out:
+ call prnstat ; get status
+ jnz TestPrnError ; error
+
+ mov al,es:[di] ; get character to print
+ xor ah,ah
+ call prnop ; print to printer
+ jz prn_con ; no error - continue
+
+ cmp ah, MODE_CTRLBRK ; M013
+ jne @f ; M013
+ mov al, error_I24_gen_failure ; M013
+ mov altah, 0 ; M013
+ jmp short pmessg ; M013
+@@:
+ test ah,timeoutstatus
+ jz prn_con ; not time out - continue
+
+TestPrnError:
+ dec bx ;retry until count is exhausted.
+ jnz prn_out
+
+pmessg:
+ jmp bc_err_cnt ; return with error
+
+; next character
+
+prn_con:
+ inc di ;point to next char and continue
+ loop prn_loop
+
+prn_done:
+ clc
+ ret
+prn_writ endp
+
+;************************************************************************
+;* *
+;* prn_stat - device driver entry to return printer status *
+;* *
+;************************************************************************
+
+prn_stat proc near
+
+ call prnstat ;device in dx
+ jnz pmessg ; other errors were found
+ test ah,notbusystatus
+ jnz prn_done ;no error. exit
+ jmp z_bus_exit ; return busy status
+prn_stat endp
+
+;************************************************************************
+;* *
+;* prnstat - utilty function to call ROM BIOS to check *
+;* printer status. Return meaningful error code *
+;* *
+;************************************************************************
+
+prnstat proc near
+ assume ds:Bios_Data,es:nothing
+
+ mov ah, 2 ; set command for get status
+prnstat endp ; fall into prnop
+
+;************************************************************************
+;* *
+;* prnop - call ROM BIOS printer function in ah *
+;* return zero true if no error *
+;* return zero false if error, al = error code *
+;* *
+;************************************************************************
+
+prnop proc near
+ assume ds:Bios_Data,es:nothing
+
+ mov dx,[auxnum] ; get printer number
+ int 17h ; call rom-bios printer routine
+
+ ; This check was added to see if this is a case of no
+ ; printer being installed. This tests checks to be sure
+ ; the error is noprinter (30h)
+
+ push ax ; M044
+ and ah, noprinter ; M044
+ cmp AH,noprinter ; Chk for no printer
+ pop ax ; M044
+
+ jne NextTest
+ and AH,NOT nopaperstatus
+ or AH,ioerrstatus
+
+; examine the status bits to see if an error occurred. unfortunately, several
+; of the bits are set so we have to pick and choose. we must be extremely
+; careful about breaking basic.
+
+NextTest:
+ test ah,(ioerrstatus+nopaperstatus) ; i/o error?
+ jz checknotready ; no, try not ready
+
+; at this point, we know we have an error. the converse is not true.
+
+ mov al,error_I24_out_of_paper
+ ; first, assume out of paper
+ test ah,nopaperstatus ; out of paper set?
+ jnz ret1 ; yes, error is set
+ inc al ; return al=10 (i/o error)
+ret1:
+ ret ; return with error
+
+checknotready:
+ mov al,2 ; assume not-ready
+ test ah,timeoutstatus ; is time-out set?
+ ret ; if nz then error, else ok
+prnop endp
+
+;************************************************************************
+;* *
+;* prn_open - send bop to disable auto-close, and wait for *
+;* a DOS close *
+;* *
+;* inputs: *
+;* outputs: BOP has been issued *
+;* *
+;************************************************************************
+
+prn_open proc near
+ push si
+ push dx
+ push ds
+ mov dx,40h
+ mov ds,dx
+ test word ptr ds:[FIXED_NTVDMSTATE_REL40], EXEC_BIT_MASK
+ pop ds
+ jnz po_nobop
+ xor dh, dh
+ mov dl, [printdev]
+ or dl, dl
+ jz @f
+ dec dl
+@@:
+ mov si,PRNIO_OPEN
+ bop %BIOS_PRINTER_IO
+po_nobop:
+ pop dx
+ pop si
+ ret
+prn_open endp
+
+;************************************************************************
+;* *
+;* prn_close - send bop to close actual printer, and re-enable *
+;* autoclose *
+;* *
+;* inputs: *
+;* outputs: BOP has been issued *
+;* *
+;************************************************************************
+
+prn_close proc near
+ push si
+ push dx
+ push ds
+ mov dx,40h
+ mov ds,dx
+ test word ptr ds:[FIXED_NTVDMSTATE_REL40], EXEC_BIT_MASK
+ pop ds
+ jnz pc_nobop
+ xor dh, dh
+ mov dl, [printdev]
+ or dl, dl
+ jz @f
+ dec dl
+@@:
+ mov si,PRNIO_CLOSE
+ bop %BIOS_PRINTER_IO
+pc_nobop:
+ pop dx
+ pop si
+ ret
+prn_close endp
+
+;************************************************************************
+;* *
+;* prn_tilbusy - output until busy. Used by print spooler. *
+;* this entry point should never block waiting for *
+;* device to come ready. *
+;* *
+;* inputs: cx = count, es:di -> buffer *
+;* outputs: set the number of bytes transferred in the *
+;* device driver request packet *
+;* *
+;************************************************************************
+
+prn_tilbusy proc near
+
+ mov si,di ; everything is set for lodsb
+
+prn_tilbloop:
+ push cx
+
+ push bx
+ xor bh,bh
+ mov bl,[printdev]
+ shl bx,1
+ mov cx,wait_count[bx] ; wait count times to come ready
+ pop bx
+
+prn_getstat:
+ call prnstat ; get status
+ jnz prn_bperr ; error
+ test ah,10000000b ; ready yet?
+ loopz prn_getstat ; no, go for more
+
+ pop cx ; get original count
+ jz prn_berr ; still not ready => done
+
+ lods es:byte ptr [si]
+ xor ah,ah
+ call prnop
+ jnz prn_berr ; error
+
+ loop prn_tilbloop ; go for more
+
+ clc ; normal no-error return
+ ret ; from device driver
+
+prn_bperr:
+ pop cx ; restore transfer count from stack
+
+prn_berr:
+ jmp bc_err_cnt
+prn_tilbusy endp
+
+;************************************************************************
+;* *
+;* prn_genioctl - get/set printer retry count *
+;* *
+;************************************************************************
+
+prn_genioctl proc near
+ assume ds:Bios_Data,es:nothing
+
+ les di,[ptrsav]
+ cmp es:[di].majorfunction,ioc_pc
+ jz prnfunc_ok
+
+prnfuncerr:
+ jmp bc_cmderr
+
+prnfunc_ok:
+ mov al,es:[di].minorfunction
+ les di,es:[di].genericioctl_packet
+ xor bh,bh
+ mov bl,[printdev] ; get index into retry counts
+ shl bx,1
+ mov cx,wait_count[bx] ; pull out retry count for device
+
+ cmp al,get_retry_count
+ jz prngetcount
+
+ cmp al,set_retry_count
+ jnz prnfuncerr
+
+ mov cx,es:[di].rc_count
+prngetcount:
+ mov wait_count[bx],cx ; place "new" retry count
+ mov es:[di].rc_count,cx ; return current retry count
+ clc
+ ret
+prn_genioctl endp
+
+;************************************************************************
+;* *
+;* prn_ioctl_query *
+;* *
+;* Added for 5.00 *
+;************************************************************************
+
+prn_ioctl_query PROC NEAR
+ assume ds:Bios_Data,es:nothing
+
+ les di,[ptrsav]
+ cmp es:[di].majorfunction,ioc_pc
+ jne prn_query_err
+
+ mov al,es:[di].minorfunction
+ cmp al,get_retry_count
+ je IOCtlSupported
+ cmp al,set_retry_count
+ jne prn_query_err
+
+IOCtlSupported:
+ clc
+ ret
+
+prn_query_err:
+ stc
+ jmp BC_CmdErr
+
+prn_ioctl_query ENDP
+
+;************************************************************************
+;* *
+;* aux port driver code -- "aux" == "com1" *
+;* *
+;* the device driver entry/dispatch code sets up auxnum to *
+;* give the com port number to use (0=com1, 1=com2, 2=com3...) *
+;* *
+;************************************************************************
+
+; values in ah, requesting function of int 14h in rom bios
+
+auxfunc_send equ 1 ;transmit
+auxfunc_receive equ 2 ;read
+auxfunc_status equ 3 ;request status
+
+; error flags, reported by int 14h, reported in ah:
+
+flag_data_ready equ 01h ;data ready
+flag_overrun equ 02h ;overrun error
+flag_parity equ 04h ;parity error
+flag_frame equ 08h ;framing error
+flag_break equ 10h ;break detect
+flag_tranhol_emp equ 20h ;transmit holding register empty
+flag_timeout equ 80h ;timeout
+
+; these flags reported in al:
+
+flag_cts equ 10h ;clear to send
+flag_dsr equ 20h ;data set ready
+flag_rec_sig equ 80h ;receive line signal detect
+
+;************************************************************************
+;* *
+;* aux_read - read cx bytes from [auxnum] aux port to buffer *
+;* at es:di *
+;* *
+;************************************************************************
+
+aux_read proc near
+ assume ds:Bios_Data,es:nothing
+
+ jcxz exvec2 ; if no characters, get out
+
+ call getbx ; put address of auxbuf in bx
+ xor al,al ; clear al register
+ xchg al,[bx] ; get character , if any, from
+ ; buffer and clear buffer
+ or al,al ; if al is nonzero there was a
+ ; character in the buffer
+ jnz aux2 ; if so skip first auxin call
+
+aux1:
+ call auxin ; get character from port
+; ^^^^^ won't return if error
+aux2:
+ stosb ; store character
+ loop aux1 ; if more characters, go around again
+
+exvec2:
+ clc ; all done, successful exit
+ ret
+
+aux_read endp
+
+;************************************************************************
+;* *
+;* auxin - call rom bios to read character from aux port *
+;* if error occurs, map the error and return one *
+;* level up to device driver exit code, setting *
+;* the number of bytes transferred appropriately *
+;* *
+;************************************************************************
+
+;
+; M026 - BEGIN
+;
+auxin proc near
+ mov ah,auxfunc_receive
+ call auxop ;check for frame, parity, or overrun errors
+ ;warning: these error bits are unpredictable
+ ; if timeout (bit 7) is set
+ test ah, flag_frame or flag_parity or flag_overrun
+ jnz arbad ; skip if any error bits set
+ ret ; normal completion, ah=stat, al=char
+
+; error getting character
+
+arbad:
+ pop ax ; remove return address (near call)
+ xor al,al
+ or al,flag_rec_sig or flag_dsr or flag_cts
+ jmp bc_err_cnt
+
+auxin endp
+
+IFDEF COMMENTEDOUT
+auxin proc near
+ push cx
+ mov cx, 20 ; number of retries on time out errors
+@@:
+ mov ah,auxfunc_receive
+ call auxop ;check for frame, parity, or overrun errors
+ ;warning: these error bits are unpredictable
+ ; if timeout (bit 7) is set
+ test ah, flag_timeout
+ jz no_timeout
+ loop @b
+no_timeout:
+ pop cx
+ test ah, flag_timeout or flag_frame or flag_parity or flag_overrun
+ jnz arbad ; skip if any error bits set
+ ret ; normal completion, ah=stat, al=char
+
+; error getting character
+
+arbad:
+ pop ax ; remove return address (near call)
+ xor al,al
+ or al,flag_rec_sig or flag_dsr or flag_cts
+ jmp bc_err_cnt
+
+auxin endp
+ENDIF
+
+;
+; M026 - END
+;
+;************************************************************************
+;* *
+;* aux_rdnd - non-destructive aux port read *
+;* *
+;************************************************************************
+
+aux_rdnd proc near
+ assume ds:Bios_Data,es:nothing
+
+ call getbx ; have bx point to auxbuf
+ mov al,[bx] ; copy contents of buffer to al
+ or al,al ; if al is non-zero (char in buffer)
+ jnz auxrdx ; then return character
+
+ call auxstat ; if not, get status of aux device
+ test ah,flag_data_ready ; test data ready
+ jz auxbus ; then device is busy (not ready)
+
+ test al,flag_dsr ;test data set ready
+ jz auxbus ; then device is busy (not ready)
+
+ call auxin ; else aux is ready, get character
+ mov [bx],al ; save character in buffer
+
+auxrdx:
+ jmp rdexit ; return al in [packet.media]
+
+auxbus:
+ jmp z_bus_exit ; return busy status
+aux_rdnd endp
+
+;************************************************************************
+;* *
+;* aux_wrst - return aux port write status *
+;* *
+;************************************************************************
+
+aux_wrst proc near
+ assume ds:Bios_Data,es:nothing
+
+ call auxstat ; get status of aux in ax
+ test al,flag_dsr ; test data set ready
+ jz auxbus ; then device is busy (not ready)
+ test ah,flag_tranhol_emp ;test transmit hold reg empty
+ jz auxbus ; then device is busy (not ready)
+ clc
+ ret
+aux_wrst endp
+
+;************************************************************************
+;* *
+;* auxstat - call rom bios to determine aux port status *
+;* *
+;* exit: ax = status *
+;* dx = [auxnum] *
+;* *
+;************************************************************************
+
+auxstat proc near
+ mov ah,auxfunc_status
+auxstat endp ; fall into auxop
+
+;************************************************************************
+;* *
+;* auxop - perform rom-biox aux port interrupt *
+;* *
+;* entry: ah = int 14h function number *
+;* exit: ax = results *
+;* dx = [auxnum] *
+;* *
+;************************************************************************
+
+auxop proc near
+ ;ah=function code
+ ;0=init, 1=send, 2=receive, 3=status
+ mov dx,[auxnum] ; get port number
+ int 14h ; call rom-bios for status
+ ret
+auxop endp
+
+;************************************************************************
+;* *
+;* aux_flsh - flush aux input buffer - set contents of *
+;* auxbuf [auxnum] to zero *
+;* *
+;* cas - shouldn't this code call the rom bios input function *
+;* repeatedly until it isn't ready? to flush out any *
+;* pending serial input queue if there's a tsr like MODE *
+;* which is providing interrupt-buffering of aux port? *
+;* *
+;************************************************************************
+
+aux_flsh proc near
+ call getbx ; get bx to point to auxbuf
+ mov byte ptr [bx],0 ; zero out buffer
+ clc ; all done, successful return
+ ret
+aux_flsh endp
+
+;************************************************************************
+;* *
+;* aux_writ - write to aux device *
+;* *
+;************************************************************************
+
+aux_writ proc near
+ assume ds:Bios_Data ; set by aux device driver entry routine
+ jcxz exvec2 ; if cx is zero, no characters
+ ; to be written, jump to exit
+aux_loop:
+ mov al,es:[di] ; get character to be written
+ inc di ; move di pointer to next character
+ mov ah,auxfunc_send ;value=1, indicates a write
+ call auxop ;send character over aux port
+
+ test ah,flag_timeout ;check for error
+ jz awok ; then no error
+ mov al,10 ; else indicate write fault
+ jmp bc_err_cnt ; call error routines
+
+ ; if cx is non-zero, still more
+awok:
+ loop aux_loop ; more characrter to print
+ clc ; all done, successful return
+ ret
+aux_writ endp
+
+;************************************************************************
+;* *
+;* getbx - return bx -> single byte input buffer for *
+;* selected aux port ([auxnum]) *
+;* *
+;************************************************************************
+
+getbx proc near
+ assume ds:Bios_Data,es:nothing
+
+ mov bx,[auxnum]
+ add bx,offset auxbuf
+ ret
+getbx endp
+
+Bios_Code ends
+ end
diff --git a/private/mvdm/softpc.new/bios/msend.asm b/private/mvdm/softpc.new/bios/msend.asm
new file mode 100644
index 000000000..305cedbe9
--- /dev/null
+++ b/private/mvdm/softpc.new/bios/msend.asm
@@ -0,0 +1,52 @@
+ page ,160
+;
+;----------------------------------------------------------------------------
+; Modification history
+;
+; 26-Feb-1991 sudeepb Ported for NT DOSEm
+;
+;----------------------------------------------------------------------------
+
+; Define end labels for each segment in
+; IO.SYS. Make the segments paragraph aligned
+; to save the trouble of rounding up at run-time.
+;
+; also defines a special segment called dos_load_seg which is
+; used to figure out where to load MSDOS (after sysinit)
+
+Bios_Data segment para public 'Bios_Data'
+ assume cs:Bios_Data
+ public BData_end
+BData_end:
+Bios_Data ends
+
+Bios_Code segment para public 'Bios_Code'
+ assume cs:Bios_Code
+ public BCode_end
+BCode_end:
+Bios_Code ends
+
+sysinitseg segment para public 'system_init'
+ assume cs:sysinitseg
+sysinitseg ends
+
+SpcKbdSeg segment para public 'SoftpcKeyboard'
+ assume cs:SpcKbdSeg
+SpcKbdSeg ends
+
+SpcMseSeg segment para public 'SoftpcMouse'
+ assume cs:SpcMseSeg
+SpcMseSeg ends
+
+SpcEmmSeg segment para public 'SoftpcEmm'
+ assume cs:SpcEmmSeg
+ public SI_end
+SI_end:
+SpcEmmSeg ends
+
+
+dos_load_seg segment para public 'dos_load_seg'
+dos_load_seg ends
+
+ end
+
diff --git a/private/mvdm/softpc.new/bios/msequ.inc b/private/mvdm/softpc.new/bios/msequ.inc
new file mode 100644
index 000000000..bf743846d
--- /dev/null
+++ b/private/mvdm/softpc.new/bios/msequ.inc
@@ -0,0 +1,56 @@
+
+ftoobig equ 80h
+fbig equ 40h
+romstatus equ 1
+romread equ 2
+romwrite equ 3
+romverify equ 4
+romformat equ 5
+
+
+rsinit = 0a3h ;rs232 initialization
+ ;9600 baud:no parity:1 stop:8 bit word
+
+lf = 10 ;line feed
+cr = 13 ;carriage return
+backsp = 8 ;backspace
+brkadr = 1bh * 4 ;006c 1bh break vector address
+timadr = 1ch * 4 ;0070 1ch timer interrupt
+dskadr = 1eh * 4 ;address of ptr to disk parameters
+sec9 = 522h ;address of disk parameters
+headsettle= sec9+9 ;address of head settle time
+normsettle= 15 ;normal head settle
+speedsettle= 0 ;speed up settle time
+initspot= 534h ;ibm wants 4 zeros here
+akport = 20h
+eoi = 20h
+
+cmdlen = 0 ;length of this command
+unit = 1 ;sub unit specifier
+cmd = 2 ;command code
+status = 3 ;status
+media = 13 ;media descriptor
+trans = 14 ;transfer address
+count = 18 ;count of blocks or characters
+start = 20 ;first block to transfer
+extra = 22 ;usually a pointer to vol id for error 15
+start_l = 26 ; extended start sector (low)
+start_h = 28 ; extended start sector (high)
+
+
+chrout = 29h
+maxerr = 5
+lstdrv = 504h
+
+bootbias = 200h
+notbusystatus = 10000000b ; not busy
+ackstatus = 01000000b ; acknowledge (for what?)
+nopaperstatus = 00100000b ; no more paper
+.selectedstatus = 00010000b ; the printer said it was selected
+ioerrstatus = 00001000b ; some kinda error
+reserved = 00000110b ; nops
+timeoutstatus = 00000001b ; time out.
+error_unknown_media = 7 ; for use in build bpb call
+
+
+
diff --git a/private/mvdm/softpc.new/bios/msgroup.inc b/private/mvdm/softpc.new/bios/msgroup.inc
new file mode 100644
index 000000000..605fe1314
--- /dev/null
+++ b/private/mvdm/softpc.new/bios/msgroup.inc
@@ -0,0 +1,18 @@
+
+tocode macro
+Bios_Data ends
+Bios_Code segment
+ assume cs:Bios_Code
+ endm
+
+todata macro
+Bios_Code ends
+Bios_Data segment
+ assume cs:Bios_Data
+ endm
+
+;align the segment on word boundary to allow for even alignment of data
+
+Bios_Data segment
+ assume cs:Bios_Data
+
diff --git a/private/mvdm/softpc.new/bios/msinit.asm b/private/mvdm/softpc.new/bios/msinit.asm
new file mode 100644
index 000000000..d4c7b4f42
--- /dev/null
+++ b/private/mvdm/softpc.new/bios/msinit.asm
@@ -0,0 +1,288 @@
+ page ,160
+ title msinit for BIOS
+;
+;----------------------------------------------------------------------------
+;
+; Modification history
+;
+; 26-Feb-1991 sudeepb Ported for NT DOSEm
+;----------------------------------------------------------------------------
+;
+
+EXTENDEDKEY equ 1 ; use extended keyboard functions
+
+ include version.inc ; set build flags
+ include biosseg.inc ; establish bios segment structure
+
+ include msequ.inc
+ include dossym.inc
+ include dosmac.inc
+ include biostruc.inc
+ include dossvc.inc
+ include vint.inc
+
+; the following segment follows sysinit. It is used to define
+; the location to load MSDOS.SYS into.
+
+dos_load_seg segment para public 'dos_load_seg'
+dos_load_seg ends
+
+ extrn RomVectors:dword
+ extrn NUMROMVECTORS:abs
+ extrn res_dev_list:word
+ extrn keyrd_func:byte ; for mscon. defined in msdata.
+ extrn keysts_func:byte ; for mscon. defined in msdata.
+ extrn endBIOSData:byte
+
+ extrn dosdatasg:word
+
+ extrn Int15:far ; M036
+ extrn int19:far
+ extrn intret:near
+ extrn cbreak:near
+ extrn outchr:near
+ extrn outchr:near
+
+sysinitseg segment
+ assume cs:sysinitseg
+ extrn current_dos_location:word
+ extrn device_list:dword
+ extrn memory_size:word
+ extrn sysinit:far
+sysinitseg ends
+
+Bios_Data_Init segment
+ assume cs:datagrp
+
+;*********************************************************
+; system initialization
+;
+; the entry conditions are established by the bootstrap
+; loader and are considered unknown. the following jobs
+; will be performed by this module:
+;
+; 1. all device initialization is performed
+;
+; 2. a local stack is set up and ds:si are set
+; to point to an initialization table. then
+; an inter-segment call is made to the first
+; byte of the dos
+;
+; 3. once the dos returns from this call the ds
+; register has been set up to point to the start
+; of free memory. the initialization will then
+; load the command program into this area
+; beginning at 100 hex and transfer control to
+; this program.
+;
+;********************************************************
+
+
+
+;===========================================================================
+;
+; entry from boot sector. the register contents are:
+;
+; dl = int 13 drive number we booted from
+; ch = media byte
+; bx = first data sector on disk.
+; ax = first data sector (high)
+; di = sectors/fat for the boot media.
+;
+ public init
+init proc near
+ assume ds:nothing,es:nothing
+
+ FCLI
+ xor ax,ax
+ mov ds,ax
+
+; Save a pack of interrupt vectors...
+
+ push cs
+ pop es ; cannot use cs override for stos
+
+ mov cx, NUMROMVECTORS ; no. of rom vectors to be saved
+ mov si, offset RomVectors ; point to list of int vectors
+next_int:
+ lods byte ptr cs:[si] ; get int number
+ cbw ; assume < 128
+ shl ax, 1
+ shl ax, 1 ; int no * 4
+ mov di, ax
+ xchg si, di
+ lodsw
+ stosw
+ lodsw
+ stosw ; save the vector
+ xchg si, di
+ loop next_int
+
+; set up int 15 for new action ; M036
+
+ mov word ptr ds:[15h*4],offset Int15 ; M036
+ mov ds:[15h*4+2],cs ; M036
+
+
+
+; set up int 19 for new action
+
+ mov word ptr ds:[19h*4],offset int19
+ mov ds:[19h*4+2],cs
+
+;
+ xor dx,dx
+ mov ss,dx
+ mov sp,700h ;local stack
+ FSTI
+ assume ss:nothing
+
+ ; NTVDM we do not intialize the com,prn ports here
+ ; to stay seamless with the host OS
+ ; 15-Sep-1992 Jonle
+ ;
+ ; mov al,3 ; init com4
+ ; call aux_init
+ ; mov al,2 ; init com3
+ ; call aux_init
+ ; mov al,1 ; init com2
+ ; call aux_init
+ ; xor al,al ; init com1
+ ; call aux_init
+ ;
+ ; mov al,2 ; init lpt3
+ ; call print_init
+ ; mov al,1 ; init lpt2
+ ; call print_init
+ ; xor al,al ; init lpt1
+ ; call print_init
+
+ xor dx,dx
+ mov ds,dx ; to initialize print screen vector
+ mov es,dx
+
+ xor ax,ax
+ mov di,initspot
+ stosw ; init four bytes to 0
+ stosw
+
+ mov ax,cs ; fetch segment
+
+ mov ds:word ptr brkadr,offset cbreak ;break entry point
+ mov ds:brkadr+2,ax ;vector for break
+
+ mov ds:word ptr chrout*4,offset outchr
+ mov ds:word ptr chrout*4+2,ax
+
+ mov di,4
+ mov bx,offset intret ;will initialize rest of interrupts
+ xchg ax,bx
+ stosw ;location 4
+ xchg ax,bx
+ stosw ;int 1 ;location 6
+ add di,4
+ xchg ax,bx
+ stosw ;location 12
+ xchg ax,bx
+ stosw ;int 3 ;location 14
+ xchg ax,bx
+ stosw ;location 16
+ xchg ax,bx
+ stosw ;int 4 ;location 18
+
+ mov ds:word ptr 500h,dx ;set print screen & break =0
+ mov ds:word ptr lstdrv,dx ;clean out last drive spec
+
+
+ mov dx,sysinitseg
+ mov ds,dx
+
+ assume ds:sysinitseg
+
+; set pointer to resident device driver chain
+
+ mov word ptr device_list,offset res_dev_list
+ mov word ptr device_list+2,cs
+
+
+ mov current_dos_location,dos_load_seg ; will load MSDOS here
+
+
+ifdef EXTENDEDKEY
+
+; we will check if the system has ibm extended keyboard by
+; looking at a byte at 40:96. if bit 4 is set, then extended key board
+; is installed, and we are going to set keyrd_func to 10h, keysts_func to 11h
+; for the extended keyboard function. use cx as the temporary register.
+
+ xor cx,cx
+ mov ds,cx
+ assume ds:nothing
+ mov cl,ds:0496h ; get keyboard flag
+ test cl,00010000b
+ jz org_key ; orginal keyboard
+ mov byte ptr keyrd_func,10h ; extended keyboard
+ mov byte ptr keysts_func,11h ; change for ext. keyboard functions
+org_key:
+
+endif
+
+ push cs
+ pop ds
+ push cs
+ pop es
+
+ assume ds:datagrp, es:datagrp
+
+ mov di, offset endBIOSData ; BIOS data segment end address
+ shr di,1
+ shr di,1
+ shr di,1
+ shr di,1 ; Converted to segmnet
+ inc di ; para align
+
+ add di,datagrp ; Add segment of BIOS data
+ mov [dosdatasg],di ; di = to be dos data segment
+
+ mov di,dos_load_seg
+
+ SVC SVC_DEMLOADDOS ; di is segment to load DOS
+ ; If it fails it never comes back
+
+ jmp sysinit
+
+init endp
+
+
+;--------------------------------------------------------------------
+
+; al = device number
+
+print_init proc near
+ assume ds:nothing,es:nothing
+
+ cbw
+ mov dx,ax ; get printer port number into dx
+ mov ah,1 ;initalize printer port
+ int 17h ;call rom-bios routine
+ ret
+
+print_init endp
+
+;--------------------------------------------------------------------
+
+aux_init proc near
+ assume ds:nothing,es:nothing
+
+ cbw
+ mov dx,ax
+ mov al,rsinit ;2400,n,1,8 (msequ.inc)
+ mov ah,0 ;initalize aux port
+ int 14h ;call rom-bios routine
+ ret
+
+aux_init endp
+
+Bios_Data_Init ends
+ end
+
diff --git a/private/mvdm/softpc.new/bios/msint13.asm b/private/mvdm/softpc.new/bios/msint13.asm
new file mode 100644
index 000000000..a95c05d92
--- /dev/null
+++ b/private/mvdm/softpc.new/bios/msint13.asm
@@ -0,0 +1,214 @@
+ page ,160
+ title MS-DOS BIOS int 2f handler
+;
+;----------------------------------------------------------------------------
+;
+; Modification history
+;
+; 26-Feb-1991 sudeepb Ported for NT DOSEm
+;----------------------------------------------------------------------------
+
+; THIS FILE SHOULD BE NAMED INT2f.ASM RATHER THAN INT13.ASM AS I HAVE RIPPED
+; THE INT 13 SUPPORT. TO REDUCE CONFUSION WHEN PICKING FIXES FROM DOS 5.1
+; THE NAME IS RETAINED AS IT IS.
+
+ include version.inc ; set build flags
+ include biosseg.inc ; establish bios segment structure
+
+ include msequ.inc
+ include biostruc.inc
+
+ include msgroup.inc ; establish Bios_Data segment
+ include vint.inc
+
+multMULT equ 4ah
+multMULTGETHMAPTR equ 1
+multMULTALLOCHMA equ 2
+
+
+Win386_RelTS equ 80h
+NT_WAIT_BOP equ 5Ah
+
+bop MACRO callid
+ db 0c4h,0c4h,callid
+endm
+
+;SR;
+; Include file for WIN386 support
+;
+ include win386.inc
+
+
+ extrn SysinitPresent:byte
+ extrn FreeHMAPtr:word
+ extrn MoveDOSIntoHMA:dword
+
+;SR;
+;New variables for Win386 support
+;
+ extrn IsWin386:byte
+ extrn Win386_SI:byte
+ extrn SI_Next:dword
+
+
+; close data, open Bios_code segment
+
+ tocode
+
+ extrn Bios_Data_Word:word
+
+; Int 2f functions to support communication of external block device
+; drivers with msdisk are not supported. It also does'nt support
+; function 13h which replaces the int 13 vector.
+;
+
+ public i2f_handler
+i2f_handler proc far
+ assume ds:nothing,es:nothing
+
+ cmp ah,13h
+ jz i2f_iret
+ cmp ah,8
+ jz i2f_iret
+
+;
+;Check for WIN386 startup and return the BIOS instance data
+;
+ cmp ah,MULTWIN386
+ jz win386call
+
+ cmp ah, multMULT
+ jne i2f_iret
+ jmp handle_multmult
+
+i2f_iret:
+ FIRET
+
+
+;WIN386 startup stuff is done here. If starting up we set our WIN386 present
+;flag and return instance data. If exiting, we reset the WIN386 present flag
+;NOTE: We assume that the BIOS int 2fh is at the bottom of the chain.
+
+win386call:
+ push ds
+ mov ds,cs:Bios_Data_Word
+ assume ds:Bios_Data
+
+ cmp al, Win386_Init ; is it win386 initializing?
+ je Win386Init
+ cmp al, Win386_Exit ; is it win386 exiting?
+ je Win386Exit
+ cmp al, Win386_RelTS ; is it app release timeslice call?
+ jne win_iret ; if not, continue int2f chain
+
+ push ax ; It's the idling case - call MS BOP A
+ xor ax,ax ; with AX = 0
+ bop NT_WAIT_BOP
+ pop ax
+ xor al, al
+ jmp short win_iret
+
+Win386Exit:
+ test dx, 1 ; is it win386 or win286 dos extender?
+ jnz win_iret ; if not win386, then continue
+ and [IsWin386], 0 ; indicate that win386 is not present
+ jmp short win_iret
+
+Win386Init:
+ test dx, 1 ; is it win386 or win286 dos extender?
+ jnz win_iret ; if not win386, then continue
+
+ or [IsWin386], 1 ; Indicate WIN386 present
+ mov word ptr [SI_Next], bx ; Hook our structure into chain
+ mov word ptr [SI_Next + 2], es
+ mov bx, offset Win386_SI ; point ES:BX to Win386_SI
+ push ds
+ pop es
+
+win_iret:
+ pop ds
+ assume ds:nothing
+ jmp i2f_iret ;return back up the chain
+
+handle_multmult:
+ cmp al, multMULTGETHMAPTR
+ jne try_2
+
+ push ds
+ call HMAPtr ; get offset of free HMA
+ mov bx, 0ffffh
+ mov es, bx ; seg of HMA
+ mov bx, di
+ not bx
+ or bx, bx
+ jz @f
+ inc bx
+@@:
+ pop ds
+ jmp i2f_iret
+try_2:
+ cmp al, multMULTALLOCHMA
+ jne try_3
+
+ push ds
+ mov di, 0ffffh ; assume not enough space
+ mov es, di
+ call HMAPtr ; get offset of free HMA
+ assume ds:Bios_Data
+ cmp di, 0ffffh
+ je InsuffHMA
+ neg di ; free space in HMA
+ cmp bx, di
+ jbe @f
+ mov di, 0ffffh
+ jmp short InsuffHMA
+@@:
+ mov di, FreeHMAPtr
+ add bx, 15
+ and bx, 0fff0h
+ add FreeHMAPtr, bx ; update the free pointer
+ jnz InsuffHMA
+ mov FreeHMAPtr, 0ffffh ; no more HMA if we have wrapped
+InsuffHMA:
+ pop ds
+ assume ds:nothing
+ jmp i2f_iret
+try_3:
+ jmp i2f_iret
+i2f_handler endp
+
+;
+;--------------------------------------------------------------------------
+;
+; procedure : HMAPtr
+;
+; Gets the offset of the free HMA area ( with respect to
+; seg ffff )
+; If DOS has not moved high, tries to move DOS high.
+; In the course of doing this, it will allocate all the HMA
+; and set the FreeHMAPtr to past the end of the BIOS and
+; DOS code. The call to MoveDOSIntoHMA (which is a pointer)
+; enters the routine in sysinit1 called FTryToMoveDOSHi.
+;
+; RETURNS : offset of free HMA in DI
+; BIOS_DATA, seg in DS
+;
+;--------------------------------------------------------------------------
+;
+HMAPtr proc near
+ mov ds, Bios_Data_Word
+ assume ds:Bios_Data
+ mov di, FreeHMAPtr
+ cmp di, 0ffffh
+ jne @f
+ cmp SysinitPresent, 0
+ je @f
+ call MoveDOSIntoHMA
+ mov di, FreeHMAPtr
+@@:
+ ret
+HMAPtr endp
+
+
+Bios_Code ends
+ end
diff --git a/private/mvdm/softpc.new/bios/ntio.sym b/private/mvdm/softpc.new/bios/ntio.sym
new file mode 100644
index 000000000..62d9798dd
--- /dev/null
+++ b/private/mvdm/softpc.new/bios/ntio.sym
Binary files differ
diff --git a/private/mvdm/softpc.new/bios/spcemm.asm b/private/mvdm/softpc.new/bios/spcemm.asm
new file mode 100644
index 000000000..02440d144
--- /dev/null
+++ b/private/mvdm/softpc.new/bios/spcemm.asm
@@ -0,0 +1,167 @@
+;
+; spcemm.asm,
+;
+; 10-Dec-1992 Jonle , adapted from em_drvr.asm from Insignia solutions
+;
+; This code serves as a stub device driver for emm memory manager.
+; Its sole purpose is for apps to be able to identify that an emm driver is
+; loaded and that LIM services are available. This code is linked into the
+; device driver chain contains a strategy, interrupt and device header
+;
+; The driver should only be loaded if emm memory is available
+; from NTVDM.
+;
+
+BOP MACRO callid
+ db 0c4h, 0c4h, callid
+endm
+
+
+;
+; Request Header, for initialization
+;
+REQHEAD STRUC
+ReqLen DB ? ; Length in bytes of request block
+ReqUnit DB ? ; Block Device unit number
+ReqFunc DB ? ; Type of request
+ReqStat DW ? ; Status Word
+REQHEAD ENDS
+
+;
+; Segment definitions for ntio.sys,
+;
+include biosseg.inc
+include vint.inc
+
+SpcEmmSeg segment
+
+ assume cs:SpcEmmSeg,ds:nothing,es:nothing
+
+;
+; SpcEmmBeg - SpcEmmEnd
+;
+; Marks the resident code, anything outside of these markers
+; is discarded after intialization
+; 11-Dec-1992 Jonle
+;
+
+ public SpcEmmBeg
+
+SpcEmmBeg label byte
+
+
+;
+; character device Header
+; must be first in the .sys file
+;
+ dd -1 ;pointer to next device driver
+ dw 8000H ;attribute (plain character device)
+ dw offset STRATEGY ;pointer to device "strategy" routine
+ dw offset Interrupt ;pointer to device "interrupt" routine
+ db 'EMMXXXX0' ;8 byte name DO NOT CHANGE THE NAME
+
+;
+; Request Header address, saved here by strategy routine
+;
+pReqHdr dd ?
+
+
+;
+; Device "strategy" entry point, save request header address
+;
+Strategy proc far
+ mov word ptr cs:pReqHdr, bx
+ mov word ptr cs:pReqHdr+2, es
+ ret
+Strategy endp
+
+
+; EmmIsr - int 67h isr
+;
+EmmIsr: ; LIM Isr
+ bop 67h
+emmiret:
+ FIRET
+
+; ret trap for em function 'alter page map & call'
+EmmRet:
+ bop 68h
+ jmp emmiret
+
+
+
+;----------------------------------------------------------------------
+; Device "interrupt" entry point
+;----------------------------------------------------------------------
+Interrupt PROC FAR
+
+ push es
+ push di
+
+ les di, cs:pReqHdr ; check for valid commands
+ cmp es:[di.ReqFunc], 0ah
+ je validcmd
+ cmp es:[di.ReqFunc], 0
+ je validcmd
+
+ mov ax, 8003h ; we don't handle anything else
+ jmp short irptexit
+
+validcmd:
+ xor ax,ax
+
+irptexit:
+ or ax, 0100h ;tell em we finished
+ mov es:[di.ReqStat],AX ;store status in request header
+
+ pop di
+ pop es
+ ret
+
+Interrupt ENDP
+
+ public SpcEmmEnd
+SpcEmmEnd label byte
+
+ public InitSpcEmm
+;
+; InitSpcEmm Initializes Spc 32 bit memory manager
+; returns ax=0 for success
+;
+; Inputs: ds is expected seg for drv code, cs is temporary sysinitseg
+; Outputs: ax zero for success
+;
+InitSpcEmm proc near
+
+ ; BOP 66 - initialize LIM memory
+ ; pass the address of bop 68 to the em manager
+ ; in ds:dx and to return the number of em pages in BX
+ ;
+ ; NOTE: All EMM options come from pif file
+ ; There are NO command line options
+ xor bx, bx
+ mov dx, offset EmmRet
+ bop 66h
+ cmp bx, 0ffffh ;ffff means incorrect config (eg no 64K gap)
+ je fail
+ cmp bx, 0 ;check expanded memory is available
+ je fail
+
+ ; set up IVT for INT 67h
+ FCLI
+ xor ax, ax
+ mov es, ax
+ mov bx, offset EmmIsr
+ mov word ptr es:[67h*4], bx
+ mov word ptr es:[(67h*4)+2], ds
+ FSTI
+
+ ret
+fail:
+ mov ax, 0ffffh
+ ret
+
+InitSpcEmm endp
+
+SpcEmmSeg ends
+ end
diff --git a/private/mvdm/softpc.new/bios/spckbd.asm b/private/mvdm/softpc.new/bios/spckbd.asm
new file mode 100644
index 000000000..ba4d82c7b
--- /dev/null
+++ b/private/mvdm/softpc.new/bios/spckbd.asm
@@ -0,0 +1,2141 @@
+;******************************************************************************
+;
+; Copyright (c) 1992 Insignia Solutions Ltd.
+;
+; Program:
+;
+; Purpose:
+;
+; Version:
+;
+; Author: Dave Bartlett
+; Modifications:
+; 1) Tim June 92. Changes to get DEC PC working. Take over
+; IVT entries 6h (illegal instruction), 11h (equipment
+; check), 16h (keyboard BIOS), 17h (printer),
+; 42h (default video).
+; 2) Tim June 92. Changed version to 1.11
+; 3) Tim June 92. Avoid accesses to host ROM as far as
+; possible. Take over lots of IVT entries and continue to
+; point them at this driver.
+; 4) Tim July 92. Version num 1.12, put pseudo ROM stuff back in.
+; 5) Tim July 92. v 1.13, use SoftPC video BIOS when windowed.
+;
+; 6) 12-Sep-1992 Jonle, Merged with ntio.sys
+; cleanup usage of assumes espcially with ES
+; optimized loading of IVT
+; other general cleanup
+;
+; This obj module is intially loaded in a temporary memory location
+; along with ntio.sys. Ntio.sys will copy the resident code (marked by
+; SpcKbdBeg, SpcKbdEnd) into the permanent memory location which resides
+; just below the normal device drivers loaded by config.sys.
+;
+; The nonresident intialization code is run with CS= temp seg
+; and DS= final seg.
+;
+;******************************************************************************
+
+
+.286
+
+include vint.inc
+
+;================================================================
+; Macros and includes
+;================================================================
+
+bop MACRO callid
+ db 0c4h,0c4h,callid
+endm
+
+
+BIOS_CPU_QUIT equ 0FEh
+BIOS_KB_INT equ 9
+BIOS_INT15 equ 15h
+BIOS_PRINTER_IO equ 17h
+UNEXP_BOP equ 2
+RTC_WAIT_FLAG equ 0a0h ; offset of rtc_wait_flag in bios data seg
+VERSIONID equ 0BEEFh
+
+FULLSCREEN equ 1
+MAX_VIDEO_FUNC equ 1Ch
+GET_FONT_FUNC equ 11h
+
+VID_MODECHANGE equ 0
+MOUSE_LIGHT_PEN equ 4
+MIN_MOUSE_FUNC equ 0F0H
+MAX_MOUSE_FUNC equ 0F7H
+XTRA_MOUSE_FUNC equ 0FAH
+MS_VIDEO_STRING equ 13FFH
+
+MOUSE_VID_BOP equ 0BEh
+EGA_VIDEO_BOP equ 42h
+
+PRT_NOTBUSY equ 80h
+PRT_NUM_PORTS equ 3
+PRT_STATE_READY equ 0
+PRT_IRQ equ 10h
+PRT_LPT_BUSY equ 1
+
+TIMER_LOW equ 6ch
+TIMER_HIGH equ 6eh
+TIMER_OVFL equ 70h
+MOTOR_STATUS equ 3fh
+MOTOR_COUNT equ 40h
+
+; Keyboard buf ptrs
+BUFFER_HEAD equ 1ah
+BUFFER_TAIL equ 1ch
+BUFFER_START equ 80h
+BUFFER_END equ 82h
+
+; kb_flag and LED bits
+KB_FLAG equ 17h
+CAPS_STATE equ 40h
+NUM_STATE equ 20h
+SCROLL_STATE equ 10h
+
+KB_FLAG_1 equ 18h
+
+KB_FLAG_2 equ 97h
+KB_LEDS equ 07h ; Keyboard LED state bits
+KB_PR_LED equ 40h ; Mode indicator update
+
+
+KB_FLAG_3 equ 96h
+LC_E1 equ 01h
+LC_E0 equ 02h
+
+
+
+
+;..............................................keyboard constants
+
+; bits in kb_flag
+ RIGHT_SHIFT = 1
+ LEFT_SHIFT = 2
+ CTL_SHIFT = 4
+ ALT_SHIFT = 8
+
+
+; bit in kb_flag_1
+ HOLD_STATE = 8
+ SCROLL_SHIFT = 10h
+ NUM_SHIFT = 20h
+ CAPS_SHIFT = 40h
+ INS_SHIFT = 80h
+ SYS_SHIFT = 04h
+
+
+; IBM scan codes
+ CTL_KEY = 29
+ LEFT_SHIFTKEY = 42
+ RIGHT_SHIFTKEY = 54
+ ALT_KEY = 56
+ CAPS_KEY = 58
+ NUM_KEY = 69
+ SCROLL_KEY = 70
+ INS_KEY = 82
+
+
+
+;
+; Segment definitions for ntio.sys,
+;
+include biosseg.inc
+
+
+SpcKbdSeg segment
+
+ assume cs:SpcKbdSeg,ds:nothing,es:nothing
+
+;
+; SpcKbdBeg - SpcKbdEnd
+;
+; Marks the resident code, anything outside of these markers
+; is discarded after intialization
+; 13-Sep-1992 Jonle
+;
+ public SpcKbdBeg
+
+SpcKbdBeg label byte
+
+;
+; Reduced data table for Video 7 modes 0 and 2.
+; This table is extracted from our video7 ROM. Only text modes are
+; required, mode 0 and 1 are identical as are modes 2 and 3.
+;
+ega_parm_setup:
+
+;--40x25--
+ DB 40,24,16 ; width,height,character height
+ DW 00800H ; Page size in bytes
+
+ DB 008H, 003H, 000H, 002H ; Sequencer Parameters
+
+ DB 067H ;Misc Reg
+
+; CRTC Parameters
+ DB 02dH, 027H, 028H, 090H, 02bH
+ DB 0a0H, 0bfH, 01fH, 000H, 04fH
+ DB 00dH, 00eH, 000H, 000H, 000H
+ DB 000H, 09cH, 0aeH, 08fH, 014H
+ DB 01fH, 096H, 0b9H, 0a3H, 0ffH
+
+; Attribute parameters
+ DB 000H, 001H, 002H, 003H, 004H
+ DB 005H, 014H, 007H, 038H, 039H
+ DB 03aH, 03bH, 03cH, 03dH, 03eH
+ DB 03fH, 00cH, 000H, 00fH, 008H
+
+; Graph parameters
+ DB 000H, 000H, 000H, 000H, 000H
+ DB 010H, 00eH, 000H, 0ffH
+
+;--80x25--
+ DB 80,24,16 ; width,height,character height
+ DW 01000H ; Page size in bytes
+
+ DB 000H, 003H, 000H, 002H ; Sequencer Parameters
+
+ DB 067H ;Misc Reg
+
+; CRTC Parameters
+ DB 05fH, 04fH, 050H, 082H, 055H
+ DB 081H, 0bfH, 01fH, 000H, 04fH
+ DB 00dH, 00eH, 000H, 000H, 000H
+ DB 000H, 09cH, 08eH, 08fH, 028H
+ DB 01fH, 096H, 0b9H, 0a3H, 0ffH
+
+; Attribute parameters
+ DB 000H, 001H, 002H, 003H, 004H
+ DB 005H, 014H, 007H, 038H, 039H
+ DB 03aH, 03bH, 03cH, 03dH, 03eH
+ DB 03fH, 00cH, 000H, 00fH, 008H
+
+; Graph parameters
+ DB 000H, 000H, 000H, 000H, 000H
+ DB 010H, 00eH, 000H, 0ffH
+
+;--80x25 mono--
+ DB 80,24,16 ; width,height,character height
+ DW 01000H ; Page size in bytes
+
+ DB 000H, 003H, 000H, 003H ; Sequencer Parameters
+
+ DB 0a6H ;Misc Reg
+
+; CRTC Parameters
+ DB 05fH, 04fH, 050H, 082H, 055H
+ DB 081H, 0bfH, 01fH, 000H, 04dH
+ DB 00bH, 00cH, 000H, 000H, 000H
+ DB 000H, 083H, 0a5H, 05dH, 028H
+ DB 00dH, 063H, 0baH, 0a3H, 0ffH
+
+; Attribute parameters
+ DB 000H, 008H, 008H, 008H, 008H
+ DB 008H, 008H, 008H, 010H, 018H
+ DB 018H, 018H, 018H, 018H, 018H
+ DB 018H, 00eH, 000H, 00fH, 008H
+
+; Graph parameters
+ DB 000H, 000H, 000H, 000H, 000H
+ DB 010H, 00aH, 000H, 0ffH
+
+; Mode b (font load)
+
+ DB 5eh,32H,8 ; width,height,character height
+ DW 09700H ; Page size in bytes
+
+ DB 001H, 00fH, 000H, 006H ; Sequencer Parameters
+
+ DB 0e7H ;Misc Reg
+
+; CRTC Parameters
+ DB 06dH, 05dH, 05eH, 090H, 061H
+ DB 08fH, 0bfH, 01fH, 000H, 040H
+ DB 000H, 000H, 000H, 000H, 000H
+ DB 000H, 0a2H, 08eH, 099H, 02fH
+ DB 000H, 0a1H, 0b9H, 0e3H, 0ffH
+
+; Attribute parameters
+ DB 000H, 001H, 002H, 003H, 004H
+ DB 005H, 014H, 007H, 038H, 039H
+ DB 03aH, 03bH, 03cH, 03dH, 03eH
+ DB 03fH, 001H, 000H, 00fH, 000H
+
+; Graph parameters
+ DB 000H, 000H, 000H, 000H, 000H
+ DB 000H, 005H, 00fH, 0ffH
+
+
+;--350 scanline 40x25
+ DB 40,24,14 ; width,height,character height
+ DW 00800H ; Page size in bytes
+
+ DB 009H, 003H, 000H, 002H ; Sequencer Parameters
+
+ DB 0a3H ;Misc Reg
+
+; CRTC Parameters
+ DB 02dH, 027H, 028H, 090H, 02bH
+ DB 0a0H, 0bfH, 01fH, 000H, 04dH
+ DB 00bH, 00cH, 000H, 000H, 000H
+ DB 000H, 083H, 0a5H, 05dH, 014H
+ DB 01fH, 063H, 0baH, 0a3H, 0ffH
+
+; Attribute parameters
+ DB 000H, 001H, 002H, 003H, 004H
+ DB 005H, 014H, 007H, 038H, 039H
+ DB 03aH, 03bH, 03cH, 03dH, 03eH
+ DB 03fH, 008H, 000H, 00fH, 000H
+
+; Graph parameters
+ DB 000H, 000H, 000H, 000H, 000H
+ DB 010H, 00eH, 000H, 0ffH
+
+;--350 scanline 80x25
+ DB 80,24,14 ; width,height,character height
+ DW 01000H ; Page size in bytes
+
+ DB 001H, 003H, 000H, 002H ; Sequencer Parameters
+
+ DB 0a3H ;Misc Reg
+
+; CRTC Parameters
+ DB 05fH, 04fH, 050H, 082H, 055H
+ DB 081H, 0bfH, 01fH, 000H, 04dH
+ DB 00bH, 00cH, 000H, 000H, 000H
+ DB 000H, 083H, 0a5H, 05dH, 028H
+ DB 01fH, 063H, 0baH, 0a3H, 0ffH
+
+; Attribute parameters
+ DB 000H, 001H, 002H, 003H, 004H
+ DB 005H, 014H, 007H, 038H, 039H
+ DB 03aH, 03bH, 03cH, 03dH, 03eH
+ DB 03fH, 008H, 000H, 00fH, 000H
+
+; Graph parameters
+ DB 000H, 000H, 000H, 000H, 000H
+ DB 010H, 00eH, 000H, 0ffH
+
+;
+; End of baby mode table.
+;
+; Table of VGA bios 'capability' info for func 1b to point at.
+vga_1b_table db 07fh, 060h, 00fh, 000h, 000h, 000h, 000h, 007h
+ db 002h, 008h, 0ffh, 00eh, 000h, 000h, 03fh, 000h
+
+; Configuration table for INT 15 Func C0 to point at.
+conf_table dw 008h
+;; db 000h, 0fch, 002h, 000h, 070h, 000h, 000h, 000h, 000h
+ db 000h, 0fch, 002h, 074h, 070h, 000h, 000h, 000h, 000h
+
+
+PRT_BUF_SIZE equ 255
+
+;================================================================
+; Printer status table
+;================================================================
+prt_status db PRT_NUM_PORTS dup (?)
+prt_state db PRT_NUM_PORTS dup (?)
+prt_control db PRT_NUM_PORTS dup (?)
+prt_lpt_stat db PRT_NUM_PORTS dup (?)
+cur_buf_size dw PRT_BUF_SIZE
+prt_data_buf db PRT_BUF_SIZE dup (?) ; buffer in the 16bit side for perf.
+cur_lpt db 0ffh ; buffer is not being used
+cur_count dw ?
+cur_busy db 0 ; initially not busy
+
+;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+; Keyboard tables
+;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+
+
+shift_keys: ;K6
+ DB INS_KEY,CAPS_KEY,NUM_KEY,SCROLL_KEY
+ DB ALT_KEY,CTL_KEY,LEFT_SHIFTKEY,RIGHT_SHIFTKEY
+
+shift_masks: ;K7
+ DB INS_SHIFT,CAPS_SHIFT,NUM_SHIFT,SCROLL_SHIFT
+ DB ALT_SHIFT,CTL_SHIFT,LEFT_SHIFT,RIGHT_SHIFT
+
+ctl_n_table: ;K8
+ DB 27, -1, 0, -1, -1, -1, 30, -1
+ DB -1, -1, -1, 31, -1, 127, 148, 17
+ DB 23, 5, 18, 20, 25, 21, 9, 15
+ DB 16, 27, 29, 10, -1, 1, 19, 4
+ DB 6, 7, 8, 10, 11, 12, -1, -1
+ DB -1, -1, 28, 26, 24, 3, 22, 2
+ DB 14, 13, -1, -1, -1, -1, 150, -1
+ DB ' ', -1
+
+ctl_f_table: ;K9
+ DB 94, 95, 96, 97, 98, 99, 100, 101
+ DB 102, 103, -1, -1, 119, 141, 132, 142
+ DB 115, 143, 116, 144, 117, 145, 118, 146
+ DB 147, -1, -1, -1, 137, 138
+
+lowercase:
+ DB 27, '1', '2', '3', '4', '5', '6', '7', '8', '9' ;K10
+ DB '0', '-', '=', 8, 9, 'q', 'w', 'e', 'r', 't'
+ DB 'y', 'u', 'i', 'o', 'p', '[', ']', 13, -1, 'a'
+ DB 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', 39
+ DB 96, -1, 92, 'z', 'x', 'c', 'v', 'b', 'n', 'm'
+ DB ',', '.', '/', -1, '*', -1, ' ', -1
+
+lc_tbl_scan:
+ DB 59, 60, 61, 62, 63, 64, 65, 66, 67, 68
+ DB -1, -1
+
+base_case:
+ DB 71, 72, 73, -1, 75, -1, 77, -1, 79, 80
+ DB 81, 82, 83, -1, -1, 92, 133, 134 ;K15
+
+uppercase: ;K11
+ DB 27, '!', '@', '#', '$', '%', '^', '&', '*', '('
+ DB ')', '_', '+', 8, 0, 'Q', 'W', 'E', 'R', 'T'
+ DB 'Y', 'U', 'I', 'O', 'P', '{', '}', 13, -1, 'A'
+ DB 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"'
+ DB 126, -1, '|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M'
+ DB '<', '>', '?', -1, 0, -1, ' ', -1;
+
+ucase_scan:
+ DB 84, 85, 86, 87, 88, 89, 90, 91, 92, 93
+ DB -1, -1
+
+numb_state:
+ DB '7', '8', '9', '-', '4', '5', '6', '+', '1', '2' ;K14
+ DB '3', '0', '.' , -1, -1, 124, 135, 136
+
+alt_table:
+ DB 82, 79, 80, 81, 75, 76, 77, 71, 72, 73 ;K30
+ DB 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
+ DB 30, 31, 32, 33, 34, 35, 36, 37, 38, 44
+ DB 45, 46, 47, 48, 49, 50
+
+;================================================================
+; Keyboard break caller
+;================================================================
+
+keyboard_break_caller:
+ int 1bh ;keyboard break
+ bop %BIOS_CPU_QUIT
+
+;================================================================
+; Print screen caller
+;================================================================
+
+print_screen_caller:
+ int 5h ;print screen
+ bop %BIOS_CPU_QUIT
+
+;================================================================
+; Int 15 caller
+;================================================================
+; Tim modified int 15 caller. Copied from BIOS2. It gives CPU
+; a chance to take other interrupts. Suspect the extra jumps are
+; now harmless with IRET hooking.
+;int15h_caller:
+ ;int 15h
+ ;bop %BIOS_CPU_QUIT
+int15h_caller:
+ int 15h ; Cassette I/O.
+ jmp k1
+k1: jmp k2
+k2: jmp k3
+k3: BOP %BIOS_CPU_QUIT
+
+;================================================================
+; Unexpected interrupt handler
+;================================================================
+
+unexp_int:
+ bop %UNEXP_BOP
+ jmp iret_com
+
+;================================================================
+;Int 13 caller
+;================================================================
+int13h_caller:
+ int 13h
+ bop %BIOS_CPU_QUIT
+
+
+;================================================================
+; New interrupt 9h handler
+;================================================================
+
+int09h_vector:
+ push ax
+ xor ax, ax
+ bop %BIOS_KB_INT
+ pop ax
+ jmp iret_com
+
+ ; CarbonCopy traces int 9 in order to gain control
+ ; over where the kbd data is coming from (the physical kbd
+ ; or the serial link) The kbd_inb instruction must be visible
+ ; in the 16 bit code via int 1 tracing, for CarbonCopy to work.
+ ; Softpc assumes the exact location of the first nop
+ ; relative to the bop just above.
+ nop
+ nop
+ in al, 60h ; keyba_io_buffers
+ nop
+ nop
+ BOP %BIOS_CPU_QUIT
+
+
+
+
+
+;=================================================================
+; IRET hooks bop table
+;=================================================================
+
+
+IRET_HOOK = 5dh ;IRET hook BOP
+
+iret_bop_table:
+ bop %IRET_HOOK
+ db 0
+iret_end_first_entry:
+ bop %IRET_HOOK
+ db 1
+ bop %IRET_HOOK
+ db 2
+ bop %IRET_HOOK
+ db 3
+ bop %IRET_HOOK
+ db 4
+ bop %IRET_HOOK
+ db 5
+ bop %IRET_HOOK
+ db 6
+ bop %IRET_HOOK
+ db 7
+ bop %IRET_HOOK
+ db 8
+ bop %IRET_HOOK
+ db 9
+ bop %IRET_HOOK
+ db 10
+ bop %IRET_HOOK
+ db 11
+ bop %IRET_HOOK
+ db 12
+ bop %IRET_HOOK
+ db 13
+ bop %IRET_HOOK
+ db 14
+ bop %IRET_HOOK
+ db 15
+
+;================================================================
+; New interrupt 13h handler
+;================================================================
+
+int13h_vector:
+ cmp dl,80h ; 0 - 7f are floppy commands
+ jb int40h_vector
+
+ cmp ah,2 ; we fail the direct access commands
+ jb diskcmd ; read/write/seek/verify/format
+ cmp ah,5 ; but let others go through (disk tables etc)
+ jbe faildisk
+ cmp ah,0ah
+ jb diskcmd
+ cmp ah,0ch
+ ja diskcmd
+faildisk:
+ push ax
+ mov ax,1 ; direct access error panel
+ bop 59h
+ pop ax ; preserve AL for safety sake
+ mov ah, 80h ; error - timeout
+ stc
+ retf 2
+
+diskcmd:
+ bop 13h
+ retf 2
+
+;================================================================
+; New interrupt 40h handler
+;================================================================
+
+int40h_vector:
+; cmp ah,2 ; we fail the direct access commands
+; jb flopcmd ; read/write/seek/verify/format
+; cmp ah,5 ; but let others go through (disk tables etc)
+; jbe failflop
+; cmp ah,0ah
+; jb flopcmd
+; cmp ah,0ch
+; ja flopcmd
+failflop:
+; push ax
+; mov ax,0 ; direct access error panel
+; bop 59h
+; pop ax
+; mov ah, 80h ; error - timeout
+; stc
+; retf 2
+
+flopcmd:
+ bop 40h
+ retf 2
+
+;; waiting for diskette interrupt
+wait_int:
+ push ds
+ push ax
+ push cx
+ mov ax, 40h
+ mov ds, ax
+ mov cx, 10h
+wait_int_loop:
+ mov al, [3Eh]
+ test al, 80h
+ loopz wait_int_loop
+ pop cx
+ pop ax
+ pop ds
+ bop %BIOS_CPU_QUIT
+
+;; floppy parameters table
+floppy_table label byte
+
+ DB 01 ;; 360KB in 360KB
+ DW OFFSET md_tbl1
+ DB 82H ;; 360KB in 1,2MB
+ DW OFFSET md_tbl2
+ DB 02 ;; 1.2MB in 1.2MB
+ DW OFFSET md_tbl3
+ DB 03 ;; 720KB in 720KB
+ DW OFFSET md_tbl4
+ DB 84H ;; 720KB in 1.44MB
+ DW OFFSET md_tbl5
+ DB 04 ;; 1.44MB in 1.44MB
+ DW OFFSET md_tbl6
+ DB 85h ;; 720KB in 2.88MB
+ DW OFFSET md_tbl7
+ DB 85h ;; 1.44MB in 2.88MB
+ DW OFFSET md_tbl8
+ DB 5 ;; 2.88MB in 2.88MB
+ DW OFFSET md_tbl9
+
+
+md_tbl1:
+ ; MEDIA = 40 track low data rate; DRIVE = 40 track low data rate
+ DB 0DFh ; 1st specify byte
+ DB 2 ; 2nd specify byte
+ DB 25H ; motor off wait time
+ DB 2 ; ie 2 bytes/sector
+ DB 9 ; sectors/track
+ DB 02Ah ; gap length
+ DB 0FFh ; data length
+ DB 050h ; gap length for format
+ DB 0F6h ; fill byte for format
+ DB 15 ; head settle time/ms
+ DB 8 ; ie 1s motor start time
+ DB 39 ; maximum track number
+ DB 80H ; transfer rate
+
+md_tbl2:
+ ; MEDIA = 40 track low data rate; DRIVE = 80 track high data rate
+ DB 0DFh ; 1st specify byte
+ DB 2 ; 2nd specify byte
+ DB 25H ; motor off wait time
+ DB 2 ; ie 2 bytes/sector
+ DB 9 ; sectors/track
+ DB 02Ah ; gap length
+ DB 0FFh ; data length
+ DB 050h ; gap length for format
+ DB 0F6h ; fill byte for format
+ DB 15 ; head settle time/ms
+ DB 8 ; ie 1s motor start time
+ DB 39 ; maximum track number
+ DB 40H ; transfer rate
+
+md_tbl3:
+ ; MEDIA = 80 track high data rate; DRIVE = 80 track high data rate
+ DB 0DFh ; 1st specify byte
+ DB 2 ; 2nd specify byte
+ DB 25H ; motor off wait time
+ DB 2 ; ie 2 bytes/sector
+ DB 15 ; sectors/track
+ DB 01Bh ; gap length
+ DB 0FFh ; data length
+ DB 054h ; gap length for format
+ DB 0F6h ; fill byte for format
+ DB 15 ; head settle time/ms
+ DB 8 ; ie 1s motor start time
+ DB 79 ; maximum track number
+ DB 0 ; transfer rate
+
+md_tbl4:
+ ; MEDIA = 80 track low data rate; DRIVE = 80 track low data rate
+ DB 0DFh ; 1st specify byte
+ DB 2 ; 2nd specify byte
+ DB 25H ; motor off wait time
+ DB 2 ; ie 2 bytes/sector
+ DB 9 ; sectors/track
+ DB 02Ah ; gap length
+ DB 0FFh ; data length
+ DB 050h ; gap length for format
+ DB 0F6h ; fill byte for format
+ DB 15 ; head settle time/ms
+ DB 8 ; ie 1s motor start ime
+ DB 79 ; maximum track number
+ DB 80H ; transfer rate
+
+md_tbl5:
+ ; MEDIA = 80 track low data rate; DRIVE = 80 track high data rate
+ DB 0DFh ; 1st specify byte
+ DB 2 ; 2nd specify byte
+ DB 25H ; motor off wait time
+ DB 2 ; ie 2 bytes/sector
+ DB 9 ; sectors/track
+ DB 02Ah ; gap length
+ DB 0FFh ; data length
+ DB 050h ; gap length for format
+ DB 0F6h ; fill byte for format
+ DB 15 ; head settle time/ms
+ DB 8 ; ie 1s motor start time
+ DB 79 ; maximum track number
+ DB 80H ; transfer rate
+
+md_tbl6:
+ ; MEDIA = 80 track high data rate; DRIVE = 80 track high data rate
+ DB 0AFh ; 1st specify byte
+ DB 2 ; 2nd specify byte
+ DB 25H ; motor off wait time
+ DB 2 ; ie 2 bytes/sector
+ DB 18 ; sectors/track
+ DB 01Bh ; gap length
+ DB 0FFh ; data length
+ DB 06Ch ; gap length for format
+ DB 0F6h ; fill byte for format
+ DB 15 ; head settle time/ms
+ DB 8 ; ie 1s motor start time
+ DB 79 ; maximum track number
+ DB 0 ; transfer rate
+
+md_tbl7:
+ ;MEDIA = 80 tracks, 9 sectors/track; DRIVE = 80 tracks, 36 sectotrs per track
+
+ DB 0E1h ; 1st specify byte
+ DB 2 ; 2nd specify byte
+ DB 25H ; motor off wait time
+ DB 2 ; ie 2 bytes/sector
+ DB 9 ; sectors/track
+ DB 02Ah ; gap length
+ DB 0FFh ; data length
+ DB 050h ; gap length for format
+ DB 0F6h ; fill byte for format
+ DB 15 ; head settle time/ms
+ DB 8 ; ie 1s motor start ime
+ DB 79 ; maximum track number
+ DB 80H ; transfer rate
+md_tbl8:
+ ;MEDIA = 80 tracks, 18 sectors/track; DRIVE = 80 tracks, 36 sectotrs per track
+
+ DB 0D1h ; 1st specify byte
+ DB 2 ; 2nd specify byte
+ DB 25H ; motor off wait time
+ DB 2 ; ie 2 bytes/sector
+ DB 18 ; sectors/track
+ DB 01Bh ; gap length
+ DB 0FFh ; data length
+ DB 065h ; gap length for format
+ DB 0F6h ; fill byte for format
+ DB 15 ; head settle time/ms
+ DB 8 ; ie 1s motor start time
+ DB 79 ; maximum track number
+ DB 0 ; transfer rate
+
+md_tbl9:
+ ;MEDIA = 80 tracks, 36 sectors/track; DRIVE = 80 tracks, 36 sectotrs per track
+
+ DB 0A1h ; 1st specify byte
+ DB 2 ; 2nd specify byte
+ DB 25H ; motor off wait time
+ DB 2 ; ie 2 bytes/sector
+ DB 36 ; sectors/track
+ DB 038h ; gap length
+ DB 0FFh ; data length
+ DB 053h ; gap length for format
+ DB 0F6h ; fill byte for format
+ DB 15 ; head settle time/ms
+ DB 8 ; ie 1s motor start time
+ DB 79 ; maximum track number
+ DB 0C0h ; transfer rate
+
+
+
+floppy_table_len equ $ - floppy_table
+
+bios_floppy_table label byte
+ DB 0DFh ; 1st specify byte
+ DB 2 ; 2nd specify byte
+ DB 25H ; motor off wait time
+ DB 2 ; ie 2 bytes/sector
+ DB 18 ; sectors/track
+ DB 01Bh ; gap length
+ DB 0FFh ; data length
+ DB 054h ; gap length for format
+ DB 0F6h ; fill byte for format
+ DB 15 ; head settle time/ms
+ DB 8 ; ie 1s motor start time
+bios_floppy_table_len equ $ - bios_floppy_table
+
+;===============================================================
+; New interrupt 15h handler
+;================================================================
+; Tim, modified this to be like a "normal" SoftPC ROM.
+; Copied from BIOS2, but rtc_wait_flag is now referenced via ES not
+; DS.
+;
+; 17-Sep-1992 Jonle , ES ref to rtc_wait was change from assume ES
+; to seg overides to prevent accidents in assuming.
+;
+
+;int15h_vector:
+ ;bop %BIOS_INT15
+ ;iret
+;;;;;;;;;STF hide this int15h_vector:
+int15h_vector:
+ call DOSTI
+ cmp ah, 88h
+ je lbl1
+ cmp ah, 91h
+ je lbl1
+ cmp ah, 86h
+ je lbl2
+ BOP 15h
+ RETF 2
+lbl1: BOP 15h
+ jmp iret_com
+lbl2: BOP 15h
+ jc lbl5
+ push cx
+ push dx
+ push es ; Tim, save ES not DS.
+ mov ax, 40 ; point es to biosdata
+ mov es, ax
+ xchg dx, cx
+lbl3:
+ test byte ptr es:[RTC_WAIT_FLAG], 080h ; check for end of wait
+ loopz lbl3 ; dec timeout delay
+ jnz lbl4 ; exit if wait ended
+ sub dx, 1 ; dec error timeout counter
+ jnc lbl3 ; loop till counters timeout
+lbl4:
+ mov byte ptr es:[RTC_WAIT_FLAG], 0 ; set function inactive
+ pop es ; Kipper, restore ES not DS.
+ pop dx
+ pop cx
+ clc
+lbl5:
+ RETF 2
+
+;=================================================================
+; Regular SoftPC int 17 handler (especially important for DEC PCs)
+;=================================================================
+
+int17h_vector:
+;
+; Do a get status purely in 16-bit code but only if the printer is ready and
+;we don't have interrupts turned on. Otherwise we must do a BOP and let 32-bit
+;code handle it.
+;
+ push si
+ push dx
+ push ax
+ mov ax, dx ; dx = adapter no., ensure it is no
+ xor dx, dx ; greater than PRT_NUM_PORTS.
+ mov si, PRT_NUM_PORTS
+ div si
+ mov si, dx
+ pop ax
+ cmp ah, 2
+ je do_prt_status
+ or ah,ah
+ je do_write
+ jmp do_print_bop
+
+do_prt_status:
+ cmp byte ptr cs:[si + prt_state], PRT_STATE_READY
+ jne do_print_bop
+ test byte ptr cs:[si + prt_control], PRT_IRQ
+ je get_status
+ jmp short do_print_bop
+
+do_write:
+ cmp byte ptr cs:[cur_lpt],0ffh
+ jne check_lpti
+ mov byte ptr cs:[cur_lpt],dl
+ mov word ptr cs:[cur_count],0
+ mov byte ptr cs:[cur_busy],0ffh
+ jmp short do_print_bop
+check_lpti:
+ cmp byte ptr cs:[cur_lpt],dl
+ je buf_ok
+ push si
+ xor si,si
+ bop %BIOS_PRINTER_IO
+ pop si
+ mov word ptr cs:[cur_count],0
+ mov byte ptr cs:[cur_lpt],dl
+ jmp short do_print_bop
+buf_ok:
+ mov dx,word ptr cs:[cur_count]
+ mov si,dx
+ mov byte ptr cs:[si + prt_data_buf],al
+ inc word ptr cs:[cur_count]
+ cmp word ptr cs:[cur_count],PRT_BUF_SIZE
+ jne no_flushing
+ xor si,si ; sub-function 0 for this bop
+ bop %BIOS_PRINTER_IO
+ test ah,08h
+ jz flush_ok
+ dec word ptr cs:[cur_count]
+ jmp short int17h_end
+flush_ok:
+ mov word ptr cs:[cur_count],0
+no_flushing:
+ mov ah,90h
+ jmp short int17h_end
+
+do_print_bop:
+ mov si,0ffffh ; sub-function 1
+ bop %BIOS_PRINTER_IO
+ jmp int17h_end
+
+get_status:
+ test byte ptr cs:[si + prt_lpt_stat], PRT_LPT_BUSY
+ jne noset
+ or byte ptr cs:[si + prt_status], PRT_NOTBUSY
+noset:
+ mov ah, cs:[si + prt_status]
+ and ah, 0f8h
+ xor ah, 48h
+int17h_end:
+ pop dx
+ pop si
+iret_com:
+ FIRET
+
+
+;=================================================================
+; Pseudo-ROM vectuz, copied from BIOS2.ASM
+;=================================================================
+
+dummy_vector: ; Copied from BIOS2.ASM
+ jmp iret_com
+illegal_bop_vector:
+ bop 72h
+ jmp iret_com
+intD11_vector:
+ bop 72h
+ jmp iret_com
+
+int05h_vector: ; Print Screen func. copied from BIOS2.ASM
+ call DOSTI
+ PUSH AX
+ PUSH BX
+ PUSH CX
+ PUSH DX
+ PUSH DS
+ ;::::::::::::::::::::::::::::::::: Setup DS to point to BIOS data area
+ MOV AX,40H
+ MOV DS,AX
+ ;::::::::::::::::::::::::::::::: Print screen already in progress ????
+ CMP BYTE PTR DS:[100H],1
+ JE end_print
+ ;::::::::::::::::::::::::::::::::::::::::::::::: Set print screen busy
+ MOV BYTE PTR DS:[100h],1
+ ;:::::::::::::::::::::::::::::::::::::::::::::::::::: Get video status
+ MOV AH,15
+ INT 10H
+ MOV CH,AH ;No of columns
+ ;:::::::::::::::::::::::::::::::::: Setup no. of columns/rows to print
+ BOP 80H ;(BIOS_PS_PRIVATE_1)
+ MOV CL,AL ;No of rows
+ ;::::::::::::::::::::::::::::::::::: Print line feed / carriage return
+ CALL print_crlf
+ ;:::::::::::::::::::::::::::::::::::::::::: Get current cursor postion
+ PUSH CX
+ MOV AH,3
+ INT 10H
+ POP CX
+ ;::::::::::::::::::::::::::::::::::::::::::::::::: Save cursor postion
+ PUSH DX ;save current cursor postion
+ XOR DH,DH ;current row being processed
+start_print_col:
+ XOR DL,DL ;current column being processed
+ ;::::::::::::::::::::::::::::::::::::::::::::::: Start printing screen
+start_print_row:
+ ;:::::::::::::::::::::::::::::::::::::::::::::::::: Set cursor postion
+ PUSH DX ;save current row,column
+ MOV AH,2
+ INT 10H
+ ;::::::::::::::::::::::::::::::::::: Read character at current postion
+ MOV AH,8
+ INT 10H
+ ;::::::::::::::::::::::::::::::::::::::::::::::::::::: Print character
+ OR al,al
+ JNZ print_char
+ MOV AL,20H
+print_char:
+ XOR DX,DX
+ XOR AH,AH
+ INT 17H
+ ;:::::::::::::::::::::::::::::::::::::::::::: Check for printer errors
+ POP DX ;Restore current row,column
+ AND AH,25H
+ JZ cont2
+ MOV BYTE PTR DS:[100H],0FFH
+ JMP short exit_print
+ ;::::::::::::::::::::::::::::::::::::::::::: Move to mext print column
+cont2:
+ INC DL ;Inc current column
+ CMP DL,CH ;Current col compared to no. of cols
+ JB start_print_row
+ ;:::::::::::::::::::::::::::::::::::::::::: End of column, print CR/LF
+ CALL print_crlf
+ ;:::::::::::::::::::::::::::::::::::::::::::::::::: More rows to print
+ INC DH ;Inc current row
+ CMP DH,CL ;Current row compared to no. of rows
+ JBE start_print_col
+ MOV BYTE PTR DS:[0100H],0
+ ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Exit print
+exit_print:
+ ;:::::::::::::::::::::::::::::::::::::; Restore orginal cursor postion
+ POP DX
+ MOV AH,2
+ INT 10H
+ ;:::::::::::::::::::::::::::::::::::::::::::::::::::: Tidy up and exit
+end_print:
+ POP DS
+ POP DX
+ POP CX
+ POP BX
+ POP AX
+ jmp iret_com
+
+ ;::::::::::::::::::::::::::::::::::::::::::::::::::::::::: Print CR/LF
+print_crlf:
+ PUSH DX
+ XOR DX,DX
+ MOV AX,0DH
+ INT 17H
+ XOR DX,DX
+ MOV AX,0AH
+ INT 17H
+ POP DX
+ RET
+; End of int05_vector (print screen).
+
+int06h_vector:
+ bop 06h
+ jmp iret_com
+
+; IVT 7 is set to unexpected interrupt.
+
+
+int08h_vector:
+; The usual int8 handler modified for optimum performance.
+; - stays in 16 bit code (no BOP)
+; - keeps interrupts off when not needed
+; - calls int 1c directly
+;
+ call DOCLI ; make sure interrupts stay off until iret
+
+ push es
+ push ds ; save some registers
+ push ax
+ push dx
+
+ mov ax, 40h ; set ds to bios data area
+ mov ds, ax
+ xor ax, ax
+ mov es, ax ; set es to IVT seg for i1c callout
+
+ inc word ptr ds:[TIMER_LOW] ; inc time counters
+ jnz i8v1
+ inc word ptr ds:[TIMER_HIGH]
+i8v1:
+ cmp word ptr ds:[TIMER_HIGH], 018h ; check for 24 hours, wrap point
+ jnz i8v2
+ cmp word ptr ds:[TIMER_LOW], 0b0h
+ jnz i8v2
+
+
+ mov word ptr ds:[TIMER_HIGH], ax ; 24 hour wrap, set OVFL bit
+ mov word ptr ds:[TIMER_LOW], ax
+ mov byte ptr ds:[TIMER_OVFL], 1
+ or al, 8 ; set Overflow bit for fake flags
+
+ ;--- ; skip floppy motor stuff
+
+
+i8v2: ; handle the floppy motor stuff
+ push ax
+ dec byte ptr ds:[MOTOR_COUNT]
+ jnz i8v3
+ and byte ptr ds:[MOTOR_STATUS], 0f0h
+ mov al, 0ch
+ mov dx, 03f2h ; costly outb happens 1/256 timer tics...
+ out dx, al
+
+i8v3:
+ pop ax
+ ; call int1c user routine directly
+ lahf ; get lobyte of flags for fake flags
+ xchg ah,al
+ push ax ; put fake flags on the stack
+ call dword ptr es:[1ch*4] ; do it!
+ call DOCLI ; make sure interrupts stay off until iret
+
+ mov al, 20h ; send eoi
+ out 20h, al
+
+ pop dx ;restore the stack
+ pop ax
+ pop ds
+ pop es
+
+ jmp iret_com
+
+
+
+int0e_vector:
+ bop 0eh
+ jmp iret_com
+
+DOCLI:
+ FCLI
+ ret
+
+DOSTI:
+ FSTI
+ ret
+
+;
+; Tim August 92. Video BIOS grabber.
+; Call SPC BIOS when in windowed mode and the host BIOS when in full-screen.
+; Controled by value of 'use_host_int10'.
+; Try to limit bops by validating calling values. Mouse has to get first shot
+; and then video bios.
+;
+
+use_host_int10 db 01h ; native/softpc bios flag
+changing_mode db 01h ; delay handshake if in bios mode change
+
+PUBLIC int10h_vector
+
+int10h_vector:
+ cmp use_host_int10, FULLSCREEN
+ je nativebios
+
+ cmp ah,VID_MODECHANGE ; mode change??
+ je modechange
+ cmp ah,MAX_VIDEO_FUNC ; range check
+ ja mousecheck ; not a vid func but mouse has higher
+ cmp ah,MOUSE_LIGHT_PEN ; light pen special case
+ je mousebios
+spcbios:
+ bop EGA_VIDEO_BOP ; regular windowed Int 10
+ jmp viddone
+
+mousecheck:
+ cmp ah,MIN_MOUSE_FUNC ; range check mouse fn f0-f7 + fa.
+ jb badvid
+ cmp ah,MAX_MOUSE_FUNC
+ jbe mousebios
+ cmp ah,XTRA_MOUSE_FUNC
+ jne badvid
+
+mousebios: ; call softpc mouse video entrypoint
+ bop MOUSE_VID_BOP
+ jmp viddone
+
+modechange: ; windowed modechange. Mouse gets a look
+ mov changing_mode,1 ; then softpc video bios. If gfx mode then
+ bop MOUSE_VID_BOP ; will go fullscreen
+ ;;;nop
+ ;;;nop ; nops aid debugging
+ ;;;bop EGA_VIDEO_BOP ; will go fullscreen here
+ nop
+ nop
+ push ax ; save video mode which may have top bit set
+ and ax,7fh
+ cmp al,3
+ jbe endmode ; if graphics mode, repeat modechange to setup
+ cmp al,7 ; video card, else fall through
+ je endmode
+ pop ax
+ jmp nativebios
+endmode:
+ pop ax
+ mov changing_mode,0 ; Clear 'mode changing' flag.
+
+viddone:
+ jmp iret_com
+
+badvid: ; unrecognised video func
+ stc
+ jmp viddone
+
+nativebios:
+ mov changing_mode,0 ; Clear 'mode changing' flag.
+ cmp ax,MS_VIDEO_STRING ; ensure not MS special video string fn
+ je ms_wrt_string
+
+ cmp ah,MIN_MOUSE_FUNC ; could be a mouse call
+ jb chk_mse_vid
+ cmp ah,MAX_MOUSE_FUNC ; range check mouse fn f0-f7 + fa.
+ jbe mousebios
+ cmp ah,XTRA_MOUSE_FUNC
+ je mousebios
+ jmp jmp_native ; probably bad func but...
+
+chk_mse_vid:
+ cmp ah,MOUSE_LIGHT_PEN ; mouse handles light pen
+ je mousebios
+ cmp ah,VID_MODECHANGE
+ jne chk_font_change
+ bop MOUSE_VID_BOP ; mouse wants first sniff at mode changes
+ jmp jmp_native ; then fall through
+chk_font_change:
+ cmp ah,GET_FONT_FUNC
+ jne jmp_native
+ bop MOUSE_VID_BOP ; select mouse buffer for new no. of lines
+ ; then fall through
+
+jmp_native:
+ db 0EAh ; far jump
+host_int10 dd ? ; to native int 10 vector
+
+ms_wrt_string:
+ push si
+ push di
+ push bp
+go_loop1:
+ mov dx,46h ; looks a good value for flags
+ push dx ; make an iret frame
+ push cs
+ mov bx, offset go_cont
+ push bx
+ mov bx,7 ; set foreground color
+ mov ah,0eh ; set command to write a character
+ mov al,es:[di] ; get char
+ inc di
+ jmp jmp_native ; make far jmp to int 10 vector
+
+go_cont:
+ loop go_loop1 ;repeat until all through
+ pop bp
+ pop di
+ pop si
+ mov ax,1 ; return success
+ jmp viddone
+;
+; int 42 - 'old' video bios entry point. Use same windowed/fullscreen
+; redirection as Int 10 above.
+;
+int42h_vector:
+ cmp use_host_int10, FULLSCREEN
+ jz maybe_host_42_bios
+
+ bop 10h ; old video bop
+ jmp iret_com
+
+ ; If it's the special BIOS print string function, don't call the
+ ; host video BIOS cos it won't know what we are talking about.
+ ; It's only in our video BIOS.
+maybe_host_42_bios:
+ cmp AH, 013h
+ jnz gogo_host_42_bios
+ cmp AL, 0ffh
+ jz ms_wrt_string ; reuse path from Int 10
+
+gogo_host_42_bios:
+ db 0EAh ; far jump
+host_int42 dd ? ; to native int 42 vector
+
+int10h_caller:
+ int 10h ; Re-entrant video entry point.
+ bop 0feh
+
+int11h_vector: ; Equipment check.
+ bop 11h
+ jmp iret_com
+int12h_vector: ; Get memory size, copied from BIOS2.ASM
+ bop 12h
+ jmp iret_com
+
+; IVT 13 is floppy io, grabbed above to fake error status.
+
+int14h_vector: ; RS-232 serial comms, copied from BIOS2
+ bop 14h
+ jmp iret_com
+
+; Int 15 cassette io, is done above.
+
+
+
+; Idle indicators- All word sized, and dword aligned
+; Int 16 keyboard vector
+
+ align 4
+ public Icounter,CharsPerTick,MinTicks
+
+Icounter dw 0
+ dw 0
+CharsPerTick dw 0
+ dw 0
+MinTicks dw 50
+ dw 0
+
+int16h_vector:
+ push ds
+ push bx
+ mov bx, 40h ; bios data adressable
+ mov ds, bx
+ cmp ah, 10h
+ call DOCLI ; make sure interrupts are off
+ jb i16vStdFns
+ jmp i16vExtFns
+
+
+ ; The dispatch code must preserve the jz,dec,dec pattern
+ ; to return the same ah value as is returned by the
+ ; standard bios (0 for supported unless otherwise documented
+ ; and nonzero for unsupported). This is because some apps look
+ ; at the ret value of ah even tho it is a side effect of the
+ ; original dispatch code in the rom bios.
+
+i16vStdFns:
+ or ah, ah
+ jz i16v00h ; read key, wait
+ dec ah
+ jz i16v01h ; read key no wait
+ dec ah
+ jz i16v02h ; get shift state
+ dec ah
+ jz i16viret ; we don't support ah=3, set kbd rate
+ dec ah
+ jz i16viret ; undefined function
+ dec ah
+ jz i16v05h ; push char into kbd buffer
+ ; the rest are undefined\unsupported
+
+ ; normal iret exit
+i16viret:
+ pop bx
+ pop ds
+ jmp iret_com
+
+
+ ; return shift state in al
+i16v02h:
+ mov al, ds:[KB_FLAG]
+ jmp i16viret
+
+
+i16v05h:
+ push si
+ mov bx, word ptr ds:[BUFFER_TAIL]
+ mov si, bx
+ call IncrBuffPtr
+ cmp bx, word ptr ds:[BUFFER_HEAD]
+ je i16v05h1
+ mov word ptr ds:[si], cx
+ mov word ptr ds:[BUFFER_TAIL], bx
+ mov al, 0
+ pop si
+ jmp i16viret
+
+i16v05h1:
+ mov al, 1
+ pop si
+ jmp i16viret
+
+
+ ; read a character, wait if none available
+i16v00h:
+ mov bx, word ptr ds:[BUFFER_HEAD]
+ cmp bx, word ptr ds:[BUFFER_TAIL]
+ jne i16v00h1
+ call DOSTI
+ mov ax, 09002h
+ int 15h ; wait device
+
+i16v00h0:
+ call DOCLI
+ mov bx, word ptr ds:[BUFFER_HEAD]
+ cmp bx, word ptr ds:[BUFFER_TAIL]
+
+i16v00h1:
+ call UpdateLed
+ jne i16v00h2
+ call IdlePoll
+ jmp i16v00h0
+
+i16v00h2: ; translate.....
+ mov ax, [bx]
+ call IncrBuffPtr
+ mov word ptr ds:[BUFFER_HEAD], bx
+ call TranslateStd
+ jc i16v00h0
+ call IdleInit
+ jmp i16viret
+
+
+ ; read a character, nowait if none available
+i16v01h:
+ mov bx, word ptr ds:[BUFFER_HEAD] ;;maybe should turn IF on ??
+ cmp bx, word ptr ds:[BUFFER_TAIL]
+ mov ax, [bx]
+ call UpdateLed
+ je i16vretf1
+
+ call IdleInit
+ call TranslateStd
+ call DOSTI
+ jnc i16vretf5 ; got a key, all done!
+ call IncrBuffPtr ; throw away key
+ mov word ptr ds:[BUFFER_HEAD], bx
+ jmp i16v01h ; go for the next one
+
+
+ ; ExtKbd read a character, nowait if none available
+i16v11h:
+ mov bx, word ptr ds:[BUFFER_HEAD] ;;maybe should turn IF on ??
+ cmp bx, word ptr ds:[BUFFER_TAIL]
+ mov ax, [bx]
+ call UpdateLed
+ je i16vretf1 ; common retf stuff for nowait
+
+ call IdleInit
+ call TranslateExt
+ call DOSTI
+ jmp i16vretf5
+
+
+ ; retf2 exit preserving flags
+i16vretf1:
+ call DOSTI
+ push ax
+ lahf
+ push ax
+
+ mov ax, cs:Icounter
+ cmp ax, cs:MinTicks
+ jb i16vretf2
+
+ mov ah, 1 ; polling kbd, idle now
+ BOP 16h
+ jmp i16vretf4
+
+i16vretf2:
+ inc cs:CharsPerTick
+
+
+i16vretf4:
+ pop ax
+ sahf
+ pop ax
+
+i16vretf5:
+ pop bx
+ pop ds
+ retf 2
+
+
+
+i16vExtFns:
+ sub ah, 10h
+ jz i16v10h ; extended read key, wait
+ dec ah
+ jz i16v11h ; extended read key, nowait
+ dec ah
+ jz i16v12h ; extended shift status
+ jmp i16viret ; undefined
+
+
+ ; return extended shift state
+i16v12h:
+ mov al, ds:[KB_FLAG_1]
+ mov ah, al
+ and al, SYS_SHIFT
+ push cx
+ mov cl, 5
+ shl al, cl
+ pop cx
+ and ah, NOT (SYS_SHIFT+HOLD_STATE+INS_SHIFT)
+ or al, ah
+ mov ah, ds:[KB_FLAG_3]
+ and ah, NOT (LC_E1+LC_E0)
+ or ah, al
+ mov al, ds:[KB_FLAG]
+ jmp i16viret
+
+
+ ; ExtKbd read a character, wait if none available
+i16v10h:
+ mov bx, word ptr ds:[BUFFER_HEAD]
+ cmp bx, word ptr ds:[BUFFER_TAIL]
+ jne i16v10h1
+ call DOSTI
+ mov ax, 09002h
+ int 15h ; wait device
+
+i16v10h0:
+ call DOCLI
+ mov bx, word ptr ds:[BUFFER_HEAD]
+ cmp bx, word ptr ds:[BUFFER_TAIL]
+
+i16v10h1:
+ call UpdateLed
+ jne i16v10h2
+ call IdlePoll
+ jmp i16v10h0
+
+i16v10h2: ; translate.....
+ mov ax, [bx]
+ call IncrBuffPtr
+ mov word ptr ds:[BUFFER_HEAD], bx
+ call TranslateExt
+ call IdleInit
+ jmp i16viret
+
+
+
+; IdlePoll - Spins waiting for a key, doing idle callouts as needed
+; flags trashed, all registers preserved
+; interrupts are left on upon exit
+;
+IdlePoll proc near
+ push ax
+
+ call DOSTI
+ mov ah, 2 ; Idle_waitio
+ BOP 16h
+IPoll1:
+ mov bx, word ptr ds:[BUFFER_HEAD]
+ cmp bx, word ptr ds:[BUFFER_TAIL] ; interrupts are off only
+ jne IPoll3 ; safe to peek for change
+
+ mov ax, cs:Icounter
+ cmp ax, cs:MinTicks
+ jae IPoll2
+ inc cs:CharsPerTick
+ jmp IPoll1
+IPoll2:
+ mov ah, 1 ; idle now
+ BOP 16h
+IPoll3:
+ pop ax
+ ret
+IdlePoll endp
+
+
+
+
+; IdleInit - reinits the idle indicators, dups functionality
+; of IDLE_init()
+;
+IdleInit proc near
+
+ mov cs:Icounter, 0
+ mov cs:CharsPerTick, 0
+
+ ret
+IdleInit endp
+
+
+; TranslateExt - Retrieves and translates next scan code
+; pair for extended kbd
+;
+; input: ax - raw scan code pair
+; output: ax - translated scan code pair
+;
+; all other flags,registers preserved
+
+TranslateExt proc near
+
+ push bx
+ push ax
+ lahf
+ mov bx, ax
+ pop ax
+ push bx
+
+ cmp al, 0f0h
+ jne TExt1
+ or ah, ah
+ jz TExt1
+ xor al, al
+TExt1:
+ mov bx, ax
+ pop ax
+ sahf
+ mov ax, bx
+ pop bx
+ ret
+
+TranslateExt endp
+
+
+; TranslateStd - Retrieves and translates next scan code
+; pair for standard kbd
+;
+; input: ax - raw scan code pair
+; output: ax - translated scan code pair
+; returns carry for throw away
+; all other flags,registers preserved
+
+TranslateStd proc near
+
+ push bx
+ push ax
+ lahf
+ mov bx, ax
+ pop ax
+ push bx
+
+ cmp ah, 0e0h
+ jne TStd1
+
+ ; keypad enter or '/'
+ mov ah, 1ch ; assume enter key
+ cmp al, 0dh
+ je TStdNoCarry
+ cmp al, 0ah
+ je TStdNoCarry
+ mov ah, 35h ; oops it was key pad!
+ jmp TStdNoCarry
+
+TStd1:
+ cmp ah, 84h
+ ja TStdCarry ; extended key ?
+
+ cmp al, 0f0h ; fill in key ?
+ jne TStd2
+ or ah, ah ; ah = 0 is special
+ jz TStdNoCarry
+ jmp TStdCarry
+
+TStd2:
+ cmp al, 0e0h ; convert to compatible output
+ jne TStdNoCarry
+ or ah, ah
+ jz TStdNoCarry
+ xor al, al
+
+TStdNoCarry:
+ mov bx, ax
+ pop ax
+ sahf
+ mov ax, bx
+ pop bx
+ clc
+ ret
+
+TStdCarry:
+ mov bx, ax
+ pop ax
+ sahf
+ mov ax, bx
+ pop bx
+ stc
+ ret
+TranslateStd endp
+
+
+
+; IncrBuffPtr - increments the buffer pointer
+;
+; input: ds:bx - curr buf ptr
+; output: ds:bx - new buf ptr
+; does not update the bios buf ptr
+
+IncrBuffPtr proc near
+ inc bx
+ inc bx
+ cmp bx, word ptr ds:[BUFFER_END]
+ jne ibpExit
+ mov bx, word ptr ds:[BUFFER_START]
+ibpExit:
+ ret
+IncrBuffPtr endp
+
+
+
+; UpdateLed - forms the data byte for the mode indicators
+; updates the led bits (MAKE_LED,SEND_LED)
+;
+; input: none
+; output: led bits updated
+;
+; Caveats: all low flags,registers preserved
+; MUST be called with interrupts off
+; does not update the kbd hardware (send_led)
+;
+UpdateLed proc near
+
+ push bx
+ push cx
+ push ax
+ lahf
+ push ax
+
+ ; make_led
+ mov al, byte ptr ds:[KB_FLAG] ; get led bits
+ and al, CAPS_STATE+NUM_STATE+SCROLL_STATE
+ mov cl, 4
+ rol al, cl ; shift for kb_flag_2
+ and al, KB_LEDS ; only led mode bits
+
+ mov bl, byte ptr ds:[KB_FLAG_2]
+ xor bl, al ; see of different
+ and bl, KB_LEDS ; only led mode bits
+ jz UledExit
+
+
+ test byte ptr ds:[KB_FLAG_2], KB_PR_LED ;if update under way
+ jnz ULedExit ; skip update
+ or byte ptr ds:[KB_FLAG_2], KB_PR_LED ;else upd in progress
+
+ mov ah, 3 ; inform softpc to set lights
+ BOP 16h
+
+ and byte ptr ds:[KB_FLAG_2], NOT KB_LEDS ;clear led bits
+ or byte ptr ds:[KB_FLAG_2], al ;stick in new led bits
+ and byte ptr ds:[KB_FLAG_2], NOT KB_PR_LED ;clear upd bit
+
+ULedExit:
+ pop ax
+ sahf
+ pop ax
+ pop cx
+ pop bx
+
+ ret
+UpdateLed endp
+
+
+
+
+; IVT 17 is printer IO, done above.
+
+int18h_vector: ; ROM BASIC, copied from BIOS2.ASM
+ bop 18h
+ jmp iret_com
+int19h_vector: ; reboot vector, we terminate vdm!
+ bop 19h
+ jmp iret_com
+
+
+IdleTicLo dw 0
+IdleTicHi dw 0
+IdleTicNum db 0
+
+int1Ah_vector: ; Time of day.
+ call DOSTI
+ cmp ah, 2
+ jl i1aTic1
+
+ bop 1ah
+ jmp iret_com
+
+i1aTic1:
+ push ds ; bios data adressable
+ push bx
+ push ax
+ mov ax, 40h
+ mov ds, ax
+ pop ax
+ call DOCLI
+
+ or ah, ah ; fn 0 or fn 1 ?
+ jnz i1aTic5
+
+i1aTic2:
+ mov al, byte ptr ds:[TIMER_OVFL] ; GetTickCount
+ mov cx, word ptr ds:[TIMER_HIGH]
+ mov dx, word ptr ds:[TIMER_LOW]
+
+
+ ; If time stamp is within 1 tic of curr tic count
+ ; do idle polling managment
+
+ cmp cs:IdleTicHi, cx ; check TIMER_HIGH
+ jnz i1aTic8
+
+ mov bx, cs:IdleTicLo ; check TIMER_LOW
+ cmp bx, dx
+ jz i1aTic3
+ inc bx
+ cmp bx, dx
+ jnz i1aTic8
+
+
+i1aTic3:
+ inc cs:IdleTicNum ; Yes, inc poll count
+ cmp cs:IdleTicNum, 16 ; Is poll count too hi ?
+ jb i1aTic9
+
+ call DOSTI
+ xor ax,ax ; Yes, do idle BOP
+ dec cs:IdleTicLo ; make sure only bop once
+ BOP 5ah
+ call DOCLI
+ jmp short i1aTic2
+
+i1aTic5:
+ mov word ptr ds:[TIMER_LOW], dx ; SetTickCount
+ mov word ptr ds:[TIMER_HIGH], cx
+
+i1aTic8:
+ mov cs:IdleTicNum, 0 ; reset idle indicators
+
+i1aTic9:
+ mov cs:IdleTicLo, dx ; store time stamp
+ mov cs:IdleTicHi, cx
+ mov byte ptr ds:[TIMER_OVFL], 0 ; common TicCount exit
+ pop bx
+ pop ds
+ jmp iret_com
+
+
+; IVT 1B is keyboard break, set to dummy.
+
+
+int1Eh_vector:
+ bop 1eh
+ jmp iret_com
+
+int70h_vector: ; Real time clock, copied from BIOS1.ASM
+ bop 70h ; rtc_bios.c:rtc_int()
+ jmp iret_com
+
+int4Ah_caller:
+ call DOSTI ; Called from base\bios\rtc_bios.c:rtc_int()
+ int 4ah ; User installed alarm.
+ jmp r1
+r1: jmp r2
+r2: jmp r3
+r3:
+ call DOCLI
+ bop 0feh
+
+int71h_vector: ; redirect, copied from BIOS1.ASM
+ bop 71h
+ int 0Ah
+ jmp iret_com
+int75h_vector: ; NPX 287.
+ bop 75h
+ int 02h
+ jmp iret_com
+;=================================================================
+; End of pseudo-ROM vectuz.
+;=================================================================
+
+
+;================================================================
+; Wait for interrupts
+;================================================================
+
+cpu_nop_code:
+ call DOSTI
+ jmp short nxt1
+nxt1: jmp short nxt2
+nxt2: jmp short nxt3
+nxt3: bop %BIOS_CPU_QUIT
+
+ public SpcKbdEnd
+SpcKbdEnd label byte
+
+ align 4 ;; makes MIPS happy
+
+; offset table for redirected functions
+kio_table dw 29 dup(?)
+
+ public InstSpcKbd
+
+;
+; InstSpcKbd - Installs the softpc custom interrupt hooks
+;
+; Inputs: ds == Resident location of SysInitSeg
+; Outputs: None
+;
+InstSpcKbd proc near
+
+ pusha
+ call DOCLI
+
+ ; The following vectors are used for both x86\mips
+ ; The dos interrupts Int 25\Int26 are handled by the dos kerenl
+ xor ax, ax
+ mov es, ax
+ mov word ptr es:[08h*4], offset int08h_vector
+ mov word ptr es:[(08h*4)+2], ds
+ mov word ptr es:[09h*4], offset int09h_vector
+ mov word ptr es:[(09h*4)+2], ds
+ mov word ptr es:[13h*4], offset int13h_vector
+ mov word ptr es:[(13h*4)+2], ds
+ mov word ptr es:[16h*4], offset int16h_vector
+ mov word ptr es:[(16h*4)+2], ds
+ mov word ptr es:[40h*4], offset int40h_vector
+ mov word ptr es:[(40h*4)+2], ds
+ mov word ptr es:[19h*4], offset int19h_vector
+ mov word ptr es:[(19h*4)+2], ds
+ mov word ptr es:[1ah*4], offset int1Ah_vector
+ mov word ptr es:[(1ah*4)+2], ds
+
+
+
+ ; BOP 5F - send interesting addresses to softpc C BIOS
+ ; CS seg of kio_table
+ ; DS seg of resident keyboard code
+ ; DI offset of bop table
+ ; CX size of bop table entry
+ ; SI offset of kio_table
+ mov si,offset sysinitgrp:kio_table
+ push ds
+ push cs
+ pop ds
+ mov word ptr [si], offset shift_keys ;K6
+ mov word ptr [si+2], offset shift_masks ;K7
+ mov word ptr [si+4], offset ctl_n_table ;K8
+ mov word ptr [si+6], offset ctl_f_table ;K9
+ mov word ptr [si+8], offset lowercase ;K10
+ mov word ptr [si+10], offset uppercase ;K11
+ mov word ptr [si+12], offset alt_table ;K30
+ mov word ptr [si+14], offset dummy_vector
+ mov word ptr [si+16], offset print_screen_caller
+ mov word ptr [si+18], offset int15h_caller
+ mov word ptr [si+20], offset cpu_nop_code
+ mov word ptr [si+22], offset int15h_vector
+ mov word ptr [si+24], offset Icounter
+ mov word ptr [si+26], offset int4Ah_caller
+ mov word ptr [si+28], offset keyboard_break_caller
+ mov word ptr [si+30], offset int10h_caller
+ mov word ptr [si+32], offset int10h_vector
+ mov word ptr [si+34], offset use_host_int10
+ mov word ptr [si+36], offset ega_parm_setup
+ mov word ptr [si+38], offset changing_mode
+ mov word ptr [si+40], offset prt_status
+ mov word ptr [si+42], offset wait_int
+ mov word ptr [si+44], offset floppy_table
+ mov word ptr [si+46], offset vga_1b_table
+ mov word ptr [si+48], offset conf_table
+ mov word ptr [si+50], offset int08h_vector
+ mov word ptr [si+52], offset int13h_vector
+ mov word ptr [si+54], offset int13h_caller
+; The last entry is reserved for assertion checking
+ mov word ptr [si+56], VERSIONID
+ pop ds
+
+ ; mov si, offset kio_table
+ mov di, offset iret_bop_table
+ mov cx, offset iret_end_first_entry - offset iret_bop_table
+ mov ax, VERSIONID
+ bop 5fh
+ jc isk_int9
+ jmp isk_Exit
+isk_int9:
+
+ ; save old video int
+ xor ax, ax
+ mov es, ax
+ mov bx, es:[40h]
+ mov si, offset host_int10
+ mov word ptr ds:[si], bx
+ mov bx, es:[42h]
+ mov word ptr ds:[si+2], bx
+
+ ; save old secondary video int (42h)
+ mov bx, es:[108h]
+ mov si, offset host_int42
+ mov word ptr ds:[si], bx
+ mov bx, es:[10ah]
+ mov word ptr ds:[si+2], bx
+
+
+;-----------------------------------------------------------
+;
+; Crazy vector grabber
+;
+; Works OK on DEC PC when grab INT's 6, 11, 16, 17, 42.
+; Now try and avoid all accesses to host ROM.
+;
+; At this point we assume ES=0
+;-----------------------------------------------------------
+
+ ; Grab some prominent vectors for pseudo-ROM routines.
+ ; start at Int 0h and work our way up as needed
+ cld
+
+ mov di, 20
+ mov ax, offset int05h_vector ; INT 05h
+ stosw ; Print screen
+ mov ax, ds
+ stosw
+ mov ax, offset int06h_vector ; INT 06h
+ stosw ; Illegal instruction.
+ mov ax, ds
+ stosw
+ mov ax, offset unexp_int ; INT 07h
+ stosw
+ mov ax, ds
+ stosw
+
+ ; int 8h Timer hardware vector already done for both x86\mips
+ ; int 9h kbd hardware vector already done for both x86\mips
+ add di, 8
+
+ mov ax, offset unexp_int ; INT 0ah
+ stosw
+ mov ax, ds
+ stosw
+ mov ax, offset unexp_int ; INT 0bh
+ stosw
+ mov ax, ds
+ stosw
+ mov ax, offset unexp_int ; INT 0ch
+ stosw
+ mov ax, ds
+ stosw
+ mov ax, offset unexp_int ; INT 0dh
+ stosw
+ mov ax, ds
+ stosw
+ mov ax, offset int0e_vector ; INT 0eh
+ stosw ; Floppy hardware int.
+ mov ax, ds
+ stosw
+ mov ax, offset unexp_int ; INT 0fh
+ stosw
+ mov ax, ds
+ stosw
+ mov ax, offset int10h_vector ; INT 10h
+ stosw
+ mov ax, ds
+ stosw
+ mov ax, offset int11h_vector ; INT 11h
+ stosw ; Equipment check.
+ mov ax, ds
+ stosw
+ mov ax, offset int12h_vector ; INT 12h
+ stosw ; Get memory size.
+ mov ax, ds
+ stosw
+
+ ; int 13h already done (see above) for both mips\x86
+
+ mov di, 14h*4 ; Communications.
+ mov ax, offset int14h_vector
+ stosw
+ mov ax, ds
+ stosw
+ mov ax, offset int15h_vector ; INT 15h
+ stosw
+ mov ax, ds
+ stosw
+
+ ; int 16h kbd hardware vector already done for both x86\mips
+ add di, 4
+
+ mov ax, offset int17h_vector ; INT 17h
+ stosw
+ mov ax, ds
+ stosw
+ mov ax, offset int18h_vector ; INT 18h
+ stosw ; ROM BASIC.
+ mov ax, ds
+ stosw
+
+ ; int 19h (reboot vector) already done for both x86\mips
+
+ ; int 1ah, time of day, already done for both x86\mips
+
+ mov di, 1Bh*4
+ mov ax, offset dummy_vector ; INT 1Bh
+ stosw ; Keyboard break.
+ mov ax, ds
+ stosw
+ mov ax, offset dummy_vector ; INT 1Ch
+ stosw ; Timer tick.
+ mov ax, ds
+ stosw
+
+ mov di, 1Eh*4 ; Floppy parameters.
+ mov ax, offset bios_floppy_table
+ stosw
+ mov ax, ds
+ stosw
+
+ ; int 40h already done (see above) for both mips\x86
+
+ mov di, 41h*4
+ mov ax, offset unexp_int ; INT 41h
+ stosw ; Hard disk parameters.
+ mov ax, ds
+ stosw
+ mov ax, offset int42h_vector ; INT 42h
+ stosw ; Default video.
+ mov ax, ds
+ stosw
+
+ mov di, 70h*4 ; Real time clock init.
+ mov ax, offset int70h_vector
+ stosw
+ mov ax, ds
+ stosw
+ mov ax, offset int71h_vector ; INT 71h Redirect.
+ stosw
+ mov ax, ds
+ stosw
+ mov ax, offset intD11_vector ; INT 72h D11 int
+ stosw
+ mov ax, ds
+ stosw
+ mov ax, offset intD11_vector ; INT 73h D11 int
+ stosw
+ mov ax, ds
+ stosw
+ mov ax, offset intD11_vector ; INT 74h D11 int
+ stosw
+ mov ax, ds
+ stosw
+ mov ax, offset int75h_vector ; INT 75h 287 int
+ stosw
+ mov ax, ds
+ stosw
+ mov ax, offset intD11_vector ; INT 76h D11 int
+ stosw
+ mov ax, ds
+ stosw
+ mov ax, offset intD11_vector ; INT 77h D11 int
+ stosw
+ mov ax, ds
+ stosw
+
+
+isk_Exit:
+ call DOSTI
+ popa
+ ret
+
+InstSpcKbd endp
+
+SpcKbdSeg ends
+ end
diff --git a/private/mvdm/softpc.new/bios/spcmse.asm b/private/mvdm/softpc.new/bios/spcmse.asm
new file mode 100644
index 000000000..bfdea5c8b
--- /dev/null
+++ b/private/mvdm/softpc.new/bios/spcmse.asm
@@ -0,0 +1,5412 @@
+; Program: Installable Device Driver for Mouse.
+;
+; Purpose: to provide compatability with the
+; Microsoft MOUSE.SYS device driver.
+; the code here installs the driver and
+; hooks the IVT in exactly the same
+; way as the current Insignia MOUSE.COM.
+;
+; Version: 1.00 Date: 28th October 1992.
+;
+; Author: Andrew Watson
+;
+; Revisions:
+;
+; 23-June-1994 Williamh, made mode 4/5 and 12 work.
+;
+; 12-Sep-1992 Jonle, Merged with ntio.sys
+; optimized loading of IVT
+;
+; 5-March-1993 Andyw, Moved fullscreen text pointer code
+; from 32bit land to 16bit driver for
+; for speed purposes.
+;
+; This obj module is intially loaded in a temporary memory location
+; along with ntio.sys. Ntio.sys will copy the resident code (marked by
+; SpcMseBeg, SpcMseEnd) into the permanent memory location which resides
+; just below the normal device drivers loaded by config.sys.
+;
+; The nonresident intialization code is run with CS= temp seg
+; and DS= final seg.
+;
+;
+;****************************************************************
+
+.286
+ include vint.inc
+
+;================================================================
+; Defined constants used in the driver.
+;================================================================
+
+
+ VERSIONID equ 0BEEFh
+ MAXCMD equ 16
+ UNKNOWN equ 8003h
+ DONE equ 0100h
+ MOUSEVER equ 0003h
+ INT1_BOP equ 0BAh
+ INT2_BOP equ 0BBh
+ IO_LANG_BOP equ 0BCh
+ IO_INTR_BOP equ 0BDh
+ VIDEO_IO_BOP equ 0BEh
+ UNSIMULATE_BOP equ 0FEh
+ VIDEO equ 010h
+ UNEXP_BOP equ 2
+ FORCE_YODA equ 05bh
+ ANDYS_BOP equ 060h
+ STACKSIZE equ 200h-1
+
+ TRUE equ 0
+ FALSE equ 1
+ STORED equ 0
+ NOTSTORED equ 1
+ ON equ 0
+ OFF equ 1
+
+ MAJOR_RELEASE_NUMBER equ 6
+ MINOR_RELEASE_NUMBER equ 26
+
+
+
+;MACROSMACROSMACROSMACROSMACROSMACROSMACROSMACROSMACROSMACROSMACROSMACROSMACROS
+
+bop MACRO callid
+ db 0c4h,0c4h,callid
+endm
+
+
+
+;=============================================================================
+; Macro to reassign the stack segment register to point at the driver code
+; segment and the stack pointer to point to the most significant word in an
+; array reserved as the driver stack.
+;=============================================================================
+
+
+;; !!!! interrupt must be disabled before calling this function !!!!!!
+
+make_stack MACRO
+ LOCAL reent ;; a local symbol to this macro
+;; call DOCLI ;; turn off interrupts during this
+ ;; macro's execution even if the CPU
+ ;; does this for you when modifying SS
+ inc cs:reentrant ;; has the interrupt been nested?
+ jnz reent ;; not reentrant if == zero
+
+ ;; The driver code is not reentrant, so start the stack at the beginning
+
+ mov cs:top_of_stack,ss ;; save the entry SS
+ mov cs:top_of_stack-2,sp ;; save SP on the stack
+ push cs ;; the current code/data segment
+ pop ss ;; point SS at CS
+
+ ;; point SP at the next free stack location.
+
+ mov sp,offset top_of_stack-2 ;; The current stack pointer position
+
+reent: ;; REENTRANT > 0 therefore reentrancy exists
+ ;; The driver has gone reentrant due to a nested interrupt, so just
+ ;; leave the stack alone because it is the same under reentrancy.
+
+;; call DOSTI ;; reenable interrupts
+
+ ENDM
+
+;=============================================================================
+; Macro to return the stack pointer and segment back to what it was when
+; the driver was called.
+;=============================================================================
+
+kill_stack MACRO
+ LOCAL reent1
+;; cli
+ cmp cs:reentrant,0 ;; is the code currently reentrant?
+ jg reent1 ;; yes it is
+ mov sp,cs:top_of_stack-2 ;; pop SP
+ mov ss,cs:top_of_stack ;; pop SS
+reent1:
+ dec cs:reentrant ;; reduce the level of reentrancy
+;; call DOSTI
+ ENDM
+
+;MACROSMACROSMACROSMACROSMACROSMACROSMACROSMACROSMACROSMACROSMACROSMACROSMACROS
+
+;
+; Segment definitions for ntio.sys,
+;
+include biosseg.inc
+
+
+
+
+SpcMseSeg segment
+ assume cs:SpcMseSeg, ds:nothing, es:nothing
+
+;
+; SpcMseBeg - SpcMseEnd
+;
+; Marks the resident code, anything outside of these markers
+; is discarded after intialization
+; 15-Sep-1992 Jonle
+;
+
+ public SpcMseBeg
+
+SpcMseBeg label byte
+
+ ; CAUTION: for crazy apps mouse recognition
+ ;
+ ; The offset for int33h_vector must not be Zero for Borlands QuattroPro
+ ; The segment must not be in ROM area for pctools
+ ; to keep the int33h_vector from having an offset of ZERO
+ ; I have moved the data above it
+ ; 25-Sep-1992 Jonle
+
+
+; describe the default screen and cursor masks
+; remember that x86 machines are little-endian
+
+ ;;; include pointer.inc
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ ;;;; We'll Get this back to an include file soon but I'm including it like
+ ;;;; this for 'diplomatic' reasons. (ie I want to check this in without
+ ;;;; also doing an 'addfile' at this stage)!!! - Simon.
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; This data will be accessed, on occasion, word by word, so
+; be tidy and align to a word boundary
+
+align 2
+
+; Describe the default mouse pointer image. This is used if the
+; user decides to switch on the pointer without specifying an image.
+
+default_cursor dw 0011111111111111b
+ dw 0001111111111111b
+ dw 0000111111111111b
+ dw 0000011111111111b
+ dw 0000001111111111b
+ dw 0000000111111111b
+ dw 0000000011111111b
+ dw 0000000001111111b
+ dw 0000000000111111b
+ dw 0000000000011111b
+ dw 0000000111111111b
+ dw 0001000011111111b
+ dw 0011000011111111b
+ dw 1111100001111111b
+ dw 1111100001111111b
+ dw 1111110001111111b
+ dw 0000000000000000b
+ dw 0100000000000000b
+ dw 0110000000000000b
+ dw 0111000000000000b
+ dw 0111100000000000b
+ dw 0111110000000000b
+ dw 0111111000000000b
+ dw 0111111100000000b
+ dw 0111111110000000b
+ dw 0111110000000000b
+ dw 0110110000000000b
+ dw 0100011000000000b
+ dw 0000011000000000b
+ dw 0000001100000000b
+ dw 0000001100000000b
+ dw 0000000000000000b
+
+ ; Set up the memory where the working cursor is situated. It is
+ ; initialised to the default cursor image
+
+;****************** ALIGNED FOR PIXEL ZERO *******************************
+
+ ; screen mask
+
+even
+current_cursor db 00111111b,11111111b,11111111b
+ db 00011111b,11111111b,11111111b
+ db 00001111b,11111111b,11111111b
+ db 00000111b,11111111b,11111111b
+ db 00000011b,11111111b,11111111b
+ db 00000001b,11111111b,11111111b
+ db 00000000b,11111111b,11111111b
+ db 00000000b,01111111b,11111111b
+ db 00000000b,00111111b,11111111b
+ db 00000000b,00011111b,11111111b
+ db 00000001b,11111111b,11111111b
+ db 00010000b,11111111b,11111111b
+ db 00110000b,11111111b,11111111b
+ db 11111000b,01111111b,11111111b
+ db 11111000b,01111111b,11111111b
+ db 11111100b,01111111b,11111111b
+
+ ; cursor mask
+
+ db 00000000b,00000000b,00000000b
+ db 01000000b,00000000b,00000000b
+ db 01100000b,00000000b,00000000b
+ db 01110000b,00000000b,00000000b
+ db 01111000b,00000000b,00000000b
+ db 01111100b,00000000b,00000000b
+ db 01111110b,00000000b,00000000b
+ db 01111111b,00000000b,00000000b
+ db 01111111b,10000000b,00000000b
+ db 01111111b,11000000b,00000000b
+ db 01101100b,00000000b,00000000b
+ db 01000110b,00000000b,00000000b
+ db 00000110b,00000000b,00000000b
+ db 00000011b,00000000b,00000000b
+ db 00000011b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+
+
+;****************** ALIGNED FOR PIXEL ONE *******************************
+
+ ; screen mask
+
+AlignData1:
+ db 10011111b,11111111b,11111111b
+ db 10001111b,11111111b,11111111b
+ db 10000111b,11111111b,11111111b
+ db 10000011b,11111111b,11111111b
+ db 10000001b,11111111b,11111111b
+ db 10000000b,11111111b,11111111b
+ db 10000000b,01111111b,11111111b
+ db 10000000b,00111111b,11111111b
+ db 10000000b,00011111b,11111111b
+ db 10000000b,00001111b,11111111b
+ db 10000000b,11111111b,11111111b
+ db 10001000b,01111111b,11111111b
+ db 10011000b,01111111b,11111111b
+ db 11111100b,00111111b,11111111b
+ db 11111100b,00111111b,11111111b
+ db 11111110b,00111111b,11111111b
+
+ ; cursor mask
+
+ db 00000000b,00000000b,00000000b
+ db 00100000b,00000000b,00000000b
+ db 00110000b,00000000b,00000000b
+ db 00111000b,00000000b,00000000b
+ db 00111100b,00000000b,00000000b
+ db 00111110b,00000000b,00000000b
+ db 00111111b,00000000b,00000000b
+ db 00111111b,10000000b,00000000b
+ db 00111111b,11000000b,00000000b
+ db 00111111b,11100000b,00000000b
+ db 00110110b,00000000b,00000000b
+ db 00100011b,00000000b,00000000b
+ db 00000011b,00000000b,00000000b
+ db 00000001b,10000000b,00000000b
+ db 00000001b,10000000b,00000000b
+ db 00000000b,00000000b,00000000b
+
+
+;****************** ALIGNED FOR PIXEL TWO *******************************
+
+ ; screen mask
+
+AlignData2:
+ db 11001111b,11111111b,11111111b
+ db 11000111b,11111111b,11111111b
+ db 11000011b,11111111b,11111111b
+ db 11000001b,11111111b,11111111b
+ db 11000000b,11111111b,11111111b
+ db 11000000b,01111111b,11111111b
+ db 11000000b,00111111b,11111111b
+ db 11000000b,00011111b,11111111b
+ db 11000000b,00001111b,11111111b
+ db 11000000b,00000111b,11111111b
+ db 11000000b,01111111b,11111111b
+ db 11000100b,00111111b,11111111b
+ db 11001100b,00111111b,11111111b
+ db 11111110b,00011111b,11111111b
+ db 11111110b,00011111b,11111111b
+ db 11111111b,00011111b,11111111b
+
+ ; cursor mask
+
+ db 00000000b,00000000b,00000000b
+ db 00010000b,00000000b,00000000b
+ db 00011000b,00000000b,00000000b
+ db 00011100b,00000000b,00000000b
+ db 00011110b,00000000b,00000000b
+ db 00011111b,00000000b,00000000b
+ db 00011111b,10000000b,00000000b
+ db 00011111b,11000000b,00000000b
+ db 00011111b,11100000b,00000000b
+ db 00011111b,11110000b,00000000b
+ db 00011011b,00000000b,00000000b
+ db 00010001b,10000000b,00000000b
+ db 00000001b,10000000b,00000000b
+ db 00000000b,11000000b,00000000b
+ db 00000000b,11000000b,00000000b
+ db 00000000b,00000000b,00000000b
+
+
+;****************** ALIGNED FOR PIXEL THREE *******************************
+
+ ; screen mask
+
+AlignData3:
+ db 11100111b,11111111b,11111111b
+ db 11100011b,11111111b,11111111b
+ db 11100001b,11111111b,11111111b
+ db 11100000b,11111111b,11111111b
+ db 11100000b,01111111b,11111111b
+ db 11100000b,00111111b,11111111b
+ db 11100000b,00011111b,11111111b
+ db 11100000b,00001111b,11111111b
+ db 11100000b,00000111b,11111111b
+ db 11100000b,00000011b,11111111b
+ db 11100000b,00111111b,11111111b
+ db 11100010b,00011111b,11111111b
+ db 11100110b,00011111b,11111111b
+ db 11111111b,00001111b,11111111b
+ db 11111111b,00001111b,11111111b
+ db 11111111b,10001111b,11111111b
+
+ ; cursor mask
+
+ db 00000000b,00000000b,00000000b
+ db 00001000b,00000000b,00000000b
+ db 00001100b,00000000b,00000000b
+ db 00001110b,00000000b,00000000b
+ db 00001111b,00000000b,00000000b
+ db 00001111b,10000000b,00000000b
+ db 00001111b,11000000b,00000000b
+ db 00001111b,11100000b,00000000b
+ db 00001111b,11110000b,00000000b
+ db 00001111b,11111000b,00000000b
+ db 00001101b,10000000b,00000000b
+ db 00001000b,11000000b,00000000b
+ db 00000000b,11000000b,00000000b
+ db 00000000b,01100000b,00000000b
+ db 00000000b,01100000b,00000000b
+ db 00000000b,00000000b,00000000b
+
+
+;****************** ALIGNED FOR PIXEL FOUR *******************************
+
+ ; screen mask
+
+AlignData4:
+ db 11110011b,11111111b,11111111b
+ db 11110001b,11111111b,11111111b
+ db 11110000b,11111111b,11111111b
+ db 11110000b,01111111b,11111111b
+ db 11110000b,00111111b,11111111b
+ db 11110000b,00011111b,11111111b
+ db 11110000b,00001111b,11111111b
+ db 11110000b,00000111b,11111111b
+ db 11110000b,00000011b,11111111b
+ db 11110000b,00000001b,11111111b
+ db 11110000b,00011111b,11111111b
+ db 11110001b,00001111b,11111111b
+ db 11110011b,00001111b,11111111b
+ db 11111111b,10000111b,11111111b
+ db 11111111b,10000111b,11111111b
+ db 11111111b,11000111b,11111111b
+
+ ; cursor mask
+
+ db 00000000b,00000000b,00000000b
+ db 00000100b,00000000b,00000000b
+ db 00000110b,00000000b,00000000b
+ db 00000111b,00000000b,00000000b
+ db 00000111b,10000000b,00000000b
+ db 00000111b,11000000b,00000000b
+ db 00000111b,11100000b,00000000b
+ db 00000111b,11110000b,00000000b
+ db 00000111b,11111000b,00000000b
+ db 00000111b,11111100b,00000000b
+ db 00000110b,11000000b,00000000b
+ db 00000100b,01100000b,00000000b
+ db 00000000b,01100000b,00000000b
+ db 00000000b,00110000b,00000000b
+ db 00000000b,00110000b,00000000b
+ db 00000000b,00000000b,00000000b
+
+
+;****************** ALIGNED FOR PIXEL FIVE *******************************
+
+ ; screen mask
+AlignData5:
+
+ db 11111001b,11111111b,11111111b
+ db 11111000b,11111111b,11111111b
+ db 11111000b,01111111b,11111111b
+ db 11111000b,00111111b,11111111b
+ db 11111000b,00011111b,11111111b
+ db 11111000b,00001111b,11111111b
+ db 11111000b,00000111b,11111111b
+ db 11111000b,00000011b,11111111b
+ db 11111000b,00000001b,11111111b
+ db 11111000b,00000000b,11111111b
+ db 11111000b,00001111b,11111111b
+ db 11111000b,10000111b,11111111b
+ db 11111001b,10000111b,11111111b
+ db 11111111b,11000011b,11111111b
+ db 11111111b,11000011b,11111111b
+ db 11111111b,11100011b,11111111b
+
+ ; cursor mask
+
+ db 00000000b,00000000b,00000000b
+ db 00000010b,00000000b,00000000b
+ db 00000011b,00000000b,00000000b
+ db 00000011b,10000000b,00000000b
+ db 00000011b,11000000b,00000000b
+ db 00000011b,11100000b,00000000b
+ db 00000011b,11110000b,00000000b
+ db 00000011b,11111000b,00000000b
+ db 00000011b,11111100b,00000000b
+ db 00000011b,11111110b,00000000b
+ db 00000011b,01100000b,00000000b
+ db 00000010b,00110000b,00000000b
+ db 00000000b,00110000b,00000000b
+ db 00000000b,00011000b,00000000b
+ db 00000000b,00011000b,00000000b
+ db 00000000b,00000000b,00000000b
+
+
+;****************** ALIGNED FOR PIXEL SIX *******************************
+
+ ; screen mask
+
+AlignData6:
+ db 11111100b,11111111b,11111111b
+ db 11111100b,01111111b,11111111b
+ db 11111100b,00111111b,11111111b
+ db 11111100b,00011111b,11111111b
+ db 11111100b,00001111b,11111111b
+ db 11111100b,00000111b,11111111b
+ db 11111100b,00000011b,11111111b
+ db 11111100b,00000001b,11111111b
+ db 11111100b,00000000b,11111111b
+ db 11111100b,00000000b,01111111b
+ db 11111100b,00000111b,11111111b
+ db 11111100b,01000011b,11111111b
+ db 11111100b,11000011b,11111111b
+ db 11111111b,11100001b,11111111b
+ db 11111111b,11100001b,11111111b
+ db 11111111b,11110001b,11111111b
+
+ ; cursor mask
+
+ db 00000000b,00000000b,00000000b
+ db 00000001b,00000000b,00000000b
+ db 00000001b,10000000b,00000000b
+ db 00000001b,11000000b,00000000b
+ db 00000001b,11100000b,00000000b
+ db 00000001b,11110000b,00000000b
+ db 00000001b,11111000b,00000000b
+ db 00000001b,11111100b,00000000b
+ db 00000001b,11111110b,00000000b
+ db 00000001b,11111111b,00000000b
+ db 00000001b,10110000b,00000000b
+ db 00000001b,00011000b,00000000b
+ db 00000000b,00011000b,00000000b
+ db 00000000b,00001100b,00000000b
+ db 00000000b,00001100b,00000000b
+ db 00000000b,00000000b,00000000b
+
+
+;****************** ALIGNED FOR PIXEL SEVEN *******************************
+
+ ; screen mask
+AlignData7:
+
+ db 11111110b,01111111b,11111111b
+ db 11111110b,00111111b,11111111b
+ db 11111110b,00011111b,11111111b
+ db 11111110b,00001111b,11111111b
+ db 11111110b,00000111b,11111111b
+ db 11111110b,00000011b,11111111b
+ db 11111110b,00000001b,11111111b
+ db 11111110b,00000000b,11111111b
+ db 11111110b,00000000b,01111111b
+ db 11111110b,00000000b,00111111b
+ db 11111110b,00000011b,11111111b
+ db 11111110b,00100001b,11111111b
+ db 11111110b,01100001b,11111111b
+ db 11111111b,11110000b,11111111b
+ db 11111111b,11110000b,11111111b
+ db 11111111b,11111000b,11111111b
+
+ ; cursor mask
+
+ db 00000000b,00000000b,00000000b
+ db 00000000b,10000000b,00000000b
+ db 00000000b,11000000b,00000000b
+ db 00000000b,11100000b,00000000b
+ db 00000000b,11110000b,00000000b
+ db 00000000b,11111000b,00000000b
+ db 00000000b,11111100b,00000000b
+ db 00000000b,11111110b,00000000b
+ db 00000000b,11111111b,00000000b
+ db 00000000b,11111111b,10000000b
+ db 00000000b,11011000b,00000000b
+ db 00000000b,10001100b,00000000b
+ db 00000000b,00001100b,00000000b
+ db 00000000b,00000110b,00000000b
+ db 00000000b,00000110b,00000000b
+ db 00000000b,00000000b,00000000b
+
+
+; Data area reserved for the clipped cursor images. When the pointer
+; reaches byte 78 in the current raster, the image needs to be clipped
+; to prevent it from being wrapped to the left hand edge of the screen.
+; The image below stops that from happening by loading the image with
+; a 1's partial AND mask and a 0's partial XOR mask.
+; Note that byte 79 also needs a clipped image set.
+
+even
+clip_cursor78 db 00111111b,11111111b,11111111b
+ db 00011111b,11111111b,11111111b
+ db 00001111b,11111111b,11111111b
+ db 00000111b,11111111b,11111111b
+ db 00000011b,11111111b,11111111b
+ db 00000001b,11111111b,11111111b
+ db 00000000b,11111111b,11111111b
+ db 00000000b,01111111b,11111111b
+ db 00000000b,00111111b,11111111b
+ db 00000000b,00011111b,11111111b
+ db 00000001b,11111111b,11111111b
+ db 00010000b,11111111b,11111111b
+ db 00110000b,11111111b,11111111b
+ db 11111000b,01111111b,11111111b
+ db 11111000b,01111111b,11111111b
+ db 11111100b,01111111b,11111111b
+
+ ; cursor mask
+
+ db 00000000b,00000000b,00000000b
+ db 01000000b,00000000b,00000000b
+ db 01100000b,00000000b,00000000b
+ db 01110000b,00000000b,00000000b
+ db 01111000b,00000000b,00000000b
+ db 01111100b,00000000b,00000000b
+ db 01111110b,00000000b,00000000b
+ db 01111111b,00000000b,00000000b
+ db 01111111b,10000000b,00000000b
+ db 01111111b,11000000b,00000000b
+ db 01101100b,00000000b,00000000b
+ db 01000110b,00000000b,00000000b
+ db 00000110b,00000000b,00000000b
+ db 00000011b,00000000b,00000000b
+ db 00000011b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+
+
+;****************** ALIGNED FOR PIXEL ONE *******************************
+
+ ; screen mask
+
+AlignClip178:
+ db 10011111b,11111111b,11111111b
+ db 10001111b,11111111b,11111111b
+ db 10000111b,11111111b,11111111b
+ db 10000011b,11111111b,11111111b
+ db 10000001b,11111111b,11111111b
+ db 10000000b,11111111b,11111111b
+ db 10000000b,01111111b,11111111b
+ db 10000000b,00111111b,11111111b
+ db 10000000b,00011111b,11111111b
+ db 10000000b,00001111b,11111111b
+ db 10000000b,11111111b,11111111b
+ db 10001000b,01111111b,11111111b
+ db 10011000b,01111111b,11111111b
+ db 11111100b,00111111b,11111111b
+ db 11111100b,00111111b,11111111b
+ db 11111110b,00111111b,11111111b
+
+ ; cursor mask
+
+ db 00000000b,00000000b,00000000b
+ db 00100000b,00000000b,00000000b
+ db 00110000b,00000000b,00000000b
+ db 00111000b,00000000b,00000000b
+ db 00111100b,00000000b,00000000b
+ db 00111110b,00000000b,00000000b
+ db 00111111b,00000000b,00000000b
+ db 00111111b,10000000b,00000000b
+ db 00111111b,11000000b,00000000b
+ db 00111111b,11100000b,00000000b
+ db 00110110b,00000000b,00000000b
+ db 00100011b,00000000b,00000000b
+ db 00000011b,00000000b,00000000b
+ db 00000001b,10000000b,00000000b
+ db 00000001b,10000000b,00000000b
+ db 00000000b,00000000b,00000000b
+
+
+;****************** ALIGNED FOR PIXEL TWO *******************************
+
+ ; screen mask
+
+AlignClip278:
+ db 11001111b,11111111b,11111111b
+ db 11000111b,11111111b,11111111b
+ db 11000011b,11111111b,11111111b
+ db 11000001b,11111111b,11111111b
+ db 11000000b,11111111b,11111111b
+ db 11000000b,01111111b,11111111b
+ db 11000000b,00111111b,11111111b
+ db 11000000b,00011111b,11111111b
+ db 11000000b,00001111b,11111111b
+ db 11000000b,00000111b,11111111b
+ db 11000000b,01111111b,11111111b
+ db 11000100b,00111111b,11111111b
+ db 11001100b,00111111b,11111111b
+ db 11111110b,00011111b,11111111b
+ db 11111110b,00011111b,11111111b
+ db 11111111b,00011111b,11111111b
+
+ ; cursor mask
+
+ db 00000000b,00000000b,00000000b
+ db 00010000b,00000000b,00000000b
+ db 00011000b,00000000b,00000000b
+ db 00011100b,00000000b,00000000b
+ db 00011110b,00000000b,00000000b
+ db 00011111b,00000000b,00000000b
+ db 00011111b,10000000b,00000000b
+ db 00011111b,11000000b,00000000b
+ db 00011111b,11100000b,00000000b
+ db 00011111b,11110000b,00000000b
+ db 00011011b,00000000b,00000000b
+ db 00010001b,10000000b,00000000b
+ db 00000001b,10000000b,00000000b
+ db 00000000b,11000000b,00000000b
+ db 00000000b,11000000b,00000000b
+ db 00000000b,00000000b,00000000b
+
+
+;****************** ALIGNED FOR PIXEL THREE *******************************
+
+ ; screen mask
+
+AlignClip378:
+ db 11100111b,11111111b,11111111b
+ db 11100011b,11111111b,11111111b
+ db 11100001b,11111111b,11111111b
+ db 11100000b,11111111b,11111111b
+ db 11100000b,01111111b,11111111b
+ db 11100000b,00111111b,11111111b
+ db 11100000b,00011111b,11111111b
+ db 11100000b,00001111b,11111111b
+ db 11100000b,00000111b,11111111b
+ db 11100000b,00000011b,11111111b
+ db 11100000b,00111111b,11111111b
+ db 11100010b,00011111b,11111111b
+ db 11100110b,00011111b,11111111b
+ db 11111111b,00001111b,11111111b
+ db 11111111b,00001111b,11111111b
+ db 11111111b,10001111b,11111111b
+
+ ; cursor mask
+
+ db 00000000b,00000000b,00000000b
+ db 00001000b,00000000b,00000000b
+ db 00001100b,00000000b,00000000b
+ db 00001110b,00000000b,00000000b
+ db 00001111b,00000000b,00000000b
+ db 00001111b,10000000b,00000000b
+ db 00001111b,11000000b,00000000b
+ db 00001111b,11100000b,00000000b
+ db 00001111b,11110000b,00000000b
+ db 00001111b,11111000b,00000000b
+ db 00001101b,10000000b,00000000b
+ db 00001000b,11000000b,00000000b
+ db 00000000b,11000000b,00000000b
+ db 00000000b,01100000b,00000000b
+ db 00000000b,01100000b,00000000b
+ db 00000000b,00000000b,00000000b
+
+
+;****************** ALIGNED FOR PIXEL FOUR *******************************
+
+ ; screen mask
+
+AlignClip478:
+ db 11110011b,11111111b,11111111b
+ db 11110001b,11111111b,11111111b
+ db 11110000b,11111111b,11111111b
+ db 11110000b,01111111b,11111111b
+ db 11110000b,00111111b,11111111b
+ db 11110000b,00011111b,11111111b
+ db 11110000b,00001111b,11111111b
+ db 11110000b,00000111b,11111111b
+ db 11110000b,00000011b,11111111b
+ db 11110000b,00000001b,11111111b
+ db 11110000b,00011111b,11111111b
+ db 11110001b,00001111b,11111111b
+ db 11110011b,00001111b,11111111b
+ db 11111111b,10000111b,11111111b
+ db 11111111b,10000111b,11111111b
+ db 11111111b,11000111b,11111111b
+
+ ; cursor mask
+
+ db 00000000b,00000000b,00000000b
+ db 00000100b,00000000b,00000000b
+ db 00000110b,00000000b,00000000b
+ db 00000111b,00000000b,00000000b
+ db 00000111b,10000000b,00000000b
+ db 00000111b,11000000b,00000000b
+ db 00000111b,11100000b,00000000b
+ db 00000111b,11110000b,00000000b
+ db 00000111b,11111000b,00000000b
+ db 00000111b,11111100b,00000000b
+ db 00000110b,11000000b,00000000b
+ db 00000100b,01100000b,00000000b
+ db 00000000b,01100000b,00000000b
+ db 00000000b,00110000b,00000000b
+ db 00000000b,00110000b,00000000b
+ db 00000000b,00000000b,00000000b
+
+
+;****************** ALIGNED FOR PIXEL FIVE *******************************
+
+ ; screen mask
+AlignClip578:
+
+ db 11111001b,11111111b,11111111b
+ db 11111000b,11111111b,11111111b
+ db 11111000b,01111111b,11111111b
+ db 11111000b,00111111b,11111111b
+ db 11111000b,00011111b,11111111b
+ db 11111000b,00001111b,11111111b
+ db 11111000b,00000111b,11111111b
+ db 11111000b,00000011b,11111111b
+ db 11111000b,00000001b,11111111b
+ db 11111000b,00000000b,11111111b
+ db 11111000b,00001111b,11111111b
+ db 11111000b,10000111b,11111111b
+ db 11111001b,10000111b,11111111b
+ db 11111111b,11000011b,11111111b
+ db 11111111b,11000011b,11111111b
+ db 11111111b,11100011b,11111111b
+
+ ; cursor mask
+
+ db 00000000b,00000000b,00000000b
+ db 00000010b,00000000b,00000000b
+ db 00000011b,00000000b,00000000b
+ db 00000011b,10000000b,00000000b
+ db 00000011b,11000000b,00000000b
+ db 00000011b,11100000b,00000000b
+ db 00000011b,11110000b,00000000b
+ db 00000011b,11111000b,00000000b
+ db 00000011b,11111100b,00000000b
+ db 00000011b,11111110b,00000000b
+ db 00000011b,01100000b,00000000b
+ db 00000010b,00110000b,00000000b
+ db 00000000b,00110000b,00000000b
+ db 00000000b,00011000b,00000000b
+ db 00000000b,00011000b,00000000b
+ db 00000000b,00000000b,00000000b
+
+
+;****************** ALIGNED FOR PIXEL SIX *******************************
+
+ ; screen mask
+
+AlignClip678:
+ db 11111100b,11111111b,11111111b
+ db 11111100b,01111111b,11111111b
+ db 11111100b,00111111b,11111111b
+ db 11111100b,00011111b,11111111b
+ db 11111100b,00001111b,11111111b
+ db 11111100b,00000111b,11111111b
+ db 11111100b,00000011b,11111111b
+ db 11111100b,00000001b,11111111b
+ db 11111100b,00000000b,11111111b
+ db 11111100b,00000000b,11111111b
+ db 11111100b,00000111b,11111111b
+ db 11111100b,01000011b,11111111b
+ db 11111100b,11000011b,11111111b
+ db 11111111b,11100001b,11111111b
+ db 11111111b,11100001b,11111111b
+ db 11111111b,11110001b,11111111b
+
+ ; cursor mask
+
+ db 00000000b,00000000b,00000000b
+ db 00000001b,00000000b,00000000b
+ db 00000001b,10000000b,00000000b
+ db 00000001b,11000000b,00000000b
+ db 00000001b,11100000b,00000000b
+ db 00000001b,11110000b,00000000b
+ db 00000001b,11111000b,00000000b
+ db 00000001b,11111100b,00000000b
+ db 00000001b,11111110b,00000000b
+ db 00000001b,11111111b,00000000b
+ db 00000001b,10110000b,00000000b
+ db 00000001b,00011000b,00000000b
+ db 00000000b,00011000b,00000000b
+ db 00000000b,00001100b,00000000b
+ db 00000000b,00001100b,00000000b
+ db 00000000b,00000000b,00000000b
+
+
+;****************** ALIGNED FOR PIXEL SEVEN *******************************
+
+ ; screen mask
+AlignClip778:
+
+ db 11111110b,01111111b,11111111b
+ db 11111110b,00111111b,11111111b
+ db 11111110b,00011111b,11111111b
+ db 11111110b,00001111b,11111111b
+ db 11111110b,00000111b,11111111b
+ db 11111110b,00000011b,11111111b
+ db 11111110b,00000001b,11111111b
+ db 11111110b,00000000b,11111111b
+ db 11111110b,00000000b,11111111b
+ db 11111110b,00000000b,11111111b
+ db 11111110b,00000011b,11111111b
+ db 11111110b,00100001b,11111111b
+ db 11111110b,01100001b,11111111b
+ db 11111111b,11110000b,11111111b
+ db 11111111b,11110000b,11111111b
+ db 11111111b,11111000b,11111111b
+
+ ; cursor mask
+
+ db 00000000b,00000000b,00000000b
+ db 00000000b,10000000b,00000000b
+ db 00000000b,11000000b,00000000b
+ db 00000000b,11100000b,00000000b
+ db 00000000b,11110000b,00000000b
+ db 00000000b,11111000b,00000000b
+ db 00000000b,11111100b,00000000b
+ db 00000000b,11111110b,00000000b
+ db 00000000b,11111111b,00000000b
+ db 00000000b,11111111b,00000000b
+ db 00000000b,11011000b,00000000b
+ db 00000000b,10001100b,00000000b
+ db 00000000b,00001100b,00000000b
+ db 00000000b,00000110b,00000000b
+ db 00000000b,00000110b,00000000b
+ db 00000000b,00000000b,00000000b
+
+
+clip_cursor79 db 00111111b,11111111b,11111111b
+ db 00011111b,11111111b,11111111b
+ db 00001111b,11111111b,11111111b
+ db 00000111b,11111111b,11111111b
+ db 00000011b,11111111b,11111111b
+ db 00000001b,11111111b,11111111b
+ db 00000000b,11111111b,11111111b
+ db 00000000b,11111111b,11111111b
+ db 00000000b,11111111b,11111111b
+ db 00000000b,11111111b,11111111b
+ db 00000001b,11111111b,11111111b
+ db 00010000b,11111111b,11111111b
+ db 00110000b,11111111b,11111111b
+ db 11111000b,01111111b,11111111b
+ db 11111000b,01111111b,11111111b
+ db 11111100b,01111111b,11111111b
+
+ ; cursor mask
+
+ db 00000000b,00000000b,00000000b
+ db 01000000b,00000000b,00000000b
+ db 01100000b,00000000b,00000000b
+ db 01110000b,00000000b,00000000b
+ db 01111000b,00000000b,00000000b
+ db 01111100b,00000000b,00000000b
+ db 01111110b,00000000b,00000000b
+ db 01111111b,00000000b,00000000b
+ db 01111111b,00000000b,00000000b
+ db 01111111b,00000000b,00000000b
+ db 01101100b,00000000b,00000000b
+ db 01000110b,00000000b,00000000b
+ db 00000110b,00000000b,00000000b
+ db 00000011b,00000000b,00000000b
+ db 00000011b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+
+
+;****************** ALIGNED FOR PIXEL ONE *******************************
+
+ ; screen mask
+
+AlignClip179:
+ db 10011111b,11111111b,11111111b
+ db 10001111b,11111111b,11111111b
+ db 10000111b,11111111b,11111111b
+ db 10000011b,11111111b,11111111b
+ db 10000001b,11111111b,11111111b
+ db 10000000b,11111111b,11111111b
+ db 10000000b,11111111b,11111111b
+ db 10000000b,11111111b,11111111b
+ db 10000000b,11111111b,11111111b
+ db 10000000b,11111111b,11111111b
+ db 10000000b,11111111b,11111111b
+ db 10001000b,11111111b,11111111b
+ db 10011000b,11111111b,11111111b
+ db 11111100b,11111111b,11111111b
+ db 11111100b,11111111b,11111111b
+ db 11111110b,11111111b,11111111b
+
+ ; cursor mask
+
+ db 00000000b,00000000b,00000000b
+ db 00100000b,00000000b,00000000b
+ db 00110000b,00000000b,00000000b
+ db 00111000b,00000000b,00000000b
+ db 00111100b,00000000b,00000000b
+ db 00111110b,00000000b,00000000b
+ db 00111111b,00000000b,00000000b
+ db 00111111b,00000000b,00000000b
+ db 00111111b,00000000b,00000000b
+ db 00111111b,00000000b,00000000b
+ db 00110110b,00000000b,00000000b
+ db 00100011b,00000000b,00000000b
+ db 00000011b,00000000b,00000000b
+ db 00000001b,00000000b,00000000b
+ db 00000001b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+
+
+;****************** ALIGNED FOR PIXEL TWO *******************************
+
+ ; screen mask
+
+AlignClip279:
+ db 11001111b,11111111b,11111111b
+ db 11000111b,11111111b,11111111b
+ db 11000011b,11111111b,11111111b
+ db 11000001b,11111111b,11111111b
+ db 11000000b,11111111b,11111111b
+ db 11000000b,11111111b,11111111b
+ db 11000000b,11111111b,11111111b
+ db 11000000b,11111111b,11111111b
+ db 11000000b,11111111b,11111111b
+ db 11000000b,11111111b,11111111b
+ db 11000000b,11111111b,11111111b
+ db 11000100b,11111111b,11111111b
+ db 11001100b,11111111b,11111111b
+ db 11111110b,11111111b,11111111b
+ db 11111110b,11111111b,11111111b
+ db 11111111b,11111111b,11111111b
+
+ ; cursor mask
+
+ db 00000000b,00000000b,00000000b
+ db 00010000b,00000000b,00000000b
+ db 00011000b,00000000b,00000000b
+ db 00011100b,00000000b,00000000b
+ db 00011110b,00000000b,00000000b
+ db 00011111b,00000000b,00000000b
+ db 00011111b,00000000b,00000000b
+ db 00011111b,00000000b,00000000b
+ db 00011111b,00000000b,00000000b
+ db 00011111b,00000000b,00000000b
+ db 00011011b,00000000b,00000000b
+ db 00010001b,00000000b,00000000b
+ db 00000001b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+
+
+;****************** ALIGNED FOR PIXEL THREE *******************************
+
+ ; screen mask
+
+AlignClip379:
+ db 11100111b,11111111b,11111111b
+ db 11100011b,11111111b,11111111b
+ db 11100001b,11111111b,11111111b
+ db 11100000b,11111111b,11111111b
+ db 11100000b,11111111b,11111111b
+ db 11100000b,11111111b,11111111b
+ db 11100000b,11111111b,11111111b
+ db 11100000b,11111111b,11111111b
+ db 11100000b,11111111b,11111111b
+ db 11100000b,11111111b,11111111b
+ db 11100000b,11111111b,11111111b
+ db 11100010b,11111111b,11111111b
+ db 11100110b,11111111b,11111111b
+ db 11111111b,11111111b,11111111b
+ db 11111111b,11111111b,11111111b
+ db 11111111b,11111111b,11111111b
+
+ ; cursor mask
+
+ db 00000000b,00000000b,00000000b
+ db 00001000b,00000000b,00000000b
+ db 00001100b,00000000b,00000000b
+ db 00001110b,00000000b,00000000b
+ db 00001111b,00000000b,00000000b
+ db 00001111b,00000000b,00000000b
+ db 00001111b,00000000b,00000000b
+ db 00001111b,00000000b,00000000b
+ db 00001111b,00000000b,00000000b
+ db 00001111b,00000000b,00000000b
+ db 00001101b,00000000b,00000000b
+ db 00001000b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+
+
+;****************** ALIGNED FOR PIXEL FOUR *******************************
+
+ ; screen mask
+
+AlignClip479:
+ db 11110011b,11111111b,11111111b
+ db 11110001b,11111111b,11111111b
+ db 11110000b,11111111b,11111111b
+ db 11110000b,11111111b,11111111b
+ db 11110000b,11111111b,11111111b
+ db 11110000b,11111111b,11111111b
+ db 11110000b,11111111b,11111111b
+ db 11110000b,11111111b,11111111b
+ db 11110000b,11111111b,11111111b
+ db 11110000b,11111111b,11111111b
+ db 11110000b,11111111b,11111111b
+ db 11110001b,11111111b,11111111b
+ db 11110011b,11111111b,11111111b
+ db 11111111b,11111111b,11111111b
+ db 11111111b,11111111b,11111111b
+ db 11111111b,11111111b,11111111b
+
+ ; cursor mask
+
+ db 00000000b,00000000b,00000000b
+ db 00000100b,00000000b,00000000b
+ db 00000110b,00000000b,00000000b
+ db 00000111b,00000000b,00000000b
+ db 00000111b,00000000b,00000000b
+ db 00000111b,00000000b,00000000b
+ db 00000111b,00000000b,00000000b
+ db 00000111b,00000000b,00000000b
+ db 00000111b,00000000b,00000000b
+ db 00000111b,00000000b,00000000b
+ db 00000110b,00000000b,00000000b
+ db 00000100b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+
+
+;****************** ALIGNED FOR PIXEL FIVE *******************************
+
+ ; screen mask
+AlignClip579:
+
+ db 11111001b,11111111b,11111111b
+ db 11111000b,11111111b,11111111b
+ db 11111000b,11111111b,11111111b
+ db 11111000b,11111111b,11111111b
+ db 11111000b,11111111b,11111111b
+ db 11111000b,11111111b,11111111b
+ db 11111000b,11111111b,11111111b
+ db 11111000b,11111111b,11111111b
+ db 11111000b,11111111b,11111111b
+ db 11111000b,11111111b,11111111b
+ db 11111000b,11111111b,11111111b
+ db 11111000b,11111111b,11111111b
+ db 11111001b,11111111b,11111111b
+ db 11111111b,11111111b,11111111b
+ db 11111111b,11111111b,11111111b
+ db 11111111b,11111111b,11111111b
+
+ ; cursor mask
+
+ db 00000000b,00000000b,00000000b
+ db 00000010b,00000000b,00000000b
+ db 00000011b,00000000b,00000000b
+ db 00000011b,00000000b,00000000b
+ db 00000011b,00000000b,00000000b
+ db 00000011b,00000000b,00000000b
+ db 00000011b,00000000b,00000000b
+ db 00000011b,00000000b,00000000b
+ db 00000011b,00000000b,00000000b
+ db 00000011b,00000000b,00000000b
+ db 00000011b,00000000b,00000000b
+ db 00000010b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+
+
+;****************** ALIGNED FOR PIXEL SIX *******************************
+
+ ; screen mask
+
+AlignClip679:
+ db 11111100b,11111111b,11111111b
+ db 11111100b,11111111b,11111111b
+ db 11111100b,11111111b,11111111b
+ db 11111100b,11111111b,11111111b
+ db 11111100b,11111111b,11111111b
+ db 11111100b,11111111b,11111111b
+ db 11111100b,11111111b,11111111b
+ db 11111100b,11111111b,11111111b
+ db 11111100b,11111111b,11111111b
+ db 11111100b,11111111b,11111111b
+ db 11111100b,11111111b,11111111b
+ db 11111100b,11111111b,11111111b
+ db 11111100b,11111111b,11111111b
+ db 11111111b,11111111b,11111111b
+ db 11111111b,11111111b,11111111b
+ db 11111111b,11111111b,11111111b
+
+ ; cursor mask
+
+ db 00000000b,00000000b,00000000b
+ db 00000001b,00000000b,00000000b
+ db 00000001b,00000000b,00000000b
+ db 00000001b,00000000b,00000000b
+ db 00000001b,00000000b,00000000b
+ db 00000001b,00000000b,00000000b
+ db 00000001b,00000000b,00000000b
+ db 00000001b,00000000b,00000000b
+ db 00000001b,00000000b,00000000b
+ db 00000001b,00000000b,00000000b
+ db 00000001b,00000000b,00000000b
+ db 00000001b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+
+
+;****************** ALIGNED FOR PIXEL SEVEN *******************************
+
+ ; screen mask
+AlignClip779:
+
+ db 11111110b,11111111b,11111111b
+ db 11111110b,11111111b,11111111b
+ db 11111110b,11111111b,11111111b
+ db 11111110b,11111111b,11111111b
+ db 11111110b,11111111b,11111111b
+ db 11111110b,11111111b,11111111b
+ db 11111110b,11111111b,11111111b
+ db 11111110b,11111111b,11111111b
+ db 11111110b,11111111b,11111111b
+ db 11111110b,11111111b,11111111b
+ db 11111110b,11111111b,11111111b
+ db 11111110b,11111111b,11111111b
+ db 11111110b,11111111b,11111111b
+ db 11111111b,11111111b,11111111b
+ db 11111111b,11111111b,11111111b
+ db 11111111b,11111111b,11111111b
+
+ ; cursor mask
+
+ db 00000000b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+ db 00000000b,00000000b,00000000b
+
+CursorOffsetLUT dw current_cursor
+ dw AlignData1
+ dw AlignData2
+ dw AlignData3
+ dw AlignData4
+ dw AlignData5
+ dw AlignData6
+ dw AlignData7
+ClipOffsetLUT78 dw clip_cursor78
+ dw AlignClip178
+ dw AlignClip278
+ dw AlignClip378
+ dw AlignClip478
+ dw AlignClip578
+ dw AlignClip678
+ dw AlignClip778
+ClipOffsetLUT79 dw clip_cursor79
+ dw AlignClip179
+ dw AlignClip279
+ dw AlignClip379
+ dw AlignClip479
+ dw AlignClip579
+ dw AlignClip679
+ dw AlignClip779
+
+; pointer to the current look up table set for the pointer image.
+; The LUTs are swapped when the pointer enters bytes 78 and 79
+; along a scanline to prevent the pointer wrapping around the screen.
+
+PointerLUT label word
+ dw offset CursorOffsetLUT
+ ;;;;;;;;;;;;;;;;;;;;;;;
+ ;;;; End of what should be an include for pointer.inc
+ ;;;;;;;;;;;;;;;;;;;;;;;
+
+ even
+ clrgend dw 06e41h,07964h,05720h,07461h,06f73h,0f36eh
+ hiresylut dw 350,350,480,480
+
+;============================================================================
+; Surprisingly, a look up table multiply is much faster than
+; the shift - add instruction sequence for multiplying by 80.
+; So it would be silly not to use it eh? Times by 80 is needed
+; to convert a raster location (1 raster = 80 bytes) in pixel
+; y coordinates into a video buffer byte index
+; Note: Multiply by 80 is also used for text mode calculations
+; now! Andy on the 9/3/93
+;============================================================================
+ even
+
+ mult80lut label word
+
+ mulsum=0
+ REPT 480 ; number of VGA scanlines for mode 12h
+ dw mulsum
+ mulsum=mulsum+80
+ ENDM
+
+;============================================================================
+; A table to do a multiply by 320. This is used for converting number of
+; rasters into video buffer offsets for mode 13h (256 VGA colour mode).
+;============================================================================
+ even
+
+ mult320lut label word
+
+ mulsum=0
+ REPT 200 ; number of VGA scanlines for mode 13h
+ dw mulsum
+ mulsum=mulsum+320
+ ENDM
+ even
+
+;============================================================================
+; Look up table for use with modes 10h and 12h. This table provides the means
+; for the selection of a clipped or unclipped pointer image depending on the
+; current x position of the pointer.
+;============================================================================
+
+ ChooseImageLUT label word
+
+ REPT 624
+ dw offset CursorOffsetLUT
+ ENDM
+
+ REPT 8
+ dw offset ClipOffsetLUT78
+ ENDM
+
+ REPT 8
+ dw offset ClipOffsetLUT79
+ ENDM
+
+;============================================================================
+; Buffer arranged for 4 plane EGA video modes. The screen where
+; the pointer is going to be drawn is scanned plane by plane and
+; saved as bitplane separations.
+;============================================================================
+
+ even ; make sure that this data is word aligned
+
+ behindcursor dw 24 dup(?) ; Plane 0
+ dw 24 dup(?) ; Plane 1
+ dw 24 dup(?) ; Plane 2
+ dw 24 dup(?) ; Plane 3
+
+
+;============================================================================
+; a table of the video buffer segment for the supported
+; BIOS text and graphics modes.
+;============================================================================
+
+ even ; make sure that this data is word aligned
+
+ videomodetable dw 0b800h,0b800h ; modes 0,1
+ dw 0b800h,0b800h ; modes 2,3
+ dw 0b800h,0b800h ; modes 4,5
+ dw 0b800h,0b000h ; modes 6,7
+ dw 0ffffh,0ffffh ; n/a
+ dw 0ffffh,0ffffh ; n/a
+ dw 0ffffh,0a000h ; n/a,mode 0dh
+ dw 0a000h,0a000h ; modes 0eh,0fh
+ dw 0a000h,0a000h ; modes 10h,11h
+ dw 0a000h,0a000h ; modes 12h,13h
+ videobufferseg dw ?
+
+ even ; make sure that this data is word aligned
+
+ hotspot dw 2 dup(0)
+
+ VRAMlasttextcelloff label word ; last text offset in VRAM
+ VRAMlastbyteoff dw ? ; Last offset in VRAM
+ VRAMlastbitoff dw ? ; LSB: Where pointer is in byte
+ ; MSB: ODD/EVEN of the pointer
+ ; first scan line
+ LastXCounters dw ? ; last X looping counter
+ LastYCounters dw ? ; last Y looping counter
+ ; ODD in LSB and EVEN in MSB
+ lasttextimage dw ? ; text cell from last time
+
+ background dw NOTSTORED ; STORED if data in buffer
+ current_position_x dw ?
+ current_position_y dw ?
+ vidbytealigned dw ?
+ lastmaskrotate dw ?
+ lastvidmode db 0ffh ; the video mode during the last int.
+ internalCF db 0ffh ; the mouse driver keeps a flag called
+ ; the internal cursor flag. If the flag
+ ; = 0, then int 33h f1 will display the
+ ; pointer, -1 = default value.
+
+ ; 32 bit code writes to this area on a hardware interrupt and
+ ; when an app does an int 33h function 3, it reads the data
+ ; directly from here.
+ ; Data format is: word 0 -> button status
+ ; word 1 -> x virtual coordinate
+ ; word 2 -> y virtual coordinate
+
+ function3data dw 3 dup(?)
+
+ conditional_off db 0 ;!= 0 if conditional off is on
+ ;
+;=============================================================================
+; Data to determine the address of where the latches should be saved in the
+; video buffer for the current video mode.
+; latchcache contains the value looked up by saveVGAregisters and used by
+; restoreVGAregisters.
+;=============================================================================
+
+
+ latchcache dw ? ; location of latch cache in VRAM
+even
+latchhomeLUT label word
+ dw ? ; mode 0
+ dw ? ; mode 1
+ dw ? ; mode 2
+ dw ? ; mode 3
+ dw ? ; mode 4
+ dw ? ; mode 5
+ dw ? ; mode 6
+ dw ? ; mode 7
+ dw ? ; mode 8
+ dw ? ; mode 9
+ dw ? ; mode a
+ dw ? ; mode b
+ dw ? ; mode c
+ dw ? ; mode d
+ dw 80*200+78 ; mode e
+ dw 80*350+78 ; mode f
+ dw 80*350+78 ; mode 10
+ dw 80*480+78 ; mode 11
+ dw 80*480+78 ; mode 12
+
+;=============================================================================
+; CGA video mode 4 is a 2 bit per pixel graphics mode. The pointer images
+; received from the application (or the default images for that matter) are
+; described by a one bit per pixel map. This look up table provides the means
+; of conversion from one to two bits per pixel.
+;=============================================================================
+even
+LUT1to2bit label word
+ dw 00000h,00003h,0000Ch,0000Fh,00030h,00033h,0003Ch,0003Fh
+ dw 000C0h,000C3h,000CCh,000CFh,000F0h,000F3h,000FCh,000FFh
+ dw 00300h,00303h,0030Ch,0030Fh,00330h,00333h,0033Ch,0033Fh
+ dw 003C0h,003C3h,003CCh,003CFh,003F0h,003F3h,003FCh,003FFh
+ dw 00C00h,00C03h,00C0Ch,00C0Fh,00C30h,00C33h,00C3Ch,00C3Fh
+ dw 00CC0h,00CC3h,00CCCh,00CCFh,00CF0h,00CF3h,00CFCh,00CFFh
+ dw 00F00h,00F03h,00F0Ch,00F0Fh,00F30h,00F33h,00F3Ch,00F3Fh
+ dw 00FC0h,00FC3h,00FCCh,00FCFh,00FF0h,00FF3h,00FFCh,00FFFh
+
+ dw 03000h,03003h,0300Ch,0300Fh,03030h,03033h,0303Ch,0303Fh
+ dw 030C0h,030C3h,030CCh,030CFh,030F0h,030F3h,030FCh,030FFh
+ dw 03300h,03303h,0330Ch,0330Fh,03330h,03333h,0333Ch,0333Fh
+ dw 033C0h,033C3h,033CCh,033CFh,033F0h,033F3h,033FCh,033FFh
+ dw 03C00h,03C03h,03C0Ch,03C0Fh,03C30h,03C33h,03C3Ch,03C3Fh
+ dw 03CC0h,03CC3h,03CCCh,03CCFh,03CF0h,03CF3h,03CFCh,03CFFh
+ dw 03F00h,03F03h,03F0Ch,03F0Fh,03F30h,03F33h,03F3Ch,03F3Fh
+ dw 03FC0h,03FC3h,03FCCh,03FCFh,03FF0h,03FF3h,03FFCh,03FFFh
+
+ dw 0C000h,0C003h,0C00Ch,0C00Fh,0C030h,0C033h,0C03Ch,0C03Fh
+ dw 0C0C0h,0C0C3h,0C0CCh,0C0CFh,0C0F0h,0C0F3h,0C0FCh,0C0FFh
+ dw 0C300h,0C303h,0C30Ch,0C30Fh,0C330h,0C333h,0C33Ch,0C33Fh
+ dw 0C3C0h,0C3C3h,0C3CCh,0C3CFh,0C3F0h,0C3F3h,0C3FCh,0C3FFh
+ dw 0CC00h,0CC03h,0CC0Ch,0CC0Fh,0CC30h,0CC33h,0CC3Ch,0CC3Fh
+ dw 0CCC0h,0CCC3h,0CCCCh,0CCCFh,0CCF0h,0CCF3h,0CCFCh,0CCFFh
+ dw 0CF00h,0CF03h,0CF0Ch,0CF0Fh,0CF30h,0CF33h,0CF3Ch,0CF3Fh
+ dw 0CFC0h,0CFC3h,0CFCCh,0CFCFh,0CFF0h,0CFF3h,0CFFCh,0CFFFh
+
+ dw 0F000h,0F003h,0F00Ch,0F00Fh,0F030h,0F033h,0F03Ch,0F03Fh
+ dw 0F0C0h,0F0C3h,0F0CCh,0F0CFh,0F0F0h,0F0F3h,0F0FCh,0F0FFh
+ dw 0F300h,0F303h,0F30Ch,0F30Fh,0F330h,0F333h,0F33Ch,0F33Fh
+ dw 0F3C0h,0F3C3h,0F3CCh,0F3CFh,0F3F0h,0F3F3h,0F3FCh,0F3FFh
+ dw 0FC00h,0FC03h,0FC0Ch,0FC0Fh,0FC30h,0FC33h,0FC3Ch,0FC3Fh
+ dw 0FCC0h,0FCC3h,0FCCCh,0FCCFh,0FCF0h,0FCF3h,0FCFCh,0FCFFh
+ dw 0FF00h,0FF03h,0FF0Ch,0FF0Fh,0FF30h,0FF33h,0FF3Ch,0FF3Fh
+ dw 0FFC0h,0FFC3h,0FFCCh,0FFCFh,0FFF0h,0FFF3h,0FFFCh,0FFFFh
+
+;============================================================================
+; Table for selection of the correct pointer image for the current location
+; in the video buffer, when using video BIOS mode 4.
+;============================================================================
+
+mode4pointerLUT label word
+ REPT 76 ; for the first 76 bytes of scanline, use these
+ dw current_cursor
+ dw AlignData1
+ dw AlignData2
+ dw AlignData3
+ ENDM
+ dw clip_cursor78
+ dw AlignClip178
+ dw AlignClip278
+ dw AlignClip378
+ dw AlignClip478
+ dw AlignClip578
+ dw AlignClip678
+ dw AlignClip778
+ dw clip_cursor79
+ dw AlignClip179
+ dw AlignClip279
+ dw AlignClip379
+ dw AlignClip479
+ dw AlignClip579
+ dw AlignClip679
+ dw AlignClip779
+
+;============================================================================
+; Look up table to adjust CX on clipping in mode 4. This allows the mode4
+; pointer drawing algorithm to use the modes 10h/12h clipped pointer data
+; without having to modify it. The problem is that mode 10/12 expects the
+; data to be 4 bits per pixel and aligned to a word, whereas mode 4 is 2 bits
+; per pixel and aligns to a byte.
+;============================================================================
+
+mode4clipCXadjustLUT label word
+ adjtemp=0 ; data for pixel x-coordinates 0 -> 307
+ REPT 77
+ dw 4 dup(adjtemp)
+ adjtemp=adjtemp+1
+ ENDM
+ dw 4 dup(76) ; data for pixels 308 -> 311
+ dw 8 dup(78) ; data for pixels 312 -> 319
+
+
+;============================================================================
+; The CGA buffer is split at 2000h. Therefore if the pointer starts writing
+; below scanline 199 on the video display, the odd scanline video buffer
+; will become corrupted. In these cases, the pointer should be clipped to
+; display scanline 199. The look up table below maps loop counters to a
+; display scanline for this purpose.
+;
+; table arrangement (odd scanline data, even scanline data)
+;
+;============================================================================
+
+mode4clipDXLUT label word
+
+ db 200-15 dup(8,8) ; scanlines 0 -> 184
+ db 8,7 ; scanline 185
+ db 7,7 ; scanline 186
+ db 7,6 ; scanline 187
+ db 6,6 ; scanline 188
+ db 6,5 ; scanline 189
+ db 5,5 ; scanline 190
+ db 5,4 ; scanline 191
+ db 4,4 ; scanline 192
+ db 4,3 ; scanline 193
+ db 3,3 ; scanline 194
+ db 3,2 ; scanline 195
+ db 2,2 ; scanline 196
+ db 2,1 ; scanline 197
+ db 1,1 ; scanline 198
+ db 1,0 ; scanline 199
+
+mode4SelectedPointer label word
+ dw ?
+
+;==========================================================================
+; Some space into which the Medium resolution graphics pointer background
+; gets stored. Note that the 256 colour mode buffer encroaches on that of
+; mode 4.
+;==========================================================================
+
+bkgrnd256 label byte ; 256 colour buffer = 24*16 @ 1 byte/pix
+ db 384-64 dup(?) ; share the CGA buffer(=64 bytes)
+
+CGAbackgrnd label byte
+
+ db 24/4*16 dup(?) ; 24 pixels/row @ 4 pixels/byte for 16
+ ; rows.
+
+;===========================================================================
+; Jump table to redirect the code flow according to the current video mode.
+; Used in the 32 bit entry point procedure.
+; Pointer drawing routines.
+;===========================================================================
+even
+drawpointerJMPT label word
+ dw offset not_supported ; mode 0
+ dw offset not_supported ; mode 1
+IFDEF SIXTEENBIT
+ dw offset drawTextPointer ; mode 2
+ dw offset drawTextPointer ; mode 3
+ELSE
+ dw offset not_supported ; mode 2
+ dw offset not_supported ; mode 3
+ENDIF
+ dw offset drawMediumResPointer ; mode 4
+ dw offset drawMediumResPointer ; mode 5
+ dw offset not_supported ; mode 6
+IFDEF SIXTEENBIT
+ dw offset drawTextPointer ; mode 7
+ELSE
+ dw offset not_supported ; mode 7
+ENDIF
+ dw offset not_supported ; mode 8
+ dw offset not_supported ; mode 9
+ dw offset not_supported ; mode a
+ dw offset not_supported ; mode b
+ dw offset not_supported ; mode c
+ dw offset not_supported ; mode d
+ dw offset not_supported ; mode e
+ dw offset drawHiResPointer ; mode f
+ dw offset drawHiResPointer ; mode 10
+ dw offset drawHiResPointer ; mode 11
+ dw offset drawHiResPointer ; mode 12
+ dw offset drawC256pointer ; mode 13
+
+;===========================================================================
+; Jump table to redirect the code flow according to the current video mode.
+; Used in the 32 bit entry point procedure.
+; INT 33h Function 1 support modules.
+;===========================================================================
+even
+int33function1JMPT label word
+ dw offset not_supported ; mode 0
+ dw offset not_supported ; mode 1
+IFDEF SIXTEENBIT
+ dw offset TextInt33Function1 ; mode 2
+ dw offset TextInt33Function1 ; mode 3
+ELSE
+ dw offset not_supported ; mode 2
+ dw offset not_supported ; mode 3
+ENDIF
+ dw offset MediumResInt33Function1 ; mode 4
+ dw offset MediumResInt33Function1 ; mode 5
+ dw offset not_supported ; mode 6
+IFDEF SIXTEENBIT
+ dw offset TextInt33Function1 ; mode 7
+ELSE
+ dw offset not_supported ; mode 7
+ENDIF
+ dw offset not_supported ; mode 8
+ dw offset not_supported ; mode 9
+ dw offset not_supported ; mode a
+ dw offset not_supported ; mode b
+ dw offset not_supported ; mode c
+ dw offset not_supported ; mode d
+ dw offset not_supported ; mode e
+ dw offset HiResInt33Function1 ; mode f
+ dw offset HiResInt33Function1 ; mode 10
+ dw offset HiResInt33Function1 ; mode 11
+ dw offset HiResInt33Function1 ; mode 12
+ dw offset C256Int33Function1 ; mode 13
+
+;===========================================================================
+; Jump table to redirect the code flow according to the current video mode.
+; Used in the 32 bit entry point procedure.
+; INT 33h Function 2 support modules.
+;===========================================================================
+even
+int33function2JMPT label word
+ dw offset not_supported ; mode 0
+ dw offset not_supported ; mode 1
+IFDEF SIXTEENBIT
+ dw offset TextInt33Function2 ; mode 2
+ dw offset TextInt33Function2 ; mode 3
+ELSE
+ dw offset not_supported ; mode 2
+ dw offset not_supported ; mode 3
+ENDIF
+ dw offset MediumResInt33Function2 ; mode 4
+ dw offset MediumResInt33Function2 ; mode 5
+ dw offset not_supported ; mode 6
+IFDEF SIXTEENBIT
+ dw offset TextInt33Function2 ; mode 7
+ELSE
+ dw offset not_supported ; mode 7
+ENDIF
+ dw offset not_supported ; mode 8
+ dw offset not_supported ; mode 9
+ dw offset not_supported ; mode a
+ dw offset not_supported ; mode b
+ dw offset not_supported ; mode c
+ dw offset not_supported ; mode d
+ dw offset not_supported ; mode e
+ dw offset HiResInt33Function2 ; mode f
+ dw offset HiResInt33Function2 ; mode 10
+ dw offset HiResInt33Function2 ; mode 11
+ dw offset HiResInt33Function2 ; mode 12
+ dw offset C256Int33Function2 ; mode 13
+
+
+
+;==========================================================================
+; Some storage space for the critical VGA registers.
+;==========================================================================
+
+;Sequencer Registers
+
+seqregs label byte
+ db 4 dup(?) ; N.B. sequencer reset reg doesn't
+ ; get saved.
+
+; Graphics Controller Registers
+
+GCregs label byte
+ db 9 dup(?)
+
+;==========================================================================
+; The mouse driver's very own stack. To prevent unnecessary tears,
+; particulary from the application running in DOS land, a stack is
+; maintained by the driver. This prevents the driver routines from
+; blowing a very full stack elsewhere.
+; N.B. on leaving the driver, the stack should be empty!
+;==========================================================================
+
+even
+mouse_stack dw STACKSIZE dup(?)
+top_of_stack label word
+ dw ? ; this is where the stack starts
+
+;===========================================================================
+; The memory variable below is incremented on entry to the 16 bit code
+; and on exit, decremented. If an interrupt occurs during the execution of
+; this 16 bit code, the flag is incremented again, and thus greater than zero
+; so it is known that the code has been reentered and the stack must be
+; maintained accordingly.
+;===========================================================================
+
+reentrant dw -1
+
+;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+;
+; END OF DATA
+;
+;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+
+
+;================================================================
+; code to redirect the flow of control from the segment:offset for
+; the mouse interrupt (33h) as indicated in the IVT (the IVT entry
+; has been set to point to here) to the Insignia mouse driver code.
+;================================================================
+int33h_vector:
+
+ jmp short skip
+
+; High level language entry point.
+
+lvector db 0EAh ; far jump opcode
+loffset dw ? ; destination offset
+lseg dw ? ; destination segment
+
+; The pointer set to our interrupt 33h handler
+
+skip:
+
+;
+; Let's just jump to the C mouse_io_interrupt code for
+; RISC and bypass the ROM like 4.0 does.
+;
+
+ bop 0BDh
+ iret
+
+
+
+db 0EAh ; far jump opcode
+moff dw ? ; will be filled in by the driver code from the IVT
+mseg dw ? ; as before
+
+DOCLI:
+ FCLI
+ ret
+
+DOSTI:
+ FSTI
+ ret
+
+DOIRET:
+ FIRET
+
+
+;================================================================
+; Functions moved out of ROM - real ROMS mapped in
+;================================================================
+
+unexp_int:
+ bop UNEXP_BOP
+ jmp DOIRET
+
+mouse_io:
+ ;
+ ; INT 33h entry point
+ ;
+
+ jmp mio_hack
+ nop
+mouse_io_lang: ; entry point for HLL
+ pushf ; check ASAP if redundant show/hide cursor
+ push di ; save di,
+ mov di, [di+14] ; get first parameter (mouse function),
+ ; then duplicate mio_hack below.
+ ; this has to be done to preserve
+ ; compatibility between both ways to
+ ; call the mouse.
+ jz lbop ; F0
+ cmp di,2
+ jg lbop ; >F2
+ je miol_2
+miol_1:
+ mov conditional_off, 0 ; disable conditonal off
+ cmp [internalCF],0 ; is the flag already zero?
+ je miol_12_quit ; if so, do nothing
+ inc [internalCF] ; increment it
+ jz lbop
+miol_12_quit:
+ pop di
+ popf
+ jmp DOIRET
+
+miol_2:
+ dec [internalCF] ; decrement the pointer internal flag
+ cmp [internalCF], 0ffh; currently displayed?
+ jne miol_12_quit
+lbop:
+ pop ax
+ popf
+ bop IO_LANG_BOP
+ retf 8
+
+mio_hack: ; int 33h handler
+ pushf ; save up the flags
+ cmp ax,1 ; mouse show cursor.
+ je mio_1
+ cmp ax,2 ; mouse hide cursor.
+ je mio_2
+ cmp ax,3 ; get button status and mouse position.
+ je mio_3
+ cmp ax,9 ; set graphics cursor
+ je mio_9
+ cmp ax,10 ; set text cursor - not supported
+ je mio_quit ; return straight back to app.
+
+ jmp short hack1bop ; none of the above, so goto 32 bit land
+
+mio_1:
+ mov conditional_off, 0 ; disable conditional off
+ cmp [internalCF],0 ; is the flag already zero?
+ je mio_quit ; if so, do nothing
+ inc [internalCF] ; increment it
+ jz hack1bop ; just turned zero, so turn pointer on
+ ; via the 32 bit code.
+mio_quit:
+ popf
+ jmp DOIRET
+
+mio_2:
+ dec [internalCF] ; decrement the pointer internal flag
+ cmp [internalCF], 0ffh; currently displayed?
+ jne mio_quit ; Already turned off, so quit
+
+hack1bop:
+ popf
+ bop IO_INTR_BOP ; BOP to the 32 bit part of the handler
+ jmp DOIRET ; return back after the BOP to caller
+mio_9:
+ call int33function9 ; change the shape of the graphics pointer
+ popf ; restore the flag state
+ jmp DOIRET ; back to the caller
+mio_3:
+ mov bx,[function3data] ; return button status
+ mov cx,[function3data+2] ; return x coordinate
+ mov dx,[function3data+4] ; return x coordinate
+ popf ; return back to the application
+ jmp DOIRET ; via an iret.
+
+
+IFDEF MOUSE_VIDEO_BIOS
+
+mouse_video_io:
+
+ pushf
+ or ah,ah
+ jne mvio1
+ jmp do_bop
+mvio1:
+ cmp ax,6f05h
+ jne mvio2
+ jmp do_bop
+mvio2:
+ cmp ah,4
+ jne mvio3
+ jmp do_bop
+mvio3:
+
+;=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
+
+ ; Microsoft EGA.LIB function support
+ ; input: AH = the function required
+
+ cmp ah,0f0h ; is function F0 or greater?
+ jge mvio4 ; YES, so check to see if less than or == F7
+ jmp go_rom ; NO, so do rom stuff
+mvio4:
+ cmp ah,0f7h ; is it greater than F7
+ jg mvio5 ; YES, so test for == FA
+ jmp ega_lib ; NO, but in range F0 to F7, so do EGALIB emm
+mvio5:
+ cmp ah,0fah
+ jne mvio6
+ jmp egaFA
+mvio6:
+ jmp go_rom
+
+ ; to get here, must want to do mouse video functions 0f0h to 0f7h or
+ ; function 0fah.
+
+ jmp ega_lib
+
+ ; data area for EGA.LIB function support
+ ; Notice that the sequencer register buffer only has space
+ ; for four entrys even though it actually has five addressable
+ ; registers. The Sequencer RESET status is not stored, so the buffer
+ ; is arranged thus:
+ ; buffer offset 0 1 2 3
+ ; register index 1 2 3 4
+ ;
+
+ even
+
+ ega_current_crtc db 25 dup(?) ; driver's copy of CRTC regs
+ ega_current_seq db 4 dup(?) ; driver's copy of Seq regs
+ ega_current_graph db 9 dup(?) ; driver's copy of GC regs
+ ega_current_attr db 20 dup(?) ; driver's copy of AC regs
+ ega_current_misc db ? ; driver's copy of misc reg
+ dirty_crtc db 25 dup(?)
+ dirty_seq db 4 dup(?)
+ dirty_graph db 9 dup(?)
+ dirty_attr db 20 dup(?)
+ ega_default_crtc db 25 dup(?) ; default EGA register values
+ ega_default_seq db 4 dup(?) ; as set by the application
+ ega_default_graph db 9 dup(?) ; through a call to F7
+ ega_default_attr db 20 dup(?)
+ ega_default_misc db ?
+
+ relnum label word
+
+ release_major db MAJOR_RELEASE_NUMBER
+ release_minor db MINOR_RELEASE_NUMBER
+
+ even
+
+ egalibjmp label word ; crafty jump table to replace a base
+ ; switch
+ dw egaF0 ; 0F0h - read one EGA register
+ dw egaF1 ; 0F1h - write one EGA register
+ dw egaF2 ; 0F2h - read register range
+ dw egaF3 ; 0F3h - write register range
+ dw egaF4 ; 0F4h - read register set
+ dw egaF5 ; 0F5h - write register set
+ dw egaF6 ; 0F6h - revert to default regs
+ dw egaF7 ; 0F7h - define deflt reg table
+ dw noint ; 0F8h is not a valid function
+ dw noint ; 0F9h is not a valid function
+ dw egaFA ; 0FAh - interrogate driver
+ega_lib:
+
+ xor al,al
+ sub ax,0f0h ; create a jump table index
+ shl ax,1 ; remember that a word pointer is reqd
+ mov si,ax
+ jmp [egalibjmp+si] ; get the relavent jump address
+
+egaF0: ;--- Read an EGA register ----------------------------------------------
+
+ pusha
+ and bx,0ffh ; just want the lower byte (BL)
+F00:
+ cmp dx,0
+ jne F08
+ mov bl,byte ptr [ega_current_crtc+bx]
+ popa
+ jmp noint
+F08:
+ cmp dx,8
+ jne F010
+ dec bx ; note that RESET is not stored
+ mov bl,byte ptr [ega_current_seq+bx]
+ popa
+ jmp noint
+F010:
+ cmp dx,010h
+ jne F018
+ mov bl,byte ptr [ega_current_graph+bx]
+ popa
+ jmp noint
+F018:
+ cmp dx,018h
+ jne F020
+ mov bl,byte ptr [ega_current_attr+bx]
+ popa
+ jmp noint
+F020:
+ cmp dx,020h
+ jne F028
+ mov bl,byte ptr [ega_current_misc]
+
+F028: ; do nothing for this case
+F0quit:
+ popa
+ jmp noint
+
+egaF1: ;--- Write an EGA register --------------------------------------------
+
+F10:
+ pusha
+ cmp dx,0
+ jne F18
+ mov dx,03d4h ; write to the CRTC index register
+ mov ax,bx ; values to write to ports 3d4/3d5
+ out dx,ax ; do the write
+ mov di,bx ; save the written values to memory
+ and di,0ffh ; get just the lower 8 bits
+ mov byte ptr [ega_current_crtc+di],bh
+ mov byte ptr [dirty_crtc+di],1
+ popa
+ jmp noint
+F18:
+ cmp dx,8
+ jne F110
+ mov dx,03c4h ; write to the Sequencer index register
+ mov ax,bx ; values to write to ports 3c4/3c5
+ out dx,ax ; do the write
+ cmp bl,0 ; Cannot index reset because it its
+ jle F18bra1 ; not stored. range = 1->4
+ and bx,0ffh ; just want BL
+ dec bx ; actually, one less than that
+ mov byte ptr [ega_current_seq+bx],ah
+ mov byte ptr [dirty_seq+bx],1
+F18bra1:
+ popa
+ jmp noint
+F110:
+ cmp dx,010h
+ jne F118
+ mov dx,03ceh ; write to the Graphics controller
+ mov ax,bx ; values to write to ports 3ce/3cf
+ out dx,ax ; do the write
+ mov di,bx ; save the written values to memory
+ and di,0ffh ; get just the lower 8 bits
+ mov byte ptr [ega_current_graph+di],bh
+ mov byte ptr [dirty_graph+di],1
+ popa
+ jmp noint
+F118:
+ cmp dx,018h
+ jne F120
+ mov dx,03dah ; clear attribute controller index
+ in al,dx ; the read clears this register
+ mov ax,bx ; need to write BX to the ports
+ mov dx,03c0h ; Attribute Controller index register
+ out dx,ax ; do the write
+ inc dx
+ mov al,020h ; EGA palette enable
+ out dx,al ; enable the palette
+ mov di,bx ; save the written values to memory
+ and di,0ffh ; get just the lower 8 bits
+ mov byte ptr [ega_current_graph+di],bh
+ mov byte ptr [dirty_graph+di],1
+ popa
+ jmp noint
+F120:
+ cmp dx,020h
+ jne F128
+ mov dx,03c2h ; EGA miscellaneous register
+ mov al,bl
+ out dx,al ; write to the register
+ mov [ega_current_misc],bl
+ popa
+ jmp noint
+F128:
+ cmp dx,028h
+ jne F128
+ mov dx,03dah ; EGA feature register
+ mov al,bl
+ out dx,al
+F1quit:
+ popa
+ jmp noint
+
+egaF2: ;--- Read a register range ---------------------------------------------
+
+ pusha
+ cmp dx,0
+ jne F28
+F20:
+ lea si,ega_current_crtc ; get the address of this buffer
+ mov dx,cx ; save this value
+ xchg ch,cl ; create an index with CH
+ and cx,0ffh ; only need CH (now CL)
+ add si,cx ; SOURCE adjust the address
+ xor dh,dh ; only want the old CL value
+ mov cx,dx ; restore CX
+ mov di,bx ; DESTINATION got from the application
+ rep movsb ; copy to the app's register block
+ popa
+ jmp noint
+F28:
+ cmp dx,8
+ jne F210
+ lea si,ega_current_seq ; get the address of this buffer
+ mov dx,cx ; save this value
+ xchg ch,cl ; create an index with CH
+ and cx,0ffh ; only need CH (now CL)
+ dec cx ; RESET is not stored, so index-1
+ add si,cx ; SOURCE adjust the address
+ xor dh,dh ; only want the old CL value
+ mov cx,dx ; restore CX
+ mov di,bx ; DESTINATION got from the application
+ rep movsb ; copy to the app's register block
+ popa
+ jmp noint
+F210:
+ cmp dx,010h
+ jne F218
+ lea si,ega_current_graph ; get the address of this buffer
+ mov dx,cx ; save this value
+ xchg ch,cl ; create an index with CH
+ and cx,0ffh ; only need CH (now CL)
+ add si,cx ; SOURCE adjust the address
+ xor dh,dh ; only want the old CL value
+ mov cx,dx ; restore CX
+ mov di,bx ; DESTINATION got from the application
+ rep movsb ; copy to the app's register block
+ popa
+ jmp noint
+F218:
+ cmp dx,018h
+ jne F2quit
+ lea si,ega_current_attr ; get the address of this buffer
+ mov dx,cx ; save this value
+ xchg ch,cl ; create an index with CH
+ and cx,0ffh ; only need CH (now CL)
+ add si,cx ; SOURCE adjust the address
+ xor dh,dh ; only want the old CL value
+ mov cx,dx ; restore CX
+ mov di,bx ; DESTINATION got from the application
+ rep movsb ; copy the application's register block
+F2quit:
+ popa
+ jmp noint
+
+egaF3: ;--- Write a register range to the EGA adapter ------------------------
+
+ pusha
+ push ds
+ push es
+F31:
+ cmp dx,0
+ jne F38
+ lea di,ega_current_crtc ; write the application data here
+ mov al,ch ; adjust the write position as required
+ cbw
+ add di,ax ; DESTINATION specified address
+ mov si,bx ; SOURCE from the application
+ lea bx,dirty_crtc ; need to write some data into here
+ add bx,ax ; well, at this offset anyway
+ mov ax,es ; The application is the source
+ mov ds,ax ; so point to its segment
+ mov dx,03d4h ; CRTC index register
+ mov ah,ch ; CRTC register to start at
+ xor ch,ch ; CX is now the loop counter
+ assume ds:nothing
+F31cp:
+ mov byte ptr cs:[bx],1 ; fill in the dirty_crtc array
+ inc bx
+ movsb ; get the value from the app to write
+ ; and write to the internal buffer
+ out dx,ax ; write to the EGA adapter
+ loop F31cp
+ jmp F3quit
+F38:
+ cmp dx,8
+ jne F310
+ lea di,ega_current_seq ; write the application data here
+ mov al,ch ; adjust the write position as required
+ cbw
+ add di,ax ; DESTINATION specified address
+ dec di ; RESET is not stored, so index-1
+ mov si,bx ; SOURCE from the application
+ lea bx,dirty_seq ; need to write some data into here
+ add bx,ax ; well, at this offset anyway
+ inc bx
+ mov ax,es ; The application is the source
+ mov ds,ax ; so point to its segment
+ mov dx,03c4h ; Sequencer index register
+ mov ah,ch ; Sequencer register to start at
+ inc ah
+ xor ch,ch ; CX is now the loop counter
+ assume ds:nothing
+F38cp:
+ mov byte ptr cs:[bx],1 ; fill in the dirty_seq array
+ inc bx
+ movsb ; get the value from the app to write
+ ; and write to the internal buffer
+ out dx,ax ; write to the EGA adapter
+ loop F38cp
+ assume ds:SpcMseSeg
+ jmp F3quit
+F310:
+ cmp dx,010h
+ jne F318
+ lea di,ega_current_graph ; write the application data here
+ mov al,ch ; adjust the write position as required
+ cbw
+ add di,ax ; DESTINATION specified address
+ mov si,bx ; SOURCE from the application
+ lea bx,dirty_graph ; need to write some data into here
+ add bx,ax ; well, at this offset anyway
+ mov ax,es ; The application is the source
+ mov ds,ax ; so point to its segment
+ mov dx,03ceh ; Graphics Controller index register
+ mov ah,ch ; GC register to start at
+ xor ch,ch ; CX is now the loop counter
+ assume ds:nothing
+F310cp:
+ mov byte ptr cs:[bx],1 ; fill in the dirty_graph array
+ inc bx
+ movsb ; get the value from the app to write
+ ; and write to the internal buffer
+ out dx,ax ; write to the EGA adapter
+ loop F310cp
+ assume ds:SpcMseSeg
+ jmp short F3quit
+F318:
+ cmp dx,018h
+ jne F3quit
+ mov dx,03dah ; clear attribute controller index
+ in al,dx ; the read clears this register
+ lea di,ega_current_attr ; write the application data here
+ mov al,ch ; adjust the write position as required
+ cbw
+ add di,ax ; DESTINATION specified address
+ mov si,bx ; SOURCE from the application
+ lea bx,dirty_attr ; need to write some data into here
+ add bx,ax ; well, at this offset anyway
+ mov ax,es ; The application is the source
+ mov ds,ax ; so point to its segment
+ mov dx,03c0h ; Attribute Controller index register
+ mov ah,ch ; AC register to start at
+ xor ch,ch ; CX is now the loop counter
+ assume ds:nothing
+F318cp:
+ mov byte ptr cs:[bx],1 ; fill in the dirty_attr array
+ inc bx
+ movsb ; get the value from the app to write
+ ; and write to the internal buffer
+ out dx,ax ; write to the EGA adapter
+ loop F318cp
+ assume ds:SpcMseSeg
+F3quit:
+ pop es
+ pop ds
+ popa
+ jmp noint
+
+egaF4: ;--- Read EGA register set -------------------------------------------
+ ;
+ ; note that the incoming/outgoing data is structured thus:
+ ;
+ ; from application --> db Port number
+ ; --> db must be zero
+ ; --> db pointer value
+ ; to application <-- db data read from register
+
+ pusha
+F4lp:
+ mov al,byte ptr es:[bx] ; get the type of the next EGA register
+ mov dl,byte ptr es:[bx+2] ; load up the offset required
+ xor dh,dh ; convert DL to a word (DX)
+ add bx,3 ; point to where the data should
+ ; be written for the application
+F40:
+ cmp al,0
+ jne F48
+ lea di,ega_current_crtc ; point to the internal CRTC reg. buffer
+ add di,dx ; index into the buffer
+ mov al,byte ptr [di] ; get the register value from the driver
+ mov byte ptr es:[bx],al ; store the register value
+ jmp short F4lp2 ; do the next loop iteration
+F48:
+ cmp al,8
+ jne F410
+ lea di,ega_current_seq ; point to the internal Sequencer buffer
+ add di,dx ; index into the buffer
+ dec di ; RESET is not stored, so index off 1
+ mov al,byte ptr [di] ; get the register value from the driver
+ mov byte ptr es:[bx],al ; store the register value
+ jmp short F4lp2 ; do the next loop iteration
+F410:
+ cmp al,010h
+ jne F418
+ lea di,ega_current_graph ; point to the internal GC reg. buffer
+ add di,dx ; index into the buffer
+ mov al,byte ptr [di] ; get the register value from the driver
+ mov byte ptr es:[bx],al ; store the register value
+ jmp short F4lp2 ; do the next loop iteration
+F418:
+ cmp al,018h
+ jne F420
+ lea di,ega_current_attr ; point to the interal AC reg. buffer
+ add di,dx ; index into the buffer
+ mov al,byte ptr [di] ; get the register value from the driver
+ mov byte ptr es:[bx],al ; store the register value
+ jmp short F4lp2 ; do the next loop iteration
+F420:
+ cmp al,020h
+ jne F4lp2
+ mov al,[ega_current_misc] ; load contents of miscellaneous reg
+ mov byte ptr[di],al ; store the register value
+
+ ; the C code actually loads BL here but I don't know why!
+F4lp2:
+ inc bx ; point to the next 'record'
+ loop F4lp
+ popa
+ jmp noint
+
+egaF5: ;--- Write EGA register set -------------------------------------------
+ ;
+ ; note that the incoming data is structured thus:
+ ;
+ ; from application --> db Port number
+ ; --> db must be zero
+ ; --> db pointer value
+ ; --> db data read from register
+
+ pusha
+F5lp:
+ mov al,byte ptr es:[bx] ; get the type of the next EGA register
+ mov dl,byte ptr es:[bx+2] ; load up the offset required
+ xor dh,dh ; turn from 8 bit to a word quantity
+ mov si,dx ; need this when accessing buffers
+ add bx,3 ; point to where the data should
+ ; be written for the application
+ mov ah,byte ptr es:[bx] ; load data to send to the port
+ inc bx ; point to the next 'record'
+F50:
+ cmp al,0
+ jne F58
+ mov al,dl ; also the port offset to access
+ mov dx,03d4h ; index register for CRTC
+ out dx,ax ; write to the specified port
+ mov byte ptr [ega_current_crtc+si],ah
+ mov byte ptr [dirty_crtc+si],1
+ jmp short F5lp2
+F58:
+ cmp al,8
+ jne F510
+ mov al,dl ; also the port offset to access
+ mov dx,03c4h ; index register for Sequencer
+ out dx,ax ; write to the specified port
+ dec si ; RESET is not stored, so index off 1
+ mov byte ptr [ega_current_seq+si],ah
+ mov byte ptr [dirty_seq+si],1
+ jmp short F5lp2
+F510:
+ cmp al,010h
+ jne F518
+ mov al,dl ; also the port offset to access
+ mov dx,03ceh ; index register for GC
+ out dx,ax ; write to the specified port
+ mov byte ptr [ega_current_graph+si],ah
+ mov byte ptr [dirty_graph+si],1
+ jmp short F5lp2
+F518:
+ cmp al,018h
+ jne F520
+ mov dx,03dah ; clear attribute controller index
+ in al,dx ; the read clears this register
+ lea di,ega_current_attr ; write the application data here
+ mov al,dl ; also the port offset to access
+ mov dx,03c0h ; index register for AC
+ out dx,ax ; write to the specified port
+ mov al,020h ; EGA palette enable
+ out dx,al ; reenable the video
+ mov byte ptr [ega_current_attr+si],ah
+ mov byte ptr [dirty_attr+si],1
+ jmp short F5lp2
+F520:
+ cmp al,020h
+ jne F528
+ mov byte ptr [ega_current_misc],ah
+ mov dx,03c2h ; Miscellaneous output register
+ xchg ah,al
+ out dx,al ; write one byte
+ jmp short F5lp2
+F528:
+ xchg ah,al
+ mov dx,03dah ; EGA feature register
+ out dx,al
+F5lp2:
+ dec cx
+ cmp cx,0
+ jz F5quit
+ jmp F5lp
+F5quit:
+ popa
+ jmp noint
+
+egaF6: ;--- Restore the EGA default register values --------------------------
+ pusha
+ push es
+
+ ; copy the default EGA register sets to the driver's internal cache
+
+ mov ax,ds
+ mov es,ax
+
+ mov cx,25
+ lea di,ega_current_crtc
+ lea si,ega_default_crtc
+ rep movsb
+ mov cx,4
+ lea di,ega_current_seq
+ lea si,ega_default_seq
+ rep movsb
+ mov cx,9
+ lea di,ega_current_graph
+ lea si,ega_default_graph
+ rep movsb
+ mov cx,20
+ lea di,ega_current_attr
+ lea si,ega_default_attr
+ rep movsb
+ mov al,[ega_default_misc]
+ mov [ega_current_misc],al
+
+ ; Set up the Sequencer defaults
+
+ mov dx,03c4h ; Sequencer index register
+ mov ax,0100h ; Synchronous reset
+ out dx,ax ; do the work
+
+ xor bx,bx ; do the four non reset registers
+ inc al ; point to the next Sequencer register
+F6lp1:
+ cmp [dirty_seq+bx],1 ; has the dirty bit been set?
+ jne F6ne1
+ mov ah,[ega_default_seq+bx] ; default value to send to the register
+ out dx,ax ; do the work
+F6ne1:
+ inc bx ; point to the next buffer location
+ inc al ; point to the next Sequencer register
+ cmp bx,3 ; copy elements 0->3 to ports
+ jl F6lp1
+ mov ax,0300h ; Clear synchronous reset
+ out dx,ax ; do the work
+
+ ; Set up the default Miscellaneous Output Register value.
+
+ mov dx,03c2h ; Miscellaneous o/p register address
+ mov al,[ega_default_misc] ; the default value
+ out dx,al ; write to the EGA/VGA
+
+ ; Set up the Cathode Ray Tube Controller in the default fashion
+
+ mov dx,03d4h ; Index to the CRTC
+ xor bx,bx ; clear an index register
+F6lp2:
+ cmp [dirty_crtc+bx],1 ; has the dirty bit been set?
+ jne F6ne2
+ mov ax,bx ; index for the CRTC index register
+ mov ah,[ega_default_crtc+bx] ; default value for the selected reg.
+ out dx,ax
+F6ne2:
+ inc bx ; point to the next location
+ cmp bx,25 ; 25 registers to copy
+ jl F6lp2
+
+ ; Set up the Attribute Controller default values
+ ; Remember that this is a funny beast which uses a flip-flop
+ ; off just one address/data port
+
+ mov dx,03dah ; CRT status register
+ in al,dx ; set the AC flip-flop
+ mov dx,03c0h ; Attibute controller address/data regs
+ xor bx,bx ; clear an index register
+F6lp3:
+ cmp [dirty_attr+bx],1 ; has the dirty bit been set?
+ jne F6ne3
+ mov ax,bx ; index for the CRTC index register
+ mov ah,[ega_default_attr+bx] ; default value for the selected reg.
+ out dx,al ; index the register, then flip the flop
+ xchg al,ah ; get the default data for this register
+ out dx,al ; write the data out
+F6ne3:
+ inc bx ; point to the next location
+ cmp bx,20 ; 20 registers to copy
+
+ ; Set the Graphics Controller default values
+
+ mov dx,03ceh ; Index to the GC
+ xor bx,bx ; clear an index register
+F6lp4:
+ cmp [dirty_graph+bx],1 ; has the dirty bit been set?
+ jne F6ne4
+ mov ax,bx ; index for the GC index register
+ mov ah,[ega_default_graph+bx] ; default value for the selected reg.
+ out dx,ax
+F6ne4:
+ inc bx ; point to the next location
+ cmp bx,9 ; 9 registers to copy
+ jl F6lp2
+
+ ; Reenable the video
+
+ mov dx,03c0h ; index register for AC
+ mov al,020h ; EGA palette enable
+ out dx,al ; reenable the video
+
+ ; Clean out the dirty register arrays
+
+ xor al,al ; put a nice zero in all the dirty
+ ; registers
+ mov cx,25+4+9+20 ; do the CRTC, SEQ, GC and AC in
+ mov di,offset dirty_crtc ; one go
+ rep stosb
+
+ pop es
+ popa
+ jmp noint
+
+egaF7: ;---Define default register table -------------------------------------
+ pusha
+ push es
+ push ds
+
+ ; Load a new set of default registers for a particular EGA/VGA component
+
+
+ mov si,bx ; SOURCE of the incoming data from the app
+ mov ax,es ; save the SOURCE segment register
+ mov bx,ds ; save the DESTINATION offset
+ mov ds,ax ; DS is now the SOURCE segment in the app
+ mov es,bx ; ES is now the DESTINATION segment in the dvr
+
+ assume ds:nothing, es:SpcMseSeg
+
+F70: ; Set the default CRTC registers
+
+ cmp dx,0
+ jne F78
+ mov cx,25 ; copy 25 register entries
+ mov di,offset ega_default_crtc
+ rep movsb ; do the copy
+ jmp short F7dirty
+
+F78: ; Set the default Sequencer registers
+
+ cmp dx,8
+ jne F710
+ mov cx,4 ; copy 4 register entries
+ mov di,offset ega_default_seq
+ rep movsb ; do the copy
+ jmp short F7dirty
+
+F710: ; Set the default Graphic Controller registers
+
+ cmp dx,10
+ jne F718
+ mov cx,9 ; copy 9 register entries
+ mov di,offset ega_default_graph
+ rep movsb ; do the copy
+ jmp short F7dirty
+
+F718: ; Set the default Attribute Controller registers
+
+ cmp dx,18
+ jne F720
+ mov cx,20 ; copy 20 register entries
+ mov di,offset ega_default_attr
+ rep movsb ; do the copy
+ jmp short F7dirty
+
+F720: ; Set the default Miscellaneous Output register
+
+ cmp dx,20
+ jne F7quit
+ mov word ptr cs:[ega_default_misc],si
+
+F7dirty:
+
+ ; Set all the dirty register arrays
+
+ mov al,1 ; put a nice one in all the dirty
+ ; registers
+ mov cx,25+4+9+20 ; dirty all the registers in one go
+ mov di,offset dirty_crtc
+ rep stosb
+
+F7quit:
+ pop ds ; need to restore the segment registers
+ pop es
+
+ assume ds:SpcMseSeg, es:nothing
+
+ popa
+
+ jmp noint
+
+egaFA: ;--- Interrogate driver -----------------------------------------------
+ ; The real Microsoft mouse driver gets this wrong (release 7.03)
+
+ push ax
+ mov ax,cs
+ mov es,ax
+ mov bx,offset relnum ; return the address of the mouse
+ ; driver version number
+ pop ax
+ jmp noint
+
+;=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
+
+ENDIF ; MOUSE_VIDEO_BIOS
+
+do_bop:
+
+ bop VIDEO_IO_BOP ;BOP BE
+ nop
+ nop
+ jnc noint
+go_rom:
+ popf
+ db 0EAh ; this is a far jump
+old_vid_int dd ? ; far pointer to the old int 10h vector
+ jmp DOIRET
+noint:
+ popf
+ jmp DOIRET
+
+mouse_int1:
+ bop INT1_BOP
+ jmp DOIRET
+
+mouse_version:
+ dw 04242h
+ dw 0000h
+
+mouse_copyright:
+ db "Windows NT MS-DOS subsystem Mouse Driver"
+
+video_io:
+ int VIDEO
+ bop UNSIMULATE_BOP
+
+mouse_int2:
+ bop INT2_BOP
+ jmp DOIRET
+
+mouseINB:
+ in al,dx
+ bop 0feh
+
+mouseOUTB:
+ out dx,al
+ bop 0feh
+
+mouseOUTW:
+ out dx,ax
+ bop 0feh
+
+
+;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+;
+;16 BIT ENTRY POINT 16 BIT ENTRY POINT 16 BIT ENTRY POINT 16 BIT ENTRY POINT
+;
+;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+;========================================================================
+; Procedure that provides the driver interface to 32 bit land. This is
+; the entry point to the Intel 16 bit driver from the mouse interrupt
+; handler in the host mouse code.
+;
+; This procedure determines the current video mode from the BIOS data
+; area, and depending on this branches to the correct display routines
+; for this mode.
+;
+; N.B. This function MUST NOT modify CX and DX because the next level
+; of functions in the driver heirarchy requires the values passed in
+; them from 32 bit land.
+;========================================================================
+
+ assume ds:SpcMseSeg
+
+entry_point_from_32bit proc near
+ make_stack ; use the driver's own stack
+ push ds
+ push ax
+ push bx
+
+ mov ax,cs
+ mov ds,ax
+
+ call getBIOSvideomode; read the BIOS data area
+ xor bx,bx ; clear the jump table index
+ shl al,1 ; create a table index for word sized entries
+ mov bl,al ; move into a base register
+ call [drawpointerJMPT+bx] ; jump to the correct routine
+
+ pop bx
+ pop ax
+ pop ds
+ kill_stack ; return to the previous stack
+
+ bop 0FEh ; return to the 32 bit side
+
+entry_point_from_32bit endp
+
+
+;========================================================================
+; Procedure to set the cursor draw flag to DO DRAW. This is called from
+; SoftPC code via a host_simulate(). This routine is called when the
+; application does an INT 33h, function 1.
+;
+; In accordance with the Microsoft Programmer's Reference, the internal
+; cursor flag (internalCF) has a default value of -1. If intenalCF = 0
+; then the cursor is drawn. If the flag is already 0, then this function
+; does nothing.
+;
+; Note: with calls to int 33h AX = 2, it is legal to
+; make internalCF less than -1.
+;========================================================================
+
+int33function1 proc near
+
+ make_stack ; use the driver's own stack
+ push ax
+ push bx
+ push ds
+
+ mov ax,cs
+ mov ds,ax
+;; do not allow mouse int comes in while we are updating the cursor.
+;; call DOCLI
+
+ ; check to see if the pointer should be drawn
+
+; cmp [internalCF],0 ; is the flag already zero?
+; jz fn1quit ; if so, do nothing
+
+ ; pointer is not ON, so increment the flag to try to turn it ON
+
+; inc [internalCF] ; increment the pointer internal flag
+; cmp [internalCF],0 ; if 0, then the pointer can be drawn
+; jl fn1quit ; it is < 0, so don't draw the pointer.
+
+ ; The internal cursor flag hits zero for the first time, so
+ ; draw the pointer.
+
+ call getBIOSvideomode; read the BIOS data area
+ xor bx,bx ; clear the jump table index
+ shl al,1 ; create a table index for word sized entries
+ mov bl,al ; move into a base register
+ call [Int33function1JMPT+bx] ; do the correct function 1 handler
+fn1quit:
+;; call DOSTI
+ pop ds
+ pop bx
+ pop ax
+ kill_stack ; return to the previous stack
+ bop 0FEh ; back to jolly old 32 bit land
+
+int33function1 endp
+
+
+
+;========================================================================
+; Procedure to set the cursor draw flag to DONT DRAW. This is called from
+; SoftPC code via a host_simulate(). This routine is called when the
+; application does an INT 33h, function 2
+;
+; Note: with calls to int 33h AX = 2, it is legal to
+; make internalCF less than -1.
+;========================================================================
+
+int33function2 proc near
+
+ make_stack ; use the driver's own stack
+ push ax
+ push bx
+ push ds
+
+ mov ax,cs
+ mov ds,ax
+;; do not allow mouse int comes in while we are updating the cursor.
+;; call DOCLI
+
+; dec [internalCF] ; decrement the pointer internal flag
+
+ ; if the internal cursor flag is less than -1, then do not try
+ ; do remove the pointer from the screen because this has already
+ ; been done.
+
+; cmp [internalCF],0ffh
+; jl fn2quit ; do nothing if < -1
+
+ ; Internal flag hits -1, so remove the pointer from the screen.
+
+ call getBIOSvideomode; read the BIOS data area
+ xor bx,bx ; clear the jump table index
+ shl al,1 ; create a table index for word sized entries
+ mov bl,al ; move into a base register
+ call [Int33function2JMPT+bx] ; do the correct function 1 handler
+fn2quit:
+;; call DOSTI
+ pop ds
+ pop bx
+ pop ax
+ kill_stack ; return to the previous stack
+
+ bop 0feh
+
+int33function2 endp
+
+;========================================================================
+; Procedure to return straight back to cloud 32. This is needed if an
+; unsupported video mode is found in the BIOS data area.
+;========================================================================
+
+not_supported proc near
+ ret ; cant't BOP 0feh here or the stack will die
+ ; (out of balance with CS:IP stored from call)
+not_supported endp
+
+;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+;
+; END 16 BIT ENTRY END 16 BIT ENTRY END 16 BIT ENTRY END 16 BIT ENTRY
+;
+;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+
+;========================================================================
+; Procedure to draw a cursor on the fullscreen X86 graphics display for
+; high resolution graphics modes.
+; This procedure saves the area about to be written over, blts the
+; pointer image onto the screen and restores the background from whence
+; cursor has just come.
+;
+; Input: CX = x-coordinate
+; DX = y-coordinate
+; Output: None
+;========================================================================
+
+
+drawHiResPointer proc near
+
+ ; save the video card's read/write context
+
+;; call DOCLI
+ pusha
+ push ds
+ mov ax,cs ; make sure that DS points to the
+ mov ds,ax ; right segment
+
+
+ call saveVGAregisters
+ call check_for_mode_change
+
+
+ mov bx,cx ; get X coordinate into a base register
+ shl bx,1 ; calculate a word index
+ mov ax,[ChooseImageLUT+bx] ; select the right image LUT
+ mov [PointerLUT],ax ; store the LUT address
+
+ xor ax,ax ; assume carry clear after the next call
+ call determineboundary
+ jnc detcont ; pointer in buonds if carry clear
+ not ax ; carry was set, so set AX non zero
+
+detcont:
+
+ ; Coordinates are now transformed from Cartesian to physical VRAM
+ ; memory byte and bit offsets.
+
+ mov di,dx ; store DX for later
+
+ ; internalCF = the current pointer status
+ ; background = indicates if a background has been stored or not
+ ;
+ ; if(internalCF == Zero && background == STORED)
+ ; The normal cursor ON condition
+
+ cmp [internalCF],0
+ jnz end_the_if ; request to turn pointer on
+ cmp [background],STORED
+ jne end_the_if
+
+ mov si,cx
+ mov di,dx
+ mov dx,[VRAMlastbyteoff]
+ mov cx,[VRAMlastbitoff]
+ call restore_background
+
+ cmp ax,0 ; should the pointer be drawn?
+ jnz end_the_if ; if the pointer has gone off the edge of
+ ; the screen, then quit
+
+ mov [VRAMlastbyteoff],di ; save the current position
+ mov [VRAMlastbitoff],si
+ mov cx,si
+ mov dx,di
+ call save_background
+ mov cx,si
+ mov dx,di
+ call drawEGApointer
+
+end_the_if:
+
+ call restoreVGAregisters
+
+ pop ds
+ popa
+;; call DOSTI
+ ret
+
+drawHiResPointer endp
+
+;========================================================================
+; Procedure to draw a cursor on the fullscreen X86 graphics display.for
+; medium resolution graphics modes.
+; This procedure saves the area about to be written over, blts the
+; pointer image onto the screen and restores the background from whence
+; cursor has just come.
+;
+; Input: CX = x-coordinate
+; DX = y-coordinate
+; Output: None
+;========================================================================
+
+drawMediumResPointer proc near
+
+ pusha
+;; call DOCLI
+
+ shr cx,1 ; map from 640 virtual to 320 real
+
+ ; CX,DX = x,y cartesian coordinates here.
+
+ call check_for_mode_change
+
+ ; internalCF = the current pointer status
+ ; background = indicates if a background has been stored or not
+ ;
+ ; if(internalCF == Zero && background == STORED)
+ ; The normal cursor ON condition
+
+
+ cmp [internalCF],0
+ jnz cant_draw_ptr ; request to turn pointer on
+ cmp [background],STORED
+ jne cant_draw_ptr
+ mov si, cx ; save new cursor position
+ mov di, dx
+ mov dx,[VRAMlastbyteoff] ;
+ mov cx,[VRAMlastbitoff]
+ mov bp,[LastYCounters] ; Y looping counter
+ call restorebkgrndmode4
+ mov cx, si ; restore new cursor position
+ mov dx, di
+ call detboundmode4 ; calculate new byte offset
+ jc cant_draw_ptr ; don't draw new cursor of out of scrn
+
+ mov [VRAMlastbyteoff], dx ; byte offset
+ mov [VRAMlastbitoff], cx ; MSB = 0FFh if start with ODD line
+ ; LSB = bit offset
+ mov [LastYCounters], bp ; MSB: even counter, LSB for odd
+ call savebkgrndmode4
+ call drawmode4pointer
+
+cant_draw_ptr:
+
+;; call DOSTI
+ popa
+ ret
+
+drawMediumResPointer endp
+
+;========================================================================
+; Procedure to draw a cursor on the fullscreen X86 graphics display for
+; medium resolution, 256 colour graphics mode. (video bios mode 13h).
+; This procedure saves the area about to be written over, blts the
+; pointer image onto the screen and restores the background from whence
+; cursor has just come.
+;
+; Input: CX = x-coordinate
+; DX = y-coordinate
+; Output: None
+;========================================================================
+
+drawC256Pointer proc near
+ pusha
+;; call DOCLI
+ shr cx,1 ; map from 640 virtual to 320 real x
+
+ ; CX,DX = x,y cartesian coordinates here.
+
+ call check_for_mode_change
+
+ ; internalCF = the current pointer status
+ ; background = indicates if a background has been stored or not
+ ;
+ ; if(internalCF == Zero && background == STORED)
+ ; The normal cursor ON condition
+
+
+ cmp [internalCF],0
+ jnz cant_draw_256ptr ; request to turn pointer on
+ cmp [background],STORED
+ jne cant_draw_256ptr
+
+ mov si,cx
+ mov di,dx
+ mov dx,[VRAMlastbyteoff]
+ mov cx,[LastXCounters]
+ mov bp,[LastYCounters]
+ call restorebkgrndmode13
+ mov cx, si
+ mov dx, di
+ call detboundmode13
+ jc cant_draw_256ptr
+
+ mov [VRAMlastbyteoff],dx ; save the current position
+ mov [LastXCounters],cx
+ mov [LastYCounters], bp
+ call savebkgrndmode13
+ call draw256pointer
+
+cant_draw_256ptr:
+;; call DOSTI
+ popa
+ ret
+drawC256Pointer endp
+
+;========================================================================
+; Procedure to draw a pointer on the fullscreen X86 text display for
+; BIOS modes 3 and 7.
+; This procedure saves the area about to be written over, XORs the
+; pointer image onto the screen and restores the background from whence
+; cursor has just come.
+;
+; Input: CX = x-coordinate
+; DX = y-coordinate
+; Output: None
+;========================================================================
+
+IFDEF SIXTEENBIT
+
+drawTextPointer proc near
+ pusha
+ push es
+
+ ; CX,DX = x,y virtual pixel coordinates here.
+ ; 0 <= x < 640
+ ; 0 <= y < 200 for 25 line mode
+ ; 0 <= y < 344 for 43 line mode
+ ; 0 <= y < 400 for 50 line mode
+ ; The virtual character size is always 8x8 virtual pixels.
+
+ call check_for_mode_change
+
+ ; internalCF = the current pointer status
+ ; background = indicates if a background has been stored or not
+ ;
+ ; if(internalCF == Zero && background == STORED)
+ ; The normal cursor ON condition
+
+ cmp [internalCF],0
+ jnz cant_draw_text_ptr ; request to turn pointer on
+ cmp [background],STORED
+ jne cant_draw_text_ptr
+
+
+ ; Calculate the current cell location as an offset
+ ; into the text buffer segment starting at B800:0
+ ; Note: The following kinky shifts allow for the fact that the text
+ ; video buffer consists of word elements of the form char:attr.
+ ; So, if a row = 80 characters wide on the screen, it is 160
+ ; bytes wide in VRAM.
+
+ mov bx,dx ; create a word table index
+ shr bx,3 ; virtual char height = 8, but 160 bytes
+ ; per text row, so save some shifts.
+ shl bx,1 ; make a word table index
+ mov di,[mult80lut+bx] ; multiply by 80 words per text row.
+ shl di,1
+ shr cx,3 ; divide the x virtual pixel coordinate
+ ; by 8 = virtual char width and mult
+ ; by 2 to get word offset in text row.
+ shl cx,1
+ add di,cx ; full VRAM location now in DI
+
+ ; Restore the text cell previously overwritten.
+
+ mov si,[VRAMlasttextcelloff]; address of last modified text cell
+ mov [VRAMlasttextcelloff],di; store the current cell location
+
+ mov ax,0b800h ; the text buffer segment
+ mov es,ax ; ES now points there
+
+ ; The text pointer uses the same magic as the graphics code
+ ; to place a pointer on the screen.
+
+ mov bx,07700h ; the magic cursor mask for pointer
+ mov cx,077ffh ; the magic screen mask for pointer
+
+ assume es:nothing
+
+ mov ax,[lasttextimage] ; restore the background
+ mov es:[si],ax ; from last time
+ mov ax,es:[di] ; load the cell to be modifyed
+ mov [lasttextimage],ax ; save this cell for next time
+ and ax,cx ; apply the screen mask
+ xor ax,bx ; apply the cursor mask
+ mov es:[di],ax ; and write back
+
+ assume es:SpcMseSeg
+
+cant_draw_text_ptr:
+
+ pop es
+ popa
+ ret
+drawTextPointer endp
+
+ENDIF ;; SIXTEENBIT
+
+;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+;
+; Interrupt 33h support functions.
+; These functions are called via a jump table from the 16 bit entry
+; point code.
+;
+;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+;========================================================================
+; Procedure to set the cursor draw flag to DO DRAW. This is called from
+; SoftPC code via a host_simulate(). This routine is called when the
+; application does an INT 33h, function 1
+;========================================================================
+
+int33function0 proc near
+
+ make_stack ; use the driver's own stack
+ push ds
+ push es
+ pusha
+
+ ; sort out the segments
+
+ mov ax,cs
+ mov ds,ax
+ mov ax,cs
+ mov es,ax
+;; do not allow mouse int comes in while we are updating the cursor.
+;; call DOCLI
+ ; set the internal pointer flag to its default value.
+
+ mov [internalCF],0ffh
+
+ ; set the default hotspot location = (0,0)
+
+ xor ax,ax
+ mov [hotspot],ax
+ mov [hotspot+2],ax
+
+ ; copy the default pointer to the working pointer buffer
+
+ lea si,default_cursor
+ lea di,current_cursor
+ call copy_pointer_to_current
+
+ ; clear the pointer enabled flag, turn the pointer off by restoring
+ ; the background.
+
+ mov [background],NOTSTORED ; there is no stored background now
+
+;; call DOSTI
+ popa
+ pop es
+ pop ds
+ kill_stack ; restore the previous stack
+ bop 0FEh
+
+int33function0 endp
+
+
+
+;========================================================================
+; Procedure to accept a cursor bit image from the current application
+; at ES:DX. This is stored as the current pointer image for use by
+; the driver.
+;========================================================================
+
+assume es:nothing
+
+int33function9 proc near
+ call DOCLI
+ make_stack ; use the driver's own stack
+ push ds
+ push es
+ pusha
+
+
+ mov ax,cs ; point at the driver data segment
+ mov ds,ax
+;; do not allow mouse int comes in while we are updating the cursor.
+;; call DOCLI
+ ; Read in the hotspot cartesian coordinate values for the
+ ; new pointer image. If the hotspot values are out of range
+ ; i.e. >127 | < -128, then reset to the boundary value
+ ; Now using kinky non modRM short forms by clever use of AX
+
+ mov ax,127 ; load accumulator with 127
+ mov bp,ax ; store this constant in a register
+ cmp ax,bx ; compare X value of hotspot with 127
+ jg test_low_x ; if 127 > BX, BX is within upper limit
+ xchg ax,bx ; BX > 127, so set to 127
+ jmp short check_y_hotspot ; now test the Y values
+
+test_low_x:
+
+ not ax ; change accumulator from 127 to -128
+ cmp ax,bx ; compare X value of hotspot with -128
+ jl check_y_hotspot ; if -128 < BX, BX is within lower lim.
+ xchg ax,bx ; BX < -128, so set it to -128
+
+check_y_hotspot:
+
+ mov ax,bp ; reload AX with 127
+ cmp ax,cx ; compare Y value of hotspot with 127
+ jg test_low_y ; if 127 > CX, Cx is within upper limit
+ xchg ax,cx ; CX > 127, so set CX to 127
+ jmp short done_hotspot_check; both hotspot coords tested, so save
+
+test_low_y:
+
+ not ax ; change accumulator from 127 to -128
+ cmp ax,cx ; compare Y value of hotspot with -128
+ jl done_hotspot_check ; if -128 < CX, CX is within lower lim.
+ xchg ax,cx ; CX < -128, so set it to -128
+
+done_hotspot_check:
+
+ mov [hotspot],bx ; save the hotspot x,y
+ mov [hotspot+2],cx ; y component of the hotspot
+
+ ; DESTINATION: the driver current pointer buffer
+ ; Note: the SOURCE is already being pointed at by DX
+
+ lea di,current_cursor ; this is the bit that must change
+ mov si,dx
+
+ ; copy in the new application pointer
+
+ mov ax,es
+ mov ds,ax ; DS now points to where ES points
+ mov ax,cs
+ mov ax,es ; ES points to our data area now
+ call copy_pointer_to_current ; Copy the pointer image appropriately
+
+ popa
+ pop es
+ pop ds
+ kill_stack ; restore the previous stack
+ call DOSTI
+ ret ; this code is called from within this
+ ; 16 bit driver, so don't BOP
+int33function9 endp
+
+;============================================================================
+; Procedure to display the pointer image in HIRES graphics modes
+;============================================================================
+
+HiResInt33Function1 proc near
+
+ pusha
+ call check_for_mode_change
+ call saveVGAregisters
+ mov cx,[current_position_x] ; get the last known cursor position
+ mov dx,[current_position_y] ; from the OS via the event loop
+ call determineboundary ; convert to VRAM coordinates
+ jc end_function1 ; if the pointer has gone off the edge
+ ; of the screen, then quit
+ mov [VRAMlastbyteoff],dx ; save the restore background location
+ mov [VRAMlastbitoff],cx
+ mov si,cx
+ mov di,dx
+ call save_background
+ mov cx,si
+ mov dx,di
+ call drawEGApointer
+ mov [background],STORED
+end_function1:
+ call restoreVGAregisters
+ popa
+ ret ; return to driver surface manager code
+
+HiResInt33Function1 endp
+
+;============================================================================
+; Procedure to display the pointer image in MEDIUMRES graphics modes
+; Note that this function does a conversion from virtual pixel coordinates
+; to real screen coordinates as required if the stored values in the
+; current_position memory locations are greater than 320 for X or 200
+; for Y.
+;============================================================================
+
+MediumResInt33Function1 proc near
+
+ pusha
+ call check_for_mode_change
+ mov cx,[current_position_x] ; get the last known cursor position
+ mov dx,[current_position_y] ; from the OS via the event loop
+ shr cx,1 ; virtual coor -> screen coor
+ call detboundmode4 ; convert to VRAM coordinates
+ jc MediumResFunction1_exit
+
+ mov [VRAMlastbyteoff],dx ; save the restore background location
+ mov [VRAMlastbitoff],cx
+ mov [LastYCounters], bp
+ call savebkgrndmode4
+ call drawmode4pointer
+ mov [background],STORED
+
+MediumResFunction1_exit:
+ popa
+ ret
+
+MediumResInt33Function1 endp
+
+;============================================================================
+; Procedure to display the pointer image in VGA 256 colour graphics modes
+;============================================================================
+
+C256Int33Function1 proc near
+ pusha
+ call check_for_mode_change
+ call modifyentry255 ; make sure that DAC entry 255 is white
+ mov cx,[current_position_x] ; get the last known cursor position
+ mov dx,[current_position_y]
+ shr cx, 1 ; virtual coor -> screen coord
+ call detboundmode13 ; convert to VRAM coordinates
+ jc C256Function1_exit
+
+ mov [VRAMlastbyteoff],dx ; save the restore background location
+ mov [LastXCounters],cx ; X loop counter
+ mov [LastYCounters], bp ; Y loop counter
+ call savebkgrndmode13
+ call draw256pointer
+ mov [background],STORED
+
+C256Function1_exit:
+ popa
+ ret ; return to driver surface manager code
+
+C256Int33Function1 endp
+
+;============================================================================
+; Procedure to show the TEXT pointer
+;============================================================================
+IFDEF SIXTEENBIT
+
+TextInt33Function1 proc near
+
+ pusha
+ push es
+
+ mov [background],STORED
+ call check_for_mode_change
+
+ mov cx,[current_position_x] ; get the last known cursor position
+ mov bx,[current_position_y] ; from the OS via the event loop
+
+ shr bx,3 ; virtual char height = 8, but 160 bytes
+ ; per text row.
+ shl bx,1 ; make a word table index
+ mov di,[mult80lut+bx] ; multiply by 80 words per text row.
+ shl di,1 ; remember 160 bytes NOT 80 in a row
+ shr cx,3 ; divide the x virtual pixel coordinate
+ ; by 8 = virtual char width and mult
+ ; by 2 to get word offset in text row.
+ shl cx,1
+ add di,cx ; full VRAM location now in DI
+
+ mov [VRAMlasttextcelloff],di; store the current cell location
+
+ mov ax,0b800h ; the text buffer segment
+ mov es,ax ; DS now points there
+
+ mov bx,07700h ; the magic cursor mask for pointer
+ mov cx,077ffh ; the magic screen mask for pointer
+
+ assume es:nothing
+
+ mov ax,es:[di] ; load the cell to be modifyed
+ mov [lasttextimage],ax ; save this cell for next time
+ and ax,cx ; apply the screen mask
+ xor ax,bx ; apply the cursor mask
+ mov es:[di],ax ; and write back
+
+ assume es:SpcMseSeg
+
+ pop es
+ popa
+ ret ; return to driver surface manager code
+
+TextInt33Function1 endp
+
+ENDIF ;; SIXTEENBIT
+;============================================================================
+; Procedure to remove the pointer image in HIRES graphics modes
+;============================================================================
+
+HiResInt33Function2 proc near
+
+ push cx
+ push dx
+
+ call saveVGAregisters
+ call check_for_mode_change
+
+ cmp [background],STORED ; is there some stored background?
+ jne no_background_stored ; no, so don't restore it
+ mov dx,[VRAMlastbyteoff]
+ mov cx,[VRAMlastbitoff]
+ call restore_background ; restored the background at correct
+ mov [background],NOTSTORED ; place. Set buffer cleared Flag
+
+no_background_stored:
+
+ call restoreVGAregisters
+
+ pop dx
+ pop cx
+ ret
+
+HiResInt33Function2 endp
+
+;============================================================================
+; Procedure to remove the pointer image in MEDIUMRES graphics modes
+;============================================================================
+
+MediumResInt33Function2 proc near
+ push cx
+ push dx
+ push bp
+ call check_for_mode_change
+
+ cmp [background],STORED ; is there some stored background?
+ jne nobkgrndstored ; no, so don't restore it
+ mov dx,[VRAMlastbyteoff]
+ cmp dx,80*100 ; mustn't be greater than buffer size
+ jl vidoffok ; it's OK, so do nothing
+ mov dx,80*10-1 ; modify DX to fit in the buffer
+vidoffok:
+ mov cx,[VRAMlastbitoff] ; CL = bit offset
+ ; CH = odd/even flag
+ and cl,3 ; cannot be greater than bit 3( 2bits/p)
+ mov bp, [LastYCounters]
+ call restorebkgrndmode4 ; restored the background at correct
+ mov [background],NOTSTORED ; place. Set buffer cleared Flag
+
+nobkgrndstored:
+ pop bp
+ pop dx
+ pop cx
+ ret
+MediumResInt33Function2 endp
+
+;============================================================================
+; Procedure to remove the pointer image in MEDIUMRES graphics modes
+;============================================================================
+
+C256Int33Function2 proc near
+ push cx
+ push dx
+ push bp
+ call check_for_mode_change
+
+ cmp [background],STORED ; is there some stored background?
+ jne nobkgrndstored256 ; no, so don't restore it
+ mov dx,[VRAMlastbyteoff]
+ mov cx,[LastXCounters]
+ mov bp,[LastYCounters]
+ call restorebkgrndmode13 ; restored the background at correct
+ mov [background],NOTSTORED ; place. Set buffer cleared Flag
+nobkgrndstored256:
+
+ pop bp
+ pop dx
+ pop cx
+ ret
+
+C256Int33Function2 endp
+
+;============================================================================
+; Procedure to remove the pointer image in TEXT modes
+;============================================================================
+
+IFDEF SIXTEENBIT
+
+TextInt33Function2 proc near
+
+ push ax
+ push si
+ push es
+
+ call check_for_mode_change
+
+ cmp [background],STORED ; is there some stored background?
+ jne no_text_background_stored ; no, so don't restore it
+
+ mov [background],NOTSTORED ; place. Set buffer cleared Flag
+
+ ; Restore the text cell previously overwritten.
+
+ mov si,[VRAMlasttextcelloff]; address of last modified text cell
+
+ mov ax,0b800h ; the text buffer segment
+ mov es,ax ; DS now points there
+
+ assume es:nothing
+
+ mov ax,[lasttextimage] ; restore the background
+ mov es:[si],ax ; from last time
+
+no_text_background_stored:
+
+ assume es:SpcMseSeg
+
+ pop es
+ pop si
+ pop ax
+ ret
+
+TextInt33Function2 endp
+
+ENDIF ;; SIXTEENBIT
+
+;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+;
+; End of Interrupt 33h support functions.
+;
+;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+;
+; Mouse driver general support functions
+;
+;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+
+;========================================================================
+; Procedure to determine if the application has changed video modes since
+; the last mouse interrupt. If it has, then the image that is saved in the
+; background restore buffer is invalid and should not be drawn.
+;========================================================================
+
+check_for_mode_change proc near
+
+ push ax
+
+ call getBIOSvideomode; peek at the BIOS data area for video mode
+ cmp al,[lastvidmode]; compare with the last mode value
+ ; from the preceding interrupt
+ jnz mode_change ; a mode change has occurred
+ pop ax ; no mode change, so quit
+ ret
+mode_change:
+ mov [background],NOTSTORED
+ mov byte ptr [lastvidmode],al ; store the new mode
+ pop ax
+
+ ret
+check_for_mode_change endp
+
+;========================================================================
+; Procedure to read the BIOS data area and get the current video mode
+; Output: AL = BIOS video mode
+; Modifies: memory variable -> currentvidmode, puts the video found in
+; the BIOS data area in this memory location.
+;========================================================================
+
+getBIOSvideomode proc near
+
+ push es
+ push bx
+ mov ax,40h ; BIOS data area segment
+ mov es,ax
+
+ mov al,es:[49h] ; get the BIOS video mode data
+
+ mov bl,al ; copy the video mode value
+ xor bh,bh
+ shl bx,1 ; create a word table index
+ mov bx,[latchhomeLUT+bx] ; get the latch hiding place for this
+ ; video mode
+ mov [latchcache],bx ; save in memory for use in save and restore
+ ; vga registers.
+
+ pop bx
+ pop es ; restore the 'normal' data segment
+ ret
+
+getBIOSvideomode endp
+
+;=========================================================================
+; Function to modify the 256th palette entry for 256 colour mode. The
+; driver requires white to be set in this DAC register triple.
+;=========================================================================
+modifyentry255 proc near
+ push ax
+ push dx
+ mov dx,03c8h
+ mov al,0ffh
+ out dx,al
+ inc dx
+ out dx,al
+ out dx,al
+ out dx,al
+ pop dx
+ pop ax
+ ret
+modifyentry255 endp
+
+
+;========================================================================
+; Procedure to copy the required pointer image to the snapshot
+; buffers. Each buffer holds a different instance of the mouse
+; pointer for each possible alignment of the pointer image in
+; a VRAM byte.
+;
+; INPUT DS:SI = pointer to the source image
+;
+;========================================================================
+
+assume ds:nothing
+
+copy_pointer_to_current proc near
+
+ push ds
+ push es
+ pusha
+
+
+ ; Set up the destination for the copy
+
+ mov ax,cs ; point ES to this segment
+ mov es,ax
+ lea di,current_cursor ; this is the bit that must change
+ mov bx,di ; save this address for a while
+ mov bp,si ; save the application source address
+
+ ; Fill the AND buffer with 1s and then fill the XOR buffer with
+ ; 0s for the byte aligned pointer condition. This is done so that
+ ; the last byte in the 3byte scanline sequence is set to the correct
+ ; value to prevent image loss from the screen.
+
+ cld ; move low mem -> high mem
+ mov ax,24 ; avoid doing a modRM load of immediate
+ mov cx,ax ; 24 words to fill.
+ mov dx,ax ; store this for a while
+ xor ax,ax ; clear AX (AX = 0)
+ not ax ; AX = 0ffffh -> fill AND mask with it.
+ rep stosw ; fill the screen mask (AND mask)
+ mov cx,dx ; do the next 24 words (XOR mask)
+ not ax ; AX = 0h -> fill XOR mask with it
+ rep stosw ; Fill the cursor mask
+
+ ; Now fill the prepared 48 word buffer with the user defined
+ ; AND and XOR masks
+ ; Note that the image passed in from the application is little-endian.
+ ; To write to the VGA planes byte by byte, the image has to be reversed
+ ; to big-endian for the purpose of quick drawing since the VGA can only
+ ; read and write one byte from/to its latches.
+
+ mov di,bx ; point to the top of the buffer again
+ mov si,bp ; point to the new pointer image
+
+ mov cx,32
+norept1:
+ lodsw ; read in the required image word
+ xchg al,ah ; convert little endian to big endian
+ stosw ; write into local buffer
+ inc di ; remember local buffer in 3 bytes wide
+ dec cx
+ jnz norept1
+
+ ; Now, the aligned mask must be rotated, then copied into each of
+ ; the seven unaligned image buffers.
+
+ mov ax,cs
+ mov ds,ax ; return to the default data segment
+
+ mov bp,1000000000000000b ; a mask for the MSBit
+
+ lea di,AlignData1 ; point to the buffer for 1 bit offset
+ mov si,bx ; source = byte aligned pointer image
+
+ push bx
+ mov bx,32*7
+norept2:
+ lodsw ; load the word from 3 byte sequence
+ xchg al,ah ; put into little-endian format
+ mov cl,byte ptr [si] ; load the remaining byte
+ shr ax,1 ; LSB now stored in CF
+ rcr cl,1 ; CF into MSB, lsb into CF
+ jnc $+4 ; CF=0 -> don't need to do anything
+ or ax,bp ; OR in the carried bit from CF
+ xchg al,ah ; return to bitstream format
+ stosw ; write the rotated data
+ mov byte ptr[di],cl
+ inc si ; point to the next source scanline
+ inc di ; point to the next dest scanline
+
+ dec bx
+ jnz norept2
+ pop bx
+
+ ; Just to do a little bit more work, the rotated buffers created
+ ; above must be copied to the instances for byte 78 and byte 79
+ ; of the scanline. These images are then cunningly clipped in the
+ ; process to the edge of the screen!
+
+ mov si,bx ; BX points to the top of current buffer
+ ; Note DI points to clip_cursor78 now
+
+ ; may as well use the nice string functions now that I don't
+ ; have to XCHG bytes. (how space and cycle efficient
+
+ xor al,al ; constant for putting in masks
+
+ ; there are 8 instances for bits 0 to 7
+
+ mov bx,8
+norept3:
+
+ ; Do the AND mask modifications for byte 78
+
+ not al ; AL = 11111111b
+ REPT 16 ; 16 scanlines
+ movsw ; copy contents of AND word
+ stosb ; Nice clear AND mask = 11111111b
+ inc si ; point to the first image byte in
+ ; the next scanline
+ ENDM
+
+ ; Do the XOR mask modifications for byte 78
+
+ not al ; AL = 00000000b
+ REPT 16 ; 16 scanlines
+ movsw ; copy contents of XOR word
+ stosb ; Nice clear XOR mask = 00000000b
+ inc si ; point to the first image byte in
+ ; the next scanline
+ ENDM
+
+ dec bx
+ jnz norept3
+
+ ; prepare the BYTE 79 instances
+ ; SI and DI should be in the right place
+
+ xor ax,ax ; constant for putting in masks
+ mov bx,2 ; constant for addressing source
+
+ ; there are 8 instances for bits 0 to 7
+
+ mov cx,8
+norept4:
+
+ ; Do the AND mask modifications for byte 79
+
+ not ax ; AX = 0ffffh
+ REPT 16 ; 16 scanlines
+ movsb ; copy contents of AND byte
+ stosw ; Nice clear AND mask (=0ffffh)
+ add si,bx ; point to the first image byte in
+ ; the next scanline
+ ENDM
+
+ ; Do the XOR mask modifications for byte 79
+
+ not ax ; AX = 0h
+ REPT 16 ; 16 scanlines
+ movsb ; copy contents of XOR byte
+ stosw ; Nice clear XOR mask
+ add si,bx ; point to the first image byte in
+ ; the next scanline
+ ENDM
+
+ dec cx
+ jz norept4quit
+ jmp norept4
+norept4quit:
+
+ popa
+ pop es
+ pop ds
+
+ ret
+copy_pointer_to_current endp
+
+;========================================================================
+; Procedure to determine the segment of the video buffer for
+; the current display mode.
+;========================================================================
+
+assume ds:SpcMseSeg
+
+getvideobuffer proc near
+
+ push ax
+ push si
+
+ ; determine the current video mode from the BIOS and save it.
+ ; Use this value to determine the video buffer segment address.
+
+ mov ah,0fh ; use the bios to get the video mode
+ int 10h
+ cbw ; create a table index
+ shl ax,1 ; word sized table entries
+ mov si,ax
+ mov ax,[videomodetable+si] ; use video mode to index the table
+ mov [videobufferseg],ax
+
+
+ pop si
+ pop ax
+ ret
+
+getvideobuffer endp
+
+IFDEF DEBUGMOUSE
+
+;=========================================================================
+; Code to provide 32 bit side with a dump of the VGA registers on request.
+;=========================================================================
+
+VGAregs db 9+5+25 dup(?) ; enough room for sequencer, GC and CTRC
+
+dumpVGAregs proc near
+
+ call DOCLI
+ pusha
+ push ds
+
+
+ mov ax,cs
+ mov ds,ax
+
+ assume ds:SpcMseSeg
+
+ ; Save the Graphics Controller registers
+
+ xor bx,bx ; Index into the G.C. register saving array
+ mov dx,03ceh ; Graphics Controller index register
+ xor ax,ax
+
+ mov cx,9 ; save 9 G.C. registers
+norept5:
+ mov al,ah
+ out dx,al ; Select it
+ inc dx ; Address the register
+ in al,dx ; Get the register contents
+ mov [VGAregs+bx],al ; Save the register
+ inc bx ; index to next array entry
+ inc ah
+ dec dx ; Sequencer index register
+ dec cx
+ jnz norept5
+
+ ; Save the Sequencer registers
+
+ mov dx,03c4h ; Sequencer index register
+ xor ax,ax
+
+ mov cx,5 ; save 5 sequencer registers
+norept6:
+ mov al,ah
+ out dx,al ; Select it
+ inc dx ; Address the register
+ in al,dx ; Get the register contents
+ mov [VGAregs+bx],al ; Save the register
+ inc bx ; index to next array entry
+ inc ah
+ dec dx ; Sequencer index register
+ dec cx
+ jnz norept6
+
+ ; Save the CRTC registers
+
+ mov dx,03d4h ; CRTC index register
+ xor ax,ax
+
+ mov cx,25 ; save 25 sequencer registers
+norept7:
+ mov al,ah
+ out dx,al ; Select it
+ inc dx ; Address the register
+ in al,dx ; Get the register contents
+ mov [VGAregs+bx],al ; Save the register
+ inc bx ; index to next array entry
+ inc ah
+ dec dx ; CRTC index register
+ dec cx
+ jnz norept7
+
+ pop ds
+ popa
+ call DOSTI
+ bop 0feh ; return to 32 bit land
+
+dumpVGAregs endp
+
+ENDIF ; DEBUGMOUSE
+
+
+;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+;
+; End of Mouse driver general support functions
+;
+;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+;========================================================================
+; Procedure to draw an EGA pointer image on the graphics screen at a
+; specified bit location.
+;
+; Input: CX = pointer offset in the current VRAM byte.
+; DX = offset in the video buffer to pointer
+; Output: None
+; Modifies: AX,BX,CX,DX,BP,SI,DI
+;========================================================================
+
+ assume ds:SpcMseSeg
+.286
+even
+
+drawEGApointer proc near
+
+ push es
+ push ds
+
+ mov ax,cs
+ mov ds,ax
+
+ cld ; index from low memory to high for LODSB
+
+ ; point to the video buffer
+
+ mov ax,0a000h
+ mov es,ax
+ mov bp,dx ; save the byte offset in VRAM for the XOR code
+
+ ; Select the Graphics Controller
+
+ mov dx,03ceh
+
+ ;************ AND MASK OPERATION **************************
+
+ ; use the bit position to select the relavent pointer image
+
+ shl cx,1 ; need a word offset into LUT
+ mov di,cx ; need an index register
+ mov bx,[PointerLUT]
+ mov si,[bx+di] ; Point to the screen (AND) mask
+ mov di,bp ; point to the byte offset in VRAM
+ mov ax,0803h ; Index the data rotate register and select AND
+ out dx,ax ; do it
+ mov ax,80-2 ; Avoid modRM loading of CX
+ mov cx,ax ; A constant handily kept in a register
+
+ ; The pointer contains 16 words of information
+ push bx
+ mov bx,16
+norept8:
+
+ lodsw ; Load 2 bytes from the AND mask into AL and AH
+ xchg al,es:[di] ; Latch the 8 pixels for updating.
+ ; and write them back out with new data
+ inc di ; point to the next byte in VRAM
+
+ xchg ah,es:[di] ; Latch the 8 pixels for updating.
+ ; and write them back out with new data
+ inc di ; point to the next byte in VRAM
+
+ lodsb ; Load a byte from the AND mask into AL
+ xchg al,es:[di] ; Latch the 8 pixels for updating.
+ ; and write them back out with new data
+ add di,cx ; point to the next byte in VRAM on the next scan
+ ; line to write to. CX contains 80-2
+
+ dec bx
+ jnz norept8
+ pop bx
+
+ ;************ XOR MASK OPERATION **************************
+
+ ; Note: SI points to current_cursor+48 now, automatically
+ ; i.e. at the start of the XOR mask.
+
+ mov di,bp ; point to the byte offset in VRAM
+ mov ax,1803h ; Index the DATA ROTATE REGISTER and
+ ; Select the XOR function to XOR CPU data in
+ out dx,ax ; Do the deed
+
+ push bx
+ mov bx,16
+norept9:
+
+ lodsw ; Load 2 bytes from the AND mask into AL and AH
+ xchg al,es:[di] ; Latch the 8 pixels for updating.
+ ; and write them back out with new data
+ inc di ; point to the next byte in VRAM
+
+ xchg ah,es:[di] ; Latch the 8 pixels for updating.
+ ; and write them back out with new data
+ inc di ; point to the next byte in VRAM
+
+ lodsb ; Load a byte from the XOR mask into AL
+ xchg al,es:[di] ; Latch the 8 pixels for updating.
+ ; and write them back out with new data
+ add di,cx ; point to the next byte in VRAM on the next scan
+ ; line to write to. CX contains 80-2
+ dec bx
+ jnz norept9
+ pop bx
+
+ pop ds
+ pop es
+ ret
+
+drawEGApointer endp
+
+;========================================================================
+; Procedure to determine what the byte and bit offset is, in the current
+; VGA buffer for the top left hand corner of the pointer bitmap.
+; The X,Y value is modified for hotspot in this routine. A flag is set,
+; also, to relay whether or not the cursor bitmap is byte aligned or not.
+;
+; INPUT: CX,DX = pointer x,y coordinates
+; OUT : DX = byte offset to top left hand pointer pixel
+; CX = bit offset in the byte
+; CF = set if it is not possible to draw the pointer on the
+; screen because of the hotspot adjustment. (Usually a
+; negative hotspot value will cause clipping and wrapping
+; problems at the right and bottom screen boundaries.
+;========================================================================
+
+determineboundary proc near
+
+ push ax
+ push bx
+ push es
+
+
+ ; do the adjustment in x,y for pointer hotspot
+ ; Also test for top or left screen boundary problems
+ ; and zero the coordinate if it goes negative.
+
+
+ sub cx,[hotspot] ; adjust the x cartesian coord for hotspot
+ jns dont_zero_x ; if x goes negative, assume zero
+ xor cx,cx
+dont_zero_x:
+ sub dx,[hotspot+2] ; adjust the y cartesian coord for the hotspot
+ jns dont_zero_y ; if y goes negative, assume zero
+ xor dx,dx
+dont_zero_y:
+
+ ; Now check the right and bottom bounds to prevent the pointer
+ ; image wrapping if the hotspot adjustment forces either of
+ ; the coordinates to exceed the screen bounds.
+ ; First, for all video modes that this function handles, the
+ ; X bound is always x < 640 ... check this first.
+
+ cmp cx,640
+ jl didntexceedX
+ stc ; Oh oh - failed, so set carry flag.
+ jmp short quitdet ; bye bye.
+
+didntexceedX:
+
+ ; Now check out the y value by finding the maximum extent from
+ ; a lut based on the current BIOS video mode.
+
+ mov ax,40h ; B.D.A. segment
+ mov es,ax ; and ES points to it.
+ mov al,byte ptr es:[49h]
+ sub al,0fh ; table is normalized. mode f is in entry
+ ; zero.
+ xor ah,ah ; create a look up table index
+ shl ax,1 ; for a table with word sized elements.
+ xchg bx,ax ; use a suitable register as index
+
+ cmp dx,[hiresylut+bx] ; get the extent and compare y coord.
+ jl didntexceedY
+ stc ; Oh oh - failed, so set carry flag.
+ jmp short quitdet ; bye bye.
+
+didntexceedY:
+
+ ; determine the byte offset from the start of the video buffer
+ ; for the modified coordinates. First calculate how many bytes
+ ; there are for the number of scanlines -1 to where the pointer
+ ; is.
+
+ mov ax,dx ; copy Y position into AX
+ shl ax,1 ; create a word table index
+ xchg ax,bx ; copy table index into a base register
+ mov dx,[mult80lut+bx] ; do a fast LUT multiply by 80
+
+ ; determine the byte position of the pixel in question
+
+ mov ax,cx ; save the x-coordinate displacement
+ and ax,7 ; do a modulus 8 to find the pixel position
+ ; in the byte. The bit number is in DX.
+
+ ; add the whole number of bytes in the current row to the number
+ ; of complete-row bytes
+
+ shr cx,3 ; divide pixels by 8 to get bytes
+ add dx,cx ; DX hold the complete byte offset.
+ xchg ax,cx ; CX = bit offset in the byte.
+
+ ; the pointer has not exceeded the screen buonds, so clear
+ ; the carry flag to signify this.
+
+ clc
+
+ ; Wind up the routine and return with the carry flag:
+ ; SET if cursor exceeded screen bounds.
+ ; CLEAR otherwise.
+quitdet:
+
+ pop es
+ pop bx
+ pop ax
+ ret
+
+determineboundary endp
+
+;========================================================================
+; Procedure to buffer up the data over which the cursor will next be
+; drawn. This data will be used to replace the cursor at a later point
+; when the cursor position has changed and for generating a cursor image
+; To prevent having separate routines for aligned and unaligned pointer
+; saves, this routine saves a pixel block 24 x 16 deep in all cases. The
+; start offset is a byte location into VRAM in which the pointer TLHC lives.
+;
+; Input: DX = VRAM byte
+; Modifies: AX,BX,DI,CX,DX,ES
+;
+;========================================================================
+
+assume ds:SpcMseSeg
+
+even
+
+save_background proc near
+
+ push ds
+ push es
+ pusha
+
+ mov ax,cs ; point DS briefly at the driver data
+ mov ds,ax
+ mov es,ax ; point ES to the driver segment
+
+ lea di,behindcursor ; DESTINATION: a nice, safe place in the
+ ; driver segment
+ mov ax,0a000h ; point DS at VRAM
+ mov ds,ax
+
+ assume ds:nothing
+
+ mov bp,dx ; save DX=VRAM byte offset for later use
+ mov dx,03ceh ; VGA GC index register
+ mov al,4 ; select the read map select reg
+ out dx,al ; Index in the map select register
+ inc dx ; DX holds port address to map select register
+ xor al,al ; plane 0 will be selected first
+
+ cld ; make sure to address forward in memory
+ mov ah,3 ; number of bytes to copy per pointer scanline
+ xor cx,cx ; counter for the REP MOVSB
+ mov bx,80-3 ; another handy constant: move to next scanline
+ ; byte.
+
+ REPT 4 ; read the 4 EGA planes individually
+
+ mov si,bp ; SOURCE: somewhere in VRAM
+ out dx,al ; do the plane selection
+ inc al ; select the next plane to latch
+
+ ; note that only one byte at a time may be read from the latches
+
+ ; do 16 scanlines for each plane
+ push dx
+ mov dx,16
+@@:
+ mov cl,ah ; CX now contains 3
+ rep movsb ; copy 3 bytes from VRAM to data segment
+ add si,bx ; move down to the first byte in next scanline
+ dec dx
+ jnz @B ; norept10
+ pop dx
+
+ ENDM
+
+ popa
+ pop es
+ pop ds
+
+ ret
+
+save_background endp
+
+;========================================================================
+; Procedure to restore the area of the screen that was behind the cursor
+; before it had moved.
+;
+; Note. Currently (2/12/92) this is the only routine that modifies the
+; VGA sequencer. Therefore, the code from save and restore vga registers
+; that maintain the sequencer registers has been moved to here for
+; centralisation purposes.
+;
+; Input: DX = VRAM byte
+; Output: None
+; Modifies: AX,BX,CX,DX,DI,SI
+;========================================================================
+assume ds:SpcMseSeg
+
+even
+
+restore_background proc near
+ push ds
+ push es
+ pusha
+
+;; call DOCLI ; turn off interrupts
+ mov ax,cs
+ mov ds,ax ; point at the driver data segment
+ mov ax,0a000h ; videobufferseg
+ mov es,ax ; point ES at VRAM segment
+ mov bp,dx ; save the pointer for later
+ mov si,offset behindcursor ; SOURCE: point at the stored planes
+
+ ; set up the Graphic Controller for the restore.
+
+ mov dx,03ceh ; VGA GC index register
+ mov ax,0003h ; Select copy into latches function
+ out dx,ax ; i.e. data rotate -> replace
+ mov ax,0ff08h ; bitmask register reset
+ out dx,ax
+
+ ; do the 4 plane restore.
+
+ mov cx,80-2 ; point to the first byte in image on next line
+ cld ; write forward in memory
+ mov bx,0102h ; BH = initial plane mask value
+ ; plane 0 is selected with a 1
+ ; BL = map mask register offset
+ mov dx,03c4h ; index register for sequencer
+
+ mov al,bl ; point to the map mask register in sequencer
+ out dx,al ; index the register into 03c5h
+ inc dx ; point to the data register
+ in al,dx ; read the data register value in
+ dec dx ; restore DX to 03c4h
+ mov [seqregs],al ; save the map mask register value
+
+ REPT 4 ; 4 planes to restore
+
+ mov di,bp ; DESTINATION: pointer into VRAM
+ mov ax,bx ; select the plane to mask and map mask register
+ out dx,ax ; do the mask
+ shl bh,1 ; point to the mask for the next iteration
+
+ push dx
+ mov dx,16
+@@:
+
+ lodsw ; load the old background data (ONE WORD)
+ xchg al,es:[di] ; latch the VRAM data and swap with the
+ inc di ; point to next byte to replace
+ xchg ah,es:[di] ; latch the VRAM data and swap with the
+ inc di ; point to next byte to replace
+ lodsb ; load the old background data (ONE BYTE)
+ xchg al,es:[di] ; latch the VRAM data and swap with the
+ add di,cx ; point to the first byte in image on next line
+
+ dec dx
+ jnz @B ; norept11
+ pop dx
+
+ ENDM
+
+ mov ah,[seqregs] ; the old map mask value
+ mov al,bl ; need to restore the map mask register
+ out dx,ax ; do the restore
+;; call DOSTI ; reenable interrupts.
+ popa
+ pop es
+ pop ds
+ ret
+restore_background endp
+
+
+;==========================================================================
+; Procedure to save the register state of the VGA card on receiving a
+; mouse pointer update interrupt. This procedure also sets up the following
+; VGA registers to nice values for the driver.
+;
+; mode register <write mode 0, read mode 0>
+; data rotate register <do not rotate, no logical ops>
+; enable set/reset register <disable set/reset>
+;
+;==========================================================================
+
+even
+assume ds:SpcMseSeg
+
+saveVGAregisters proc near
+
+ push dx
+ push di
+ push es
+
+ ; Save the Graphics Controller registers that the
+ ; Driver uses
+
+ xor bx,bx ; Index into the G.C. register saving array
+ mov dx,03ceh ; Graphics Controller index register
+ xor al,al
+
+ push cx
+ mov cx,9 ; save 9 G.C. registers
+norept12:
+ out dx,al ; Select it
+ inc dx ; Address the register
+ in al,dx ; Get the register contents
+ mov [GCregs+bx],al ; Save the register
+ inc bx ; index to next array entry
+ mov al,bl
+ dec dx ; G.C. index register
+ dec cx
+ jnz norept12
+ pop cx
+
+ ; save the latches to location in a bit of video buffer
+ ; off the screen.
+
+ mov ax,0a000h ; point to the video buffer
+ mov es,ax
+
+ assume es:nothing
+
+ mov ax,0105h ; select write mode 1 to squirt latches out
+ out dx,ax ; do the selection
+ mov di,[latchcache] ; 1 byte over the last location
+ mov es:[di],al ; write the latches out to the planes
+
+ ; disable the enable set/reset register
+
+ mov ax,01h ; select enable set/reset register and clear it
+ out dx,ax
+
+ ; clear the data rotate register (no logical operations).
+
+ inc ax
+ inc ax ; select data rotate register and clear it
+ out dx,ax ; AX = 3 therefore points to the DRR
+
+ ; set write mode 0 for the graphics display
+ ; conveniently, this also sets read mode to 0 which is needed too!
+
+ inc ax
+ inc ax ; select write mode 0
+ out dx,ax ; AX = 5, i.e. the mode register
+
+ ; color don't care. don't care for all planes
+ inc ax ;register 7, color don't care
+ inc ax
+ out dx, ax
+ ; bit mask register. enable all planes
+ ;
+ inc ax ;register 8, bit mask
+ not ah
+ out dx, ax
+ pop es
+ pop di
+ pop dx
+ ret
+
+saveVGAregisters endp
+
+;==========================================================================
+; Procedure to restore the register state of the VGA card after dealing
+; with mouse pointer update interrupt.
+;==========================================================================
+
+restoreVGAregisters proc near
+
+ assume ds:SpcMseSeg
+
+ push es
+ push di
+ push bx
+
+ ; restore the latches that where saved in the video planes
+
+ mov ax,0a000h ; point to the video buffer
+ mov es,ax
+
+ assume es:nothing
+
+ mov di,[latchcache] ; the byte just off the end of the buffer
+ mov al,es:[di] ; read in the latches
+
+ ; Restore the Graphics Controller registers that the
+ ; Driver uses
+
+ xor ax,ax ; create an index
+ xor bx,bx ; Index into the G.C. register saving array
+ mov dx,03ceh ; Graphics Controller index register
+
+norept13:
+ mov ah,[GCregs+bx] ; restore the register
+ out dx,ax ; Select it
+ inc al ; index for the next register
+ inc bx ; index to next array entry
+ cmp al,9
+ jne norept13
+
+ pop bx
+ pop di
+ pop es
+ ret
+
+restoreVGAregisters endp
+
+;=======================================================================
+; Procedure to draw a BIOS Mode 4 graphics pointer to the display.
+; Input: DX = byte offset
+; CL = bit offset in the byte
+; CH = 0FFh if ODD, 0 if EVEN
+; BP = Y loop counter, ODD in LSB, EVEN in MSB
+;=======================================================================
+drawmode4pointer proc near
+
+ pusha
+ push es
+ cld
+
+ xchg dx, bp ;
+ mov di, bp ; bp = di = byte offset, dx = y counters
+ mov ax,0b800h ; point a segment register to
+ mov es,ax ; the CGA video buffer.
+ or ch, ch ;
+ je drawonevenscanline ;
+ jmp drawonoddscanline ; otherwise do an ODD job
+
+; ANDEVEN ANDEVEN ANDEVEN ANDEVEN ANDEVEN ANDEVEN ANDEVEN ANDEVEN ANDEVEN
+
+drawonevenscanline:
+
+ mov si,[mode4SelectedPointer]
+ ; Load a word of the pointer image, convert it to two bits per
+ ; pixel and write to the screen for even scanlines
+
+ xor cx, cx
+ mov cl, dh ; number of even scanlines to draw
+ push dx
+evensl1:
+ mov dx,3
+norept14:
+ lodsb ; load 8 pixels from pointer bitmap
+ xor bh,bh ; want a zero extended 16 bit value
+ mov bl,al ; copy into a base register
+ shl bx,1 ; create a word address
+ mov ax,[LUT1to2bit+bx] ; get the byte to word conversion
+ xchg al,ah ; little-endianise
+ mov bx,es:[di] ; get the current displayed 8 pixels
+ and ax,bx ; AND the AND mask in
+ stosw ; write to the video buffer
+ dec dx
+ jnz norept14
+
+ add si,3
+ add di,80-6
+ loop evensl1
+ pop dx
+
+ ; Load a word of the pointer image, convert it to two bits per
+ ; pixel and write to the screen for odd scanlines
+
+ mov si,[mode4SelectedPointer]
+ add si,3
+ mov di,bp
+ add di,02000h ; offset into video buffer
+ ; the video buffer
+ mov cl,dl ; number of odd scanlines to draw
+ push dx
+oddsl1:
+ mov dx,3
+norept15:
+ lodsb ; load 8 pixels from bitmap
+ xor bh,bh
+ mov bl,al ; copy into a base register
+ shl bx,1 ; create a word address
+ mov ax,[LUT1to2bit+bx] ; get the byte to word conversion
+ xchg al,ah
+ mov bx,es:[di] ; get the current displayed 8 pixels
+ and ax,bx ; AND the AND mask in
+ stosw ; write to the video buffer
+ dec dx
+ jnz norept15
+
+ add si,3
+ add di,80-6
+ loop oddsl1
+ pop dx
+
+; XOREVEN XOREVEN XOREVEN XOREVEN XOREVEN XOREVEN XOREVEN XOREVEN XOREVEN
+
+
+ mov si,[mode4SelectedPointer]
+ add si,48
+
+ mov di,bp ; offset into video buffer
+
+ ; Load a word of the pointer image, convert it to two bits per
+ ; pixel and write to the screen for even scanlines
+
+ mov cl,dh ; number of even scanlines to draw
+ push dx
+evensl2:
+ mov dx,3
+norept16:
+ lodsb ; load 8 pixels from bitmap
+ xor bh,bh
+ mov bl,al ; copy into a base register
+ shl bx,1 ; create a word address
+ mov ax,[LUT1to2bit+bx] ; get the byte to word conversion
+ xchg al,ah
+ mov bx,es:[di] ; get the current displayed 8 pixels
+ xor ax,bx ; XOR the XOR mask in
+ stosw ; write to the video buffer
+ dec dx
+ jnz norept16
+
+ add si,3
+ add di,80-6
+ loop evensl2
+ pop dx
+
+ ; Load a word of the pointer image, convert it to two bits per
+ ; pixel and write to the screen for odd scanlines
+
+ mov si,[mode4SelectedPointer]
+ add si,48+3
+ mov di,bp
+ add di,02000h ; offset into video buffer
+ ; the video buffer
+ mov cl,dl ; number of odd scanlines to draw
+oddsl2:
+ mov dx,3
+norept17:
+ lodsb ; load 8 pixels from bitmap
+ xor bh,bh
+ mov bl,al ; copy into a base register
+ shl bx,1 ; create a word address
+ mov ax,[LUT1to2bit+bx] ; get the byte to word conversion
+ xchg al,ah
+ mov bx,es:[di] ; get the current displayed 8 pixels
+ xor ax,bx ; XOR the XOR mask in
+ stosw ; write to the video buffer
+ dec dx
+ jnz norept17
+
+ add si,3
+ add di,80-6
+ loop oddsl2
+ pop es
+ popa
+ ret
+
+
+; ANDODD ANDODD ANDODD ANDODD ANDODD ANDODD ANDODD ANDODD ANDODD ANDODD ANDODD
+;
+; This part of the code draws the pointer on an odd numbered scanline
+; of the video display. Since the video buffer is split, 0000 to 1fff
+; containing even scanlines and 2000 to 3fff containing odd, the data
+; must be manipulated in a subtly different fashion than that of the
+; even display scanline code.
+; The even scanline code display arrangement falls through naturally,
+; with an even scanline drawing thus:
+; buffer 0: scanline 0
+; buffer 1: scanline 0
+; buffer 0: scanline 1
+; buffer 1: scanline 1
+; buffer 0: scanline 2
+; buffer 1: scanline 2 etc.
+; whereas in the odd case:
+; buffer 1: scanline 0
+; buffer 0: scanline 0
+; buffer 1: scanline 1
+; buffer 0: scanline 1
+; buffer 1: scanline 2
+; buffer 0: scanline 2 etc.
+; and this requires that the odd image scanlines must be placed
+; one scanline lower in the even buffer than the even image scanlines
+; do in the odd buffer
+
+drawonoddscanline:
+
+
+ ; Load a word of the pointer image, convert it to two bits per
+ ; pixel and write to the screen for odd scanlines
+
+ mov si,[mode4SelectedPointer]
+ add di,02000h ; offset into video buffer
+ ; the video buffer
+
+ xor cx,cx
+ mov cl,dl ; number of odd scanlines to draw
+ push dx
+oddsl3:
+ mov dx,3
+norept18:
+ lodsb ; load 8 pixels from bitmap
+ xor bh,bh
+ mov bl,al ; copy into a base register
+ shl bx,1 ; create a word address
+ mov ax,[LUT1to2bit+bx] ; get the byte to word conversion
+ xchg al,ah
+ mov bx,es:[di] ; get the current displayed 8 pixels
+ and ax,bx ; AND the AND mask in
+ stosw ; write to the video buffer
+ dec dx
+ jnz norept18
+
+ add si,3
+ add di,80-6
+ loop oddsl3
+ pop dx
+
+
+ ; Load a word of the pointer image, convert it to two bits per
+ ; pixel and write to the screen for even scanlines
+
+ and dh,dh
+ jz dontdothis1 ; can't do the loop 0 times
+
+ mov si,[mode4SelectedPointer]
+ add si,3
+ mov di,bp
+ add di,6 ; This is required to align the
+ ; even and odd scanlines together
+ mov cl,dh ; number of even scanlines to draw
+ push dx
+evensl3:
+ add di,80-6 ; remember even BELOW odd
+ mov dx,3
+norept19:
+ lodsb ; load 8 pixels from bitmap
+ xor bh,bh
+ mov bl,al ; copy into a base register
+ shl bx,1 ; create a word address
+ mov ax,[LUT1to2bit+bx] ; get the byte to word conversion
+ xchg al,ah
+ mov bx,es:[di] ; get the current displayed 8 pixels
+ and ax,bx ; AND the AND mask in
+ stosw ; write to the video buffer
+ dec dx
+ jnz norept19
+ add si,3
+ loop evensl3
+ pop dx
+
+dontdothis1:
+
+; XORODD XORODD XORODD XORODD XORODD XORODD XORODD XORODD XORODD XORODD XORODD
+
+
+ mov si,[mode4SelectedPointer]
+ add si,48
+ mov di,bp ; offset into video buffer
+ add di,02000h ; offset into video buffer
+ ; the video buffer
+
+ ; Load a word of the pointer image, convert it to two bits per
+ ; pixel and write to the screen for odd scanlines
+
+ mov cl,dl ; number of odd scanlines to draw
+ push dx
+oddsl4:
+ mov dx,3
+norept20:
+ lodsb ; load 8 pixels from bitmap
+ xor bh,bh
+ mov bl,al ; copy into a base register
+ shl bx,1 ; create a word address
+ mov ax,[LUT1to2bit+bx] ; get the byte to word conversion
+ xchg al,ah
+ mov bx,es:[di] ; get the current displayed 8 pixels
+ xor ax,bx ; XOR the XOR mask in
+ stosw ; write to the video buffer
+ dec dx
+ jnz norept20
+ add si,3
+ add di,80-6
+ loop oddsl4
+ pop dx
+
+ ; Load a word of the pointer image, convert it to two bits per
+ ; pixel and write to the screen for even scanlines
+
+ and dh,dh ; can't do a loop 0 times
+ jz dontdothis2
+
+ mov si,[mode4SelectedPointer]
+ add si,48+3
+ mov di,bp
+ add di,6
+
+ mov cl,dh ; number of even scanlines to draw
+
+evensl4:
+ add di,80-6
+ mov dx,3
+norept21:
+ lodsb ; load 8 pixels from bitmap
+ xor bh,bh
+ mov bl,al ; copy into a base register
+ shl bx,1 ; create a word address
+ mov ax,[LUT1to2bit+bx] ; get the byte to word conversion
+ xchg al,ah
+ mov bx,es:[di] ; get the current displayed 8 pixels
+ xor ax,bx ; XOR the XOR mask in
+ stosw ; write to the video buffer
+ dec dx
+ jnz norept21
+
+ add si,3
+ loop evensl4
+
+dontdothis2:
+
+; XORXORXORXORXORXORXORXORXORXORXORXORXORXORXORXORXORXORXORXORXORXORXORXOR
+
+ pop es
+ popa
+ ret
+drawmode4pointer endp
+
+;========================================================================
+; Procedure to determine what the byte and bit offset is, in the current
+; VGA buffer for the top left hand corner of the pointer bitmap.
+; The X,Y value is modified for hotspot in this routine.
+; Y looping counter(ODD and EVEN) are also returned
+; The CGA buffer is interleaved, and runs from B800:0000 to B800:1999 for
+; odd scanlines and from B800:2000 for even scanlines.
+;
+; INPUT: CX,DX = pointer x,y coordinates
+; OUT :
+; carry set if either X or Y is out of screen
+; DX = byte offset to top left hand pointer pixel of the pointer
+; CL = bit offset in the byte
+; CH = 0FFh if ODD, 0 if EVEN
+; BP = Y loop counter(ODD in LSB and EVEN in MSB)
+;========================================================================
+
+detboundmode4 proc near
+
+ push ax
+ push bx
+ push ds
+
+ mov ax,cs
+ mov ds,ax
+
+ assume ds:SpcMseSeg
+
+
+ ; do the adjustment in x,y for pointer hotspot
+ ; modify the raw X,Y values for hotspot
+
+ sub cx,[hotspot] ; adjust the x cartesian coord for hotspot
+ jns dont_zero_xmode4; if x goes negative, assume zero
+ xor cx,cx
+
+dont_zero_xmode4:
+
+ sub dx,[hotspot+2] ; adjust the y cartesian coord for the hotspot
+ jns dont_zero_ymode4; if y goes negative, assume zero
+ xor dx,dx
+
+dont_zero_ymode4:
+
+ cmp cx, 320 ;
+ jae detboundmode4_exit ; CY is cleared
+ cmp dx, 200
+ jae detboundmode4_exit ; CY is cleared
+ ; determine the byte offset from the start of the video buffer
+ ; for the modified coordinates. First calculate how many bytes
+ ; there are for the number of scanlines -1 to where the pointer
+ ; is. Also if the pointer starts on a odd scanline, set CF, else
+ ; clear CF.
+
+ mov ax,dx ; copy Y position into AX
+ mov bp,dx ; copy Y position into BP for use later
+
+ ; CGA video buffer is split in two. Therefore, screen scanline 0 maps
+ ; to video buffer scanline 0 and screen scanline 1 maps to video
+ ; buffer+2000h, scanline 0
+
+ and ax,0fffeh ; do the mapping 0->0, 1->0, 2->1, 3->1 etc.
+ ; and create a word table index
+ mov bx, ax ; copy table index into a base register
+ ; 2bits/pixel -> 4 pixels/byte
+ ; sine x total is 320, we have 80bytes
+ ; so a shl bx, 1 will be wrong.
+ mov dx,[mult80lut+bx] ; do a fast LUT multiply by 80
+
+ ; determine the byte position of the pixel in question
+
+ mov ax,cx ; save the x-coordinate displacement
+ and ax,3 ; do a modulus 4 to find the pixel position
+ ; in the byte. The byte number will be in DX.
+
+ ; add the whole number of bytes in the current row to the number
+ ; of complete-row bytes. Note that mode 4 is 2bits per pixel, so
+ ; there are four pixels represented by one byte.
+
+ mov bx,cx ; Save in a base reg. to create a table index
+ shl bx,1 ; Create a table index for word sized entries
+ add dx,[mode4clipCXadjustLUT+bx]; DX hold the complete byte offset.
+ mov cx, ax ; CX = bit offset in the byte.
+
+ mov ax, [mode4pointerLUT + bx] ; select appropriate pointer
+ mov [mode4SelectedPointer], ax
+
+ ; Odd or Even scanline? note BP contains y cartesian coordinate
+
+ mov bx, bp ; y coordinate
+ shr bp, 1 ; shift right to determine if odd or even
+ ; CF if odd, or 0 if even.
+ sbb ch, ch ; CH = 0FFh if ODD, 0 if EVEN
+ shl bx, 1
+ mov bp, [mode4clipDXLUT + bx] ;the Y counters
+ stc ; we are fine, set the CY so we will return
+ ; CY cleared.
+detboundmode4_exit:
+ cmc ; revese the CY
+ pop ds
+ pop bx
+ pop ax
+ ret
+
+detboundmode4 endp
+
+
+
+;=============================================================================
+; Procedure to save the area of CGA video buffer into which the pointer will
+; be drawn. The memory buffer in which this data is stored is arranged odd
+; scanlines first, then even. So, the first 48 bytes are the odd scanline
+; data.
+;
+; Input: DX = byte offset
+; CL = bit offset in the byte
+; CH = 0FFh if ODD, 0 if EVEN
+; BP = Y loop counter, ODD in LSB, EVEN in MSB
+;
+;=============================================================================
+
+savebkgrndmode4 proc near
+
+ pusha
+ push es
+ push ds
+
+ ; set up the segment registers as required
+
+ mov ax,ds
+ mov es,ax
+ mov ax,0b800h
+ mov ds,ax
+ assume ds:nothing, es:SpcMseSeg
+ mov si,dx ; start the save.
+ or ch, ch
+ je svbkeven ; check the returned carry flag
+
+ ; the image's first scanline is odd
+
+ mov di,offset CGAbackgrnd ; where the background will be saved
+ mov bx,bp ; set the loop counter up
+ xor bh,bh ; don't want unwanted mess in MSB
+ add si,2000h ; odd part of buffer starts at 2000h
+svodd1:
+ mov cx,3 ; copy six bytes
+ rep movsw ; do the image scanline save
+ add si,80-6 ; point to the next scanline
+ dec bx ; decrement the loop counter
+ jnz svodd1 ; do more scanlines if necessary
+
+ ; save some even scanlines if need be.
+
+ mov si,dx ; offset into CGA buffer
+ add si, 80
+ mov bx,bp ; set up the loop counter
+ xchg bl,bh ; get the even part of loop counter
+ xor bh,bh ; trash the top end trash
+ and bx,bx ; check for a zero loop
+ jz misseven ; can't have a loop which execs 0 times
+ mov di,offset CGAbackgrnd+48; where the background will be saved
+sveven1:
+ mov cx,3 ; copy six bytes = 24 pixels
+ rep movsw ; do the scanline save
+ add si,80-6 ; point to the next scanline
+ dec bx ; decrement the loop counter
+ jnz sveven1 ; do more scanlines if necessary
+
+misseven: ; jump to here if there are no even scanlines to draw
+
+ jmp short endsavemode4
+
+svbkeven: ; the image's first scanline is even
+
+ mov di,offset CGAbackgrnd+48; where the background will be saved
+
+ mov bx,bp ; get the loop counter
+ xchg bl,bh ; rearrage to get the even part
+ xor bh,bh ; clear out the trash
+sveven2:
+ mov cx,3 ; copy six bytes
+ rep movsw ; do the copy
+ add si,80-6 ; point to the next scanline
+ dec bx ; decrement the loop counter
+ jnz sveven2 ; do more scanlines if necessary
+
+ mov si,dx ; offset into CGA buffer
+ add si,2000h ; odd part of the video buffer
+ mov di,offset CGAbackgrnd ; where to save the odd scanlines
+ mov bx,bp ; get the loop counter
+ xor bh,bh ; clear out the unwanted trash
+svodd2:
+ mov cx,3 ; copy six bytes
+ rep movsw ; do the copy
+ add si,80-6 ; point to the next scanline
+ dec bx ; decrement the loop counter
+ jnz svodd2 ; do more scanlines if necessary
+
+endsavemode4:
+ assume ds:SpcMseSeg, es:nothing
+
+ pop ds
+ pop es
+ popa
+ ret
+savebkgrndmode4 endp
+
+;=============================================================================
+; Procedure to restore the area of CGA video buffer into which the pointer
+; was drawn. The memory buffer in which this data is stored is arranged
+; odd scanlines first, then even. So, the first 48 bytes are the odd scanline
+; data.
+;
+; Input:
+; DX = byte offset to top left hand pointer pixel of the pointer
+; CL = bit offset in the byte
+; CH = 0FFh if ODD, 0 if EVEN
+; BP = Y loop counter(ODD in LSB and EVEN in MSB)
+;
+;=============================================================================
+
+restorebkgrndmode4 proc near
+
+ pusha
+ push es
+
+ ; set up the segment registers as required
+
+ mov ax,0b800h
+ mov es,ax
+ mov di,dx ; restore background
+ or ch, ch
+ je rsbkeven ; check the returned carry flag
+
+ ; the image's first scanline is odd. The CGA buffer is translated
+ ; so that a scanline (row N) from the even part of the buffer appears
+ ; on the screen at raster I. The scanline at position N from the
+ ; odd part of the video buffer maps to screen position I+1. If the
+ ; 1st. scanline is odd, then this is drawn at raster A and the
+ ; following algorithm draws the 1st. even row at raster A+1 to
+ ; compensate for the video buffer arrangement.
+
+ mov si,offset CGAbackgrnd ; where the background is be saved
+ add di,2000h ; do the odd buffer
+
+ mov bx,bp ; set the loop counter up
+ xor bh,bh ; clear out the MSB trash
+rsodd1:
+ mov cx,3 ; copy six bytes
+ rep movsw ; do the restore
+ add di,80-6 ; point to the next odd scanline
+ dec bx ; decrement the loop counter
+ jnz rsodd1 ; restore more even scanlines if needed
+
+ mov bx,bp ; let the loop counter
+ xchg bl,bh ; get the even part
+ xor bh,bh ; clear out the MSB trash
+ and bx,bx ; test for zero even scanlines
+ jz misseven1rs ; can't have a zero execute loop
+ mov di,dx ; offset into CGA buffer
+ add di,80 ; get the odd/even scanlines instep
+ mov si,offset CGAbackgrnd+48; where the background is be saved
+rseven1:
+ mov cx,3 ; restore six bytes
+ rep movsw ; do the restore
+ add di,80-6 ; point to the next even scanline
+ dec bx ; decrement the loop counter
+ jnz rseven1 ; restore more even scanlines if needed
+
+misseven1rs: ; jump to here if there are no even scanlines to be restored.
+
+ jmp short endrestoremode4
+
+rsbkeven: ; the image's first scanline is even
+
+ mov si,offset CGAbackgrnd+48; where the background will be saved
+
+ mov bx,bp ; get the loop counter
+ xchg bl,bh ; get the even part of the loop counter
+ xor bh,bh ; scrap the MSB trash
+rseven2:
+ mov cx,3 ; restore six bytes
+ rep movsw ; do the restore
+ add di,80-6 ; point to the next even scanline
+ dec bx ; decrement the loop counter
+ jnz rseven2 ; do more even scanlines if needed
+
+ mov di,dx ; offset into CGA buffer
+ add di,2000h ; do the odd buffer
+ mov si,offset CGAbackgrnd ; where to save the odd scanlines
+
+ mov bx,bp ; set the loop counter up
+ xor bh,bh ; scrap the MSB trash
+rsodd2:
+ mov cx,3 ; restore six bytes
+ rep movsw ; do the restore
+ add di,80-6 ; point to the next odd scanline
+ dec bx ; decrement the loop counter
+ jnz rsodd2 ; restore more odd scanlines if needed
+
+endrestoremode4:
+ assume ds:SpcMseSeg, es:nothing
+
+ pop es
+ popa
+ ret
+restorebkgrndmode4 endp
+
+;============================================================================
+; Procedure to draw the pointer image into the video buffer for mode 13h
+; VGA graphics.
+;
+; Input:
+; DX = byte offset
+; BP = Y loop counter
+; CX = X loop counter
+;
+;============================================================================
+
+draw256pointer proc near
+ pusha
+ push es
+ push ds
+
+ mov ax,0a000h ; point to the 256 colour mode video buffer
+ mov es,ax
+ mov ax,cs
+ mov ds,ax
+
+ assume ds:SpcMseSeg, es:nothing
+
+ cld ; write forward through the buffer
+ ; DX = TLHC pixel offset in the video buffer.
+ mov di,dx ; point DI at the video buffer location of fun
+ mov si, offset current_cursor ; we only use this cursor shape
+ ; because every pixel is on byte
+ ; boundary. The X counter would
+ ; take care of X clipping
+y_256:
+ push cx
+ lodsw ;and mask
+ mov dx, [si + 48 - 2] ;xor mask
+ inc si ;we don't need the third byte
+ xchg al, ah ; byte sequence
+ xchg dh, dl ;
+x_256:
+ shl ax, 1 ;AND mask bit
+ sbb bl, bl ; bl = 0FFf if CY, 0 if not CY
+ and bl, es:[di] ;and the target and save the result
+ shl dx, 1 ;XOR mask bit
+ sbb bh, bh ;
+ xor bl, bh ;xor with the save result
+ mov es:[di], bl ;update the target
+ inc di ;next pixel
+ loop x_256 ;until this scan line is done
+ pop cx ;recovery X loop counter
+ add di, 320 ;target address to next scan line
+ sub di, cx
+ dec bp ;Y counter
+ jne y_256
+
+ pop ds
+ pop es
+ popa
+ ret
+draw256pointer endp
+
+;=============================================================================
+; Procedure to save the area of 256 colour mode video buffer into which the
+; pointer will be drawn. The memory buffer in which this data is stored is
+; arranged odd scanlines first, then even. So, the first 48 bytes are the odd
+; scanline data.
+;
+; Input:
+; DX = byte offset
+; BP = Y loop counter
+; CX = X loop counter
+;
+;=============================================================================
+
+savebkgrndmode13 proc near
+ pusha
+ push es
+ push ds
+
+ mov di,offset bkgrnd256 ; point to the area in which backgound
+ ; data will be saved
+ mov si,dx ; SOURCE: the video buffer at x,y
+
+ mov ax,0a000h
+ mov ds,ax
+ mov ax,cs
+ mov es,ax
+ mov bx, cx ;x counter
+ mov dx, 320
+ sub dx, bx
+ assume ds:nothing, es:SpcMseSeg
+ cld
+save_256_loop:
+ mov cx, bx
+ shr cx, 1
+ rep movsw
+ adc cl, 0
+ rep movsb
+ add si, dx ; next scan line offset
+ dec bp ; until Y counter is done
+ jne save_256_loop
+
+ pop ds
+ pop es
+
+ assume es:nothing, ds:SpcMseSeg
+
+ popa
+ ret
+savebkgrndmode13 endp
+
+;=============================================================================
+; Procedure to replace an existing pointer image in the 256 colour video
+; buffer with the data that was there previous to the pointer draw operation.
+; The data is stored in an internal (to the driver) buffer.
+;
+; Input:
+; DX = byte offset
+; BP = Y loop counter
+; CX = X loop counter
+;
+;=============================================================================
+
+restorebkgrndmode13 proc near
+ pusha
+ push es
+
+ mov di,dx ; DESTINATION: in the VRAM
+ mov ax,0a000h ; point a segment register at video buffer
+ mov es,ax
+
+ assume es:nothing
+ mov bx, cx
+ mov si,offset bkgrnd256 ; where the data is saved
+ mov dx, 320
+ sub dx, bx
+
+ cld ; write forward in memory
+restore_256_loop:
+ mov cx, bx
+ shr cx, 1
+ rep movsw
+ adc cl, 0
+ rep movsb
+ add di, dx
+ dec bp
+ jne restore_256_loop
+
+ pop es
+ popa
+ ret
+restorebkgrndmode13 endp
+
+;========================================================================
+; Procedure to determine what the byte offset is, in the current
+; VGA buffer for the top left hand corner of the pointer bitmap.
+; The X,Y value is modified for hotspot in this routine. X and Y looping
+; counters are also returned.
+;
+; INPUT: CX,DX = pointer x,y coordinates
+; OUT :
+; carry set if either X or Y is out of screen
+; DX = byte offset to top left hand pointer pixel of the pointer
+; CX = X counter
+; BP = Y counter
+;========================================================================
+
+detboundmode13 proc near
+
+ push ax
+ push bx
+ push ds
+
+ mov ax,cs
+ mov ds,ax
+
+ assume ds:SpcMseSeg
+
+
+ ; do the adjustment in x,y for pointer hotspot
+ ; modify the raw X,Y values for hotspot
+
+ sub cx,[hotspot] ; adjust the x cartesian coord for hotspot
+ jns dont_zero_xmode13; if x goes negative, assume zero
+ xor cx,cx
+
+dont_zero_xmode13:
+
+ sub dx,[hotspot+2] ; adjust the y cartesian coord for the hotspot
+ jns dont_zero_ymode13; if y goes negative, assume zero
+ xor dx,dx
+
+dont_zero_ymode13:
+ cmp cx, 320
+ jae detboundmode13_exit ; CY is cleared
+ cmp dx, 200 ;
+ jae detboundmode13_exit ; CY is cleared
+
+ ; CX and DX are now validated for the following section: buffer
+ ; offset determination. Note, unlike other video modes, mode 13
+ ; provides a direct mapping of the video display to video buffer.
+ ; in other words; 1 byte represents 1 pixel. From this, it is not
+ ; necessary to provide byte alignment data.
+
+ mov bx,dx ; save in a base register
+ shl bx,1 ; create a word table index
+ mov dx,[mult320LUT+bx] ; do the multiply by 320
+ ; add in the offset along the current raster.
+
+ add dx,cx ; cx contains the byte offset from
+ mov ax,[mode4clipDXLUT + bx]; get Y loop counter from table
+ add al, ah ; the table has ODD/EVEN counters
+ cbw
+ mov bp, ax ; the final Y counter
+ ; column 0.
+ mov ax, 320 ; calculate X loop counter
+ sub ax, cx
+ cmp ax, 16 ;
+ jl set_new_x_counter
+ mov ax, 16
+set_new_x_counter:
+ mov cx, ax ; X counter
+ stc ; everything is fine, set CY
+ ; so we will return CY cleared
+detboundmode13_exit:
+ cmc ; complement the CY
+ pop ds
+ pop bx
+ pop ax
+ ret
+
+detboundmode13 endp
+
+
+ public SpcMseEnd
+SpcMseEnd label byte
+
+;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+;
+; Installation Code From Here Downwards
+;
+;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+; segment:offset table for redirected mouse functions for real rom version.
+
+mio_table dw 38 dup(?)
+
+
+
+ assume cs:SpcMseSeg,ds:nothing,es:nothing
+
+ public InstSpcMse
+;
+; InstSpcMse - Installs the softpc mouse driver code
+;
+; Inputs: ds == Resident location of SpcMseSeg
+; Outputs: None
+;
+InstSpcMse proc near
+
+ ;;;;;;;;;;;;;;;;do ret to use old mouse driver;;; ret
+
+ pusha
+
+ ; save old int 10 vector
+ xor ax,ax
+ mov es,ax
+ mov ax,es:[40h]
+ mov si,offset old_vid_int
+ mov word ptr ds:[si],ax
+ mov ax,es:[42h]
+ mov word ptr ds:[si+2],ax
+
+ mov bx,ds
+ mov si,offset sysinitgrp:mio_table
+ push ds
+ push cs
+ pop ds
+
+ mov word ptr ds:[si], offset mouse_io
+ mov word ptr ds:[si+2],bx
+
+IFDEF MOUSE_VIDEO_BIOS
+
+ mov word ptr ds:[si+4],offset mouse_video_io
+ mov word ptr ds:[si+6],bx
+
+ENDIF ; MOUSE_VIDEO_BIOS
+
+ mov word ptr ds:[si+8],offset mouse_int1
+ mov word ptr ds:[si+10],bx
+ mov word ptr ds:[si+12], offset mouse_version
+ mov word ptr ds:[si+14],bx
+ mov word ptr ds:[si+16],offset mouse_copyright
+ mov word ptr ds:[si+18],bx
+ mov word ptr ds:[si+20],offset video_io
+ mov word ptr ds:[si+22],bx
+ mov word ptr ds:[si+24],offset mouse_int2
+ mov word ptr ds:[si+26],bx
+ mov word ptr ds:[si+28],offset entry_point_from_32bit
+ mov word ptr ds:[si+30],bx
+ mov word ptr ds:[si+32],offset int33function0
+ mov word ptr ds:[si+34],bx
+ mov word ptr ds:[si+36],offset int33function1
+ mov word ptr ds:[si+38],bx
+ mov word ptr ds:[si+40],offset int33function2
+ mov word ptr ds:[si+42],bx
+ mov word ptr ds:[si+44],offset int33function9
+ mov word ptr ds:[si+46],bx
+ mov word ptr ds:[si+48],offset current_position_x
+ mov word ptr ds:[si+50],bx
+ mov word ptr ds:[si+52],offset current_position_y
+ mov word ptr ds:[si+54],bx
+ mov word ptr ds:[si+56],offset mouseINB
+ mov word ptr ds:[si+58],bx
+ mov word ptr ds:[si+60],offset mouseOUTB
+ mov word ptr ds:[si+62],bx
+ mov word ptr ds:[si+64],offset mouseOUTW
+ mov word ptr ds:[si+66],bx
+ mov word ptr ds:[si+68],offset VRAMlasttextcelloff
+ mov word ptr ds:[si+70],bx
+ mov word ptr ds:[si+72],offset internalCF
+ mov word ptr ds:[si+74],bx
+ mov word ptr ds:[si+76],offset function3data
+ mov word ptr ds:[si+78],bx
+ mov word ptr ds:[si+80],offset conditional_off
+ mov word ptr ds:[si+82],bx
+ pop ds
+ mov bx, offset sysinitgrp:mio_table
+ bop 0C8h ; Host mouse installer BOP
+
+; get the freshly written int 33h vector from IVT
+; write the vector segment:offset data to the jump patch
+
+ xor ax,ax
+ mov es,ax
+ mov ax,es:[33h*4]
+ mov bx,es:[(33h*4)+2]
+ mov si,offset moff
+ mov word ptr ds:[si],ax
+ mov word ptr ds:[si+2],bx
+ add ax,2 ; HLL entry point
+ mov si,offset loffset
+ mov word ptr ds:[si],ax
+ mov word ptr ds:[si+2],bx
+
+; write the new value to the IVT
+ call DOCLI
+ mov bx, offset int33h_vector
+ mov word ptr es:[33h*4], bx
+ mov bx, ds
+ mov word ptr es:[(33h*4)+2], bx
+ call DOSTI
+
+ popa
+ ret
+InstSpcMse endp
+
+SpcMseSeg ends
+ end
diff --git a/private/mvdm/softpc.new/bios/sysconf.asm b/private/mvdm/softpc.new/bios/sysconf.asm
new file mode 100644
index 000000000..6a5209942
--- /dev/null
+++ b/private/mvdm/softpc.new/bios/sysconf.asm
@@ -0,0 +1,3972 @@
+page ,160
+ title bios system initialization
+;
+;----------------------------------------------------------------------------
+;
+; Modification history
+;
+; 26-Feb-1991 sudeepb Ported for NT DOSEm
+;----------------------------------------------------------------------------
+
+ include version.inc ; set version build flags
+ include biosseg.inc ; establish bios segment structure
+
+lf equ 10
+cr equ 13
+tab equ 9
+
+have_install_cmd equ 00000001b ; config.sys has install= commands
+has_installed equ 00000010b ; sysinit_base installed.
+
+default_filenum = 8
+
+ break macro ; dummy empty macro
+ endm
+
+ include sysvar.inc
+ include pdb.inc ; M020
+ include syscall.inc
+ include doscntry.inc
+ include devsym.inc
+ include devmark.inc
+
+ include umb.inc
+ include dossym.inc
+ include dossvc.inc
+ include cmdsvc.inc
+ include softpc.inc
+
+stacksw equ true ;include switchable hardware stacks
+
+ if ibmjapver
+noexec equ true
+ else
+noexec equ false
+ endif
+
+
+
+
+; external variable defined in ibmbio module for multi-track
+
+multrk_on equ 10000000b ;user spcified mutitrack=on,or system turns
+ ; it on after handling config.sys file as a
+ ; default value,if multrk_flag = multrk_off1.
+multrk_off1 equ 00000000b ;initial value. no "multitrack=" command entered.
+multrk_off2 equ 00000001b ;user specified multitrack=off.
+
+Bios_Data segment
+ extrn multrk_flag:word
+ extrn keyrd_func:byte
+ extrn keysts_func:byte
+Bios_Data ends
+
+; end of multi-track definition.
+
+sysinitseg segment
+
+assume cs:sysinitseg,ds:nothing,es:nothing,ss:nothing
+
+ extrn badopm:byte,crlfm:byte,badcom:byte,badmem:byte,badblock:byte
+ extrn badsiz_pre:byte,badld_pre:byte
+ extrn badstack:byte,badcountrycom:byte
+ extrn badcountry:byte,insufmemory:byte
+ extrn condev:byte,auxdev:byte,prndev:byte,commnd:byte,config:byte
+ extrn cntry_drv:byte,cntry_root:byte,cntry_path:byte
+ extrn memory_size:word
+ extrn buffers:word
+ extrn files:byte,num_cds:byte
+ extrn dosinfo:dword
+ extrn fcbs:byte,keep:byte
+ extrn confbot:word,alloclim:word,command_line:byte
+ extrn zero:byte,sepchr:byte
+ extrn count:word,chrptr:word,cntryfilehandle:word
+ extrn memlo:word,memhi:word,prmblk:word,ldoff:word
+ extrn packet:byte,unitcount:byte,break_addr:dword
+ extrn bpb_addr:dword,drivenumber:byte,sysi_country:dword
+ extrn config_size:word
+ extrn install_flag:word
+ extrn badorder:byte
+ extrn errorcmd:byte
+ extrn linecount:word
+ extrn showcount:byte
+ extrn buffer_linenum:word
+ extrn h_buffers:word
+ extrn badparm:byte
+ extrn configmsgflag:word
+ extrn org_count:word
+ extrn multi_pass_id:byte
+
+ extrn mem_err:near,setdoscountryinfo:near
+ extrn pararound:near,tempcds:near
+ extrn set_country_path:near,move_asciiz:near,delim:near
+ extrn badfil:near,round:near
+ extrn do_install_exec:near
+ extrn setdevmark:near
+
+ extrn print:near,organize:near,newline:near
+ extrn parseline:near
+ extrn badload:near,calldev:near,prnerr:near
+
+ extrn runhigh:byte
+ extrn IsXMSLoaded:near
+
+ extrn TryToMovDOSHi:near
+
+ifdef DBCS
+ extrn testkanj:near
+endif
+
+ extrn bEchoConfig:byte ; NTVDM flag off\on echo of cfg processing
+
+ if stacksw
+
+; internal stack parameters
+
+entrysize equ 8
+
+mincount equ 8
+defaultcount equ 9
+maxcount equ 64
+
+minsize equ 32
+defaultsize equ 128
+maxsize equ 512
+
+DOS_FLAG_OFFSET equ 86h
+
+ extrn stack_count:word
+ extrn stack_size:word
+ extrn stack_addr:dword
+
+ endif
+
+ public doconf
+ public getchr
+ public multi_pass
+ public AllocUMB
+ public AllocUMBLow ; NTVDM
+ public multdeviceflag
+multdeviceflag db 0
+ public devmark_addr
+devmark_addr dw ? ;segment address for devmark.
+ public setdevmarkflag
+setdevmarkflag db 0 ;flag used for devmark
+
+ems_stub_installed db 0
+
+IFDEF DONT_LOAD_OS2_DD ; M045
+
+Os2ChkBuf DD 0 ; Tmp read buffer
+
+ENDIF ; M045
+
+badparm_ptr label dword
+badparm_off dw 0
+badparm_seg dw 0
+
+;******************************************************************************
+;take care of config.sys file.
+;system parser data and code.
+;******************************************************************************
+
+;*******************************************************************
+; parser options set for msbio sysconf module
+;*******************************************************************
+;
+;**** default assemble swiches definition **************************
+
+ ifndef farsw
+farsw equ 0 ; near call expected
+ endif
+
+ ifndef datesw
+datesw equ 0 ; check date format
+ endif
+
+ ifndef timesw
+timesw equ 0 ; check time format
+ endif
+
+ ifndef filesw
+filesw equ 1 ; check file specification
+ endif
+
+ ifndef capsw
+capsw equ 0 ; perform caps if specified
+ endif
+
+ ifndef cmpxsw
+cmpxsw equ 0 ; check complex list
+ endif
+
+ ifndef numsw
+numsw equ 1 ; check numeric value
+ endif
+
+ ifndef keysw
+keysw equ 0 ; support keywords
+ endif
+
+ ifndef swsw
+swsw equ 1 ; support switches
+ endif
+
+ ifndef val1sw
+val1sw equ 1 ; support value definition 1
+ endif
+
+ ifndef val2sw
+val2sw equ 0 ; support value definition 2
+ endif
+
+ ifndef val3sw
+val3sw equ 1 ; support value definition 3
+ endif
+
+ ifndef drvsw
+drvsw equ 1 ; support drive only format
+ endif
+
+ ifndef qussw
+qussw equ 0 ; support quoted string format
+ endif
+
+
+ include parse.asm ;together with psdata.inc
+
+;control block definitions for parser.
+;---------------------------------------------------
+; buffer = [n | n,m] {/e}
+
+p_parms struc
+ dw ?
+ db 1 ; an extra delimiter list
+ db 1 ; length is 1
+ db ';' ; delimiter
+p_parms ends
+
+p_pos struc
+ dw ? ; numeric value??
+ dw ? ; function
+ dw ? ; result value buffer
+
+; note: by defining result_val before this structure, we could remove
+; the "result_val" from every structure invocation
+
+ dw ? ; value list
+ db 0 ; no switches/keywords
+p_pos ends
+
+p_range struc
+ db 1 ; range definition
+ db 1 ; 1 definition of range
+ db 1 ; item tag for this range
+ dd ? ; numeric min
+ dd ? ; numeric max
+p_range ends
+
+buf_parms p_parms <buf_parmsx>
+buf_parmsx dw 201h,buf_pos1,buf_pos2 ; min 1, max 2 positionals
+ db 1 ; one switch
+ dw sw_x_ctrl
+ db 0 ; no keywords
+
+buf_pos1 p_pos <8000h,0,result_val,buf_range_1> ; numeric
+buf_range_1 p_range <,,,1,99> ; M050
+buf_pos2 p_pos <8001h,0,result_val,buf_range_2> ; optional num.
+buf_range_2 p_range <,,,0,8>
+
+sw_x_ctrl p_pos <0,0,result_val,noval,1> ; followed by one switch
+switch_x db '/X',0 ; M016
+
+p_buffers dw 0 ; local variables
+p_h_buffers dw 0
+p_buffer_slash_x db 0
+
+;common definitions ------------
+noval db 0
+
+result_val label byte
+ db ? ; type returned
+ db ? ; item tag returned
+ dw ? ; es:offset of the switch defined
+rv_byte label byte
+rv_dword dd ? ; value if number,or seg:offset to string.
+;-------------------------------
+
+; break = [ on | off ]
+
+brk_parms p_parms <brk_parmsx>
+
+brk_parmsx dw 101h,brk_pos ; min,max = 1 positional
+ db 0 ; no switches
+ db 0 ; no keywords
+
+brk_pos p_pos <2000h,0,result_val,on_off_string> ; simple string
+
+on_off_string label byte
+ db 3 ; signals that there is a string choice
+ db 0 ; no range definition
+ db 0 ; no numeric values choice
+ db 2 ; 2 strings for choice
+ db 1 ; the 1st string tag
+ dw on_string
+ db 2 ; the 2nd string tag
+ dw off_string
+
+on_string db "ON",0
+off_string db "OFF",0
+
+p_ctrl_break db 0 ; local variable
+
+;--------------------------------
+
+; country = n {m {path}}
+; or
+; country = n,,path
+
+cntry_parms p_parms <cntry_parmsx>
+
+cntry_parmsx dw 301h,cntry_pos1,cntry_pos2,cntry_pos3 ; min 1, max 3 pos.
+ db 0 ; no switches
+ db 0 ; no keywords
+
+cntry_pos1 p_pos <8000h,0,result_val,cc_range> ; numeric value
+cc_range p_range <,,,1,999>
+cntry_pos2 p_pos <8001h,0,result_val,cc_range> ; optional num.
+cntry_pos3 p_pos <201h,0,result_val,noval> ; optional filespec
+
+p_cntry_code dw 0 ; local variable
+p_code_page dw 0 ; local variable
+
+;--------------------------------
+
+; files = n
+
+files_parms p_parms <files_parmsx>
+
+files_parmsx dw 101h,files_pos ; min,max 1 positional
+ db 0 ; no switches
+ db 0 ; no keywords
+
+files_pos p_pos <8000h,0,result_val,files_range,0> ; numeric value
+files_range p_range <,,,8,255>
+
+p_files db 0 ; local variable
+
+;-------------------------------
+
+; fcbs = n,m
+
+fcbs_parms p_parms <fcbs_parmsx>
+
+fcbs_parmsx dw 201h,fcbs_pos_1,fcbs_pos_2 ; min,max = 2 positional
+ db 0 ; no switches
+ db 0 ; no keywords
+
+fcbs_pos_1 p_pos <8000h,0,result_val,fcbs_range> ; numeric value
+fcbs_range p_range <,,,1,255>
+fcbs_pos_2 p_pos <8000h,0,result_val,fcbs_keep_range> ; numeric value
+fcbs_keep_range p_range <,,,0,255>
+
+p_fcbs db 0 ; local variable
+p_keep db 0 ; local variable
+
+;-------------------------------
+; lastdrive = x
+
+ldrv_parms p_parms <ldrv_parmsx>
+
+ldrv_parmsx dw 101h,ldrv_pos ; min,max = 1 positional
+ db 0 ; no switches
+ db 0 ; no keywords
+
+ldrv_pos p_pos <110h,10h,result_val,noval> ; drive only, ignore colon
+ ; remove colon at end
+p_ldrv db 0 ; local variable
+
+;-------------------------------
+
+; stacks = n,m
+
+stks_parms p_parms <stks_parmsx>
+
+stks_parmsx dw 202h,stks_pos_1,stks_pos_2 ; min,max = 2 positionals
+ db 0 ; no switches
+ db 0 ; no keywords
+
+stks_pos_1 p_pos <8000h,0,result_val,stks_range> ; numeric value
+stks_range p_range <,,,0,64>
+stks_pos_2 p_pos <8000h,0,result_val,stk_size_range> ; numeric value
+stk_size_range p_range <,,,0,512>
+
+p_stack_count dw 0 ; local variable
+p_stack_size dw 0 ; local variable
+
+;-------------------------------
+
+; multitrack = [ on | off ]
+
+mtrk_parms p_parms <mtrk_parmsx>
+
+mtrk_parmsx dw 101h,mtrk_pos ; min,max = 1 positional
+ db 0 ; no switches
+ db 0 ; no keywords
+
+mtrk_pos p_pos <2000h,0,result_val,on_off_string> ; simple string
+
+p_mtrk db 0 ; local variable
+
+;-------------------------------
+; switches=/k
+
+swit_parms p_parms <swit_parmsx>
+
+swit_parmsx dw 0 ; no positionals
+ db 3 ; 2 switches for now. M059 M063
+ dw swit_k_ctrl ; /k control
+ dw swit_t_ctrl ; /t control M059
+ dw swit_w_ctrl ; /w control M063
+ db 0 ; no keywords
+
+swit_k_ctrl p_pos <0,0,result_val,noval,1> ; switch string follows
+swit_k db '/K',0
+swit_t_ctrl p_pos <0,0,result_val,noval,1> ; switch string follows M059
+swit_t db '/T',0 ; M059
+swit_w_ctrl p_pos <0,0,result_val,noval,1> ; switch string follows M063
+swit_w db '/W',0 ; M063
+
+p_swit_k db 0 ; local variable
+p_swit_t db 0 ; local variable M059
+p_swit_w db 0 ; local variable M063
+
+;-------------------------------
+
+; DOS = [ high | low ]
+
+dos_parms p_parms <dos_parmsx>
+
+dos_parmsx db 1 ; min parameters
+ db 2 ; max parameters
+ dw dos_pos ;
+ dw dos_pos ;
+ db 0 ; no switches
+ db 0 ; no keywords
+
+dos_pos p_pos <2000h,0,result_val,dos_strings> ; simple string
+ p_pos <2000h,0,result_val,dos_strings> ; simple string
+
+dos_strings label byte
+ db 3 ; signals that there is a string choice
+ db 0 ; no range definition
+ db 0 ; no numeric values choice
+ db 4 ; 4 strings for choice
+ db 1 ; the 1st string tag
+ dw hi_string
+ db 2 ; the 2nd string tag
+ dw lo_string
+ db 3
+ dw umb_string
+ db 4
+ dw noumb_string
+
+hi_string db "HIGH",0
+lo_string db "LOW",0
+umb_string db "UMB",0
+noumb_string db "NOUMB",0
+
+p_dos_hi db 0 ; local variable
+ ; BUGBUG : I dont know whether PARSER uses
+ ; this variable or not
+
+
+
+;******************************************************************************
+
+ public DevEntry
+
+DevSize dw ? ; size of the device driver being loaded(paras)
+DevLoadAddr dw ? ; Mem addr where the device driver is 2 b loaded
+DevLoadEnd dw ? ; MaxAddr to which device can be loaded
+DevEntry dd ? ; Entry point to the device driver
+DevBrkAddr dd ? ; Break address of the device driver
+;
+DevUMB db 0 ; byte indicating whether to load DDs in UMBs
+DevUMBAddr dw 0 ; cuurent UMB used fro loading devices (paras)
+DevUMBSize dw 0 ; Size of the current UMB being used (paras)
+DevUMBFree dw 0 ; Start of free are in the current UMB (paras)
+;
+DevXMSAddr dd ?
+;
+DevExecAddr dw ? ; Device load address parameter to Exec call
+DevExecReloc dw ? ; Device load relocation factor
+;
+DeviceHi db 0 ; Flag indicating whther the current device
+ ; is being loaded into UMB
+DevSizeOption dw ? ; SIZE= option
+;
+Int12Lied db 0 ; did we trap int 12 ?
+OldInt12Mem dw ? ; value in 40:13h (int 12 ram)
+ThreeComName db 'PROTMAN$' ; 3Com Device name
+;
+FirstUMBLinked db 0
+DevDOSData dw ? ; segment of DOS Data
+DevCmdLine dd ? ; Current Command line
+DevSavedDelim db ? ; The delimiter which was replaced with null
+ ; to use the file name in the command line
+;
+;----------------------------------------------------------------------------
+;
+; procedure : doconf
+;
+; Config file is parsed intitially with this routine. For the
+; Subsequent passes 'multi_pass' entry is used .
+;
+;----------------------------------------------------------------------------
+;
+doconf proc near
+ push cs
+ pop ds
+ assume ds:sysinitseg
+
+ mov ax,(char_oper shl 8) ;get switch character
+ int 21h
+ mov [command_line+1],dl ; set in default command line
+
+ mov dx,offset config ;now pointing to file description
+ mov ax,open shl 8 ;open file "config.sys"
+ stc ;in case of int 24
+ int 21h ;function request
+ jnc noprob ; brif opened okay
+ mov multi_pass_id,11 ; set it to unreasonable number
+ ret
+noprob: ;get file size (note < 64k!!)
+ mov bx,ax
+ xor cx,cx
+ xor dx,dx
+ mov ax,(lseek shl 8) or 2
+ int 21h
+ mov [count],ax
+
+ xor dx,dx
+ mov ax,lseek shl 8 ;reset pointer to beginning of file
+ int 21h
+
+ mov dx,[confbot] ;use current confbot value
+ mov ax,[count]
+ mov [config_size],ax ;save the size of config.sys file.
+ call pararound
+ sub dx,ax
+ sub dx,11h ;room for header
+ mov [confbot],dx ; config starts here. new conbot value.
+ call tempcds ; finally get cds to "safe" location
+ assume ds:nothing,es:nothing
+
+ mov dx,[confbot]
+ mov ds,dx
+ mov es,dx
+ xor dx,dx
+ mov cx,[count]
+ mov ah,read
+ stc ;in case of int 24
+ int 21h ;function request
+ pushf
+
+; find the eof mark in the file. if present,then trim length.
+
+ push ax
+ push di
+ push cx
+ mov al,1ah ; eof mark
+ mov di,dx ; point ro buffer
+ jcxz puteol ; no chars
+ repnz scasb ; find end
+ jnz puteol ; none found and count exahusted
+
+; we found a 1a. back up
+
+ dec di ; backup past 1a
+
+; just for the halibut,stick in an extra eol
+
+puteol:
+ mov al,cr
+ stosb
+ mov al,lf
+ stosb
+ sub di,dx ; difference moved
+ mov count,di ; new count
+
+ pop cx
+ pop di
+ pop ax
+
+ push cs
+ pop ds
+ assume ds:sysinitseg
+
+ push ax
+ mov ah,close
+ int 21h
+ pop ax
+ popf
+ jc conferr ;if not we've got a problem
+ cmp cx,ax
+ jz getcom ;couldn't read the file
+
+conferr:
+ mov dx,offset config ;want to print config error
+ call badfil
+endconv:
+ ret
+;
+;----------------------------------------------------------------------------
+;
+; entry : multi_pass
+;
+; called to execute device=,install= commands
+;
+;----------------------------------------------------------------------------
+;
+
+multi_pass:
+ push cs
+ pop ds
+
+ cmp multi_pass_id,10
+ jae endconv ; do nothing. just return.
+
+ push confbot
+ pop es ; es -> confbot
+
+ mov si,org_count
+ mov count,si ; set count
+ xor si,si
+ mov chrptr,si ; reset chrptr,linecount
+ mov linecount,si
+ call getchr
+ jmp short conflp
+
+getcom:
+ call organize ;organize the file
+ call getchr
+
+conflp: jc endconv
+
+;*** call reset_dos_version ; still need to reset version even ibmdos handles this through
+;*** ; function 4bh call,since ibmdos does not know when load/overlay call finishes.
+
+ inc linecount ; increase linecount.
+ mov multdeviceflag,0 ; reset multdeviceflag.
+ mov setdevmarkflag,0 ; reset setdevmarkflag.
+ cmp al,lf ; linefeed?
+ je blank_line ; then ignore this line.
+
+ mov ah,al
+ call getchr
+ jnc tryi
+
+ cmp multi_pass_id,2
+ jae endconv ;do not show badop again for multi_pass.
+ jmp badop
+
+coff: push cs
+ pop ds
+ call newline
+ jmp conflp
+
+blank_line:
+ call getchr
+ jmp conflp
+
+coff_p:
+ push cs
+ pop ds
+
+
+;to handle install= commands,we are going to use multi-pass.
+;the first pass handles the other commands and only set install_flag when
+;it finds any install command. the second pass will only handle the
+;install= command.
+
+;------------------------------------------------------------------------------
+;install command
+;------------------------------------------------------------------------------
+tryi:
+ cmp multi_pass_id,0 ; the initial pass for DOS=HI
+ je multi_try_doshi
+
+ cmp multi_pass_id,2 ; the second pass was for ifs=
+ je coff ; now it is NOPs
+ ; This pass can be made use of if
+ ; we want do some config.sys process
+ ; after device drivers are loaded
+ ; and before install= commands
+ ; are processed
+
+ cmp multi_pass_id,3 ; the third pass for install= ?
+ je multi_try_i
+ cmp ah, 'H'
+ je coff
+ cmp ah, 'E'
+ je coff
+ cmp ah,'I' ; install= command?
+ jne tryb ; the first pass is for normal operation.
+ or install_flag,have_install_cmd ; set the flag
+ jmp coff ; and handles the next command
+
+multi_try_i:
+ cmp ah,'I' ; install= command?
+ jne multi_pass_filter ; no. ignore this.
+ call do_install_exec ;install it.
+ jmp coff ;to handle next install= command.
+
+multi_pass_filter:
+ cmp ah,'Y' ; comment?
+ je multi_pass_adjust
+ cmp ah,'Z' ; bad command?
+ je multi_pass_adjust
+ cmp ah,'0' ; rem?
+ jne coff ; ignore the rest of the commands.
+
+multi_pass_adjust: ; these commands need to
+ dec chrptr ; adjust chrptr,count
+ inc count ; for newline proc.
+
+multi_pass_coff:
+ jmp coff ; to handle next install= commands.
+
+
+
+;----------------------------------------------------------------------------
+; DOS=HIGH/LOW command
+;
+; EchoConfig command turns on con echo for config processing
+; NTVDM 14-Aug-1992 Jonle
+;----------------------------------------------------------------------------
+;
+multi_try_doshi:
+ cmp ah, 'H'
+ je it_is_h
+ cmp ah, 'E'
+ jne multi_pass_filter
+
+ mov cs:bEchoConfig, ah ; init console
+ CMDSVC SVC_CMDINITCONSOLE
+ jmp coff
+
+
+it_is_h: ; M003 - removed initing DevUMB
+ ; & runhigh
+ mov di,offset dos_parms
+ xor cx,cx
+ mov dx,cx
+h_do_parse:
+ call sysinit_parse
+ jnc h_parse_ok ; parse error
+h_badparm:
+ call badparm_p ; show message and end the serach loop.
+ jmp short h_end
+
+h_parse_ok:
+ cmp ax,$p_rc_eol ; end of line?
+ jz h_end ; then end the $endloop
+ call ProcDOS
+ jmp short h_do_parse
+h_end:
+ jmp coff
+
+
+;------------------------------------------------------------------------------
+; buffer command
+;------------------------------------------------------------------------------
+;*******************************************************************************
+; *
+; function: parse the parameters of buffers= command. *
+; *
+; input : *
+; es:si -> parameters in command line. *
+; output: *
+; buffers set *
+; buffer_slash_x flag set if /x option chosen. *
+; h_buffers set if secondary buffer cache specified. *
+; *
+; subroutines to be called: *
+; sysinit_parse *
+; logic: *
+; { *
+; set di points to buf_parms; /*parse control definition*/ *
+; set dx,cx to 0; *
+; reset buffer_slash_x; *
+; while (end of command line) *
+; { sysinit_parse; *
+; if (no error) then *
+; if (result_val.$p_synonym_ptr == slash_e) then /*not a switch *
+; buffer_slash_x = 1 *
+; else if (cx == 1) then /* first positional */ *
+; buffers = result_val.$p_picked_val; *
+; else h_buffers = result_val.$p_picked_val; *
+; else {show error message;error exit} *
+; }; *
+; if (buffer_slash_x is off & buffers > 99) then show_error; *
+; }; *
+; *
+;*******************************************************************************
+
+tryb:
+ cmp ah,'B'
+ jnz tryc
+
+ ; NTVDM - buffers command is ignored
+ ; 15-Aug-1992 Jonle
+ jmp coff
+
+if 0
+ mov p_buffer_slash_x,0
+ mov di,offset buf_parms
+ xor cx,cx
+ mov dx,cx
+
+do7:
+ call sysinit_parse
+ jnc if7 ; parse error,
+ call badparm_p ; and show messages and end the search loop.
+ jmp short sr7
+
+if7:
+ cmp ax,$p_rc_eol ; end of line?
+ jz en7 ; then jmp to $endloop for semantic check
+ cmp result_val.$p_synonym_ptr,offset switch_x
+ jnz if11
+
+; mov p_buffer_slash_x,1 ; set the flag M016
+ jmp short en11
+
+if11:
+ mov ax,word ptr result_val.$p_picked_val
+ cmp cx,1
+ jnz if13
+
+ mov p_buffers,ax
+ jmp short en11
+
+if13:
+ mov p_h_buffers,ax
+en11:
+ jmp do7
+
+en7:
+ cmp p_buffers,99
+ jbe if18
+; cmp p_buffer_slash_x,0 ; M016
+; jnz if18
+
+ call badparm_p
+ mov p_h_buffers,0
+ jmp short sr7
+
+if18:
+ mov ax,p_buffers ; we don't have any problem.
+ mov buffers,ax ; now,let's set it really.
+
+ mov ax,p_h_buffers
+ mov h_buffers,ax
+
+; mov al,p_buffer_slash_x ; M016
+; mov buffer_slash_x,al
+
+ mov ax,linecount
+ mov buffer_linenum,ax ; save the line number for the future use.
+
+sr7:
+ jmp coff
+endif
+
+
+;------------------------------------------------------------------------------
+; break command
+;------------------------------------------------------------------------------
+;****************************************************************************
+; *
+; function: parse the parameters of break = command. *
+; *
+; input : *
+; es:si -> parameters in command line. *
+; output: *
+; turn the control-c check on or off. *
+; *
+; subroutines to be called: *
+; sysinit_parse *
+; logic: *
+; { *
+; set di to brk_parms; *
+; set dx,cx to 0; *
+; while (end of command line) *
+; { sysinit_parse; *
+; if (no error) then *
+; if (result_val.$p_item_tag == 1) then /*on */ *
+; set p_ctrl_break,on; *
+; else /*off */ *
+; set p_ctrl_break,off; *
+; else {show message;error_exit}; *
+; }; *
+; if (no error) then *
+; dos function call to set ctrl_break check according to *
+; }; *
+; *
+;****************************************************************************
+
+tryc:
+ cmp ah,'C'
+ jnz trym
+ mov di,offset brk_parms
+ xor cx,cx
+ mov dx,cx
+do22:
+ call sysinit_parse
+ jnc if22 ; parse error
+ call badparm_p ; show message and end the serach loop.
+ jmp short sr22
+
+if22:
+ cmp ax,$p_rc_eol ; end of line?
+ jz en22 ; then end the $endloop
+ cmp result_val.$p_item_tag,1
+ jnz if26
+
+ mov p_ctrl_break,1 ; turn it on
+ jmp short en26
+
+if26:
+ mov p_ctrl_break,0 ; turn it off
+en26:
+ jmp short do22 ; we actually set the ctrl break
+
+en22:
+ mov ah,set_ctrl_c_trapping ; if we don't have any parse error.
+ mov al,1
+ mov dl,p_ctrl_break
+ int 21h
+sr22:
+ jmp coff
+
+;------------------------------------------------------------------------------
+; multitrack command
+;------------------------------------------------------------------------------
+;******************************************************************************
+; *
+; function: parse the parameters of multitrack= command. *
+; *
+; input : *
+; es:si -> parameters in command line. *
+; output: *
+; turn multrk_flag on or off. *
+; *
+; subroutines to be called: *
+; sysinit_parse *
+; logic: *
+; { *
+; set di to brk_parms; *
+; set dx,cx to 0; *
+; while (end of command line) *
+; { sysinit_parse; *
+; if (no error) then *
+; if (result_val.$p_item_tag == 1) then /*on */ *
+; set p_mtrk,on; *
+; else /*off */ *
+; set p_mtrk,off; *
+; else {show message;error_exit}; *
+; }; *
+; if (no error) then *
+; dos function call to set multrk_flag according to p_mtrk. *
+; *
+; }; *
+; *
+;******************************************************************************
+
+trym:
+ cmp ah,'M'
+ jnz tryu
+
+ mov di,offset mtrk_parms
+ xor cx,cx
+ mov dx,cx
+do31:
+ call sysinit_parse
+ jnc if31 ; parse error
+ call badparm_p ; show message and end the serach loop.
+ jmp short sr31
+if31:
+ cmp ax,$p_rc_eol ; end of line?
+ jz en31 ; then end the $endloop
+
+ cmp result_val.$p_item_tag,1
+ jnz if35
+
+ mov p_mtrk,1 ; turn it on temporarily.
+ jmp short en35
+
+if35:
+ mov p_mtrk,0 ; turn it off temporarily.
+en35:
+ jmp short do31 ; we actually set the multrk_flag here
+
+en31:
+ push ds
+ mov ax,Bios_Data
+ mov ds,ax
+ assume ds:Bios_Data
+
+ cmp p_mtrk,0
+ jnz if39
+
+ mov multrk_flag,multrk_off2 ; 0001h
+ jmp short en39
+
+if39:
+ mov multrk_flag,multrk_on ; 8000h
+en39:
+ pop ds
+ assume ds:sysinitseg
+sr31:
+ jmp coff
+
+
+;
+;-----------------------------------------------------------------------------
+; devicehigh command
+;-----------------------------------------------------------------------------
+;
+ assume ds:nothing
+tryu:
+ cmp ah, 'U'
+ jne tryd
+ mov badparm_off, si ; stash it there in case of an error
+ mov badparm_seg, es
+ call ParseSize ; process the size= option
+ jnc @f
+ call badparm_p
+ jmp coff
+@@:
+ push si
+ push es
+@@:
+ mov al, es:[si]
+ cmp al, cr
+ je @f
+ cmp al, lf
+ je @f
+ call delim
+ jz @f
+ inc si
+ jmp @b
+@@:
+ mov DevSavedDelim, al ; Save the delimiter before replacing
+ ; it with null
+ mov byte ptr es:[si], 0
+ pop es
+ pop si
+
+ mov DeviceHi, 0
+ cmp DevUMB, 0 ; do we support UMBs
+ je LoadDevice ; no, we don't
+ mov DeviceHi, 1
+ jmp short LoadDevice
+;
+;------------------------------------------------------------------------------
+; device command
+;------------------------------------------------------------------------------
+
+ assume ds:nothing
+tryd:
+ cmp ah,'D'
+ jz gotd
+ jmp tryq
+gotd:
+ mov DeviceHi, 0 ; not to be loaded in UMB ;M007
+ mov DevSizeOption, 0
+ mov DevSavedDelim, ' ' ; In case of DEVICE= the null has to
+ ; be replaced with a ' '
+
+LoadDevice:
+ mov bx,cs ;device= or devicehigh= command.
+ mov ds,bx
+
+ mov word ptr [bpb_addr],si ; pass the command line to the dvice
+ mov word ptr [bpb_addr+2],es
+
+ mov word ptr DevCmdLine, si ; save it for ourself
+ mov word ptr DevCmdLine+2, es
+
+ call round
+
+ call SizeDevice
+ jc BadFile
+
+ call InitDevLoad
+
+ mov ax, DevLoadAddr
+ add ax, DevSize
+ jc NoMem
+ cmp DevLoadEnd, ax
+ jae LoadDev
+
+NoMem:
+ jmp mem_err
+
+BadFile:
+ cmp byte ptr es:[si], cr
+ jne @f
+ jmp badop
+@@:
+ call badload
+ jmp coff
+
+LoadDev:
+ push es
+ pop ds
+ assume ds:nothing
+ mov dx,si ;ds:dx points to file name
+
+ if noexec
+ les bx,dword ptr cs:[memlo]
+ call ldfil ;load in the device driver
+
+ else
+
+ call ExecDev ; load device driver using exec call
+
+ endif
+
+badldreset:
+ push ds
+ pop es ;es:si back to config.sys
+ push cs
+ pop ds ;ds back to sysinit
+ jc BadFile
+goodld:
+ push es
+ push si ; ???
+
+ call RemoveNull
+
+ push es
+ push si
+
+ push cs
+ pop es
+
+
+;NTVDM: block device drivers are not supported.
+; Putup user warning popup for unsupported device driver
+; 29-Sep-1992 Jonle
+;
+ push ds
+ push si
+ lds si, DevEntry ; peek the header attribute
+ test word ptr ds:[si.sdevatt],devtyp ; IS block device driver?
+ pop si
+ pop ds
+ jnz got_device_com_cont ; no!
+
+ pop si ;clear the stack
+ pop es
+
+ mov ax, NOSUPPORT_DRIVER
+ BOP BOP_NOSUPPORT
+ jmp short erase_dev_do
+
+got_device_com_cont:
+
+ call LieInt12Mem
+ call UpdatePDB ; update the PSP:2 value M020
+
+ cmp cs:multdeviceflag, 0 ; Pass limit only for the 1st device
+ ; driver in the file ; M027
+ jne skip_pass_limit ; ; M027
+
+ mov word ptr break_addr, 0 ; pass the limit to the DD
+ mov bx, DevLoadEnd
+ mov word ptr break_addr+2, bx
+skip_pass_limit: ; M027
+ mov bx,sdevstrat
+ call calldev ; calldev (sdevstrat);
+ mov bx,sdevint
+ call calldev ; calldev (sdevint);
+
+ call TrueInt12Mem
+
+ mov ax, word ptr break_addr ; move break addr from the req packet
+ mov word ptr DevBrkAddr, ax
+ mov ax, word ptr break_addr+2
+ mov word ptr DevBrkAddr+2, ax
+
+ assume ds:nothing
+
+ cmp DevUMB, 0
+ jz @f
+ call AllocUMB
+@@:
+
+;
+;------ If we are waiting to be moved into hma lets try it now !!!
+;
+ cmp runhigh, 0ffh
+ jne @f
+
+ call TryToMovDOSHi ; move DOS into HMA if reqd
+@@:
+
+ pop si
+ pop ds
+ mov byte ptr [si],0 ; *p = 0;
+
+ push cs
+ pop ds
+
+ jmp short was_device_com
+
+
+erase_dev_do: ; modified to show message "error in config.sys..."
+ pop si
+ pop es
+
+ push cs
+ pop ds
+
+; test [setdevmarkflag],setbrkdone ;if already set_break is done,
+; jnz skip1_resetmemhi ; then do not
+; dec [memhi] ;adjust memhi by a paragrah of devmark.
+
+skip1_resetmemhi:
+ cmp configmsgflag,0
+ je no_error_line_msg
+
+ call error_line ; no "error in config.sys" msg for device driver. dcr d493
+ mov configmsgflag,0 ;set the default value again.
+
+no_error_line_msg:
+ jmp coff
+;
+;----------------------------------------------------------------------------
+;
+was_device_com:
+ mov ax,word ptr [DevBrkAddr+2]
+ cmp ax,DevLoadEnd
+ jbe breakok
+
+ pop si
+ pop es
+ jmp BadFile
+
+breakok:
+ lds si,DevEntry ;ds:si points to header
+ les di,cs:[dosinfo] ;es:di point to dos info
+ mov ax,ds:[si.sdevatt] ;ax Dev attributes
+;
+;------ lets deal with character devices,
+; NTVDM: removed check for block drivers, jonle
+;
+ischardev:
+ or cs:[setdevmarkflag],for_devmark
+ call DevSetBreak ; go ahead and alloc mem for device
+ jc erase_dev_do ;device driver's init routine failed.
+
+ test ax,iscin ;is it a console in?
+ jz tryclk
+
+ mov word ptr es:[di.sysi_con],si
+ mov word ptr es:[di.sysi_con+2],ds
+
+tryclk: test ax,isclock ;is it a clock device?
+ jz linkit
+
+ mov word ptr es:[di+sysi_clock],si
+ mov word ptr es:[di+sysi_clock+2],ds
+
+linkit:
+
+ mov cx,word ptr es:[di.sysi_dev] ;dx:cx = head of list
+ mov dx,word ptr es:[di.sysi_dev+2]
+
+ mov word ptr es:[di.sysi_dev],si ;set head of list in dos
+ mov word ptr es:[di.sysi_dev+2],ds
+ mov ax,ds:[si] ;get pointer to next device
+ mov word ptr cs:[DevEntry],ax ;and save it
+
+ mov word ptr ds:[si],cx ;link in the driver
+ mov word ptr ds:[si+2],dx
+
+enddev:
+ pop si
+ pop es
+ inc ax ;ax = ffff (no more devs if yes)?
+ jz coffj3
+
+ inc cs:multdeviceflag ; possibly multiple device driver.
+ call DevBreak ; M009
+ jmp goodld ; otherwise pretend we loaded it in
+
+coffj3: mov cs:multdeviceflag,0 ; reset the flag
+ call DevBreak
+ jmp coff
+
+bad_bpb_size_sector:
+ pop si
+ pop es
+ mov dx,offset badsiz_pre
+ mov bx,offset crlfm
+ call prnerr
+
+; test [setdevmarkflag],setbrkdone ;if already set_break is done,
+; jnz skip2_resetmemhi ; then do not
+; dec [memhi] ;adjust memhi by a paragrah of devmark.
+
+skip2_resetmemhi:
+ jmp coff
+
+
+;------------------------------------------------------------------------------
+; country command
+; the syntax is:
+; country=country id {,codepage {,path}}
+; country=country id {,,path} :default codepage id in dos
+;------------------------------------------------------------------------------
+
+tryq:
+ cmp ah,'Q'
+ jz tryq_cont
+ jmp tryf
+tryq_cont:
+
+ mov cntry_drv,0 ; reset the drive,path to default value.
+ mov p_code_page,0
+ mov di,offset cntry_parms
+ xor cx,cx
+ mov dx,cx
+do52:
+ call sysinit_parse
+ jnc if52 ; parse error,check error code and
+
+ call cntry_error ; show message and end the search loop.
+ mov p_cntry_code,-1 ; signals that parse error.
+ jmp short sr52
+
+if52:
+ cmp ax,$p_rc_eol ; end of line?
+ jz sr52 ; then end the search loop
+
+ cmp result_val.$p_type,$p_number ; numeric?
+ jnz if56
+
+ mov ax,word ptr result_val.$p_picked_val
+ cmp cx,1
+ jnz if57
+
+ mov p_cntry_code,ax
+ jmp short en57
+
+if57:
+ mov p_code_page,ax
+en57:
+ jmp short en56 ; path entered
+
+if56:
+ push ds
+ push es
+ push si
+ push di
+
+ push cs
+ pop es
+
+ lds si,rv_dword ; move the path to known place.
+ mov di,offset cntry_drv
+ call move_asciiz
+
+ pop di
+ pop si
+ pop es
+ pop ds
+
+en56:
+ jmp do52
+
+sr52:
+ cmp p_cntry_code,-1 ; had a parse error?
+ jne tryq_open
+ jmp coff
+
+tryqbad: ;"invalid country code or code page"
+ stc
+ mov dx,offset badcountry
+ jmp tryqchkerr
+
+tryq_open:
+ cmp cntry_drv,0
+ je tryq_def
+ mov dx,offset cntry_drv
+ jmp short tryq_openit
+
+tryq_def:
+ mov dx,offset cntry_root
+tryq_openit:
+ mov ax,3d00h ;open a file
+ stc
+ int 21h
+ jc tryqfilebad ;open failure
+
+ mov cs:cntryfilehandle,ax ;save file handle
+ mov bx,ax
+ mov ax,cs:p_cntry_code
+ mov dx,cs:p_code_page ; now,ax=country id,bx=filehandle
+ mov cx,cs:[memhi]
+ add cx,384 ; need 6k buffer to handle country.sys
+ ; M023
+ cmp cx,cs:[alloclim]
+ ja tryqmemory ;cannot allocate the buffer for country.sys
+
+ mov si,offset cntry_drv ;ds:si -> cntry_drv
+ cmp byte ptr [si],0 ;default path?
+ jne tryq_set_for_dos
+
+ inc si
+ inc si ;ds:si -> cntry_root
+
+tryq_set_for_dos:
+ les di,cs:sysi_country ;es:di -> country info tab in dos
+ push di ;save di
+ add di,ccpath_countrysys
+ call move_asciiz ;set the path to country.sys in dos.
+ pop di ;es:di -> country info tab again.
+
+ mov cx,cs:[memhi]
+ mov ds,cx
+ xor si,si ;ds:si -> 2k buffer to be used.
+ call setdoscountryinfo ;now do the job!!!
+ jnc tryqchkerr ;read error or could not find country,code page combination
+
+ cmp cx,-1 ;could not find matching country_id,code page?
+ je tryqbad ;then "invalid country code or code page"
+
+tryqfilebad:
+ push cs
+ pop es
+ cmp cs:cntry_drv,0 ;is the default file used?
+ je tryqdefbad
+
+ mov si,offset cntry_drv
+ jmp short tryqbadload
+
+tryqdefbad: ;default file has been used.
+ mov si,offset cntry_root ;es:si -> \country.sys in sysinit_seg
+tryqbadload:
+ call badload ;ds will be restored to sysinit_seg
+ mov cx,cs:[confbot]
+ mov es,cx ;restore es -> confbot.
+ jmp short coffj4
+
+tryqmemory:
+ mov dx,offset insufmemory
+tryqchkerr:
+ mov cx,cs:[confbot]
+ mov es,cx ;restore es -> confbot seg
+ push cs
+ pop ds ;retore ds to sysinit_seg
+ jnc coffj4 ;if no error,then exit
+
+ call print ;else show error message
+ call error_line
+
+coffj4:
+ mov bx,cntryfilehandle
+ mov ah,3eh
+ int 21h ;close a file. don't care even if it fails.
+ jmp coff
+
+cntry_error proc near
+
+;function: show "invalid country code or code page" messages,or
+; "error in country command" depending on the error code
+; in ax returned by sysparse;
+;in: ax - error code
+; ds - sysinitseg
+; es - confbot
+;out: show message. dx destroyed.
+
+ cmp ax,$p_out_of_range
+ jnz if64
+ mov dx,offset badcountry ;"invalid country code or code page"
+ jmp short en64
+
+if64:
+ mov dx,offset badcountrycom ;"error in contry command"
+en64:
+ call print
+ call error_line
+ ret
+cntry_error endp
+
+;------------------------------------------------------------------------------
+; files command
+;------------------------------------------------------------------------------
+;*******************************************************************************
+; function: parse the parameters of files= command. *
+; *
+; input : *
+; es:si -> parameters in command line. *
+; output: *
+; variable files set. *
+; *
+; subroutines to be called: *
+; sysinit_parse *
+; logic: *
+; { *
+; set di points to files_parms; *
+; set dx,cx to 0; *
+; while (end of command line) *
+; { sysinit_parse; *
+; if (no error) then *
+; files = result_val.$p_picked_val *
+; else *
+; error exit; *
+; }; *
+; }; *
+; *
+;*******************************************************************************
+tryf:
+ cmp ah,'F'
+ jnz tryl
+
+ mov di,offset files_parms
+ xor cx,cx
+ mov dx,cx
+
+do67:
+ call sysinit_parse
+ jnc if67 ; parse error
+ call badparm_p ; and show messages and end the search loop.
+ jmp short sr67
+
+if67:
+ cmp ax,$p_rc_eol ; end of line?
+ jz en67 ; then end the $endloop
+ mov al,byte ptr result_val.$p_picked_val
+ mov p_files,al ; save it temporarily
+ jmp short do67
+
+en67:
+ mov al,p_files
+ SVC SVC_DEMWOWFILES ; For WOW VDM Set the file= to max.
+ mov files,al ; no error. really set the value now.
+
+sr67:
+ jmp coff
+
+;------------------------------------------------------------------------------
+; lastdrive command
+;------------------------------------------------------------------------------
+;*******************************************************************************
+; function: parse the parameters of lastdrive= command. *
+; *
+; input : *
+; es:si -> parameters in command line. *
+; output: *
+; set the variable num_cds. *
+; *
+; subroutines to be called: *
+; sysinit_parse *
+; logic: *
+; { *
+; set di points to ldrv_parms; *
+; set dx,cx to 0; *
+; while (end of command line) *
+; { sysinit_parse; *
+; if (no error) then *
+; set num_cds to the returned value; *
+; else /*error exit*/ *
+; error exit; *
+; }; *
+; }; *
+; *
+;*******************************************************************************
+
+tryl:
+ cmp ah,'L'
+ jnz tryp
+ jmp coff
+
+;NTVDM Ignore the lastdrive command. Dos will figure this from the host OS.
+; 17-Aug-1992 Jonle
+if 0
+
+ mov di,offset ldrv_parms
+ xor cx,cx
+ mov dx,cx
+
+do73:
+ call sysinit_parse
+ jnc if73 ; parse error
+ call badparm_p ; and show messages and end the search loop.
+ jmp short sr73
+
+if73:
+ cmp ax,$p_rc_eol ; end of line?
+ jz en73 ; then end the $endloop
+ mov al,rv_byte ; pick up the drive number
+ mov p_ldrv,al ; save it temporarily
+ jmp do73
+
+en73:
+ mov al,p_ldrv
+ mov num_cds,al ; no error. really set the value now.
+sr73:
+ jmp coff
+endif
+
+
+;--------------------------------------------------------------------------
+; setting drive parameters
+;--------------------------------------------------------------------------
+
+tryp:
+ cmp ah,'P'
+ jnz tryk
+ jmp coff
+
+; sudeepb 04-Mar-1991 : Ignoring DRIVEPARM command
+; call parseline
+; jc trypbad
+;
+; call setparms
+; call diddleback
+; jc trypbad
+; jmp coff
+;trypbad:jmp badop
+
+;--------------------------------------------------------------------------
+; setting internal stack parameters
+; stacks=m,n where
+; m is the number of stacks (range 8 to 64,default 9)
+; n is the stack size (range 32 to 512 bytes,default 128)
+; j.k. 5/5/86: stacks=0,0 implies no stack installation.
+; any combinations that are not within the specified limits will
+; result in "unrecognized command" error.
+;--------------------------------------------------------------------------
+
+;****************************************************************************
+; *
+; function: parse the parameters of stacks= command. *
+; the minimum value for "number of stacks" and "stack size" is *
+; 8 and 32 each. in the definition of sysparse value list,they *
+; are set to 0. this is for accepting the exceptional case of *
+; stacks=0,0 case (,which means do not install the stack.) *
+; so,after sysparse is done,we have to check if the entered *
+; values (stack_count,stack_size) are within the actual range, *
+; (or if "0,0" pair has been entered.) *
+; input : *
+; es:si -> parameters in command line. *
+; output: *
+; set the variables stack_count,stack_size. *
+; *
+; subroutines to be called: *
+; sysinit_parse *
+; logic: *
+; { *
+; set di points to stks_parms; *
+; set dx,cx to 0; *
+; while (end of command line) *
+; { sysinit_parse; *
+; if (no error) then *
+; { if (cx == 1) then /* first positional = stack count */ *
+; p_stack_count = result_val.$p_picked_val; *
+; if (cx == 2) then /* second positional = stack size */ *
+; p_stack_size = result_val.$p_picked_val; *
+; } *
+; else /*error exit*/ *
+; error exit; *
+; }; *
+; here check p_stack_count,p_stack_size if it meets the condition; *
+; if o.k.,then set stack_count,stack_size; *
+; else error_exit; *
+; }; *
+;****************************************************************************
+
+tryk:
+ cmp ah,'K'
+ je do_tryk
+ jmp trys
+
+ if stacksw
+
+do_tryk:
+ mov di,offset stks_parms
+ xor cx,cx
+ mov dx,cx
+
+do79:
+ call sysinit_parse
+ jnc if79 ; parse error
+
+ mov dx,offset badstack ; "invalid stack parameter"
+ call print ; and show messages and end the search loop.
+ call error_line
+ jmp sr79
+
+if79:
+ cmp ax,$p_rc_eol ; end of line?
+ jz en79 ; then end the $endloop
+
+ mov ax,word ptr result_val.$p_picked_val
+ cmp cx,1
+ jnz if83
+
+ mov p_stack_count,ax
+ jmp short en83
+
+if83:
+ mov p_stack_size,ax
+en83:
+ jmp do79
+
+en79:
+ cmp p_stack_count,0
+ jz if87
+
+ cmp p_stack_count,mincount
+ jb ll88
+ cmp p_stack_size,minsize
+ jnb if88
+
+ll88:
+ mov p_stack_count,-1 ; invalid
+if88:
+ jmp short en87
+
+if87:
+ cmp p_stack_size,0
+ jz en87
+ mov p_stack_count,-1 ; invalid
+en87:
+ cmp p_stack_count,-1 ; invalid?
+ jnz if94
+
+ mov stack_count,defaultcount ;reset to default value.
+ mov stack_size,defaultsize
+ mov word ptr stack_addr,0
+
+ mov dx,offset badstack
+ call print
+ call error_line
+ jmp short sr79
+
+if94:
+ mov ax,p_stack_count
+ mov stack_count,ax
+ mov ax,p_stack_size
+ mov stack_size,ax
+ mov word ptr stack_addr,-1 ; stacks= been accepted.
+sr79:
+ jmp coff
+
+ endif
+
+;------------------------------------------------------------------------
+; shell command
+;------------------------------------------------------------------------
+
+trys:
+ cmp ah,'S'
+ jnz tryx
+
+ mov [command_line+1],0
+ mov di,offset commnd + 1
+ mov [di-1],al
+
+storeshell:
+ call getchr
+ or al,al
+ jz getshparms
+
+ cmp al," "
+ jb endsh
+
+ mov [di],al
+ inc di
+ jmp storeshell
+
+endsh:
+ mov byte ptr [di],0
+; push di
+; mov di,offset commnd
+; SVC SVC_SETSHELLNAME
+; pop di
+
+ call getchr
+ cmp al,lf
+ jnz conv
+
+ call getchr
+conv: jmp conflp
+
+getshparms:
+ mov byte ptr [di],0
+ mov di,offset command_line+1
+
+parmloop:
+ call getchr
+ cmp al," "
+ jb endsh
+ mov [di],al
+ inc di
+ jmp parmloop
+
+;------------------------------------------------------------------------
+; fcbs command
+;------------------------------------------------------------------------
+
+;************************************************************************
+; function: parse the parameters of fcbs= command. *
+; *
+; input : *
+; es:si -> parameters in command line. *
+; output: *
+; set the variables fcbs,keep. *
+; *
+; subroutines to be called: *
+; sysinit_parse *
+; logic: *
+; { *
+; set di points to fcbs_parms; *
+; set dx,cx to 0; *
+; while (end of command line) *
+; { sysparse; *
+; if (no error) then *
+; { if (cx == 1) then /* first positional = fcbs */ *
+; fcbs = result_val.$p_picked_val; *
+; if (cx == 2) then /* second positional = keep */ *
+; keep = result_val.$p_picked_val; *
+; } *
+; else /*error exit*/ *
+; error exit; *
+; }; *
+; }; *
+;************************************************************************
+
+tryx:
+ cmp ah,'X'
+ jnz tryy
+
+ mov di,offset fcbs_parms
+ xor cx,cx
+ mov dx,cx
+
+do98:
+ call sysinit_parse
+ jnc if98 ; parse error
+ call badparm_p ; and show messages and end the search loop.
+ jmp short sr98
+
+if98:
+ cmp ax,$p_rc_eol ; end of line?
+ jz en98 ; then end the $endloop
+
+ mov al,byte ptr result_val.$p_picked_val
+ cmp cx,1 ; the first positional?
+ jnz if102
+ mov p_fcbs,al
+ jmp short en102
+
+if102:
+ mov p_keep,al
+en102:
+ jmp do98
+
+en98:
+ mov al,p_fcbs ; M017
+ mov fcbs,al ; M017
+ mov keep,0 ; M017
+sr98:
+ jmp coff
+
+;-------------------------------------------------------------------------
+; comment= do nothing. just decrese chrptr,and increase count for correct
+; line number
+;-------------------------------------------------------------------------
+
+tryy:
+ cmp ah,'Y'
+ jne try0
+
+donothing:
+ dec chrptr
+ inc count
+ jmp coff
+
+;------------------------------------------------------------------------
+; rem command
+;------------------------------------------------------------------------
+
+try0: ;do nothing with this line.
+ cmp ah,'0'
+ je donothing
+
+;-----------------------------------------------------------------------
+; switches command
+;-----------------------------------------------------------------------
+;****************************************************************************
+; *
+; function: parse the option switches specified. *
+; note - this command is intended for the future use also. when we need to *
+; to set system data flag,use this command. *
+; *
+; input : *
+; es:si -> parameters in command line. *
+; output: *
+; p_swit_k set if /k option chosen. *
+; *
+; subroutines to be called: *
+; sysinit_parse *
+; logic: *
+; { *
+; set di points to swit_parms; /*parse control definition*/ *
+; set dx,cx to 0; *
+; while (end of command line) *
+; { sysinit_parse; *
+; if (no error) then *
+; if (result_val.$p_synonym_ptr == swit_k) then *
+; p_swit_k = 1 *
+; endif *
+; else {show error message;error exit} *
+; }; *
+; }; *
+; *
+;****************************************************************************
+
+ cmp ah,'1' ;switches= command entered?
+ je do_try1
+ jmp tryt
+do_try1:
+ mov di,offset swit_parms
+ xor cx,cx
+ mov dx,cx
+
+do110:
+ call sysinit_parse
+ jnc if110 ; parse error
+ call badparm_p ; and show messages and end the search loop.
+ jmp short sr110
+
+if110:
+ cmp ax,$p_rc_eol ; end of line?
+ jz en110 ; then jmp to $endloop for semantic check
+
+ cmp result_val.$p_synonym_ptr,offset swit_k
+ jnz if115 ; ;M059
+ mov p_swit_k,1 ; set the flag
+ jmp do110
+if115: ;M059
+ cmp result_val.$p_synonym_ptr, offset swit_t ;M059
+ jne if116 ;M059 M063
+ mov p_swit_t, 1 ;M059
+ jmp do110 ;M059
+if116:
+ cmp result_val.$p_synonym_ptr, offset swit_w ;M063
+ jne do110 ;M063
+ mov p_swit_w, 1 ;M063
+ jmp do110 ;M063
+en110:
+ cmp p_swit_k,1 ;if /k entered,
+
+ push ds
+ mov ax,Bios_Data
+ mov ds,ax
+ assume ds:Bios_Data
+ jnz if117
+ mov keyrd_func,0 ;use the conventional keyboard functions
+ mov keysts_func,1
+if117:
+; mov al, p_swit_t ;M059
+; mov t_switch, al ;M059
+
+ cmp p_swit_w, 0 ;M063
+ je skip_dos_flag ;M063
+ push es
+ push bx
+ mov ah, GET_IN_VARS ;M063
+ int 21h ;M063
+ or byte ptr es:[DOS_FLAG_OFFSET], SUPPRESS_WINA20 ;M063
+ pop bx
+ pop es
+skip_dos_flag: ;M063
+ pop ds
+ assume ds:sysinitseg
+
+sr110:
+ jmp coff
+
+;------------------------------------------------------------------------
+; NTCMDPROMPT command. This command forces SCS functionality to use
+; cmd.exe prompt rather than command.com's prompt on shelling out
+; and on finding a TSR.
+;------------------------------------------------------------------------
+tryt:
+ cmp ah,'T'
+ je tryt_5
+ jmp short tryo
+
+tryt_5:
+ push si
+ push bp
+ xor ax,ax
+ mov bp,ax
+ mov si,ax
+ mov al,4
+ mov ah,setdpb
+ int 21h
+ pop bp
+ pop si
+ jmp coff
+
+;------------------------------------------------------------------------
+; DOSONLY command. This command forces only DOS binaries to run from
+; command.com prompt. non_dos binaries will putup the stub message
+; of unable to run it under DOS.
+;------------------------------------------------------------------------
+tryo:
+ cmp ah,'O'
+ je tryo_5
+ jmp short tryz
+
+tryo_5:
+ push si
+ push bp
+ xor ax,ax
+ mov bp,ax
+ mov si,ax
+ mov al,6
+ mov ah,setdpb
+ int 21h
+ pop bp
+ pop si
+ jmp coff
+
+;------------------------------------------------------------------------
+; bogus command
+;------------------------------------------------------------------------
+
+tryz:
+ cmp ah,0ffh
+ je tryff
+
+ dec chrptr
+ inc count
+ jmp short badop
+
+;------------------------------------------------------------------------
+; null command
+;------------------------------------------------------------------------
+
+tryff: ;skip this command.
+ jmp donothing
+
+doconf endp
+
+;------------------------------------------------------------------------------
+
+sysinit_parse proc
+;set up registers for sysparse
+;in) es:si -> command line in confbot
+; di -> offset of the parse control defintion.
+;
+;out) calls sysparse.
+; carry will set if parse error.
+; *** the caller should check the eol condition by looking at ax
+; *** after each call.
+; *** if no parameters are found,then ax will contain a error code.
+; *** if the caller needs to look at the synomym@ of the result,
+; *** the caller should use cs:@ instead of es:@.
+; cx register should be set to 0 at the first time the caller calls this
+; procedure.
+; ax - exit code
+; bl - terminated delimeter code
+; cx - new positional ordinal
+; si - set to pase scanned operand
+; dx - selected result buffer
+
+ push es ;save es,ds
+ push ds
+
+ push es
+ pop ds ;now ds:si -> command line
+
+ push cs
+ pop es ;now es:di -> control definition
+
+ mov cs:badparm_seg,ds ;save the pointer to the parm
+ mov cs:badparm_off,si ; we are about to parse for badparm msg.
+ mov dx,0
+ call sysparse
+ cmp ax,$p_no_error ;no error
+
+;**cas note: when zero true after cmp, carry clear
+
+ jz ll4
+ cmp ax,$p_rc_eol ;or the end of line?
+ jnz if4
+
+ll4:
+ clc
+ jmp short en4
+
+if4:
+ stc
+en4:
+ pop ds
+ pop es
+ ret
+sysinit_parse endp
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : badop_p
+;
+; same thing as badop,but will make sure to set ds register back
+; to sysinitseg and return back to the caller.
+;
+;----------------------------------------------------------------------------
+;
+badop_p proc near
+
+
+ push cs
+ pop ds ;set ds to configsys seg.
+ mov dx,offset badopm
+ call print
+ call error_line
+ ret
+
+badop_p endp
+;
+;----------------------------------------------------------------------------
+;
+; label : badop
+;
+;----------------------------------------------------------------------------
+;
+badop: mov dx,offset badopm ;want to print command error "unrecognized command..."
+ call print
+ call error_line ;show "error in config.sys ..." .
+ jmp coff
+
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : badparm_p
+;
+; show "bad command or parameters - xxxxxx"
+; in badparm_seg,badparm_off -> xxxxx
+;
+;----------------------------------------------------------------------------
+;
+badparm_p proc near
+
+
+ push ds
+ push dx
+ push si
+
+ push cs
+ pop ds
+
+ mov dx,offset badparm
+ call print ;"bad command or parameters - "
+ lds si,badparm_ptr
+
+; print "xxxx" until cr.
+
+do1:
+ mov dl,byte ptr [si] ; get next character
+ cmp dl,cr ; is a carriage return?
+ jz en1 ; exit loop if so
+
+ mov ah,std_con_output ; function 2
+ int 21h ; display character
+ inc si ; next character
+ jmp do1
+en1:
+ push cs
+ pop ds
+
+ mov dx,offset crlfm
+ call print
+ call error_line
+
+ pop si
+ pop dx
+ pop ds
+badparmp_ret:
+ ret
+badparm_p endp
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : getchr
+;
+;----------------------------------------------------------------------------
+;
+getchr proc near
+ push cx
+ mov cx,count
+ jcxz nochar
+
+ mov si,chrptr
+ mov al,es:[si]
+ dec count
+ inc chrptr
+ clc
+get_ret:
+ pop cx
+ ret
+
+nochar: stc
+ jmp short get_ret
+getchr endp
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : incorrect_order
+;
+; show "incorrect order in config.sys ..." message.
+;
+;----------------------------------------------------------------------------
+;
+
+incorrect_order proc near
+
+ mov dx,offset badorder
+ call print
+ call showlinenum
+ ret
+
+incorrect_order endp
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : error_line
+;
+; show "error in config.sys ..." message.
+;
+;----------------------------------------------------------------------------
+;
+ public error_line
+error_line proc near
+
+
+ push cs
+ pop ds
+ mov dx,offset errorcmd
+ call print
+ call showlinenum
+ ret
+
+error_line endp
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : showlinenum
+;
+; convert the binary linecount to decimal ascii string in showcount
+;and display showcount at the current curser position.
+;in.) linecount
+;
+;out) the number is printed.
+;
+;----------------------------------------------------------------------------
+;
+showlinenum proc near
+
+
+ push es
+ push ds
+ push di
+
+ push cs
+ pop es ; es=cs
+
+ push cs
+ pop ds
+
+ mov di,offset showcount+4 ; di -> the least significant decimal field.
+ mov cx,10 ; decimal devide factor
+ mov ax,cs:linecount
+
+sln_loop:
+ cmp ax,10 ; < 10?
+ jb sln_last
+
+ xor dx,dx
+ div cx
+ or dl,30h ; add "0" (= 30h) to make it an ascii.
+ mov [di],dl
+ dec di
+ jmp sln_loop
+
+sln_last:
+ or al,30h
+ mov [di],al
+ mov dx,di
+ call print ; show it.
+ pop di
+ pop ds
+ pop es
+ ret
+showlinenum endp
+
+comment ^
+set_devmark proc near
+;***************************************************************************
+; function: set a paragraph of informations infront of a device file or *
+; an ifs file to be loaded for mem command. *
+; the structure is: *
+; devmark_id byte "d" for device,"i" for ifs *
+; devmark_size size in para for the device loaded *
+; devmark_filename 11 bytes. filename *
+; *
+; input : *
+; [memhi] = address to set up devmark. *
+; [memlo] = 0 *
+; es:si -> pointer to [drive][path]filename,0 *
+; [ifs_flag] = is_ifs bit set if ifs= command. *
+; *
+; output: devmark_id,devmark_filename set *
+; cs:[devmark_addr] set. *
+; ax,cx register destroyed. *
+;***************************************************************************
+
+ push ds
+ push si
+ push es
+ push di
+
+ mov di,cs:[memhi]
+ mov ds,di
+ assume ds:nothing
+ mov [devmark_addr],di ; save the devmark address for the future.
+ mov ds:[devmark_id],devmark_device ; 'd'
+ inc di
+ mov ds:[devmark_seg],di
+ xor al,al
+ push si
+ pop di ; now es:si = es:di = [path]filename,0
+ mov cx,128 ; maximum 128 char
+ repnz scasb ; find 0
+ dec di ; now es:di-> 0
+sdvmk_backward: ; find the pointer to the start of the filename.
+ mov al,byte ptr es:[di] ; we do this by check es:di backward until
+ cmp al,'\' ; di = si or di -> '\' or di -> ':'.
+ je sdvmk_gotfile
+ cmp al,':'
+ je sdvmk_gotfile
+ cmp di,si
+ je sdvmk_fileptr
+ dec di
+ jmp sdvmk_backward
+sdvmk_gotfile:
+ inc di
+sdvmk_fileptr: ; now es:di -> start of file name
+ push di ; cas - holy sh*t!!! CODE!
+ pop si ; save di to si.
+
+ push ds ; switch es,ds
+ push es
+ pop ds
+ pop es ; now,ds:si -> start of filename
+
+ mov di,devmark_filename
+ push di
+ mov al,' '
+ mov cx,8
+ rep stosb ; clean up memory.
+ pop di
+ mov cx,8 ; max 8 char. only
+sdvmk_loop:
+ lodsb
+ cmp al,'.'
+ je sdvmk_done
+ cmp al,0
+ je sdvmk_done
+ stosb
+ loop sdvmk_loop
+
+sdvmk_done:
+ pop di
+ pop es
+ pop si
+ pop ds
+ ret
+set_devmark endp
+^
+; =========================================================================
+;reset_dos_version proc near
+;
+;;function: issue ax=122fh,dx=0,int 2fh to restore the dos version.
+;
+; push ax
+; push dx
+; mov ax,122fh
+; mov dx,0
+; int 2fh
+; pop dx
+; pop ax
+; ret
+;reset_dos_version endp
+;
+;
+; =========================================================================
+
+IFDEF DONT_LOAD_OS2_DD ; M045
+
+EXE_SIG EQU 5a4dh ; .EXE file signature
+OS2_SIG EQU 454eh ; OS2 .EXE file signature
+
+SIGNATURE_LEN EQU 2 ; Lenght of .EXE signature in bytes
+SIZE_DWORD EQU 4
+
+SEG_SIG_OFFSET EQU 18h ; Offset of segmented .EXE signature
+SEG_EXE_SIG EQU 40h ; Signature of a segmented .EXE file
+SEG_HEADER_PTR EQU 3ch ; Offsets of ptr to segmented header
+
+; =========================================================================
+; CheckForOS2 PROC
+;
+; Examines an open file to see if it is really an OS2 executable file.
+;
+; REGISTERS: AX - Open file handle
+; RETURNS: Carry - Carry set if file is an OS2 executable or error.
+; DESTROYS: NOTHING
+; NOTE: The file ptr is assumed to be set to start of file
+; on entry and is not reset to begining of the file
+; on exit.
+;
+; Strategy: If word value at 00h == 454eh file is OS2
+; else if word value at 00h == 5a4dh and
+; (word value at 18h == 40h and the dword ptr at 3ch
+; points to word value of 454eh) file is OS2.
+;
+; =========================================================================
+
+CheckForOS2 PROC NEAR
+
+ push AX
+ push BX
+ push CX
+ push DX
+ push DS
+ push BP
+
+ push CS ; BUGBUG
+ pop DS ; NOT ROM DOS COMPATIBLE
+
+ mov BX,AX ; Put open file handle in BX
+ mov BP,offset DS:Os2ChkBuf ; Save buff offset for latter
+
+ ; First we need to read in the first 2 bytes of the file
+ ; to see if it's an OS2 .EXE file and if not see if
+ ; it is a DOS .EXE file.
+
+ mov AX,(read shl 8) ; AH = DOS read function
+ mov CX,SIGNATURE_LEN ; CX = size of word value
+ mov DX,BP ; DS:DX --> tmp buffer
+ int 21h
+ jc OS2ChkExit ; Return carry on error
+
+ dec AX ; Check number of byte read
+ dec AX
+ jnz NotOs2 ; Must be at end of file
+
+ mov AX, WORD PTR DS:Os2ChkBuf
+ cmp AX, OS2_SIG ; Check for 454eh
+ je IsOS2 ; Return is OS2 if match
+ cmp AX, EXE_SIG ; Now see if it's a DOS .EXE
+ jne NotOS2 ; If no match can't be OS2
+
+ ; Here we know the file has a valid DOS .EXE signature so
+ ; now we need to see if it's a segmented .EXE file by looking
+ ; for the segmented .EXE signature at file offset 18h
+
+ mov AX,(lseek shl 8) ; AX = Seek from begining
+ xor CX,CX
+ mov DX,SEG_SIG_OFFSET ; CX:DX = offset of segmented
+ int 21h ; Seek to offset 18h
+ jc OS2ChkExit ; Return carry on error
+
+ mov AX,read shl 8 ; AX = Read file
+ mov CX,SIGNATURE_LEN ; CX = size of word value
+ mov DX,BP ; Restore buffer offset
+ int 21h ; DS:DX -> buffer
+ jc OS2ChkExit ; Return carry on error
+
+ dec AX ; Check number of byte read
+ dec AX
+ jnz NotOs2 ; Must be at end of file
+
+ cmp WORD PTR DS:Os2ChkBuf,SEG_EXE_SIG ; Chk for segmented .EXE file
+ jne NotOS2 ; Can't be OS2 if no match
+
+ ; Here we know we have a segmented .EXE file so we have
+ ; to get the offset of the start of the segmented header
+ ; from offset 3ch in the file.
+
+ mov AX,(lseek shl 8) ; AX = Seek from begining
+ xor CX,CX
+ mov DX,SEG_HEADER_PTR ; CX:DX = offset of head ptr
+ int 21h ; Seek to offset 3ch
+ jc OS2ChkExit ; Return carry on error
+
+ mov AX,(read shl 8) ; AX = Read file
+ mov CX,SIZE_DWORD ; CX = size of dword (4 bytes)
+ mov DX,BP ; Restore buffer offset
+ int 21h ; Read in 4 byte offset
+ jc OS2ChkExit ; Return carry on error
+
+ cmp AX,SIZE_DWORD ; Check number of byte read
+ jne NotOs2 ; Must be at end of file
+
+ ; At this point OS2ChkBuf has a 4 byte offset into the file
+ ; to the start of a segmented .EXE header so we need to read
+ ; the 2 bytes at this location to see if they are 454eh
+
+ mov DX,WORD PTR DS:Os2ChkBuf
+ mov CX,WORD PTR DS:Os2ChkBuf[2] ; CX:DX = offset of new header
+ mov AX,(lseek shl 8) ; AX = Seek from begining
+ int 21h ; Seek to offset 3ch
+ jc OS2ChkExit ; Return carry on error
+
+ mov AX,(read shl 8) ; AX = Read file
+ mov CX,SIGNATURE_LEN ; CX = size of word (2 bytes)
+ mov DX,BP ; DS:DX --> Os2ChkBuf
+ int 21h ; Read in 4 byte offset
+ jc OS2ChkExit ; Return carry on error
+
+ dec AX ; Check number of byte read
+ dec AX
+ jnz NotOs2 ; Must be at end of file
+
+ ; We have the segmented .EXE header in OS2ChkBuf so all
+ ; we have left to do is see if it's a .EXE signature.
+
+ cmp WORD PTR DS:OS2ChkBuf,OS2_SIG ; Check for 454eh
+ jne NotOs2 ; Not OS2 if it doesn't match
+
+IsOs2:
+ stc ; Signal error or OS2 .EXE
+ jmp SHORT OS2ChkExit
+NotOs2:
+ clc ; Signal no err and not OS2
+
+OS2ChkExit:
+ pop BP
+ pop DS
+ pop DX
+ pop CX
+ pop BX
+ pop AX
+ ret
+
+CheckForOS2 ENDP
+
+ENDIF ; M045
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : ProcDOS
+;
+; Process the result of DOS= parsing
+;
+; result_val.$p_item_tag = 1 for DOS=HIGH
+; = 2 for DOS=LOW
+; = 3 for DOS=UMB
+; = 4 for DOS=NOUMB
+;----------------------------------------------------------------------------
+;
+ProcDOS proc near
+ assume ds:nothing, es:nothing
+ xor ah, ah
+ mov al, result_val.$p_item_tag
+ dec ax
+ jz pd_hi
+ dec ax
+ jz pd_lo
+ dec ax
+ jz pd_umb
+ mov DevUMB, 0
+ ret
+pd_umb:
+ mov DevUMB, 0ffh
+ ret
+pd_lo:
+ mov runhigh, 0
+ ret
+pd_hi:
+ mov runhigh, 0ffh
+ ret
+ProcDOS endp
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : LieInt12Mem
+;
+; Input : DevEntry points to Device Start address (offset == 0)
+; alloclim set to the limit of low memory.
+;
+; Output : none
+;
+; Changes the ROM BIOS variable which stores the total low memory
+; If a 3com device driver (any character device with name 'PROTMAN$')
+; is being loaded alloclim is converted into Ks and stored in 40:13h
+; Else if a device driver being loaded into UMB the DevLoadEnd is
+; converted into Ks and stored in 40:13h
+;
+;----------------------------------------------------------------------------
+;
+LieInt12Mem proc near
+
+ assume ds:nothing, es:nothing
+
+ mov ax, alloclim ; lie INT 12 as alloclim
+ ; assuming that it is 3Com
+ call IsIt3Com? ; Is it 3Com driver?
+ je lim_set ; yes, lie to him differently
+ cmp DeviceHi, 0 ; Is the DD being loaded in UMB
+ je limx ; no, don't lie
+ mov ax, DevLoadEnd ; lie INT 12 as end of UMB
+lim_set:
+ call SetInt12Mem
+limx:
+ ret
+LieInt12Mem endp
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : SetInt12Mem
+;
+; Input : AX = Memory size to be set (in paras)
+; Output : none
+;
+; Sets the variable 40:13 to the memory size passed in AX
+; It saves the old value in 40:13 in OldInt12Mem,
+; It also sets a flag Int12Lied to 0ffh, which is checked before
+; restoring the value of 40:13
+;
+;----------------------------------------------------------------------------
+;
+SetInt12Mem proc near
+
+ assume ds:nothing, es:nothing
+
+ push ds
+ mov bx, 40h
+ mov ds, bx ; ROM BIOS Data Segment
+ mov bx, word ptr ds:[13h] ; INT 12 memory variable
+ mov OldInt12Mem, bx ; save it
+ mov cl, 6
+ shr ax, cl ; convert paras into Ks
+ mov word ptr ds:[13h], ax ; Lie
+ mov Int12Lied, 0ffh ; mark that we are lying
+ pop ds
+ ret
+SetInt12Mem endp
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : TrueInt12Mem
+;
+; Input : Int12Lied = 0 if we are not lying currently
+; = 0ffh if we are lying
+; OldInt12Mem = Saved value of 40:13h
+;
+; Output : none
+;
+; Resets the INT 12 Memory variable if we were lying about int 12
+; and resets the flag which indicates that we were lying
+;
+;----------------------------------------------------------------------------
+;
+TrueInt12Mem proc near
+
+ assume ds:nothing, es:nothing
+
+ cmp Int12Lied, 0 ; were we lying so far?
+ mov Int12Lied, 0 ; reset it anyway
+ je timx ; no, we weren't
+ push ds
+ mov ax, 40h
+ mov ds, ax
+ mov ax, OldInt12Mem
+ mov word ptr ds:[13h], ax ; restore INT 12 memory
+ pop ds
+timx:
+ ret
+TrueInt12Mem endp
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : IsIt3Com?
+;
+; Input : DevEntry = Seg:0 of device driver
+; Output : Zero flag set if device name is 'PROTMAN$'
+; else Zero flag is reset
+;
+;----------------------------------------------------------------------------
+;
+IsIt3Com? proc near
+ assume ds:nothing, es:nothing, ss:nothing
+ push ds
+ push es
+ push si
+ lds si, DevEntry ; ptr to device header
+ add si, sdevname ; ptr device name
+ push cs
+ pop es
+ mov di, offset ThreeComName
+ mov cx, 8 ; name length
+ rep cmpsb
+ pop si
+ pop es
+ pop ds
+ ret
+IsIt3Com? endp
+
+;M020 : BEGIN
+;
+;----------------------------------------------------------------------------
+;----------------------------------------------------------------------------
+;
+UpdatePDB proc near
+ assume ds:nothing
+ push ds
+ mov ah, 62h
+ int 21h
+ mov ds, bx
+ mov bx, alloclim
+ mov ds:[PDB_Block_Len], bx
+ pop ds
+ ret
+UpdatePDB endp
+;
+; M020 : END
+;
+;----------------------------------------------------------------------------
+;
+; procedure : InitDevLoad
+;
+; Input : DeviceHi = 0 indicates load DD in low memory
+; = 1 indicates load in UMB
+; DevSize = Size of the device driver file in paras
+;
+; Output : none
+;
+; Initializes DevLoadAddr, DevLoadEnd & DevEntry.
+; Also sets up a header for the Device driver entry for mem utility
+;
+;----------------------------------------------------------------------------
+;
+InitDevLoad proc near
+
+ assume ds:nothing, es:nothing
+
+ cmp DeviceHi, 0 ; Are we loading in UMB
+ je InitForLo ; no, init for lo mem
+ call SpaceInUMB? ; Do we have space left in the
+ ; current UMB ?
+ jnc InitForHi ; yes, we have
+ call ShrinkUMB ; shrink the current UMB in use
+ call GetUMBForDev ; else try to allocate new UMB
+ jc InitForLo ; we didn't succeed, so load
+ ; in low memory
+InitForHi:
+ mov ax, DevUMBFree ; get Para addr of free mem
+ mov dx, DevUMBAddr ; UMB start addr
+ add dx, DevUMBSize ; DX = UMB End addr
+ jmp short idl1
+
+InitForLo:
+ mov DeviceHi, 0 ; in case we failed to load
+ ; into UMB indicate that we
+ ; are loading low
+ mov ax, memhi ; AX = start of Low memory
+ mov dx, alloclim ; DX = End of Low memory
+idl1:
+ call DevSetMark ; setup a sub-arena for DD
+ mov DevLoadAddr, ax ; init the Device load address
+ mov DevLoadEnd, dx ; init the limit of the block
+ mov word ptr DevEntry, 0 ; init Entry point to DD
+ mov word ptr DevEntry+2, ax
+ ret
+InitDevLoad endp
+
+
+;------------------------------------------------------------------
+; NTVDM 08-Dec-1992 Jonle
+;
+; AllocUMBLow- Allocates a chunk from memory from UMB area
+; or from low memory area in case UMB memory
+; is unavailable.
+;
+; The arena is marked as
+;
+; Input: es:di addr of arena name to copy
+; cx size to allocate
+;
+; Output: es:di points to memory allocated
+;
+;------------------------------------------------------------------
+AllocUMBLow proc near
+
+ assume ds:nothing, es:nothing
+
+ mov ax, cx ; convert size to paras
+ add ax, 18 ; extra for dummy dev header for mem.exe
+ call pararound
+ mov DevSize, ax
+
+ mov word ptr [bpb_addr], di ; fake cmd line for dev name
+ mov word ptr [bpb_addr+2], es
+
+ mov al, DevUMB ; we want UMB
+ mov DeviceHi, al
+
+ call InitDevLoad
+
+ mov ax, word ptr DevEntry+2 ; mark arena for mem.exe
+ dec ax
+ mov es, ax
+ mov byte ptr es:[devmark_id], devmark_spc
+
+ inc ax ; mark final size
+ add ax, DevSize
+ mov word ptr DevBrkAddr+2,ax
+ mov word ptr DevBrkAddr, 0
+ call DevBreak
+
+ mov di, word ptr DevEntry ; es:di -> deventry
+ mov ax, word ptr DevEntry+2
+ mov es, ax
+
+AllocUMBLow endp
+
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : SpaceInUMB?
+;
+; Input : DevUMBAddr, DevUMBSize, DevUMBFree & DevSize
+; Output : Carry set if no space in UMB
+; Carry clear if Space is available for the device in
+; current UMB
+;
+;----------------------------------------------------------------------------
+;
+SpaceInUMB? proc near
+
+ assume ds:nothing, es:nothing
+
+ mov ax, DevUMBSize
+ add ax, DevUMBAddr ; End of UMB
+ sub ax, DevUMBFree ; - Free = Remaining space
+ or ax, ax ; Nospace ?
+ jnz @f
+ stc
+ ret
+@@:
+ dec ax ; space for sub-arena
+ cmp ax, DevSize ; do we have space ?
+ ret
+SpaceInUMB? endp
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : GetUMBForDev
+;
+; Input : DevSize
+; Output : Carry set if couldn't allocate a UMB to fit the
+; the device.
+; If success carry clear
+;
+; Allocates the biggest UMB for loading devices and updates
+; DevUMBSize, DevUMBAddr & DevUMBFree if it succeeded in allocating
+; UMB.
+;
+; This routine relies on the fact that all of the low memory
+; is allocated, and any DOS alloc calls should return memory
+; from the UMB pool.
+;
+;----------------------------------------------------------------------------
+;
+GetUMBForDev proc near
+
+ assume ds:nothing, es:nothing
+
+if 0
+;;
+ mov bx, 0ffffh
+ mov ax, 4800h
+ int 21h
+
+ or bx, bx
+ jz gufd_err
+
+ dec bx
+ cmp DevSize, bx
+ ja gufd_err
+ inc bx
+ mov ax, 4800h
+ int 21h
+ jc gufd_err
+
+ push ds
+ dec ax
+ mov ds, ax
+ mov word ptr ds:[arena_owner], 8
+ mov word ptr ds:[arena_name], 'DS'
+ inc ax
+ pop ds
+
+ mov DevUMBSize, bx ; update the UMB Variables
+ mov DevUMBAddr, ax
+ mov DevUMBFree, ax
+ clc ; mark no error
+ ret
+gufd_err:
+ xor ax, ax
+ mov DevUMBSize, ax ; erase the previous values
+ mov DevUMBAddr, ax
+ mov DevUMBFree, ax
+ stc
+ ret
+else
+;; we changed the allocation strategy to best-fit for NT. This is because
+;; we want to reserve bigger blocks for loadhigh command. In most case,
+;; device drivers are smaller than TSR(ran from loadhigh). This change give
+;; us a better chance to load the big tsr like DOSX.EXE to UMB and
+;; give applications more free conventional memory.
+;; The following implementation seems slow because every time we need an
+;; UMB, we go through the chain. This is done because each request has
+;; different size - We can grab all UMBs from the very beginning and put
+;; them in a list, but we have to maintain the list. -williamh
+ push cx
+ push dx
+ push es
+ xor cx, cx ;; allocated count = 0
+ mov dx, DevSize
+ inc dx ;; minimum size in paras
+ ;; bios needs its sub-arena
+search_for_best_block:
+ mov bx, 0ffffh ;; get largest block size
+ mov ah, 48h ;; so far
+ int 21h
+ cmp bx, dx ;; will this satisfy ours?
+ jb allocate_the_block ;; no, break
+ mov ah, 48h ;; allocate this block
+ int 21h
+ jc allocate_the_block ;; failed, use the previous one
+ inc cx ;; we have one more allocated
+ push bx ;; save the size
+ push ax ;; save the address
+ jmp short search_for_best_block
+
+allocate_the_block:
+;; the block saved on the top of the stack is the best fit one
+;; grab it if there is one
+ jcxz gufd_err ;; no block found, error
+ pop ax ;; get the address
+ pop DevUMBSize ;; and size
+ mov DevUMBAddr, ax
+ mov DevUMBFree, ax
+ dec ax
+ push ds
+ mov ds, ax
+ mov word ptr ds:[arena_owner], 8
+ mov word ptr ds:[arena_name], 'DS'
+ pop ds
+ dec cx
+;; now free those unnecessary blocks
+ jcxz allocate_done
+free_allocated_blocks:
+ pop es ;; get the address
+ add sp, 2 ;; discard the size
+ mov ah, 49h ;; free it
+ int 21h
+ loop free_allocated_blocks
+allocate_done:
+ clc ; mark no error
+ jmp short GetUMBForDevExit
+gufd_err:
+ xor ax, ax
+ mov DevUMBSize, ax ; erase the previous values
+ mov DevUMBAddr, ax
+ mov DevUMBFree, ax
+ stc
+GetUMBForDevExit:
+ pop es
+ pop dx
+ pop cx
+ ret
+endif
+
+GetUMBForDev endp
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : DevSetMark
+;
+; Input : AX - Free segment were device is going to be loaded
+; Output : AX - Segment at which device can be loaded (AX=AX+1)
+;
+; Creates a sub-arena for the device driver
+; puts 'D' marker in the sub-arena
+; Put the owner of the sub-arena as (AX+1)
+; Copies the file name into sub-arena name field
+;
+; Size field of the sub-arena will be set only at succesful
+; completion of Device load.
+;
+;----------------------------------------------------------------------------
+;
+DevSetMark proc near
+
+ assume ds:nothing, es:nothing
+
+ push es
+ push di
+ push ds
+ push si
+ mov es, ax
+ mov byte ptr es:[devmark_id], devmark_device ; 'D'
+ inc ax
+ mov word ptr es:[devmark_seg], ax
+;
+;-------------- Copy file name
+;
+ push ax ; save load addr
+ lds si, bpb_addr ; command line is still there
+;M004 - BEGIN
+ mov di, si
+ cld
+dsm_again:
+ lodsb
+ cmp al, ':'
+ jne isit_slash
+ mov di, si
+ jmp dsm_again
+isit_slash:
+ cmp al, '\'
+ jne isit_null
+ mov di, si
+ jmp dsm_again
+isit_null:
+
+ifdef DBCS
+ call testkanj
+ jz @f ; if this is not lead byte
+ lodsb ; get tail byte
+@@:
+endif
+
+ or al, al
+ jnz dsm_again
+ mov si, di
+;M004 - END
+ mov di, devmark_filename
+ mov cx, 8 ; maximum 8 characters
+dsm_next_char:
+ lodsb
+ or al, al
+ jz blankout
+ cmp al, '.'
+ jz blankout
+ stosb
+ loop dsm_next_char
+blankout:
+ jcxz dsm_exit
+ mov al, ' '
+ rep stosb ; blank out the rest
+dsm_exit:
+ pop ax ; restore load addr
+ pop si
+ pop ds
+ pop di
+ pop es
+ ret
+DevSetMark endp
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : SizeDevice
+;
+; Input : ES:SI - points to device file to be sized
+;
+; Output : Carry set if file cannot be opened or if it is an OS2EXE file
+;
+; Calculates the size of the device file in paras and stores it
+; in DevSize
+;
+;----------------------------------------------------------------------------
+;
+SizeDevice proc near
+
+ assume ds:nothing, es:nothing
+
+ push es
+ pop ds
+ mov dx, si ; ds:dx -> file name
+ mov ax, 3d00h ; open
+ int 21h
+ jc sd_err ; open failed
+
+IFDEF DONT_LOAD_OS2_DD ; M045
+ call CheckForOS2 ; is it a OS2 EXE file ?
+ jc sd_close ; yeah, we dont load them
+ENDIF ; M045
+
+ mov bx, ax ; BX - file handle
+ mov ax, 4202h ; seek
+ xor cx, cx
+ mov dx, cx ; to end of file
+ int 21h
+ jc sd_close ; did seek fail (impossible)
+ add ax, 15 ; para convert
+ adc dx, 0
+ test dx, 0fff0h ; size > 0ffff paras ?
+ jz @f ; no
+ mov DevSize, 0ffffh ; invalid device size
+ ; assuming that we fail later
+ jmp short sd_close
+@@:
+ mov cl, 4 ; conver it to paras
+ shr ax, cl
+ mov cl, 12
+ shl dx, cl
+ or ax, dx ;
+ cmp ax, DevSizeOption
+ ja @f
+ mov ax, DevSizeOption
+@@:
+ mov DevSize, ax ; save file size
+ clc
+sd_close:
+ pushf ; let close not spoil our
+ ; carry flag
+ mov ax, 3e00h ; close
+ int 21h ; we are not checking for err
+ popf
+sd_err:
+ ret
+SizeDevice endp
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : ExecDev
+;
+; Input : ds:dx -> device to be executed
+; DevLoadAddr - contains where device has to be loaded
+;
+; Output : Carry if error
+; Carry clear if no error
+;
+; Loads a device driver using the 4b03h function call
+;
+;----------------------------------------------------------------------------
+;
+ExecDev proc near
+
+ assume ds:nothing, es:nothing
+
+ mov bx, DevLoadAddr
+ mov DevExecAddr, bx ; Load the parameter block
+ ; block for exec with
+ ; Load address
+ mov DevExecReloc, bx
+ mov bx,cs
+ mov es,bx
+ mov bx,offset DevExecAddr ;es:bx points to parameters
+ mov al,3
+ mov ah,exec
+ int 21h ;load in the device driver
+ ret
+ExecDev endp
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : RemoveNull
+;
+; Input : ES:SI points to a null terminated string
+;
+; Output : none
+;
+; Replaces the null at the end of a string with blank
+;
+;----------------------------------------------------------------------------
+;
+
+RemoveNull proc near
+
+ assume ds:nothing, es:nothing
+
+rn_next:
+ mov bl, es:[si]
+ or bl, bl ; null ?
+ jz rn_gotnull
+ inc si ; advance the pointer
+ jmp rn_next
+rn_gotnull:
+ mov bl, DevSavedDelim
+ mov byte ptr es:[si], bl ; replace null with blank
+ ret
+RemoveNull endp
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : RoundBreakAddr
+;
+; Input : DevBrkAddr
+; Output : DevBrkAddr
+;
+; Rounds DevBrkAddr to a para address so that it is of the form xxxx:0
+;
+;----------------------------------------------------------------------------
+;
+RoundBreakAddr proc near
+
+ assume ds:nothing, es:nothing
+
+ mov ax, word ptr DevBrkAddr
+ call pararound
+ add word ptr DevBrkAddr+2, ax
+ mov word ptr DevBrkAddr, 0
+ mov ax, DevLoadEnd
+ cmp word ptr DevBrkAddr+2, ax
+ jbe rba_ok
+ jmp mem_err
+rba_ok:
+ ret
+RoundBreakAddr endp
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : DevSetBreak
+;
+; Input : DevBrkAddr
+; Output : Carry set if Device returned Init failed
+; Else carry clear
+;
+;----------------------------------------------------------------------------
+;
+DevSetBreak proc near
+
+ assume ds:nothing, es:nothing
+
+ push ax
+
+ mov ax,word ptr [DevBrkAddr+2] ;remove the init code
+ cmp multdeviceflag, 0
+ jne set_break_continue ;do not check it.
+ cmp ax, DevLoadAddr
+ jne set_break_continue ;if not same, then o.k.
+
+ cmp word ptr [DevBrkAddr],0
+ je break_failed ;[DevBrkAddr+2]=[memhi] & [DevBrkAddr]=0
+
+set_break_continue:
+ call RoundBreakAddr
+ pop ax
+ clc
+ ret
+break_failed:
+ pop ax
+ stc
+ ret
+DevSetBreak endp
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : DevBreak
+;
+; Input : DevLoadAddr & DevBrkAddr
+; Output : none
+;
+; Marks a succesful install of a device driver
+; Sets device size field in sub-arena &
+; Updates Free ptr in UMB or adjusts memhi
+;
+;----------------------------------------------------------------------------
+;
+DevBreak proc near
+
+ assume ds:nothing, es:nothing
+
+ push ds
+ mov ax, DevLoadAddr
+ mov bx, word ptr [DevBrkAddr+2]
+ dec ax ; seg of sub-arena
+ mov ds, ax
+ inc ax ; Back to Device segment
+ sub ax, bx
+ neg ax ; size of device in paras
+ mov ds:[devmark_size], ax ; store it in sub-arena
+ cmp DeviceHi, 0
+ je db_lo
+ mov DevUMBFree, bx ; update Free ptr in UMB
+ jmp short db_exit
+db_lo:
+ mov memhi, bx
+ mov memlo, 0
+db_exit:
+ pop ds
+ ret
+DevBreak endp
+;
+;----------------------------------------------------------------------------
+;
+; procedure : ParseSize
+;
+; Parses the command line for SIZE= command
+;
+; ES:SI = command line to parsed
+;
+; returns ptr to command line after SIZE= option in ES:SI
+; updates the DevSizeOption variable with value supplied
+; in SIZE=option
+; Returns carry if the SIZE option was invalid
+;
+;----------------------------------------------------------------------------
+;
+ParseSize proc near
+
+ assume ds:nothing, es:nothing
+
+ mov DevSizeOption, 0 ; init the value
+ mov word ptr DevCmdLine, si
+ mov word ptr DevCmdLine+2, es
+ call SkipDelim
+ cmp word ptr es:[si], 'IS'
+ jne ps_no_size
+ cmp word ptr es:[si+2], 'EZ'
+ jne ps_no_size
+ mov al, es:[si+4]
+ call delim
+ jne ps_no_size
+ add si, 5
+ call GetHexNum
+ jc ps_err
+ mov DevSizeOption, ax
+ call SkipDelim
+ps_no_size:
+ clc
+ ret
+ps_err:
+ stc
+ ret
+ParseSize endp
+;
+;----------------------------------------------------------------------------
+;
+; procedure : SkipDelim
+;
+; Skips delimiters in the string pointed to by ES:SI
+; Returns ptr to first non-delimiter character in ES:SI
+;
+;----------------------------------------------------------------------------
+;
+SkipDelim proc near
+
+ assume ds:nothing, es:nothing
+
+sd_next_char:
+ mov al, es:[si]
+ call delim
+ jnz sd_ret
+ inc si
+ jmp sd_next_char
+sd_ret:
+ ret
+SkipDelim endp
+;
+;----------------------------------------------------------------------------
+;
+; procedure : GetHexNum
+;
+; Converts an ascii string terminated by a delimiter into binary.
+; Assumes that the ES:SI points to a Hexadecimal string
+;
+; Returns in AX the number number of paras equivalent to the
+; hex number of bytes specified by the hexadecimal string.
+;
+; Returns carry in case it encountered a non-hex character or
+; if it encountered crlf
+;
+;----------------------------------------------------------------------------
+;
+GetHexNum proc near
+
+ assume ds:nothing, es:nothing
+
+ xor ax, ax
+ xor dx, dx
+ghn_next:
+ mov bl, es:[si]
+ cmp bl, cr
+ je ghn_err
+ cmp bl, lf
+ je ghn_err
+ push ax
+ mov al, bl
+ call Delim
+ pop ax
+ jz ghn_into_paras
+ call GetNibble
+ jc ghn_err
+ mov cx, 4
+ghn_shift1:
+ shl ax, 1
+ rcl dx, 1
+ loop ghn_shift1
+ or al, bl
+ inc si
+ jmp ghn_next
+ghn_into_paras:
+ add ax, 15
+ adc dx, 0
+ test dx, 0fff0h
+ jnz ghn_err
+ mov cx, 4
+ghn_shift2:
+ clc
+ rcr dx, 1
+ rcr ax, 1
+ loop ghn_shift2
+ clc
+ ret
+ghn_err:
+ stc
+ ret
+GetHexNum endp
+;
+;----------------------------------------------------------------------------
+;
+; procedure : GetNibble
+;
+; Convert one nibble (hex digit) in BL into binary
+;
+; Retruns binary value in BL
+;
+; Returns carry if BL contains non-hex digit
+;
+;----------------------------------------------------------------------------
+;
+GetNibble proc near
+ cmp bl, '0'
+ jb gnib_err
+ cmp bl, '9'
+ ja is_it_hex
+ sub bl, '0' ; clc
+ ret
+is_it_hex:
+ cmp bl, 'A'
+ jb gnib_err
+ cmp bl, 'F'
+ ja gnib_err
+ sub bl, 'A'- 10 ; clc
+ ret
+gnib_err:
+ stc
+ ret
+GetNibble endp
+;
+;
+;============================================================================
+;============================================================================
+;
+;----------------------------------------------------------------------------
+;
+; procedure : AllocUMB
+;
+; Allocate all UMBs and link it to DOS arena chain
+;
+;----------------------------------------------------------------------------
+;
+AllocUMB proc near
+ call InitAllocUMB ; link in the first UMB
+ jc au_exit ; quit on error
+au_next:
+ call umb_allocate ; allocate
+ jc au_coalesce
+ call umb_insert ; & insert till no UMBs
+ jmp short au_next
+au_coalesce:
+ call umb_coalesce ; coalesce all UMBs
+au_exit:
+ ret
+AllocUMB endp
+;
+;----------------------------------------------------------------------------
+;
+; procedure : InitAllocUMB
+;
+;----------------------------------------------------------------------------
+;
+InitAllocUMB proc near
+ call IsXMSLoaded
+ jnz iau_err ; quit on no XMS driver
+ mov ah, 52h
+ int 21h ; get DOS DATA seg
+ mov DevDOSData, es ; & save it for later
+ mov ax, 4310h
+ int 2fh
+ mov word ptr DevXMSAddr, bx ; get XMS driver address
+ mov word ptr DevXMSAddr+2, es
+ cmp FirstUMBLinked, 0 ; have we already linked a UMB?
+ jne @f ; quit if we already did it
+ call LinkFirstUMB ; else link the first UMB
+ jc iau_err
+ mov FirstUMBLinked, 0ffh ; mark that 1st UMB linked
+@@:
+ clc
+ ret
+iau_err:
+ stc
+ ret
+InitAllocUMB endp
+
+;-------------------------------------------------------------------------
+;
+; Procedure Name : umb_allocate
+;
+; Inputs : DS = data
+;
+; Outputs : if UMB available
+; Allocates the largest available UMB and
+; BX = segment of allocated block
+; DX = size of allocated block
+; NC
+; else
+; CY
+;
+; Uses : BX, DX
+;
+;-------------------------------------------------------------------------
+
+umb_allocate proc near
+
+ push ax
+ mov ah, XMM_REQUEST_UMB
+ mov dx, 0ffffh ; try to allocate largest
+ ; possible
+ call dword ptr DevXMSAddr
+ ; dx now contains the size of
+ ; the largest UMB
+ or dx, dx
+ jz ua_err
+
+ mov ah, XMM_REQUEST_UMB
+ call dword ptr DevXMSAddr
+
+ cmp ax, 1 ; Q: was the reqst successful
+ jne ua_err ; N: error
+
+ clc
+
+ua_done:
+ pop ax
+ ret
+
+ua_err:
+ stc
+ jmp short ua_done
+
+umb_allocate endp
+
+
+
+;---------------------------------------------------------------------------
+;
+; Procedure Name : umb_insert
+;
+; Inputs : DOSDATA:UMB_HEAD = start of umb chain
+; : BX = seg address of UMB to be linked in
+; : DX = size of UMB to be linked in paras
+; ; DS = data
+;
+; Outputs : links the UMB into the arena chain
+;
+; Uses : AX, CX, ES, DX, BX
+;
+;---------------------------------------------------------------------------
+
+
+umb_insert proc near
+
+ push ds
+
+ mov ds, [DevDOSData]
+ mov ds, ds:[UMB_ARENA] ; es = UMB_HEAD
+ mov ax, ds
+ mov es, ax
+
+ui_next:
+ cmp ax, bx ; Q: is current block above
+ ; new block
+ ja ui_insert ; Y: insert it
+ ; Q: is current block the
+ ; last
+ cmp es:[arena_signature], arena_signature_end
+ jz ui_append ; Y: append new block to chain
+ ; N: get next block
+
+ mov ds, ax ; M005
+ call get_next ; ax = es = next block
+ jmp short ui_next
+
+ui_insert:
+
+ mov cx, ds ; ds = previous arena
+ inc cx ; top of previous block
+
+ sub cx, bx
+ neg cx ; cx = size of used block
+ mov ds:[arena_signature], arena_signature_normal
+ mov ds:[arena_owner], 8 ; mark as system owned
+ mov ds:[arena_size], cx
+ mov word ptr ds:[arena_name], 'CS'
+
+; prepare the arena at start of new block
+
+ mov es, bx
+ mov es:[arena_signature], arena_signature_normal
+ mov es:[arena_owner], arena_owner_system
+ ; mark as free
+ sub dx, 2 ; make room for arena at
+ ; start & end of new block
+ mov es:[arena_size], dx
+
+; prepare arena at end of new block
+
+ add bx, dx
+ inc bx
+ mov es, bx ; es=arena at top of new block
+ inc bx ; bx=top of new block
+
+ ; ax contains arena just above
+ ; this block
+ sub ax, bx ; ax = size of used block
+
+ mov es:[arena_signature], arena_signature_normal
+ mov es:[arena_owner], 8 ; mark as system owned
+ mov es:[arena_size], ax
+ mov word ptr es:[arena_name], 'CS'
+
+ jmp short ui_done
+
+ui_append:
+
+ ; es = arena of last block
+
+ add ax, es:[arena_size] ; ax=top of last block-1 para
+ sub es:[arena_size], 1 ; reflect the space we are
+ ; going to rsrv on top of this
+ ; block for the next arena.
+ mov es:[arena_signature], arena_signature_normal
+
+ mov cx, ax ; cx=top of prev block-1
+ inc ax
+ sub ax, bx ; ax=top of prev block -
+ ; seg. address of new block
+
+ neg ax
+
+ mov es, cx ; ds = arena of unused block
+
+
+ mov es:[arena_signature], arena_signature_normal
+ mov es:[arena_owner], 8 ; mark as system owned
+ mov es:[arena_size], ax
+ mov word ptr es:[arena_name], 'CS'
+
+; prepare the arena at start of new block
+
+ mov es, bx
+ mov es:[arena_signature], arena_signature_end
+ mov es:[arena_owner], arena_owner_system
+ ; mark as free
+ dec dx ; make room for arena
+ mov es:[arena_size], dx
+
+ui_done:
+ pop ds
+ ret
+
+umb_insert endp
+
+
+;
+;----------------------------------------------------------------------------
+;
+;** umb_coalesce - Combine free blocks ahead with current block
+;
+; Coalesce adds the block following the argument to the argument block,
+; iff it's free. Coalesce is usually used to join free blocks, but
+; some callers (such as $setblock) use it to join a free block to it's
+; preceeding allocated block.
+;
+; EXIT 'C' clear if OK
+; (ds) unchanged, this block updated
+; (ax) = address of next block, IFF not at end
+; 'C' set if arena trashed
+; USES cx, di, ds, es
+;
+;----------------------------------------------------------------------------
+;
+
+umb_coalesce proc near
+
+
+
+ xor di, di
+
+ mov es, [DevDOSData]
+ mov es, es:[UMB_ARENA] ; es = UMB_HEAD
+
+uc_nextfree:
+ mov ax, es
+ mov ds, ax
+ cmp es:[arena_owner], di ; Q: is current arena free
+ jz uc_again ; Y: try to coalesce with next block
+ ; N: get next arena
+ call get_next ; es, ax = next arena
+ jc uc_done
+ jmp short uc_nextfree
+uc_again:
+ call get_next ; ES, AX <- next block
+ jc uc_done
+uc_check:
+ cmp es:[arena_owner],di ; Q: is arena free
+ jnz uc_nextfree ; N: get next free arena
+ ; Y: coalesce
+ mov cx,es:[arena_size] ; cx <- next block size
+ inc cx ; cx <- cx + 1 (for header size)
+ add ds:[arena_size],cx ; current size <- current size + cx
+ mov cl,es:[di] ; move up signature
+ mov ds:[di],cl
+ jmp short uc_again ; try again
+uc_done:
+ ret
+
+umb_coalesce endp
+
+;
+;----------------------------------------------------------------------------
+;
+;** get_next - Find Next item in Arena
+;
+; ENTRY dS - pointer to block head
+; EXIT AX,ES - pointers to next head
+; 'C' set iff arena damaged
+;
+;----------------------------------------------------------------------------
+;
+
+get_next proc near
+
+ cmp byte ptr ds:[0], arena_signature_end
+ je gn_err
+
+ mov ax,ds ; ax=current block
+ add ax,ds:[arena_size] ; ax=ax + current block length
+ inc ax ; remember that header!
+ mov es, ax
+ clc
+ ret
+gn_err:
+ stc
+ ret
+
+get_next endp
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : LinkFirstUMB
+;
+;----------------------------------------------------------------------------
+;
+LinkFirstUMB proc near
+
+ call umb_allocate
+ jc lfu_err
+
+; bx = segment of allocated UMB
+; dx = size of UMB
+
+ int 12h ; ax = size of memory
+ mov cl, 6
+ shl ax, cl ; ax = size in paragraphs
+
+ mov cx, ax ; cx = size in paras
+ sub ax, bx ; ax = - size of unused block
+
+ neg ax
+
+ sub cx, 1 ; cx = first umb_arena
+ mov es, cx ; es = first umb_arena
+
+ mov es:[arena_signature], arena_signature_normal
+ mov es:[arena_owner], 8 ; mark as system owned
+
+ mov es:[arena_size], ax
+ mov word ptr es:[arena_name], 'CS'
+
+
+; put in the arena for the first UMB
+
+ mov es, bx ; es has first free umb seg
+ mov es:[arena_signature], arena_signature_end
+ mov es:[arena_owner], arena_owner_system
+ ; mark as free
+ dec dx ; make room for arena
+ mov es:[arena_size], dx
+
+
+ mov es, [DevDOSData]
+ mov di, UMB_ARENA
+ mov es:[di], cx ; initialize umb_head in DOS
+ ; data segment with the arena
+ ; just below Top of Mem
+
+; we must now scan the arena chain and update the size of the last
+; arena
+
+ mov di, DOS_ARENA
+ mov es, word ptr es:[di] ; es = start arena
+ xor di, di
+
+
+scan_next:
+ cmp byte ptr es:[di], arena_signature_end
+ jz got_last
+
+ mov ax, es
+ add ax, es:[arena_size]
+ inc ax
+ mov es, ax
+ jmp short scan_next
+
+got_last:
+;; -williamh- we reserved the last paragraph for UMB_HEAD already.
+;; refer to sysinit1.asm!goinit
+;; The following instruction was commentted out for this reason.
+;; sub es:[arena_size], 1
+;;
+ mov es:[arena_signature], arena_signature_normal
+ clc
+ ret
+
+lfu_err:
+ stc
+ ret
+LinkFirstUMB endp
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : ShrinkUMB
+;
+; Shrinks the current UMB in use, so that the unused portions
+; of the UMB is given back to the DOS free mem pool
+;
+;----------------------------------------------------------------------------
+;
+ public ShrinkUMB
+
+ShrinkUMB proc near
+ cmp DevUMBAddr, 0
+ je su_exit
+ push es
+ push bx
+ mov bx, DevUMBFree
+ sub bx, DevUMBAddr
+ mov es, DevUMBAddr
+ mov ax, 4a00h
+ int 21h
+ mov ax, es
+ dec ax
+ mov es, ax
+ mov word ptr es:[arena_owner], 8
+ pop bx
+ pop es
+su_exit:
+ ret
+ShrinkUMB endp
+
+;M002 - BEGIN
+;
+;----------------------------------------------------------------------------
+;
+; procedure : UnlinkUMB
+;
+; Unlinks the UMBs from the DOS arena chain
+;
+;----------------------------------------------------------------------------
+;
+ public UnlinkUMB
+
+UnlinkUMB proc near
+ push ds
+ push es
+ cmp FirstUMBLinked, 0
+ je ulu_x ; nothing to unlink
+ mov es, DevDOSData ; get DOS data seg
+ mov ds, es:[DOS_ARENA]
+ mov di, es:[UMB_ARENA]
+ulu_next:
+ call get_next
+ jc ulu_x
+ cmp di, ax ; is the next one UMB ?
+ je ulu_found
+ mov ds, ax
+ jmp ulu_next
+ulu_found:
+ mov ds:[arena_signature], 'Z'
+ulu_x:
+ pop es
+ pop ds
+ ret
+UnlinkUMB endp
+
+;M002 - END
+
+; =========================================================================
+;
+sysinitseg ends
+ end
diff --git a/private/mvdm/softpc.new/bios/sysimes.asm b/private/mvdm/softpc.new/bios/sysimes.asm
new file mode 100644
index 000000000..ee958e288
--- /dev/null
+++ b/private/mvdm/softpc.new/bios/sysimes.asm
@@ -0,0 +1,26 @@
+ page ,160
+ ;
+;----------------------------------------------------------------------------
+;
+; Modification history
+;
+; 26-Feb-1991 sudeepb Ported for NT DOSEm
+;----------------------------------------------------------------------------
+
+ include version.inc ; set build flags
+ include biosseg.inc ; establish bios segment structure
+
+sysinitseg segment
+
+ public badopm,crlfm,badsiz_pre,badld_pre,badcom,badcountry
+ public badmem,badblock,badstack
+ public insufmemory,badcountrycom
+ public badorder,errorcmd
+ public badparm
+ public toomanydrivesmsg ;M029
+
+ include msbio.cl3
+
+sysinitseg ends
+ end
+
diff --git a/private/mvdm/softpc.new/bios/sysinit1.asm b/private/mvdm/softpc.new/bios/sysinit1.asm
new file mode 100644
index 000000000..e45d95e34
--- /dev/null
+++ b/private/mvdm/softpc.new/bios/sysinit1.asm
@@ -0,0 +1,4007 @@
+ page ,160
+ title bios system initialization
+;
+;----------------------------------------------------------------------------
+;
+; Modification history
+;
+; 26-Feb-1991 sudeepb Ported for NT DOSEm
+;----------------------------------------------------------------------------
+
+break macro ; dummy empty macro
+ endm
+ include version.inc
+ include biosseg.inc
+ include sysvar.inc
+ include curdir.inc
+ include pdb.inc
+ include exe.inc
+ include sf.inc
+ include arena.inc
+ include syscall.inc
+ include devsym.inc
+ include ioctl.inc
+ include biostruc.inc
+ include dossym.inc
+ include dosmac.inc
+ include mult.inc
+ include dossvc.inc
+ include dbgsvc.inc
+ include cmdsvc.inc
+ include xmssvc.inc
+ include vint.inc
+
+Bios_Code segment
+ extrn BCode_start:near
+ extrn BCode_end:near
+ extrn seg_reinit:far
+
+Bios_Code ends
+
+ include devmark.inc
+ include cputype.inc
+
+
+true equ 0ffffh
+false equ 0
+cr equ 13
+lf equ 10
+tab equ 9
+
+;multMULT equ 4ah
+multMULTGETHMAPTR equ 1
+multMULTALLOCHMA equ 2
+
+
+stacksw equ true ;include switchable hardware stacks
+mycds_size equ 71 ; size of curdir_list. if it is not
+ ;the same, then will generate compile error.
+
+if DEBUG ; BUGBUG - Jeez, remove this!
+ dossize equ 0b200h
+else
+ dossize equ 0a000h
+endif
+
+ if ibmjapver
+noexec equ true
+ else
+noexec equ false
+ endif
+
+; if mycds_size <> curdirlen,then force a compilatiaon error.
+
+ if mycds_size ne curdirlen
+ %out !!! sysinit1 compilation failed. different cds size !!!
+ .errne mycds_size eq curdirlen
+ endif
+
+ if not ibmjapver
+ extrn re_init:far
+ endif
+
+ ifdef TAIWAN
+ extrn cdosinit:near
+ endif
+
+;---------------------------------------
+
+Bios_Data segment
+
+;equates for main stack and stack initialization program
+
+ if stacksw
+
+ extrn NextStack:dword ; Win386 Instance table stuff
+ extrn IT_StackLoc:dword ; we have to plug in so that our
+ extrn IT_StackSize:word ; stacks can be instanced
+
+entrysize equ 8
+
+mincount equ 8
+defaultcount equ 9
+maxcount equ 64
+
+minsize equ 32
+defaultsize equ 128
+maxsize equ 512
+
+allocbyte equ 0
+intlevel equ 1
+savedsp equ 2
+savedss equ 4
+newsp equ 6
+
+free equ 0
+allocated equ 1
+overflowed equ 2
+clobbered equ 3
+
+
+
+
+
+
+; external variables in ibmbio for int19h handling rouitne.
+
+ extrn int19sem:byte
+
+ irp aa,<02,08,09,0a,0b,0c,0d,0e,70,72,73,74,76,77>
+ extrn int19old&aa:dword
+ endm
+ endif
+
+
+;---------------------------------------
+; external variable defined in ibmbio module for multi-track
+multrk_on equ 10000000b ;user spcified mutitrack=on,or system turns
+ ; it on after handling config.sys file as a
+ ; default value,if multrk_flag = multrk_off1.
+multrk_off1 equ 00000000b ;initial value. no "multitrack=" command entered.
+multrk_off2 equ 00000001b ;user specified multitrack=off.
+
+ extrn multrk_flag:word
+;
+;SR; Win386 present flag
+;
+ extrn IsWin386:BYTE
+;
+;SR; Added for SetFocus routine for WIN386 support
+;
+ extrn V86_Crit_SetFocus:far
+
+ extrn xms:dword ; entry point for xms driver
+ extrn inHMA:byte ; flag meaning we're running high
+
+ extrn FreeHMAPtr:word
+ extrn MoveDOSIntoHMA:dword
+ extrn SysinitPresent:byte
+ extrn DemInfoFlag:byte
+ extrn spc_mse_int10:dword
+ extrn int29Perf:dword
+
+ extrn outchr:near
+Bios_Data ends
+
+; NTVDM 16-Sep-1992 Jonle
+; Softpc Kbd, mouse, emm drivers
+SpcKbdSeg segment
+ extrn InstSpcKbd:near
+ extrn SpcKbdBeg:byte
+ extrn SpcKbdEnd:byte
+ extrn int10h_vector:near
+SpcKbdSeg ends
+
+SpcMseSeg segment
+ extrn InstSpcMse:near
+ extrn SpcMseBeg:byte
+ extrn SpcMseEnd:byte
+SpcMseSeg ends
+
+SpcEmmSeg segment
+ extrn InitSpcEmm:near
+ extrn SpcEmmBeg:byte
+ extrn SpcEmmEnd:byte
+ extrn SI_end:byte
+SpcEmmSeg ends
+
+
+
+
+sysinitseg segment
+ assume cs:sysinitseg, ds:nothing,es:nothing,ss:nothing
+
+ extrn badcom:byte
+ extrn condev:byte
+ extrn auxdev:byte
+ extrn prndev:byte
+ extrn commnd:byte
+ extrn devmark_addr:word
+ extrn setdevmarkflag:byte
+ extrn pathstring:byte
+
+ extrn print:near
+ extrn int24:near
+ extrn mem_err:near
+ extrn doconf:near
+ extrn multi_pass:near
+
+ extrn badload:near
+ extrn error_line:near
+
+ extrn ShrinkUMB:near
+ extrn UnlinkUMB:near ;M002
+ extrn AllocUMB:near
+ extrn toomanydrivesmsg:byte ; M029
+
+
+ ;NTVDM
+ extrn MseDev:byte ; internal mouse driver name
+ extrn AllocUMBLow:near ; mem alloc for new internal drivers
+ extrn bEchoConfig:byte
+ extrn config:byte
+
+ public current_dos_location
+ public device_list
+ public sysi_country
+ public memory_size
+ public default_drive
+ public buffers
+ public files
+ public num_cds
+ public sysinit
+ public cntryfilehandle
+ public command_line
+
+ if stacksw ; internal stack information
+ public stack_count
+ public stack_size
+ public stack_addr
+ endif
+
+ public dosinfo
+ public fcbs
+ public keep
+ public confbot
+ public alloclim
+ public zero
+ public sepchr
+ public count
+ public chrptr
+ public org_count
+ public bufptr
+ public memlo
+ public prmblk
+ public memhi
+ public ldoff
+ public area
+ public packet
+ public unitcount
+ public break_addr
+ public bpb_addr
+ public drivenumber
+ public config_size
+ public install_flag
+ public com_level
+ public cmmt
+ public cmmt1
+ public cmmt2
+ public cmd_indicator
+ public linecount
+ public showcount
+ public buffer_linenum
+ public donotshownum
+ public h_buffers
+ public configmsgflag
+ public do_install_exec
+ public multi_pass_id
+ public temp_bcode_seg
+ public seg_reinit_ptr
+
+ public toomanydrivesflag ; M029
+
+sysinit$:
+ if stacksw
+.sall
+
+; interrupt level 2, 3, 4, 5, 6, 7,(10, 11, 12, 14, 15 - at level)
+; should follow the standard interrupt sharing scheme which has
+; a standard header structure.
+; fyi, the following shows the relations between
+; the interrupt vector and interrupt level.
+; vec(hex) 2 8 9 a b c d e 70 72 73 74 76 77
+; lvl(deci) 9 0 1 2 3 4 5 6 8 10 11 12 14 15
+; msstack module modifies the following interrupt vectors
+; to meet the standard interrupt sharing standard;
+; a, b, c, d, e, 72, 73, 74, 76, 77.
+; also, for interrupt level 7 and 15, the firstflag in a standard header
+; should be initialized to indicat whether this interrupt handler is
+; the first (= 80h) or not. the firstflag entry of int77h's
+; program header is initialized in this module.
+; firstflag is only meaningful for interrupt level 7 and 15.
+;
+
+; user specifies the number of stack elements - default = 9
+; minimum = 8
+; maximum = 64
+;
+; intercepts asynchronous hardware interrupts only
+;
+; picks a stack from pool of stacks and switches to it
+;
+; calls the previously saved interrupt vector after pushing flags
+;
+; on return, returns the stack to the stack pool
+;
+
+
+; this is a modification of stacks:
+; 1. to fix a bug which was causing the program to take up too much space.
+; 2. to dispense stack space from hi-mem first rather than low-mem first.
+; . clobbers the stack that got too big instead of innocent stack
+; . allows system to work if the only stack that got too big was the most
+; deeply nested one
+; 3. disables nmi interrupts while setting the nmi vector.
+; 4. double checks that a nested interrupt didn't get the same stack.
+; 5. intercepts ints 70, 72-77 for pc-ats and other future products
+
+ even
+ dw 0 ; spare field but leave these in order
+stackcount dw 0
+stackat dw 0
+stacksize dw 0
+stacks dw 0
+ dw 0
+
+firstentry dw stacks
+lastentry dw stacks+(defaultcount*entrysize)-entrysize
+nextentry dw stacks+(defaultcount*entrysize)-entrysize
+
+
+; these are the individual interrupt handlers
+
+ assume ds:nothing,es:nothing,ss:nothing
+
+public int02
+public old02
+ old02 dd 0
+int02 proc far
+
+;; NTVDM support for pc convertable is NOT NEEDED 10-Aug-1992 Jonle
+;;
+;; *********************************************************************
+;;
+;; this is special support for the pc convertible / nmi handler
+;;
+;; on the pc convertible, there is a situation where an nmi can be
+;; caused by using the "out" instructions to certain ports. when this
+;; occurs, the pc convertible hardware *guarantees* that **nothing**
+;; can stop the nmi or interfere with getting to the nmi handler. this
+;; includes other type of interrupts (hardware and software), and
+;; also includes other type of nmi's. when any nmi has occured,
+;; no other interrtupt (hardware, software or nmi) can occur until
+;; the software takes specific steps to allow further interrupting.
+;;
+;; for pc convertible, the situation where the nmi is generated by the
+;; "out" to a control port requires "fixing-up" and re-attempting. in
+;; otherwords, it is actually a "restartable exception". in this
+;; case, the software handler must be able to get to the stack in
+;; order to figure out what instruction caused the problem, where
+;; it was "out"ing to and what value it was "out"ing. therefore,
+;; we will not switch stacks in this situation. this situation is
+;; detected by interrogating port 62h, and checking for a bit value
+;; of 80h. if set, *****do not switch stacks*****.
+;;
+;; *********************************************************************
+;
+; push ax
+; push es
+; mov ax,0f000h
+; mov es,ax
+; cmp byte ptr es:[0fffeh],mdl_convert ;check if convertible
+; pop es
+; jne normal02
+;
+; in al,62h
+; test al,80h
+; jz normal02
+;
+;special02:
+; pop ax
+; jmp dword ptr old02
+;
+;normal02:
+; pop ax
+;
+
+ call do_int_stacks
+ dw old02
+
+int02 endp
+
+public int08
+public old08
+old08 dd 0
+int08 proc far
+ call do_int_stacks
+ dw old08
+int08 endp
+
+public int09
+public old09
+old09 dd 0
+int09 proc far
+
+; keyboard interrupt must have a three byte jump, a nop and a zero byte
+; as its first instruction for compatibility reasons
+
+ ifidn <09>,<09>
+ jmp short keyboard_lbl
+ nop
+ db 0
+keyboard_lbl label near
+ endif
+
+ call do_int_stacks
+ dw old09
+int09 endp
+
+public int70
+public old70
+old70 dd 0
+int70 proc far
+ call do_int_stacks
+ dw old70
+int70 endp
+
+ irp a,<0a,0b,0c,0d,0e,72,73,74,76,77>
+public int&a
+public old&a
+public firstflag&a
+int&a proc far
+ jmp short entry_int&a&_stk
+old&a dd 0 ;forward pointer
+ dw 424bh ;compatible signature for int. sharing
+firstflag&a db 0 ;the firstly hooked.
+ jmp short intret_&a ;reset routine. we don't care this.
+ db 7 dup (0) ;reserved for future.
+entry_int&a&_stk:
+ call do_int_stacks
+ dw old&a
+intret_&a:
+ jmp DOIRET
+int&a endp
+ endm
+
+
+DOCLI:
+ FCLI
+ ret
+DOSTI:
+ FSTI
+ ret
+DOIRET:
+ FIRET
+
+
+;********************************************************************
+;common routines
+
+; do interrupt stack switching. the fake return address holds
+; a pointer to the far-pointer of the actual interrupt
+; service routine
+
+do_int_stacks:
+ push ax
+ push bp
+ push es
+ mov es, cs:[stacks+2] ; get segment of stacks
+
+ mov bp,nextentry ; get most likely candidate
+ mov al,allocated
+ xchg es:byte ptr allocbyte[bp],al ; grab the entry
+ cmp al,free ; still avail?
+ jne notfree02
+
+ sub nextentry,entrysize ; set for next interrupt
+
+found02:
+ mov es:word ptr savedsp[bp],sp ; save sp value
+ mov es:word ptr savedss[bp],ss ; save ss also
+
+ mov ax,bp ; temp save of table offset
+
+
+ mov bp,es:word ptr newsp[bp] ; get new sp value
+ cmp es:[bp],ax ; check for offset into table
+ jne foundbad02
+
+ push bp
+ mov bp,sp
+ mov ax,8[bp] ; get offset of interrupt vector
+ pop bp
+
+ push es ; ss:sp = new stack
+ pop ss
+ mov sp,bp
+
+ mov bp,ax ; get pointer to interrupt vector
+ mov bp,cs:[bp]
+ pushf ; go execute the real interrupt handler
+ call cs:dword ptr [bp] ; call the old interrupt vector
+
+ mov bp,sp ; retrieve the table offset for us
+ mov bp,es:[bp] ; but leave it on the stack
+ mov ss,es:word ptr savedss[bp] ; get old stack back
+ mov sp,es:word ptr savedsp[bp]
+
+
+ mov es:byte ptr allocbyte[bp],free ; free the entry
+ mov nextentry,bp ; setup to use next time
+
+newerror02:
+ pop es
+ pop bp ; saved on entry
+ pop ax ; saved on entry
+ add sp,2 ; lose the fake return address
+
+intret_02:
+ jmp DOIRET ; done with this interrupt
+
+notfree02:
+ cmp al,allocated ; error flag
+ je findnext02 ; no, continue
+ xchg es:byte ptr allocbyte[bp],al ; yes, restore error value
+
+findnext02:
+ call longpath
+ jmp found02
+
+foundbad02:
+ cmp bp,firstentry
+ jc findnext02
+ mov bp,ax ; flag this entry
+ mov es:byte ptr allocbyte[bp],clobbered
+ jmp findnext02 ; keep looking
+longpath:
+ mov bp,lastentry ; start with last entry in table
+
+lploopp:
+ cmp es:byte ptr allocbyte[bp],free ; is entry free?
+ jne inuse ; no, try next one
+
+ mov al,allocated
+ xchg es:byte ptr allocbyte[bp],al ; allocate entry
+ cmp al,free ; is it still free?
+ je found ; yes, go use it
+
+ cmp al,allocated ; is it other than allocated or free?
+ je inuse ; no, check the next one
+
+ mov es:byte ptr allocbyte[bp],al ; yes, put back the error state
+
+inuse:
+ cmp bp,firstentry
+ je fatal
+ sub bp,entrysize
+ jmp lploopp
+
+found:
+ ret
+
+fatal proc near
+
+; NTVDM support for pc convertable is NOT NEEDED 10-Aug-1992 Jonle
+;
+; push ds
+; mov ax, 0f000h ;look at the model byte
+; mov ds, ax
+; cmp ds:byte ptr [0fffeh], mdl_convert ;convertible?
+; pop ds
+; jne skip_nmis
+;
+; mov al,07h ; disable pc convertible nmis
+; out 72h,al
+;
+;skip_nmis:
+
+ call DOCLI ; disable and mask
+ mov al,0ffh ; all other ints
+ out 021h,al
+ out 0a1h,al
+
+ mov si,cs
+ mov ds,si
+ mov si,offset fatal_msg
+
+;SR;
+; We set all foci to this VM to issue the stack failure message
+;
+ push ax
+ push ds
+ mov ax,Bios_Data
+ mov ds,ax
+ assume ds:Bios_Data
+
+ test ds:[IsWin386],1
+ pop ds
+ pop ax
+ assume ds:nothing
+ jz fatal_loop ;win386 not present, continue
+
+ call V86_Crit_SetFocus ;set focus to this VM
+;
+;SR; We do not bother about the returned status of this call.
+;
+
+fatal_loop:
+ lodsb
+ cmp al,'$'
+ je fatal_done
+
+ mov bl,7
+ mov ah,14
+ int 010h ; whoops, this enables ints
+ jmp fatal_loop
+
+fatal_done:
+ jmp fatal_done
+fatal endp
+
+ include msbio.cl5 ;fatal stack error message
+.xall
+ public endstackcode
+endstackcode label byte
+ endif
+
+sysinit:
+ jmp goinit
+;
+;----------------------------------------------------------------------------
+;
+DDHighInfo struc
+ ddhigh_CSegPtr dd ? ; pointer to code segment to be relocated
+ ddhigh_CSegLen dw ? ; length of code segment to be relocated
+ ddhigh_CallBak dd ? ; pointer to the call back routine
+DDHighInfo ends
+
+ public runhigh
+runhigh db 0h
+
+
+dosinfo dd 0 ; address of the DOS Sysini Variables
+
+dos_temp_location label dword
+dosinit dw 0
+current_dos_location dw 0
+
+device_list dd 0
+
+sysi_country dd 0 ; pointer to country table in dos
+
+dos_segreinit dw 0,0 ; room for dword
+
+lo_doscod_size dw 0 ; dos code size when in low mem
+hi_doscod_size dw 0 ; dos code size when in HMA
+
+def_php dw 0
+
+
+; M022--
+; pointer for calling into Bios_Code for re-initializing segment values.
+; call with ax = new segment for Bios_Code. Notice that we'll
+; call it in its temporary home, cuz seg_reinit won't get moved to
+; the new home.
+
+seg_reinit_ptr label dword
+
+ dw offset Bios_Code:seg_reinit
+temp_bcode_seg dw Bios_Code
+
+
+;variables for stack initialization program.
+
+ if stacksw
+stack_count dw defaultcount
+stack_size dw defaultsize
+stack_addr dd 0
+ endif
+
+; various default values
+
+memory_size dw 1
+RPLMemTop dw 0
+default_drive db 0 ;initialized by ibminit.
+buffers dw -1 ; initialized during buffer allocation
+h_buffers dw 0 ; # of the heuristic buffers. initially 0.
+singlebuffersize dw ? ; maximum sector size + buffer header
+
+files db 8 ; enough files for pipe
+fcbs db 4 ; performance for recycling
+keep db 0 ; keep original set
+num_cds db 1 ; minimum needed is 1, so that initialization does'nt have a problem
+confbot dw ?
+alloclim dw ?
+DirStrng db "A:\",0 ; string for the root directory of a drive
+command_line db 2,0,"P" ;default command.com args
+ db 125 dup (0)
+zero db 0
+sepchr db 0
+linecount dw 0 ; line count in config.sys
+showcount db ' ',cr,lf,'$' ; used to convert linecount to ascii.
+buffer_linenum dw 0 ; line count for "buffers=" command if entered.
+
+
+buf_prev_off dw 0
+
+ if not noexec
+comexe exec0 <0,command_line,default_drive,zero>
+ endif
+
+;------------------------------------------------------------------
+; variables for install= command.
+
+multi_pass_id db 0 ; parameter passed to multi_pass
+ ; indicating the pass number
+ ; 0 - do scan for DOS=HIGH/LOW
+ ; 1 - load device drivers
+ ; 2 - was to load IFS
+ ; now it is unused
+ ; 3 - do install=
+ ; >3 - nop
+install_flag dw 0
+
+have_install_cmd equ 00000001b ; config.sys has install= commands
+has_installed equ 00000010b ; sysinit_base installed.
+
+config_size dw 0 ; size of config.sys file. set by sysconf.asm
+sysinit_base_ptr dd 0 ; pointer to sysinit_base
+sysinit_ptr dd 0 ; returning addr. from sysinit_base
+checksum dw 0 ; used by sum_up
+
+ldexec_fcb db 20 dup (' ') ;big enough
+ldexec_line db 0 ;# of parm characters
+ldexec_start db ' '
+ldexec_parm db 80 dup (0)
+
+instexe exec0 <0,ldexec_line,ldexec_fcb,ldexec_fcb>
+
+;------------------------------------------------------------------
+;variables for comment=
+
+com_level db 0 ;level of " " in command line
+cmmt db 0 ;length of comment string token
+cmmt1 db 0 ;token
+cmmt2 db 0 ;token
+cmd_indicator db ?
+donotshownum db 0
+
+;------------------------------------------------------------------
+count dw 0
+org_count dw 0
+chrptr dw 0
+cntryfilehandle dw 0
+old_area dw 0
+impossible_owner_size dw 0 ; paragraph
+;------------------------------------------------------------------
+
+bucketptr label dword
+bufptr label dword ;leave this stuff in order!
+memlo dw 0
+prmblk label word
+memhi dw 0
+ldoff dw 0
+area dw 0
+
+packet db 24 ; was 22
+ db 0
+ db 0 ;initialize code
+ dw 0
+ db 8 dup (?)
+
+unitcount db 0
+break_addr dd 0
+bpb_addr dd 0
+drivenumber db 0
+configmsgflag dw 0 ; used to control "error in config.sys line #" message
+
+toomanydrivesflag db 0 ;>24 fixed disk partitions flag ; M029
+
+BCodeSeg dw Bios_Code
+
+
+
+
+;SR;
+; This is the communication block between the DOS and the BIOS. It starts at
+;the SysinitPresent flag. Any other data that needs to be communicated
+;to the DOS should be added after SysinitPresent. The pointer to this block
+;is passed to DOS as part of the DOSINIT call.
+;
+
+BiosComBlock dd Bios_Data:SysinitPresent
+
+tempstack db 80h dup (?)
+
+goinit:
+
+ifdef JAPAN
+ mov ah,50h ; set crt mode
+ mov al,0
+ mov bx,81 ; for JAPAN
+ int 10h
+ mov ah,50h ; set keyboard mode
+ mov al,0
+ mov bx,81 ; for JAPAN
+ int 16h
+endif
+ cld
+
+;; Before we installed spckbd.asm (we hook a lot of vectors there),
+;; we shouldn't invoke any interrupt calls directly to bios(they will
+;; go directly to ROM bios). Since we do know what exactly those ROM
+;; bios(s) do, a safer manner is to issue bop to our 32 bits side.
+;; int 12h ; Get Memory in 1k
+ BOP 12h
+ mov cl,6
+ shl ax,cl ;convert to 16-byte blocks(segment no.)
+ mov cx,ax
+ dec cx ; one para for an arena at end of mem
+ ; in case of UMBs
+ mov memory_size,cx
+
+ push cs
+ pop ds
+ xor si,si
+ mov di,si
+ mov ax, offset sysinitgrp:SI_end ; need this much room for sysinit
+ call off_to_para
+ sub cx,ax
+
+; we need to leave room for the DOS and for the BIOS
+; code above sysinit in memory
+;
+ sub cx,dossize/16 ; leave this much room for DOS
+
+ mov ax,offset BCode_end
+ call off_to_para ; leave this much room for BIOS code
+ sub cx,ax
+
+ mov es,cx ; offset where sysinit will be located
+ mov cx,offset sysinitgrp:SI_end
+ shr cx,1 ;divide by 2 to get words
+ rep movsw ;relocate sysinit
+
+ push es ; push relocated segment
+ mov ax,offset sysin
+ push ax ; push relocated entry point
+
+ retf ; far jump to relocated sysinit
+
+
+; move the dos to its proper location
+
+sysin:
+ assume ds:nothing,es:nothing,ss:nothing
+
+ mov ax, Bios_Data ; point DS to BIOS data
+ mov ds, ax
+
+ assume ds:Bios_Data
+
+ mov word ptr MoveDOSIntoHMA+2, cs ; set seg of routine to move DOS
+ mov SysinitPresent, 1 ; flag that MoveDOSIntoHMA can be called
+
+ SVC SVC_ISDEBUG
+ mov DemInfoFlag, al
+
+ test al,ISDBG_DEBUGGEE
+ je @f
+ SAVEREG <bx,dx,es>
+ mov bx, cs ; current base of BIOS
+ xor cx, cx
+ mov dx, current_dos_location; get offset of end of code
+ sub dx, bios_data ; add in length of data segment
+ REPT 4
+ shl dx, 1
+ rcl cx, 1
+ endm
+
+ mov ax, SYMOP_LOAD SHL 8 + ID_NTIO
+ SVC SVC_DEMSYSTEMSYMBOLOP
+
+ mov bx, 1 ; bugbug: Hardcoded segment number
+ mov ax, ds ; low segment location
+ mov es, ax ; relocated segment
+
+ mov ax, SYMOP_MOVE SHL 8 + ID_NTIO
+ SVC SVC_DEMSYSTEMSYMBOLOP
+
+ RESTOREREG <es,dx,bx>
+@@:
+
+; first move the MSDOS.SYS image up to a harmless place
+; on top of our new sysinitseg
+
+ mov ax,offset sysinitgrp:SI_end ; how big is sysinitseg?
+ call off_to_para
+ mov cx,cs ; pick a buffer for msdos above us
+ add ax,cx
+ mov es,ax
+ xor si,si
+ mov di,si
+
+ mov ds,[current_dos_location] ; where it is (set by msinit)
+
+ assume ds:nothing
+
+ mov cx,dossize/2
+ rep movsw
+ mov [current_dos_location],es
+
+; The DOS code is ORGed at a non-zero value to allow it to be located in
+; HIMEM. Thus, the DOS segment location must be adjusted accordingly.
+
+ mov ax,ds:word ptr 3 ; get offset of dos
+ mov [dosinit],ax ; that's the entry point offset
+ call off_to_para ; subtract this much from segment
+ sub [current_dos_location],ax
+
+
+; BIOS code is moved to the top of memory
+; until it is determined whether it will be running in HIMEM or not.
+
+
+; now put Bios_Code up on top of that. Assume Bios_Code + dossize < 64k
+
+ mov ax,es
+ add ax,dossize/16 ; get paragraph of end of dos
+ mov es,ax
+ xchg ax,temp_bcode_seg ; swap with original home of Bios_Code
+ mov ds,ax ; point to loaded image of Bios_Code
+
+ assume ds:nothing
+
+ mov si,offset BCode_start
+ mov di,si
+ mov cx,offset BCode_end
+ sub cx,si
+ shr cx,1
+ rep movsw ; move Bios_Code into place
+
+ mov ax,es ; tell it what segment it's in
+ call [seg_reinit_ptr] ; far call to seg_reinit in Bios_Code (M022)
+
+
+; now call dosinit while it's in its temporary home
+
+ les di,cs:[BiosComBlock] ; ptr to BIOS communication block
+ lds si,cs:[device_list] ; set for call to dosinit
+
+ assume ds:nothing, es:nothing
+
+ mov dx,cs:[memory_size] ; set for call to dosinit
+
+ call DOCLI
+ mov ax,cs
+ mov ss,ax
+ align 2 ; assembler wouldn't let me do an "and 0fffeh"
+locstack label byte ; on the mov sp,offset locstack
+ mov sp,offset locstack ; set stack
+
+ call DOSTI
+
+
+; This call to DOSINIT will relocate the DOS data from its present location
+; at the top of memory, to its final location in low memory just above the
+; BIOS data. It will then build important DOS data structures in low
+; memory following the DOS data. It returns (among many other things) the
+; new starting address of free memory.
+
+ call [dos_temp_location] ; call dosinit
+ ;es:di -> sysinitvars_ext
+
+ mov [def_php],ds ; save pointer to PSP
+ mov [hi_doscod_size],ax ; size of doscode (including exepatch)
+ mov [lo_doscod_size],cx ; (not including exepatch)
+ mov [dos_segreinit],dx ; save offset of segreinit
+
+ mov ax,word ptr es:[di.sysi_initvars]
+ mov word ptr dosinfo,ax
+ mov ax,word ptr es:[di.sysi_initvars+2]
+ mov word ptr [dosinfo+2],ax ;set the sysvar pointer
+
+ mov ax,word ptr es:[di.sysi_country_tab]
+ mov word ptr [sysi_country],ax
+ mov ax,word ptr es:[di.sysi_country_tab+2]
+ mov word ptr [sysi_country+2],ax ;set the sysi_country pointer
+
+ mov es,[current_dos_location] ; give dos its temporary loc.
+ mov [dos_segreinit+2],es
+;
+ les di,dosinfo ;es:di -> dosinfo
+
+ clc ;get the extended memory size
+
+; execute the get extended memory size subfunction in the bios int 15h
+; if the function reports an error do nothing else store the extended
+; memory size reported at the appropriate location in the dosinfo buffer
+; currently pointed to by es:di. use the offsets specified in the
+; definition of the sysinitvars struct in inc\sysvar.inc
+
+ mov ah,88h
+;; IBM ps/2 90 int 15(ah = 88h) read a coms byte(0B6h) which we don't support.
+;; it returns 0 on this query.
+;; we issue a bop to 32bits to get the real extended memeory size
+;; int 15h ;check extended memory size
+ BOP 15h
+;; jc no_ext_memory
+ mov es:[di].sysi_ext_mem,ax ;save extended memory size
+;; or ax, ax
+no_ext_memory:
+ mov ax,es:[di.sysi_maxsec] ; get the sector size
+ add ax,bufinsiz ; size of buffer header
+ mov [singlebuffersize],ax ; total size for a buffer
+
+ SVC SVC_DEMGETBOOTDRIVE
+ mov [default_drive],al
+ mov es:[di.sysi_boot_drive],al ; set sysi_boot_drive
+
+; determine if 386 system...
+if 1
+ get_cpu_type ; macro to determine cpu type
+ cmp ax,2 ; is it a 386?
+ jne not_386_system ; no: don't mess with flag
+endif
+
+ mov es:[di.sysi_dwmove],1
+not_386_system:
+ mov al,es:[di.sysi_numio]
+ mov drivenumber,al ; save start of installable block drvs
+
+ mov ax,cs
+ sub ax,11h ; room for PSP we will copy shortly
+ mov cx,[singlebuffersize] ; temporary single buffer area
+ shr cx,1
+ shr cx,1 ; divide size by 16...
+ shr cx,1
+ shr cx,1 ; ...to get paragraphs...
+ inc cx ; ... and round up
+
+; cas note: this unorthodox paragraph rounding scheme wastes a byte if
+; [singlebuffersize] ever happens to be zero mod 16. Could this
+; ever happen? Only if the buffer overhead was zero mod 16, since
+; it is probably safe to assume that the sector size always will be.
+;
+; mohans also found a bug in CONFIG.SYS processing where it replaces
+; EOF's with cr,lf's, without checking for collision with [confbot].
+; perhaps the extra byte this code guarantees is what has kept that
+; other code from ever causing a problem???
+
+ sub ax,cx
+ mov [confbot],ax ; temp "unsafe" location
+; push es ; preserve pointer to DOSINFO data
+; push di
+
+; setup and initialize the temporary buffer
+
+; les di,es:[di.sysi_buf] ;get the buffer chain entry pointer
+; mov word ptr es:[di.Dirty_Buff_Count],0
+; mov word ptr es:[di.Buff_Queue],0
+; mov word ptr es:[di.Buff_Queue+2],ax
+; mov es,ax
+; xor ax,ax
+; mov di,ax ;es:di -> single buffer
+
+; mov es:[di.buf_next],ax ;points to itself
+; mov es:[di.buf_prev],ax ;points to itself
+
+; mov word ptr es:[di.buf_id],00ffh ;free buffer,clear flag
+; mov word ptr es:[di.buf_sector],0
+; mov word ptr es:[di.buf_sector+2],0
+
+; pop di ; restore pointer to DOSINFO data
+; pop es
+
+ push cs
+ pop ds
+
+ assume ds:sysinitseg
+
+ call tempcds ; set up cdss so re_init and sysinit
+ ; can make disk system calls
+ assume ds:nothing ; tempcds trashes ds
+
+ mov ds,[def_php] ; retreive pointer to PSP returned by DOSINIT
+
+ if not ibmjapver
+ call re_init ; re-call the bios
+ endif
+
+ call DOSTI ; ints ok
+ cld ; make sure
+
+; dosinit has set up a default "process" (php) at ds:0. we will move it out
+; of the way by putting it just below sysinit at end of memory.
+
+ mov bx,cs
+ sub bx,10h
+ mov es,bx
+ xor si,si
+ mov di,si
+ mov cx,80h
+ rep movsw
+
+ mov word ptr es:[pdb_jfn_pointer + 2],es ; relocate
+ mov ah,set_current_pdb
+ int 21h ; tell dos we moved it
+
+ push ds ; preserve DS returned by DOSINIT
+ push cs
+ pop ds ; point DS to sysinitseg
+
+ assume ds:sysinitseg
+
+ ; set up temp. critical error handler
+ mov dx,offset int24 ;set up int 24 handler
+ mov ax,(set_interrupt_vector shl 8) or 24h
+ int 21h
+
+ cmp byte ptr [TooManyDrivesFlag],0 ;Q: >24 partitions? M029
+ je no_err ; N: continue M029
+ mov dx,offset TooManyDrivesMsg ; Y: print error message M029
+ call print ; M029
+no_err: ; M029
+
+ pop ds ; start of free memory
+
+ assume ds:nothing
+
+ mov dl,[default_drive]
+ or dl,dl
+ jz nodrvset ; bios didn't say
+ dec dl ; a = 0
+ mov ah,set_default_drive
+ int 21h ;select the disk
+
+nodrvset:
+
+;
+; Process the CONFIG.SYS file
+;
+
+ProcessConfig:
+
+;
+; NTVDM store temp file name for config.sys, 23-Nov-1992 Jonle
+;
+ push ds
+ push cs
+ pop ds
+ assume ds:sysinitseg
+ mov dx,offset config ; ds:dx points file description
+ CMDSVC SVC_GETCONFIGSYS
+ pop ds
+ assume ds:nothing
+
+
+ifndef TAIWAN
+
+ call doconf ;do pre-scan for dos=high/low
+
+else ; taiwan
+
+ call chkoemlocaldrv
+ mov cs:oemdriverinst,ax
+ call cdosinit
+ push es
+ push bx
+
+ pop bx
+ pop es
+ call maketempvector ;make dummy int service routine
+
+ call doconf ;do pre-scan for dos=high/low
+
+ call chklocalexist ;check if local dev drv exist
+ ;if not found,system halt
+ call recovercsiint ;recover csi interrupt vector
+endif ; taiwan
+
+
+
+; Now, we decide what to do with the DOS code.
+; It will either be relocated to low memory, above the DOS data structures,
+; or else it will be located in HiMem, in which case a stub with the DOS
+; code entry points will be located in low memory. Dos_segreinit is used
+; to tell the DOS data where the code has been placed, and to install the
+; low memory stub if necessary. If the DOS is going to go into HiMem, we
+; must first initialize it in its present location and load the installable
+; device drivers. Then, if a HiMem driver has been located, we can actually
+; relocate the DOS code into HiMem.
+;
+
+; M025 begin
+
+ cmp runhigh, 0 ; Did user choose to run low ?
+ je dont_install_stub ; yes, don't install dos low mem stub
+;
+;------ user chose to load high
+;
+
+
+ mov es,[current_dos_location] ; give dos its temporary loc.
+
+ xor ax,ax ; ax = 00 ---> install stub
+ call cs:dword ptr [dos_segreinit] ; call dos segreinit
+ jmp short do_multi_pass
+
+;
+;------ User chose to load dos low
+;
+dont_install_stub:
+
+ xor bx, bx ; M012
+ ; don't use int 21 call to alloc mem
+
+ call MovDOSLo ; move it !
+
+
+ mov ax, 1 ; dont install stub
+ mov es, current_dos_location; set_dos_final_position set it up
+ call dword ptr dos_segreinit ; inform dos about new seg
+
+
+do_multi_pass:
+
+ call AllocFreeMem ; allocate all the free mem
+ ; & update [memhi] & [area]
+ ; start of free memory.
+
+; M025 end
+
+
+
+; NTVDM
+; Copy softpc keyboard driver resident code to start of free mem
+; Install Softpc IVT hooks
+ mov al,devmark_spc
+ call setdevmark
+ mov es, cs:[devmark_addr]
+ mov word ptr es:[arena_name], 'BK'
+ mov word ptr es:[arena_name+2], 'D'
+
+ cld
+ mov ax,[memhi]
+ push ds
+ mov cx,Bios_Data
+ mov ds,cx
+ assume ds:Bios_Data
+ mov word ptr spc_mse_int10,offset int10h_vector
+ mov word ptr spc_mse_int10+2,ax
+ mov word ptr int29Perf,offset outchr ; sudeepb 03-Nov-1992
+ mov word ptr int29Perf+2,ds ; added for int10 performance
+ pop ds
+ assume ds:nothing
+
+ mov es,ax ;es dest seg. for SpcKbd
+ push es
+ push cs
+ pop ds ;ds src seg for SpcKbd
+ mov si,offset sysinitgrp:SpcKbdBeg
+ mov cx,offset sysinitgrp:SpcKbdEnd
+ sub cx,si
+ xor di,di
+ mov [memlo],cx
+ or [setdevmarkflag],for_devmark
+ call round
+ rep movsb
+ pop ds
+ call sysinitgrp:InstSpcKbd
+
+ ; save value of int09 for int 09 hardware stack disable
+ xor ax,ax
+ mov ds,ax
+ mov si, 09h*4
+ lodsw
+ mov word ptr cs:old09, ax
+ lodsw
+ mov word ptr cs:old09+2, ax
+
+ ; save value of int08 for int 08 hardware stack disable
+ mov si, 08h*4
+ lodsw
+ mov word ptr cs:old08, ax
+ lodsw
+ mov word ptr cs:old08+2, ax
+
+
+; NTVDM
+; Attempt to init emm memory manager. if we have emm
+; then load internal emm stub device driver.
+;
+ ; check if emm memory is available
+ mov ax, [memhi]
+ inc ax ;1 para for arena header
+ mov ds, ax ;expected seg for emm drv
+ call sysinitgrp:InitSpcEmm
+ cmp ax, 0
+ jne NoEmmServices
+
+ ; fill in the arena name
+ mov al, devmark_device
+ call setdevmark
+ mov es, cs:[devmark_addr]
+ mov word ptr es:[arena_name], 'ME'
+ mov word ptr es:[arena_name+2], 'M'
+
+ ; copy in emm stub driver code
+ cld
+ mov ax,[memhi]
+ mov es,ax
+ push es ;save for diddling devheader
+ push cs
+ pop ds
+ mov si,offset sysinitgrp:SpcEmmBeg
+ mov cx,offset sysinitgrp:SpcEmmEnd
+ sub cx,si
+ xor di,di
+ mov [memlo],cx
+ or [setdevmarkflag],for_devmark
+ call round
+ rep movsb
+
+ ; link in emm stub driver
+ ; so apps can find emm driver
+ pop ds
+ xor si, si ;ds:si = device header
+ les di, cs:[dosinfo] ;es:di = to dos info
+ mov cx,word ptr es:[di.sysi_dev] ;dx:cx = head of list
+ mov dx,word ptr es:[di.sysi_dev+2]
+ mov word ptr es:[di.sysi_dev],si ;set head of list in dos
+ mov word ptr es:[di.sysi_dev+2],ds
+ mov word ptr ds:[si], cx ;link in the driver
+ mov word ptr ds:[si+2], dx
+
+NoEmmServices:
+
+
+; Now, process config.sys some more.
+; Load the device drivers and install programs
+ inc cs:multi_pass_id ; multi_pass_id = 1
+ call multi_pass ; load device drivers
+
+
+; NTVDM
+; Install Softpc Mouse driver in UMB if can else in LOW memory
+; This must be done after himem.sys is loaded for umb support
+;
+ mov cx, offset sysinitgrp:SpcMseEnd
+ sub cx, offset sysinitgrp:SpcMseBeg ; cx, size of SpceMse
+ mov di, offset MseDev
+ push cs
+ pop es ; es:di, dest
+ push cx ; preserve cx
+ call AllocUMBLow
+ pop cx
+ push es ; save to pass to InstSpcMse
+
+ mov si, offset sysinitgrp:SpcMseBeg
+ push cs
+ pop ds ; ds:si, Source of SpcMse code
+ rep movsb
+
+ pop ds
+ call sysinitgrp:InstSpcMse
+
+
+
+ call ShrinkUMB
+ call UnlinkUMB ; unlink all UMBs ;M002
+ inc cs:multi_pass_id ; multi_pass_id = 2
+ call multi_pass ; was load ifs (now does nothing)
+ call endfile ; setup fcbs, files, buffers etc
+
+;
+;Reset SysinitPresent flag here. This is needed for the special fix for lying
+;to device drivers. This has been moved up to this point to avoid problems
+;with overlays called from installed programs
+;
+ mov ax,Bios_Data
+ mov es,ax ; point ES to bios data
+
+ assume es:Bios_Data
+
+ mov es:SysinitPresent,0 ; clear SysinitPresent flag
+
+ test install_flag,have_install_cmd ; are there install commands?
+ jz dolast ; no, no need for further processing
+ inc cs:multi_pass_id ; mult_pass_id = 3
+ call multi_pass ; execute install= commands
+dolast:
+ assume es:nothing
+
+; [area] has the segment address for the allocated memory of sysinit, confbot.
+; free the confbot area used for config.sys and sysinit itself.
+
+
+; Now if DOS is supposed to run high, we actually move it into high memory
+; (if HiMem manager is available).
+;
+; There is also this little hack for CPM style DOS calls that needs to
+; be done when A20 is set...
+
+ cmp runhigh, 0ffh ; are we still waiting to be moved?
+ jne @f ; no, our job is over
+ call LoadDOSHiOrLo
+@@:
+
+ cmp runhigh, 0 ; are we running low
+ je @f ; yes, no CPM hack needed
+ call CPMHack ; make ffff:d0 same as 0:c0
+@@:
+
+
+; We are now done with CONFIG.SYS processing
+
+ConfigDone:
+;; let NTVDM knows that we have done config.sys processing
+ xor al, al ;config.sys done
+ BOP BOP_NOTIFICATION ;
+ call AllocUMB ; allocate remaining UMBs if there are any
+ mov cs:[donotshownum],1 ; done with config.sys. do not show line number message.
+ mov es,[area]
+
+ assume es:nothing
+
+ mov ah,49h ; free allocated memory for command.com
+ int 21h
+
+ test cs:[install_flag],has_installed ; sysinit_base installed?
+ jz skip_free_sysinitbase ; no.
+
+;set block from the old_area with impossible_owner_size.
+;this will free the unnecessary sysinit_base that had been put in memory to
+;handle install= command.
+
+ push es
+ push bx
+ mov es,cs:[old_area]
+ mov bx,cs:[impossible_owner_size]
+ mov ah,setblock
+ int 21h
+ mov ax,es
+ dec ax
+ mov es,ax ;point to arena
+ mov es:[arena_owner],8 ;set impossible owner
+ mov word ptr es:[arena_name], 'DS' ; System Data
+ pop bx
+ pop es
+
+skip_free_sysinitbase:
+
+if noexec
+ mov bp,ds ;save command.com segment
+ push ds
+ pop es
+ mov bx,cs
+ sub bx,10h ; point to current php
+ mov ds,bx
+ xor si,si
+ mov di,si
+ mov cx,80h
+ rep movsw ; copy it to new location for shell
+ mov word ptr es:[pdb_jfn_pointer + 2],es ; relocate
+ mov bx,es
+ mov ah,set_current_pdb
+ int 21h ; tell dos we moved it
+ mov es:[pdb_parent_pid],es ;we are the root
+endif ; noexec
+
+ push cs
+ pop ds ; point DS to sysinitseg
+
+ assume ds:sysinitseg
+
+; set up the parameters for command
+
+ mov si,offset command_line+1
+
+if noexec
+ mov di,81h
+else
+ push ds
+ pop es
+ mov di,si
+endif
+
+ mov cl,-1
+comtranlp: ;find length of command line
+ inc cl
+ lodsb
+ stosb ;copy command line in
+ or al,al
+ jnz comtranlp
+ dec di
+ mov al,cr ; cr terminate
+ stosb
+
+if noexec
+ mov es:[80h],cl ; set up header
+ mov al,[default_drive]
+ mov es:[5ch],al
+else
+ mov [command_line],cl ;count
+endif
+
+ mov dx,offset commnd ;now pointing to file description
+
+
+if noexec
+ mov es,bp ;set load address
+ mov bx,100h
+ call dfil ;read in command
+ jc comerr
+ mov ds,bp
+ mov dx,80h
+ mov ah,set_dma ;set disk tranfer address
+ int 21h
+ call DOCLI
+ mov ss,bp
+ mov sp,dx
+ call DOSTI
+ xor ax,ax ;push a word of zeros
+ push ax
+ push bp ;set high part of jump address
+ mov ax,100h
+ push ax ;set low part of jump address
+ retf ;crank up command!
+
+else ; not noexec
+
+; we are going to open the command interpreter and size it as is done in
+; ldfil. the reason we must do this is that sysinit is in free memory. if
+; there is not enough room for the command interpreter,exec will probably
+; overlay our stack and code so when it returns with an error sysinit won't be
+; here to catch it. this code is not perfect (for instance .exe command
+; interpreters are possible) because it does its sizing based on the
+; assumption that the file being loaded is a .com file. it is close enough to
+; correctness to be usable.
+
+ push dx ; save pointer to name
+
+; first, find out where the command interpreter is going to go.
+
+ mov bx,0ffffh
+ mov ah,alloc
+ int 21h ;get biggest piece
+ mov ah,alloc
+ int 21h ; second time gets it
+ jc memerrjx ; oooops
+
+ mov es,ax
+ mov ah,dealloc
+ int 21h ; give it right back
+ mov bp,bx
+
+; es:0 points to block,and bp is the size of the block
+; in para.
+
+; we will now adjust the size in bp down by the size of sysinit. we
+; need to do this because exec might get upset if some of the exec
+; data in sysinit is overlayed during the exec.
+
+ mov bx,[memory_size] ; get location of end of memory
+ mov ax,cs ; get location of beginning of sysinit
+ sub bx,ax ; bx is size of sysinit in para
+ add bx,11h ; add the sysinit php
+ sub bp,bx ; sub sysinit size from amount of free memory
+ jc memerrjx ; if there isn't even this much memory, give up
+
+ mov ax,(open shl 8) ;open the file being execed
+ stc ;in case of int 24
+ int 21h
+ jc comerr ; ooops
+
+ mov bx,ax ;handle in bx
+ xor cx,cx
+ xor dx,dx
+ mov ax,(lseek shl 8) or 2
+ stc ;in case of int 24
+ int 21h ; get file size in dx:ax
+ jc comerr
+ ; convert size in dx:ax to para in ax
+ add ax,15 ; round up size for conversion to para
+ adc dx,0
+ call off_to_para
+ mov cl,12
+ shl dx,cl ; low nibble of dx to high nibble
+ or ax,dx ; ax is now # of para for file
+ add ax,10h ; 100h byte php
+ cmp ax,bp ; will command fit in available mem?
+ jb okld ; jump if yes.
+memerrjx:
+ jmp mem_err
+
+okld:
+ mov ah,close
+ int 21h ; close file
+
+ pop dx ; recover pointer to name
+ push cs ; point es to sysinitseg
+ pop es
+ mov bx,offset comexe ; point to exec block
+ mov word ptr [bx.exec0_com_line+2],cs ; set segments
+ mov word ptr [bx.exec0_5c_fcb+2],cs
+ mov word ptr [bx.exec0_6c_fcb+2],cs
+ xor ax,ax ;load and go
+ mov ah,exec
+ stc ;in case of int 24
+ int 21h ;go start up command
+ endif
+
+; note fall through if exec returns (an error)
+
+comerr:
+ mov dx,offset badcom ;want to print command error
+ extrn badfil:near
+ call badfil
+ public stall
+stall: SVC SVC_DEMEXITVDM ; Will Kill The VDM
+
+;
+;----------------------------------------------------------------------------
+; procedure : AllocFreeMem
+;
+; Allocate Max memory from DOS to find out where to load DOS.
+; DOS is at temporary location when this call is being made
+;
+; Inputs : None
+; Outputs: The biggest chunk of memory is allocated (all mem at init time)
+; [area] & [memhi] set to the para value of the start of the
+; free memory.
+;
+; Uses : AX, BX
+;
+;----------------------------------------------------------------------------
+;
+AllocFreeMem proc near
+
+ assume es:nothing, ds:nothing
+ mov bx,0ffffh
+ mov ah,alloc
+ int 21h ;first time fails
+ mov ah,alloc
+ int 21h ;second time gets it
+ mov [area],ax
+ mov [memhi],ax ; memhi:memlo now points to
+ ret
+ ; start of free memory
+AllocFreeMem endp
+
+; start M000
+ include msbio.cl6
+; end M000
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : LoadDOSHiOrLo
+;
+; Tries to move DOS into HMA. If it fails then loads
+; DOS into Low memory.
+;
+;----------------------------------------------------------------------------
+;
+
+LoadDOSHiOrLo proc near
+ call TryToMovDOSHi ; Try moving it into HMA (M024)
+ jc LdngLo ; If that don't work...
+ ret
+LdngLo:
+ push cs
+ pop ds
+ mov ah, 9
+ mov dx, offset DOSLOMSG ; inform user that we are
+ int 21h ; loading low
+
+ ; actually move the dos, and reinitialize it.
+
+ mov bx, 1 ; M012
+ ; use int 21 alloc for mem
+ call MovDOSLo
+ mov es,[current_dos_location] ; give dos its temporary loc.
+ xor ax,ax ; ax = 00 ---> install stub
+ call cs:dword ptr [dos_segreinit] ; call dos segreinit
+
+ mov runhigh, 0 ; mark that we are running lo
+ ret
+LoadDOSHiOrLo endp
+
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : TryToMovDOSHi
+;
+; This tries to move DOS into HMA.
+; Returns CY if it failed.
+; If it succeeds returns with carry cleared.
+;
+;
+;----------------------------------------------------------------------------
+;
+
+ public TryToMovDOSHi
+
+TryToMovDOSHi proc near
+ call MovDOSHi
+ jc ttldhx
+
+
+ mov es,[current_dos_location] ; give dos its temporary loc.
+
+ xor ax,ax ; ax = 00 ---> install stub
+ call cs:dword ptr [dos_segreinit] ; call dos segreinit
+
+ mov runhigh, 1
+ clc
+ttldhx:
+ ret
+TryToMovDOSHi endp
+
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : MovDOSHi
+;
+; Tries to allocate HMA and Move DOS/BIOS code into HMA
+;
+; Returns : CY if it failed
+;
+;----------------------------------------------------------------------------
+;
+
+MovDOSHi proc near
+ call AllocHMA
+ jc mdhx ; did we get HMA?
+ mov ax, 0ffffh ; yes, HMA seg = 0ffffh
+ mov es, ax
+
+ ; actually move the BIOS and DOS
+
+ call MovBIOS ; First move BIOS into HMA
+
+ ; ES:DI points to free HMA after BIOS
+
+ mov cx, hi_doscod_size ; pass the code size of DOS
+ ; when it is in HMA
+ call MovDOS ; and move it
+
+ ; ES:DI points to free HMA after DOS
+
+ call SaveFreeHMAPtr ; Save the Free HMA ptr
+ clc
+mdhx:
+ ret
+MovDOSHi endp
+
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : MovDOSLo
+;
+; Allocates memory from DOS and moves BIOS/DOS code into it
+;
+;----------------------------------------------------------------------------
+;
+
+
+MovDOSLo proc near
+ call AllocMemForDOS ; incestuosly!!!
+ mov es, ax ; pass the segment to MovBIOS
+ call MovBIOS
+;
+;------ ES:DI points memory immediately after BIOS
+;
+ mov cx, lo_doscod_size ; DOS code size when loaded
+ ; low
+ call MovDOS
+ ret
+MovDOSLo endp
+
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : MovBIOS
+;
+; Moves BIOS code into requested segment
+;
+; In : ES - segment to which BIOS is to be moved
+; ( it moves always into offset BCode_Start)
+;
+; Out : ES:DI - pointer to memory immediately after BIOS
+;
+;----------------------------------------------------------------------------
+;
+
+
+MovBIOS proc near
+ mov ds, temp_bcode_seg ; current BIOS code seg
+ mov si, offset BCode_Start
+ mov di, si
+ mov cx, offset BCode_End
+ sub cx, si ; size of BIOS
+ shr cx, 1 ; Both the labels are para
+ ; aligned
+ rep movsw
+ push es
+ push di ; save end of BIOS
+ mov ax, es
+ mov BCodeSeg, ax ; save it for later use
+ call [seg_reinit_ptr] ; far call to seg_reinit (M022)
+ pop di
+ pop es ; get back end of BIOS
+ ret
+MovBIOS endp
+
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : MovDOS
+;
+; Moves DOS code into requested area
+;
+; In : ES:DI - pointer to memory where DOS is to be moved
+; CX - size of DOS code to be moved
+;
+; Out : ES:DI - pointer to memory immediately after DOS
+;
+;----------------------------------------------------------------------------
+;
+
+
+MovDOS proc near
+ push es
+ push di
+ lds si, dos_temp_location ; current location of DOS
+ rep movsb
+ pop bx ; get back offset into which
+ ; DOS was moved
+ mov ax, dosinit ; get the offset at which DOS
+ ; wants to run
+ sub ax, bx
+ call off_to_para
+ pop bx ; get the segment at which
+ ; we moved DOS into
+ sub bx, ax ; Adjust segment
+ mov current_dos_location, bx ; and save it
+ ret
+MovDOS endp
+
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : AllocMemForDOS
+;
+; Allocate memory for DOS/BIOS code from DOS !!!
+;
+; Out : AX - seg of allocated memoryblock
+;
+;----------------------------------------------------------------------------
+;
+
+
+AllocMemForDOS proc near
+ mov ax, offset BCode_end
+ sub ax, offset BCode_start ; BIOS code size
+ add ax, lo_doscod_size ; + DOS code size
+ add ax, 15
+ call off_to_para ; convert to para
+ or bx, bx ; M012
+ ; can we use int 21 for alloc
+ mov bx, ax
+ jz update_arena ; M012
+ mov ah, 48h ; request DOS
+ int 21h
+ jc FatalErr ; IF ERR WE ARE HOSED
+ sub ax, 3 ; Take care ORG 30h of
+ ; BIOS code
+ mov es, ax
+ mov word ptr es:[20h+arena_owner], 08h ; mark it as system
+ mov word ptr es:[20h+arena_name], 'CS' ; code area
+ ret
+
+;
+; M012 : BEGIN
+;
+update_arena:
+ push ds
+ push di
+ push cx
+ push dx
+ lds di, dosinfo ; get ptr to DOS var
+ dec di
+ dec di ; Arena head is immediately
+ ; before sysvar
+ mov es, ds:[di] ; es = arena head
+ mov cx, es:[arena_size] ; cx = total low mem size
+ cmp cx, bx ; is it sufficient ?
+ jb FatalErr ; no, fatal error
+ mov dl, es:[arena_signature]
+ mov ax, es
+ add ax, bx ; ax = new arena head
+ mov ds:[di], ax ; store it in DOS data area
+ mov ds, ax
+ mov byte ptr ds:[arena_signature], dl ; type of arena
+ mov word ptr ds:[arena_owner], 0 ; free
+ sub cx, bx ; size of the new block
+ mov word ptr ds:[arena_size], cx ; store it in the arena
+ mov ax, es ; return seg to the caller
+ sub ax, 3 ; Take care ORG 30h of
+ ; BIOS code
+ pop dx
+ pop cx
+ pop di
+ pop ds
+ ret
+;
+; M012 : END
+;
+FatalErr:
+ push cs
+ pop ds
+ mov dx, offset FEMsg
+ mov ah, 9h
+ int 21h
+ cli
+ hlt
+AllocMemForDOS endp
+
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : AllocHMA
+;
+; grab_the_hma tries to enable a20 and make sure there is memory
+; up there. If it gets any sort of error, it will return with
+; carry set so that we can resort to running low.
+;
+; It also returns ES: -> 0ffffh if it returns success
+;
+;----------------------------------------------------------------------------
+;
+
+AllocHMA proc near
+ assume ds:nothing,es:nothing
+;
+; cas note: The pre-286 check is no longer needed here since the
+; presence of XMS is sufficient. However, this code hasn't
+; been deleted because it can be recycled for skipping the
+; extra pass of CONFIG.SYS and assuming we're running low
+; in the case of a pre-286.
+
+;
+;; see if we're running on a pre-286. If not, force low.
+;
+; xor ax,ax
+; pushf ; save flags (like int)
+; push ax
+; popf
+; pushf
+; pop ax
+; popf ; restore original flags (like int)
+; and ax,0f000h
+; cmp ax,0f000h ; 8088/8086?
+; jz grab_hma_error
+;
+ push ds
+ mov ax,Bios_Data
+ mov ds,ax
+ assume ds:Bios_Data
+
+ call IsXMSLoaded
+ jnz grabhma_error
+
+ mov ax,4310h
+ int 2fh ; get the vector into es:bx
+ mov word ptr xms,bx
+ mov word ptr xms+2,es
+
+ mov ah,1 ; request HMA
+ mov dx,0ffffh
+ call xms
+ dec ax
+ jz @f ; error if not able to allocate HMA
+
+;
+;------ Himem may be lying because it has allocated mem for int 15
+;
+ mov ah, 88h
+ int 15h
+ cmp ax, 64 ; less than 64 K of hma ?
+ jb grabhma_error
+
+@@: mov ah,5 ; localenableA20
+ call xms
+ dec ax
+ jnz grabhma_error ; error if couldn't enable A20
+
+ mov ax,0ffffh
+ mov es,ax
+ mov es:word ptr 10h,1234h ; see if we can really read/write there
+ cmp es:word ptr 10h,1234h
+ jnz grabhma_error ; don't try to load there if XMS lied
+
+ clc
+ pop ds
+ ret
+
+grabhma_error:
+ stc
+ pop ds
+ assume ds:nothing
+ ret
+
+AllocHMA endp
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : IsXMSLoaded
+;
+; Checks whether a XMS driver is loaded
+;
+; Returns : Z flag set if XMS driver loaded
+; Z flag reset if no XMS drivers are present
+;
+;----------------------------------------------------------------------------
+;
+ public IsXMSLoaded
+
+IsXMSLoaded proc near
+ mov ax,4300h
+ int 2fh
+ cmp al,80h ; XMS installed?
+ ret
+IsXMSLoaded endp
+
+;
+;
+;----------------------------------------------------------------------------
+; procedure : FTryToMovDOSHi
+;
+; Called from HMA suballoc calls
+;
+;----------------------------------------------------------------------------
+;
+;
+
+ public FTryToMovDOSHi
+FTryToMovDOSHi proc far
+
+ push ax
+ push bx
+ push cx
+ push dx
+ push si
+ push di
+ push ds
+ push es
+ cmp runhigh, 0ffh
+ jne @f
+
+ call TryToMovDOSHi
+@@:
+ pop es
+ pop ds
+ pop di
+ pop si
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+
+ ret
+FTryToMovDOSHi endp
+
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : SaveFreeHMAPtr
+;
+; Save the Free HMA pointer in BIOS variable for later use.
+; (INT 2f ax==4a01 call returns pointer to free HMA)
+; Normalizes the pointer to ffff:xxxx format and stores only
+; the offset.
+;
+; Inputs : ES:DI - pointer to free HMA
+; Output : FreeHMAPtr in BIOS data segment updated
+;
+;----------------------------------------------------------------------------
+;
+SaveFreeHMAPtr proc near
+ mov bx, es
+ mov ax, 0ffffh ; HMA segment
+ sub ax, bx
+ add di, 15 ; para round
+ and di, 0fff0h
+ mov cl, 4
+ shl ax, cl
+ sub di, ax
+ push ds
+ mov ax, Bios_Data
+ mov ds, ax
+ assume ds:Bios_Data
+ mov FreeHMAPtr, di
+ mov inHMA, 0ffh
+ pop ds
+ assume ds:nothing
+ ret
+SaveFreeHMAPtr endp
+;
+;
+;----------------------------------------------------------------------------
+;
+; procedure : CPMHack
+;
+; Copies the code from 0:c0 into ffff:0d0h
+; for CPM comatibilty
+;
+;----------------------------------------------------------------------------
+;
+CPMHack proc near
+ push ds
+ mov cx, 0ffffH
+ mov es, cx ; ES = FFFF
+ xor cx, cx
+ mov ds, cx ; DS = 0
+ mov si, 0c0h
+ mov di, 0d0h
+ mov cx, 5
+ cld
+ rep movsb ; move 5 bytes from 0:C0 to FFFF:D0
+ pop ds
+ ret
+CPMHack endp
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : off_to_para
+;
+;----------------------------------------------------------------------------
+;
+
+off_to_para proc near
+ shr ax,1
+ shr ax,1
+ shr ax,1
+ shr ax,1
+ ret
+off_to_para endp
+
+
+;** TempCDS - Create (Temporary?) CDS
+;
+; ENTRY ?? BUGBUG
+; (DS) = SysInitSeg
+; EXIT ?? BUGBUG
+; USES ?? BUGBUG
+
+ public tempcds
+Procedure TempCDS
+
+ assume ds:sysinitseg
+ les di,dosinfo
+ mov cl,byte ptr es:[di.sysi_numio]
+ xor ch,ch ; (cx) = # of block devices
+ mov es:[di.sysi_ncds],cl ; one CDS per device
+ mov al,cl
+ mov ah,size curdir_list
+ mul ah ; (ax) = byte size for those CDSs
+ call pararound ; (ax) = paragraph size for CDSs
+ mov si,[confbot]
+; BUGBUG - we don't update confbot - won't someone else use it?
+ sub si,ax
+ mov [alloclim],si ; can't alloc past here!
+ mov word ptr es:[di.sysi_cds + 2],si
+ mov ax,si
+ mov word ptr es:[di.sysi_cds],0 ; set address of CDS list
+ assume ds:nothing
+ mov es,ax
+ xor di,di ; (es:di) = address of 1st CDS
+
+
+
+;* Initialize our temporary CDSs.
+;
+; (cx) = count of CDSs left to process
+; (si) = 0 based drive being processed
+; (es:di) = address of next CDS
+
+fooset:
+ xor dx,dx ; indicator to stop removable checks
+foogo:
+ mov ax,word ptr DirStrng
+ .errnz CURDIR_TEXT ; setup the root as the curdir
+ stosw
+ mov ax,word ptr DirStrng+2
+ stosw
+ xor ax,ax
+ push cx
+ .errnz CURDIR_FLAGS - CURDIR_TEXT - size CURDIR_TEXT
+ mov cx,curdir_flags - 4
+ rep stosb ; zero out rest of CURDIR_TEXTs
+
+; Here es:di points to CURDIR_FLAGS
+
+ or dx,dx ; have we found one fixed drive?
+ jnz fixed_drv2 ; NZ -> yes dont do IOCTL check
+
+ cmp byte ptr DirStrng, 'B'
+ jbe not_fixed ; 'A' and 'B' are always removable
+
+ mov bl,byte ptr DirStrng
+ sub bl,'A'
+ inc bl ; C is 3
+ mov ax,4408h
+ int 21h ; Is drive removable
+ jc fixed_drv ; Could'nt find means NET hence fixed
+ or ax,ax
+ jnz fixed_drv
+
+not_fixed:
+ mov ax,CURDIR_LOCAL OR CURDIR_INUSE
+ jmp short fill_in
+
+
+fixed_drv:
+ inc dx
+fixed_drv2:
+ mov ax,CURDIR_LOCAL OR CURDIR_INUSE OR CURDIR_NT_FIX
+
+fill_in:
+
+ FOLLOWS CURDIR_FLAGS,CURDIR_TEXT,2
+ stosw ; Save Flags
+
+ mov ax,2
+ FOLLOWS CURDIR_END,CURDIR_FLAGS,2
+ stosw ; Save CURDIR_END
+
+ inc byte ptr DirStrng
+ pop cx
+ loop foogo
+ mov byte ptr DirStrng,"A"
+ ret
+
+EndProc TempCDS
+
+
+;** EndFile - Build DOS structures
+;
+; This procedure is called after the config.sys has been processed and
+; installable device drivers have been loaded (but before "install="
+; programs are loaded) to create the dos structures such as SFTs, buffers,
+; FCBs, CDSs, etc. It also loads the sysinit_base module in low memory
+; to allow for the safe EXECing of "install=" programs. All memory
+; above these structures is deallocated back to DOS.
+;
+; ENTRY ?? BUGBUG
+; EXIT ?? BUGBUG
+; USES ?? BUGBUG
+
+
+;------------------------------------------------------------------------------
+; allocate files
+;------------------------------------------------------------------------------
+
+endfile:
+
+; we are now setting up final cdss,buffers,files,fcss strings etc. we no
+; longer need the space taken by the temp stuff below confbot,so set alloclim
+; to confbot.
+
+; if this procedure has been called to take care of install= command,
+; then we have to save es,si registers.
+
+ push ds
+ mov ax,Bios_Data
+ mov ds,ax
+ assume ds:Bios_Data
+
+ cmp multrk_flag,multrk_off1 ;=0,multrack= command entered?
+ jne multrk_flag_done
+ or multrk_flag,multrk_on ; default will be on.
+multrk_flag_done:
+
+ pop ds
+ assume ds:nothing
+
+ mov ax,[confbot]
+ mov [alloclim],ax
+
+ push cs
+ pop ds
+ extrn round:near
+ call round
+ mov al,[files]
+ sub al,5
+ jbe dofcbs
+
+ push ax
+ mov al,devmark_files
+ call setdevmark ; set devmark for sfts (files)
+ pop ax
+ xor ah,ah ; do not use cbw instruction!!!!!
+ ; it does sign extend.
+ mov bx,[memlo]
+ mov dx,[memhi]
+ lds di,dosinfo ;get pointer to dos data
+ lds di,[di+sysi_sft] ;ds:bp points to sft
+ mov word ptr [di+sflink],bx
+ mov word ptr [di+sflink+2],dx ;set pointer to new sft
+
+ push cs
+ pop ds
+
+ les di,dword ptr [memlo] ;point to new sft
+ mov word ptr es:[di+sflink],-1
+ mov es:[di+sfcount],ax
+ mov bl,size sf_entry
+ mul bl ;ax = number of bytes to clear
+ mov cx,ax
+ add [memlo],ax ;allocate memory
+ mov ax,6
+ add [memlo],ax ;remember the header too
+ or [setdevmarkflag],for_devmark
+ call round ; check for mem error before the stosb
+ add di,ax
+ xor ax,ax
+ rep stosb ;clean out the stuff
+
+;------------------------------------------------------------------------------
+; allocate fcbs
+;------------------------------------------------------------------------------
+
+dofcbs:
+ push cs
+ pop ds
+ call round
+ mov al,devmark_fcbs ;='x'
+ call setdevmark
+ mov al,[fcbs]
+ xor ah,ah ; do not use cbw instruction!!!!!
+ ; it does sign extend.
+ mov bx,[memlo]
+ mov dx,[memhi]
+ lds di,dosinfo ;get pointer to dos data
+ assume ds:nothing
+
+ mov word ptr [di+sysi_fcb],bx
+ mov word ptr [di+sysi_fcb+2],dx ;set pointer to new table
+ mov bl,cs:keep
+ xor bh,bh
+ mov [di+sysi_keep],bx
+
+ push cs
+ pop ds
+ assume ds:sysinitseg
+
+ les di,dword ptr [memlo] ;point to new table
+ mov word ptr es:[di+sflink],-1
+ mov es:[di+sfcount],ax
+ mov bl,size sf_entry
+ mov cx,ax
+ mul bl ;ax = number of bytes to clear
+ add [memlo],ax ;allocate memory
+ mov ax,size sf-2
+ add [memlo],ax ;remember the header too
+ or [setdevmarkflag],for_devmark
+ call round ; check for mem error before the stosb
+ add di,ax ;skip over header
+ mov al,"A"
+fillloop:
+ push cx ; save count
+ mov cx,size sf_entry ; number of bytes to fill
+ cld
+ rep stosb ; filled
+
+ mov word ptr es:[di-(size sf_entry)+sf_ref_count],0
+ mov word ptr es:[di-(size sf_entry)+sf_position],0
+ mov word ptr es:[di-(size sf_entry)+sf_position+2],0
+
+ pop cx
+ loop fillloop
+
+;------------------------------------------------------------------------------
+; allocate cdss
+;------------------------------------------------------------------------------
+buf1:
+ call round
+
+ push ax
+ mov ax,devmark_cds ;='l'
+ call setdevmark
+ pop ax
+
+ les di,dosinfo
+ mov cl,byte ptr es:[di.sysi_numio]
+
+;NTVDM Ignore the lastdrive command. There exists only one cds for all
+; network drives and dos has already set sysi_numio to be
+; num real drives + 1 for all network drives 17-Aug-1992 Jonle
+;
+; cmp cl,[num_cds]
+; jae gotncds ; user setting must be at least numio
+; mov cl,[num_cds]
+;gotncds:
+;
+ xor ch,ch
+ mov es:[di.sysi_ncds],cl
+ mov ax,[memhi]
+ mov word ptr es:[di.sysi_cds + 2],ax
+ mov ax,[memlo]
+ mov word ptr es:[di.sysi_cds],ax
+ mov al,cl
+ mov ah,size curdir_list
+ mul ah
+ call pararound
+ add [memhi],ax
+
+ or [setdevmarkflag],for_devmark
+ call round ; check for mem error before initializing
+ assume ds:nothing
+ les di,es:[di.sysi_cds]
+ call fooset
+
+;------------------------------------------------------------------------------
+; allocate space for internal stack
+;------------------------------------------------------------------------------
+
+ if stacksw
+
+ push cs
+ pop ds
+ assume ds:sysinitseg
+
+doinstallstack:
+ mov ax,[stack_count] ; stack_count = 0?
+ or ax,ax ;then,stack size must be 0 too.
+ jz skipstack ;don't install stack.
+
+; dynamic relocation of stack code.
+
+ call round ;[memhi] = seg. for stack code
+ ;[memlo] = 0
+
+; set devmark block into memory for mem command
+; devmark_id = 's' for stack
+
+ mov al,devmark_stk ;='s'
+ call setdevmark
+
+ mov ax,[memhi]
+ mov es,ax ;es -> seg. the stack code is going to move.
+ assume es:nothing
+ push cs
+ pop ds
+ xor si,si ;!!we know that stack code is at the beginning of sysinit.
+ xor di,di
+ mov cx,offset endstackcode
+ mov [memlo],cx
+ call round ;have enough space for relocation?
+ rep movsb
+
+ push ds ; stick the location of the NextStack entry
+ mov ax,Bios_Data ; into the Win386 Instance Data tables
+ mov ds,ax
+ assume ds:Bios_Data
+ mov word ptr NextStack,offset nextentry
+ mov word ptr NextStack+2,es
+
+ mov ax,[memlo]
+ mov word ptr [stack_addr],ax ;set for stack area initialization
+ mov word ptr IT_StackLoc,ax ; pass it as Instance Data, too
+ mov ax,[memhi] ;this will be used by stack_init routine.
+ mov word ptr [stack_addr+2],ax
+ mov word ptr IT_StackLoc+2,ax
+
+; space for internal stack area = stack_count(entrysize + stack_size)
+
+ mov ax,entrysize
+ add ax,[stack_size]
+ mul [stack_count]
+
+ mov IT_StackSize,ax ; pass through to Instance Tables
+
+ pop ds ; no more need to access Instance Table
+ assume ds:nothing
+
+ call pararound ; convert size to pargraphs
+ add [memhi],ax
+ or [setdevmarkflag],for_devmark ;to set the devmark_size for stack by round routine.
+ call round ; check for memory error before
+ ; continuing
+ call stackinit ; initialize hardware stack. cs=ds=sysinitseg,es=relocated stack code & data
+
+skipstack:
+ endif
+
+ push cs
+ pop ds
+ assume ds:sysinitseg
+
+ mov al,[files]
+ xor ah,ah ; do not use cbw instruction!!!!!
+ ; it does sign extend.
+ mov cx,ax
+ xor bx,bx ;close standard input
+ mov ah,close
+ int 21h
+;; go directly to the handle table; donot close any invalid handles
+ push si
+ mov ah, Get_Current_PDB ;
+ int 21h
+ les si, es:[pdb_jfn_pointer]
+ mov bx, 2
+rcclloop:
+ cmp byte ptr es:[bx][si], 0FFh ;skip invalid handle
+ je skip_the_handle
+ mov ah,close ; need output so we can print message
+ int 21h ; in case we can't get new one open.
+skip_the_handle:
+ inc bx
+ loop rcclloop
+ pop si
+
+ mov dx,offset condev
+ mov al,2
+ mov ah,open ;open con for read/write
+ stc ; set for possible int 24
+ int 21h
+ jnc goaux
+ call badfil
+ jmp short goaux2
+
+goaux: push ax
+ mov bx,1 ;close standard output
+ mov ah,close
+ int 21h
+ pop ax
+
+ mov bx,ax ;new device handle
+ mov ah,xdup
+ int 21h ;dup to 1,stdout
+ mov ah,xdup
+ int 21h ;dup to 2,stderr
+
+goaux2: mov dx,offset auxdev
+ mov al,2 ;read/write access
+ extrn open_dev:near
+ call open_dev
+
+ mov dx,offset prndev
+ mov al,1 ;write only
+ call open_dev
+
+;global rearm command for shared interrupt devices attached in the system;
+;shared interrupt attachment has some problem when it issues interrupt
+;during a warm reboot. once the interrupt is presented by the attachment,
+;no further interrupts on that level will be presented until a global rearm
+;is issued. by the request of the system architecture group, msbio will
+;issue a global rearm after every device driver is loaded.
+;to issue a global rearm: ;for pc1,xt,palace
+;
+; out 02f2h,xx ; interrupt level 2
+; out 02f3h,xx ; interrupt level 3
+; out 02f4h,xx ; interrupt level 4
+; out 02f5h,xx ; interrupt level 5
+; out 02f6h,xx ; interrupt level 6
+; out 02f7h,xx ; interrupt level 7
+;
+; for pc at,in addition to the above commands,
+; need to handle the secondary interrupt handler
+;
+; out 06f2h,xx ; interrupt level 10
+; out 06f3h,xx ; interrupt level 11
+; out 06f4h,xx ; interrupt level 12
+; out 06f6h,xx ; interrupt level 14
+; out 06f7h,xx ; interrupt level 15
+;
+; for round-up machine
+;
+; none.
+
+; where xx stands for any value.
+;
+; for your information,after naples level machine,the system service bios
+; call (int 15h),function ah=0c0h returns the system configuration parameters
+;
+;
+; Sudeepb 31-Dec-1991 Commented out for NT
+if 0
+ push ax
+ push bx
+ push dx
+ push es
+
+ mov al,0ffh ;reset h/w by writing to port
+ mov dx,2f2h ;get starting address
+ out dx,al ; out 02f2h,0ffh
+ inc dx
+ out dx,al ; out 02f3h,0ffh
+ inc dx
+ out dx,al ; out 02f4h,0ffh
+ inc dx
+ out dx,al ; out 02f5h,0ffh
+ inc dx
+ out dx,al ; out 02f6h,0ffh
+ inc dx
+ out dx,al ; out 02f7h,0ffh
+
+;sb secondary global rearm
+
+ mov ax,0f000h ;get machine type
+ mov es,ax
+ cmp byte ptr es:[0fffeh],0fch ;q:is it a at type machine
+ je startrearm ; *if at no need to check
+
+ mov ah,0c0h ;get system configuration
+ int 15h ; *
+ jc finishrearm ; *jmp if old rom
+
+; test feature byte for secondary interrupt controller
+
+ test es:[bx.bios_sd_featurebyte1],scndintcontroller
+ je finishrearm ;jmp if it is there
+
+startrearm:
+ mov al,0ffh ;write any pattern to port
+ mov dx,6f2h ;get starting address
+ out dx,al ;out 06f2h,0ffh
+ inc dx ;bump address
+ out dx,al ;out 06f3h,0ffh
+ inc dx ;bump address
+ out dx,al ;out 06f4h,0ffh
+ inc dx ;bump address
+ inc dx ;bump address
+ out dx,al ;out 06f6h,0ffh
+ inc dx ;bump address
+ out dx,al ;out 06f7h,0ffh
+
+finishrearm:
+ pop es
+ pop dx
+ pop bx
+ pop ax
+endif
+
+; global rearm end *******************
+
+;------------------------------------------------------------------------------
+; allocate sysinit_base for install= command
+;------------------------------------------------------------------------------
+; sysinit_base allocation.
+; check if endfile has been called to handle install= command.
+
+set_sysinit_base:
+
+;--------------------------------------------------------------------------
+;sysinit_base will be established in the secure area of
+;lower memory when it handles the first install= command.
+;sysinit_base is the place where the actual exec function will be called and
+;will check sysinit module in high memory if it is damaged by the application
+;program. if sysinit module has been broken,then "memory error..." message
+;is displayed by sysinit_base.
+;--------------------------------------------------------------------------
+
+ push ax ; set devmark for mem command
+ mov ax,[memhi]
+ sub ax,[area]
+ mov [impossible_owner_size],ax ;remember the size in case.
+ mov al,devmark_inst
+ call setdevmark
+ pop ax
+
+ mov di,[memhi]
+ mov es,di
+ assume es:nothing
+ mov word ptr [sysinit_base_ptr+2],di ; save this entry for the next use.
+ xor di,di
+ mov word ptr [sysinit_base_ptr],di ; es:di -> destination.
+ mov si,offset sysinit_base ;ds:si -> source code to be relocated.
+ mov cx,(offset end_sysinit_base) - (offset sysinit_base)
+ add [memlo],cx
+ or cs:[setdevmarkflag],for_devmark
+ call round ; check mem error. also,readjust memhi for the next use.
+ rep movsb ; reallocate it.
+
+ mov word ptr [sysinit_ptr],offset sysinitptr ; returing address from
+ mov word ptr [sysinit_ptr+2],cs ; sysinit_base back to sysinit.
+ or [install_flag],has_installed ; set the flag.
+
+;------------------------------------------------------------------------------
+; free the rest of the memory from memhi to confbot. still from confbot to
+; the top of the memory will be allocated for sysinit and config.sys if
+; have_install_cmd.
+;------------------------------------------------------------------------------
+
+ call round
+ mov bx,[memhi]
+ mov ax,[area]
+ mov [old_area],ax ; save [area]
+ mov es,ax ;calc what we needed
+ sub bx,ax
+ mov ah,setblock
+ int 21h ;give the rest back
+
+ push es
+ mov ax,es
+ dec ax
+ mov es,ax ;point to arena
+ mov es:[arena_owner],8 ;set impossible owner
+ mov word ptr es:[arena_name], 'DS' ; System Data
+ pop es
+
+ mov bx,0ffffh
+ mov ah,alloc
+ int 21h
+ mov ah,alloc
+ int 21h ; allocate the rest of the memory
+
+ mov [memhi],ax ; start of the allocated memory
+ mov [memlo],0 ; to be used next.
+
+;;;; at this moment,memory from [memhi]:0 to top-of-the memory is
+;;;; allocated.
+;;;; to protect sysinit,confbot module (from confbot (or =alloclim at
+;;;; this time) to the top-of-the memory),here we are going to
+;;;; 1). "setblock" from memhi to confbot.
+;;;; 2). "alloc" from confbot to the top of the memory.
+;;;; 3). "free alloc memory" from memhi to confbot.
+
+;memory allocation for sysinit,confbot module.
+
+ mov es,ax
+ mov bx,[confbot]
+ sub bx,ax ; confbot - memhi
+ dec bx ; make a room for the memory block id.
+ dec bx ; make sure!!!.
+ mov ah,setblock
+ int 21h ; this will free (confbot to top of memory)
+ mov bx,0ffffh
+ mov ah,alloc
+ int 21h
+ mov ah,alloc
+ int 21h ; allocate (confbot to top of memory)
+ mov [area],ax ; save allocated memory segment.
+ ; need this to free this area for command.com.
+ mov es,[memhi]
+ mov ah,49h ; free allocated memory.
+ int 21h ; free (memhi to confbot(=area))
+
+endfile_ret:
+ ret
+
+; End of "EndFile" DOS structure configuration.
+
+
+;-------------------------------------------------------------------------
+; Do_Install_Exec
+;
+; This procedure is used to EXEC a program being loaded via the
+; "install=" mechanism in config.sys. It does this by setting up
+; the parameters, and then jumping to sysinit_base, which has been
+; setup in low memory. When complete, sysinit_base will jump back
+; up to this procedure (if sysinit remains uncorrupted by the installed
+; program).
+
+do_install_exec proc near ; now,handles install= command.
+
+ push si ; save si for config.sys again.
+
+; we are going to call load/exec function.
+; set es:bx to the parameter block here;;;;;;;
+; set ds:dx to the asciiz string. remember that we already has 0
+; after the filename. so parameter starts after that. if next
+; character is a line feed (i.e. 10),then assume that the 0
+; we already encountered used to be a carrage return. in this
+; case,let's set the length to 0 which will be followed by
+; carridge return.
+
+; es:si -> command line in config.sys. points to the first non blank
+;character after =.
+
+ push es
+ push ds
+ pop es
+ pop ds ; es->sysinitseg,ds->confbot seg
+ assume ds:nothing
+ mov dx,si ; ds:dx->file name,0 in config.sys image.
+
+ xor cx,cx
+ cld
+ mov cs:ldexec_start,' ' ; clear out the parm area
+ mov di,offset ldexec_parm
+installfilename: ; skip the file name
+ lodsb ; al = ds:si; si++
+ cmp al,0
+ je got_installparm
+ jmp installfilename
+got_installparm: ; copy the parameters to ldexec_parm
+ lodsb
+ mov es:[di],al
+ cmp al,lf ; line feed?
+ je done_installparm
+ inc cl ; # of char. in the parm.
+ inc di
+ jmp got_installparm
+done_installparm:
+ mov byte ptr cs:[ldexec_line],cl ; length of the parm.
+ cmp cl,0 ;if no parm,then
+ jne install_seg_set ; let the parm area
+ mov byte ptr cs:[ldexec_start],cr ; starts with cr.
+install_seg_set:
+ mov word ptr cs:0,0 ; make a null environment segment
+ mov ax,cs ; by overlap jmp instruction of sysinitseg.
+
+;hkn; the environment pointer is made 0. so the current environment ptr.
+;hkn; will be the same as pdb_environ which after dosinit is 0.
+
+ mov cs:[instexe.exec0_environ],0 ; set the environment seg.
+
+
+ mov word ptr cs:[instexe.exec0_com_line+2],ax ; set the seg.
+ mov word ptr cs:[instexe.exec0_5c_fcb+2],ax
+ mov word ptr cs:[instexe.exec0_6c_fcb+2],ax
+ call sum_up
+ mov es:checksum,ax ; save the value of the sum
+ xor ax,ax
+ mov ah,exec ; load/exec
+ mov bx,offset instexe ; es:bx -> parm block.
+ push es ; save es,ds for load/exec
+ push ds ; these registers will be restored in sysinit_base.
+ jmp cs:dword ptr sysinit_base_ptr ; jmp to sysinit_base to execute
+ ; load/exec function and check sum.
+
+;j.k. this is the returning address from sysinit_base.
+
+sysinitptr: ; returning far address from sysinit_base
+ pop si ; restore si for config.sys file.
+ push es
+ push ds
+ pop es
+ pop ds ; now ds - sysinitseg,es - confbot
+ jnc exec_exit_code
+
+
+ push si ; error in loading the file for install=.
+ call badload ; es:si-> path,filename,0.
+ pop si
+ jmp short install_exit_ret
+
+exec_exit_code:
+ mov ah,4dh
+ int 21h
+ cmp ah,3 ;only accept "stay resident" prog.
+ je install_exit_ret
+ call error_line ;inform the user
+
+ stc
+
+install_exit_ret:
+ ret
+
+do_install_exec endp
+
+
+
+;** ParaRound - Round Up length to paragraph multiple
+;
+; ParaRound rounds a byte count up to a multiple of 16, then divides
+; by 16 yielding a "length in paragraphs" value.
+;
+; ENTRY (ax) = byte length
+; EXIT (ax) = rounded up length in paragraphs
+; USES ax, flags
+
+Procedure ParaRound
+
+ add ax,15
+ rcr ax,1
+ shr ax,1
+ shr ax,1
+ shr ax,1
+ ret
+
+EndProc ParaRound
+
+
+;------------------------------------------------------------------------------
+; sysinit_base module.
+;
+; This module is relocated by the routine EndFile to a location in low
+; memory. It is then called by SYSINIT to perform the EXEC of programs
+; that are being loaded by the "install=" command. After the EXEC call
+; completes, this module performs a checksum on the SYSINIT code (at the
+; top of memory) to be sure that the EXECed program did not damage it.
+; If it did, then this module will print an error message and stop the
+; system. Otherwise, it returns control to SYSINIT.
+;
+;
+;in: after relocation,
+; ax = 4b00h - load and execute the program dos function.
+; ds = confbot. segment of config.sys file image
+; es = sysinitseg. segment of sysinit module itself.
+; ds:dx = pointer to asciiz string of the path,filename to be executed.
+; es:bx = pointer to a parameter block for load.
+; SI_end (byte) - offset vaule of end of sysinit module label
+; bigsize (word) - # of word from confbot to SI_end.
+; chksum (word) - sum of every byte from confbot to SI_end in a
+; word boundary moduler form.
+; sysinit_ptr (dword ptr) - return address to sysinit module.
+;
+;note: sysinit should save necessary registers and when the control is back
+
+ public sysinit_base
+sysinit_base:
+ mov word ptr cs:sysinit_base_ss,ss ; save stack
+ mov word ptr cs:sysinit_base_sp,sp
+ int 21h ; load/exec dos call.
+ mov ss,word ptr cs:sysinit_base_ss ; restore stack
+ mov sp,word ptr cs:sysinit_base_sp
+ pop ds ; restore confbot seg
+ pop es ; restore sysinitseg
+ jc sysinit_base_end ; load/exec function failed.
+ ; at this time,i don't have to worry about
+ ; that sysinit module has been broken or not.
+ call sum_up ; otherwise,check if it is good.
+ cmp es:checksum,ax
+ je sysinit_base_end
+
+; memory broken. show "memory allocation error" message and stall.
+
+ mov ah,9
+ push cs
+ pop ds
+ mov dx,offset mem_alloc_err_msgx - sysinit_base
+ int 21h
+ jmp $ ; hang here!!!!
+
+sysinit_base_end: jmp es:sysinit_ptr ;return back to sysinit module
+
+sum_up:
+
+;in: es - sysinitseg.
+;out: ax - result
+;
+;remark: since this routine will only check starting from "locstack" to the end of
+; sysinit segment,the data area, and the current stack area are not
+; coverd. in this sense,this check sum routine only gives a minimal
+; gaurantee to be safe.
+;
+;first sum up confbot seg.
+
+ push ds
+ mov ax,es:confbot
+ mov ds,ax
+ xor si,si
+ xor ax,ax
+ mov cx,es:config_size ; if config_size has been broken,then this
+ ;whole test better fail.
+ shr cx,1 ; make it a word count
+ jz sum_sys_code ; when config.sys file not exist.
+sum1:
+ add ax,ds:word ptr [si]
+ inc si
+ inc si
+ loop sum1
+;now,sum up sysinit module.
+sum_sys_code:
+ mov si,offset locstack ; starting after the stack.
+ ; this does not cover the possible stack code!!!
+ mov cx,offset sysinitgrp:SI_end ; SI_end is the label at the end of sysinit
+ sub cx,si ; from after_checksum to SI_end
+ shr cx,1
+sum2:
+ add ax,es:word ptr [si]
+ inc si
+ inc si
+ loop sum2
+ pop ds
+ ret
+
+sysinit_base_ss equ $-sysinit_base
+ dw ?
+sysinit_base_sp equ $-sysinit_base
+ dw ?
+mem_alloc_err_msgx:
+
+ include msbio.cl4 ; memory allocation error message
+
+end_sysinit_base label byte
+
+;------------------------------------------------------------------------------
+; ibmstack initialization routine.
+ if stacksw
+.sall
+;
+; to follow the standard interrupt sharing scheme, msstack.asm
+; has been modified. this initialization routine also has to
+; be modified because for the interrupt level 7 and 15, firstflag
+; should be set to signal that this interrupt handler is the
+; first handler hooked to this interrupt vector.
+; we determine this by looking at the instruction pointed by
+; this vector. if it is iret, then this handler should be the
+; first one. in our case, only the interrupt vector 77h is the
+; interrupt level 15. (we don't hook interrupt level 7.)
+;
+; the followings are mainly due to m.r.t; ptm fix of p886 12/3/86
+; some design changes are needed to the above interrupt sharing
+; method. the above sharing scheme assumes that 1). interrupt
+; sharing is never done on levels that have bios support. 2). "phantom"
+; interrupts would only be generated on levels 7 and 15.
+; these assumptions are not true any more. we have to use the firstflag
+; for every level of interrupt. we will set the firstflag on the following
+; conditions:
+;
+; a. if the cs portion of the vector is 0000, then "first"
+; b. else if cs:ip points to valid shared header, then not "first"
+; c. else if cs:ip points to an iret, then "first"
+; d. else if cs:ip points to dummy, then "first"
+;
+; where dummy is - the cs portion must be f000, and the ip portion must
+; be equal to the value at f000:ff01. this location is the initial value
+; from vector_table for interrupt 7, one of the preserved addresses in all
+; the bioses for all of the machines.
+;
+; system design group requests bios to handle the phantom interrupts.
+;
+; the "phantom" interrupt is an illegal interrupt such as an interrupt
+; produced by the bogus adapter card even without interrupt request is
+; set. more specifically, 1). the 8259 has a feature when running in
+; edge triggered mode to latch a pulse and present the interrupt when
+; the processor indicates interrupt acknowledge (inta). the interrupt
+; pulse was exist at the time of inta to get a "phantom" interrupt.
+; 2). or, this is caused by adapter cards placing a glitch on the
+; interrupt line.
+;
+; to handle those "phantom" interrupts, the main stack code will check
+; the own firstflag, and if it is not "first" (which means the forward
+; pointer points to the legal shared interrupt handler), then pass the
+; control. if it is the first, then the following action should be
+; taken. we don't have to implement skack logic in this case.
+;
+; to implement this logic, we rather choose a simple method.
+; if ont of the above "firstflag" conditions is met, we are not
+; going to hook this interrupt vector. the reason is if the original
+; vector points to "iret" and do nothing, we don't need
+; to implement the stack logic for it. this will simplify implementation
+; while maintaining compatibility with the old version of dos.
+; this implies that in the main stack code, there might be a stack code
+; that will never be used, a dead code.
+;
+;in - cs, ds -> sysinitseg, es -> relocated stack code & data.
+
+ page
+ assume ds:sysinitseg
+stackinit proc near
+
+ push ax
+ push ds
+ push es
+ push bx
+ push cx
+ push dx
+ push di
+ push si
+ push bp
+
+;currently es -> stack code area
+
+ mov ax, cs:[stack_count] ;defined in cs
+ mov es:[stackcount], ax ;defined in stack code area
+ mov ax, [stack_size] ;in cs
+ mov es:[stacksize], ax
+ mov ax, word ptr cs:[stack_addr] ; offset
+ mov word ptr es:[stacks], ax
+ mov ax, word ptr cs:[stack_addr+word] ; segment
+ mov word ptr es:[stacks+word], ax
+
+; initialize the data fields with the parameters
+
+; "firstentry" will always be at stacks
+
+ mov bp, word ptr es:stacks ; get offset of stack
+ mov es:firstentry,bp
+
+; the stacks will always immediately follow the table entries
+
+ mov ax,entrysize
+ mov cx,es:stackcount
+ mul cx
+ add ax,bp
+ mov es:stackat,ax
+ mov bx,ax
+ sub bx,2
+
+; zero the entire stack area to start with
+
+ mov di,es:stackat
+ mov ax,es:stacksize
+ mul cx
+ mov cx,ax
+ xor ax,ax
+ push es
+ pop ds ;ds = relocated stack code seg.
+ assume ds:nothing
+
+;now, ds -> stack code area
+
+ mov es, word ptr ds:[stacks+2] ; get segment of stack area.
+ cld
+ rep stosb
+
+ mov cx, ds:stackcount
+
+; loop for "count" times, building a table entry
+; cs = sysinitseg, ds = relocated stack code seg , es = segment of stack space
+; cx = number of entries
+; es:bp => base of stacks - 2
+; es:bx => first table entry
+
+buildloop:
+ mov es:byte ptr allocbyte[bp],free
+ mov es:byte ptr intlevel[bp],al ;ax = 0
+ mov es:word ptr savedsp[bp],ax
+ mov es:word ptr savedss[bp],ax
+ add bx,ds:stacksize
+ mov es:word ptr newsp[bp],bx
+ mov es:[bx],bp
+ add bp,entrysize
+
+ loop buildloop
+
+ sub bp,entrysize
+ mov ds:lastentry,bp
+ mov ds:nextentry,bp
+
+; NTVDM support for pc convertable is NOT NEEDED 10-Aug-1992 Jonle
+; push ds
+; mov ax, 0f000h ;look at the model byte
+; mov ds, ax
+; cmp ds:byte ptr [0fffeh], mdl_convert ;convertible?
+; pop ds
+; jne skip_disablenmis
+;
+; mov al,07h ; disable convertible nmis
+; out 72h,al
+;
+;skip_disablenmis:
+
+ xor ax,ax
+ mov es,ax ;es - segid of vector table at 0
+ assume es:nothing ;ds - relocated stack code segment
+
+ call DOCLI
+
+ irp aa,<02,70>
+
+ mov si,aa&h*4 ;pass where vector is to be adjusted
+ mov di, offset int19old&aa ;we have to set old&aa for int19 handler too.
+ mov bx,offset old&aa ;pass where to save original owner pointer
+ mov dx,offset int&aa ;pass where new handler is
+ call new_init_loop ;adjust the vector to new handler,
+ ; saving pointer to original owner
+ endm
+
+
+ ; NTVDM int 08, 09, special handling 24-Jan-1993 Jonle
+ ;
+ ; These Ints are usually done in the macro above with int 02,70
+ ; However, we don't need stack swapping as long as no device
+ ; driver has hooked it. These ints are also left alone so that
+ ; softpc will know if they have been hooked by an app.
+
+ mov si, 09h*4
+ mov ax, word ptr es:[si+0]
+ cmp word ptr old09, ax
+ jne do_I9StkSwap
+ mov ax, word ptr es:[si+2]
+ cmp word ptr old09+2, ax
+ je skip_I9StkSwap
+do_I9StkSwap:
+ mov di, offset int19old09
+ mov bx,offset old09
+ mov dx,offset int09
+ call new_init_loop
+skip_I9StkSwap:
+
+ mov si, 08h*4
+ mov ax, word ptr es:[si+0]
+ cmp word ptr old08, ax
+ jne do_I8StkSwap
+ mov ax, word ptr es:[si+2]
+ cmp word ptr old08+2, ax
+ je skip_I8StkSwap
+do_I8StkSwap:
+ mov di, offset int19old08
+ mov bx,offset old08
+ mov dx,offset int08
+ call new_init_loop
+skip_I8StkSwap:
+
+
+ irp aa,<0a,0b,0c,0d,0e,72,73,74,76,77> ;shared interrupts
+
+ mov si,aa&h*4 ;pass where vector is to be adjusted
+ push ds ;save relocated stack code segment
+ lds bx, es:[si] ;ds:bx -> original interrupt handler
+ push ds
+ pop dx ;dx = segment value
+
+ cmp dx,0
+ jz int&aa&_first
+
+ cmp byte ptr ds:[bx],0cfh ;does vector point to an iret?
+ jz int&aa&_first
+
+ cmp word ptr ds:[bx.6],424bh ;magic offset (see int&aa, msstack.inc)
+ jz int&aa&_not_first
+
+ cmp dx,0f000h ;rom bios segment
+ jnz int&aa&_not_first
+
+ push es
+ push dx
+ mov dx,0f000h
+ mov es,dx
+ cmp bx,word ptr es:0ff01h
+ pop dx
+ pop es
+ jz int&aa&_first
+
+int&aa&_not_first: ;not the first. we are going to hook vector.
+ pop ds
+ mov di, offset int19old&aa ;we have to set old&aa for int19 handler too.
+ mov bx, offset old&aa ;pass where to save original owner pointer
+ mov dx, offset int&aa ;pass where new handler is
+ call new_init_loop ;adjust the vector to new handler, saving
+ ;pointer to original owner.
+ jmp short int&aa&_end
+int&aa&_first: ;the first. don't have to hook stack code.
+ pop ds
+int&aa&_end:
+
+ endm
+
+; NTVDM support for pc convertable is NOT NEEDED 10-Aug-1992 Jonle
+; push ds
+; mov ax, 0f000h ;loook at the model byte
+; mov ds, ax
+; cmp ds:byte ptr [0fffeh], mdl_convert ;pc convertible?
+; pop ds
+; jne skip_enablenmis
+;
+; mov al,27h ; enable convertible nmis
+; out 72h,al
+;
+; skip_enablenmis:
+
+ call DOSTI
+ mov ax,Bios_Data
+ mov ds,ax
+ assume ds:Bios_Data
+
+
+ mov [int19sem],1 ; indicate that int 19
+ ; initialization is complete
+
+ pop bp ; restore all
+ pop si
+ pop di
+ pop dx
+ pop cx
+ pop bx
+
+ pop es
+ pop ds
+ assume ds:sysinitseg
+
+ pop ax
+ ret
+stackinit endp
+
+new_init_loop proc near
+
+;input: si=ofset into vector table of the particular int vector being adjusted
+; bx=ds:offset of oldxx, where will be saved the pointer to original owner
+; dx=ds:offset of intxx, the new interrupt handler
+; di=offset value of int19old&aa variable in bios.
+; es=zero, segid of vector table
+; ds=relocated stack code segment
+
+ mov ax,es:[si+0] ;remember offset in vector
+ mov word ptr ds:[bx],ax ; to original owner in ds
+ mov ax,es:[si+2] ;remember segid in vector
+ mov word ptr ds:[bx]+2,ax ; to original owner in ds
+
+ push ds
+ mov ax,Bios_Data
+ mov ds,ax ;set int19oldxx value in bios for
+ mov ax,es:[si+0] ;int 19 handler
+ mov word ptr ds:[di],ax
+ mov ax,es:[si+2]
+ mov word ptr ds:[di]+2,ax
+ pop ds
+
+ mov word ptr es:[si+0],dx ;set vector to point to new int handler
+ mov es:[si+2],ds
+ ret
+new_init_loop endp
+
+
+.xall
+ endif
+;------------------------------------------------------------------------------
+ public setdevmark
+setdevmark proc
+
+;set the devmark for mem command.
+;in: [memhi] - the address to place devmark
+; [memlo] = 0
+; al = id for devmark_id
+;out: devmark established.
+; the address saved in cs:[devmark_addr]
+; [memhi] increase by 1.
+
+ push es
+ push cx
+
+ mov cx,cs:[memhi]
+ mov cs:[devmark_addr],cx
+ mov es,cx
+ mov es:[devmark_id],al
+ inc cx
+ mov es:[devmark_seg],cx
+
+ pop cx
+ pop es
+ inc cs:[memhi]
+ ret
+setdevmark endp
+
+
+ ifdef TAIWAN
+
+;---------------------
+; entry : none
+; exit : ax = 0 --> oem local driver not found
+; = 1 --> oem local driver found
+; destore : ds,es,bx,cx,dx,si,di
+; description :
+; search config.sys to find oem local driver.
+; oem local driver should in \csi\driver\ directory .
+; if (found oem local driver in config.sys)
+; ax=1;
+; else
+; ax=0;
+; return;
+; ps. please see state diagram for state description.
+;---------------------
+
+chkoemlocaldrv proc near
+ push es
+ push ds
+ push bx
+ push cx
+ push dx
+ push di
+ push si
+ call chkconfig
+ pop si
+ pop di
+ pop dx
+ pop cx
+ pop bx
+ pop ds
+ pop es
+ ret
+chkoemlocaldrv endp
+
+config_sys db "C:\CONFIG.SYS",0
+sizeofconfig dw 0
+filehandle dw 0
+workingmemptr dw 0
+deviceid db "DEVICE"
+csidrvid db "CSI\DRIVER\"
+localdrvname dw 0
+chkconfig proc near
+ call preprocess
+ jnc initstate
+ jmp notfoundret
+
+;
+; processing config.sys
+;
+; state 0
+; ds:si --> current line ( end of line is oah or 0dh )
+
+initstate:
+ mov si,dx
+state_0:
+ push cs
+ pop es
+ mov di,offset deviceid
+ mov cx,3
+ repz cmpsw
+ jz state_1
+ mov ax,0ffffh
+ jmp state_10
+state_1:
+ lodsb
+ cmp al,' '
+ jz state_1
+ cmp al,'='
+ jz state_2
+state_10a:
+ jmp state_10
+state_2:
+ lodsb
+ cmp al,' '
+ jz state_2
+ cmp al,'\'
+ jz state_5
+ cmp al,'A'
+ jb state_10a
+ cmp al,'z'
+ ja state_10a
+state_3:
+ dec si
+ mov cs:[localdrvname],si
+ inc si
+state_4:
+ lodsb
+ cmp al,':'
+ jz state_6
+ jmp state_10
+state_5:
+ dec si
+ mov cs:[localdrvname],si
+ inc si
+ jmp state_7
+state_6:
+ lodsb
+ cmp al,'\'
+ jz state_7
+ cmp al,'c'
+ jne state_10a
+ inc si
+state_7:
+ mov di,offset csidrvid
+ mov cx,11
+ repz cmpsb
+ jnz state_10a
+state_8:
+ lodsb
+ cmp al,'1'
+ jb state_10
+ cmp al,'z'
+ ja state_10
+state_9:
+tryopenlocaldrv:
+ mov dx,cs:[localdrvname]
+ mov si,dx
+chknextbyte:
+ lodsb
+ cmp al,0h
+ jz openfile
+ cmp al,' '
+ jne chknextbyte
+ dec si
+ mov byte ptr ds:[si],0
+openfile:
+ mov ax,3d00h ; open config.sys
+ stc
+ int 21h
+ jc notfoundret
+ mov bx,ax ; bx = file handle
+ mov ah,3eh
+ int 21h ; close local driver
+ jc notfoundret
+ jmp foundret
+
+state_10:
+ cmp al,1ah ; look current char. == eof ?
+ jz notfoundret
+ lodsb
+ cmp al,0
+ jz newlinestate
+ cmp al,1ah
+ jz notfoundret
+ jmp state_10
+newlinestate:
+ lodsb
+ cmp al,1ah
+ jz notfoundret
+ cmp al,0
+ jz newlinestate
+ dec si
+ jmp state_0
+notfoundret:
+ mov ax,0
+ jmp freemem
+foundret:
+ mov ax,1
+freemem:
+ push ax
+ call freememory
+ pop ax
+ ret
+
+chkconfig endp
+
+preprocess proc near
+ push cs
+ pop ds
+ mov dx,offset config_sys
+ mov ax,3d00h ; open config.sys
+ stc
+ int 21h
+ jc errorfile
+
+; get size of config.sys
+
+ mov bx,ax ; bx = file handle
+ mov cs:[filehandle],bx
+ xor cx,cx
+ xor dx,dx
+ mov ax,4202h ; move file ptr
+ int 21h
+ mov cs:[sizeofconfig],ax ; ax == size of config.sys
+ xor dx,dx ; ignore more than 64k of config
+ mov ax,4200h ; mov file ptr to beginning of file
+ int 21h
+
+; allocate for config.sys
+
+ mov ax,cs:[sizeofconfig]
+ add ax,15 ; change to para
+ rcr ax,1
+ shr ax,1
+ shr ax,1
+ shr ax,1
+ add ax,20h
+ mov bx,ax ; size of memory in para
+ mov ah,48h
+ int 21h
+ jc memerr
+ ; ax --> free memory
+ mov cs:[workingmemptr],ax
+
+; read config.sys
+
+ mov bx,cs:[filehandle] ; file handle
+ mov cx,cs:[sizeofconfig] ; byte count of reading
+ xor dx,dx
+ mov ds,ax ; ds:dx --> buffer
+ mov ah,3fh
+ int 21h
+ jc errorfile
+
+; translate to upper case
+
+ call transtoupper
+ clc
+ ret
+errorfile:
+memerr:
+ stc
+ ret
+preprocess endp
+
+; entry : ds:dx --> buffer
+; exit : none
+; description : translate all letter in buffer to upper type
+; ps ,don't change ds:dx
+
+transtoupper proc near
+ cld
+ mov cx,cs:[sizeofconfig]
+ mov si,dx
+transnext:
+ lodsb
+ cmp al,'A'
+ jb chklfcr
+ cmp al,'z'
+ ja chkcounter
+ sub al,'a'-'A'
+ mov ds:[si-1],al
+ jmp chkcounter
+chklfcr:
+ cmp al,0dh
+ jz setzero
+ cmp al,0ah
+ jz setzero
+ jmp chkcounter
+setzero:
+ mov al,0
+ mov ds:[si-1],al
+chkcounter:
+ loop transnext
+ ret
+transtoupper endp
+
+;entry : none ( free memory block ptr in [workingmem] )
+;exit : none
+
+freememory proc near
+ mov ax,cs:[workingmemptr]
+ mov es,ax
+ mov ah,49h
+ int 21h
+ ret
+freememory endp
+
+
+; name : maketempvector
+; entry : es:bx -->
+; dd original int 9 vector ( offfset ,segment )
+; dd original int 10h vector ( offfset ,segment )
+; dd original int 16h vector ( offfset ,segment )
+;
+; exit : none
+; description : 1. save local driver table in static area
+; 2. make temp. vector for int9 ,10h ,16h
+;
+oemdriverinst dw 0
+orgvectblptr dd 0
+
+ db 0eah
+dummyint9 dd 0
+ db 0eah
+dummyint10h dd 0
+ db 0eah
+dummyint16h dd 0
+
+csiint9 dd 0
+csiint10h dd 0
+csiint16h dd 0
+
+maketempvector proc near
+ push ds
+ push ax
+ push di
+ push si
+ push cx
+
+; save table ptr
+
+ mov word ptr cs:[orgvectblptr],bx
+ mov word ptr cs:[orgvectblptr+2],es
+ cmp cs:oemdriverinst,0
+ jnz ignoreint9
+
+; make temp. vector for int 9 ,
+
+ mov bx,9 ; int #
+ push cs
+ pop es
+ mov di,offset csiint9 ; es:di --> store area for csi vector
+ push cs
+ pop ds
+ mov si,offset dummyint9 ; ds:si --> dummy int service
+ call dummyvector
+
+ignoreint9:
+
+; make temp. vector for int 10h
+
+ mov bx,10h ; int #
+ push cs
+ pop es
+ mov di,offset csiint10h ; es:di --> store area for csi vector
+ push cs
+ pop ds
+ mov si,offset dummyint10h ; ds:si --> dummy int service
+ call dummyvector
+
+; make temp. vector for int 16h
+
+ mov bx,16h ; int #
+ push cs
+ pop es
+ mov di,offset csiint16h ; es:di --> store area for csi vector
+ push cs
+ pop ds
+ mov si,offset dummyint16h ; ds:si --> dummy int service
+ call dummyvector
+ pop cx
+ pop si
+ pop di
+ pop ax
+ pop ds
+ ret
+
+
+maketempvector endp
+
+;name : dummyvector
+; entey : ds:si --> dummy int sevice routine
+; es:di --> point to csi vector store area
+; bx == int number
+; exit : none
+; description :
+; setting dummy vector of int 9 ,10h,16h
+; for recover csi vector
+; /* phase 1*/
+; [ds:si]=[0:bx*4]
+; [ds:si+2]=[0:bx*4+2]
+; /* phase 2*/
+; [es:di]=[0:bx*4]
+; [es:di+2]=[0:bx*4+2]
+; /* phase 2*/
+; [0:bx*4]=si-1;
+; [0:bx*4+2]=ds;
+
+dummyvector proc near
+ shl bx,1 ; bx <- bx*4
+ shl bx,1 ; ie ,get offset of vector
+
+; phase 1
+; es --> 0
+; es:bx --> cpu int vector table
+
+ xor ax,ax
+ push es
+ mov es,ax
+ mov ax,es:[bx] ; get offset ds-->0
+ mov ds:[si],ax ; store offset
+ mov ax,es:[bx+2] ; get offset ds-->0
+ mov ds:[si+2],ax ; store segment
+ pop es
+
+; phase 2
+; ds --> 0
+; ds:bx --> cpu int vector table
+
+ xor ax,ax
+ push ds
+ mov ds,ax
+ mov ax,ds:[bx] ; get offset
+ mov es:[di],ax ; store offset
+ mov ax,ds:[bx+2] ; get offset
+ mov es:[di+2],ax ; store segment
+ pop ds
+
+; phase 3
+; es --> 0
+; es:bx --> cpu int vector table
+
+ xor ax,ax
+ push es
+ mov es,ax
+ dec si
+ mov es:[bx],si
+ mov ax,ds
+ mov es:[bx+2],ax
+ pop es
+ ret
+dummyvector endp
+
+; name : recovercsiint
+; entry : none
+; exit :none
+; description :
+; recover int 9 ,10h,16h ,for csi vector
+
+recovercsiint proc near
+ push es
+ push ds
+ push ax
+ push bx
+ push cx
+ push dx
+ push si
+ push di
+
+;recover int 9
+
+ cmp cs:oemdriverinst,0
+ jnz ignoreint9recover
+
+ push cs
+ pop ds
+ mov si,offset dummyint9
+ push cs
+ pop es
+
+ mov di,offset csiint9
+ mov bx,9
+ mov ax,0
+ call recoverint
+ignoreint9recover:
+
+; recover int 10h
+
+ push cs
+ pop ds
+ mov si,offset dummyint10h
+ push cs
+ pop es
+ mov di,offset csiint10h
+ mov bx,10h
+ mov ax,0+4
+ call recoverint
+
+;recover int 16h
+
+ push cs
+ pop ds
+ mov si,offset dummyint16h
+ push cs
+ pop es
+ mov di,offset csiint16h
+ mov bx,16h
+ mov ax,0+4+4
+ call recoverint
+ pop di
+ pop si
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ pop ds
+ pop es
+ ret
+recovercsiint endp
+
+; name : recoverint
+; entey : ds:si --> dummy int sevice routine
+; es:di --> point to csi vector store area
+; bx == int number
+; ax == 0 ; int 9
+; 4 ; int 10h
+; 4+4 ; int 16h
+; exit : none
+; description :
+; 1. if( [0:bx*4] == si-1 .and. [es:bx*4+2] == ds )
+; {
+; [0:bx*4] = [es:di];
+; [0:bx*4+2] = [es:di+2];
+; }
+; else
+; {
+; /* phase 1 */
+; [ds:si] = [(*orgvectblptr)+ax]
+; [ds:si+2]= [(*orgvectblptr)+ax+2];
+; /* phase 2 */
+; [orgvectblptr+ax) ]=[0:bx*4] ;
+; [orgvectblptr+ax+2 ]=[0:bx*4+2] ;
+; /* phase 3 */
+; [0:bx*4] = [es:di];
+; [0:bx*4+2] = [es:di+2];
+;
+;
+; }
+
+;
+
+recoverint proc near
+;chek vector change ?
+; es --> 0
+
+ push es
+ mov cx,ax
+ xor ax,ax
+ mov es,ax
+ shl bx,1
+ shl bx,1 ; es:bx --> cpu int vector
+ mov ax,si
+ dec ax
+ cmp es:[bx],ax ; offset same ?
+ jne vectorbechanged
+
+ mov ax,ds
+ cmp es:[bx+2],ax ; segmnet same ?
+ jne vectorbechanged
+ pop es
+
+; vector not be changed
+; ds --> 0
+
+ xor ax,ax
+ mov ds,ax ; ds:bx --> cpu int vector
+ mov ax,es:[di]
+ mov ds:[bx],ax
+ mov ax,es:[di+2]
+ mov ds:[bx+2],ax
+ ret
+
+vectorbechanged:
+
+;phase 1
+; di:es --> addres of local driver
+
+ pop es
+ push di
+ push es
+ mov di,word ptr cs:[orgvectblptr]
+ mov es,word ptr cs:[orgvectblptr+2]
+ add di,cx
+ mov ax,es:[di]
+ mov ds:[si],ax
+ mov ax,es:[di+2]
+ mov ds:[si+2],ax
+
+;phase2
+; di:es --> addres of local driver
+; ds --> 0
+
+ push ds
+ xor ax,ax
+ mov ds,ax
+ mov ax,ds:[bx] ; ds:bx --> cpu int vector
+ mov es:[di],ax
+ mov ax,ds:[bx+2]
+ mov es:[di+2],ax
+ pop ds
+ pop es
+ pop di
+
+;phase3
+; ds --> 0
+
+ xor ax,ax
+ push ds
+ mov ds,ax
+ mov cx,es:[di]
+ mov ds:[bx],cx ; ds:bx --> cpu int vector
+ mov cx,es:[di+2]
+ mov ds:[bx+2],cx
+ pop ds
+ ret
+
+recoverint endp
+
+;name : chklocalexist
+;entry : none
+;exit :none
+; descriptin : check local driver exist ?
+; if not exist system halt !
+; otherwise null return
+
+chklocalexist proc near
+ push ax
+ push cx
+ push dx
+ mov ah,0dbh
+ mov al,80h ; module_extsysutil
+ mov cx,01 ; syscmd_extquerysysmode
+ int 16h
+ test ax,8000h ; bit 15 on
+ jnz csisystemerror ; no,system halt
+ ; yes ,dx == country id
+ push dx ; save current id
+ mov dx,58h
+ mov ah,0dbh
+ mov al,80h ; module_extsysutil
+ mov cx,02 ; syscmd_extsetsysmode
+ int 16h
+ test ax,8000h ; bit 15 on
+ jnz localdrvnotfound ; no ,local driver error
+
+ pop cx
+ cmp cx,dx ; current id == previous id ?
+ jnz localdrvnotfound ; no ,local driver error
+
+ pop dx
+ pop cx
+ pop ax
+ ret
+
+localdrvnotfound:
+csisystemerror:
+ push cs
+ pop ds
+ mov dx,offset bootfailmsg
+ mov ah,9
+ int 21h
+ cli
+ hlt
+ ret
+
+chklocalexist endp
+ endif
+
+sysinitseg ends
+ end
diff --git a/private/mvdm/softpc.new/bios/sysinit2.asm b/private/mvdm/softpc.new/bios/sysinit2.asm
new file mode 100644
index 000000000..3439dd2ed
--- /dev/null
+++ b/private/mvdm/softpc.new/bios/sysinit2.asm
@@ -0,0 +1,1609 @@
+ page ,160
+title bios system initialization
+
+;
+;----------------------------------------------------------------------------
+;
+; Modification history
+;
+; 26-Feb-1991 sudeepb Ported for NT DOSEm
+;----------------------------------------------------------------------------
+
+
+ include version.inc ; set version build flags
+ include biosseg.inc ; establish bios segment structure
+
+lf equ 10
+cr equ 13
+tab equ 9
+
+; the following depends on the positions of the various letters in switchlist
+
+switchnum equ 11111000b ; which switches require number
+
+ include syscall.inc
+ include doscntry.inc
+ include devsym.inc
+ include ioctl.inc
+ include devmark.inc ; needed
+
+
+stacksw equ true ;include switchable hardware stacks
+
+ if ibmjapver
+noexec equ true
+ else
+noexec equ false
+ endif
+
+
+sysinitseg segment public
+
+assume cs:sysinitseg,ds:nothing,es:nothing,ss:nothing
+
+ extrn badopm:byte,crlfm:byte,badcom:byte,badmem:byte,badblock:byte
+ extrn badsiz_pre:byte,badld_pre:byte
+
+ extrn dosinfo:dword
+ extrn memory_size:word,fcbs:byte,keep:byte
+ extrn default_drive:byte,confbot:word,alloclim:word
+ extrn buffers:word,zero:byte,sepchr:byte
+ extrn files:byte
+ extrn count:word,chrptr:word
+ extrn bufptr:byte,memlo:word,prmblk:byte,memhi:word
+ extrn ldoff:word,area:word,packet:byte,unitcount:byte,
+ extrn break_addr:dword,bpb_addr:dword,drivenumber:byte
+ extrn com_level:byte, cmmt:byte, cmmt1:byte, cmmt2:byte
+ extrn cmd_indicator:byte
+ extrn donotshownum:byte
+ extrn multdeviceflag:byte
+ extrn devmark_addr:word
+ extrn setdevmarkflag:byte
+ extrn org_count:word
+
+ extrn pararound:near
+ extrn getchr:near
+ extrn stall:near
+ extrn error_line:near
+
+ extrn DevEntry:dword
+
+ insert_blank db 0 ; M051: indicates that blank has been
+ ; M051: inserted
+
+ public int24,open_dev,organize,mem_err,newline,calldev,badload
+ public prndev,auxdev,config,commnd,condev,getnum,badfil,prnerr
+ public round,delim,print
+ public parseline,
+ public setdoscountryinfo,set_country_path,move_asciiz
+ public cntry_drv,cntry_root,cntry_path
+ public delim
+ public pathstring
+
+ public MseDev ; NTVDM internal mouse driver
+
+
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : parseline
+;
+; entry point is parseline. al contains the first character in command line.
+;
+;----------------------------------------------------------------------------
+;
+
+parseline proc near
+ ; don't get character first time
+ push ds
+
+ push cs
+ pop ds
+ assume ds:sysinitseg
+
+nextswtch:
+ cmp al,cr ; carriage return?
+ jz done_line
+ cmp al,lf ; linefeed?
+ jz put_back ; put it back and done
+
+; anything less or equal to a space is ignored.
+
+ cmp al,' ' ; space?
+ jbe get_next ; skip over space
+ cmp al,'/'
+ jz getparm
+ stc ; mark error invalid-character-in-input
+ jmp short exitpl
+
+getparm:
+ call check_switch
+ mov word ptr switches,bx ; save switches read so far
+ jc swterr
+
+get_next:
+ call getchr
+ jc done_line
+ jmp nextswtch
+
+swterr:
+ jmp short exitpl ; exit if error
+
+done_line:
+ test word ptr switches,flagdrive ; see if drive specified
+ jnz okay
+ stc ; mark error no-drive-specified
+ jmp short exitpl
+
+okay:
+; mov ax,word ptr switches
+; and ax,0003h ; get flag bits for changeline and non-rem
+; mov word ptr deviceparameters.dp_deviceattributes,ax
+; mov word ptr deviceparameters.dp_tracktableentries, 0
+; clc ; everything is fine
+; call setdeviceparameters
+exitpl:
+ pop ds
+ ret
+
+put_back:
+ inc count ; one more char to scan
+ dec chrptr ; back up over linefeed
+ jmp short done_line
+
+parseline endp
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : check_switch
+;
+; processes a switch in the input. it ensures that the switch is valid, and
+; gets the number, if any required, following the switch. the switch and the
+; number *must* be separated by a colon. carry is set if there is any kind of
+; error.
+;
+;----------------------------------------------------------------------------
+;
+
+check_switch proc near
+
+ call getchr
+ jc err_check
+ and al,0dfh ; convert it to upper case
+ cmp al,'A'
+ jb err_check
+ cmp al,'Z'
+ ja err_check
+
+ push es
+
+ push cs
+ pop es
+
+ mov cl,byte ptr switchlist ; get number of valid switches
+ mov ch,0
+ mov di,1+offset switchlist ; point to string of valid switches
+ repne scasb
+
+ pop es
+ jnz err_check
+
+ mov ax,1
+ shl ax,cl ; set bit to indicate switch
+ mov bx,word ptr switches ; get switches so far
+ or bx,ax ; save this with other switches
+ mov cx,ax
+ test ax, switchnum ; test against switches that require number to follow
+ jz done_swtch
+
+ call getchr
+ jc err_swtch
+
+ cmp al,':'
+ jnz err_swtch
+
+ call getchr
+ push bx ; preserve switches
+ mov byte ptr cs:sepchr,' ' ; allow space separators
+ call getnum
+ mov byte ptr cs:sepchr,0
+ pop bx ; restore switches
+
+; because getnum does not consider carriage-return or line-feed as ok, we do
+; not check for carry set here. if there is an error, it will be detected
+; further on (hopefully).
+
+ call process_num
+
+done_swtch:
+ clc
+ ret
+
+err_swtch:
+ xor bx,cx ; remove this switch from the records
+err_check:
+ stc
+ ret
+
+check_switch endp
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : process_num
+;
+; this routine takes the switch just input, and the number following (if any),
+; and sets the value in the appropriate variable. if the number input is zero
+; then it does nothing - it assumes the default value that is present in the
+; variable at the beginning. zero is ok for form factor and drive, however.
+;
+;----------------------------------------------------------------------------
+;
+
+process_num proc near
+ test word ptr switches,cx ; if this switch has been done before,
+ jnz done_ret ; ignore this one.
+ test cx,flagdrive
+ jz try_f
+ mov byte ptr drive,al
+ jmp short done_ret
+
+try_f:
+ test cx,flagff
+ jz try_t
+
+; ensure that we do not get bogus form factors that are not supported
+
+; mov byte ptr deviceparameters.dp_devicetype,al
+ jmp short done_ret
+
+try_t:
+ or ax,ax
+ jz done_ret ; if number entered was 0, assume default value
+ test cx,flagcyln
+ jz try_s
+
+; mov word ptr deviceparameters.dp_cylinders,ax
+ jmp short done_ret
+
+try_s:
+ test cx,flagseclim
+ jz try_h
+ mov word ptr slim,ax
+ jmp short done_ret
+
+; must be for number of heads
+
+try_h:
+ mov word ptr hlim,ax
+
+done_ret:
+ clc
+ ret
+
+process_num endp
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : organize
+;
+;----------------------------------------------------------------------------
+;
+ assume ds:nothing, es:nothing
+organize proc near
+
+ mov cx,[count]
+ jcxz nochar1
+ call mapcase
+ xor si,si
+ mov di,si
+ xor ax,ax
+ mov com_level, 0
+
+;org1: call get ;skip leading control characters
+; cmp al,' '
+; jb org1
+org1:
+ call skip_comment
+ jz end_commd_line ; found a comment string and skipped.
+ call get2 ; not a comment string. then get a char.
+ cmp al, lf
+ je end_commd_line ; starts with a blank line.
+ cmp al, ' '
+ jbe org1 ; skip leading control characters
+ jmp short findit
+
+end_commd_line:
+ stosb ; store line feed char in buffer for the linecount.
+ mov com_level, 0 ; reset the command level.
+ jmp org1
+
+nochar1:
+ stc
+ ret
+
+findit:
+ push cx
+ push si
+ push di
+ mov bp,si
+ dec bp
+ mov si,offset comtab ;prepare to search command table
+ mov ch,0
+findcom:
+ mov di,bp
+ mov cl,[si]
+ inc si
+ jcxz nocom
+ repe cmpsb
+ lahf
+ add si,cx ;bump to next position without affecting flags
+ sahf
+ lodsb ;get indicator letter
+ jnz findcom
+ cmp byte ptr es:[di], cr ;the next char might be cr,lf
+ je gotcom0 ; such as in "rem",cr,lf case.
+ cmp byte ptr es:[di], lf
+ je gotcom0
+ push ax
+ mov al, byte ptr es:[di] ;now the next char. should be a delim.
+ call delim
+ pop ax
+ jnz findcom
+gotcom0:
+ pop di
+ pop si
+ pop cx
+ jmp short gotcom
+
+nocom:
+ pop di
+ pop si
+ pop cx
+ mov al,'Z'
+ stosb ; save indicator char.
+skip_line:
+ call get2
+ cmp al, lf ; skip this bad command line
+ jne skip_line
+ jmp end_commd_line ; handle next command line
+
+gotcom: stosb ;save indicator char in buffer
+ mov cmd_indicator, al ; save it for the future use.
+
+org2: call get2 ;skip the commad name until delimiter
+ cmp al, lf
+ je org21
+ cmp al, cr
+ je org21
+
+ call delim
+ jnz org2
+ jmp short org3
+
+org21: ;if cr or lf then
+ dec si ; undo si, cx register
+ inc cx ; and continue
+
+org3:
+ cmp cmd_indicator, 'Y' ; comment= command?
+ je get_cmt_token
+ cmp cmd_indicator, 'I' ; install= command?
+ je org_file
+ cmp cmd_indicator, 'D' ; device= command?
+ je org_file
+ cmp cmd_indicator, 'S' ; shell= is a special one!!!
+ je org_file
+ cmp cmd_indicator, '1' ; switches= command?
+ je org_switch
+
+ jmp org4
+
+org_switch:
+ call skip_comment
+ jz end_commd_line_brdg
+
+ call get2
+ call org_delim
+ jz org_switch
+
+ stosb
+ jmp org5
+
+org_file: ; get the filename and put 0 at end,
+ call skip_comment
+ jz org_put_zero
+
+ call get2 ; not a comment
+ call delim
+ jz org_file ; skip the possible delimeters
+
+ stosb ; copy the first non delim char found in buffer
+
+org_copy_file:
+ call skip_comment ; comment char in the filename?
+ jz org_put_zero ; then stop copying filename at that point
+
+ call get2
+ cmp al, '/' ; a switch char? (device=filename/xxx)
+ je end_file_slash ; this will be the special case.
+
+ stosb ; save the char. in buffer
+ call delim
+ jz end_copy_file
+
+ cmp al, ' '
+ ja org_copy_file ; keep copying
+ jmp short end_copy_file ; otherwise, assume end of the filename.
+
+get_cmt_token: ; get the token. just max. 2 char.
+ call get2
+ cmp al, ' ' ; skip white spaces or "=" char.
+ je get_cmt_token ; (we are allowing the other special
+ cmp al, tab ; charaters can used for comment id.
+ je get_cmt_token ; character.)
+ cmp al, '=' ; = is special in this case.
+ je get_cmt_token
+ cmp al, cr
+ je get_cmt_end ; cannot accept the carridge return
+ cmp al, lf
+ je get_cmt_end
+
+ mov cmmt1, al ; store it
+ mov cmmt, 1 ; 1 char. so far.
+ call get2
+ cmp al, ' '
+ je get_cmt_end
+ cmp al, tab
+ je get_cmt_end
+ cmp al, cr
+ je get_cmt_end
+ cmp al, lf
+ je end_commd_line_brdg
+
+ mov cmmt2, al
+ inc cmmt
+
+get_cmt_end:
+ call get2
+ cmp al, lf
+ jne get_cmt_end ; skip it.
+
+end_commd_line_brdg: jmp end_commd_line ; else jmp to end_commd_line
+
+org_put_zero: ; make the filename in front of
+ mov byte ptr es:[di], 0 ; the comment string to be an asciiz.
+ inc di
+ jmp end_commd_line ; (maybe null if device=/*)
+
+end_file_slash: ; al = "/" option char.
+ mov byte ptr es:[di],0 ; make a filename an asciiz
+ inc di ; and
+ stosb ; store "/" after that.
+ jmp short org5 ; continue with the rest of the line
+
+end_copy_file:
+ mov byte ptr es:[di-1], 0 ; make it an asciiz and handle the next char.
+ cmp al, lf
+ je end_commd_line_brdg
+ jmp short org5
+
+org4: ; org4 skips all delimiters after the command name except for '/'
+ call skip_comment
+ jz end_commd_line_brdg
+
+ call get2
+ call org_delim ; skip delimiters except '/' (mrw 4/88)
+ jz org4
+ jmp short org51
+
+org5: ; rest of the line
+ call skip_comment ; comment?
+ jz end_commd_line_brdg
+ call get2 ; not a comment.
+
+org51:
+ stosb ; copy the character
+ cmp al, '"' ; a quote ?
+ je at_quote
+ cmp al, ' '
+ ja org5
+ ; M051 - Start
+
+ cmp cmd_indicator, 'U' ; Q: is this devicehigh
+ jne not_dh ; N:
+ cmp al, lf ; Q: is this line feed
+ je org_dhlf ; Y: stuff a blank before the lf
+ cmp al, cr ; Q: is this a cr
+ jne org5 ; N:
+ mov byte ptr es:[di-1], ' ' ; overwrite cr with blank
+ stosb ; put cr after blank
+ inc [insert_blank] ; indicate that blank has been
+ ; inserted
+ jmp org5
+not_dh: ; M051 - End
+
+ cmp al, lf ; line feed?
+ je org1_brdg ; handles the next command line.
+ jmp org5 ; handles next char in this line.
+
+org_dhlf: ; M051 - Start
+ cmp [insert_blank], 1 ; Q:has a blank already been inserted
+ je org1_brdg ; Y:
+ mov byte ptr es:[di-1], ' ' ; overwrite lf with blank
+ stosb ; put lf after blank
+ ; M051 - End
+
+org1_brdg:
+ mov [insert_blank], 0 ; M051: clear blank indicator for
+ ; M051: devicehigh
+ jmp org1
+
+at_quote:
+ cmp com_level, 0
+ je up_level
+ mov com_level, 0 ; reset it.
+ jmp org5
+
+up_level:
+ inc com_level ; set it.
+ jmp org5
+
+organize endp
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : get2
+;
+;----------------------------------------------------------------------------
+;
+get2 proc near
+ jcxz noget
+ mov al,es:[si]
+ inc si
+ dec cx
+od_ret:
+ ret
+noget:
+ pop cx
+ mov count,di
+ mov org_count, di
+ xor si,si
+ mov chrptr,si
+ng_ret:
+ ret
+get2 endp
+
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : skip_comment
+;
+;skip the commented string until lf, if current es:si-> a comment string.
+;in) es:si-> sting
+; cx -> length.
+;out) zero flag not set if not found a comment string.
+; zero flag set if found a comment string and skipped it. al will contain
+; the line feed charater at this moment when return.
+; ax register destroyed.
+; if found, si, cx register adjusted accordingly.
+;
+;----------------------------------------------------------------------------
+;
+skip_comment proc near
+
+ jcxz noget ; get out of the organize routine.
+ cmp com_level, 0 ; only check it if parameter level is 0.
+ jne no_commt ; (not inside quotations)
+
+ cmp cmmt, 1
+ jb no_commt
+
+ mov al, es:[si]
+ cmp cmmt1, al
+ jne no_commt
+
+ cmp cmmt, 2
+ jne skip_cmmt
+
+ mov al, es:[si+1]
+ cmp cmmt2, al
+ jne no_commt
+
+skip_cmmt:
+ jcxz noget ; get out of organize routine.
+ mov al, es:[si]
+ inc si
+ dec cx
+ cmp al, lf ; line feed?
+ jne skip_cmmt
+
+no_commt:
+ ret
+
+skip_comment endp
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : delim
+;
+;----------------------------------------------------------------------------
+;
+delim proc near
+ cmp al,'/' ; ibm will assume "/" as an delimeter.
+ jz delim_ret
+
+ cmp al, 0 ; special case for sysinit!!!
+ jz delim_ret
+
+org_delim: ; used by organize routine except for getting
+ cmp al,' ' ;the filename.
+ jz delim_ret
+ cmp al,9
+ jz delim_ret
+ cmp al,'='
+ jz delim_ret
+ cmp al,','
+ jz delim_ret
+ cmp al,';'
+delim_ret:
+ ret
+delim endp
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : newline
+;
+; newline returns with first character of next line
+;
+;----------------------------------------------------------------------------
+;
+
+newline proc near
+
+ call getchr ;skip non-control characters
+ jc nl_ret
+ cmp al,lf ;look for line feed
+ jnz newline
+ call getchr
+nl_ret:
+ ret
+
+newline endp
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : mapcase
+;
+;----------------------------------------------------------------------------
+;
+mapcase proc near
+ push cx
+ push si
+ push ds
+
+ push es
+ pop ds
+
+ xor si,si
+
+convloop:
+ lodsb
+
+ ifdef DBCS
+ call testkanj
+ jz normconv ; if this is not lead byte
+
+ mov ah,al
+ lodsb ; get tail byte
+ cmp ax,DB_SPACE
+ jnz @f ; if this is not dbcs space
+ mov word ptr [si-2],' ' ; set 2 single space
+@@:
+
+ dec cx
+ jcxz convdone ;just ignore 1/2 kanji error
+ jmp short noconv
+
+;fall through, know al is not in 'a'-'z' range
+
+normconv:
+ endif
+
+ cmp al,'a'
+ jb noconv
+ cmp al,'z'
+ ja noconv
+ sub al,20h
+ mov [si-1],al
+noconv:
+ loop convloop
+
+convdone:
+ pop ds
+ pop si
+ pop cx
+ ret
+
+ ifdef DBCS
+
+ public testkanj
+testkanj:
+ push si
+ push ds
+
+ push ax
+ mov ax,6300h ; get dos dbcs vector
+ int 21h
+ pop ax
+
+bdbcs_do:
+
+ cmp ds:word ptr [si],0 ; end of lead byte info?
+ jz bdbcs_notfound ; jump if so
+ cmp al,ds:[si] ; less than first byte character?
+ jb bdbcs_next ; jump if not
+ cmp al,ds:[si+1] ; grater than first byte character?
+ ja bdbcs_next
+
+bdbcs_found:
+
+ push ax
+ xor ax,ax
+ inc ax ; reset zero flag
+ pop ax
+
+bdbcs_exit:
+
+ pop ds
+ pop si
+ ret
+
+bdbcs_notfound:
+
+ push ax
+ xor ax,ax ; set zero flag
+ pop ax
+ jmp short bdbcs_exit
+
+bdbcs_next:
+
+ add si,2 ; points next lead byte table
+ jmp short bdbcs_do
+
+ endif ; DBCS
+
+mapcase endp
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : round
+;
+; round the values in memlo and memhi to paragraph boundary.
+; perform bounds check.
+;
+;----------------------------------------------------------------------------
+;
+
+round proc near
+
+ push ax
+ mov ax,[memlo]
+
+ call pararound ; para round up
+
+ add [memhi],ax
+ mov [memlo],0
+ mov ax,memhi ; ax = new memhi
+ cmp ax,[alloclim] ; if new memhi >= alloclim, error
+ jae mem_err
+ test cs:[setdevmarkflag], for_devmark
+ jz skip_set_devmarksize
+ push es
+ push si
+ mov si, cs:[devmark_addr]
+ mov es, si
+ sub ax, si
+ dec ax
+ mov es:[devmark_size], ax ; paragraph
+ and cs:[setdevmarkflag], not_for_devmark
+ pop si
+ pop es
+skip_set_devmarksize:
+ pop ax
+ clc ;clear carry
+ ret
+
+mem_err:
+ mov dx,offset badmem
+ push cs
+ pop ds
+ call print
+ jmp stall
+
+round endp
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : calldev
+;
+;----------------------------------------------------------------------------
+;
+calldev proc near
+
+ mov ds,word ptr cs:[DevEntry+2]
+ add bx,word ptr cs:[DevEntry] ;do a little relocation
+ mov ax,ds:[bx]
+
+ push word ptr cs:[DevEntry]
+ mov word ptr cs:[DevEntry],ax
+ mov bx,offset packet
+ call [DevEntry]
+ pop word ptr cs:[DevEntry]
+ ret
+
+calldev endp
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : todigit
+;
+;----------------------------------------------------------------------------
+;
+todigit proc near
+ sub al,'0'
+ jb notdig
+ cmp al,9
+ ja notdig
+ clc
+ ret
+notdig:
+ stc
+ ret
+todigit endp
+
+;
+;----------------------------------------------------------------------------
+;
+; procedure : getnum
+;
+; getnum parses a decimal number.
+; returns it in ax, sets zero flag if ax = 0 (may be considered an
+; error), if number is bad carry is set, zero is set, ax=0.
+;
+;----------------------------------------------------------------------------
+;
+
+getnum proc near
+
+ push bx
+ xor bx,bx ; running count is zero
+
+b2:
+ call todigit ; do we have a digit
+ jc badnum ; no, bomb
+
+ xchg ax,bx ; put total in ax
+ push bx ; save digit
+ mov bx,10 ; base of arithmetic
+ mul bx ; shift by one decimal di...
+ pop bx ; get back digit
+ add al,bl ; get total
+ adc ah,0 ; make that 16 bits
+ jc badnum ; too big a number
+
+ xchg ax,bx ; stash total
+
+ call getchr ;get next digit
+ jc b1 ; no more characters
+ cmp al, ' ' ; space?
+ jz b15 ; then end of digits
+ cmp al, ',' ; ',' is a seperator!!!
+ jz b15 ; then end of digits.
+ cmp al, tab ; tab
+ jz b15
+ cmp al,sepchr ; allow 0 or special separators
+ jz b15
+ cmp al,'/' ; see if another switch follows
+ nop ; cas - remnant of old bad code
+ nop
+ jz b15
+ cmp al,lf ; line-feed?
+ jz b15
+ cmp al,cr ; carriage return?
+ jz b15
+ or al,al ; end of line separator?
+ jnz b2 ; no, try as a valid char...
+
+b15:
+ inc count ; one more character to s...
+ dec chrptr ; back up over separator
+b1:
+ mov ax,bx ; get proper count
+ or ax,ax ; clears carry, sets zero accordingly
+ pop bx
+ ret
+badnum:
+ mov sepchr,0
+ xor ax,ax ; set zero flag, and ax = 0
+ pop bx
+ stc ; and carry set
+ ret
+
+getnum endp
+
+;*****************************************************************
+
+setdoscountryinfo proc near
+
+;input: es:di -> pointer to dos_country_cdpg_info
+; ds:0 -> buffer.
+; si = 0
+; ax = country id
+; dx = code page id. (if 0, then use ccsyscodepage as a default.)
+; bx = file handle
+; this routine can handle maxium 438 country_data entries.
+;
+;output: dos_country_cdpg_info set.
+; carry set if any file read failure or wrong information in the file.
+; carry set and cx = -1 if cannot find the matching country_id, codepage
+; _id in the file.
+
+ push di
+ push ax
+ push dx
+
+ xor cx,cx
+ xor dx,dx
+ mov ax,512 ;read 512 bytes
+ call readincontrolbuffer ;read the file header
+ jc setdosdata_fail
+
+ push es
+ push si
+
+ push cs
+ pop es
+
+ mov di,offset country_file_signature
+ mov cx,8 ;length of the signature
+ repz cmpsb
+
+ pop si
+ pop es
+ jnz setdosdata_fail ;signature mismatch
+
+ add si,18 ;si -> county info type
+ cmp byte ptr ds:[si],1 ;only accept type 1 (currently only 1 header type)
+ jne setdosdata_fail ;cannot proceed. error return
+
+ inc si ;si -> file offset
+ mov dx,word ptr ds:[si] ;get the info file offset.
+ mov cx,word ptr ds:[si+2]
+ mov ax,6144 ;read 6144 bytes.
+ call readincontrolbuffer ;read info
+ jc setdosdata_fail
+
+ mov cx, word ptr ds:[si] ;get the # of country, codepage combination entries
+ cmp cx, 438 ;cannot handle more than 438 entries.
+ ;
+ ja setdosdata_fail
+
+ inc si
+ inc si ;si -> entry information packet
+ pop dx ;restore code page id
+ pop ax ;restore country id
+ pop di
+
+setdoscntry_find: ;search for desired country_id,codepage_id.
+ cmp ax, word ptr ds:[si+2] ;compare country_id
+ jne setdoscntry_next
+
+ cmp dx, 0 ;no user specified code page ?
+ je setdoscntry_any_codepage;then no need to match code page id.
+ cmp dx, word ptr ds:[si+4] ;compare code page id
+ je setdoscntry_got_it
+
+setdoscntry_next:
+ add si, word ptr ds:[si] ;next entry
+ inc si
+ inc si ;take a word for size of entry itself
+ loop setdoscntry_find
+
+ mov cx, -1 ;signals that bad country id entered.
+setdoscntry_fail:
+ stc
+ ret
+
+setdosdata_fail:
+ pop si
+ pop cx
+ pop di
+ jmp short setdoscntry_fail
+
+setdoscntry_any_codepage: ;use the code_page_id of the country_id found.
+ mov dx, word ptr ds:[si+4]
+
+setdoscntry_got_it: ;found the matching entry
+ mov cs:cntrycodepage_id, dx ;save code page id for this country.
+ mov dx, word ptr ds:[si+10] ;get the file offset of country data
+ mov cx, word ptr ds:[si+12]
+ mov ax, 512 ;read 512 bytes
+ call readincontrolbuffer
+ jc setdoscntry_fail
+
+ mov cx, word ptr ds:[si] ;get the number of entries to handle.
+ inc si
+ inc si ;si -> first entry
+
+setdoscntry_data:
+ push di ;es:di -> dos_country_cdpg_info
+ push cx ;save # of entry left
+ push si ;si -> current entry in control buffer
+
+ mov al, byte ptr ds:[si+2] ;get data entry id
+ call getcountrydestination ;get the address of destination in es:di
+ jc setdoscntry_data_next ;no matching data entry id in dos
+
+ mov dx, word ptr ds:[si+4] ;get offset of data
+ mov cx, word ptr ds:[si+6]
+ mov ax,4200h
+ stc
+ int 21h ;move pointer
+ jc setdosdata_fail
+
+ mov dx,512 ;start of data buffer
+ mov cx,20 ;read 20 bytes only. we only need to
+ mov ah,3fh ;look at the length of the data in the file.
+ stc
+ int 21h ;read the country.sys data
+ jc setdosdata_fail ;read failure
+
+ cmp ax,cx
+ jne setdosdata_fail
+
+ mov dx,word ptr ds:[si+4] ;get offset of data again.
+ mov cx,word ptr ds:[si+6]
+ mov ax,4200h
+ stc
+ int 21h ;move pointer back again
+ jc setdosdata_fail
+
+ push si
+ mov si,(512+8) ;get length of the data from the file
+ mov cx,word ptr ds:[si]
+ pop si
+ mov dx,512 ;start of data buffer
+ add cx,10 ;signature + a word for the length itself
+ mov ah,3fh ;read the data from the file.
+ stc
+ int 21h
+ jc setdosdata_fail
+
+ cmp ax, cx
+ jne setdosdata_fail
+
+ mov al,byte ptr ds:[si+2] ;save data id for future use.
+ mov si,(512+8) ;si-> data buffer + id tag field
+ mov cx,word ptr ds:[si] ;get the length of the file
+ inc cx ;take care of a word for lenght of tab
+ inc cx ;itself.
+ cmp cx,(2048 - 512 - 8) ;fit into the buffer?
+ ja setdosdata_fail
+
+ if bugfix
+ call setdbcs_before_copy
+ endif
+
+ cmp al, setcountryinfo ;is the data for setcountryinfo table?
+ jne setdoscntry_mov ;no, don't worry
+
+ push word ptr es:[di+ccmono_ptr-cccountryinfolen] ;cannot destroy ccmono_ptr address. save them.
+ push word ptr es:[di+ccmono_ptr-cccountryinfolen+2] ;at this time di -> cccountryinfolen
+ push di ;save di
+
+ push ax
+ mov ax,cs:cntrycodepage_id ;do not use the code page info in country_info
+ mov ds:[si+4], ax ;use the saved one for this !!!!
+ pop ax
+
+setdoscntry_mov:
+ rep movsb ;copy the table into dos
+ cmp al, setcountryinfo ;was the ccmono_ptr saved?
+ jne setdoscntry_data_next
+
+ pop di ;restore di
+ pop word ptr es:[di+ccmono_ptr-cccountryinfolen+2] ;restore
+ pop word ptr es:[di+ccmono_ptr-cccountryinfolen]
+
+setdoscntry_data_next:
+ pop si ;restore control buffer pointer
+ pop cx ;restore # of entries left
+ pop di ;restore pointer to dso_country_cdpg
+ add si, word ptr ds:[si] ;try to get the next entry
+ inc si
+ inc si ;take a word of entry length itself
+ dec cx
+ cmp cx,0
+ je setdoscntry_ok
+ jmp setdoscntry_data
+
+setdoscntry_ok:
+ ret
+setdoscountryinfo endp
+
+ if bugfix
+setdbcs_before_copy proc near
+
+ cmp al,setdbcs ; dbcs vector set?
+ jnz @f ; jump if not
+ cmp word ptr es:[di], 0 ; zero byte data block?
+ jz @f ; jump if so
+
+ push di
+ push ax
+ push cx
+ mov cx,es:[di] ; load block length
+ add di,2 ; points actual data
+ xor al,al ; fill bytes
+ rep stosb ; clear data block
+ pop cx
+ pop ax
+ pop di
+@@:
+ ret
+setdbcs_before_copy endp
+ endif
+
+getcountrydestination proc near
+
+;get the destination address in the dos country info table.
+;input: al - data id
+; es:di -> dos_country_cdpg_info
+;on return:
+; es:di -> destination address of the matching data id
+; carry set if no matching data id found in dos.
+
+ push cx
+ add di,ccnumber_of_entries ;skip the reserved area, syscodepage etc.
+ mov cx,word ptr es:[di] ;get the number of entries
+ inc di
+ inc di ;si -> the first start entry id
+
+getcntrydest:
+ cmp byte ptr es:[di],al
+ je getcntrydest_ok
+ cmp byte ptr es:[di],setcountryinfo ;was it setcountryinfo entry?
+ je getcntrydest_1
+
+ add di,5 ;next data id
+ jmp short getcntrydest_loop
+
+getcntrydest_1:
+ add di,new_country_size + 3 ;next data id
+getcntrydest_loop:
+ loop getcntrydest
+ stc
+ jmp short getcntrydest_exit
+
+getcntrydest_ok:
+ cmp al,setcountryinfo ;select country info?
+ jne getcntrydest_ok1
+
+ inc di ;now di -> cccountryinfolen
+ jmp short getcntrydest_exit
+
+getcntrydest_ok1:
+ les di,dword ptr es:[di+1] ;get the destination in es:di
+
+getcntrydest_exit:
+ pop cx
+ ret
+getcountrydestination endp
+
+
+readincontrolbuffer proc near
+
+;move file pointer to cx:dx
+;read ax bytes into the control buffer. (should be less than 2 kb)
+;si will be set to 0 hence ds:si points to the control buffer.
+;entry: cx,dx offset from the start of the file where the read/write pointer
+; be moved.
+; ax - # of bytes to read
+; bx - file handle
+; ds - buffer seg.
+;return: the control data information is read into ds:0 - ds:0200.
+; cx,dx value destroyed.
+; carry set if error in reading file.
+
+ push ax ;# of bytes to read
+ mov ax, 4200h
+ stc
+ int 21h ;move pointer
+ pop cx ;# of bytes to read
+ jc ricb_exit
+
+ xor dx,dx ;ds:dx -> control buffer
+ xor si,si
+ mov ah,3fh ;read into the buffer
+ stc
+ int 21h ;should be less than 1024 bytes.
+
+ricb_exit:
+ ret
+readincontrolbuffer endp
+
+
+set_country_path proc near
+
+;in: ds - sysinitseg, es - confbot, si -> start of the asciiz path string
+; dosinfo_ext, cntry_drv, cntry_root, cntry_path
+; assumes current directory is the root directory.
+;out: ds:di -> full path (cntry_drv).
+; set the cntry_drv string from the country=,,path command.
+; ds, es, si value saved.
+
+ push si
+
+ push ds ;switch ds, es
+ push es
+ pop ds
+ pop es ;now ds -> confbot, es -> sysinitseg
+
+ call chk_drive_letter ;current ds:[si] is a drive letter?
+ jc scp_default_drv ;no, use current default drive.
+
+ mov al, byte ptr ds:[si]
+ inc si
+ inc si ;si -> next char after ":"
+ jmp short scp_setdrv
+
+scp_default_drv:
+ mov ah, 19h
+ int 21h
+ add al, "A" ;convert it to a character.
+
+scp_setdrv:
+ mov cs:cntry_drv, al ;set the drive letter.
+ mov di, offset cntry_path
+ mov al, byte ptr ds:[si]
+ cmp al, "\"
+ je scp_root_dir
+
+ cmp al,"/" ;let's accept "/" as an directory delim
+ je scp_root_dir
+
+ jmp short scp_path
+
+scp_root_dir:
+ dec di ;di -> cntry_root
+scp_path:
+ call move_asciiz ;copy it
+
+ mov di, offset cntry_drv
+scpath_exit:
+
+ push ds ;switch ds, es
+ push es
+ pop ds
+ pop es ;ds, es value restored
+
+ pop si
+ ret
+set_country_path endp
+
+
+chk_drive_letter proc near
+;check if ds:[si] is a drive letter followed by ":".
+;assume that every alpha charater is already converted to upper case.
+;carry set if not.
+
+ push ax
+ cmp byte ptr ds:[si], "A"
+ jb cdletter_no
+ cmp byte ptr ds:[si], "Z"
+ ja cdletter_no
+ cmp byte ptr ds:[si+1], ":"
+ jne cdletter_no
+
+ jmp short cdletter_exit
+
+cdletter_no:
+ stc
+
+cdletter_exit:
+ pop ax
+ ret
+chk_drive_letter endp
+
+
+move_asciiz proc near
+;in: ds:si -> source es:di -> target
+;out: copy the string until 0.
+;assumes there exists a 0.
+
+masciiz_loop:
+ movsb
+ cmp byte ptr ds:[si-1],0 ;was it 0?
+ jne masciiz_loop
+ ret
+move_asciiz endp
+
+;
+; ds:dx points to string to output (asciz)
+;
+; prints <badld_pre> <string> <badld_post>
+
+badfil:
+ push cs
+ pop es
+
+ mov si,dx
+badload:
+ mov dx,offset badld_pre ;want to print config error
+ mov bx, offset crlfm
+
+prnerr:
+ push cs
+ pop ds
+ call print
+
+prn1:
+ mov dl,es:[si]
+ or dl,dl
+ jz prn2
+ mov ah,std_con_output
+ int 21h
+ inc si
+ jmp prn1
+
+prn2:
+ mov dx,bx
+ call print
+ cmp donotshownum,1 ; suppress line number when handling command.com
+ je prnexit
+ call error_line
+prnexit:
+ ret
+
+print:
+ cmp cs:bEchoConfig, 0 ; NTVDM skip print call, Jonle
+ je prnexit
+
+ mov ah,std_con_string_output
+ int 21h
+
+ ret
+
+ if noexec
+
+; load non exe file called [ds:dx] at memory location es:bx
+
+ldfil:
+ push ax
+ push bx
+ push cx
+ push dx
+ push si
+ push ds
+ push bx
+
+ xor ax,ax ;open the file
+ mov ah,open
+ stc ;in case of int 24
+ int 21h
+ pop dx ;clean stack in case jump
+ jc ldret
+
+ push dx
+ mov bx,ax ;handle in bx
+ xor cx,cx
+ xor dx,dx
+ mov ax,(lseek shl 8) or 2
+ stc ;in case of int 24
+ int 21h ; get file size in dx:ax
+ jc ldclsp
+
+ or dx,dx
+ jnz lderrp ; file >64k
+ pop dx
+
+ push dx
+ mov cx,es ; cx:dx is xaddr
+ add dx,ax ; add file size to xaddr
+ jnc dosize
+ add cx,1000h ; ripple carry
+dosize:
+ mov ax,dx
+ call pararound
+ mov dx,ax
+
+ add cx,dx
+ cmp cx,[alloclim]
+ jb okld
+ jmp mem_err
+
+okld:
+ xor cx,cx
+ xor dx,dx
+ mov ax,lseek shl 8 ;reset pointer to beginning of file
+ stc ;in case of int 24
+ int 21h
+ jc ldclsp
+
+ pop dx
+
+ push es ;read the file in
+ pop ds ;trans addr is ds:dx
+
+ mov cx,0ff00h ; .com files arn't any bigger than
+ ; 64k-100h
+ mov ah,read
+ stc ;in case of int 24
+ int 21h
+ jc ldcls
+
+ mov si,dx ;check for exe file
+ cmp word ptr [si],"ZM"
+ clc ; assume ok
+ jnz ldcls ; only know how to do .com files
+
+ stc
+ jmp short ldcls
+
+lderrp:
+ stc
+ldclsp:
+ pop dx ;clean stack
+ldcls:
+ pushf
+ mov ah,close ;close the file
+ stc
+ int 21h
+ popf
+
+ldret: pop ds
+ pop si
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ ret
+ endif
+
+;
+; open device pointed to by dx, al has access code
+; if unable to open do a device open null device instead
+;
+open_dev:
+ call open_file
+ jnc open_dev3
+
+open_dev1:
+ mov dx,offset nuldev
+ call open_file
+of_ret:
+ ret
+
+open_dev3:
+ mov bx,ax ; handle from open to bx
+ xor ax,ax ; get device info
+ mov ah,ioctl
+ int 21h
+ test dl,10000000b
+ jnz of_ret
+
+ mov ah,close
+ int 21h
+ jmp open_dev1
+
+open_file:
+ mov ah,open
+ stc
+ int 21h
+ ret
+
+; test int24. return back to dos with the fake user response of "fail"
+
+int24:
+ mov al, 3 ; fail the system call
+ iret ; return back to dos.
+
+include copyrigh.inc ; copyright statement
+
+nuldev db "NUL",0
+condev db "CON",0
+auxdev db "AUX",0
+prndev db "PRN",0
+MseDev db "MOUSE",0 ; NTVDM for internal spc mouse
+
+
+
+
+; NTVDM we use a temp file for config.sys 23-Nov-1992 Jonle
+; config db "C:\CONFIG.SYS",0
+config db 64 dup (0)
+
+cntry_drv db "A:"
+cntry_root db "\"
+cntry_path db "COUNTRY.SYS",0
+ db 52 dup (0)
+
+country_file_signature db 0ffh,'COUNTRY'
+
+cntrycodepage_id dw ?
+
+commnd db "\COMMAND.COM",0
+ db 51 dup (0)
+
+pathstring db 64 dup (0)
+
+comtab label byte
+
+; cmd len command cmd code
+; ------- ------- --------
+;
+ db 7, "BUFFERS", 'B'
+ db 5, "BREAK", 'C'
+ db 6, "DEVICE", 'D'
+ db 10, "DEVICEHIGH", 'U'
+ db 5, "FILES", 'F'
+ db 4, "FCBS", 'X'
+ db 9, "LASTDRIVE", 'L'
+ db 10, "MULTITRACK", 'M'
+ db 8, "DRIVPARM", 'P'
+if stacksw
+ db 6, "STACKS", 'K'
+endif
+ db 7, "COUNTRY", 'Q'
+ db 5, "SHELL", 'S'
+ db 7, "INSTALL", 'I'
+ db 7, "COMMENT", 'Y'
+ db 3, "REM", '0'
+ db 8, "SWITCHES", '1'
+ db 3, "DOS", 'H'
+ db 10, "ECHOCONFIG", 'E' ; NTVDM 14-Aug-1992 Jonle
+ db 11, "NTCMDPROMPT", 'T' ; NTVDM 06-May-1993 sudeepb
+ db 7, "DOSONLY", 'O' ; NTVDM 06-May-1993 sudeepb
+ db 0
+
+hlim dw 2
+slim dw 9
+
+public bEchoConfig ; NTVDM - 14-Aug-1992 Jonle
+bEchoConfig db 0
+
+public drive
+drive db ?
+
+public switches
+switches dw 0
+
+
+switchlist db 8,"FHSTDICN" ; preserve the positions of n and c.
+
+; the following depend on the positions of the various letters in switchlist
+
+;switchnum equ 11111000b ; which switches require number
+
+flagec35 equ 00000100b ; electrically compatible 3.5 inch disk drive
+flagdrive equ 00001000b
+flagcyln equ 00010000b
+flagseclim equ 00100000b
+flagheads equ 01000000b
+flagff equ 10000000b
+
+sysinitseg ends
+ end
+