;; This is the C prototype header file for DOSCALLS.  This provides
;; the minimal DOS dependent interface for flatmodel programs into
;; DOS.        The primary support needed is the ability to allocate and
;; de-allocate memory in the low 1mb of address space.
;; extern char * cdecl AllocLowMem(long int size,short *selector); // Allocate low memory.
;; extern void cdecl FreeLowMem(short selector); // Free allocated memory.
;; extern char * cdecl RealPtr(char *real); // Convert flat model address to segment:offset
;; extern void cdecl memorymove(char *dest,char *source,long int length);
;;																																					 */
;;		Written by John W. Ratcliff (c) 1994
;;			 Compuserve: 70253,3237
;;			 Genie: J.RATCLIFF3
;;			 BBS: 1-314-939-0200
;;			 Addresss:
;;			    747 Napa Lane
;;			    St. Charles, MO 63304
;;																																					 */
	IDEAL
	P386
	JUMPS
	MODEL FLAT,C
	CODESEG

	public	SetVolume
	public	InWindows
	public	AllocLowMem
	public	FreeLowMem
	public	RealPtr
	public	memorymove
	public	memoryset
	public	tprint
	public	TextCursor
	public	GetHeartBeat
	public	DBUG
	public	ChangeDirectory
	public	CD_Init
	public	InstallServiceRoutine
	public	RestoreServiceRoutine
;;**	    public  IOCTL

Macro	useall
	uses	ebx,ecx,edx,esi,edi,es,ds
	endm

Macro	RepStosb
       mov     ah,al	       ; AH=AL
       push    ax		; push word size of move
       push    ax		; and again
       pop     eax		; pop long word value of move
       push    ecx		 ; Save the total number of bytes to store
       shr     ecx,2		 ; how many double words to move?
       rep     stosd		; store this many long words.
       pop     ecx		 ; restore CX register.
       and     ecx,3		 ; remaining number of bytes to move.
       rep     stosb		; move the final bytes.
       endm

Macro	RepMovsb
	push	ecx
	shr	ecx,2		 ; words.
	rep	movsd
	pop	ecx
	and	ecx,3
	rep	movsb
	endm

Proc	C AllocLowMem	near
	ARG	AMOUNT:DWORD,SELECTOR:DWORD
	useall

	mov	ebx,[AMOUNT]	; Get number of bytes requested.
	add	ebx,15		; Round up to closest number of paragraphs.
	shr	ebx,4		; /16.
	mov	eax,0100h	; Allocate.
	int	31h		; Allocate memory.
	jc	@@ERR
	shl	eax,4		; Into flat model address space.
	mov	ebx,[SELECTOR]	; Get address of selector.
	mov	[ebx],dx	; Save selector.
	jmp short @@RET
@@ERR:	xor	eax,eax 	; Zero return address.
@@RET:
	ret
	endp

Proc	C FreeLowMem	near
	ARG	SELECTOR:DWORD
	useall

	mov	eax,0101h
	mov	edx,[SELECTOR]
	int	31h

	ret
	endp

Proc	C RealPtr	near
	ARG	DATA:DWORD
	useall

	mov	eax,[DATA]
	mov	edx,eax
	and	eax,0Fh 	; Offset portion.
	and	edx,0FFFF0h
	shl	edx,(16-4)
	add	eax,edx

	ret
	endp

Proc	C memorymove near
	ARG	DEST:DWORD,SOURCE:DWORD,MLEN:DWORD
	useall

	push	ds
	pop	es

	mov	esi,[SOURCE]
	mov	edi,[DEST]
	mov	ecx,[MLEN]

	RepMovsb

	ret
	endp

Proc	C memoryset near
	ARG	DEST:DWORD,VALUE:DWORD,MLEN:DWORD
	useall

	push	ds
	pop	es

	mov	edi,[DEST]
	mov	ecx,[MLEN]
	mov	eax,[VALUE]

	RepStosb


	ret
	endp

