;    File              : $Workfile$
;
;    Description       :
;
;    Original Author   : 
;
;    Last Edited By    : $Author$
;
;-----------------------------------------------------------------------;
;    Copyright Work of Caldera, Inc. All Rights Reserved.
;      
;    THIS WORK IS A COPYRIGHT WORK AND CONTAINS CONFIDENTIAL,
;    PROPRIETARY AND TRADE SECRET INFORMATION OF CALDERA, INC.
;    ACCESS TO THIS WORK IS RESTRICTED TO (I) CALDERA, INC. EMPLOYEES
;    WHO HAVE A NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF
;    THEIR ASSIGNMENTS AND (II) ENTITIES OTHER THAN CALDERA, INC. WHO
;    HAVE ACCEPTED THE CALDERA OPENDOS SOURCE LICENSE OR OTHER CALDERA LICENSE
;    AGREEMENTS. EXCEPT UNDER THE EXPRESS TERMS OF THE CALDERA LICENSE
;    AGREEMENT NO PART OF THIS WORK MAY BE USED, PRACTICED, PERFORMED,
;    COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, ABRIDGED,
;    CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST,
;    TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF
;    CALDERA, INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT
;    AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO CRIMINAL AND
;    CIVIL LIABILITY.
;-----------------------------------------------------------------------;
;
;    *** Current Edit History ***
;    *** End of Current Edit History ***
;
;    $Log$
;    INT2F.A86 1.23 94/11/14 10:34:17
;    Fixed the NWDOS.386 stuff. Still point at startupinfo, but take out the
;    vxdname and the vxdnameseg entries.
;    INT2F.A86 1.22 94/10/07 09:05:11
;    Added patch 005 as source fix. Removed the stuff to load NWDOS.386 as
;    the vxd is no longer needed.
;    INT2F.A86 1.21 94/03/24 18:40:10
;    Support para-aligned HMA allocations (Stacker 4 bug)    
;    INT2F.A86 1.20 93/09/28 19:43:12
;    Extra field to export upper memory root on windows startup
;    INT2F.A86 1.19 93/09/06 15:37:35
;    Startup Broadcast fills entry ES:BX into SwStartupInfo "next" link field
;    INT2F.A86 1.16 93/08/06 16:35:58
;    Change DELWATCH int 2F hook for getnblk to getblk
;    INT2F.A86 1.15 93/07/20 22:47:21
;    Pass on Int 2F/12FF to BIOS - (really to CONFIG)
;    INT2F.A86 1.11 93/06/11 02:10:01
;    GateA20 disabled on EXEC for EXEPACKED apps
;    ENDLOG
;
;   DOS INT 2F Support
;
	include	pcmode.equ
	include i:msdos.equ
	include	i:mserror.equ
	include	i:driver.equ
	include	i:psp.def
	include	i:doshndl.def
	include	i:redir.equ

PCM_CODE	CSEG	BYTE

	extrn	get_dseg:near		; in PCMIF.PCM
	extrn	do_int24:near		; in PCMIF.PCM
	extrn	dos_entry:near
	extrn	strlen:near		; in SUPPORT.PCM
	extrn	toupper:near		; in UTILS.FDO (in BDOS_CODE)
	extrn	ReadTOD:near		; in UTILS.FDO (in BDOS_CODE)
	extrn	share_delay:near	; in UTILS.FDO (in BDOS_CODE)

eject

PointHMA:
;--------
; On Entry:
;	None
; On Exit:
;	DS = DOS data seg
;	BX = bytes available (0 if none)
;	ES:DI -> start of available area (FFFF:FFFF if none)
;	All other regs preserved
;
	call	get_dseg		; DS = DOS data
	mov	di,0FFFFh
	mov	es,di			; ES:DI = FFFF:FFFF
	mov	bx,hmaRoot
	test	bx,bx			; have we an HMA ?
	 jz	PointHMA10
	mov	di,bx			; ES:DI = start of HMA free area
	mov	bx,es:2[bx]		; BX = length
	sub	bx,4			; forget the header
	and	bl,not 15		; make it complete para's
PointHMA10:
	ret	

QueryHMA:
;--------
; On Entry:
;	None
; On Exit:
;	BX = bytes available (0 if none)
;	ES:DI -> start of available area (FFFF:FFFF if none)
;	All other regs preserved
;
	push	ds
	call	PointHMA		; registers ready for return
	jmps	int2F_BIOS		; give CONFIG processing a chance


AllocHMA:
;--------
; On Entry:
;	BX = bytes required
; On Exit:
;	ES:DI -> start of available area (FFFF:FFFF if none)
;
	push	ds
	xchg	ax,bx			; AX = bytes required
	add	ax,15
	and	al,not 15		; round up to para's
	call	PointHMA
	xchg	ax,bx
	cmp	ax,bx			; enough room up there ?
	 jae	AllocHMA10
	mov	di,es			; ES:DI = FFFF:FFFF
	jmps	AllocHMA20
