⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cf_fat.c

📁 Nokia3510i手机液晶屏驱动程序
💻 C
字号:
#include <ctype.h>
#include <string.h>
#include "CF_FAT.h"
#include "CF_IO.h"

uint8_t FS_Initialize(void)
{
	uint16_t w;
	uint32_t l;
	if(CF_Initialize())
		return FS_ERR_MEDIAERR;
	if(CF_LBAOpen(0))
		return FS_ERR_MEDIAERR;
	if(CF_LBAReadb() == 0xeb)		//If first byte is a instruction of JMP, it has no DPT.
		FS_BPB.StartLBA = 0;
	else
	{
		CF_LBASeek(0x1be);
		if(CF_LBAReadb() != 0x80)
		{
			CF_LBAClose();
			return FS_ERR_UNFORMAT;
		}
		CF_LBASeek(0x1c6);
		FS_BPB.StartLBA = CF_LBAReadl();
	}
	CF_LBAClose();
	CF_LBAOpen(FS_BPB.StartLBA);
	CF_LBASeek(0x00b);
	if(CF_LBAReadw() != 0x0200)
	{
		CF_LBAClose();
		return FS_ERR_UNKNOWNFAT;
	}
	FS_BPB.SectorsPerCluster = CF_LBAReadb();
	switch(FS_BPB.SectorsPerCluster)
	{
		case 1:
			FS_BPB.LShift = 0;
			break;
		case 2:
			FS_BPB.LShift = 1;
			break;
		case 4:
			FS_BPB.LShift = 2;
			break;
		case 8:
			FS_BPB.LShift = 3;
			break;
		case 16:
			FS_BPB.LShift = 4;
			break;
		case 32:
			FS_BPB.LShift = 5;
			break;
		case 64:
			FS_BPB.LShift = 6;
			break;
		case 128:
			FS_BPB.LShift = 7;
			break;
		default:
			CF_LBAClose();
			return FS_ERR_UNKNOWNFAT;
	}
	FS_BPB.Type = FS_TYPE_OTHER;
	FS_BPB.SectorsBeforeFAT = CF_LBAReadw();
	FS_BPB.FATs = CF_LBAReadb();
	FS_BPB.FAT16RootEntries = CF_LBAReadw();
	if(FS_BPB.FAT16RootEntries == 0)
		FS_BPB.Type = FS_TYPE_FAT32;
	w = CF_LBAReadw();
	if(w)
		FS_BPB.TotalSectors = w;
	CF_LBASeek(0x16);
	w = CF_LBAReadw();
	if(FS_BPB.Type != FS_TYPE_FAT32)
		FS_BPB.SectorsPerFAT = w;
	CF_LBASeek(0x20);
	l = CF_LBAReadl();
	if(l)
		FS_BPB.TotalSectors = l;
	if(FS_BPB.Type != FS_TYPE_FAT32)
	{
		if((FS_BPB.TotalSectors >> FS_BPB.LShift) < 4085)
			FS_BPB.Type = FS_TYPE_FAT12;
		else
			FS_BPB.Type = FS_TYPE_FAT16;
	}
	l = CF_LBAReadl();
	if(FS_BPB.Type == FS_TYPE_FAT32)
		FS_BPB.SectorsPerFAT = l;
	CF_LBASeek(0x2c);
	l = CF_LBAReadl();
	if(FS_BPB.Type == FS_TYPE_FAT32)
		FS_BPB.FAT32RootStartCluster = l;
	else
		FS_BPB.FAT32RootStartCluster = 0;
	FS_FAT.StartLBA = FS_BPB.StartLBA + FS_BPB.SectorsBeforeFAT;
	if(FS_BPB.Type == FS_TYPE_FAT32)
		FS_FAT.LShift = 2;
	else if(FS_BPB.Type == FS_TYPE_FAT16)
		FS_FAT.LShift = 1;
	else
		FS_FAT.LShift = 0;
	FS_CurrentDir.Attrib = FS_RootDir.Attrib = 0x10;
	FS_CurrentDir.StartCluster = FS_RootDir.StartCluster = FS_BPB.FAT32RootStartCluster;
	if(FS_BPB.Type == FS_TYPE_FAT32)
	{
		FS_FAT.DataStartLBA = FS_FAT.StartLBA + FS_BPB.FATs * FS_BPB.SectorsPerFAT;
		FS_CurrentDir.StartLBA = FS_RootDir.StartLBA = FS_FAT.DataStartLBA + ((FS_BPB.FAT32RootStartCluster - 2) << FS_BPB.LShift);
	}
	else
	{
		FS_CurrentDir.StartLBA = FS_RootDir.StartLBA = FS_FAT.StartLBA + FS_BPB.FATs * FS_BPB.SectorsPerFAT;
		FS_FAT.DataStartLBA = FS_RootDir.StartLBA + (FS_BPB.FAT16RootEntries >> 4);
	}
	FS_CurrentDir.Length = FS_RootDir.Length = 0;
	FS_CurrentDir.Offset = FS_RootDir.Offset = 0;
	CF_LBAClose();
	return FS_ERR_NOERR;
}

