Tvůrce webu je i pro tebe! Postav třeba web. Bez grafika. Bez kodéra. Hned.
wz

IO_DSK.ASM

Ovladač disku


; ============================================================================
;
;                            MicroDOS - Disk device
;
; ============================================================================

; ------------- BIOS Parameter Block, BPB

struc		BPB

BPB_sector:	resw	1		; 0: bytes per sector
BPB_cluster:	resb	1		; 2: sectors per cluster (0FFh=unknown)
BPB_res:	resw	1		; 3: number of reserved sectors (BOOT)
BPB_fat:	resb	1		; 5: number of FATs
BPB_root:	resw	1		; 6: number of ROOT entries
BPB_total:	resw	1		; 8: total sectors
BPB_media:	resb	1		; 0Ah: media descriptor (0=unknown)
					;	see Media ID byte
BPB_fatsec:	resw	1		; 0Bh: sectors per FAT
BPB_trksec:	resw	1		; 0Dh: sectors per track
BPB_heads:	resw	1		; 0Fh: number of heads

endstruc

BPB_SIZE	equ	BPB_size	; 11h = 17 bytes

; ------------- Media ID byte

MEDIAID_320K	EQU	0ffh		; floppy 320K, double-sided, 8 sectors
MEDIAID_160K	EQU	0feh		; floppy 160K, single-sided, 8 sectors
MEDIAID_360K	EQU	0fdh		; floppy 360K, double-sided, 9 sectors
MEDIAID_180K	EQU	0fch		; floppy 180K, single-sided, 9 sectors
MEDIAID_1M2	EQU	0f9h		; floppy 1.2M, double-sided, 15 sectors
MEDIAID_720K	EQU	MEDIAID_1M2	; floppy 720K, double-sided, 9 sectors
MEDIAID_HD	EQU	0f8h		; hard disk
MEDIAID_OTHER	EQU	0f0h		; other media
MEDIAID_1M44	EQU	MEDIAID_OTHER	; floppy 1.44M, double-sided, 18 sect.

; ------------- BIOS disk error codes

BIOS_WRITE	EQU	0cch		; write fault
BIOS_READY	EQU	80h		; device not ready (timeout)
BIOS_SEEK	EQU	40h		; seek failure
BIOS_CONTROL	EQU	20h		; controller failed
BIOS_CRC	EQU	10h		; CRC failure
BIOS_DMA	EQU	8		; DMA overrun
BIOS_CHANGE	EQU	6		; ivalid disk change
BIOS_SECTOR	EQU	4		; required sector not found
BIOS_PROT	EQU	3		; write-protect violation
BIOS_ADDRESS	EQU	2		; bad address mark
BIOS_COMMAND	EQU	1		; bad command
BIOS_GENERAL	EQU	0		; unknown error

; ------------- Device driver error codes

ERR_PROT	EQU	0	; write-protect violation
ERR_UNIT	EQU	1	; unknown unit
ERR_READY	EQU	2	; device not ready
ERR_COMMAND	EQU	3	; unknown command
ERR_CRC		EQU	4	; CRC failure
ERR_LENGTH	EQU	5	; bad drive request structure length
ERR_SEEK	EQU	6	; seek failure
ERR_MEDIA	EQU	7	; unknown media
ERR_SECTOR	EQU	8	; sector not found
ERR_PAPER	EQU	9	; printer out of paper
ERR_WRITE	EQU	10	; write fault
ERR_READ	EQU	11	; read fault
ERR_GENERAL	EQU	12	; general failure
ERR_CHANGE	EQU	15	; ivalid disk change

; ----------------------------------------------------------------------------
;                    Change phantom disk (only floppy disk)
; ----------------------------------------------------------------------------
; INPUT:	AL = required disk (0=A: or 1=B:)
; ----------------------------------------------------------------------------

; ------------- Check, if there is need to change disk

SetPhantom:	cmp	al,2		; is it hard disk?
		jae	SetPhantom9	; it is hard disk
		test	byte [cs:DiskFlags],B0 ; use phantom disk?
		jz	SetPhantom9	; don't use phantom disk

; ------------- Push registers

		push	ax		; push AX
		push	dx		; push DX
		push	ds		; push DS

; ------------- Check if phantom disk has been changed

		mov	ah,al		; AH <- required disk
		xor	dx,dx		; DX <- 0
		mov	ds,dx		; DS <- 0
		xchg	ah,[CurPhantom]	; AH <- get old phantom disk status
		cmp	al,ah		; has been phantom disk changed?
		je	SetPhantom8	; phantom disk has not been changed