AllocHMA10:
	add	hmaRoot,bx		; set new start
	mov	ax,es:2[di]		; get length
	sub	ax,bx			; subtract what we just allocated
	mov	es:2[di+bx],ax		; set new length
	cmp	ax,4			; have we shrunk to zero spare ?
	mov	ax,es:[di]		; move link field to
	mov	es:[di+bx],ax		;  new head
	 ja	AllocHMA20
	mov	hmaRoot,ax		; set new hmaRoot
AllocHMA20:
	mov	ax,4A02h		; "restore" AX
	pop	ds
	iret

eject
;	++++++++++++++++++++++++++++
;	Int 2F - Multiplex Interrupt
;	++++++++++++++++++++++++++++
;
;	This interrupt is used by DBASE III Plus
;
;	On Entry:-   	AH -	Multi-Plex Number
;				01 - 	Print Spooler
;				02 -	Assign Command (Documented)
;				05 -	Critical Error Msg
;				06 -	Assign Command (By Inspection)
;				08 -	DRIVER.SYS Interface for MS-DOS 3.xx
;				10 -	Share Command
;				11 -	Internal DOS - Network Hooks
;				12 -	Internal DOS - Support Services
;				13 -	Original INT 13 ROS ISR Address (BIOS)
;				14 -	NLSFUNC utility
;				AD -	IBM CodePage Screen Driver
;				B7 -	Append Command
;				B8 -	Network Command
;
;			AL -	Function Code
;				00 - 	Get Installed State (All)
;				01 -	Submit File (PRINT)
;				02 -	Cancel File (PRINT)
;				03 -	Cancel All Files (PRINT)	 
;				04 -	Spooler Status (PRINT)
;				05 -	End of Status (PRINT)	
;
;	The Network Test returns the current Network configuration in
;	BX when the Get Installed State is requested.
;
;		BX = 0008h	Redirector	|	Increasing
;		BX = 0080h	Receiver	|	 Network
;		BX = 0004h	Messenger	|      Functionality
;		BX = 0040h	Server		V
;
	Public	int2F_entry

int2F_entry:
	sti
	cld
	cmp ah,012h ! je i2f_12		; intercept the AH=12 subfunctions
	cmp ah,011h ! je i2f_11		; intercept the AH=11 subfunctions
	cmp ah,010h ! je i2f_10		; intercept the AH=10 subfunctions
	cmp ah,005h ! je i2f_05		; intercept the AH=05 subfunctions
	cmp ax,4A01h! je QueryHMA	; intercept Query Free HMA Space
	cmp ax,4A02h! je AllocHMA	; intercept Allocate HMA space
	cmp ah,016h ! jne int2F_exit	; intercept the AH=16 subfucntions
	jmp	WindowsHooks		; go do windows things...
int2F_exit:
	push	ds			; pass onto BIOS now
	call	get_dseg		; trying to remain ROMMABLE
int2F_BIOS:
	jmpf	ds:int2FNext		;  hence this complication


eject
i2f_05:
;------
; CRITICAL ERROR MSG
; This is the critical error message interceptor.
; On Entry: AL = extended error code.
; On Exit:  if CY clear then ES:DI -> ASCIIZ string to be used in place
;	 of the default error message
	stc				; please use the default message
	retf	2			; IRET, but keep flags


eject
i2f_10:
;------
; SHARE
	cmp	al,i2f_10size		; do we do this one ?
	 jae	int2F_exit		;  no, skip it
	shl	al,1			; we need a word offset
	 jz	int2F_exit		;  exit if share installation check
	cbw				; zero AH
	xchg	ax,bx			; we will index with it
	push	ds
	call	get_dseg		; get PCMode data seg
	push ds ! pop es
	call	i2f_10tbl[bx]		; execute the function
	pop	ds
	retf	2			;  and return

eject
i2f_11:
;------
; MSNET redirector
	test	al,al			; is it installation check ?
	 jz	i2f_11_10
	mov	ax,1			; no, return ED_FUNCTION error
	stc				; indicate an error
i2f_11_10:
	retf	2			; return

eject
i2f_12:
;------
; DOS Internal
; Support DOS internal functions here
	cmp	al,0FFh			; should we pass it on to the BIOS ?
	 je	int2F_exit		; yes, do so
	cmp	al,i2f_12size		; do we do this one ?
	 jae	i2f_12_bad		;  no, skip it
	push	bp
	xor	ah,ah
	add	ax,ax			; make sub-func a word
	mov	bp,ax			; we need offset in pointer register
	mov	ax,i2f_12tbl[bp]	; get address of service routine
	mov	bp,sp			; BP points to stack frame
	call	ax			; call the service routine
	pop	bp
i2f_12_exit:
	retf	2			; IRET, but returning flags
i2f_12_bad:
	mov	ax,-ED_FUNCTION
	stc
	retf	2


