Index: /trunk/XTIDE_Universal_BIOS/Inc/DmaController.inc
===================================================================
--- /trunk/XTIDE_Universal_BIOS/Inc/DmaController.inc	(revision 477)
+++ /trunk/XTIDE_Universal_BIOS/Inc/DmaController.inc	(revision 477)
@@ -0,0 +1,202 @@
+; Project name	:	XTIDE Universal BIOS
+; Description	:	Equates for 8237 DMA Controllers.
+
+;
+; XTIDE Universal BIOS and Associated Tools 
+; Copyright (C) 2009-2010 by Tomi Tilli, 2011-2012 by XTIDE Universal BIOS Team.
+;
+; This program is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2 of the License, or
+; (at your option) any later version.
+; 
+; This program is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.		
+; Visit http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+;
+
+%ifndef DMA_CONTROLLER_INC
+%define DMA_CONTROLLER_INC
+
+; 8237 Master (8-bit) and Slave (16-bit) DMA Controller Ports
+
+; Page Registers
+PAGE_DMA8_CH_1		EQU		83h
+PAGE_DMA8_CH_2		EQU		81h
+PAGE_DMA8_CH_3		EQU		82h
+PAGE_DMA16_CH_5		EQU		8Bh		; AT+
+PAGE_DMA16_CH_6		EQU		89h		; AT+
+PAGE_DMA16_CH_7		EQU		8Ah		; AT+
+
+; Base and Current Address Registers
+BASE_AND_CURRENT_ADDRESS_REGISTER_DMA8_CH1_out	EQU		02h
+BASE_AND_CURRENT_ADDRESS_REGISTER_DMA8_CH2_out	EQU		04h
+BASE_AND_CURRENT_ADDRESS_REGISTER_DMA8_CH3_out	EQU		06h
+BASE_AND_CURRENT_ADDRESS_REGISTER_DMA16_CH5_out	EQU		0C4h	; AT+
+BASE_AND_CURRENT_ADDRESS_REGISTER_DMA16_CH6_out	EQU		0C8h	; AT+
+BASE_AND_CURRENT_ADDRESS_REGISTER_DMA16_CH7_out	EQU		0CCh	; AT+
+CURRENT_ADDRESS_REGISTER_DMA8_CH1_in			EQU		02h
+CURRENT_ADDRESS_REGISTER_DMA8_CH2_in			EQU		04h
+CURRENT_ADDRESS_REGISTER_DMA8_CH3_in			EQU		06h
+CURRENT_ADDRESS_REGISTER_DMA16_CH5_in			EQU		0C4h	; AT+
+CURRENT_ADDRESS_REGISTER_DMA16_CH6_in			EQU		0C8h	; AT+
+CURRENT_ADDRESS_REGISTER_DMA16_CH7_in			EQU		0CCh	; AT+
+
+; Base and Current Count Registers
+BASE_AND_CURRENT_COUNT_REGISTER_DMA8_CH1_out	EQU		03h
+BASE_AND_CURRENT_COUNT_REGISTER_DMA8_CH2_out	EQU		05h
+BASE_AND_CURRENT_COUNT_REGISTER_DMA8_CH3_out	EQU		07h
+BASE_AND_CURRENT_COUNT_REGISTER_DMA16_CH5_out	EQU		0C6h	; AT+
+BASE_AND_CURRENT_COUNT_REGISTER_DMA16_CH6_out	EQU		0CAh	; AT+
+BASE_AND_CURRENT_COUNT_REGISTER_DMA16_CH7_out	EQU		0CEh	; AT+
+CURRENT_COUNT_REGISTER_DMA8_CH1_in				EQU		03h
+CURRENT_COUNT_REGISTER_DMA8_CH2_in				EQU		05h
+CURRENT_COUNT_REGISTER_DMA8_CH3_in				EQU		07h
+CURRENT_COUNT_REGISTER_DMA16_CH5_in				EQU		0C6h	; AT+
+CURRENT_COUNT_REGISTER_DMA16_CH6_in				EQU		0CAh	; AT+
+CURRENT_COUNT_REGISTER_DMA16_CH7_in				EQU		0CEh	; AT+
+
+; Command Registers (Command Value used by PCs is 0)
+COMMAND_REGISTER_DMA8_out		EQU		08h
+COMMAND_REGISTER_DMA16_out		EQU		0D0h	; AT+
+	MEM_TO_MEM_XFERS_DISABLE	EQU		0
+	MEM_TO_MEM_XFERS_ENABLE		EQU		(1<<0)
+
+	CH0_ADDRESS_HOLD_DISABLE	EQU		0
+	CH0_ADDRESS_HOLD_ENABLE		EQU		(1<<1)	; When MEM_TO_MEM_XFERS_ENABLE
+
+	CONTROLLER_ENABLE			EQU		0
+	CONTROLLER_DISABLE			EQU		(1<<2)	; Instead of Controller Enable
+
+	NORMAL_TIMING				EQU		0
+	COMPRESSED_TIMING			EQU		(1<<3)	; Instead of Normal Timing when MEM_TO_MEM_XFERS_DISABLE
+
+	FIXED_PRIORITY				EQU		0
+	ROTATING_PRIORITY			EQU		(1<<4)	; Instead of Fixed Priority
+
+	LATE_WRITE_SELECTION		EQU		0
+	EXTENDED_WRITE_SELECTION	EQU		(1<<5)	; Instead of Late Write Selection
+
+	DREQ_SENSE_ACTIVE_HIGH		EQU		0
+	DREQ_SENSE_ACTIVE_LOW		EQU		(1<<6)	; Instead of DREQ Sense Active High
+
+	DACK_SENSE_ACTIVE_LOW		EQU		0
+	DACK_SENSE_ACTIVE_HIGH		EQU		(1<<7)	; Instead of DACK Sense Active Low
+
+
+; Status Registers
+STATUS_REGISTER_DMA8_in			EQU		COMMAND_REGISTER_DMA8_out
+	FLG_CH1_HAS_REACHED_TERMINAL_COUNT		EQU		(1<<1)
+	FLG_CH2_HAS_REACHED_TERMINAL_COUNT		EQU		(1<<2)
+	FLG_CH3_HAS_REACHED_TERMINAL_COUNT		EQU		(1<<3)
+	FLG_CH1_REQUEST							EQU		(1<<5)
+	FLG_CH2_REQUEST							EQU		(1<<6)
+	FLG_CH3_REQUEST							EQU		(1<<7)
+STATUS_REGISTER_DMA16_in		EQU		COMMAND_REGISTER_DMA16_out	; AT+
+	FLG_CH5_HAS_REACHED_TERMINAL_COUNT		EQU		(1<<1)
+	FLG_CH6_HAS_REACHED_TERMINAL_COUNT		EQU		(1<<2)
+	FLG_CH7_HAS_REACHED_TERMINAL_COUNT		EQU		(1<<3)
+	FLG_CH5_REQUEST							EQU		(1<<5)
+	FLG_CH6_REQUEST							EQU		(1<<6)
+	FLG_CH7_REQUEST							EQU		(1<<7)
+
+
+; Request Registers (Software DMA Request)
+REQUEST_REGISTER_DMA8_out		EQU		09h
+	FLG_SET_REQUEST		EQU		(1<<2)
+	CLEAR_CH1_REQUEST	EQU		CHANNEL_1
+	CLEAR_CH2_REQUEST	EQU		CHANNEL_2
+	CLEAR_CH3_REQUEST	EQU		CHANNEL_3
+	SET_CH1_REQUEST		EQU		(CHANNEL_1 | FLG_SET_REQUEST)
+	SET_CH2_REQUEST		EQU		(CHANNEL_2 | FLG_SET_REQUEST)
+	SET_CH3_REQUEST		EQU		(CHANNEL_3 | FLG_SET_REQUEST)
+REQUEST_REGISTER_DMA16_out		EQU		0D2h	; AT+
+	CLEAR_CH5_REQUEST	EQU		CLEAR_CH1_REQUEST
+	CLEAR_CH6_REQUEST	EQU		CLEAR_CH2_REQUEST
+	CLEAR_CH7_REQUEST	EQU		CLEAR_CH3_REQUEST
+	SET_CH5_REQUEST		EQU		SET_CH1_REQUEST
+	SET_CH6_REQUEST		EQU		SET_CH2_REQUEST
+	SET_CH7_REQUEST		EQU		SET_CH3_REQUEST
+
+
+; Mask Registers (setting a mask bit disables DMA channel)
+MASK_REGISTER_DMA8_out			EQU		0Ah
+	FLG_SET_MASK		EQU		FLG_SET_REQUEST
+	CLEAR_CH1_MASK_BIT	EQU		CLEAR_CH1_REQUEST
+	CLEAR_CH2_MASK_BIT	EQU		CLEAR_CH2_REQUEST
+	CLEAR_CH3_MASK_BIT	EQU		CLEAR_CH3_REQUEST
+	SET_CH1_MASK_BIT	EQU		SET_CH1_REQUEST
+	SET_CH2_MASK_BIT	EQU		SET_CH2_REQUEST
+	SET_CH3_MASK_BIT	EQU		SET_CH3_REQUEST
+MASK_REGISTER_DMA16_out			EQU		0D4h	; AT+
+	CLEAR_CH5_MASK_BIT	EQU		CLEAR_CH5_REQUEST
+	CLEAR_CH6_MASK_BIT	EQU		CLEAR_CH6_REQUEST
+	CLEAR_CH7_MASK_BIT	EQU		CLEAR_CH7_REQUEST
+	SET_CH5_MASK_BIT	EQU		SET_CH5_REQUEST
+	SET_CH6_MASK_BIT	EQU		SET_CH6_REQUEST
+	SET_CH7_MASK_BIT	EQU		SET_CH7_REQUEST
+
+
+; Mode Registers
+MODE_REGISTER_DMA8_out			EQU		0Bh
+	; Select channel number (bits 0...1)
+	CHANNEL_1			EQU		1
+	CHANNEL_2			EQU		2
+	CHANNEL_3			EQU		3
+MODE_REGISTER_DMA16_out			EQU		0D6h	; AT+
+	CHANNEL_5			EQU		CHANNEL_1
+	CHANNEL_6			EQU		CHANNEL_2
+	CHANNEL_7			EQU		CHANNEL_3
+	; Transfer type (bits 2...3)
+	VERIFY				EQU		(0<<2)
+	WRITE				EQU		(1<<2)	; To memory
+	READ				EQU		(2<<2)	; From memory
+	; Autoinitialization enable/disable (bit 4)
+	AUTOINIT_DISABLE	EQU		0
+	AUTOINIT_ENABLE		EQU		(1<<4)	; Instead of autoinitialization disable
+	; Address increment/decrement select (bit 5)
+	ADDRESS_INCREMENT	EQU		0
+	ADDRESS_DECREMENT	EQU		(1<<5)	; Instead of address increment
+	; Mode type selection (bits 6...7)
+	DEMAND_MODE			EQU		(0<<6)
+	SINGLE_MODE			EQU		(1<<6)
+	BLOCK_MODE			EQU		(2<<6)
+	CASCADE_MODE		EQU		(3<<6)
+
+
+; Clear Byte Flip-Flops (any byte resets low/high byte flip-flop to low)
+CLEAR_FLIPFLOP_DMA8_out			EQU		0Ch
+CLEAR_FLIPFLOP_DMA16_out		EQU		0D8h	; AT+
+
+
+; Temporary Registers
+TEMP_REGISTER_DMA8_in			EQU		0Dh
+TEMP_REGISTER_DMA16_in			EQU		0DAh	; AT+
+
+
+; Master Clear (any byte does the same as hardware reset)
+MASTER_CLEAR_DMA8_out			EQU		TEMP_REGISTER_DMA8_in
+MASTER_CLEAR_DMA16_out			EQU		TEMP_REGISTER_DMA16_in	; AT+
+
+
+; Clear all mask bits (any byte enables all DMA channels)
+CLEAR_ALL_MASK_BITS_DMA8_out	EQU		0Eh
+CLEAR_ALL_MASK_BITS_DMA16_out	EQU		0DCh	; AT+
+
+
+; Write All Mask Bits
+WRITE_ALL_MASK_BITS_DMA8_out	EQU		0Fh
+	ALL_MASK_BITS_SET_CH0		EQU		(1<<0)
+	ALL_MASK_BITS_SET_CH1		EQU		(1<<CHANNEL_1)
+	ALL_MASK_BITS_SET_CH2		EQU		(1<<CHANNEL_2)
+	ALL_MASK_BITS_SET_CH3		EQU		(1<<CHANNEL_3)
+WRITE_ALL_MASK_BITS_DMA16_out	EQU		0DEh	; AT+
+	ALL_MASK_BITS_SET_CH4		EQU		ALL_MASK_BITS_SET_CH0
+	ALL_MASK_BITS_SET_CH5		EQU		(1<<CHANNEL_5)
+	ALL_MASK_BITS_SET_CH6		EQU		(1<<CHANNEL_6)
+	ALL_MASK_BITS_SET_CH7		EQU		(1<<CHANNEL_7)
+
+
+%endif ; DMA_CONTROLLER_INC
Index: /trunk/XTIDE_Universal_BIOS/Inc/ModuleDependency.inc
===================================================================
--- /trunk/XTIDE_Universal_BIOS/Inc/ModuleDependency.inc	(revision 476)
+++ /trunk/XTIDE_Universal_BIOS/Inc/ModuleDependency.inc	(revision 477)
@@ -36,4 +36,5 @@
 ; Include module specific .INC files
 %ifdef MODULE_8BIT_IDE