; ------------- Display prompt text

		add	al,"A"		; AL <- ASCII name of disk 
		mov	[cs:PhantTextA],al ; store phantom disk name
		mov	dx,PhantText	; DX <- message to change disk
		call	DispText	; display message

; ------------- Flush keyboard input buffer

		mov	ax,[41Ch]	; AX <- write pointer to buffer
		mov	[41Ah],ax	; read pointer from bufferu

; ------------- Wait for key input		

		mov	ah,0		; AH <- 0 function code
		int	16h		; read character from keyboard

; ------------- Pop registers

SetPhantom8:	pop	ds		; pop DS
		pop	dx		; pop DX
		pop	ax		; pop AX
SetPhantom9:	ret

; ----------------------------------------------------------------------------
;            Prepare disk time and time pointer (only floppy disk)
; ----------------------------------------------------------------------------
; INPUT:	AL = drive number (0=A: or 1=B:)
; OUTPUT:	CX:DX = current time
;		BX = pointer to last access time
; ----------------------------------------------------------------------------

; ------------- Prepare pointer to last access time (-> BX)

GetDiskTime:	xor	bx,bx		; BX <- 0
		mov	bl,al		; BL <- drive number
		shl	bx,1		; drive number * 2
		shl	bx,1		; drive number * 4
		add	bx,DiskParAccess ; BX <- pointer to last acces time

; ------------- Load system time (-> CX:DX)

		call	GetTimer	; load system timer
		ret

; ----------------------------------------------------------------------------
;         Test time of access to removable disk (without changeline)
; ----------------------------------------------------------------------------
; INPUT:	AL = drive number (0=A: or 1=B:)
; OUTPUT:	CY = medium has not been changed (else unknown state)
; ----------------------------------------------------------------------------

; ------------- Push registers

TestDiskTime:	push	bx		; push BX
		push	cx		; push CX
		push	dx		; push DX

; ------------- Prepare disk time (-> CX:DX) and time pointer (-> BX)

		call	GetDiskTime	; prepare time and pointer

; ------------- Time interval

		sub	dx,[cs:bx] 	; time LOW
		sbb	cx,[cs:bx+2] 	; time HIGH

; ------------- Check time interval

		clc			; flag - unknown media state
		jnz	TestDiskTime2	; it is too long interval
		cmp	dx,byte 2*18	; check 2 seconds interval

; ------------- Pop registers

TestDiskTime2:	pop	dx		; pop DX
		pop	cx		; pop CX
		pop	bx		; pop BX
		ret

; ----------------------------------------------------------------------------
;          Set time of access to removable disk (without changeline)
; ----------------------------------------------------------------------------
; INPUT:	AL = logical drive number (0=A:, 1=B:,...)
; ----------------------------------------------------------------------------

; ------------- Check if it is valid disk

SetDiskTime:	cmp	al,2		; is it hard disk?
		jae	SetDiskTime8	; it is hard disk
		
; ------------- Push registers

		push	bx		; push BX
		push	cx		; push CX
		push	dx		; push DX

; ------------- Check if this drive supports changeline

		xor	bx,bx		; BX <- 0
		mov	bl,al		; BL <- drive number
		test	byte [cs:bx+DiskParFlags],B0 ; supports changeline?
		jnz	SetDiskTime6	; disk supports changeline

; ------------- Prepare disk time (-> CX:DX) and time pointer (-> BX)

		call	GetDiskTime	; prepare time and pointer

; ------------- Store new time of disk access

		mov	[cs:bx],dx	; push time LOW
		mov	[cs:bx+2],cx	; push time HIGH

; ------------- Pop registers

SetDiskTime6:	pop	dx		; pop DX
		pop	cx		; pop CX
		pop	bx		; pop BX
SetDiskTime8:	ret

; ----------------------------------------------------------------------------
;                           Test disk change
; ----------------------------------------------------------------------------
; INPUT:	AL = logical drive number (0=A:, 1=B:,...)
; OUTPUT:       CY = medium has not been changed (else unknown state)
; ----------------------------------------------------------------------------

; ------------- Push registers

DiskChange:	push	ax		; push AX
		push	dx		; push DX

; ------------- Check if it is fixed disk (it cannot be changed)

		cmp	al,2		; is it fixed disk?
		jae	DiskChange6	; medium has not been changed

