; =============================================================================
;
;                         Litos8 system disk (logical disk)
;
; =============================================================================
; Limitations: Sector size must be 512 bytes. Partition size is max. 2 GB.
; File system FAT12 or FAT16.

; -----------------------------------------------------------------------------
; Exported user functions (18):
;	SDiskGetNum - get number of valid system disks
;	SDiskGetDesc - get system disk descriptor
;	SDiskGetInfo - get system disk info TEXT
;	SDiskGetAllInfo - get system all disks info TEXT
;	SDiskReadSect - read cached sector
;	SDDCheck - check system disk device
;	SDDSize - get system disk size
;	SDDRead - read from system disk device
;	SDDWrite - write to system disk device
;	SDiskCheckSize - check system disk size
;	SDiskReload - reload system disk
;	SDiskMediaDesc - get system disk default media descriptor
;	DefFATType - get default FAT type
;	DefRootSize - get default root directory size
;	DefClustSize - get default cluster size
;	SDiskDefPar - get default parameters of system disk
;	GetClustNum - calculate number of clusters
;	BuildBoot - build BOOT sector parameter table
; -----------------------------------------------------------------------------

		CODEINIT_SECTION

; -----------------------------------------------------------------------------
;                       INIT: Initialize system disk driver
; -----------------------------------------------------------------------------

; ------------- prepare BDD table

SDiskInit:	mov	si,BDDTab	; SI <- table of BDD descriptors
		mov	cx,[BDDNum]	; CX <- number of BIOS disks
		jcxz	SDiskInit8	; no BIOS disk

; ------------- push registers

SDiskInit2:	push	si		; push SI (BDD descriptor)
		push	cx		; push CX (disk counter)

; ------------- skip invalid floppy disks

		cmp	byte [si+BDD_Disk],10h ; floppy disk?
		jb	short SDiskInit4 ; floppy disk is OK
		cmp	byte [SDDLastDisk],2 ; check minimal disks
		jae	short SDiskInit4 ; number of disks is OK
		mov	byte [SDDLastDisk],2 ; skip invalid floppy disks

; ------------- load system disks for this BDD

SDiskInit4:	xor	cx,cx		; CX <- 0, start sector LOW
		xor	di,di		; DI <- 0, start sector HIGH
		mov	[SDDExtStart],cx ; extended start sector LOW
		mov	[SDDExtStart+2],di ; extended start sector HIGH
		mov	ax,[si+BDD_SectNum] ; AX <- number of sectors LOW
		mov	dx,[si+BDD_SectNum+2] ; DX <- number of sectors HIGH
		call	SDiskAdd	; add system disk

; ------------- pop registers

		pop	cx		; pop CX (disk counter)
		pop	si

; ------------- next BDD descriptor

		add	si,BDD_size	; SI <- next BDD descriptor
		loop	SDiskInit2	; next disk
SDiskInitRet:
SDiskInit8:	ret

; -----------------------------------------------------------------------------
;                            INIT: Add system disk
; -----------------------------------------------------------------------------
; INPUT:	SI = BDD Bios disk descriptor
;		DX:AX = number of sectors
;		DI:CX = absolute start sector
; DESTROYS:	All.
; -----------------------------------------------------------------------------

; ------------- check number of disks

SDiskAdd:	cmp	byte [si+BDD_Disk],RAMDISK ; RAM disk?
		je	short SDiskAdd1	; RAM disk is reserved
		cmp	byte [SDDLastDisk],SDISK_MAX-1 ; check number of disks
		jae	short SDiskInitRet ; no available descriptor

; ------------- skip RAW memory disk

		cmp	byte [si+BDD_Disk],MEMDISK ; memory disk?
		je	short SDiskInitRet ; skip memory disk

; ------------- check disk size

SDiskAdd1:	mov	bp,ax		; BP <- number of sectors LOW
		or	bp,dx		; check disk size
		jz	short SDiskInitRet ; invalid disk size

; ------------- prepare SDD descriptor -> BX

		mov	bx,SDDTab + SDD_size*(SDISK_MAX-1) ; BX <- last disk
		cmp	byte [si+BDD_Disk],RAMDISK ; RAM disk?
		je	short SDiskAdd2 ; RAM disk
		xchg	ax,bx		; BX <- push AX
		mov	al,SDD_size	; AL <- size of SDD descriptor
		mul	byte [SDDLastDisk]; AX <- offset of last SDD descriptor
		add	ax,SDDTab	; AX <- address of SDD descriptor
		xchg	ax,bx		; BX <- SDD descriptor, AX <- pop AX

; ------------- initialize descriptor

SDiskAdd2:	mov	[bx+SDD_BDD],si	; BDD descriptor
		mov	[bx+SDD_StartSect],cx ; start sector LOW
		mov	[bx+SDD_StartSect+2],di ; start sector HIGH
		push	ax		; push AX
		push	dx		; push DX
		mov	al,SDISK_MAX-1	; AL <- RAM disk
		cmp	byte [si+BDD_Disk],RAMDISK ; RAM disk?
		je	short SDiskAdd23 ; RAM disk
		mov	al,[SDDLastDisk] ; AL <- last disk
SDiskAdd23:	mov	[bx+SDD_FlagsDisk],al ; AL <- system disk
		call	GetDateTimeUnix	; get date and time in Unix format
		mov	[bx+SDD_LastTime],ax ; set last access time mark
		pop	dx		; pop DX
		pop	ax		; pop AX

; ------------- removable disk, use default descriptor

		test	byte [si+BDD_Flags],BDDF_Removable ; removable media?
		jz	short SDiskAdd3 ; not removable media
		or	byte [bx+SDD_FlagsDisk],SDDF_Removable ; removable flag
		call	SDiskInitDef	; initialize default parameters
		jmp	SDiskAdd8

; ------------- read boot sector DX:AX -> SI

SDiskAdd3:      xchg	ax,cx		; AX <- start LOW, CX <- number LOW
		xchg	dx,di		; DX <- start HIGH, DI <- number HIGH
		push	bx		; push BX
		mov	bx,si		; BX <- BDD descriptor
		call	BDiskReadSect	; read sector
		pop	bx		; pop BX
		jc	short SDiskAdd9	; error

; ------------- check signature

		cmp	word [si+1feh],0aa55h ; check signature
		jne	short SDiskAdd9	; invalid boot sector

; ------------- load system disk parameters

		call	SDiskLoad	; load system disk parameters
		jnc	short SDiskAdd7	; disk is valid

; ------------- prepare to load partitions

		mov	bp,1beh		; BP <- first partition
		mov	bx,[bx+SDD_BDD]	; BX <- BDD descriptor

; ------------- push registers

SDiskAdd5:	push	ax		; push AX (start sector LOW)
		push	dx		; push DX (start sector HIGH)
		push	bx		; push BX (BDD descriptor)
		push	bp		; push BP (partition offset)
		push	word [SDDExtStart] ; push extended start sector LOW
		push	word [SDDExtStart+2] ; push extended start sector HIGH

; ------------- get partition start sector -> DI:CX

		lea	si,[si+bp]	; SI <- partition descriptor
		xchg	bx,si		; BX <- partition, SI <- BDD descriptor

; ------------- start sector of this partition -> CX:DI

		mov	cx,[bx+8]	; CX <- start sector LOW
		mov	di,[bx+10]	; DI <- start sector HIGH
		cmp	bp,1beh		; primary partition?
		je	short SDiskAdd52 ; yes, primary partition
		mov	ax,[SDDExtStart] ; AX <- extended start sector LOW
		mov	dx,[SDDExtStart+2] ; DX <- extended start sector HIGH
