;  read.S
;
;  Copyright 1999-2006 John Coffman
;  Copyright 2009-2011 Joachim Wiedorn
;  All rights reserved.
;
;  Licensed under the terms contained in the file 'COPYING'
;  in the source directory.
;

#define NEW_WRITE 1
;
; lba_read:      read using LBA
;
;  Enter with:
;       AL      actual count of blocks to transfer
;       DL      device (0x00=A:, 0x80=C:, 0x81=D:) and LINEAR/LBA32 flags
;       ES:BX   buffer pointer
;       DI:CX   LBA to read
;
;  Exit with:
;       No Error:  carry clear
;       CX      count of blocks read
;       ES:BX   unchanged
;       DX      unchanged
;       AH      error status if CF=1
;       DI      trashed
;

lba_read:       push    si              ;save some registers
#ifndef JRC_NOCOMPACT
                push    bx
                push    dx
                xor     ah,ah           ;convert count to word
                push    ax
#endif
                push    cx              ;gotta ask about 32-bit addressing 
                push    bx
#ifndef JRC_FLAGS_IN_DH
		mov     dh,dl           ;use BL for flag test
#endif
		and     dl,#DEV_MASK_asm    ;remove spurious flags (0x8F)
#ifndef JRC_MBR
		test    dh,#LBA32_FLAG
		jz	no_lba          ;linear will never use EDD calls
#endif
#ifndef JRC_NOCOMPACT
	        cmp     al,#127		;test for LINEAR transfer too big
		ja      no_lba          ; for LBA mode (127 is max)
                push    ax
#endif
                mov     bx,#0x55AA      ;magic number
                mov     ah,#0x41        ;function call
                int     0x13
#ifndef JRC_NOCOMPACT
                pop     ax
#endif
                jc      no_lba
                cmp     bx,#0xAA55      ;magic return
                jne     no_lba
                test    cl,#EDD_PACKET  ;packet calls supported?
                jz      no_lba


; LBA mode is to be used

lba_avail:
                pop     bx
                pop     cx

#ifndef JRC_NOCOMPACT
                pop     ax
                push    ax
#endif
#ifndef JRC_DS_EQ_SS
                push    ds              ;save DS
#endif
		push	dword #0		;  0L is pushed
                push    di              ;LBA hi word
                push    cx              ;    lo word
                push    es              ;ES:BX
                push    bx
#ifndef JRC_NOCOMPACT
                push    ax
#else
                push    #1		;count always 1
#endif
                push    #16		;size of parameter area  ;#
                         		;actually pushes a word
                mov     si,sp		;DS:SI is param block pointer
#ifndef JRC_DS_EQ_SS
                push    ss
                pop     ds              ;DS:SI points at param block
#endif
#ifndef JRC_NOCOMPACT
                mov     ax,#0x4200      ;read function -- must be AX
					; as AL has meaning on WRITE
                call    dsk_do_rw
#else
;;;		mov     ax,#0x4200      ;read function
		mov	ah,#0x42	;read only -- AL matters not
                int     0x13
#endif
                lea     sp,word ptr (si+16)      ;use lea so flags are not changed
#ifndef JRC_DS_EQ_SS
                pop     ds              ;restore DS
#endif
                jmp     lba_read_exit1



no_lba:
                pop     bx
                pop     cx


lba_small:                      ;must get the disk geometry
#ifndef JRC_NOCOMPACT
lba_more_small:
                push    bx
                push    di
                push    cx
                push    ax
#endif
                push    bx
                push    dx
                push    di
                push    cx

                push    es
                mov     ah,#8          ; DL is set to device
#ifndef JRC_NOCOMPACT
                call    dsk_do_int13
#else
                int     0x13
#endif
                pop     es
                jc      lba_geom_error

                push    cx
                shr     cl,#6		;;;;
                xchg    cl,ch           ;CX is max cylinder number
                mov     di,cx           ;DI saves it
                pop     cx

		shr	dx,#8
		xchg	ax,dx		;AX <- DX
		inc	ax		;AX is number of heads (256 allowed)

