/**************************************************************************//**
 * @file     nvtfat_fat.h
 * @version  V3.00
 * @brief    N9H20 series NVTFAT driver header file
 *
 * SPDX-License-Identifier: Apache-2.0
 * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/

#ifndef	_NVTFAT_FAT_H_
#define	_NVTFAT_FAT_H_


/* Defined for long filenames */
#define	LFN_MAX_FILENAME			514		/* maximum length of LFN in bytes */

/* Macro to	convert	Cluster	number to logical sector number	*/
#define	ClustNo2SecNo(n) ((UINT32)(n - 2) * ptLDisk->tFatInfo.uBpbSecPerClus + ptLDisk->tFatInfo.uDataSecStart)

#define SECTOR_TYPE_FILE			0
#define SECTOR_TYPE_DIR				1
#define SECTOR_TYPE_FAT				2
#define SECTOR_TYPE_PART			3

typedef	struct sector_buf_S
{
	UINT8		*pucData;			/* cached sector contents                             */
	LDISK_T 	*ptLDisk; 			/* LDISK_T * associated	with this sector              */
	UINT32		uSectorNo;			/* logical sector number                              */
	BOOL 		bIsDirty;			/* dirty or not                                       */
	INT  		nReaderCnt;			/* how many threads are reading it                    */
	UINT32		jiffy;				/* access time stamp                                  */
	VOID 		*os_owner;			/* for OS                                             */
	VOID 		*os_priv;			/* for OS                                             */
} 	SEC_BUFF_T;

/* For FAT and DATA sector check out */
#define READ_ACCESS				0
#define WRITE_ACCESS			1


/*======================================================== FAT information ==*/
typedef struct fat_info_S
{
	/*- The followings are BPB fields commonly used by FAT16/FAT32 -*/
	
	UINT32      uBpbBytesPerSec;    /* BPB[11], size:2 */
	UINT32      uBpbSecPerClus;     /* BPB[13], size:1 */
	UINT16      usBpbRsvdSecCnt;    /* BPB[14], size:2 */
	UINT8       ucBpbNumFATs;       /* BPB[16], size:1 */
	UINT16      usBpbRootEntCnt;    /* BPB[17], size:2 */
	UINT32      uBpbTotalSectors;   /* FAT12/FAT16 - BPB[19], size:2 */
									/* FAT32 - BPB[32], size: 4 */
	UINT8       ucBpbMedia;         /* BPB[21], size:1 */
	UINT32      uBpbFatSize;        /* FAT12/FAT16 - BPB[22], size:2 */
									/* FAT32 - BPB[36], size:4 */
	UINT16      usBpbSecPerTrk;     /* BPB[24], size:2 */
	UINT16      usBpbNumHeads;      /* BPB[26], size:2 */
	UINT32      uBpbHiddSec;        /* BPB[28], size:4 */
	
	UINT32      uBsVolID;           /* FAT12/FAT16 - BPB[39], size:4 */
									/* FAT32 - BPB[67], size:4 */
	CHAR        sBsVolLab[12];      /* FAT12/FAT16 - BPB[43], size:11 */
									/* FAT32 - BPB[71], size:4 */

	UINT32   	uBpbRootClus;       /* BPB[44], size:4 */
	UINT16   	usBpbFsInfo;        /* BPB[48], size:2 */
	
	/*- The following is FAT32 structure start from offset 36 -*/
	
	/* UINT32   uBpbBytesPerSec; */ /* BPB[36], size:4 */
	/* UINT16   usBsDrvNum;  */     /* BPB[40], size:2 */
	/* UINT16   usBpbFsVer; */      /* BPB[42], size:2 */
	/* UINT16   usBpbBkBootSec; */  /* BPB[50], size:2 */
	/* bpb_Reserved */              /* BPB[52], size:12 */
	/* usBsDrvNum */                /* BPB[64], size:1 */
	/* bs_Reserved1 */              /* BPB[65], size:1 */
	/* bs_BootSig */                /* BPB[66], size:1 */

	/*- The followings are proprietary used by our driver -*/
	UINT32      uEndClusMark;    	/* FAT12 = 0xFF7, FAT16 = 0xFFF7, FAT32 = 0x0FFFFFF7 */
	UINT8		ucFatType;			/* TYPE_FAT12/TYPE_FAT16/TYPE_FAT32 */
	UINT32      uSecSzMask;      	/* uBpbBytesPerSec - 1 */
	UINT32      uBytesPerClus;   	/* uBpbBytesPerSec * uBpbSecPerClus */
	UINT32		uLastSecNo;			/* the last physical sector number on this partition */
	UINT32      uLastClusNo;    	/* last cluster number on this partition */
	UINT32      uFatSecStart;    	/* sector number of the first FAT sector */
	UINT32      uDataSecStart;   	/* sector number of first data sector */
	UINT32      uRootDirStartSec;	/* FAT12/16 first sector number of the root directory */
	UINT32		uFsInfoSecNo;		/* FAT32 - the sector number of pucFSInfo sector */
	UINT32		uFreeClusSearchIdx;	/* the next start point to search a free cluster */
	UINT32		uTotalFreeClus;		/* total number of free clusters */
	UINT8		pucFSInfo[512];		/* pucFSInfo sector */
}  	FAT_INFO_T;


