Index: /trunk/XTIDE_Universal_BIOS/Inc/Controllers/XTCF.inc
===================================================================
--- /trunk/XTIDE_Universal_BIOS/Inc/Controllers/XTCF.inc	(revision 478)
+++ /trunk/XTIDE_Universal_BIOS/Inc/Controllers/XTCF.inc	(revision 479)
@@ -45,6 +45,8 @@
 ; 8-bit PIO transfers (port I/O) are used if Control Register is zero.
 ; Any other value means DMA transfers (using DMA channel 3).
-XTCF_8BIT_PIO_MODE					EQU		0
-XTCF_MEMORY_MAPPED_MODE				EQU		0A0h
+XTCF_8BIT_PIO_MODE						EQU		0
+XTCF_DMA_MODE							EQU		10h
+XTCF_MEMORY_MAPPED_MODE					EQU		0A0h
+RAISE_DRQ_AND_CLEAR_XTCF_XFER_COUNTER	EQU		40h
 
 
Index: /trunk/XTIDE_Universal_BIOS/Inc/DmaController.inc
===================================================================
--- /trunk/XTIDE_Universal_BIOS/Inc/DmaController.inc	(revision 478)
+++ /trunk/XTIDE_Universal_BIOS/Inc/DmaController.inc	(revision 479)
@@ -87,5 +87,5 @@
 
 
-; Status Registers
+; Status Registers (reading will clear Terminal Count flags)
 STATUS_REGISTER_DMA8_in			EQU		COMMAND_REGISTER_DMA8_out
 	FLG_CH1_HAS_REACHED_TERMINAL_COUNT		EQU		(1<<1)
Index: /trunk/XTIDE_Universal_BIOS/Src/Device/IDE/IdeDmaTransfer.asm
===================================================================
--- /trunk/XTIDE_Universal_BIOS/Src/Device/IDE/IdeDmaTransfer.asm	(revision 478)
+++ /trunk/XTIDE_Universal_BIOS/Src/Device/IDE/IdeDmaTransfer.asm	(revision 479)
@@ -21,6 +21,6 @@
 ; 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, 
+	.wTotalBytesXferred			resb	2	; 0-1, 
+	.wBytesLeftToXfer			resb	2	; 2-3, 0 = 65536
 	.bbbPhysicalAddress			resb	3	; 4-6, 
 								resb	1	; 7, IDEPACK.bDeviceControl
@@ -50,9 +50,8 @@
 	; Initialize DMAVARS
 	xor		cx, cx
-	mov		[bp+DMAVARS.wTotalWordsXferred], cx
+	mov		[bp+DMAVARS.wTotalBytesXferred], 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
+	mov		[bp+DMAVARS.wBytesLeftToXfer], cx
 
 	; Convert Segment:Offset type pointer to physical address
@@ -60,6 +59,6 @@
 	mov		cx, es
 %rep 4
-	shl	cx, 1
-	rcl	bx, 1
+	shl		cx, 1
+	rcl		bx, 1
 %endrep
 	add		cx, si
@@ -68,21 +67,25 @@
 	mov		[bp+DMAVARS.bbbPhysicalAddress+2], bl
 
-	; Calculate bytes for first page - 1
+	; Calculate bytes for first page
 	neg		cx	; Max number of bytes for first page, 0 = 65536
-	dec		cx
-	MIN_U	cx, [bp+DMAVARS.wBytesLeftToXferLessOne]
+	MIN_U	cx, [bp+DMAVARS.wBytesLeftToXfer]
 
 	; Are we reading or writing?
+	mov		bl, CHANNEL_3 | READ | AUTOINIT_DISABLE | ADDRESS_INCREMENT | DEMAND_MODE	; Assume write command
 	test	al, 16	; Bit 4 is cleared on all the read commands but set on 3 of the 4 write commands
-	jnz		SHORT WriteBlockToXTCF
+	jnz		SHORT TransferBlockToOrFromXTCF
 	cmp		al, COMMAND_WRITE_MULTIPLE