PROC	C tprint near
	ARG	XLOC:DWORD,YLOC:DWORD,LN:DWORD,STRING:DWORD,COLOR:DWORD
	useall

	mov	esi,[STRING]	    ;; Get base address of text to print.
	cmp	[LN],0		;; If length passed is zero, then use string length.
	jne	@@LNPASS	;; use length passed.
	or	esi,esi 	  ;; Null string?
	jz	@@EXIT		;; yes, exit.
	mov	edi,esi
	xor	eax,eax
	mov	ecx,-1
	repnz	scasb
	neg	ecx
	dec	ecx		 ; Less one.
	mov	[LN],ecx	 ; Length of string.
@@LNPASS:
;; If ylocation above are below clip window, exit.
	mov	eax,[YLOC]		 ;; Get destination ylocation.
	or	eax,eax 		  ;; < top margin?
	js	@@EXIT			 ;; yes, doesn't fit.
	cmp	eax,25			 ;; > bottom margin?
	jg	@@EXIT			 ;; yes, doesn't fit.

;; If xlocation > right margin? yes->exit.
	mov	eax,[XLOC]		 ;; Get xlocation passed?
	cmp	eax,79			 ;; > right margin?
	jg	@@EXIT			;; doesn't fit, exit.
	or	eax,eax
	jns	@@SKP1			;; no, start postion is ok.
	neg	eax			 ;; Make it positive.
	or	esi,esi 		  ;; Null string?
	jz	@@REN
	add	esi,eax 		  ;; Number of pixels to skip.
@@REN:	sub	[LN],eax		 ;; Differnece, from total length.
	js	@@EXIT
	jz	@@EXIT			 ;; If length zerod out, get out.
	mov	[XLOC],0		;; Set it.
@@SKP1:
	add	eax,[LN]		 ;; Add total length.
	dec	eax			 ;; Less one to ending pixel position.
	cmp	eax,79			 ;; Past right margin?
	jle	@@SKIP			;; no->it fits fine.
	sub	eax,79			 ;; Amount past right margin.
	sub	[LN],eax		 ;; Lower total length.
	js	@@EXIT			;; if negitze, no go.
@@SKIP: mov	edi,0B8000h
	mov	eax,160
	mul	[YLOC]
	add	edi,eax
	mov	eax,[XLOC]
	shl	eax,1
	add	edi,eax

	mov	eax,[COLOR]
	mov	ah,al			;; Into AH.
	mov	ecx,[LN]		 ;; Length.
	or	esi,esi
	jz	@@SPACE 		;; Fill rest with spaces
@@SND:	lodsb				;; Get character to send.
	or	al,al			;; Is it eos?
	jz	@@SPACE 		;; fill rest with spaces.
	stosw
	loop	@@SND
	jmp	@@EXIT
@@SPACE:mov	al,20h			;; Space character.
@@FILL: rep	stosw			;; Fill rest with spaces.


@@EXIT:
	ret
	endp

PROC	C TextCursor near
	ARG	XLOC:DWORD,YLOC:DWORD
	useall

	mov	eax,[YLOC]
	mov	edx,[XLOC]
	mov	dh,al
	mov	ah,2
	mov	bh,0
	int	10h

	ret
	endp

Proc	C GetHeartBeat	near
	mov	eax,[046Ch]
	ret
	endp

Macro	HEXOUT
	local	@@dig,@@alf
	mov	eax,edx ;	get current value.
	and	eax,0Fh
	shr	edx,4	; down 4.
	cmp	eax,9
	jle	@@dig
	sub	eax,10
	add	eax,'A'
	jmp short @@alf
@@dig:	add	eax,'0'
@@alf:	mov	[edi],al
	sub	edi,2
	endm

Proc	C DBUG	near
	ARG	VALUE:DWORD,XLOC:DWORD,YLOC:DWORD
	useall

	mov	edi,0B0000h	; base addres
	mov	eax,160
	mul	[YLOC]
	add	edi,eax
	add	edi,[XLOC]
	add	edi,[XLOC]
	add	edi,8*2
	mov	edx,[VALUE]

	HEXOUT
	HEXOUT
	HEXOUT
	HEXOUT

	HEXOUT
	HEXOUT
	HEXOUT
	HEXOUT

	ret
	endp

Proc	C ChangeDirectory near
	arg dirname:dword
	useall

	mov	esi,[STRING]
	cmp	[byte esi+1],':'      ; Drive letter specified?
	jne	@@GO
	lodsb
	cmp	al,'a'
	jb	@@OK
	cmp	al,'z'
	ja	@@OK
	sub	al,32
