; 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 ; ------------------------------- 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 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+Offset to HostSector ; ==================================================================== ; Parameters: [in] xh,xl Cluster Number ; [in] zl Offset ; [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 1,2,4,8,16,32,64,128 ! ; ==================================================================== fat_gethostsec: ; Get Offset into Data area of Disk rcall fat_clusttosec ; add given offset add xl,zl adc xh,_0 adc yl,_0 adc yh,_0 ; 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 1,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: lsr temp tst temp breq fat_c2s_end lsl xl rol xh rol yl rol yh rjmp fat_c2s_loop fat_c2s_end: ret ; ==================================================================== ; Function: CP/M Sector to Cluster & Offset ; ==================================================================== ; 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 1,2,4,8,16,32,64,128 ! ; ==================================================================== fat_cpmtoclust: 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: ldd xl,z+1 ; startsector ldd xh,z+2 ldd yl,z+3 ldd yh,z+4 add xl,temp ; startsector + offset adc xh,temp2 adc yl,temp3 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 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