; ------------- Check if changeline is supported

		mov	ah,0		; AX = drive number
		xchg	ax,bx		; BX <- drive number
		test	byte [cs:bx+DiskParFlags],B0 ; changeline supported?
		xchg	ax,bx		; AX <- drive number
		jnz	DiskChange4	; changeline is supported

; ------------- Changeline not supported - test last access time

		call	TestDiskTime	; check last access time
		jmp	short DiskChange8 ; CY = medium has not been changed

; ------------- Test changeline state

DiskChange4:	xchg	ax,dx		; DL <- disk number
		mov	ah,22		; AH <- function code
		call	Int13		; test changeline state
		jnc	DiskChange6	; no error, disk has not been changed
		cmp	ah,6		; change flag?
		je	DiskChange8	; disk has been changed
DiskChange6:	stc			; flag - medium has not been changed

; ------------- Pop registers

DiskChange8:	pop	dx		; pop DX
		pop	ax		; pop AX
		ret

; ----------------------------------------------------------------------------
;                           Current disk reset
; ----------------------------------------------------------------------------

; ------------- Push registers

DiskReset:	push	ax		; push AX
		push	dx		; push DX

; ------------- Disk reset

		mov	ah,0		; AH <- function code
		mov	dl,[cs:DiskDrive] ; DL <- disk
		call	Int13		; disk reset

; ------------- Pop registers

		pop	dx		; pop DX
		pop	ax		; pop AX
		ret

; ----------------------------------------------------------------------------
;             Transfer LBA address to CHS address (for current drive)
; ----------------------------------------------------------------------------
; INPUT:	DX = absolute sector
;		CS:SI = disk parameter table BPB
; OUTPUT:	CL = bit 0 - 5: sector number (1 to 63)
;		     bit 6 - 7: cylinder (bits 8 to 9)
;		CH = cylinder (bits 0 to 7)
;		DH = head number (0 to 255)
;		DL = disk number
; CONDITIONS:	sectors per track: max. 63
;		heads per cylinder: max. 256
;		cylinders: max. 1024
; ----------------------------------------------------------------------------

; ------------- Push registers

LBAtoCHS:	push	ax		; push AX
		push	bx		; push BX

; ------------- Prepare number of sectors per cylinder (-> AX)

		push	dx		; push DX (absolute sector)
		mov	ax,[cs:si+BPB_trksec] ; AX <- sectors per track
		mov	bx,ax		; BX <- sectors per track
		mul	word [cs:si+BPB_heads] ; AX <- sectors per cylinder
		xchg	ax,cx		; CX <- sectors per cylinder
		pop	ax		; pop AX (absolute sector)

; ------------- Calculate cylinder number (->AX) and sector in cylinder (->DX)

		xor	dx,dx		; DX <- 0
		div	cx		; AX <- cylinder, DX <- sector in cyl.

; ------------- Prepare cylinder number (-> CX)

		xchg	al,ah		; AH <- cylinder LOW, AL <- cyl. HIGH
		ror	al,1
		ror	al,1		; AL <- bits 8 - 9 to position 6 - 7
		and	al,B7+B6	; mask bits 6 and 7 of cylinder HIGH
		xchg	ax,cx		; CX <- cylinder
		
; ------------- Calculate head (-> DH) and sector (-> CL)

		xchg	ax,dx		; AX <- sector in cylinder
		div	bl 		; AL <- head, AH <- sector
		inc	ah		; AH <- sector + 1
		or	cl,ah		; CL <- cylinder HIGH + sector
		mov	dh,al		; DH <- head number

; ------------- Pop registers

		pop	bx		; pop BX
		pop	ax		; pop AX

; ------------- Disk number (-> DL)

		mov	dl,[cs:DiskDrive] ; DL <- disk
		ret

; ----------------------------------------------------------------------------
;    Low-level read/write/verify data from/to disk (with repeat on error)
; ----------------------------------------------------------------------------
; INPUT:	AH = function code 2=read, 3=write
;		DX = starting sector
;		CX = number of sectors (minimal 1)
;               ES:BX = transfer buffer
; OUTPUT:	CY = error
;		AH = DOS error code (valid if CY, else undefined)
;		DX = new sector
;		CX = number of remaining sectors (0 if NC)
;		ES:BX = new transfer buffer (normalized)
; DESTROYS:	AL
; ----------------------------------------------------------------------------

; ------------- Push registers

ReadWriteLow:	push	bp		; push BP

; ------------- Prepare error counter

ReadWriteLow0:	mov	bp,2		; BP <- number of repetition

