;*DDK*************************************************************************/
;
; COPYRIGHT (C) Microsoft Corporation, 1989
; COPYRIGHT    Copyright (C) 1995 IBM Corporation
;
;    The following IBM OS/2 WARP source code is provided to you solely for
;    the purpose of assisting you in your development of OS/2 WARP device
;    drivers. You may use this code in accordance with the IBM License
;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
;    Copyright statement may not be removed.;
;*****************************************************************************/
;       SCCSID = @(#)iodelay.inc	6.1 90/11/16
;      SCCSID = @(#)iodelay..inc	1.0 90/09/17
; ****************************************************************************
; *									     *
; *									     *
; *									     *
; ****************************************************************************
;
; This file provides the following macros
;
;	DevIODelay -	Device Driver IODelay (16 bit)
;	DevIODelay32 -	Device Driver IODelay (32 bit)
;	kIODelay -	Kernel IODelay (16 bit)
;	kIODelay32 -	Kernel IODelay (32 bit)
;	dhIODelay -	DosHlp IODelay (16 bit)
;	dhIODelay32 -	DosHlp IODelay (32 bit)


?REG_AX equ 0h
?REG_CX equ 1h
?REG_DX equ 2h
?REG_BX equ 3h
?REG_BP equ 5h
?REG_SI equ 6h
?REG_DI equ 7h

IO_DEC	equ 48h

ifndef	MI_MOV_REG_IMM
    include mi.inc
endif

;***	DevIODelay - Delay at least 500ns with 16bit DEVICE options

DevIODelay macro scratch
	IODelayWorker <scratch>,<DEVICE>,<16bit>
	endm

;***	DevIODelay32 - Delay at least 500ns with 32bit DEVICE options

DevIODelay32 macro scratch
	IODelayWorker <scratch>,<DEVICE>,<32bit>
	endm

;***	kIODelay - Delay at least 500ns with 16bit KERNEL options

kIODelay macro scratch
	IODelayWorker <scratch>,<KERNEL>,<16bit>
	endm

;***	kIODelay32 - Delay at least 500ns with 32bit KERNEL options

kIODelay32 macro scratch
	IODelayWorker <scratch>,<KERNEL>,<32bit>
	endm

;***	dhIODelay - Delay at least 500ns with 16bit OS2LDR options

dhIODelay macro scratch
	IODelayWorker <scratch>,<OS2LDR>,<16bit>
	endm

;***	dhIODelay32 - Delay at least 500ns with 32bit OS2LDR options

dhIODelay32 macro scratch
	IODelayWorker <scratch>,<OS2LDR>,<32bit>
	endm


;***	IODelayWorker - Delay at least 500ns to allow an IN/OUT
;		  instruction to complete
;
;	Flushes the prefetch queue and waits until the AT bus catches up.
;	Primarily needed when back to back IO is performed on the same
;	hardware.
;
;	PARAMETERS:
;		    scratch - register to use for count
;
;		    type - type of code IODelayWorker is used
;
;			    (OS2LDR)
;			    (KERNEL)
;			    (DEVICE)
;
;		    codesize - size of code IODelayWorker is used in
;
;			    (32BIT)
;			    (16BIT)
;
;	NOTE:
;		The type of code determines the method used to obtain
;		the count value.  In the case of OS2LDR and KERNEL a
;		explicit fixup must be performed.  For the DEVICE case
;		the loader performs the fixup.	The code size is
;		also used to detemine how to code the register use.
;
;

IODelayWorker macro	scratch,type,codesize
local a ,b
	ifb	<type>
	    if2
		%out "Must specify type and code size"
		%out "Usage: IODelayWorker reg,type,code size"
		.err
	    endif
	elseifb <codesize>
	    if2
		%out "Must specify code size"
		%out "Usage: IODelayWorker reg,type,codesize"
		.err
	    endif

	else

	ifidni	<codesize>,<16bit>
	    ifb     <scratch>
		?reg_scratch = ?REG_AX
	    else
		ifidni	<scratch>,<ax>
		    ?reg_scratch = ?REG_AX
		elseifidni	<scratch>,<bx>
		    ?reg_scratch = ?REG_BX
		elseifidni	<scratch>,<cx>
		    ?reg_scratch = ?REG_CX
		elseifidni	<scratch>,<dx>
		    ?reg_scratch = ?REG_DX
		elseifidni	<scratch>,<bp>
		    ?reg_scratch = ?REG_BP
		elseifidni	<scratch>,<si>
		    ?reg_scratch = ?REG_SI
		elseifidni	<scratch>,<di>
		    ?reg_scratch = ?REG_DI
		else
		   %out "Bad register argument:" &scratch
		   .err
		endif
	    endif
	elseifidni <codesize>,<32bit>
	    ifb     <scratch>
		?reg_scratch = ?REG_AX
	    else
		ifidni	<scratch>,<eax>
		    ?reg_scratch = ?REG_AX
		elseifidni	<scratch>,<ebx>
		    ?reg_scratch = ?REG_BX
		elseifidni	<scratch>,<ecx>
		    ?reg_scratch = ?REG_CX
		elseifidni	<scratch>,<edx>
		    ?reg_scratch = ?REG_DX
		elseifidni	<scratch>,<ebp>
		    ?reg_scratch = ?REG_BP
		elseifidni	<scratch>,<esi>
		    ?reg_scratch = ?REG_SI
		elseifidni	<scratch>,<edi>
		    ?reg_scratch = ?REG_DI
		else
		   %out "Bad register argument:" &scratch
		   .err
		endif
	    endif
	else
	    %out "Bad code size specified:" &codesize
	    .err
	endif

	; mov	ax,DELAYTIME
	db	(MI_MOV_REG_IMM + ?reg_scratch)
    b::
	ifidni	<type>,<os2ldr>
	    ifidni  <codesize>,<16bit>
		dw  0
	    else
		dd  0
	    endif
	    IODELAYFIXUP segment

		ifidni	<codesize>,<16bit>
		    dw	offset DGROUP:b
		else
		    ; only the first 16 bits will be significant
		    ; the second 16 bits specify 32-bit operand
		    ; and a padding character

		    dd	offset DGROUP:b
		endif

		ifidni	<codesize>,<16bit>
		    db	1	    ; specify 16-bit operand
		    db	0		;; pad
		endif

	    IODELAYFIXUP ends
	else
	    ifndef DOSIODELAYCNT
		EXTRN		DOSIODELAYCNT:ABS
	    endif
	    ifidni  <codesize>,<16bit>
		dw  DOSIODELAYCNT
	    else
		dd  DOSIODELAYCNT
	    endif
	endif
	ALIGN	4
    a::
	;dec	ax
	db	(IO_DEC + ?reg_scratch)
	jnz	a

	endif

	endm