+	%include "DmaController.inc"
 	%include "IDE_8bit.inc"			; For IDE 8-bit data port macros
 	%include "XTCF.inc"				; For Lo-tech XT-CF
Index: /trunk/XTIDE_Universal_BIOS/Src/Device/IDE/IdeDmaTransfer.asm
===================================================================
--- /trunk/XTIDE_Universal_BIOS/Src/Device/IDE/IdeDmaTransfer.asm	(revision 476)
+++ /trunk/XTIDE_Universal_BIOS/Src/Device/IDE/IdeDmaTransfer.asm	(revision 477)
@@ -21,4 +21,8 @@
 ; This struct must not be larger than IDEPACK without INTPACK.
 struc DMAVARS	; Must not be larger than 9 bytes! See IDEPACK in RamVars.inc.
+	.wTotalWordsXferred			resb	2	; 0-1, 
+	.wBytesLeftToXferLessOne	resb	2	; 2-3, 
+	.bbbPhysicalAddress			resb	3	; 4-6, 
+								resb	1	; 7, IDEPACK.bDeviceControl
 endstruc
 
@@ -32,5 +36,5 @@
 ;		AL:		IDE command that was used to start the transfer
 ;				(all PIO read and write commands including Identify Device)
-;		ES:SI:	Ptr to normalized data buffer
+;		ES:SI:	Ptr to data buffer (not normalized)
 ;		DS:DI:	Ptr to DPT (in RAMVARS segment)
 ;		SS:BP:	Ptr to IDEPACK