; ------------- Next try on error

ReadWriteLow1:	push	ax		; push AX
		push	bx		; push BX
		push	cx		; push CX
		push	dx		; push DX
		push	si		; push SI

; ------------- Prepare disk table (-> SI)

		mov	si,[cs:DiskParBPBCurr] ; get BPB table

; ------------- Limit number of sectors to 127 (due to some BIOSes)

		cmp	cx,127		; max. number of sectors
		jbe	ReadWriteLow2	; number of sectors is OK
		mov	cx,127		; limit number of sectors
ReadWriteLow2:	mov	al,cl		; AL <- number of sectors

; ------------- Translate LBA address to CHS address

		call	LBAtoCHS	; translate to CHS address

; ------------- Prepare number of sectors in one operation (-> AL)

		push	bx		; push BX
		mov	bl,cl		; BL <- sector number
		and	bl,3Fh		; mask sector number (1 to 63)
		dec	bx		; BL = sector number (0 to 62)
		mov	bh,[cs:si+BPB_trksec] ; BH <- sectors per track
		sub	bh,bl		; BH <- sectors to end of track
		cmp	al,bh		; test number of sectors
		jbe	ReadWriteLow4	; number of sectors is OK
		mov	al,bh		; AL <- limit number of sectors
ReadWriteLow4:	pop	bx		; pop BX

; ------------- Do operation

		push	ax		; push AX (AL=number of sectors)
		call	Int13		; transfer data
		xchg	ax,bx		; BH <- error
		pop	ax		; pop AX, number of required sectors
		mov	ah,bh		; AH <- error code

; ------------- Pop registers (AL = sectors, AH = error, CY = error)

		pop	si		; pop SI
		pop	dx		; pop DX
		pop	cx		; pop CX
		pop	bx		; pop BX

; ------------- Repeate on error

		jnc	ReadWriteLow6	; operation OK
		dec	bp		; error counter
		jz	ReadWriteLow9	; no other attempt (CY is set)

; ------------- Reset disk and try again

		call	DiskReset	; disk reset
		pop	ax		; pop AX (function code)
		jmp	short ReadWriteLow1 ; next attempt

; ------------- Shift registers

ReadWriteLow6:	mov	ah,0		; AX = number of sectors

		add	dx,ax		; shift starting sector LOW
		sub	cx,ax		; decrease remaining sectors

		push	dx		; push DX
		push	si		; push SI

		mov	si,SECTORSIZE	; SI <- size of sector
		mul	si		; * number of bytes per sector
		add	ax,bx		; DX:AX <- shift offset
		adc	dx,byte 0	; overflow
		mov	bp,16		; BP <- 16 divisor
		div	bp		; AX <- offset HIGH
		mov	bx,dx		; BX <- offset LOW
		mov	dx,es		; DX <- segment
		add	ax,dx		; AX <- new segment
		mov	es,ax		; ES <- new segment

		pop	si		; pop SI
		pop	dx		; pop DX

		pop	ax		; pop AX

; ------------- Next group of sectors (and set NC)

		or	cx,cx		; all sectors are transfered?
		jnz	ReadWriteLow0	; transfer next group of sectors
		push	ax		; push AX

; ------------- Prepare registers

ReadWriteLow9:	pop	bp		; destroy AX
		pop	bp		; pop BP
		ret

; ----------------------------------------------------------------------------
;               read/write data from/to disk (with DMA check)
; ----------------------------------------------------------------------------
; INPUT:	AH = function code 2=read, 3=write
;		AL = logical drive number (0=A:, 1=B:,...)
;		CX = number of sectors
;		DX = starting sector number
;               ES:BX = transfer buffer
; OUTPUT:	CY = error
;		AH = BIOS error code
;		CX = number of remaining sectors (0 if NC)
;		DX = new sector
;		ES:BX = new transfer buffer
; ----------------------------------------------------------------------------

; ------------- Check zero number of sectors (set NC)

ReadWrite:	or	cx,cx		; remain any sectors?
		jnz	ReadWrite1	; remain any sectors

; ------------- Update system timer for removable media without changeline

		call	SetDiskTime	; set last disk access time
		clc			; clear error flag
		ret			; end of transfer

; ------------- Push registers

ReadWrite1:	push	si		; push SI
		push	di		; push DI
		push	bp		; push BP
		push	ds		; push DS
		push	cx		; push CX (number of sectors)
		push	ax		; push AX (function code)

		mov	bp,cx		; BP <- number of sectors