uint32_t FS_GetNextCluster(uint32_t Cluster)
{
	uint8_t f1, f2;
	uint16_t cc;
	uint32_t c;
	if((FS_BPB.Type == FS_TYPE_FAT32) || (FS_BPB.Type == FS_TYPE_FAT16))	//FAT16 or FAT32
	{
		CF_LBAOpen(FS_FAT.StartLBA + (Cluster >> (9 - FS_FAT.LShift)));
		CF_LBASeek((Cluster & ((1 << (9 - FS_FAT.LShift)) - 1)) << FS_FAT.LShift);	// locate a FAT entry
		if(FS_BPB.Type == FS_TYPE_FAT32)		//FAT32
			c = CF_LBAReadl();
		else		//FAT16
			c = CF_LBAReadw();
	}
	else		//FAT12. It's more complicated. Because there are 1.5 bytes (12-bits) per FAT entry.
	{
		CF_LBAOpen(FS_FAT.StartLBA + ((Cluster + (Cluster << 1)) >> 10));	//multiply by 3, then divide by 1024
		cc = Cluster & 0b1111111111;
		if(cc < 342)
			CF_LBASeek(cc + (cc >> 1));	//multiply by 1.5 without using floating point
		else if(cc < 683)
			CF_LBASeek((cc - 342) + ((cc - 342) >> 1) + 1);
		else
			CF_LBASeek((cc - 682) + ((cc - 682) >> 1) - 1);
		if(((cc >> 1) << 1) == cc)
		{
			f1 = CF_LBAReadb();
			if(cc == 682)
				CF_LBAOpen(CF_CurrentLBA + 1);
			f2 = (CF_LBAReadb() & 0b00001111) << 4;
		}
		else
		{
			f1 = CF_LBAReadb() >> 4;
			if(cc == 341)
				CF_LBAOpen(CF_CurrentLBA + 1);
			f2 = CF_LBAReadb();
		}
		c = (((uint16_t)f2) << 4) + f1;
	}
	CF_LBAClose();
	return c;
}

uint8_t FS_SearchFile(char *FName, FS_TFile *R, uint8_t dir)
{
	uint8_t i = 0, j = 0, attr, s;
	uint16_t c, o;
	uint32_t LBA, Cluster;
	char Name[9], Ext[4];
	char dName[9], dExt[4];
	memset(Name, 0x20, 8);
	memset(Ext, 0x20, 3);
	while(FName[i])
		if(FName[i] == '.')
		{
			i ++;
			while(FName[i])
				Ext[j ++] = toupper(FName[i ++]);
		}
		else
		{
			Name[i] = toupper(FName[i]);
			i ++;
		}
	Name[8] = Ext[3] = 0;
	Cluster = FS_CurrentDir.StartCluster;
	LBA = FS_CurrentDir.StartLBA;
	while(1)
	{
		for(s = 0; s < FS_BPB.SectorsPerCluster; s ++, LBA ++)	//for each sector in a cluster
		{
			CF_LBAOpen(LBA);	//Open a sector of current directory
			for(o = 0; o < 512; o += 0x20)
			{
				CF_LBASeek(o);
				for(i = 0; i < 8; i ++)
					dName[i] = toupper(CF_LBAReadb());
				for(i = 0; i < 3; i ++)
					dExt[i] = toupper(CF_LBAReadb());
				attr = CF_LBAReadb();
				dName[8] = dExt[3] = 0;
				if(dName[0] == 0)
				{
					CF_LBAClose();
					return FS_ERR_NOTFOUND;
				}
				else if(dName[0] != 0xe5)
				{
					if((strcmp(Name, dName) == 0) && (strcmp(Ext, dExt) == 0) && ((attr & 0b00001000) == 0) && ((attr & 0b00010000) || (dir == 0)) )		//if bingo
					{
						R->Attrib = attr;
						CF_LBASeek(o + 0x14);
						c = CF_LBAReadw();
						CF_LBASeek(o + 0x1a);
						R->StartCluster = CF_LBAReadw();
						R->Length = CF_LBAReadl();
						if(FS_BPB.Type == FS_TYPE_FAT32)
							R->StartCluster += (uint32_t)c << 16;
						R->CurrentLBA = R->StartLBA = FS_FAT.DataStartLBA + ((R->StartCluster - 2) << FS_BPB.LShift);
						R->CurrentCluster = R->StartCluster;
						R->Offset = 0;
						CF_LBAClose();
						return FS_ERR_NOERR;
					}
				}
			}
		}
		if(Cluster != 0)	//Cluster==0 is for FAT16/FAT12, where the root directory is stored consecutively.
		{
			Cluster = FS_GetNextCluster(Cluster);
			if(	((FS_BPB.Type == FS_TYPE_FAT32) && (Cluster >= FS_FAT32_EOF)) ||
				((FS_BPB.Type == FS_TYPE_FAT16) && (Cluster >= FS_FAT16_EOF)) ||
				((FS_BPB.Type == FS_TYPE_FAT12) && (Cluster >= FS_FAT12_EOF)))	//if it is the last cluster
				return FS_ERR_NOTFOUND;
			LBA = FS_FAT.DataStartLBA + ((Cluster - 2) << FS_BPB.LShift);
		}
	}
}

