www.pudn.com > test_megbox_vc.rar > fat_ioct.c, change:2005-04-29,size:32679b


/* 
********************************************************************** 
*                          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; 
}