; ------------- Normalize buffer (-> ES(AX):BX)

		push	dx		; push DX
		
		mov	ax,bx		; AX <- offset of buffer
		and	bx,byte 0fh	; normalize offset
		mov	cl,4		; CL <- 4 number of shifts
		shr	ax,cl		; AX <- offset as segment
		mov	dx,es		; DX <- destination segment
		add	ax,dx		; AX <- normalized segment
		mov	es,ax		; ES <- normalized segment

; ------------- Limit number of sectors to next 64 KB boundary (-> BP)

		shl	ax,cl		; AX * 16 (=segment as offset)
		add	ax,bx		; AX <- absolute offset in 64 KB
		xor	dx,dx		; DX <- 0 offset HIGH
		neg	ax		; AX <- complement to 64 KB boundary
		sbb	dx,byte -1	; DX <- 1 if AX=0, else DX <- 0
		mov	cx,SECTORSIZE	; SI <- size of sector
		div	cx		; AX <- calculate number of sectors
		cmp	ax,bp		; remain less sectors?
		jb	ReadWrite2	; remain less sectors
		xchg	ax,bp		; AX <- limit number of sectors
ReadWrite2:     xchg	ax,bp		; BP <- number of sectors

		pop	dx		; pop DX

; ------------- No whole sector - use temporary buffer

		pop	ax		; pop AX (AH = function code)
		push	ax		; push AX
		or	bp,bp		; remains any sector?
		jnz	ReadWrite5	; remains any sector
		mov	bp,1		; required 1 sector

; ------------- On "write" transfer sector to temporary buffer

		cmp	ah,3		; write?
		jne	ReadWrite3	; it is not write

		push	es		; push ES

		mov	cx,SECTORSIZE/2	; CX <- sector size in words
		push	es		; push ES (segment of buffer)
		pop	ds		; DS <- segment of buffer
		mov	si,bx		; SI <- offset of buffer
		push	cs		; push CS
		pop	es		; ES <- segment of temporary buffer
		mov	di,DiskBuff	; DI <- offset of temporary buffer
		cld			; direction up
		rep	movsw		; transfer sector

		pop	es		; pop ES

; ------------- Transfer data of one sector

ReadWrite3:	push	bx		; push BX
		push	es		; push ES

		mov	di,bp		; transfer 1 sector
		push	cs		; push CS
		pop	es		; ES <- segment of temporary buffer
		mov	bx,DiskBuff	; BX <- offset of temporary buffer
		call	ReadWriteLow	; read/write 1 sector

		pop	es		; pop ES
		pop	bx		; pop BX
		jc	ReadWrite7	; error (AH=error code)

; ------------- On "read" transfer sector from temporary buffer

		pop	ax		; pop AX (AH = function code)
		push	ax		; push AX

		cmp	ah,2		; read ?
		jne	ReadWrite4	; it is not read

		mov	cx,SECTORSIZE/2	; CX <- sector size in words
		mov	di,bx		; DI <- offset of buffer
		push	cs		; push CS
		pop	ds		; DS <- segment of temporary buffer
		mov	si,DiskBuff	; SI <- offset of temporary buffer
		cld			; direction up
		rep	movsw		; transfer sector

; ------------- New transfer address (-> ES:BX, here AH = function code)

ReadWrite4:	add	bx,SECTORSIZE	; shift offset of buffer
		jmp	short ReadWrite6

; ------------- Transfer group of sectors

ReadWrite5:	mov	cx,bp		; DI <- number of sectors to transfer
		call	ReadWriteLow	; transfer sectors
		pushf			; push flags
		sub	bp,cx		; BP <- number of transfered sectors
		popf			; pop flags
		jc	ReadWrite7	; error	

; ------------- Return function code

		pop	ax		; pop AX (AH = function code)
		push	ax		; push AX

; ------------- Change number of sectors (here AH = function code)

ReadWrite6:	pop	ax		; pop AX
		pop	cx		; pop CX
		sub	cx,bp		; change number of sectors
		push	cx		; push CX
		push	ax		; push AX		
		clc			; operation OK

; ------------- Pop registers (CY=error, AH=function code or error code)

ReadWrite7:	pop	bp		; destroy AX
ReadWrite8:	pop	cx		; pop CX
		pop	ds		; pop DS
		pop	bp		; pop BP
		pop	di		; pop DI
		pop	si		; pop SI
		jc	ReadWrite9	; error
		jmp	ReadWrite	; next group of sectors
ReadWrite9:	ret