-	je		SHORT WriteBlockToXTCF
-	; Fall to ReadBlockFromXTCF
-
-
-;--------------------------------------------------------------------
-; ReadBlockFromXTCF
+	je		SHORT TransferBlockToOrFromXTCF
+
+	; Read command
+	mov		bl, CHANNEL_3 | WRITE | AUTOINIT_DISABLE | ADDRESS_INCREMENT | DEMAND_MODE
+	; Fall to TransferBlockToOrFromXTCF
+
+
+;--------------------------------------------------------------------
+; TransferBlockToOrFromXTCF
 ;	Parameters:
-;		CX:		Bytes in first page - 1
+;		BX:		Mode byte for DMA Mode Register
+;		CX:		Bytes in first page
 ;		DS:DI:	Ptr to DPT (in RAMVARS segment)
 ;		SS:BP:	Ptr to DMAVARS
@@ -96,5 +99,5 @@
 ;		AL, BX, DX
 ;--------------------------------------------------------------------
-ReadBlockFromXTCF:
+TransferBlockToOrFromXTCF:
 	; 8-bit DMA transfers must be done withing 64k physical page.
 	; We support maximum of 128 sectors (65536 bytes) per one INT 13h call
@@ -102,66 +105,56 @@
 
 	; Transfer first DMA page
-	mov		ah, CHANNEL_3 | WRITE | AUTOINIT_DISABLE | ADDRESS_INCREMENT | DEMAND_MODE
-	call	StartDMAtransferForXTCFwithDmaModeInAH
-	call	UpdateVariablesForSecondPageIfRequired
-	jc		SHORT ReturnNumberOfSectorsXferred		; Second page not needed
+	call	StartDMAtransferForXTCFwithDmaModeInBL
+	jcxz	.ReturnNumberOfSectorsXferred			; One page was enough (128 sectors)
+	mov		[bp+DMAVARS.wTotalBytesXferred], cx		; Store total BYTEs transferred so far
+
+	; Get bytes left to transfer for second DMA page
+	mov		ax, [bp+DMAVARS.wBytesLeftToXfer]
+	sub		ax, cx
+	jz		SHORT .ReturnNumberOfSectorsXferred		; Transfer was within 64k page
+
+	; Increment address
+	xchg	cx, ax
+	add		[bp+DMAVARS.bbbPhysicalAddress], ax
+	adc		[bp+DMAVARS.bbbPhysicalAddress+2], bh	; Never sets CF
 
 	; Transfer second DMA page if necessary (always less than 64k)
-	mov		ah, CHANNEL_3 | WRITE | AUTOINIT_DISABLE | ADDRESS_INCREMENT | DEMAND_MODE
-	call	StartDMAtransferForXTCFwithDmaModeInAH
-	; Fall to BothDmaPagesTransferred
-
-BothDmaPagesTransferred:
-	inc		cx			; Never overflows since second page always less than 64k
-	shr		cx, 1		; BYTEs to WORDs
-	add		[bp+DMAVARS.wTotalWordsXferred], cx
-ReturnNumberOfSectorsXferred:
+	call	StartDMAtransferForXTCFwithDmaModeInBL
+	add		[bp+DMAVARS.wTotalBytesXferred], cx
+
+.ReturnNumberOfSectorsXferred:
+	; Check errors
 	mov		bx, TIMEOUT_AND_STATUS_TO_WAIT(TIMEOUT_DRQ, FLG_STATUS_BSY)
 	call	IdeWait_PollStatusFlagInBLwithTimeoutInBH
 	jc		SHORT .ErrorInTransfer