uint8_t FS_ChangeDir(char *DirName)
{
	FS_TFile D;
	if(strcmp(DirName, "\\") == 0)
	{
		FS_CurrentDir.Attrib = FS_RootDir.Attrib;
		FS_CurrentDir.StartCluster = FS_RootDir.StartCluster;
		FS_CurrentDir.StartLBA = FS_RootDir.StartLBA;
		FS_CurrentDir.Offset = FS_RootDir.Offset;
		FS_CurrentDir.Length = FS_RootDir.Length;
		return FS_ERR_NOERR;
	}
	if(FS_SearchFile(DirName, &D, 1))
		return FS_ERR_NOTFOUND;
	else
	{
		FS_CurrentDir.Attrib = D.Attrib;
		FS_CurrentDir.StartCluster = D.StartCluster;
		FS_CurrentDir.StartLBA = D.StartLBA;
		FS_CurrentDir.Offset = D.Offset;
		FS_CurrentDir.Length = D.Length;
		return FS_ERR_NOERR;
	}
}

uint8_t FS_Open(FS_TFile *F, char *FileName)
{
	if(FS_SearchFile(FileName, F, 0))
		return FS_ERR_NOTFOUND;
	else
	{
		F->ClusterChain = NULL;
		return FS_ERR_NOERR;
	}
}

void FS_Close(FS_TFile *F)
{
}

uint8_t FS_Seek(FS_TFile *F, uint32_t off)
{
	uint32_t i;
	if(off >= F->Length)
		return FS_ERR_SEEKERR;
	else
	{
		if(off < F->Offset)
		{
			F->CurrentCluster = F->StartCluster;
			F->CurrentLBA = F->StartLBA;
			F->Offset = 0;
		}
		if(F->ClusterChain == NULL)
			for(i = (F->Offset >> 9); i < (off >> 9); i ++)
			{
				F->CurrentLBA ++;
				if(((F->CurrentLBA - FS_FAT.DataStartLBA) & ((1 << FS_BPB.LShift) - 1)) == 0)
				{
					F->CurrentCluster = FS_GetNextCluster(F->CurrentCluster);
					F->CurrentLBA = FS_FAT.DataStartLBA + ((F->CurrentCluster - 2) << FS_BPB.LShift);
				}
			}
		else
		{
			F->CurrentCluster = F->ClusterChain[off >> (9 + FS_BPB.LShift)];
			F->CurrentLBA = FS_FAT.DataStartLBA + ((F->CurrentCluster - 2) << FS_BPB.LShift) + ((off >> 9) & ((1 << FS_BPB.LShift) - 1));
		}
		F->Offset = off;
		return FS_ERR_NOERR;
	}
}

uint32_t FS_Read(FS_TFile *F, char *buf, uint32_t count)
{
	uint32_t i = 0;
	CF_LBAOpen(F->CurrentLBA);
	CF_LBASeek(F->Offset & 511);
	while(i < count)
	{
		*(buf ++) = CF_LBAReadb();
		i ++;
		if(FS_Seek(F, F->Offset + 1))
		{
			CF_LBAClose();
			return i;
		}
		if((F->Offset & 511) == 0)
			CF_LBAOpen(F->CurrentLBA);
	}
	CF_LBAClose();
	return i;
}

void FS_FastBlockRead(FS_TFile *F, char *buf, uint8_t sectors)
{
	F->Offset = ((F->Offset >> 9) << 9);
	while(sectors)
	{
		CF_LBAReadSector(F->CurrentLBA, 1, buf);
		buf += 512;
		FS_Seek(F, F->Offset + 512);
		sectors --;
	}
}

void FS_GetClusterChain(FS_TFile *F, uint32_t *chain)
{
	uint32_t c;
	*chain = F->StartCluster;
	do
	{
		c = FS_GetNextCluster(*chain);
		chain ++;
		*chain = c;
		if(	((FS_BPB.Type == FS_TYPE_FAT32) && (c >= FS_FAT32_EOF)) ||
			((FS_BPB.Type == FS_TYPE_FAT16) && (c >= FS_FAT16_EOF)) ||
			((FS_BPB.Type == FS_TYPE_FAT12) && (c >= FS_FAT12_EOF)))		//if it is the last cluster
			break;
	} while(1);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -