; FEB-24-2006 - Design note, This BPB structure will be used for the fat16/32 code as well.

RETRYCOUNT      EQU 3
FDC_STATE       db 0
FDC_ERROR       db 0
floppynum       db 0
fl_drive        db 0
bootdrive       db 0

bpbjump   db 3 dup(0)
        include   \nxdos\src\boot\BPB.ASM
bpbfiller db 512 dup(0)

; ===========================================================================
; Primitives for interfacing directly with NEC micro PD765 chip controller
; ===========================================================================

WaitForFDC proc far
     mov  dx, 03F4h ; dx = port
w_FDC_l:
     in   al, dx                          ; al = main status register
     test al, 00010000b                 ; IF Bit 4 != 0...
     jnz  w_FDC_l                        ; ...THEN go on waiting
     mov  al, [FDC_STATE]                ; al = FDC state
     cmp  al, 0                          ; IF state != "ready"...
     jne  w_FDC_l                        ; ...THEN go on waiting
     ret
WaitForFDC endp

DisableFDD proc far
     call waitforFDC
     mov  dx, 03f2h   ; port for DOR
     mov  al, 00000000b
     out  dx, al      ; disable all FDDS and FDC
     ret
DisableFDD endp

SendFDCCommand proc far
; bl = command
        mov  dx, 03f4h
wait_loop:
        in   al, dx     ; status register
        test al, 80h    ; bit 7=0 = FDC not ready
        jz   wait_loop
        mov  al, bl
        mov  dx, 03f5h  ; write command to FDC
        out  dx, al
        ret
SendFDCCommand endp

GetFDCResult proc far
     mov  dx, 03f4h
g_FDC_r_l:
     in   al, dx   ; status
     test al, 80h
     jz  g_FDC_r_l
     mov  dx, 03f5h
     in   al, dx
     ret
GetFDCResult endp

RecalibrateFDD proc far

  call WaitForFDC ; wait until FDC is ready
  mov  al, 1
  mov [FDC_STATE], al ; FDC state = "command without result phase"

  mov bl, 00000111b ; bl = command byte 1 (command)
  call SendFDCCommand ; send command byte 1

  mov bl, [bootdrive] ; bl = command byte 2 (drive)
  call SendFDCCommand ; send command byte 2

  ret
RecalibrateFDD endp

EnableFDD proc far
  sti
  mov al, 1
  mov [FDC_STATE], al ; FDC state = "command without result phase"

  ; enable boot drive
  mov dl, [bootdrive] ; dl = boot drive
  cmp dl, 0 ; IF drive != 0 (a: under DOS)...
  jne check_b ; ...THEN wether it is 1 (b: under DOS)...
  mov al, 00011100b ; ...ELSE select drive 0
  jmp check_end
check_b:
  mov al, 00101101b ; select drive 1
check_end:
  mov dx, 03F2h ; dx = port of DOR
  out dx, al ; enable drive

  ; set data rate
  mov dx, 03F7h ; dx = port
  mov al , 00000000b ; al = data rate (500 kbit/s, standard)
  out dx, al ; write al to configuration register

  ; set other drive parameters
  mov bl, 00000011b
  call SendFDCCommand ; command byte 0 (command)
  mov bl, 00h ; step time = 16 ms, head move up time = 256 ms
  call SendFDCCommand ; command byte 1
  mov bl, 00000000b ; head move down time = 256 ms, DMA mode enabled
  call SendFDCCommand ; command byte 2

  ; recalibrate drive
  call RecalibrateFDD
  ret
EnableFDD endp

