; FAT12 I/O routines
; By: Christopher R. Evans in 2005, 2006

DEBUG_FAT12 EQU 0

FAT12_drive          db 0
FAT12_mounted        dw 0
FAT12_disk_modified  dw 0
FAT12_fat_start      dw 1
FAT12_fat2_start     dw 10
FAT12_fat_sectors    dw 9
FAT12_data_start     dw 33
FAT12_RootDirSecs    dw 0
FAT12_root_dir_start dw 0

debug_FAT12ROOT proc far
            IF (DEBUG_FAT12)
            push cs
            pop  es
            mov  si, offset [FAT12_ROOT]
            mov  cx, 128
            call debugdump
            call pauseprompt
            ENDIF
            ret
debug_FAT12ROOT endp

debug_FAT12FAT  proc far
            IF (DEBUG_FAT12)
            push cs
            pop  es
            mov  si, offset [FAT12_FAT]
            mov  cx, 128
            call debugdump
            call pauseprompt
            ENDIF
            ret
debug_FAT12FAT  endp

FAT12_Mount proc far
; DL = Driveno
; Output : CF = CY on error
            mov  cs:FAT12_drive, dl
            mov  FL_drive, dl
            call FL_RESET
            push cs
            pop  es                                        
            mov  ah, 2                   
            mov  al, 1 
            mov  cx, 1                   
            mov  dh, 0
            mov  dl, FL_Drive
            mov  bx, offset cs:bpbjump
            int  13h
            jc   FAT12_Mount_error
            mov  al, bSig
            cmp  al, 29h
            jne  FAT12_Mount_error
            cmp  byte ptr SystemID[4], '6'  ; check for FAT-16 system
            je   FAT12_Mount_error
            IF (DEBUG_FAT12)
            call cs:show_bpb
            call pauseprompt
            ENDIF
            call cs:FAT12_CALCPARAMS
            call cs:FAT12_loadroot
            jc   FAT12_Mount_error
            call debug_FAT12ROOT
            call cs:FAT12_loadfat
            jc   FAT12_Mount_error
            call debug_FAT12FAT
            call cs:FAT12_loadfat2
            jc   FAT12_Mount_error
            mov  ax, 1
            mov  FAT12_mounted, ax
            clc
            jmp  FAT12_Mount_Okay
FAT12_Mount_error:
            xor  ax, ax
            stc
FAT12_Mount_Okay:
            ret
FAT12_Mount endp

FAT12_unmount proc far
            mov  ax, FAT12_disk_modified
            or   ax, ax
            jz   FAT12_NO_COMMIT

            ; write FATS and root dir to disk
            call cs:FAT12_saveroot
            call cs:FAT12_savefat
            ; commit read cache to disk.

FAT12_NO_COMMIT:
            lea  di, FAT12_root
            mov  cx, FAT12_root_size
            mov  bl, 0
            call fillarray

            lea  di, FAT12_FAT
            mov  cx, FAT12_FAT1_size
            mov  bl, 0
            call fillarray

            lea  di, FAT12_FAT2
            mov  cx, FAT12_FAT2_size
            mov  bl, 0
            call fillarray
            xor  ax, ax
            mov  FAT12_mounted, ax
            ret
FAT12_unmount endp

FAT12_CALCPARAMS proc far
                mov  bx, word ptr [wReservedsects]
                xor  ax, ax
                xor  dx, dx
                add  ax, bx
                mov  bx, word ptr [lHiddensects]
                add  ax, bx
                mov  bx, word ptr [lHiddensects+2]
                adc  bx, 0 
                mov  word ptr FAT12_fat_start, ax
                ;
                mov  bx, wSectsperfat
                add  ax, bx
                mov  word ptr FAT12_fat2_start, ax
                ;
                mov  ax, wSectsperfat
                mov  word ptr FAT12_fat_sectors, ax

                xor  ax, ax
                mov  al, bFATs
                mov  bx, wSectsperfat
                xor  dx, dx
                mul  bx

                inc  ax
                mov  word ptr FAT12_root_dir_start, ax

                ;    18
                mov  ax, wRootentries
                mov  bx, 32
                xor  dx, dx
                mul  bx
                mov  bx, wSectsize
                div  bx
                mov  FAT12_RootDirSecs, ax  
                ; 14
                mov  ax, word ptr FAT12_fat_sectors
                mov  bx, 2
                xor  dx, dx
                mul  bx
                mov  bx, word ptr FAT12_RootDirSecs
                add  ax, bx
                inc  ax
                mov  FAT12_data_start, ax  
                ; 33

            IF (DEBUG_FAT12)
            mov  ax, FAT12_fat_start
            call putnum
            _echo ' '
            mov  ax, FAT12_root_dir_start
            call putnum
            _echo ' '
            mov  ax, FAT12_RootDirSecs
            call putnum
            _echo ' '
            mov  ax, FAT12_data_start
            call putnum
            _newline
            ENDIF

                ret
