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,2013 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 ; ############################################################################
62 fat_partfound: .byte 1 ; (partition: 0= no found 0xff=found )
63 fat_parttbl: .byte 4 ; first fat16 partition entry
64 ; only startsector is needed
65 fat_clustersize: .byte 1 ; sectors per cluster
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.
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
77 .equ o_fat_partfound = 0
78 .equ o_fat_parttbl = 1
79 .equ o_fat_clustersize = 5
80 .equ o_fat_ptr2fat = 6
81 .equ o_fat_ptr2dat = 10
82 .equ o_fat_last_dsk = 14
83 .equ o_fat_log_clust = 15
84 .equ o_fat_clust_offset= 17
85 .equ o_fat_clust_ptr = 18
89 fat_last_fatsect: .byte 1
90 .equ o_fat_last_fatsect = 22
96 ; ############################################################################
97 ; Start of Code Segment
98 ; ############################################################################
102 fat_cfname: .db FAT16_IMAGENAME_PREFIX, 0
103 fat_cfext: .db FAT16_IMAGENAME_SUFFIX, 0
106 ; ============================================================================
107 ; Function: Initialize internal FAT-Partition Variables
108 ; ============================================================================
110 ; ----------------------------------------------------------------------------
112 ; Variables : [out] fat_parttabl
113 ; ----------------------------------------------------------------------------
115 ; This Routine initializes the internal Variables, that point to the
116 ; first Found FAT16 Partition.
117 ; ============================================================================
118 fat_init_partitiontable:
121 std y+o_fat_partfound, _0
122 std y+o_fat_parttbl+0, _0
123 std y+o_fat_parttbl+1, _0
124 std y+o_fat_parttbl+2, _0
125 std y+o_fat_parttbl+3, _0
129 ; ============================================================================
130 ; Function: Resets the Cache
131 ; ============================================================================
133 ; ----------------------------------------------------------------------------
135 ; Variables : [out] fat_log_clust
137 ; ----------------------------------------------------------------------------
139 ; This Routine resets the internal Cache- Variables. After reset, the
140 ; next read or write Command will initialize a scan of the FAT of
141 ; the FAT16-Partition for the given sector.
142 ; ============================================================================
145 std y+o_fat_log_clust ,_255
146 std y+o_fat_log_clust+1,_255
147 std y+o_fat_last_dsk ,_255
149 std y+o_fat_last_fatsect,_255
154 ; ============================================================================
155 ; Function: Saves FAT16 Partitiondata for later Scanning
156 ; ============================================================================
158 ; ----------------------------------------------------------------------------
159 ; Registers : [in] z Pointer to the Partitondata
160 ; Variables : [out] fat_partfound Boolean for "Partition found"
161 ; [out] fat_parttbl Pointer to Partitiontable
162 ; ----------------------------------------------------------------------------
164 ; This funktion sets the internal Variables to the Start and Size
165 ; of a given FAT16 Paritition. This Information will be used for a
166 ; later scanning of the Partition. See Function "fat_scan_partition"
167 ; for more information.
168 ; ============================================================================
173 printstring "fat16 part found"
179 ; set fat16 partition found flag
181 std y+o_fat_partfound,_255
183 ; save data from first fat16 partition
185 ldd temp,z+PART_START
186 std y+o_fat_parttbl,temp
187 ldd temp,z+PART_START+1
188 std y+o_fat_parttbl+1,temp
189 ldd temp,z+PART_START+2
190 std y+o_fat_parttbl+2,temp
191 ldd temp,z+PART_START+3
192 std y+o_fat_parttbl+3,temp
196 ; ============================================================================
197 ; Read and Scann a FAT16 Partition for Imagedatefiles
198 ; ============================================================================
201 ; ----------------------------------------------------------------------------
202 ; This Routine reads the Bootblock and scanns it for a Diskimage
203 ; ============================================================================
209 printstring "fat16 scanning"
213 ; Check if a FAT16 Partition was realy found
220 printstring "free entries in ptable ?"
224 ; Check for free entries in partition table
230 printstring "read fat bootblock."
234 ; Scan partition start
242 ; Load first sector from Partition
245 breq fat_bootblock_check
247 ; Read error: Block not found
255 printstring "fat16 bootblock check"
262 ; get sectors per cluster from bootblock
263 ldd temp,z+FAT16_BSO_CLUSTSZ
264 std y+o_fat_clustersize,temp
267 printstring "Sectors per Cluster "
272 ; get max num of entries in root direktory from bootblock
273 ldd temp ,z+FAT16_BSO_NUMDIRENT
274 ldd temp2,z+FAT16_BSO_NUMDIRENT+1
277 printstring "Max. entries in rootdir.: "
281 ; Calculate begin of DATA Clusters within the Volume
282 ; Num. Dir.Sektors = (Num. of Dir. entries * 32) / Bytes per Sektor
284 ; Sectorsize is fixed at 512 bytes, makes 16 entries per sector
287 ; Num. Direntries / 16
297 push temp ;save # of rootdir sectors
303 printstring " sectors)"
308 ; Print begin of Volume
309 printstring "Begin of Volume at: "
310 ldd temp, y+o_fat_parttbl+2
311 ldd temp2,y+o_fat_parttbl+3
313 ldd temp, y+o_fat_parttbl+0
314 ldd temp2,y+o_fat_parttbl+1
319 ; get num of reseved sectors from bootblock
320 ldd _tmp0,z+FAT16_BSO_RESSECT
321 ldd _tmp1,z+FAT16_BSO_RESSECT+1
323 ; Calculate begin of FAT within the Volume
324 ldd xl,y+o_fat_parttbl+0
325 ldd xh,y+o_fat_parttbl+1
326 ldd temp,y+o_fat_parttbl+2
327 ldd temp2,y+o_fat_parttbl+3
334 std y+o_fat_ptr2fat ,xl
335 std y+o_fat_ptr2fat+1,xh
336 std y+o_fat_ptr2fat+2,temp
337 std y+o_fat_ptr2fat+3,temp2
340 printstring "Begin of FAT at___: "
347 ; get num of sectors per FAT-Table from bootblock
348 ldd temp, z+FAT16_BSO_SECPERFAT
349 ldd temp2,z+FAT16_BSO_SECPERFAT+1
352 printstring "Sectors per FAT___: "
357 ; get num of FAT Tables from bootblock
358 ldd temp3,z+FAT16_BSO_NUMFATCP
361 printstring "Ammount of FAT copies: "
371 ; Calculate begin of Root- Directory within the Volume
373 ldd xl, y+o_fat_ptr2fat+0
374 ldd xh, y+o_fat_ptr2fat+1
375 ldd temp, y+o_fat_ptr2fat+2
376 ldd temp2,y+o_fat_ptr2fat+3
380 breq fat_calc_dp_lend
387 rjmp fat_calc_dp_loop
392 printstring "Begin of DIR at___: "
403 pop temp3 ;number of rootdir sectors
410 std y+o_fat_ptr2dat ,xl
411 std y+o_fat_ptr2dat+1,xh
412 std y+o_fat_ptr2dat+2,temp
413 std y+o_fat_ptr2dat+3,temp2
416 printstring "Begin of Data at__: "
423 ;-------------------------------------------------------------------------------
424 ; Here starts the scan of the directory for valid image files.
427 fat_next_sector_loop:
429 ; Get a pointer to the last+1 directory sector
441 ; Load sector from Directory
445 breq fat_look_for_images
447 ; Read error: Block not found
451 ; Looks at a read directory block for image entries
460 ldi temp2,STRLEN(FAT16_IMAGENAME_PREFIX)
462 brne fat_look_continue
466 ldi temp2,STRLEN(FAT16_IMAGENAME_SUFFIX)
468 brne fat_look_continue
471 ldd temp2,y+STRLEN(FAT16_IMAGENAME_PREFIX)
472 ldi temp,FAT16_FIRST_IMAGENAME
473 fat_look_imgname_loop:
475 breq fat_look_imgname_match
477 cpi temp,FAT16_LAST_IMAGENAME+1
478 brlo fat_look_imgname_loop
479 rjmp fat_look_continue
481 fat_look_imgname_match:
482 rcall fat_store_new_entry
488 ldi temp,high(hostbuf+HOSTSIZE)
489 cpi xl,low(hostbuf+HOSTSIZE)
491 brne fat_look_for_loop
493 fat_scan_next_sector:
496 brne fat_next_sector_loop
503 dbg_print_parttbl_raw:
510 lcall dbg_hexdump_line
511 adiw z,PARTENTRY_SIZE
512 cpi zl,low(hostparttbltop)
513 ldi temp,high(hostparttbltop)
523 ;-------------------------------------------------------------------------------
524 ; Create new Partition Entry
525 ; ============================================================================
526 ; Function: Create new Partition Entry
527 ; ============================================================================
528 ; Parameters: [in] yh,yl Directory entry
530 ; ----------------------------------------------------------------------------
534 ; ----------------------------------------------------------------------------
537 ; ============================================================================
541 ; Found a valid image
544 printstring "Found a valid Image! Y="
556 printstring "Insert entry in Tab: --> "
560 printstring "Tab before:"
562 rcall dbg_print_parttbl_raw
571 breq fat_st_insert_slot
572 sbrs temp,log2(dskType_FAT)
573 rjmp fat_st_search_next
575 ldd temp,z+PTAB_START+2
577 brlo fat_st_ins_before
580 adiw z,PARTENTRY_SIZE
581 cpi zl,low(hostparttbltop)
582 ldi temp,high(hostparttbltop)
584 brne fat_st_searchpos
591 printstring "Table is full. --> ptr: "
603 ldiw z,hostparttbltop-PARTENTRY_SIZE
604 fat_st_insert_mkslotloop:
607 breq fat_st_insert_slot
610 std z+PARTENTRY_SIZE,_tmp0
611 rjmp fat_st_insert_mkslotloop
615 ; Set Type of Partition to FAT16- Fileimage
619 ; Offset to Startcluster + 2
622 std z+PTAB_START, _tmp0
623 std z+PTAB_START+1,_tmp1
625 std z+PTAB_START+2,temp2
626 std z+PTAB_START+3,_0
628 ; Convert Filesize to ammount of sectors
629 ; (calc with 512byte/sector)
636 cpse _tmp0,_0 ;round up
648 ; store ammount of sectors in partitiontable
650 tst temp ;file size larger than 65535 sectors?
660 ; Test finding of the first sector
669 printstring "Begin of image at: "
680 ; Table counts one more entry if it was'nt allready full
693 printstring "Table now:"
694 rcall dbg_print_parttbl_raw
701 ; ============================================================================
702 ; Function: Cluster to HostSector
703 ; ============================================================================
704 ; Registers: [in] xl,xh Cluster Number
705 ; [out] yh,yl,xh,xl Sector Number on Disk
706 ; Variables: [in] fat_clustersize Ammount of Sectors per Cluster
708 ; ----------------------------------------------------------------------------
710 ; Calculates the logical Sectornumber given the physical ClusterNumber
711 ; and the size of a Cluster un sectors.
713 ; ! Only works with Clustersizes 2,4,8,16,32,64,128 !
714 ; ============================================================================
719 ; Get Offset into Data area of Disk
723 sbiw x,2 ; Substract the 2 reserved clusters
725 ldd temp,y+o_fat_clustersize
739 ; Add begin of data area to offset
741 ldd temp,y+o_fat_ptr2dat+0
743 ldd temp,y+o_fat_ptr2dat+1
745 ldd temp,y+o_fat_ptr2dat+2
747 ldd temp,y+o_fat_ptr2dat+3
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 ; ====================================================================
764 rcall dsk_getpartentry ; get partition entry
766 ; Get First FAT- Cluster Number of Diskimage
771 .if FAT16_DBG_FAT > 0
772 printstring "Search log. cluster "
777 printstring "Search phys. cluster "
786 ; breq fat_found_phsy_clust
788 rjmp fat_found_phsy_clust
790 ; Get Next Cluster from Fat
792 ; Trick: 512 Bytes Per Sector equals to 256 FAT- entries per Sector
793 ; so given: yl is the Offset within the FAT Sector
794 ; yh is the number off the FAT sector to Read
796 ; in zh,zl: Pointer to Word within the Sector to read
797 ; in yh..xl: Start sector number (LBA)
798 ; out zh,zl : word thats been read
803 ; Create FAT Offset Value
813 ; Check, if required fat sector allready in buffer
815 lds temp2,fat_last_fatsect
816 sts fat_last_fatsect,temp
820 ; Not in buffer, get fat sector
822 lds xl,fat_ptr2fat ;get FAT start
826 add xl,temp ;add cluster offset within sector
832 printstring "Read FAT sec: "
854 lds xl,fat_ptr2fat ;get FAT start
858 add xl,temp ;add cluster offset within sector
869 ; Check next logical Cluster
872 rjmp fat_next_phsy_clust
874 ; Found the physical cluster
875 fat_found_phsy_clust:
877 .if FAT16_DBG_FAT > 0
878 printstring "Found phys. Cluster at:"
886 ; ============================================================================
887 ; Function: This Routine searches for the Sector within an Imagefile
888 ; ============================================================================
889 ; Registers: [out] xl,xh,yl,yh Pointer to the sector on the SD-Card
890 ; [out] temp Error variable (0= No Error)
891 ; Variables: [in] hostdsk host disk #, (partition #)
892 ; [in] hostlba host block #, relative to part.start
893 ; [in] fat_last_dsk number of disk with entry in cache
894 ; [in] fat_log_clust last searched logical cluster
895 ; [in] fat_clust_offset offset within the cluster
896 ; [in] fat_clust_ptr sector of last real cluster
897 ; ----------------------------------------------------------------------------
899 ; This routine uses the variables hostdsk and hostlba to find an sector
901 ; The CP/M sector given within "hostlba" are splited to a logical cluster-
902 ; number and the subsector within this logical cluster.
903 ; logical cluster number = hostlba / fat_clustersize
904 ; The logical cluster number will be compared to the logical cluster number
905 ; within the cache. When this clusters are the same and the diskid's are
906 ; also the same, then the cached physical sector will be used.
907 ; When the clusters or the disks don't match, a seek for the physical
908 ; cluster is performed. This seek is done thru an access over the fat of
909 ; the fat16 partition. the routine starts at the first cluster of the
910 ; imagefile and goes along the linked list of clusternumber till it reaches
911 ; the searched cluster. The found clusternumber will be used to calculate
912 ; the sektor where this cluster lies on the sd card. Both the found physical
913 ; cluster and the logical cluster together with the physical sectornumber
914 ; are stored in the cache.
915 ; The last step done is to add the subsectoroffset to the found physical
916 ; sector. this gives the pointer to the sector to be read and or written.
917 ; ============================================================================
922 ; ################# Get logical Number of Cluster within the imagefile
923 ; printstring "calc log sector"
924 ; Logical Sectornumber in x
928 ; Divide logical Sectornumber by size of Cluster in sectors
929 lds zl,fat_clustersize
942 rjmp fat_search_clst_lp
945 ; at this point xh and xl are carying the logical cluster number
946 ; printstring "find subsector"
947 ; ################# Get subsector within the logical cluster for later use
949 lds zl,fat_clustersize
953 breq fat_found_subsec
957 rjmp fat_search_clst_lp2
962 sts fat_clust_offset,zl
964 ; Check against last HOSTDISK searched
968 brne fat_wrong_cache_clst
970 ; Check against last Cluster searched
972 lds yh,fat_log_clust+1
976 brne fat_wrong_cache_clst
978 ; Last Cluster = searched Cluster -> get Sectornumber from cache
980 lds xh,fat_clust_ptr+1
981 lds yl,fat_clust_ptr+2
982 lds yh,fat_clust_ptr+3
986 ; Cluster is not in cache, so we must search for it
987 fat_wrong_cache_clst:
991 sts fat_log_clust+1,xh
993 ; Map Logical Cluster-Number to "Physical" Cluster Number using the FAT
994 rcall fat_find_phsy_clust
996 ; Get StartSector of "physical" Cluster
1000 ; Found the physical sector
1001 .if FAT16_DBG_FAT > 0
1002 printstring "Found phys. Sector at:"
1010 ; Save the found Sector for later use into cache
1011 sts fat_clust_ptr ,xl
1012 sts fat_clust_ptr+1,xh
1013 sts fat_clust_ptr+2,yl
1014 sts fat_clust_ptr+3,yh
1016 ; Add- Subsector to Startsector
1018 lds zl,fat_clust_offset
1024 ; Found the physical sector
1025 .if FAT16_DBG_FAT > 0
1026 printstring "Sector with Offset at:"
1036 #endif /* FAT16_SUPPORT */
1038 ; vim:set ts=8 noet nowrap