@@ -40,6 +44,239 @@
 ;		CF:		Cleared if success, Set if error
 ;	Corrupts registers:
-;		AL, BX, DX, SI, ES
+;		AL, BX, DX
 ;--------------------------------------------------------------------
 ALIGN JUMP_ALIGN
 IdeDmaTransfer_StartWithCommandInAL:
+	; Initialize DMAVARS
+	xor		cx, cx
+	mov		[bp+DMAVARS.wTotalWordsXferred], cx
+	mov		ch, [bp+IDEPACK.bSectorCount]	; CX = WORDs to transfer
+	shl		cx, 1							; WORDs to BYTEs, 0 = 65536
+	dec		cx
+	mov		[bp+DMAVARS.wBytesLeftToXferLessOne], cx
+
+	; Convert Segment:Offset type pointer to physical address
+	xor		bx, bx
+	mov		cx, es
+%rep 4
+	shl	cx, 1
+	rcl	bx, 1
+%endrep
+	add		cx, si
+	adc		bl, bh
+	mov		[bp+DMAVARS.bbbPhysicalAddress], cx
+	mov		[bp+DMAVARS.bbbPhysicalAddress+2], bl
+
+	; Calculate bytes for first page - 1
+	neg		cx	; Max number of bytes for first page, 0 = 65536
+	dec		cx
+	MIN_U	cx, [bp+DMAVARS.wBytesLeftToXferLessOne]
+
+	; Are we reading or writing?
+	test	al, 16	; Bit 4 is cleared on all the read commands but set on 3 of the 4 write commands
+	jnz		SHORT WriteBlockToXTCF
+	cmp		al, COMMAND_WRITE_MULTIPLE
+	je		SHORT WriteBlockToXTCF
+	; Fall to ReadBlockFromXTCF
+
+
+;--------------------------------------------------------------------
+; ReadBlockFromXTCF
+;	Parameters:
+;		CX:		Bytes in first page - 1
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to DMAVARS
+;	Returns:
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		AH:		BIOS Error code
+;		CX:		Number of successfully transferred sectors
+;		CF:		0 if transfer successful
+;				1 if any error
+;	Corrupts registers:
+;		AL, BX, DX
+;--------------------------------------------------------------------
+ReadBlockFromXTCF:
+	; 8-bit DMA transfers must be done withing 64k physical page.
+	; We support maximum of 128 sectors (65536 bytes) per one INT 13h call
+	; so we might need to separate transfer to 2 separate DMA operations.
+
+	; Transfer first DMA page
+	mov		ah, CHANNEL_3 | WRITE | AUTOINIT_DISABLE | ADDRESS_INCREMENT | DEMAND_MODE
+	call	StartDMAtransferForXTCFwithDmaModeInAH
+	jc		SHORT ReturnNumberOfSectorsXferred
+
+	; Transfer second DMA page if necessary (always less than 64k)
+	call	UpdateVariablesForSecondPageIfRequired
+	jc		SHORT SecondDmaPageIsNotRequired
+	mov		ah, CHANNEL_3 | WRITE | AUTOINIT_DISABLE | ADDRESS_INCREMENT | DEMAND_MODE
+	call	StartDMAtransferForXTCFwithDmaModeInAH
+	jc		SHORT ReturnNumberOfSectorsXferred
+	; Fall to BothDmaPagesTransferredSuccessfully
+
+BothDmaPagesTransferredSuccessfully:
+	inc		cx			; Never overflows since second page always less than 64k
+	shr		cx, 1		; BYTEs to WORDs
+	add		[bp+DMAVARS.wTotalWordsXferred], cx
+SecondDmaPageIsNotRequired:
+	xor		ah, ah
+ReturnNumberOfSectorsXferred:
+	mov		cx, [bp+DMAVARS.wTotalWordsXferred]
+	xchg	cl, ch		; WORDs to sectors
+	ret
+
+
+;--------------------------------------------------------------------
+; WriteBlockToXTCF
+;	Parameters:
+;		CX:		Bytes in first page - 1
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		SS:BP:	Ptr to DMAVARS
+;	Returns:
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;		AH:		BIOS Error code
+;		CX:		Number of successfully transferred sectors
+;		CF:		0 if transfer successful
+;				1 if any error
+;	Corrupts registers:
+;		AL, BX, DX
+;--------------------------------------------------------------------
+WriteBlockToXTCF:
+	; Transfer first DMA page
+	mov		ah, CHANNEL_3 | READ | AUTOINIT_DISABLE | ADDRESS_INCREMENT | DEMAND_MODE
+	call	StartDMAtransferForXTCFwithDmaModeInAH
+	jc		SHORT ReturnNumberOfSectorsXferred
+
+	; Transfer second DMA page if necessary (always less than 64k)
+	call	UpdateVariablesForSecondPageIfRequired
+	jc		SHORT SecondDmaPageIsNotRequired
+	mov		ah, CHANNEL_3 | READ | AUTOINIT_DISABLE | ADDRESS_INCREMENT | DEMAND_MODE
+	call	StartDMAtransferForXTCFwithDmaModeInAH
+	jc		SHORT ReturnNumberOfSectorsXferred
+	jmp		SHORT BothDmaPagesTransferredSuccessfully
+
+
+;--------------------------------------------------------------------
+; StartDMAtransferForXTCFwithDmaModeInAH
+;	Parameters:
+;		AH:		Byte for DMA Mode Register
+;		CX:		Number of BYTEs to transfer - 1
+;		DS:DI:	Ptr to DPT (in RAMVARS segment)
+;	Returns:
+;		AH:		BIOS Error code
+;		CF:		0 if transfer successful
+;				1 if any error
+;	Corrupts registers:
+;		AL, BX, DX
+;--------------------------------------------------------------------
+StartDMAtransferForXTCFwithDmaModeInAH:
+	push	cx
+
+	; Program 8-bit DMA Controller
+
+	; Disable Interrupts and DMA Channel 3 during DMA setup
+	cli										; Disable interrupts
+	mov		al, SET_CH3_MASK_BIT
+	out		MASK_REGISTER_DMA8_out, al		; Disable DMA Channel 3
+
+	; Set DMA Mode (read or write using channel 3)
+	mov		al, ah
+	out		MODE_REGISTER_DMA8_out, al
+
+	; Set address to DMA controller
+	out		CLEAR_FLIPFLOP_DMA8_out, al		; Reset flip-flop to low byte
+	mov		ax, [bp+DMAVARS.bbbPhysicalAddress]
+	out		BASE_AND_CURRENT_ADDRESS_REGISTER_DMA8_CH3_out, al	; Low byte
+	mov		al, ah
+	out		BASE_AND_CURRENT_ADDRESS_REGISTER_DMA8_CH3_out, al	; High byte
+	mov		al, [bp+DMAVARS.bbbPhysicalAddress+2]
+	out		PAGE_DMA8_CH_3, al
+
+	; Set number of bytes to transfer (DMA controller must be programmed number of bytes - 1)
+	out		CLEAR_FLIPFLOP_DMA8_out, al		; Reset flip-flop to low byte
+	mov		ax, cx
+	out		BASE_AND_CURRENT_COUNT_REGISTER_DMA8_CH3_out, al	; Low byte
+	mov		al, ah
+	out		BASE_AND_CURRENT_COUNT_REGISTER_DMA8_CH3_out, al	; High byte
+
+	; Enable DMA Channel 3
+	mov		al, CLEAR_CH3_MASK_BIT
+	out		MASK_REGISTER_DMA8_out, al		; Enable DMA Channel 3
+	sti										; Enable interrupts
+
+
+	; XT-CFv2 will present data in 16-byte blocks, but byte count may not
+	; be divisable by 16 due to boundary crossing.  So catch any < 16-byte
+	; block by adding 15, then dividing bytes (in CX) by 16 to get the
+	; total block requests.  The 8237 is programmed with the actual byte
+	; count and will end the transfer by asserting TC when done.
+	xor		ax, ax
+	add		cx, BYTE 1 + 15		; Number of BYTEs to xfer + 15
+	adc		al, ah
+	shr		ax, 1
+	rcr		cx, 1
+	eSHR_IM	cx, 3				; CX = Number of 16 byte blocks
+	mov		dx, [di+DPT.wBasePort]
+	add		dl, XTCF_CONTROL_REGISTER
+
+.MoreToDo:						; at this point, cx must be >0
+	mov		al, 0x40			; 0x40 = Raise DRQ and clear XT-CFv2 transfer counter
+.NextDemandBlock:
+	out		dx, al				; get up to 16 bytes from XT-CF card
+	loop	.NextDemandBlock	; decrement CX and loop if <> 0
+								; (Loop provides a wait-state between 16-byte blocks; do not unroll)
+
+.CleanUp:
+	; check the transfer is actually done - in case another DMA operation messed things up
+	inc		cx										; set up CX, in case we need to do an extra iteration
+	in		al, STATUS_REGISTER_DMA8_in				; get DMA status register
+	test	al, FLG_CH3_HAS_REACHED_TERMINAL_COUNT	; test DMA ch.3 TC bit
+	jz		SHORT .MoreToDo							; it wasn't set so get more bytes
+
+.EndDMA:
+	mov		al, 0x10			; 
+	out		dx, al				; set back to DMA enabled status
+
+	; Check IDE Status Register for errors
+	mov		bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_DRQ, FLG_STATUS_BSY)
+	call	IdeWait_PollStatusFlagInBLwithTimeoutInBH
+	pop		cx
+	ret
+
+
+;--------------------------------------------------------------------
+; UpdateVariablesForSecondPageIfRequired
+;	Parameters:
+;		CX:		Number of BYTEs in first page - 1
+;		SS:BP:	Ptr to DMAVARS
+;	Returns:
+;		CX:		Bytes left to transfer - 1 (if CF = 0)
+;		CF:		0 if second DMA transfer required
+;				1 if one DMA transfer was enough
+;	Corrupts registers:
+;		AX, (CX)
+;--------------------------------------------------------------------
+UpdateVariablesForSecondPageIfRequired:
+	inc		cx							; BYTEs in first page
+	jcxz	.FullPageXferred			; 0 = 65536
+
+	; Store total WORDs transferred so far
+	mov		ax, cx
+	shr		ax, 1						; BYTEs to WORDs
+	mov		[bp+DMAVARS.wTotalWordsXferred], ax
+
+	; Get bytes left to transfer for second DMA page
+	mov		ax, [bp+DMAVARS.wBytesLeftToXferLessOne]
+	sub		ax, cx
+	jb		SHORT .OnePageWasEnough
+
+	; Increment address
+	add		[bp+DMAVARS.bbbPhysicalAddress], cx
+	adc		BYTE [bp+DMAVARS.bbbPhysicalAddress+2], 0	; Never sets CF
+	xchg	cx, ax
+	ret
+
+.FullPageXferred:
+	mov		WORD [bp+DMAVARS.wTotalWordsXferred], 65536 / 2
+	stc
+.OnePageWasEnough:
+	ret
Index: /trunk/XTIDE_Universal_BIOS/Src/Device/Idepack.asm
===================================================================
--- /trunk/XTIDE_Universal_BIOS/Src/Device/Idepack.asm	(revision 476)
+++ /trunk/XTIDE_Universal_BIOS/Src/Device/Idepack.asm	(revision 477)
@@ -75,4 +75,15 @@
 
 	; Normalize data buffer pointer to ES:SI