SDiskAdd52:	add	cx,ax		; CX <- absolute start sector LOW
		adc	di,dx		; DI <- absolute start sector HIGH
		jc	short SDiskAdd6 ; invalid partition

; ------------- get partition size -> DX:AX

		mov	ax,[bx+12]	; AX <- number of sectors LOW
		mov	dx,[bx+14]	; DX <- number of sectors HIGH
		mov	bp,cx		; BP <- start sector LOW
		or	bp,di		; BP <- valid start sector?
		jz	short SDiskAdd6	; invalid start sector

; ------------- prepare extended start sector (only main partition)

		cmp	word [SDDExtStart],byte 0 ; check start sectr LOW
		jne	short SDiskAdd54 ; it is already set
		cmp	word [SDDExtStart+2],byte 0 ; check start sectr HIGH
		jne	short SDiskAdd54 ; it is already set
		mov	[SDDExtStart],cx ; extended start sector LOW
		mov	[SDDExtStart+2],di ; extended start sector HIGH

; ------------- add system disk

SDiskAdd54:	call	SDiskAdd	; add system disk

; ------------- pop registers

SDiskAdd6:	pop	word [SDDExtStart+2] ; pop extended start sector HIGH
		pop	word [SDDExtStart] ; pop extended start sector LOW
		pop	bp		; pop BP (partition offset)
		pop	bx		; pop BX (BDD descriptor)
		pop	dx		; pop DX (start sector HIGH)
		pop	ax		; pop AX (start sector LOW)

; ------------- shift to next partition

		add	bp,byte 16	; BP <- next partition
		cmp	bp,1feh		; end of boot record?
		jae	short SDiskAdd9	; end of boot record

; ------------- reload boot sector DX:AX -> SI

		call	BDiskReadSect	; read sector
		jnc	short SDiskAdd5	; load next partition
SDiskAdd9:	ret

; ------------- increase number of system disks

SDiskAdd7:	or	byte [bx+SDD_FlagsDisk],SDDF_Valid ; disk is valid
SDiskAdd8:	mov	si,[bx+SDD_BDD] ; SI <- BDD descriptor
		cmp	byte [si+BDD_Disk],RAMDISK ; RAM disk?
		je	short SDiskAdd82 ; RAM disk
		inc	byte [SDDLastDisk] ; increase number of disks
SDiskAdd82:	inc	byte [SDDNum]	; increase number of valid disks
		ret


		CODE_SECTION

; -----------------------------------------------------------------------------
;            Initialize system disk parameters to default values
; -----------------------------------------------------------------------------
; INPUT:	DX:AX = number of sectors
;		BX = pointer to SDD descriptor
; NOTES:	SDD_StartSect must be set to partition start sector.
;		SDD_BDD must be set to BDD descriptor.
; -----------------------------------------------------------------------------

; ------------- push registers

SDiskInitDef:	push	ax		; push AX
		push	cx		; push CX
		push	dx		; push DX
		push	di		; push DI

; ------------- get default parameters

		xor	cx,cx		; default parameters
		xor	di,di		; default root size
		call	SDiskDefPar	; get default parameters

; ------------- set base entries

		and	byte [bx+SDD_FlagsDisk],~SDDF_FormMask ; clear format
		or	[bx+SDD_FlagsDisk],ch ; set file format
		mov	[bx+SDD_SectClust],cl ; sectors per cluster
		mov	byte [bx+SDD_FatNum],2 ; number of FAT tables
		mov	word [bx+SDD_ResSect],1 ; reserved sectors
		mov	[bx+SDD_RootEntries],di ; number of root entries

; ------------- total number of sectors
		
		mov	[bx+SDD_SectNum],ax ; total number of sectors LOW
		mov	[bx+SDD_SectNum+2],dx ; total number of sectors HIGH

; ------------- cluster size

		push	cx		; push CX (FAT type and cluster size)
		mov	ch,cl		; CH <- sectors per cluster
		mov	cl,0
		shl	cx,1		; CX <- cluster size
		mov	[bx+SDD_ClustSize],cx ; cluster size

; ------------- number of root sectors

		add	di,15		; round up
		mov	cl,4
		shr	di,cl		; DI <- root sectors
		mov	[bx+SDD_RootSect],di ; number of root sectors
		pop	cx		; pop CX (FAT type and cluster size)

; ------------- sectors per one FAT table

		stc			; include boot sector
		sbb	ax,di		; subtract root and boot sectors
		sbb	dx,byte 0	; borrow
		push	di		; push DI (root sectors)
		push	ax		; push AX
		push	dx		; push DX
		call	GetClustNum	; get number of clusters -> AX
		xor	dx,dx		; DX <- 0
		mov	di,ax		; DI <- number of clusters
		cmp	ch,SDDF_FAT16	; FAT16 ?
		je	short SDiskInitDef4 ; yes
		shr	di,1		; DI <- number of clusters / 2
		inc	di		; round up
SDiskInitDef4:	add	ax,di		; AX <- number of clusters *2 or *1.5
		adc	dx,byte 0	; DX <- overflow
		add	ax,511		; round up to sector
		adc	dx,byte 0
		mov	al,ah
		mov	ah,dl		; AX <- FAT bytes / 256
		shr	ax,1		; AX <- number of FAT sectors
		mov	[bx+SDD_FatSect],ax ; sectors per one FAT table
		xchg	ax,di		; DI <- sectors per one FAT table
		pop	dx		; pop DX
		pop	ax		; pop AX

; ------------- number of clusters

		shl	di,1		; DI <- sectors per 2 FAT tables
		sub	ax,di		; subtract FAT sectors
		sbb	dx,byte 0	; borrow
		call	GetClustNum	; get number of clusters
		mov	[bx+SDD_ClustNum],ax ; number of clusters
		pop	cx		; pop CX (root sectors)

; ------------- root start sector

		mov	ax,[bx+SDD_StartSect] ; AX <- start sectors LOW
		mov	[bx+SDD_HiddenSect],ax ; hidden sectors LOW
		mov	dx,[bx+SDD_StartSect+2] ; DX <- start sectors HIGH
		mov	[bx+SDD_HiddenSect+2],dx ; hidden sectors HIGH
		inc	di		; DI <- sectors per 2 FAT + boot sector
		add	ax,di		; add FAT and BOOT
		adc	dx,byte 0	; carry
		mov	[bx+SDD_RootStart],ax ; root start sector LOW
		mov	[bx+SDD_RootStart+2],dx ; root start sector HIGH

; ------------- data start sector

		add	ax,cx		; add ROOT sectors
		adc	dx,byte 0	; carry
		mov	[bx+SDD_ClustStart],ax ; data start sector LOW
		mov	[bx+SDD_ClustStart+2],dx ; data start sector HIGH

; ------------- random serial disk number

		call	RandDWord	; get random dword
		mov	[bx+SDD_Serial],ax ; serial LOW
		mov	[bx+SDD_Serial+2],dx ; serial HIGH

; ------------- media descriptor

		call	SDiskMediaDesc	; get media descriptor
		mov	[bx+SDD_MediaDesc],al ; media descriptor

; ------------- pop registers

		pop	di		; pop DI
		pop	dx		; pop DX
		pop	cx		; pop CX
		pop	ax		; pop AX
		ret

