1 ; Various functions for the Interaction with the FAT16 Filesystem
3 ; Copyright (C) 2010 Frank Zoll
4 ; Copyright (C) 2010 Sprite_tm
5 ; Copyright (C) 2010 Leo C.
7 ; This file is part of avrcpm.
9 ; avrcpm is free software: you can redistribute it and/or modify it
10 ; under the terms of the GNU General Public License as published by
11 ; the Free Software Foundation, either version 3 of the License, or
12 ; (at your option) any later version.
14 ; avrcpm is distributed in the hope that it will be useful,
15 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ; GNU General Public License for more details.
19 ; You should have received a copy of the GNU General Public License
20 ; along with avrcpm. If not, see <http://www.gnu.org/licenses/>.
25 ; ============================================================================
28 ; Size of a Sector is fixed to 512 Bytes by Base - MMC Driver implementation
29 ; The Functions below therefore assume a fixed Size of 512 Bytes per Sector.
30 ; ============================================================================
35 ; ############################################################################
36 ; Defines for FAT16 Structures
37 ; ############################################################################
39 /*These are the Offsets to the Variables within the Bootsector of a FAT16
42 ;#define FAT16_BSO_SECSIZE 0x0b ; Offset to Sectorsize Word
43 #define FAT16_BSO_CLUSTSZ 0x0d ; Offset to Clustersize Byte
44 #define FAT16_BSO_RESSECT 0x0e ; Offset to Number of Reserved Sectors
45 #define FAT16_BSO_VOLPTR 0x1c ; Offset to First VolumeSector
46 #define FAT16_BSO_SECPERFAT 0x16 ; Offset to Number of Sectors per Fat
47 #define FAT16_BSO_NUMFATCP 0x10 ; Offset to Ammount of FAT Copys
48 #define FAT16_BSO_NUMDIRENT 0x11 ; Offset to Max. Root Dir. entries
50 #define FAT16_FIRST_IMAGENAME 'A' /* First letter of filename to search */
51 #define FAT16_LAST_IMAGENAME 'Z' /* Last letter of filename to */
52 #define FAT16_IMAGENAME_PREFIX "CPMDSK_"
53 #define FAT16_IMAGENAME_SUFFIX "IMG"
55 ; ############################################################################
56 ; Start of Data Segment
57 ; ############################################################################
61 fat_partfound: .byte 1 ; (partition: 0= no found 0xff=found )
62 fat_parttbl: .byte 4 ; first fat16 partition entry
63 ; only startsector is needed
64 fat_clustersize: .byte 1 ; sectors per cluster
65 fat_numdirentries:.byte 2 ; Max. num. of entries within Rootdirektory
66 fat_ptr2fat: .byte 4 ; pointer to the first fat sector
67 fat_ptr2dat: .byte 4 ; pointer to the first data sector
69 /*These variables define a cache that holds the last Cluster and Sector
70 thats been searched vor. To save some of the valuabe SRAM- Space these
71 variables also are used as temporary variables by the function
74 fat_last_dsk: .byte 1 ; number of disk with entry in cache
75 fat_log_clust: .byte 2 ; last searched logical cluster
76 fat_clust_offset: .byte 1 ; offset within the cluster
77 fat_clust_ptr: .byte 4 ; sector of last real cluster
79 /* This Variable is only needed within the scanning of the directory
80 for tempoary variable storage.. todo: optimize away :-) */
81 fat_temp: .byte 3 ; for tempoary use
83 ; ############################################################################
84 ; Start of Code Segment
85 ; ############################################################################
88 ; ============================================================================
89 ; Function: Initialize internal FAT-Partition Variables
90 ; ============================================================================
92 ; ----------------------------------------------------------------------------
94 ; Variables : [out] fat_parttabl
95 ; ----------------------------------------------------------------------------
97 ; This Routine initializes the internal Variables, that point to the
98 ; first Found FAT16 Partition.
99 ; ============================================================================
100 fat_init_partitiontable:
111 ; ============================================================================
112 ; Function: Resets the Cache
113 ; ============================================================================
115 ; ----------------------------------------------------------------------------
117 ; Variables : [out] fat_log_clust
119 ; ----------------------------------------------------------------------------
121 ; This Routine resets the internal Cache- Variables. After reset, the
122 ; next read or write Command will initialize a scan of the FAT of
123 ; the FAT16-Partition for the given sector.
124 ; ============================================================================
126 sts fat_log_clust ,_255
127 sts fat_log_clust+1,_255
128 sts fat_last_dsk ,_255
131 ; ============================================================================
132 ; Function: Saves FAT16 Partitiondata for later Scanning
133 ; ============================================================================
135 ; ----------------------------------------------------------------------------
136 ; Registers : [in] z Pointer to the Partitondata
137 ; Variables : [out] fat_partfound Boolean for "Partition found"
138 ; [out] fat_parttbl Pointer to Partitiontable
139 ; ----------------------------------------------------------------------------
141 ; This funktion sets the internal Variables to the Start and Size
142 ; of a given FAT16 Paritition. This Information will be used for a
143 ; later scanning of the Partition. See Function "fat_scan_partition"
144 ; for more information.
145 ; ============================================================================
150 printstring "fat16 part found"
155 ; save variables on stack
159 ; set fat16 partition found flag
160 sts fat_partfound,_255
162 ; save data from first fat16 partition
165 ldd temp,z+PART_START
167 ldd temp,z+PART_START+1
169 ldd temp,z+PART_START+2
171 ldd temp,z+PART_START+3
174 ; reload variables from stack
180 ; ============================================================================
181 ; Read and Scann a FAT16 Partition for Imagedatefiles
182 ; ============================================================================
185 ; ----------------------------------------------------------------------------
186 ; This Routine reads the Bootblock and scanns it for a Diskimage
187 ; ============================================================================
193 printstring "fat16 scanning"
197 ; Check if a FAT16 Partition was realy found
204 printstring "free entries in ptable ?"
208 ; Check for free entries in partition table
214 printstring "read fat bootblock."
218 ; Scan partition start
225 ; Load first sector from Partition
228 breq fat_bootblock_check
230 ; Read error: Block not found
238 printstring "fat16 bootblock check"
242 ; get sectors per cluster from bootblock
243 ldiw z,hostbuf+FAT16_BSO_CLUSTSZ
245 sts fat_clustersize,temp
248 printstring "Sectors per Cluster "
253 ; get num of FAT Tables from bootblock
254 ldiw z,hostbuf+FAT16_BSO_NUMFATCP
256 sts fat_last_dsk,temp ; low byte
259 printstring "Ammount of FAT copies: "
264 ; get max num of entries in root direktory from bootblock
265 ldiw z,hostbuf+FAT16_BSO_NUMDIRENT
267 sts fat_numdirentries,temp ; low byte
269 sts fat_numdirentries+1,temp2 ; high byte
272 printstring "Max. entries in rootdir.: "
277 ; Print begin of Volume
286 printstring "Begin of Volume at: "
294 ; get num of sectors per FAT-Table from bootblock
295 ldiw z,hostbuf+FAT16_BSO_SECPERFAT
297 sts fat_log_clust,temp ; low byte
299 sts fat_log_clust+1,temp2 ; high byte
302 printstring "Sectors per FAT__: "
307 ; get num of reseved sectors from bootblock
308 ldiw z,hostbuf+FAT16_BSO_RESSECT
312 ; Calculate begin of FAT within the Volume
330 printstring "Begin of FAT at___: "
338 ; Calculate begin of Root- Directory within the Volume
345 lds temp ,fat_log_clust
346 lds temp2,fat_log_clust+1
347 lds temp3,fat_last_dsk
351 breq fat_calc_dp_lend
360 rjmp fat_calc_dp_loop
363 sts fat_clust_ptr ,xl
364 sts fat_clust_ptr+1,xh
365 sts fat_clust_ptr+2,yl
366 sts fat_clust_ptr+3,yh
370 printstring "Begin of DIR at___: "
378 ; Calculate begin of DATA Clusters within the Volume
379 ; Num. Dir.Sektors = (Num. of Dir. entries * 32) / Bytes per Sektor
381 ; Sectorsize is fixed at 512 bytes, makes 16 entries per sector
383 lds zl,fat_numdirentries ; low byte
384 lds zh,fat_numdirentries+1 ; high byte
386 ; Num. Direntries / 16
397 lds xh,fat_clust_ptr+1
398 lds yl,fat_clust_ptr+2
399 lds yh,fat_clust_ptr+3
412 printstring "Begin of Data at__: "
420 ; Here Starts the Scann of the Directory for valid image Files.
422 ; Init Image-Namecounter
423 ldi temp,FAT16_FIRST_IMAGENAME
424 sts fat_last_dsk,temp
426 fat_scan_for_next_image:
428 ; Init Offset into Directory-Sectors
430 sts fat_clust_offset,temp
432 ; Init counter for number of entry left to scan
433 lds temp,fat_numdirentries
434 sts fat_log_clust ,temp
436 lds temp,fat_numdirentries+1
437 sts fat_log_clust+1,temp
439 fat_next_sector_loop:
440 ; Get a Pointer to the first Directory sector
442 lds xh,fat_clust_ptr+1
443 lds yl,fat_clust_ptr+2
444 lds yh,fat_clust_ptr+3
447 lds temp,fat_clust_offset
453 ; Load sector from Directory
456 breq fat_look_for_images
458 ; Read error: Block not found
462 ; Looks at a read directory block for image entries
497 lds temp3,fat_last_dsk ; Get actual Diskname (A to Z)
517 rjmp fat_store_new_entry
529 cpi temp2,16 ; max entries/sector
530 breq fat_scan_next_sector
531 rjmp fat_look_for_loop
533 fat_scan_next_sector:
536 lds _tmp0, fat_log_clust
537 lds _tmp1, fat_log_clust+1
542 sts fat_log_clust,_tmp0
543 sts fat_log_clust+1,_tmp1
549 lds temp,fat_clust_offset
551 sts fat_clust_offset,temp
553 rjmp fat_next_sector_loop
557 lds temp,fat_last_dsk
559 sts fat_last_dsk,temp
561 ldi temp2,FAT16_LAST_IMAGENAME
563 brge fat_scaned_last_disk
565 rjmp fat_scan_for_next_image
567 fat_scaned_last_disk:
572 ; Create new Partition Entry
575 ; Found a valid image
577 printstring "Found a valid Image! Z="
590 adiw y,PARTENTRY_SIZE
592 rjmp fat_look_store_loop
595 ; Set Type of Partition to FAT16- Fileimage
600 ; Offset to Startcluster + 2
611 ; Convert Filesize to ammount of sectors
612 ; (calc with 512byte/sector)
620 cpse _tmp0,_0 ;round up
632 ; store ammount of sectors in partitiontable
634 tst zl ;file size larger than 65535 sectors?
644 ; Test finding of the first sector
651 printstring "Begin of image at: "
659 ; Check for another free entry in partition table
667 rjmp fat_scan_for_more
674 ; ============================================================================
675 ; Function: Cluster to HostSector
676 ; ============================================================================
677 ; Parameters: [in] xh,xl Cluster Number
678 ; [out] yh,yl,xh,xl Sector Number on Disk
679 ; ----------------------------------------------------------------------------
681 ; Variables : [used] fat_clustersize Ammount of Sectors per Cluster
683 ; ----------------------------------------------------------------------------
685 ; ! Only works with Clustersizes 2,4,8,16,32,64,128 !
686 ; ============================================================================
689 ; Get Offset into Data area of Disk
693 ; add begin of data area to offset
694 lds temp,fat_ptr2dat+0
696 lds temp,fat_ptr2dat+1
698 lds temp,fat_ptr2dat+2
700 lds temp,fat_ptr2dat+3
704 ; ============================================================================
705 ; Function: Cluster to Sector
706 ; ============================================================================
707 ; Registers: [in] xl,xh Cluster Number
708 ; [out] xl,xh,yl,yh Sector Number
709 ; Variables: [in] fat_clustersize Ammount of Sectors per Cluster
711 ; ----------------------------------------------------------------------------
713 ; Calculates the logical Sectornumber given the physical ClusterNumber
714 ; and the size of a Cluster un sectors.
716 ; ! Only works with Clustersizes 2,4,8,16,32,64,128 !
717 ; ============================================================================
721 sbiw x,2 ; Substract the 2 reserved clusters
723 lds temp,fat_clustersize
739 ; ====================================================================
740 ; Function: Searches a physical Cluster, given the logical Cluster
741 ; ====================================================================
742 ; Registers: [in] xh,xl logical- Cluster
743 ; [out] yh,yl physical- Cluster
745 ; --------------------------------------------------------------------
747 ; ====================================================================
750 rcall dsk_getpartentry ; get partition entry
752 ; Get First FAT- Cluster Number of Diskimage
757 .if FAT16_DBG_FAT > 0
758 printstring "Search log. cluster "
763 printstring "Search phys. cluster "
772 breq fat_found_phsy_clust
773 ; Get Next Cluster from Fat
775 ; Trick: 512 Bytes Per Sector equals to 256 FAT- entries per Sector
776 ; so given: yl is the Offset within the FAT Sector
777 ; yh is the number off the FAT sector to Read
779 ; in zh,zl: Pointer to Word within the Sector to read
780 ; in yh..xl: Start sector number (LBA)
781 ; out zh,zl : word thats been read
785 ; Create FAT Offset Value
796 ; Add Cluster offset within sector
808 ; Check next logical Cluster
812 rjmp fat_next_phsy_clust
814 ; Found the physical cluster
815 fat_found_phsy_clust:
817 .if FAT16_DBG_FAT > 0
818 printstring "Found phys. Cluster at:"
826 ; ============================================================================
827 ; Function: This Routine searches for the Sector within an Imagefile
828 ; ============================================================================
829 ; Registers: [out] xl,xh,yl,yh Pointer to the Sector on the SD-Card
830 ; [out] temp Error- Variable (0= No Error)
831 ; Variables: [in] hostdsk host disk #, (partition #)
832 ; [in] hostlba host block #, relative to part.start
833 ; [in] fat_last_dsk number of disk with entry in cache
834 ; [in] fat_log_clust last searched logical cluster
835 ; [in] fat_clust_offset offset within the cluster
836 ; [in] fat_clust_ptr sector of last real cluster
837 ; ----------------------------------------------------------------------------
839 ; This Routine uses the variables hostdsk and hostlba to find an Sector
841 ; The CP/M Sector given within "hostlba" are splited to a logical Cluster-
842 ; Number and the Subsector within this logical Cluster.
843 ; logical Cluster Number = hostlba / fat_clustersize
844 ; The logical Cluster Number will be compared to the logical Cluster- Number
845 ; within the Cache. When this Clusters are the same and the DiskID's are
846 ; also the same, then the cached physical Sector will be used.
847 ; When the Clusters or the Disks don't match, a seek for the physical
848 ; Cluster is performed. This seek is done thru an access over the FAT of
849 ; the FAT16 Partition. The Routine starts at the first Cluster of the
850 ; Imagefile and goes along the linked list of Clusternumber till it reaches
851 ; the searched cluster. The found Clusternumber will be used to calculate
852 ; the Sektor where this Cluster lies on the SD- Card. Both the found physical
853 ; Cluster and the logical Cluster together with the physical Sectornumber
854 ; are stored in the cache.
855 ; The last step done is to add the SubSectorOffset to the found physical
856 ; Sector. This gives the pointer to the Sector to be read and or written.
857 ; ============================================================================
861 rcall dsk_getpartentry ; get partition entry
868 ldd xl,z+5 ; get size of disk in sectors
871 cp temp,xl ; check given sector against disksize
879 ; ################# Get logical Number of Cluster within the imagefile
880 ; printstring "calc log sector"
881 ; Get logical Sectornumber from temp
885 ; Divide logical Sectornumber by size of Cluster in sectors
886 lds zl,fat_clustersize
899 rjmp fat_search_clst_lp
902 ; at this point xh and xl are carying the logical cluster number
903 ; printstring "find subsector"
904 ; ################# Get Subsector within the logical Cluster for later use
906 lds zl,fat_clustersize
910 breq fat_found_subsec
914 rjmp fat_search_clst_lp2
919 sts fat_clust_offset,zl
921 ; Check against last HOSTDISK searched
925 brne fat_wrong_cache_clst
927 ; Check against last Cluster searched
929 lds yh,fat_log_clust+1
932 brne fat_wrong_cache_clst
934 brne fat_wrong_cache_clst
936 ; Last Cluster = searched Cluster -> get Sectornumber from cache
938 lds xh,fat_clust_ptr+1
939 lds yl,fat_clust_ptr+2
940 lds yh,fat_clust_ptr+3
944 ; Cluster is not in cache, so we must search for it
945 fat_wrong_cache_clst:
949 sts fat_log_clust+1,xh
951 ; Map Logical Cluster-Number to "Physical" Cluster Number using the FAT
952 rcall fat_find_phsy_clust
954 ; Get StartSector of "physical" Cluster
958 ; Found the physical sector
959 .if FAT16_DBG_FAT > 0
960 printstring "Found phys. Sector at:"
968 ; Save the found Sector for later use into cache
969 sts fat_clust_ptr ,xl
970 sts fat_clust_ptr+1,xh
971 sts fat_clust_ptr+2,yl
972 sts fat_clust_ptr+3,yh
974 ; Add- Subsector to Startsector
976 lds zl,fat_clust_offset
982 ; Found the physical sector
983 .if FAT16_DBG_FAT > 0
984 printstring "Sector with Offset at:"
996 ; ============================================================================
997 ; Function: Does a Disk write operation
998 ; ============================================================================
999 ; Registers: [out] temp Error-Variable ( 0= No Error)
1000 ; Variables: [in] hostdsk host disk #, (partition #)
1001 ; [in] hostlba host block #, relative to part.start
1002 ; [in] hostbuf Sector to be written
1003 ; ----------------------------------------------------------------------------
1005 ; This Routine writes a Sector to the Imagefile inside an FAT16 Partition.
1006 ; ============================================================================
1009 .if FAT16_RWDEBUG > 1
1011 printstring "host write "
1020 rjmp fat_rdwr_err ; skip disk change detection code
1022 ; After a second thought, the following code doesn't make sense, because
1023 ; disk change (change of one or more disk images) can not reliably detected.
1024 ; At least with the existing code.
1028 rcall mgr_init_partitions
1034 lcall mmcWriteSect ; disabled till read is functioning
1047 ; ============================================================================
1048 ; Function: Does a Disk read operation
1049 ; ============================================================================
1051 ; Variables: [in] hostdsk host disk #, (partition #)
1052 ; [in] hostlba host block #, relative to part.start
1053 ; [out] hostbuf Sector read by this routine
1054 ; ----------------------------------------------------------------------------
1056 ; This Routine reads a Sector from the Imagefile inside a FAT16 Partition.
1057 ; ============================================================================
1060 .if FAT16_RWDEBUG > 1
1062 printstring "host read "
1069 .if FAT16_RWDEBUG > 0
1070 printstring "Read Image Sector:"
1089 rjmp fat_rdwr_err ; skip disk change detection code
1091 rcall mgr_init_partitions
1103 ; vim:set ts=8 noet nowrap