1566 lines
54 KiB
Text
1566 lines
54 KiB
Text
//------------------------------------------------------------------------
|
|
// FAT16 Library
|
|
//
|
|
// Author: Mattias Hansson
|
|
// Copyright (c) : 2005 Mattias Hansson
|
|
// License: GNU LGPL 2
|
|
// Language: 65CM v0.4+
|
|
// Dependencies: mmc64lib, multdivlib
|
|
// ZP usage: $14-15, $3f-$41, $4b-$4c, $49-$4a
|
|
// Target: Commodore 64 with MMC64 interface
|
|
// (possible future conversions for other platforms possible)
|
|
//
|
|
// External functions:
|
|
// lib_fat16_mount_partition
|
|
// lib_fat16_dirstart
|
|
// lib_fat16_dirnext
|
|
// lib_fat16_chdir
|
|
// lib_fat16_fopen
|
|
// lib_fat16_fblockread
|
|
// lib_fat16_fblockwrite
|
|
// lib_fat16_fclose
|
|
// lib_fat16_seek //future expansion
|
|
// lib_fat16_fgetc //future expansion
|
|
// lib_fat16_fputc //future expansion
|
|
//
|
|
//
|
|
// Internal function:
|
|
// lib_fat16_calc_total_clusters
|
|
// lib_fat16_int_read_cluster_sector
|
|
// lib_fat16_int_write_cluster_sector
|
|
// lib_fat16_int_get_cluster_link
|
|
// lib_fat16_int_set_cluster_link (rw-support)
|
|
// lib_fat16_int_search_free_clusters (rw-support)
|
|
// lib_fat16_int_get_free_cluster (rw_support)
|
|
// lib_fat16_int_add_dir_entry (rw-support)
|
|
// TODO: lib_fat16_int_update_dir_entry (rw-support) //internal in fclose?
|
|
//
|
|
// External define support:
|
|
// __LIB_FAT16_MAX_OPEN_FILES - define this to the # of open files you
|
|
// need in your project (default=5)
|
|
// If you #DEFINE this in your own code
|
|
// before #INCLUDE:ing the lib, the lib
|
|
// will "obey" your setting.
|
|
//
|
|
// OBS: use __LIB_MMC64_READONLY instead of mocking with any R/W
|
|
// settings in this lib. This lib is configured to obey that
|
|
// directive also.
|
|
//
|
|
//------------------------------------------------------------------------
|
|
|
|
#IFNDEF __LIB_FAT16
|
|
#DEFINE __LIB_FAT16 = 1
|
|
|
|
//If you want to change this -> See above in the header.
|
|
#IFNDEF __LIB_FAT16_MAX_OPEN_FILES
|
|
#DEFINE __LIB_FAT16_MAX_OPEN_FILES = 5
|
|
#IFEND
|
|
|
|
//This is the total size of a file descriptor record
|
|
//OBS! Do NOT (re)define this one from outside!!!
|
|
//NOTE: If lib is compiled for R/W this is redefined
|
|
//below.
|
|
#DEFINE __LIB_FAT16_FILE_DESCRIPTOR_SIZE = 14
|
|
|
|
#INCLUDE <multdivlib.c65>
|
|
#INCLUDE <fat16/mmc64lib.c65>
|
|
|
|
//We inherit the "write support" ([Y]/n) from settings in mmc64rwlib.c65
|
|
#IFDEF __LIB_MMC64_WRITESUPPORT
|
|
#PRINT Write access in fat16lib.c65 is experimental!!!
|
|
#DEFINE __LIB_FAT16_WRITESUPPORT = 1
|
|
#UNDEF __LIB_FAT16_FILE_DESCRIPTOR_SIZE
|
|
//note: see description of descriptor it below
|
|
#DEFINE __LIB_FAT16_FILE_DESCRIPTOR_SIZE = 22
|
|
#IFEND
|
|
|
|
#INCLUDE <fat16/fat16lowlib.c65>
|
|
|
|
GOTO lib_fat16_skip
|
|
|
|
//Precalculated sector locations
|
|
WORD lib_fat16_partition_bootsector_lo
|
|
BYTE lib_fat16_partition_bootsector_hi
|
|
|
|
WORD lib_fat16_fat1_sector_lo
|
|
BYTE lib_fat16_fat1_sector_hi
|
|
|
|
WORD lib_fat16_rootdir_sector_lo
|
|
BYTE lib_fat16_rootdir_sector_hi
|
|
|
|
WORD lib_fat16_data_sector_lo
|
|
BYTE lib_fat16_data_sector_hi
|
|
|
|
//dir access variables
|
|
WORD lib_fat16_active_dir_startcluster // Important if a subdir spans over several clusters. special: $0000 = root directory
|
|
WORD lib_fat16_active_dir_cluster // special: $0000 = root directory
|
|
WORD lib_fat16_active_dir_sector // Special if active_dir_cluster = $0000 = "root dir" this may be more than
|
|
// "lib_fat16_sectors_per_cluster-1". Thats the reason that this is of type WORD.
|
|
WORD lib_fat16_active_dir_entry_offset // address to the current directory-entry we shall examine in bytes. (inside the fat-buffer)
|
|
// Starts @ lib_fat16_buffer_ptr and in incremented with 32 per entry
|
|
BYTE lib_fat16_active_dir_bitmask // The bitmask, sent in when calling "lib_fat16_dirstart", used in "lib_fat16_dirnext"
|
|
|
|
//------------------------------------------------------------------------
|
|
// File descriptor table
|
|
//
|
|
// An array of records representing closed or open files.
|
|
//
|
|
// Purpose: Having a file open and currently in a read or write process
|
|
// requires the lib to hold some info about the location in the file
|
|
// etc. If we want several files open at once (and heck yes we want it
|
|
// since this is a freakin mass-storage device for our beloved C64) we
|
|
// must multiply the descriptor records for as many files we want open
|
|
// simultaniously.
|
|
//
|
|
// NOTE: To change how many files we can have open -> change the constant
|
|
// "lib_fat16_max_open_files" under the constant declaration section.
|
|
//
|
|
// Description of a record:
|
|
//
|
|
// offset size field_description
|
|
// --------------------------------------
|
|
// 0 2 Current cluster ($0002-$ffef) special $0000 - file not open
|
|
// 2 1 Current sector offset in the cluster (0..127)
|
|
// 3 2 Current byte position in current sector (0..511)
|
|
// 5 4 File total size in bytes (0..2147483647)
|
|
// 9 4 Current position in file, counted in bytes (0..2147483647)
|
|
// 13 1 One of the "lib_fat16_filemode_*" constants
|
|
//
|
|
// The rest of the descriptor below is only avaliable if the lib is compiled
|
|
// with R/W access enabled.
|
|
//
|
|
// 14 2 Direntry cluster (writemode only) //($0000 = rootdir)
|
|
// 16 2 Direntry directory sector (writemode only) //used as fclose() must
|
|
// 18 2 Direntry offset in sector (writemode only) //update the entry at close
|
|
// 20 2 First cluster in file (writemode only) //To be written to fileentry at fclose()
|
|
//
|
|
// Total sizeof(descriptor) = 22 bytes (14 if READONLY)
|
|
//------------------------------------------------------------------------
|
|
// File descriptor access constants
|
|
//------------------------------------------------------------------------
|
|
BYTE CONST FAT16_DESC_CURR_CLUSTER = 0
|
|
BYTE CONST FAT16_DESC_CURR_SECTOR = 2
|
|
BYTE CONST FAT16_DESC_CURR_POS = 3
|
|
BYTE CONST FAT16_DESC_FILESIZE = 5
|
|
BYTE CONST FAT16_DESC_FILEPOS = 9
|
|
BYTE CONST FAT16_DESC_FILEMODE = 13
|
|
#IFDEF __LIB_FAT16_WRITESUPPORT
|
|
BYTE CONST FAT16_DESC_DIRE_CLUSTER = 14
|
|
BYTE CONST FAT16_DESC_DIRE_SECTOR = 16
|
|
BYTE CONST FAT16_DESC_DIRE_OFFSET = 18
|
|
BYTE CONST FAT16_DESC_FIRST_CLUSTER = 20
|
|
#IFEND
|
|
|
|
|
|
BYTE lib_fat16_file_descriptor_size @ __LIB_FAT16_FILE_DESCRIPTOR_SIZE
|
|
ASM
|
|
lib_fat16_file_descriptors
|
|
!fill (lib_fat16_max_open_files*lib_fat16_file_descriptor_size), $ff
|
|
ENDASM
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
//lib_fat16_calc_total_clusters (INTERNAL)
|
|
//
|
|
// purpose: To calculate the number of the last cluster in a filesystem
|
|
//
|
|
// Method:
|
|
// ( Total sectors - ( data-area-start - start of partition) ) / clusters_per_sector = clusters_of_data_area
|
|
|
|
#IFDEF __LIB_FAT16_WRITESUPPORT
|
|
FUNC lib_fat16_calc_total_clusters
|
|
WORD dataarea_offset_lo
|
|
BYTE dataarea_offset_hi
|
|
//these two represent the dataarea size in sectors.
|
|
WORD dataarea_size_lo
|
|
WORD dataarea_size_hi
|
|
BYTE sectors_per_cluster
|
|
|
|
LET sectors_per_cluster = lib_fat16_sectors_per_cluster
|
|
//data-area-start - start of partition
|
|
ASM
|
|
sec
|
|
lda lib_fat16_data_sector_lo
|
|
sbc lib_fat16_partition_bootsector_lo
|
|
sta |dataarea_offset_lo|
|
|
lda lib_fat16_data_sector_lo+1
|
|
sbc lib_fat16_partition_bootsector_lo+1
|
|
sta |dataarea_offset_lo|+1
|
|
lda lib_fat16_data_sector_hi
|
|
sbc lib_fat16_partition_bootsector_hi
|
|
sta |dataarea_offset_hi|
|
|
ENDASM
|
|
//Total sectors - "offset of start of dataarea in partition"
|
|
ASM
|
|
sec
|
|
lda lib_fat16_total_sectors_lo
|
|
sbc |dataarea_offset_lo|
|
|
sta |dataarea_size_lo|
|
|
lda lib_fat16_total_sectors_lo+1
|
|
sbc |dataarea_offset_lo|+1
|
|
sta |dataarea_size_lo|+1
|
|
lda lib_fat16_total_sectors_hi
|
|
sbc |dataarea_offset_hi|
|
|
sta |dataarea_size_hi|
|
|
lda lib_fat16_total_sectors_hi+1
|
|
sbc #0
|
|
sta |dataarea_size_hi|+1
|
|
ENDASM
|
|
//sectors_of_data_area / sectors_per_cluster = total_clusters
|
|
//First bit unimportant (1 sector per cluster and we're done here!)
|
|
ASM
|
|
lsr |sectors_per_cluster|
|
|
ENDASM
|
|
WHILE sectors_per_cluster
|
|
ASM
|
|
clc
|
|
ror |dataarea_size_hi|+1
|
|
ror |dataarea_size_hi|
|
|
ror |dataarea_size_lo|+1
|
|
ror |dataarea_size_lo|
|
|
|
|
lsr |sectors_per_cluster|
|
|
ENDASM
|
|
WEND
|
|
|
|
LET lib_fat16_total_clusters = dataarea_size_lo
|
|
|
|
//CALL lib_dbg_hexoutw ( lib_fat16_total_clusters )
|
|
//CALL lib_dbg_textoutlf ( " total clusters" )
|
|
|
|
FEND
|
|
#IFEND
|
|
|
|
//------------------------------------------------------------------------
|
|
// lib_fat16_mount_partition
|
|
//
|
|
// Purpose:
|
|
// 1. To mount one of the 4 possible partitions on a MMC or SD card.
|
|
// 2. Setup all the needed FAT pointers for work.
|
|
// 3. Active directory = root-dir of the disk.
|
|
//
|
|
// Parameters:
|
|
// lib_fat16_mp_partnr = partition nr to mount 0..3
|
|
// lib_fat16_mp_status = returns 0 if success otherwise !0
|
|
//
|
|
// Preparation: lib_mmc64_cardinit (inherited from our usage of
|
|
// lib_mmc64_readsector)
|
|
//
|
|
// Note: if the SD/MMC is superfloppy formatted "partition nr" is ignored
|
|
//
|
|
// Usage of lib temp variables:
|
|
// lib_fat16_tempw
|
|
// lib_fat16_tempw2
|
|
// lib_fat16_tempb
|
|
//------------------------------------------------------------------------
|
|
|
|
BYTE lib_fat16_mp_partnr
|
|
BYTE lib_fat16_mp_status
|
|
FUNC lib_fat16_mount_partition ( lib_fat16_mp_partnr out:lib_fat16_mp_status )
|
|
|
|
BYTE callstat //internal status communication with lower level routines
|
|
|
|
|
|
LET lib_fat16_mp_status = 1 //assume a problem
|
|
|
|
//Note to developers: comment line below if using a constant buffer reference
|
|
POINTER lib_fat16_buffer_ptr TO lib_fat16_fatbuffer
|
|
//!!!!DEBUG CODE!!!!: To easily look at the fat-buffer while debugging we can place it where we like it here.
|
|
//LET lib_fat16_buffer_ptr = $c000 //comment this line when finished debugging
|
|
|
|
//Two formats exist:
|
|
// 1. Removable Harddrive mode (sector0 = mbr with partition table)
|
|
// 2. Superfloppy mode USB-ZIP (sector0 = partition boot record )
|
|
//We must determine what this (likely) is.
|
|
CALL lib_mmc64_readsector ( 0 0 lib_fat16_buffer_ptr callstat )
|
|
IF 0 != callstat
|
|
SUBEND //error! Read of MBR failed.
|
|
ENDIF
|
|
|
|
//First we assume that this is a "Removable Harddrive".
|
|
|
|
//Calculate the address (in the buffer) to the partition record caller selected
|
|
ADD $1be + lib_fat16_buffer_ptr -> lib_fat16_tempw
|
|
WHILE lib_fat16_mp_partnr
|
|
ADD 16 + lib_fat16_tempw -> lib_fat16_tempw
|
|
DEC lib_fat16_mp_partnr
|
|
WEND
|
|
|
|
//Is the type of the partition = FAT16 = $06 ?
|
|
PEEK lib_fat16_tempw[4] -> lib_fat16_tempb
|
|
IF lib_fat16_tempb == $06 //Yes
|
|
//Now we extract the partition bootsector start and store it for
|
|
//future usage. (needed when calculating the rest of the data areas)
|
|
GETASWORD@ lib_fat16_tempw[8] -> lib_fat16_partition_bootsector_lo
|
|
PEEK lib_fat16_tempw[10] -> lib_fat16_partition_bootsector_hi
|
|
|
|
//Read the boot record of the FAT16 partition
|
|
CALL lib_mmc64_readsector ( lib_fat16_partition_bootsector_lo lib_fat16_partition_bootsector_hi lib_fat16_buffer_ptr callstat )
|
|
IF 0 != callstat
|
|
SUBEND //error! Read of FAT16 partition boot record failed!
|
|
ENDIF
|
|
ELSE //No. Is this a "SuperFloppy"? (we take a wild guess)
|
|
//So we set the partition boot sector to 0
|
|
LET lib_fat16_partition_bootsector_lo = 0
|
|
LET lib_fat16_partition_bootsector_hi = 0
|
|
ENDIF
|
|
|
|
//MHTAG 20051205
|
|
//CALL lib_dbg_hexoutb ( lib_fat16_partition_bootsector_hi )
|
|
//CALL lib_dbg_hexoutw ( lib_fat16_partition_bootsector_lo )
|
|
//CALL lib_dbg_textoutlf ( " start of partition" )
|
|
|
|
|
|
//Get "bytes per sector". This is a sanity check for if this might be a FAT16 PBR
|
|
//The code highly depends on $200 bytes per sector so it's good having this covered.
|
|
|
|
LET lib_fat16_tempw = lib_fat16_buffer_ptr
|
|
GETASWORD@ lib_fat16_tempw[11] -> lib_fat16_tempw2
|
|
IF lib_fat16_tempw2 != LIB_FAT16_SECTOR_SIZE
|
|
SUBEND //error! "bytes per sector" is not $200 (512) (or this is not a FAT16 pbr!)
|
|
ENDIF
|
|
|
|
//Get "Sectors per cluster"
|
|
PEEK lib_fat16_tempw[13] -> lib_fat16_sectors_per_cluster
|
|
|
|
//Get "Reserved sectors" (including FAT boot sector)
|
|
GETASWORD@ lib_fat16_tempw[14] -> lib_fat16_reserved_sectors
|
|
//Get "nr of FATs"
|
|
PEEK lib_fat16_tempw[16] -> lib_fat16_nr_of_fats
|
|
//Get "max nr of rootdir entries"
|
|
GETASWORD@ lib_fat16_tempw[17] -> lib_fat16_rootdir_entries
|
|
//Get "sectors per fat"
|
|
GETASWORD@ lib_fat16_tempw[22] -> lib_fat16_sectors_per_fat
|
|
|
|
|
|
#IFDEF __LIB_FAT16_WRITESUPPORT
|
|
|
|
//MHTAG 20051205
|
|
GETASWORD@ lib_fat16_tempw[34] -> lib_fat16_total_sectors_hi
|
|
//CALL lib_dbg_hexoutw ( lib_fat16_total_sectors_hi )
|
|
GETASWORD@ lib_fat16_tempw[32] -> lib_fat16_total_sectors_lo
|
|
//CALL lib_dbg_hexoutw ( lib_fat16_total_sectors_lo )
|
|
//CALL lib_dbg_textoutlf ( " total sectors" )
|
|
|
|
#IFEND
|
|
|
|
|
|
//Now we'll do some precalculations based on the values we've read
|
|
//so that we know the start sectors of all areas of the partition.
|
|
|
|
//known
|
|
//WORD lib_fat16_partition_bootsector_lo
|
|
//BYTE lib_fat16_partition_bootsector_hi
|
|
|
|
//First FAT starts after the reserved sectors
|
|
// this below means fat1_sector = partition_start + reserved_sectors
|
|
// in assembler due to this beeing a 24-bit number
|
|
ASM
|
|
clc
|
|
lda lib_fat16_reserved_sectors
|
|
adc lib_fat16_partition_bootsector_lo
|
|
sta lib_fat16_fat1_sector_lo
|
|
lda lib_fat16_reserved_sectors+1
|
|
adc lib_fat16_partition_bootsector_lo+1
|
|
sta lib_fat16_fat1_sector_lo+1
|
|
lda #0
|
|
adc lib_fat16_partition_bootsector_hi
|
|
sta lib_fat16_fat1_sector_hi
|
|
ENDASM
|
|
|
|
//Partition root-dir starts after the FATs
|
|
//So first we must figure out how much space all the FATs take up together.
|
|
LET lib_fat16_tempw = lib_fat16_nr_of_fats
|
|
CALL lib_multdiv_mult ( lib_fat16_tempw lib_fat16_sectors_per_fat )
|
|
|
|
//Now "total size of FATs" + "offset to the first FAT" = "root dir start"
|
|
ASM
|
|
clc
|
|
lda lib_fat16_tempw
|
|
adc lib_fat16_fat1_sector_lo
|
|
sta lib_fat16_rootdir_sector_lo
|
|
lda lib_fat16_tempw+1
|
|
adc lib_fat16_fat1_sector_lo+1
|
|
sta lib_fat16_rootdir_sector_lo+1
|
|
lda #0
|
|
adc lib_fat16_fat1_sector_hi
|
|
sta lib_fat16_rootdir_sector_hi
|
|
ENDASM
|
|
|
|
//Partitions data-area starts after the root-dir. To calculate the total size of the data-area in sectors
|
|
//we use this formula: ( "max root dir entries" * size of directory entry (32) ) / sector size(512)
|
|
//To simplify 1 sector has space for 16, 32-byte directory entries.
|
|
//So "max root dir entries" / 16 = "size of the total root-dir in sectors"
|
|
LET lib_fat16_tempw = lib_fat16_rootdir_entries
|
|
CALL lib_multdiv_div ( lib_fat16_tempw 16 )
|
|
|
|
LET lib_fat16_rootdir_sectors = lib_fat16_tempw
|
|
//Now "total size of root dir in sectors" + "root dir start sector" = "start of data area"
|
|
ASM
|
|
clc
|
|
lda lib_fat16_tempw
|
|
adc lib_fat16_rootdir_sector_lo
|
|
sta lib_fat16_data_sector_lo
|
|
lda lib_fat16_tempw+1
|
|
adc lib_fat16_rootdir_sector_lo+1
|
|
sta lib_fat16_data_sector_lo+1
|
|
lda #0
|
|
adc lib_fat16_rootdir_sector_hi
|
|
sta lib_fat16_data_sector_hi
|
|
ENDASM
|
|
|
|
//MHTAG 20051205
|
|
//CALL lib_dbg_hexoutb ( lib_fat16_data_sector_hi )
|
|
//CALL lib_dbg_hexoutw ( lib_fat16_data_sector_lo )
|
|
//CALL lib_dbg_textoutlf ( " data area start-sector" )
|
|
|
|
#IFDEF __LIB_FAT16_WRITESUPPORT
|
|
CALL lib_fat16_calc_total_clusters
|
|
#IFEND
|
|
|
|
//Now we've calculated all the pointers that important in this partition
|
|
//For the more high level FAT16 access routines
|
|
|
|
//Initialize work variables
|
|
//LET lib_fat16_active_cluster = $ffff
|
|
LET lib_fat16_active_dir_startcluster = $0000 // startdir = root
|
|
|
|
#IFDEF __LIB_FAT16_WRITESUPPORT
|
|
//MHTAG 20051114 - prepare writing by finding some suitable write space when mounting
|
|
LET lib_fat16_first_write_cluster = $ffff
|
|
LET lib_fat16_last_write_cluster = 0
|
|
CALL lib_fat16_int_search_free_clusters ( callstat )
|
|
IF callstat != 0
|
|
SUBEND
|
|
ENDIF
|
|
#IFEND
|
|
|
|
LET lib_fat16_mp_status = 0 //if we got this far, we've successfully mounted the partition!
|
|
|
|
FEND
|
|
|
|
//------------------------------------------------------------------------
|
|
// lib_fat16_dirnext
|
|
// lib_fat16_dirnext_le (INTERNAL)
|
|
//
|
|
// Purpose:
|
|
// To scan active directory for the next direntry with the same bitmask
|
|
// that was passed to the latest call to lib_fat16_dirfirst
|
|
//
|
|
// Parameters:
|
|
// lib_fat16_ds_entry_ptr - pointer to the fat entry (check FAT docs for struct layout)
|
|
// NULL = 0 = not found / whole dir listed
|
|
// lib_fat16_ds_status - result code: 0 - success
|
|
// 1 - internal error
|
|
// lib_fat16_dn_firstnamechar - $00 = last entry, else not last entry
|
|
//
|
|
// Preparation: lib_fat16_dirfirst
|
|
//
|
|
// Usage of lib temp variables:
|
|
// lib_fat16_tempw (pointer to current dir-entry in sector-buffer-memory)
|
|
//
|
|
// Note:
|
|
// When we enter this routine we're about to read the next dir
|
|
// entry. We must however first look at and adjust (if needed) the current
|
|
// cluster/sector/dir_entry_offset if we've passed a border in the previous
|
|
// call.
|
|
//
|
|
//------------------------------------------------------------------------
|
|
|
|
|
|
|
|
WORD lib_fat16_dn_entry_ptr
|
|
BYTE lib_fat16_dn_status
|
|
BYTE lib_fat16_dn_firstnamechar
|
|
|
|
#IFDEF __LIB_FAT16_WRITESUPPORT
|
|
|
|
FUNC lib_fat16_dirnext_le ( out:lib_fat16_dn_entry_ptr out:lib_fat16_dn_status out:lib_fat16_dn_firstnamechar )
|
|
LET lib_fat16_dn_firstnamechar = $ff //when we write a new file we must be sure that a valid 0-entry terminated the dir.
|
|
#IFEND
|
|
|
|
FUNC lib_fat16_dirnext ( out:lib_fat16_dn_entry_ptr out:lib_fat16_dn_status )
|
|
|
|
BYTE callstat
|
|
BYTE filetype
|
|
BYTE validentry //valid directory entry found for the caller (exit condition)
|
|
|
|
LET lib_fat16_dn_status = 1
|
|
LET lib_fat16_dn_entry_ptr = 0
|
|
LET validentry = 0
|
|
WHILE validentry = 0
|
|
//have we passed the end of the sector (in buffer) yet?
|
|
IF lib_fat16_active_dir_entry_offset >= LIB_FAT16_SECTOR_SIZE
|
|
INC lib_fat16_active_dir_sector
|
|
|
|
//if this is the root directory
|
|
IF lib_fat16_active_dir_startcluster == 0
|
|
IF lib_fat16_active_dir_sector >= lib_fat16_rootdir_sectors
|
|
//(For all I know this is an error in the filesystem not to terminate the
|
|
// directory with an entry that starts with a NULL-char). I just choose not to take action
|
|
BREAK //read to the end of directory successfully. no more data
|
|
ENDIF
|
|
ELSE //if this is in a normal cluster
|
|
IF lib_fat16_active_dir_sector >= lib_fat16_sectors_per_cluster //we've passed the last sector of it
|
|
|
|
//Call will update the "lib_fat16_active_dir_cluster" to the next cluster link.
|
|
CALL lib_fat16_int_get_cluster_link ( lib_fat16_active_dir_cluster callstat )
|
|
IF callstat != 0
|
|
SUBEND //internal error (or end of cluster-chain == error in filesystem)
|
|
ENDIF
|
|
|
|
IF lib_fat16_active_dir_cluster == LIB_FAT16_CLUSTER_FREE
|
|
SUBEND //internal error (or error in filesystem), how did we end up at an free cluster while folloing a chain?
|
|
ENDIF
|
|
|
|
// end of cluster-chain. we are ready with this dir-scan!
|
|
IF lib_fat16_active_dir_cluster >= LIB_FAT16_CLUSTER_END
|
|
//(For all I know this is an error in the filesystem not to terminate the
|
|
// directory with an entry that starts with a NULL-char). I just choose not to take action
|
|
BREAK //read to the end of directory successfully. no more data
|
|
ENDIF
|
|
|
|
//since we've gone to a new cluster we restart the internal "cluster sector offset counter"
|
|
LET lib_fat16_active_dir_sector = 0
|
|
ENDIF
|
|
ENDIF
|
|
|
|
LET lib_fat16_active_dir_entry_offset = 0 //restart "offset in sector" counter
|
|
CALL lib_fat16_int_read_cluster_sector ( lib_fat16_active_dir_cluster lib_fat16_active_dir_sector lib_fat16_buffer_ptr callstat )
|
|
IF callstat != 0
|
|
SUBEND //internal error
|
|
ENDIF
|
|
|
|
ENDIF
|
|
|
|
//calc the pointer address the the direntry in memory
|
|
ADD lib_fat16_buffer_ptr + lib_fat16_active_dir_entry_offset -> lib_fat16_tempw
|
|
|
|
PEEK lib_fat16_tempw -> lib_fat16_dn_firstnamechar
|
|
|
|
//is it the end of the directory?
|
|
IF lib_fat16_dn_firstnamechar == LIB_FAT16_END_OF_DIR
|
|
//This is the correct end of an FAT16 directory. (see two "BREAK"s above)
|
|
BREAK //read to the end of directory successfully. no more data
|
|
ENDIF
|
|
|
|
//is it a deleted entry?
|
|
IF lib_fat16_dn_firstnamechar != LIB_FAT16_DELETED_FILE
|
|
//no it exists!
|
|
|
|
//Check the filetype of the current direntry
|
|
PEEK lib_fat16_tempw[11] -> filetype
|
|
|
|
IF lib_fat16_active_dir_bitmask != 0
|
|
//calc the pointer to the filetype-bitfield in the direntry
|
|
AND filetype WITH lib_fat16_active_dir_bitmask -> filetype
|
|
//is it a fileentry of a type we're looking for?
|
|
IF filetype != 0
|
|
//found a matching entry, no more looping.
|
|
LET lib_fat16_dn_entry_ptr = lib_fat16_tempw
|
|
LET validentry = 1
|
|
ENDIF
|
|
ELSE //bitmask = 0, we want ALL file-entries!
|
|
AND filetype WITH 8 -> filetype
|
|
//(but not volume labels (and long filenames))
|
|
IF filetype == 0
|
|
//no volume label - it seams ok to return
|
|
LET lib_fat16_dn_entry_ptr = lib_fat16_tempw
|
|
LET validentry = 1
|
|
ENDIF
|
|
|
|
ENDIF
|
|
ENDIF
|
|
|
|
//prepare the offset to the next direntry read
|
|
ADD LIB_FAT16_DIRENTRY_SIZE + lib_fat16_active_dir_entry_offset -> lib_fat16_active_dir_entry_offset
|
|
|
|
WEND
|
|
|
|
LET lib_fat16_dn_status = 0
|
|
FEND
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
// lib_fat16_dirstart
|
|
//
|
|
// Purpose:
|
|
// To scan active directory for the first entry that maches the given bitmask
|
|
//
|
|
// Parameters:
|
|
// lib_fat16_ds_bitmask - a bitmask that will be AND:ed with the entries
|
|
// of the active directory. If the result is not 0
|
|
// the entry is considered as a match returned to caller.
|
|
// (refer to FAT documentation for the meaning of the bits).
|
|
// special: value 0 lists all files and subdirs but not
|
|
// volume labels (and the LFN-support in VFAT)
|
|
// lib_fat16_ds_entry_ptr - pointer to the fat entry (check FAT docs for struct layout)
|
|
// NULL = 0 = not found / whole dir listed
|
|
// lib_fat16_ds_status - result code: 0 - success
|
|
// 1 - internal error
|
|
//
|
|
// Preparation: lib_mmc64_cardinit (inherited from our usage of
|
|
// lib_mmc64_readsector)
|
|
// lib_fat16_mount_partition
|
|
//
|
|
// Usage of lib temp variables:
|
|
//
|
|
//------------------------------------------------------------------------
|
|
|
|
BYTE lib_fat16_ds_bitmask
|
|
WORD lib_fat16_ds_entry_ptr
|
|
BYTE lib_fat16_ds_status
|
|
FUNC lib_fat16_dirstart ( lib_fat16_ds_bitmask out:lib_fat16_ds_entry_ptr out:lib_fat16_ds_status )
|
|
|
|
BYTE callstat
|
|
|
|
LET lib_fat16_ds_status = 1
|
|
LET lib_fat16_active_dir_cluster = lib_fat16_active_dir_startcluster
|
|
LET lib_fat16_active_dir_sector = 0
|
|
LET lib_fat16_active_dir_entry_offset = 0
|
|
LET lib_fat16_active_dir_bitmask = lib_fat16_ds_bitmask
|
|
|
|
CALL lib_fat16_int_read_cluster_sector ( lib_fat16_active_dir_cluster lib_fat16_active_dir_sector lib_fat16_buffer_ptr callstat )
|
|
IF callstat != 0
|
|
SUBEND
|
|
ENDIF
|
|
|
|
CALL lib_fat16_dirnext ( lib_fat16_ds_entry_ptr callstat )
|
|
IF callstat != 0
|
|
SUBEND
|
|
ENDIF
|
|
|
|
LET lib_fat16_ds_status = 0 //set success if all went ok
|
|
FEND
|
|
|
|
//------------------------------------------------------------------------
|
|
// lib_fat16_chdir
|
|
//
|
|
// Purpose:
|
|
// To change to one of the avaliable directories that exist in current
|
|
// dir.
|
|
//
|
|
// Parameters:
|
|
// lib_fat16_cd_dirname_ptr - pointer to a 11-char string. If this string
|
|
// is found to be an exact match of a directory-
|
|
// entry in the current dir, we will change to
|
|
// this new directory.
|
|
// lib_fat16_cd_status - 0 = success, !0 = unable to change dir or internal error
|
|
//
|
|
// Preparation: lib_fat16_mount_partition
|
|
//
|
|
// Usage of lib temp variables:
|
|
//
|
|
// Note:
|
|
// In FAT16 there are always (except in the ROOT-dir) two dirs
|
|
// avaliable, one called "." and the other ".."
|
|
// "." points to the current dir (which just makes you go back where you are
|
|
// i.e. pointless =) (but there was a need for it in DOS long ago)
|
|
// ".." points back to the parent dir.
|
|
//
|
|
//------------------------------------------------------------------------
|
|
|
|
WORD lib_fat16_cd_dirname_ptr
|
|
BYTE lib_fat16_cd_status
|
|
FUNC lib_fat16_chdir ( lib_fat16_cd_dirname_ptr out:lib_fat16_cd_status )
|
|
|
|
WORD direntry @ $14
|
|
BYTE callstat
|
|
BYTE charcount
|
|
BYTE char1
|
|
BYTE char2
|
|
WORD dirnamecmp_ptr
|
|
|
|
LET lib_fat16_cd_status = 1
|
|
|
|
//search for directories in current dir
|
|
CALL lib_fat16_dirstart ( 16 direntry callstat )
|
|
IF callstat != 0
|
|
SUBEND //internal error
|
|
ENDIF
|
|
WHILE direntry
|
|
//Compare the strings
|
|
LET dirnamecmp_ptr = lib_fat16_cd_dirname_ptr
|
|
LET charcount = 11
|
|
WHILE charcount
|
|
PEEK dirnamecmp_ptr -> char1
|
|
PEEK direntry -> char2
|
|
IF char1 != char2
|
|
GOTO lib_fat16_cd_findnext
|
|
ENDIF
|
|
INC dirnamecmp_ptr
|
|
INC direntry
|
|
DEC charcount
|
|
WEND
|
|
//if we got here we have a match! So we change dir!
|
|
//offset from start of direntry is now 11 and we want to 26
|
|
GETASWORD@ direntry[26-11] -> lib_fat16_active_dir_startcluster
|
|
GOTO lib_fat16_cd_exitsuccess
|
|
|
|
LABEL lib_fat16_cd_findnext
|
|
CALL lib_fat16_dirnext ( direntry callstat )
|
|
IF callstat != 0
|
|
SUBEND //internal error
|
|
ENDIF
|
|
WEND
|
|
|
|
//if we came here through the loop but didn't find anything the cd has failed - exit with errorcode
|
|
SUBEND
|
|
|
|
LABEL lib_fat16_cd_exitsuccess
|
|
LET lib_fat16_cd_status = 0
|
|
FEND
|
|
|
|
//------------------------------------------------------------------------
|
|
// lib_fat16_int_get_free_cluster (internal)
|
|
//
|
|
// purpose: This routine is used when the lib needs a new cluster to write
|
|
// to, may it be for filedata or for extending a subdirectory
|
|
// with an entry past the end of it's current last cluster
|
|
//
|
|
// The need of this routine comes because
|
|
// lib_fat16_int_find_unused_clusters can only find new cluster
|
|
// holes however with any fragmentation these holes are spread
|
|
// between chunks data on the disk. So this routine searches
|
|
// for next cluster hole as needed.
|
|
//
|
|
// An error is issued if diskspace is full.
|
|
//------------------------------------------------------------------------
|
|
|
|
#IFDEF __LIB_FAT16_WRITESUPPORT
|
|
|
|
WORD lib_fat16_int_cw_free_cluster_nr
|
|
BYTE lib_fat16_int_cw_status
|
|
|
|
FUNC lib_fat16_int_get_free_cluster ( out:lib_fat16_int_cw_free_cluster_nr out:lib_fat16_int_cw_status )
|
|
|
|
BYTE callstat
|
|
|
|
LET lib_fat16_int_cw_status = 1 //error
|
|
|
|
//Are there any more free clusters in the previously discovered (or not discovered)
|
|
//"cluster hole"?
|
|
IF lib_fat16_first_write_cluster > lib_fat16_last_write_cluster
|
|
//No, so we try to find another "cluster hole"
|
|
CALL lib_fat16_int_search_free_clusters ( callstat )
|
|
IF callstat != 0
|
|
SUBEND
|
|
ENDIF
|
|
ENDIF
|
|
|
|
LET lib_fat16_int_cw_free_cluster_nr = lib_fat16_last_write_cluster
|
|
DEC lib_fat16_last_write_cluster
|
|
|
|
LET lib_fat16_int_cw_status = 0 //success
|
|
|
|
FEND
|
|
|
|
#IFEND
|
|
|
|
//------------------------------------------------------------------------
|
|
// lib_fat16_int_add_dir_entry (INTERNAL)
|
|
//
|
|
// Purpose: when a new, previously not existing, file is opened for
|
|
// writing, a new direntry must be added to the current
|
|
// directory. This function does that.
|
|
// Note: This function is only responsible for allocating a new
|
|
// uninitialized entry, whereas the fopen function is responsible
|
|
// to make sure that we don't add a duplicate entry in the
|
|
// directory.
|
|
//
|
|
// Method: This function gets its input from the dirstart/dirnext done
|
|
// by fopen() when searching, if the file for write exists from
|
|
// before.
|
|
// Then it copies the last entry forward one entry
|
|
// (if possible). If all went successful it returns the pointers
|
|
// to the newly allocated entry to the caller.
|
|
//
|
|
// Preparation: fopen() internal call
|
|
// Run dirstart/dirnext until the active directory ends.
|
|
// This is done in fopen() before calling this function.
|
|
//
|
|
// Parameters:
|
|
//
|
|
// lib_fat16_ae_new_entry_filename - pointer the a 11 char long filename
|
|
// for the new entry.
|
|
// lib_fat16_ae_new_entry_cluster - The cluster in which the new direntry
|
|
// resides.
|
|
//
|
|
//
|
|
// ZP-vars:
|
|
// lib_fat16_tempw, lib_fat16_tempw2
|
|
//------------------------------------------------------------------------
|
|
|
|
#IFDEF __LIB_FAT16_WRITESUPPORT
|
|
|
|
WORD lib_fat16_ae_new_entry_filename
|
|
WORD lib_fat16_ae_new_entry_cluster
|
|
WORD lib_fat16_ae_new_entry_sector
|
|
WORD lib_fat16_ae_new_entry_offset
|
|
BYTE lib_fat16_ae_status
|
|
|
|
FUNC lib_fat16_int_add_dir_entry ( lib_fat16_ae_new_entry_filename out:lib_fat16_ae_new_entry_cluster out:lib_fat16_ae_new_entry_sector out:lib_fat16_ae_new_entry_offset out:lib_fat16_ae_status )
|
|
|
|
LET lib_fat16_ae_status = 1
|
|
|
|
WORD null_entry_cluster
|
|
WORD null_entry_sector
|
|
WORD null_entry_offset
|
|
|
|
BYTE callstat
|
|
|
|
|
|
//We assume caller has used looped to the last direntry with "dirnext"
|
|
//NOTE!! If this is not the case we will OVERWRITE valid entries.
|
|
LET lib_fat16_ae_new_entry_cluster = lib_fat16_active_dir_cluster
|
|
LET lib_fat16_ae_new_entry_sector = lib_fat16_active_dir_sector
|
|
LET lib_fat16_ae_new_entry_offset = lib_fat16_active_dir_entry_offset
|
|
LET null_entry_cluster = lib_fat16_active_dir_cluster
|
|
LET null_entry_sector = lib_fat16_active_dir_sector
|
|
LET null_entry_offset = lib_fat16_active_dir_entry_offset
|
|
|
|
//-------------------------------------------------------
|
|
//TASK1: prepare to move the NULL-entry (end-of-dir)
|
|
// (leaving the old position for the new entry)
|
|
|
|
//Is the last entry the last entry in sector also?
|
|
IF null_entry_offset >= LIB_FAT16_SECTOR_SIZE-LIB_FAT16_DIRENTRY_SIZE
|
|
INC null_entry_sector
|
|
//This is the ROOT dir?
|
|
IF null_entry_cluster == 0
|
|
IF null_entry_sector >= lib_fat16_rootdir_sectors
|
|
SUBEND //root directory cannot be exceeded
|
|
ELSE
|
|
//There are rootdir sectors left so we just take the next one.
|
|
LET null_entry_offset = 0
|
|
ENDIF
|
|
ELSE //this is NOT the ROOT-dir
|
|
//must we allocate another cluster to fit the new entry?
|
|
IF null_entry_cluster >= lib_fat16_sectors_per_cluster
|
|
//Yes, so we ask for another cluster.
|
|
CALL lib_fat16_int_get_free_cluster ( null_entry_cluster callstat )
|
|
IF callstat != 0
|
|
SUBEND //Could not get another cluster (disk probably full)
|
|
ENDIF
|
|
//Now we have the number of a free cluster, yet we have to:
|
|
// a. Link the old last cluster to this new cluster
|
|
// b. mark the new cluster as the last in the chain
|
|
|
|
//a.
|
|
CALL lib_fat16_int_set_cluster_link ( lib_fat16_ae_new_entry_cluster null_entry_cluster callstat )
|
|
IF callstat != 0
|
|
SUBEND //internal error
|
|
ENDIF
|
|
|
|
//b.
|
|
//Note: allthough everything above > $ffef is a "cluster chain ended", some badly written drivers only understand $ffff
|
|
CALL lib_fat16_int_set_cluster_link ( null_entry_cluster $ffff callstat )
|
|
IF callstat != 0
|
|
SUBEND //internal error
|
|
ENDIF
|
|
|
|
//Now in the new cluster we restart the internal "offsets"
|
|
LET null_entry_offset = 0
|
|
LET null_entry_sector = 0
|
|
|
|
ELSE //no, we just use another sector in the current cluster
|
|
LET null_entry_offset = 0
|
|
ENDIF
|
|
ENDIF
|
|
ELSE //last entry is not at the end of a sector.
|
|
ADD LIB_FAT16_DIRENTRY_SIZE + null_entry_offset -> null_entry_offset
|
|
ENDIF
|
|
|
|
//When we've got here we have calculated all the pointers
|
|
//to the newly created END-OF-DIR entry.
|
|
|
|
//-------------------------------------------------------
|
|
//TASK2 - Write a new NULL-entry.
|
|
|
|
//Read up the sector where it resides.
|
|
CALL lib_fat16_int_read_cluster_sector ( null_entry_cluster null_entry_sector lib_fat16_buffer_ptr callstat )
|
|
IF callstat != 0
|
|
SUBEND //internal error
|
|
ENDIF
|
|
//Adjust offset to where in memory the buffer is.
|
|
ADD lib_fat16_buffer_ptr + null_entry_offset -> lib_fat16_tempw2
|
|
//make this a "null-entry"
|
|
POKE lib_fat16_tempw2 , 0
|
|
//and write it back to disk
|
|
CALL lib_fat16_int_write_cluster_sector ( null_entry_cluster null_entry_sector lib_fat16_buffer_ptr callstat )
|
|
IF callstat != 0
|
|
SUBEND //internal error
|
|
ENDIF
|
|
|
|
|
|
//-------------------------------------------------------
|
|
//TASK3 - Create a new direntry (empty file)
|
|
//Read up the sector where it resides.
|
|
CALL lib_fat16_int_read_cluster_sector ( lib_fat16_ae_new_entry_cluster lib_fat16_ae_new_entry_sector lib_fat16_buffer_ptr callstat )
|
|
IF callstat != 0
|
|
SUBEND //internal error
|
|
ENDIF
|
|
//Adjust offset to where in memory the buffer is.
|
|
ADD lib_fat16_buffer_ptr + lib_fat16_ae_new_entry_offset -> lib_fat16_tempw2
|
|
//Copy in the new filename
|
|
LET lib_fat16_tempw = lib_fat16_ae_new_entry_filename
|
|
ASM
|
|
ldy #0
|
|
lib_fat16_ae_l1
|
|
lda (lib_fat16_tempw),y
|
|
sta (lib_fat16_tempw2),y
|
|
iny
|
|
cpy #11
|
|
bne lib_fat16_ae_l1
|
|
|
|
;clear the rest of the entry (NULLs)
|
|
lda #0
|
|
lib_fat16_ae_l2
|
|
sta (lib_fat16_tempw2),y
|
|
iny
|
|
cpy #32
|
|
bne lib_fat16_ae_l2
|
|
ENDASM
|
|
|
|
CALL lib_fat16_int_write_cluster_sector ( lib_fat16_ae_new_entry_cluster lib_fat16_ae_new_entry_sector lib_fat16_buffer_ptr callstat )
|
|
IF callstat != 0
|
|
SUBEND //internal error
|
|
ENDIF
|
|
|
|
LET lib_fat16_ae_status = 0
|
|
|
|
FEND
|
|
#IFEND
|
|
|
|
//------------------------------------------------------------------------
|
|
// lib_fat16_fopen
|
|
//
|
|
// Purpose:
|
|
// To open a file in the current directory and initialize a descriptor
|
|
// table entry.
|
|
// A file we're opening for read must exist.
|
|
// A file we're opening for write must NOT exist.
|
|
//
|
|
// Parameters:
|
|
// descriptor_ptr - this is the fileptr the user needs to
|
|
// remember for all further operations
|
|
// on this file. If = 0 = NULL then
|
|
// the function was unable to open the file.
|
|
// lib_fat16_fo_filename_ptr - 11 char string, that must match the dir-
|
|
// entry exacly (or represent the new filename
|
|
// when writing).
|
|
// lib_fat16_fo_filemode - use one of the filemode constants defined in
|
|
// the constant section. "lib_fat16_filemode_*"
|
|
// currently only "LIB_FAT16_FILEMODE_READ" is
|
|
// implemented.
|
|
// lib_fat16_fo_status - 0 = success. !0 = file open error or internal
|
|
// error.
|
|
//
|
|
// Preparation: lib_fat16_mount_partition
|
|
//
|
|
// Dependencies: This function uses both "lib_fat16_dirstart" and
|
|
// "lib_fat16_dirnext" so don't use fopen in a dir-scan
|
|
// sequence. (it won't work at all as lib_fat16_dirstart
|
|
// will reset the current search your are doing)
|
|
//
|
|
//
|
|
// Usage of lib temp variables:
|
|
// (none) ... used lib_fat16_tempw before.
|
|
//
|
|
//------------------------------------------------------------------------
|
|
|
|
WORD descriptor_ptr
|
|
WORD lib_fat16_fo_filename_ptr
|
|
BYTE lib_fat16_fo_filemode
|
|
BYTE lib_fat16_fo_status
|
|
|
|
FUNC lib_fat16_fopen ( out:descriptor_ptr lib_fat16_fo_filename_ptr lib_fat16_fo_filemode out:lib_fat16_fo_status )
|
|
|
|
WORD descr @ $49
|
|
BYTE max_files
|
|
WORD clusternr
|
|
WORD direntry @ $14
|
|
BYTE callstat
|
|
BYTE charcount
|
|
BYTE char1
|
|
BYTE char2
|
|
BYTE attributes
|
|
WORD filnamecmp_ptr
|
|
WORD wtemp
|
|
#IFDEF __LIB_FAT16_WRITESUPPORT
|
|
BYTE lastdirentrychar
|
|
WORD new_entry_cluster
|
|
WORD new_entry_sector
|
|
WORD new_entry_offset
|
|
#IFEND
|
|
|
|
LET lib_fat16_fo_status = 1
|
|
LET descriptor_ptr = 0
|
|
|
|
#IFNDEF __LIB_FAT16_WRITESUPPORT
|
|
//if library is compiled for readonly support, trying to opening file for write is forbidden
|
|
IF lib_fat16_fo_filemode != LIB_FAT16_FILEMODE_READ
|
|
SUBEND
|
|
ENDIF
|
|
#IFEND
|
|
|
|
//------------------------------------------
|
|
//TASK1 - search for an avaliable descriptor
|
|
|
|
//max files is defined as the address of "lib_fat16_max_open_files".
|
|
//This is a little quirk to get it into a local variable
|
|
ASM
|
|
lda #<lib_fat16_max_open_files
|
|
sta |max_files|
|
|
ENDASM
|
|
POINTER descr TO lib_fat16_file_descriptors
|
|
WHILE max_files
|
|
GETASWORD@ descr -> clusternr
|
|
IF clusternr == $ffff
|
|
GOTO lib_fat16_fo_task2
|
|
ENDIF
|
|
ADD descr + __LIB_FAT16_FILE_DESCRIPTOR_SIZE -> descr
|
|
DEC max_files
|
|
WEND
|
|
|
|
SUBEND //unable to find a free filedescriptor-slot, return error
|
|
|
|
//--------------------------------------------------------
|
|
//TASK2 - find the requested file in the current directory
|
|
LABEL lib_fat16_fo_task2
|
|
|
|
CALL lib_fat16_dirstart ( 0 direntry callstat )
|
|
IF callstat != 0
|
|
SUBEND //internal error
|
|
ENDIF
|
|
WHILE direntry
|
|
//Compare the strings
|
|
LET filnamecmp_ptr = lib_fat16_fo_filename_ptr
|
|
LET charcount = 11
|
|
WHILE charcount
|
|
PEEK filnamecmp_ptr -> char1
|
|
PEEK direntry -> char2
|
|
IF char1 != char2
|
|
GOTO lib_fat16_fo_findnext
|
|
ENDIF
|
|
|
|
INC filnamecmp_ptr
|
|
INC direntry
|
|
DEC charcount
|
|
WEND
|
|
|
|
//if we got here we have a match! Now this must be a valid file
|
|
//so we've test the attributes of it.
|
|
PEEK direntry -> attributes
|
|
//if the direntry is systemfile, volume label or directory we cannot open it!
|
|
AND attributes WITH 4+8+16 -> attributes
|
|
IF attributes != 0
|
|
SUBEND //error, direntry was not valid to open (see reasons above)
|
|
ENDIF
|
|
#IFDEF __LIB_FAT16_WRITESUPPORT
|
|
IF lib_fat16_fo_filemode == LIB_FAT16_FILEMODE_READ
|
|
#IFEND
|
|
GOTO lib_fat16_fo_task4
|
|
#IFDEF __LIB_FAT16_WRITESUPPORT
|
|
ELSE
|
|
SUBEND //it's write error to try to overwrite an existing file.
|
|
ENDIF
|
|
#IFEND
|
|
|
|
|
|
|
|
LABEL lib_fat16_fo_findnext
|
|
#IFDEF __LIB_FAT16_WRITESUPPORT
|
|
CALL lib_fat16_dirnext_le ( direntry callstat lastdirentrychar )
|
|
#IFEND
|
|
#IFNDEF __LIB_FAT16_WRITESUPPORT
|
|
CALL lib_fat16_dirnext ( direntry callstat )
|
|
#IFEND
|
|
IF callstat != 0
|
|
SUBEND //internal error
|
|
ENDIF
|
|
WEND
|
|
|
|
|
|
#IFDEF __LIB_FAT16_WRITESUPPORT
|
|
IF lib_fat16_fo_filemode == LIB_FAT16_FILEMODE_READ
|
|
#IFEND
|
|
SUBEND // if we got here, we didn't find the file the caller requested for read access
|
|
#IFDEF __LIB_FAT16_WRITESUPPORT
|
|
ENDIF
|
|
#IFEND
|
|
|
|
|
|
#IFDEF __LIB_FAT16_WRITESUPPORT
|
|
//-------------------------------------------------------------------
|
|
//TASK3 - If writemode we need to create us a new direntry
|
|
|
|
//check verification that dirnext was on the last entry in dir
|
|
IF lastdirentrychar != LIB_FAT16_END_OF_DIR
|
|
SUBEND //The DIR did not end with a NULL-filename. Eighter a filesystem error or
|
|
//it might be the rootdir that is completely filled
|
|
//We cannot however proceed to create another file in this condition.
|
|
ENDIF
|
|
|
|
CALL lib_fat16_int_add_dir_entry ( lib_fat16_fo_filename_ptr new_entry_cluster new_entry_sector new_entry_offset callstat )
|
|
IF callstat != 0
|
|
SUBEND //internal error
|
|
ENDIF
|
|
|
|
|
|
#IFEND
|
|
|
|
//-------------------------------------------------------------------
|
|
//TASK4 - Copy info from the direntry to the accuired(or created)file descriptor
|
|
|
|
LABEL lib_fat16_fo_task4
|
|
|
|
//clear descriptor
|
|
ASM
|
|
ldy #0
|
|
tya
|
|
lib_fat16_fo_l2
|
|
sta (|descr|),y
|
|
iny
|
|
cpy #lib_fat16_file_descriptor_size
|
|
bne lib_fat16_fo_l2
|
|
ENDASM
|
|
|
|
//Copy the startcluster to the descriptor
|
|
// (direntry points to position 11 in the directory-entry
|
|
// since we've scanned the filename before. therefore "X-11"
|
|
GETASWORD@ direntry[26-11] -> clusternr
|
|
PUTASWORD@ descr[FAT16_DESC_CURR_CLUSTER] VALUE clusternr
|
|
|
|
//Copy the filesize to the descriptor. (Two words == one double word :-)
|
|
GETASWORD@ direntry[26-11+2] -> wtemp
|
|
PUTASWORD@ descr[FAT16_DESC_FILESIZE] VALUE wtemp
|
|
GETASWORD@ direntry[26-11+4] -> wtemp
|
|
PUTASWORD@ descr[FAT16_DESC_FILESIZE+2] VALUE wtemp
|
|
|
|
//set filemode in descriptor
|
|
POKE descr[FAT16_DESC_FILEMODE] , lib_fat16_fo_filemode
|
|
|
|
#IFDEF __LIB_FAT16_WRITESUPPORT
|
|
IF lib_fat16_fo_filemode == LIB_FAT16_FILEMODE_WRITE
|
|
PUTASWORD@ descr[FAT16_DESC_DIRE_CLUSTER] VALUE new_entry_cluster
|
|
PUTASWORD@ descr[FAT16_DESC_DIRE_SECTOR] VALUE new_entry_sector
|
|
PUTASWORD@ descr[FAT16_DESC_DIRE_OFFSET] VALUE new_entry_offset
|
|
ENDIF
|
|
#IFEND
|
|
|
|
LET descriptor_ptr = descr
|
|
LET lib_fat16_fo_status = 0
|
|
FEND
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
// lib_fat16_fclose
|
|
// lib_fat16_fclose (returns status of operation R/W only)
|
|
//
|
|
// Purpose:
|
|
// To close an open file specified by a descriptor pointer, the caller
|
|
// accuired from a previous call to "lib_fat16_fopen"
|
|
//
|
|
// Parameters:
|
|
// lib_fat16_fc_descriptor_ptr - the file pointer.
|
|
//
|
|
// Preparation: lib_fat16_mount_partition, lib_fat16_fopen
|
|
//
|
|
// Usage of lib temp variables:
|
|
// (none) ... used lib_fat16_tempw before
|
|
//
|
|
//------------------------------------------------------------------------
|
|
|
|
//WORD lib_fat16_fc_descriptor_ptr
|
|
WORD lib_fat16_fc_descr @ $49
|
|
#IFDEF __LIB_FAT16_WRITESUPPORT
|
|
BYTE lib_fat16_fc_stat
|
|
FUNC lib_fat16_fcloses ( lib_fat16_fc_descr out:lib_fat16_fc_stat )
|
|
LET lib_fat16_fc_stat = 1
|
|
#IFEND
|
|
FUNC lib_fat16_fclose ( lib_fat16_fc_descr )
|
|
|
|
//LET lib_fat16_fc_descr = lib_fat16_fc_descriptor_ptr
|
|
|
|
#IFDEF __LIB_FAT16_WRITESUPPORT
|
|
BYTE filemode
|
|
WORD direntry @ $14
|
|
WORD entry_cluster
|
|
WORD entry_sector
|
|
WORD entry_offset
|
|
WORD startcluster
|
|
WORD clusternr // <- this is the last cluster!
|
|
WORD filesize_lo
|
|
WORD filesize_hi
|
|
BYTE callstat
|
|
|
|
PEEK lib_fat16_fc_descr[FAT16_DESC_FILEMODE] -> filemode
|
|
IF filemode != LIB_FAT16_FILEMODE_READ
|
|
|
|
//read up the direntry
|
|
GETASWORD@ lib_fat16_fc_descr[FAT16_DESC_DIRE_CLUSTER] -> entry_cluster
|
|
GETASWORD@ lib_fat16_fc_descr[FAT16_DESC_DIRE_SECTOR] -> entry_sector
|
|
GETASWORD@ lib_fat16_fc_descr[FAT16_DESC_DIRE_OFFSET] -> entry_offset
|
|
CALL lib_fat16_int_read_cluster_sector ( entry_cluster entry_sector lib_fat16_buffer_ptr callstat )
|
|
IF callstat != 0
|
|
SUBEND
|
|
ENDIF
|
|
|
|
ADD lib_fat16_buffer_ptr + entry_offset -> direntry
|
|
|
|
//update it
|
|
GETASWORD@ lib_fat16_fc_descr[FAT16_DESC_FIRST_CLUSTER] -> startcluster
|
|
GETASWORD@ lib_fat16_fc_descr[FAT16_DESC_CURR_CLUSTER] -> clusternr
|
|
PUTASWORD@ direntry[26] VALUE startcluster
|
|
|
|
//Copy the filesize to the descriptor. (Two words == one double word :-)
|
|
GETASWORD@ lib_fat16_fc_descr[FAT16_DESC_FILEPOS] -> filesize_lo
|
|
PUTASWORD@ direntry[28] VALUE filesize_lo
|
|
GETASWORD@ lib_fat16_fc_descr[FAT16_DESC_FILEPOS+2] -> filesize_hi
|
|
PUTASWORD@ direntry[30] VALUE filesize_hi
|
|
|
|
//write down the direntry
|
|
CALL lib_fat16_int_write_cluster_sector ( entry_cluster entry_sector lib_fat16_buffer_ptr callstat )
|
|
IF callstat != 0
|
|
SUBEND
|
|
ENDIF
|
|
|
|
//mark last cluster in file as last-in-cluster-chain
|
|
//
|
|
//Note: allthough everything above > $ffef is a "cluster chain ended", some badly written drivers only understand $ffff
|
|
CALL lib_fat16_int_set_cluster_link ( clusternr $ffff callstat )
|
|
IF callstat != 0
|
|
SUBEND
|
|
ENDIF
|
|
|
|
ENDIF
|
|
LET lib_fat16_fc_stat = 0 //if we got here it's a success
|
|
#IFEND
|
|
|
|
//we set the "current cluster" to $ffff. This
|
|
//indicates for "lib_fat16_fopen" that this
|
|
//descriptor location is up for grabs
|
|
ASM
|
|
ldy #0
|
|
;tya
|
|
lda #$ff
|
|
sta (lib_fat16_fc_descr),y
|
|
iny
|
|
sta (lib_fat16_fc_descr),y
|
|
ENDASM
|
|
|
|
FEND
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
// lib_fat16_fblockread
|
|
//
|
|
// Purpose:
|
|
// Try to read a block of 512 bytes from an file that is open for reading.
|
|
// If the file end before we've reached 512 read bytes the reading ends.
|
|
// (Or more correct: we don't write anymore to memory-buffer, but the
|
|
// sector is fully read)
|
|
//
|
|
// Parameters:
|
|
// lib_fat16_fr_descriptor_ptr - the file pointer.
|
|
// lib_fat16_fr_block_ptr - pointer to memory where to write the block
|
|
// read from the file
|
|
// lib_fat16_fr_read_count - The number of bytes actually read from
|
|
// file. If this is not equal to 512
|
|
// it usually means we've reached the end
|
|
// of the file.
|
|
//
|
|
// Preparation: lib_fat16_mount_partition, lib_fat16_fopen
|
|
//
|
|
// NOTE: this routine calls "lib_fat16_int_get_cluster_link" which
|
|
// will ruin any ongoing "lib_fat16_dirstart" - "lib_fat16_dirnext"
|
|
// sequencen. Don't do it. ( both use the internal FAT-buffer )
|
|
//
|
|
// Usage of lib temp variables:
|
|
// (none) ... used lib_fat16_tempw before
|
|
//
|
|
//------------------------------------------------------------------------
|
|
|
|
//WORD lib_fat16_fr_descriptor_ptr
|
|
WORD lib_fat16_fr_descr @ $49
|
|
WORD lib_fat16_fr_block_ptr
|
|
WORD lib_fat16_fr_read_count
|
|
BYTE lib_fat16_fr_status
|
|
FUNC lib_fat16_fblockread ( lib_fat16_fr_descr lib_fat16_fr_block_ptr out:lib_fat16_fr_read_count out:lib_fat16_fr_status )
|
|
|
|
WORD lib_fat16_fr_current_cluster
|
|
WORD lib_fat16_fr_sector_in_cluster //note ONLY the lowbyte in this one i used (must be word for call to next_cluster_link).
|
|
BYTE lib_fat16_fr_current_filemode
|
|
BYTE lib_fat16_fr_callstat
|
|
WORD lib_fat16_fr_filesize_lo
|
|
WORD lib_fat16_fr_filesize_hi
|
|
WORD lib_fat16_fr_filepos_lo
|
|
WORD lib_fat16_fr_filepos_hi
|
|
WORD lib_fat16_fr_fileleft_lo
|
|
WORD lib_fat16_fr_fileleft_hi
|
|
|
|
LET lib_fat16_fr_status = 1
|
|
|
|
//--------------------------------------
|
|
//TASK1 - is the file valid for reading - copy data
|
|
|
|
//LET lib_fat16_fr_descr = lib_fat16_fr_descriptor_ptr
|
|
GETASWORD@ lib_fat16_fr_descr[FAT16_DESC_CURR_CLUSTER] -> lib_fat16_fr_current_cluster
|
|
|
|
PEEK lib_fat16_fr_descr[FAT16_DESC_FILEMODE] -> lib_fat16_fr_current_filemode
|
|
IF lib_fat16_fr_current_filemode != LIB_FAT16_FILEMODE_READ
|
|
SUBEND //error. file not open for reading.
|
|
ENDIF
|
|
|
|
//copy descriptor data to local variables
|
|
PEEK lib_fat16_fr_descr[FAT16_DESC_CURR_SECTOR] -> lib_fat16_fr_sector_in_cluster
|
|
//Copy filesize och filepos from descriptor (8 bytes for two 32-bit variables)
|
|
ASM
|
|
ldy #5
|
|
ldx #0
|
|
lib_fat16_fr_l1
|
|
lda (lib_fat16_fr_descr),y
|
|
sta |lib_fat16_fr_filesize_lo|,x
|
|
iny
|
|
inx
|
|
cpx #8
|
|
bne lib_fat16_fr_l1
|
|
ENDASM
|
|
|
|
IF lib_fat16_fr_current_cluster == 0
|
|
//special case - empty (0-size) file is valid to open for reading but only 0 bytes can be read.
|
|
IF lib_fat16_fr_filesize_lo == 0
|
|
IF lib_fat16_fr_filesize_hi == 0
|
|
LET lib_fat16_fr_read_count = 0
|
|
LET lib_fat16_fr_status = 0 //exit is set to success
|
|
ENDIF
|
|
ENDIF
|
|
SUBEND //error (unless special above) - file is not open
|
|
ENDIF
|
|
|
|
//-------------------------------------------
|
|
//TASK2 - Adjust clusters / sectors if needed
|
|
|
|
//Did the previous read put us past the end of the cluster?
|
|
IF lib_fat16_fr_sector_in_cluster >= lib_fat16_sectors_per_cluster
|
|
|
|
//Call will update the "lib_fat16_active_dir_cluster" to the next cluster link.
|
|
CALL lib_fat16_int_get_cluster_link ( lib_fat16_fr_current_cluster lib_fat16_fr_callstat )
|
|
IF lib_fat16_fr_callstat != 0
|
|
SUBEND //internal error
|
|
ENDIF
|
|
LET lib_fat16_fr_sector_in_cluster = 0
|
|
ENDIF
|
|
|
|
//now if ( "File total size in bytes" - "Current position in file" ) < 512 then the sector we just read contains the EOF
|
|
//subtracting 32 bit values is so very funny on 6502 :)
|
|
ASM
|
|
sec
|
|
lda |lib_fat16_fr_filesize_lo|
|
|
sbc |lib_fat16_fr_filepos_lo|
|
|
sta |lib_fat16_fr_fileleft_lo|
|
|
lda |lib_fat16_fr_filesize_lo|+1
|
|
sbc |lib_fat16_fr_filepos_lo|+1
|
|
sta |lib_fat16_fr_fileleft_lo|+1
|
|
lda |lib_fat16_fr_filesize_hi|
|
|
sbc |lib_fat16_fr_filepos_hi|
|
|
sta |lib_fat16_fr_fileleft_hi|
|
|
lda |lib_fat16_fr_filesize_hi|+1
|
|
sbc |lib_fat16_fr_filepos_hi|+1
|
|
sta |lib_fat16_fr_fileleft_hi|+1
|
|
ENDASM
|
|
|
|
//----------------------------------------------
|
|
//TASK3 - Do the actual read
|
|
|
|
|
|
LET lib_fat16_fr_read_count = LIB_FAT16_SECTOR_SIZE
|
|
IF lib_fat16_fr_fileleft_hi == 0
|
|
IF lib_fat16_fr_fileleft_lo < LIB_FAT16_SECTOR_SIZE
|
|
//We've just read to the end of the file
|
|
//of course we could know that from the link-table also. but we want to report
|
|
//the number of bytes read to the caller.
|
|
LET lib_fat16_fr_read_count = lib_fat16_fr_fileleft_lo
|
|
|
|
CALL lib_fat16_int_read_cluster_sector_part ( lib_fat16_fr_current_cluster lib_fat16_fr_sector_in_cluster lib_fat16_fr_block_ptr 0 lib_fat16_fr_read_count lib_fat16_fr_callstat )
|
|
IF lib_fat16_fr_callstat != 0
|
|
SUBEND //internal error
|
|
ENDIF
|
|
|
|
GOTO lib_fat16_fr_skipelse1
|
|
ENDIF
|
|
ENDIF
|
|
|
|
CALL lib_fat16_int_read_cluster_sector ( lib_fat16_fr_current_cluster lib_fat16_fr_sector_in_cluster lib_fat16_fr_block_ptr lib_fat16_fr_callstat )
|
|
IF lib_fat16_fr_callstat != 0
|
|
SUBEND //internal error
|
|
ENDIF
|
|
|
|
LABEL lib_fat16_fr_skipelse1
|
|
INC lib_fat16_fr_sector_in_cluster //we've just read it so we add the offset
|
|
|
|
//----------------------------------------------
|
|
//TASK4 - Recalc filepos
|
|
// Write back data to the file descriptor
|
|
PUTASWORD@ lib_fat16_fr_descr[FAT16_DESC_CURR_CLUSTER] VALUE lib_fat16_fr_current_cluster
|
|
ASM
|
|
ldy #2
|
|
lda |lib_fat16_fr_sector_in_cluster|
|
|
sta (lib_fat16_fr_descr),y
|
|
|
|
; increment the position (32-bit add)
|
|
|
|
ldy #9
|
|
clc
|
|
lda (lib_fat16_fr_descr),y
|
|
adc lib_fat16_fr_read_count ; lowbyte of the sector read
|
|
sta (lib_fat16_fr_descr),y
|
|
iny
|
|
lda (lib_fat16_fr_descr),y
|
|
adc lib_fat16_fr_read_count+1 ; hibyte of the sector read
|
|
sta (lib_fat16_fr_descr),y
|
|
iny
|
|
lda (lib_fat16_fr_descr),y
|
|
adc #0 ; does not apply (sector is max 512 bytes)
|
|
sta (lib_fat16_fr_descr),y
|
|
iny
|
|
lda (lib_fat16_fr_descr),y
|
|
adc #0 ; does not apply (sector is max 512 bytes)
|
|
sta (lib_fat16_fr_descr),y
|
|
ENDASM
|
|
|
|
LET lib_fat16_fr_status = 0
|
|
FEND
|
|
|
|
//------------------------------------------------------------------------
|
|
// lib_fat16_fblockwrite
|
|
//
|
|
// Purpose:
|
|
// To write a block (512) of data to a file, opened for writing.
|
|
// If the complete size of the file is not dividable by 512, the size of
|
|
// the last block is allowed to be less than 512 bytes.
|
|
//
|
|
// Params:
|
|
//
|
|
//
|
|
//
|
|
//------------------------------------------------------------------------
|
|
|
|
#IFDEF __LIB_FAT16_WRITESUPPORT
|
|
|
|
//WORD lib_fat16_fw_descriptor_ptr
|
|
WORD lib_fat16_fw_descr @ $49
|
|
WORD lib_fat16_fw_block_ptr
|
|
WORD lib_fat16_fw_block_size
|
|
BYTE lib_fat16_fw_status
|
|
FUNC lib_fat16_fblockwrite ( lib_fat16_fw_descr lib_fat16_fw_block_ptr lib_fat16_fw_block_size out:lib_fat16_fw_status )
|
|
|
|
WORD lib_fat16_fw_start_cluster
|
|
WORD lib_fat16_fw_current_cluster
|
|
WORD lib_fat16_fw_sector_in_cluster
|
|
WORD lib_fat16_fw_new_cluster
|
|
BYTE lib_fat16_fw_current_filemode
|
|
BYTE lib_fat16_fw_callstat
|
|
|
|
LET lib_fat16_fw_status = 1 //assume error
|
|
|
|
//LET lib_fat16_fw_descr = lib_fat16_fw_descriptor_ptr
|
|
//----------------------------------------------
|
|
//TASK1 - Read up vital data from filedescriptor
|
|
|
|
PEEK lib_fat16_fw_descr[FAT16_DESC_FILEMODE] -> lib_fat16_fw_current_filemode
|
|
IF lib_fat16_fw_current_filemode != LIB_FAT16_FILEMODE_WRITE
|
|
SUBEND //error. file not open for writing.
|
|
ENDIF
|
|
GETASWORD@ lib_fat16_fw_descr[FAT16_DESC_FIRST_CLUSTER] -> lib_fat16_fw_start_cluster
|
|
GETASWORD@ lib_fat16_fw_descr[FAT16_DESC_CURR_CLUSTER] -> lib_fat16_fw_current_cluster
|
|
PEEK lib_fat16_fw_descr[FAT16_DESC_CURR_SECTOR] -> lib_fat16_fw_sector_in_cluster
|
|
|
|
//This assures that only the last sector (block) written can be other than the size of a sector.
|
|
IF lib_fat16_fw_block_size != LIB_FAT16_SECTOR_SIZE
|
|
IF lib_fat16_fw_block_size > LIB_FAT16_SECTOR_SIZE
|
|
SUBEND //error - not supported
|
|
ENDIF
|
|
//LET lib_fat16_fw_current_filemode = LIB_FAT16_FILEMODE_WRITE_ENDED
|
|
POKE lib_fat16_fw_descr[FAT16_DESC_FILEMODE] , LIB_FAT16_FILEMODE_WRITE_ENDED
|
|
IF lib_fat16_fw_block_size == 0 //Writing 0 bytes to a valid open write-file is OK (but nothing happens)
|
|
LET lib_fat16_fw_status = 0
|
|
SUBEND
|
|
ENDIF
|
|
ENDIF
|
|
|
|
//----------------------------------------------
|
|
//TASK2 - Is this the first block in the file?
|
|
IF lib_fat16_fw_start_cluster == 0
|
|
CALL lib_fat16_int_get_free_cluster ( lib_fat16_fw_start_cluster lib_fat16_fw_callstat )
|
|
IF lib_fat16_fw_callstat != 0
|
|
SUBEND //Could not get another cluster (disk probably full)
|
|
ENDIF
|
|
PUTASWORD@ lib_fat16_fw_descr[FAT16_DESC_FIRST_CLUSTER] VALUE lib_fat16_fw_start_cluster
|
|
LET lib_fat16_fw_current_cluster = lib_fat16_fw_start_cluster
|
|
//As this file is just opened sector_in_cluster is set to 0
|
|
//LET lib_fat16_fw_sector_in_cluster = 0
|
|
ENDIF
|
|
|
|
//----------------------------------------------
|
|
//TASK3 - Time to allocate another cluster?
|
|
IF lib_fat16_fw_sector_in_cluster >= lib_fat16_sectors_per_cluster
|
|
CALL lib_fat16_int_get_free_cluster ( lib_fat16_fw_new_cluster lib_fat16_fw_callstat )
|
|
IF lib_fat16_fw_callstat != 0
|
|
SUBEND //Could not get another cluster (disk probably full)
|
|
ENDIF
|
|
//Update the cluster link from last cluster to the new one.
|
|
CALL lib_fat16_int_set_cluster_link ( lib_fat16_fw_current_cluster lib_fat16_fw_new_cluster lib_fat16_fw_callstat )
|
|
IF lib_fat16_fw_callstat != 0
|
|
SUBEND //internal error
|
|
ENDIF
|
|
LET lib_fat16_fw_sector_in_cluster = 0
|
|
LET lib_fat16_fw_current_cluster = lib_fat16_fw_new_cluster
|
|
ENDIF
|
|
|
|
//----------------------------------------------
|
|
//TASK4 - Write the data!
|
|
CALL lib_fat16_int_write_cluster_sector_part ( lib_fat16_fw_current_cluster lib_fat16_fw_sector_in_cluster lib_fat16_fw_block_ptr 0 lib_fat16_fw_block_size lib_fat16_fw_callstat )
|
|
IF lib_fat16_fw_callstat != 0
|
|
SUBEND //internal error
|
|
ENDIF
|
|
INC lib_fat16_fw_sector_in_cluster //step forward for next write
|
|
|
|
//----------------------------------------------
|
|
//TASK5 - Update descriptor (and filepos calc)
|
|
|
|
PUTASWORD@ lib_fat16_fw_descr[FAT16_DESC_CURR_CLUSTER] VALUE lib_fat16_fw_current_cluster
|
|
POKE lib_fat16_fw_descr[FAT16_DESC_CURR_SECTOR] , lib_fat16_fw_sector_in_cluster
|
|
|
|
ASM
|
|
; increment the position (32-bit add)
|
|
|
|
ldy #9
|
|
clc
|
|
lda (lib_fat16_fw_descr),y
|
|
adc lib_fat16_fw_block_size ; lowbyte of the sector read
|
|
sta (lib_fat16_fw_descr),y
|
|
iny
|
|
lda (lib_fat16_fw_descr),y
|
|
adc lib_fat16_fw_block_size+1 ; hibyte of the sector read
|
|
sta (lib_fat16_fw_descr),y
|
|
iny
|
|
lda (lib_fat16_fw_descr),y
|
|
adc #0 ; does not apply (sector is max 512 bytes)
|
|
sta (lib_fat16_fw_descr),y
|
|
iny
|
|
lda (lib_fat16_fw_descr),y
|
|
adc #0 ; does not apply (sector is max 512 bytes)
|
|
sta (lib_fat16_fw_descr),y
|
|
ENDASM
|
|
|
|
LET lib_fat16_fw_status = 0 //if we got here it's a success
|
|
FEND
|
|
|
|
#IFEND
|
|
|
|
|
|
LABEL lib_fat16_skip
|
|
|
|
#IFEND
|