i2f_12tbl	dw	i2f_1200
		dw	i2f_1201
		dw	i2f_1202
		dw	i2f_1203
		dw	i2f_1204
		dw	i2f_1205
		dw	i2f_1206
		dw	i2f_12nyi	; Move disk buffer
		dw	i2f_1208
		dw	i2f_12nyi	; DS:DI -> Disk Buffer ??
		dw	i2f_120A
		dw	i2f_120B
		dw	i2f_120C
		dw	i2f_120D
if DOS5
		dw	share_delay	; delay
else
		dw	i2f_120E	; get buffers
endif
		dw	i2f_12nyi	; relink buffer ES:DI ([DI+5].20 <- 0) - Trout
		dw	i2f_1210
		dw	i2f_1211
		dw	i2f_1212
		dw	i2f_1213
		dw	i2f_1214
		dw	i2f_12nyi	; Disk buffer DS:SI ??? (Write - Trout)
		dw	i2f_1216
		dw	i2f_1217
		dw	i2f_1218
		dw	i2f_1219
		dw	i2f_121A
		dw	i2f_121B
		dw	i2f_121C
		dw	i2f_121D
		dw	i2f_121E
		dw	i2f_121F
		dw	i2f_1220
		dw	i2f_1221
		dw	i2f_1222
		dw	i2f_1223
		dw	share_delay
		dw	i2f_1225
		dw	i2f_1226
		dw	i2f_1227
		dw	i2f_1228
		dw	i2f_1229
		dw	i2f_122A
		dw	i2f_122B
		dw	i2f_122C
		dw	i2f_122D
i2f_12size	equ	((offset $) - (offset i2f_12tbl))/2

i2f_12nyi:
; Sets CY the falls through to installation check - so returns ax = 00FF
; Who knows what to do ?
	stc				; indicate problem ?

i2f_1200:
	mov	ax,00FFh
	ret

i2f_1201:
; Close file ??? (at current_dhndl)
	les	di,current_dhndl
	mov	bx,es:DHNDL_WATTR[di]
	test	bh,DHAT_REMOTE/100h
	 jz	i2f_1201_10		; is it networked ?
	mov	ax,I2F_CLOSE
	int	2fh			; then close using int 2f call
i2f_1201_10:				; else do nothing for now
	ret

i2f_1202:
; Get Interrupt Vector pointer
	xor	bx,bx
	mov	es,bx			; point at the vectors
	mov	bl,8[bp]		; pick up which vector
	add	bx,bx
	add	bx,bx			; make it a DWORD offset
	ret

i2f_1203:
; Get DOS Data segment
	jmp	get_dseg		; return DS = DOS data seg

i2f_1204:
; Normalise path character
	mov	ax,8[bp]		; the char is on the stack
tobslash:
	cmp	al,'/'			; if it's a fslash
	 jne	i2f_1204_10
	mov	al,'\'			;  make it a bslash
i2f_1204_10:
	cmp	al,'\'			; set ZF if bslash
	ret

i2f_1205:
; Output Character on the stack
	push	dx
	mov	ah,MS_C_WRITE
	mov	dx,8[bp]		; get char from the stack
	call	dos_entry		;  and output it
	pop	dx
	ret
	
i2f_1206:
; Invoke critical error INT 24
	push	ds
	mov	ax,8[bp]		; action/drive on stack
	mov	es,0[bp]		; seg was in BP
	call	get_dseg		; get the segment right
	call	do_int24		; invoke the critical error handler
	push	ax
    les ax,int24_esbp       
	mov	[bp],ax			; really return new BP
	pop	ax
	pop	ds
	ret

i2f_1208:
; Decrement word at ES:DI, skipping zero
	mov	ax,es:word ptr [di]	; return the word in AX
i2f_1208_10:
	dec	es:word ptr [di]	; dec it
	 jz	i2f_1208_10		;  dec again if it's zero
	ret
	
i2f_120A:
	push	ds
	lds	si,current_ddsc		; point at current driver
	lodsb				; get the drive
	cbw				; pretend dos area read
	pop	ds
	mov	err_drv,al
	mov	rwmode,ah		; set error drive for Int 24h
	mov	ax,3			; return a Fail ?
	stc				; return as error
	ret
	
i2f_120B:
; ES:DI -> system file table entry
	mov	ax,20h			; sharing violation
	stc				; return as error
	ret
	
i2f_120C:
; Open file ??? (at current_dhndl)
	les	di,current_dhndl
; would need to call the device driver, but as we don't support this for
; block devices and as it is generally not supported for remote files (but
; only known to be called from redirectors) we leave this out for later
	test	es:byte ptr DHNDL_MODE+1[di],DHM_FCB/100h
	 jz	i2f_120C_10		; is it an FCB open ?
	mov	ax,current_psp
	mov	es:DHNDL_PSP[di],ax	; update owning PSP field
i2f_120C_10:				; else do nothing for now
	ret