; -----------------------------------------------------------------------------
;                  Load system disk parameters from BOOT sector
; -----------------------------------------------------------------------------
; INPUT:	BX = pointer to SDD descriptor
;		SI = pointer to BOOT sector
; OUTPUT:	CY = invalid system disk
; NOTES:	SDD_StartSect must be set to partition start sector.
; -----------------------------------------------------------------------------

; ------------- push registers

SDiskLoad:	push	ax		; push AX
		push	cx		; push CX
		push	dx		; push DX
		push	di		; push DI

; ------------- check extension signature

		cmp	byte [si+BOOT_Signature],BOOTSIGN ; check signature
		jne	short SDiskLoad82 ; invalid disk

; ------------- check sector size

		cmp	word [si+BOOT_SectSize],SECTSIZE ; check sector size
		jne	short SDiskLoad82 ; invalid disk

; ------------- load cluster size

		mov	al,[si+BOOT_ClustSize] ; AL <- sectors per cluster
		or	al,al		; check cluster size
		jz	short SDiskLoad82 ; invalid cluster size
		mov	ah,al		; AH <- number of sectors per cluster
		mov	[bx+SDD_SectClust],al ; number of sectors per cluster
SDiskLoad1:	shr	al,1		; cluster size / 2
		jnc	short SDiskLoad1 ; next test
		jnz	short SDiskLoad82 ; invalid cluster size
		shl	ax,1		; AX <- cluster size in bytes
		jc	short SDiskLoad82 ; 64 KB cluster size is invalid
		mov	[bx+SDD_ClustSize],ax ; cluster size

; ------------- reserved sectors (boot)

		mov	ax,[si+BOOT_Reserved] ; AX <- reserved sectors
		cmp	ax,byte 16	; check value
		ja	short SDiskLoad82 ; invalid reserved sectors
		mov	[bx+SDD_ResSect],ax ; reserved sectors

; ------------- number of FAT tables

		mov	al,[si+BOOT_FATNum] ; AL <- number of FAT tables
		or	al,al		; check minimal value
		jz	short SDiskLoad82 ; invalid FAT tables
		cmp	al,4		; check maximal value
		ja	short SDiskLoad82 ; invalid FAT tables
		mov	[bx+SDD_FatNum],al ; number of FAT tables

; ------------- number of ROOT entries

		mov	ax,[si+BOOT_RootSize] ; AX <- number of root entries
		cmp	ax,byte 4	; check minimal value
		jb	short SDiskLoad82 ; invalid root
		mov	[bx+SDD_RootEntries],ax ; number of root entries
		mov	cl,4		; CL <- number of shifts
		add	ax,15		; round up
		shr	ax,cl		; AX <- number of root sectors
		mov	[bx+SDD_RootSect],ax ; number of root sectors

; ------------- total number of sectors

		xor	dx,dx		; DX <- 0
		mov	ax,[si+BOOT_SectNumW] ; AX <- number of sectors WORD
		or	ax,ax		; number of sectors WORD = 0 ?
		jnz	short SDiskLoad2 ; number of sectors is OK
		mov	ax,[si+BOOT_SectNum] ; AX <- number of sectors LOW
		mov	dx,[si+BOOT_SectNum+2] ; DX <- number of sectors HIGH
SDiskLoad2:	cmp	dx,byte 40h	; check max. number of sectors (2 GB)
		jbe	short SDiskLoad22 ; number of sectors is OK

SDiskLoad82:	jmp	SDiskLoad8	; invalid disk

SDiskLoad22:	mov	[bx+SDD_SectNum],ax ; number of sectors LOW
		mov	[bx+SDD_SectNum+2],dx ; number of sectors HIGH

; ------------- media descriptor

		mov	al,[si+BOOT_MediaDesc] ; AL <- media descriptor
		mov	[bx+SDD_MediaDesc],al ; media descriptor

; ------------- FAT size

		mov	ax,[si+BOOT_FATSize] ; AX <- number of sectors per FAT
		or	ax,ax		; check minimal FAT size
		jz	short SDiskLoad82 ; FAT size is OK
		cmp	ah,1		; check maximal FAT size (256)
		ja	short SDiskLoad82 ; invalid FAT size
		mov	[bx+SDD_FatSect],ax ; number of sectors per FAT

; ------------- hidden sectors

		mov	ax,[si+BOOT_Hidden] ; AX <- hidden sectors LOW
		mov	[bx+SDD_HiddenSect],ax ; hidden sectors LOW
		mov	ax,[si+BOOT_Hidden+2] ; AX <- hidden sectors HIGH
		mov	[bx+SDD_HiddenSect+2],ax ; hidden sectors HIGH

; ------------- serial

		mov	ax,[si+BOOT_Serial] ; AX <- serial LOW
		mov	[bx+SDD_Serial],ax ; serial LOW
		mov	ax,[si+BOOT_Serial+2] ; AX <- serial HIGH
		mov	[bx+SDD_Serial+2],ax ; serial HIGH

; ------------- FAT system

		cmp	word [si+BOOT_FatName],"FA" ; check FAT 1
		jne	short SDiskLoad82 ; invalid file system
		cmp	word [si+BOOT_FatName+2],"T1" ; check FAT 2
		jne	short SDiskLoad82 ; invalid file system
		mov	al,SDDF_FAT12	; AL <- FAT12
		cmp	word [si+BOOT_FatName+4],"2 " ; check FAT 3
		je	short SDiskLoad3 ; FAT12
		cmp	word [si+BOOT_FatName+4],"6 " ; check FAT 3
		jne	short SDiskLoad82 ; invalid disk
		mov	al,SDDF_FAT16	; AL <- FAT16
SDiskLoad3:	and	byte [bx+SDD_FlagsDisk],~SDDF_FormMask ; clear format
		or	byte [bx+SDD_FlagsDisk],al ; set file format

; ------------- root start sector

		mov	al,[bx+SDD_FatNum] ; AL <- number of FAT tables
		cbw			; AX <- number of FAT tables
		mul	word [bx+SDD_FatSect] ; DX:AX <- sectors per FATs
		add	ax,[bx+SDD_ResSect] ; add number of boot sectors
		adc	dx,byte 0	; carry
		mov	cx,ax		; CX <- FAT and boot LOW
		mov	di,dx		; DI <- FAT and boot HIGH
		add	ax,[bx+SDD_StartSect] ; add start sectors LOW
		adc	dx,[bx+SDD_StartSect+2] ; add start sectors HIGH
		mov	[bx+SDD_RootStart],ax ; root start sector LOW
		mov	[bx+SDD_RootStart+2],dx ; root start sector HIGH

; ------------- data start sector

		add	ax,[bx+SDD_RootSect] ; add number of root sectors
		adc	dx,byte 0	; carry
		mov	[bx+SDD_ClustStart],ax ; data start sector LOW
		mov	[bx+SDD_ClustStart+2],dx ; data start sector HIGH

; ------------- number of clusters

		mov	ax,[bx+SDD_SectNum] ; AX <- number of sectors LOW
		mov	dx,[bx+SDD_SectNum+2] ; DX <- number of sectors HIGH
		sub	ax,cx		; subtract FAT and boot LOW
		sbb	dx,di		; subtract FAT and boot HIGH
		jc	short SDiskLoad8 ; invalid disk size
		sub	ax,[bx+SDD_RootSect] ; subtract root sectors
		sbb	dx,byte 0	; borrow
		jc	short SDiskLoad8 ; invalid disk size
		mov	cl,[bx+SDD_SectClust] ; CL <- sectors per cluster
		call	GetClustNum	; get number of clusters
		jc	short SDiskLoad8 ; overflow
		or	ax,ax		; minimal clusters
		jz	short SDiskLoad8 ; invalid disk
		cmp	ax,FAT16_NUM	; FAT16 max. clusters
		ja	short SDiskLoad8 ; overflow
		mov	cx,ax		; CX <- number of clusters
		test	byte [bx+SDD_FlagsDisk],SDDF_FAT16 ; FAT16?
		jnz	short SDiskLoad4 ; FAT16
		cmp	ax,FAT12_NUM	; FAT12 max. clusters
		ja	short SDiskLoad8 ; overflow
		shr	cx,1		; CX <- number of clusters / 2
		inc	cx		; round up