; compensate for Davide BIOS bug
		dec	cx		; 1..63 -> 0..62;  0->63
		and	cx,#0x003f	;CX is number of sectors
		inc	cx		; allow Sectors==0 to mean 64

                mul     cx		; kills DX
                xchg    ax,si           ;save in SI

                pop     ax              ;was CX
                pop     dx              ;was DI
                cmp     dx,si
                jae     lba_geom_error2  ;prevent division error
                div     si              ;AX is cyl, DX is head/sect
                cmp     ax,di
                ja      lba_geom_error2  ;cyl is too big

                shl     ah,#6		;;;;
                xchg    al,ah
                xchg    ax,dx
                div     cl              ;AH = sec-1, AL = head
#ifndef JRC_NOCOMPACT
                sub     cl,ah           ;CX = max count possible
                mov     si,cx           ;save in SI
#endif
                inc     ah
                add     dl,ah           ;form Cyl/Sec
                mov     cx,dx
                pop     dx              ;get device
                pop     bx
                xchg    al,dh           ;

#ifndef JRC_NOCOMPACT
                pop     ax              ;restore the count
                push    ax              ;keep in the stack
                cmp     ax,si           ;
                jb      lba_cntltmax
                mov     ax,si           ;smaller is in AX
lba_cntltmax:   push    ax
                mov     ah,#2           ;READ
                call    dsk_do_rw
#else
                mov     ax,#0x201       ;read, count of 1
                int     0x13
#endif
        ; carry is set or clear
#ifndef JRC_NOCOMPACT
                pop     bx              ;actual count read (was AX)
                pop     si              ;count remaining
                pop     cx
                pop     di
                jc      lba_read_exit_e
                add     cx,bx           ;update lba address
                adc     di,#0           ;the # was omitted in rev 3
                xchg    ax,bx
                pop     bx              ;buffer address
                add     bh,al           ;update ES:BX
                add     bh,al           ;LILO has already checked for seg update
                xchg    si,ax
                sub     ax,si           ;AX is remaining count after transfer
                jnz     lba_more_small
                         ; after the sub yields 0, the carry is clear
#endif
lba_read_exit1:	jmp	lba_read_exit

#ifndef JRC_NOCOMPACT

#ifndef LCF_READONLY

#if NEW_WRITE

dsk_do_rw:	or	ah,#0		; 0=read, 1=write, 2=read-only test
dsk_wrflag	equ	*-1		; byte data area is the immediate

#else
dsk_wrflag:     .byte   0               ; 0=read, 1=write, 2=read-only test

dsk_do_rw:
                seg     cs
                or	ah,dsk_wrflag
#endif

#else
#if DEBUG_NEW
dsk_wrflag:     .byte   0               ; 0=read, 1=write, 2=read-only test
#endif
dsk_do_rw:
#endif

dsk_do_int13:
                push    bp
                mov     bp,#5           ;number of tries
dsk_do_int13a:  pusha
                int     0x13
                jnc     dsk_io_exit
                dec     bp              ;does not affect the carry
                jz      dsk_io_exit
                xor     ax,ax           ;reset disk controllers
                int     0x13
                popa
                dec     bp
                jmp     dsk_do_int13a

dsk_io_exit:    mov     bp,sp           ;do not touch any flags
                lea     sp,(bp+16)      ;an ADD would touch flags
                pop     bp              ;do not touch any flags
                ret
#endif
lba_geom_error:
                pop     cx
                pop     di
                jmp     lba_g3
lba_geom_error2:
                mov     ah,#0x40         ;seek failure error code
lba_g3:         pop     dx
                pop     bx
#ifndef JRC_NOCOMPACT
                pop     cx              ;was AX
                pop     cx
                pop     di
lba_read_exit_e:
                pop     bx
#endif
                stc
lba_read_exit:
#ifndef JRC_NOCOMPACT
                pop     cx              ;return count in CX
                pop     dx
                pop     bx
#endif
                pop     si
#ifndef JRC_NORETURN
                ret
#endif