i2f_120D:
; Get Date/Time
	push	ds
	push	es
	push	cx
	push	bx
	push	si
	push	di
	push	ss
	pop	ds
	call	ReadTOD
	pop	di
	pop	si
	pop	bx
	pop	cx
	pop	es
	pop	ds
	ret


if DOS5 eq 0
i2f_120E:
; Disk Buffers
; On Return ES:DI -> first disk buffer
;
	les	di,ss:bcb_root		; get head of buffer chain
	ret
endif


i2f_1210:
; Find Dirty Buffer Entry DS:SI -> 1st buffer, On exit DS:SI-> 1st dirty buffer
; ZF set if none found
	xor	ax,ax			; never find dirty buffers
	ret
	
i2f_1211:
; Normalise ASCIIZ filename DS:SI -> source buffer, ES:DI -> dest buffer
; make uppercase, fslash becomes bslash
; (Stops at slash - Trout)
	lodsb				; get a character
	call	toupper			; upper case it
	call	tobslash		; convert '/' to '\'
	stosb				; plant it
	test	al,al			; terminating zero ?
	 jnz	i2f_1211
	mov	ax,8[bp]		; AX from stack
	ret
	
i2f_1212:
; Get length of ASCIIZ string ES:DI
	push ds ! push si
	push es ! pop ds
	mov	si,di			; make DS:SI -> ASCIIZ
	call	i2f_1225		;  then use our other primitive
	pop si ! pop ds
	ret

i2f_1213:
; Upperase character on stack
	mov	ax,8[bp]		; get the character
	jmp	toupper			; use BDOS Intl routine
	
i2f_1214:
; Compare far pointers DS:SI with ES:DI
	cmp	di,si
	 jne	i2f_1214_10
	push ax ! push bx
	mov	ax,ds
	mov	bx,es
	cmp	ax,bx
	pop bx ! pop ax
i2f_1214_10:
	ret

i2f_1216:
; Get address in ES:DI of DOSHNDL for file BX
	push	ds
	call	get_dseg		; we work with the PCMODE data
	les	di,file_ptr		; get the address of the first entry
	pop	ds
	push	bx			; handle # in BX
i2f_1216_10:
	cmp	bx,es:DCNTRL_COUNT[di]	; handle in this block?
	 jb	i2f_1216_20		; skip if yes
	sub	bx,es:DCNTRL_COUNT[di]	; update the internal file number
	les	di,es:DCNTRL_DSADD[di]	; get the next entry and check
	cmp	di,0FFFFh		;   for the end of the list
	 jnz	i2f_1216_10 
	pop	ax			; handle # back in AX
	stc				; invalid file handle number
	ret

i2f_1216_20:
	push	dx			; save DX and calculate the offset
	mov	ax,DHNDL_LEN		;   of the DOS Handle
	mul	bx
	add	di,ax			; add structure offset (should be 0) 
	add	di,DCNTRL_LEN		;    and then skip the header
	pop	dx
	pop	ax			; handle # back in AX
;	clc
	ret				; valid file handle number
	
i2f_1217:
; Default Drive ???
; On Exit:
; AL = drive we have set to, DS:SI -> LDT structure
	call	get_dseg		; DS -> PCMODE data
	mov	ax,8[bp]		; get the drive
	cmp	al,last_drv		; do we have an LDT for it ?
	 jae	i2f_1217_10		; if not do no more
	cmp	word ptr ldt_ptr+2,0	; valid LDT ?
	 je	i2f_1217_10
	push	ax
	mov	ah,LDT_LEN
	mul	ah
	lds	si,ldt_ptr
	add	si,ax			; DS:SI -> requested LDT, current_LDT
	mov	ss:word ptr current_ldt,si
	mov	ss:word ptr current_ldt+2,ds
	pop	ax
	stc				; indicate NO error (CY inverted)
i2f_1217_10:
	cmc	
	ret				; CY set if invalid


i2f_1218:
; DS:SI -> User register on DOS Call
	call	get_dseg		; we save SS:SP after PUSH$DOS
	lds	si,int21regs_ptr	;  in this location
	ret

i2f_1219:
; Stack = drive (0=default, 1 = A: etc)
	push ds ! push si ! push word ptr 8[bp]
	dec	byte ptr 8[bp]		; make drive zero based
	cmp	byte ptr 8[bp],0ffh	; do we want the default ?
	 jne	i2f_1219_10
	call	get_dseg
	mov	al,current_dsk
	mov	byte ptr 8[bp],al	; use the default drive
i2f_1219_10:
	call	i2f_1217		; set's up current_ldt
	 jc	i2f_1219_20
	test	ds:byte ptr 44h[si],40h	; is it valid LDT ?
	 jnz	i2f_1219_20
	stc				; indicate an error
i2f_1219_20:
	pop word ptr 8[bp] ! pop si ! pop ds
	ret