SDiskLoad4:	mov	[bx+SDD_ClustNum],ax ; number of clusters

; ------------- check FAT size

		xor	dx,dx		; DX <- 0
		add	ax,cx		; AX <- number of clusters *2 or *1.5
		adc	dx,byte 0	; carry
		add	ax,511		; round up to sector
		adc	dx,byte 0
		mov	al,ah
		mov	ah,dl		; AX <- FAT bytes / 256
		shr	ax,1		; AX <- number of FAT sectors
		cmp	ax,[bx+SDD_FatSect] ; check number of sectors
		ja	short SDiskLoad8 ; invalid FAT size

; ------------- disk is valid

		or	byte [bx+SDD_FlagsDisk],SDDF_Valid ; disk is valid
		jmp	short SDiskLoad9

; ------------- error, reset disk parameters

SDiskLoad8:	and	byte [bx+SDD_FlagsDisk],~SDDF_Valid ; clear valid flag
		stc			; set error flag

; ------------- pop registers

SDiskLoad9:	pop	di		; pop DI
		pop	dx		; pop DX
		pop	cx		; pop CX
		pop	ax		; pop AX
		ret

; -----------------------------------------------------------------------------
;                             Reload system disk
; -----------------------------------------------------------------------------
; INPUT:	BX = pointer to SDD descriptor
; OUTPUT:	CY = error
; NOTES:	Loads SDD of removable disk if needed.
; -----------------------------------------------------------------------------

; ------------- check if it is removable disk

SDiskReload:	test	byte [bx+SDD_FlagsDisk],SDDF_Removable ; removable?
		jz	short SDiskReload9 ; not removable media

; ------------- push registers

		push	ax		; push AX
		push	dx		; push DX
		push	si		; push SI

; ------------- get time delta -> AX

		call	GetDateTimeUnix	; get date and time in Unix format
		sub	ax,[bx+SDD_LastTime] ; AX <- interval
		add	[bx+SDD_LastTime],ax ; shift last time

; ------------- invalid disk is loaded immediately

		test	byte [bx+SDD_FlagsDisk],SDDF_Valid ; valid format?
		jz	short SDiskReload2 ; uknown disk format

; ------------- check last access time

		cmp	ax,byte 3	; check interval
		cmc			; NC = short interval
		jnc	short SDiskReload8 ; disk is valid

; ------------- mark disk as invalid

SDiskReload2:	and	byte [bx+SDD_FlagsDisk],~SDDF_Valid ; clear valid flag

; ------------- read boot sector

		mov	ax,[bx+SDD_StartSect] ; AX <- start sector LOW
		mov	dx,[bx+SDD_StartSect+2] ; DX <- start sector HIGH
		call	SDiskReadSect	; read sector
		jc	short SDiskReload8 ; read error

; ------------- check signature

		cmp	word [si+1feh],0aa55h ; check signature
		stc			; set error flag
		jne	short SDiskReload8 ; invalid boot sector

; ------------- load system disk parameters

		call	SDiskLoad	; load system disk parameters

; ------------- pop registers

SDiskReload8:	pop	si		; pop SI
		pop	dx		; pop DX	
		pop	ax		; pop AX
SDiskReload9:	ret

; -----------------------------------------------------------------------------
;                    Get system disk default media descriptor
; -----------------------------------------------------------------------------
; INPUT:	BX = pointer to SDD descriptor
; OUTPUT:	AL = default media descriptor
; -----------------------------------------------------------------------------

; ------------- push registers

SDiskMediaDesc:	push	cx		; push CX
		push	si		; push SI

; ------------- get BDD descriptor -> SI

		mov	si,[bx+SDD_BDD] ; SI <- BDD descriptor

; ------------- get drive type -> CH

		mov	ch,[si+BDD_Flags] ; CH <- BDD flags
		and	ch,BDDF_TypeMask ; CH <- drive type

; ------------- hard disk
; F8:	HDD
		mov	al,0f8h		; AL <- HDD descriptor
		cmp	ch,BDDF_HardDisk ; hard disk ?
		je	short SDiskMediaDesc8 ; hard disk

; ------------- check disk size >= 5 MB

		cmp	word [bx+SDD_SectNum+2],byte 0 ; check disk size HIGH
		jne	short SDiskMediaDesc8 ; disk is too big
		mov	cx,[bx+SDD_SectNum] ; CX <- disk size LOW
		cmp	ch,28h ; check disk size LOW
		jae	short SDiskMediaDesc8 ; disk is loo big

; ------------- floppy 2.88 MB, 1.44 MB
; F0:	2.88MB C=80 H=2 S=36
;	1.44MB C=80 H=2 S=18

		mov	al,0f0h		; AL <- floppy 2.88 MB, 1.44 MB
		cmp	ch,0ah		; check disk size LOW, 1.3 MB
		jae	short SDiskMediaDesc8 ; disk is > 1.3 MB

; ------------- floppy disk descriptor
; FF:	320KB C=40 H=2 S=8
; FE:	160KB C=40 H=1 S=8
; FD:	360KB C=40 H=2 S=9
; FC:	180KB C=40 H=1 S=9
; FB:	640KB C=80 H=2 S=8
; FA:	320KB C=80 H=1 S=8
; F9:	720KB C=80 H=2 S=9
;	1.2MB C=80 H=2 S=15

		mov	al,0f8h		; AL <- base descriptor
		cmp	byte [si+BDD_Heads],1 ; 1 side?
		jbe	short SDiskMediaDesc2 ; 1 side
		or	al,B0		; set 2 sides flag
SDiskMediaDesc2:cmp	byte [si+BDD_SectTrack],8 ; 8 sectors per track?
		ja	short SDiskMediaDesc3 ; more than 8 sectors
		or	al,B1		; set 8 sectors flag
SDiskMediaDesc3:cmp	byte [si+BDD_Cylinders],60 ; 40 cylinders?
		jae	short SDiskMediaDesc4 ; more than 40 cylinders
		or	al,B2		; set 40 cylinders flag
SDiskMediaDesc4:cmp	al,0f8h		; reserved media type?
		jne	SDiskMediaDesc8	; media type is OK
		inc	ax		; AL <- change to 0f9h

; ------------- pop registers

SDiskMediaDesc8:pop	si		; pop SI
		pop	cx		; pop CX
		ret

; -----------------------------------------------------------------------------
;                          Check system disk size
; -----------------------------------------------------------------------------
; INPUT:	DX:AX = total number of disk sectors (5..400000h)
; OUTPUT:	CY = error, invalid disk size ( < 2.5 KB or > 2 GB)
; -----------------------------------------------------------------------------

; ------------- check minimum disk size (sectors: BOOT, FAT1, FAT2, ROOT, DATA)

SDiskCheckSize:	or	dx,dx		; check disk size HIGH
		jnz	short SDiskCheckSize2 ; disk size is OK
		cmp	ax,5		; minimum disk size
		jb	short SDiskCheckSize6 ; invalid disk size

