www.pudn.com > ucos_vc.zip > fat_ioct.c
/*
**********************************************************************
* Micrium, Inc.
* 949 Crestview Circle
* Weston, FL 33327-1848
*
* uC/FS
*
* (c) Copyright 2001 - 2003, Micrium, Inc.
* All rights reserved.
*
***********************************************************************
----------------------------------------------------------------------
File : fat_ioctc.c
Purpose : FAT File System Layer IOCTL
----------------------------------------------------------------------
Known problems or limitations with current version
----------------------------------------------------------------------
None.
---------------------------END-OF-HEADER------------------------------
*/
/*********************************************************************
*
* #include Section
*
**********************************************************************
*/
#include "fs_conf.h"
#include "fs_port.h"
#include "fs_dev.h"
#include "fs_api.h"
#include "fs_fsl.h"
#include "fs_int.h"
#include "fs_os.h"
#include "fs_lbl.h"
#include "fs_fat.h"
#include "fs_clib.h"
/*********************************************************************
*
* #define constants
*
**********************************************************************
*/
#define FS_KNOWNMEDIA_NUM sizeof(_FS_wd_format_media_table) / sizeof(_FS_wd_format_media_type)
#ifndef FS_FAT_NOFORMAT
#define FS_FAT_NOFORMAT 0
#endif
#ifndef FS_FAT_DISKINFO
#define FS_FAT_DISKINFO 1
#endif
#ifndef FS_SUPPORT_SEC_ACCESS
#define FS_SUPPORT_SEC_ACCESS 1
#endif
/*********************************************************************
*
* Local data types
*
**********************************************************************
*/
#if (FS_FAT_NOFORMAT==0)
typedef struct {
FS_i32 media_id;
FS_u32 totsec32;
FS_u32 hiddsec;
FS_u16 totsec16;
FS_u16 rootentcnt;
FS_u16 fatsz16;
FS_u16 secpertrk;
FS_u16 numheads;
char secperclus;
char media;
char fsystype;
} _FS_wd_format_media_type;
typedef struct {
FS_u32 SecNum;
FS_u32 Num;
} _FS_FAT_ROOTENTCNT ;
typedef struct {
FS_u32 SecNum;
FS_u16 Num;
} _FS_FAT_SECPERCLUST;
/*********************************************************************
*
* Local Variables
*
**********************************************************************
*/
/* media_id totsec32 hidsec totsec16 rootent fatsz16 secpertrk numheads secperclus media fstype */
static const _FS_wd_format_media_type _FS_wd_format_media_table[] = {
{ FS_MEDIA_RAM_16KB, 0x00000000UL, 0x00000000UL, 0x0020, 0x0040, 0x0001, 0x0004, 0x0004, 0x01, (char) 0xf8, 0 },
{ FS_MEDIA_RAM_64KB, 0x00000000UL, 0x00000000UL, 0x0080, 0x0040, 0x0001, 0x0004, 0x0004, 0x01, (char) 0xf8, 0 },
{ FS_MEDIA_RAM_128KB, 0x00000000UL, 0x00000000UL, 0x0100, 0x0080, 0x0001, 0x0004, 0x0004, 0x01, (char) 0xf8, 0 },
{ FS_MEDIA_RAM_256KB, 0x00000000UL, 0x00000000UL, 0x0200, 0x0080, 0x0002, 0x0004, 0x0004, 0x01, (char) 0xf8, 0 },
{ FS_MEDIA_RAM_512KB, 0x00000000UL, 0x00000000UL, 0x0400, 0x00e0, 0x0003, 0x0004, 0x0004, 0x01, (char) 0xf8, 0 },
{ FS_MEDIA_FD_144MB, 0x00000000UL, 0x00000000UL, 0x0b40, 0x00e0, 0x0009, 0x0012, 0x0002, 0x01, (char) 0xf0, 0 },
{ FS_MEDIA_SMC_1MB, 0x00000000UL, 0x0000000DUL, 0x07c3, 0x0100, 0x0001, 0x0004, 0x0004, 0x08, (char) 0xf8, 0 },
{ FS_MEDIA_SMC_2MB, 0x00000000UL, 0x0000000bUL, 0x0f95, 0x0100, 0x0002, 0x0008, 0x0004, 0x08, (char) 0xf8, 0 },
{ FS_MEDIA_SMC_4MB, 0x00000000UL, 0x0000001bUL, 0x1f25, 0x0100, 0x0002, 0x0008, 0x0004, 0x10, (char) 0xf8, 0 },
{ FS_MEDIA_SMC_8MB, 0x00000000UL, 0x00000019UL, 0x3e67, 0x0100, 0x0003, 0x0010, 0x0004, 0x10, (char) 0xf8, 0 },
{ FS_MEDIA_SMC_16MB, 0x00000000UL, 0x00000029UL, 0x7cd7, 0x0100, 0x0003, 0x0010, 0x0004, 0x20, (char) 0xf8, 0 },
{ FS_MEDIA_SMC_32MB, 0x00000000UL, 0x00000023UL, 0xf9dd, 0x0100, 0x0006, 0x0010, 0x0008, 0x20, (char) 0xf8, 0 },
{ FS_MEDIA_SMC_64MB, 0x0001f3c9UL, 0x00000037UL, 0x0000, 0x0100, 0x000c, 0x0020, 0x0008, 0x20, (char) 0xf8, 0 },
{ FS_MEDIA_SMC_128MB, 0x0003e7d1UL, 0x0000002fUL, 0x0000, 0x0100, 0x0020, 0x0020, 0x0010, 0x20, (char) 0xf8, 1 },
{ FS_MEDIA_MMC_32MB, 0x00000000UL, 0x00000020UL, 0xf460, 0x0200, 0x003d, 0x0020, 0x0004, 0x04, (char) 0xf8, 1 },
{ FS_MEDIA_MMC_64MB, 0x0001e8e0UL, 0x00000020UL, 0x0000, 0x0200, 0x007a, 0x0020, 0x0008, 0x04, (char) 0xf8, 1 },
{ FS_MEDIA_MMC_128MB, 0x0003d2e0UL, 0x00000020UL, 0x0000, 0x0200, 0x00f5, 0x0020, 0x0008, 0x04, (char) 0xf8, 1 },
{ FS_MEDIA_SD_16MB, 0x00000000UL, 0x00000039UL, 0x7187, 0x0200, 0x0003, 0x0020, 0x0002, 0x20, (char) 0xf8, 0 },
{ FS_MEDIA_SD_64MB, 0x0001dbd9UL, 0x00000027UL, 0x0000, 0x0200, 0x000c, 0x0020, 0x0008, 0x20, (char) 0xf8, 0 },
{ FS_MEDIA_SD_128MB, 0x0003c09fUL, 0x00000061UL, 0x0000, 0x0200, 0x001f, 0x0020, 0x0008, 0x20, (char) 0xf8, 1 },
{ FS_MEDIA_CF_32MB, 0x00000000UL, 0x00000020UL, 0xf760, 0x0200, 0x007c, 0x0020, 0x0004, 0x02, (char) 0xf8, 1 },
{ FS_MEDIA_CF_64MB, 0x0001e860UL, 0x00000020UL, 0x0000, 0x0200, 0x007b, 0x0020, 0x0004, 0x04, (char) 0xf8, 1 }
};
/* table for getting number of root entries for a given media size */
static const _FS_FAT_ROOTENTCNT _FS_auto_rootcnt[] = {
{ 0x100, 0x40 },
{ 0x200, 0x80 },
{ 0x0b40UL, 0xe0 },
{ 0x0001f3c9UL, 0x100 },
{ 0xffffffffUL, 0x200 }
};
/* table for calculating cluster size */
static const _FS_FAT_SECPERCLUST _FS_auto_secperclust[] = {
/* medias up to 512MB are formatted with FAT16 */
{ 0x0b40UL, 0x0001 },
{ 32680UL, 0x0002 },
{ 262144UL, 0x0004 },
{ 524288UL, 0x0008 },
{ 1048576UL, 0x0010 },
/* medias bigger than 512MB are formatted with FAT32 */
{ 16777216UL, 0x0008 },
{ 33554432UL, 0x0010 },
{ 67108864UL, 0x0020 },
{ 0xffffffffUL, 0x0040 }
};
#endif /* FS_FAT_NOFORMAT==0 */
/*********************************************************************
*
* Local functions
*
**********************************************************************
*/
#if (FS_FAT_NOFORMAT==0)
/*********************************************************************
*
* _FS_fat_format
*
Description:
FS internal function. Format a media using specified parameters.
Currently this function needs many parameters. The function will be
improved.
Parameters:
pDriver - Pointer to a device driver function table.
Unit - Unit number.
SecPerClus - Number of sector per allocation unit.
RootEntCnt - For FAT12/FAT16, this is the number of 32 byte root
directory entries. 0 for FAT32.
TotSec16 - 16-bit total count of sectors. If zero, TotSec32 must
be none-zero.
TotSec32 - 32-bit total count of sectors. If zero, TotSec16 must
be none-zero.
Media - Media byte.
FATSz16 - 16-bit count of sectors occupied by one FAT. 0 for
FAT32 volumes, which use FATSz32.
FATSz32 - 32-bit count of sectors occupied by one FAT. This is
valid for FAT32 medias only.
SecPerTrk - Sectors per track.
NumHeads - Number of heads.
HiddSec - Count of hidden sectors preceding the partition.
FSysType - ==0 => FAT12
==1 => FAT16
==2 => FAT32
Return value:
>=0 - Media has been formatted.
<0 - An error has occured.
*/
static int _FS_fat_format(const FS__device_type *pDriver,FS_u32 Unit, char SecPerClus,
FS_u16 RootEntCnt, FS_u16 TotSec16, FS_u32 TotSec32, char Media,
FS_u16 FATSz16, FS_u32 FATSz32, FS_u16 SecPerTrk,FS_u16 NumHeads,
FS_u32 HiddSec, char FSysType) {
FS__FAT_BPB bpb;
FS_u32 sector;
FS_u32 value;
char *buffer;
int i;
int j;
int n;
buffer = FS__fat_malloc(FS_FAT_SEC_SIZE);
if (!buffer) {
return -1;
}
FS__CLIB_memset(buffer, 0x00, (FS_size_t)FS_FAT_SEC_SIZE);
/* Setup BPB */
FS__CLIB_memset(&bpb, 0x00, (FS_size_t)sizeof(bpb));
bpb.BytesPerSec = 0x0200; /* _512_,1024,2048,4096 */
bpb.SecPerClus = SecPerClus; /* sec in allocation unit */
if (FSysType != 2) {
bpb.RsvdSecCnt = 0x0001; /* 1 for FAT12 & FAT16 */
}
#if (FS_FAT_NOFAT32==0)
else {
bpb.RsvdSecCnt = 0x0020; /* 32 for FAT32 */
}
#else
/* FAT32 disabled */
else {
FS__fat_free(buffer);
return -1;
}
#endif /* FS_FAT_NOFAT32==0 */
bpb.NumFATs = 0x02; /* 2 */
bpb.RootEntCnt = RootEntCnt; /* number of root dir entries */
bpb.TotSec16 = TotSec16; /* RSVD+FAT+ROOT+DATA (<64k) */
bpb.FATSz16 = FATSz16; /* number of FAT sectors */
bpb.TotSec32 = TotSec32; /* RSVD+FAT+ROOT+FATA (>=64k) */
bpb.Signature = 0xaa55; /* 0xAA55 Signature */
/* setup BPB specifics for FAT32 */
bpb.FATSz32 = FATSz32; /* number of FAT sectors */
bpb.ExtFlags = 0x0000; /* mirroring info */
bpb.RootClus = 0x00000002UL; /* root dir clus for FAT32 */
bpb.FSInfo = 0x0001; /* position of FSInfo structure */
/*
Prepare buffer with information of the BPB
offset 0 - 35 is same for FAT12/FAT16 and FAT32
*/
/* jmpBoot = 0xe9 0x0000 */
buffer[0] = (char)0xe9;
buffer[1] = (char)0x00;
buffer[2] = (char)0x00;
/* OEMName = ' ' */
for (i = 3; i < 11; i++) {
buffer[i] = (char)0x20;
}
/* BytesPerSec */
buffer[11] = (char)(bpb.BytesPerSec & 0xff);
buffer[12] = (char)((unsigned int)(bpb.BytesPerSec & 0xff00) >> 8);
/* SecPerClus */
buffer[13] = (char)bpb.SecPerClus;
/* RsvdSecCnt */
buffer[14] = (char)(bpb.RsvdSecCnt & 0xff);
buffer[15] = (char)((unsigned int)(bpb.RsvdSecCnt & 0xff00) >> 8);
/* NumFATs */
buffer[16] = (char)bpb.NumFATs;
/* RootEntCnt */
buffer[17] = (char)(bpb.RootEntCnt & 0xff);
buffer[18] = (char)((unsigned int)(bpb.RootEntCnt & 0xff00) >> 8);
/* TotSec16 */
buffer[19] = (char)(bpb.TotSec16 & 0xff);
buffer[20] = (char)((unsigned int)(bpb.TotSec16 & 0xff00) >> 8);
/* Media */
buffer[21] = Media;
/* FATSz16 */
buffer[22] = (char)(bpb.FATSz16 & 0xff);
buffer[23] = (char)((unsigned int)(bpb.FATSz16 & 0xff00) >> 8);
/* SecPerTrk */
buffer[24] = (char)(SecPerTrk & 0xff);
buffer[25] = (char)((unsigned int)(SecPerTrk & 0xff00) >> 8);
/* NumHeads */
buffer[26] = (char)(NumHeads & 0xff);
buffer[27] = (char)((unsigned int)(NumHeads & 0xff00) >> 8);
/* HiddSec */
buffer[28] = (char)(HiddSec & 0xff);
buffer[29] = (char)((FS_u32)(HiddSec & 0x0000ff00UL) >> 8);
buffer[30] = (char)((FS_u32)(HiddSec & 0x00ff0000UL) >> 16);
buffer[31] = (char)((FS_u32)(HiddSec & 0xff000000UL) >> 24);
/* TotSec32 */
buffer[32] = (char)(bpb.TotSec32 & 0xff);
buffer[33] = (char)((FS_u32)(bpb.TotSec32 & 0x0000ff00UL) >> 8);
buffer[34] = (char)((FS_u32)(bpb.TotSec32 & 0x00ff0000UL) >> 16);
buffer[35] = (char)((FS_u32)(bpb.TotSec32 & 0xff000000UL) >> 24);
/* Offset 36 and above have different meanings for FAT12/FAT16 and FAT32 */
if (FSysType != 2) {
/* FAT12/FAT16 */
/* DrvNum = 0x00 (floppy) */
buffer[36] = (char)0x00;
/* Reserved1 = 0x00 (floppy) */
buffer[37] = (char)0x00;
/* BootSig = 0x00 (next three fields are not 'present') */
buffer[38] = (char)0x00;
/* VolID = 0x00000000 (serial number, e.g. date/time) */
for (i = 39; i < 43; i++) {
buffer[i] = (char)0x00;
}
/* VolLab = ' ' */
for (i = 43; i < 54; i++) {
buffer[i] = (char)0x20;
}
/* FilSysType = 'FAT12' */
if (FSysType == 0) {
FS__CLIB_strncpy(&buffer[54], "FAT12 ", 8);
}
else {
FS__CLIB_strncpy(&buffer[54], "FAT16 ", 8);
}
}
#if (FS_FAT_NOFAT32==0)
else {
/* FAT32 */
/* FATSz32 */
buffer[36] = (char)(bpb.FATSz32 & 0xff);
buffer[37] = (char)((FS_u32)(bpb.FATSz32 & 0x0000ff00UL) >> 8);
buffer[38] = (char)((FS_u32)(bpb.FATSz32 & 0x00ff0000UL) >> 16);
buffer[39] = (char)((FS_u32)(bpb.FATSz32 & 0xff000000UL) >> 24);
/* EXTFlags */
buffer[40] = (char)(bpb.ExtFlags & 0xff);
buffer[41] = (char)((unsigned int)(bpb.ExtFlags & 0xff00) >> 8);
/* FSVer = 0:0 */
buffer[42] = 0x00;
buffer[43] = 0x00;
/* RootClus */
buffer[44] = (char)(bpb.RootClus & 0xff);
buffer[45] = (char)((FS_u32)(bpb.RootClus & 0x0000ff00UL) >> 8);
buffer[46] = (char)((FS_u32)(bpb.RootClus & 0x00ff0000UL) >> 16);
buffer[47] = (char)((FS_u32)(bpb.RootClus & 0xff000000UL) >> 24);
/* FSInfo */
buffer[48] = (char)(bpb.FSInfo & 0xff);
buffer[49] = (char)((unsigned int)(bpb.FSInfo & 0xff00) >> 8);
/* BkBootSec = 0x0006; */
buffer[50] = 0x06;
buffer[51] = 0x00;
/* Reserved */
for (i = 52; i < 64; i++) {
buffer[i] = (char)0x00;
}
/* DrvNum = 0x00 (floppy) */
buffer[64] = (char)0x00;
/* Reserved1 = 0x00 (floppy) */
buffer[65] = (char)0x00;
/* BootSig = 0x00 (next three fields are not 'present') */
buffer[66] = (char)0x00;
/* VolID = 0x00000000 (serial number, e.g. date/time) */
for (i = 67; i < 71; i++) {
buffer[i] = (char)0x00;
}
/* VolLab = ' ' */
for (i = 71; i < 82; i++) {
buffer[i] = (char)0x20;
}
/* FilSysType = 'FAT12' */
FS__CLIB_strncpy(&buffer[82], "FAT32 ", 8);
}
#endif /* FS_FAT_NOFAT32==0 */
/* Signature = 0xAA55 */
buffer[510] = (char)0x55;
buffer[511] = (char)0xaa;
/* Write BPB to media */
i = FS__lb_write(pDriver, Unit, 0, (void*)buffer);
if (i < 0) {
FS__fat_free(buffer);
return -1;
}
if (FSysType == 2) {
/* Write backup BPB */
i = FS__lb_write(pDriver, Unit, 6, (void*)buffer);
if (i<0) {
FS__fat_free(buffer);
return -1;
}
}
/* Init FAT 1 & 2 */
FS__CLIB_memset(buffer, 0x00, (FS_size_t)FS_FAT_SEC_SIZE);
for (sector = 0; sector < 2 * (bpb.FATSz16 + bpb.FATSz32); sector++) {
value = sector % (bpb.FATSz16 + bpb.FATSz32);
if (value != 0) {
i = FS__lb_write(pDriver, Unit, bpb.RsvdSecCnt + sector, (void*)buffer);
if (i<0) {
FS__fat_free(buffer);
return -1;
}
}
}
buffer[0] = (char)Media;
buffer[1] = (char)0xff;
buffer[2] = (char)0xff;
if (FSysType != 0) {
buffer[3] = (char)0xff;
}
#if (FS_FAT_NOFAT32==0)
if (FSysType == 2) {
buffer[4] = (char)0xff;
buffer[5] = (char)0xff;
buffer[6] = (char)0xff;
buffer[7] = (char)0x0f;
buffer[8] = (char)0xff;
buffer[9] = (char)0xff;
buffer[10] = (char)0xff;
buffer[11] = (char)0x0f;
}
#endif /* FS_FAT_NOFAT32==0 */
for (i = 0; i < 2; i++) {
j = FS__lb_write(pDriver, Unit, (FS_u32)bpb.RsvdSecCnt + i * ((FS_u32)bpb.FATSz16+bpb.FATSz32), (void*)buffer);
if (j < 0) {
FS__fat_free(buffer);
return -1;
} // two fat table
}
/* Init root directory area */
FS__CLIB_memset(buffer, 0x00, (FS_size_t)FS_FAT_SEC_SIZE);
if (bpb.RootEntCnt != 0) {
/* FAT12/FAT16 */
n = (((FS_u32)bpb.RootEntCnt * 32) / (FS_u32)512); //n show the sectors accupied by root directory entries
for (i = 0; i < n; i++) {
j = FS__lb_write(pDriver, Unit, bpb.RsvdSecCnt + 2 * bpb.FATSz16 + i, (void*)buffer); //reserved sectors under fat12/16 is 1
if (j < 0) {
FS__fat_free(buffer);
return -1;
}
}
}
#if (FS_FAT_NOFAT32==0)
else {
/* FAT32 */
n = bpb.SecPerClus;
for (i = 0; i < n; i++) {
j = FS__lb_write(pDriver, Unit, bpb.RsvdSecCnt + 2 * bpb.FATSz32 + (bpb.RootClus - 2) * n + i, (void*)buffer);
if (j < 0) {
FS__fat_free(buffer);
return -1;
}
}
}
#endif /* FS_FAT_NOFAT32==0 */
#if (FS_FAT_NOFAT32==0)
if (FSysType == 2) {
/* Init FSInfo */
FS__CLIB_memset(buffer, 0x00, (FS_size_t)FS_FAT_SEC_SIZE);
/* LeadSig = 0x41615252 */
buffer[0] = (char)0x52;
buffer[1] = (char)0x52;
buffer[2] = (char)0x61;
buffer[3] = (char)0x41;
/* StructSig = 0x61417272 */
buffer[484] = (char)0x72;
buffer[485] = (char)0x72;
buffer[486] = (char)0x41;
buffer[487] = (char)0x61;
/* Invalidate last known free cluster count */
buffer[488] = (char)0xff;
buffer[489] = (char)0xff;
buffer[490] = (char)0xff;
buffer[491] = (char)0xff;
/* Give hint for free cluster search */
buffer[492] = (char)0xff;
buffer[493] = (char)0xff;
buffer[494] = (char)0xff;
buffer[495] = (char)0xff;
/* TrailSig = 0xaa550000 */
buffer[508] = (char)0x00;
buffer[509] = (char)0x00;
buffer[510] = (char)0x55;
buffer[511] = (char)0xaa;
i = FS__lb_write(pDriver, Unit, bpb.FSInfo, (void*)buffer);
if (i < 0) {
FS__fat_free(buffer);
return -1;
}
}
#endif /* FS_FAT_NOFAT32==0 */
FS__fat_free(buffer);
return 0;
}
/*********************************************************************
*
* _FS_FAT_AutoFormat
*
Description:
FS internal function. Get information about the media from the
device driver. Based on that informaton, calculate parameters for
formatting that media and call the format routine.
Parameters:
Idx - Index of device in the device information table
referred by FS__pDevInfo.
Unit - Unit number.
Return value:
>=0 - Media has been formatted.
<0 - An error has occured.
*/
static int _FS_FAT_AutoFormat(int Idx, FS_u32 Unit) {
struct {
FS_u32 hiddennum;
FS_u32 headnum;
FS_u32 secnum;
FS_u32 partsize;
} devinfo;
FS_u32 rootentcnt;
FS_u32 fatsz;
FS_u32 rootdirsectors;
FS_u32 tmpval1;
FS_u32 tmpval2;
FS_u32 fatsz32;
FS_u32 totsec32;
FS_u32 resvdseccnt;
FS_u16 totsec16;
FS_u16 fatsz16;
int i;
unsigned char secperclust;
char fsystype;
/* Get info from device */
devinfo.hiddennum = 0x00001111UL;
devinfo.headnum = 0x00002222UL;
devinfo.secnum = 0x00003333UL;
devinfo.partsize = 0x00004444UL;
i = FS__lb_ioctl(FS__pDevInfo[Idx].devdriver, Unit, FS_CMD_GET_DEVINFO, 0, (void*)&devinfo);
if (i) {
return -1;
}
/* Check if the driver really supports FS_CMD_GET_DEVINFO */
if (devinfo.hiddennum == 0x00001111UL) {
if (devinfo.headnum == 0x00002222UL) {
if (devinfo.secnum == 0x00003333UL) {
if (devinfo.partsize == 0x00004444UL) {
return -1;
}
}
}
}
if (devinfo.partsize <= 1048576UL) {
fsystype = 1; /* FAT16 */
}
#if (FS_FAT_NOFAT32==0)
else {
fsystype = 2; /* FAT32 */
}
#else
else {
/* FAT32 disabled */
return -1;
}
#endif /* FS_FAT_NOFAT32==0 */
/* Set correct RootEntCnt & ResvdSecCnt */
if (fsystype != 2) {
/* FAT16 */
i = 0;
while (_FS_auto_rootcnt[i].SecNum < devinfo.partsize) {
i++;
}
rootentcnt = (FS_u16)_FS_auto_rootcnt[i].Num;
resvdseccnt = 1;
}
#if (FS_FAT_NOFAT32==0)
else {
/* FAT32 */
rootentcnt = 0;
resvdseccnt = 0x20;
}
#endif /* FS_FAT_NOFAT32==0 */
/* Determinate SecPerClust */
i = 0;
while (_FS_auto_secperclust[i].SecNum < devinfo.partsize) {
i++;
}
secperclust = (unsigned char) _FS_auto_secperclust[i].Num;
/*
FAT16/FAT32 FAT size calculation
The formula used is following the Microsoft specification
version 1.03 very closely. Therefore the calculated FAT
size can be up to 8 sectors bigger than required for the
media. This is a waste of up to 8 sectors, but not a problem
regarding correctness of the media's data.
*/
rootdirsectors = ((rootentcnt * 32 ) + 511) / 512;
tmpval1 = devinfo.partsize - (resvdseccnt + rootdirsectors);
tmpval2 = (256 * secperclust) + 2;
#if (FS_FAT_NOFAT32==0)
if (fsystype == 2) {
tmpval2 = tmpval2 / 2;
}
#endif /* FS_FAT_NOFAT32==0 */
fatsz = (tmpval1 + (tmpval2 - 1)) / tmpval2;
if (fsystype != 2) {
fatsz16 = (FS_u16)fatsz;
fatsz32 = 0;
}
#if (FS_FAT_NOFAT32==0)
else {
fatsz16 = 0;
fatsz32 = fatsz;
}
#endif /* FS_FAT_NOFAT32==0 */
/* Number of total sectors (512 byte units) of the media
This is independent of FAT type (FAT12/FAT16/FAT32) */
if (devinfo.partsize < 0x10000UL) {
totsec16 = (FS_u16)devinfo.partsize;
totsec32 = 0;
}
else {
totsec16 = 0;
totsec32 = devinfo.partsize;
}
/* Format media using calculated values */
i = _FS_fat_format(FS__pDevInfo[Idx].devdriver,
Unit,
secperclust,
(FS_u16)rootentcnt,
totsec16,
totsec32,
(char)0xf8,
fatsz16,
fatsz32,
(FS_u16)devinfo.secnum,
(FS_u16)devinfo.headnum,
devinfo.hiddennum,
fsystype);
return i;
}
#endif /* FS_FAT_NOFORMAT==0 */
#if FS_FAT_DISKINFO
/*********************************************************************
*
* _FS_fat_GetTotalFree
*
Description:
FS internal function. Store information about used/unused clusters
in a FS_DISKFREE_T data structure.
Parameters:
Idx - Index of device in the device information table
referred by FS__pDevInfo.
Unit - Unit number.
pDiskData - Pointer to a FS_DISKFREE_T data structure.
Return value:
==0 - Information is stored in pDiskData.
<0 - An error has occured.
*/
static int _FS_fat_GetTotalFree(int Idx, FS_u32 Unit, FS_DISKFREE_T *pDiskData) {
FS_u32 freeclust;
FS_u32 usedclust;
FS_u32 totclust;
FS_u32 fatentry;
FS_u32 fatsize;
FS_i32 fatoffs;
FS_i32 bytespersec;
FS_i32 cursec;
FS_i32 fatsec;
FS_i32 lastsec;
FS_i32 fatindex;
int fattype;
int err;
char *buffer;
unsigned char a;
unsigned char b;
#if (FS_FAT_NOFAT32==0)
unsigned char c;
unsigned char d;
#endif
if (!pDiskData) {
return -1; /* No pointer to a FS_DISKFREE_T structure */
}
buffer = FS__fat_malloc(FS_FAT_SEC_SIZE);
if (!buffer) {
return -1;
}
fattype = FS__fat_which_type(Idx, Unit);
#if (FS_FAT_NOFAT32!=0)
if (fattype == 2) {
FS__fat_free(buffer);
return -1;
}
#endif /* FS_FAT_NOFAT32!=0 */
fatsize = FS__FAT_aBPBUnit[Idx][Unit].FATSz16;
if (fatsize == 0) {
fatsize = FS__FAT_aBPBUnit[Idx][Unit].FATSz32;
}
bytespersec = (FS_i32)FS__FAT_aBPBUnit[Idx][Unit].BytesPerSec;
/* Calculate total allocation units on disk */
totclust = FS__FAT_aBPBUnit[Idx][Unit].TotSec16;
if (!totclust) {
totclust = FS__FAT_aBPBUnit[Idx][Unit].TotSec32;
}
totclust -= FS__FAT_aBPBUnit[Idx][Unit].RsvdSecCnt;
totclust -= 2*fatsize;
usedclust = FS__FAT_aBPBUnit[Idx][Unit].RootEntCnt;
usedclust *= 0x20;
usedclust /= bytespersec;
totclust -= usedclust;
totclust /= FS__FAT_aBPBUnit[Idx][Unit].SecPerClus;
/* Scan FAT for free and used entries */
cursec = 0;
fatsec = 0;
lastsec = -1;
fatentry = 0xffffUL;
freeclust = 0;
usedclust = 0;
while (1) {
if (cursec >= (FS_i32)totclust) {
break; /* Last cluster reached */
}
if (fatsec >= (FS_i32)fatsize + FS__FAT_aBPBUnit[Idx][Unit].RsvdSecCnt) {
break; /* End of FAT reached */
}
if (fattype == 1) {
fatindex = (cursec + 2) + ((cursec + 2) / 2); /* FAT12 */
}
else if (fattype == 2) {
fatindex = (cursec + 2) * 4; /* FAT32 */
}
else {
fatindex = (cursec + 2) * 2; /* FAT16 */
}
fatsec = FS__FAT_aBPBUnit[Idx][Unit].RsvdSecCnt + (fatindex / bytespersec);
fatoffs = fatindex % bytespersec;
if (fatsec != lastsec) {
err = FS__lb_read(FS__pDevInfo[Idx].devdriver, Unit, fatsec, (void*)buffer);
if (err < 0) {
err = FS__lb_read(FS__pDevInfo[Idx].devdriver, Unit, fatsize + fatsec, (void*)buffer);
if (err < 0) {
FS__fat_free(buffer);
return -1;
}
/* Try to repair original FAT sector with contents of copy */
FS__lb_write(FS__pDevInfo[Idx].devdriver, Unit, fatsec, (void*)buffer);
}
lastsec = fatsec;
}
if (fattype == 1) {
if (fatoffs == (bytespersec - 1)) {
a = buffer[fatoffs];
err = FS__lb_read(FS__pDevInfo[Idx].devdriver, Unit, fatsec+1, (void*)buffer);
if (err < 0) {
err = FS__lb_read(FS__pDevInfo[Idx].devdriver, Unit, fatsize + fatsec + 1, (void*)buffer);
if (err < 0) {
FS__fat_free(buffer);
return -1;
}
/* Try to repair original FAT sector with contents of copy */
FS__lb_write(FS__pDevInfo[Idx].devdriver, Unit, fatsec + 1, (void*)buffer);
}
lastsec = fatsec + 1;
b = buffer[0];
}
else {
a = buffer[fatoffs];
b = buffer[fatoffs + 1];
}
if (cursec & 1) {
fatentry = ((a & 0xf0) >> 4 ) + 16 * b;
}
else {
fatentry = a + 256 * (b & 0x0f);
}
fatentry &= 0x0fff;
}
#if (FS_FAT_NOFAT32==0)
else if (fattype == 2) {
a = buffer[fatoffs];
b = buffer[fatoffs + 1];
c = buffer[fatoffs + 2];
d = buffer[fatoffs + 3];
fatentry = a + 0x100UL * b + 0x10000UL * c + 0x1000000UL * d;
fatentry &= 0x0fffffffUL;
}
#endif /* FS_FAT_NOFAT32==0 */
else {
a = buffer[fatoffs];
b = buffer[fatoffs + 1];
fatentry = a + 256 * b;
fatentry &= 0xffffUL;
}
cursec++;
if (fatentry == 0) {
freeclust++;
}
else {
usedclust++;
}
}
FS__fat_free(buffer);
pDiskData->total_clusters = totclust;
pDiskData->avail_clusters = freeclust;
pDiskData->sectors_per_cluster = FS__FAT_aBPBUnit[Idx][Unit].SecPerClus;
pDiskData->bytes_per_sector = (FS_u16)bytespersec;
return 0;
}
#endif /* FS_FAT_DISKINFO */
/*********************************************************************
*
* Global functions
*
**********************************************************************
*/
/*********************************************************************
*
* FS__fat_ioctl
*
Description:
FS internal function. Execute device command. The FAT layer checks
first, if it has to process the command (e.g. format). Any other
command is passed to the device driver.
Parameters:
Idx - Index of device in the device information table
referred by FS__pDevInfo.
Unit - Unit number.
Cmd - Command to be executed.
Aux - Parameter depending on command.
pBuffer - Pointer to a buffer used for the command.
Return value:
Command specific. In general a negative value means an error.
*/
int FS__fat_ioctl(int Idx, FS_u32 Unit, FS_i32 Cmd, FS_i32 Aux, void *pBuffer) {
int x;
#if ((FS_SUPPORT_SEC_ACCESS) || (FS_FAT_NOFORMAT==0))
int i;
#endif
#if (FS_FAT_NOFORMAT==0)
int j;
#endif
FS__lb_ioctl(FS__pDevInfo[Idx].devdriver, Unit, FS_CMD_INC_BUSYCNT, 0, (void*)0); /* Turn on busy signal */
#if (FS_FAT_NOFORMAT==0)
if (Cmd == FS_CMD_FORMAT_MEDIA) {
j = 0;
while (1) {
if (j >= FS_KNOWNMEDIA_NUM) {
break; /* Not a known media */
}
if (_FS_wd_format_media_table[j].media_id == Aux) {
break; /* Media found in the list */
}
j++;
} //find the right media
if (j >= FS_KNOWNMEDIA_NUM) { //can't find the right media
FS__lb_ioctl(FS__pDevInfo[Idx].devdriver, Unit, FS_CMD_DEC_BUSYCNT, 0, (void*)0); /* Turn off busy signal */
return -1;
}
i = FS__lb_status(FS__pDevInfo[Idx].devdriver, Unit); //get status of device, if ok return 1
if (i >= 0) {
x = _FS_fat_format(FS__pDevInfo[Idx].devdriver,
Unit,
_FS_wd_format_media_table[j].secperclus,
_FS_wd_format_media_table[j].rootentcnt,
_FS_wd_format_media_table[j].totsec16,
_FS_wd_format_media_table[j].totsec32,
_FS_wd_format_media_table[j].media,
_FS_wd_format_media_table[j].fatsz16,
0,
_FS_wd_format_media_table[j].secpertrk,
_FS_wd_format_media_table[j].numheads,
_FS_wd_format_media_table[j].hiddsec,
_FS_wd_format_media_table[j].fsystype);
i = FS__lb_ioctl(FS__pDevInfo[Idx].devdriver, Unit, FS_CMD_FLUSH_CACHE, 0, (void*)0);
if (i < 0) {
x = i;
}
else {
/* Invalidate BPB */
for (i = 0; i < (int)FS__maxdev; i++) {
for (j = 0; j < (int)FS__fat_maxunit; j++) {
FS__FAT_aBPBUnit[i][j].Signature = 0x0000;
}
}
}
}
else {
FS__lb_ioctl(FS__pDevInfo[Idx].devdriver, Unit, FS_CMD_DEC_BUSYCNT, 0, (void*)0); /* Turn off busy signal */
return -1;
}
}
else if (Cmd == FS_CMD_FORMAT_AUTO) {
i = FS__lb_status(FS__pDevInfo[Idx].devdriver, Unit);
if (i >= 0) {
x = _FS_FAT_AutoFormat(Idx, Unit);
i = FS__lb_ioctl(FS__pDevInfo[Idx].devdriver, Unit, FS_CMD_FLUSH_CACHE, 0, (void*)0);
if (i < 0) {
x = i;
}
}
else {
x = -1;
}
}
#else /* FS_FAT_NOFORMAT==0 */
if (Cmd == FS_CMD_FORMAT_MEDIA) {
x = -1; /* Format command is not supported */
}
#endif /* FS_FAT_NOFORMAT==0 */
#if FS_FAT_DISKINFO
else if (Cmd == FS_CMD_GET_DISKFREE) {
i = FS__fat_checkunit(Idx, Unit);
if (i > 0) {
x = _FS_fat_GetTotalFree(Idx, Unit, (FS_DISKFREE_T*)pBuffer);
i = FS__lb_ioctl(FS__pDevInfo[Idx].devdriver, Unit, FS_CMD_FLUSH_CACHE, 0, (void*)0);
if (i < 0) {
x = i;
}
}
else {
x = -1;
}
}
#else /* FS_FAT_DISKINFO==0 */
else if (Cmd == FS_CMD_GET_DISKFREE) {
x = -1; /* Diskinfo command not supported */
}
#endif /* FS_FAT_DISKINFO */
#if FS_SUPPORT_SEC_ACCESS
else if ((Cmd == FS_CMD_READ_SECTOR) || (Cmd == FS_CMD_WRITE_SECTOR)) {
if (!pBuffer) {
FS__lb_ioctl(FS__pDevInfo[Idx].devdriver, Unit, FS_CMD_DEC_BUSYCNT, 0, (void*)0);
return -1;
}
i = FS__lb_status(FS__pDevInfo[Idx].devdriver, Unit);
if (i >= 0) {
if (Cmd == FS_CMD_READ_SECTOR) {
x = FS__lb_read(FS__pDevInfo[Idx].devdriver, Unit, Aux, pBuffer);
}
else {
x = FS__lb_write(FS__pDevInfo[Idx].devdriver, Unit, Aux, pBuffer);
}
}
else {
x = -1;
}
}
#else /* FS_SUPPORT_SEC_ACCESS */
else if ((Cmd == FS_CMD_READ_SECTOR) || (Cmd == FS_CMD_WRITE_SECTOR)) {
FS__lb_ioctl(FS__pDevInfo[Idx].devdriver, Unit, FS_CMD_DEC_BUSYCNT, 0, (void*)0);
return -1;
}
#endif /* FS_SUPPORT_SEC_ACCESS */
else {
/* Maybe command for driver */
x = FS__lb_ioctl(FS__pDevInfo[Idx].devdriver, Unit, Cmd, Aux, (void*)pBuffer);
}
FS__lb_ioctl(FS__pDevInfo[Idx].devdriver, Unit, FS_CMD_DEC_BUSYCNT, 0, (void*)0); /* Turn off busy signal */
return x;
}