i2f_121A:
; Get files drive DS:SI -> drives, AL = drive
	xor	ax,ax			; assume default drive
	cmp	ds:byte ptr 1[si],':'
	 jne	i2f_121A_10		; if no drive letter, then default
	mov	al,ds:byte ptr [si]
	test	al,al			; null string ?
	 jz	i2f_121A_10		;  then it's the default drive
	call	toupper
	sub	al,'A'-1		; make one based
	 jbe	i2f_121A_20		; it's invalid..
	push	ds
	call	get_dseg
	cmp	al,last_drv		; is it a valid drive ?
	pop	ds
	 ja	i2f_121A_20		; yes, return it
i2f_121A_10:
	clc
	ret
i2f_121A_20:
	mov	al,0FFh			; invalid drive
	stc
	ret

i2f_121B:
; On Entry CX = year-1980
; On Exit AL = days in February
	push	bx
	mov	bx,offset days_in_month+1
	mov	ds:byte ptr [bx],28	; assume 28 days in Feb
	test	cl,3			; is it a leap year ?
	 jnz	i2f_121B_10
	inc	ds:byte ptr [bx]	; yes, we have 29
i2f_121B_10:
	mov	yearsSince1980,cl	; save the year
	mov	al,ds:byte ptr [bx]	; return the days in Feb
	pop	bx
	ret

i2f_121C:
; Checksum Memory CX bytes at DS:SI, DX = initial checksum
; DX = final checksum
; I've seen this used to total days in N months.
; On Entry:
;	CX = current month
;	DX = total days in prior years
;	DS:SI -> days-per-month table
; On Exit:
;	DX = Total days to start of current month
;
	xor	ax,ax			; clear AX
	jcxz	i2f_121C_20		; check for zero bytes
i2f_121C_10:
	lodsb				; get a byte
	add	dx,ax			; add to the checksum
	loop	i2f_121C_10		; until we run out
i2f_121C_20:
	ret

i2f_121D:
; Calculate Date
; On Entry:
;	CX = 0
;	DX = total day count this year
;	DS:SI -> days-per-month table
; On Exit:
;	CX = Month
;	DX = Day
;
	xor	ax,ax
i2f_121D_10:
	lodsb
	inc	cx
	sub	dx,ax
	 jnb	i2f_121D_10
	dec	cx			; undo the last count
	add	dx,ax			; undo the sub
	cmp	dx,ax			; get the flags right
	ret

i2f_121E:
; Compare Filenames at DS:SI and ES:DI
	push si ! push di ! push cx
	call	i2f_1225		; find length of DS:SI filename
	push	cx
	call	i2f_1212		; find length of ES:DI filename
	pop	ax
	cmp	ax,cx			; if lengths not the same
	 jne	i2f_121E_20		;  don't even bother
i2f_121E_10:
	push	cx
	lodsb
	call	toupper
	call	tobslash		; normalise slash characters
	push	ax			; save it
	mov	al,es:byte ptr [di]
	inc	di
	call	toupper
	call	tobslash		; normalise slash again
	pop	cx			; recover the character
	cmp	al,cl			; are they the same?
	pop	cx
	loope	i2f_121E_10		; yes, try again if we have any left
i2f_121E_20:
	pop cx ! pop di ! pop si
	mov	ax,8[bp]		; return stack value in AX
	ret

i2f_121F:
; Build drive info into block
; Stack = Drive (1=A: etc)
	push ds ! push si ! push dx
	call	get_dseg
	les	di,current_ldt
	push	di
	mov	ax,8[bp]		; get the drive we want to do
	stosb				; plant the ASCII
	xchg	ax,dx			; save drive in DX
	mov	ax,'\:'
	stosw				; we have d:\
	xor	ax,ax
	mov	cx,LDT_FLAGS-3
	rep	stosb			; zero rest of name and flags
;	lea	di,LDT_FLAGS
	and	dl,1fh			; convert from ASCII
	dec	dx			; into zero based drive number
	cmp	dl,phys_drv		; valid physical drive ?
	 jae	i2f_121F_10		; mark it as such
	mov	ax,LFLG_PHYSICAL
i2f_121F_10:
	stosw				; set flags
;	lea	di,LDT_PDT
	lea	si,ddsc_ptr-18h
i2f_121F_20:
	lds	si,18h[si]
	cmp	si,-1
	 je	i2f_121F_30
	cmp	dl,[si]			; is this the DDSC for the drive
	 jne	i2f_121F_20		; if so save it away
i2f_121F_30:
	xchg	ax,si			; AX = DDSC offset
	stosw
	mov	ax,ds			; AX = DDSC seg
	stosw
;	lea	di,LDT_BLK
	mov	ax,0FFFFh		; AX = FFFF
	stosw ! stosw ! stosw		; fill in block info
;	lea	di,LDT_ROOTLEN
	mov	ax,2
	stosw				; set root length
	pop	di
	pop dx ! pop si ! pop ds
	ret