#define FAT12_END_CLUS_MARK			0xFF8			
#define FAT16_END_CLUS_MARK			0xFFF8
#define FAT32_END_CLUS_MARK			0x0FFFFFF8

#define FAT12_BAD_CLUS_MARK			0xFF7
#define FAT16_BAD_CLUS_MARK			0xFFF7
#define FAT32_BAD_CLUS_MARK			0x0FFFFFF7


#define TYPE_FAT12					12
#define TYPE_FAT16					16
#define TYPE_FAT32					32


/*================================================ FAT directory structure ==*/
/* 
 * A FAT directory entry size is 32 bytes and sector size is 512 bytes.
 * So, it must be word-aligned.
 */
/* physical file name entry */
typedef struct dir_ent_S
{
	UINT8       pucDirName[8];		/* Offset: 0,  Size: 11 */
	UINT8		pucDirExtName[3];	
	UINT8       ucDirAttrib;		/* Offset: 11, Size: 1  */
	UINT8       ucDirNTRes;			/* Offset: 12, Size: 1  */
	UINT8       ucDirCTimeTenth;	/* Offset: 13, Size: 1  */
	UINT8       pucDirCTime[2];    	/* Offset: 14, Size: 2  */
	UINT8       pucDirCDate[2];     /* Offset: 16, Size: 2  */
	UINT8       pucDirLADate[2];  	/* Offset: 18, Size: 2  */
	UINT8       pucDirFirstClusHi[2];/* Offset: 20, Size: 2  */
	UINT8       pucDirWTime[2];     /* Offset: 22, Size: 2  */
	UINT8       pucDirWDate[2];		/* Offset: 24, Size: 2  */
	UINT8       pucDirFirstClusLo[2];/* Offset: 26, Size: 2  */
	UINT8       pucDirFileSize[4];	/* Offset: 28, Size: 4  */
} 	DIR_ENT_T;


/* physical long file name entry */
typedef struct lfn_ent_S
{
	UINT8       ucLDirOrd;			/* Offset: 0,  Size: 1 */
	UINT8       pucLDirName1[10];   /* Offset: 1,  Size: 10, Unicode Chars 1~5 */
	UINT8       ucLDirAttrib;       /* Offset: 11, Size: 1, always 0x0F */
	UINT8       ucLDirType;         /* Offset: 12, Size: 1 */
	UINT8       ucLDirChksum;       /* Offset: 13, Size: 1, Checksum of 8.3 name */
	UINT8       pucLDirName2[12];   /* Offset: 14, Size: 12, Unicode Chars 6-11 */
	UINT8       pucLDirFirstClusLo[2]; 	/* Offset: 26, Size: 2, always 0  */
	UINT8       pucLDirName3[4];    /* Offset: 28, Size: 4, Unicode Chars 12-13 */
} 	LFN_ENT_T;