+%ifdef MODULE_8BIT_IDE
+	cmp		BYTE [di+DPT_ATA.bDevice], DEVICE_8BIT_XTCF_DMA
+	jne		SHORT .NormalizeForSmallestPossibleOffset
+
+	; DMA transfers do not need to normalize pointer
+	; (it will be converted to physical address in IdeDmaTransfer.asm)
+	les		si, [es:si+DAP.dwMemoryAddress]
+	jmp		SHORT GetDeviceControlByteToIdepackAndStartTransfer
+%endif ; MODULE_8BIT_IDE
+
+.NormalizeForSmallestPossibleOffset:
 	mov		ax, [es:si+DAP.wOffset]
 	mov		cx, ax
Index: /trunk/XTIDE_Universal_BIOS/Src/Handlers/Int13h/AH1Eh_XTCF.asm
===================================================================
--- /trunk/XTIDE_Universal_BIOS/Src/Handlers/Int13h/AH1Eh_XTCF.asm	(revision 476)
+++ /trunk/XTIDE_Universal_BIOS/Src/Handlers/Int13h/AH1Eh_XTCF.asm	(revision 477)
@@ -112,5 +112,6 @@
 	mov		BYTE [di+DPT_ATA.bDevice], DEVICE_8BIT_XTCF_DMA
 	mov		al, [di+DPT_ATA.bBlockSize]