FAT12_CALCPARAMS endp

; the first sector of cluster 2 (data region) is computed as follows:
; FAT12_rootdirsectors = ((BPB_RootEntries*32)+(BPB_Bytespersec-1))/BPB_Bytespersec;
; rootdirectory size = BPB_reserved+(BPB_numFats*FATSz);
; 1st data sector = BPB_reserved+(BPB_numFats*FATSz)+RootDirSect;

FAT12_LoadRoot proc
            mov  dl, FAT12_drive
            mov  FL_drive, dl
            xor  dx, dx
            mov  ax, FAT12_root_dir_start    ; root directory location
            mov  di, FAT12_RootDirSecs     ; root dir size
            push cs
            pop  es
            mov  bx, offset [FAT12_ROOT]
            call readdisk
            jc   lraf_me
            push cs
            pop  es
            mov  bx, offset [FAT12_ROOT]
            clc
            ret
lraf_me:    stc
            ret
FAT12_LoadRoot endp

FAT12_SaveRoot proc
            mov  dl, FAT12_drive
            mov  FL_drive, dl
            xor  dx, dx
            mov  ax, FAT12_root_dir_start    ; root directory location
            mov  di, FAT12_RootDirSecs     ; root dir size
            push cs
            pop  es
            mov  bx, offset [FAT12_ROOT]
            call writedisk
            jc   sraf_me
            push cs
            pop  es
            mov  bx, offset [FAT12_ROOT]
            clc
            ret
sraf_me:    stc
            ret
FAT12_SaveRoot endp

FAT12_loadFAT proc far
            mov  dl, FAT12_drive
            mov  FL_drive, dl
            xor  dx, dx
            mov  ax, FAT12_fat_start
            mov  di, FAT12_fat_sectors
            push cs
            pop  es
            mov  bx, offset [FAT12_FAT]
            call readdisk
            jc   lraf_me2
            push cs
            pop  es
            mov  di, offset [FAT12_FAT]
            clc
            ret
lraf_me2:   stc
            ret
FAT12_loadFAT endp

FAT12_loadFAT2 proc far
            mov  dl, FAT12_drive
            mov  FL_drive, dl
            xor  dx, dx
            mov  ax, FAT12_fat2_start
            mov  di, FAT12_fat_sectors
            push cs
            pop  es
            mov  bx, offset [FAT12_FAT2]
            call readdisk
            jc   lraf2_me2
            push cs
            pop  es
            mov  di, offset [FAT12_FAT2]
            clc
            ret
lraf2_me2:   stc
            ret
FAT12_loadFAT2 endp

FAT12_saveFAT proc far
            mov  dl, FAT12_drive
            mov  FL_drive, dl
            xor  dx, dx
            mov  ax, FAT12_fat_start
            mov  di, FAT12_fat_sectors
            push cs
            pop  es
            mov  bx, offset [FAT12_FAT]
            call writedisk
            jc   sraf_me2
            push cs
            pop  es
            mov  di, offset [FAT12_FAT]
            clc
            ret
sraf_me2:   stc
            ret
FAT12_saveFAT endp

FAT12_saveFAT2 proc far
            mov  dl, FAT12_drive
            mov  FL_drive, dl
            xor  dx, dx
            mov  ax, FAT12_fat2_start
            mov  di, FAT12_fat_sectors
            push cs
            pop  es
            mov  bx, offset [FAT12_FAT2]
            call writedisk
            jc   sraf2_me2
            push cs
            pop  es
            mov  di, offset [FAT12_FAT2]
            clc
            ret
sraf2_me2:   stc
            ret
FAT12_saveFAT2 endp

FAT12_findfile proc far
; ES:SI = ROOT DIRECTORY
; DS:DI = Filename
; Output: AX = FIRST CLUSTER OF FILE
;         CF = CY on error
                mov     bx, wRootentries
FAT12_FF1:
                cmp  byte ptr es:[si], 0  ; null entry?
                je   FAT12_FNF   
                mov  cx, 0bh
                push si
                push di
                repe cmpsb   ; repeat if ZF = 1 CX > 0
                pop  di
                pop  si
                je   FAT12_FF
                dec  bx
                jz   FAT12_FNF
                add  si, 32      ; next entry
                jmp  FAT12_FF1
FAT12_FNF:    
                stc
                jmp  F12X
FAT12_FF:
                mov  ax, word ptr [SI+1aH]  ; first cluster
                cmp  ax, 2                  ; start cluster
                jb   FAT12_FNF   
                ; save first cluster for using by kernel
                mov  bl, byte ptr [SI+0bh]  ; move attribute byte to bl
                mov  cx, word ptr [SI+16h]  ; move time      word to cx
                mov  dx, word ptr [SI+18h]  ; move date      word to dx
                mov  si, word ptr [SI+1eH]  ; size low
                mov  di, word ptr [SI+1cH]  ; size high     
               ; and  bl, 0018h              ; notvalidfilemask
               ; ja   FAT12_FNF   
                clc