ReadPhysicalSector proc far
; ReadPhysicalSector: read physical sector from floppy disk
; in:  dh = head
;      ch = cylinder
;      cl = sector
;      es:di = destination address
; out: al = error code (0 = "no error", 1 = "error")
;-----------------------------------------------------------------------------
  push es
  push di ; save destination address
  push cx ; save sector
  push cx ; save sector
  push dx ; save head
  push cx ; save cylinder
  push dx ; save head
  push cx ; save cylinder
  push dx ; save head

  ; set up DMA channel
  mov  bl, 2 ; bl = DMA channel (FDC)
  call UnmaskDMAChannel ; unmask channel 2
  call DisableDMA ; disable DMA
  mov  al, 01000110b ; al = mode
  out  0Bh, al ; send mode to slave
  out  0Ch, al ; reset flip flop (value of al is not important)
  mov  al, 00h
  out  04h, al ; send low byte (0000XXh) of (temporary) destination address (001000h)
  mov  al, 10h
  out  04h, al ; send high byte (00XX00h) of (temporary) destination address (001000h)
  mov  al, 00h ; al = 64k page (XX0000h)
  out  81h, al ; send 64k page
  out  0Ch, al ; reset flip flop (value of al is not important)
  mov  al, 0FFh
  out  05h, al ; send low byte of data size (512 - 1 = 01FFh)
  mov  al, 01h
  out  05h, al ; send high byte of data size (512 - 1 = 01FFh)
  call EnableDMA ; enable DMA

  sti ; enable IRQs (perhaps disabled by int instruction)

  ; go to cylinder
  call WaitForFDC ; wait until FDC is ready
  mov  al, 1
  mov  [FDC_STATE], al ; FDC state = "command without result phase"
  mov  bl, 00001111b
  call SendFDCCommand ; command byte 0 (command)
  mov  bl, [bootdrive] ; bl = boot drive (D)
  pop  dx ; dh = head
  shl  dh, 2 ; bit 2 of dh = head (H)
  or   bl, dh ; bl = 00000HDD
  call SendFDCCommand ; command byte 1 (head, drive)
  pop  cx ; ch = cylinder
  mov  bl, ch ; bl = cylinder
  call SendFDCCommand ; command byte 2 (cylinder)

  ; prepare reading sector
  call WaitForFDC ; wait until FDC is ready
  mov  al, 2
  mov [FDC_STATE], al ; FDC state = "reading sector"

  ; command byte 0 (single track operation, MFM, no deleted address marks)
  mov  bl, 01100110b ; bl = command byte
  call SendFDCCommand

  ; command byte 1 (head, cylinder)
  mov  bl, [bootdrive] ; bl = boot drive (D)
  pop  dx ; dh = head (H)
  shl  dh, 2 ; bit 2 of dh = head
  or   bl, dh ; bl = 00000HDD
  call SendFDCCommand

  ; command byte 2 (cylinder)
  pop  cx ; ch = cylinder
  mov  bl, ch ; bl = cylinder
  call SendFDCCommand

  ; command byte 3 (head)
  pop  dx ; dh = head
  mov  bl, dh ; bl = head
  call SendFDCCommand

  ; command byte 4 (first sector to read)
  pop  cx ; cl = sector
  mov  bl, cl ; bl = sector
  call SendFDCCommand

  ; command byte 5 (sector size)
  mov  bl, 2 ; bl = sector size (512 byte)
  call SendFDCCommand

  ; command byte 6 (last sector to read)
  pop  cx ; cl = sector
  mov  bl, cl ; bl = sector
  call SendFDCCommand

  ; command byte 7
  mov  bl, 27 ; bl = GAP3 length (standard)
  call SendFDCCommand

  ; command byte 8
  mov  bl, 0FFh ; bl = data length (standard)
  call SendFDCCommand

  ; wait for command execution and analyse results
  call WaitForFDC ; wait until FDC is ready
  mov  al, [FDC_ERROR] ; al = FDC error code
  cmp  al, 0 ; IF error code == 0 ("no error")...
  je   copy_data ; ...THEN copy read data to destination address
  pop  dx ; clear stack
  mov  al, 1 ; al = error code = "error"
  jmp  rs_end

  ; copy data to destination address
copy_data:
  pop  di
  pop  es ; es:di
  push ds
  mov  ax, 0050h
  mov  ds, ax
  mov  si, 1000h ; ds:si = source address
  mov  cx, 512 ; copy 512 byte
  cld
  rep  movsb ; copy data
  pop  ds
  mov  al, 0 ; al = error code (no error)

rs_end:
  ret
ReadPhysicalSector endp

;-----------------------------------------------------------------------------
ReadSector proc far ; read sector from floppy disk
;-----------------------------------------------------------------------------
; in:  bx = LSN
;      es:di = destination address
; out: al = error code (0 = "no error", 1 = "error")
;-----------------------------------------------------------------------------
    mov cx, RETRYCOUNT