-	mov		cx, [bp+DMAVARS.wTotalWordsXferred]
-	xchg	cl, ch		; WORDs to sectors
+
+	; Return number of sectors transferred
+	mov		cx, [bp+DMAVARS.wTotalBytesXferred]
+	jcxz	.FullPageOf128SectorsXferred
+%ifdef USE_186
+	shr		cx, 9		; BYTEs to sectors
+%else
+	xchg	cl, ch		; BYTEs to WORDs
+	shr		cx, 1		; WORDs to sectors
+%endif
+	clc
+	ret
+
+.FullPageOf128SectorsXferred:
+	mov		cx, 128
 	ret
 
 .ErrorInTransfer:
-	mov		cx, 0		; No way to know how many bytes got xferred
-	ret
-
-
-;--------------------------------------------------------------------
-; WriteBlockToXTCF
+	mov		cx, 0		; No way to know how many sectors got transferred
+	ret
+
+
+;--------------------------------------------------------------------
+; StartDMAtransferForXTCFwithDmaModeInBL
 ;	Parameters:
-;		CX:		Bytes in first page - 1
+;		BL:		Byte for DMA Mode Register
+;		CX:		Number of BYTEs to transfer
 ;		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
-;--------------------------------------------------------------------
-ALIGN JUMP_ALIGN
-WriteBlockToXTCF:
-	; Transfer first DMA page
-	mov		ah, CHANNEL_3 | READ | AUTOINIT_DISABLE | ADDRESS_INCREMENT | DEMAND_MODE
-	call	StartDMAtransferForXTCFwithDmaModeInAH
-	call	UpdateVariablesForSecondPageIfRequired
-	jc		SHORT ReturnNumberOfSectorsXferred		; Second page not needed
-
-	; Transfer second DMA page if necessary (always less than 64k)
-	mov		ah, CHANNEL_3 | READ | AUTOINIT_DISABLE | ADDRESS_INCREMENT | DEMAND_MODE
-	call	StartDMAtransferForXTCFwithDmaModeInAH
-	jmp		SHORT BothDmaPagesTransferred
-
-
-;--------------------------------------------------------------------
-; StartDMAtransferForXTCFwithDmaModeInAH
-;	Parameters:
-;		AH:		Byte for DMA Mode Register
-;		CX:		Number of BYTEs to transfer - 1
-;		DS:DI:	Ptr to DPT (in RAMVARS segment)
 ;	Returns:
 ;		Nothing
@@ -170,9 +163,6 @@
 ;--------------------------------------------------------------------
 ALIGN JUMP_ALIGN
-StartDMAtransferForXTCFwithDmaModeInAH:
-	push	cx
-
+StartDMAtransferForXTCFwithDmaModeInBL:
 	; Program 8-bit DMA Controller
-
 	; Disable Interrupts and DMA Channel 3 during DMA setup
 	cli										; Disable interrupts
@@ -181,5 +171,5 @@
 
 	; Set DMA Mode (read or write using channel 3)
-	mov		al, ah
+	mov		al, bl
 	out		MODE_REGISTER_DMA8_out, al
 
@@ -196,4 +186,5 @@
 	out		CLEAR_FLIPFLOP_DMA8_out, al		; Reset flip-flop to low byte
 	mov		ax, cx
+	dec		ax								; DMA controller is programmed for one byte less
 	out		BASE_AND_CURRENT_COUNT_REGISTER_DMA8_CH3_out, al	; Low byte
 	mov		al, ah
@@ -206,314 +197,21 @@
 
 
-	; 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.
-	add		cx, BYTE 1 + 15		; Number of BYTEs to xfer + 15 (bit 16 in CF)
-	rcr		cx, 1
-	eSHR_IM	cx, 3				; CX = Number of 16 byte blocks
+	; XT-CF transfers 16 bytes at a time. We need to manually
+	; start transfer for every block.
 	mov		dx, [di+DPT.wBasePort]
 	add		dl, XTCF_CONTROL_REGISTER
-
-.MoreToDo:						; at this point, cx must be >0
-	mov		al, 40h				; 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, 10h				; 
-	out		dx, al				; set back to DMA enabled status
-	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)
-;--------------------------------------------------------------------
 ALIGN JUMP_ALIGN