i2f_1220:
; Get pointer to system file table number for handle BX into ES:DI
	push	ds
	call	get_dseg
	mov	es,current_psp
	mov	ax,6			; assume illegal
	cmp	bx,PSP_XFNMAX		; is it a legal handle
	cmc				; invert CY for error return
	 jc	i2f_1220_10		;  no, forget it
	les	di,PSP_XFTPTR		; get XFT from PSP
	add	di,bx			; add in the offset
;	clc
i2f_1220_10:
	pop	ds
	ret

i2f_1221:
	mov	ah,MS_X_EXPAND		; let the FDOS do the walking...
	call	DOS			;  and call our internal entry point
	 jnc	i2f_1221_10
	neg	ax			; get error code correct
	stc				;  before returning error
i2f_1221_10:
	ret

i2f_1222:
; Store error class, locus, action from DS:SI
i2f_1222_10:
	lodsw
	cmp	al,byte ptr error_code	; have we found the error ?
	 je	i2f_1222_20
	inc	al			; or hit the end of the list ?
	 jz	i2f_1222_20
	lodsw				; skip this one
	jmp	i2f_1222_10		; and try the next
i2f_1222_20:
	cmp	ah,0ffh			; valid error class ?
	 je	i2f_1222_30
	mov	error_class,ah
i2f_1222_30:
	lodsw
	cmp	al,0ffh
	 je	i2f_1222_40
	mov	error_action,al
i2f_1222_40:
	cmp	ah,0ffh
	 je	i2f_1222_50
	mov	error_locus,ah	
i2f_1222_50:
	ret

i2f_1223:
; On Entry buffer at 4E6 filled with Device name - eg. "NAME1   "
; Preserve word ptr [4E6]
; if byte ptr [4E6] = 5 then byte ptr [4E6] = E5
; if byte ptr [506] & 8 then exit now with STC
; otherwise work down device chain
; Find device driver for device NAME1
; Check if character device
	push	ds
	call	get_dseg
if FALSE
	push	word ptr name_buf	; save 1st char of name
	test	magic_byte,8		; magic location and number ??
	 jnz	i2f_1223_40		; can we do the check ?
	cmp	name_buf,5
	 jne	i2f_1223_10		; if 1st char is 5, make it
	mov	name_buf,0e5h		;  an E5
i2f_1223_10:
endif
	mov	si,offset nul_device	; start from NUL
i2f_1223_20:
	test	ds:DH_ATTRIB[si],DA_CHARDEV
	 jz	i2f_1223_30		; skip unless character device
	mov	cx,8
	lea	di,name_buf		; point at name we are looking for
	push	si
	lea	si,ds:DH_NAME[si]	; point a device name
	repe	cmpsb			; compare the names
	pop	si
	 jne	i2f_1223_30		; if we found it, save info
	mov	es:word ptr current_device,si
	mov	es:word ptr current_device+2,ds
	mov	bh,ds:byte ptr DH_ATTRIB[si]
	or	bh,0e0h
	xor	bh,20h			; clear this bit
	clc				; we found it
	jmps	i2f_1223_50
i2f_1223_30:
	lds	si,ds:DH_NEXT[si]
	cmp	si,0ffffh		; any more entries ?
	 jne	i2f_1223_20		; yes, do them
i2f_1223_40:
	stc
i2f_1223_50:
if FALSE
	pushf
	call	get_dseg		; we may have scambled DS
	popf
	pop	word ptr name_buf	; restore 1st character
endif
	pop	ds
	ret


i2f_1225:
; Get length of ASCIIZ string DS:SI
	call	strlen
	inc	cx			; include the terminating zero
	mov	ax,8[bp]		; restore AX from stack
	ret

; The following are NOT required for MSNET - they are used by NLSFUNC

i2f_1226:
; Open the file at DS:DX
	mov	al,cl			; open mode in CL on entry
	mov	ah,MS_X_OPEN		; open the file
DOS:
	push ds ! push es ! pop ds ! pop es
	call	dos_entry		; reverse DS/ES before for dos_entry
	push ds ! push es ! pop ds ! pop es
	ret

i2f_1227:
; Close file BX
	mov	ah,MS_X_CLOSE		; close the file
	jmps	DOS

i2f_1228:
; LSEEK on file BX
	mov	ax,[bp]			; seek mode in BP on entry
	mov	ah,MS_X_LSEEK		; do the seek
	jmps	DOS
	
i2f_1229:
; Read from file BX
	mov	ah,MS_X_READ
	jmps	DOS

i2f_122A:
; Set fastopen entry point to DS:SI
; SI = FFFF, sdont't set - just check if installed
	mov	ax,si			; AX = offset
	inc	ax			; AX = 0 if it's an installation check
	stc				; assume it is, and say not installed
	 jne	i2f_122A_10
	clc				; fail new installation
i2f_122A_10:
	ret

i2f_122B:
; IOCTL
	mov	al,[bp]			; get IOCTL minor
	mov	ah,MS_X_IOCTL
	jmps	DOS

i2f_122C:
; Get 2nd device driver header address
	push	ds
	call	get_dseg
	lds	ax,ds:dword ptr nul_device
	mov	bx,ds			; BX:AX -> 2nd device header
	pop	ds
	ret