read_loop:
    push bx ; save LSN
    push cx ; save counter
    push di ; save destination offset

    ; read sector
    mov  ax, bx
    call cs:LBA_To_CHS ; cl = sector, ch = cylinder, dh = head
    call ReadPhysicalSector ; read sector
    cmp al, 0 ; IF error code == 0 ("no error")...
    je rs_success1 ; ...THEN terminate reading sector

    call RecalibrateFDD ; recalibrate drive

    pop di ; edi = destination offset
    pop cx ; load counter
    pop bx ; bx = LSN
    loop read_loop ; read again

    ; reading sector failed
    mov al, 1 ; al = error code (error)
    jmp readsect_end

    ; sector successfully read
rs_success1:
    pop ax ; clear stack
    pop ax ; clear stack
    pop ax ; clear stack
    mov al, 0 ; al = error code ("no error")
readsect_end:
    ret
ReadSector endp 

; ===========================================================================
; Bios dependant routines for high level disk support
; ===========================================================================

FL_RESET proc far
; DL = Drive
		mov	ah,0		; reset disk
		int	13h
                jc      FL_RESET_ERR
                mov  ax, 1              ; TRUE okay
                ret
FL_RESET_ERR:   mov  ax, 0              ; FALSE is not
                ret                     
FL_RESET endp

