c65gm/lib/fat16/fat16lowlib.c65

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