; ----------------------------------------------------------------------------
;                     Init default BPB disk parameters
; ----------------------------------------------------------------------------
; INPUT:	CS:SI = BPB disk parameters
; ----------------------------------------------------------------------------

; ------------- Push registers

DefDiskPar:	push	ds		; push DS

; ------------- Prepare registers

		push	cs		; push CS
		pop	ds		; DS <- data segment

; ------------- Init parameters

		mov	word [si+BPB_sector],SECTORSIZE ; sector size
		mov	byte [si+BPB_cluster],0ffh ; sectors per cluster
		mov	word [si+BPB_res],1 ; reserved sectors (BOOT)
		mov	byte [si+BPB_fat],2 ; number of FATs
		mov	word [si+BPB_root],64 ; number of ROOT entries
		mov	word [si+BPB_total],8*40 ; total sectors
		mov	byte [si+BPB_media],0 ; media descriptor
		mov	word [si+BPB_fatsec],2 ; sectors per FAT
		mov	byte [si+BPB_trksec],8 ; sectors per track
		mov	word [si+BPB_heads],1 ; number of heads

; ------------- Pop registers

		pop	ds		; pop DS
		ret

; ----------------------------------------------------------------------------
;                    Load disk parameters of current disk
; ----------------------------------------------------------------------------
; INPUT:	AL = logical drive number (0=A:, 1=B:,...)
; ----------------------------------------------------------------------------

; ------------- Push registers

LoadDiskPar:	call	PushAll		; push all registers

; ------------- Prepare DS

		push	cs		; push CS
		pop	ds		; DS <- data segment

; ------------- Read BOOT sector

		mov	ah,2		; AH <- 2 function code for reading
		mov	bx,DiskBuff	; BX <- disk buffer
		mov	cx,1		; CX <- 1 number of sectors
		xor	dx,dx		; DX <- 0 starting sector
		push	cs		; push CS
		pop	es		; ES <- data segment
		call	ReadWrite	; read BOOT sector
		jc	LoadDiskPar8	; error

; ------------- Check if it is valid BOOT sector

		cmp	word [DiskBuff+512-2],0aa55h ; check BOOT identifier
		jne	LoadDiskPar8	; invalid BOOT sector
		mov	si,DiskBuff+11	; BPB of BOOT sector
		cmp	word [si+BPB_sector],SECTORSIZE ; check sector size
		jne	LoadDiskPar8	; invalid sector size

; ------------- Load parameters from BOOT sector

		push	cs		; push CS
		pop	es		; ES <- data segment
		mov	di,[DiskParBPBCurr] ; DI <- current disk table
		mov	cx,BPB_SIZE	; CX <- size of BPB table
		cld			; set direction up
		rep	movsb		; store BPB table

; ------------- Pop registers

LoadDiskPar8:	call	PopAll		; pop all registers
		ret

; ----------------------------------------------------------------------------
;                 Init disk parameters of current disk
; ----------------------------------------------------------------------------
; INPUT:	AL = logical drive number (0=A:, 1=B:,...)
; ----------------------------------------------------------------------------

; ------------- Push registers

InitDiskPar:	push	ax		; push AX
		push	bx		; push BX
		push	cx		; push CX
		push	dx		; push DX
		push	si		; push SI

; ------------- Prepare pointer to disk parameters (-> SI)

		mov	si,[cs:DiskParBPBCurr] ; SI <- pointer to table

; ------------- Check if it is hard drive

		mov	dl,[cs:DiskDrive] ; DL <- disk drive
		or	dl,dl		; is it hard drive?
		jns	InitDiskPar4	; it is not hard drive

; ------------- Check if fixed disk parameters are initialized

		cmp	byte [cs:si+BPB_media],0 ; is table initialized?
		jne	InitDiskPar9	; table is already initialized

; ------------- Init default BPB disk parameters

		call	DefDiskPar	; inti default BPB disk parameters

; ------------- Load fixed disk parameters

		mov	ah,8		; AH <- 8 function code
		call	Int131		; load fixed disk parameters
		jc	InitDiskPar9	; error

; ------------- Check number of hard drives

		or	dl,dl		; is any hard disk?
		jz	InitDiskPar9	; no hard disk

; ------------- Set media type

		mov	byte [cs:si+BPB_media],MEDIAID_HD ; hard disk

; ------------- Set number of sectors per track

		mov	al,cl		; AL <- maximum sector number
		and	ax,byte 3Fh	; mask sector number
		mov	[cs:si+BPB_trksec],ax ; number of sectors per track
		push	ax		; push AX (sectors per track)

