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 PARTID1_FAT16 0x0E
40 #define PARTID2_FAT16 0x06
42 /*These are the Offsets to the Variables within the Bootsector of a FAT16
45 ;#define FAT16_BSO_SECSIZE 0x0b ; Offset to Sectorsize Word
46 #define FAT16_BSO_CLUSTSZ 0x0d ; Offset to Clustersize Byte
47 #define FAT16_BSO_RESSECT 0x0e ; Offset to Number of Reserved Sectors
48 #define FAT16_BSO_VOLPTR 0x1c ; Offset to First VolumeSector
49 #define FAT16_BSO_SECPERFAT 0x16 ; Offset to Number of Sectors per Fat
50 #define FAT16_BSO_NUMFATCP 0x10 ; Offset to Ammount of FAT Copys
51 #define FAT16_BSO_NUMDIRENT 0x11 ; Offset to Max. Root Dir. Entrys
52 #define FAT16_FIRST_IMAGENAME 'A' ; First letter of filename to search
53 #define FAT16_LAST_IMAGENAME 'A'+MAXDISKS-1 ; Last letter of filename to
56 ; ############################################################################
57 ; Start of Data Segment
58 ; ############################################################################
61 fat_partfound: .byte 1 ; (partition: 0= no found 1=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_numdirentrys:.byte 2 ; Max. num. of entrys 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 ; ============================================================================
128 sts fat_log_clust ,yl
129 sts fat_log_clust+1,yl
134 ; ============================================================================
135 ; Function: Saves FAT16 Partitiondata for later Scanning
136 ; ============================================================================
138 ; ----------------------------------------------------------------------------
139 ; Registers : [in] z Pointer to the Partitondata
140 ; Variables : [out] fat_partfound Boolean for "Partition found"
141 ; [out] fat_parttbl Pointer to Partitiontable
142 ; ----------------------------------------------------------------------------
144 ; This funktion sets the internal Variables to the Start and Size
145 ; of a given FAT16 Paritition. This Information will be used for a
146 ; later scanning of the Partition. See Function "fat_scan_partition"
147 ; for more information.
148 ; ============================================================================
152 printstring "fat16 part found"
157 ; save variables on stack
161 ; set fat16 partition found flag
165 ; save data from first fat16 partition
168 ldd temp,z+PART_START
170 ldd temp,z+PART_START+1
172 ldd temp,z+PART_START+2
174 ldd temp,z+PART_START+3
177 ; reload variables from stack
183 ; ============================================================================
184 ; Read and Scann a FAT16 Partition for Imagedatefiles
185 ; ============================================================================
188 ; ----------------------------------------------------------------------------
189 ; This Routine reads the Bootblock and scanns it for a Diskimage
190 ; ============================================================================
196 printstring "fat16 scanning"
200 ; Check if a FAT16 Partition was realy found
207 printstring "free entrys in ptable ?"
211 ; Check for free Entrys in Partition table
217 printstring "read fat bootblock."
221 ; Scan partition start
228 ; Load first sector from Partition
231 breq fat_bootblock_check
233 ; Read error: Block not found
241 printstring "fat16 bootblock check"
245 ; get sectors per cluster from bootblock
246 ldiw z,hostbuf+FAT16_BSO_CLUSTSZ
248 sts fat_clustersize,temp
251 printstring "Sectors per Cluster "
256 ; get num of FAT Tables from bootblock
257 ldiw z,hostbuf+FAT16_BSO_NUMFATCP
259 sts fat_last_dsk,temp ; low byte
262 printstring "Ammount of FAT copies: "
267 ; get max num of entrys in root direktory from bootblock
268 ldiw z,hostbuf+FAT16_BSO_NUMDIRENT
270 sts fat_numdirentrys,temp ; low byte
272 sts fat_numdirentrys+1,temp2 ; high byte
275 printstring "Max. entrys in Rootdir.: "
280 ; Print begin of Volume
289 printstring "Begin of Volume at: "
299 ; get num of sectors per FAT-Table from bootblock
300 ldiw z,hostbuf+FAT16_BSO_SECPERFAT
302 sts fat_log_clust,temp ; low byte
304 sts fat_log_clust+1,temp2 ; high byte
307 printstring "Sectors per FAT__: "
312 ; get num of reseved sectors from bootblock
313 ldiw z,hostbuf+FAT16_BSO_RESSECT
317 ; Calculate begin of FAT within the Volume
335 printstring "Begin of FAT at___: "
345 ; Calculate begin of Root- Directory within the Volume
352 lds temp ,fat_log_clust
353 lds temp2,fat_log_clust+1
354 lds temp3,fat_last_dsk
358 breq fat_calc_dp_lend
367 rjmp fat_calc_dp_loop
370 sts fat_clust_ptr ,xl
371 sts fat_clust_ptr+1,xh
372 sts fat_clust_ptr+2,yl
373 sts fat_clust_ptr+3,yh
377 printstring "Begin of DIR at___: "
387 ; Calculate begin of DATA Clusters within the Volume
388 ; Num. Dir.Sektors = (Num. of Dir. Entrys * 32) / Bytes per Sektor
390 ; Sectorsize is fixed at 512 Bytes, makes 16 Entrys per Sektor
392 lds zl,fat_numdirentrys ; low byte
393 lds zh,fat_numdirentrys+1 ; high byte
395 ; Num. Direntrys / 16
406 lds xh,fat_clust_ptr+1
407 lds yl,fat_clust_ptr+2
408 lds yh,fat_clust_ptr+3
421 printstring "Begin of Data at__: "
431 ; Here Starts the Scann of the Directory for valid image Files.
433 ; Init Image-Namecounter
434 ldi temp,FAT16_FIRST_IMAGENAME
435 sts fat_last_dsk,temp
437 fat_scan_for_next_image:
439 ; Init Offset into Directory-Sectors
441 sts fat_clust_offset,temp
443 ; Init counter for number of entry left to scan
444 lds temp,fat_numdirentrys
445 sts fat_log_clust ,temp
447 lds temp,fat_numdirentrys+1
448 sts fat_log_clust+1,temp
450 fat_next_sector_loop:
451 ; Get a Pointer to the first Directory sector
453 lds xh,fat_clust_ptr+1
454 lds yl,fat_clust_ptr+2
455 lds yh,fat_clust_ptr+3
458 lds temp,fat_clust_offset
464 ; Load sector from Directory
467 breq fat_look_for_images
469 ; Read error: Block not found
473 ; Looks at a read directory block for image entrys
508 lds temp3,fat_last_dsk ; Get actual Diskname (A to Z)
528 rjmp fat_store_new_entry
540 cpi temp2,16 ; max entrys/sector
541 breq fat_scan_next_sector
542 rjmp fat_look_for_loop
544 fat_scan_next_sector:
547 lds temp3, fat_log_clust
548 lds temp4, fat_log_clust+1
553 sts fat_log_clust,temp3
554 sts fat_log_clust+1,temp4
560 lds temp,fat_clust_offset
562 sts fat_clust_offset,temp
564 rjmp fat_next_sector_loop
568 lds temp,fat_last_dsk
570 sts fat_last_dsk,temp
572 ldi temp2,FAT16_LAST_IMAGENAME
574 brge fat_scaned_last_disk
576 rjmp fat_scan_for_next_image
578 fat_scaned_last_disk:
583 ; Create new Partition Entry
586 ; Found a valid image
588 printstring "Found a valid Image ! Z="
602 adiw y,PARTENTRY_SIZE
604 rjmp fat_look_store_loop
607 ; Set Type of Partition to FAT16- Fileimage
612 ; Offset to Startcluster + 2
633 ; Convert Filesize to ammount of sectors
634 ; (calc with 512byte/sector)
645 ; store ammount of sectors in partitiontable
652 ; Test finding of the first sector
659 printstring "Begin of Image at: "
669 ; Check for another free entry in partition table
677 rjmp fat_scan_for_more
684 ; ============================================================================
685 ; Function: Cluster to HostSector
686 ; ============================================================================
687 ; Parameters: [in] xh,xl Cluster Number
688 ; [out] yh,yl,xh,xl Sector Number on Disk
689 ; ----------------------------------------------------------------------------
691 ; Variables : [used] fat_clustersize Ammount of Sectors per Cluster
693 ; ----------------------------------------------------------------------------
695 ; ! Only works with Clustersizes 2,4,8,16,32,64,128 !
696 ; ============================================================================
699 ; Get Offset into Data area of Disk
703 ; add begin of data area to offset
704 lds temp,fat_ptr2dat+0
706 lds temp,fat_ptr2dat+1
708 lds temp,fat_ptr2dat+2
710 lds temp,fat_ptr2dat+3
714 ; ============================================================================
715 ; Function: Cluster to Sector
716 ; ============================================================================
717 ; Registers: [in] xl,xh Cluster Number
718 ; [out] xl,xh,yl,yh Sector Number
719 ; Variables: [in] fat_clustersize Ammount of Sectors per Cluster
721 ; ----------------------------------------------------------------------------
723 ; Calculates the logical Sectornumber given the physical ClusterNumber
724 ; and the size of a Cluster un sectors.
726 ; ! Only works with Clustersizes 2,4,8,16,32,64,128 !
727 ; ============================================================================
733 sub xl,temp ; Substract the 2 reserved clusters
736 lds temp,fat_clustersize
753 ; ====================================================================
754 ; Function: Searches a physical Cluster, given the logical Cluster
755 ; ====================================================================
756 ; Registers: [in] xh,xl logical- Cluster
757 ; [out] yh,yl physical- Cluster
759 ; --------------------------------------------------------------------
761 ; ====================================================================
766 rcall dsk_getpartentry ; get partition entry
769 ; Get First FAT- Cluster Number of Diskimage
774 .if FAT16_DBG_FAT > 0
775 printstring "Search log. Cluster "
781 printstring "Search phys. Cluster "
791 breq fat_found_phsy_clust
792 ; Get Next Cluster from Fat
794 ; Trick: 512 Bytes Per Sector equals to 256 FAT- Entrys per Sector
795 ; so given: yl is the Offset within the FAT Sector
796 ; yh is the number off se FAT sector to Read
798 ; in zh,zl: Pointer to Word within the Sector to read
799 ; in yh..xl: Start sector number (LBA)
800 ; out zh,zl : word thats been read
804 ; Create FAT Offset Value
815 ; Add Cluster offset within sector
828 ; Check next logical Cluster
832 rjmp fat_next_phsy_clust
834 ; Found the physical cluster
835 fat_found_phsy_clust:
837 .if FAT16_DBG_FAT > 0
838 printstring "Found phys. Cluster at:"
847 ; ============================================================================
848 ; Function: This Routine searches for the Sector within an Imagefile
849 ; ============================================================================
850 ; Registers: [out] xl,xh,yl,yh Pointer to the Sector on the SD-Card
851 ; [out] temp Error- Variable (0= No Error)
852 ; Variables: [in] hostdsk host disk #, (partition #)
853 ; [in] hostlba host block #, relative to part.start
854 ; [in] fat_last_dsk number of disk with entry in cache
855 ; [in] fat_log_clust last searched logical cluster
856 ; [in] fat_clust_offset offset within the cluster
857 ; [in] fat_clust_ptr sector of last real cluster
858 ; ----------------------------------------------------------------------------
860 ; This Routine uses the variables hostdsk and hostlba to find an Sector
862 ; The CP/M Sector given within "hostlba" are splited to a logical Cluster-
863 ; Number and the Subsector within this logical Cluster.
864 ; logical Cluster Number = hostlba / fat_clustersize
865 ; The logical Cluster Number will be compared to the logical Cluster- Number
866 ; within the Cache. When this Clusters are the same and the DiskID's are
867 ; also the same, then the cached physical Sector will be used.
868 ; When the Clusters or the Disks don't match, a seek for the physical
869 ; Cluster is performed. This seek is done thru an access over the FAT of
870 ; the FAT16 Partition. The Routine starts at the first Cluster of the
871 ; Imagefile and goes along the linked list of Clusternumber till it reaches
872 ; the searched cluster. The found Clusternumber will be used to calculate
873 ; the Sektor where this Cluster lies on the SD- Card. Both the found physical
874 ; Cluster and the logical Cluster together with the physical Sectornumber
875 ; are stored in the cache.
876 ; The last step done is to add the SubSectorOffset to the found physical
877 ; Sector. This gives the pointer to the Sector to be read and or written.
878 ; ============================================================================
884 rcall dsk_getpartentry ; get partition entry
892 ldd xl,z+5 ; get size of disk in sectors
896 cp temp,xl ; check given sector against disksize
905 ; ################# Get logical Number of Cluster within the imagefile
906 ; printstring "calc log sector"
907 ; Get logical Sectornumber from temp
912 ; Divide logical Sectornumber by size of Cluster in sectors
913 lds zl,fat_clustersize
926 rjmp fat_search_clst_lp
929 ; at this point xh and xl are carying the logical cluster number
930 ; printstring "find subsector"
931 ; ################# Get Subsector within the logical Cluster for later use
933 lds zl,fat_clustersize
937 breq fat_found_subsec
941 rjmp fat_search_clst_lp2
946 sts fat_clust_offset,zl
948 ; Check against last HOSTDISK searched
952 brne fat_wrong_cache_clst
954 ; Check against last Cluster searched
956 lds yh,fat_log_clust+1
959 brne fat_wrong_cache_clst
961 brne fat_wrong_cache_clst
963 ; Last Cluster = searched Cluster -> get Sectornumber from cache
965 lds xh,fat_clust_ptr+1
966 lds yl,fat_clust_ptr+2
967 lds yh,fat_clust_ptr+3
971 ; Cluster is not in cache, so we must search for it
972 fat_wrong_cache_clst:
976 sts fat_log_clust+1,xh
978 ; Map Logical Cluster-Number to "Physical" Cluster Number using the FAT
979 rcall fat_find_phsy_clust
981 ; Get StartSector of "physical" Cluster
986 ; Found the physical sector
987 .if FAT16_DBG_FAT > 0
988 printstring "Found phys. Sector at:"
998 ; Save the found Sector for later use into cache
999 sts fat_clust_ptr ,xl
1000 sts fat_clust_ptr+1,xh
1001 sts fat_clust_ptr+2,yl
1002 sts fat_clust_ptr+3,yh
1004 ; Add- Subsector to Startsector
1006 lds zl,fat_clust_offset
1012 ; Found the physical sector
1013 .if FAT16_DBG_FAT > 0
1014 printstring "Sector with Offset at:"
1028 ; ============================================================================
1029 ; Function: Does a Disk write operation
1030 ; ============================================================================
1031 ; Registers: [out] temp Error-Variable ( 0= No Error)
1032 ; Variables: [in] hostdsk host disk #, (partition #)
1033 ; [in] hostlba host block #, relative to part.start
1034 ; [in] hostbuf Sector to be written
1035 ; ----------------------------------------------------------------------------
1037 ; This Routine writes a Sector to the Imagefile inside an FAT16 Partition.
1038 ; ============================================================================
1041 .if FAT16_RWDEBUG > 1
1043 printstring "host write "
1052 rjmp fat_rdwr_err ; skip disk change detection code
1054 ; After a second thought, the following code doesn't make sense, because
1055 ; disk change (change of one or more disk images) can not reliably detected.
1056 ; At least with the existing code.
1060 rcall mgr_init_partitions
1066 call mmcWriteSect ; disabled till read is functioning
1079 ; ============================================================================
1080 ; Function: Does a Disk read operation
1081 ; ============================================================================
1083 ; Variables: [in] hostdsk host disk #, (partition #)
1084 ; [in] hostlba host block #, relative to part.start
1085 ; [out] hostbuf Sector read by this routine
1086 ; ----------------------------------------------------------------------------
1088 ; This Routine reads a Sector from the Imagefile inside an FAT16 Partition.
1089 ; ============================================================================
1092 .if FAT16_RWDEBUG > 1
1094 printstring "host read "
1101 .if FAT16_RWDEBUG > 0
1102 printstring "Read Image Sector:"
1121 rjmp fat_rdwr_err ; skip disk change detection code
1123 rcall mgr_init_partitions