fl_readdisk proc far
                mov     cx,[FL_cylinder]      ; cylinder number
		mov	al,1		; error code
		cmp	ch,3
		ja	fl_error	; can't write above 3FFh=1023

		xchg	ch,cl		; ch=low 8 bits of cylinder number
                mov     dh,[FL_head]      ; head number
		ror	cl,1		; bits 8-9 of cylinder number...
                ror    cl,1            ; ...to bits 6-7 in CL
                or      cl,[FL_sector]      ; sector number (bits 0-5)

                mov     al,[FL_no_sectors]       ; number of sectors
                mov  bx, FL_READBUF_SEG
                mov  es, bx
                mov  bx, FL_READBUF_OFS
                mov     dl,[FL_Drive]      ; drive (if or'ed 80h its hard drive)
		int	13h		; process sectors

		sbb	al,al		; carry: al=ff, else al=0
		and	al,ah		; carry: error code, else 0
fl_error:
		mov	ah,0
                ret
FL_READBUF_SEG dw ?
FL_READBUF_OFS dw ?
FL_no_sectors  db ?
FL_sector      db ?
FL_head        db ?
FL_cylinder    dw ?
fl_readdisk endp

FL_LBA_READWRITE proc far
; Returns 0 if successful, error code otherwise.
		push	si
		push	ds
                mov     dl,[FL_LBA_W_Drive]      ; drive (if or'ed 80h its hard drive)
                mov     ax,[FL_LBA_W_Commd]       ; command
                lds     si,[FL_LBA_W_Addr]       ; far dap pointer
		int	13h		; process sectors
		pop	ds
		pop	si
		mov	al,ah		; place error code into al
		mov	ah,0
                ret      
FL_LBA_W_Drive  db 0
FL_LBA_W_Commd  dw 0
FL_LBA_W_Addr   dd 0
FL_LBA_READWRITE endp

FL_DISKCHANGED proc far
; Read disk change line status.
; returns 1 if disk has changed, 0 if not, 0xFF if error.
; DL = Drive 
                mov  ah,16h          ; read change status type
                ; mov  dl, drive
                int  13h
                jc   changelineinactive
                cmp  ah, 6
                jne  FL_DC_ERROR
                mov  ax, 0001h
                jmp  short FL_DC_X
FL_DC_ERROR:    mov  ax, 00ffh
                jmp  short FL_DC_X
changelineinactive:
                xor  ax, ax
FL_DC_X:
                ret
FL_DISKCHANGED endp

; Format tracks (sector should be 0).

FL_FORMAT proc far
                mov  ah,5            ; format track
                call fl_readdisk
                ret
FL_FORMAT endp

FL_VERIFY proc far
		mov	ah,4		; verify sector(s)
                call fl_readdisk
                ret
FL_VERIFY endp

FL_READ proc far
		mov	ah,2		; read sector(s)
                call fl_readdisk
                ret
FL_READ endp

FL_WRITE proc far
		mov	ah,3		; write sector(s)
                call fl_readdisk
                ret
FL_WRITE endp

FL_SETDISKTYPE proc far
; AL = FORMAT TYPE
; DL = DRIVE 
		mov	ah,17h		; set disk type for format
		int	13h
		ret
FL_320_360K    EQU 01h
FL_320_360K12M EQU 02h
FL_12M         EQU 03h
FL_720K        EQU 04h
FL_SETDISKTYPE endp

FL_SETMEDIATYPE proc far
; DL = drive
; CX = number of tracks
; BX = sectors pre track

                mov  ah, 18h            ; set media type for format
                dec  ch
                xchg ch, cl
                ror  cl, 1
                ror  cl, 1
                or   cl, bl
                int  13h
                jc   skip1eDPT
		push	es
		xor	dx,dx
		mov	es,dx
		cli
                mov     [es:1eh*4],di
                pop     word [es:1eh*4+2] ; set int 0x1e table to es:di
		sti
skip1eDPT:
                ret
FL_SETMEDIATYPE endp

LBACHS proc near
;*************************************************************************
; PROCEDURE LBACHS
; convert "ax=2; LBA addressing scheme to CHS addressing scheme
; absolute sector = (logical sector / sectors per track) + 1
; absolute head   = (logical sector / sectors per track) MOD number of heads
; absolute track  = logical sector / (sectors per track * number of heads)
; BX = SPT
; CX = Heads
; AX = LBASECTOR
;*************************************************************************

     push ax
     push bx
     push cx
     xor  dx, dx
     div  bx
     inc  dl
     mov  byte ptr [lbachs_sector], dl
     pop  bx  ; heads
     xor  dx, dx
     div  bx
     mov  byte ptr [lbachs_Head], dl
     mov  byte ptr [lbachs_Track], al
     pop  bx
     pop  bx
     mov  al, lbachs_sector
     mov  bl, lbachs_head
     mov  cl, lbachs_track
     ret
lbachs_sector db ?
lbachs_head   db ?
lbachs_track  db ?
LBACHS endp

CalcCHS proc far
;Abs sector = (SPT / LOGICAL SECTOR) +1
;Abs head   = (SPT / LOGICAL SECTOR) MOD heads
;Abs track  = SPT / (LOGICAL SECTOR * heads)
        push bx
        cmp  ax, wSectspertrack
        jnb  Secttoobig
        push ax
        mov  bx, ax
        mov  ax, wSectspertrack
        xor  dx, dx
        div  bx
        clc
        jmp  short CALCCHSX
Secttoobig:
        stc
CALCCHSx:
        pop  bx
        ret
CHS_Sector db 0
CHS_Head   db 0
CHS_Track  dw 0
CalcCHS endp

LBA_to_CHS proc far
; AX = LSN
        push ax

        ; calculate head = (LSN/SPT)%2
        mov  bx, wSectspertrack
        xor  dx, dx
        div  bx
        and  al, 01h   ; clear bit 1 to 7  al = al % 2
        mov  dh, al    ; head
        ;
        ; calculate track
        pop  ax
        push ax
        mov  bx, wSectspertrack
        add  bx, wSectspertrack
        xor  dx, dx
        div  bx        ; track = LSN / (2 * SPT)
        mov  ch, al    ; track
        ;
        ; calculate sector
        pop  ax
        mov  bx, wSectspertrack
        xor  dx, dx
        div  bx
        inc  dl
        mov  cl, dl  ; ah
        ret
LBA_to_CHS endp

readsectors proc far
; CX    = sectors
; AX    = Starting sector
; ES:BX = Buffer
rs_main:
        mov  di, RETRYCOUNT
rs_sectorloop:
        mov  rs_sect, ax
        mov  rs_sects, cx
        ;
        xor  dx, dx
        div  word ptr [wSectspertrack]
        inc  dl
        mov  byte ptr [abssector], dl
        xor  dx, dx
        div  word ptr [wHeads]
        mov  byte ptr [abshead], dl
        mov  byte ptr [abstrack], al
        ;
        mov  ah, 02h
        mov  al, 01
        mov  ch, byte ptr [abstrack]
        mov  cl, byte ptr [abssector]
        mov  dh, byte ptr [abshead]
        mov  dl, FL_Drive
        int  13h
        jnc  rs_success
        xor  ax, ax
        int  13h
        dec  di
        mov  ax, cs:rs_sect
        mov  cx, cs:rs_sects
        jnz  rs_sectorloop
        stc
        jmp  rs_x
rs_success:
        mov  ax, 0e2eh
        int  10h
        clc
        mov  ax, cs:rs_sect
        mov  cx, cs:rs_sects
        add  bx, wSectsize
        inc  ax
        ; dec cx
        loop rs_main
rs_x:
        ret
abssector db 0
abshead   db 0
abstrack  db 0
rs_sect   dw 0
rs_Sects  dw 0
readsectors endp

writesectors proc far
; CX    = sectors
; AX    = Starting sector
; ES:BX = Buffer
ws_main:
        mov  di, RETRYCOUNT
ws_sectorloop:
        push ax
        push bx
        push cx
        ;
        xor  dx, dx
        div  word ptr [wSectspertrack]
        inc  dl
        mov  byte ptr [abssector], dl
        xor  dx, dx
        div  word ptr [wHeads]
        mov  byte ptr [abshead], dl
        mov  byte ptr [abstrack], al
        ;
        mov  ah, 03h
        mov  al, 01
        mov  ch, byte ptr [abstrack]
        mov  cl, byte ptr [abssector]
        mov  dh, byte ptr [abshead]
        mov  dl, FL_Drive
        int  13h
        jnc  ws_success
        xor  ax, ax
        int  13h
        dec  di
        pop  cx
        pop  bx
        pop  ax
        jnz  ws_sectorloop
        stc
        jmp  ws_x
ws_success:
        mov  ax, 0e2eh
        int  10h
        clc
        pop  cx
        pop  bx
        pop  ax
        add  bx, wSectsize
        inc  ax
        loop ws_main
ws_x:
        ret
writesectors endp

; ===========================================================================
readDisk        proc far
;       readDisk:       Reads a number of sectors into memory.
;
;       Call with:      DX:AX = 32-bit DOS sector number
;                       DI = number of sectors to read
;                       ES:BX = destination buffer
;                       ES must be 64k aligned (1000h, 2000h etc).
;
;       Returns:        CF set on error
;                       ES:BX points one byte after the last byte read. 
; ===========================================================================
		push    si
read_next:      push    dx
		push    ax

		;
		; translate sector number to BIOS parameters
		;

		;
		; abs = sector                          offset in track
		;     + head * sectPerTrack             offset in cylinder
		;     + track * sectPerTrack * nHeads   offset in platter
		; 
		; t1     = abs  /  sectPerTrack         (ax has t1)
		; sector = abs mod sectPerTrack         (cx has sector)
		;
                div     word ptr wSectspertrack
		mov     cx, dx

		;
		; t1   = head + track * nHeads
		;
		; track = t1  /  nHeads                 (ax has track)
		; head  = t1 mod nHeads                 (dl has head)
		;
		xor     dx, dx
                div     word ptr wHeads

		; the following manipulations are necessary in order to 
		; properly place parameters into registers.
		; ch = cylinder number low 8 bits
		; cl = 7-6: cylinder high two bits
		;      5-0: sector
		mov     dh, dl                  ; save head into dh for bios
		ror     ah, 1                   ; move track high bits into
		ror     ah, 1                   ; bits 7-6 (assumes top = 0)
		xchg    al, ah                  ; swap for later
                mov     dl, byte ptr wSectspertrack
		sub     dl, cl
		inc     cl                      ; sector offset from 1
		or      cx, ax                  ; merge cylinder into sector
		mov     al, dl                  ; al has # of sectors left

		; Calculate how many sectors can be transfered in this read
		; due to dma boundary conditions.
		push    dx

		mov     si, di                  ; temp register save
		; this computes remaining bytes because of modulo 65536
		; nature of dma boundary condition
		mov     ax, bx                  ; get offset pointer
		neg     ax                      ; and convert to bytes
		jz      ax_min_1                ; started at seg:0, skip ahead

		xor     dx, dx                  ; convert to sectors
                div     word ptr wSectsize
		
		cmp     ax, di                  ; check remainder vs. asked
		jb      ax_min_1                ; less, skip ahead
		mov     si, ax                  ; transfer only what we can

ax_min_1:       pop     dx

		; Check that request sectors do not exceed track boundary
                mov     si, wSectspertrack
		inc     si
		mov     ax, cx                  ; get the sector/cyl byte
		and     ax, 03fh                ; and mask out sector
		sub     si, ax                  ; si has how many we can read
		mov     ax, di
		cmp     si, di                  ; see if asked <= available
		jge     ax_min_2
		mov     ax, si                  ; get what can be xfered

ax_min_2:       mov     si, RETRYCOUNT
		mov     ah, 2
                mov     dl, FL_drive

retry:          push    ax
		int     13h
		pop     ax
                jnc     read_ok
		push    ax
		xor     ax, ax          ; reset the drive
		int     13h
		pop     ax
		dec     si
		jnz     retry
		stc
		pop     ax
		pop     dx
		pop     si
		ret

read_next_jmp:  jmp     short read_next
read_ok:        xor     ah, ah                          
		mov     si, ax                  ; AX = SI = number of sectors read      
                mul     word ptr wSectsize ; AX = number of bytes read
		add     bx, ax                  ; add number of bytes read to BX
		jnc     no_incr_es              ; if overflow...

		mov     ax, es       
		add     ah, 10h                 ; ...add 1000h to ES
		mov     es, ax
		
no_incr_es:     pop     ax
		pop     dx                      ; DX:AX = last sector number

		add     ax, si
		adc     dx, 0                   ; DX:AX = next sector to read
		sub     di, si                  ; if there is anything left to read,
                jg      read_next_jmp           ; continue

		clc
		pop     si
		ret
readDisk        endp

; ===========================================================================
writeDisk        proc far
;       writeDisk:       writes a number of sectors into memory.
;
;       Call with:      DX:AX = 32-bit DOS sector number
;                       DI = number of sectors to write
;                       ES:BX = destination buffer
;                       ES must be 64k aligned (1000h, 2000h etc).
;
;       Returns:        CF set on error
;                       ES:BX points one byte after the last byte write. 
; ===========================================================================
		push    si
write_next:      push    dx
		push    ax

		;
		; translate sector number to BIOS parameters
		;

		;
		; abs = sector                          offset in track
		;     + head * sectPerTrack             offset in cylinder
		;     + track * sectPerTrack * nHeads   offset in platter
		; 
		; t1     = abs  /  sectPerTrack         (ax has t1)
		; sector = abs mod sectPerTrack         (cx has sector)
		;
                div     word ptr wSectspertrack
		mov     cx, dx

		;
		; t1   = head + track * nHeads
		;
		; track = t1  /  nHeads                 (ax has track)
		; head  = t1 mod nHeads                 (dl has head)
		;
		xor     dx, dx
                div     word ptr wHeads

		; the following manipulations are necessary in order to 
		; properly place parameters into registers.
		; ch = cylinder number low 8 bits
		; cl = 7-6: cylinder high two bits
		;      5-0: sector
		mov     dh, dl                  ; save head into dh for bios
		ror     ah, 1                   ; move track high bits into
		ror     ah, 1                   ; bits 7-6 (assumes top = 0)
		xchg    al, ah                  ; swap for later
                mov     dl, byte ptr wSectspertrack
		sub     dl, cl
		inc     cl                      ; sector offset from 1
		or      cx, ax                  ; merge cylinder into sector
		mov     al, dl                  ; al has # of sectors left

                ; Calculate how many sectors can be transfered in this write
		; due to dma boundary conditions.
		push    dx

		mov     si, di                  ; temp register save
		; this computes remaining bytes because of modulo 65536
		; nature of dma boundary condition
		mov     ax, bx                  ; get offset pointer
		neg     ax                      ; and convert to bytes
                jz      wr_ax_min_1                ; started at seg:0, skip ahead

		xor     dx, dx                  ; convert to sectors
                div     word ptr wSectsize
		
		cmp     ax, di                  ; check remainder vs. asked
                jb      wr_ax_min_1                ; less, skip ahead
		mov     si, ax                  ; transfer only what we can

wr_ax_min_1:       pop     dx

		; Check that request sectors do not exceed track boundary
                mov     si, wSectspertrack
		inc     si
		mov     ax, cx                  ; get the sector/cyl byte
		and     ax, 03fh                ; and mask out sector
                sub     si, ax                  ; si has how many we can write
		mov     ax, di
		cmp     si, di                  ; see if asked <= available
                jge     wr_ax_min_2
		mov     ax, si                  ; get what can be xfered

wr_ax_min_2:       mov     si, RETRYCOUNT
                mov     ah, 3
                mov     dl, FL_drive

wr_retry:          push    ax
		int     13h
		pop     ax
                jnc     write_ok
		push    ax
		xor     ax, ax          ; reset the drive
		int     13h
		pop     ax
		dec     si
                jnz     wr_retry
		stc
		pop     ax
		pop     dx
		pop     si
		ret

write_next_jmp:  jmp     short write_next
write_ok:        xor     ah, ah                          
                mov     si, ax                  ; AX = SI = number of sectors write      
                mul     word ptr wSectsize ; AX = number of bytes write
                add     bx, ax                  ; add number of bytes write to BX
                jnc     wr_no_incr_es              ; if overflow...

		mov     ax, es       
		add     ah, 10h                 ; ...add 1000h to ES
		mov     es, ax
		
wr_no_incr_es:  pop     ax
		pop     dx                      ; DX:AX = last sector number

		add     ax, si
                adc     dx, 0                   ; DX:AX = next sector to write
                sub     di, si                  ; if there is anything left to write,
                jg      write_next_jmp           ; continue

		clc
		pop     si
		ret
writeDisk        endp

; ===========================================================================
SHOW_BPB proc far
; ===========================================================================
        _output  aboem, 8, 1
        _newline

        _print SectSize_msg, 1
        mov  ax, wsectsize
        call putnum
        _newline
        _print SPC______msg, 1
        xor  ax, ax
        mov  al, bSectsperclust
        call putnum
        _newline
        _print Reserved_msg, 1
        xor  ax, ax
        mov  ax, wReservedsects
        call putnum
        _newline
        _print FATS_____msg, 1
        xor  ax, ax
        mov  al, bFats
        call putnum
        _newline
        _print RootEnt__msg, 1
        xor  ax, ax
        mov  ax, wRootentries
        call putnum
        _newline
        _print SmallSec_msg, 1
        xor  ax, ax
        mov  ax, wSmallsectors
        call putnum
        _newline
        _print MediaID__msg, 1
        xor  ax, ax
        mov  al, bMedia
        call put_hex
        _echo 'H'
        _newline
        _print SPF______msg, 1
        xor  ax, ax
        mov  ax, wSectsperfat 
        call putnum
        _newline
        _print SPT______msg, 1
        xor  ax, ax
        mov  ax, wSectspertrack 
        call putnum
        _newline
        _print Heads____msg, 1
        xor  ax, ax
        mov  ax, wHeads 
        call putnum
        _newline
        _print Hiddensc_msg, 1
        xor  ax, ax
        mov  ax, word ptr lHiddensects+2
        call putnum
        mov  ax, word ptr lHiddensects
        call putnum
        _newline
        _print Largesec_msg, 1
        xor  ax, ax
        mov  ax, word ptr lLargesects+2
        call putnum
        mov  ax, word ptr lLargesects
        call putnum
        _newline
        _print Driveno__msg, 1
        xor  ax, ax
        mov  al, bPhysicaldrvno
        call putnum
        _newline
        _print CurHead__msg, 1
        xor  ax, ax
        mov  al, bCurrenthead
        call putnum
        _newline
        _print bpb_sig__msg, 1
        xor  ax, ax
        mov  al, bSig
        call put_hex
        _echo 'H'
        _newline
        _print Serialno_msg, 1
        xor  ax, ax
        mov  ax, word ptr lSerialNo+2
        call put_hex
        mov  ax, word ptr lSerialNo
        call put_hex
        _echo 'H'
        _newline
        _print Vollabel_msg, 1
        _output Vollabel, 11, 1
        _newline
        _print SystemID_msg, 1
        _output SystemID, 07, 1
        _newline
         ret
SectSize_msg db 'Sector    : ',0
SPC______msg db 'S.P.C.    : ',0
Reserved_msg db 'Reserved  : ',0
Fats_____msg db 'FAT(s)    : ',0
RootEnt__msg db 'Root block: ',0
SmallSec_msg db 'Small Sect: ',0
MediaID__msg db 'Media Type: ',0
SPF______msg db 'S. Per FAT: ',0
SPT______msg db 'S.P.T.    : ',0
Heads____msg db 'Heads     : ',0
Hiddensc_msg db 'Hidden    : ',0
Largesec_msg db 'Large Sect: ',0
Driveno__msg db 'Drive     : ',0
Curhead__msg db 'Head      : ',0
bpb_sig__msg db 'BPB Flag  : ',0
Serialno_msg db 'Serial  # : ',0
vollabel_msg db 'Volume    : ',0
SystemID_msg db 'System ID : ',0
SHOW_BPB endp