; ------------- check maximum disk size (2 GB, i.e. 400000h of 512 sectors)

SDiskCheckSize2:cmp	dx,byte 40h	; check 2 GB HIGH, use 512 B sectors
		jne	short SDiskCheckSize4 ; not 2 GB
		cmp	ax,byte 1	; check 2 GB LOW
SDiskCheckSize4:cmc			; CY = invalid disk size
SDiskCheckSize6:ret

; -----------------------------------------------------------------------------
;                           Get default FAT type
; -----------------------------------------------------------------------------
; INPUT:	DX:AX = total number of disk sectors (5..400000h)
; OUTPUT:	CH = default FAT type (SDDF_FAT12, SDDF_FAT16)
; -----------------------------------------------------------------------------

DefFATType:	mov	ch,SDDF_FAT16	; CH <- FAT16
		or	dx,dx		; check number of sectors
		jnz	short DefFATType9 ; large disk
		cmp	ax,5000h	; check 10 MB LOW
		jae	short DefFATType9 ; >= 10 MB, use FAT16
		mov	ch,SDDF_FAT12	; CH <- FAT12
DefFATType9:	ret

; -----------------------------------------------------------------------------
;                         Get default root directory size
; -----------------------------------------------------------------------------
; INPUT:	DX:AX = total number of disk sectors (5..400000h)
; OUTPUT:	DI = number of root directory entries (16,32,112,224,448,512)
; -----------------------------------------------------------------------------

; ------------- size >= 5 MB (hard disk, FAT16), use 32 sectors, 512 entries

DefRootSize:	mov	di,32*SECTDIRNUM ; DI <- 32 sectors, 512 entries
		or	dx,dx		; check disk size HIGH
		jnz	short DefRootSize8 ; size >= 5 MB
		cmp	ah,28h		; check 5 MB
		jae	short DefRootSize8 ; size >= 5 MB

; ------------- size >= 2 MB (2.88 MB), use 28 sectors, 448 entries

		mov	di,28*SECTDIRNUM ; DI <- 28 sectors, 448 entries
		cmp	ah,10h		; check 2 MB
		jae	short DefRootSize8 ; size >= 2 MB

; ------------- size >= 1 MB (1.2 MB, 1.44 MB), use 14 sectors, 224 entries

		shr	di,1		; DI <- 14 sectors, 224 entries
		cmp	ah,8		; check 1 MB
		jae	short DefRootSize8 ; size >= 1 MB

; ------------- size >= 340 KB (360 KB, 720 KB), use 7 sectors, 112 entries

		shr	di,1		; DI <- 7 sectors, 112 entries
		cmp	ax,2a8h		; check 340 KB
		jae	short DefRootSize8 ; size > 340 KB

; ------------- size >= 128 KB (180 KB, 320 KB), use 4 sectors, 64 entries

		mov	di,4*SECTDIRNUM ; DI <- 4 sectors, 64 entries
		or	ah,ah		; check 128 KB
		jnz	short DefRootSize8 ; size > 128 KB

; ------------- size >= 64 KB, use 2 sectors, 32 entries

		shr	di,1		; DI <- 2 sectors, 32 entries
		or	al,al		; check 64 KB
		js	short DefRootSize8 ; size > 64 KB

; ------------- size < 64 KB, use 1 sector, 16 entries

		shr	di,1		; DI <- 1 sector, 16 entries
DefRootSize8:	ret

; -----------------------------------------------------------------------------
;                          Get default cluster size
; -----------------------------------------------------------------------------
; INPUT:	DX:AX = total number of disk sectors
;				FAT12: 5..40000h, FAT16: 5..400000h
;		CH = FAT type (SDDF_FAT12, SDDF_FAT16)
;		DI = number of root directory entries (1..0ffffh)
; OUTPUT:	CL = sectors per cluster (1,2,4,8,16,32,64)
; -----------------------------------------------------------------------------
; Cluster size must be power of 2 and < 65K -> max. cluster size is 32KB.
;
; Cluster size (sectors per cluster):
;  FAT12:
;	0..127 KB: 1
;	128..999 KB: 2 (FDD 360 KB, 720 KB)
;	1..1.9 MB: 1 (FDD 1.2 MB, 1.4 MB)
;	2..3.9 MB: 2 (FDD 2.88 MB)
;	4..7 MB: 4
;	8..15 MB: 8
;	16..31 MB: 16
;	32..63 MB: 32
;	64..127 MB: 64
;  FAT16:
;	0..255 KB: 1
;	256 KB..1.9 MB: 8
;	2..3.9 MB: 4
;	4..7 MB: 2
;	8..31 MB: 1
;	32..63 MB: 2
;	64..127 MB: 4
;	128..255 MB: 8
;	256..511 MB: 16
;	512..1023 MB: 32
;	1024..2047 MB: 64

; ------------- push registers

DefClustSize:	push	ax		; push AX
		push	dx		; push DX
		push	di		; push DI

; ------------- decrease disk size by root directory sectors

		xchg	ax,di		; AX <- number of root entries
		add	ax,SECTDIRNUM-1	; AX <- round up
		rcr	ax,1		; AX <- /2
		shr	ax,1
		shr	ax,1
		shr	ax,1		; AX <- number of root sectors
		xchg	ax,di		; DI <- number of root sectors
		sub	ax,di		; subtract root sectors LOW
		sbb	dx,byte 0	; borrow
		mov	cl,1		; CL <- 1, minimal cluster size
		jc	short DefClustSize9 ; error

; ------------- prepare table -> DI

		mov	di,FAT12ClustSize-5 ; DI <- FAT12 table
		cmp	ch,SDDF_FAT12	; FAT12?
		je	short DefClustSize2 ; FAT12
		mov	di,FAT16ClustSize-5 ; DI <- FAT16 table

; ------------- find cluster size -> CL

DefClustSize2:	add	di,byte 5	; DI <- shift table pointer
		mov	cl,[di]		; CL <- number of sectors
		cmp	dx,[di+3]	; compare disk size HIGH
		jne	short DefClustSize4
		cmp	ax,[di+1]	; compare disk size LOW
DefClustSize4:	jb	short DefClustSize2 ; next table entry

; ------------- pop registers

DefClustSize9:	pop	di		; pop DI
		pop	dx		; pop DX
		pop	ax		; pop AX
		ret

; -----------------------------------------------------------------------------
;                   Get default parameters of system disk
; -----------------------------------------------------------------------------
; INPUT:	DX:AX = total number of disk sectors
;				FAT12: 5..40000h, FAT16: 5..400000h
;		CL = sectors per cluster (1,2,4,8,16,32,64; 0=auto)
;		CH = FAT type (SDDF_FAT12, SDDF_FAT16; 0=auto)
;		DI = number of root directory entries (1..0ffffh, 0=auto)
; OUTPUT:	Default parameters
; -----------------------------------------------------------------------------

; ------------- FAT type

SDiskDefPar:	or	ch,ch		; unknown FAT type?
		jnz	short SDiskDefPar2 ; FAT type is OK
		call	DefFATType	; default FAT type

; ------------- number of root directory entries

SDiskDefPar2:	or	di,di		; unknown root directory entries?
		jnz	short SDiskDefPar4 ; root size is OK
		call	DefRootSize	; default root directory entries

; ------------- sectors per cluster

SDiskDefPar4:	or	cl,cl		; unknown sectors per cluster?
		jnz	short SDiskDefPar6 ; cluster size is OK
		call	DefClustSize	; default cluster size
