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 #define PARTID_FAT16 0x0E
41 /*These are the Offsets to the Variables within the Bootsector of a FAT16
44 ;#define FAT16_BSO_SECSIZE 0x0b ; Offset to Sectorsize Word
45 #define FAT16_BSO_CLUSTSZ 0x0d ; Offset to Clustersize Byte
46 #define FAT16_BSO_RESSECT 0x0e ; Offset to Number of Reserved Sectors
47 #define FAT16_BSO_VOLPTR 0x1c ; Offset to First VolumeSector
48 #define FAT16_BSO_SECPERFAT 0x16 ; Offset to Number of Sectors per Fat
49 #define FAT16_BSO_NUMFATCP 0x10 ; Offset to Ammount of FAT Copys
50 #define FAT16_BSO_NUMDIRENT 0x11 ; Offset to Max. Root Dir. Entrys
51 #define FAT16_FIRST_IMAGENAME 'A' ; First letter of filename to search
52 #define FAT16_LAST_IMAGENAME 'Z' ; Last letter of filename to search
54 ; ############################################################################
55 ; Start of Data Segment
56 ; ############################################################################
59 fat_partfound: .byte 1 ; (partition: 0= no found 1=found )
60 fat_parttbl: .byte 4 ; first fat16 partition entry
61 ; only startsector is needed
62 fat_clustersize: .byte 1 ; sectors per cluster
63 fat_numdirentrys:.byte 2 ; Max. num. of entrys within Rootdirektory
64 fat_ptr2fat: .byte 4 ; pointer to the first fat sector
65 fat_ptr2dat: .byte 4 ; pointer to the first data sector
67 /*These variables define a cache that holds the last Cluster and Sector
68 thats been searched vor. To save some of the valuabe SRAM- Space these
69 variables also are used as temporary variables by the function
72 fat_last_dsk: .byte 1 ; number of disk with entry in cache
73 fat_log_clust: .byte 2 ; last searched logical cluster
74 fat_clust_offset: .byte 1 ; offset within the cluster
75 fat_clust_ptr: .byte 4; ; sector of last real cluster
78 ; ############################################################################
79 ; Start of Code Segment
80 ; ############################################################################
83 ; ============================================================================
84 ; Function: Initialize internal FAT-Partition Variables
85 ; ============================================================================
87 ; ----------------------------------------------------------------------------
89 ; Variables : [out] fat_parttabl
90 ; ----------------------------------------------------------------------------
92 ; This Routine initializes the internal Variables, that point to the
93 ; first Found FAT16 Partition.
94 ; ============================================================================
95 fat_init_partitiontable:
110 ; ============================================================================
111 ; Function: Resets the Cache
112 ; ============================================================================
114 ; ----------------------------------------------------------------------------
116 ; Variables : [out] fat_log_clust
118 ; ----------------------------------------------------------------------------
120 ; This Routine resets the internal Cache- Variables. After reset, the
121 ; next read or write Command will initialize a scan of the FAT of
122 ; the FAT16-Partition for the given sector.
123 ; ============================================================================
127 sts fat_log_clust ,yl
128 sts fat_log_clust+1,yl
133 ; ============================================================================
134 ; Function: Saves FAT16 Partitiondata for later Scanning
135 ; ============================================================================
137 ; ----------------------------------------------------------------------------
138 ; Registers : [in] z Pointer to the Partitondata
139 ; Variables : [out] fat_partfound Boolean for "Partition found"
140 ; [out] fat_parttbl Pointer to Partitiontable
141 ; ----------------------------------------------------------------------------
143 ; This funktion sets the internal Variables to the Start and Size
144 ; of a given FAT16 Paritition. This Information will be used for a
145 ; later scanning of the Partition. See Function "fat_scan_partition"
146 ; for more information.
147 ; ============================================================================
151 printstring "fat16 part found",0
156 ; save variables on stack
160 ; set fat16 partition found flag
164 ; save data from first fat16 partition
167 ldd temp,z+PART_START
169 ldd temp,z+PART_START+1
171 ldd temp,z+PART_START+2
173 ldd temp,z+PART_START+3
176 ; Don't need the Size of the Partition for use with Imagefiles
177 ; ldd temp,z+PART_SIZE
179 ; ldd temp,z+PART_SIZE+1
181 ; ldd temp,z+PART_SIZE+2
183 ; ldd temp,z+PART_SIZE+3
187 ; reload variables from stack
193 ; ============================================================================
194 ; Read and Scann a FAT16 Partition for Imagedatefiles
195 ; ============================================================================
198 ; ----------------------------------------------------------------------------
199 ; This Routine reads the Bootblock and scanns it for a Diskimage
200 ; ============================================================================
206 printstring "fat16 scanning",0
210 ; Check if a FAT16 Partition was realy found
217 printstring "free entrys in ptable ?",0
221 ; Check for free Entrys in Partition table
227 printstring "read fat bootblock.",0
231 ; Scan partition start
238 ; Load first sector from Partition
241 breq fat_bootblock_check
243 ; Read error: Block not found
251 printstring "fat16 bootblock check",0
255 ; get sectors per cluster from bootblock
256 ldiw z,hostbuf+FAT16_BSO_CLUSTSZ
258 sts fat_clustersize,temp
261 printstring "Sectors per Cluster ",0
266 ; get num of FAT Tables from bootblock
267 ldiw z,hostbuf+FAT16_BSO_NUMFATCP
269 sts fat_last_dsk,temp ; low byte
272 printstring "Ammount of FAT copies: ",0
277 ; get max num of entrys in root direktory from bootblock
278 ldiw z,hostbuf+FAT16_BSO_NUMDIRENT
280 sts fat_numdirentrys,temp ; low byte
282 sts fat_numdirentrys+1,temp2 ; high byte
285 printstring "Max. entrys in Rootdir.: ",0
290 ; Print begin of Volume
299 printstring "Begin of Volume at: ",0
309 ; get num of sectors per FAT-Table from bootblock
310 ldiw z,hostbuf+FAT16_BSO_SECPERFAT
312 sts fat_log_clust,temp ; low byte
314 sts fat_log_clust+1,temp2 ; high byte
317 printstring "Sectors per FAT__: ",0
322 ; get num of reseved sectors from bootblock
323 ldiw z,hostbuf+FAT16_BSO_RESSECT
327 ; Calculate begin of FAT within the Volume
345 printstring "Begin of FAT at___: ",0
355 ; Calculate begin of Root- Directory within the Volume
362 lds temp ,fat_log_clust
363 lds temp2,fat_log_clust+1
364 lds temp3,fat_last_dsk
368 breq fat_calc_dp_lend
380 sts fat_clust_ptr ,xl
381 sts fat_clust_ptr+1,xh
382 sts fat_clust_ptr+2,yl
383 sts fat_clust_ptr+3,yh
387 printstring "Begin of DIR at___: ",0
397 ; Calculate begin of DATA Clusters within the Volume
398 ; Num. Dir.Sektors = (Num. of Dir. Entrys * 32) / Bytes per Sektor
400 ; Sectorsize is fixed at 512 Bytes, makes 16 Entrys per Sektor
402 lds zl,fat_numdirentrys ; low byte
403 lds zh,fat_numdirentrys+1 ; high byte
405 ; Num. Direntrys / 16
416 lds xh,fat_clust_ptr+1
417 lds yl,fat_clust_ptr+2
418 lds yh,fat_clust_ptr+3
431 printstring "Begin of Data at__: ",0
441 ; Here Starts the Scann of the Directory for valid image Files.
443 ; Init Image-Namecounter
444 ldi temp,FAT16_FIRST_IMAGENAME
445 sts fat_last_dsk,temp
447 fat_scan_for_next_image:
449 ; Init Offset into Directory-Sectors
451 sts fat_clust_offset,temp
453 ; Init counter for number of entry left to scan
454 lds temp,fat_numdirentrys
455 sts fat_log_clust ,temp
457 lds temp,fat_numdirentrys+1
458 sts fat_log_clust+1,temp
460 fat_next_sector_loop:
461 ; Get a Pointer to the first Directory sector
463 lds xh,fat_clust_ptr+1
464 lds yl,fat_clust_ptr+2
465 lds yh,fat_clust_ptr+3
468 lds temp,fat_clust_offset
474 ; Load sector from Directory
477 breq fat_look_for_images
479 ; Read error: Block not found
483 ; Looks at a read directory block for image entrys
518 lds temp3,fat_last_dsk ; Get actual Diskname (A to Z)
535 sts fat_clust_ptr ,zl
536 sts fat_clust_ptr+1,zh
537 sts fat_clust_ptr+2,temp2
538 jmp fat_store_new_entry
544 printstring "At:Scann for more ",0
548 lds zl ,fat_clust_ptr
549 lds zh ,fat_clust_ptr+1
550 lds temp2,fat_clust_ptr+2
560 cpi temp2,16 ; max entrys/sector
561 breq fat_scan_next_sector
562 jmp fat_look_for_loop
564 fat_scan_next_sector:
567 printstring "At:Scan next Sector",0
571 lds temp3, fat_log_clust
572 lds temp4, fat_log_clust+1
577 sts fat_log_clust,temp3
578 sts fat_log_clust+1,temp4
584 lds temp,fat_clust_offset
586 sts fat_clust_offset,temp
588 rjmp fat_next_sector_loop
593 printstring "At:Scan at end",0
597 lds temp,fat_last_dsk
599 sts fat_last_dsk,temp
601 ldi temp2,FAT16_LAST_IMAGENAME
603 brge fat_scaned_last_disk
605 rjmp fat_scan_for_next_image
607 fat_scaned_last_disk:
612 ; Create new Partition Entry
615 ; Found a valid image
617 printstring "Found a valid Image ! Z=",0
631 adiw y,PARTENTRY_SIZE
633 jmp fat_look_store_loop
636 ; Set Type of Partition to FAT16- Fileimage
641 printstring "ClusterID",0
643 ; Offset to Startcluster + 2
672 ; Convert Filesize to ammount of sectors
673 ; (calc with 512byte/sector)
684 ; store ammount of sectors in partitiontable
691 ; Test finding of the first sector
698 printstring "Begin of Image at: ",0
708 ; Check for another free entry in partition table
716 jmp fat_scan_for_more
723 ; ============================================================================
724 ; Function: Cluster to HostSector
725 ; ============================================================================
726 ; Parameters: [in] xh,xl Cluster Number
727 ; [out] yh,yl,xh,xl Sector Number on Disk
728 ; ----------------------------------------------------------------------------
730 ; Variables : [used] fat_clustersize Ammount of Sectors per Cluster
732 ; ----------------------------------------------------------------------------
734 ; ! Only works with Clustersizes 2,4,8,16,32,64,128 !
735 ; ============================================================================
738 ; Get Offset into Data area of Disk
742 ; add begin of data area to offset
743 lds temp,fat_ptr2dat+0
745 lds temp,fat_ptr2dat+1
747 lds temp,fat_ptr2dat+2
749 lds temp,fat_ptr2dat+3
753 ; ============================================================================
754 ; Function: Cluster to Sector
755 ; ============================================================================
756 ; Registers: [in] xl,xh Cluster Number
757 ; [out] xl,xh,yl,yh Sector Number
758 ; Variables: [in] fat_clustersize Ammount of Sectors per Cluster
760 ; ----------------------------------------------------------------------------
762 ; Calculates the logical Sectornumber given the physical ClusterNumber
763 ; and the size of a Cluster un sectors.
765 ; ! Only works with Clustersizes 2,4,8,16,32,64,128,512,1024 !
766 ; ============================================================================
772 sub xl,temp ; Substract the 2 reserved clusters
775 lds temp,fat_clustersize
792 ; ====================================================================
793 ; Function: Searches a physical Cluster, given the logical Cluster
794 ; ====================================================================
795 ; Registers: [in] xh,xl logical- Cluster
796 ; [out] yh,yl physical- Cluster
798 ; --------------------------------------------------------------------
800 ; ====================================================================
805 rcall dsk_getpartentry ; get partition entry
808 ; Get First FAT- Cluster Number of Diskimage
813 .if FAT16_DBG_FAT > 0
814 printstring "Search log. Cluster ",0
820 printstring "Search phys. Cluster ",0
830 breq fat_found_phsy_clust
831 ; Get Next Cluster from Fat
833 ; Trick: 512 Bytes Per Sector equals to 256 FAT- Entrys per Sector
834 ; so given: yl is the Offset within the FAT Sector
835 ; yh is the number off se FAT sector to Read
837 ; in zh,zl: Pointer to Word within the Sector to read
838 ; in yh..xl: Start sector number (LBA)
839 ; out zh,zl : word thats been read
843 ; Create FAT Offset Value
854 ; Add Cluster offset within sector
867 ; Check next logical Cluster
871 rjmp fat_next_phsy_clust
873 ; Found the physical cluster
874 fat_found_phsy_clust:
875 .if FAT16_DBG_FAT > 0
876 printstring "Found phys. Cluster at:",0
885 ; ============================================================================
886 ; Function: This Routine searches for the Sector within an Imagefile
887 ; ============================================================================
888 ; Registers: [out] xl,xh,yl,yh Pointer to the Sector on the SD-Card
889 ; [out] temp Error- Variable (0= No Error)
890 ; Variables: [in] hostdsk host disk #, (partition #)
891 ; [in] hostlba host block #, relative to part.start
892 ; [in] fat_last_dsk number of disk with entry in cache
893 ; [in] fat_log_clust last searched logical cluster
894 ; [in] fat_clust_offset offset within the cluster
895 ; [in] fat_clust_ptr sector of last real cluster
896 ; ----------------------------------------------------------------------------
898 ; This Routine uses the variables hostdsk and hostlba to find an Sector
900 ; The CP/M Sector given within "hostlba" are splited to a logical Cluster-
901 ; Number and the Subsector within this logical Cluster.
902 ; logical Cluster Number = hostlba / fat_clustersize
903 ; The logical Cluster Number will be compared to the logical Cluster- Number
904 ; within the Cache. When this Clusters are the same and the DiskID's are
905 ; also the same, then the cached physical Sector will be used.
906 ; When the Clusters or the Disks don't match, a seek for the physical
907 ; Cluster is performed. This seek is done thru an access over the FAT of
908 ; the FAT16 Partition. The Routine starts at the first Cluster of the
909 ; Imagefile and goes along the linked list of Clusternumber till it reaches
910 ; the searched cluster. The found Clusternumber will be used to calculate
911 ; the Sektor where this Cluster lies on the SD- Card. Both the found physical
912 ; Cluster and the logical Cluster together with the physical Sectornumber
913 ; are stored in the cache.
914 ; The last step done is to add the SubSectorOffset to the found physical
915 ; Sector. This gives the pointer to the Sector to be read and or written.
916 ; ============================================================================
922 rcall dsk_getpartentry ; get partition entry
930 ldd xl,z+5 ; get size of disk in sectors
934 cp temp,xl ; check given sector against disksize
943 ; ################# Get logical Number of Cluster within the imagefile
944 ; printstring "calc log sector"
945 ; Get logical Sectornumber from temp
950 ; Divide logical Sectornumber by size of Cluster in sectors
951 lds zl,fat_clustersize
964 rjmp fat_search_clst_lp
966 ; at this point xh and xl are carying the logical cluster number
967 ; printstring "find subsector"
968 ; ################# Get Subsector within the logical Cluster for later use
970 lds zl,fat_clustersize
974 breq fat_found_subsec
978 rjmp fat_search_clst_lp2
983 sts fat_clust_offset,zl
985 ; Check against last HOSTDISK searched
989 brne fat_wrong_cache_clst
991 ; Check against last Cluster searched
993 lds yh,fat_log_clust+1
996 brne fat_wrong_cache_clst
998 brne fat_wrong_cache_clst
1000 ; Last Cluster = searched Cluster -> get Sectornumber from cache
1001 lds xl,fat_clust_ptr
1002 lds xh,fat_clust_ptr+1
1003 lds yl,fat_clust_ptr+2
1004 lds yh,fat_clust_ptr+3
1008 ; Cluster is not in cache, so we must search for it
1009 fat_wrong_cache_clst:
1012 sts fat_log_clust,xl
1013 sts fat_log_clust+1,xh
1015 ; Map Logical Cluster-Number to "Physical" Cluster Number using the FAT
1016 rcall fat_find_phsy_clust
1018 ; Get StartSector of "physical" Cluster
1021 rcall fat_gethostsec
1022 ; Found the physical sector
1023 .if FAT16_DBG_FAT > 0
1024 printstring "Found phys. Sector at:",0
1034 ; Save the found Sector for later use into cache
1035 sts fat_clust_ptr ,xl
1036 sts fat_clust_ptr+1,xh
1037 sts fat_clust_ptr+2,yl
1038 sts fat_clust_ptr+3,yh
1040 ; Add- Subsector to Startsector
1042 lds zl,fat_clust_offset
1048 ; Found the physical sector
1049 .if FAT16_DBG_FAT > 0
1050 printstring "Sector with Offset at:",0
1064 ; ============================================================================
1065 ; Function: Does a Disk write operation
1066 ; ============================================================================
1067 ; Registers: [out] temp Error-Variable ( 0= No Error)
1068 ; Variables: [in] hostdsk host disk #, (partition #)
1069 ; [in] hostlba host block #, relative to part.start
1070 ; [in] hostbuf Sector to be written
1071 ; ----------------------------------------------------------------------------
1073 ; This Routine writes a Sector to the Imagefile inside an FAT16 Partition.
1074 ; ============================================================================
1077 .if FAT16_RWDEBUG > 1
1079 printstring "host write "
1084 ;call mmcWriteSect ; disabled till read is functioning
1088 rcall mgr_init_partitions
1094 ;call mmcWriteSect ; disabled till read is functioning
1107 ; ============================================================================
1108 ; Function: Does a Disk read operation
1109 ; ============================================================================
1111 ; Variables: [in] hostdsk host disk #, (partition #)
1112 ; [in] hostlba host block #, relative to part.start
1113 ; [out] hostbuf Sector read by this routine
1114 ; ----------------------------------------------------------------------------
1116 ; This Routine reads a Sector from the Imagefile inside an FAT16 Partition.
1117 ; ============================================================================
1120 .if FAT16_RWDEBUG > 1
1122 printstring "host read "
1129 .if FAT16_RWDEBUG > 0
1130 printstring "Read Image Sector:"
1149 rcall mgr_init_partitions