/* FAT file attributes */
#define A_NORMAL       	0x00        /* Normal file, no attributes */
#define A_RDONLY       	0x01        /* Read only attribute */
#define A_HIDDEN       	0x02        /* Hidden file */
#define A_SYSTEM       	0x04        /* System file */
#define A_LABEL        	0x08        /* Volume label */
#define A_DIR          	0x10        /* Directory    */
#define A_ARCHIVE       0x20        /* Archive */
#define A_LFN           0x0F		/* (A_RDONLY | A_HIDDEN | A_SYSTEM | A_LABEL) */
#define A_LFN_MASK      0x3F		/* (A_LFN | A_DIR | A_ARCHIVE) */


/*================================================ Run-time data structure ==*/
/*
 *  Each FILE_T has its own FAT configuration on a FAT file system. Refer to the
 *  FILE_T defined in nvtfat.h.
 */
typedef struct file_control_block_S
{
	/* For directory entry */	
	//CHAR		suLongName[LFN_MAX_FILENAME];
	CHAR		szShortName[14];
	UINT8       ucDirAttrib;		/* file attribute */
	UINT8       ucDirNTRes;
	UINT8	    ucDirCTimeTenth;    /* Millisecond stamp at file creation time */	UINT16      dirCtime;           /* Time file was created */
	UINT16      usDirCDate;         /* Date file was created */
	UINT16      usDirLDate;         /* Last access date */
	UINT16      usDirWTime;			/* Time of last write. Note that file creation is considered a write. */
	UINT16      usDirWDate;			/* Date of last write. Note that file creation is considered a write. */
	
	UINT32		uDirEntSecNo;		/* Number of the sector where this directory entry is located. */
	INT			nDirEntInSecOffset;	/* Directory entry offset of this file in <uDirEntSecNo> sector. */

	/* for run-time file operation */
	BOOL		bIsFat16Root;		/* is FAT12/FAT16 root directory */

	BOOL		bIsRWBuffDirty;		/* read/write buffer is dirty or not */
	UINT8		*pucRWBuff;			/* file r/w buffer */
	INT64		n64RWBuffMapPos;	/* the file position of the r/w buffer mapped to */
	UINT32		uRWBuffSecNo;		/* the start sector number of r/w buffer */
	INT 		nRWBuffSecCnt;		/* the start sector number of r/w buffer */
	INT			nClusCnt;			/* number of clusters cached in r/w buffer */
	UINT32		uRWBuffSize;		/* the size of read/write buffer */

	UINT32		*pucCCBuff;			/* cluster chain buffer */
	UINT32		uCCBuffSize;		/* cluster chain buffer size */
	UINT32		uCCEntCnt;			/* cluster chain entry count */
	UINT32		uCCDoneFPos;		/* cluster chain done file position */

	UINT32  	uFirstClusNo;   	/* first cluster number of this file */
	UINT32		uLastClusNo;
	UINT32  	uCurClusNo;         /* the number of the cluster currently used */
	INT64		n64FileSize;		/* The total length of this file */
	INT64  		n64FilePos;         /* current position in file */
}  	FAT_FCB_T;


#ifdef ECOS
extern cyg_mutex_t  _fat_mutex;
#define FAT_MUTEX_INIT()		cyg_mutex_init(&_fat_mutex)   
#define FAT_MUTEX_LOCK()        cyg_mutex_lock(&_fat_mutex)
#define FAT_MUTEX_UNLOCK()		cyg_mutex_unlock(&_fat_mutex)
#else  /* Non-OS */
#define FAT_MUTEX_INIT()		
#define FAT_MUTEX_LOCK()        
#define FAT_MUTEX_UNLOCK()
#endif



/*====================================== External reference in library only ==*/
extern DISK_OP_T _fs_tFatDiskOperation;
extern FILE_OP_T _fs_tFatFileOperation;
extern BOOL		 _fs_bLockFileSystem;