SDiskDefPar6:	ret

; -----------------------------------------------------------------------------
;                         Calculate number of clusters
; -----------------------------------------------------------------------------
; INPUT:	DX:AX = data sectors (without boot, root and FATs)
;		CL = sectors per cluster (1,2,4,8,16,32,64)
; OUTPUT:	AX = number of clusters (0..0ffffh)
;		CY = overflow (number of clusters > 64K)
; -----------------------------------------------------------------------------

; ------------- push registers

GetClustNum:	push	bx		; push BX
		push	cx		; push CX
		push	dx		; push DX

; ------------- get number of clusters -> DX:AX

		mov	ch,0		; CX <- sectors per cluster
		xchg	ax,bx		; BX <- data sectors LOW
		xchg	ax,dx		; AX <- data sectors HIGH
		xor	dx,dx		; DX <- 0
		div	cx		; AX <- clusters HIGH, DX <- rest
		xchg	ax,bx		; AX <- sectors LOW,BX <- clusters HIGH
		div	cx		; AX <- clusters LOW

; ------------- check overflow

		or	bx,bx		; overflow?
		jz	short GetClustNum4 ; no overflow
		or	ax,byte -1	; AX <- -1, limit to 0ffffh
		stc			; set error flag

; ------------- pop registers

GetClustNum4:	pop	dx		; pop DX
		pop	cx		; pop CX
		pop	bx		; pop BX
		ret

; -----------------------------------------------------------------------------
;                       Build BOOT sector parameter table
; -----------------------------------------------------------------------------
; INPUT:	DX:AX = total number of disk sectors
;				FAT12: 5..40000h, FAT16: 5..400000h
;		CL = sectors per cluster (1,2,4,8,16,32,64; 0=auto)
;		CH = FAT type (SDDF_FAT12, SDDF_FAT16; 0=auto)
;		DI = number of root directory entries (1..0ffffh, 0=auto)
;		SI = pointer to BOOT sector (BOOTHEAD structure)
; OUTPUT:	Default parameters
; NOTES:	Fills up these entries: BOOT_OEM_Ident, BOOT_SectSize,
;			BOOT_ClustSize, BOOT_Reserved, BOOT_RootSize,
;			BOOT_SectNumW, BOOT_FATSize, BOOT_SectNum,
;			BOOT_Signature, BOOT_Serial, BOOT_FatName
; -----------------------------------------------------------------------------

; ------------- get default parameters

BuildBoot:	call	SDiskDefPar	; get default parameters

; ------------- push registers

		push	ax		; push AX
		push	dx		; push DX
		push	di		; push DI

; ------------- fill up boot table

		mov	word [si+BOOT_OEM_Ident],"LI" ; OEM ident. 1
		mov	word [si+BOOT_OEM_Ident+2],"TO" ; OEM ident. 2
		mov	word [si+BOOT_OEM_Ident+4],"S8" ; OEM ident. 3
		mov	word [si+BOOT_OEM_Ident+6]," 1" ; OEM ident. 4
		mov	word [si+BOOT_SectSize],SECTSIZE ; sector size
		mov	[si+BOOT_ClustSize],cl ; sectors per cluster
		mov	word [si+BOOT_Reserved],1 ; reserved sectors
		mov	[si+BOOT_RootSize],di ; number of root entries
		mov	byte [si+BOOT_Signature],BOOTSIGN ; signature

; ------------- number of sectors

		and	word [si+BOOT_SectNumW],byte 0 ; number of sectors WORD
		mov	[si+BOOT_SectNum],ax ; number of sectors LOW
		mov	[si+BOOT_SectNum+2],dx ; number of sectors HIGH
		or	dx,dx		; number of sectors >= 64K ?
		jnz	short BuildBoot2 ; disk is >= 64K sectors
		mov	[si+BOOT_SectNumW],ax ; number of sectors WORD
		mov	[si+BOOT_SectNum],dx ; clear number of sectors LOW

; ------------- subtract boot and root -> DX:AX

BuildBoot2:	add	di,15		; round up root size
		shr	di,1
		shr	di,1
		shr	di,1
		shr	di,1		; DI <- sectors per root
		inc	di		; include BOOT sector
		sub	ax,di		; subtract boot and root
		sbb	dx,byte 0	; borrow
		jnc	short BuildBoot4 ; disk size is OK
		xor	ax,ax		; AX <- 0, limit disk size
		xor	dx,dx		; DX <- 0

; ------------- get FAT size

BuildBoot4:	call	GetClustNum	; get number of clusters -> AX
		xor	dx,dx		; DX <- 0
		mov	di,ax		; DI <- number of clusters
		cmp	ch,SDDF_FAT16	; FAT16 ?
		je	short BuildBoot6 ; yes
		shr	di,1		; DI <- number of clusters / 2
		inc	di		; round up
BuildBoot6:	add	ax,di		; AX <- number of clusters *2 or *1.5
		adc	dx,byte 0	; DX <- overflow
		add	ax,511		; round up to sector
		adc	dx,byte 0
		mov	al,ah
		mov	ah,dl		; AX <- FAT bytes / 256
		shr	ax,1		; AX <- number of FAT sectors
		mov	[si+BOOT_FATSize],ax ; sectors per one FAT table

; ------------- random serial disk number

		call	RandDWord	; get random dword
		mov	[si+BOOT_Serial],ax ; serial LOW
		mov	[si+BOOT_Serial+2],dx ; serial HIGH

; ------------- FAT name

		mov	word [si+BOOT_FatName],"FA"
		mov	word [si+BOOT_FatName+2],"T1"
		mov	word [si+BOOT_FatName+4],"2 "
		mov	word [si+BOOT_FatName+6],"  "
		cmp	ch,SDDF_FAT12	; FAT12 ?
		je	short BuildBoot8 ; yes
		mov	byte [si+BOOT_FatName+4],"6" ; FAT16

; ------------- pop registers

BuildBoot8:	pop	di		; pop DI
		pop	dx		; pop DX
		pop	ax		; pop AX
		ret

; -----------------------------------------------------------------------------
;                        Get number of valid system disks
; -----------------------------------------------------------------------------
; OUTPUT:	AL = number of system disks (0..16)
; -----------------------------------------------------------------------------

SDiskGetNum:	mov	al,[SDDNum]
		ret

; -----------------------------------------------------------------------------
;                         Get system disk descriptor
; -----------------------------------------------------------------------------
; INPUT:	AL = disk number (0...)
; OUTPUT:	BX = pointer to SDD descriptor (or NULL on CY error)
;		CY = error, invalid disk number (returns BX = NULL)
; -----------------------------------------------------------------------------

SDiskGetDesc:	cmp	al,SDISK_MAX	; check disk number
		jae	short SDiskGetDesc6 ; error, invalid disk
		xchg	ax,bx		; BX <- push AX
		mov	al,SDD_size	; AL <- descriptor size
		mul	bl		; AX <- offset of descriptor
		add	ax,SDDTab	; AX <- SDD address
		xchg	ax,bx		; AX <- pop AX, BX <- SDD address
		cmp	word [bx+SDD_BDD],byte 1 ; check BDD descriptor
		jnc	SDiskGetDesc8	; disk is OK
SDiskGetDesc6:	xor	bx,bx		; BX <- 0
		stc			; set error flag
SDiskGetDesc8:	ret