-	jmp		AH24h_SetBlockSize	; AH=24h limits block size if necessary
+	call	AH24h_SetBlockSize	; AH=24h limits block size if necessary
+	jmp		SHORT .Enable8bitPioMode
 
 .SetMemoryMappedMode:
@@ -120,4 +121,8 @@
 .Set8bitPioMode:
 	mov		BYTE [di+DPT_ATA.bDevice], DEVICE_8BIT_XTCF_PIO8
+	; Fall to .Enable8bitPioMode
+	
+	; We always need to enable 8-bit mode since 16-bit mode is restored
+	; when controller is reset (AH=0h or Dh)
 .Enable8bitPioMode:	
 	jmp		AH23h_Enable8bitPioMode
Index: /trunk/XTIDE_Universal_BIOS/Src/Handlers/Int13h/Tools/Prepare.asm
===================================================================
--- /trunk/XTIDE_Universal_BIOS/Src/Handlers/Int13h/Tools/Prepare.asm	(revision 476)
+++ /trunk/XTIDE_Universal_BIOS/Src/Handlers/Int13h/Tools/Prepare.asm	(revision 477)
@@ -94,23 +94,19 @@
 ALIGN JUMP_ALIGN
 Prepare_BufferToESSIforOldInt13hTransfer:
+	mov		si, [bp+IDEPACK.intpack+INTPACK.bx]	; Load offset
+
+%ifdef MODULE_8BIT_IDE
 	cmp		BYTE [di+DPT_ATA.bDevice], DEVICE_8BIT_XTCF_DMA
 	jne		SHORT .NormalizeForSmallestPossibleOffset
 
