686 lines
23 KiB
Text
686 lines
23 KiB
Text
//------------------------------------------------------------------------
|
|
// FAT16 Library Low Level
|
|
//
|
|
// Author: Mattias Hansson
|
|
// Target: Commodore 64 with MMC64 interface
|
|
// (possible future conversions for other platforms possible)
|
|
//
|
|
// Purpose: To provide lowlevel access routines for the FAT16 Library
|
|
//
|
|
// Routines:
|
|
// lib_fat16_int_read_cluster_sector (INTERNAL)
|
|
//
|
|
//
|
|
//
|
|
//------------------------------------------------------------------------
|
|
|
|
|
|
#IFNDEF __LIB_FAT16LOW
|
|
#DEFINE __LIB_FAT16LOW = 1
|
|
|
|
GOTO lib_fat16low_skip
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
// FAT16 constants
|
|
//------------------------------------------------------------------------
|
|
WORD CONST LIB_FAT16_CLUSTER_FREE = $0000
|
|
WORD CONST LIB_FAT16_CLUSTER_END = $fff0 //this value or above = clusterchain ended
|
|
BYTE CONST LIB_FAT16_DIRENTRY_SIZE = $20
|
|
BYTE CONST LIB_FAT16_DELETED_FILE = $e5
|
|
BYTE CONST LIB_FAT16_END_OF_DIR = $00
|
|
WORD CONST LIB_FAT16_SECTOR_SIZE = 512
|
|
|
|
//******Do NOT EVER access this var as a regular variable***********
|
|
//special: this is NOT a regular variable for usage!!!!!!!!!!!!!!!!!
|
|
//The "Address" defines how many files may be open simultainously!!!
|
|
//If you want to change the number of open files, change the!!!!!!!!
|
|
//address to the number you of files you want open!!!!!!!!!!!!!!!!!!
|
|
BYTE lib_fat16_max_open_files @ __LIB_FAT16_MAX_OPEN_FILES
|
|
//******Do NOT EVER access this var as a regular variable***********
|
|
|
|
BYTE CONST LIB_FAT16_FILEMODE_READ = 0
|
|
BYTE CONST LIB_FAT16_FILEMODE_WRITE = 1
|
|
//This filemode is special as it's only valid for fclose()
|
|
//This file gets set when blockwriting another size then $512
|
|
//as further writes would not be alligned with the sectors.
|
|
BYTE CONST LIB_FAT16_FILEMODE_WRITE_ENDED = 2
|
|
//BYTE CONST LIB_FAT16_FILEMODE_READWRITE = 2 //future expansion
|
|
|
|
#IFDEF __LIB_FAT16_WRITESUPPORT
|
|
//This constant controls how many consecutive clusters will be controlled
|
|
//for beeing free when mounting a partition for read/write access.
|
|
//Generally speaking this is good when having an unfragmented disk/card
|
|
//with just a little data on it, as i shortens the mount time.
|
|
|
|
//However if you'll be writing much data (like several megabytes) you'll
|
|
//probably want to set this to $ffff (no limit) since this will not add
|
|
//any performance penalty (for searching new free clusters) when you've
|
|
//reached the limit.
|
|
|
|
#IFDEF __LIB_MMC64_OPTIMIZE_SPEED
|
|
WORD CONST LIB_FAT16_WRITE_CLUSTERS_MAX = $400
|
|
#IFEND
|
|
#IFNDEF __LIB_MMC64_OPTIMIZE_SPEED
|
|
//Explanation: if we don't cache the reads, every single cluster
|
|
//we search (in fat) will force the lib to re-read the sector again
|
|
//which will take painfully much time
|
|
#PRINT __LIB_MMC64_OPTIMIZE_SPEED combined with __LIB_FAT16_WRITESUPPORT is catastrophic performance-wise.
|
|
WORD CONST LIB_FAT16_WRITE_CLUSTERS_MAX = $10
|
|
#IFEND
|
|
|
|
|
|
#IFEND
|
|
|
|
//------------------------------------------------------------------------
|
|
// FAT16 common variables
|
|
//------------------------------------------------------------------------
|
|
|
|
//Info for developers: the lib_fat16_buffer_ptr must point out an 512 byte area
|
|
//You can choose to do so by a constant or variable.
|
|
//Default is a variable that points out an area reserved inside this library
|
|
//called "lib_fat16_fatbuffer". If you change this to a constant, remark
|
|
//the "lib_fat16_fatbuffer" area to save the unused filler.
|
|
|
|
//WORD CONST lib_fat16_buffer_ptr = $c800 //change this for your particular usage
|
|
// //(size needed is "one sector" = 512 bytes )
|
|
|
|
WORD lib_fat16_buffer_ptr
|
|
BYTE lib_fat16_sectors_per_cluster // needed for cluster reading routine
|
|
WORD lib_fat16_reserved_sectors // offset from FAT16 boot record to FATs (file allocation tables)
|
|
BYTE lib_fat16_nr_of_fats // self*sectors_per_fat = offset from FATs to the root directory
|
|
WORD lib_fat16_sectors_per_fat // (see above)
|
|
WORD lib_fat16_rootdir_entries // Max file-entries in the ROOT directory
|
|
// ( self * size of directory entry (32) ) / 512 =
|
|
// offset from ROOT directory to DATA area (where clusters begin.
|
|
// N.B. First cluster here is #2 (!))
|
|
WORD lib_fat16_rootdir_sectors // calculated size of rootdir measured in sectors.
|
|
|
|
#IFDEF __LIB_FAT16_WRITESUPPORT
|
|
|
|
WORD lib_fat16_total_clusters = 0 // ( sectors_per_fat * bytes_per_sector ($200) ) / 2 == ( sectors_per_fat * $100 ).
|
|
|
|
WORD lib_fat16_first_write_cluster = $ffff //these two are used internally by lib_fat16_int_find_unused_clusters and
|
|
WORD lib_fat16_last_write_cluster = $0000 //lib_fat16_fwriteblock to find new areas for writing bit by bit (as needed)
|
|
WORD lib_fat16_total_sectors_lo
|
|
WORD lib_fat16_total_sectors_hi
|
|
|
|
#IFEND
|
|
|
|
//Temp ZP-variables for usage in the lib.
|
|
WORD lib_fat16_tempw @ $3f
|
|
WORD lib_fat16_tempw2 @ $4b
|
|
BYTE lib_fat16_tempb @ $41
|
|
|
|
//------------------------------------------------------------------------
|
|
// 512 byte internal buffer for FAT16 operations.
|
|
//------------------------------------------------------------------------
|
|
LABEL lib_fat16_fatbuffer
|
|
ASM
|
|
!fill 512
|
|
ENDASM
|
|
|
|
//------------------------------------------------------------------------
|
|
// lib_fat16_int_read_cluster_sector (INTERNAL)
|
|
//
|
|
// Purpose:
|
|
// 1. To read out a specific sector in a specific cluster
|
|
// or
|
|
// 2. To read out a sector in the root-dir
|
|
//
|
|
// Parameters:
|
|
// lib_fat16_int_rc_cluster - cluster to read. special: 0 = root-dir
|
|
// lib_fat16_int_rc_sector - sector # inside the cluster (0..lib_fat16_sectors_per_cluster-1)
|
|
// special: if in root-dir (0..lib_fat16_rootdir_sectors-1)
|
|
// lib_fat16_int_rc_buffer_ptr - pointer, where to put the read sector in memory
|
|
// lib_fat16_int_rc_status - 0 = OK. !0 = error.
|
|
//
|
|
// Preparation: lib_fat16_mount_partition
|
|
//
|
|
// Usage of lib temp variables:
|
|
// lib_fat16_tempw2
|
|
// lib_fat16_tempb
|
|
//------------------------------------------------------------------------
|
|
|
|
WORD lib_fat16_int_rc_cluster
|
|
WORD lib_fat16_int_rc_sector
|
|
WORD lib_fat16_int_rc_buffer_ptr
|
|
BYTE lib_fat16_int_rc_status
|
|
|
|
FUNC lib_fat16_int_read_cluster_sector ( lib_fat16_int_rc_cluster lib_fat16_int_rc_sector lib_fat16_int_rc_buffer_ptr out:lib_fat16_int_rc_status )
|
|
WORD first_pos // in bytes
|
|
WORD read_count
|
|
|
|
LET first_pos = 0
|
|
LET read_count = LIB_FAT16_SECTOR_SIZE
|
|
|
|
FUNC lib_fat16_int_read_cluster_sector_part ( lib_fat16_int_rc_cluster lib_fat16_int_rc_sector lib_fat16_int_rc_buffer_ptr first_pos read_count out:lib_fat16_int_rc_status )
|
|
|
|
BYTE spc_count
|
|
WORD csect_offset_lo
|
|
BYTE csect_offset_hi
|
|
BYTE callstat //status for internal calls
|
|
|
|
|
|
LET lib_fat16_int_rc_status = 1 //indicate an error at first (we SUBEND out if things go wrong)
|
|
|
|
IF lib_fat16_int_rc_cluster == 0 //the root directory
|
|
IF lib_fat16_int_rc_sector >= lib_fat16_rootdir_sectors
|
|
SUBEND // caller tried to make us read past the root-dir region. probably an internal error.
|
|
ENDIF
|
|
//Now we must add the start sector for the rootdir with the sector requested inside it, to get the right one
|
|
ASM
|
|
clc
|
|
lda lib_fat16_rootdir_sector_lo
|
|
adc lib_fat16_int_rc_sector
|
|
sta lib_fat16_tempw2
|
|
lda lib_fat16_rootdir_sector_lo+1
|
|
adc lib_fat16_int_rc_sector+1
|
|
sta lib_fat16_tempw2+1
|
|
lda lib_fat16_rootdir_sector_hi
|
|
adc #0
|
|
sta lib_fat16_tempb
|
|
ENDASM
|
|
CALL lib_mmc64_readsector ( lib_fat16_tempw2 lib_fat16_tempb lib_fat16_int_rc_buffer_ptr callstat )
|
|
IF callstat != 0
|
|
SUBEND
|
|
ENDIF
|
|
GOTO lib_fat16_int_rc_exit_success
|
|
ENDIF
|
|
|
|
//Else this is a real cluster in the dataarea that's about to be read
|
|
IF lib_fat16_int_rc_sector >= lib_fat16_sectors_per_cluster
|
|
SUBEND // caller passed a sector offset beyond the end of the cluster. probably an internal error
|
|
ENDIF
|
|
|
|
//Adjust for data-area starting with cluster #2
|
|
SUBT lib_fat16_int_rc_cluster - 2 -> lib_fat16_int_rc_cluster
|
|
|
|
//Now we must multiply the clusternr with "nr of sectors per cluster" to
|
|
//get a valid sector-offset into the data-area
|
|
LET csect_offset_lo = lib_fat16_int_rc_cluster
|
|
LET csect_offset_hi = 0
|
|
LET spc_count = lib_fat16_sectors_per_cluster
|
|
//First bit unimportant (1 sector per cluster and we're done here!)
|
|
ASM
|
|
lsr |spc_count|
|
|
ENDASM
|
|
WHILE spc_count
|
|
ASM
|
|
clc
|
|
rol |csect_offset_lo|
|
|
rol |csect_offset_lo|+1
|
|
rol |csect_offset_hi|
|
|
|
|
lsr |spc_count|
|
|
ENDASM
|
|
WEND
|
|
|
|
// "real sector to access" = "start of data area" + "cluster sector offset" + lib_fat16_int_rc_sector (sector # in cluster)
|
|
//first we do "start of data area" + "cluster sector offset"
|
|
ASM
|
|
clc
|
|
lda lib_fat16_data_sector_lo
|
|
adc |csect_offset_lo|
|
|
sta lib_fat16_tempw2
|
|
lda lib_fat16_data_sector_lo+1
|
|
adc |csect_offset_lo|+1
|
|
sta lib_fat16_tempw2+1
|
|
lda lib_fat16_data_sector_hi
|
|
adc |csect_offset_hi|
|
|
sta lib_fat16_tempb
|
|
ENDASM
|
|
//now we add the lib_fat16_int_rc_sector
|
|
ASM
|
|
clc
|
|
lda lib_fat16_tempw2
|
|
adc |lib_fat16_int_rc_sector|
|
|
sta lib_fat16_tempw2
|
|
lda lib_fat16_tempw2+1
|
|
adc #0 ; we know that "sectors per cluster" cannot exceed 128.
|
|
sta lib_fat16_tempw2+1
|
|
lda lib_fat16_tempb
|
|
adc #0
|
|
sta lib_fat16_tempb
|
|
ENDASM
|
|
|
|
//Mostly we read whole sectors. However if the file ends in (( size % 0x200 )!=0) the file ends someplace inside
|
|
//a sector, and we must read the last sector partly.
|
|
CALL lib_mmc64_readsector_part ( lib_fat16_tempw2 lib_fat16_tempb lib_fat16_int_rc_buffer_ptr first_pos read_count callstat )
|
|
IF callstat != 0
|
|
SUBEND
|
|
ENDIF
|
|
|
|
|
|
LABEL lib_fat16_int_rc_exit_success
|
|
|
|
LET lib_fat16_int_rc_status = 0
|
|
FEND
|
|
|
|
//------------------------------------------------------------------------
|
|
// lib_fat16_int_write_cluster_sector (INTERNAL)
|
|
//
|
|
// Purpose:
|
|
// 1. To write a specific sector in a specific cluster
|
|
// or
|
|
// 2. To write a sector in the root-dir
|
|
//
|
|
// Parameters:
|
|
// lib_fat16_int_wc_cluster - cluster to write. special: 0 = root-dir
|
|
// lib_fat16_int_wc_sector - sector # inside the cluster (0..lib_fat16_sectors_per_cluster-1)
|
|
// special: if in root-dir (0..lib_fat16_rootdir_sectors-1)
|
|
// lib_fat16_int_wc_buffer_ptr - pointer, sector-data in memory to write
|
|
// lib_fat16_int_wc_status - 0 = OK. !0 = error.
|
|
//
|
|
// Preparation: lib_fat16_mount_partition
|
|
//
|
|
// Usage of lib temp variables:
|
|
// lib_fat16_tempw2
|
|
// lib_fat16_tempb
|
|
//------------------------------------------------------------------------
|
|
|
|
#IFDEF __LIB_FAT16_WRITESUPPORT
|
|
|
|
WORD lib_fat16_int_wc_cluster
|
|
WORD lib_fat16_int_wc_sector
|
|
WORD lib_fat16_int_wc_buffer_ptr
|
|
BYTE lib_fat16_int_wc_status
|
|
|
|
FUNC lib_fat16_int_write_cluster_sector ( lib_fat16_int_wc_cluster lib_fat16_int_wc_sector lib_fat16_int_wc_buffer_ptr out:lib_fat16_int_wc_status )
|
|
WORD first_pos // in bytes
|
|
WORD write_count
|
|
|
|
LET first_pos = 0
|
|
LET write_count = LIB_FAT16_SECTOR_SIZE
|
|
|
|
FUNC lib_fat16_int_write_cluster_sector_part ( lib_fat16_int_wc_cluster lib_fat16_int_wc_sector lib_fat16_int_wc_buffer_ptr first_pos write_count out:lib_fat16_int_wc_status )
|
|
|
|
BYTE spc_count
|
|
WORD csect_offset_lo
|
|
BYTE csect_offset_hi
|
|
BYTE callstat //status for internal calls
|
|
|
|
|
|
LET lib_fat16_int_wc_status = 1 //indicate an error at first (we SUBEND out if things go wrong)
|
|
|
|
IF lib_fat16_int_wc_cluster == 0 //the root directory
|
|
IF lib_fat16_int_wc_sector >= lib_fat16_rootdir_sectors
|
|
SUBEND // caller tried to make us read past the root-dir region. probably an internal error.
|
|
ENDIF
|
|
//Now we must add the start sector for the rootdir with the sector requested inside it, to get the right one
|
|
ASM
|
|
clc
|
|
lda lib_fat16_rootdir_sector_lo
|
|
adc lib_fat16_int_wc_sector
|
|
sta lib_fat16_tempw2
|
|
lda lib_fat16_rootdir_sector_lo+1
|
|
adc lib_fat16_int_wc_sector+1
|
|
sta lib_fat16_tempw2+1
|
|
lda lib_fat16_rootdir_sector_hi
|
|
adc #0
|
|
sta lib_fat16_tempb
|
|
ENDASM
|
|
CALL lib_mmc64_writesector ( lib_fat16_tempw2 lib_fat16_tempb lib_fat16_int_wc_buffer_ptr callstat )
|
|
IF callstat != 0
|
|
SUBEND
|
|
ENDIF
|
|
GOTO lib_fat16_int_wc_exit_success
|
|
ENDIF
|
|
|
|
//Else this is a real cluster in the dataarea that's about to be read
|
|
IF lib_fat16_int_wc_sector >= lib_fat16_sectors_per_cluster
|
|
SUBEND // caller passed a sector offset beyond the end of the cluster. probably an internal error
|
|
ENDIF
|
|
|
|
//Adjust for data-area starting with cluster #2
|
|
SUBT lib_fat16_int_wc_cluster - 2 -> lib_fat16_int_wc_cluster
|
|
|
|
//Now we must multiply the clusternr with "nr of sectors per cluster" to
|
|
//get a valid sector-offset into the data-area
|
|
LET csect_offset_lo = lib_fat16_int_wc_cluster
|
|
LET csect_offset_hi = 0
|
|
LET spc_count = lib_fat16_sectors_per_cluster
|
|
//First bit unimportant (1 sector per cluster and we're done here!)
|
|
ASM
|
|
lsr |spc_count|
|
|
ENDASM
|
|
WHILE spc_count
|
|
ASM
|
|
clc
|
|
rol |csect_offset_lo|
|
|
rol |csect_offset_lo|+1
|
|
rol |csect_offset_hi|
|
|
|
|
lsr |spc_count|
|
|
ENDASM
|
|
WEND
|
|
|
|
// "real sector to access" = "start of data area" + "cluster sector offset" + lib_fat16_int_wc_sector (sector # in cluster)
|
|
//first we do "start of data area" + "cluster sector offset"
|
|
ASM
|
|
clc
|
|
lda lib_fat16_data_sector_lo
|
|
adc |csect_offset_lo|
|
|
sta lib_fat16_tempw2
|
|
lda lib_fat16_data_sector_lo+1
|
|
adc |csect_offset_lo|+1
|
|
sta lib_fat16_tempw2+1
|
|
lda lib_fat16_data_sector_hi
|
|
adc |csect_offset_hi|
|
|
sta lib_fat16_tempb
|
|
ENDASM
|
|
//now we add the lib_fat16_int_wc_sector
|
|
ASM
|
|
clc
|
|
lda lib_fat16_tempw2
|
|
adc |lib_fat16_int_wc_sector|
|
|
sta lib_fat16_tempw2
|
|
lda lib_fat16_tempw2+1
|
|
adc #0 ; we know that "sectors per cluster" cannot exceed 128.
|
|
sta lib_fat16_tempw2+1
|
|
lda lib_fat16_tempb
|
|
adc #0
|
|
sta lib_fat16_tempb
|
|
ENDASM
|
|
|
|
//Mostly we read whole sectors. However if the file ends in (( size % 0x200 )!=0) the file ends someplace inside
|
|
//a sector, and we must read the last sector partly.
|
|
CALL lib_mmc64_writesector_part ( lib_fat16_tempw2 lib_fat16_tempb lib_fat16_int_wc_buffer_ptr first_pos write_count callstat )
|
|
IF callstat != 0
|
|
SUBEND
|
|
ENDIF
|
|
|
|
|
|
LABEL lib_fat16_int_wc_exit_success
|
|
|
|
LET lib_fat16_int_wc_status = 0
|
|
FEND
|
|
|
|
#IFEND
|
|
|
|
//------------------------------------------------------------------------
|
|
// lib_fat16_int_get_cluster_link (INTERNAL)
|
|
//
|
|
// Purpose:
|
|
// Return the next cluster nr for a given cluster.
|
|
// In the FAT the position for the current cluster holds the link
|
|
// to the next cluster in the "chain".
|
|
// special values are: $0000 unallocated, $ffef-$ffff end-of-cluster-chain
|
|
//
|
|
// Parameters:
|
|
// lib_fat16_int_nc_cluster_nr - we send in our current cluster number
|
|
// and we get the next returned in the
|
|
// same param
|
|
// lib_fat16_int_nc_status - the status operation. 0 = success
|
|
// !0 = failure (probably internal)
|
|
//
|
|
// Preparation: lib_fat16_dirnext (caller)
|
|
// (unfinished) lib_fat16_fopen
|
|
//
|
|
// Usage of lib temp variables:
|
|
// lib_fat16_tempw2
|
|
// lib_fat16_tempb
|
|
//
|
|
//
|
|
// lib_fat16_int_set_cluster_link (INTERNAL)
|
|
//
|
|
// Purpose: to update the two FAT's with a new value for the cluster-link
|
|
//
|
|
// Additional parameter:
|
|
// lib_fat16_int_nc_target_cluster_nr = the new cluster-link to write
|
|
//
|
|
// Sorry for the clutter, but this way saves a whole lot of code to
|
|
// support write-access //Mattias
|
|
//
|
|
// A note on caching: Since a fat-sector is read, updated and written back
|
|
// at once we don't need to invalidate the "caching" of the FAT-buffer.
|
|
// (a later cached read will still be valid)
|
|
//------------------------------------------------------------------------
|
|
|
|
|
|
WORD lib_fat16_int_nc_cluster_nr
|
|
BYTE lib_fat16_int_nc_status
|
|
|
|
#IFDEF __LIB_FAT16_WRITESUPPORT
|
|
|
|
BYTE lib_fat16_int_nc_writeflag
|
|
WORD lib_fat16_int_nc_target_cluster_nr
|
|
FUNC lib_fat16_int_set_cluster_link ( lib_fat16_int_nc_cluster_nr lib_fat16_int_nc_target_cluster_nr out:lib_fat16_int_nc_status )
|
|
|
|
LET lib_fat16_int_nc_writeflag = 1
|
|
|
|
#IFEND
|
|
|
|
FUNC lib_fat16_int_get_cluster_link ( io:lib_fat16_int_nc_cluster_nr out:lib_fat16_int_nc_status )
|
|
|
|
BYTE sect_offset
|
|
BYTE callstat
|
|
WORD sector_lo
|
|
BYTE sector_hi
|
|
|
|
//MHTAG 20050927 - this internal variable was replaced internally for lib_fat16_tempw2 (ZP-vars == better code)
|
|
//WORD lib_fat16_int_nc_link_offset_bytes
|
|
|
|
LET lib_fat16_int_nc_status = 1
|
|
|
|
//Clusters in the data-area are numbered from 2 (i.e. 2 = offset 0 )
|
|
IF lib_fat16_int_nc_cluster_nr < 2
|
|
SUBEND
|
|
ENDIF
|
|
|
|
//Values from $fff0 are "bad", reserved or cluster-chain end markers. (endmark>=$fff8)
|
|
//We don't care here, since we cannot follow longer anyhow.
|
|
IF lib_fat16_int_nc_cluster_nr >= LIB_FAT16_CLUSTER_END
|
|
SUBEND
|
|
ENDIF
|
|
|
|
// exp for the sector offset on disk for requested cluster entry:
|
|
// "first FAT sector" + ( (cluster_nr * "sizeof cluster entry (2 bytes in FAT16 )") / 512 )
|
|
// simplified = "first FAT sector" + ( cluster_nr / 256 ) i.e. the high byte of "cluster nr"
|
|
// div 256 = shift left 8 bits, so we simply take the highbyte and move it to the lowbyte (see below)
|
|
ASM
|
|
lda lib_fat16_int_nc_cluster_nr+1
|
|
sta |sect_offset|
|
|
ENDASM
|
|
//and now we add the "first FAT sector"
|
|
ASM
|
|
clc
|
|
lda lib_fat16_fat1_sector_lo
|
|
adc |sect_offset|
|
|
sta lib_fat16_tempw2
|
|
lda lib_fat16_fat1_sector_lo+1
|
|
adc #0
|
|
sta lib_fat16_tempw2+1
|
|
lda lib_fat16_fat1_sector_hi
|
|
adc #0
|
|
sta lib_fat16_tempb
|
|
ENDASM
|
|
|
|
LET sector_lo = lib_fat16_tempw2
|
|
LET sector_hi = lib_fat16_tempb
|
|
|
|
//read up the sector
|
|
CALL lib_mmc64_readsector ( sector_lo sector_hi lib_fat16_buffer_ptr callstat )
|
|
IF callstat != 0
|
|
SUBEND //pass the read error on to the caller.
|
|
ENDIF
|
|
|
|
//calculate the position of the link
|
|
//Following the logic above the offset the the position of the link in the sector must be in the low-byte
|
|
//However since every entry is 2 bytes long, we must multiply the lowbyte with 2 to get the offset in bytes
|
|
//
|
|
//MHTAG 20050927 - all usage of lib_fat16_tempw2 below in this func is replacement for lib_fat16_int_nc_link_offset_bytes
|
|
ASM
|
|
clc
|
|
lda lib_fat16_int_nc_cluster_nr
|
|
rol
|
|
sta lib_fat16_tempw2
|
|
lda #0
|
|
rol
|
|
sta lib_fat16_tempw2+1
|
|
ENDASM
|
|
|
|
ADD lib_fat16_tempw2 + lib_fat16_buffer_ptr -> lib_fat16_tempw2
|
|
|
|
#IFDEF __LIB_FAT16_WRITESUPPORT
|
|
//if readaccess - skit this section
|
|
IF lib_fat16_int_nc_writeflag == 1
|
|
//this section updates the cluster link value and writes the fat-sector back to disk
|
|
PUTASWORD@ lib_fat16_tempw2 VALUE lib_fat16_int_nc_target_cluster_nr
|
|
|
|
CALL lib_mmc64_writesector ( sector_lo sector_hi lib_fat16_buffer_ptr callstat )
|
|
IF callstat != 0
|
|
SUBEND //pass the read error on to the caller.
|
|
ENDIF
|
|
|
|
//now we must update the second FAT.
|
|
//change here to support more than 2 FATs
|
|
//reason for decision to support only 2 = VERY standard. Even linux vfat driver relies on two FATs
|
|
//24-bit addition of the size of one fat to get right offset
|
|
ASM
|
|
clc
|
|
lda |sector_lo|
|
|
adc lib_fat16_sectors_per_fat
|
|
sta |sector_lo|
|
|
lda |sector_lo|+1
|
|
adc lib_fat16_sectors_per_fat+1
|
|
sta |sector_lo|+1
|
|
lda |sector_hi|
|
|
adc #0
|
|
sta |sector_hi|
|
|
ENDASM
|
|
//and finally the actual write.
|
|
CALL lib_mmc64_writesector ( sector_lo sector_hi lib_fat16_buffer_ptr callstat )
|
|
IF callstat != 0
|
|
SUBEND //pass the read error on to the caller.
|
|
ENDIF
|
|
|
|
GOTO lib_fat16_int_nc_skipread
|
|
ENDIF
|
|
#IFEND
|
|
|
|
//return it
|
|
GETASWORD@ lib_fat16_tempw2 -> lib_fat16_int_nc_cluster_nr
|
|
|
|
#IFDEF __LIB_FAT16_WRITESUPPORT
|
|
LABEL lib_fat16_int_nc_skipread
|
|
LET lib_fat16_int_nc_writeflag = 0 //reset for next access of this function
|
|
#IFEND
|
|
|
|
LET lib_fat16_int_nc_status = 0
|
|
FEND
|
|
|
|
//------------------------------------------------------------------------
|
|
// lib_fat16_int_search_free_clusters
|
|
//
|
|
// Purpose: To find clusters on the mounted drive that are free to allocate
|
|
// for new filedata.
|
|
//
|
|
// Usage: When mounting a partition for R/W access this routine is called
|
|
// to find unused clusters, in the event that a write is issued. The
|
|
// routine searches for a "cluster hole" of max LIB_FAT16_WRITE_CLUSTERS_MAX
|
|
// continous clusters (to reduce search time). It updates the variables
|
|
// lib_fat16_first_write_cluster and lib_fat16_last_write_cluster with
|
|
// the limits of the found "cluster hole" (range of unallocated clusters)
|
|
//
|
|
// If writing has completely filled previously discovered "cluster hole"
|
|
// the write routines may call this routine again to try to find more
|
|
// unclaimed disc space to fill.
|
|
//
|
|
// Method:
|
|
// Space for writing is searched from the end of the FAT (last clusters)
|
|
// and backwards until we find free clusters. When we find a free cluster
|
|
// we set the "lib_fat16_last_write_cluster" marker and continue backwards
|
|
// for a while (until we reach a count or until we hit data again. This is
|
|
// where we set the "lib_fat16_first_write_cluster" marker.
|
|
// After this operation we know about an area between the two markers that
|
|
// consists of free clusters, ready to use for writing file-data
|
|
//------------------------------------------------------------------------
|
|
|
|
#IFDEF __LIB_FAT16_WRITESUPPORT
|
|
|
|
BYTE lib_fat16_int_fu_status
|
|
|
|
FUNC lib_fat16_int_search_free_clusters ( out:lib_fat16_int_fu_status )
|
|
|
|
WORD active_cluster
|
|
WORD active_link
|
|
WORD cluster_search_max
|
|
BYTE callstat
|
|
|
|
LET lib_fat16_int_fu_status = 1 //default = error exit
|
|
|
|
//-----------------------------------------------------
|
|
//TASK1 - find out where to start the search
|
|
LET active_cluster = lib_fat16_first_write_cluster
|
|
IF active_cluster == $ffff //if free area is uninitialized yet
|
|
LET active_cluster = lib_fat16_total_clusters //start the search at the end of the fat
|
|
ENDIF
|
|
|
|
//-----------------------------------------------------
|
|
//TASK2 - rewind until we reach:
|
|
// a) free clusters
|
|
// b) start of fat
|
|
|
|
WHILE 1
|
|
LET active_link = active_cluster
|
|
CALL lib_fat16_int_get_cluster_link ( active_link callstat )
|
|
IF callstat != 0
|
|
SUBEND //internal error
|
|
ENDIF
|
|
IF active_link == 0
|
|
BREAK
|
|
ENDIF
|
|
DEC active_cluster
|
|
WEND
|
|
|
|
IF active_cluster < 2 //disk is full. Unable to find a single free cluster!
|
|
SUBEND
|
|
ENDIF
|
|
|
|
LET lib_fat16_last_write_cluster = active_cluster
|
|
|
|
//-----------------------------------------------------
|
|
//TASK3 - rewind until we reach the end of the free area.
|
|
|
|
//LET active_link = active_cluster
|
|
LET cluster_search_max = LIB_FAT16_WRITE_CLUSTERS_MAX
|
|
WHILE active_link == LIB_FAT16_CLUSTER_FREE
|
|
DEC cluster_search_max
|
|
IF cluster_search_max == 0
|
|
BREAK
|
|
ENDIF
|
|
DEC active_cluster
|
|
LET active_link = active_cluster
|
|
CALL lib_fat16_int_get_cluster_link ( active_link callstat )
|
|
IF callstat != 0
|
|
SUBEND //internal error
|
|
ENDIF
|
|
WEND
|
|
|
|
IF active_cluster < 2
|
|
LET active_cluster = 1
|
|
ENDIF
|
|
|
|
INC active_cluster //this one was used so we need the next one (the first free)
|
|
LET lib_fat16_first_write_cluster = active_cluster
|
|
|
|
//now we should have found a area free for writing.
|
|
|
|
//MHTAG 20051114 - debug writes out the free area to the screen
|
|
//CALL lib_dbg_hexoutw ( lib_fat16_first_write_cluster )
|
|
//CALL lib_dbg_outlf
|
|
//CALL lib_dbg_hexoutw ( lib_fat16_last_write_cluster )
|
|
//CALL lib_dbg_outlf
|
|
|
|
|
|
|
|
LET lib_fat16_int_fu_status = 0 //if we got this far it's a success
|
|
|
|
FEND
|
|
|
|
#IFEND
|
|
|
|
LABEL lib_fat16low_skip
|
|
|
|
#IFEND
|