; -----------------------------------------------------------------------------
;                       Get system disk info TEXT
; -----------------------------------------------------------------------------
; INPUT:	AL = system disk number (0...)
; OUTPUT:	BX = pointer to TEXT structure (NULL on memory error)
;		CY = disk or memory error (BX = NULL)
; NOTES:	Returned text should be destroyed using TextFree.
; -----------------------------------------------------------------------------

; ------------- push registers

SDiskGetInfo:	push	ax		; push AX
		push	cx		; push CX
		push	dx		; push DX
		push	si		; push SI
		push	di		; push DI

; ------------- get system disk descriptor -> DI

		call	SDiskGetDesc	; get disk descriptor
		jnc	short SDiskGetInfo0
SDiskGetInfo99:	jmp	SDiskGetInfo9	; invalid disk

SDiskGetInfo0:	mov	di,bx		; DI <- disk descriptor

; ------------- create TEXT -> BX

		xchg	ax,bx		; BL <- disk
		call	TextNewEmpty	; create new text
		xchg	ax,bx		; BX <- TEXT structure, AL <- disk
		jc	short SDiskGetInfo99 ; memory error

; ------------- disk name

		add	al,"A"		; AL <- disk name
		call	TextAddChar	; add disk name

; ------------- BIOS number

		mov	ax,SDTextBIOS	; ": BIOS="
		call	TextAddText	; add text
		mov	si,[di+SDD_BDD]	; SI <- BDD descriptor
		mov	al,[si+BDD_Disk] ; AL <- disk
		call	TextAddHByte	; add disk HEX number

; ------------- FAT format

		mov	ax,SDTextFAT12	; FAT12
		test	byte [di+SDD_FlagsDisk],SDDF_FAT12 ; FAT12 ?
		jnz	short SDiskGetInfo2 ; FAT 12
		mov	ax,SDTextFAT16	; FAT16
SDiskGetInfo2:	call	TextAddText	; add text

; ------------- disk size

		call	TextAddSpc	; add space
		mov	al,[di+SDD_SectClust] ; AL <- sectors per cluster
		cbw			; AX <- sectors per cluster
		mul	word [di+SDD_ClustNum] ; DX:AX <- disk size
		call	TextAddDiskSize	; add disk size

; ------------- number of clusters

		mov	ax,SDTextClust	; AX <- text "clust="
		call	TextAddText	; add text
		mov	ax,[di+SDD_ClustNum] ; AX <- number of clusters
		call	TextAddWord	; add number of clusters
		mov	al,"x"
		call	TextAddChar	; add "x" character
		mov	al,[di+SDD_SectClust] ; AL <- sectors per cluster
		shr	al,1		; 1 sector?
		jnc	short SDiskGetInfo3 ; no

		mov	ax,512
		call	TextAddWord	; add "512"
		jmp	short SDiskGetInfo4

SDiskGetInfo3:	call	TextAddByte	; add cluster size
		mov	al,"K"
		call	TextAddChar	; add "K" char
SDiskGetInfo4:	mov	al,"B"
		call	TextAddChar	; add "B" char

; ------------- ROOT entries

		mov	ax,SDTextRoot	; AX <- text "root="
		call	TextAddText	; add text
		mov	ax,[di+SDD_RootEntries] ; AX <- root entries
		call	TextAddWord	; add root entries

; ------------- FAT size

		mov	ax,SDTextFAT	; AX <- text "FAT="
		call	TextAddText	; add text
		mov	al,[di+SDD_FatNum] ; AL <- number of FAT tables
		call	TextAddByte	; add number
		mov	al,"x"
		call	TextAddChar	; add "x" character
		mov	ax,[di+SDD_FatSect] ; AX <- number of FAT sectors
		call	TextAddWord	; add number

; ------------- start sector

		mov	ax,SDTextStart	; AX <- text "start="
		call	TextAddText	; add text
		mov	ax,[di+SDD_StartSect] ; AX <- start sector LOW
		mov	dx,[di+SDD_StartSect+2] ; DX <- start sector HIGH
		call	TextAddDWord	; add number

; ------------- pop registers

		clc			; clear error flag
SDiskGetInfo9:	pop	di		; pop DI
		pop	si		; pop SI
		pop	dx		; pop DX
		pop	cx		; pop CX
		pop	ax		; pop AX
		ret

; -----------------------------------------------------------------------------
;                           Get system all disks info TEXT
; -----------------------------------------------------------------------------
; OUTPUT:	BX = pointer to TEXT structure (NULL on memory error)
;		CY = memory error (BX = NULL)
; NOTES:	Returned text should be destroyed using TextFree.
; -----------------------------------------------------------------------------

; ------------- push registers

SDiskGetAllInfo:push	ax		; push AX
		push	dx		; push DX

; ------------- create TEXT

		call	TextNewEmpty	; create new text
		xchg	bx,ax		; BX <- TEXT structure
		jc	short SDiskGetAllInf9 ; memory error

; ------------- total number of disks

		mov	ax,SDTextDiskNum ; AX <- text "System disks="
		call	TextAddText	; add text "System disks="
		mov	al,[SDDNum]	; AL <- total number of disks
		call	TextAddByte	; add total number of disks
		call	TextAddNewLine	; add new line

; ------------- add disc descriptors

		mov	al,0		; AL <- disk index
SDiskGetAllInf2:push	ax		; push AX

		mov	dx,bx		; DX <- TEXT descriptor
		call	SDiskGetInfo	; get disk info
		xchg	ax,bx		; AX <- disk TEXT
		mov	bx,dx		; BX <- TEXT descriptor
		jc	short SDiskGetAllInf6 ; error

		call	TextAddText	; add text
		xchg	ax,bx		; AX <- TEXT, BX <- disk TEXT
		call	TextFree	; free disk TEXT 
		xchg	ax,bx		; BX <- TEXT
		call	TextAddNewLine	; add new line

SDiskGetAllInf6:pop	ax		; pop AX
		inc	ax		; increase disk index
		cmp	al,SDISK_MAX	; next disk?
		jb	short SDiskGetAllInf2 ; get next disk

; ------------- pop registers

		clc			; clear error flag
SDiskGetAllInf9:pop	dx		; pop DX
		pop	ax		; pop AX
		ret

; -----------------------------------------------------------------------------
;                         Read cached sector (into SectBuf)
; -----------------------------------------------------------------------------
; INPUT:	DX:AX = absolute sector (0..)
;		BX = pointer to SDD descriptor
; OUTPUT:	SI = sector buffer SectBuf
;		CY = operation error
; -----------------------------------------------------------------------------

SDiskReadSect:	push	bx		; push BX
		mov	bx,[bx+SDD_BDD]	; BX <- BDD descriptor
		call	BDiskReadSect	; read cached sector
		pop	bx		; pop BX
		ret

; -----------------------------------------------------------------------------
;                         Check system disk device
; -----------------------------------------------------------------------------
; INPUT:	BL = system disk (0..)
; OUTPUT:	CY = invalid system disk
; -----------------------------------------------------------------------------

SDDCheck:	push	ax		; push AX
		push	bx		; push BX
		xchg	ax,bx		; AL <- system disk number
		call	SDiskGetDesc	; get SDD descriptor
		pop	bx		; pop BX
		pop	ax		; pop AX
		ret

; -----------------------------------------------------------------------------
;                         Get system disk size
; -----------------------------------------------------------------------------
; INPUT:	BL = system disk (0..)
; OUTPUT:	DX:AX = media size (0 on error)
;		CY = invalid system disk (DX:AX = 0)
; -----------------------------------------------------------------------------