i2f_122D:
; Get extended error code
	mov	ax,error_code
	ret


;
; Our FDOS extentions live here
;
if DELWATCH
	extrn	locate_buffer:near
	extrn	flush_drive:near
	extrn	delfat:near
	extrn	allocate_cluster:near
	extrn	getblk:near
	extrn	change_fat_entry:near
	extrn	fixup_hashing:near
	
; for speed/code size we just call directly in BLACK.A86
endif

i2f_10tbl	dw	i2f_10nyi	; never gets here...
		dw	i2f_1001	; install fdos hook
if DELWATCH
if FALSE
		dw	i2f_1002	; read buffer
		dw	i2f_1003	; flush buffers
		dw	i2f_1004	; free fat chain
		dw	i2f_1005	; allocate cluster
		dw	i2f_1006	; next cluster
		dw	i2f_1007	; update fat entry
		dw	i2f_1008	; fixup checksums
else
		dw	locate_buffer	; ask BLACK to find that buffer
		dw	flush_drive	; ask BLACK to flush buffers
		dw	delfat		; ask BLACK to release FAT chain
		dw	allocate_cluster; ask DEBLOCK to allocate space
		dw	getblk		; ask DEBLOCK to return next block
		dw	change_fat_entry; ask DEBLOCK to update fat entry
		dw	fixup_hashing	; ask BLACK to fixup hashing/checksums
endif
		dw	i2f_1009	; directory buffer info
endif
i2f_10size	equ	(offset $ - offset i2f_10tbl)/2

i2f_1001:
;--------
; install fdos stub
;
; On Entry:
;	DX:AX -> new fdos_stub entry address
; On Exit:
;	None
;
	call	get_dseg		; get PCMode data seg
	mov	word ptr fdos_stub,ax	; fixup our share stubs
	mov	word ptr fdos_stub+WORD,dx
i2f_10nyi:
	ret

if DELWATCH
if FALSE

i2f_1002:
;--------
; read buffer
; On Entry:
;	CH = 0FFh (pre-read required)
;	CL = BF_ISFAT/BF_ISDIR/BF_ISDATA
;	AH:DX = 24 bit sector number
; On Exit:
;	ES:SI -> Buffer control block
;
    jmp locate_buffer       

i2f_1003:
;--------
; flush buffers
; On Entry:
;	AL = drive
;	AH = buffer type to flush (BF_ISFAT+BF_ISDIR+BF_ISDATA)
; On Exit:
;	None
;
    jmp flush_drive     

i2f_1004:
;--------
; free fat chain
; On Entry:
;	AX = 1st block to release on current drive
; On Exit:
;	None
    jmp delfat          

i2f_1005:
;--------
; allocate cluster
; On Entry:
;	AX = block to start search from (eg. current end of file)
;	     0000 = start of disk
; On Exit:
;	AX = 0000 if none available
;	     else allocated block (marked as End Of Chain)
;
	jmp	allocate_cluster	; ask DEBLOCK.A86 to allocate some space

i2f_1006:
;--------
; get next cluster
; On Entry:
;	AX = current block
; On Exit:
;	AX = next block in chain
;
	jmp	getblk			; ask DEBLOCK.A86 to return next block

i2f_1007:
;--------
; change fat entry
; On Entry:
;	AX = fat entry to change
;	DX = new value
; On Exit:
;	None
;
	jmp	change_fat_entry	; ask DEBLOCK.A86 to modify FAT entry

i2f_1008:
;--------
; update hash code for directory entry on current drive
; On Entry:
;	AX =	segment of dir buffer
;	CX =	cluster to fixup (0 = root)
;	DI =	directory entry index(clipped to cluster if subdir)
;	AX:SI->	dir entry (single entry for hashing)
; On Exit:
;	None
;
	jmp	fixup_hashing

endif

i2f_1009:
;--------
; return dirbuf info
; On Entry:
;	None
; On Exit:
;	ES:DI -> 128 byte directory record buffer
;	ES:SI -> dir bcb structure
;		0[si] = drive (FF = invalid)
;		1[si] = low byte of record number
;		2[si] = mid byte of record number
;		3[si] =  hi byte of record number
;
	push cs ! pop es
	mov	si,offset invalid_dir_bcb
	ret

invalid_dir_bcb	db	0ffh		; drive is invalid
;		db	?,?,?		; don't bother about record number

endif	;DELWATCH


WindowsHooks:
;------------
; On Entry:
;	AH = 16h, it's a windows broadcast
;	AL = subfunction, other regs as appropriate
; On Exit:
;	Various
;
if DOS5
	cmp	al,07h			; 1607: Virtual device init
	 je	WindowsDOSMGR
endif
	test	dx,1			; is it a DOSX broadcast ?
	 jnz	WindowsExit
	cmp	al,05h			; 1605: Windows enhanced mode init
	 je	WindowsStartup
