; ****************************************************************************
; TRDOS386.ASM (TRDOS 386 Kernel) - v2.0.2 - diskio.s
; ----------------------------------------------------------------------------
; Last Update: 30/08/2020
; ----------------------------------------------------------------------------
; 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:
	clc ; 20/07/2020
	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)

; 27/05/2016 - TRDOS 386 (TRDOS v2.0)
; 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)
;	     ** 27/05/2016 - TRDOS 386 (TRDOS v2.0) **	
;            ** EBX = Buffer address for floppy disk parameters table **
;	  OUTPUT
;	    (ES:DI) POINTS TO DRIVE PARAMETER TABLE
; 	    *** TRDOS 386 note: floppy disk parameter table (16 bytes)
;	    will be returned to user in EBX, buffer address *** 27/05/2016 ***		
;					
;	    (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

; 30/08/2020 - TRDOS 386 v2

;;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

; 30/08/2020
; 29/08/2020
; 01/06/2016
; 28/05/2016
; 27/05/2016 - TRDOS 386 (TRDOS v.2.0)
;-------------------------------------------------------------------------------
; DISK_PARMS	(AH = 08H)	
;	READ DRIVE PARAMETERS.
;
; ON ENTRY:	DI : DRIVE #
;		; 27/05/2016
;		EBX = Buffer Address for floppy disk parameters table (16 bytes)
;
; 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 #
;	     ** 27/05/2016 - TRDOS 386 (TRDOS v2.0) **	
;            ** EBX = Buffer address for floppy disk parameters table **
;		;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
     ;  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      NON_DRV
	inc     dl
	and     ah, ah
	jz      short STO_DL
	inc     dl
STO_DL:
	; 30/08/2020
	cmp	dx, di
	jna	NON_DRV
	;
	;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
	ja	NON_DRV1 ; 29/08/2020
	;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
	;
	; 28/05/2016
	; 27/05/2016
	; return floppy disk parameters table to user
	; in user's buffer, which is pointed by EBX
	;
	push	edi
	mov	edi, [ebp+4]  		; ebx (input), user's buffer address
	; 29/08/2020
	or	edi, edi
	jz	short no_copy_fdpt
	;
	movzx	eax, al
        mov	[ebp+4], eax   ; ebx	; drive type (for floppy drives)
	; 01/06/2016 (INT 33h, disk type return for floppy disks, in BL)
	mov	[user_buffer], eax	; 01/06/2016 (overwrite ebx return value)
	;(INT 33h, Function 08h will replace user's buffer addr with disk type!)
	;
	mov	esi, ebx 		; floppy disk parameter table (16 bytes)
	mov	ecx, 16 ; 16 bytes
        call    transfer_to_user_buffer ; trdosk6.s (16/05/2016)
no_copy_fdpt:
	pop	edi	
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

	; 30/08/2020
	call	XLAT_OLD
	;mov	ah, NOT_RDY ; drive not ready
	mov	ah, INIT_FAIL ; DRIVE PARAMETER ACTIVITY FAILED 
	stc	; cf -> 1, ah = 'drive not ready' error code
	retn		

;-----	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 

; 30/08/2020

;-------------------------------------------------------------------------------
; 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
	
	; 30/08/2020
	call	XLAT_OLD
	sub	eax, eax
	stc	; cf = 1 -> drive not ready, ah = 0 (disk type = 0)
	retn

;-------------------------------------------------------------------------------
; 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
	IRETd				; RETURN FROM INTERRUPT

;-------------------------------------------------------------------------------
; DSKETTE_SETUP
;	THIS ROUTINE DOES A PRELIMINARY CHECK TO SEE WHAT TYPE OF
;	DISKETTE DRIVES ARE ATTACH TO THE SYSTEM.
;-------------------------------------------------------------------------------

; 29/05/2016 - TRDOS 386 (TRDOS v2.0)

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
	clc	; 29/05/2016
	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
	clc ; 20/07/2020
	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

; 30/08/2020 - TRDOS 386 v2

;--- 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					       :	
;	     ; 27/05/2016 - TRDOS 386 (TRDOS v2.0)						       :	 	
;	     EBX = Buffer address for fixed disk parameters table (32 bytes)   :
;	   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       :
;								:
;----------------------------------------------------------------

; 29/05/2016 - TRDOS 386 (TRDOS v2.0)

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
	clc 	; 29/05/2016
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	:
;----------------------------------------

; 30/08/2020
; 29/08/2020
; 15/01/2017
; 14/01/2017
; 07/01/2017
; 02/01/2017
; 01/06/2016
; 16/05/2016, 27/05/2016, 28/05/2016, 29/05/2016
; 29/04/2016 - TRDOS 386 (TRDOS v2.0)
int33h:  ; DISK I/O
	; 29/05/2016
	and	byte [esp+8], 11111110b  ; clear carry bit of eflags register
	; 16/05/2016
	push	ds
	push	ebx ; user's buffer address (virtual)
	mov	bx, KDATA ; System (Kernel's) data segment
	mov	ds, bx

	;;15/01/2017
	; 14/01/2017
	; 02/01/2017
	;;mov	byte [intflg], 33h	; disk io interrupt 
	;pop	ebx
	;mov	[user_buffer], ebx		

	pop	dword [user_buffer] ; 01/06/2016

	mov	byte [scount], 0 ; sector count for transfer
	cmp	ah, 03h ; chs write
	ja	short int33h_2
	je	short int33h_0
	cmp	ah, 02h ; chs read
	jb	short int33h_5
	jmp	short int33h_4
int33h_0:
	; transfer user's buffer content to sector buffer
	push	ecx
	movzx	ecx, al
int33h_1:
	push	esi
	mov	esi, [user_buffer]
	; esi = user's buffer address (virtual, ebx)
	push	edi
	push	es
	push	eax
	mov	ax, KDATA
	mov	es, ax
	mov	edi, Cluster_Buffer
	shl	ecx, 9 ; * 512
	call	transfer_from_user_buffer
	pop	eax
	pop	es
	pop	edi
	pop	esi
	pop	ecx
	jnc	short int33h_5
	mov	ebx, [user_buffer] ; 01/06/2016
	pop	ds

	;;15/01/2017
	; 02/01/2017
	;cli
	;;mov	byte [ss:intflg], 0 ; 07/01/2017
	;
	; (*) 29/05/2016
	; (*) retf 4 ; skip eflags on stack

	; 29/05/2016 -set carry flag on stack-
	; [esp] = EIP
	; [esp+4] = CS
	; [esp+8] = E-FLAGS
	or	byte [esp+8], 1  ; set carry bit of eflags register
	; [esp+12] = ESP (user)
	; [esp+16] = SS (User)
	mov	eax, 0FFh ; Unknown error !?
	;iretd
	jmp	short int33h_7  ; 07/01/2017	

	; (*) 29/05/2016 - 'ref 4' intruction causes to stack fault
	; (OUTER-PRIVILEGE-LEVEL)
	; INTEL 80386 PROGRAMMER'S REFERENCE MANUAL 1986
	; // RETF instruction:
	;
	; IF OperandMode=32 THEN
 	;    Load CS:EIP from stack;
 	;    Set CS RPL to CPL;
 	;    Increment eSP by 8 plus the immediate offset if it exists;
 	;    Load SS:eSP from stack;
 	; ELSE (* OperandMode=16 *)
 	;    Load CS:IP from stack;
 	;    Set CS RPL to CPL;
 	;    Increment eSP by 4 plus the immediate offset if it exists;
	;    Load SS:eSP from stack;
 	; FI;
	;
	; //

int33h_2:
	cmp	ah, 05h ; format track
	ja	short int33h_3
	jb	short int33h_5
	push	ecx
	mov	ecx, 1
	jmp	short int33h_1
int33h_3:
	cmp	ah, 1Ch ; LBA write
	ja	short int33h_5
	je	short int33h_0
	cmp	ah, 1Bh ; LBA read
	je	short int33h_4
	; 29/08/2020
	cmp	ah, 08h ; get disk parameters
	;jne	short int33h_5
	je	short int33h_10
	cmp	ah, 15h	; read DASD type (get disk size)
	jne	short int33h_5
int33h_10:
	; 01/06/2016
	mov	ebx, [user_buffer] ; user's buffer address
	jmp	short int33h_6
int33h_4:
	mov	byte [scount], al ; <= 128 sectors
int33h_5:
	mov	ebx, Cluster_Buffer ; max. 65536 bytes
				    ; buf. addr: 70000h	
	;mov	byte [ClusterBuffer_Valid], 0
int33h_6:
	pop	ds
	pushfd
	push 	cs
	call 	DISK_IO
	mov	ebx, [CS:user_buffer] ; 01/06/2016
	jc	short int33h_9
	;
	cmp	byte [CS:scount], 0
	jna	short int33h_7
	;
	; transfer sector buffer content to user's buffer
	push	es
	push	ds
	push	eax
	mov	ax, KDATA
	mov	ds, ax
	mov	es, ax
	push	ecx
	push	esi
	push	edi
	movzx	ecx, byte [scount]
	shl	ecx, 9 ; * 512 bytes
	mov	edi, ebx ; user's buffer address
	mov	esi, Cluster_Buffer
	call	transfer_to_user_buffer
	pop	edi
	pop	esi
	pop	ecx
	pop	eax
	pop	ds
	pop	es
	jc	short int33h_8
int33h_7:
	cli
	;;15/01/2017
	;;mov	byte [ss:intflg], 0 ; 07/01/2017
	; cf = 0  ; use eflags which is in stack
	iretd	
int33h_8:
	mov	eax, 0FFh ; Unknown error !?
int33h_9:
	; cf = 1

	; (*) 29/05/2016	
	; (*) retf 4 ; skip eflags on stack
	; Note: This 'retf 4' was wrong, -it was causing
	;       to stack errors in ring 3-
	;	POP sequence of 'retf 4' is as
	;       "eip, cs, eflags, esp, ss, +4 bytes" 
        ;       it is not as "eip, cs, +4 bytes, esp, ss" ! 

	; 29/05/2016 -set carry flag on stack-
	or	byte [esp+8], 1  ; set carry bit of eflags register
	;iretd
	jmp	short int33h_7 ; 07/01/2017

; 30/08/2020
; 09/12/2017
; 29/05/2016
; 27/05/2016 - TRDOS 386 (TRDOS v2.0)

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) ; 83h ; 30/08/2020 
	;JA	short RET_2
	jna	short _A0
	; 29/05/2016
	push	ds
	push	eax ; 30/08/2020 (ax --> eax)
	mov	ax, KDATA
	mov	ds, ax
	pop	eax ; 
        mov     ah, 0AAh        ; Hard disk drive not ready !
				; (Programmer's guide to AMIBIOS, 1992)
	mov     byte [DISK_STATUS1], ah
	pop	ds
	jmp	short RET_2
_A0:
	; 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
int33h_bad_cmd:
	; 16/05/2016
	; 30/01/2015
	; 29/05/2016
	push	ds
	push	ax
	mov	ax, KDATA
	mov	ds, ax
	pop	ax
	mov	ah, BAD_CMD
	mov     [DISK_STATUS1], ah ; BAD_CMD  ; COMMAND ERROR
        ;jmp	short RET_2
RET_2:
	; (*) 29/05/2016
	; (*) retf 4
	or	byte [esp+8], 1 ; set carry bit of eflags register
	iretd
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
	; (*) 29/05/2016
	; (*) retf 4
	cmp	ah, 1
	jc	short _A5 
	or	byte [esp+8], 1 ; set carry bit of eflags register
_A5:
	iretd

; 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
        movzx	eax, ax ; 09/12/2017
	;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

; 30/08/2020

;----------------------------------------
;	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
	movzx	eax, dl ; 28/08/2020
	CALL	GET_VEC 		; GET DISK PARAMETERS ADDRESS
	
	; 28/08/2020 - TRDOS 386 v2
	test	byte [ebx+20], 40h	; LBA bit (bit 6)
	jnz	short RDT3 ; LBA disk (may be > 8GB)

	;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
	; 28/08/2020
	;sub	al, al
RDT4:
	sub	eax, eax ; 28/08/2020
	;
	MOV	AH,03H			; INDICATE FIXED DISK
	; 30/08/2020 (clc is not needed here)
	;and	byte [esp+8], 0FEh ; clear carry bit of eflags register
RDT2:	
	POP	eBX			; RESTORE REGISTERS
	;POP	ES
	POP	DS
	; (*) CLC			; CLEAR CARRY
	;RETf	2
	; (*) 29/05/2016
	; (*) retf 4
	; 30/08/2020 (clc is not needed here)
	;and	byte [esp+8], 0FEh ; clear carry bit of eflags register
	iretd

RDT3:	; 28/08/2020
	; (use the result of INT 13h, function 48h as disk size)
	; eax = al = zero based hard disk number
	; 29/08/2020
	;add	al, 2 ; hd0 = physical disk drive 2
	shl	al, 2 ; * 4
RDT5:
	;add	eax, drv.size
	add	eax, drv.size+8 ; 29/08/2020
	mov	dx, [eax]   ; low word of disk size
	mov	cx, [eax+2] ; high word of disk size
	;sub	eax, eax
	jmp	short RDT4		

RDT_NOT_PRESENT:
	; 30/08/2020
	mov	byte [DISK_STATUS1], NOT_RDY ; DRIVE NOT READY

	;SUB	AX,AX			; DRIVE NOT PRESENT RETURN
	sub	eax, eax ; 30/08/2020
	MOV	CX,AX			; ZERO BLOCK COUNT
	MOV	DX,AX
	; 30/08/2020
	or	byte [esp+16], 1 ; set carry bit of eflags register
		; cf = 1 -> ah = 0, drive not ready, disk type = 0
	JMP	short RDT2

; 28/05/2016
; 27/05/2016 - TRDOS 386 (TRDOS v2.0)

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

GET_PARM_N:
	; ebx = user's buffer address for parameters table
;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	; 27/05/2016
	;
	SUB	DL,80H
	;CMP	DL,MAX_FILE		; TEST WITHIN RANGE
	;JAE	short G4 ; 29/08/2020 - BugFix
	; 30/08/2020
	cmp	dl, [HF_NUM] ; is hard disk index < hard disk count ?	
	jae	short G4     ; no, error ! drive not ready !	
	;
	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 
	;mov	di, bx			; HDPT offset

	; 29/08/2020
	cmp	dword [esp], 0
	ja	short G7 ; ebx > 0

	; if EBX (user's buffer address) = 0, do not copy DPT
	pop	ebx
	jmp	short G5
G7:
	; 27/05/2016
	; return fixed disk parameters table to user
	; in user's buffer, which is pointed by EBX
	;
	xchg	edi, [esp]		; ebx (input)-> edi, edi -> [esp]
	push	esi
	mov	esi, ebx		; hard disk parameter table (32 bytes)	
	mov	ebx, edi		; ebx = user's buffer address
	push	ecx
	push	eax
	mov	ecx, 32 ; 32 bytes
	call	transfer_to_user_buffer ; trdosk6.s (16/05/2016)
	pop	eax
	pop	ecx
	pop	esi
	pop	edi
	jnc	short G5
	; 29/05/2016 (*)
	mov	eax, 0FFh ; unknown error !
G6:
	or	byte [esp+16], 1 ; set carry bit of eflags register
G5:
	; 27/05/2016
	;POP	eBX			; RESTORE REGISTERS
	POP	ES
	POP	DS
	;RETf	2
	; (*) 29/05/2016
	; (*) retf 4
	; (*) or byte [esp+8], 1 ; set carry bit of eflags register
	iretd
G4:
	MOV     byte [DISK_STATUS1],INIT_FAIL ; OPERATION FAILED
	;mov	ah, NOT_DRY ; 30/08/2020 - 'drive not ready' error code
	MOV	AH,INIT_FAIL
	SUB	AL,AL
	;SUB	DX,DX
	; 30/08/2020
	mov	dl, [HF_NUM] ; disk count
	sub	dh, dh
	SUB	CX,CX
	; 29/05/2016 (*)
	;STC				; SET ERROR FLAG
	;JMP	short G5
	; 29/08/2020 - BugFix
	pop	ebx
	jmp	short G6

;----------------------------------------
;	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 ///