-	; Normalize segment for physical 64k pages
-	xor		bx, bx
-	mov		si, [bp+IDEPACK.intpack+INTPACK.es]	; Load segment
-%rep 4
-	shl		si, 1
-	rcl		bx, 1
-%endrep
-	add		si, [bp+IDEPACK.intpack+INTPACK.bx]
-	adc		bx, BYTE 0
-	mov		es, bx								; ES:SI now has physical address
+	; DMA transfers do not need to normalize pointer
+	; (it will be converted to physical address in IdeDmaTransfer.asm)
+	mov		es, [bp+IDEPACK.intpack+INTPACK.es]
 	jmp		SHORT Prepare_ByValidatingSectorsInALforOldInt13h
+%endif ; MODULE_8BIT_IDE
 
 	; Normalize segment for 16b pages
 .NormalizeForSmallestPossibleOffset:
-	mov		bx, [bp+IDEPACK.intpack+INTPACK.bx]	; Load offset
-	mov		si, bx
+	mov		bx, si
 	eSHR_IM	bx, 4								; Divide offset by 16
 	add		bx, [bp+IDEPACK.intpack+INTPACK.es]
Index: /trunk/XTIDE_Universal_BIOS/Src/Main.asm
===================================================================
--- /trunk/XTIDE_Universal_BIOS/Src/Main.asm	(revision 476)
+++ /trunk/XTIDE_Universal_BIOS/Src/Main.asm	(revision 477)
@@ -82,5 +82,5 @@
 		at	ROMVARS.wBootTimeout,	dw	BOOT_MENU_DEFAULT_TIMEOUT
 %endif