-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
-
-
-
-
-%if 0
-;--------------------------------------------------------------------
-ALIGN JUMP_ALIGN
-ReadBlockFromXTCF:
-;	Parameters:
-;		CX:		Block size in 512 byte sectors (1..64)
-;		DX:		IDE Data port address
-;		ES:DI:		Normalized ptr to buffer to receive data
-;	Returns:
-;		Nothing
-;	Corrupts registers:
-;		AX, BX, CX
-
-	; use config register to see what we're doing:
-	; < A0 = DMA via ch.3
-	; > A0 = mem-mapped IO (word-length)
-	; 
-	
-	or		dl, 0x1f	; XT-CF board control register address (base + 1fh)
-	in		al, dx		; get control register
-	cmp		al, 0xA0	; test al against 0xA0:
-	jae	.MemMapIO		; - use memory-mapped IO if >=A0h
-	or		al, al		; test al against 0 (quicker than cmp):
-	jz	.PortIO			; - use port-based IO (the default) if it was zero
-					; otherwise, 0 < al < A0h, so fall to DMA mode
-
-.DMAIO:
-	; work out how much we're transferring.  We can't cross a physical 64KB boundary
-	; but since the max transfer size is 64KB, we only ever need to do one or two DMA operations
-	
-	; first, normalise the pointer - we need ES to be a physical page address 
-	
-	mov		ax, es
-	mov		ch, cl			; max sectors is 128; also sectors << 8 = words, and we need cl...
-	mov		cl, 4			; ... for the rotate parameter
-	rol		ax, cl			; ax = es rol 4
-	mov		bx, ax			; bx = ax = es rol 4
-	and		al, 0xf0		; ax (15..4) now has es (11..0)
-	and		bx, 0x000f		; bx (3..0) now has es (15..12)
-	add		di, ax			; add offset portion of es (in ax) to di...
-	adc		bl, 0			; ... and if it overflowed, increment bl
-	mov		es, bx			; es now has physical segment address >> 12
-
-	; now check how much we can transfer without crossing a physical page boundary
-	mov		bx, di			; 
-	not		bx			; 65535 - di = number of bytes we could transfer -1 now in bx
-	xor		cl, cl			; zero cl; cx now has transfer size in words
-	shl		cx, 1			; words to bytes; CX has total byte count
-	dec		cx			; calling DMA with 0 implies 1 byte transferred (so max is 64k exactly)
-	cmp		bx, cx			; can we do it in one hit?
-	jae	.LastDMA
-
-	; at this point, the (bytes-1) for this transfer are in bx, total byte count -1 in cx
-	; and we need to do 2 DMA operations as the buffer straddles a physical 64k boundary
-	
-	sub		cx, bx			; cx has bytes for 2nd transfer (as (x-1)-(y-1) = x-y)
-	dec		cx			; cx has bytes-1 for 2nd transfer
-	xchg		bx, cx			; bx = bytes-1 for 2nd transfer; cx = bytes-1 for this transfer
-	mov		ah, 0x07		; request a read DMA transfer
-	call	DemandBasedTransferWithBytesInCX
-
-	; DMA 1 of 2 done - set up registers for second transfer
-	mov		cx, bx			; bytes-1 for the 2nd transfer back in cx
-	; 1st transfer is done, now for the second
-ALIGN JUMP_ALIGN
-.LastDMA:
-	; at this point, (bytes-1) for this transfer are in CX
-	mov		ah, 0x07		; request a read DMA transfer
-	call	DemandBasedTransferWithBytesInCX
-
-	; transfer is done, set ES back to a physical segment address
-	mov		ax, es			; 
-	mov		cl, 4			; 
-	ror		ax, cl			; ax = es ror 4.  Since ES was >> 12 (for DMA controller) so
-	mov		es, ax			; now it's back to normal format
-	
-	; pointer format restored - we're done
-	and		dl, 0xE0		; restore register values
-	ret
-
-
-;--------------------------------------------------------------------
-ALIGN JUMP_ALIGN
-WriteBlockToXTCF:
-	; use config register to see what we're doing:
-	; 0 = not set; use byte-length port-IO
-	; < A0 = DMA via ch.3
-	; > A0 = mem-mapped IO (word-length)
-	; 
-	
-	or		dl, 0x1f	; XT-CF board control register address (base + 1fh)
-	in		al, dx		; get control register
-	cmp		al, 0xA0	; test al against 0xA0:
-	jae	.MemMapIO		; - use memory-mapped IO if >=A0h
-	or		al, al		; test al against 0 (quicker than cmp):
-	jz	.PortIO			; - use port-based IO (the default) if it was zero
-					; otherwise, 0 < al < A0h, so fall to DMA mode
-
-.DMAIO:
-	; work out how much we're transferring.  We can't cross a physical 64KB boundary
-	; but since the max transfer size is 64KB, we only ever need to do one or two DMA operations
-
-	push		di			; save di...
-	mov		di, si			; ...and move si to di (for DMA routine)
-	
-	; first, normalise the pointer - we need ES to be a physical page address 
-	
-	mov		ax, es
-	mov		ch, cl			; max sectors is 64; also sectors << 8 = words, and we need cl...
-	mov		cl, 4			; ... for the rotate parameter
-	rol		ax, cl			; ax = es rol 4
-	mov		bx, ax			; bx = ax = es rol 4
-	and		al, 0xf0		; ax (15..4) now has es (11..0)
-	and		bx, 0x000f		; bx (3..0) now has es (15..12)
-	add		di, ax			; add offset portion of es (in ax) to si...
-	adc		bl, 0			; ... and if it overflowed, increment bl
-	mov		es, bx			; es now has physical segment address >> 12
-
-	; now check how much we can transfer without crossing a physical page boundary
-	mov		bx, di			; 
-	not		bx			; 65535 - di = number of bytes we could transfer -1 now in bx
-	xor		cl, cl			; zero cl; cx now has transfer size in words
-	shl		cx, 1			; words to bytes; CX has total byte count
-	dec		cx			; calling DMA with 0 implies 1 byte transferred (so max is 64k exactly)
-	cmp		bx, cx			; can we do it in one hit?
-	jae	.LastDMA
-
-	; at this point, the (bytes-1) for this transfer are in bx, total byte count -1 in cx
-	; and we need to do 2 DMA operations as the buffer straddles a physical 64k boundary
-	
-	sub		cx, bx			; cx has bytes for 2nd transfer (as (x-1)-(y-1) = x-y)
-	dec		cx			; cx has bytes-1 for 2nd transfer
-	xchg		bx, cx			; bx = bytes-1 for 2nd transfer; cx = bytes-1 for this transfer
-	mov		ah, 0x0b		; request a write DMA transfer
-	call	DemandBasedTransferWithBytesInCX
-
-	; DMA 1 of 2 done - set up registers for second transfer
-	mov		cx, bx			; bytes-1 for the 2nd transfer back in cx
-	; 1st transfer is done, now for the second
-ALIGN JUMP_ALIGN
-.LastDMA:
-	; at this point, (bytes-1) for this transfer are in CX
-	mov		ah, 0x0b		; request a write DMA transfer
-	call	DemandBasedTransferWithBytesInCX
-
-	; transfer is done, set ES back to a physical segment address
-	mov		ax, es			; 
-	mov		cl, 4			; 
-	ror		ax, cl			; ax = es ror 4.  Since ES was >> 12 (for DMA controller) so
-	mov		es, ax			; now it's back to normal format
-
-	mov		si, di			; move di (used by DMA routine) back to si
-	
-	; pointers updated - we're done
-	pop		di			; 
-	and		dl, 0xE0		; restore register values
-	ret
-
-
-; -------------------------------------------------------------------------------------------------------------
-; 
-; DemandBasedTransferWithBytesInCX
-; ================================
-; 
-; DMA Transfer function:
-; - AH = 0x07 for read from media - demand/inc/non-auto-init/write(to memory)/ch3
-; - AH = 0x0b for write to media  - demand/inc/non-auto-init/read(from memory)/ch3
-; - byte count -1 in CX
-; - XT-CF control register in DX
-; - physical segment address in ES *but* high four bits in low four bits (i.e. shr 12)
-; - buffer offset (from physical segment) in DI
-;
-; Note - cannot cross a physical segment boundary, but ES will be updated (maintaining the >>12
-;        format) if after the last byte has been transferred the pointer needs to be updated to
-;        the next physical segment.
-; 
-; Preserves:	BX, DX
-; Corrupts: 	AX, CX
-; Updates: 	ES, DI
-; 
-; -------------------------------------------------------------------------------------------------------------
-
-ALIGN JUMP_ALIGN
-DemandBasedTransferWithBytesInCX:
-	cli					; clear interrupts while we set up the actual DMA transfer
-	mov		al, 0x07		; mask (4) + channel (3)
-	out		0x0a, al		; send to DMA mask register
-	mov		al, ah			; retrieve the transfer mode passed in...
-	out		0x0b, al		; and send mode to DMA mode register
-	out		0x0c, al		; clear DMA byte-order flip-flop (write any value)
-	mov		ax, di			; di has buffer offset
-	out		0x06, al		; 
-	mov		al, ah			; 
-	out		0x06, al		; send offset to DMA controller address port for ch.3
-	mov		ax, es			; es has physical segment address >> 12
-	out		0x82, al		; send the relavent 4-bits to DMA controller page for ch.3
-	out		0x0c, al		; clear DMA byte-order flip-flop (write any value)
-	mov		ax, cx			; byte count to AX
-	out		0x07, al		; send low-byte of transfer size in bytes...
-	mov		al, ah			; mov high byte to low byte...
-	out		0x07, al		; ...and high byte to DMA controller count port for ch.3
-	mov		al, 0x03		; clear bit mask (0) + channel (3)
-	out		0x0a, al		; send to DMA mask register - enable the DMA!
-	sti					; enable interrutps; let the CPU see to anything outstanding
-
-	mov		ax, es			; update ES:DI (values have been loaded into DMA controller)
-	inc		cx			; CX back to actual bytes
-	add		di, cx			; add bytes to DI...
-	adc		ax, 0			; ...and if it overflowed, increment...
-	mov		es, ax			; ...ES
-
-	add		cx, 15			; XT-CFv2 will present data in 16-byte blocks, but byte count may not
-	shr		cx, 1			; be divisable by 16 due to boundary crossing.  So catch any < 16-byte
-	shr		cx, 1			; block by adding 15, then dividing bytes (in CX) by 16 to get the
-	shr		cx, 1			; total block requests.  The 8237 is programmed with the actual byte
-	shr		cx, 1			; count and will end the transfer by asserting TC when done.
-
-.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, 0x08		; get DMA status register
-	and		al, 0x08		; test DMA ch.3 TC bit
-	jz	.MoreToDo			; it wasn't set so get more bytes
-.EndDMA:
-	mov		al, 0x10		; 
-	out		dx, al			; set back to DMA enabled status
-	ret
-	
-%endif ; 0
-
-
-
+.TransferNextBlock:
+	mov		al, RAISE_DRQ_AND_CLEAR_XTCF_XFER_COUNTER
+	cli									; We want no ISR to read DMA Status Register before we do
+	out		dx, al						; Transfer up to 16 bytes to/from XT-CF card
+	; * Here XT-CF sets CPU to wait states during transfer *
+	in		al, STATUS_REGISTER_DMA8_in
+	sti
+	test	al, FLG_CH3_HAS_REACHED_TERMINAL_COUNT
+	jz		SHORT .TransferNextBlock	; All bytes transferred?
+
+	; Restore XT-CF to normal operation
+	mov		al, XTCF_DMA_MODE
+	out		dx, al
+	ret
