; ****************************************************************************
; TRDOS386.ASM (TRDOS 386 Kernel) - v2.0.0 - diskio.s
; ----------------------------------------------------------------------------
; Last Update: 18/02/2016
; ----------------------------------------------------------------------------
; Beginning: 24/01/2016
; ----------------------------------------------------------------------------
; Assembler: NASM version 2.11 (trdos386.s)
; ----------------------------------------------------------------------------
; Turkish Rational DOS
; Operating System Project v2.0 by ERDOGAN TAN (Beginning: 04/01/2016)
;
; Derived from 'Retro UNIX 386 Kernel - v0.2.1.0' source code by Erdogan Tan
; diskio.inc (22/08/2015)
;
; Derived from 'IBM PC-XT-286' BIOS source code (1986) 
; ****************************************************************************

; Retro UNIX 386 v1 Kernel - DISKIO.INC
; Last Modification: 22/08/2015
; 	(Initialized Disk Parameters Data is in 'DISKDATA.INC') 
; 	(Uninitialized Disk Parameters Data is in 'DISKBSS.INC') 

; DISK I/O SYSTEM - Erdogan Tan (Retro UNIX 386 v1 project)

; ///////// DISK I/O SYSTEM ///////////////

; 06/02/2015
diskette_io:
	pushfd
	push 	cs
	call 	DISKETTE_IO_1
	retn
	
;;;;;; DISKETTE I/O ;;;;;;;;;;;;;;;;;;;; 06/02/2015 ;;;
;//////////////////////////////////////////////////////

; DISKETTE I/O - Erdogan Tan (Retro UNIX 386 v1 project)
; 20/02/2015
; 06/02/2015 (unix386.s)
; 16/12/2014 - 02/01/2015 (dsectrm2.s)
;
; Code (DELAY) modifications - AWARD BIOS 1999 (ADISK.EQU, COMMON.MAC)
;
; ADISK.EQU

;----- Wait control constants 

;amount of time to wait while RESET is active.

WAITCPU_RESET_ON	EQU	21		;Reset on must last at least 14us
						;at 250 KBS xfer rate.
						;see INTEL MCS, 1985, pg. 5-456

WAITCPU_FOR_STATUS	EQU	100		;allow 30 microseconds for
						;status register to become valid
						;before re-reading.

;After sending a byte to NEC, status register may remain
;incorrectly set for 24 us.

WAITCPU_RQM_LOW		EQU	24		;number of loops to check for
						;RQM low.

; COMMON.MAC
;
;	Timing macros
;

%macro 		SIODELAY 0 			; SHORT IODELAY
		jmp short $+2
%endmacro		

%macro		IODELAY  0			; NORMAL IODELAY
		jmp short $+2
		jmp short $+2
%endmacro

%macro		NEWIODELAY 0
		out	0ebh,al
%endmacro 

; (According to) AWARD BIOS 1999 - ATORGS.ASM (dw -> equ, db -> equ)
;;; WAIT_FOR_MEM
;WAIT_FDU_INT_LO	equ	017798		; 2.5 secs in 30 micro units.
;WAIT_FDU_INT_HI	equ	1
WAIT_FDU_INT_LH		equ	83334		; 27/02/2015 (2.5 seconds waiting)
;;; WAIT_FOR_PORT
;WAIT_FDU_SEND_LO	equ	16667		; .5 secons in 30 us units.
;WAIT_FDU_SEND_HI	equ	0
WAIT_FDU_SEND_LH	equ 	16667		; 27/02/2015	
;Time to wait while waiting for each byte of NEC results = .5
;seconds.  .5 seconds = 500,000 micros.  500,000/30 = 16,667.
;WAIT_FDU_RESULTS_LO	equ	16667		; .5 seconds in 30 micro units.
;WAIT_FDU_RESULTS_HI	equ	0
WAIT_FDU_RESULTS_LH	equ	16667  ; 27/02/2015
;;; WAIT_REFRESH
;amount of time to wait for head settle, per unit in parameter
;table = 1 ms.
WAIT_FDU_HEAD_SETTLE	equ	33		; 1 ms in 30 micro units.


; //////////////// DISKETTE I/O ////////////////

; 11/12/2014 (copy from IBM PC-XT Model 286 BIOS - POSTEQU.INC)

;----------------------------------------
;	EQUATES USED BY POST AND BIOS	:
;----------------------------------------

;--------- 8042 KEYBOARD INTERFACE AND DIAGNOSTIC CONTROL REGISTERS ------------
;PORT_A		EQU	060H		; 8042 KEYBOARD SCAN CODE/CONTROL PORT
;PORT_B		EQU	061H		; PORT B READ/WRITE DIAGNOSTIC REGISTER
;REFRESH_BIT	EQU	00010000B	; REFRESH TEST BIT

;----------------------------------------
;	CMOS EQUATES FOR THIS SYSTEM	:
;-------------------------------------------------------------------------------
;CMOS_PORT	EQU	070H		; I/O ADDRESS OF CMOS ADDRESS PORT
;CMOS_DATA	EQU	071H		; I/O ADDRESS OF CMOS DATA PORT
;NMI		EQU	10000000B	; DISABLE NMI INTERRUPTS MASK -
					;  HIGH BIT OF CMOS LOCATION ADDRESS

;---------- CMOS TABLE LOCATION ADDRESS'S ## -----------------------------------
CMOS_DISKETTE	EQU	010H		; DISKETTE DRIVE TYPE BYTE	      ;
;		EQU	011H		; - RESERVED			      ;C
CMOS_DISK	EQU	012H		; FIXED DISK TYPE BYTE		      ;H
;		EQU	013H		; - RESERVED			      ;E
CMOS_EQUIP	EQU	014H		; EQUIPMENT WORD LOW BYTE	      ;C

;---------- DISKETTE EQUATES ---------------------------------------------------
INT_FLAG	EQU	10000000B	; INTERRUPT OCCURRENCE FLAG
DSK_CHG 	EQU	10000000B	; DISKETTE CHANGE FLAG MASK BIT
DETERMINED	EQU	00010000B	; SET STATE DETERMINED IN STATE BITS
HOME		EQU	00010000B	; TRACK 0 MASK
SENSE_DRV_ST	EQU	00000100B	; SENSE DRIVE STATUS COMMAND
TRK_SLAP	EQU	030H		; CRASH STOP (48 TPI DRIVES)
QUIET_SEEK	EQU	00AH		; SEEK TO TRACK 10
;MAX_DRV 	EQU	2		; MAX NUMBER OF DRIVES
HD12_SETTLE	EQU	15		; 1.2 M HEAD SETTLE TIME
HD320_SETTLE	EQU	20		; 320 K HEAD SETTLE TIME
MOTOR_WAIT	EQU	37		; 2 SECONDS OF COUNTS FOR MOTOR TURN OFF

;---------- DISKETTE ERRORS ----------------------------------------------------
;TIME_OUT	EQU	080H		; ATTACHMENT FAILED TO RESPOND
;BAD_SEEK	EQU	040H		; SEEK OPERATION FAILED
BAD_NEC 	EQU	020H		; DISKETTE CONTROLLER HAS FAILED
BAD_CRC 	EQU	010H		; BAD CRC ON DISKETTE READ
MED_NOT_FND	EQU	00CH		; MEDIA TYPE NOT FOUND
DMA_BOUNDARY	EQU	009H		; ATTEMPT TO DMA ACROSS 64K BOUNDARY
BAD_DMA 	EQU	008H		; DMA OVERRUN ON OPERATION
MEDIA_CHANGE	EQU	006H		; MEDIA REMOVED ON DUAL ATTACH CARD
RECORD_NOT_FND	EQU	004H		; REQUESTED SECTOR NOT FOUND
WRITE_PROTECT	EQU	003H		; WRITE ATTEMPTED ON WRITE PROTECT DISK
BAD_ADDR_MARK	EQU	002H		; ADDRESS MARK NOT FOUND
BAD_CMD 	EQU	001H		; BAD COMMAND PASSED TO DISKETTE I/O

;---------- DISK CHANGE LINE EQUATES -------------------------------------------
NOCHGLN 	EQU	001H		; NO DISK CHANGE LINE AVAILABLE
CHGLN		EQU	002H		; DISK CHANGE LINE AVAILABLE

;---------- MEDIA/DRIVE STATE INDICATORS ---------------------------------------
TRK_CAPA	EQU	00000001B	; 80 TRACK CAPABILITY
FMT_CAPA	EQU	00000010B	; MULTIPLE FORMAT CAPABILITY (1.2M)
DRV_DET 	EQU	00000100B	; DRIVE DETERMINED
MED_DET 	EQU	00010000B	; MEDIA DETERMINED BIT
DBL_STEP	EQU	00100000B	; DOUBLE STEP BIT
RATE_MSK	EQU	11000000B	; MASK FOR CLEARING ALL BUT RATE
RATE_500	EQU	00000000B	; 500 KBS DATA RATE
RATE_300	EQU	01000000B	; 300 KBS DATA RATE
RATE_250	EQU	10000000B	; 250 KBS DATA RATE
STRT_MSK	EQU	00001100B	; OPERATION START RATE MASK
SEND_MSK	EQU	11000000B	; MASK FOR SEND RATE BITS

;---------- MEDIA/DRIVE STATE INDICATORS COMPATIBILITY -------------------------
M3D3U		EQU	00000000B	; 360 MEDIA/DRIVE NOT ESTABLISHED
M3D1U		EQU	00000001B	; 360 MEDIA,1.2DRIVE NOT ESTABLISHED
M1D1U		EQU	00000010B	; 1.2 MEDIA/DRIVE NOT ESTABLISHED
MED_UNK 	EQU	00000111B	; NONE OF THE ABOVE

;---------- INTERRUPT EQUATES --------------------------------------------------
;EOI		EQU	020H		; END OF INTERRUPT COMMAND TO 8259
;INTA00		EQU	020H		; 8259 PORT
INTA01		EQU	021H		; 8259 PORT
INTB00		EQU	0A0H		; 2ND 8259
INTB01		EQU	0A1H		;

;-------------------------------------------------------------------------------
DMA08		EQU	008H		; DMA STATUS REGISTER PORT ADDRESS
DMA		EQU	000H		; DMA CH.0 ADDRESS REGISTER PORT ADDRESS
DMA18		EQU	0D0H		; 2ND DMA STATUS PORT ADDRESS
DMA1		EQU	0C0H		; 2ND DMA CH.0 ADDRESS REGISTER ADDRESS
;-------------------------------------------------------------------------------
;TIMER		EQU	040H		; 8254 TIMER - BASE ADDRESS

;-------------------------------------------------------------------------------
DMA_PAGE	EQU	081H		; START OF DMA PAGE REGISTERS

; 06/02/2015 (unix386.s, protected mode modifications)
; (unix386.s <-- dsectrm2.s)
; 11/12/2014 (copy from IBM PC-XT Model 286 BIOS - DSEG.INC)

; 10/12/2014
;
;int40h:
;	pushf
;	push 	cs
;	;cli
;	call 	DISKETTE_IO_1
;	retn

; DSKETTE ----- 04/21/86 DISKETTE BIOS
; (IBM PC XT Model 286 System BIOS Source Code, 04-21-86)
;