-	at	ROMVARS.bIdeCnt,		db	2						; Number of supported controllers
+	at	ROMVARS.bIdeCnt,		db	3						; Number of supported controllers
 	at	ROMVARS.bBootDrv,		db	80h						; Boot Menu default drive
 	at	ROMVARS.bMinFddCnt, 	db	0						; Do not force minimum number of floppy drives
@@ -104,7 +104,10 @@
 	at	ROMVARS.ideVars1+IDEVARS.drvParamsSlave+DRVPARAMS.wFlags,	dw	DISABLE_WRITE_CACHE | FLG_DRVPARAMS_BLOCKMODE | (TRANSLATEMODE_AUTO<<TRANSLATEMODE_FIELD_POSITION)
 
-	at	ROMVARS.ideVars2+IDEVARS.wBasePort,			dw	DEVICE_ATA_TERTIARY_PORT
-	at	ROMVARS.ideVars2+IDEVARS.wControlBlockPort,	dw	DEVICE_ATA_TERTIARY_PORTCTRL
-	at	ROMVARS.ideVars2+IDEVARS.bDevice,			db	DEVICE_16BIT_ATA
+	;at	ROMVARS.ideVars2+IDEVARS.wBasePort,			dw	DEVICE_ATA_TERTIARY_PORT
+	;at	ROMVARS.ideVars2+IDEVARS.wControlBlockPort,	dw	DEVICE_ATA_TERTIARY_PORTCTRL
+	;at	ROMVARS.ideVars2+IDEVARS.bDevice,			db	DEVICE_16BIT_ATA
+	at	ROMVARS.ideVars2+IDEVARS.wBasePort,			dw	0D800h
+	at	ROMVARS.ideVars2+IDEVARS.wControlBlockPort,	dw	0
+	at	ROMVARS.ideVars2+IDEVARS.bDevice,			db	DEVICE_8BIT_JRIDE_ISA
 	at	ROMVARS.ideVars2+IDEVARS.bIRQ,				db	0
 	at	ROMVARS.ideVars2+IDEVARS.drvParamsMaster+DRVPARAMS.wFlags,	dw	DISABLE_WRITE_CACHE | FLG_DRVPARAMS_BLOCKMODE | (TRANSLATEMODE_AUTO<<TRANSLATEMODE_FIELD_POSITION)