if DOS5
	cmp	al,06h			; 1606: Windows enhanced mode exit
	 je	WindowsShutdown
endif
WindowsExit:
	iret



WindowsStartup:
;--------------
	push	ds
	call	get_dseg		; DS -> our data
if DOS5
	inc	criticalSectionEnable	; enable Int 2Ah for Windows
	inc	WindowsHandleCheck
endif

;;if 0		Put this back in, as instance data still required
;;		Removed pointer to vxd in HEADER.A86   BAP

	mov	SwStartupInfo+2,bx	; Commented out, as NWDOS.386
	mov	SwStartupInfo+4,es	; no longer needed.
	push	ds
	pop	es			; ES -> pcmode data
	mov	bx,offset SwStartupInfo
;;endif
	jmp	int2F_BIOS		; pass on to the BIOS

if DOS5

WindowsShutdown:
;---------------
	push	ds
	call	get_dseg		; DS -> our data
	dec	criticalSectionEnable	; enable Int 2Ah for Windows
	dec	WindowsHandleCheck
	pop	ds
	sub	dx,dx			; return success
	iret


WindowsDOSMGR:
;-------------
	cmp	bx,15h			; is it DOS manager?
	 jne	WindowsExit		; forget the others
;	cmp	cx,0
	 jcxz	WindowsCX0
	dec	cx
	 jcxz	WindowsCX1
	dec	cx ! dec cx ! dec cx
	 jcxz	WindowsCX4
	dec	cx
	 jcxz	WindowsCX5
	iret


WindowsCX0:
;----------
	push	ds
	call	get_dseg
	push	ds
	pop	es			; ES = DOS data segment
	pop	ds
	lea	bx,windowsData		; ES:BX -> secret variables
	inc	cx			; tell them we've responded
	iret

WindowsCX1:
;----------
	mov	bx,dx			; entry DX=1Fh, exit BX=1Fh
	mov	ax,0B97Ch		; AX, DX are magic values
    mov dx,0A2ABh       
;	xor	cx,cx			; CX = 0
	iret

WindowsCX4:
;----------
	xor	dx,dx
;	xor	cx,cx			; CX = 0
	iret

WindowsCX5:
;----------
;	entry:	ES:DI -> device driver
;		determine device driver size in bytes

	push	ds
	test	di,di			; not primary DEVICE= driver?
	 jnz	WindowsCX5NoDev		; can't have DMD preceeding it
	mov	ax,es			; get device segment
	dec	ax			; DMD is one paragraph lower down
	mov	ds,ax			; DS:DI -> device DMD
	inc	ax			; AX = device driver segment
	cmp	ds:byte ptr 0[di],'D'	; see if 'D'device=
	 jne	WindowsCX5NoDev		; skip if not
	cmp	ax,ds:word ptr 1[di]	; owned by the driver ?
	 jne	WindowsCX5NoDev		; skip if not

	mov	ax,10h			; bytes per paragraph
	mul	ds:word ptr 3[di]	; bytes in device driver
	pop	ds
	mov	bx,dx			; BX = high word
	xchg	ax,cx			; CX = low word
	mov	ax,0B97Ch		; AX, DX are magic values
    mov dx,0A2ABh       
	iret

WindowsCX5NoDev:
; ES:DI -> not an external device 
	pop	ds
	xor	ax,ax
	xor	dx,dx
;	xor	cx,cx			; CX = 0
	iret

endif
eject
PCMODE_DATA	DSEG	WORD
	extrn	hmaRoot:word
	extrn	last_drv:byte
	extrn	phys_drv:byte
	extrn	ddsc_ptr:dword
	extrn	current_psp:word
	extrn	current_dsk:byte
	extrn	net_delay:word
	extrn	nul_device:byte
	extrn	error_code:word
	extrn	error_class:byte
	extrn	error_action:byte
	extrn	error_locus:byte
	extrn	file_ptr:dword
	extrn	ldt_ptr:dword
	extrn	current_device:dword
	extrn	current_ldt:dword
	extrn	current_dhndl:dword
	extrn	current_ddsc:dword
	extrn	yearsSince1980:byte
	extrn	days_in_month:byte
	extrn	name_buf:byte
	extrn	int21regs_ptr:dword
	extrn	int24_esbp:dword
	extrn	int2FNext:dword
	extrn	fdos_stub:dword
	extrn	SwStartupInfo:word
	extrn	err_drv:byte
	extrn	rwmode:byte

if DOS5
	extrn	indos_flag:byte, machine_id:byte, internal_data:byte, dmd_upper_root:word

	extrn	criticalSectionEnable:byte
	extrn	WindowsHandleCheck:byte

GLOBAL_DATA	dseg
	
windowsData	dw	5		; version number ?
		dw	$		; dummy
		dw	$		; dummy
		dw	offset indos_flag
		dw	offset machine_id
		dw	offset internal_data-10
		dw	offset dmd_upper_root
else
	extrn	bcb_root:dword
endif
	end