;-- INT13H ---------------------------------------------------------------------
; DISKETTE I/O
;	THIS INTERFACE PROVIDES ACCESS TO THE 5 1/4 INCH 360 KB,
;	1.2 MB, 720 KB AND 1.44 MB DISKETTE DRIVES.
; INPUT
;	(AH) =  00H RESET DISKETTE SYSTEM
;		HARD RESET TO NEC, PREPARE COMMAND, RECALIBRATE REQUIRED
;		ON ALL DRIVES
;------------------------------------------------------------------------------- 
;	(AH)= 01H  READ THE STATUS OF THE SYSTEM INTO (AH)
;		@DISKETTE_STATUS FROM LAST OPERATION IS USED
;-------------------------------------------------------------------------------
;	REGISTERS FOR READ/WRITE/VERIFY/FORMAT
;	(DL) - DRIVE NUMBER (0-1 ALLOWED, VALUE CHECKED)
;	(DH) - HEAD NUMBER (0-1 ALLOWED, NOT VALUE CHECKED)
;	(CH) - TRACK NUMBER (NOT VALUE CHECKED)
;		MEDIA	DRIVE	TRACK NUMBER
;		320/360	320/360	    0-39
;		320/360	1.2M	    0-39
;		1.2M	1.2M	    0-79
;		720K	720K	    0-79
;		1.44M	1.44M	    0-79	
;	(CL) - 	SECTOR NUMBER (NOT VALUE CHECKED, NOT USED FOR FORMAT)
;		MEDIA	DRIVE	SECTOR NUMBER
;		320/360	320/360	     1-8/9
;		320/360	1.2M	     1-8/9
;		1.2M	1.2M	     1-15
;		720K	720K	     1-9
;		1.44M	1.44M	     1-18		
;	(AL)	NUMBER OF SECTORS (NOT VALUE CHECKED)
;		MEDIA	DRIVE	MAX NUMBER OF SECTORS
;		320/360	320/360	        8/9
;		320/360	1.2M	        8/9
;		1.2M	1.2M		15
;		720K	720K		9
;		1.44M	1.44M		18
;
;	(ES:BX) - ADDRESS OF BUFFER (NOT REQUIRED FOR VERIFY)
;
;-------------------------------------------------------------------------------
;	(AH)= 02H  READ THE DESIRED SECTORS INTO MEMORY
;-------------------------------------------------------------------------------
;	(AH)= 03H  WRITE THE DESIRED SECTORS FROM MEMORY
;-------------------------------------------------------------------------------
;	(AH)= 04H  VERIFY THE DESIRED SECTORS
;-------------------------------------------------------------------------------
;	(AH)= 05H  FORMAT THE DESIRED TRACK
;		(ES,BX) MUST POINT TO THE COLLECTION OF DESIRED ADDRESS FIELDS
;		FOR THE	TRACK. EACH FIELD IS COMPOSED OF 4 BYTES, (C,H,R,N),
;		WHERE C = TRACK NUMBER, H=HEAD NUMBER, R = SECTOR NUMBER, 
;		N= NUMBER OF BYTES PER SECTOR (00=128,01=256,02=512,03=1024),
;		THERE MUST BE ONE ENTRY FOR EVERY SECTOR ON THE TRACK.
;		THIS INFORMATION IS USED TO FIND THE REQUESTED SECTOR DURING 
;		READ/WRITE ACCESS.
;		PRIOR TO FORMATTING A DISKETTE, IF THERE EXISTS MORE THAN
;		ONE SUPPORTED MEDIA FORMAT TYPE WITHIN THE DRIVE IN QUESTION,
;		THEN "SET DASD TYPE" (INT 13H, AH = 17H) OR 'SET MEDIA TYPE'
;		(INT 13H, AH =  18H) MUST BE CALLED TO SET THE DISKETTE TYPE
;		THAT IS TO BE FORMATTED. IF "SET DASD TYPE" OR "SET MEDIA TYPE"
;		IS NOT CALLED, THE FORMAT ROUTINE WILL ASSUME THE 
;		MEDIA FORMAT TO BE THE MAXIMUM CAPACITY OF THE DRIVE.
;
;		THESE PARAMETERS OF DISK BASE MUST BE CHANGED IN ORDER TO
;		FORMAT THE FOLLOWING MEDIAS:
;		---------------------------------------------
;		: MEDIA  :     DRIVE      : PARM 1 : PARM 2 :
;		---------------------------------------------
;		: 320K	 : 320K/360K/1.2M :  50H   :   8    :
;		: 360K	 : 320K/360K/1.2M :  50H   :   9    :
;		: 1.2M	 : 1.2M           :  54H   :  15    :
;		: 720K	 : 720K/1.44M     :  50H   :   9    :
;		: 1.44M	 : 1.44M          :  6CH   :  18    :		  	
;		---------------------------------------------
;		NOTES: - PARM 1 = GAP LENGTH FOR FORMAT
;		       - PARM 2 = EOT (LAST SECTOR ON TRACK)
;		       - DISK BASE IS POINTED BY DISK POINTER LOCATED
;			 AT ABSOLUTE ADDRESS 0:78.
;		       - WHEN FORMAT OPERATIONS ARE COMPLETE, THE PARAMETERS
;			 SHOULD BE RESTORED TO THEIR RESPECTIVE INITIAL VALUES.			
;-------------------------------------------------------------------------------
;	(AH) = 08H READ DRIVE PARAMETERS
;	REGISTERS
;	  INPUT
;	    (DL) - DRIVE NUMBER (0-1 ALLOWED, VALUE CHECKED)
;	  OUTPUT
;	    (ES:DI) POINTS TO DRIVE PARAMETER TABLE
;	    (CH) - LOW ORDER 8 OF 10 BITS MAXIMUM NUMBER OF TRACKS
;	    (CL) - BITS 7 & 6 - HIGH ORDER TWO BITS OF MAXIMUM TRACKS
;	           BITS 5 THRU 0 - MAXIMUM SECTORS PER TRACK
;	    (DH) - MAXIMUM HEAD NUMBER
;	    (DL) - NUMBER OF DISKETTE DRIVES INSTALLED
;	    (BH) - 0
;	    (BL) - BITS 7 THRU 4 - 0
;	           BITS 3 THRU 0 - VALID DRIVE TYPE VALUE IN CMOS
;	    (AX) - 0
;	 UNDER THE FOLLOWING CIRCUMSTANCES:
;	    (1) THE DRIVE NUMBER IS INVALID,
;	    (2) THE DRIVE TYPE IS UNKNOWN AND CMOS IS NOT PRESENT, 
;	    (3) THE DRIVE TYPE IS UNKNOWN AND CMOS IS BAD,
;	    (4) OR THE DRIVE TYPE IS UNKNOWN AND THE CMOS DRIVE TYPE IS INVALID
;	    THEN ES,AX,BX,CX,DH,DI=0 ; DL=NUMBER OF DRIVES. 
;	    IF NO DRIVES ARE PRESENT THEN: ES,AX,BX,CX,DX,DI=0.
;	    @DISKETTE_STATUS = 0 AND CY IS RESET.
;-------------------------------------------------------------------------------
;	(AH)= 15H  READ DASD TYPE
;	OUTPUT REGISTERS
;	(AH) - ON RETURN IF CARRY FLAG NOT SET, OTHERWISE ERROR	
;		00 - DRIVE NOT PRESENT	
;		01 - DISKETTE, NO CHANGE LINE AVAILABLE
;		02 - DISKETTE, CHANGE LINE AVAILABLE	
;		03 - RESERVED (FIXED DISK)
;	(DL) - DRIVE NUMBER (0-1 ALLOWED, VALUE CHECKED)
;-------------------------------------------------------------------------------
;	(AH)= 16H  DISK CHANGE LINE STATUS
;	OUTPUT REGISTERS
;	(AH) - 00 - DISK CHANGE LINE NOT ACTIVE	
;	       06 - DISK CHANGE LINE ACTIVE & CARRY BIT ON
;	(DL) - DRIVE NUMBER (0-1 ALLOWED, VALUE CHECKED)
;-------------------------------------------------------------------------------
;	(AH)= 17H  SET DASD TYPE FOR FORMAT
;	INPUT REGISTERS
;	(AL) -	00 - NOT USED	
;		01 - DISKETTE 320/360K IN 360K DRIVE	
;		02 - DISKETTE 360K IN 1.2M DRIVE
;		03 - DISKETTE 1.2M IN 1.2M DRIVE
;		04 - DISKETTE 720K IN 720K DRIVE
;	(DL) - DRIVE NUMBER (0-1 ALLOWED, VALUE CHECKED:
;	       (DO NOT USE WHEN DISKETTE ATTACH CARD USED)
;-------------------------------------------------------------------------------
;	(AH)= 18H  SET MEDIA TYPE FOR FORMAT
;	INPUT REGISTERS
;	(CH) - LOW ORDER 8 OF 10 BITS MAXIMUM TRACKS
;	(CL) - BITS 7 & 6 - HIGH ORDER TWO BITS OF MAXIMUM TRACKS
;	       BITS 5 THRU 0 - MAXIMUM SECTORS PER TRACK
;	(DL) - DRIVE NUMBER (0-1 ALLOWED, VALUE CHACKED)
;	OUTPUT REGISTERS:
;	(ES:DI) - POINTER TO DRIVE PARAMETERS TABLE FOR THIS MEDIA TYPE,
;		  UNCHANGED IF (AH) IS NON-ZERO
;	(AH) - 00H, CY = 0, TRACK AND SECTORS/TRACK COMBINATION IS SUPPORTED
;	     - 01H, CY = 1, FUNCTION IS NOT AVAILABLE
;	     - 0CH, CY = 1, TRACK AND SECTORS/TRACK COMBINATION IS NOT SUPPORTED
;	     - 80H, CY = 1, TIME OUT (DISKETTE NOT PRESENT)		
;-------------------------------------------------------------------------------
;	DISK CHANGE STATUS IS ONLY CHECKED WHEN A MEDIA SPECIFIED IS OTHER
;	THAN 360 KB DRIVE. IF THE DISK CHANGE LINE IS FOUND TO BE
;	ACTIVE THE FOLLOWING ACTIONS TAKE PLACE:
;		ATTEMPT TO RESET DISK CHANGE LINE TO INACTIVE STATE. 
;		IF ATTEMPT SUCCEEDS SET DASD TYPE FOR FORMAT AND RETURN DISK 
;		CHANGE ERROR CODE
;		IF ATTEMPT FAILS RETURN TIMEOUT ERROR CODE AND SET DASD TYPE 
;		TO A PREDETERMINED STATE INDICATING MEDIA TYPE UNKNOWN.
;	IF THE DISK CHANGE LINE IN INACTIVE PERFORM SET DASD TYPE FOR FORMAT.
;
; DATA VARIABLE -- @DISK_POINTER
;	DOUBLE WORD POINTER TO THE CURRENT SET OF DISKETTE PARAMETERS
;-------------------------------------------------------------------------------
; OUTPUT FOR ALL FUNCTIONS
;	AH = STATUS OF OPERATION
;		STATUS BITS ARE DEFINED IN THE EQUATES FOR @DISKETTE_STATUS
;		VARIABLE IN THE DATA SEGMENT OF THIS MODULE
;	CY = 0	SUCCESSFUL OPERATION (AH=0 ON RETURN, EXCEPT FOR READ DASD
;		TYPE AH=(15)).
;	CY = 1	FAILED OPERATION (AH HAS ERROR REASON)
;	FOR READ/WRITE/VERIFY
;		DS,BX,DX,CX PRESERVED
;	NOTE: IF AN ERROR IS REPORTED BY THE DISKETTE CODE, THE APPROPRIATE 
;		ACTION IS TO RESET THE DISKETTE, THEN RETRY THE OPERATION.
;		ON READ ACCESSES, NO MOTOR START DELAY IS TAKEN, SO THAT 
;		THREE RETRIES ARE REQUIRED ON READS TO ENSURE THAT THE 
;		PROBLEM IS NOT DUE TO MOTOR START-UP.
;-------------------------------------------------------------------------------
;
; DISKETTE STATE MACHINE - ABSOLUTE ADDRESS 40:90 (DRIVE A) & 91 (DRIVE B)
;
;   -----------------------------------------------------------------
;   |       |       |       |       |       |       |       |       |
;   |   7   |   6   |   5   |   4   |   3   |   2   |   1   |   0   |
;   |       |       |       |       |       |       |       |       |
;   -----------------------------------------------------------------
;	|	|	|	|	|	|	|	|
;	|	|	|	|	|	-----------------
;	|	|	|	|	|		|
;	|	|	|	|    RESERVED		|
;	|	|	|	|		  PRESENT STATE
;	|	|	|	|	000: 360K IN 360K DRIVE UNESTABLISHED
;	|	|	|	|	001: 360K IN 1.2M DRIVE UNESTABLISHED
;	|	|	|	|	010: 1.2M IN 1.2M DRIVE UNESTABLISHED
;	|	|	|	|	011: 360K IN 360K DRIVE ESTABLISHED
;	|	|	|	|	100: 360K IN 1.2M DRIVE ESTABLISHED
;	|	|	|	|	101: 1.2M IN 1.2M DRIVE ESTABLISHED
;	|	|	|	|	110: RESERVED
;	|	|	|	|	111: NONE OF THE ABOVE
;	|	|	|	|
;	|	|	|	------>	MEDIA/DRIVE ESTABLISHED
;	|	|	|
;	|	|	-------------->	DOUBLE STEPPING REQUIRED (360K IN 1.2M
;	|	|			DRIVE)
;	|	|
;	------------------------------>	DATA TRANSFER RATE FOR THIS DRIVE:
;
;						00: 500 KBS
;						01: 300 KBS
;						10: 250 KBS
;						11: RESERVED
;
;
;-------------------------------------------------------------------------------
; STATE OPERATION STARTED - ABSOLUTE ADDRESS 40:92 (DRIVE A) & 93 (DRIVE B)
;-------------------------------------------------------------------------------
; PRESENT CYLINDER NUMBER - ABSOLUTE ADDRESS 40:94 (DRIVE A) & 95 (DRIVE B)
;-------------------------------------------------------------------------------

struc MD
	.SPEC1		resb	1	; SRT=D, HD UNLOAD=0F - 1ST SPECIFY BYTE
	.SPEC2		resb	1	; HD LOAD=1, MODE=DMA - 2ND SPECIFY BYTE
	.OFF_TIM	resb	1	; WAIT TIME AFTER OPERATION TILL MOTOR OFF
	.BYT_SEC	resb	1	; 512 BYTES/SECTOR
	.SEC_TRK	resb	1	; EOT (LAST SECTOR ON TRACK)
	.GAP		resb	1	; GAP LENGTH
	.DTL		resb	1	; DTL
	.GAP3		resb	1	; GAP LENGTH FOR FORMAT
	.FIL_BYT	resb	1	; FILL BYTE FOR FORMAT
	.HD_TIM		resb	1	; HEAD SETTLE TIME (MILLISECONDS)
	.STR_TIM	resb	1	; MOTOR START TIME (1/8 SECONDS)
	.MAX_TRK	resb	1	; MAX. TRACK NUMBER
	.RATE		resb	1	; DATA TRANSFER RATE
endstruc

BIT7OFF	EQU	7FH
BIT7ON	EQU	80H

;;int13h: ; 16/02/2015
;; 16/02/2015 - 21/02/2015
int40h:
	pushfd
	push 	cs
	call 	DISKETTE_IO_1
	retn	

DISKETTE_IO_1:

	STI				; INTERRUPTS BACK ON
	PUSH	eBP			; USER REGISTER
	PUSH	eDI			; USER REGISTER
	PUSH	eDX			; HEAD #, DRIVE # OR USER REGISTER
	PUSH	eBX			; BUFFER OFFSET PARAMETER OR REGISTER
	PUSH	eCX			; TRACK #-SECTOR # OR USER REGISTER
	MOV	eBP,eSP			; BP     => PARAMETER LIST DEP. ON AH
					; [BP]   = SECTOR #
					; [BP+1] = TRACK #
					; [BP+2] = BUFFER OFFSET
					; FOR RETURN OF DRIVE PARAMETERS:
					; CL/[BP] = BITS 7&6 HI BITS OF MAX CYL
					; 	    BITS 0-5 MAX SECTORS/TRACK
					; CH/[BP+1] = LOW 8 BITS OF MAX CYL.
					; BL/[BP+2] = BITS 7-4 = 0
					;	      BITS 3-0 = VALID CMOS TYPE
					; BH/[BP+3] = 0
					; DL/[BP+4] = # DRIVES INSTALLED
					; DH/[BP+5] = MAX HEAD #
					; DI/[BP+6] = OFFSET TO DISK BASE
	push	es ; 06/02/2015	
	PUSH	DS			; BUFFER SEGMENT PARM OR USER REGISTER
	PUSH	eSI			; USER REGISTERS
	;CALL	DDS			; SEGMENT OF BIOS DATA AREA TO DS
	;mov	cx, cs
	;mov	ds, cx
	mov	cx, KDATA
        mov     ds, cx
        mov     es, cx

	;CMP	AH,(FNC_TAE-FNC_TAB)/2	; CHECK FOR > LARGEST FUNCTION
	cmp	ah,(FNC_TAE-FNC_TAB)/4 ; 18/02/2015
	JB	short OK_FUNC		; FUNCTION OK
	MOV	AH,14H			; REPLACE WITH KNOWN INVALID FUNCTION
OK_FUNC:
	CMP	AH,1			; RESET OR STATUS ?
	JBE	short OK_DRV		; IF RESET OR STATUS DRIVE ALWAYS OK
	CMP	AH,8			; READ DRIVE PARMS ?
	JZ	short OK_DRV		; IF SO DRIVE CHECKED LATER
	CMP	DL,1			; DRIVES 0 AND 1 OK
	JBE	short OK_DRV		; IF 0 OR 1 THEN JUMP
	MOV	AH,14H			; REPLACE WITH KNOWN INVALID FUNCTION
OK_DRV:
	xor	ecx, ecx
	;mov	esi, ecx ; 08/02/2015
	mov	edi, ecx ; 08/02/2015
	MOV	CL,AH			; CL = FUNCTION
	;XOR	CH,CH			; CX = FUNCTION
	;SHL	CL, 1			; FUNCTION TIMES 2
	SHL	CL, 2 ; 20/02/2015	; FUNCTION TIMES 4 (for 32 bit offset)
	MOV	eBX,FNC_TAB		; LOAD START OF FUNCTION TABLE
	ADD	eBX,eCX			; ADD OFFSET INTO TABLE => ROUTINE
	MOV	AH,DH			; AX = HEAD #,# OF SECTORS OR DASD TYPE
	XOR	DH,DH			; DX = DRIVE #
	MOV	SI,AX			; SI = HEAD #,# OF SECTORS OR DASD TYPE
	MOV     DI,DX                   ; DI = DRIVE #
	;
	; 11/12/2014
        mov     [cfd], dl               ; current floppy drive (for 'GET_PARM')        
	;
	MOV	AH, [DSKETTE_STATUS]	; LOAD STATUS TO AH FOR STATUS FUNCTION
	MOV	byte [DSKETTE_STATUS],0	; INITIALIZE FOR ALL OTHERS

;	THROUGHOUT THE DISKETTE BIOS, THE FOLLOWING INFORMATION IS CONTAINED IN
;	THE FOLLOWING MEMORY LOCATIONS AND REGISTERS. NOT ALL DISKETTE BIOS
;	FUNCTIONS REQUIRE ALL OF THESE PARAMETERS.
;
;		DI	: DRIVE #
;		SI-HI	: HEAD #
;		SI-LOW	: # OF SECTORS OR DASD TYPE FOR FORMAT
;		ES	: BUFFER SEGMENT
;		[BP]	: SECTOR #
;		[BP+1]	: TRACK #
;		[BP+2]	: BUFFER OFFSET
;
;	ACROSS CALLS TO SUBROUTINES THE CARRY FLAG (CY=1), WHERE INDICATED IN 
;	SUBROUTINE PROLOGUES, REPRESENTS AN EXCEPTION RETURN (NORMALLY AN ERROR 
;	CONDITION). IN MOST CASES, WHEN CY = 1, @DSKETTE_STATUS CONTAINS THE 
;	SPECIFIC ERROR CODE.
;
					; (AH) = @DSKETTE_STATUS
	CALL	dWORD [eBX]		; CALL THE REQUESTED FUNCTION
	POP	eSI			; RESTORE ALL REGISTERS
	POP	DS
	pop	es	; 06/02/2015
	POP	eCX
	POP	eBX
	POP	eDX
	POP	eDI
	MOV	eBP, eSP
	PUSH	eAX
	PUSHFd
	POP	eAX
	;MOV	[BP+6], AX
	mov	[ebp+12], eax  ; 18/02/2015, flags
	POP	eAX
	POP	eBP
	IRETd

;-------------------------------------------------------------------------------
; DW --> dd (06/02/2015)
FNC_TAB	dd	DSK_RESET		; AH = 00H; RESET
	dd	DSK_STATUS		; AH = 01H; STATUS
	dd	DSK_READ		; AH = 02H; READ
	dd	DSK_WRITE		; AH = 03H; WRITE
	dd	DSK_VERF		; AH = 04H; VERIFY
	dd	DSK_FORMAT		; AH = 05H; FORMAT
	dd	FNC_ERR			; AH = 06H; INVALID
	dd	FNC_ERR			; AH = 07H; INVALID
	dd	DSK_PARMS		; AH = 08H; READ DRIVE PARAMETERS
	dd	FNC_ERR			; AH = 09H; INVALID
	dd	FNC_ERR			; AH = 0AH; INVALID
	dd	FNC_ERR			; AH = 0BH; INVALID
	dd	FNC_ERR			; AH = 0CH; INVALID
	dd	FNC_ERR			; AH = 0DH; INVALID
	dd	FNC_ERR			; AH = 0EH; INVALID
	dd	FNC_ERR			; AH = 0FH; INVALID
	dd	FNC_ERR			; AH = 10H; INVALID
	dd	FNC_ERR			; AH = 11H; INVALID
	dd	FNC_ERR			; AH = 12H; INVALID
	dd	FNC_ERR			; AH = 13H; INVALID
	dd	FNC_ERR			; AH = 14H; INVALID
	dd	DSK_TYPE		; AH = 15H; READ DASD TYPE
	dd	DSK_CHANGE		; AH = 16H; CHANGE STATUS
	dd	FORMAT_SET		; AH = 17H; SET DASD TYPE
	dd	SET_MEDIA		; AH = 18H; SET MEDIA TYPE	
FNC_TAE EQU     $                       ; END

;-------------------------------------------------------------------------------
; DISK_RESET	(AH = 00H)	
;		RESET THE DISKETTE SYSTEM.
;
; ON EXIT:	@DSKETTE_STATUS, CY REFLECT STATUS OF OPERATION
;-------------------------------------------------------------------------------
DSK_RESET:
	MOV	DX,03F2H		; ADAPTER CONTROL PORT
	CLI				; NO INTERRUPTS
	MOV	AL,[MOTOR_STATUS]	; GET DIGITAL OUTPUT REGISTER REFLECTION
	AND	AL,00111111B		; KEEP SELECTED AND MOTOR ON BITS
	ROL	AL,4			; MOTOR VALUE TO HIGH NIBBLE
					; DRIVE SELECT TO LOW NIBBLE
	OR	AL,00001000B		; TURN ON INTERRUPT ENABLE
	OUT	DX,AL			; RESET THE ADAPTER
	MOV	byte [SEEK_STATUS],0	; SET RECALIBRATE REQUIRED ON ALL DRIVES
	;JMP	$+2			; WAIT FOR I/O
	;JMP	$+2			; WAIT FOR I/O (TO INSURE MINIMUM
					;      PULSE WIDTH)
	; 19/12/2014
	NEWIODELAY

	; 17/12/2014 
	; AWARD BIOS 1999 - RESETDRIVES (ADISK.ASM)
	mov	ecx, WAITCPU_RESET_ON	; cx = 21 -- Min. 14 micro seconds !?
wdw1:
	NEWIODELAY   ; 27/02/2015
	loop	wdw1
	;
	OR	AL,00000100B		; TURN OFF RESET BIT
	OUT	DX,AL			; RESET THE ADAPTER
	; 16/12/2014
	IODELAY
	;
	;STI				; ENABLE THE INTERRUPTS
	CALL	WAIT_INT		; WAIT FOR THE INTERRUPT
	JC	short DR_ERR		; IF ERROR, RETURN IT
	MOV	CX,11000000B		; CL = EXPECTED @NEC_STATUS
NXT_DRV:
	PUSH	CX			; SAVE FOR CALL
	MOV	eAX, DR_POP_ERR 	; LOAD NEC_OUTPUT ERROR ADDRESS
	PUSH	eAX			; "
	MOV	AH,08H			; SENSE INTERRUPT STATUS COMMAND
	CALL	NEC_OUTPUT
	POP	eAX			; THROW AWAY ERROR RETURN
	CALL	RESULTS			; READ IN THE RESULTS
	POP	CX			; RESTORE AFTER CALL
	JC	short DR_ERR		; ERROR RETURN
	CMP	CL, [NEC_STATUS]	; TEST FOR DRIVE READY TRANSITION
	JNZ	short DR_ERR		; EVERYTHING OK
	INC	CL			; NEXT EXPECTED @NEC_STATUS
	CMP	CL,11000011B		; ALL POSSIBLE DRIVES CLEARED
	JBE	short NXT_DRV		; FALL THRU IF 11000100B OR >
	;
	CALL	SEND_SPEC		; SEND SPECIFY COMMAND TO NEC
RESBAC:
	CALL	SETUP_END		; VARIOUS CLEANUPS
	MOV	BX,SI			; GET SAVED AL TO BL
	MOV	AL,BL			; PUT BACK FOR RETURN
	RETn		
DR_POP_ERR:
	POP	CX			; CLEAR STACK
DR_ERR:
	OR	byte [DSKETTE_STATUS],BAD_NEC ; SET ERROR CODE
	JMP	SHORT RESBAC		; RETURN FROM RESET

;-------------------------------------------------------------------------------
; DISK_STATUS	(AH = 01H)
;	DISKETTE STATUS.
;
; ON ENTRY:	AH : STATUS OF PREVIOUS OPERATION
;
; ON EXIT:	AH, @DSKETTE_STATUS, CY REFLECT STATUS OF PREVIOUS OPERATION.
;-------------------------------------------------------------------------------
DSK_STATUS:
	MOV	[DSKETTE_STATUS],AH	; PUT BACK FOR SETUP END
	CALL	SETUP_END		; VARIOUS CLEANUPS
	MOV	BX,SI			; GET SAVED AL TO BL
	MOV	AL,BL			; PUT BACK FOR RETURN
	RETn		

;-------------------------------------------------------------------------------
; DISK_READ	(AH = 02H)	
;	DISKETTE READ.
;
; ON ENTRY:	DI	: DRIVE #
;		SI-HI	: HEAD #
;		SI-LOW	: # OF SECTORS
;		ES	: BUFFER SEGMENT
;		[BP]	: SECTOR #
;		[BP+1]	: TRACK #
;		[BP+2]	: BUFFER OFFSET
;
; ON EXIT:	@DSKETTE_STATUS, CY REFLECT STATUS OF OPERATION
;-------------------------------------------------------------------------------

; 06/02/2015, ES:BX -> EBX (unix386.s)

DSK_READ:
	AND	byte [MOTOR_STATUS],01111111B ; INDICATE A READ OPERATION
	MOV	AX,0E646H		; AX = NEC COMMAND, DMA COMMAND
	CALL	RD_WR_VF		; COMMON READ/WRITE/VERIFY
	RETn

;-------------------------------------------------------------------------------
; DISK_WRITE	(AH = 03H)
;	DISKETTE WRITE.
;
; ON ENTRY:	DI	: DRIVE #
;		SI-HI	: HEAD #
;		SI-LOW	: # OF SECTORS
;		ES	: BUFFER SEGMENT
;		[BP]	: SECTOR #
;		[BP+1]	: TRACK #
;		[BP+2]	: BUFFER OFFSET
;
; ON EXIT:	@DSKETTE_STATUS, CY REFLECT STATUS OF OPERATION
;-------------------------------------------------------------------------------

; 06/02/2015, ES:BX -> EBX (unix386.s)

DSK_WRITE:
	MOV	AX,0C54AH		; AX = NEC COMMAND, DMA COMMAND
        OR      byte [MOTOR_STATUS],10000000B ; INDICATE WRITE OPERATION
	CALL	RD_WR_VF		; COMMON READ/WRITE/VERIFY
	RETn

;-------------------------------------------------------------------------------
; DISK_VERF	(AH = 04H)
;	DISKETTE VERIFY.
;
; ON ENTRY:	DI	: DRIVE #
;		SI-HI	: HEAD #
;		SI-LOW	: # OF SECTORS
;		ES	: BUFFER SEGMENT
;		[BP]	: SECTOR #
;		[BP+1]	: TRACK #
;		[BP+2]	: BUFFER OFFSET
;
; ON EXIT:	@DSKETTE_STATUS, CY REFLECT STATUS OF OPERATION
;-------------------------------------------------------------------------------
DSK_VERF:
	AND	byte [MOTOR_STATUS],01111111B ; INDICATE A READ OPERATION
	MOV	AX,0E642H		; AX = NEC COMMAND, DMA COMMAND
	CALL	RD_WR_VF		; COMMON READ/WRITE/VERIFY
	RETn

;-------------------------------------------------------------------------------
; DISK_FORMAT	(AH = 05H)
;	DISKETTE FORMAT.
;
; ON ENTRY:	DI	: DRIVE #
;		SI-HI	: HEAD #
;		SI-LOW	: # OF SECTORS
;		ES	: BUFFER SEGMENT
;		[BP]	: SECTOR #
;		[BP+1]	: TRACK #
;		[BP+2]	: BUFFER OFFSET
;		@DISK_POINTER POINTS TO THE PARAMETER TABLE OF THIS DRIVE
;
; ON EXIT:	@DSKETTE_STATUS, CY REFLECT STATUS OF OPERATION
;-------------------------------------------------------------------------------
DSK_FORMAT:
	CALL	XLAT_NEW		; TRANSLATE STATE TO PRESENT ARCH.
	CALL	FMT_INIT		; ESTABLISH STATE IF UNESTABLISHED
        OR      byte [MOTOR_STATUS], 10000000B ; INDICATE WRITE OPERATION
	CALL	MED_CHANGE		; CHECK MEDIA CHANGE AND RESET IF SO
        JC      short FM_DON            ; MEDIA CHANGED, SKIP
	CALL	SEND_SPEC		; SEND SPECIFY COMMAND TO NEC
	CALL	CHK_LASTRATE		; ZF=1 ATTEMPT RATE IS SAME AS LAST RATE
        JZ      short FM_WR             ; YES, SKIP SPECIFY COMMAND
	CALL	SEND_RATE		; SEND DATA RATE TO CONTROLLER
FM_WR:
	CALL	FMTDMA_SET		; SET UP THE DMA FOR FORMAT
        JC      short FM_DON            ; RETURN WITH ERROR
	MOV	AH,04DH			; ESTABLISH THE FORMAT COMMAND
	CALL	NEC_INIT		; INITIALIZE THE NEC
        JC      short FM_DON            ; ERROR - EXIT
        MOV     eAX, FM_DON             ; LOAD ERROR ADDRESS
	PUSH	eAX			; PUSH NEC_OUT ERROR RETURN
	MOV	DL,3			; BYTES/SECTOR VALUE TO NEC
	CALL	GET_PARM
	CALL	NEC_OUTPUT
	MOV	DL,4			; SECTORS/TRACK VALUE TO NEC
	CALL	GET_PARM
	CALL	NEC_OUTPUT
	MOV	DL,7			; GAP LENGTH VALUE TO NEC
	CALL	GET_PARM
	CALL	NEC_OUTPUT
	MOV	DL,8			; FILLER BYTE TO NEC
	CALL	GET_PARM
	CALL	NEC_OUTPUT
	POP	eAX			; THROW AWAY ERROR
	CALL	NEC_TERM		; TERMINATE, RECEIVE STATUS, ETC,
FM_DON:
	CALL	XLAT_OLD		; TRANSLATE STATE TO COMPATIBLE MODE
	CALL	SETUP_END		; VARIOUS CLEANUPS
	MOV	BX,SI			; GET SAVED AL TO BL
	MOV	AL,BL			; PUT BACK FOR RETURN
	RETn

;-------------------------------------------------------------------------------
; FNC_ERR
;	INVALID FUNCTION REQUESTED OR INVALID DRIVE: 
;	SET BAD COMMAND IN STATUS.
;
; ON EXIT: 	@DSKETTE_STATUS, CY REFLECT STATUS OF OPERATION
;-------------------------------------------------------------------------------
FNC_ERR:				; INVALID FUNCTION REQUEST
	MOV	AX,SI			; RESTORE AL
	MOV	AH,BAD_CMD		; SET BAD COMMAND ERROR
	MOV	[DSKETTE_STATUS],AH	; STORE IN DATA AREA
	STC				; SET CARRY INDICATING ERROR
	RETn

;-------------------------------------------------------------------------------
; DISK_PARMS	(AH = 08H)	
;	READ DRIVE PARAMETERS.
;
; ON ENTRY:	DI : DRIVE #
;
; ON EXIT:	CL/[BP]   = BITS 7 & 6 HI 2 BITS OF MAX CYLINDER
;		            BITS 0-5 MAX SECTORS/TRACK
;		CH/[BP+1] = LOW 8 BITS OF MAX CYLINDER
;		BL/[BP+2] = BITS 7-4 = 0
;		            BITS 3-0 = VALID CMOS DRIVE TYPE
;		BH/[BP+3] = 0
;		DL/[BP+4] = # DRIVES INSTALLED (VALUE CHECKED)
;		DH/[BP+5] = MAX HEAD #
;		DI/[BP+6] = OFFSET TO DISK_BASE
;		ES        = SEGMENT OF DISK_BASE
;		AX        = 0
;
;		NOTE : THE ABOVE INFORMATION IS STORED IN THE USERS STACK AT
;		       THE LOCATIONS WHERE THE MAIN ROUTINE WILL POP THEM
;		       INTO THE APPROPRIATE REGISTERS BEFORE RETURNING TO THE
;		       CALLER.
;-------------------------------------------------------------------------------
DSK_PARMS:
	CALL	XLAT_NEW		; TRANSLATE STATE TO PRESENT ARCH,
     ;	MOV	WORD [BP+2],0		; DRIVE TYPE = 0
	sub     edx, edx ; 20/02/2015
        mov	[ebp+4], edx ; 20/02/2015
     ;  MOV     AX, [EQUIP_FLAG]        ; LOAD EQUIPMENT FLAG FOR # DISKETTES
     ;  AND     AL,11000001B            ; KEEP DISKETTE DRIVE BITS
     ;  MOV     DL,2                    ; DISKETTE DRIVES = 2
     ;  CMP     AL,01000001B            ; 2 DRIVES INSTALLED ?
     ;  JZ      short STO_DL            ; IF YES JUMP
     ;  DEC     DL                      ; DISKETTE DRIVES = 1
     ;  CMP     AL,00000001B            ; 1 DRIVE INSTALLED ?
     ;  JNZ     short NON_DRV           ; IF NO JUMP
	;sub	edx, edx
	mov     ax, [fd0_type]
	and     ax, ax
	jz      short NON_DRV
	inc     dl
	and     ah, ah
	jz      short STO_DL
	inc     dl
STO_DL:
	;MOV	[BP+4],DL		; STORE NUMBER OF DRIVES
	mov	[ebp+8], edx ; 20/02/2015	 	
	CMP	DI,1			; CHECK FOR VALID DRIVE
	JA	short NON_DRV1		; DRIVE INVALID
	;MOV	BYTE [BP+5],1		; MAXIMUM HEAD NUMBER =	1
	mov	byte [ebp+9], 1  ; 20/02/2015	
	CALL	CMOS_TYPE		; RETURN DRIVE TYPE IN AL
	;;20/02/2015
	;;JC	short CHK_EST		; IF CMOS BAD CHECKSUM ESTABLISHED
	;;OR	AL,AL			; TEST FOR NO DRIVE TYPE
	JZ	short CHK_EST		; JUMP IF SO
	CALL	DR_TYPE_CHECK		; RTN CS:BX = MEDIA/DRIVE PARAM TBL
	JC	short CHK_EST		; TYPE NOT IN TABLE (POSSIBLE BAD CMOS)
	;MOV	[BP+2],AL		; STORE VALID CMOS DRIVE TYPE
        mov	[ebp+4], al ; 06/02/2015
	MOV     CL, [eBX+MD.SEC_TRK]     ; GET SECTOR/TRACK
        MOV     CH, [eBX+MD.MAX_TRK]     ; GET MAX. TRACK NUMBER
	JMP	SHORT STO_CX		; CMOS GOOD, USE CMOS
CHK_EST:
	MOV	AH, [DSK_STATE+eDI]	; LOAD STATE FOR THIS DRIVE
	TEST	AH,MED_DET		; CHECK FOR ESTABLISHED STATE
	JZ	short NON_DRV1		; CMOS BAD/INVALID OR UNESTABLISHED
USE_EST:
	AND	AH,RATE_MSK		; ISOLATE STATE
	CMP	AH,RATE_250		; RATE 250 ?
	JNE	short USE_EST2		; NO, GO CHECK OTHER RATE

;-----	DATA RATE IS 250 KBS, TRY 360 KB TABLE FIRST

	MOV	AL,01			; DRIVE TYPE 1 (360KB)
	CALL	DR_TYPE_CHECK		; RTN CS:BX = MEDIA/DRIVE PARAM TBL
        MOV     CL, [eBX+MD.SEC_TRK]    ; GET SECTOR/TRACK
        MOV     CH, [eBX+MD.MAX_TRK]    ; GET MAX. TRACK NUMBER
	TEST	byte [DSK_STATE+eDI],TRK_CAPA ; 80 TRACK ?
	JZ	short STO_CX		; MUST BE 360KB DRIVE 

;-----	IT IS 1.44 MB DRIVE

PARM144:
	MOV	AL,04			; DRIVE TYPE 4 (1.44MB)
	CALL	DR_TYPE_CHECK		; RTN CS:BX = MEDIA/DRIVE PARAM TBL
        MOV     CL, [eBX+MD.SEC_TRK]    ; GET SECTOR/TRACK
        MOV     CH, [eBX+MD.MAX_TRK]    ; GET MAX. TRACK NUMBER
STO_CX:
	MOV	[eBP],eCX		; SAVE POINTER IN STACK FOR RETURN
ES_DI:
	;MOV	[BP+6],BX		; ADDRESS OF MEDIA/DRIVE PARM TABLE 
	mov	[ebp+12], ebx ; 06/02/2015
	;MOV	AX,CS			; SEGMENT MEDIA/DRIVE PARAMETER TABLE
	;MOV	ES,AX			; ES IS SEGMENT OF TABLE
DP_OUT:
	CALL	XLAT_OLD		; TRANSLATE STATE TO COMPATIBLE MODE
	XOR	AX,AX			; CLEAR
	CLC
	RETn

;-----	NO DRIYE PRESENT HANDLER

NON_DRV:
	;MOV	BYTE [BP+4],0		; CLEAR NUMBER OF DRIVES
	mov	[ebp+8], edx ; 0 ; 20/02/2015
NON_DRV1:
	CMP	DI,80H			; CHECK FOR FIXED MEDIA TYPE REQUEST
	JB	short NON_DRV2		; CONTINUE IF NOT REQUEST FALL THROUGH

;-----	FIXED DISK REQUEST FALL THROUGH ERROR
	
	CALL	XLAT_OLD		; ELSE TRANSLATE TO COMPATIBLE MODE
	MOV	AX,SI			; RESTORE AL
	MOV	AH,BAD_CMD		; SET BAD COMMAND ERROR
	STC
	RETn

NON_DRV2:
	;XOR	AX,AX			; CLEAR PARMS IF NO DRIVES OR CMOS BAD
	xor	eax, eax	
	MOV	[eBP],AX		; TRACKS, SECTORS/TRACK = 0
	;MOV	[BP+5],AH		; HEAD = 0
	mov	[ebp+9], ah ; 06/02/2015
	;MOV	[BP+6],AX		; OFFSET TO DISK_BASE = 0
	mov	[ebp+12], eax
	;MOV	ES,AX			; ES IS SEGMENT OF TABLE
	JMP	SHORT DP_OUT

;-----	DATA RATE IS EITHER 300 KBS OR 500 KBS, TRY 1.2 MB TABLE FIRST

USE_EST2:
	MOV	AL,02			; DRIVE TYPE 2 (1.2MB)
	CALL	DR_TYPE_CHECK		; RTN CS:BX = MEDIA/DRIVE PARAM TBL
        MOV     CL, [eBX+MD.SEC_TRK]    ; GET SECTOR/TRACK
        MOV     CH, [eBX+MD.MAX_TRK]    ; GET MAX. TRACK NUMBER
	CMP	AH,RATE_300		; RATE 300 ?
	JZ	short STO_CX		; MUST BE 1.2MB DRIVE
	JMP	SHORT PARM144		; ELSE, IT IS 1.44MB DRIVE 

;-------------------------------------------------------------------------------
; DISK_TYPE (AH = 15H)	
;	THIS ROUTINE RETURNS THE TYPE OF MEDIA INSTALLED.
;
;  ON ENTRY:	DI = DRIVE #
;
;  ON EXIT:	AH = DRIVE TYPE, CY=0
;-------------------------------------------------------------------------------
DSK_TYPE:
	CALL	XLAT_NEW		; TRANSLATE STATE TO PRESENT ARCH.
	MOV	AL, [DSK_STATE+eDI]	; GET PRESENT STATE INFORMATION
	OR	AL,AL			; CHECK FOR NO DRIVE
	JZ	short NO_DRV
	MOV	AH,NOCHGLN		; NO CHANGE LINE FOR 40 TRACK DRIVE
	TEST	AL,TRK_CAPA		; IS THIS DRIVE AN 80 TRACK DRIVE?
	JZ	short DT_BACK			; IF NO JUMP
	MOV	AH,CHGLN		; CHANGE LINE FOR 80 TRACK DRIVE
DT_BACK:
	PUSH	AX			; SAVE RETURN VALUE
	CALL	XLAT_OLD		; TRANSLATE STATE TO COMPATIBLE MODE
	POP	AX			; RESTORE RETURN VALUE
	CLC				; NO ERROR
	MOV	BX,SI			; GET SAVED AL TO BL
	MOV	AL,BL			; PUT BACK FOR RETURN
	RETn
NO_DRV:	
	XOR	AH,AH			; NO DRIVE PRESENT OR UNKNOWN
	JMP	SHORT DT_BACK

;-------------------------------------------------------------------------------
; DISK_CHANGE	(AH = 16H)
;	THIS ROUTINE RETURNS THE STATE OF THE DISK CHANGE LINE.
;
; ON ENTRY:	DI = DRIVE #
;
; ON EXIT:	AH = @DSKETTE_STATUS
;		     00 - DISK CHANGE LINE INACTIVE, CY = 0
;		     06 - DISK CHANGE LINE ACTIVE, CY = 1
;-------------------------------------------------------------------------------
DSK_CHANGE:
	CALL	XLAT_NEW		; TRANSLATE STATE TO PRESENT ARCH.
	MOV	AL, [DSK_STATE+eDI]	; GET MEDIA STATE INFORMATION
	OR	AL,AL			; DRIVE PRESENT ?
	JZ	short DC_NON		; JUMP IF NO DRIVE
	TEST	AL,TRK_CAPA		; 80 TRACK DRIVE ?
	JZ	short SETIT		; IF SO , CHECK CHANGE LINE
DC0:
        CALL    READ_DSKCHNG            ; GO CHECK STATE OF DISK CHANGE LINE
	JZ	short FINIS		; CHANGE LINE NOT ACTIVE

SETIT:	MOV	byte [DSKETTE_STATUS], MEDIA_CHANGE ; INDICATE MEDIA REMOVED

FINIS:	CALL	XLAT_OLD		; TRANSLATE STATE TO COMPATIBLE MODE
	CALL	SETUP_END		; VARIOUS CLEANUPS
	MOV	BX,SI			; GET SAVED AL TO BL
	MOV	AL,BL			; PUT BACK FOR RETURN
	RETn
DC_NON:
	OR	byte [DSKETTE_STATUS], TIME_OUT ; SET TIMEOUT, NO DRIVE
	JMP	SHORT FINIS

;-------------------------------------------------------------------------------
; FORMAT_SET	(AH = 17H)
;	THIS ROUTINE IS USED TO ESTABLISH THE TYPE OF MEDIA TO BE USED
;	FOR THE FOLLOWING FORMAT OPERATION.
;
; ON ENTRY:	SI LOW = DASD TYPE FOR FORMAT
;		DI     = DRIVE #
;
; ON EXIT:	@DSKETTE_STATUS REFLECTS STATUS
;		AH = @DSKETTE_STATUS
;		CY = 1 IF ERROR
;-------------------------------------------------------------------------------
FORMAT_SET:
	CALL	XLAT_NEW		; TRANSLATE STATE TO PRESENT ARCH.
	PUSH	SI			; SAVE DASD TYPE
	MOV	AX,SI			; AH = ? , AL , DASD TYPE
	XOR	AH,AH			; AH , 0 , AL , DASD TYPE
	MOV	SI,AX			; SI = DASD TYPE
	AND	byte [DSK_STATE+eDI], ~(MED_DET+DBL_STEP+RATE_MSK) ; CLEAR STATE
	DEC	SI			; CHECK FOR 320/360K MEDIA & DRIVE
	JNZ	short NOT_320		; BYPASS IF NOT
	OR	byte [DSK_STATE+eDI], MED_DET+RATE_250 ; SET TO 320/360
	JMP	SHORT S0

NOT_320:
	CALL	MED_CHANGE		; CHECK FOR TIME_OUT
	CMP	byte [DSKETTE_STATUS], TIME_OUT
	JZ	short S0		; IF TIME OUT TELL CALLER
S3:
	DEC	SI			; CHECK FOR 320/360K IN 1.2M DRIVE
	JNZ	short NOT_320_12	; BYPASS IF NOT
	OR	byte [DSK_STATE+eDI], MED_DET+DBL_STEP+RATE_300 ; SET STATE
	JMP	SHORT S0

NOT_320_12:
	DEC	SI			; CHECK FOR 1.2M MEDIA IN 1.2M DRIVE
	JNZ	short NOT_12		; BYPASS IF NOT
	OR	byte [DSK_STATE+eDI], MED_DET+RATE_500 ; SET STATE VARIABLE
	JMP	SHORT S0		; RETURN TO CALLER

NOT_12:	
	DEC	SI			; CHECK FOR SET DASD TYPE 04
	JNZ	short FS_ERR		; BAD COMMAND EXIT IF NOT VALID TYPE

	TEST	byte [DSK_STATE+eDI], DRV_DET ; DRIVE DETERMINED ?
	JZ	short ASSUME		; IF STILL NOT DETERMINED ASSUME
	MOV	AL,MED_DET+RATE_300
        TEST    byte [DSK_STATE+eDI], FMT_CAPA ; MULTIPLE FORMAT CAPABILITY ?
	JNZ	short OR_IT_IN		; IF 1.2 M THEN DATA RATE 300

ASSUME:
	MOV	AL,MED_DET+RATE_250	; SET UP

OR_IT_IN:
	OR	[DSK_STATE+eDI], AL	; OR IN THE CORRECT STATE
S0:
	CALL	XLAT_OLD		; TRANSLATE STATE TO COMPATIBLE MODE
	CALL	SETUP_END		; VARIOUS CLEANUPS
	POP	BX			; GET SAVED AL TO BL
	MOV	AL,BL			; PUT BACK FOR RETURN
	RETn

FS_ERR:
	MOV	byte [DSKETTE_STATUS], BAD_CMD ; UNKNOWN STATE,BAD COMMAND
	JMP	SHORT S0

;-------------------------------------------------------------------------------
; SET_MEDIA	(AH = 18H)
;	THIS ROUTINE SETS THE TYPE OF MEDIA AND DATA RATE 
;	TO BE USED FOR THE FOLLOWING FORMAT OPERATION.
;
; ON ENTRY:
;	[BP]	= SECTOR PER TRACK
;	[BP+1]	= TRACK #
;	DI	= DRIVE #
;
; ON EXIT:
;	@DSKETTE_STATUS REFLECTS STATUS
;	IF NO ERROR:
;		AH = 0
;		CY = 0
;		ES = SEGMENT OF MEDIA/DRIVE PARAMETER TABLE
;		DI/[BP+6] = OFFSET OF MEDIA/DRIVE PARAMETER TABLE
;	IF ERROR:	
;		AH = @DSKETTE_STATUS
;		CY = 1
;-------------------------------------------------------------------------------
SET_MEDIA:
	CALL	XLAT_NEW		; TRANSLATE STATE TO PRESENT ARCH.
        TEST    byte [DSK_STATE+eDI], TRK_CAPA ; CHECK FOR CHANGE LINE AVAILABLE
	JZ	short SM_CMOS		; JUMP IF 40 TRACK DRIVE
	CALL	MED_CHANGE		; RESET CHANGE LINE
	CMP	byte [DSKETTE_STATUS], TIME_OUT ; IF TIME OUT TELL CALLER
	JE	short SM_RTN
	MOV	byte [DSKETTE_STATUS], 0 ; CLEAR STATUS
SM_CMOS:
	CALL	CMOS_TYPE		; RETURN DRIVE TYPE IN (AL)
	;;20/02/2015
	;;JC	short MD_NOT_FND	; ERROR IN CMOS
	;;OR	AL,AL			; TEST FOR NO DRIVE
	JZ	short SM_RTN		; RETURN IF SO
	CALL	DR_TYPE_CHECK		; RTN CS:BX = MEDIA/DRIVE PARAM TBL
	JC	short MD_NOT_FND	; TYPE NOT IN TABLE (BAD CMOS)
	PUSH	eDI			; SAVE REG.
	XOR	eBX,eBX			; BX = INDEX TO DR. TYPE TABLE
	MOV	eCX,DR_CNT		; CX = LOOP COUNT
DR_SEARCH:
	MOV	AH, [DR_TYPE+eBX]	; GET DRIVE TYPE
	AND	AH,BIT7OFF		; MASK OUT MSB
	CMP	AL,AH			; DRIVE TYPE MATCH ?
	JNE	short NXT_MD		; NO, CHECK NEXT DRIVE TYPE
DR_FND:
	MOV	eDI, [DR_TYPE+eBX+1] 	; DI = MEDIA/DRIVE PARAM TABLE
MD_SEARCH:
        MOV     AH, [eDI+MD.SEC_TRK]    ; GET SECTOR/TRACK
	CMP	[eBP],AH		; MATCH?
	JNE	short NXT_MD		; NO, CHECK NEXT MEDIA
        MOV     AH, [eDI+MD.MAX_TRK]    ; GET MAX. TRACK #
	CMP 	[eBP+1],AH		; MATCH?
	JE	short MD_FND		; YES, GO GET RATE
NXT_MD:
	;ADD	BX,3			; CHECK NEXT DRIVE TYPE
        add	ebx, 5 ; 18/02/2015
	LOOP    DR_SEARCH
	POP	eDI			; RESTORE REG.
MD_NOT_FND:
	MOV	byte [DSKETTE_STATUS], MED_NOT_FND ; ERROR, MEDIA TYPE NOT FOUND
	JMP	SHORT SM_RTN		; RETURN
MD_FND:
        MOV     AL, [eDI+MD.RATE]       ; GET RATE
	CMP	AL,RATE_300		; DOUBLE STEP REQUIRED FOR RATE 300
	JNE	short MD_SET
	OR	AL,DBL_STEP
MD_SET:
	;MOV	[BP+6],DI		; SAVE TABLE POINTER IN STACK
	mov	[ebp+12], edi ; 18/02/2015
	OR	AL,MED_DET		; SET MEDIA ESTABLISHED
	POP	eDI
	AND	byte [DSK_STATE+eDI], ~(MED_DET+DBL_STEP+RATE_MSK) ; CLEAR STATE
	OR	[DSK_STATE+eDI], AL
	;MOV	AX, CS			; SEGMENT OF MEDIA/DRIVE PARAMETER TABLE
	;MOV	ES, AX			; ES IS SEGMENT OF TABLE
SM_RTN:
	CALL	XLAT_OLD		; TRANSLATE STATE TO COMPATIBLE MODE
	CALL	SETUP_END		; VARIOUS CLEANUPS
	RETn

;----------------------------------------------------------------
; DR_TYPE_CHECK							:
;	CHECK IF THE GIVEN DRIVE TYPE IN REGISTER (AL)		:
;	IS SUPPORTED IN BIOS DRIVE TYPE TABLE			:
; ON ENTRY:							:
;	AL = DRIVE TYPE						:
; ON EXIT:							:
;	CS = SEGMENT MEDIA/DRIVE PARAMETER TABLE (CODE)		:
;	CY = 0 	DRIVE TYPE SUPPORTED				:
;	     BX = OFFSET TO MEDIA/DRIVE PARAMETER TABLE		:
;	CY = 1	DRIVE TYPE NOT SUPPORTED 			:
; REGISTERS ALTERED: eBX						:
;----------------------------------------------------------------		
DR_TYPE_CHECK:
	PUSH	AX			
	PUSH	eCX
	XOR	eBX,eBX			; BX = INDEX TO DR_TYPE TABLE
	MOV	eCX,DR_CNT		; CX = LOOP COUNT
TYPE_CHK:	
	MOV	AH,[DR_TYPE+eBX]	; GET DRIVE TYPE
	CMP	AL,AH			; DRIVE TYPE MATCH?
	JE	short DR_TYPE_VALID	; YES, RETURN WITH CARRY RESET
	;ADD	BX,3			; CHECK NEXT DRIVE TYPE
        add	ebx, 5	; 16/02/2015 (32 bit address modification)
	LOOP    TYPE_CHK
	;
	mov	ebx, MD_TBL6		; 1.44MB fd parameter table
					; Default for GET_PARM (11/12/2014)
	;
	STC				; DRIVE TYPE NOT FOUND IN TABLE
	JMP	SHORT TYPE_RTN
DR_TYPE_VALID:
	MOV	eBX,[DR_TYPE+eBX+1] 	; BX = MEDIA TABLE
TYPE_RTN:
	POP	eCX
	POP	AX
	RETn	
		
;----------------------------------------------------------------
; SEND_SPEC							:
;	SEND THE SPECIFY COMMAND TO CONTROLLER USING DATA FROM	:
;	THE DRIVE PARAMETER TABLE POINTED BY @DISK_POINTER	:
; ON ENTRY:	@DISK_POINTER = DRIVE PARAMETER TABLE		:
; ON EXIT:	NONE						:	
; REGISTERS ALTERED: CX, DX					:
;----------------------------------------------------------------		
SEND_SPEC:
	PUSH	eAX			; SAVE AX
	MOV	eAX, SPECBAC		; LOAD ERROR ADDRESS
	PUSH	eAX			; PUSH NEC_OUT ERROR RETURN
	MOV	AH,03H			; SPECIFY COMMAND
	CALL	NEC_OUTPUT		; OUTPUT THE COMMAND
	SUB	DL,DL			; FIRST SPECIFY BYTE
	CALL	GET_PARM		; GET PARAMETER TO AH
	CALL	NEC_OUTPUT		; OUTPUT THE COMMAND
	MOV	DL,1			; SECOND SPECIFY BYTE
	CALL	GET_PARM		; GET PARAMETER TO AH
	CALL	NEC_OUTPUT		; OUTPUT THE COMMAND
	POP	eAX			; POP ERROR RETURN
SPECBAC:
	POP	eAX			; RESTORE ORIGINAL AX VALUE
	RETn

;----------------------------------------------------------------
; SEND_SPEC_MD							:
;	SEND THE SPECIFY COMMAND TO CONTROLLER USING DATA FROM	:
;	THE MEDIA/DRIVE PARAMETER TABLE POINTED BY (CS:BX)	:
; ON ENTRY:	CS:BX = MEDIA/DRIVE PARAMETER TABLE		:
; ON EXIT:	NONE						:	
; REGISTERS ALTERED: AX						:
;----------------------------------------------------------------		
SEND_SPEC_MD:
	PUSH	eAX			; SAVE RATE DATA
	MOV	eAX, SPEC_ESBAC		; LOAD ERROR ADDRESS
	PUSH	eAX			; PUSH NEC_OUT ERROR RETURN
	MOV	AH,03H			; SPECIFY COMMAND
	CALL	NEC_OUTPUT		; OUTPUT THE COMMAND
        MOV     AH, [eBX+MD.SPEC1]      ; GET 1ST SPECIFY BYTE
	CALL	NEC_OUTPUT		; OUTPUT THE COMMAND
        MOV     AH, [eBX+MD.SPEC2]      ; GET SECOND SPECIFY BYTE
	CALL	NEC_OUTPUT		; OUTPUT THE COMMAND
	POP	eAX			; POP ERROR RETURN
SPEC_ESBAC:
	POP	eAX			; RESTORE ORIGINAL AX VALUE
	RETn

;-------------------------------------------------------------------------------
; XLAT_NEW  
;	TRANSLATES DISKETTE STATE LOCATIONS FROM COMPATIBLE
;	MODE TO NEW ARCHITECTURE.
;
; ON ENTRY:	DI = DRIVE #
;-------------------------------------------------------------------------------
XLAT_NEW:
	CMP	eDI,1				; VALID DRIVE
	JA	short XN_OUT			; IF INVALID BACK
	CMP	byte [DSK_STATE+eDI], 0		; NO DRIVE ?
	JZ	short DO_DET			; IF NO DRIVE ATTEMPT DETERMINE
	MOV	CX,DI				; CX = DRIVE NUMBER
	SHL	CL,2				; CL = SHIFT COUNT, A=0, B=4
	MOV	AL, [HF_CNTRL]			; DRIVE INFORMATION
	ROR	AL,CL				; TO LOW NIBBLE
	AND	AL,DRV_DET+FMT_CAPA+TRK_CAPA	; KEEP DRIVE BITS
        AND     byte [DSK_STATE+eDI], ~(DRV_DET+FMT_CAPA+TRK_CAPA)
	OR	[DSK_STATE+eDI], AL		; UPDATE DRIVE STATE
XN_OUT:
	RETn
DO_DET:
	CALL	DRIVE_DET			; TRY TO DETERMINE
	RETn

;-------------------------------------------------------------------------------
; XLAT_OLD 
;	TRANSLATES DISKETTE STATE LOCATIONS FROM NEW
;	ARCHITECTURE TO COMPATIBLE MODE.
;
; ON ENTRY:	DI = DRIVE
;-------------------------------------------------------------------------------
XLAT_OLD:
	CMP	eDI,1			; VALID DRIVE ?
        ;JA     short XO_OUT            ; IF INVALID BACK
        ja      XO_OUT
        CMP	byte [DSK_STATE+eDI],0	; NO DRIVE ?
	JZ	short XO_OUT		; IF NO DRIVE TRANSLATE DONE

;-----	TEST FOR SAVED DRIVE INFORMATION ALREADY SET

	MOV	CX,DI			; CX = DRIVE NUMBER
	SHL	CL,2			; CL = SHIFT COUNT, A=0, B=4
	MOV	AH,FMT_CAPA		; LOAD MULTIPLE DATA RATE BIT MASK
	ROR	AH,CL			; ROTATE BY MASK
	TEST	[HF_CNTRL], AH		; MULTIPLE-DATA RATE DETERMINED ?
	JNZ	short SAVE_SET		; IF SO, NO NEED TO RE-SAVE

;-----	ERASE DRIVE BITS IN @HF_CNTRL FOR THIS DRIVE

	MOV	AH,DRV_DET+FMT_CAPA+TRK_CAPA ; MASK TO KEEP
	ROR	AH,CL			; FIX MASK TO KEEP
	NOT	AH			; TRANSLATE MASK
	AND	[HF_CNTRL], AH		; KEEP BITS FROM OTHER DRIVE INTACT

;-----	ACCESS CURRENT DRIVE BITS AND STORE IN @HF_CNTRL

	MOV	AL, [DSK_STATE+eDI]	; ACCESS STATE
	AND	AL,DRV_DET+FMT_CAPA+TRK_CAPA ; KEEP DRIVE BITS
	ROR	AL,CL			; FIX FOR THIS DRIVE
	OR	[HF_CNTRL], AL		; UPDATE SAVED DRIVE STATE

;-----	TRANSLATE TO COMPATIBILITY MODE

SAVE_SET:
	MOV	AH, [DSK_STATE+eDI]	; ACCESS STATE
	MOV	BH,AH			; TO BH FOR LATER
	AND	AH,RATE_MSK		; KEEP ONLY RATE
	CMP	AH,RATE_500		; RATE 500 ?
	JZ	short CHK_144		; YES 1.2/1.2 OR 1.44/1.44
	MOV	AL,M3D1U		; AL = 360 IN 1.2 UNESTABLISHED
	CMP	AH,RATE_300		; RATE 300 ?
	JNZ	short CHK_250		; NO, 360/360, 720/720 OR 720/1.44
	TEST	BH,DBL_STEP		; CHECK FOR DOUBLE STEP
	JNZ	short TST_DET		; MUST BE 360 IN 1.2
UNKNO:
	MOV	AL,MED_UNK		; NONE OF THE ABOVE
	JMP	SHORT AL_SET		; PROCESS COMPLETE
CHK_144:
	CALL	CMOS_TYPE		; RETURN DRIVE TYPE IN (AL)
	;;20/02/2015
	;;JC	short UNKNO		; ERROR, SET 'NONE OF ABOVE'
	jz	short UNKNO ;; 20/02/2015
	CMP	AL,2			; 1.2MB DRIVE ?
	JNE	short UNKNO		; NO, GO SET 'NONE OF ABOVE'
	MOV	AL,M1D1U		; AL = 1.2 IN 1.2 UNESTABLISHED
	JMP	SHORT TST_DET
CHK_250:
	MOV	AL,M3D3U		; AL = 360 IN 360 UNESTABLISHED
	CMP	AH,RATE_250		; RATE 250 ?
	JNZ	short UNKNO		; IF SO FALL IHRU
	TEST	BH,TRK_CAPA		; 80 TRACK CAPABILITY ?
	JNZ	short UNKNO		; IF SO JUMP, FALL THRU TEST DET
TST_DET:
	TEST	BH,MED_DET		; DETERMINED ?
	JZ	short AL_SET		; IF NOT THEN SET
	ADD	AL,3			; MAKE DETERMINED/ESTABLISHED
AL_SET:
	AND	byte [DSK_STATE+eDI], ~(DRV_DET+FMT_CAPA+TRK_CAPA) ; CLEAR DRIVE
	OR	[DSK_STATE+eDI], AL	; REPLACE WITH COMPATIBLE MODE
XO_OUT:
	RETn

;-------------------------------------------------------------------------------
; RD_WR_VF
;	COMMON READ, WRITE AND VERIFY: 
;	MAIN LOOP FOR STATE RETRIES.
;
; ON ENTRY:	AH = READ/WRITE/VERIFY NEC PARAMETER
;		AL = READ/WRITE/VERIFY DMA PARAMETER
;
; ON EXIT:	@DSKETTE_STATUS, CY REFLECT STATUS OF OPERATION
;-------------------------------------------------------------------------------
RD_WR_VF:
	PUSH	AX			; SAVE DMA, NEC PARAMETERS
	CALL	XLAT_NEW		; TRANSLATE STATE TO PRESENT ARCH.
	CALL	SETUP_STATE		; INITIALIZE START AND END RATE
	POP	AX			; RESTORE READ/WRITE/VERIFY
DO_AGAIN:
	PUSH	AX			; SAVE READ/WRITE/VERIFY PARAMETER
	CALL	MED_CHANGE		; MEDIA CHANGE AND RESET IF CHANGED
	POP	AX			; RESTORE READ/WRITE/VERIFY
        JC      RWV_END                 ; MEDIA CHANGE ERROR OR TIME-OUT
RWV:
	PUSH	AX			; SAVE READ/WRITE/VERIFY PARAMETER
	MOV	DH, [DSK_STATE+eDI]	; GET RATE STATE OF THIS DRIVE
	AND	DH,RATE_MSK		; KEEP ONLY RATE
	CALL	CMOS_TYPE		; RETURN DRIVE TYPE IN AL (AL)
	;;20/02/2015
	;;JC	short RWV_ASSUME	; ERROR IN CMOS
	jz	short RWV_ASSUME ; 20/02/2015
	CMP	AL,1			; 40 TRACK DRIVE?
	JNE	short RWV_1		; NO, BYPASS CMOS VALIDITY CHECK
	TEST	byte [DSK_STATE+eDI], TRK_CAPA ; CHECK FOR 40 TRACK DRIVE
	JZ	short RWV_2		; YES, CMOS IS CORRECT
	MOV	AL,2			; CHANGE TO 1.2M
	JMP	SHORT RWV_2
RWV_1:
	JB	short RWV_2		; NO DRIVE SPECIFIED, CONTINUE
	TEST    byte [DSK_STATE+eDI], TRK_CAPA ; IS IT REALLY 40 TRACK?
	JNZ	short RWV_2		; NO, 80 TRACK
	MOV	AL,1			; IT IS 40 TRACK, FIX CMOS VALUE
	jmp	short rwv_3
RWV_2:
	OR	AL,AL			; TEST FOR NO DRIVE
	JZ	short RWV_ASSUME	; ASSUME TYPE, USE MAX TRACK
rwv_3:
	CALL	DR_TYPE_CHECK		; RTN CS:BX = MEDIA/DRIVE PARAM TBL.
	JC	short RWV_ASSUME	; TYPE NOT IN TABLE (BAD CMOS)

;-----	SEARCH FOR MEDIA/DRIVE PARAMETER TABLE

	PUSH	eDI			; SAVE DRIVE #
	XOR	eBX,eBX			; BX = INDEX TO DR_TYPE TABLE
	MOV	eCX,DR_CNT		; CX = LOOP COUNT
RWV_DR_SEARCH:
	MOV	AH, [DR_TYPE+eBX]	; GET DRIVE TYPE
	AND	AH,BIT7OFF		; MASK OUT MSB
	CMP	AL,AH			; DRIVE TYPE MATCH?
	JNE	short RWV_NXT_MD	; NO, CHECK NEXT DRIVE TYPE
RWV_DR_FND:
	MOV	eDI, [DR_TYPE+eBX+1] 	; DI = MEDIA/DRIVE PARAMETER TABLE
RWV_MD_SEARH:
        CMP     DH, [eDI+MD.RATE]       ; MATCH?
	JE	short RWV_MD_FND	; YES, GO GET 1ST SPECIFY BYTE
RWV_NXT_MD:
	;ADD	BX,3			; CHECK NEXT DRIVE TYPE
	add	eBX, 5
	LOOP	RWV_DR_SEARCH
	POP	eDI			; RESTORE DRIVE #

;-----	ASSUME PRIMARY DRIVE IS INSTALLED AS SHIPPED

RWV_ASSUME:
	MOV	eBX, MD_TBL1		; POINT TO 40 TRACK 250 KBS
	TEST 	byte [DSK_STATE+eDI], TRK_CAPA ; TEST FOR 80 TRACK
	JZ	short RWV_MD_FND1	; MUST BE 40 TRACK
	MOV	eBX, MD_TBL3		; POINT TO 80 TRACK 500 KBS
	JMP	short RWV_MD_FND1	; GO SPECIFY PARAMTERS

;-----	CS:BX POINTS TO MEDIA/DRIVE PARAMETER TABLE
	 			
RWV_MD_FND:
	MOV	eBX,eDI			; BX = MEDIA/DRIVE PARAMETER TABLE
	POP	eDI			; RESTORE DRIVE #
	
;-----	SEND THE SPECIFY COMMAND TO THE CONTROLLER

RWV_MD_FND1:
	CALL	SEND_SPEC_MD
	CALL	CHK_LASTRATE		; ZF=1 ATTEMP RATE IS SAME AS LAST RATE
	JZ	short RWV_DBL		; YES,SKIP SEND RATE COMMAND
	CALL	SEND_RATE		; SEND DATA RATE TO NEC
RWV_DBL:
	PUSH	eBX			; SAVE MEDIA/DRIVE PARAM TBL ADDRESS
	CALL	SETUP_DBL		; CHECK FOR DOUBLE STEP
	POP	eBX			; RESTORE ADDRESS
	JC	short CHK_RET		; ERROR FROM READ ID, POSSIBLE RETRY
	POP	AX			; RESTORE NEC, DMA COMMAND
	PUSH	AX			; SAVE NEC COMMAND
	PUSH	eBX			; SAVE MEDIA/DRIVE PARAM TBL ADDRESS
	CALL	DMA_SETUP		; SET UP THE DMA
	POP	eBX 
	POP	AX			; RESTORE NEC COMMAND
	JC	short RWV_BAC		; CHECK FOR DMA BOUNDARY ERROR
	PUSH	AX			; SAVE NEC COMMAND
	PUSH	eBX			; SAVE MEDIA/DRIVE PARAM TBL ADDRESS
	CALL	NEC_INIT		; INITIALIZE NEC
	POP	eBX			; RESTORE ADDRESS
	JC	short CHK_RET		; ERROR - EXIT
	CALL	RWV_COM			; OP CODE COMMON TO READ/WRITE/VERIFY
	JC	short CHK_RET		; ERROR - EXIT
	CALL	NEC_TERM		; TERMINATE, GET STATUS, ETC.
CHK_RET:
	CALL	RETRY			; CHECK FOR, SETUP RETRY
	POP	AX			; RESTORE READ/WRITE/VERIFY PARAMETER
	JNC	short RWV_END		; CY = 0 NO RETRY
        JMP     DO_AGAIN                ; CY = 1 MEANS RETRY
RWV_END:
	CALL	DSTATE			; ESTABLISH STATE IF SUCCESSFUL
	CALL	NUM_TRANS		; AL = NUMBER TRANSFERRED
RWV_BAC:				; BAD DMA ERROR ENTRY
	PUSH	AX			; SAVE NUMBER TRANSFERRED
	CALL	XLAT_OLD		; TRANSLATE STATE TO COMPATIBLE MODE
	POP	AX			; RESTORE NUMBER TRANSFERRED
	CALL	SETUP_END		; VARIOUS CLEANUPS
	RETn

;-------------------------------------------------------------------------------
; SETUP_STATE:	INITIALIZES START AND END RATES.
;-------------------------------------------------------------------------------
SETUP_STATE:
	TEST	byte [DSK_STATE+eDI], MED_DET ; MEDIA DETERMINED ?
	JNZ	short J1C		; NO STATES IF DETERMINED
        MOV     AX,(RATE_500*256)+RATE_300  ; AH = START RATE, AL = END RATE
	TEST	byte [DSK_STATE+eDI],DRV_DET ; DRIVE ?
	JZ	short AX_SET		; DO NOT KNOW DRIVE
	TEST	byte [DSK_STATE+eDI], FMT_CAPA ; MULTI-RATE?
	JNZ	short AX_SET		; JUMP IF YES
        MOV     AX,RATE_250*257         ; START A END RATE 250 FOR 360 DRIVE
AX_SET:	
	AND	byte [DSK_STATE+eDI], ~(RATE_MSK+DBL_STEP) ; TURN OFF THE RATE
	OR	[DSK_STATE+eDI], AH	; RATE FIRST TO TRY
	AND	byte [LASTRATE], ~STRT_MSK ; ERASE LAST TO TRY RATE BITS
	ROR	AL,4			; TO OPERATION LAST RATE LOCATION
	OR	[LASTRATE], AL		; LAST RATE
J1C:	
	RETn

;-------------------------------------------------------------------------------
;  FMT_INIT: ESTABLISH STATE IF UNESTABLISHED AT FORMAT TIME.
;-------------------------------------------------------------------------------
FMT_INIT:
	TEST	byte [DSK_STATE+eDI], MED_DET ; IS MEDIA ESTABLISHED
	JNZ	short F1_OUT		; IF SO RETURN
	CALL	CMOS_TYPE		; RETURN DRIVE TYPE IN AL
	;; 20/02/2015
	;;JC	short CL_DRV		; ERROR IN CMOS ASSUME NO DRIVE
	jz	short CL_DRV ;; 20/02/2015
	DEC	AL			; MAKE ZERO ORIGIN
	;;JS	short CL_DRV		; NO DRIVE IF AL 0
	MOV	AH, [DSK_STATE+eDI]	; AH = CURRENT STATE
	AND	AH, ~(MED_DET+DBL_STEP+RATE_MSK) ; CLEAR
	OR	AL,AL			; CHECK FOR 360
	JNZ	short N_360		; IF 360 WILL BE 0
	OR	AH,MED_DET+RATE_250	; ESTABLISH MEDIA
	JMP	SHORT SKP_STATE		; SKIP OTHER STATE PROCESSING
N_360:	
	DEC	AL			; 1.2 M DRIVE
	JNZ	short N_12		; JUMP IF NOT
F1_RATE:
	OR	AH,MED_DET+RATE_500	; SET FORMAT RATE
	JMP	SHORT SKP_STATE		; SKIP OTHER STATE PROCESSING
N_12:	
	DEC	AL			; CHECK FOR TYPE 3
	JNZ	short N_720		; JUMP IF NOT
	TEST	AH,DRV_DET		; IS DRIVE DETERMINED
	JZ	short ISNT_12		; TREAT AS NON 1.2 DRIVE
	TEST	AH,FMT_CAPA		; IS 1.2M
	JZ	short ISNT_12		; JUMP IF NOT
	OR	AH,MED_DET+RATE_300	; RATE 300
	JMP	SHORT SKP_STATE		; CONTINUE
N_720:
	DEC	AL			; CHECK FOR TYPE 4
	JNZ	short CL_DRV		; NO DRIVE, CMOS BAD
	JMP	SHORT F1_RATE
ISNT_12: 
	OR	AH,MED_DET+RATE_250	; MUST BE RATE 250

SKP_STATE:
	MOV	[DSK_STATE+eDI], AH	; STORE AWAY
F1_OUT:
	RETn
CL_DRV:	
	XOR	AH,AH			; CLEAR STATE
	JMP	SHORT SKP_STATE		; SAVE IT

;-------------------------------------------------------------------------------
; MED_CHANGE	
;	CHECKS FOR MEDIA CHANGE, RESETS MEDIA CHANGE, 
;	CHECKS MEDIA CHANGE AGAIN.
;
; ON EXIT:	CY = 1 MEANS MEDIA CHANGE OR TIMEOUT
;		@DSKETTE_STATUS = ERROR CODE
;-------------------------------------------------------------------------------
MED_CHANGE:
	CALL	READ_DSKCHNG		; READ DISK CHANCE LINE STATE
	JZ	short MC_OUT		; BYPASS HANDLING DISK CHANGE LINE
	AND	byte [DSK_STATE+eDI], ~MED_DET ; CLEAR STATE FOR THIS DRIVE

;	THIS SEQUENCE ENSURES WHENEVER A DISKETTE IS CHANGED THAT
;	ON THE NEXT OPERATION THE REQUIRED MOTOR START UP TIME WILL
;	BE WAITED. (DRIVE MOTOR MAY GO OFF UPON DOOR OPENING).

	MOV	CX,DI			; CL = DRIVE 0
	MOV	AL,1			; MOTOR ON BIT MASK
	SHL	AL,CL			; TO APPROPRIATE POSITION
	NOT	AL			; KEEP ALL BUT MOTOR ON
	CLI				; NO INTERRUPTS
	AND	[MOTOR_STATUS], AL	; TURN MOTOR OFF INDICATOR
	STI				; INTERRUPTS ENABLED
	CALL	MOTOR_ON		; TURN MOTOR ON

;-----	THIS SEQUENCE OF SEEKS IS USED TO RESET DISKETTE CHANGE SIGNAL

	CALL	DSK_RESET		; RESET NEC
	MOV	CH,01H			; MOVE TO CYLINDER 1
	CALL	SEEK			; ISSUE SEEK
	XOR	CH,CH			; MOVE TO CYLINDER 0
	CALL	SEEK			; ISSUE SEEK
	MOV	byte [DSKETTE_STATUS], MEDIA_CHANGE ; STORE IN STATUS
OK1:
	CALL	READ_DSKCHNG		; CHECK MEDIA CHANGED AGAIN
	JZ	short OK2		; IF ACTIVE, NO DISKETTE, TIMEOUT
OK4:
	MOV	byte [DSKETTE_STATUS], TIME_OUT ; TIMEOUT IF DRIVE EMPTY
OK2:		
	STC				; MEDIA CHANGED, SET CY
	RETn
MC_OUT:
	CLC				; NO MEDIA CHANGED, CLEAR CY
	RETn

;-------------------------------------------------------------------------------
; SEND_RATE
;	SENDS DATA RATE COMMAND TO NEC
; ON ENTRY:	DI = DRIVE #
; ON EXIT:	NONE
; REGISTERS ALTERED: DX
;-------------------------------------------------------------------------------
SEND_RATE:
	PUSH	AX			; SAVE REG.
	AND	byte [LASTRATE], ~SEND_MSK ; ELSE CLEAR LAST RATE ATTEMPTED
	MOV	AL, [DSK_STATE+eDI]	; GET RATE STATE OF THIS DRIVE
	AND	AL,SEND_MSK		; KEEP ONLY RATE BITS
	OR	[LASTRATE], AL		; SAVE NEW RATE FOR NEXT CHECK
	ROL	AL,2			; MOVE TO BIT OUTPUT POSITIONS
	MOV	DX,03F7H		; OUTPUT NEW DATA RATE
	OUT	DX,AL
	POP	AX			; RESTORE REG.
	RETn

;-------------------------------------------------------------------------------
; CHK_LASTRATE
;	CHECK PREVIOUS DATE RATE SNT TO THE CONTROLLER.
; ON ENTRY:
;	DI = DRIVE #
; ON EXIT:
;	ZF =  1 DATA RATE IS THE SAME AS THE LAST RATE SENT TO NEC
;	ZF =  0 DATA RATE IS DIFFERENT FROM LAST RATE
; REGISTERS ALTERED: DX
;-------------------------------------------------------------------------------
CHK_LASTRATE:
	PUSH	AX			; SAVE REG
	AND	AH, [LASTRATE]		; GET LAST DATA RATE SELECTED
	MOV	AL, [DSK_STATE+eDI]	; GET RATE STATE OF THIS DRIVE
        AND     AX, SEND_MSK*257        ; KEEP ONLY RATE BITS OF BOTH
	CMP	AL, AH			; COMPARE TO PREVIOUSLY TRIED
					; ZF = 1 RATE IS THE SAME
	POP	AX			; RESTORE REG.
	RETn

;-------------------------------------------------------------------------------
; DMA_SETUP
;	THIS ROUTINE SETS UP THE DMA FOR READ/WRITE/VERIFY OPERATIONS.
;
; ON ENTRY:	AL = DMA COMMAND
;
; ON EXIT:	@DSKETTE_STATUS, CY REFLECT STATUS OF OPERATION
;-------------------------------------------------------------------------------

; SI = Head #, # of Sectors or DASD Type

; 22/08/2015
; 08/02/2015 - Protected Mode Modification
; 06/02/2015 - 07/02/2015
; NOTE: Buffer address must be in 1st 16MB of Physical Memory (24 bit limit).
; (DMA Addres = Physical Address)
; (Retro UNIX 386 v1 Kernel/System Mode Virtual Address = Physical Address)
;


; 04/02/2016 (clc)
; 20/02/2015 modification (source: AWARD BIOS 1999, DMA_SETUP)
; 16/12/2014 (IODELAY)

DMA_SETUP:

;; 20/02/2015
	mov	edx, [ebp+4] 		; Buffer address
	test	edx, 0FF000000h		; 16 MB limit (22/08/2015, bugfix)
	jnz	short dma_bnd_err_stc
	;
	push	ax			; DMA command
	push	edx			; *
	mov	dl, 3			; GET BYTES/SECTOR PARAMETER
	call	GET_PARM		; 
	mov	cl, ah 			; SHIFT COUNT (0=128, 1=256, 2=512 ETC)
	mov	ax, si			; Sector count
	mov	ah, al			; AH =  # OF SECTORS
	sub	al, al			; AL = 0, AX = # SECTORS * 256
	shr	ax, 1			; AX = # SECTORS * 128
	shl	ax, cl			; SHIFT BY PARAMETER VALUE
	dec	ax			; -1 FOR DMA VALUE
	mov	cx, ax
	pop	edx			; *
	pop	ax
	cmp	al, 42h
        jne     short NOT_VERF
	mov	edx, 0FF0000h
	jmp	short J33
NOT_VERF:
	add	dx, cx			; check for overflow
	jc	short dma_bnd_err
	;
	sub	dx, cx			; Restore start address
J33:
	CLI				; DISABLE INTERRUPTS DURING DMA SET-UP
	OUT	DMA+12,AL		; SET THE FIRST/LA5T F/F
	IODELAY				; WAIT FOR I/O
	OUT	DMA+11,AL		; OUTPUT THE MODE BYTE
	mov	eax, edx		; Buffer address
	OUT	DMA+4,AL		; OUTPUT LOW ADDRESS
	IODELAY				; WAIT FOR I/O
	MOV	AL,AH
	OUT	DMA+4,AL		; OUTPUT HIGH ADDRESS
	shr	eax, 16
	IODELAY				; I/O WAIT STATE
	OUT	081H,AL			; OUTPUT highest BITS TO PAGE REGISTER
	IODELAY
	mov	ax, cx			; Byte count - 1
	OUT	DMA+5,AL		; LOW BYTE OF COUNT
	IODELAY				; WAIT FOR I/O
	MOV	AL, AH
	OUT	DMA+5,AL		; HIGH BYTE OF COUNT
	IODELAY
	STI				; RE-ENABLE INTERRUPTS
	MOV	AL, 2			; MODE FOR 8237
	OUT	DMA+10, AL		; INITIALIZE THE DISKETTE CHANNEL

	clc	; 04/02/2016
	retn

dma_bnd_err_stc:
	stc
dma_bnd_err:
	MOV	byte [DSKETTE_STATUS], DMA_BOUNDARY ; SET ERROR
	RETn				; CY SET BY ABOVE IF ERROR

;; 16/12/2014
;;	CLI				; DISABLE INTERRUPTS DURING DMA SET-UP
;;	OUT	DMA+12,AL		; SET THE FIRST/LA5T F/F
;;	;JMP	$+2			; WAIT FOR I/O
;;	IODELAY
;; 	OUT	DMA+11,AL		; OUTPUT THE MODE BYTE
;;	;SIODELAY
;;      ;CMP	AL, 42H			; DMA VERIFY COMMAND
;;      ;JNE	short NOT_VERF		; NO
;;      ;XOR	AX, AX			; START ADDRESS
;;      ;JMP	SHORT J33
;;;NOT_VERF:	
;;	;MOV	AX,ES			; GET THE ES VALUE
;;	;ROL	AX,4			; ROTATE LEFT
;;	;MOV	CH,AL			; GET HIGHEST NIBBLE OF ES TO CH
;;	;AND	AL,11110000B		; ZERO THE LOW NIBBLE FROM SEGMENT
;;	;ADD	AX,[BP+2]		; TEST FOR CARRY FROM ADDITION
;;	mov	eax, [ebp+4] ; 06/02/2015	
;;	;JNC	short J33
;;	;INC	CH			; CARRY MEANS HIGH 4 BITS MUST BE INC
;;;J33:
;;	PUSH	eAX			; SAVE START ADDRESS
;;	OUT	DMA+4,AL		; OUTPUT LOW ADDRESS
;;	;JMP	$+2			; WAIT FOR I/O
;;	IODELAY
;;	MOV	AL,AH
;;	OUT	DMA+4,AL		; OUTPUT HIGH ADDRESS
;;	shr	eax, 16	     ; 07/02/2015
;;	;MOV	AL,CH			; GET HIGH 4 BITS
;;	;JMP	$+2			; I/O WAIT STATE
;;	IODELAY
;;	;AND	AL,00001111B
;;	OUT	081H,AL			; OUTPUT HIGH 4 BITS TO PAGE REGISTER
;;	;SIODELAY
;;
;;;----- DETERMINE COUNT
;;	sub	eax, eax ; 08/02/2015
;;	MOV	AX, SI			; AL =  # OF SECTORS
;;	XCHG	AL, AH			; AH =  # OF SECTORS
;;	SUB	AL, AL			; AL = 0, AX = # SECTORS * 256
;;	SHR	AX, 1			; AX = # SECTORS * 128
;;	PUSH	AX			; SAVE # OF SECTORS * 128
;;	MOV	DL, 3			; GET BYTES/SECTOR PARAMETER
;;	CALL	GET_PARM		; "
;;	MOV	CL,AH			; SHIFT COUNT (0=128, 1=256, 2=512 ETC)
;;	POP	AX			; AX = # SECTORS * 128
;;	SHL	AX,CL			; SHIFT BY PARAMETER VALUE
;;	DEC	AX			; -1 FOR DMA VALUE
;;	PUSH	eAX  ; 08/02/2015	; SAVE COUNT VALUE
;;	OUT	DMA+5,AL		; LOW BYTE OF COUNT
;;	;JMP	$+2			; WAIT FOR I/O
;;	IODELAY
;;	MOV	AL, AH
;;	OUT	DMA+5,AL		; HIGH BYTE OF COUNT
;;	;IODELAY
;;	STI				; RE-ENABLE INTERRUPTS
;;	POP	eCX  ; 08/02/2015 	; RECOVER COUNT VALUE
;;	POP	eAX  ; 08/02/2015	; RECOVER ADDRESS VALUE
;;	;ADD	AX, CX			; ADD, TEST FOR 64K OVERFLOW
;;	add	ecx, eax ; 08/02/2015
;;	MOV	AL, 2			; MODE FOR 8237
;;	;JMP	$+2			; WAIT FOR I/O
;;	SIODELAY
;;	OUT	DMA+10, AL		; INITIALIZE THE DISKETTE CHANNEL
;;	;JNC	short NO_BAD		; CHECK FOR ERROR
;;	jc	short dma_bnd_err ; 08/02/2015
;;	and	ecx, 0FFF00000h ; 16 MB limit
;;	jz	short NO_BAD
;;dma_bnd_err:
;;	MOV	byte [DSKETTE_STATUS], DMA_BOUNDARY ; SET ERROR
;;NO_BAD:
;;	RETn				; CY SET BY ABOVE IF ERROR

;-------------------------------------------------------------------------------
; FMTDMA_SET
;	THIS ROUTINE SETS UP THE DMA CONTROLLER FOR A FORMAT OPERATION.
;
; ON ENTRY:	NOTHING REQUIRED
;
; ON EXIT:	@DSKETTE_STATUS, CY REFLECT STATUS OF OPERATION
;-------------------------------------------------------------------------------

FMTDMA_SET:
;; 20/02/2015 modification	
	mov	edx, [ebp+4] 		; Buffer address
	test	edx, 0FFF00000h		; 16 MB limit
	jnz	short dma_bnd_err_stc
	;
	push	dx			; *
	mov	DL, 4			; SECTORS/TRACK VALUE IN PARM TABLE
	call	GET_PARM		; "
	mov	al, ah			; AL = SECTORS/TRACK VALUE
	sub	ah, ah			; AX = SECTORS/TRACK VALUE
	shl	ax, 2			; AX = SEC/TRK * 4 (OFFSET C,H,R,N)
	dec	ax			; -1 FOR DMA VALUE
	mov	cx, ax
	pop	dx			; *
	add	dx, cx			; check for overflow
	jc	short dma_bnd_err
	;
	sub	dx, cx			; Restore start address
	;
	MOV	AL, 04AH		; WILL WRITE TO THE DISKETTE
	CLI				; DISABLE INTERRUPTS DURING DMA SET-UP
	OUT	DMA+12,AL		; SET THE FIRST/LA5T F/F
	IODELAY				; WAIT FOR I/O
	OUT	DMA+11,AL		; OUTPUT THE MODE BYTE
	mov	eax, edx		; Buffer address
	OUT	DMA+4,AL		; OUTPUT LOW ADDRESS
	IODELAY				; WAIT FOR I/O
	MOV	AL,AH
	OUT	DMA+4,AL		; OUTPUT HIGH ADDRESS
	shr	eax, 16
	IODELAY				; I/O WAIT STATE
	OUT	081H,AL			; OUTPUT highest BITS TO PAGE REGISTER
	IODELAY
	mov	ax, cx			; Byte count - 1
	OUT	DMA+5,AL		; LOW BYTE OF COUNT
	IODELAY				; WAIT FOR I/O
	MOV	AL, AH
	OUT	DMA+5,AL		; HIGH BYTE OF COUNT
	IODELAY
	STI				; RE-ENABLE INTERRUPTS
	MOV	AL, 2			; MODE FOR 8237
	OUT	DMA+10, AL		; INITIALIZE THE DISKETTE CHANNEL
	retn

;; 08/02/2015 - Protected Mode Modification
;;	MOV	AL, 04AH		; WILL WRITE TO THE DISKETTE
;;	CLI				; DISABLE INTERRUPTS DURING DMA SET-UP
;;	OUT	DMA+12,AL		; SET THE FIRST/LA5T F/F
;;	;JMP	$+2			; WAIT FOR I/O
;;	IODELAY
;;	OUT	DMA+11,AL		; OUTPUT THE MODE BYTE
;;	;MOV	AX,ES			; GET THE ES VALUE
;;	;ROL	AX,4			; ROTATE LEFT
;;	;MOV	CH,AL			; GET HIGHEST NIBBLE OF ES TO CH
;;	;AND	AL,11110000B		; ZERO THE LOW NIBBLE FROM SEGMENT
;;	;ADD	AX,[BP+2]		; TEST FOR CARRY FROM ADDITION
;;	;JNC	short J33A
;;	;INC	CH			; CARRY MEANS HIGH 4 BITS MUST BE INC
;;	mov	eax, [ebp+4] ; 08/02/2015
;;;J33A:
;;	PUSH	eAX ; 08/02/2015	; SAVE START ADDRESS
;;	OUT	DMA+4,AL		; OUTPUT LOW ADDRESS
;;	;JMP	$+2			; WAIT FOR I/O
;;	IODELAY
;;	MOV	AL,AH
;;	OUT	DMA+4,AL		; OUTPUT HIGH ADDRESS
;;	shr 	eax, 16 ; 08/02/2015
;;	;MOV	AL,CH			; GET HIGH 4 BITS
;;	;JMP	$+2			; I/O WAIT STATE
;;	IODELAY
;;	;AND	AL,00001111B
;;	OUT	081H,AL			; OUTPUT HIGH 4 BITS TO PAGE REGISTER
;;
;;;----- DETERMINE COUNT
;;	sub	eax, eax ; 08/02/2015
;;	MOV	DL, 4			; SECTORS/TRACK VALUE IN PARM TABLE
;;	CALL	GET_PARM		; "
;;	XCHG	AL, AH			; AL = SECTORS/TRACK VALUE
;;	SUB	AH, AH			; AX = SECTORS/TRACK VALUE
;;	SHL	AX, 2			; AX = SEC/TRK * 4 (OFFSET C,H,R,N)
;;	DEC	AX			; -1 FOR DMA VALUE
;;	PUSH	eAX 	; 08/02/2015	; SAVE # OF BYTES TO BE TRANSFERED
;;	OUT	DMA+5,AL		; LOW BYTE OF COUNT
;;	;JMP	$+2			; WAIT FOR I/O
;;	IODELAY
;;	MOV	AL, AH
;;	OUT	DMA+5,AL		; HIGH BYTE OF COUNT
;;	STI				; RE-ENABLE INTERRUPTS
;;	POP	eCX	; 08/02/2015	; RECOVER COUNT VALUE
;;	POP	eAX	; 08/02/2015	; RECOVER ADDRESS VALUE
;;	;ADD	AX, CX			; ADD, TEST FOR 64K OVERFLOW
;;	add	ecx, eax ; 08/02/2015
;;	MOV	AL, 2			; MODE FOR 8237
;;	;JMP	$+2			; WAIT FOR I/O
;;	SIODELAY
;;	OUT	DMA+10, AL		; INITIALIZE THE DISKETTE CHANNEL
;;	;JNC	short FMTDMA_OK		; CHECK FOR ERROR
;;	jc	short fmtdma_bnd_err ; 08/02/2015
;;	and	ecx, 0FFF00000h  ; 16 MB limit
;;	jz	short FMTDMA_OK
;;	stc	; 20/02/2015
;;fmtdma_bnd_err:
;;	MOV	byte [DSKETTE_STATUS], DMA_BOUNDARY ; SET ERROR
;;FMTDMA_OK:
;;	RETn				; CY SET BY ABOVE IF ERROR

;-------------------------------------------------------------------------------
; NEC_INIT	
;	THIS ROUTINE SEEKS TO THE REQUESTED TRACK AND INITIALIZES
;	THE NEC FOR THE READ/WRITE/VERIFY/FORMAT OPERATION.
;
; ON ENTRY:	AH = NEC COMMAND TO BE PERFORMED
;
; ON EXIT:	@DSKETTE_STATUS, CY REFLECT STATUS OF OPERATION
;-------------------------------------------------------------------------------
NEC_INIT:
	PUSH	AX			; SAVE NEC COMMAND
	CALL	MOTOR_ON		; TURN MOTOR ON FOR SPECIFIC DRIVE

;-----	DO THE SEEK OPERATION

	MOV	CH,[eBP+1]		; CH = TRACK #
	CALL	SEEK			; MOVE TO CORRECT TRACK
	POP	AX			; RECOVER COMMAND
	JC	short ER_1		; ERROR ON SEEK
	MOV	eBX, ER_1		; LOAD ERROR ADDRESS
	PUSH	eBX			; PUSH NEC_OUT ERROR RETURN

;-----	SEND OUT THE PARAMETERS TO THE CONTROLLER

	CALL	NEC_OUTPUT		; OUTPUT THE OPERATION COMMAND
	MOV	AX,SI			; AH = HEAD #
	MOV	eBX,eDI			; BL = DRIVE #
	SAL	AH,2			; MOVE IT TO BIT 2
	AND	AH,00000100B		; ISOLATE THAT BIT
	OR	AH,BL			; OR IN THE DRIVE NUMBER
	CALL	NEC_OUTPUT		; FALL THRU CY SET IF ERROR
	POP	eBX			; THROW AWAY ERROR RETURN
ER_1:
	RETn

;-------------------------------------------------------------------------------
; RWV_COM
;	THIS ROUTINE SENDS PARAMETERS TO THE NEC SPECIFIC TO THE 
;	READ/WRITE/VERIFY OPERATIONS.
;
; ON ENTRY:	CS:BX = ADDRESS OF MEDIA/DRIVE PARAMETER TABLE
; ON EXIT:	@DSKETTE_STATUS, CY REFLECT STATUS OF OPERATION
;-------------------------------------------------------------------------------
RWV_COM:
	MOV	eAX, ER_2		; LOAD ERROR ADDRESS
	PUSH	eAX			; PUSH NEC_OUT ERROR RETURN
	MOV	AH,[eBP+1]		; OUTPUT TRACK #
	CALL	NEC_OUTPUT
	MOV	AX,SI			; OUTPUT HEAD #
	CALL	NEC_OUTPUT
        MOV     AH,[eBP]                ; OUTPUT SECTOR #
	CALL	NEC_OUTPUT
	MOV	DL,3			; BYTES/SECTOR PARAMETER FROM BLOCK
	CALL	GET_PARM 		; ... TO THE NEC
	CALL	NEC_OUTPUT		; OUTPUT TO CONTROLLER
	MOV	DL,4			; EOT PARAMETER FROM BLOCK
	CALL	GET_PARM 		; ... TO THE NEC
	CALL	NEC_OUTPUT		; OUTPUT TO CONTROLLER
        MOV     AH, [eBX+MD.GAP]        ; GET GAP LENGTH
_R15:
	CALL	NEC_OUTPUT
	MOV	DL,6			; DTL PARAMETER PROM BLOCK
	CALL	GET_PARM		;  TO THE NEC
	CALL	NEC_OUTPUT		; OUTPUT TO CONTROLLER
	POP	eAX			; THROW AWAY ERROR EXIT
ER_2:
	RETn

;-------------------------------------------------------------------------------
; NEC_TERM
;	THIS ROUTINE WAITS FOR THE OPERATION THEN ACCEPTS THE STATUS 
;	FROM THE NEC FOR THE READ/WRITE/VERIFY/FORWAT OPERATION.
;
; ON EXIT:	@DSKETTE_STATUS, CY REFLECT STATUS OF OPERATION
;-------------------------------------------------------------------------------
NEC_TERM:

;-----	LET THE OPERATION HAPPEN

	PUSH	eSI			; SAVE HEAD #, # OF SECTORS
	CALL	WAIT_INT		; WAIT FOR THE INTERRUPT
	PUSHF
	CALL	RESULTS			; GET THE NEC STATUS
	JC	short SET_END_POP
	POPF
	JC	short SET_END		; LOOK FOR ERROR

;-----	CHECK THE RESULTS RETURNED BY THE CONTROLLER

	CLD				; SET THE CORRECT DIRECTION
	MOV	eSI, NEC_STATUS		; POINT TO STATUS FIELD
	lodsb				; GET ST0
	AND	AL,11000000B		; TEST FOR NORMAL TERMINATION
	JZ	short SET_END
	CMP	AL,01000000B		; TEST FOR ABNORMAL TERMINATION
	JNZ	short J18		; NOT ABNORMAL, BAD NEC

;-----	ABNORMAL TERMINATION, FIND OUT WHY

	lodsb				; GET ST1
	SAL	AL,1			; TEST FOR EDT FOUND
	MOV	AH,RECORD_NOT_FND
	JC	short J19
	SAL	AL,2
	MOV	AH,BAD_CRC
	JC	short J19
	SAL	AL,1			; TEST FOR DMA OVERRUN
	MOV	AH,BAD_DMA
	JC	short J19
	SAL	AL,2			; TEST FOR RECORD NOT FOUND
	MOV	AH,RECORD_NOT_FND
	JC	short J19
	SAL	AL,1
	MOV	AH,WRITE_PROTECT	; TEST FOR WRITE_PROTECT
	JC	short J19
	SAL	AL,1			; TEST MISSING ADDRESS MARK
	MOV	AH,BAD_ADDR_MARK
	JC	short J19

;----- 	NEC MUST HAVE FAILED
J18:
	MOV	AH,BAD_NEC
J19:
	OR	[DSKETTE_STATUS], AH
SET_END:
	CMP	byte [DSKETTE_STATUS], 1 ; SET ERROR CONDITION
	CMC
	POP	eSI
	RETn				; RESTORE HEAD #, # OF SECTORS

SET_END_POP:
	POPF
	JMP	SHORT SET_END

;-------------------------------------------------------------------------------
; DSTATE:	ESTABLISH STATE UPON SUCCESSFUL OPERATION.
;-------------------------------------------------------------------------------
DSTATE:
	CMP	byte [DSKETTE_STATUS],0	; CHECK FOR ERROR
	JNZ	short SETBAC		    ; IF ERROR JUMP
	OR	byte [DSK_STATE+eDI],MED_DET ; NO ERROR, MARK MEDIA AS DETERMINED
	TEST	byte [DSK_STATE+eDI],DRV_DET ; DRIVE DETERMINED ?
	JNZ	short SETBAC		; IF DETERMINED NO TRY TO DETERMINE
	MOV	AL,[DSK_STATE+eDI]	; LOAD STATE
	AND	AL,RATE_MSK		; KEEP ONLY RATE
	CMP	AL,RATE_250		; RATE 250 ?
	JNE	short M_12		; NO, MUST BE 1.2M OR 1.44M DRIVE

;----- 	CHECK IF IT IS 1.44M

	CALL	CMOS_TYPE		; RETURN DRIVE TYPE IN (AL)
	;;20/02/2015
	;;JC	short M_12		; CMOS BAD
	jz	short M_12 ;; 20/02/2015
	CMP	AL, 4			; 1.44MB DRIVE ?
	JE	short M_12		; YES
M_720:
	AND	byte [DSK_STATE+eDI], ~FMT_CAPA ; TURN OFF FORMAT CAPABILITY
	OR	byte [DSK_STATE+eDI],DRV_DET  ; MARK DRIVE DETERMINED
	JMP	SHORT SETBAC		; BACK
M_12:	
	OR	byte [DSK_STATE+eDI],DRV_DET+FMT_CAPA 
					; TURN ON DETERMINED & FMT CAPA
SETBAC:
	RETn

;-------------------------------------------------------------------------------
; RETRY	
;	DETERMINES WHETHER A RETRY IS NECESSARY. 
;	IF RETRY IS REQUIRED THEN STATE INFORMATION IS UPDATED FOR RETRY.
;
; ON EXIT:	CY = 1 FOR RETRY, CY = 0 FOR NO RETRY
;-------------------------------------------------------------------------------
RETRY:
	CMP	byte [DSKETTE_STATUS],0	; GET STATUS OF OPERATION
	JZ	short NO_RETRY		; SUCCESSFUL OPERATION
	CMP	byte [DSKETTE_STATUS],TIME_OUT ; IF TIME OUT NO RETRY
	JZ	short NO_RETRY
	MOV	AH,[DSK_STATE+eDI]	; GET MEDIA STATE OF DRIVE
	TEST	AH,MED_DET		; ESTABLISHED/DETERMINED ?
	JNZ	short NO_RETRY		; IF ESTABLISHED STATE THEN TRUE ERROR
	AND	AH,RATE_MSK		; ISOLATE RATE
	MOV	CH,[LASTRATE]		; GET START OPERATION STATE
	ROL	CH,4			; TO CORRESPONDING BITS
	AND	CH,RATE_MSK		; ISOLATE RATE BITS
	CMP	CH,AH			; ALL RATES TRIED
	JE	short NO_RETRY		; IF YES, THEN TRUE ERROR

;	SETUP STATE INDICATOR FOR RETRY ATTEMPT TO NEXT RATE
;	 00000000B (500) -> 10000000B	(250)
;	 10000000B (250) -> 01000000B	(300)
;	 01000000B (300) -> 00000000B	(500)

	CMP	AH,RATE_500+1		; SET CY FOR RATE 500
	RCR	AH,1			; TO NEXT STATE
	AND	AH,RATE_MSK		; KEEP ONLY RATE BITS
	AND	byte [DSK_STATE+eDI], ~(RATE_MSK+DBL_STEP)
					; RATE, DBL STEP OFF
	OR	[DSK_STATE+eDI],AH	; TURN ON NEW RATE
	MOV	byte [DSKETTE_STATUS],0	; RESET STATUS FOR RETRY
	STC				; SET CARRY FOR RETRY
	RETn				; RETRY RETURN

NO_RETRY:
	CLC				; CLEAR CARRY NO RETRY
	RETn				; NO RETRY RETURN

;-------------------------------------------------------------------------------
; NUM_TRANS
;	THIS ROUTINE CALCULATES THE NUMBER OF SECTORS THAT WERE
;	ACTUALLY TRANSFERRED TO/FROM THE DISKETTE.
;
; ON ENTRY:	[BP+1] = TRACK
;		SI-HI  = HEAD
;		[BP]   = START SECTOR
;
; ON EXIT:	AL = NUMBER ACTUALLY TRANSFERRED
;-------------------------------------------------------------------------------
NUM_TRANS:
	XOR	AL,AL			; CLEAR FOR ERROR
	CMP	byte [DSKETTE_STATUS],0	; CHECK FOR ERROR
	JNZ	NT_OUT			; IF ERROR 0 TRANSFERRED
	MOV	DL,4			; SECTORS/TRACK OFFSET TO DL
	CALL	GET_PARM		; AH = SECTORS/TRACK
	MOV	BL, [NEC_STATUS+5]	; GET ENDING SECTOR
	MOV	CX,SI			; CH = HEAD # STARTED
	CMP	CH, [NEC_STATUS+4]	; GET HEAD ENDED UP ON
	JNZ	DIF_HD			; IF ON SAME HEAD, THEN NO ADJUST
	MOV	CH, [NEC_STATUS+3]	; GET TRACK ENDED UP ON
	CMP	CH,[eBP+1]		; IS IT ASKED FOR TRACK
	JZ	short SAME_TRK		; IF SAME TRACK NO INCREASE
	ADD	BL,AH			; ADD SECTORS/TRACK
DIF_HD:
	ADD	BL,AH			; ADD SECTORS/TRACK
SAME_TRK:
	SUB	BL,[eBP]		; SUBTRACT START FROM END
	MOV	AL,BL			; TO AL
NT_OUT:
	RETn

;-------------------------------------------------------------------------------
; SETUP_END
;	RESTORES @MOTOR_COUNT TO PARAMETER PROVIDED IN TABLE 
;	AND LOADS @DSKETTE_STATUS TO AH, AND SETS CY.
;
; ON EXIT:
;	AH, @DSKETTE_STATUS, CY REFLECT STATUS OF OPERATION
;-------------------------------------------------------------------------------
SETUP_END:
	MOV	DL,2			; GET THE MOTOR WAIT PARAMETER
	PUSH	AX			; SAVE NUMBER TRANSFERRED
	CALL	GET_PARM
	MOV	[MOTOR_COUNT],AH	; STORE UPON RETURN
	POP	AX			; RESTORE NUMBER TRANSFERRED
	MOV	AH, [DSKETTE_STATUS]	; GET STATUS OF OPERATION
	OR	AH,AH			; CHECK FOR ERROR
	JZ	short NUN_ERR			; NO ERROR
	XOR	AL,AL			; CLEAR NUMBER RETURNED
NUN_ERR: 
	CMP	AH,1			; SET THE CARRY FLAG TO INDICATE
	CMC				; SUCCESS OR FAILURE
	RETn

;-------------------------------------------------------------------------------
; SETUP_DBL
;	CHECK DOUBLE STEP.
;
; ON ENTRY :	DI = DRIVE
;
; ON EXIT :	CY = 1 MEANS ERROR
;-------------------------------------------------------------------------------
SETUP_DBL:
	MOV	AH, [DSK_STATE+eDI]	; ACCESS STATE
	TEST	AH,MED_DET		; ESTABLISHED STATE ?
	JNZ	short NO_DBL			; IF ESTABLISHED THEN DOUBLE DONE

;-----	CHECK FOR TRACK 0 TO SPEED UP ACKNOWLEDGE OF UNFORMATTED DISKETTE

	MOV	byte [SEEK_STATUS],0	; SET RECALIBRATE REQUIRED ON ALL DRIVES
	CALL	MOTOR_ON		; ENSURE MOTOR STAY ON
	MOV	CH,0			; LOAD TRACK 0
	CALL	SEEK			; SEEK TO TRACK 0
	CALL	READ_ID			; READ ID FUNCTION
	JC	short SD_ERR		; IF ERROR NO TRACK 0

;-----	INITIALIZE START AND MAX TRACKS (TIMES 2 FOR BOTH HEADS)

	MOV	CX,0450H 		; START, MAX TRACKS
	TEST	byte [DSK_STATE+eDI],TRK_CAPA ; TEST FOR 80 TRACK CAPABILITY
	JZ	short CNT_OK		; IF NOT COUNT IS SETUP
	MOV	CL,0A0H			; MAXIMUM TRACK 1.2 MB

;	ATTEMPT READ ID OF ALL TRACKS, ALL HEADS UNTIL SUCCESS; UPON SUCCESS,
;	MUST SEE IF ASKED FOR TRACK IN SINGLE STEP MODE = TRACK ID READ; IF NOT
;	THEN SET DOUBLE STEP ON.

CNT_OK:
        MOV     byte [MOTOR_COUNT], 0FFH ; ENSURE MOTOR STAYS ON FOR OPERATION 
	PUSH	CX			; SAVE TRACK, COUNT
	MOV	byte [DSKETTE_STATUS],0	; CLEAR STATUS, EXPECT ERRORS
	XOR	AX,AX			; CLEAR AX
	SHR	CH,1			; HALVE TRACK, CY = HEAD
	RCL	AL,3			; AX = HEAD IN CORRECT BIT
	PUSH	AX			; SAVE HEAD
	CALL	SEEK			; SEEK TO TRACK
	POP	AX			; RESTORE HEAD
	OR	DI,AX			; DI = HEAD OR'ED DRIVE
	CALL	READ_ID			; READ ID HEAD 0
	PUSHF				; SAVE RETURN FROM READ_ID
	AND	DI,11111011B		; TURN OFF HEAD 1 BIT
	POPF				; RESTORE ERROR RETURN
	POP	CX			; RESTORE COUNT
	JNC	short DO_CHK		; IF OK, ASKED = RETURNED TRACK ?
	INC	CH			; INC FOR NEXT TRACK
	CMP	CH,CL			; REACHED MAXIMUM YET
	JNZ	short CNT_OK		; CONTINUE TILL ALL TRIED

;-----	FALL THRU, READ ID FAILED FOR ALL TRACKS

SD_ERR:	
	STC				; SET CARRY FOR ERROR
	RETn				; SETUP_DBL ERROR EXIT

DO_CHK:
	MOV	CL, [NEC_STATUS+3]	; LOAD RETURNED TRACK
	MOV	[DSK_TRK+eDI], CL	; STORE TRACK NUMBER
	SHR	CH,1			; HALVE TRACK
	CMP	CH,CL			; IS IT THE SAME AS ASKED FOR TRACK
	JZ	short NO_DBL		; IF SAME THEN NO DOUBLE STEP
	OR	byte [DSK_STATE+eDI],DBL_STEP ; TURN ON DOUBLE STEP REQUIRED
NO_DBL:
	CLC				; CLEAR ERROR FLAG
	RETn

;-------------------------------------------------------------------------------
; READ_ID
;	READ ID FUNCTION.
;
; ON ENTRY:	DI : BIT 2 = HEAD; BITS 1,0 = DRIVE
;
; ON EXIT: 	DI : BIT 2 IS RESET, BITS 1,0 = DRIVE
;		@DSKETTE_STATUS, CY REFLECT STATUS OF OPERATION
;-------------------------------------------------------------------------------
READ_ID:
	MOV	eAX, ER_3		; MOVE NEC OUTPUT ERROR ADDRESS
	PUSH	eAX
	MOV	AH,4AH			; READ ID COMMAND
	CALL	NEC_OUTPUT		; TO CONTROLLER
	MOV	AX,DI			; DRIVE # TO AH, HEAD 0
	MOV	AH,AL
	CALL	NEC_OUTPUT		; TO CONTROLLER
	CALL	NEC_TERM		; WAIT FOR OPERATION, GET STATUS
	POP	eAX			; THROW AWAY ERROR ADDRESS
ER_3:
	RETn

;-------------------------------------------------------------------------------
; CMOS_TYPE
;	RETURNS DISKETTE TYPE FROM CMOS
;
; ON ENTRY:	DI = DRIVE #
;
; ON EXIT:	AL = TYPE; CY REFLECTS STATUS
;-------------------------------------------------------------------------------

CMOS_TYPE: ; 11/12/2014
mov	al, [eDI+fd0_type]
and 	al, al ; 18/12/2014
retn

;CMOS_TYPE:
;	MOV	AL, CMOS_DIAG		; CMOS DIAGNOSTIC STATUS BYTE ADDRESS
;	CALL	CMOS_READ		; GET CMOS STATUS
;	TEST	AL,BAD_BAT+BAD_CKSUM	; BATTERY GOOD AND CHECKSUM VALID
;	STC				; SET CY = 1 INDICATING ERROR FOR RETURN
;	JNZ	short BAD_CM		; ERROR IF EITHER BIT ON
;	MOV	AL,CMOS_DISKETTE	; ADDRESS OF DISKETTE BYTE IN CMOS
;	CALL	CMOS_READ		; GET DISKETTE BYTE
;	OR	DI,DI			; SEE WHICH DRIVE IN QUESTION
;	JNZ	short TB		; IF DRIVE 1, DATA IN LOW NIBBLE
;	ROR	AL,4			; EXCHANGE NIBBLES IF SECOND DRIVE
;TB:
;	AND	AL,0FH			; KEEP ONLY DRIVE DATA, RESET CY, 0
;BAD_CM:
;	RETn				; CY, STATUS OF READ

;-------------------------------------------------------------------------------
; GET_PARM
;	THIS ROUTINE FETCHES THE INDEXED POINTER FROM THE DISK_BASE
;	BLOCK POINTED TO BY THE DATA VARIABLE @DISK_POINTER. A BYTE FROM
;	THAT TABLE IS THEN MOVED INTO AH, THE INDEX OF THAT BYTE BEING
;	THE PARAMETER IN DL.
;
; ON ENTRY:	DL = INDEX OF BYTE TO BE FETCHED
;
; ON EXIT:	AH = THAT BYTE FROM BLOCK
;		AL,DH DESTROYED
;-------------------------------------------------------------------------------
GET_PARM:
	;PUSH	DS
	PUSH	eSI
    	;SUB	AX,AX			; DS = 0, BIOS DATA AREA
    	;MOV	DS,AX
	;;mov	ax, cs
	;;mov	ds, ax
	; 08/02/2015 (protected mode modifications, bx -> ebx)
	XCHG	eDX,eBX			; BL = INDEX
	;SUB	BH,BH			; BX = INDEX
	and	ebx, 0FFh
    	;LDS	SI, [DISK_POINTER]	; POINT TO BLOCK
	;
	; 17/12/2014
	mov	ax, [cfd] ; current (AL) and previous fd (AH)
	cmp	al, ah
	je	short gpndc
	mov	[pfd], al ; current drive -> previous drive
	push	ebx ; 08/02/2015
	mov	bl, al 
	; 11/12/2014
	mov	al, [eBX+fd0_type]	; Drive type (0,1,2,3,4)
	; 18/12/2014
	and	al, al
	jnz	short gpdtc
	mov	ebx, MD_TBL6		; 1.44 MB param. tbl. (default)
        jmp     short gpdpu
gpdtc:	
	call	DR_TYPE_CHECK
	; cf = 1 -> eBX points to 1.44MB fd parameter table (default)
gpdpu:
	mov	[DISK_POINTER], ebx
	pop	ebx
gpndc:
	mov	esi, [DISK_POINTER] ; 08/02/2015, si -> esi
	MOV	AH, [eSI+eBX]		; GET THE WORD
	XCHG	eDX,eBX			; RESTORE BX
	POP	eSI
	;POP	DS
	RETn

;-------------------------------------------------------------------------------
; MOTOR_ON
;	TURN MOTOR ON AND WAIT FOR MOTOR START UP TIME. THE @MOTOR_COUNT
;	IS REPLACED WITH A SUFFICIENTLY HIGH NUMBER (0FFH) TO ENSURE
;	THAT THE MOTOR DOES NOT GO OFF DURING THE OPERATION. IF THE
;	MOTOR NEEDED TO BE TURNED ON, THE MULTI-TASKING HOOK FUNCTION
;	(AX=90FDH, INT 15) IS CALLED TELLING THE OPERATING SYSTEM
;	THAT THE BIOS IS ABOUT TO WAIT FOR MOTOR START UP. IF THIS
;	FUNCTION RETURNS WITH CY = 1, IT MEANS THAT THE MINIMUM WAIT
;	HAS BEEN COMPLETED. AT THIS POINT A CHECK IS MADE TO ENSURE
;	THAT THE MOTOR WASN'T TURNED OFF BY THE TIMER. IF THE HOOK DID
;	NOT WAIT, THE WAIT FUNCTION (AH=086H) IS CALLED TO WAIT THE
;	PRESCRIBED AMOUNT OF TIME. IF THE CARRY FLAG IS SET ON RETURN,
;	IT MEANS THAT THE FUNCTION IS IN USE AND DID NOT PERFORM THE
;	WAIT. A TIMER 1 WAIT LOOP WILL THEN DO THE WAIT.
;
; ON ENTRY:	DI = DRIVE #
; ON EXIT:	AX,CX,DX DESTROYED
;-------------------------------------------------------------------------------
MOTOR_ON:
	PUSH	eBX			; SAVE REG.
	CALL	TURN_ON			; TURN ON MOTOR
	JC	short MOT_IS_ON		; IF CY=1 NO WAIT
	CALL	XLAT_OLD		; TRANSLATE STATE TO COMPATIBLE MODE
	CALL	XLAT_NEW		; TRANSLATE STATE TO PRESENT ARCH,
	;CALL	TURN_ON 		; CHECK AGAIN IF MOTOR ON
	;JC	MOT_IS_ON		; IF NO WAIT MEANS IT IS ON
M_WAIT:
	MOV	DL,10			; GET THE MOTOR WAIT PARAMETER
	CALL	GET_PARM
	;MOV	AL,AH			; AL = MOTOR WAIT PARAMETER
	;XOR	AH,AH			; AX = MOTOR WAIT PARAMETER
	;CMP	AL,8			; SEE IF AT LEAST A SECOND IS SPECIFIED
	cmp	ah, 8
	;JAE	short GP2		; IF YES, CONTINUE
	ja	short J13
	;MOV	AL,8			; ONE SECOND WAIT FOR MOTOR START UP
	mov	ah, 8

;-----	AS CONTAINS NUMBER OF 1/8 SECONDS (125000 MICROSECONDS) TO WAIT
GP2:	
;----- 	FOLLOWING LOOPS REQUIRED WHEN RTC WAIT FUNCTION IS ALREADY IN USE
J13:					; WAIT FOR 1/8 SECOND PER (AL)
	MOV	eCX,8286		; COUNT FOR 1/8 SECOND AT 15.085737 US
	CALL	WAITF			; GO TO FIXED WAIT ROUTINE
	;DEC	AL			; DECREMENT TIME VALUE
	dec	ah
	JNZ	short J13		; ARE WE DONE YET
MOT_IS_ON:
	POP	eBX			; RESTORE REG.
	RETn

;-------------------------------------------------------------------------------
; TURN_ON
;	TURN MOTOR ON AND RETURN WAIT STATE.
;
; ON ENTRY:	DI = DRIVE #
;
; ON EXIT:	CY = 0 MEANS WAIT REQUIRED
;		CY = 1 MEANS NO WAIT REQUIRED
;		AX,BX,CX,DX DESTROYED
;-------------------------------------------------------------------------------
TURN_ON:
	MOV	eBX,eDI			; BX = DRIVE #
	MOV	CL,BL			; CL = DRIVE #
	ROL	BL,4			; BL = DRIVE SELECT
	CLI				; NO INTERRUPTS WHILE DETERMINING STATUS
	MOV	byte [MOTOR_COUNT],0FFH	; ENSURE MOTOR STAYS ON FOR OPERATION
	MOV	AL, [MOTOR_STATUS]	; GET DIGITAL OUTPUT REGISTER REFLECTION
	AND	AL,00110000B		; KEEP ONLY DRIVE SELECT BITS
	MOV	AH,1			; MASK FOR DETERMINING MOTOR BIT
	SHL	AH,CL			; AH = MOTOR ON, A=00000001, B=00000010

;  AL = DRIVE SELECT FROM @MOTOR_STATUS
;  BL = DRIVE SELECT DESIRED
;  AH = MOTOR ON MASK DESIRED

	CMP	AL,BL			; REQUESTED DRIVE ALREADY SELECTED ?
	JNZ	short TURN_IT_ON	; IF NOT SELECTED JUMP
	TEST	AH, [MOTOR_STATUS]	; TEST MOTOR ON BIT
	JNZ	short NO_MOT_WAIT	; JUMP IF MOTOR ON AND SELECTED

TURN_IT_ON:
	OR	AH,BL			; AH = DRIVE SELECT AND MOTOR ON
	MOV	BH,[MOTOR_STATUS]	; SAVE COPY OF @MOTOR_STATUS BEFORE
	AND	BH,00001111B		; KEEP ONLY MOTOR BITS
	AND	byte [MOTOR_STATUS],11001111B ; CLEAR OUT DRIVE SELECT
	OR	[MOTOR_STATUS],AH	; OR IN DRIVE SELECTED AND MOTOR ON
	MOV	AL,[MOTOR_STATUS]	; GET DIGITAL OUTPUT REGISTER REFLECTION
	MOV	BL,AL			; BL=@MOTOR_STATUS AFTER, BH=BEFORE
	AND	BL,00001111B		; KEEP ONLY MOTOR BITS
	STI				; ENABLE INTERRUPTS AGAIN
	AND	AL,00111111B		; STRIP AWAY UNWANTED BITS
	ROL	AL,4			; PUT BITS IN DESIRED POSITIONS
	OR	AL,00001100B		; NO RESET, ENABLE DMA/INTERRUPT
	MOV	DX,03F2H		; SELECT DRIVE AND TURN ON MOTOR
	OUT	DX,AL
	CMP	BL,BH			; NEW MOTOR TURNED ON ?
	;JZ	short NO_MOT_WAIT	; NO WAIT REQUIRED IF JUST SELECT
	je	short no_mot_w1 ; 27/02/2015 
	CLC				; (re)SET CARRY MEANING WAIT
	RETn

NO_MOT_WAIT:
	sti
no_mot_w1: ; 27/02/2015
	STC				; SET NO WAIT REQUIRED
	;STI				; INTERRUPTS BACK ON
	RETn

;-------------------------------------------------------------------------------
; HD_WAIT
;	WAIT FOR HEAD SETTLE TIME.
;
; ON ENTRY:	DI = DRIVE #
;
; ON EXIT:	AX,BX,CX,DX DESTROYED
;-------------------------------------------------------------------------------
HD_WAIT:
	MOV	DL,9			; GET HEAD SETTLE PARAMETER
	CALL	GET_PARM
	or	ah, ah	; 17/12/2014
	jnz	short DO_WAT
        TEST    byte [MOTOR_STATUS],10000000B ; SEE IF A WRITE OPERATION
	;JZ	short ISNT_WRITE	; IF NOT, DO NOT ENFORCE ANY VALUES
	;OR	AH,AH			; CHECK FOR ANY WAIT?
	;JNZ	short DO_WAT		; IF THERE DO NOT ENFORCE
	jz	short HW_DONE
	MOV	AH,HD12_SETTLE		; LOAD 1.2M HEAD SETTLE MINIMUM
	MOV	AL,[DSK_STATE+eDI]	; LOAD STATE
	AND	AL,RATE_MSK		; KEEP ONLY RATE
	CMP	AL,RATE_250		; 1.2 M DRIVE ?
	JNZ	short DO_WAT		; DEFAULT HEAD SETTLE LOADED
;GP3:
	MOV	AH,HD320_SETTLE		; USE 320/360 HEAD SETTLE
;	JMP	SHORT DO_WAT

;ISNT_WRITE:
;	OR	AH,AH			; CHECK FOR NO WAIT
;	JZ	short HW_DONE		; IF NOT WRITE AND 0 ITS OK

;-----	AH CONTAINS NUMBER OF MILLISECONDS TO WAIT
DO_WAT:
;	MOV	AL,AH			; AL = # MILLISECONDS
;	;XOR	AH,AH			; AX = # MILLISECONDS
J29:					; 	1 MILLISECOND LOOP
	;mov	cx, WAIT_FDU_HEAD_SETTLE ; 33 ; 1 ms in 30 micro units.
	MOV	eCX,66			; COUNT AT 15.085737 US PER COUNT
	CALL	WAITF			; DELAY FOR 1 MILLISECOND
	;DEC	AL			; DECREMENT THE COUNT
	dec	ah
	JNZ	short J29		; DO AL MILLISECOND # OF TIMES
HW_DONE:
	RETn

;-------------------------------------------------------------------------------
; NEC_OUTPUT
;	THIS ROUTINE SENDS A BYTE TO THE NEC CONTROLLER AFTER TESTING
;	FOR CORRECT DIRECTION AND CONTROLLER READY THIS ROUTINE WILL
;	TIME OUT IF THE BYTE IS NOT ACCEPTED WITHIN A REASONABLE AMOUNT
;	OF TIME, SETTING THE DISKETTE STATUS ON COMPLETION.
; 
; ON ENTRY: 	AH = BYTE TO BE OUTPUT
;
; ON EXIT:	CY = 0  SUCCESS
;		CY = 1  FAILURE -- DISKETTE STATUS UPDATED
;		        IF A FAILURE HAS OCCURRED, THE RETURN IS MADE ONE LEVEL
;		        HIGHER THAN THE CALLER OF NEC OUTPUT. THIS REMOVES THE
;		        REQUIREMENT OF TESTING AFTER EVERY CALL OF NEC_OUTPUT.
;		AX,CX,DX DESTROYED
;-------------------------------------------------------------------------------

; 09/12/2014 [Erdogan Tan] 
;	(from 'PS2 Hardware Interface Tech. Ref. May 88', Page 09-05.)
; Diskette Drive Controller Status Register (3F4h)
;	This read only register facilitates the transfer of data between
;	the system microprocessor and the controller.
; Bit 7 - When set to 1, the Data register is ready to transfer data 
;	  with the system micrprocessor.
; Bit 6 - The direction of data transfer. If this bit is set to 0,
;	  the transfer is to the controller.
; Bit 5 - When this bit is set to 1, the controller is in the non-DMA mode.
; Bit 4 - When this bit is set to 1, a Read or Write command is being executed.
; Bit 3 - Reserved.
; Bit 2 - Reserved.
; Bit 1 - When this bit is set to 1, dskette drive 1 is in the seek mode.
; Bit 0 - When this bit is set to 1, dskette drive 1 is in the seek mode.

; Data Register (3F5h)
; This read/write register passes data, commands and parameters, and provides
; diskette status information.
  		
NEC_OUTPUT:
	;PUSH	BX			; SAVE REG.
	MOV	DX,03F4H		; STATUS PORT
	;MOV	BL,2			; HIGH ORDER COUNTER
	;XOR	CX,CX			; COUNT FOR TIME OUT
	; 16/12/2014
	; waiting for (max.) 0.5 seconds
        ;;mov     byte [wait_count], 0 ;; 27/02/2015
	;
	; 17/12/2014
	; Modified from AWARD BIOS 1999 - ADISK.ASM - SEND_COMMAND
	;
	;WAIT_FOR_PORT:	Waits for a bit at a port pointed to by DX to
	;		go on.
	;INPUT:
	;	AH=Mask for isolation bits.
	;	AL=pattern to look for.
	;	DX=Port to test for
	;	BH:CX=Number of memory refresh periods to delay.
	;	     (normally 30 microseconds per period.)
	;
	;WFP_SHORT:  
	;	Wait for port if refresh cycle is short (15-80 Us range).
	;

;	mov	bl, WAIT_FDU_SEND_HI+1	; 0+1
;	mov	cx, WAIT_FDU_SEND_LO	; 16667
	mov	ecx, WAIT_FDU_SEND_LH   ; 16667 (27/02/2015)
;
;WFPS_OUTER_LP:
;	;
;WFPS_CHECK_PORT:
J23:
	IN	AL,DX			; GET STATUS
	AND	AL,11000000B		; KEEP STATUS AND DIRECTION
	CMP	AL,10000000B		; STATUS 1 AND DIRECTION 0 ?
	JZ	short J27		; STATUS AND DIRECTION OK
WFPS_HI:
	IN	AL, PORT_B	;061h	; SYS1	; wait for hi to lo
	TEST	AL,010H			; transition on memory
	JNZ	SHORT WFPS_HI		; refresh.
WFPS_LO:
	IN	AL, PORT_B		; SYS1
	TEST	AL,010H
	JZ	SHORT WFPS_LO
	;LOOP	SHORT WFPS_CHECK_PORT
	loop	J23	; 27/02/2015
;	;
;	dec	bl
;	jnz	short WFPS_OUTER_LP
;	jmp	short WFPS_TIMEOUT	; fail
;J23:
;	IN	AL,DX			; GET STATUS
;	AND	AL,11000000B		; KEEP STATUS AND DIRECTION
;	CMP	AL,10000000B		; STATUS 1 AND DIRECTION 0 ?
;	JZ	short J27		; STATUS AND DIRECTION OK
	;LOOP	J23			; CONTINUE TILL CX EXHAUSTED
	;DEC	BL			; DECREMENT COUNTER
	;JNZ	short J23		; REPEAT TILL DELAY FINISHED, CX = 0
   
	;;27/02/2015
	;16/12/2014
        ;;cmp     byte [wait_count], 10   ; (10/18.2 seconds)
	;;jb	short J23

;WFPS_TIMEOUT:

;-----	FALL THRU TO ERROR RETURN

	OR	byte [DSKETTE_STATUS],TIME_OUT
	;POP	BX			; RESTORE REG.
	POP	eAX ; 08/02/2015	; DISCARD THE RETURN ADDRESS
	STC				; INDICATE ERROR TO CALLER
	RETn

;-----	DIRECTION AND STATUS OK; OUTPUT BYTE

J27:	
	MOV	AL,AH			; GET BYTE TO OUTPUT
	INC	DX			; DATA PORT = STATUS PORT + 1
	OUT	DX,AL			; OUTPUT THE BYTE
	;;NEWIODELAY  ;; 27/02/2015
	; 27/02/2015
	PUSHF				; SAVE FLAGS
	MOV	eCX, 3			; 30 TO 45 MICROSECONDS WAIT FOR
	CALL 	WAITF			; NEC FLAGS UPDATE CYCLE
	POPF				; RESTORE FLAGS FOR EXIT
	;POP	BX			; RESTORE REG
	RETn				; CY = 0 FROM TEST INSTRUCTION

;-------------------------------------------------------------------------------
; SEEK
;	THIS ROUTINE WILL MOVE THE HEAD ON THE NAMED DRIVE TO THE NAMED
;	TRACK. IF THE DRIVE HAS NOT BEEN ACCESSED SINCE THE DRIVE
;	RESET COMMAND WAS ISSUED, THE DRIVE WILL BE RECALIBRATED.
;
; ON ENTRY:	DI = DRIVE #
;		CH = TRACK #
;
; ON EXIT:	@DSKETTE_STATUS, CY REFLECT STATUS OF OPERATION.
;		AX,BX,CX DX DESTROYED
;-------------------------------------------------------------------------------
SEEK:
	MOV	eBX,eDI			; BX = DRIVE #
	MOV	AL,1			; ESTABLISH MASK FOR RECALIBRATE TEST
	XCHG	CL,BL			; SET DRIVE VALULE INTO CL
	ROL	AL,CL			; SHIFT MASK BY THE DRIVE VALUE
	XCHG	CL,BL			; RECOVER TRACK VALUE
	TEST	AL,[SEEK_STATUS]	; TEST FOR RECALIBRATE REQUIRED
	JNZ	short J28A		; JUMP IF RECALIBRATE NOT REQUIRED

	OR	[SEEK_STATUS],AL	; TURN ON THE NO RECALIBRATE BIT IN FLAG
	CALL	RECAL			; RECALIBRATE DRIVE
	JNC	short AFT_RECAL		; RECALIBRATE DONE

;-----	ISSUE RECALIBRATE FOR 80 TRACK DISKETTES

	MOV	byte [DSKETTE_STATUS],0	; CLEAR OUT INVALID STATUS
	CALL	RECAL			; RECALIBRATE DRIVE
	JC	short RB		; IF RECALIBRATE FAILS TWICE THEN ERROR

AFT_RECAL:
        MOV     byte [DSK_TRK+eDI],0    ; SAVE NEW CYLINDER AS PRESENT POSITION
	OR	CH,CH			; CHECK FOR SEEK TO TRACK 0
	JZ	short DO_WAIT		; HEAD SETTLE, CY = 0 IF JUMP

;-----	DRIVE IS IN SYNCHRONIZATION WITH CONTROLLER, SEEK TO TRACK

J28A:	TEST	byte [DSK_STATE+eDI],DBL_STEP ; CHECK FOR DOUBLE STEP REQUIRED
	JZ	short _R7		; SINGLE STEP REQUIRED BYPASS DOUBLE
	SHL	CH,1			; DOUBLE NUMBER OF STEP TO TAKE

_R7:	CMP	CH, [DSK_TRK+eDI]	; SEE IF ALREADY AT THE DESIRED TRACK
	JE	short RB		; IF YES, DO NOT NEED TO SEEK

	MOV	eDX, NEC_ERR		; LOAD RETURN ADDRESS
	PUSH	eDX ; (*)		; ON STACK FOR NEC OUTPUT ERROR
	MOV	[DSK_TRK+eDI],CH	; SAVE NEW CYLINDER AS PRESENT POSITION
	MOV	AH,0FH			; SEEK COMMAND TO NEC
	CALL	NEC_OUTPUT
	MOV	eBX,eDI			; BX = DRIVE #
	MOV	AH,BL			; OUTPUT DRIVE NUMBER
	CALL	NEC_OUTPUT
	MOV	AH, [DSK_TRK+eDI]	; GET CYLINDER NUMBER
	CALL	NEC_OUTPUT
	CALL	CHK_STAT_2		; ENDING INTERRUPT AND SENSE STATUS

;-----	WAIT FOR HEAD SETTLE

DO_WAIT:
	PUSHF				; SAVE STATUS
	CALL	HD_WAIT			; WAIT FOR HEAD SETTLE TIME
	POPF				; RESTORE STATUS
RB:
NEC_ERR:
	; 08/02/2015 (code trick here from original IBM PC/AT DISKETTE.ASM)
	; (*) nec_err -> retn (push edx -> pop edx) -> nec_err -> retn
	RETn				; RETURN TO CALLER

;-------------------------------------------------------------------------------
; RECAL
;	RECALIBRATE DRIVE
;
; ON ENTRY:	DI = DRIVE #
;
; ON EXIT:	CY REFLECTS STATUS OF OPERATION.
;-------------------------------------------------------------------------------
RECAL:
	PUSH	CX
	MOV	eAX, RC_BACK		; LOAD NEC_OUTPUT ERROR
	PUSH	eAX
	MOV	AH,07H			; RECALIBRATE COMMAND
	CALL	NEC_OUTPUT
	MOV	eBX,eDI			; BX = DRIVE #
	MOV	AH,BL
	CALL	NEC_OUTPUT		; OUTPUT THE DRIVE NUMBER
	CALL	CHK_STAT_2		; GET THE INTERRUPT AND SENSE INT STATUS
	POP	eAX			; THROW AWAY ERROR
RC_BACK:
	POP	CX
	RETn

;-------------------------------------------------------------------------------
; CHK_STAT_2
;	THIS ROUTINE HANDLES THE INTERRUPT RECEIVED AFTER RECALIBRATE,
;	OR SEEK TO THE ADAPTER. THE INTERRUPT IS WAITED FOR, THE
;	INTERRUPT STATUS SENSED, AND THE RESULT RETURNED TO THE CALLER.
;
; ON EXIT:	@DSKETTE_STATUS, CY REFLECT STATUS OF OPERATION.
;-------------------------------------------------------------------------------
CHK_STAT_2:
        MOV     eAX, CS_BACK            ; LOAD NEC_OUTPUT ERROR ADDRESS
	PUSH	eAX
	CALL	WAIT_INT		; WAIT FOR THE INTERRUPT
	JC	short J34		; IF ERROR, RETURN IT
	MOV	AH,08H			; SENSE INTERRUPT STATUS COMMAND
	CALL	NEC_OUTPUT
	CALL	RESULTS			; READ IN THE RESULTS
	JC	short J34
	MOV	AL,[NEC_STATUS]		; GET THE FIRST STATUS BYTE
	AND	AL,01100000B		; ISOLATE THE BITS
	CMP	AL,01100000B		; TEST FOR CORRECT VALUE
	JZ	short J35		; IF ERROR, GO MARK IT
	CLC				; GOOD RETURN
J34:
	POP	eAX			; THROW AWAY ERROR RETURN
CS_BACK:
	RETn
J35:
	OR	byte [DSKETTE_STATUS], BAD_SEEK
	STC				; ERROR RETURN CODE
	JMP	SHORT J34

;-------------------------------------------------------------------------------
; WAIT_INT
;	THIS ROUTINE WAITS FOR AN INTERRUPT TO OCCUR A TIME OUT ROUTINE
;	TAKES PLACE DURING THE WAIT, SO THAT AN ERROR MAY BE RETURNED
;	IF THE DRIVE IS NOT READY.
;
; ON EXIT: 	@DSKETTE_STATUS, CY REFLECT STATUS OF OPERATION.
;-------------------------------------------------------------------------------

; 17/12/2014
; 2.5 seconds waiting !
;(AWARD BIOS - 1999, WAIT_FDU_INT_LOW, WAIT_FDU_INT_HI)
; amount of time to wait for completion interrupt from NEC.


WAIT_INT:
	STI				; TURN ON INTERRUPTS, JUST IN CASE
	CLC				; CLEAR TIMEOUT INDICATOR
       ;MOV	BL,10			; CLEAR THE COUNTERS
       ;XOR	CX,CX			; FOR 2 SECOND WAIT

	; Modification from AWARD BIOS - 1999 (ATORGS.ASM, WAIT
	;
	;WAIT_FOR_MEM:	
	;	Waits for a bit at a specified memory location pointed
	;	to by ES:[DI] to become set.
	;INPUT:
	;	AH=Mask to test with.
	;	ES:[DI] = memory location to watch.
	;	BH:CX=Number of memory refresh periods to delay.
	;	     (normally 30 microseconds per period.)

	; waiting for (max.) 2.5 secs in 30 micro units.
;	mov 	cx, WAIT_FDU_INT_LO		; 017798
;;	mov 	bl, WAIT_FDU_INT_HI
;	mov 	bl, WAIT_FDU_INT_HI + 1
	; 27/02/2015
	mov 	ecx, WAIT_FDU_INT_LH	; 83334 (2.5 seconds)		
WFMS_CHECK_MEM:
	test	byte [SEEK_STATUS],INT_FLAG ; TEST FOR INTERRUPT OCCURRING
        jnz     short J37
WFMS_HI:
	IN	AL,PORT_B  ; 061h	; SYS1, wait for lo to hi
	TEST	AL,010H			; transition on memory
	JNZ	SHORT WFMS_HI		; refresh.
WFMS_LO:
	IN	AL,PORT_B		;SYS1
	TEST	AL,010H
	JZ	SHORT WFMS_LO
        LOOP    WFMS_CHECK_MEM
;WFMS_OUTER_LP:
;;	or	bl, bl			; check outer counter
;;	jz	short J36A		; WFMS_TIMEOUT
;	dec	bl
;	jz	short J36A	
;	jmp	short WFMS_CHECK_MEM

	;17/12/2014
	;16/12/2014
;        mov     byte [wait_count], 0    ; Reset (INT 08H) counter
;J36:
;	TEST	byte [SEEK_STATUS],INT_FLAG ; TEST FOR INTERRUPT OCCURRING
;	JNZ	short J37
	;16/12/2014
	;LOOP	J36			; COUNT DOWN WHILE WAITING
	;DEC	BL			; SECOND LEVEL COUNTER
	;JNZ	short J36
;       cmp     byte [wait_count], 46   ; (46/18.2 seconds)
;	jb	short J36

;WFMS_TIMEOUT:
;J36A:
	OR	byte [DSKETTE_STATUS], TIME_OUT ; NOTHING HAPPENED
	STC				; ERROR RETURN
J37:
	PUSHF				; SAVE CURRENT CARRY
	AND	byte [SEEK_STATUS], ~INT_FLAG ; TURN OFF INTERRUPT FLAG
	POPF				; RECOVER CARRY
	RETn				; GOOD RETURN CODE

;-------------------------------------------------------------------------------
; RESULTS
;	THIS ROUTINE WILL READ ANYTHING THAT THE NEC CONTROLLER RETURNS 
;	FOLLOWING AN INTERRUPT.
;
; ON EXIT:	@DSKETTE_STATUS, CY REFLECT STATUS OF OPERATION.
;		AX,BX,CX,DX DESTROYED
;-------------------------------------------------------------------------------
RESULTS:
	PUSH	eDI
	MOV	eDI, NEC_STATUS		; POINTER TO DATA AREA
	MOV	BL,7			; MAX STATUS BYTES
	MOV	DX,03F4H		; STATUS PORT

;-----	WAIT FOR REQUEST FOR MASTER

_R10: 
	; 16/12/2014
	; wait for (max) 0.5 seconds
	;MOV	BH,2			; HIGH ORDER COUNTER
	;XOR	CX,CX			; COUNTER

	;Time to wait while waiting for each byte of NEC results = .5
	;seconds.  .5 seconds = 500,000 micros.  500,000/30 = 16,667.
	; 27/02/2015
	mov 	ecx, WAIT_FDU_RESULTS_LH ; 16667  
	;mov	cx, WAIT_FDU_RESULTS_LO  ; 16667
	;mov	bh, WAIT_FDU_RESULTS_HI+1 ; 0+1

WFPSR_OUTER_LP:
	;
WFPSR_CHECK_PORT:
J39:					; WAIT FOR MASTER
	IN	AL,DX			; GET STATUS
	AND	AL,11000000B		; KEEP ONLY STATUS AND DIRECTION
	CMP	AL,11000000B		; STATUS 1 AND DIRECTION 1 ?
	JZ	short J42		; STATUS AND DIRECTION OK
WFPSR_HI:
	IN	AL, PORT_B	;061h	; SYS1	; wait for hi to lo
	TEST	AL,010H			; transition on memory
	JNZ	SHORT WFPSR_HI		; refresh.
WFPSR_LO:
	IN	AL, PORT_B		; SYS1
	TEST	AL,010H
	JZ	SHORT WFPSR_LO
        LOOP    WFPSR_CHECK_PORT
	;; 27/02/2015
	;;dec	bh
	;;jnz	short WFPSR_OUTER_LP
	;jmp	short WFPSR_TIMEOUT	; fail

	;;mov	byte [wait_count], 0
;J39:					; WAIT FOR MASTER
;	IN	AL,DX			; GET STATUS
;	AND	AL,11000000B		; KEEP ONLY STATUS AND DIRECTION
;	CMP	AL,11000000B		; STATUS 1 AND DIRECTION 1 ?
;	JZ	short J42		; STATUS AND DIRECTION OK
	;LOOP	J39			; LOOP TILL TIMEOUT
	;DEC	BH			; DECREMENT HIGH ORDER COUNTER
	;JNZ	short J39		; REPEAT TILL DELAY DONE
	;
	;;cmp	byte [wait_count], 10  ; (10/18.2 seconds)
	;;jb	short J39	

;WFPSR_TIMEOUT:
	OR	byte [DSKETTE_STATUS],TIME_OUT
	STC				; SET ERROR RETURN
	JMP	SHORT POPRES		; POP REGISTERS AND RETURN

;-----	READ IN THE STATUS

J42:
	JMP	$+2			; I/O DELAY
	INC	DX			; POINT AT DATA PORT
	IN	AL,DX			; GET THE DATA
	; 16/12/2014
	NEWIODELAY
        MOV     [eDI],AL                ; STORE THE BYTE
	INC	eDI			; INCREMENT THE POINTER
	; 16/12/2014
;	push	cx
;	mov	cx, 30
;wdw2:
;	NEWIODELAY
;	loop	wdw2
;	pop	cx

	MOV	eCX,3			; MINIMUM 24 MICROSECONDS FOR NEC
	CALL	WAITF			; WAIT 30 TO 45 MICROSECONDS
	DEC	DX			; POINT AT STATUS PORT
	IN	AL,DX			; GET STATUS
	; 16/12/2014
	NEWIODELAY
	;
	TEST	AL,00010000B		; TEST FOR NEC STILL BUSY
	JZ	short POPRES		; RESULTS DONE ?

	DEC	BL			; DECREMENT THE STATUS COUNTER
        JNZ     short _R10              ; GO BACK FOR MORE
	OR	byte [DSKETTE_STATUS],BAD_NEC ; TOO MANY STATUS BYTES
	STC				; SET ERROR FLAG

;-----	RESULT OPERATION IS DONE
POPRES:
	POP	eDI
	RETn				; RETURN WITH CARRY SET

;-------------------------------------------------------------------------------
; READ_DSKCHNG
;	READS THE STATE OF THE DISK CHANGE LINE.
;
; ON ENTRY:	DI = DRIVE #
;
; ON EXIT:	DI = DRIVE #
;		ZF = 0 : DISK CHANGE LINE INACTIVE
;		ZF = 1 : DISK CHANGE LINE ACTIVE
;		AX,CX,DX DESTROYED
;-------------------------------------------------------------------------------
READ_DSKCHNG:
	CALL	MOTOR_ON		; TURN ON THE MOTOR IF OFF
	MOV	DX,03F7H		; ADDRESS DIGITAL INPUT REGISTER
	IN	AL,DX			; INPUT DIGITAL INPUT REGISTER
	TEST	AL,DSK_CHG		; CHECK FOR DISK CHANGE LINE ACTIVE
	RETn				; RETURN TO CALLER WITH ZERO FLAG SET

;-------------------------------------------------------------------------------
; DRIVE_DET
;	DETERMINES WHETHER DRIVE IS 80 OR 40 TRACKS AND
;	UPDATES STATE INFORMATION ACCORDINGLY.
; ON ENTRY:	DI = DRIVE #
;-------------------------------------------------------------------------------
DRIVE_DET:
	CALL	MOTOR_ON		; TURN ON MOTOR IF NOT ALREADY ON
	CALL	RECAL			; RECALIBRATE DRIVE
	JC	short DD_BAC		; ASSUME NO DRIVE PRESENT
	MOV	CH,TRK_SLAP		; SEEK TO TRACK 48
	CALL	SEEK
	JC	short DD_BAC		; ERROR NO DRIVE
	MOV	CH,QUIET_SEEK+1		; SEEK TO TRACK 10
SK_GIN:
	DEC	CH			; DECREMENT TO NEXT TRACK
	PUSH	CX			; SAVE TRACK
	CALL	SEEK
	JC	short POP_BAC		; POP AND RETURN
	MOV	eAX, POP_BAC		; LOAD NEC OUTPUT ERROR ADDRESS
	PUSH	eAX
	MOV	AH,SENSE_DRV_ST		; SENSE DRIVE STATUS COMMAND BYTE
	CALL	NEC_OUTPUT		; OUTPUT TO NEC
	MOV	AX,DI			; AL = DRIVE
	MOV	AH,AL			; AH = DRIVE
	CALL	NEC_OUTPUT		; OUTPUT TO NEC
	CALL	RESULTS			; GO GET STATUS
	POP	eAX			; THROW AWAY ERROR ADDRESS
	POP	CX			; RESTORE TRACK
	TEST	byte [NEC_STATUS], HOME	; TRACK 0 ?
	JZ	short SK_GIN		; GO TILL TRACK 0
	OR	CH,CH			; IS HOME AT TRACK 0
	JZ	short IS_80		; MUST BE 80 TRACK DRIVE

;	DRIVE IS A 360; SET DRIVE TO DETERMINED;
;	SET MEDIA TO DETERMINED AT RATE 250.

	OR	byte [DSK_STATE+eDI], DRV_DET+MED_DET+RATE_250
	RETn				; ALL INFORMATION SET
IS_80:
	OR	byte [DSK_STATE+eDI], TRK_CAPA ; SETUP 80 TRACK CAPABILITY
DD_BAC:
	RETn
POP_BAC:
	POP	CX			; THROW AWAY
	RETn

fdc_int:  
	  ; 30/07/2015	
	  ; 16/02/2015
;int_0Eh: ; 11/12/2014

;--- HARDWARE INT 0EH -- ( IRQ LEVEL  6 ) --------------------------------------
; DISK_INT
;	THIS ROUTINE HANDLES THE DISKETTE INTERRUPT.
;
; ON EXIT:	THE INTERRUPT FLAG IS SET IN @SEEK_STATUS.
;-------------------------------------------------------------------------------
DISK_INT_1:

	PUSH	AX			; SAVE WORK REGISTER
	push	ds
	mov	ax, KDATA
	mov 	ds, ax
        OR      byte [SEEK_STATUS], INT_FLAG ; TURN ON INTERRUPT OCCURRED
	MOV     AL,EOI                  ; END OF INTERRUPT MARKER
	OUT	INTA00,AL		; INTERRUPT CONTROL PORT
	pop	ds
	POP	AX			; RECOVER REGISTER
	IRET				; RETURN FROM INTERRUPT

;-------------------------------------------------------------------------------
; DSKETTE_SETUP
;	THIS ROUTINE DOES A PRELIMINARY CHECK TO SEE WHAT TYPE OF
;	DISKETTE DRIVES ARE ATTACH TO THE SYSTEM.
;-------------------------------------------------------------------------------
DSKETTE_SETUP:
	;PUSH	AX			; SAVE REGISTERS
	;PUSH	BX
	;PUSH	CX
	PUSH	eDX
	;PUSH	DI
	;;PUSH	DS
	; 14/12/2014
	;mov	word [DISK_POINTER], MD_TBL6
	;mov	[DISK_POINTER+2], cs
	;
	;OR	byte [RTC_WAIT_FLAG], 1	; NO RTC WAIT, FORCE USE OF LOOP
	XOR	eDI,eDI			; INITIALIZE DRIVE POINTER
	MOV	WORD [DSK_STATE],0	; INITIALIZE STATES
	AND	byte [LASTRATE],~(STRT_MSK+SEND_MSK) ; CLEAR START & SEND
	OR	byte [LASTRATE],SEND_MSK ; INITIALIZE SENT TO IMPOSSIBLE
	MOV	byte [SEEK_STATUS],0	; INDICATE RECALIBRATE NEEDED
	MOV	byte [MOTOR_COUNT],0	; INITIALIZE MOTOR COUNT
	MOV	byte [MOTOR_STATUS],0	; INITIALIZE DRIVES TO OFF STATE
	MOV	byte [DSKETTE_STATUS],0	; NO ERRORS
	;
	; 28/02/2015
	;mov	word [cfd], 100h 
	call	DSK_RESET
	pop	edx
	retn

;SUP0:
;	CALL	DRIVE_DET		; DETERMINE DRIVE
;	CALL	XLAT_OLD		; TRANSLATE STATE TO COMPATIBLE MODE
;	; 02/01/2015
;	;INC	DI			; POINT TO NEXT DRIVE
;	;CMP	DI,MAX_DRV		; SEE IF DONE
;	;JNZ	short SUP0		; REPEAT FOR EACH ORIVE
;       cmp     byte [fd1_type], 0	
;	jna	short sup1
;	or	di, di
;	jnz	short sup1
;	inc	di
;       jmp     short SUP0
;sup1:
;	MOV	byte [SEEK_STATUS],0	; FORCE RECALIBRATE
;	;AND	byte [RTC_WAIT_FLAG],0FEH ; ALLOW FOR RTC WAIT
;	CALL	SETUP_END		; VARIOUS CLEANUPS
;	;;POP	DS			; RESTORE CALLERS REGISTERS
;	;POP	DI
;	POP	eDX
;	;POP	CX
;	;POP	BX
;	;POP	AX
;	RETn

;//////////////////////////////////////////////////////
;; END OF DISKETTE I/O ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;

int13h: ; 21/02/2015
	pushfd
	push 	cs
	call 	DISK_IO
	retn

;;;;;; DISK I/O ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 21/02/2015 ;;;
;/////////////////////////////////////////////////////////////////////

; DISK I/O - Erdogan Tan (Retro UNIX 386 v1 project)
; 18/02/2016
; 17/02/2016
; 23/02/2015
; 21/02/2015 (unix386.s)
; 22/12/2014 - 14/02/2015 (dsectrm2.s)
;
; Original Source Code:
; DISK ----- 09/25/85 FIXED DISK BIOS
; (IBM PC XT Model 286 System BIOS Source Code, 04-21-86)
;
; Modifications: by reference of AWARD BIOS 1999 (D1A0622) 
;		 Source Code - ATORGS.ASM, AHDSK.ASM
;


;The wait for controller to be not busy is 10 seconds.
;10,000,000 / 30 = 333,333.  333,333 decimal = 051615h
;;WAIT_HDU_CTLR_BUSY_LO	equ	1615h		
;;WAIT_HDU_CTLR_BUSY_HI	equ	  05h
WAIT_HDU_CTRL_BUSY_LH	equ	51615h	 ;21/02/2015		

;The wait for controller to issue completion interrupt is 10 seconds.
;10,000,000 / 30 = 333,333.  333,333 decimal = 051615h
;;WAIT_HDU_INT_LO	equ	1615h
;;WAIT_HDU_INT_HI	equ	  05h
WAIT_HDU_INT_LH		equ	51615h	; 21/02/2015

;The wait for Data request on read and write longs is
;2000 us. (?)
;;WAIT_HDU_DRQ_LO	equ	1000	; 03E8h
;;WAIT_HDU_DRQ_HI	equ	0
WAIT_HDU_DRQ_LH		equ	1000	; 21/02/2015

; Port 61h (PORT_B)
SYS1		equ	61h	; PORT_B  (diskette.inc)

; 23/12/2014
%define CMD_BLOCK       eBP-8  ; 21/02/2015


;--- INT 13H -------------------------------------------------------------------
;									       :
; FIXED DISK I/O INTERFACE						       :
;									       :
;	THIS INTERFACE PROVIDES ACCESS TO 5 1/4" FIXED DISKS THROUGH           :
;	THE IBM FIXED DISK CONTROLLER.					       :
;									       :
;	THE  BIOS  ROUTINES  ARE  MEANT  TO  BE  ACCESSED  THROUGH	       :
;	SOFTWARE  INTERRUPTS  ONLY.    ANY  ADDRESSES  PRESENT	IN	       :
;	THESE  LISTINGS  ARE  INCLUDED	 ONLY	FOR  COMPLETENESS,	       :
;	NOT  FOR  REFERENCE.  APPLICATIONS   WHICH  REFERENCE  ANY	       :
;	ABSOLUTE  ADDRESSES  WITHIN  THE  CODE	SEGMENTS  OF  BIOS	       :
;	VIOLATE  THE  STRUCTURE  AND  DESIGN  OF  BIOS. 		       :
;									       :
;------------------------------------------------------------------------------:
;									       :
; INPUT  (AH)= HEX COMMAND VALUE					       :
;									       :
;	(AH)= 00H  RESET DISK (DL = 80H,81H) / DISKETTE 		       :
;	(AH)= 01H  READ THE STATUS OF THE LAST DISK OPERATION INTO (AL)        :
;		    NOTE: DL < 80H - DISKETTE				       :
;			  DL > 80H - DISK				       :
;	(AH)= 02H  READ THE DESIRED SECTORS INTO MEMORY 		       :
;	(AH)= 03H  WRITE THE DESIRED SECTORS FROM MEMORY		       :
;	(AH)= 04H  VERIFY THE DESIRED SECTORS				       :
;	(AH)= 05H  FORMAT THE DESIRED TRACK				       :
;	(AH)= 06H  UNUSED						       :
;	(AH)= 07H  UNUSED						       :
;	(AH)= 08H  RETURN THE CURRENT DRIVE PARAMETERS			       :
;	(AH)= 09H  INITIALIZE DRIVE PAIR CHARACTERISTICS		       :
;		    INTERRUPT 41 POINTS TO DATA BLOCK FOR DRIVE 0	       :
;		    INTERRUPT 46 POINTS TO DATA BLOCK FOR DRIVE 1	       :
;	(AH)= 0AH  READ LONG						       :
;	(AH)= 0BH  WRITE LONG  (READ & WRITE LONG ENCOMPASS 512 + 4 BYTES ECC) :
;	(AH)= 0CH  SEEK 						       :
;	(AH)= 0DH  ALTERNATE DISK RESET (SEE DL)			       :
;	(AH)= 0EH  UNUSED						       :
;	(AH)= 0FH  UNUSED						       :
;	(AH)= 10H  TEST DRIVE READY					       :
;	(AH)= 11H  RECALIBRATE						       :
;	(AH)= 12H  UNUSED						       :
;	(AH)= 13H  UNUSED						       :
;	(AH)= 14H  CONTROLLER INTERNAL DIAGNOSTIC			       :
;	(AH)= 15H  READ DASD TYPE					       :
;									       :
;-------------------------------------------------------------------------------
;									       :
;	REGISTERS USED FOR FIXED DISK OPERATIONS			       :
;									       :
;		(DL)	-  DRIVE NUMBER     (80H-81H FOR DISK. VALUE CHECKED)  :
;		(DH)	-  HEAD NUMBER	    (0-15 ALLOWED, NOT VALUE CHECKED)  :
;		(CH)	-  CYLINDER NUMBER  (0-1023, NOT VALUE CHECKED)(SEE CL):
;		(CL)	-  SECTOR NUMBER    (1-17, NOT VALUE CHECKED)	       :
;									       :
;			   NOTE: HIGH 2 BITS OF CYLINDER NUMBER ARE PLACED     :
;				 IN THE HIGH 2 BITS OF THE CL REGISTER	       :
;				 (10 BITS TOTAL)			       :
;									       :
;		(AL)	-  NUMBER OF SECTORS (MAXIMUM POSSIBLE RANGE 1-80H,    :
;					      FOR READ/WRITE LONG 1-79H)       :
;									       :
;		(ES:BX) -  ADDRESS OF BUFFER FOR READS AND WRITES,	       :
;			   (NOT REQUIRED FOR VERIFY)			       :
;									       :
;		FORMAT (AH=5) ES:BX POINTS TO A 512 BYTE BUFFER. THE FIRST     :
;			   2*(SECTORS/TRACK) BYTES CONTAIN F,N FOR EACH SECTOR.:
;			   F = 00H FOR A GOOD SECTOR			       :
;			       80H FOR A BAD SECTOR			       :
;			   N = SECTOR NUMBER				       :
;			   FOR AN INTERLEAVE OF 2 AND 17 SECTORS/TRACK	       :
;			   THE TABLE SHOULD BE: 			       :
;									       :
;		   DB	   00H,01H,00H,0AH,00H,02H,00H,0BH,00H,03H,00H,0CH     :
;		   DB	   00H,04H,00H,0DH,00H,05H,00H,0EH,00H,06H,00H,0FH     :
;		   DB	   00H,07H,00H,10H,00H,08H,00H,11H,00H,09H	       :
;									       :
;-------------------------------------------------------------------------------

;-------------------------------------------------------------------------------
; OUTPUT								       :
;	AH = STATUS OF CURRENT OPERATION				       :
;	     STATUS BITS ARE DEFINED IN THE EQUATES BELOW		       :
;	CY = 0	SUCCESSFUL OPERATION (AH=0 ON RETURN)			       :
;	CY = 1	FAILED OPERATION (AH HAS ERROR REASON)			       :
;									       :
;	NOTE:	ERROR 11H  INDICATES THAT THE DATA READ HAD A RECOVERABLE      :
;		ERROR WHICH WAS CORRECTED BY THE ECC ALGORITHM.  THE DATA      :
;		IS PROBABLY GOOD,   HOWEVER THE BIOS ROUTINE INDICATES AN      :
;		ERROR TO ALLOW THE CONTROLLING PROGRAM A CHANCE TO DECIDE      :
;		FOR ITSELF.  THE  ERROR  MAY  NOT  RECUR  IF  THE DATA IS      :
;		REWRITTEN.						       :
;									       :
;	IF DRIVE PARAMETERS WERE REQUESTED (DL >= 80H), 		       :
;	   INPUT:							       :
;	     (DL) = DRIVE NUMBER					       :
;	   OUTPUT:							       :
;	     (DL) = NUMBER OF CONSECUTIVE ACKNOWLEDGING DRIVES ATTACHED (1-2)  :
;		    (CONTROLLER CARD ZERO TALLY ONLY)			       :
;	     (DH) = MAXIMUM USEABLE VALUE FOR HEAD NUMBER		       :
;	     (CH) = MAXIMUM USEABLE VALUE FOR CYLINDER NUMBER		       :
;	     (CL) = MAXIMUM USEABLE VALUE FOR SECTOR NUMBER		       :
;		    AND CYLINDER NUMBER HIGH BITS			       :
;									       :
;	IF READ DASD TYPE WAS REQUESTED,				       :
;									       :
;	AH = 0 - NOT PRESENT						       :
;	     1 - DISKETTE - NO CHANGE LINE AVAILABLE			       :
;	     2 - DISKETTE - CHANGE LINE AVAILABLE			       :
;	     3 - FIXED DISK						       :
;									       :
;	CX,DX = NUMBER OF 512 BYTE BLOCKS WHEN AH = 3			       :
;									       :
;	REGISTERS WILL BE PRESERVED EXCEPT WHEN THEY ARE USED TO RETURN        :
;	INFORMATION.							       :
;									       :
;	NOTE: IF AN ERROR IS REPORTED BY THE DISK CODE, THE APPROPRIATE        :
;		ACTION IS TO RESET THE DISK, THEN RETRY THE OPERATION.	       :
;									       :
;-------------------------------------------------------------------------------

SENSE_FAIL	EQU	0FFH		; NOT IMPLEMENTED
NO_ERR		EQU	0E0H		; STATUS ERROR/ERROR REGISTER=0
WRITE_FAULT	EQU	0CCH		; WRITE FAULT ON SELECTED DRIVE
UNDEF_ERR	EQU	0BBH		; UNDEFINED ERROR OCCURRED
NOT_RDY 	EQU	0AAH		; DRIVE NOT READY
TIME_OUT	EQU	80H		; ATTACHMENT FAILED TO RESPOND
BAD_SEEK	EQU	40H		; SEEK OPERATION FAILED
BAD_CNTLR	EQU	20H		; CONTROLLER HAS FAILED
DATA_CORRECTED	EQU	11H		; ECC CORRECTED DATA ERROR
BAD_ECC 	EQU	10H		; BAD ECC ON DISK READ
BAD_TRACK	EQU	0BH		; NOT IMPLEMENTED
BAD_SECTOR	EQU	0AH		; BAD SECTOR FLAG DETECTED
;DMA_BOUNDARY	EQU	09H		; DATA EXTENDS TOO FAR
INIT_FAIL	EQU	07H		; DRIVE PARAMETER ACTIVITY FAILED
BAD_RESET	EQU	05H		; RESET FAILED
;RECORD_NOT_FND	EQU	04H		; REQUESTED SECTOR NOT FOUND
;BAD_ADDR_MARK	EQU	02H		; ADDRESS MARK NOT FOUND
;BAD_CMD 	EQU	01H		; BAD COMMAND PASSED TO DISK I/O

;--------------------------------------------------------
;							:
; FIXED DISK PARAMETER TABLE				:
;  -  THE TABLE IS COMPOSED OF A BLOCK DEFINED AS:	:
;							:
;  +0	(1 WORD) - MAXIMUM NUMBER OF CYLINDERS		:
;  +2	(1 BYTE) - MAXIMUM NUMBER OF HEADS		:
;  +3	(1 WORD) - NOT USED/SEE PC-XT			:
;  +5	(1 WORD) - STARTING WRITE PRECOMPENSATION CYL	:
;  +7	(1 BYTE) - MAXIMUM ECC DATA BURST LENGTH	:
;  +8	(1 BYTE) - CONTROL BYTE 			:
;		   BIT	  7 DISABLE RETRIES -OR-	:
;		   BIT	  6 DISABLE RETRIES		:
;		   BIT	  3 MORE THAN 8 HEADS		:
;  +9	(3 BYTES)- NOT USED/SEE PC-XT			:
; +12	(1 WORD) - LANDING ZONE 			:
; +14	(1 BYTE) - NUMBER OF SECTORS/TRACK		:
; +15	(1 BYTE) - RESERVED FOR FUTURE USE		:
;							:
;	 - TO DYNAMICALLY DEFINE A SET OF PARAMETERS	:
;	   BUILD A TABLE FOR UP TO 15 TYPES AND PLACE	:
;	   THE CORRESPONDING VECTOR INTO INTERRUPT 41	:
;	   FOR DRIVE 0 AND INTERRUPT 46 FOR DRIVE 1.	:
;							:
;--------------------------------------------------------

;--------------------------------------------------------
;							:
; HARDWARE SPECIFIC VALUES				:
;							:
;  -  CONTROLLER I/O PORT				:
;							:
;     > WHEN READ FROM: 				:
;	HF_PORT+0 - READ DATA (FROM CONTROLLER TO CPU)	:
;	HF_PORT+1 - GET ERROR REGISTER			:
;	HF_PORT+2 - GET SECTOR COUNT			:
;	HF_PORT+3 - GET SECTOR NUMBER			:
;	HF_PORT+4 - GET CYLINDER LOW			:
;	HF_PORT+5 - GET CYLINDER HIGH (2 BITS)		:
;	HF_PORT+6 - GET SIZE/DRIVE/HEAD 		:
;	HF_PORT+7 - GET STATUS REGISTER 		:
;							:
;     > WHEN WRITTEN TO:				:
;	HF_PORT+0 - WRITE DATA (FROM CPU TO CONTROLLER) :
;	HF_PORT+1 - SET PRECOMPENSATION CYLINDER	:
;	HF_PORT+2 - SET SECTOR COUNT			:
;	HF_PORT+3 - SET SECTOR NUMBER			:
;	HF_PORT+4 - SET CYLINDER LOW			:
;	HF_PORT+5 - SET CYLINDER HIGH (2 BITS)		:
;	HF_PORT+6 - SET SIZE/DRIVE/HEAD 		:
;	HF_PORT+7 - SET COMMAND REGISTER		:
;							:
;--------------------------------------------------------

;HF_PORT 	EQU	01F0H	; DISK PORT
;HF1_PORT	equ	0170h	
;HF_REG_PORT	EQU	03F6H
;HF1_REG_PORT	equ	0376h

HDC1_BASEPORT	equ	1F0h
HDC2_BASEPORT	equ	170h		

align 2

;-----		STATUS REGISTER

ST_ERROR	EQU	00000001B	;
ST_INDEX	EQU	00000010B	;
ST_CORRCTD	EQU	00000100B	; ECC CORRECTION SUCCESSFUL
ST_DRQ		EQU	00001000B	;
ST_SEEK_COMPL	EQU	00010000B	; SEEK COMPLETE
ST_WRT_FLT	EQU	00100000B	; WRITE FAULT
ST_READY	EQU	01000000B	;
ST_BUSY 	EQU	10000000B	;

;-----		ERROR REGISTER

ERR_DAM 	EQU	00000001B	; DATA ADDRESS MARK NOT FOUND
ERR_TRK_0	EQU	00000010B	; TRACK 0 NOT FOUND ON RECAL
ERR_ABORT	EQU	00000100B	; ABORTED COMMAND
;		EQU	00001000B	; NOT USED
ERR_ID		EQU	00010000B	; ID NOT FOUND
;		EQU	00100000B	; NOT USED
ERR_DATA_ECC	EQU	01000000B
ERR_BAD_BLOCK	EQU	10000000B


RECAL_CMD	EQU	00010000B	; DRIVE RECAL	(10H)
READ_CMD	EQU	00100000B	;	READ	(20H)
WRITE_CMD	EQU	00110000B	;	WRITE	(30H)
VERIFY_CMD	EQU	01000000B	;	VERIFY	(40H)
FMTTRK_CMD	EQU	01010000B	; FORMAT TRACK	(50H)
INIT_CMD	EQU	01100000B	;   INITIALIZE	(60H)
SEEK_CMD	EQU	01110000B	;	SEEK	(70H)
DIAG_CMD	EQU	10010000B	; DIAGNOSTIC	(90H)
SET_PARM_CMD	EQU	10010001B	; DRIVE PARMS	(91H)
NO_RETRIES	EQU	00000001B	; CHD MODIFIER	(01H)
ECC_MODE	EQU	00000010B	; CMD MODIFIER	(02H)
BUFFER_MODE	EQU	00001000B	; CMD MODIFIER	(08H)

;MAX_FILE	EQU	2
;S_MAX_FILE	EQU	2
MAX_FILE	equ	4		; 22/12/2014
S_MAX_FILE	equ	4		; 22/12/2014

DELAY_1 	EQU	25H		; DELAY FOR OPERATION COMPLETE
DELAY_2 	EQU	0600H		; DELAY FOR READY
DELAY_3 	EQU	0100H		; DELAY FOR DATA REQUEST

HF_FAIL 	EQU	08H		; CMOS FLAG IN BYTE 0EH

;-----		COMMAND BLOCK REFERENCE

;CMD_BLOCK      EQU     BP-8            ; @CMD_BLOCK REFERENCES BLOCK HEAD IN SS
					;  (BP) POINTS TO COMMAND BLOCK TAIL
					;	AS DEFINED BY THE "ENTER" PARMS
; 19/12/2014
ORG_VECTOR	equ	4*13h		; INT 13h vector
DISK_VECTOR	equ	4*40h		; INT 40h vector (for floppy disks)
;HDISK_INT	equ	4*76h		; Primary HDC - Hardware interrupt (IRQ14)
;HDISK_INT1	equ	4*76h		; Primary HDC - Hardware interrupt (IRQ14)
;HDISK_INT2	equ	4*77h		; Secondary HDC - Hardware interrupt (IRQ15)
;HF_TBL_VEC	equ	4*41h		; Pointer to 1st fixed disk parameter table
;HF1_TBL_VEC	equ	4*46h		; Pointer to 2nd fixed disk parameter table

align 2

;----------------------------------------------------------------
; FIXED DISK I/O SETUP						:
;								:
;  -  ESTABLISH TRANSFER VECTORS FOR THE FIXED DISK		:
;  -  PERFORM POWER ON DIAGNOSTICS				:
;     SHOULD AN ERROR OCCUR A "1701" MESSAGE IS DISPLAYED       :
;								:
;----------------------------------------------------------------

DISK_SETUP:
	;CLI
	;;MOV	AX,ABS0 			; GET ABSOLUTE SEGMENT
	;xor	ax,ax
	;MOV	DS,AX				; SET SEGMENT REGISTER
	;MOV	AX, [ORG_VECTOR] 		; GET DISKETTE VECTOR
	;MOV	[DISK_VECTOR],AX		;  INTO INT 40H
	;MOV	AX, [ORG_VECTOR+2]
	;MOV	[DISK_VECTOR+2],AX
	;MOV	word [ORG_VECTOR],DISK_IO	; FIXED DISK HANDLER
	;MOV	[ORG_VECTOR+2],CS
	; 1st controller (primary master, slave)   - IRQ 14
	;;MOV	word [HDISK_INT],HD_INT		; FIXED DISK INTERRUPT
	;mov	word [HDISK_INT1],HD_INT	;
	;;MOV	[HDISK_INT+2],CS
	;mov	[HDISK_INT1+2],CS
	; 2nd controller (secondary master, slave) - IRQ 15
	;mov	word [HDISK_INT2],HD1_INT	;
	;mov	[HDISK_INT2+2],CS
	;
	;;MOV	word [HF_TBL_VEC],HD0_DPT	; PARM TABLE DRIVE 80
	;;MOV	word [HF_TBL_VEC+2],DPT_SEGM
	;;MOV	word [HF1_TBL_VEC],HD1_DPT	; PARM TABLE DRIVE 81
	;;MOV	word [HF1_TBL_VEC+2],DPT_SEGM
	;push	cs
	;pop	ds
	;mov	word [HDPM_TBL_VEC],HD0_DPT	; PARM TABLE DRIVE 80h
	;mov	word [HDPM_TBL_VEC+2],DPT_SEGM
	mov 	dword [HDPM_TBL_VEC], (DPT_SEGM*16)+HD0_DPT
	;mov	word [HDPS_TBL_VEC],HD1_DPT	; PARM TABLE DRIVE 81h
	;mov	word [HDPS_TBL_VEC+2],DPT_SEGM
	mov 	dword [HDPS_TBL_VEC], (DPT_SEGM*16)+HD1_DPT
	;mov	word [HDSM_TBL_VEC],HD2_DPT	; PARM TABLE DRIVE 82h
	;mov	word [HDSM_TBL_VEC+2],DPT_SEGM
	mov 	dword [HDSM_TBL_VEC], (DPT_SEGM*16)+HD2_DPT
	;mov	word [HDSS_TBL_VEC],HD3_DPT	; PARM TABLE DRIVE 83h
	;mov	word [HDSS_TBL_VEC+2],DPT_SEGM
	mov 	dword [HDSS_TBL_VEC], (DPT_SEGM*16)+HD3_DPT
	;
	;;IN	AL,INTB01		; TURN ON SECOND INTERRUPT CHIP
	;;;AND	AL,0BFH
	;;and	al, 3Fh			; enable IRQ 14 and IRQ 15
	;;;JMP	$+2
	;;IODELAY
	;;OUT	INTB01,AL
	;;IODELAY
	;;IN	AL,INTA01		; LET INTERRUPTS PASS THRU TO
	;;AND	AL,0FBH 		;  SECOND CHIP
	;;;JMP	$+2
	;;IODELAY
	;;OUT	INTA01,AL
	;
	;STI
	;;PUSH	DS			; MOVE ABS0 POINTER TO
	;;POP	ES			; EXTRA SEGMENT POINTER
	;;;CALL	DDS			; ESTABLISH DATA SEGMENT
	;;MOV	byte [DISK_STATUS1],0 	; RESET THE STATUS INDICATOR
	;;MOV	byte [HF_NUM],0		; ZERO NUMBER OF FIXED DISKS
	;;MOV	byte [CONTROL_BYTE],0
	;;MOV	byte [PORT_OFF],0	; ZERO CARD OFFSET
	; 20/12/2014 - private code by Erdogan Tan
		      ; (out of original PC-AT, PC-XT BIOS code)
	;mov	si, hd0_type
	mov	esi, hd0_type
	;mov	cx, 4
	mov	ecx, 4
hde_l:
	lodsb
	cmp	al, 80h			; 8?h = existing
	jb	short _L4
	inc	byte [HF_NUM]		; + 1 hard (fixed) disk drives
_L4: ; 26/02/2015
	loop	hde_l	
;_L4:					; 0 <= [HF_NUM] =< 4
;L4:
	; 
	;; 31/12/2014 - cancel controller diagnostics here
	;;;mov 	cx, 3  ; 26/12/2014 (Award BIOS 1999)
	;;mov 	cl, 3
	;;
	;;MOV	DL,80H			; CHECK THE CONTROLLER
;;hdc_dl:
	;;MOV	AH,14H			; USE CONTROLLER DIAGNOSTIC COMMAND
	;;INT	13H			; CALL BIOS WITH DIAGNOSTIC COMMAND
	;;;JC	short CTL_ERRX		; DISPLAY ERROR MESSAGE IF BAD RETURN
	;;;jc	short POD_DONE ;22/12/2014
	;;jnc	short hdc_reset0
	;;loop	hdc_dl
	;;; 27/12/2014
	;;stc
	;;retn
	;
;;hdc_reset0:
	; 18/01/2015
	mov	cl, [HF_NUM]
	and	cl, cl
	jz	short POD_DONE
	;
	mov	dl, 7Fh
hdc_reset1:
	inc	dl
	;; 31/12/2015
	;;push	dx
	;;push	cx
	;;push	ds
	;;sub	ax, ax
	;;mov	ds, ax
	;;MOV	AX, [TIMER_LOW]		; GET START TIMER COUNTS
	;;pop	ds
	;;MOV	BX,AX
	;;ADD	AX,6*182		; 60 SECONDS* 18.2
	;;MOV	CX,AX
	;;mov	word [wait_count], 0	; 22/12/2014 (reset wait counter)
	;;
	;; 31/12/2014 - cancel HD_RESET_1
	;;CALL	HD_RESET_1		; SET UP DRIVE 0, (1,2,3)
	;;pop	cx
	;;pop	dx
	;;
	; 18/01/2015
	mov	ah, 0Dh ; ALTERNATE RESET
	;int	13h
	call	int13h
	loop	hdc_reset1
POD_DONE:
	RETn

;;-----	POD_ERROR

;;CTL_ERRX:
;	;MOV	SI,OFFSET F1782 	; CONTROLLER ERROR
;	;CALL	SET_FAIL		; DO NOT IPL FROM DISK
;	;CALL	E_MSG			; DISPLAY ERROR AND SET (BP) ERROR FLAG
;	;JMP	short POD_DONE

;;HD_RESET_1:
;;	;PUSH	BX			; SAVE TIMER LIMITS
;;	;PUSH	CX
;;RES_1: MOV	AH,09H			; SET DRIVE PARAMETERS
;;	INT	13H
;;	JC	short RES_2
;;	MOV	AH,11H			; RECALIBRATE DRIVE
;;	INT	13H
;;	JNC	short RES_CK		; DRIVE OK
;;RES_2: ;CALL	POD_TCHK		; CHECK TIME OUT
;;	cmp	word [wait_count], 6*182 ; waiting time (in timer ticks)
;;					; (30 seconds)		
;;	;cmc
;;	;JNC	short RES_1
;;	jb	short RES_1
;;;RES_FL: ;MOV	SI,OFFSET F1781 	; INDICATE DISK 1 FAILURE;
;;	;TEST	DL,1
;;	;JNZ	RES_E1
;;	;MOV	SI,OFFSET F1780 	; INDICATE DISK 0 FAILURE
;;	;CALL	SET_FAIL		; DO NOT TRY TO IPL DISK 0
;;	;JMP	SHORT RES_E1
;;RES_ER: ; 22/12/2014
;;RES_OK:
;;	;POP	CX			; RESTORE TIMER LIMITS
;;	;POP	BX
;;	RETn
;;
;;RES_RS: MOV	AH,00H			; RESET THE DRIVE
;;	INT	13H
;;RES_CK: MOV	AH,08H			; GET MAX CYLINDER,HEAD,SECTOR
;;	MOV	BL,DL			; SAVE DRIVE CODE
;;	INT	13H
;;	JC	short RES_ER
;;	MOV	[NEC_STATUS],CX 	; SAVE MAX CYLINDER, SECTOR
;;	MOV	DL,BL			; RESTORE DRIVE CODE
;;RES_3: MOV	AX,0401H		; VERIFY THE LAST SECTOR
;;	INT	13H
;;	JNC	short RES_OK		; VERIFY OK
;;	CMP	AH,BAD_SECTOR		; OK ALSO IF JUST ID READ
;;	JE	short RES_OK
;;	CMP	AH,DATA_CORRECTED
;;	JE	short RES_OK
;;	CMP	AH,BAD_ECC
;;	JE	short RES_OK
;;	;CALL	POD_TCHK		; CHECK FOR TIME OUT
;;	cmp	word [wait_count], 6*182 ; waiting time (in timer ticks)
;;					; (60 seconds)		
;;	cmc
;;	JC	short RES_ER		; FAILED
;;	MOV	CX,[NEC_STATUS] 	; GET SECTOR ADDRESS, AND CYLINDER
;;	MOV	AL,CL			; SEPARATE OUT SECTOR NUMBER
;;	AND	AL,3FH
;;	DEC	AL			; TRY PREVIOUS ONE
;;	JZ	short RES_RS		; WE'VE TRIED ALL SECTORS ON TRACK
;;	AND	CL,0C0H 		; KEEP CYLINDER BITS
;;	OR	CL,AL			; MERGE SECTOR WITH CYLINDER BITS
;;	MOV	[NEC_STATUS],CX 	; SAVE CYLINDER, NEW SECTOR NUMBER
;;	JMP	short RES_3		; TRY AGAIN
;;;RES_ER: MOV	SI,OFFSET F1791 	; INDICATE DISK 1 ERROR
;;	;TEST	DL,1
;;	;JNZ	short RES_E1
;;	;MOV	SI,OFFSET F1790 	; INDICATE DISK 0 ERROR
;;;RES_E1:
;;	;CALL	E_MSG			; DISPLAY ERROR AND SET (BP) ERROR FLAG
;;;RES_OK:
;;	;POP	CX			; RESTORE TIMER LIMITS
;;	;POP	BX
;;	;RETn
;
;;SET_FAIL:
;	;MOV	AX,X*(CMOS_DIAG+NMI)	; GET CMOS ERROR BYTE
;	;CALL	CMOS_READ
;	;OR	AL,HF_FAIL		; SET DO NOT IPL FROM DISK FLAG
;	;XCHG	AH,AL			; SAVE IT
;	;CALL	CMOS_WRITE		; PUT IT OUT
;	;RETn
;
;;POD_TCHK:				; CHECK FOR 30 SECOND TIME OUT
;	;POP	AX			; SAVE RETURN
;	;POP	CX			; GET TIME OUT LIMITS
;	;POP	BX
;	;PUSH	BX			; AND SAVE THEM AGAIN
;	;PUSH	CX
;	;PUSH	AX
;	;push	ds
;	;xor	ax, ax
;	;mov	ds, ax			; RESTORE RETURN
;	;MOV	AX, [TIMER_LOW]		; AX = CURRENT TIME
;	;				; BX = START TIME
;	;				; CX = END TIME
;	;pop	ds
;	;CMP	BX,CX
;	;JB	short TCHK1		; START < END
;	;CMP	BX,AX
;	;JB	short TCHKG		; END < START < CURRENT
;	;JMP	SHORT TCHK2		; END, CURRENT < START
;;TCHK1: CMP	AX,BX
;;	JB	short TCHKNG		; CURRENT < START < END
;;TCHK2: CMP	AX,CX
;;	JB	short TCHKG		; START < CURRENT < END
;;					; OR CURRENT < END < START
;;TCHKNG: STC				; CARRY SET INDICATES TIME OUT
;;	RETn
;;TCHKG: CLC				; INDICATE STILL TIME
;;	RETn
;;
;;int_13h:

;----------------------------------------
;	FIXED DISK BIOS ENTRY POINT	:
;----------------------------------------

DISK_IO:
	CMP	DL,80H			; TEST FOR FIXED DISK DRIVE
	;JAE	short A1		; YES, HANDLE HERE
	;;;INT	40H			; DISKETTE HANDLER
	;;call	int40h
	jb	DISKETTE_IO_1
;RET_2:
	;RETf	2			; BACK TO CALLER
;	retf	4
A1:
	STI				; ENABLE INTERRUPTS
	;; 04/01/2015
	;;OR	AH,AH
	;;JNZ	short A2
	;;INT	40H			; RESET NEC WHEN AH=0
	;;SUB	AH,AH
	CMP	DL,(80H + S_MAX_FILE - 1)
	JA	short RET_2
	; 18/01/2015
	or	ah,ah
	jz	short A4
	cmp	ah, 0Dh	; Alternate reset
	jne	short A2
	sub	ah,ah	; Reset
	jmp	short A4
A2:
	CMP	AH,08H			; GET PARAMETERS IS A SPECIAL CASE
	;JNZ	short A3
        ;JMP    GET_PARM_N
	je	GET_PARM_N
A3:	CMP	AH,15H			; READ DASD TYPE IS ALSO
	;JNZ	short A4
        ;JMP    READ_DASD_TYPE
        je      READ_DASD_TYPE
	; 02/02/2015
	cmp	ah, 1Dh			;(Temporary for Retro UNIX 386 v1)
	; 12/01/2015
	cmc
	jnc	short A4
	; 30/01/2015
	;mov     byte [CS:DISK_STATUS1],BAD_CMD  ; COMMAND ERROR
        mov     byte [DISK_STATUS1], BAD_CMD
	;jmp	short RET_2
RET_2:
	retf	4
A4:					; SAVE REGISTERS DURING OPERATION
	ENTER	8,0			; SAVE (BP) AND MAKE ROOM FOR @CMD_BLOCK
	PUSH	eBX			;  IN THE STACK, THE COMMAND BLOCK IS:
	PUSH	eCX			;   @CMD_BLOCK == BYTE PTR [BP]-8
	PUSH	eDX
	PUSH	DS
	PUSH	ES
	PUSH	eSI
	PUSH	eDI
	;;04/01/2015
	;;OR	AH,AH			; CHECK FOR RESET
	;;JNZ	short A5
	;;MOV	DL,80H			; FORCE DRIVE 80 FOR RESET
;;A5:	
	;push	cs
	;pop	ds
	; 21/02/2015
	push	ax
	mov	ax, KDATA
	mov	ds, ax
	mov	es, ax	
	pop	ax
	CALL	DISK_IO_CONT		; PERFORM THE OPERATION
	;;CALL	DDS			; ESTABLISH SEGMENT
	MOV	AH,[DISK_STATUS1]	; GET STATUS FROM OPERATION
	CMP	AH,1			; SET THE CARRY FLAG TO INDICATE
	CMC				; SUCCESS OR FAILURE
	POP	eDI			; RESTORE REGISTERS
	POP	eSI
        POP     ES
        POP     DS
	POP	eDX
	POP	eCX
	POP	eBX
	LEAVE				; ADJUST (SP) AND RESTORE (BP)
	;RETf	2			; THROW AWAY SAVED FLAGS
	retf	4

; 21/02/2015
;       dw --> dd
D1:					; FUNCTION TRANSFER TABLE
	dd	DISK_RESET		; 000H
	dd	RETURN_STATUS		; 001H
	dd	DISK_READ		; 002H
	dd	DISK_WRITE		; 003H
	dd	DISK_VERF		; 004H
	dd	FMT_TRK 		; 005H
	dd	BAD_COMMAND		; 006H	FORMAT BAD SECTORS
	dd	BAD_COMMAND		; 007H	FORMAT DRIVE
	dd	BAD_COMMAND		; 008H	RETURN PARAMETERS
	dd	INIT_DRV		; 009H
	dd	RD_LONG 		; 00AH
	dd	WR_LONG 		; 00BH
	dd	DISK_SEEK		; 00CH
	dd	DISK_RESET		; 00DH
	dd	BAD_COMMAND		; 00EH	READ BUFFER
	dd	BAD_COMMAND		; 00FH	WRITE BUFFER
	dd	TST_RDY 		; 010H
	dd	HDISK_RECAL		; 011H
	dd	BAD_COMMAND		; 012H	MEMORY DIAGNOSTIC
	dd	BAD_COMMAND		; 013H	DRIVE DIAGNOSTIC
	dd	CTLR_DIAGNOSTIC 	; 014H	CONTROLLER DIAGNOSTIC
	; 02/02/2015 (Temporary - Retro UNIX 386 v1 - DISK I/O test)
	dd	BAD_COMMAND		; 015h
	dd	BAD_COMMAND		; 016h
	dd	BAD_COMMAND		; 017h
	dd	BAD_COMMAND		; 018h
	dd	BAD_COMMAND		; 019h
	dd	BAD_COMMAND		; 01Ah
	dd	DISK_READ		; 01Bh ; LBA read
	dd	DISK_WRITE		; 01Ch ; LBA write
D1L     EQU    $ - D1

DISK_IO_CONT:
	;;CALL	DDS			; ESTABLISH SEGMENT
	CMP	AH,01H			; RETURN STATUS
	;;JNZ	short SU0
        ;;JMP    RETURN_STATUS
	je	RETURN_STATUS
SU0:
	MOV	byte [DISK_STATUS1],0 	; RESET THE STATUS INDICATOR
	;;PUSH	BX			; SAVE DATA ADDRESS
	;mov	si, bx ;; 14/02/2015
	mov	esi, ebx ; 21/02/2015
	MOV	BL,[HF_NUM]		; GET NUMBER OF DRIVES
	;; 04/01/2015
	;;PUSH	AX
	AND	DL,7FH			; GET DRIVE AS 0 OR 1
					; (get drive number as 0 to 3)
	CMP	BL,DL
        ;;JBE   BAD_COMMAND_POP         ; INVALID DRIVE
        jbe     BAD_COMMAND ;; 14/02/2015
        ;
	;;03/01/2015
	sub	ebx, ebx
	mov	bl, dl
	;sub	bh, bh
	mov	[LBAMode], bh 	; 0
	;;test	byte [bx+hd0_type], 1	; LBA ready ?
	;test	byte [ebx+hd0_type], 1
	;jz	short su1		; no
	;inc	byte [LBAMode]
;su1:
	; 21/02/2015 (32 bit modification)
	;04/01/2015
	push	ax ; ***
	;PUSH	ES ; **
	PUSH	DX ; *
	push	ax
	CALL	GET_VEC 		; GET DISK PARAMETERS
	; 02/02/2015
	;mov	ax, [ES:BX+16] ; I/O port base address (1F0h, 170h)
	mov	ax, [ebx+16]
	mov	[HF_PORT], ax
	;mov	dx, [ES:BX+18] ; control port address (3F6h, 376h)
	mov	dx, [ebx+18]
	mov	[HF_REG_PORT], dx
	;mov	al, [ES:BX+20] ; head register upper nibble (A0h,B0h,E0h,F0h)
	mov	al, [ebx+20]
	; 23/02/2015
	test	al, 40h	 ; LBA bit (bit 6)
	jz 	short su1
	inc	byte [LBAMode] ; 1 
su1: 	 
	shr 	al, 4
	and	al, 1			
	mov	[hf_m_s], al 
	;
	; 03/01/2015
	;MOV	AL,byte [ES:BX+8]	; GET CONTROL BYTE MODIFIER
	mov	al, [ebx+8]
	;MOV	DX,[HF_REG_PORT]	; Device Control register	
	OUT	DX,AL			; SET EXTRA HEAD OPTION
					; Control Byte:  (= 08h, here)
					; bit 0 - 0
					; bit 1 - nIEN (1 = disable irq)
					; bit 2 - SRST (software RESET)
					; bit 3 - use extra heads (8 to 15)
					;         -always set to 1-	
					; (bits 3 to 7 are reserved
					;          for ATA devices)
	MOV	AH,[CONTROL_BYTE]	; SET EXTRA HEAD OPTION IN
	AND	AH,0C0H 		; CONTROL BYTE
	OR	AH,AL
	MOV	[CONTROL_BYTE],AH	
	; 04/01/2015
	pop	ax
	pop	dx ; * ;; 14/02/2015
	and	ah, ah	; Reset function ?
	jnz	short su2
	;;pop	dx ; * ;; 14/02/2015
	;pop	es ; **
	pop	ax ; ***
	;;pop	bx
        jmp     DISK_RESET
su2:
	cmp	byte [LBAMode], 0
	jna	short su3
	;
	; 02/02/2015 (LBA read/write function calls)
	cmp	ah, 1Bh
	jb	short lbarw1
	cmp	ah, 1Ch
	ja 	short invldfnc
	;;pop	dx ; * ; 14/02/2015
	;mov	ax, cx ; Lower word of LBA address (bits 0-15)
	mov	eax, ecx ; LBA address (21/02/2015)
	;; 14/02/2015
	mov	cl, dl ; 14/02/2015
	;;mov	dx, bx
	;mov	dx, si ; higher word of LBA address (bits 16-23)
	;;mov	bx, di
	;mov	si, di ; Buffer offset
	jmp	short lbarw2
lbarw1:
	; convert CHS to LBA
	;
	; LBA calculation - AWARD BIOS - 1999 - AHDSK.ASM
	; LBA = "# of Heads" * Sectors/Track * Cylinder + Head * Sectors/Track
	;	+ Sector - 1
	push	dx ; * ;; 14/02/2015
	;xor	dh, dh
	xor	edx, edx
	;mov	dl, [ES:BX+14]	; sectors per track (logical)
	mov	dl, [ebx+14]
	;xor	ah, ah
	xor	eax, eax
	;mov	al, [ES:BX+2]	; heads (logical) 	
	mov	al, [ebx+2]
	dec	al
	inc	ax		; 0 =  256
	mul 	dx
		; AX = # of Heads" * Sectors/Track
	mov	dx, cx
	;and	cx, 3Fh	 ; sector  (1 to 63)
	and	ecx, 3fh
	xchg	dl, dh
	shr	dh, 6
		; DX = cylinder (0 to 1023)
	;mul 	dx
		; DX:AX = # of Heads" * Sectors/Track * Cylinder
	mul	edx
	dec	cl  ; sector - 1
	;add	ax, cx
	;adc	dx, 0
		; DX:AX = # of Heads" * Sectors/Track * Cylinder + Sector -1
	add	eax, ecx
	pop	cx ; * ; ch = head, cl = drive number (zero based)
	;push	dx
	;push	ax
	push	eax
	;mov	al, [ES:BX+14]	; sectors per track (logical)	
	mov	al, [ebx+14]
	mul	ch
		;  AX = Head * Sectors/Track
        cwd
	;pop	dx
	pop	edx
	;add	ax, dx
	;pop	dx
	;adc	dx, 0 ; add carry bit
	add	eax, edx
lbarw2:
	sub	edx, edx ; 21/02/2015
	mov	dl, cl ; 21/02/2015
        mov     byte [CMD_BLOCK], 0 ; Features Register
				; NOTE: Features register (1F1h, 171h)
				; is not used for ATA device R/W functions. 
				; It is old/obsolete 'write precompensation'
				; register and error register
				; for old ATA/IDE devices.
	; 18/01/2014
	;mov	ch, [hf_m_s]	; Drive 0 (master) or 1 (slave)
	mov	cl, [hf_m_s]
	;shl	ch, 4		; bit 4 (drive bit)
	;or	ch, 0E0h	; bit 5 = 1
				; bit 6 = 1 = LBA mode
				; bit 7 = 1
	or	cl, 0Eh ; 1110b
	;and	dh, 0Fh		; LBA byte 4 (bits 24 to 27)
	and	eax, 0FFFFFFFh
	shl	ecx, 28 ; 21/02/2015
	;or	dh, ch
	or	eax, ecx	
	;;mov	[CMD_BLOCK+2], al ; LBA byte 1 (bits 0 to 7)
				  ; (Sector Number Register)
	;;mov	[CMD_BLOCK+3], ah ; LBA byte 2 (bits 8 to 15)
				  ; (Cylinder Low Register)
	;mov	[CMD_BLOCK+2], ax ; LBA byte 1, 2
	;mov	[CMD_BLOCK+4], dl ; LBA byte 3 (bits 16 to 23)
				  ; (Cylinder High Register)
	;;mov	[CMD_BLOCK+5], dh ; LBA byte 4 (bits 24 to 27)
				  ; (Drive/Head Register)
	
	;mov	[CMD_BLOCK+4], dx ; LBA byte 4, LBA & DEV select bits
	mov	[CMD_BLOCK+2], eax ; 21/02/2015
	;14/02/2015
	;mov	dl, cl ; Drive number (INIT_DRV)		
	jmp	short su4
su3:
	; 02/02/2015 
	; (Temporary functions 1Bh & 1Ch are not valid for CHS mode) 
	cmp 	ah, 14h
	jna 	short chsfnc
invldfnc:
        ; 14/02/2015  
	;pop	es ; **
        pop     ax ; ***
        ;jmp     short BAD_COMMAND_POP
        jmp     short BAD_COMMAND
chsfnc:	
	;MOV	AX,[ES:BX+5]		; GET WRITE PRE-COMPENSATION CYLINDER
	mov	ax, [ebx+5]
	SHR	AX,2
	MOV	[CMD_BLOCK],AL
	;;MOV	AL,[ES:BX+8]		; GET CONTROL BYTE MODIFIER
	;;PUSH	DX
	;;MOV	DX,[HF_REG_PORT]
	;;OUT	DX,AL			; SET EXTRA HEAD OPTION
	;;POP	DX ; * 
	;;POP	ES ; **
	;;MOV	AH,[CONTROL_BYTE]	; SET EXTRA HEAD OPTION IN
	;;AND	AH,0C0H 		; CONTROL BYTE	
	;;OR	AH,AL
	;;MOV	[CONTROL_BYTE],AH
	;
	MOV	AL,CL			; GET SECTOR NUMBER
	AND	AL,3FH
	MOV	[CMD_BLOCK+2],AL
	MOV	[CMD_BLOCK+3],CH 	; GET CYLINDER NUMBER
	MOV	AL,CL
	SHR	AL,6
	MOV	[CMD_BLOCK+4],AL 	; CYLINDER HIGH ORDER 2 BITS
	;;05/01/2015
	;;MOV	AL,DL			; DRIVE NUMBER
	mov	al, [hf_m_s]
	SHL	AL,4
	AND	DH,0FH			; HEAD NUMBER
	OR	AL,DH
	;OR	AL,80H or 20H
	OR	AL,80h+20h		; ECC AND 512 BYTE SECTORS
	MOV	[CMD_BLOCK+5],AL 	; ECC/SIZE/DRIVE/HEAD
su4:
	;POP	ES ; **
        ;; 14/02/2015
        ;;POP   AX
        ;;MOV   [CMD_BLOCK+1],AL        ; SECTOR COUNT
        ;;PUSH  AX
        ;;MOV   AL,AH                   ; GET INTO LOW BYTE
        ;;XOR   AH,AH                   ; ZERO HIGH BYTE
        ;;SAL   AX,1                    ; *2 FOR TABLE LOOKUP
        pop     ax ; ***
        mov     [CMD_BLOCK+1], al
        sub	ebx, ebx
	mov     bl, ah
        ;xor     bh, bh
        ;sal     bx, 1
        sal	bx, 2	; 32 bit offset (21/02/2015)
	;;MOV   SI,AX                   ; PUT INTO SI FOR BRANCH
        ;;CMP   AX,D1L                  ; TEST WITHIN RANGE
        ;;JNB   short BAD_COMMAND_POP
        ;cmp     bx, D1L
	cmp	ebx, D1L
	jnb	short BAD_COMMAND
        ;xchg    bx, si
        xchg	ebx, esi
	;;;POP	AX			; RESTORE AX
	;;;POP	BX			; AND DATA ADDRESS
	
	;;PUSH	CX
	;;PUSH	AX			; ADJUST ES:BX
	;MOV	CX,BX			; GET 3 HIGH ORDER NIBBLES OF BX
	;SHR	CX,4
	;MOV	AX,ES
	;ADD	AX,CX
	;MOV	ES,AX
	;AND	BX,000FH		; ES:BX CHANGED TO ES:000X
	;;POP	AX
	;;POP	CX
	;;JMP	word [CS:SI+D1]
	;jmp	word [SI+D1]
	jmp	dword [esi+D1]
;;BAD_COMMAND_POP:
;;	POP	AX
;;	POP	BX
BAD_COMMAND:
        MOV     byte [DISK_STATUS1],BAD_CMD  ; COMMAND ERROR
	MOV	AL,0
	RETn

;----------------------------------------
;	RESET THE DISK SYSTEM  (AH=00H) :
;----------------------------------------

; 18-1-2015 : one controller reset (not other one)

DISK_RESET:
	CLI
	IN	AL,INTB01		; GET THE MASK REGISTER
	;JMP	$+2
	IODELAY
	;AND	AL,0BFH 		; ENABLE FIXED DISK INTERRUPT
	and	al,3Fh			; 22/12/2014 (IRQ 14 & IRQ 15)
	OUT	INTB01,AL
	STI				; START INTERRUPTS
	; 14/02/2015
	mov	di, dx	
	; 04/01/2015
	;xor	di,di
drst0:
	MOV	AL,04H  ; bit 2 - SRST 
	;MOV	DX,HF_REG_PORT
	MOV	DX,[HF_REG_PORT]
	OUT	DX,AL			; RESET
;	MOV	CX,10			; DELAY COUNT
;DRD:	DEC	CX
;	JNZ	short DRD		; WAIT 4.8 MICRO-SEC
	;mov	cx,2			; wait for 30 micro seconds	
        mov	ecx, 2 ; 21/02/2015
	call    WAITF                   ; (Award Bios 1999 - WAIT_REFRESH,
                                        ; 40 micro seconds)
	mov	al,[CONTROL_BYTE]
	AND	AL,0FH			; SET HEAD OPTION
	OUT	DX,AL			; TURN RESET OFF
	CALL	NOT_BUSY
	JNZ	short DRERR		; TIME OUT ON RESET
	MOV	DX,[HF_PORT]
	inc	dl  ; HF_PORT+1
	; 02/01/2015 - Award BIOS 1999 - AHDSK.ASM
        ;mov     cl, 10
        mov     ecx, 10 ; 21/02/2015 
drst1:
	IN	AL,DX			; GET RESET STATUS
	CMP	AL,1
	; 04/01/2015
	jz	short drst2
	;JNZ	short DRERR		; BAD RESET STATUS
        	; Drive/Head Register - bit 4
	loop	drst1
DRERR:	
	MOV	byte [DISK_STATUS1],BAD_RESET ; CARD FAILED
	RETn
drst2:
	; 14/02/2015
	mov	dx,di
;drst3:
;	; 05/01/2015
;	shl 	di,1
;	; 04/01/2015
;	mov	ax,[di+hd_cports]
;	cmp	ax,[HF_REG_PORT]
;	je	short drst4
;	mov	[HF_REG_PORT], ax
;	; 03/01/2015
;	mov	ax,[di+hd_ports]
;       mov     [HF_PORT], ax
;	; 05/01/2014
;	shr	di,1
;	; 04/01/2015
;	jmp	short drst0	; reset other controller
;drst4:
;	; 05/01/2015
;	shr	di,1
;	mov	al,[di+hd_dregs]
;	and	al,10h ; bit 4 only
;	shr	al,4 ; bit 4  -> bit 0
;	mov	[hf_m_s], al ; (0 = master, 1 = slave)
	;
	mov	al, [hf_m_s] ; 18/01/2015
	test	al,1
;	jnz	short drst6
        jnz     short drst4
	AND     byte [CMD_BLOCK+5],0EFH ; SET TO DRIVE 0
;drst5:
drst3:
	CALL	INIT_DRV		; SET MAX HEADS
	;mov	dx,di
	CALL	HDISK_RECAL		; RECAL TO RESET SEEK SPEED
	; 04/01/2014
;	inc	di
;	mov	dx,di
;	cmp	dl,[HF_NUM]
;	jb	short drst3
;DRE:
	MOV	byte [DISK_STATUS1],0 	; IGNORE ANY SET UP ERRORS
	RETn
;drst6:
drst4:		; Drive/Head Register - bit 4
	OR      byte [CMD_BLOCK+5],010H ; SET TO DRIVE 1     
        ;jmp    short drst5
        jmp     short drst3

;----------------------------------------
;	DISK STATUS ROUTINE  (AH = 01H) :
;----------------------------------------

RETURN_STATUS:
	MOV	AL,[DISK_STATUS1]	; OBTAIN PREVIOUS STATUS
        MOV     byte [DISK_STATUS1],0   ; RESET STATUS
	RETn

;----------------------------------------
;	DISK READ ROUTINE    (AH = 02H) :
;----------------------------------------

DISK_READ:
	MOV	byte [CMD_BLOCK+6],READ_CMD
        JMP     COMMANDI

;----------------------------------------
;	DISK WRITE ROUTINE   (AH = 03H) :
;----------------------------------------

DISK_WRITE:
	MOV	byte [CMD_BLOCK+6],WRITE_CMD
        JMP     COMMANDO

;----------------------------------------
;	DISK VERIFY	     (AH = 04H) :
;----------------------------------------

DISK_VERF:
	MOV	byte [CMD_BLOCK+6],VERIFY_CMD
	CALL	COMMAND
	JNZ	short VERF_EXIT		; CONTROLLER STILL BUSY
	CALL	_WAIT			; (Original: CALL WAIT)	
	JNZ	short VERF_EXIT		; TIME OUT
	CALL	CHECK_STATUS
VERF_EXIT:
	RETn

;----------------------------------------
;	FORMATTING	     (AH = 05H) :
;----------------------------------------

FMT_TRK:				; FORMAT TRACK	(AH = 005H)
	MOV	byte [CMD_BLOCK+6],FMTTRK_CMD
	;PUSH	ES
	;PUSH	BX
	push	ebx
	CALL	GET_VEC 		; GET DISK PARAMETERS ADDRESS
	;MOV	AL,[ES:BX+14]		; GET SECTORS/TRACK
	mov	al, [ebx+14]
	MOV	[CMD_BLOCK+1],AL 	; SET SECTOR COUNT IN COMMAND
	pop	ebx
	;POP	BX
	;POP	ES
        JMP     CMD_OF                  ; GO EXECUTE THE COMMAND

;----------------------------------------
;	READ DASD TYPE	     (AH = 15H) :
;----------------------------------------

READ_DASD_TYPE:
READ_D_T:				; GET DRIVE PARAMETERS
	PUSH	DS			; SAVE REGISTERS
	;PUSH	ES
	PUSH	eBX
	;CALL	DDS			; ESTABLISH ADDRESSING
	;push	cs
	;pop	ds
        mov	bx, KDATA
	mov	ds, bx
	;mov	es, bx
	MOV     byte [DISK_STATUS1],0
	MOV	BL,[HF_NUM]		; GET NUMBER OF DRIVES
	AND	DL,7FH			; GET DRIVE NUMBER
	CMP	BL,DL
	JBE	short RDT_NOT_PRESENT 	; RETURN DRIVE NOT PRESENT
	CALL	GET_VEC 		; GET DISK PARAMETER ADDRESS
	;MOV	AL,[ES:BX+2]		; HEADS
	mov	al, [ebx+2]
	;MOV	CL,[ES:BX+14]
	mov	cl, [ebx+14]
	IMUL	CL			; * NUMBER OF SECTORS
	;MOV	CX,[ES:BX]		; MAX NUMBER OF CYLINDERS
	mov	cx ,[ebx]
	;
	; 02/01/2015 
	; ** leave the last cylinder as reserved for diagnostics **
	; (Also in Award BIOS - 1999, AHDSK.ASM, FUN15 -> sub ax, 1)
	DEC	CX			; LEAVE ONE FOR DIAGNOSTICS
	;
	IMUL	CX			; NUMBER OF SECTORS
	MOV	CX,DX			; HIGH ORDER HALF
	MOV	DX,AX			; LOW ORDER HALF
	;SUB	AX,AX
	sub	al, al
	MOV	AH,03H			; INDICATE FIXED DISK
RDT2:	POP	eBX			; RESTORE REGISTERS
	;POP	ES
	POP	DS
	CLC				; CLEAR CARRY
	;RETf	2
	retf	4
RDT_NOT_PRESENT:
	SUB	AX,AX			; DRIVE NOT PRESENT RETURN
	MOV	CX,AX			; ZERO BLOCK COUNT
	MOV	DX,AX
	JMP	short RDT2

;----------------------------------------
;	GET PARAMETERS	     (AH = 08H) :
;----------------------------------------

GET_PARM_N:
;GET_PARM:				; GET DRIVE PARAMETERS
	PUSH	DS			; SAVE REGISTERS
	;PUSH	ES
	PUSH	eBX
	;MOV	AX,ABS0 		; ESTABLISH ADDRESSING
	;MOV	DS,AX
	;TEST	DL,1			; CHECK FOR DRIVE 1
	;JZ	short G0
	;LES	BX,@HF1_TBL_VEC
	;JMP	SHORT G1
;G0:	LES	BX,@HF_TBL_VEC
;G1:
	;CALL	DDS			; ESTABLISH SEGMENT
	; 22/12/2014
	;push	cs
	;pop	ds
	mov	bx, KDATA
	mov	ds, bx
	;mov	es, bx
	;
	SUB	DL,80H
	CMP	DL,MAX_FILE		; TEST WITHIN RANGE
	JAE	short G4
	;
	xor	ebx, ebx ; 21/02/2015
	; 22/12/2014
	mov	bl, dl
	;xor	bh, bh  
	shl	bl, 2			; convert index to offset
	;add	bx, HF_TBL_VEC
	add	ebx, HF_TBL_VEC
	;mov	ax, [bx+2]
	;mov	es, ax			; dpt segment
	;mov	bx, [bx]		; dpt offset
	mov	ebx, [ebx] ; 32 bit offset	

	MOV	byte [DISK_STATUS1],0
        ;MOV     AX,[ES:BX]              ; MAX NUMBER OF CYLINDERS
	mov	ax, [ebx]
	;;SUB	AX,2			; ADJUST FOR 0-N
	dec	ax			; max. cylinder number
	MOV	CH,AL
	AND	AX,0300H		; HIGH TWO BITS OF CYLINDER
	SHR	AX,1
	SHR	AX,1
	;OR	AL,[ES:BX+14]		; SECTORS
	or	al, [ebx+14]
	MOV	CL,AL
	;MOV	DH,[ES:BX+2]		; HEADS
	mov	dh, [ebx+2]
	DEC	DH			; 0-N RANGE
	MOV	DL,[HF_NUM]		; DRIVE COUNT
	SUB	AX,AX
        ;27/12/2014 
	; ES:DI = Address of disk parameter table from BIOS
	;(Programmer's Guide to the AMIBIOS - 1993)
	;mov	di, bx			; HDPT offset
	mov	edi, ebx
G5:
	POP	eBX			; RESTORE REGISTERS
	;POP	ES
	POP	DS
	;RETf	2
	retf	4
G4:
	MOV     byte [DISK_STATUS1],INIT_FAIL ; OPERATION FAILED
	MOV	AH,INIT_FAIL
	SUB	AL,AL
	SUB	DX,DX
	SUB	CX,CX
	STC				; SET ERROR FLAG
	JMP	short G5

;----------------------------------------
;	INITIALIZE DRIVE     (AH = 09H) :
;----------------------------------------
	; 03/01/2015
	; According to ATA-ATAPI specification v2.0 to v5.0
	; logical sector per logical track
	; and logical heads - 1 would be set but
	; it is seen as it will be good
	; if physical parameters will be set here
	; because, number of heads <= 16.
	; (logical heads usually more than 16)
	; NOTE: ATA logical parameters (software C, H, S)
	;	== INT 13h physical parameters

;INIT_DRV:
;	MOV	byte [CMD_BLOCK+6],SET_PARM_CMD
;	CALL	GET_VEC 		; ES:BX -> PARAMETER BLOCK
;	MOV	AL,[ES:BX+2]		; GET NUMBER OF HEADS
;	DEC	AL			; CONVERT TO 0-INDEX
;	MOV	AH,[CMD_BLOCK+5] 	; GET SDH REGISTER
;	AND	AH,0F0H 		; CHANGE HEAD NUMBER
;	OR	AH,AL			; TO MAX HEAD
;	MOV	[CMD_BLOCK+5],AH
;	MOV	AL,[ES:BX+14]		; MAX SECTOR NUMBER
;	MOV	[CMD_BLOCK+1],AL
;	SUB	AX,AX
;	MOV	[CMD_BLOCK+3],AL 	; ZERO FLAGS
;	CALL	COMMAND 		; TELL CONTROLLER
;	JNZ	short INIT_EXIT		; CONTROLLER BUSY ERROR
;	CALL	NOT_BUSY		; WAIT FOR IT TO BE DONE
;	JNZ	short INIT_EXIT		; TIME OUT
;	CALL	CHECK_STATUS
;INIT_EXIT:
;	RETn

; 04/01/2015
; 02/01/2015 - Derived from from AWARD BIOS 1999
;				 AHDSK.ASM - INIT_DRIVE
INIT_DRV:
	;xor	ah,ah
	xor	eax, eax ; 21/02/2015
	mov	al,11 ; Physical heads from translated HDPT
        cmp     [LBAMode], ah   ; 0
	ja	short idrv0
	mov	al,2  ; Physical heads from standard HDPT
idrv0:
	; DL = drive number (0 based)
	call	GET_VEC
	;push	bx
	push	ebx ; 21/02/2015
	;add	bx,ax
	add	ebx, eax
	;; 05/01/2015
	mov	ah, [hf_m_s] ; drive number (0= master, 1= slave)
	;;and 	ah,1 
	shl	ah,4
	or	ah,0A0h  ; Drive/Head register - 10100000b (A0h)	
	;mov	al,[es:bx]
	mov	al, [ebx] ; 21/02/2015
	dec	al	 ; last head number 
	;and	al,0Fh
	or	al,ah	 ; lower 4 bits for head number
	;
	mov	byte [CMD_BLOCK+6],SET_PARM_CMD
	mov	[CMD_BLOCK+5],al
	;pop	bx
	pop	ebx
	sub	eax, eax ; 21/02/2015
	mov	al,4 ; Physical sec per track from translated HDPT
	cmp	byte [LBAMode], 0
	ja	short idrv1
	mov	al,14 ; Physical sec per track from standard HDPT
idrv1:
	;xor	ah,ah
	;add	bx,ax
	add	ebx, eax ; 21/02/2015
	;mov	al,[es:bx]
			; sector number
	mov	al, [ebx]
	mov	[CMD_BLOCK+1],al
	sub	al,al
	mov	[CMD_BLOCK+3],al  ; ZERO FLAGS
	call	COMMAND 	  ; TELL CONTROLLER
	jnz	short INIT_EXIT	  ; CONTROLLER BUSY ERROR
	call	NOT_BUSY	  ; WAIT FOR IT TO BE DONE
	jnz	short INIT_EXIT	  ; TIME OUT
	call	CHECK_STATUS
INIT_EXIT:
	RETn

;----------------------------------------
;	READ LONG	     (AH = 0AH) :
;----------------------------------------

RD_LONG:
	;MOV	@CMD_BLOCK+6,READ_CMD OR ECC_MODE
        mov     byte [CMD_BLOCK+6],READ_CMD + ECC_MODE 
        JMP     COMMANDI

;----------------------------------------
;	WRITE LONG	     (AH = 0BH) :
;----------------------------------------

WR_LONG:
	;MOV	@CMD_BLOCK+6,WRITE_CMD OR ECC_MODE
        MOV     byte [CMD_BLOCK+6],WRITE_CMD + ECC_MODE
        JMP     COMMANDO

;----------------------------------------
;	SEEK		     (AH = 0CH) :
;----------------------------------------

DISK_SEEK:
        MOV     byte [CMD_BLOCK+6],SEEK_CMD
	CALL	COMMAND
	JNZ	short DS_EXIT 		; CONTROLLER BUSY ERROR
	CALL	_WAIT
        JNZ     DS_EXIT                 ; TIME OUT ON SEEK
	CALL	CHECK_STATUS
        CMP     byte [DISK_STATUS1],BAD_SEEK
	JNE	short DS_EXIT
        MOV     byte [DISK_STATUS1],0
DS_EXIT:
	RETn

;----------------------------------------
;	TEST DISK READY      (AH = 10H) :
;----------------------------------------

TST_RDY:				; WAIT FOR CONTROLLER
	CALL	NOT_BUSY
	JNZ	short TR_EX
	MOV	AL,[CMD_BLOCK+5] 	; SELECT DRIVE
	MOV	DX,[HF_PORT]
	add	dl,6
	OUT	DX,AL
	CALL	CHECK_ST		; CHECK STATUS ONLY
	JNZ	short TR_EX
	MOV	byte [DISK_STATUS1],0 	; WIPE OUT DATA CORRECTED ERROR
TR_EX:	
	RETn

;----------------------------------------
;	RECALIBRATE	     (AH = 11H) :
;----------------------------------------

HDISK_RECAL:
        MOV     byte [CMD_BLOCK+6],RECAL_CMD ; 10h, 16
	CALL	COMMAND 		; START THE OPERATION
	JNZ	short RECAL_EXIT	; ERROR
	CALL	_WAIT			; WAIT FOR COMPLETION
	JZ	short RECAL_X 		; TIME OUT ONE OK ?
	CALL	_WAIT			; WAIT FOR COMPLETION LONGER
	JNZ	short RECAL_EXIT	; TIME OUT TWO TIMES IS ERROR
RECAL_X:
	CALL	CHECK_STATUS
	CMP	byte [DISK_STATUS1],BAD_SEEK ; SEEK NOT COMPLETE
	JNE	short RECAL_EXIT	; IS OK
	MOV	byte [DISK_STATUS1],0
RECAL_EXIT:
        CMP     byte [DISK_STATUS1],0
	RETn

;----------------------------------------
;      CONTROLLER DIAGNOSTIC (AH = 14H) :
;----------------------------------------

CTLR_DIAGNOSTIC:
        CLI                             ; DISABLE INTERRUPTS WHILE CHANGING MASK
	IN	AL,INTB01		; TURN ON SECOND INTERRUPT CHIP
	;AND	AL,0BFH
	and	al, 3Fh			; enable IRQ 14 & IRQ 15
	;JMP	$+2
	IODELAY
	OUT	INTB01,AL
	IODELAY
	IN	AL,INTA01		; LET INTERRUPTS PASS THRU TO
	AND	AL,0FBH 		;  SECOND CHIP
	;JMP	$+2
	IODELAY
	OUT	INTA01,AL
	STI
	CALL	NOT_BUSY		; WAIT FOR CARD
	JNZ	short CD_ERR		; BAD CARD
	;MOV	DX, HF_PORT+7
	mov	dx, [HF_PORT]
	add	dl, 7
	MOV	AL,DIAG_CMD		; START DIAGNOSE
	OUT	DX,AL
	CALL	NOT_BUSY		; WAIT FOR IT TO COMPLETE
	MOV	AH,TIME_OUT
	JNZ	short CD_EXIT 		; TIME OUT ON DIAGNOSTIC
	;MOV	DX,HF_PORT+1		; GET ERROR REGISTER
	mov	dx, [HF_PORT]
	inc	dl
	IN	AL,DX
	MOV	[HF_ERROR],AL		; SAVE IT
	MOV	AH,0
	CMP	AL,1			; CHECK FOR ALL OK
	JE	SHORT CD_EXIT
CD_ERR: MOV	AH,BAD_CNTLR
CD_EXIT:
	MOV	[DISK_STATUS1],AH
	RETn

;----------------------------------------
; COMMANDI				:
;	REPEATEDLY INPUTS DATA TILL	:
;	NSECTOR RETURNS ZERO		:
;----------------------------------------
COMMANDI:
	CALL	CHECK_DMA		; CHECK 64K BOUNDARY ERROR
	JC	short CMD_ABORT
	;MOV	DI,BX
	mov	edi, ebx ; 21/02/2015
	CALL	COMMAND 		; OUTPUT COMMAND
	JNZ	short CMD_ABORT
CMD_I1:
	CALL	_WAIT			; WAIT FOR DATA REQUEST INTERRUPT
	JNZ	short TM_OUT		; TIME OUT
cmd_i1x: ; 18/02/2016
	;MOV	CX,256			; SECTOR SIZE IN WORDS
	mov	ecx, 256 ; 21/02/2015	
	;MOV	DX,HF_PORT
	mov	dx,[HF_PORT]
	CLI
	CLD
	REP	INSW			; GET THE SECTOR
	STI
	TEST	byte [CMD_BLOCK+6],ECC_MODE ; CHECK FOR NORMAL INPUT
	JZ	short CMD_I3
	CALL	WAIT_DRQ		; WAIT FOR DATA REQUEST
	JC	short TM_OUT
	;MOV	DX,HF_PORT
	mov	dx,[HF_PORT]
	;MOV	CX,4			; GET ECC BYTES
	mov 	ecx, 4 ; mov cx, 4 
CMD_I2: IN	AL,DX
	;MOV	[ES:DI],AL		; GO SLOW FOR BOARD
	mov 	[edi], al ; 21/02/2015
	INC	eDI
	LOOP	CMD_I2
CMD_I3: 
	; wait for 400 ns
	add 	dl, 7
	in	al, dx
	in	al, dx
	in	al, dx
	;
	CALL	CHECK_STATUS
	JNZ	short CMD_ABORT		; ERROR RETURNED
	DEC	byte [CMD_BLOCK+1]	; CHECK FOR MORE
	;JNZ	SHORT CMD_I1
	jnz	short cmd_i1x ; 18/02/2016
CMD_ABORT:
TM_OUT: RETn

;----------------------------------------
; COMMANDO				:
;	REPEATEDLY OUTPUTS DATA TILL	:
;	NSECTOR RETURNS ZERO		:
;----------------------------------------
COMMANDO:
	CALL	CHECK_DMA		; CHECK 64K BOUNDARY ERROR
	JC	short CMD_ABORT
CMD_OF: MOV	eSI,eBX ; 21/02/2015
	CALL	COMMAND 		; OUTPUT COMMAND
	JNZ	short CMD_ABORT
	CALL	WAIT_DRQ		; WAIT FOR DATA REQUEST
	JC	short TM_OUT			; TOO LONG
CMD_O1: ;PUSH	DS
	;PUSH	ES			; MOVE ES TO DS
	;POP	DS
	;MOV	CX,256			; PUT THE DATA OUT TO THE CARD
	;MOV	DX,HF_PORT
	; 01/02/2015
	mov	dx, [HF_PORT]
	;push	es
	;pop	ds
	;mov	cx, 256
	mov	ecx, 256 ; 21/02/2015
	CLI
	CLD
	REP	OUTSW
	STI
	;POP	DS			; RESTORE DS
	TEST	byte [CMD_BLOCK+6],ECC_MODE ; CHECK FOR NORMAL OUTPUT
	JZ	short CMD_O3
	CALL	WAIT_DRQ		; WAIT FOR DATA REQUEST
	JC	short TM_OUT
	;MOV	DX,HF_PORT
	mov	dx, [HF_PORT]
	;MOV	CX,4			; OUTPUT THE ECC BYTES
	mov	ecx, 4  ; mov cx, 4
CMD_O2: ;MOV	AL,[ES:SI]
	mov	al, [esi]
	OUT	DX,AL
	INC	eSI
	LOOP	CMD_O2
CMD_O3:
	CALL	_WAIT			; WAIT FOR SECTOR COMPLETE INTERRUPT
	JNZ	short TM_OUT		; ERROR RETURNED
	CALL	CHECK_STATUS
	JNZ	short CMD_ABORT
	TEST	byte [HF_STATUS],ST_DRQ	; CHECK FOR MORE
	JNZ	SHORT CMD_O1
	;MOV	DX,HF_PORT+2		; CHECK RESIDUAL SECTOR COUNT
	mov	dx, [HF_PORT]
	;add	dl, 2
	inc	dl
	inc	dl
	IN	AL,DX			;
	TEST	AL,0FFH 		;
	JZ	short CMD_O4			; COUNT = 0  OK
	MOV	byte [DISK_STATUS1],UNDEF_ERR 
					; OPERATION ABORTED - PARTIAL TRANSFER
CMD_O4:
	RETn

;--------------------------------------------------------
; COMMAND						:
;	THIS ROUTINE OUTPUTS THE COMMAND BLOCK		:
; OUTPUT						:
;	BL = STATUS					:
;	BH = ERROR REGISTER				:
;--------------------------------------------------------

COMMAND:
	PUSH	eBX			; WAIT FOR SEEK COMPLETE AND READY
	;;MOV	CX,DELAY_2		; SET INITIAL DELAY BEFORE TEST
COMMAND1:
	;;PUSH	CX			; SAVE LOOP COUNT
	CALL	TST_RDY 		; CHECK DRIVE READY
	;;POP	CX
	JZ	short COMMAND2		; DRIVE IS READY
        CMP     byte [DISK_STATUS1],TIME_OUT ; TST_RDY TIMED OUT--GIVE UP
	;JZ	short CMD_TIMEOUT
	;;LOOP	COMMAND1		; KEEP TRYING FOR A WHILE
	;JMP	SHORT COMMAND4		; ITS NOT GOING TO GET READY
	jne	short COMMAND4
CMD_TIMEOUT:
	MOV	byte [DISK_STATUS1],BAD_CNTLR
COMMAND4:
	POP	eBX
        CMP     byte [DISK_STATUS1],0   ; SET CONDITION CODE FOR CALLER
	RETn
COMMAND2:
	POP	eBX
	PUSH	eDI
	MOV	byte [HF_INT_FLAG],0	; RESET INTERRUPT FLAG
	CLI				; INHIBIT INTERRUPTS WHILE CHANGING MASK
	IN	AL,INTB01		; TURN ON SECOND INTERRUPT CHIP
	;AND	AL,0BFH
	and	al, 3Fh			; Enable IRQ 14 & 15
	;JMP	$+2
	IODELAY
	OUT	INTB01,AL
	IN	AL,INTA01		; LET INTERRUPTS PASS THRU TO
	AND	AL,0FBH 		;  SECOND CHIP
	;JMP	$+2
	IODELAY
	OUT	INTA01,AL
	STI
	XOR	eDI,eDI			; INDEX THE COMMAND TABLE
	;MOV	DX,HF_PORT+1		; DISK ADDRESS
	mov	dx, [HF_PORT]
	inc	dl
	TEST	byte [CONTROL_BYTE],0C0H ; CHECK FOR RETRY SUPPRESSION
	JZ	short COMMAND3
	MOV	AL, [CMD_BLOCK+6] 	; YES-GET OPERATION CODE
	AND	AL,0F0H 		; GET RID OF MODIFIERS
	CMP	AL,20H			; 20H-40H IS READ, WRITE, VERIFY
	JB	short COMMAND3
	CMP	AL,40H
	JA	short COMMAND3
	OR	byte [CMD_BLOCK+6],NO_RETRIES 
					; VALID OPERATION FOR RETRY SUPPRESS
COMMAND3:
	MOV	AL,[CMD_BLOCK+eDI]	; GET THE COMMAND STRING BYTE
	OUT	DX,AL			; GIVE IT TO CONTROLLER
	IODELAY
	INC	eDI			; NEXT BYTE IN COMMAND BLOCK
	INC	DX			; NEXT DISK ADAPTER REGISTER
	cmp	di, 7	; 1/1/2015	; ALL DONE?
	JNZ	short COMMAND3		; NO--GO DO NEXT ONE
	POP	eDI
	RETn				; ZERO FLAG IS SET

;CMD_TIMEOUT:
;	MOV	byte [DISK_STATUS1],BAD_CNTLR
;COMMAND4:
;	POP	BX
;	CMP	[DISK_STATUS1],0 	; SET CONDITION CODE FOR CALLER
;	RETn

;----------------------------------------
;	WAIT FOR INTERRUPT		:
;----------------------------------------
;WAIT:
_WAIT:
	STI				; MAKE SURE INTERRUPTS ARE ON
	;SUB	CX,CX			; SET INITIAL DELAY BEFORE TEST
	;CLC
	;MOV	AX,9000H		; DEVICE WAIT INTERRUPT
	;INT	15H
	;JC	WT2			; DEVICE TIMED OUT
	;MOV	BL,DELAY_1		; SET DELAY COUNT

	;mov	bl, WAIT_HDU_INT_HI
	;; 21/02/2015
	;;mov	bl, WAIT_HDU_INT_HI + 1
	;;mov	cx, WAIT_HDU_INT_LO
	mov	ecx, WAIT_HDU_INT_LH
					; (AWARD BIOS -> WAIT_FOR_MEM)
;-----	WAIT LOOP

WT1:	
	;TEST	byte [HF_INT_FLAG],80H	; TEST FOR INTERRUPT
	test 	byte [HF_INT_FLAG],0C0h
	;LOOPZ	WT1
	JNZ	short WT3		; INTERRUPT--LETS GO
	;DEC	BL
	;JNZ	short WT1		; KEEP TRYING FOR A WHILE

WT1_hi:
	in	al, SYS1 ; 61h (PORT_B)	; wait for lo to hi
	test	al, 10h			; transition on memory
	jnz	short WT1_hi		; refresh.
WT1_lo:
	in	al, SYS1 		; 061h (PORT_B)	
	test	al, 10h			
	jz	short WT1_lo
	loop	WT1
	;;or	bl, bl
	;;jz	short WT2	
	;;dec	bl
	;;jmp	short WT1
	;dec	bl
	;jnz	short WT1	

WT2:	MOV	byte [DISK_STATUS1],TIME_OUT ; REPORT TIME OUT ERROR
	JMP	SHORT WT4
WT3:	MOV	byte [DISK_STATUS1],0
	MOV	byte [HF_INT_FLAG],0
WT4:	CMP	byte [DISK_STATUS1],0 	; SET CONDITION CODE FOR CALLER
	RETn

;----------------------------------------
;	WAIT FOR CONTROLLER NOT BUSY	:
;----------------------------------------
NOT_BUSY:
	STI				; MAKE SURE INTERRUPTS ARE ON
	;PUSH	eBX
	;SUB	CX,CX			; SET INITIAL DELAY BEFORE TEST
	mov	DX, [HF_PORT]
	add	dl, 7			; Status port (HF_PORT+7)
	;MOV	BL,DELAY_1
					; wait for 10 seconds
	;mov 	cx, WAIT_HDU_INT_LO	; 1615h
	;;mov 	bl, WAIT_HDU_INT_HI	;   05h
	;mov	bl, WAIT_HDU_INT_HI + 1
	mov	ecx, WAIT_HDU_INT_LH  ; 21/02/2015
	;
;;      mov     byte [wait_count], 0    ; Reset wait counter
NB1:	
	IN	AL,DX			; CHECK STATUS
	;TEST	AL,ST_BUSY
	and	al, ST_BUSY
	;LOOPNZ	NB1
	JZ	short NB2		; NOT BUSY--LETS GO
	;DEC	BL			
	;JNZ	short NB1		; KEEP TRYING FOR A WHILE

NB1_hi: IN	AL,SYS1			; wait for hi to lo
	TEST	AL,010H			; transition on memory
	JNZ	SHORT NB1_hi		; refresh.
NB1_lo: IN	AL,SYS1
	TEST	AL,010H
	JZ	short NB1_lo
	LOOP	NB1
	;dec	bl
	;jnz	short NB1
	;
;;      cmp     byte [wait_count], 182  ; 10 seconds (182 timer ticks)
;;	jb	short NB1
	;
	;MOV	[DISK_STATUS1],TIME_OUT	; REPORT TIME OUT ERROR
	;JMP	SHORT NB3
	mov	al, TIME_OUT
NB2:	
	;MOV	byte [DISK_STATUS1],0
;NB3:	
	;POP	eBX
	mov	[DISK_STATUS1], al	;;; will be set after return
	;CMP	byte [DISK_STATUS1],0 	; SET CONDITION CODE FOR CALLER
	or	al, al			; (zf = 0 --> timeout)
	RETn

;----------------------------------------
;	WAIT FOR DATA REQUEST		:
;----------------------------------------
WAIT_DRQ:
	;MOV	CX,DELAY_3
	;MOV	DX,HF_PORT+7
	mov	dx, [HF_PORT]
	add	dl, 7
	;;MOV	bl, WAIT_HDU_DRQ_HI	; 0
	;MOV	cx, WAIT_HDU_DRQ_LO	; 1000 (30 milli seconds)
					; (but it is written as 2000
					; micro seconds in ATORGS.ASM file
					; of Award Bios - 1999, D1A0622)
	mov 	ecx, WAIT_HDU_DRQ_LH ; 21/02/2015 
WQ_1:	IN	AL,DX			; GET STATUS
	TEST	AL,ST_DRQ		; WAIT FOR DRQ
	JNZ	short WQ_OK
	;LOOP	WQ_1			; KEEP TRYING FOR A SHORT WHILE
WQ_hi:	
	IN	AL,SYS1			; wait for hi to lo
	TEST	AL,010H			; transition on memory
	JNZ	SHORT WQ_hi		; refresh.
WQ_lo:  IN      AL,SYS1
	TEST	AL,010H
	JZ	SHORT WQ_lo
	LOOP	WQ_1

        MOV     byte [DISK_STATUS1],TIME_OUT ; ERROR
	STC
WQ_OK:
	RETn
;WQ_OK:	;CLC
;	RETn

;----------------------------------------
;	CHECK FIXED DISK STATUS 	:
;----------------------------------------
CHECK_STATUS:
	CALL	CHECK_ST		; CHECK THE STATUS BYTE
	JNZ	short CHECK_S1		; AN ERROR WAS FOUND
	TEST	AL,ST_ERROR		; WERE THERE ANY OTHER ERRORS
	JZ	short CHECK_S1		; NO ERROR REPORTED
	CALL	CHECK_ER		; ERROR REPORTED
CHECK_S1:
	CMP	byte [DISK_STATUS1],0 	; SET STATUS FOR CALLER
	RETn

;----------------------------------------
;	CHECK FIXED DISK STATUS BYTE	:
;----------------------------------------
CHECK_ST:
	;MOV	DX,HF_PORT+7		; GET THE STATUS
	mov	dx, [HF_PORT]
	add	dl, 7
	
	; 17/02/2016
	;(http://wiki.osdev.org/ATA_PIO_Mode)
	;"delay 400ns to allow drive to set new values of BSY and DRQ"
	IN	AL,DX
	;in	al, dx ; 100ns
	;in	al, dx ; 100ns
 	;in	al, dx ; 100ns
	NEWIODELAY ; 18/02/2016 (AWARD BIOS - 1999, 'CKST' in AHSDK.ASM)
	;
	MOV	[HF_STATUS],AL
	MOV	AH,0
	TEST	AL,ST_BUSY		; IF STILL BUSY
	JNZ	short CKST_EXIT		;  REPORT OK
	MOV	AH,WRITE_FAULT
	TEST	AL,ST_WRT_FLT		; CHECK FOR WRITE FAULT
	JNZ	short CKST_EXIT
	MOV	AH,NOT_RDY
	TEST	AL,ST_READY		; CHECK FOR NOT READY
	JZ	short CKST_EXIT
	MOV	AH,BAD_SEEK
	TEST	AL,ST_SEEK_COMPL	; CHECK FOR SEEK NOT COMPLETE
	JZ	short CKST_EXIT
	MOV	AH,DATA_CORRECTED
	TEST	AL,ST_CORRCTD		; CHECK FOR CORRECTED ECC
	JNZ	short CKST_EXIT
	MOV	AH,0
CKST_EXIT:
	MOV	[DISK_STATUS1],AH	; SET ERROR FLAG
	CMP	AH,DATA_CORRECTED	; KEEP GOING WITH DATA CORRECTED
	JZ	short CKST_EX1
	CMP	AH,0
CKST_EX1:
	RETn

;----------------------------------------
;	CHECK FIXED DISK ERROR REGISTER :
;----------------------------------------
CHECK_ER:
	;MOV	DX, HF_PORT+1		; GET THE ERROR REGISTER
	mov	dx, [HF_PORT]		;
	inc	dl
	IN	AL,DX
	MOV	[HF_ERROR],AL
	PUSH	eBX ; 21/02/2015
	MOV	eCX,8			; TEST ALL 8 BITS
CK1:	SHL	AL,1			; MOVE NEXT ERROR BIT TO CARRY
	JC	short CK2		; FOUND THE ERROR
	LOOP	CK1			; KEEP TRYING
CK2:	MOV	eBX, ERR_TBL		; COMPUTE ADDRESS OF
	ADD	eBX,eCX			; ERROR CODE
	;;MOV	AH,BYTE [CS:BX]		; GET ERROR CODE
	;mov	ah, [bx]
	mov	ah, [ebx] ; 21/02/2015	
CKEX:	MOV	[DISK_STATUS1],AH	; SAVE ERROR CODE
	POP	eBX
	CMP	AH,0
	RETn

;--------------------------------------------------------
; CHECK_DMA						:
;  -CHECK ES:BX AND # SECTORS TO MAKE SURE THAT IT WILL :
;   FIT WITHOUT SEGMENT OVERFLOW.			:
;  -ES:BX HAS BEEN REVISED TO THE FORMAT SSSS:000X	:
;  -OK IF # SECTORS < 80H (7FH IF LONG READ OR WRITE)	:
;  -OK IF # SECTORS = 80H (7FH) AND BX <= 00H (04H)	:
;  -ERROR OTHERWISE					:
;--------------------------------------------------------
CHECK_DMA:
	PUSH	AX			; SAVE REGISTERS
	MOV	AX,8000H		; AH = MAX # SECTORS AL = MAX OFFSET
        TEST    byte [CMD_BLOCK+6],ECC_MODE
	JZ	short CKD1
	MOV	AX,7F04H		; ECC IS 4 MORE BYTES
CKD1:	CMP	AH, [CMD_BLOCK+1] 	; NUMBER OF SECTORS
	JA	short CKDOK		; IT WILL FIT
	JB	short CKDERR		; TOO MANY
	CMP	AL,BL			; CHECK OFFSET ON MAX SECTORS
	JB	short CKDERR		; ERROR
CKDOK:	CLC				; CLEAR CARRY
	POP	AX
	RETn				; NORMAL RETURN
CKDERR: STC				; INDICATE ERROR
        MOV     byte [DISK_STATUS1],DMA_BOUNDARY
	POP	AX
	RETn

;----------------------------------------
;	SET UP ES:BX-> DISK PARMS	:
;----------------------------------------
					
; INPUT -> DL = 0 based drive number
; OUTPUT -> ES:BX = disk parameter table address

GET_VEC:
	;SUB	AX,AX			; GET DISK PARAMETER ADDRESS
	;MOV	ES,AX
	;TEST	DL,1
	;JZ	short GV_0
;	LES	BX,[HF1_TBL_VEC] 	; ES:BX -> DRIVE PARAMETERS
;	JMP	SHORT GV_EXIT
;GV_0:
;	LES	BX,[HF_TBL_VEC]		; ES:BX -> DRIVE PARAMETERS
;
	;xor	bh, bh
	xor	ebx, ebx
	mov	bl, dl
	;;02/01/2015
	;;shl	bl, 1			; port address offset
	;;mov	ax, [bx+hd_ports]	; Base port address (1F0h, 170h)
	;;shl	bl, 1			; dpt pointer offset
	shl	bl, 2	;;
	;add	bx, HF_TBL_VEC		; Disk parameter table pointer
	add	ebx, HF_TBL_VEC ; 21/02/2015
	;push	word [bx+2]		; dpt segment
	;pop	es
	;mov	bx, [bx]		; dpt offset
	mov	ebx, [ebx]		
;GV_EXIT:
	RETn

hdc1_int: ; 21/02/2015
;--- HARDWARE INT 76H -- ( IRQ LEVEL  14 ) ----------------------
;								:
;	FIXED DISK INTERRUPT ROUTINE				:
;								:
;----------------------------------------------------------------

; 22/12/2014
; IBM PC-XT Model 286 System BIOS Source Code - DISK.ASM (HD_INT)
;	 '11/15/85'
; AWARD BIOS 1999 (D1A0622) 
;	Source Code - ATORGS.ASM (INT_HDISK, INT_HDISK1)

;int_76h:
HD_INT:
	PUSH	AX
	PUSH	DS
	;CALL	DDS
	; 21/02/2015 (32 bit, 386 pm modification)
	mov	ax, KDATA
	mov 	ds, ax
	;
	;;MOV	@HF_INT_FLAG,0FFH	; ALL DONE
        ;mov     byte [CS:HF_INT_FLAG], 0FFh
	mov	byte [HF_INT_FLAG], 0FFh
	;
	push	dx
	mov	dx, HDC1_BASEPORT+7	; Status Register (1F7h)
					; Clear Controller
Clear_IRQ1415:				; (Award BIOS - 1999)
	in	al, dx			;
	pop	dx
	NEWIODELAY
	;
	MOV	AL,EOI			; NON-SPECIFIC END OF INTERRUPT
	OUT	INTB00,AL		; FOR CONTROLLER #2
	;JMP	$+2			; WAIT
	NEWIODELAY
	OUT	INTA00,AL		; FOR CONTROLLER #1
	POP	DS
	;STI				; RE-ENABLE INTERRUPTS
	;MOV	AX,9100H		; DEVICE POST
	;INT	15H			;  INTERRUPT
irq15_iret: ; 25/02/2015
	POP	AX
	IRETd				; RETURN FROM INTERRUPT

hdc2_int: ; 21/02/2015
;++++ HARDWARE INT 77H ++ ( IRQ LEVEL  15 ) +++++++++++++++++++++
;								:
;	FIXED DISK INTERRUPT ROUTINE				:
;								:
;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

;int_77h:
HD1_INT:
	PUSH	AX
	; Check if that is a spurious IRQ (from slave PIC)
	; 25/02/2015 (source: http://wiki.osdev.org/8259_PIC)
	mov	al, 0Bh  ; In-Service Register
	out	0A0h, al
        jmp short $+2
	jmp short $+2
	in	al, 0A0h
	and 	al, 80h ; bit 7 (is it real IRQ 15 or fake?)
	jz	short irq15_iret ; Fake (spurious)IRQ, do not send EOI)
	;
	PUSH	DS
	;CALL	DDS
	; 21/02/2015 (32 bit, 386 pm modification)
	mov	ax, KDATA
	mov 	ds, ax
	;
	;;MOV	@HF_INT_FLAG,0FFH	; ALL DONE
        ;or      byte [CS:HF_INT_FLAG],0C0h 
	or	byte [HF_INT_FLAG], 0C0h
	;
	push	dx
	mov	dx, HDC2_BASEPORT+7	; Status Register (177h)
					; Clear Controller (Award BIOS 1999)
	jmp	short Clear_IRQ1415


;%include 'diskdata.inc' ; 11/03/2015
;%include 'diskbss.inc' ; 11/03/2015


;////////////////////////////////////////////////////////////////////
;; END OF DISK I/O SYTEM ///