SDDSize:	push	bx		; push BX

		xchg	ax,bx		; AL <- system disk number
		xor	dx,dx		; DX <- 0
		call	SDiskGetDesc	; get SDD descriptor
		mov	ax,dx		; AX <- 0
		jc	short SDDSize4	; error, invalid disk

		mov	ah,[bx+SDD_SectNum] ; AX <- number of sectors * 256
		mov	dx,[bx+SDD_SectNum+1] ; DX <- number of sectors HIGH
		shl	ax,1		; AX <- size LOW
		rcl	dx,1		; DX <- size HIGH
		clc			; clear error flag

SDDSize4:	pop	bx		; pop BX
		ret

; -----------------------------------------------------------------------------
;                      Read from system disk device
; -----------------------------------------------------------------------------
; INPUT:	DX:AX = current sector offset
;		BL = system disk (0..1)
;		CX = number of sectors
;		DI = destination buffer
; OUTPUT:	CY = error (CX > 0)
;		CX = remaining sectors (or CX = 0 if no error NC)
; -----------------------------------------------------------------------------

; ------------- push registers 1

SDDRead:	push	bx		; push BX

; ------------- get SDD descriptor -> BX

		push	ax		; push AX
		xchg	ax,bx		; AL <- system disk number
		call	SDiskGetDesc	; get SDD descriptor
		pop	ax		; pop AX
		jc	short SDDRead9	; invalid disk

; ------------- push registers 2

		push	ax		; push AX
		push	dx		; push DX
		push	di		; push DI

; ------------- change to absolute sector -> DX:AX

		add	ax,[bx+SDD_StartSect] ; AX <- absolute sector LOW
		adc	dx,[bx+SDD_StartSect+2] ; DX <- absolute sector HIGH

; ------------- read data from disk

		mov	bx,[bx+SDD_BDD]	; BX <- BDD descriptor
		call	BDiskRead	; read sectors
		jc	short SDDRead6	; error
		xor	cx,cx		; CX <- 0, data OK

; ------------- pop registers

SDDRead6:	pop	di		; pop DI
		pop	dx		; pop DX
		pop	ax		; pop AX

SDDRead9:	pop	bx		; pop BX
		ret

; -----------------------------------------------------------------------------
;                      Write to system disk device
; -----------------------------------------------------------------------------
; INPUT:	DX:AX = current sector offset
;		BL = system disk (0..1)
;		CX = number of sectors
;		DI = source buffer
; OUTPUT:	CY = error (CX > 0)
;		CX = remaining sectors (or CX = 0 if no error NC)
; -----------------------------------------------------------------------------

; ------------- push registers 1

SDDWrite:	push	bx		; push BX

; ------------- get SDD descriptor -> BX

		push	ax		; push AX
		xchg	ax,bx		; AL <- system disk number
		call	SDiskGetDesc	; get SDD descriptor
		pop	ax		; pop AX
		jc	short SDDWrite9	; invalid disk

; ------------- push registers 2

		push	ax		; push AX
		push	dx		; push DX
		push	di		; push DI

; ------------- change to absolute sector -> DX:AX

		add	ax,[bx+SDD_StartSect] ; AX <- absolute sector LOW
		adc	dx,[bx+SDD_StartSect+2] ; DX <- absolute sector HIGH

; ------------- write data to disk

		mov	bx,[bx+SDD_BDD]	; BX <- BDD descriptor
		call	BDiskWrite	; write sectors
		jc	short SDDWrite6	; error
		xor	cx,cx		; CX <- 0, data OK

; ------------- pop registers

SDDWrite6:	pop	di		; pop DI
		pop	dx		; pop DX
		pop	ax		; pop AX

SDDWrite9:	pop	bx		; pop BX
		ret

; -----------------------------------------------------------------------------
;                            Constant data
; -----------------------------------------------------------------------------

		CONST_SECTION

; ------------- FAT12 default number of sectors per cluster
; Max. 4078 clusters, FAT size max. 12 sectors

FAT12ClustSize:	db	64		; 64..127 MB: 64
		dd	FAT12_NUM*32 + 1 + 2*FAT12_FATSECT ; 130521 (63.7 MB)

		db	32		; 32..63 MB: 32
		dd	FAT12_NUM*16 + 1 + 2*FAT12_FATSECT ; 65273 (31.9 MB)

		db	16		; 16..31 MB: 16
		dd	FAT12_NUM*8 + 1 + 2*FAT12_FATSECT ; 32648 (15.9 MB)

		db	8		; 8..15 MB: 8
		dd	FAT12_NUM*4 + 1 + 2*FAT12_FATSECT ; 16337 (8 MB)

		db	4		; 4..7 MB: 4
		dd	FAT12_NUM*2 + 1 + 2*FAT12_FATSECT ; 8181 (4 MB)

		db	2		; 2..3.9 MB: 2
		dd	FAT12_NUM + 1 + 2*FAT12_FATSECT ; 4103 (2 MB)

		db	1		; 1..1.9 MB: 1
		dd	2048		; (1 MB)

		db	2		; 128..999 KB: 2
		dd	256		; (128 KB)

		db	1		; 0..127 KB: 1
		dd	0

; ------------- FAT16 default number of sectors per cluster
; Max. 65518 clusters, FAT size max. 256 sectors

FAT16ClustSize:	db	64		; 1024..2047 MB: 64
		dd	FAT16_NUM*32 + 1 + 2*FAT16_FATSECT ; 2097089 (1024 MB)

		db	32		; 512..1023 MB: 32
		dd	FAT16_NUM*16 + 1 + 2*FAT16_FATSECT ; 1048801 (512 MB)

		db	16		; 256..511 MB: 16
		dd	FAT16_NUM*8 + 1 + 2*FAT16_FATSECT ; 524657 (256 MB)

		db	8		; 128..255 MB: 8
		dd	FAT16_NUM*4 + 1 + 2*FAT16_FATSECT ; 262585 (128 MB)

		db	4		; 64..127 MB: 4
		dd	FAT16_NUM*2 + 1 + 2*FAT16_FATSECT ; 131549 (64 MB)

		db	2		; 32..63 MB: 2
		dd	FAT16_NUM + 1 + 2*FAT16_FATSECT ; 66031 (32 MB)

		db	1		; 8..31 MB: 1
		dd	16384		; (8 MB)

		db	2		; 4..7 MB: 2
		dd	8192		; (4 MB)

		db	4		; 2..3.9 MB: 4
		dd	4096		; (2 MB)

		db	8		; 256 KB..1.9 MB: 8
		dd	512		; (256 KB)

		db	1		; 0..255 KB: 1
		dd	0

; ------------- system disk info texts

SDTextDiskNum:	CTEXT	"System disks="
SDTextBIOS:	CTEXT	": ("
SDTextFAT12:	CTEXT	"h) FAT12"
SDTextFAT16:	CTEXT	"h) FAT16"
SDTextClust:	CTEXT	" clust="
SDTextRoot:	CTEXT	" root="
SDTextFAT:	CTEXT	" FAT="
SDTextStart:	CTEXT	" start="

; -----------------------------------------------------------------------------
;                            Uninitialised data
; -----------------------------------------------------------------------------

		DATA_SECTION

; ------------- System disks descriptors

		align	4, resb 1
SDDTab:		resb	SDD_size * SDISK_MAX ; disk descriptors
SDDNum:		resw	1		; number of valid system disks
SDDLastDisk:	resw	1		; index of last system disk + 1
SDDExtStart:	resd	1		; initialize - extended start sector