@@OK:	cmp	al,'A'
	jb	@@err
	cmp	al,'Z'
	ja	@@err
	sub	al,'A'
	xor	ah,ah
	mov	dx,ax
	mov	ah,0Eh
	int	21h
	jc	@@err
	inc	esi		 ; Skip past colon.
@@GO:	mov	edx,esi
        mov     ah,03Bh         ; change directory function
        int     21h             ; perform function
	jc	@@err		; if carry clear set then return error.
        mov     ax,1            ; return OK indicator
@@out:
	ret
@@err:	xor	ax,ax
	jmp short @@out
	endp

;; Initialize CD.  Locates current drive, or first CD drive encountered.
;; Returns:
;;	   -1	= No CD-ROM extensions.
;;	   -2	= No CD-ROM drives on the machine.
;;	   -3	= version number of MSCDEX is too low
;; Positive: drive number.
Proc	C CD_Init  near
	LOCAL	handle:word,drive:word
	useall

	xor	eax,eax 	; zero whole eax first.
	mov	ax,1900h
	int	21h		; Find out what drive we are on.
	xor	ah,ah
	mov	[drive],ax

	mov	cx,ax		; Is this a CD rom drive?
	mov	ax,150Bh	;
	xor	bx,bx
	int	2Fh		; Perform request.

	cmp	bx,0ADADh	; CD-ROM extensions installed?
	je	@@COOL		; Yes.
	mov	ax,-1
	jmp	@@exit		; Exit with -1 return code.
@@COOL: or	ax,ax		; Test return code.
	jnz	@@COOLER		; yes, on cd-rom drive.
	mov	ax,1500h
	xor	bx,bx
	int	2Fh
	or	bx,bx		; zero return code?
	jnz	@@GOT
	mov	ax,-2		; No CD-ROM drives on this system.
	jmp	@@exit
@@GOT:	mov	[drive],cx	; Set drive.
@@COOLER:
	mov	ax,150Ch	; check version number.
	int	2Fh		; Check.
	cmp	bx,020Ah	; 2.10 or greater required.
	jge	@@COOLEST	; still cool.
	mov	ax,-3		; version number too low
	jmp	@@exit
@@COOLEST:
	mov	ax,[drive]	; Get drive number.
@@exit:
	ret
	endp



Proc	C IOCTL   near
	ARG	DRIVE:DWORD,REQUEST:DWORD
	useall

	mov	eax,[REQUEST]
	mov	edx,eax
	and	eax,0Fh 	; Offset portion.
	and	edx,0FFFF0h
	shr	edx,4
;; AX -> offset
;; DX -> segment
	mov	bx,ax
	mov	es,dx
	mov	eax,1510h
	mov	ecx,[DRIVE]
	int	2Fh

	ret
	endp

Proc	C	 InWindows	near

	mov	eax,1600h
	int	2fh
	test	al,7Fh
	jz	@@notwindows
	mov	eax,1
	jmp	@@done
@@notwindows:
	mov	eax,0
@@done:
	ret
	endp

voltab	dw	256 dup(?)	; Address of precomputed volume table.

Proc	C SetVolume near
	arg	sound:dword,len:dword,vol:dword
	useall

	mov	esi,[sound]	; address of audio data.
	mov	ebx,[vol]	; volume.
	lea	edi,[voltab]  ; Get address of volume table.
	mov	ecx,0
@@vol:	mov	eax,ecx 	; baseline.
	sub	eax,128 	; -128+128
	imul	ebx		; times volume.
	sar	eax,8		; /256
	add	eax,128 	; back to baseline.
	mov	[edi],al
	inc	edi
	inc	ecx
	cmp	ecx,256
	jne	@@vol

	mov	ecx,[len]	; length of audio data.
	xor	eax,eax 	;
	lea	edi,[voltab]	;
@@go:	mov	al,[esi]	; get byte.
	mov	al,[edi+eax]	    ; /256
	mov	[esi],al
	inc	esi
	dec	ecx
	jnz	@@go

	ret
	endp