F12X:           ret
; OFFSET    LENGTH
; 00        8       -  Filename
; 08h       3       -  extension
; 0bh       1       -  attribute
; 0ch       10      -  reserved  unused in fat12/16
; 16h       2       -  time  BCD
; 18h       2       -  date  BCD
; 1ah       2       -  Starting cluster or 0
; 1ch       4       -  File Size in bytes
; 
FAT12_findfile endp

; loadfile (cluster, address) : boolean
; convert cluster to LBA
; read LBA sector for spc count into address
; add address + 512 bytes
; look up next cluster entry get new cluster value
; if cluster is 0ff0 or above then its eof
; if cluster is 0ff7 then it be a bad sector, abort.
; if cluster is 0ff8 then it end of file 
; loop to loadfile top

; ===========================================================================
loadimage proc far
; AX    = cluster
; ES:BX = buffer
; ===========================================================================
          push di
          push si
          push ds
          push es
          push ax
          push bx
          push dx
          mov  FAT12_cluster, ax
load_image:
          mov  ax, FAT12_cluster
          ; cluster to LBA
          dec  ax
          dec  ax      ; sub  ax, 2
          xor  cx, cx
          mov  cl, byte ptr [bSectsperclust]
          mul  cx
          add  ax, word ptr [FAT12_data_start]
          ;
;          xor  cx, cx
;          mov  cl, byte ptr [bSectsperclust]
;          call readsectors
         ; jc   li_failure

          mov  dl, FAT12_drive
          xor  dx, dx
          xor  cx, cx
          mov  cl, byte ptr [bSectsperclust]
          mov  di, cx
          xor  cx, cx
          call readdisk
          ; jc   li_failure


; ---------------------------------------------
          ; compute next cluster
          mov  ax, FAT12_cluster
          mov  cx, ax
          mov  dx, ax
          shr  dx, 1            ; divide by 2
          add  cx, dx
          mov  bx, offset FAT12_FAT
          add  bx, cx
          mov  dx, word ptr [bx]   ; read two bytes from FAT table
          test ax, 1
          jnz  li_odd_cluster
li_even_cluster:
          and  dx, 0FFFh           ; take twelve bits
          jmp  li_done
li_odd_cluster:
          shr  dx, 4               ; take high twelve bits
li_done:
          mov  FAT12_cluster, dx
          mov  cx, fat12_filesize
          add  cx, 512
          mov  fat12_filesize, cx
;          cmp  dx, 0ff7h
;          je   li_failure     
;          cmp  dx, 0ff8h
;          je   li_doneloading
          cmp  dx, 0ff0h
          jb   load_image
li_doneloading:
          clc
          mov  cx, fat12_filesize
          jmp  li_ret
li_failure:
          stc
li_ret:
          pop  dx
          pop  bx
          pop  ax
          pop  es
          pop  ds
          pop  si
          pop  di
          ret
FAT12_cluster dw 0
fat12_filesize dw 0
loadimage endp

;word nextcluster number filepointer, prevcluster
;{
;        offsetfromfat = prevcluster * 1.5
;        fatentrynum   = read contents from offsetfromfat+fatstartinglocation
;        if (nextcluster is even)
;                return fatentry & 0fffh
;           else
;                fatentrynum = fatentrynum >> 4  ; shr 4
;                fatentrynum = fatentrynum & 0fffh
;                return fatentrynum
;}

;int SearchAndPrintFile(filePointer, offset,fileName,startingClusterNumber,choice)
;{
;         if(current directory!= root directory)
;                 if(first Entry!='.'  || Second Entry!='..')
;                         return 0;
;
;        while(1)
;        {
;                if( current directory!=root directory)
;                            if( 16 entries are already read) 
;                                     get next cluster number from FAT;
;                 if(deleted entry)
;                            continue;
;                  if(first byte=0x00)
;                            return(numberOfMatchingFiles);
;                 
;                  if(current entry name = fileName)
;                            print file information;
;                             numberOfMatchingFiles++;
;                   
;                 if(current entry=sub directory)
;                       SearchAndPrintFile(filePointer, offset,fileName,startingClusterNumber,choice);
;                      
;            }
;               
;}

FAT12_ROOT  db ((224*32)+(512-1)/512) dup(0)
FAT12_ROOT_SIZE EQU $ - FAT12_ROOT
FAT12_FAT   db 9*512 dup(0) ; 0feh
FAT12_FAT1_SIZE EQU $ - FAT12_FAT
FAT12_FAT2  db 9*512 dup(0)
FAT12_FAT2_SIZE EQU $ - FAT12_FAT2