extern INT  fs_fat_parse_partition(PDISK_T *ptPDisk, PARTITION_T *ptPartition, UINT32 uBpbSecNo);
extern INT  fs_fat_format_partition(PDISK_T *ptPDisk, PARTITION_T *ptPartition, INT nType);

extern INT   fs_fat32_scan_disk(LDISK_T *ptLDisk);
extern INT   fs_fat32_defragment_disk(LDISK_T *ptLDisk);

/* Cache */
extern VOID fs_fat_init_sector_cache(VOID);
extern VOID fs_fat_debug_sector_cache(VOID);

extern INT  fs_fat_check_out_sec(LDISK_T *ptLDisk, UINT32 uSectorNo, INT nAccess, SEC_BUFF_T **ptSecBuff);
extern VOID  fs_fat_check_in_sec(SEC_BUFF_T *ptSecBuff, INT nAccess, BOOL bIsDirty);
extern INT  fs_fat_flush_sector_cache(LDISK_T *ptLDisk);
extern VOID fs_fat_clear_sector_cache(LDISK_T *ptLDisk);

/* FAT32 pucFSInfo sector */
//extern INT  fs_fat_update_fs_info(LDISK_T *ptLDisk);

extern INT  fsScanDisk(INT nDriveNo);

/* FAT table */
extern INT  read_fs_info(LDISK_T *ptLDisk);
extern INT  fs_read_fat_table(LDISK_T *ptLDisk, UINT32 uClusNo, UINT32 *puEntryValue);
extern INT  fs_write_fat_table(LDISK_T *ptLDisk, UINT32 uClusNo, UINT32 uEntryValue);
extern INT  fs_fat_reclaim_clusters(LDISK_T *ptLDisk, UINT32 uStartClusNo);
extern INT  fs_fat_allocate_cluster(FILE_T *ptFile);

/* directory entry */
extern INT  fs_fat_delete_file(LDISK_T *ptLDisk, CHAR *suFullName, CHAR *szAsciiName, BOOL bIsDirectory);
extern INT  fs_fat_create_file(FILE_T *ptFile, CHAR *suFullName, CHAR *szAsciiName, UINT32 *uClusNoOfParent);
extern INT  fs_fat_merge_file(LDISK_T *ptLDisk, CHAR *suFileNameA, CHAR *szAsciiNameA, CHAR *suFileNameB, CHAR *szAsciiNameB);
extern INT  fs_fat_get_next_dir_entry(FILE_T *ptFile, UINT8 *pucBuff, CHAR **szLongName, DIR_ENT_T *ptDirEnt, UINT32 *uStartPos);
extern VOID fs_fat_set_dire_mtime(FAT_FCB_T *ptFcb, DIR_ENT_T *ptDire, INT bType);
extern VOID fs_fat_set_sdir_name(CHAR *szShortName, DIR_ENT_T *ptDire);
extern VOID fs_fat_get_sdir_name(CHAR *szShortName, DIR_ENT_T *ptDire);
extern UINT8  *fs_fat_get_ldir_name(UINT8 *pucNameBuff, LFN_ENT_T *ptLDire);
extern VOID fs_fat_set_dire_info(FAT_FCB_T *ptFcb, DIR_ENT_T *ptDire);
extern VOID fs_fat_get_dire_info(FAT_FCB_T *ptFcb, DIR_ENT_T *ptDire);
extern INT  fs_fat_search_file(FILE_T *ptFile, CHAR *szFileName);
extern INT  fs_fat_delete_tree(LDISK_T *ptLDisk, CHAR *suFullName, CHAR *szAsciiName);
extern INT  fs_update_first_cluster(FILE_T *ptFile, UINT32 uClusNo);

extern VOID fs_fat_dump_fcb(FAT_FCB_T *ptFcb);
extern VOID fsDumpUniStr(UINT8 *suStr);

#endif	/* _NVTFAT_FAT_H_ */