; ------------- Set number of heads

		mov	al,dh		; AL <- maximum head number
		inc	ax		; AX <- number of heads
		mov	[cs:si+BPB_heads],ax ; number of heads

; ------------- Prepare number of sectors per cylinder

		pop	dx		; pop DX (sectors per track)
		mul	dx		; prepare sectors per cylindex
		xchg	ax,dx		; DX <- sectors per cylinder

; ------------- Prepare number of cylinders

		xchg	ax,cx		; AX <- cylinders and sectors
		xchg	al,ah		; AX <- cylinders
		rol	ah,1		; rotate 1 bit of cylinder HIGH
		rol	ah,1		; rotate 1 bit of cylinder HIGH
		and	ah,3		; mask high 2 bits of cylinders
		inc	ax		; AX <- number of cylinders

; ------------- Prepare total number of sectors

		mul	dx		; AX <- total number of sectors
		or	dx,dx		; overflow number of sectors?
		jz	InitDiskPar2	; number of sectors is OK
		mov	ax,0ffffh	; limit number of sectors
InitDiskPar2:	mov	[cs:si+BPB_total],ax ; set total number of sectors
		jmp	short InitDiskPar6

; ------------- Check if floppy disk has been changed

InitDiskPar4:	call	DiskChange	; disk changed?
		jc	InitDiskPar9	; disk has not been changed

; ------------- Load disk parameters

InitDiskPar6:	call	LoadDiskPar	; load disk parameters

; ------------- Pop registers

InitDiskPar9:	pop	si		; pop SI
		pop	dx		; pop DX
		pop	cx		; pop CX
		pop	bx		; pop BX
		pop	ax		; pop AX
		ret

; ----------------------------------------------------------------------------
;                  Int 25h interrupt routine - read from disk
; ----------------------------------------------------------------------------
; INPUT:	AL = drive number (0=A:, 1=B:,...)
;		CX = number of sectors to read
;		DX = starting sector number
;		DS:BX = data buffer
; OUTPUT:	CY = error
;		AH = status (see "BIOS disk error codes")
;		AL = DOS error code (see "Device driver error codes")
;		CX = number of remaining sectors (0 if NC)
; ----------------------------------------------------------------------------
; NOTES: Original flags are left on stack and must be popped by caller
; ----------------------------------------------------------------------------

MyInt25:	mov	ah,2		; AH <- 2 function code (read)
		jmp	short MyInt256

; ----------------------------------------------------------------------------
;                  Int 26h interrupt routine - write to disk
; ----------------------------------------------------------------------------
; INPUT:	AL = drive number (0=A:, 1=B:,...)
;		CX = number of sectors to write
;		DX = starting sector number
;		DS:BX = data buffer
; OUTPUT:	CY = error
;		AH = status (see "BIOS disk error codes")
;		AL = DOS error code (see "Device driver error codes")
;		CX = number of remaining sectors (0 if NC)
; ----------------------------------------------------------------------------
; NOTES: Original flags are left on stack and must be popped by caller
; ----------------------------------------------------------------------------

MyInt26:	mov	ah,3		; AH <- 3 function code (write)

; ------------- Check disk number

MyInt256:	cmp	al,MAXDISK	; check disk number
		jb	MyInt2561	; disk number is OK
		stc			; set error flag
		mov	ax,BIOS_GENERAL*256+ERR_UNIT ; invalid disk unit
		retf

; ------------- Change phantom disk

MyInt2561:	call	SetPhantom	; set new phantom disk

; ------------- Change phantom drive B: to A:

		cmp	al,1		; is it drive B: ?
		jne	MyInt2562	; it is not drive B:
		test	byte [cs:DiskFlags],B0 ; use phantom disk?
		jz	MyInt2562	; don't use phantom disk
		mov	al,0		; change to drive A:

; ------------- Prepare disk number (floppy or hard drive)

MyInt2562:	push	ax		; push AX
		cmp	al,2		; is it hard disk?
		jb	MyInt2563	; it is floppy disk
%ifndef NOHD
		add	al,80h-2	; change to hard disk
%endif
MyInt2563:	mov	[cs:DiskDriveFnc],ax ; store disk and function code
		pop	ax		; pop AX

; ------------- Pointer to current disk parameter table

		push	ax		; push AX
		mov	ah,BPB_SIZE	; AH <- size of one table
		mul	ah		; AX <- offset of disk param table
		add	ax,DiskParBPB	; AX <- address of disk param table
		mov	[cs:DiskParBPBCurr],ax ; store pointer to table
		pop	ax		; pop AX

