; Various functions for the Interaction with the FAT16 Filesystem ; ; Copyright (C) 2010 Frank Zoll ; ; This file is part of avrcpm. ; ; avrcpm is free software: you can redistribute it and/or modify it ; under the terms of the GNU General Public License as published by ; the Free Software Foundation, either version 3 of the License, or ; (at your option) any later version. ; ; avrcpm is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with avrcpm. If not, see . ; ; $Id$ ; ; =========================================================================== ; Prelimitary ! ; °°°°°°°°°°°°° ; Size of a Sector is fixed to 512 Bytes by Base - MMC Driver implementation ; The Functions below therefore assume a fixed Size of 512 Bytes per Sector. ; =========================================================================== #ifndef FAT16_SUPPORT #define FAT16_SUPPORT 1 #define FAT16_DEBUG 2 #endif #if FAT16_SUPPORT ;-------------------------------- Defines for FAT16 Structures #define PARTID_FAT16 0x0E ;#define FAT16_BSO_SECSIZE 0x0b ; BootSectorOffset to Sectorsize Word #define FAT16_BSO_CLUSTSZ 0x0d ; BootSectorOffset to Clustersize Byte #define FAT16_BSO_RESSECT 0x0e ; BootSectorOffset to Number of Reserved Sectors #define FAT16_BSO_VOLPTR 0x1c ; BootSectorOffset to First VolumeSector #define FAT16_BSO_SECPERFAT 0x16 ; BootSectorOffset to Number of Sectors per Fat #define FAT16_BSO_NUMFATCP 0x10 ; BootSectorOffset to Ammount of FAT Copys #define FAT16_BSO_NUMDIRENT 0x11 ; BootSectorOffset to Max. Root Dir. Entrys ;-------------------------------- Start of Data Segment .dseg fat_partfound: .byte 1 ; (0= no fat partition found 1=found partition) fat_parttbl: .byte 8 ; first fat16 partition entry (start sector, sector count) ;fat_sectorsize: .byte 2 ; size of sector in bytes fat_clustersize: .byte 1 ; sectors per cluster fat_ressectors: .byte 2 ; number of reserved sectors fat_secperfat: .byte 2 ; number of sectors per fat fat_numfatcp: .byte 1 ; Number of FAT Copies fat_numdirentrys:.byte 2 ; Max. ammount of Directory Entrys within Rootdirektory fat_ptr2fat: .byte 4 ; pointer to the first fat sector fat_ptr2dir: .byte 4 ; pointer to the first root directory sector fat_ptr2dat: .byte 4 ; pointer to the first data sector fat_last_dsk: .byte 1 ; number of disk with entry in cache fat_log_clust: .byte 2 ; last searched logical cluster fat_clust_offset: .byte 1 ; offset within the cluster fat_clust_ptr: .byte 4; ; sector of last real cluster ; ------------------------------- Start of Code Segment .cseg ; ==================================================================== ; Function: Does a Disk read/write operation ; ==================================================================== ; Parameters ; -------------------------------------------------------------------- ; Registers : none ; Variables : [r] seekdsk Number of Disk to Read ; [r] seeksec Sector to read ; [r] seektrk Track to read ; -------------------------------------------------------------------- ; Description: ; ==================================================================== fat_init_partitiontable: sts fat_partfound,_0 ldiw y,fat_parttbl st y+,_0 st y+,_0 st y+,_0 st y+,_0 st y+,_0 st y+,_0 st y+,_0 st y+,_0 ldi yl,0xFF sts fat_log_clust ,yl sts fat_log_clust+1,yl sts fat_last_dsk ,yl ret ; ==================================================================== ; Function: Add's a FAT16 Partition for later Scanning ; ==================================================================== ; Parameters ; -------------------------------------------------------------------- ; Registers : ; Variables : ; -------------------------------------------------------------------- ; Description: ; This funktion sets the internal Variables to set Start and Size ; of a given FAT16 Paritition. This Information will be used for a ; later scanning of the Partition. See Function "fat_scan_partition" ; for more information. ; ==================================================================== fat_add_partition: .if FAT16_DEBUG > 0 printstring "fat16 part found",0 printnewline .endif ; save variables on stack push yl push yh ; set fat16 partition found flag ldi yl,1 sts fat_partfound,yl ; save data from first fat16 partition ldiw y,fat_parttbl ldd temp,z+PART_START st y+,temp ldd temp,z+PART_START+1 st y+,temp ldd temp,z+PART_START+2 st y+,temp ldd temp,z+PART_START+3 st y+,temp ldd temp,z+PART_SIZE st y+,temp ldd temp,z+PART_SIZE+1 st y+,temp ldd temp,z+PART_SIZE+2 st y+,temp ldd temp,z+PART_SIZE+3 st y+,temp ; reload variables from stack pop yh pop yl ret ; --------------------------------------------------------------------------- ; Read and Scann a FAT16 Partition for Imagedatefiles ; --------------------------------------------------------------------------- ; This Routine reads the Bootblock and scanns it for a Diskimage ; Input Registers : none ; Output Registers : none ; Changes Variables: none ; --------------------------------------------------------------------------- fat_scan_partition: .if FAT16_DEBUG > 0 printstring "fat16 scanning",0 printnewline .endif ; Check if a FAT16 Partition was realy found lds yl,fat_partfound cpi yl,1 brne fat_scan_error .if FAT16_DEBUG > 0 printstring "free entrys in ptable ?",0 printnewline .endif ; Check for free Entrys in Partition table lds yl,ndisks cpi yl,MAXDISKS breq fat_scan_error .if FAT16_DEBUG > 0 printstring "read fat bootblock.",0 printnewline .endif ; Scan partition start ldiw z,fat_parttbl ldd xl,z+0 ldd xh,z+1 ldd yl,z+2 ldd yh,z+3 ; Load first sector from Partition rcall mmcReadSect tst temp breq fat_bootblock_check ; Read error: Block not found fat_scan_error: clr temp ret fat_bootblock_check: .if FAT16_DEBUG > 0 printstring "fat16 bootblock check",0 printnewline .endif ; -> Size of Sectors fixed at 512 Bytes ; Get ammount of Bytes per Sector ; ldiw z,hostbuf+FAT16_BSO_SECSIZE ; ldiw y,fat_sectorsize ; ld temp,z ; st y+, temp ; ldd temp2,z+1 ; st y , temp2 ; ;.if FAT16_DEBUG > 0 ; printstring "Bytes per Sector ",0 ; rcall printhexw ; printnewline ;.endif ; Anzahl der Sectoren pro Cluster lesen ldiw z,hostbuf+FAT16_BSO_CLUSTSZ ld temp,z sts fat_clustersize,temp .if FAT16_DEBUG > 0 printstring "Sectors per Cluster ",0 rcall printhex printnewline .endif ; Anzahl der reservierten Sectoren ldiw z,hostbuf+FAT16_BSO_RESSECT ld temp,z+ sts fat_ressectors,temp ; low byte ld temp2,z sts fat_ressectors+1,temp2 ; high byte .if FAT16_DEBUG > 0 printstring "Reserved Sectors__: ",0 rcall printhexw printnewline .endif ; Anzahl der Sectoren pro FAT ldiw z,hostbuf+FAT16_BSO_SECPERFAT ld temp,z+ sts fat_secperfat,temp ; low byte ld temp2,z sts fat_secperfat+1,temp2 ; high byte .if FAT16_DEBUG > 0 printstring "Sectors per FAT__: ",0 rcall printhexw printnewline .endif ; Anzahl der FAT kopien ldiw z,hostbuf+FAT16_BSO_NUMFATCP ld temp,z sts fat_numfatcp,temp ; low byte .if FAT16_DEBUG > 0 printstring "Ammount of FAT copies: ",0 rcall printhex printnewline .endif ; Max. Anzahl der Dir. Enträge im Root Verz. ldiw z,hostbuf+FAT16_BSO_NUMDIRENT ld temp,z+ sts fat_numdirentrys,temp ; low byte ld temp2,z sts fat_numdirentrys+1,temp2 ; high byte .if FAT16_DEBUG > 0 printstring "Max. entrys in Rootdir.: ",0 rcall printhexw printnewline .endif ; Print begin of Volume .if FAT16_DEBUG > 1 ldiw z,fat_parttbl ldd xl,z+0 ldd xh,z+1 ldd yl,z+2 ldd yh,z+3 printstring "Begin of Volume at: ",0 mov temp ,yl mov temp2,yh rcall printhexw mov temp ,xl mov temp2,xh rcall printhexw printnewline .endif ; Calculate begin of FAT within the Volume lds temp ,fat_ressectors lds temp2,fat_ressectors+1 ldiw z,fat_parttbl ldd xl,z+0 ldd xh,z+1 ldd yl,z+2 ldd yh,z+3 add xl,temp adc xh,temp2 adc yl,_0 adc yh,_0 sts fat_ptr2fat ,xl sts fat_ptr2fat+1,xh sts fat_ptr2fat+2,yl sts fat_ptr2fat+3,yh .if FAT16_DEBUG > 1 printstring "Begin of FAT at___: ",0 mov temp ,yl mov temp2,yh rcall printhexw mov temp ,xl mov temp2,xh rcall printhexw printnewline .endif ; Calculate begin of Root- Directory within the Volume ldiw z,fat_ptr2fat ldd xl,z+0 ldd xh,z+1 ldd yl,z+2 ldd yh,z+3 lds temp ,fat_secperfat lds temp2,fat_secperfat+1 lds temp3,fat_numfatcp fat_calc_dp_loop: cp temp3,_0 breq fat_calc_dp_lend add xl,temp adc xh,temp2 adc yl,_0 adc yh,_0 dec temp3 jmp fat_calc_dp_loop fat_calc_dp_lend: sts fat_ptr2dir ,xl sts fat_ptr2dir+1,xh sts fat_ptr2dir+2,yl sts fat_ptr2dir+3,yh .if FAT16_DEBUG > 1 printstring "Begin of DIR at___: ",0 mov temp ,yl mov temp2,yh rcall printhexw mov temp ,xl mov temp2,xh rcall printhexw printnewline .endif ; Calculate begin of DATA Clusters within the Volume ; Num. Dir.Sektors = (Num. of Dir. Entrys * 32) / Bytes per Sektor ; Sectorsize is fixed at 512 Bytes, makes 16 Entrys per Sektor lds zl,fat_numdirentrys ; low byte lds zh,fat_numdirentrys+1 ; high byte ; Num. Direntrys / 16 lsr zh ror zl lsr zh ror zl lsr zh ror zl lsr zh ror zl lds xl,fat_ptr2dir lds xh,fat_ptr2dir+1 lds yl,fat_ptr2dir+2 lds yh,fat_ptr2dir+3 add xl,zl adc xh,zh adc yl,_0 adc yh,_0 sts fat_ptr2dat ,xl sts fat_ptr2dat+1,xh sts fat_ptr2dat+2,yl sts fat_ptr2dat+3,yh .if FAT16_DEBUG > 1 printstring "Begin of Data at__: ",0 mov temp ,yl mov temp2,yh rcall printhexw mov temp ,xl mov temp2,xh rcall printhexw printnewline .endif ; Here Starts the Scann of the Directory for valid image Files. lds xl,fat_ptr2dir lds xh,fat_ptr2dir+1 lds yl,fat_ptr2dir+2 lds yh,fat_ptr2dir+3 ; Load first sector from Directory call mmcReadSect tst temp breq fat_look_for_images ; Read error: Block not found clr temp ret ; Looks at a read directory block for image entrys fat_look_for_images: ldiw z,hostbuf ldi temp2,0 fat_look_for_loop: ldd temp,z+0 cpi temp,'C' brne fat_look_not_ok ldd temp,z+1 cpi temp,'P' brne fat_look_not_ok ldd temp,z+2 cpi temp,'M' brne fat_look_not_ok ldd temp,z+3 cpi temp,'D' brne fat_look_not_ok ldd temp,z+4 cpi temp,'S' brne fat_look_not_ok ldd temp,z+5 cpi temp,'K' brne fat_look_not_ok ldd temp,z+6 cpi temp,'_' brne fat_look_not_ok ldd temp,z+8 cpi temp,'I' brne fat_look_not_ok ldd temp,z+9 cpi temp,'M' brne fat_look_not_ok ldd temp,z+10 cpi temp,'G' brne fat_look_not_ok jmp fat_store_new_entry fat_look_not_ok: //ldi temp,32 addiw z,32 inc temp2 cpi temp2,16 ; max entrys/sector breq fat_scan_next_sector jmp fat_look_for_loop fat_scan_next_sector: ret ; Create new Partition Entry fat_store_new_entry: ; Found a valid image .if FAT16_DEBUG > 1 printstring "Found a valid Image ! ",0 printnewline .endif ldiw y,hostparttbl lds temp,ndisks fat_look_store_loop: cp temp,_0 breq fat_look_store adiw y,PARTENTRY_SIZE dec temp jmp fat_look_store_loop fat_look_store: ; Set Type of Partition to FAT16- Fileimage ldi temp,dskType_FAT st y+,temp ; Offset to Startcluster + 2 ldd temp,z+0x1A st y+,temp ldd temp,z+0x1B st y+,temp ldi temp,0 st y+,temp st y+,temp ; Filesize in Bytes - 2,4,8,16,32,64,128,256,512 ; ldd temp,z+0x1C ; st y+,temp ; ldd temp,z+0x1D ; st y+,temp ; ldd temp,z+0x1E ; st y+,temp ; ldd temp,z+0x1F ; st y+,temp ; Convert Filesize to ammount of sectors ldd xl,z+0x1D ldd xh,z+0x1E ldd zl,z+0x1F mov zh,_0 lsr zh ror zl ror xh ror xl ; store ammount of sectors in partitiontable st y+,xl st y+,xh st y+,zl st y+,zh ; Check for another free entry in partition table lds temp,ndisks inc temp sts ndisks,temp .if FAT16_DEBUG > 1 ; Test finding of the first sector ldd xl,z+0x1A ldd xh,z+0x1B ldi zl,0 rcall fat_gethostsec printstring "Begin of Image at: ",0 mov temp ,yl mov temp2,yh rcall printhexw mov temp ,xl mov temp2,xh rcall printhexw printnewline .endif ; cp temp,MAXDISKS ; brne fat_scan_for_more ret ; ==================================================================== ; Function: Cluster to HostSector ; ==================================================================== ; Parameters: [in] xh,xl Cluster Number ; [out] yh,yl,xh,xl Sector Number on Disk ; -------------------------------------------------------------------- ; Registers : ; Variables : [used] fat_clustersize Ammount of Sectors per Cluster ; [changes] temp ; -------------------------------------------------------------------- ; Description: ; ! Only works with Clustersizes 2,4,8,16,32,64,128 ! ; ==================================================================== fat_gethostsec: ; Get Offset into Data area of Disk rcall fat_clusttosec ; add begin of data area to offset lds temp,fat_ptr2dat+0 add xl,temp lds temp,fat_ptr2dat+1 adc xh,temp lds temp,fat_ptr2dat+2 adc yl,temp lds temp,fat_ptr2dat+3 adc yh,temp ret ; ==================================================================== ; Function: Cluster to Sector ; ==================================================================== ; Parameters: [in] xl,xh Cluster Number ; [out] xl,xh,yl,yh Sector Number ; -------------------------------------------------------------------- ; Registers : ; Variables : [used] fat_clustersize Ammount of Sectors per Cluster ; [changes] temp ; -------------------------------------------------------------------- ; Description: ; ! Only works with Clustersizes 2,4,8,16,32,64,128 ! ; ==================================================================== fat_clusttosec: clr yl clr yh ldi temp,2 sub xl,temp ; Substract the 2 reserved clusters sbc xh,_0 lds temp,fat_clustersize fat_c2s_loop: tst temp breq fat_c2s_end lsr temp lsl xl rol xh rol yl rol yh rjmp fat_c2s_loop fat_c2s_end: ret ; ==================================================================== ; Function: Searches a physical Cluster, given the logical Cluster ; ==================================================================== ; Parameters ; -------------------------------------------------------------------- ; Registers : [r] xh,xl logical- Cluster ; [w] yh,yl physical- Cluster ; -------------------------------------------------------------------- ; Description: ; ==================================================================== fat_find_phsy_clust: mov temp2,xl lds xl,hostdsk rcall dsk_getpartentry ; get partition entry mov xl,temp2 ; Get First FAT- Cluster Number of Diskimage ldd xl,z+1 ldd xh,z+2 fat_next_phsy_clust: cp xl,_0 cpc xh,_0 breq fat_found_phsy_clust ; Get Next Cluster from Fat ; Trick: 512 Bytes Per Sector equals to 256 FAT- Entrys per Sector ; so given: yl is the Offset within the FAT Sector ; yh is the number off se FAT sector to Read ; in zh,zl: Pointer to Word within the Sector to read ; in yh..xl: Start sector number (LBA) ; out zh,zl : word thats been read push xl push xh ; Create FAT Offset Value clr zh mov zl,yl lsl zl rol zh ; Get FAT Start mov temp,yh lds xl,fat_ptr2fat lds xh,fat_ptr2fat+1 lds yl,fat_ptr2fat+2 lds yh,fat_ptr2fat+3 ; Add Sector offset add xl,temp adc xh,_0 adc yl,_0 adc yh,_0 call mmcReadWord pop xh pop xl mov yl,zl mov yh,zh ; Check next logical Cluster ldi zl,1 sub xl,zl sbc xh,_0 rjmp fat_next_phsy_clust ; Found the physical cluster fat_found_phsy_clust: ret ; ==================================================================== ; Function: Does a Disk write operation ; ==================================================================== ; Parameters ; -------------------------------------------------------------------- ; Registers : none ; Variables : [r] seekdsk Number of Disk to Read ; [r] seeksec Sector to read ; [r] seektrk Track to read ; hostdsk = host disk #, (partition #) ; hostlba = host block #, relative to partition start ; Read/Write "hostsize" bytes to/from hostbuf ; -------------------------------------------------------------------- ; Description: ; ==================================================================== fat_hostparam: lds xl,hostdsk .if HOSTRW_DEBUG mov temp,xl subi temp,-('A') rcall uartputc printstring ": " .endif rcall dsk_getpartentry ; get partition entry fat_hostlend: lds temp ,hostlba lds temp2,hostlba+1 lds temp3,hostlba+2 .if HOSTRW_DEBUG printstring "lba: " clr temp4 rcall print_ultoa .endif ldd xl,z+5 ; get size of disk in sectors ldd xh,z+6 ldd yl,z+7 cp temp,xl ; check given sector against disksize cpc temp2,xh cpc temp3,yl brcs fat_hp1 .if HOSTRW_DEBUG printstring ", max: " push temp4 push temp3 push temp2 push temp movw temp,x mov temp3,yl clr temp4 rcall print_ultoa pop temp pop temp2 pop temp3 pop temp4 printstring " " .endif clr temp ret fat_hp1: ; ################# Get logical Number of Cluster within the imagefile ; printstring "calc log sector" ; Get logical Sectornumber from temp mov xl,temp mov xh,temp2 mov yl,temp3 mov yh,_0 ; Divide logical Sectornumber by size of Cluster in sectors lds zl, fat_clustersize fat_search_clst_lp: tst zl breq fat_found_clst lsr yh ror yl ror xh ror xl lsr zl rjmp fat_search_clst_lp fat_found_clst: ; at this point xh and xl are carying the logical cluster number ; printstring "find subsector" ; ################# Get Subsector within the logical Cluster for later use mov yl,xl lds zl, fat_clustersize fat_search_clst_lp2: tst zl breq fat_found_subsec lsl yl lsr zl rjmp fat_search_clst_lp2 fat_found_subsec: mov zl,temp sub zl,yl sts fat_clust_offset,zl ; Check against last HOSTDISK searched lds yl,fat_last_dsk lds yh,hostdsk cp yl,yh brne fat_wrong_cache_clst ; Check against last Cluster searched lds yl,fat_log_clust lds yh,fat_log_clust+1 cp yl,xl brne fat_wrong_cache_clst cp yh,xh brne fat_wrong_cache_clst ; Last Cluster = searched Cluster -> get Sectornumber from cache lds xl,fat_clust_ptr lds xh,fat_clust_ptr+1 lds yl,fat_clust_ptr+2 lds yh,fat_clust_ptr+3 rjmp fat_add_offset ; ################# Cluster is not in cache, so we must search for it fat_wrong_cache_clst: lds yl,hostdsk sts fat_last_dsk,yl sts fat_log_clust,xl sts fat_log_clust+1,xh ; ################# Map Logical Cluster-Number to "Physical" Cluster Number using the FAT rcall fat_find_phsy_clust ; ################# Get StartSector of "physical" Cluster mov xl,yl mov xh,yh rcall fat_gethostsec ; Save the found Sector for later use into cache sts fat_clust_ptr ,xl sts fat_clust_ptr+1,xh sts fat_clust_ptr+2,yl sts fat_clust_ptr+3,yh ; Add- Subsector to Startsector fat_add_offset: lds zl,fat_clust_offset add xl,zl adc xh,_0 adc yl,_0 adc yh,_0 .if HOSTRW_DEBUG printstring ", abs:" push temp4 push temp3 push temp2 push temp movw temp,x movw temp3,y rcall print_ultoa pop temp pop temp2 pop temp3 pop temp4 printstring " " .endif ori temp,255 fat_hpex: ret ; ==================================================================== ; Function: Does a Disk write operation ; ==================================================================== ; Parameters ; -------------------------------------------------------------------- ; Registers : none ; Variables : [r] seekdsk Number of Disk to Read ; [r] seeksec Sector to read ; [r] seektrk Track to read ; -------------------------------------------------------------------- ; Description: ; ==================================================================== fat_writehost: .if HOSTRW_DEBUG printnewline printstring "host write " .endif rcall fat_hostparam breq fat_rdwr_err ;call mmcWriteSect ; disabled till read is functioning tst temp breq fat_rdwr_ok rcall mgr_init_partitions cbr temp,0x80 breq fat_rdwr_err rcall fat_hostparam breq fat_rdwr_err ;call mmcWriteSect ; disabled till read is functioning tst temp brne fat_rdwr_err rjmp fat_rdwr_ok ; ==================================================================== ; Function: Does a Disk read operation ; ==================================================================== ; Parameters ; -------------------------------------------------------------------- ; Registers : none ; Variables : [r] seekdsk Number of Disk to Read ; [r] seeksec Sector to read ; [r] seektrk Track to read ; -------------------------------------------------------------------- ; Description: ; ==================================================================== fat_readhost: .if HOSTRW_DEBUG printnewline printstring "host read " .endif rcall fat_hostparam breq fat_rdwr_err printstring "Read Image Sector:" push temp4 push temp3 push temp2 push temp movw temp,x movw temp3,y rcall print_ultoa pop temp pop temp2 pop temp3 pop temp4 printstring " " call mmcReadSect tst temp breq fat_rdwr_ok rcall mgr_init_partitions cbr temp,0x80 breq fat_rdwr_err rcall fat_hostparam breq fat_rdwr_err call mmcReadSect tst temp brne fat_rdwr_err fat_rdwr_ok: sts erflag,_0 ret fat_rdwr_err: sts erflag,_255 ret #endif