oldtimeroff	dd	?	; 32 bit address.
oldtimersel	dw	?	; selector.
datasel 	dw	?	; data selector.
oldtimeracc	dw	0	; timer accumulator.
serviceroutine	dd	?	; address of routine to service
stacksp 	dd	?	; saved stack location.
stackss 	dw	?	; saved stack selector.

scratchstack	db 1024 dup(?)	; stack.
LABEL	stackat BYTE		; where the stack is located at.

TIMERRATE	dw	0	; timer interrupt rate in ticks


Proc	C InstallServiceRoutine near
	arg	address:dword,IRATE:dword
	useall
; install timer interrupt to poll the driver

	xor	ax,ax
	cmp	[IRATE],0	; standard 18.2 rate?
	je	@@STANDARD
	cmp	[IRATE],18	; >=18.2?
	jle	@@STANDARD
	mov	dx,0012h	; High word of 1,193,180.
	mov	ax,34DCh	; Low word of 1,193,180.
	mov	ebx,[IRATE]
	div	bx		; result is value.
;; divisor rate.
@@STANDARD:
	mov	[TIMERRATE],ax		   ; advance rate

        cli
	mov	eax,[address]
	mov	[serviceroutine],eax
	mov	[datasel],ds	; save data selector.
        push    es
        mov     ax,cs
        mov     es,ax
        lea     ebx,[mixtimer]
        mov     cl,0
        call    irqsetvect
	mov	[oldtimeroff],ebx	; save chain value.
        mov     [oldtimersel],es
        pop     es

; set the timer frequency to 70 hertz
        mov     al,36h
        out     43h,al
	mov	ax,[TIMERRATE]
        out     40h,al
        mov     al,ah
        out     40h,al
        sti

	ret
	endp

Proc	C RestoreServiceRoutine near

; restore the timer frequency to 18.2 hertz

        cli
        mov     al,36h
        out     43h,al
        xor     al,al
        out     40h,al
        out     40h,al

; deinstall timer interrupt used to poll the driver

        push    es
        mov     ebx,[oldtimeroff]
        mov     es,[oldtimersel]
        mov     cl,0
        call    irqsetvect
        pop     es
        sti

	ret
	endp


;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; mixtimer - timer interrupt routine used to poll the sound driver
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
Proc	mixtimer	far
        push    eax
        push    ds
        mov     ds,[cs:datasel]

	push	es
	mov	es,[cs:datasel]
	push	gs		; preserve gs
	push	fs		; preserve fs
	pushad

	cli
	mov	[stacksp],esp
	mov	[stackss],ss
	mov	ss,[datasel]
	lea	esp,[stackat]
	sti

	call	[serviceroutine]

	cli
	mov	ss,[stackss]
	mov	esp,[stacksp]
	sti

	popad
	pop	fs
	pop	gs
	pop	es

	mov	ax,[TIMERRATE]
	add	[oldtimeracc],ax
        jnc     mixtimerf0              ; time to call the old IRQ0 vector?
        pop     ds                      ; yes, jump to the old IRQ0 service
        pop     eax
	jmp	[fword cs:oldtimeroff]	; chain to original timer vector.
mixtimerf0:
        mov     al,20h                  ; nope, send PIC acknowledge and exit
        out     20h,al
        pop     ds
        pop     eax
        iretd
	endp


;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
; irqsetvect - set the IRQ handler routine
; In:
;  ES:EBX = IRQ handler routine address
;  CL = IRQ level
; Out:
;  ES:EBX = previous IRQ handler address
;같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같같
Proc	irqsetvect	near
        push    eax
        push    ecx
        push    edx

; get the PIC interrupt master and slave base address

        push    ebx
        push    ecx
        mov     ax,0400h
        int     31h
        pop     ecx
        pop     ebx

; get the IDT interrupt slot number for the IRQ number

        mov     al,cl
        cmp     al,08h
        jb      irqsetvectf0
        mov     dh,dl
        sub     al,08h
irqsetvectf0:
        add     al,dh

; saves and change the IRQ handler routine

        push    ds
        push    es
        push    ebx
        mov     ah,35h
        int     21h
        pop     edx
        pop     ds
        push    es
        push    ebx
        mov     ah,25h
        int     21h
        pop     ebx
        pop     es
        pop     ds

        pop     edx
        pop     ecx
        pop     eax
        ret
	endp

	end