; ------------- Init disk parameters

		call	InitDiskPar	; init disk parameters
	
; ------------- Do disk operation

		push	bx		; push BX
		push	dx		; push DX
		push	es		; push ES
		push	ds		; push DS
		pop	es		; ES <- segment of buffer
		call	ReadWrite	; read/write
		pop	es		; pop ES
		pop	dx		; pop DX
		pop	bx		; pop BX

; ------------- Remap BIOS error code to DOS error code

		jnc	MyInt2564	; there is no error
		call	BIOSError	; remap error code
MyInt2564:	retf

; ----------------------------------------------------------------------------
;                       Remap BIOS error to DOS error
; ----------------------------------------------------------------------------
; INPUT:	AH = BIOS error code
; OUTPUT:	AL = DOS error code
;		CY = set errorflag
; ----------------------------------------------------------------------------

BIOSError:	push	bx		; push BX
		mov	bx,ErrorTab-2	; BX <- error table - 2
BIOSError2:	inc	bx		; skip BIOS error code
		inc	bx		; skip DOS error code
		cmp	ah,[cs:bx]	; check BIOS error code
		je	BIOSError4	; found error code
		cmp	byte [cs:bx],0	; was it last code?
		jne	BIOSError2	; check next error code
BIOSError4:	mov	al,[cs:bx+1]	; AL <- DOS error code
		pop	bx		; pop BX
		stc			; set errorflag
		ret

; ----------------------------------------------------------------------------
;                Call Int 13h interrupt with saving registers 1
; ----------------------------------------------------------------------------

; ------------- Push registers

Int131:		push	si		; push SI
		push	di		; push DI
		push	bp		; push BP
		push	ds		; push DS
		push	es		; push ES

; ------------- Call INT 13h

		stc			; preset error flag (due to some BIOSes)
		int	13h		; call INT 13h
		sti			; enable interrupt (due to some BIOSes)

; ------------- Pop registers

		pop	es		; pop ES
		pop	ds		; pop DS
		pop	bp		; pop BP
		pop	di		; pop DI
		pop	si		; pop SI
		ret

; ----------------------------------------------------------------------------
;                Call Int 13h interrupt with saving registers
; ----------------------------------------------------------------------------

; ------------- Push registers

Int13:		push	bx		; push BX
		push	cx		; push CX
		push	dx		; push DX

; ------------- Call INT 13h

		call	Int131		; call int 13h

; ------------- Pop registers

		pop	dx		; pop DX
		pop	cx		; pop CX
		pop	bx		; pop BX
		ret

; ----------------------------------------------------------------------------
;                                    Data
; ----------------------------------------------------------------------------

; ------------- Disk setup

DiskNum:	db	0		; total number of disk drives
DiskFlags:	db	0		; disk flags
					;	bit 0: use phantom disk

PhantText:	db	CR,LF,'Insert diskette for drive '
PhantTextA:	db	'A: and press any key when ready',CR,LF,LF,0

; ------------- Disk parameter tables

DiskParBPBCurr:	dw	DiskParBPB	; pointer to current disk table

DiskParFlags:	times	2 db 0		; parameters (only floppy)
					;	bit 0: changeline supported

DiskParAccess:	times 	2 dd -1		; last access time (only floppy)

; ------------- Current disk

DiskDriveFnc:
DiskDrive:	db	0		; current disk drive (0=A:...80h=C:)
DiskFnc:	db	2		; disk function code (2=read, 3=write)

; ------------- BIOS disk error codes

ErrorTab:	db	BIOS_WRITE, ERR_WRITE	; write fault
		db	BIOS_READY, ERR_READY	; timeout (not ready)
		db	BIOS_SEEK, ERR_SEEK	; seek failed
		db	BIOS_CONTROL, ERR_READY	; controller failed
		db	BIOS_CRC, ERR_CRC	; CRC error
		db	BIOS_DMA, ERR_CRC	; DMA overrun
		db	BIOS_CHANGE, ERR_CHANGE	; disk changed
		db	BIOS_SECTOR, ERR_SECTOR	; sector not found
		db	BIOS_PROT, ERR_PROT	; write-protection
		db	BIOS_ADDRESS, ERR_SECTOR; bad address mark
		db	0, ERR_GENERAL		; unknown error (must be last!)

Zpět na stránku systému MICRODOS