|
|
@@ -1,2154 +0,0 @@
|
|
|
-/****************************************************************************
|
|
|
-* This file is part of the AVRIDE device driver.
|
|
|
-*
|
|
|
-* Copyright (c) 2002-2004 by Michael Fischer. All rights reserved.
|
|
|
-*
|
|
|
-* Redistribution and use in source and binary forms, with or without
|
|
|
-* modification, are permitted provided that the following conditions
|
|
|
-* are met:
|
|
|
-*
|
|
|
-* 1. Redistributions of source code must retain the above copyright
|
|
|
-* notice, this list of conditions and the following disclaimer.
|
|
|
-* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
-* notice, this list of conditions and the following disclaimer in the
|
|
|
-* documentation and/or other materials provided with the distribution.
|
|
|
-* 3. Neither the name of the author nor the names of its contributors may
|
|
|
-* be used to endorse or promote products derived from this software
|
|
|
-* without specific prior written permission.
|
|
|
-*
|
|
|
-* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
-* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
-* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
|
-* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
|
|
-* THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
-* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
|
-* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
|
-* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
|
-* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
|
-* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
|
|
-* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
-* SUCH DAMAGE.
|
|
|
-*
|
|
|
-****************************************************************************
|
|
|
-* History:
|
|
|
-*
|
|
|
-* 14.12.02 mifi First Version
|
|
|
-* 23.12.02 mifi Add FileOpen, FileClose, FileError, FileSize,
|
|
|
-* FileSeek and FileRead. But the FileSeek function.
|
|
|
-* does not work in the moment, later...
|
|
|
-* 28.12.02 mifi Now support FAT16 AND FAT32.
|
|
|
-* 01.01.03 mifi Support long directory entries, but without to
|
|
|
-* check the checksum of the short entry.
|
|
|
-* Change FAT32FileSize return value from int to long.
|
|
|
-* The max size of a long filename segment is
|
|
|
-* (FAT_LONG_NAME_LEN-1). But the complete filename can
|
|
|
-* be longer.
|
|
|
-*
|
|
|
-* segment1/segment2/segment3/index.html
|
|
|
-*
|
|
|
-* segmentX max length = (FAT_LONG_NAME_LEN-1)
|
|
|
-*
|
|
|
-* 04.01.03 mifi Take a look at the return values...
|
|
|
-* 18.01.03 mifi Change Licence from GPL to BSD.
|
|
|
-* 25.01.03 mifi Implement a new FindFile function.
|
|
|
-* I have some trouble with short file names under
|
|
|
-* Win98. Win98 store a short name like "enlogo.gif"
|
|
|
-* as a long name, nasty OS.
|
|
|
-* Remove FAT32_MAX_FILES and the array aFileHandle,
|
|
|
-* a file handle will now be allocated by NutHeapAlloc,
|
|
|
-* therefore we have no restrictions about the count of
|
|
|
-* the open file handle. (Only by available memory)
|
|
|
-* 27.01.03 mifi Rename all FAT32xxx function to FATxxx.
|
|
|
-*
|
|
|
-* 28.01.03 mifi Start porting to Nut/OS 3.X.X
|
|
|
-* 19.06.03 mifi Change the call of IDEInit, now we use the BaseAddress
|
|
|
-* of 0. Because the fat module does not need to know the
|
|
|
-* address. It will be handled in ide.c.
|
|
|
-* 29.06.03 mifi First ATAPI-Version
|
|
|
-* Now we can read files from a CD-ROM. But there exist
|
|
|
-* some open points:
|
|
|
-* - only first session from a multisession CD is supported
|
|
|
-* - only iso9660, no Joliet support now, later
|
|
|
-* 24.07.04 mifi Some changes to support more than one drive (datanut)
|
|
|
-* 25.07.04 mifi Add support for the PCMCIA_11 hardware.
|
|
|
-* 27.07.04 mifi Start to add functionality for write function.
|
|
|
-* 03.08.04 mifi Add format function.
|
|
|
-****************************************************************************/
|
|
|
-#define __FAT_C__
|
|
|
-
|
|
|
-#define LOG_MODULE LOG_FAT_MODULE
|
|
|
-
|
|
|
-#include <string.h>
|
|
|
-#include <stddef.h>
|
|
|
-#include <ctype.h>
|
|
|
-#include <time.h>
|
|
|
-
|
|
|
-#include <sys/heap.h>
|
|
|
-#include <sys/event.h>
|
|
|
-#include <sys/thread.h>
|
|
|
-
|
|
|
-#include <sys/device.h>
|
|
|
-
|
|
|
-#include "typedefs.h"
|
|
|
-
|
|
|
-#include "fat.h"
|
|
|
-#include "fatdrv.h"
|
|
|
-#include "portio.h"
|
|
|
-#include "log.h"
|
|
|
-
|
|
|
-
|
|
|
-/*==========================================================*/
|
|
|
-/* DEFINE: All Structures and Common Constants */
|
|
|
-/*==========================================================*/
|
|
|
-//
|
|
|
-// FAT return codes
|
|
|
-//
|
|
|
-#define FAT_OK 0
|
|
|
-#define FAT_ERROR -1
|
|
|
-#define FAT_ERROR_EOF -2
|
|
|
-#define FAT_ERROR_IDE -3
|
|
|
-
|
|
|
-//
|
|
|
-// Define for correct return values Nut/OS
|
|
|
-//
|
|
|
-#define NUTDEV_OK 0
|
|
|
-#define NUTDEV_ERROR -1
|
|
|
-#define NUTDEV_WRONG_HW -2
|
|
|
-
|
|
|
-#define FAT_MAX_DRIVE 3
|
|
|
-
|
|
|
-//
|
|
|
-// Some defines for the FAT structures
|
|
|
-//
|
|
|
-#define ZIP_DRIVE_BR_SECTOR 32
|
|
|
-
|
|
|
-#define BPB_RsvdSecCnt 32
|
|
|
-#define BPB_NumFATs 2
|
|
|
-#define BPB_HiddSec 63
|
|
|
-
|
|
|
-#define FAT32_MEDIA 0xf8
|
|
|
-#define FAT32_SECTOR_SIZE HW_SECTOR_SIZE
|
|
|
-
|
|
|
-#define FAT32_OFFSET_FSINFO 1
|
|
|
-#define FAT32_OFFSET_BACKUP_BOOT 6
|
|
|
-
|
|
|
-#define FAT16_CLUSTER_EOF 0x0000FFFF
|
|
|
-#define FAT16_CLUSTER_ERROR 0x0000FFF7
|
|
|
-#define FAT16_CLUSTER_MASK 0x0000FFFF
|
|
|
-
|
|
|
-#define FAT32_CLUSTER_EOF 0x0FFFFFFF
|
|
|
-#define FAT32_CLUSTER_ERROR 0x0FFFFFF7
|
|
|
-#define FAT32_CLUSTER_MASK 0x0FFFFFFF
|
|
|
-
|
|
|
-#define FAT_SIGNATURE 0xAA55
|
|
|
-
|
|
|
-#define MBR_SIGNATURE FAT_SIGNATURE
|
|
|
-#define MBR_FAT32 0x0B
|
|
|
-
|
|
|
-#define FSINFO_FIRSTSIGNATURE 0x41615252
|
|
|
-#define FSINFO_FSINFOSIGNATURE 0x61417272
|
|
|
-#define FSINFO_SIGNATURE FAT_SIGNATURE
|
|
|
-
|
|
|
-#define DIRECTORY_ATTRIBUTE_READ_ONLY 0x01
|
|
|
-#define DIRECTORY_ATTRIBUTE_HIDDEN 0x02
|
|
|
-#define DIRECTORY_ATTRIBUTE_SYSTEM_FILE 0x04
|
|
|
-#define DIRECTORY_ATTRIBUTE_VOLUME_ID 0x08
|
|
|
-#define DIRECTORY_ATTRIBUTE_DIRECTORY 0x10
|
|
|
-#define DIRECTORY_ATTRIBUTE_ARCHIVE 0x20
|
|
|
-
|
|
|
-//
|
|
|
-// DIRECTORY_ATTRIBUTE_READ_ONLY |
|
|
|
-// DIRECTORY_ATTRIBUTE_HIDDEN |
|
|
|
-// DIRECTORY_ATTRIBUTE_SYSTEM_FILE |
|
|
|
-// DIRECTORY_ATTRIBUTE_VOLUME_ID
|
|
|
-//
|
|
|
-#define DIRECTORY_ATTRIBUTE_LONG_NAME 0x0F
|
|
|
-
|
|
|
-//
|
|
|
-// DIRECTORY_ATTRIBUTE_READ_ONLY |
|
|
|
-// DIRECTORY_ATTRIBUTE_HIDDEN |
|
|
|
-// DIRECTORY_ATTRIBUTE_SYSTEM_FILE |
|
|
|
-// DIRECTORY_ATTRIBUTE_VOLUME_ID |
|
|
|
-// DIRECTORY_ATTRIBUTE_DIRECTORY |
|
|
|
-// DIRECTORY_ATTRIBUTE_ARCHIVE
|
|
|
-//
|
|
|
-#define DIRECTORY_ATTRIBUTE_LONG_NAME_MASK 0x3F
|
|
|
-
|
|
|
-#define FAT_NAME_LEN 8
|
|
|
-#define FAT_EXT_LEN 3
|
|
|
-
|
|
|
-//
|
|
|
-// FAT_SHORT_NAME_LEN name len =
|
|
|
-// name + ext + 1 for the point
|
|
|
-//
|
|
|
-#define FAT_SHORT_NAME_LEN (FAT_NAME_LEN+FAT_EXT_LEN+1)
|
|
|
-#define FAT_LONG_NAME_LEN 64
|
|
|
-
|
|
|
-
|
|
|
-//
|
|
|
-// Some stuff for HD and CD, DRIVE_INFO Flags
|
|
|
-//
|
|
|
-//
|
|
|
-#define FLAG_FAT_IS_CDROM 0x0001
|
|
|
-#define FLAG_FAT_IS_ZIP 0x0002
|
|
|
-
|
|
|
-//
|
|
|
-// DiskSize to SectorPerCluster table
|
|
|
-//
|
|
|
-typedef struct
|
|
|
-{
|
|
|
- DWORD DiskSize;
|
|
|
- BYTE SecPerClusVal;
|
|
|
-} DSKSZTOSECPERCLUS;
|
|
|
-
|
|
|
-typedef struct _FAT32FileDataTime
|
|
|
-{
|
|
|
- unsigned Seconds:5;
|
|
|
- unsigned Minute:6;
|
|
|
- unsigned Hour:5;
|
|
|
- unsigned Day:5;
|
|
|
- unsigned Month:4;
|
|
|
- unsigned Year:7;
|
|
|
-} FAT32_FILEDATETIME, *PFAT32_FILEDATETIME;
|
|
|
-
|
|
|
-typedef struct _FAT32DirectoryEntry
|
|
|
-{
|
|
|
- BYTE Name[FAT_NAME_LEN];
|
|
|
- BYTE Extension[FAT_EXT_LEN];
|
|
|
- BYTE Attribute;
|
|
|
- BYTE Reserved[8];
|
|
|
- WORD HighCluster;
|
|
|
- FAT32_FILEDATETIME Date;
|
|
|
- WORD LowCluster;
|
|
|
- DWORD FileSize;
|
|
|
-} FAT32_DIRECTORY_ENTRY;
|
|
|
-
|
|
|
-typedef struct _FAT32DirectoryEntryLong
|
|
|
-{
|
|
|
- BYTE Order;
|
|
|
- WORD Name1[5];
|
|
|
- BYTE Attribute;
|
|
|
- BYTE Type;
|
|
|
- BYTE Chksum;
|
|
|
- WORD Name2[6];
|
|
|
- WORD LowCluster;
|
|
|
- WORD Name3[2];
|
|
|
-} FAT32_DIRECTORY_ENTRY_LONG;
|
|
|
-
|
|
|
-typedef struct _FAT32FileSystemInformation
|
|
|
-{
|
|
|
- DWORD FirstSignature;
|
|
|
- BYTE Reserved1[480];
|
|
|
- DWORD FSInfoSignature;
|
|
|
- DWORD NumberOfFreeClusters;
|
|
|
- DWORD MostRecentlyAllocatedCluster;
|
|
|
- BYTE Reserved2[12];
|
|
|
- BYTE Reserved3[2];
|
|
|
- WORD Signature;
|
|
|
-} FAT32_FSINFO;
|
|
|
-
|
|
|
-typedef struct _FAT32PartitionEntry
|
|
|
-{
|
|
|
- BYTE BootInd;
|
|
|
- BYTE FirstHead;
|
|
|
- BYTE FirstSector;
|
|
|
- BYTE FirstTrack;
|
|
|
- BYTE FileSystem;
|
|
|
- BYTE LastHead;
|
|
|
- BYTE LastSector;
|
|
|
- BYTE LastTrack;
|
|
|
- DWORD StartSectors;
|
|
|
- DWORD NumSectors;
|
|
|
-} FAT32_PARTITION_ENTRY;
|
|
|
-
|
|
|
-typedef struct _FAT32PartionTable
|
|
|
-{
|
|
|
- BYTE LoadInstruction[446];
|
|
|
- FAT32_PARTITION_ENTRY Partition[4];
|
|
|
- WORD Signature; /* AA55 */
|
|
|
-} FAT32_PARTITION_TABLE;
|
|
|
-
|
|
|
-typedef struct _bpbfat16
|
|
|
-{
|
|
|
- BYTE DrvNum;
|
|
|
- BYTE Reserved1;
|
|
|
- BYTE BootSig;
|
|
|
- DWORD VollID;
|
|
|
- BYTE VolLab[11];
|
|
|
- BYTE FilSysType[8];
|
|
|
- BYTE Reserved2[28];
|
|
|
-} BPBFAT16;
|
|
|
-
|
|
|
-typedef struct _bpbfat32
|
|
|
-{
|
|
|
- DWORD FATSz32; // xxx
|
|
|
- WORD ExtFlags; // 0
|
|
|
- WORD FSVer; // must 0
|
|
|
- DWORD RootClus; //
|
|
|
- WORD FSInfo; // typically 1
|
|
|
- WORD BkBootSec; // typically 6
|
|
|
- BYTE Reserved[12]; // set all to zero
|
|
|
- BYTE DrvNum; // must 0x80
|
|
|
- BYTE Reserved1; // set all to zero
|
|
|
- BYTE BootSig; // must 0x29
|
|
|
- DWORD VollID; // xxx
|
|
|
- BYTE VolLab[11]; // "abcdefghijk"
|
|
|
- BYTE FilSysType[8]; // "FAT32 "
|
|
|
-} BPBFAT32;
|
|
|
-
|
|
|
-typedef union _bpboffset36
|
|
|
-{
|
|
|
- BPBFAT16 FAT16;
|
|
|
- BPBFAT32 FAT32;
|
|
|
-} BPBOFFSET36;
|
|
|
-
|
|
|
-typedef struct _FAT32BootRecord
|
|
|
-{
|
|
|
- BYTE JumpBoot[3]; // 0xeb, 0x58, 0x90
|
|
|
- BYTE OEMName[8]; // "MSWIN4.1"
|
|
|
- WORD BytsPerSec; // must 512
|
|
|
- BYTE SecPerClus; // 8 for 4K cluster
|
|
|
- WORD RsvdSecCnt; // typically 32 for FAT32
|
|
|
- BYTE NumFATs; // always 2
|
|
|
- WORD RootEntCnt; // must 0 for FAT32
|
|
|
- WORD TotSec16; // must 0 for FAT32
|
|
|
- BYTE Media; // must 0xf8
|
|
|
-
|
|
|
- WORD FATSz16; // 0 for FAT32
|
|
|
- WORD SecPerTrk; // 63 for FAT32
|
|
|
- WORD NumHeads; // 255 for FAT32
|
|
|
- DWORD HiddSec; // 63 for FAT32
|
|
|
-
|
|
|
- DWORD TotSec32; // xxx
|
|
|
-
|
|
|
- BPBOFFSET36 Off36;
|
|
|
-
|
|
|
- BYTE Reserved[420];
|
|
|
- WORD Signature; // must 0xAA55
|
|
|
-} FAT32_BOOT_RECORD, *PFAT32_BOOT_RECORD;
|
|
|
-
|
|
|
-typedef struct _fat_entry_table16
|
|
|
-{
|
|
|
- WORD aEntry[256];
|
|
|
-} FAT_ENTRY_TABLE16;
|
|
|
-
|
|
|
-typedef struct _fat_entry_table32
|
|
|
-{
|
|
|
- DWORD aEntry[128];
|
|
|
-} FAT_ENTRY_TABLE32;
|
|
|
-
|
|
|
-typedef union _fat_dir_table
|
|
|
-{
|
|
|
- FAT32_DIRECTORY_ENTRY aShort[16];
|
|
|
- FAT32_DIRECTORY_ENTRY_LONG aLong[16];
|
|
|
-} FAT_DIR_TABLE;
|
|
|
-
|
|
|
-typedef struct _drive_info
|
|
|
-{
|
|
|
- BYTE bIsFAT32;
|
|
|
- BYTE bDevice;
|
|
|
- BYTE bSectorsPerCluster;
|
|
|
- BYTE bFlags;
|
|
|
-
|
|
|
- WORD wSectorSize;
|
|
|
-
|
|
|
- DWORD dwRootDirSectors;
|
|
|
- DWORD dwFirstRootDirSector;
|
|
|
-
|
|
|
- DWORD dwRootCluster;
|
|
|
- DWORD dwFAT1StartSector;
|
|
|
- DWORD dwFAT2StartSector;
|
|
|
- DWORD dwCluster2StartSector;
|
|
|
-
|
|
|
- DWORD dwClusterSize;
|
|
|
-} DRIVE_INFO;
|
|
|
-
|
|
|
-typedef struct _fhandle
|
|
|
-{
|
|
|
- DWORD dwFileSize;
|
|
|
- DWORD dwStartCluster;
|
|
|
- DWORD dwReadCluster;
|
|
|
- DWORD dwFilePointer; /* total file pointer */
|
|
|
- DWORD dwClusterPointer; /* cluster read pointer */
|
|
|
-
|
|
|
- int nLastError;
|
|
|
- int nEOF;
|
|
|
-
|
|
|
- DRIVE_INFO *pDrive;
|
|
|
-} FHANDLE;
|
|
|
-
|
|
|
-static int QuickFormat(NUTDEVICE *dev, DRIVE_INFO *pDrive);
|
|
|
-
|
|
|
-/*==========================================================*/
|
|
|
-/* DEFINE: Definition of all local Data */
|
|
|
-/*==========================================================*/
|
|
|
-static int nIsInit = FALSE;
|
|
|
-
|
|
|
-static BYTE *pSectorBuffer = NULL;
|
|
|
-static char *pLongName1 = NULL;
|
|
|
-static char *pLongName2 = NULL;
|
|
|
-static DRIVE_INFO sDriveInfo[FAT_MAX_DRIVE];
|
|
|
-
|
|
|
-static HANDLE hFATSemaphore;
|
|
|
-
|
|
|
-static DSKSZTOSECPERCLUS DskTableFAT32[] = {
|
|
|
- { 66600, 0}, /* disks up to 32.5MB, the 0 value for SecPerClusVal trips an error */
|
|
|
- { 532480, 1}, /* disks up to 260 MB, 0.5k cluster */
|
|
|
- { 16777216, 8}, /* disks up to 8 GB, 4k cluster */
|
|
|
- { 33554432, 16}, /* disks up to 16 GB, 8k cluster */
|
|
|
- { 67108864, 32}, /* disks up to 32 GB, 16k cluster */
|
|
|
- { 0xFFFFFFFF, 64} /* disks greather than 32GB, 32k cluster */
|
|
|
-};
|
|
|
-
|
|
|
-#define DSK_TABLE_FAT32_ENTRY_COUNT (sizeof(DskTableFAT32) / sizeof(DSKSZTOSECPERCLUS))
|
|
|
-/*==========================================================*/
|
|
|
-/* DEFINE: Definition of all local Procedures */
|
|
|
-/*==========================================================*/
|
|
|
-
|
|
|
-void FATRelease()
|
|
|
-{
|
|
|
- nIsInit=FALSE;
|
|
|
-}
|
|
|
-/************************************************************/
|
|
|
-/* FATLock */
|
|
|
-/************************************************************/
|
|
|
-void FATLock(void)
|
|
|
-{
|
|
|
- NutEventWait(&hFATSemaphore, 0);
|
|
|
-}
|
|
|
-
|
|
|
-/************************************************************/
|
|
|
-/* FATFree */
|
|
|
-/************************************************************/
|
|
|
-void FATFree(void)
|
|
|
-{
|
|
|
- NutEventPost(&hFATSemaphore);
|
|
|
-}
|
|
|
-
|
|
|
-/************************************************************/
|
|
|
-/* FATSemaInit */
|
|
|
-/************************************************************/
|
|
|
-void FATSemaInit(void)
|
|
|
-{
|
|
|
- NutEventPost(&hFATSemaphore);
|
|
|
-}
|
|
|
-
|
|
|
-/************************************************************/
|
|
|
-/* GetFirstSectorOfCluster */
|
|
|
-/************************************************************/
|
|
|
-static DWORD GetFirstSectorOfCluster(DRIVE_INFO *pDrive, DWORD dwCluster)
|
|
|
-{
|
|
|
- DWORD dwSector;
|
|
|
-
|
|
|
- if (pDrive->bFlags & FLAG_FAT_IS_CDROM)
|
|
|
- {
|
|
|
- dwSector = dwCluster;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- dwSector = (dwCluster - 2) * pDrive->bSectorsPerCluster;
|
|
|
- dwSector += pDrive->dwCluster2StartSector;
|
|
|
- }
|
|
|
-
|
|
|
- return(dwSector);
|
|
|
-}
|
|
|
-
|
|
|
-/************************************************************/
|
|
|
-/* GetNextCluster */
|
|
|
-/************************************************************/
|
|
|
-static DWORD GetNextCluster(DRIVE_INFO *pDrive, DWORD dwCluster)
|
|
|
-{
|
|
|
- DWORD dwNextCluster;
|
|
|
- DWORD dwSector;
|
|
|
- DWORD dwIndex;
|
|
|
- FAT_ENTRY_TABLE16 *pFatTable16;
|
|
|
- FAT_ENTRY_TABLE32 *pFatTable32;
|
|
|
-
|
|
|
- if (pDrive->bFlags & FLAG_FAT_IS_CDROM)
|
|
|
- {
|
|
|
- dwNextCluster = dwCluster + 1;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- if (pDrive->bIsFAT32 == TRUE)
|
|
|
- {
|
|
|
- //
|
|
|
- // (HW_SECTOR_SIZE / sizeof(long)) == 128
|
|
|
- //
|
|
|
- dwSector = (dwCluster / 128) + pDrive->dwFAT1StartSector;
|
|
|
- dwIndex = dwCluster % 128;
|
|
|
-
|
|
|
- HWReadSectors(pDrive->bDevice, pSectorBuffer, dwSector, 1);
|
|
|
- pFatTable32 = (FAT_ENTRY_TABLE32 *) pSectorBuffer;
|
|
|
-
|
|
|
- dwNextCluster = (pFatTable32->aEntry[dwIndex] & FAT32_CLUSTER_MASK);
|
|
|
- if ((dwNextCluster == FAT32_CLUSTER_EOF) || (dwNextCluster == FAT32_CLUSTER_ERROR))
|
|
|
- {
|
|
|
- dwNextCluster = 0;
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
- else
|
|
|
- { /* FAT16 */
|
|
|
- //
|
|
|
- // (HW_SECTOR_SIZE / sizeof(word)) == 256
|
|
|
- //
|
|
|
- dwSector = (dwCluster / 256) + pDrive->dwFAT1StartSector;
|
|
|
- dwIndex = dwCluster % 256;
|
|
|
-
|
|
|
- HWReadSectors(pDrive->bDevice, pSectorBuffer, dwSector, 1);
|
|
|
- pFatTable16 = (FAT_ENTRY_TABLE16 *) pSectorBuffer;
|
|
|
-
|
|
|
- dwNextCluster = (pFatTable16->aEntry[dwIndex] & FAT16_CLUSTER_MASK);
|
|
|
- if ((dwNextCluster == FAT16_CLUSTER_EOF) || (dwNextCluster == FAT16_CLUSTER_ERROR))
|
|
|
- {
|
|
|
- dwNextCluster = 0;
|
|
|
- }
|
|
|
-
|
|
|
- } /* endif pDrive->bIsFAT32 */
|
|
|
- }
|
|
|
-
|
|
|
- return(dwNextCluster);
|
|
|
-}
|
|
|
-
|
|
|
-/************************************************************/
|
|
|
-/* GetLongChar */
|
|
|
-/************************************************************/
|
|
|
-static char GetLongChar(WORD wValue)
|
|
|
-{
|
|
|
- BYTE Value;
|
|
|
-
|
|
|
- Value = (BYTE)(wValue & 0x00FF);
|
|
|
- if (Value == 0xFF)
|
|
|
- {
|
|
|
- Value = 0;
|
|
|
- }
|
|
|
-
|
|
|
- if (Value != 0)
|
|
|
- {
|
|
|
- Value = toupper(Value);
|
|
|
- }
|
|
|
-
|
|
|
- return((char)Value);
|
|
|
-}
|
|
|
-
|
|
|
-/************************************************************/
|
|
|
-/* FindFile */
|
|
|
-/* */
|
|
|
-/* Find a file by a given name pLongName. */
|
|
|
-/* */
|
|
|
-/* It is possible that a SHORT name like "enlogo.gif" */
|
|
|
-/* is stored as a LONG name. I have seen this */
|
|
|
-/* nasty behaviour by Win98. Therefore I will check */
|
|
|
-/* the long name too, even if nIsLongName is FALSE. */
|
|
|
-/************************************************************/
|
|
|
-static DWORD FindFile(DRIVE_INFO *pDrive,
|
|
|
- FAT32_DIRECTORY_ENTRY *pSearchEntry,
|
|
|
- char *pLongName,
|
|
|
- DWORD dwDirCluster,
|
|
|
- DWORD *pFileSize,
|
|
|
- int nIsLongName)
|
|
|
-{
|
|
|
- int i, x;
|
|
|
- BYTE bError;
|
|
|
- int nNameLen;
|
|
|
- int nMaxLen;
|
|
|
- BYTE bFound;
|
|
|
- BYTE bEndLoop;
|
|
|
- BYTE bOrder;
|
|
|
- BYTE bMaxOrder;
|
|
|
- int nDirMaxSector;
|
|
|
- DWORD dwSector;
|
|
|
- DWORD dwNewCluster;
|
|
|
- FAT32_DIRECTORY_ENTRY *pDirEntryShort;
|
|
|
- FAT32_DIRECTORY_ENTRY_LONG *pDirEntryLong;
|
|
|
- char *pDirName = 0;
|
|
|
- FAT_DIR_TABLE *pDirTable;
|
|
|
-
|
|
|
- bError = FALSE;
|
|
|
- *pFileSize = 0;
|
|
|
- dwNewCluster = 0;
|
|
|
-
|
|
|
- nNameLen = strlen(pLongName);
|
|
|
-
|
|
|
- bMaxOrder = (BYTE) ((nNameLen + 12) / 13);
|
|
|
- nMaxLen = (int) (bMaxOrder * 13);
|
|
|
- if (nMaxLen >= (FAT_LONG_NAME_LEN - 1))
|
|
|
- {
|
|
|
- bError = TRUE;
|
|
|
- }
|
|
|
-
|
|
|
- bOrder = (BYTE) (0x40 | bMaxOrder);
|
|
|
- if (bOrder == 0xE5)
|
|
|
- {
|
|
|
- //
|
|
|
- // I do not know what should I do if the bOrder is 0xe5.
|
|
|
- // This is a sign for a "empty" entry.
|
|
|
- //
|
|
|
- bError = TRUE;
|
|
|
- }
|
|
|
-
|
|
|
- if (bError == FALSE)
|
|
|
- {
|
|
|
- bFound = FALSE;
|
|
|
- bEndLoop = FALSE;
|
|
|
- while ((bEndLoop == FALSE) && (dwDirCluster != 0))
|
|
|
- {
|
|
|
- dwSector = GetFirstSectorOfCluster(pDrive, dwDirCluster);
|
|
|
- nDirMaxSector = (int) pDrive->bSectorsPerCluster;
|
|
|
-
|
|
|
- //
|
|
|
- // Test for special case dwDirCluster and FAT16.
|
|
|
- //
|
|
|
- if ((dwDirCluster == 1) && (pDrive->bIsFAT32 == FALSE))
|
|
|
- {
|
|
|
- dwSector = pDrive->dwFirstRootDirSector;
|
|
|
- nDirMaxSector = (int) pDrive->dwRootDirSectors;
|
|
|
- }
|
|
|
- //
|
|
|
- // One cluster has SecPerCluster sectors.
|
|
|
- //
|
|
|
- for (i = 0; i < nDirMaxSector; i++)
|
|
|
- {
|
|
|
- HWReadSectors(pDrive->bDevice, pSectorBuffer, dwSector + i, 1);
|
|
|
- pDirTable = (FAT_DIR_TABLE *) pSectorBuffer;
|
|
|
-
|
|
|
- //
|
|
|
- // And one sector has 16 entries.
|
|
|
- //
|
|
|
- // HW_SECTOR_SIZE / sizeof(FAT32_DIRECTORY_ENTRY) = 16
|
|
|
- //
|
|
|
- for (x = 0; x < 16; x++)
|
|
|
- {
|
|
|
- if (bFound == TRUE)
|
|
|
- {
|
|
|
- pDirEntryShort = (FAT32_DIRECTORY_ENTRY *) & pDirTable->aShort[x];
|
|
|
- dwNewCluster = pDirEntryShort->HighCluster;
|
|
|
- dwNewCluster = (dwNewCluster << 16) | (DWORD) pDirEntryShort->LowCluster;
|
|
|
- *pFileSize = pDirEntryShort->FileSize;
|
|
|
- bEndLoop = TRUE;
|
|
|
- break;
|
|
|
- }
|
|
|
- //
|
|
|
- // Check for valid entry.
|
|
|
- //
|
|
|
- pDirEntryShort = (FAT32_DIRECTORY_ENTRY *) & pDirTable->aShort[x];
|
|
|
- pDirEntryLong = (FAT32_DIRECTORY_ENTRY_LONG *) & pDirTable->aLong[x];
|
|
|
-
|
|
|
- if (nIsLongName == FALSE)
|
|
|
- {
|
|
|
- //
|
|
|
- // Check if it could be a short name. If Win2000 tell us it
|
|
|
- // is a short name, it is true. But with Win98 we must
|
|
|
- // test both, short and long...
|
|
|
- //
|
|
|
- if ((pDirEntryShort->Name[0] != 0xE5) && (pDirEntryShort->Name[0] != 0x00))
|
|
|
- {
|
|
|
- if (memcmp(pDirEntryShort, pSearchEntry, 11) == 0)
|
|
|
- {
|
|
|
- //
|
|
|
- // Check for the correct attribute, this is done with
|
|
|
- // the '&' and not with the memcmp.
|
|
|
- // With the '&' it is possible to find a hidden archive too :-)
|
|
|
- //
|
|
|
- if ((pDirEntryShort->Attribute & pSearchEntry->Attribute) ==
|
|
|
- pSearchEntry->Attribute)
|
|
|
- {
|
|
|
-
|
|
|
- dwNewCluster = pDirEntryShort->HighCluster;
|
|
|
- dwNewCluster = (dwNewCluster << 16) | (DWORD) pDirEntryShort->LowCluster;
|
|
|
- *pFileSize = pDirEntryShort->FileSize;
|
|
|
-
|
|
|
- bEndLoop = TRUE;
|
|
|
- break;
|
|
|
-
|
|
|
- } /* endif Attribute */
|
|
|
- } /* endif test Name+Ext */
|
|
|
- } /* endif Name[0] != 0xe5, 0x00 */
|
|
|
- }
|
|
|
- /*
|
|
|
- * endif nIsLongName == FALSE
|
|
|
- */
|
|
|
- if ((pDirEntryLong->Attribute == DIRECTORY_ATTRIBUTE_LONG_NAME)
|
|
|
- && (pDirEntryLong->Order == bOrder))
|
|
|
- {
|
|
|
- //
|
|
|
- // Next bOrder is bOrder--
|
|
|
- //
|
|
|
- if (bOrder & 0x40)
|
|
|
- {
|
|
|
- bOrder &= ~0x40;
|
|
|
-
|
|
|
- //
|
|
|
- // Get the space for the name.
|
|
|
- //
|
|
|
- pDirName = pLongName2;
|
|
|
-
|
|
|
- //
|
|
|
- // Set the end of string.
|
|
|
- //
|
|
|
- pDirName[nMaxLen--] = 0;
|
|
|
- }
|
|
|
-
|
|
|
- pDirName[nMaxLen--] = GetLongChar(pDirEntryLong->Name3[1]);
|
|
|
- pDirName[nMaxLen--] = GetLongChar(pDirEntryLong->Name3[0]);
|
|
|
-
|
|
|
- pDirName[nMaxLen--] = GetLongChar(pDirEntryLong->Name2[5]);
|
|
|
- pDirName[nMaxLen--] = GetLongChar(pDirEntryLong->Name2[4]);
|
|
|
- pDirName[nMaxLen--] = GetLongChar(pDirEntryLong->Name2[3]);
|
|
|
- pDirName[nMaxLen--] = GetLongChar(pDirEntryLong->Name2[2]);
|
|
|
- pDirName[nMaxLen--] = GetLongChar(pDirEntryLong->Name2[1]);
|
|
|
- pDirName[nMaxLen--] = GetLongChar(pDirEntryLong->Name2[0]);
|
|
|
-
|
|
|
- pDirName[nMaxLen--] = GetLongChar(pDirEntryLong->Name1[4]);
|
|
|
- pDirName[nMaxLen--] = GetLongChar(pDirEntryLong->Name1[3]);
|
|
|
- pDirName[nMaxLen--] = GetLongChar(pDirEntryLong->Name1[2]);
|
|
|
- pDirName[nMaxLen--] = GetLongChar(pDirEntryLong->Name1[1]);
|
|
|
- pDirName[nMaxLen--] = GetLongChar(pDirEntryLong->Name1[0]);
|
|
|
-
|
|
|
- bOrder--;
|
|
|
- if (bOrder == 0)
|
|
|
- {
|
|
|
- //
|
|
|
- // Now compare the name.
|
|
|
- //
|
|
|
- bOrder = (BYTE) (0x40 | bMaxOrder);
|
|
|
- nMaxLen = (int) (bMaxOrder * 13);
|
|
|
- if (memcmp(pLongName, pDirName, strlen(pLongName)) == 0)
|
|
|
- {
|
|
|
- //
|
|
|
- // The next entry will be the correct entry.
|
|
|
- //
|
|
|
- bFound = TRUE;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- /*
|
|
|
- * pDirEntryLong->Order == bOrder
|
|
|
- */
|
|
|
- } /* endfor x<16 */
|
|
|
-
|
|
|
- if (bEndLoop == TRUE)
|
|
|
- {
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (bEndLoop == FALSE)
|
|
|
- {
|
|
|
- //
|
|
|
- // No file found in this cluster, get the next one.
|
|
|
- //
|
|
|
- dwDirCluster = GetNextCluster(pDrive, dwDirCluster);
|
|
|
- }
|
|
|
- } /* endwhile */
|
|
|
-
|
|
|
- }
|
|
|
- /*
|
|
|
- * endif bError == FALSE
|
|
|
- */
|
|
|
- return(dwNewCluster);
|
|
|
-}
|
|
|
-
|
|
|
-/************************************************************/
|
|
|
-/* MountHW */
|
|
|
-/************************************************************/
|
|
|
-static int MountHW(int nDrive)
|
|
|
-{
|
|
|
- int nError;
|
|
|
- int i;
|
|
|
- DWORD dwSector;
|
|
|
- DWORD dwFATSz;
|
|
|
- DWORD dwRootDirSectors;
|
|
|
- FAT32_PARTITION_TABLE *pPartitionTable;
|
|
|
- FAT32_BOOT_RECORD *pBootRecord;
|
|
|
- DRIVE_INFO *pDrive;
|
|
|
-
|
|
|
- nError = HW_OK;
|
|
|
- i = nDrive;
|
|
|
- pDrive = &sDriveInfo[nDrive];
|
|
|
- dwSector = 0;
|
|
|
-
|
|
|
- if (pDrive->bFlags & FLAG_FAT_IS_ZIP)
|
|
|
- {
|
|
|
- dwSector = ZIP_DRIVE_BR_SECTOR;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- //
|
|
|
- // Try to find a PartitionTable.
|
|
|
- //
|
|
|
- nError = HWReadSectors(nDrive, pSectorBuffer, 0, 1);
|
|
|
- if (nError == HW_OK)
|
|
|
- {
|
|
|
- pPartitionTable = (FAT32_PARTITION_TABLE *) pSectorBuffer;
|
|
|
-
|
|
|
- if (pPartitionTable->Signature == FAT_SIGNATURE)
|
|
|
- {
|
|
|
- if (pPartitionTable->Partition[0].NumSectors)
|
|
|
- {
|
|
|
- //
|
|
|
- // We found a PartitionTable, read BootRecord.
|
|
|
- //
|
|
|
- dwSector = pPartitionTable->Partition[0].StartSectors;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (dwSector != 0)
|
|
|
- {
|
|
|
- HWReadSectors(i, pSectorBuffer, dwSector, 1);
|
|
|
- pBootRecord = (FAT32_BOOT_RECORD *) pSectorBuffer;
|
|
|
-
|
|
|
- //
|
|
|
- // Test valid BootRecord.
|
|
|
- //
|
|
|
- if (pBootRecord->Signature == FAT_SIGNATURE)
|
|
|
- {
|
|
|
- pDrive->bSectorsPerCluster = pBootRecord->SecPerClus;
|
|
|
-
|
|
|
- if (pBootRecord->FATSz16 != 0)
|
|
|
- {
|
|
|
- dwFATSz = pBootRecord->FATSz16;
|
|
|
- pDrive->bIsFAT32 = FALSE;
|
|
|
- pDrive->dwRootCluster = 1; /* special value, see */
|
|
|
- /* FindFile */
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- dwFATSz = pBootRecord->Off36.FAT32.FATSz32;
|
|
|
- pDrive->bIsFAT32 = TRUE;
|
|
|
- pDrive->dwRootCluster = pBootRecord->Off36.FAT32.RootClus;
|
|
|
- }
|
|
|
-
|
|
|
- dwRootDirSectors =
|
|
|
- ((pBootRecord->RootEntCnt * 32) +
|
|
|
- (pBootRecord->BytsPerSec - 1)) / pBootRecord->BytsPerSec;
|
|
|
-
|
|
|
- pDrive->dwFAT1StartSector = pBootRecord->HiddSec + pBootRecord->RsvdSecCnt;
|
|
|
- pDrive->dwFAT2StartSector = pDrive->dwFAT1StartSector + dwFATSz;
|
|
|
-
|
|
|
- pDrive->dwCluster2StartSector =
|
|
|
- pBootRecord->HiddSec + pBootRecord->RsvdSecCnt +
|
|
|
- (pBootRecord->NumFATs * dwFATSz) + dwRootDirSectors;
|
|
|
-
|
|
|
- pDrive->dwClusterSize = pBootRecord->SecPerClus * pDrive->wSectorSize;
|
|
|
-
|
|
|
- pDrive->dwRootDirSectors = dwRootDirSectors;
|
|
|
- pDrive->dwFirstRootDirSector = pDrive->dwFAT2StartSector + dwFATSz;
|
|
|
-
|
|
|
- } /* endif pBootRecord->Signature */
|
|
|
- }
|
|
|
- /*
|
|
|
- * endif dwSector != 0
|
|
|
- */
|
|
|
- return(nError);
|
|
|
-}
|
|
|
-
|
|
|
-/************************************************************/
|
|
|
-/* MountAllDrives */
|
|
|
-/************************************************************/
|
|
|
-static int MountDrive(BYTE bDrive)
|
|
|
-{
|
|
|
- int nError;
|
|
|
-
|
|
|
- nError = HW_OK;
|
|
|
-
|
|
|
- FATLock();
|
|
|
-
|
|
|
- if (pLongName1 == NULL)
|
|
|
- {
|
|
|
- pLongName1 = (char *)NutHeapAlloc(FAT_LONG_NAME_LEN);
|
|
|
- }
|
|
|
- if (pLongName2 == NULL)
|
|
|
- {
|
|
|
- pLongName2 = (char *)NutHeapAlloc(FAT_LONG_NAME_LEN);
|
|
|
- }
|
|
|
- if (pSectorBuffer == NULL)
|
|
|
- {
|
|
|
- pSectorBuffer = (BYTE *)NutHeapAlloc(MAX_SECTOR_SIZE);
|
|
|
- }
|
|
|
-
|
|
|
- if ((pSectorBuffer != NULL) && (pLongName1 != NULL) && (pLongName2 != NULL))
|
|
|
- {
|
|
|
- memset((BYTE *) & sDriveInfo[bDrive], 0x00, sizeof(DRIVE_INFO));
|
|
|
-
|
|
|
- sDriveInfo[bDrive].bDevice = bDrive;
|
|
|
- sDriveInfo[bDrive].wSectorSize = HWGetSectorSize(bDrive);
|
|
|
-
|
|
|
- if (HWIsCDROMDevice(bDrive) == TRUE)
|
|
|
- {
|
|
|
- sDriveInfo[bDrive].bFlags |= FLAG_FAT_IS_CDROM;
|
|
|
- }
|
|
|
-
|
|
|
- if (HWIsZIPDevice(bDrive) == TRUE)
|
|
|
- {
|
|
|
- sDriveInfo[bDrive].bFlags |= FLAG_FAT_IS_ZIP;
|
|
|
- }
|
|
|
-
|
|
|
- switch (sDriveInfo[bDrive].wSectorSize)
|
|
|
- {
|
|
|
- case HW_SECTOR_SIZE:{
|
|
|
- nError = MountHW(bDrive);
|
|
|
- break;
|
|
|
- }
|
|
|
- default:{
|
|
|
- nError = HW_ERROR;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- /*
|
|
|
- * endif pSectorBuffer != NULL
|
|
|
- */
|
|
|
- FATFree();
|
|
|
-
|
|
|
- return(nError);
|
|
|
-}
|
|
|
-
|
|
|
-/************************************************************/
|
|
|
-/* MountAllDrives */
|
|
|
-/************************************************************/
|
|
|
-static int MountAllDrives(void)
|
|
|
-{
|
|
|
- BYTE i;
|
|
|
- int nError = HW_OK;
|
|
|
-
|
|
|
- for (i = 0; i < FAT_MAX_DRIVE; i++)
|
|
|
- {
|
|
|
- MountDrive(i);
|
|
|
- }
|
|
|
-
|
|
|
- return(nError);
|
|
|
-}
|
|
|
-
|
|
|
-/*==========================================================*/
|
|
|
-/* DEFINE: All code exported by the NUTDEVICE */
|
|
|
-/*==========================================================*/
|
|
|
-/************************************************************/
|
|
|
-/* FATUnMountDrive */
|
|
|
-/************************************************************/
|
|
|
-static int FATUnMountDrive(int nDrive)
|
|
|
-{
|
|
|
- int nError;
|
|
|
- DRIVE_INFO *pDrive;
|
|
|
-
|
|
|
- FATLock();
|
|
|
-
|
|
|
- nError = FAT_OK;
|
|
|
-
|
|
|
- if ((nDrive >= HW_DRIVE_C) && (nDrive <= HW_DRIVE_D))
|
|
|
- {
|
|
|
- pDrive = &sDriveInfo[nDrive];
|
|
|
- pDrive->bSectorsPerCluster = 0;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- nError = FAT_ERROR;
|
|
|
- }
|
|
|
-
|
|
|
- FATFree();
|
|
|
-
|
|
|
- return(nError);
|
|
|
-}
|
|
|
-
|
|
|
-/************************************************************/
|
|
|
-/* CFMount */
|
|
|
-/************************************************************/
|
|
|
-static void CFMount(int nDrive)
|
|
|
-{
|
|
|
- BYTE *pSectorBuffer;
|
|
|
-
|
|
|
- pSectorBuffer = (BYTE *) NutHeapAlloc(MAX_SECTOR_SIZE);
|
|
|
- if (pSectorBuffer != NULL)
|
|
|
- {
|
|
|
- MountDrive(nDrive);
|
|
|
- NutHeapFree(pSectorBuffer);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/************************************************************/
|
|
|
-/* CFUnMount */
|
|
|
-/************************************************************/
|
|
|
-static void CFUnMount(int nDrive)
|
|
|
-{
|
|
|
- FATUnMountDrive(nDrive);
|
|
|
-}
|
|
|
-
|
|
|
-/************************************************************/
|
|
|
-/* FATInit */
|
|
|
-/************************************************************/
|
|
|
-static int FATInit(NUTDEVICE * pDevice)
|
|
|
-{
|
|
|
- int nError;
|
|
|
- int nHWMode;
|
|
|
- BYTE *pSectorBuffer;
|
|
|
-
|
|
|
- nError = NUTDEV_ERROR;
|
|
|
- nHWMode = 0;
|
|
|
- pSectorBuffer = NULL;
|
|
|
-
|
|
|
- if ((nIsInit == FALSE) &&
|
|
|
- (pDevice->dev_name[0] == 'F') &&
|
|
|
- (pDevice->dev_name[1] == 'A') &&
|
|
|
- (pDevice->dev_name[2] == 'T'))
|
|
|
- {
|
|
|
- nError = NUTDEV_OK;
|
|
|
-
|
|
|
- //
|
|
|
- // Get the mode.
|
|
|
- //
|
|
|
- switch (pDevice->dev_base)
|
|
|
- {
|
|
|
-
|
|
|
-#if (FAT_USE_MMC_INTERFACE >= 1)
|
|
|
- case FAT_MODE_MMC:
|
|
|
- nHWMode = 0;
|
|
|
- break;
|
|
|
-#endif
|
|
|
- default:
|
|
|
- nError = NUTDEV_ERROR;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- if (nError == NUTDEV_OK)
|
|
|
- {
|
|
|
- //
|
|
|
- // Init my semaphore.
|
|
|
- //
|
|
|
- FATSemaInit();
|
|
|
-
|
|
|
- pSectorBuffer = (BYTE *) NutHeapAlloc(MAX_SECTOR_SIZE);
|
|
|
- if (pSectorBuffer != NULL)
|
|
|
- {
|
|
|
- /*
|
|
|
- * HW init
|
|
|
- */
|
|
|
- nError = HWInit(nHWMode, CFMount, CFUnMount);
|
|
|
- if (nError == HW_OK)
|
|
|
- {
|
|
|
- HWMountAllDevices(nHWMode, pSectorBuffer);
|
|
|
-
|
|
|
- /*
|
|
|
- * FAT init
|
|
|
- */
|
|
|
- MountAllDrives();
|
|
|
-
|
|
|
- nError = NUTDEV_OK;
|
|
|
- nIsInit = TRUE;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- nError = NUTDEV_WRONG_HW;
|
|
|
- }
|
|
|
-
|
|
|
- NutHeapFree(pSectorBuffer);
|
|
|
- } /* endif pSectorBuffer != NULL */
|
|
|
- } /* endif nError == NUTDEV_OK */
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- if (nIsInit == TRUE)
|
|
|
- {
|
|
|
-#if (FAT_USE_MMC_INTERFACE >= 1)
|
|
|
- if ((pDevice->dev_name[0] == 'F') &&
|
|
|
- (pDevice->dev_name[1] == 'M') &&
|
|
|
- (pDevice->dev_name[2] == '0'))
|
|
|
- {
|
|
|
- /*
|
|
|
- * Always OK, because the MMC card
|
|
|
- * can be inserted later.
|
|
|
- */
|
|
|
- nError = NUTDEV_OK;
|
|
|
- }
|
|
|
-#endif /* (FAT_USE_MMC_INTERFACE >= 0) */
|
|
|
-
|
|
|
- } /* endif (nIsInit == TRUE) */
|
|
|
- } /* endif nIsInit == FALSE */
|
|
|
-
|
|
|
- return(nError);
|
|
|
-}
|
|
|
-
|
|
|
-/************************************************************/
|
|
|
-/* GetDriveByDevice */
|
|
|
-/************************************************************/
|
|
|
-static DRIVE_INFO* GetDriveByDevice (NUTDEVICE *pDevice)
|
|
|
-{
|
|
|
- DRIVE_INFO* pDrive = NULL;
|
|
|
-
|
|
|
- if (pDevice != NULL)
|
|
|
- {
|
|
|
- switch (pDevice->dev_name[2])
|
|
|
- {
|
|
|
- case 'F':{
|
|
|
- pDrive = &sDriveInfo[HW_DRIVE_C];
|
|
|
- break;
|
|
|
- }
|
|
|
- case '0':{
|
|
|
- pDrive = &sDriveInfo[HW_DRIVE_D];
|
|
|
- break;
|
|
|
- }
|
|
|
- case '1':{
|
|
|
- pDrive = &sDriveInfo[HW_DRIVE_E];
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return(pDrive);
|
|
|
-}
|
|
|
-
|
|
|
-/************************************************************/
|
|
|
-/* FATFileOpen */
|
|
|
-/* */
|
|
|
-/* Opens an existing file for reading. */
|
|
|
-/* */
|
|
|
-/* Parameters: pName points to a string that specifies the */
|
|
|
-/* name of the file to open. The name must */
|
|
|
-/* exactly match the full pathname of the file.*/
|
|
|
-/* */
|
|
|
-/* Returns: A pointer to a FILE structure that can be */
|
|
|
-/* used to read the file and retrieve */
|
|
|
-/* information about the file. */
|
|
|
-/* */
|
|
|
-/* A return value of -1 indicates an error. */
|
|
|
-/************************************************************/
|
|
|
-static NUTFILE *FATFileOpen(NUTDEVICE *pDevice, CONST char *pName, int nMode,
|
|
|
- int nAccess)
|
|
|
-{
|
|
|
- int i, x;
|
|
|
- int nError;
|
|
|
- int nEndWhile;
|
|
|
- DWORD dwFileSize;
|
|
|
- DWORD dwCluster;
|
|
|
- FHANDLE *hFile;
|
|
|
- DRIVE_INFO *pDrive;
|
|
|
- FAT32_DIRECTORY_ENTRY sDirEntry;
|
|
|
- NUTFILE *hNUTFile;
|
|
|
- int nLongName;
|
|
|
- char *pLongName;
|
|
|
- char *pShortName;
|
|
|
- char *pExtension;
|
|
|
-
|
|
|
- //
|
|
|
- // If the user has forgotten to call NUTDeviceOpen,
|
|
|
- // we must call FATInit.
|
|
|
- //
|
|
|
- if (nIsInit == FALSE)
|
|
|
- {
|
|
|
- FATInit(pDevice);
|
|
|
- }
|
|
|
-
|
|
|
- FATLock();
|
|
|
-
|
|
|
- pDrive = NULL;
|
|
|
- nError = TRUE;
|
|
|
- nLongName = FALSE;
|
|
|
- pLongName = (char *)pLongName1;
|
|
|
-
|
|
|
- //
|
|
|
- // hFile is our FAT-Handle.
|
|
|
- //
|
|
|
- hFile = NULL;
|
|
|
-
|
|
|
- //
|
|
|
- // hNUTFile is the.... correct, NUT handle.
|
|
|
- //
|
|
|
- hNUTFile = (NUTFILE *) NUTDEV_ERROR;
|
|
|
-
|
|
|
- pDrive = GetDriveByDevice(pDevice);
|
|
|
-
|
|
|
- if ((pDrive != NULL) && (pDrive->bSectorsPerCluster != 0) && (pName[0] != 0))
|
|
|
- {
|
|
|
-
|
|
|
- //
|
|
|
- // Create a new file handle.
|
|
|
- //
|
|
|
- hFile = (FHANDLE *) NutHeapAlloc(sizeof(FHANDLE));
|
|
|
-
|
|
|
- if ((pDrive->dwFAT1StartSector) && (hFile != NULL) && (*pName != '.'))
|
|
|
- {
|
|
|
-
|
|
|
- memset(hFile, 0x00, sizeof(FHANDLE));
|
|
|
-
|
|
|
- //
|
|
|
- // Start by the ROOT dir...
|
|
|
- //
|
|
|
- dwCluster = pDrive->dwRootCluster;
|
|
|
-
|
|
|
- //
|
|
|
- // If the first char a "/", jump over, e.g. "/index.html"
|
|
|
- //
|
|
|
- //
|
|
|
- if (*pName == '/')
|
|
|
- {
|
|
|
- pName++;
|
|
|
- }
|
|
|
-
|
|
|
- nEndWhile = FALSE;
|
|
|
- while (nEndWhile == FALSE)
|
|
|
- { /* master loop */
|
|
|
-
|
|
|
- nLongName = FALSE;
|
|
|
-
|
|
|
- //
|
|
|
- // Get Name
|
|
|
- //
|
|
|
- i = 0;
|
|
|
- while ((*pName != '/') && (*pName != '\\') && (*pName != 0))
|
|
|
- {
|
|
|
-
|
|
|
- if (i >= (FAT_LONG_NAME_LEN - 1))
|
|
|
- {
|
|
|
- nEndWhile = TRUE;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- pLongName[i] = toupper(*pName);
|
|
|
-
|
|
|
- i++;
|
|
|
- pName++;
|
|
|
- } /* endwhile Name */
|
|
|
-
|
|
|
- if (nEndWhile == FALSE)
|
|
|
- {
|
|
|
- pLongName[i] = 0;
|
|
|
-
|
|
|
- //
|
|
|
- // Check if it is a Long Directory Entry.
|
|
|
- // Yes, I know that 'i' is the length of the string.
|
|
|
- // But the code is easier to read with the next strlen.
|
|
|
- //
|
|
|
- if (strlen(pLongName) <= FAT_SHORT_NAME_LEN)
|
|
|
- {
|
|
|
- //
|
|
|
- // It could be a ShortName, but "abc.defg" is possible
|
|
|
- // and this is a long name too. Therfore we need some tests.
|
|
|
- //
|
|
|
- pExtension = strchr(pLongName, '.');
|
|
|
- if (pExtension == NULL)
|
|
|
- {
|
|
|
- if (strlen(pLongName) > FAT_NAME_LEN)
|
|
|
- {
|
|
|
- nLongName = TRUE;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- nLongName = FALSE;
|
|
|
- }
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- //
|
|
|
- // Check the length of the extensions.
|
|
|
- //
|
|
|
- pExtension++; /* jump over the '.' */
|
|
|
- if (strlen(pExtension) > 3)
|
|
|
- {
|
|
|
- nLongName = TRUE;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- else
|
|
|
- { /* Len > FAT_SHORT_NAME_LEN */
|
|
|
- //
|
|
|
- // Now we have a LongName, sure.
|
|
|
- // See the "nasty Win98" in FindFile :-)
|
|
|
- //
|
|
|
- nLongName = TRUE;
|
|
|
- }
|
|
|
-
|
|
|
- //
|
|
|
- // Here we knows, if we have a LongName or ShortName.
|
|
|
- //
|
|
|
- if (nLongName == FALSE)
|
|
|
- {
|
|
|
- //
|
|
|
- // ShortName
|
|
|
- //
|
|
|
- pShortName = pLongName;
|
|
|
- memset(&sDirEntry, 0x00, sizeof(FAT32_DIRECTORY_ENTRY));
|
|
|
- memset(sDirEntry.Name, 0x20, FAT_NAME_LEN);
|
|
|
- memset(sDirEntry.Extension, 0x20, FAT_EXT_LEN);
|
|
|
-
|
|
|
- //
|
|
|
- // Get the name
|
|
|
- //
|
|
|
- i = 0;
|
|
|
- while ((pShortName[i] != '.') && (pShortName[i] != 0))
|
|
|
- {
|
|
|
- sDirEntry.Name[i] = pShortName[i];
|
|
|
- i++;
|
|
|
- }
|
|
|
- //
|
|
|
- // And the extension
|
|
|
- //
|
|
|
- if (pShortName[i] == '.')
|
|
|
- {
|
|
|
- i++; /* jump over the '.' */
|
|
|
- x = 0;
|
|
|
- while (pShortName[i] != 0)
|
|
|
- {
|
|
|
- sDirEntry.Extension[x] = pShortName[i];
|
|
|
- i++;
|
|
|
- x++;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- //
|
|
|
- // The file could be a long or short one.
|
|
|
- // I have seen that Win98 store the short filename
|
|
|
- // in a long one :-(
|
|
|
- //
|
|
|
- switch (*pName)
|
|
|
- {
|
|
|
- //
|
|
|
- // The file is an ARCHIVE
|
|
|
- //
|
|
|
- case 0:{
|
|
|
- nEndWhile = TRUE;
|
|
|
- sDirEntry.Attribute = DIRECTORY_ATTRIBUTE_ARCHIVE;
|
|
|
-
|
|
|
- if (pDrive->bFlags & FLAG_FAT_IS_CDROM)
|
|
|
- {
|
|
|
- dwCluster = 0;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- dwCluster =
|
|
|
- FindFile(pDrive, &sDirEntry, pLongName, dwCluster, &dwFileSize,
|
|
|
- nLongName);
|
|
|
- }
|
|
|
- if (dwCluster != 0)
|
|
|
- {
|
|
|
- hFile->dwFileSize = dwFileSize;
|
|
|
- hFile->dwStartCluster = dwCluster;
|
|
|
- hFile->dwReadCluster = dwCluster;
|
|
|
- hFile->dwFilePointer = 0;
|
|
|
- hFile->dwClusterPointer = 0;
|
|
|
- hFile->pDrive = pDrive;
|
|
|
- hFile->nLastError = FAT_OK;
|
|
|
- hFile->nEOF = FALSE;
|
|
|
-
|
|
|
- nError = FALSE;
|
|
|
- }
|
|
|
- break;
|
|
|
- } /* endcase 0 */
|
|
|
-
|
|
|
- //
|
|
|
- // The file is a DIRECTORY
|
|
|
- //
|
|
|
- case '/':
|
|
|
- case '\\':{
|
|
|
- pName++; /* jump over the char */
|
|
|
-
|
|
|
- sDirEntry.Attribute = DIRECTORY_ATTRIBUTE_DIRECTORY;
|
|
|
-
|
|
|
- if (pDrive->bFlags & FLAG_FAT_IS_CDROM)
|
|
|
- {
|
|
|
- dwCluster = 0;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- dwCluster =
|
|
|
- FindFile(pDrive, &sDirEntry, pLongName, dwCluster, &dwFileSize,
|
|
|
- nLongName);
|
|
|
- }
|
|
|
- if (dwCluster != 0)
|
|
|
- {
|
|
|
-
|
|
|
- //
|
|
|
- // The new Cluster is the Cluster of the directory
|
|
|
- //
|
|
|
-
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- nEndWhile = TRUE;
|
|
|
- }
|
|
|
- break;
|
|
|
- } /* endcase / \ */
|
|
|
-
|
|
|
- default:{
|
|
|
- nEndWhile = TRUE;
|
|
|
- break;
|
|
|
- }
|
|
|
- } /* end switch */
|
|
|
-
|
|
|
- }
|
|
|
- /*
|
|
|
- * endif nEndWhile == FALSE
|
|
|
- */
|
|
|
- } /* end while */
|
|
|
-
|
|
|
- }
|
|
|
- /*
|
|
|
- * endif pDrive->dwFAT1StartSector
|
|
|
- */
|
|
|
- if (nError == TRUE)
|
|
|
- {
|
|
|
- //
|
|
|
- // We found no file, therefore we can delete our FAT-Handle
|
|
|
- //
|
|
|
- if (hFile != NULL)
|
|
|
- {
|
|
|
- NutHeapFree(hFile);
|
|
|
- }
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- //
|
|
|
- // We have found a FILE and can create a NUT-Handle.
|
|
|
- //
|
|
|
- hNUTFile = NutHeapAlloc(sizeof(NUTFILE));
|
|
|
- if (hNUTFile != NULL)
|
|
|
- {
|
|
|
- hNUTFile->nf_next = 0;
|
|
|
- hNUTFile->nf_dev = pDevice;
|
|
|
- hNUTFile->nf_fcb = hFile;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- //
|
|
|
- // Error, no mem for the NUT-Handle, therefore we
|
|
|
- // can delete our FAT-Handle too.
|
|
|
- //
|
|
|
- NutHeapFree(hFile);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
- /*
|
|
|
- * endif pName[0] != 0
|
|
|
- */
|
|
|
- FATFree();
|
|
|
-
|
|
|
- return(hNUTFile);
|
|
|
-}
|
|
|
-
|
|
|
-/************************************************************/
|
|
|
-/* FATFileClose */
|
|
|
-/* */
|
|
|
-/* Close a previously opened file. */
|
|
|
-/* */
|
|
|
-/* Parameters: hNUTFile Identifies the file to close. */
|
|
|
-/* This pointer must have been created by */
|
|
|
-/* calling FAT32FileOpen(). */
|
|
|
-/* */
|
|
|
-/* Returns: 0 if the function is successfully closed, */
|
|
|
-/* -1 otherwise. */
|
|
|
-/************************************************************/
|
|
|
-static int FATFileClose(NUTFILE * hNUTFile)
|
|
|
-{
|
|
|
- int nError;
|
|
|
- FHANDLE *hFile;
|
|
|
-
|
|
|
- nError = NUTDEV_ERROR;
|
|
|
-
|
|
|
- FATLock();
|
|
|
-
|
|
|
- if (hNUTFile != NULL)
|
|
|
- {
|
|
|
- hFile = (FHANDLE *) hNUTFile->nf_fcb;
|
|
|
- if (hFile != NULL)
|
|
|
- {
|
|
|
- //
|
|
|
- // Clear our FAT-Handle
|
|
|
- //
|
|
|
- NutHeapFree(hFile);
|
|
|
- }
|
|
|
- //
|
|
|
- // Clear the NUT-Handle
|
|
|
- //
|
|
|
- NutHeapFree(hNUTFile);
|
|
|
-
|
|
|
- nError = NUTDEV_OK;
|
|
|
- }
|
|
|
-
|
|
|
- FATFree();
|
|
|
-
|
|
|
- return(nError);
|
|
|
-}
|
|
|
-
|
|
|
-/************************************************************/
|
|
|
-/* FATFileSize */
|
|
|
-/* */
|
|
|
-/* Retrieve the size of a file. */
|
|
|
-/* */
|
|
|
-/* Parameters: pFile Identifies the file to query. */
|
|
|
-/* This pointer must have been created by */
|
|
|
-/* calling FAT32FileOpen(). */
|
|
|
-/* */
|
|
|
-/* Returns: The number of bytes in this file or */
|
|
|
-/* -1 if an error occured */
|
|
|
-/************************************************************/
|
|
|
-long FATFileSize(NUTFILE * hNUTFile)
|
|
|
-{
|
|
|
- long lSize;
|
|
|
- FHANDLE *hFile;
|
|
|
-
|
|
|
- FATLock();
|
|
|
-
|
|
|
- lSize = NUTDEV_ERROR;
|
|
|
-
|
|
|
- if (hNUTFile != NULL)
|
|
|
- {
|
|
|
- hFile = (FHANDLE *) hNUTFile->nf_fcb;
|
|
|
- if (hFile != NULL)
|
|
|
- {
|
|
|
- lSize = hFile->dwFileSize;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- FATFree();
|
|
|
-
|
|
|
- return(lSize);
|
|
|
-}
|
|
|
-
|
|
|
-#if 0
|
|
|
-/************************************************************/
|
|
|
-/* FATFileSeek */
|
|
|
-/* */
|
|
|
-/* Move the file pointer to a new position. */
|
|
|
-/* It points to the next byte to be read from a file. */
|
|
|
-/* The file pointer is automatically incremented for */
|
|
|
-/* each byte read. When the file is opened, it is at */
|
|
|
-/* position 0, the beginning of the file. */
|
|
|
-/* */
|
|
|
-/* Parameters: pFile Identifies the file to seek. */
|
|
|
-/* This pointer must have been created by */
|
|
|
-/* calling FAT32FileOpen(). */
|
|
|
-/* */
|
|
|
-/* lPos Specifies the new absolute position */
|
|
|
-/* of the file pointer. */
|
|
|
-/* */
|
|
|
-/* Returns: 0 if the function is successful, */
|
|
|
-/* -1 otherwise. */
|
|
|
-/************************************************************/
|
|
|
-int FATFileSeek(FILE * pFile, long lPos)
|
|
|
-{
|
|
|
- int nError = NUTDEV_ERROR;
|
|
|
- FHANDLE *hFile;
|
|
|
-
|
|
|
- FATLock();
|
|
|
-
|
|
|
- hFile = (FHANDLE *) pFile;
|
|
|
-
|
|
|
- //
|
|
|
- // We must do some work here...
|
|
|
- //
|
|
|
- nError = FAT32_ERROR;
|
|
|
-
|
|
|
- FATFree();
|
|
|
-
|
|
|
- return(nError);
|
|
|
-}
|
|
|
-#endif
|
|
|
-
|
|
|
-/************************************************************/
|
|
|
-/* FATFileRead */
|
|
|
-/* */
|
|
|
-/* Read data from a file. */
|
|
|
-/* */
|
|
|
-/* Parameters: pFile Identifies the file to read from. */
|
|
|
-/* This pointer must have been created by */
|
|
|
-/* calling FAT32FileOpen(). */
|
|
|
-/* */
|
|
|
-/* pData Points to the buffer that receives */
|
|
|
-/* the data. */
|
|
|
-/* */
|
|
|
-/* nSize Specifies the number of bytes to */
|
|
|
-/* read from the file. */
|
|
|
-/* */
|
|
|
-/* Returns: The number of bytes read from the file or */
|
|
|
-/* -1 if an error occured. */
|
|
|
-/************************************************************/
|
|
|
-int FATFileRead(NUTFILE * hNUTFile, void *pData, int nSize)
|
|
|
-{
|
|
|
- int nError;
|
|
|
- int nBytesRead;
|
|
|
- int nBytesToRead;
|
|
|
- FHANDLE *hFile;
|
|
|
- DRIVE_INFO *pDrive;
|
|
|
- BYTE *pByte;
|
|
|
- DWORD dwReadSector;
|
|
|
- DWORD dwSector;
|
|
|
- int nSectorCount;
|
|
|
- int nSectorOffset;
|
|
|
- WORD wSectorSize;
|
|
|
-
|
|
|
- nBytesRead = 0;
|
|
|
-
|
|
|
- FATLock();
|
|
|
-
|
|
|
- hFile = NULL;
|
|
|
- nError = NUTDEV_ERROR;
|
|
|
-
|
|
|
- if (hNUTFile != NULL)
|
|
|
- {
|
|
|
- hFile = (FHANDLE *) hNUTFile->nf_fcb;
|
|
|
- }
|
|
|
-
|
|
|
- if ((hFile != NULL) && (nSize != 0))
|
|
|
- {
|
|
|
- if (hFile->dwFilePointer < hFile->dwFileSize)
|
|
|
- {
|
|
|
-
|
|
|
- if ((hFile->dwFilePointer + nSize) > hFile->dwFileSize)
|
|
|
- {
|
|
|
- nSize = (int) (hFile->dwFileSize - hFile->dwFilePointer);
|
|
|
- }
|
|
|
-
|
|
|
- pDrive = (DRIVE_INFO *) hFile->pDrive;
|
|
|
- pByte = (BYTE *) pData;
|
|
|
-
|
|
|
- nBytesRead = nSize;
|
|
|
- wSectorSize = pDrive->wSectorSize;
|
|
|
-
|
|
|
- while (nSize)
|
|
|
- {
|
|
|
- dwSector = GetFirstSectorOfCluster(pDrive, hFile->dwReadCluster);
|
|
|
- nSectorCount = hFile->dwClusterPointer / wSectorSize;
|
|
|
- nSectorOffset = hFile->dwClusterPointer % wSectorSize;
|
|
|
-
|
|
|
- //
|
|
|
- // (Sector + SectorCount) is the sector to read
|
|
|
- // SectorOffset is the start position in the sector itself
|
|
|
- //
|
|
|
- dwReadSector = dwSector + nSectorCount;
|
|
|
-
|
|
|
- nError = HWReadSectors(pDrive->bDevice, pSectorBuffer, dwReadSector, 1);
|
|
|
- if (nError == HW_OK)
|
|
|
- {
|
|
|
- //
|
|
|
- // Find the size we can read from ONE sector
|
|
|
- //
|
|
|
- if (nSize > (int) wSectorSize)
|
|
|
- {
|
|
|
- nBytesToRead = wSectorSize;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- nBytesToRead = nSize;
|
|
|
- }
|
|
|
-
|
|
|
- //
|
|
|
- // Test inside a sector
|
|
|
- //
|
|
|
- if ((nSectorOffset + nBytesToRead) > (int) wSectorSize)
|
|
|
- {
|
|
|
- nBytesToRead = wSectorSize - nSectorOffset;
|
|
|
- }
|
|
|
-
|
|
|
- memcpy(pByte, &pSectorBuffer[nSectorOffset], nBytesToRead);
|
|
|
- pByte += nBytesToRead;
|
|
|
-
|
|
|
- hFile->dwFilePointer += nBytesToRead;
|
|
|
- hFile->dwClusterPointer += nBytesToRead;
|
|
|
-
|
|
|
- //
|
|
|
- // Check for EOF
|
|
|
- if (hFile->dwFilePointer >= hFile->dwFileSize)
|
|
|
- {
|
|
|
- hFile->nEOF = TRUE;
|
|
|
- }
|
|
|
-
|
|
|
- if (hFile->dwClusterPointer >= pDrive->dwClusterSize)
|
|
|
- {
|
|
|
- //
|
|
|
- // We must switch to the next cluster
|
|
|
- //
|
|
|
- hFile->dwReadCluster = GetNextCluster(pDrive, hFile->dwReadCluster);
|
|
|
- hFile->dwClusterPointer = 0;
|
|
|
- }
|
|
|
-
|
|
|
- nSize -= nBytesToRead;
|
|
|
-
|
|
|
- }
|
|
|
- else
|
|
|
- { /* HWReadSectors Error */
|
|
|
-
|
|
|
- nBytesRead = 0;
|
|
|
- hFile->nLastError = FAT_ERROR_IDE;
|
|
|
- break;
|
|
|
- } /* endif nError == HW_OK */
|
|
|
-
|
|
|
- } /* endwhile */
|
|
|
-
|
|
|
- }
|
|
|
- else
|
|
|
- { /* reached the EOF */
|
|
|
- hFile->nLastError = FAT_ERROR_EOF;
|
|
|
- } /* endif hFile->dwFilePointer < hFile->dwFileSize */
|
|
|
-
|
|
|
- }
|
|
|
- /*
|
|
|
- * endif (hFile != NULL) && (nSize != 0)
|
|
|
- */
|
|
|
- FATFree();
|
|
|
-
|
|
|
- return(nBytesRead);
|
|
|
-}
|
|
|
-
|
|
|
-/************************************************************/
|
|
|
-/* FATFileWrite */
|
|
|
-/* */
|
|
|
-/* Write data to a file. */
|
|
|
-/* */
|
|
|
-/* Parameters: pFile Identifies the file to write to. */
|
|
|
-/* This pointer must have been created by */
|
|
|
-/* calling FAT32FileOpen(). */
|
|
|
-/* */
|
|
|
-/* pData Points to the buffer that holds */
|
|
|
-/* the data. */
|
|
|
-/* */
|
|
|
-/* nSize Specifies the number of bytes to */
|
|
|
-/* write to the file. */
|
|
|
-/* */
|
|
|
-/* Returns: The number of bytes written to the file or */
|
|
|
-/* -1 if an error occured. */
|
|
|
-/************************************************************/
|
|
|
-static int FATFileWrite(NUTFILE * hNUTFile, CONST void *pData, int nSize)
|
|
|
-{
|
|
|
- int nError;
|
|
|
-
|
|
|
- nError = NUTDEV_ERROR;
|
|
|
-
|
|
|
- return(nError);
|
|
|
-}
|
|
|
-
|
|
|
-#ifdef __HARVARD_ARCH__
|
|
|
-static int FATFileWriteP(NUTFILE * hNUTFile, PGM_P pData, int nSize)
|
|
|
-{
|
|
|
- int nError;
|
|
|
-
|
|
|
- nError = NUTDEV_ERROR;
|
|
|
-
|
|
|
- return(nError);
|
|
|
-}
|
|
|
-#endif
|
|
|
-
|
|
|
-/************************************************************/
|
|
|
-/* FATIOCtl */
|
|
|
-/* */
|
|
|
-/* Perform IOCTL control functions. */
|
|
|
-/* */
|
|
|
-/* reg May be set to one of the following constants: */
|
|
|
-/* */
|
|
|
-/* Parameters: dev Identifies the device to use. */
|
|
|
-/* reg Requested control function. */
|
|
|
-/* conf Points to a buffer that contains any */
|
|
|
-/* data required for the given control */
|
|
|
-/* function or receives data from that */
|
|
|
-/* function. */
|
|
|
-/* Returns: 0 on success, or -1 if an error occured. */
|
|
|
-/************************************************************/
|
|
|
-int FATIOCtl(NUTDEVICE *dev, int req, void *conf)
|
|
|
-{
|
|
|
- int nError = NUTDEV_ERROR;
|
|
|
- DRIVE_INFO *pDrive = GetDriveByDevice(dev);
|
|
|
-
|
|
|
- if (pDrive != NULL)
|
|
|
- {
|
|
|
- switch (req)
|
|
|
- {
|
|
|
-
|
|
|
-#if (FAT_SUPPORT_FORMAT >= 1)
|
|
|
- case FAT_IOCTL_QUICK_FORMAT: {
|
|
|
- nError = QuickFormat(dev, pDrive);
|
|
|
- break;
|
|
|
- }
|
|
|
-#endif
|
|
|
-
|
|
|
- default: {
|
|
|
- nError = NUTDEV_ERROR;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return(nError);
|
|
|
-}
|
|
|
-
|
|
|
-//
|
|
|
-// FAT Device information structure.
|
|
|
-// Is mapped to the FAT-Device.
|
|
|
-// The user MUST first register the FAT hardware.
|
|
|
-//
|
|
|
-NUTDEVICE devFAT = {
|
|
|
- 0, /* Pointer to next device. */
|
|
|
-
|
|
|
- /*
|
|
|
- * Unique device name.
|
|
|
- */
|
|
|
- {'F', 'A', 'T', 0, 0, 0, 0, 0, 0},
|
|
|
-
|
|
|
- IFTYP_STREAM, /* Type of device. */
|
|
|
- 2, /* Base address. */
|
|
|
- 0, /* First interrupt number. */
|
|
|
- 0, /* Interface control block. */
|
|
|
- 0, /* Driver control block. */
|
|
|
- FATInit, /* Driver initialization routine. */
|
|
|
- 0, /* Driver specific control function. */
|
|
|
- 0, /* Driver specific read function. */
|
|
|
- 0, /* Driver specific write function. */
|
|
|
-
|
|
|
-#ifdef __HARVARD_ARCH__
|
|
|
- 0, /* Driver specific write_p function. */
|
|
|
-#endif
|
|
|
-
|
|
|
- 0, /* Driver specific open function. */
|
|
|
- 0, /* Driver specific close function. */
|
|
|
- 0
|
|
|
-};
|
|
|
-
|
|
|
-#if (FAT_USE_MMC_INTERFACE >= 1)
|
|
|
-//
|
|
|
-// FATUSB Device information structure.
|
|
|
-// Is mapped to the first USB drive
|
|
|
-//
|
|
|
-NUTDEVICE devFATMMC0 = {
|
|
|
- 0, /* Pointer to next device. */
|
|
|
-
|
|
|
- /*
|
|
|
- * Unique device name.
|
|
|
- */
|
|
|
- {'F', 'M', '0', 0, 0, 0, 0, 0, 0},
|
|
|
-
|
|
|
- IFTYP_STREAM, /* Type of device. */
|
|
|
- 2, /* Base address. */
|
|
|
- 0, /* First interrupt number. */
|
|
|
- 0, /* Interface control block. */
|
|
|
- 0, /* Driver control block. */
|
|
|
- FATInit, /* Driver initialization routine. */
|
|
|
- FATIOCtl, /* Driver specific control function. */
|
|
|
- FATFileRead, /* Driver specific read function. */
|
|
|
- FATFileWrite, /* Driver specific write function. */
|
|
|
-
|
|
|
-#ifdef __HARVARD_ARCH__
|
|
|
- FATFileWriteP, /* Driver specific write_p function. */
|
|
|
-#endif
|
|
|
-
|
|
|
- FATFileOpen, /* Driver specific open function. */
|
|
|
- FATFileClose, /* Driver specific close function. */
|
|
|
- FATFileSize
|
|
|
-};
|
|
|
-#endif /* (FAT_USE_MMC_INTERFACE >= 1) */
|
|
|
-
|
|
|
-
|
|
|
-#if (FAT_SUPPORT_FORMAT >= 1)
|
|
|
-/************************************************************/
|
|
|
-/* GetClusterSize */
|
|
|
-/************************************************************/
|
|
|
-static BYTE GetClusterSize (DWORD dTotalSectors)
|
|
|
-{
|
|
|
- BYTE bIndex;
|
|
|
- BYTE bSecPerClus = 0;
|
|
|
-
|
|
|
- for (bIndex=0; bIndex<DSK_TABLE_FAT32_ENTRY_COUNT; bIndex++)
|
|
|
- {
|
|
|
- if (dTotalSectors <= DskTableFAT32[bIndex].DiskSize)
|
|
|
- {
|
|
|
- bSecPerClus = DskTableFAT32[bIndex].SecPerClusVal;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return(bSecPerClus);
|
|
|
-}
|
|
|
-
|
|
|
-/************************************************************/
|
|
|
-/* QuickFormat */
|
|
|
-/************************************************************/
|
|
|
-static int QuickFormat(NUTDEVICE *dev, DRIVE_INFO *pDrive)
|
|
|
-{
|
|
|
- DWORD i;
|
|
|
- int nError = NUTDEV_ERROR;
|
|
|
- BYTE *pBuffer;
|
|
|
- BYTE bDevice;
|
|
|
- BYTE bSecPerClus;
|
|
|
- DWORD dSector;
|
|
|
- DWORD dFirstDataSector;
|
|
|
- DWORD dLastDataSector;
|
|
|
- DWORD dMaxClusterCount;
|
|
|
- DWORD dFAT1StartSector=0;
|
|
|
- DWORD dFAT2StartSector=0;
|
|
|
- DWORD dCluster2StartSector;
|
|
|
- DWORD dClearCount;
|
|
|
- DWORD dTotalSectors;
|
|
|
- DWORD dPossibleClusterCount;
|
|
|
- DWORD dFATSz32;
|
|
|
- FAT32_PARTITION_TABLE *pPartitionTable;
|
|
|
- FAT32_BOOT_RECORD *pBootRecord;
|
|
|
- FAT32_FSINFO *pFSInfo;
|
|
|
- FAT32_DIRECTORY_ENTRY *pDirEntry;
|
|
|
- LONG *pLong;
|
|
|
- DWORD dVollID;
|
|
|
-
|
|
|
- FATLock();
|
|
|
-
|
|
|
- /*
|
|
|
- * Get the sector buffer
|
|
|
- */
|
|
|
- pBuffer = (u_char *)NutHeapAlloc(pDrive->wSectorSize);
|
|
|
- if (pBuffer != NULL)
|
|
|
- {
|
|
|
-
|
|
|
- bDevice = pDrive->bDevice;
|
|
|
- dTotalSectors = HWGetTotalSectors(bDevice);
|
|
|
- dTotalSectors -= BPB_RsvdSecCnt;
|
|
|
-
|
|
|
- bSecPerClus = GetClusterSize(dTotalSectors);
|
|
|
- if (bSecPerClus == 0)
|
|
|
- {
|
|
|
- /*
|
|
|
- * Sorry, to small for FAT32,
|
|
|
- * the lib will support FAT16 later....
|
|
|
- */
|
|
|
- NutHeapFree(pBuffer);
|
|
|
- return(NUTDEV_ERROR);
|
|
|
- }
|
|
|
-
|
|
|
- dPossibleClusterCount = (dTotalSectors / (LONG)bSecPerClus);
|
|
|
-
|
|
|
- dFATSz32 = (dPossibleClusterCount * sizeof(long) +
|
|
|
- (FAT32_SECTOR_SIZE -1) ) / FAT32_SECTOR_SIZE;
|
|
|
-
|
|
|
- /*
|
|
|
- * First we will clear the sectors which we will use
|
|
|
- * for the MBR, BPB and the FA's.
|
|
|
- */
|
|
|
- dClearCount = BPB_HiddSec + BPB_RsvdSecCnt;
|
|
|
- dClearCount += (BPB_NumFATs * dFATSz32) + bSecPerClus;
|
|
|
-
|
|
|
- memset(pBuffer, 0x00, pDrive->wSectorSize);
|
|
|
- for (i=0; i<dClearCount; i++)
|
|
|
- {
|
|
|
- nError = HWWriteSectors(bDevice, pBuffer, i, 1);
|
|
|
- if (nError != HW_OK)
|
|
|
- {
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /*
|
|
|
- * Create the Volume serial number,
|
|
|
- * we have no random value, therefore
|
|
|
- * use the dTotalSectors and time.
|
|
|
- */
|
|
|
- dVollID = (DWORD)time(NULL) * dTotalSectors;
|
|
|
-
|
|
|
- /*
|
|
|
- * Create MBR (MasterBootRecord)
|
|
|
- */
|
|
|
- memset(pBuffer, 0x00, pDrive->wSectorSize);
|
|
|
- pPartitionTable = (FAT32_PARTITION_TABLE *)pBuffer;
|
|
|
-
|
|
|
- pPartitionTable->Partition[0].BootInd = 0x00;
|
|
|
- pPartitionTable->Partition[0].FirstHead = 1;
|
|
|
- pPartitionTable->Partition[0].FirstSector = 1;
|
|
|
- pPartitionTable->Partition[0].FirstTrack = 0;
|
|
|
- pPartitionTable->Partition[0].FileSystem = MBR_FAT32;
|
|
|
- pPartitionTable->Partition[0].LastHead = 0;
|
|
|
- pPartitionTable->Partition[0].LastSector = 0;
|
|
|
- pPartitionTable->Partition[0].StartSectors = BPB_HiddSec;
|
|
|
- pPartitionTable->Partition[0].NumSectors = dTotalSectors;
|
|
|
- pPartitionTable->Signature = MBR_SIGNATURE;
|
|
|
-
|
|
|
- /*
|
|
|
- * Write the MBR to the drive
|
|
|
- */
|
|
|
- nError = HWWriteSectors(bDevice, pBuffer, 0, 1);
|
|
|
- if (nError == HW_OK)
|
|
|
- {
|
|
|
- /*
|
|
|
- * Create the BPB
|
|
|
- */
|
|
|
- memset(pBuffer, 0x00, pDrive->wSectorSize);
|
|
|
- pBootRecord = (FAT32_BOOT_RECORD *)pBuffer;
|
|
|
-
|
|
|
- pBootRecord->JumpBoot[0] = 0xEB;
|
|
|
- pBootRecord->JumpBoot[1] = 0x58;
|
|
|
- pBootRecord->JumpBoot[2] = 0x90;
|
|
|
-
|
|
|
- pBootRecord->OEMName[0] = 'M';
|
|
|
- pBootRecord->OEMName[1] = 'S';
|
|
|
- pBootRecord->OEMName[2] = 'D';
|
|
|
- pBootRecord->OEMName[3] = 'O';
|
|
|
- pBootRecord->OEMName[4] = 'S';
|
|
|
- pBootRecord->OEMName[5] = '5';
|
|
|
- pBootRecord->OEMName[6] = '.';
|
|
|
- pBootRecord->OEMName[7] = '0';
|
|
|
-
|
|
|
- pBootRecord->BytsPerSec = FAT32_SECTOR_SIZE;
|
|
|
- pBootRecord->SecPerClus = bSecPerClus;
|
|
|
- pBootRecord->RsvdSecCnt = BPB_RsvdSecCnt;
|
|
|
- pBootRecord->NumFATs = BPB_NumFATs;
|
|
|
- pBootRecord->RootEntCnt = 0;
|
|
|
- pBootRecord->TotSec16 = 0;
|
|
|
- pBootRecord->Media = FAT32_MEDIA;
|
|
|
-
|
|
|
- pBootRecord->FATSz16 = 0;
|
|
|
- pBootRecord->SecPerTrk = 63;
|
|
|
- pBootRecord->NumHeads = 255;
|
|
|
-
|
|
|
- pBootRecord->HiddSec = BPB_HiddSec;
|
|
|
- pBootRecord->TotSec32 = dTotalSectors;
|
|
|
-
|
|
|
- pBootRecord->Off36.FAT32.FATSz32 = dFATSz32;
|
|
|
- pBootRecord->Off36.FAT32.ExtFlags = 0;
|
|
|
- pBootRecord->Off36.FAT32.FSVer = 0;
|
|
|
- pBootRecord->Off36.FAT32.RootClus = 2;
|
|
|
- pBootRecord->Off36.FAT32.FSInfo = FAT32_OFFSET_FSINFO;
|
|
|
- pBootRecord->Off36.FAT32.BkBootSec = FAT32_OFFSET_BACKUP_BOOT;
|
|
|
-
|
|
|
- pBootRecord->Off36.FAT32.DrvNum = 0x00;
|
|
|
- pBootRecord->Off36.FAT32.BootSig = 0x29;
|
|
|
- pBootRecord->Off36.FAT32.VollID = dVollID;
|
|
|
- pBootRecord->Off36.FAT32.VolLab[0] = 'N';
|
|
|
- pBootRecord->Off36.FAT32.VolLab[1] = 'O';
|
|
|
- pBootRecord->Off36.FAT32.VolLab[2] = ' ';
|
|
|
- pBootRecord->Off36.FAT32.VolLab[3] = 'N';
|
|
|
- pBootRecord->Off36.FAT32.VolLab[4] = 'A';
|
|
|
- pBootRecord->Off36.FAT32.VolLab[5] = 'M';
|
|
|
- pBootRecord->Off36.FAT32.VolLab[6] = 'E';
|
|
|
- pBootRecord->Off36.FAT32.VolLab[7] = ' ';
|
|
|
- pBootRecord->Off36.FAT32.VolLab[8] = ' ';
|
|
|
- pBootRecord->Off36.FAT32.VolLab[9] = ' ';
|
|
|
- pBootRecord->Off36.FAT32.VolLab[10] = ' ';
|
|
|
-
|
|
|
- pBootRecord->Off36.FAT32.FilSysType[0] = 'F';
|
|
|
- pBootRecord->Off36.FAT32.FilSysType[1] = 'A';
|
|
|
- pBootRecord->Off36.FAT32.FilSysType[2] = 'T';
|
|
|
- pBootRecord->Off36.FAT32.FilSysType[3] = '3';
|
|
|
- pBootRecord->Off36.FAT32.FilSysType[4] = '2';
|
|
|
- pBootRecord->Off36.FAT32.FilSysType[5] = ' ';
|
|
|
- pBootRecord->Off36.FAT32.FilSysType[6] = ' ';
|
|
|
- pBootRecord->Off36.FAT32.FilSysType[7] = ' ';
|
|
|
-
|
|
|
- pBootRecord->Signature = FAT_SIGNATURE;
|
|
|
-
|
|
|
- /*
|
|
|
- * Write the BPB to the drive
|
|
|
- */
|
|
|
- dSector = BPB_HiddSec;
|
|
|
- nError = HWWriteSectors(bDevice, pBuffer, dSector, 1);
|
|
|
- if (nError == HW_OK)
|
|
|
- {
|
|
|
- dSector += FAT32_OFFSET_BACKUP_BOOT;
|
|
|
- nError = HWWriteSectors(bDevice, pBuffer, dSector, 1);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /*
|
|
|
- * Create the FSINFO
|
|
|
- */
|
|
|
- if (nError == HW_OK)
|
|
|
- {
|
|
|
- memset(pBuffer, 0x00, pDrive->wSectorSize);
|
|
|
- pFSInfo = (FAT32_FSINFO *)pBuffer;
|
|
|
-
|
|
|
- dFirstDataSector = BPB_HiddSec + BPB_RsvdSecCnt;
|
|
|
- dLastDataSector = dTotalSectors;
|
|
|
- dMaxClusterCount = dLastDataSector - dFirstDataSector;
|
|
|
- dMaxClusterCount = dMaxClusterCount / (LONG)bSecPerClus;
|
|
|
-
|
|
|
- pFSInfo->FirstSignature = FSINFO_FIRSTSIGNATURE;
|
|
|
- pFSInfo->FSInfoSignature = FSINFO_FSINFOSIGNATURE;
|
|
|
- pFSInfo->NumberOfFreeClusters = dMaxClusterCount;
|
|
|
- pFSInfo->MostRecentlyAllocatedCluster = 2;
|
|
|
- pFSInfo->Signature = FSINFO_SIGNATURE;
|
|
|
-
|
|
|
- /*
|
|
|
- * Write the FSINFO to the drive
|
|
|
- */
|
|
|
- dSector = BPB_HiddSec + FAT32_OFFSET_FSINFO;
|
|
|
- nError = HWWriteSectors(bDevice, pBuffer, dSector, 1);
|
|
|
- }
|
|
|
-
|
|
|
- /*
|
|
|
- * Write first FAT entry after format.
|
|
|
- */
|
|
|
- if (nError == HW_OK)
|
|
|
- {
|
|
|
- dFAT1StartSector = BPB_HiddSec + BPB_RsvdSecCnt;
|
|
|
- dFAT2StartSector = dFAT1StartSector + dFATSz32;
|
|
|
-
|
|
|
- memset(pBuffer, 0x00, pDrive->wSectorSize);
|
|
|
- pLong = (LONG *)pBuffer;
|
|
|
-
|
|
|
- /*
|
|
|
- * Set the two reserved cluster after the format,
|
|
|
- * take a look in the MS Hardware White Paper
|
|
|
- * Version 1.03, December 6, 2000 for more information.
|
|
|
- */
|
|
|
- *pLong++ = 0x0FFFFFF8;
|
|
|
- *pLong++ = FAT32_CLUSTER_EOF;
|
|
|
- *pLong++ = FAT32_CLUSTER_EOF;
|
|
|
-
|
|
|
- nError = HWWriteSectors(bDevice, pBuffer, dFAT1StartSector, 1);
|
|
|
- if (nError == HW_OK)
|
|
|
- {
|
|
|
- nError = HWWriteSectors(bDevice, pBuffer, dFAT2StartSector, 1);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /*
|
|
|
- * Create RootDir
|
|
|
- */
|
|
|
- if (nError == HW_OK)
|
|
|
- {
|
|
|
- memset(pBuffer, 0x00, pDrive->wSectorSize);
|
|
|
- pDirEntry = (FAT32_DIRECTORY_ENTRY *)pBuffer;
|
|
|
-
|
|
|
- pDirEntry->Name[0] = 'E';
|
|
|
- pDirEntry->Name[1] = 'T';
|
|
|
- pDirEntry->Name[2] = 'H';
|
|
|
- pDirEntry->Name[3] = 'E';
|
|
|
- pDirEntry->Name[4] = 'R';
|
|
|
- pDirEntry->Name[5] = 'N';
|
|
|
- pDirEntry->Name[6] = 'U';
|
|
|
- pDirEntry->Name[7] = 'T';
|
|
|
-
|
|
|
- pDirEntry->Extension[0] = ' ';
|
|
|
- pDirEntry->Extension[1] = ' ';
|
|
|
- pDirEntry->Extension[2] = ' ';
|
|
|
-
|
|
|
- pDirEntry->Attribute = DIRECTORY_ATTRIBUTE_VOLUME_ID;
|
|
|
- pDirEntry->HighCluster = 0;
|
|
|
- pDirEntry->LowCluster = 0;
|
|
|
- pDirEntry->FileSize = 0;
|
|
|
-
|
|
|
- dCluster2StartSector = dFAT2StartSector + dFATSz32;
|
|
|
- nError = HWWriteSectors(bDevice, pBuffer, dCluster2StartSector, 1);
|
|
|
- }
|
|
|
-
|
|
|
- NutHeapFree(pBuffer);
|
|
|
-
|
|
|
- FATFree();
|
|
|
-
|
|
|
-
|
|
|
- /*
|
|
|
- * Don't forget to mount the drive
|
|
|
- */
|
|
|
- if (nError == HW_OK)
|
|
|
- {
|
|
|
- nError = MountDrive(bDevice);
|
|
|
- }
|
|
|
-
|
|
|
- if (nError == HW_OK)
|
|
|
- {
|
|
|
- nError = NUTDEV_OK;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- nError = NUTDEV_ERROR;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return(nError);
|
|
|
-}
|
|
|
-#endif /* (FAT_SUPPORT_FORMAT >= 1) */
|
|
|
-
|