www.pudn.com > File_SD_OS.rar > disk.C


/****************************************Copyright (c)************************************************** 
**                               广州周立功单片机发展有限公司 
**                                     研    究    所 
**                                        ARM开发组 
** 
**                                 http://www.zlgmcu.com 
** 
**--------------文件信息-------------------------------------------------------------------------------- 
**文   件   名: disk.c 
**创   建   人: 陈明计 
**最后修改日期: 2003年9月3日 
**描        述: FAT文件系统关于逻辑盘管理的部分 
**               
**--------------历史版本信息---------------------------------------------------------------------------- 
** 创建人: 陈明计 
** 版  本: V1.0 
** 日 期: 2003年9月3日 
** 描 述: 原始版本 
** 
**--------------当前版本修订------------------------------------------------------------------------------ 
** 修改人: 陈明计 
** 日 期: 2004年4月10日 
** 描 述: 增加注释 
** 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
#define IN_DISK 
#include "config.h" 
Disk_Info DiskInfo[MAX_DRIVES];     //逻辑盘信息 
 
/********************************************************************************************************* 
** 函数名称: DiskInit 
** 功能描述: 初始化逻辑盘管理模块 
** 
** 输 入: 无 
** 
** 输 出: 无 
**          
** 全局变量: DiskInfo 
** 调用模块: 无 
** 
** 作 者: 陈明计 
** 日 期: 2003年9月3日 
**------------------------------------------------------------------------------------------------------- 
** 修改人: 陈明计 
** 日 期: 2004年4月10日 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
        void DiskInit(void) 
{ 
    uint8 i; 
     
    for (i = 0; i < MAX_DRIVES; i++) 
    { 
        DiskInfo[i].Drive = EMPTY_DRIVE;    // 没有分配 
        DiskInfo[i].FATType = 0xff;         // 无效的文件系统 
        DiskInfo[i].SecPerClus = 0;         // 每簇扇区数 
        DiskInfo[i].NumFATs = 0;            // FAT表数 
        DiskInfo[i].SecPerDisk = 0xffffffff;// 逻辑驱动器包含扇区数 
        DiskInfo[i].BytsPerSec = 0;         // 每扇区字节数 
        DiskInfo[i].RootDirTable = 0;       // 根目录开始扇区号(FAT32为开始簇号) 
        DiskInfo[i].RootSecCnt = 0;         // 根目录占用扇区数 
        DiskInfo[i].FATStartSec = 0;        // FAT表开始扇区号 
        DiskInfo[i].FATSecCnt = 0;          // 每个FAT占用扇区数 
        DiskInfo[i].DataStartSec = 0;       // 数据区开始扇区号 
        DiskInfo[i].PathClusIndex = 0;      // 当前目录 
        DiskInfo[i].DiakCommand = NULL;     // 驱动程序 
    } 
    CacheInit();                //初始化磁盘cache 
} 
 
/********************************************************************************************************* 
** 函数名称: GetDiskInfo 
** 功能描述: 获取指定逻辑盘信息 
** 
** 输 入: 逻辑盘号 
** 
** 输 出: 指向逻辑盘信息的结构体指针 
**          
** 全局变量: DiskInfo 
** 调用模块: 无 
** 
** 作 者: 陈明计 
** 日 期: 2003年9月3日 
**------------------------------------------------------------------------------------------------------- 
** 修改人: 
** 日 期: 
 
 
 
 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
        Disk_Info * GetDiskInfo(uint8 Drive) 
{ 
    Disk_Info *Rt; 
    Rt = NULL; 
    if (Drive < MAX_DRIVES) 
    if (DiskInfo[Drive].Drive < MAX_DRIVES) 
    { 
        Rt = DiskInfo + Drive; 
    } 
    return Rt; 
} 
 
/********************************************************************************************************* 
** 函数名称: GetDiskInfo2 
** 功能描述: 获取指定逻辑盘信息(不判断) 
** 
** 输 入: 逻辑盘号 
** 
** 输 出: 指向逻辑盘信息的结构体指针 
**          
** 全局变量: DiskInfo 
** 调用模块: 无 
** 
** 作 者: 陈明计 
** 日 期: 2003年9月3日 
**------------------------------------------------------------------------------------------------------- 
** 修改人: 
** 日 期: 
 
 
 
 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
        Disk_Info * GetDiskInfo2(uint8 Drive) 
{ 
    Disk_Info *Rt; 
    Rt = NULL; 
    if (Drive < MAX_DRIVES) 
    if (DiskInfo[Drive].Drive != EMPTY_DRIVE ) 
    { 
        Rt = DiskInfo + Drive; 
    } 
    return Rt; 
} 
 
/********************************************************************************************************* 
** 函数名称: GetEmptyDiskInfoAddr 
** 功能描述: 获取空闲逻辑盘 
** 
** 输 入: 无 
** 
** 输 出: 指向逻辑盘信息的结构体指针 
**          
** 全局变量: DiskInfo 
** 调用模块: 无 
** 
** 作 者: 陈明计 
** 日 期: 2003年9月3日 
**------------------------------------------------------------------------------------------------------- 
** 修改人: 
** 日 期: 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
        Disk_Info * GetEmptyDiskInfoAddr(void) 
{ 
    uint8 i; 
    Disk_Info *Rt; 
     
    Rt = NULL; 
    for (i = 0; i < MAX_DRIVES; i++) 
    { 
        if (DiskInfo[i].Drive == EMPTY_DRIVE)     // 逻辑盘号空闲 
        { 
            Rt = DiskInfo + i; 
            DiskInfo[i].Drive = i; 
            break; 
        } 
    } 
    return Rt; 
} 
 
/********************************************************************************************************* 
** 函数名称: FsMount 
** 功能描述: 内部加载卷 
** 
** 输 入: Disk:逻辑盘信息指针 
**         Buf:扇区0内容 
** 输 出: RETURN_OK:成功 
**        其它参考fat.h中关于返回值的说明 
** 
** 作 者: 陈明计 
** 日 期: 2004年12月31日 
**------------------------------------------------------------------------------------------------------- 
** 修改人: 
** 日 期: 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
        uint8 FsMount(Disk_Info *Disk, uint8 *Buf) 
{ 
    unsigned int temp; 
    uint32 temp1; 
     
    if (Buf[510] != 0x55 || Buf[511] != 0xaa)      /* 有效标志 */ 
    { 
        Disk->Drive = UN_MOUNT_DRIVE; 
        return DISK_NO_FORMAT; 
    } 
    if (Buf[21] != 0xF0) 
    if (Buf[21] < 0xF8) 
    { 
        Disk->Drive = UN_MOUNT_DRIVE; 
        return DISK_NO_FORMAT; 
    } 
     
    /* 每扇区字节数 */ 
    Disk->BytsPerSec = Buf[11] | (Buf[12] << 8); 
    /* 每簇扇区数 */ 
    Disk->SecPerClus = Buf[13]; 
    /* FAT开始扇区号 */ 
    Disk->FATStartSec = Buf[14] | (Buf[15] << 8); 
    /* FAT表个数 */ 
    Disk->NumFATs = Buf[16]; 
    /* 根目录占扇区数 */  
    Disk->RootSecCnt = ((Buf[17] | (Buf[18] << 8)) * 32 +  
                               Disk->BytsPerSec - 1) / 
                               Disk->BytsPerSec; 
 
    /* 逻辑盘(卷)占扇区数 */ 
    temp = Buf[19] | (Buf[20] << 8); 
    if (temp != 0) 
    { 
        Disk->SecPerDisk = temp; 
    } 
    else 
    { 
        Disk->SecPerDisk = Buf[32] | (Buf[33] << 8); 
        Disk->SecPerDisk |= (((uint32)Buf[34] << 16) | ((uint32)Buf[35] << 24)); 
    } 
    /* FAT表占用扇区数 */ 
    temp = Buf[22] | (Buf[23] << 8); 
    if (temp != 0) 
    { 
        Disk->FATSecCnt = temp; 
    } 
    else 
    { 
        Disk->FATSecCnt = Buf[36] | (Buf[37] << 8); 
        Disk->FATSecCnt |= (((uint32)Buf[38] << 16) | (uint32)(Buf[39] << 24)); 
    } 
                 
    /* 当前目录为根目录 */ 
    Disk->PathClusIndex = 0; 
    /* 根目录开始扇区号 */ 
    Disk->RootDirTable = Disk->NumFATs * Disk->FATSecCnt +  
                               Disk->FATStartSec; 
    /* 数据区开始扇区号 */ 
    Disk->DataStartSec = Disk->RootDirTable + Disk->RootSecCnt; 
    temp1 = Disk->SecPerDisk - Disk->DataStartSec; 
    temp1 = temp1 / Disk->SecPerClus; 
    Disk->ClusPerData = temp1; 
    /* 判断是FAT12、FAT16还是FAT32 */ 
    if (temp1 < 4085) 
    { 
        Disk->FATType = FAT12; 
    } 
    else if (temp1 < 65525) 
    { 
        Disk->FATType = FAT16; 
    } 
    else 
    { 
        Disk->FATType = FAT32; 
        /* FAT32 RootDirTable为开始簇号 */ 
        Disk->RootDirTable = Buf[44] | (Buf[45] << 8); 
        Disk->RootDirTable |= (((uint32)Buf[46] << 16) | ((uint32)Buf[47] << 24)); 
        Disk->PathClusIndex = Disk->RootDirTable; 
    } 
    Disk->Drive = Disk - DiskInfo; 
    return RETURN_OK; 
} 
 
 
/********************************************************************************************************* 
** 函数名称: FsUMount 
** 功能描述: 卸载卷 
** 
** 输 入: Disk:逻辑盘信息指针 
**         Buf:逻辑扇区0内容 
** 输 出: RETURN_OK:成功 
**        其它参考fat.h中关于返回值的说明 
** 
** 作 者: 陈明计 
** 日 期: 2004年12月31日 
**------------------------------------------------------------------------------------------------------- 
** 修改人: 陈明计 
** 日 期: 2005年2月2日 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
        uint8 FsUMount(uint8 Drive) 
{ 
    if (Drive < MAX_DRIVES) 
    { 
        FreeDriveCache(Drive); 
        DiskInfo[Drive].Drive = UN_MOUNT_DRIVE; 
        return RETURN_OK; 
    } 
    else 
    { 
        return NOT_FIND_DISK; 
    } 
} 
 
/********************************************************************************************************* 
** 函数名称: FloppyDiskInit 
** 功能描述: 软盘格式硬件初始化 
** 
** 输 入: DiakCommand:驱动程序接口函数 
**         RsvdForLow:保留给底层的指针 
**         Buf:逻辑扇区0内容 
**         SecOffset:逻辑扇区偏移 
** 输 出: 无 
**          
** 作 者: 陈明计 
** 日 期: 2004年12月31日 
**------------------------------------------------------------------------------------------------------- 
** 修改人: 
** 日 期: 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
        static void FloppyDiskInit(uint16  (* DiakCommand)(uint8 Cammand, void *Parameter), 
                                   void *RsvdForLow , uint8 *Buf, uint32 SecOffset) 
{ 
    Disk_Info *Disk; 
 
    Disk = GetEmptyDiskInfoAddr(); 
    if (Disk == NULL) 
    { 
        return; 
    } 
   	Disk->DiakCommand = DiakCommand; 
   	Disk->SecOffset = SecOffset; 
   	Disk->RsvdForLow = RsvdForLow; 
 
    FsMount(Disk, Buf); 
} 
 
/********************************************************************************************************* 
** 函数名称: HardDiskInit 
** 功能描述: 硬盘格式硬件初始化 
** 
** 输 入: DiakCommand:驱动程序接口函数 
**         RsvdForLow:保留给底层的指针 
**         Buf:扇区0内容 
** 输 出: 无 
**          
** 作 者: 陈明计 
** 日 期: 2004年12月31日 
**------------------------------------------------------------------------------------------------------- 
** 修改人: 
** 日 期: 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
static void HardDiskInit(uint16  (* DiakCommand)(uint8 Cammand, void *Parameter), 
                                 void *RsvdForLow, uint8 *Buf, uint32 SecOffset); 
 
        static void _HardDiskInit(uint16  (* DiakCommand)(uint8 Cammand, void *Parameter), 
                                 void *RsvdForLow , uint8 *Buf, uint32 SecOffset, uint16 offset) 
{ 
    uint32 temp1, temp2; 
    Disk_RW_Parameter Pa; 
     
    Pa.SectorIndex = SecOffset; 
    Pa.RsvdForLow = RsvdForLow; 
    Pa.Buf = Buf; 
    if(DiakCommand(DISK_READ_SECTOR, &Pa) != DISK_READ_OK) 
    { 
        return; 
    } 
 
    if (Buf[510] != 0x55 || Buf[511] != 0xaa)       /* 有效标志 */ 
    { 
        FloppyDiskInit(DiakCommand, RsvdForLow, Buf, SecOffset); 
        return; 
    } 
     
    if (Buf[0x1be] == 0x80 || Buf[0x1be] == 0x00)    /* 第1分区表有效 */ 
    if (Buf[0x1ce] == 0x80 || Buf[0x1ce] == 0x00)    /* 第2分区表有效 */ 
    if (Buf[0x1de] == 0x80 || Buf[0x1de] == 0x00)    /* 第3分区表有效 */ 
    if (Buf[0x1ee] == 0x80 || Buf[0x1ee] == 0x00)    /* 第4分区表有效 */ 
    { 
        temp1 = Buf[0x1be] + Buf[0x1ce] + Buf[0x1de] + Buf[0x1ee]; 
        if (temp1 != 0 && temp1 != 0x80) 
        { 
            FloppyDiskInit(DiakCommand, RsvdForLow, Buf, SecOffset); 
            return; 
        } 
    } 
 
    switch (Buf[offset + 4])    /* 第1分区 */ 
    { 
        case 0x01:              /* FAT12*/ 
        #if 0 
            break; 
        #endif 
        case 0x04:              /* FAT16*/ 
        #if 0 
            break; 
        #endif 
        case 0x06:              /* FAT16*/ 
        #if 0 
            break; 
        #endif 
        case 0x0b:              /* FAT32*/ 
        #if 0 
            break; 
        #endif 
        case 0x0c:              /* FAT32*/ 
        #if 0 
            break; 
        #endif 
        case 0x0e:              /* FAT16*/ 
        #if 0 
            break; 
        #endif 
        case 0x1b:              /* FAT32*/ 
        #if 0 
            break; 
        #endif 
        case 0x1c:              /* FAT32*/ 
            temp1 = Buf[offset + 8] | (Buf[offset + 9] << 8); 
            temp2 = ((uint32)(Buf[offset + 10] | (Buf[offset + 11] << 8))) << 16; 
            temp1 = temp1 | temp2; 
             
            SecOffset = temp1 + SecOffset; 
 
            Pa.SectorIndex = SecOffset; 
            Pa.RsvdForLow = RsvdForLow; 
            Pa.Buf = Buf; 
            if(DiakCommand(DISK_READ_SECTOR, &Pa) != DISK_READ_OK) 
            { 
                return; 
            } 
 
            FloppyDiskInit(DiakCommand, RsvdForLow, Buf, SecOffset); 
            break; 
        case 0x05:              /* 扩展分区 */ 
        #if 0 
            break; 
        #endif 
        case 0x0f:              /* 扩展分区 */ 
            temp1 = Buf[offset + 8] | (Buf[offset + 9] << 8); 
            temp2 = ((uint32)(Buf[offset + 10] | (Buf[offset + 11] << 8))) << 16; 
            temp1 = temp1 | temp2; 
            HardDiskInit(DiakCommand, RsvdForLow, Buf, SecOffset + temp1); 
            break; 
        default: 
            break; 
    } 
} 
 
        static void HardDiskInit(uint16  (* DiakCommand)(uint8 Cammand, void *Parameter), 
                                 void *RsvdForLow, uint8 *Buf, uint32 SecOffset) 
{ 
    _HardDiskInit(DiakCommand, RsvdForLow, Buf, SecOffset, 0x1be);   /* 第1个分区 */ 
    _HardDiskInit(DiakCommand, RsvdForLow, Buf, SecOffset, 0x1ce);   /* 第2个分区 */ 
    _HardDiskInit(DiakCommand, RsvdForLow, Buf, SecOffset, 0x1de);   /* 第3个分区 */ 
    _HardDiskInit(DiakCommand, RsvdForLow, Buf, SecOffset, 0x1ee);   /* 第4个分区 */ 
} 
/********************************************************************************************************* 
** 函数名称: AddFileDriver 
** 功能描述: 增加一个底层驱动程序 
** 
** 输 入: DiakCommand:驱动程序接口函数 
** 
** 输 出: 无 
**          
** 全局变量: DiskInfo 
** 调用模块: 无 
** 
** 作 者: 陈明计 
** 日 期: 2003年9月5日 
**------------------------------------------------------------------------------------------------------- 
** 修改人: 陈明计 
** 日 期: 2004年4月10日 
**------------------------------------------------------------------------------------------------------ 
 
 
 
********************************************************************************************************/ 
        void AddFileDriver(uint16  (* DiakCommand)(uint8 Cammand, void *Parameter), void *RsvdForLow) 
{ 
    unsigned int temp; 
    uint8 Buf[DISK_CACHE_SIZE]; 
    Disk_RW_Parameter Pa; 
     
    if (DiakCommand == NULL)        // 参数无效退出 
    { 
        return; 
    } 
 
    Pa.SectorIndex = 0; 
    Pa.RsvdForLow = RsvdForLow; 
    Pa.Buf = Buf; 
    if (DiakCommand(DISK_INIT, &Pa) == DISK_INIT_NOT_OK)   // 底层驱动初始化不成功退出 
    { 
        return; 
    } 
 
    Pa.SectorIndex = 0; 
    Pa.RsvdForLow = RsvdForLow; 
    Pa.Buf = Buf; 
    if(DiakCommand(DISK_READ_SECTOR, &Pa) != DISK_READ_OK) 
    { 
        return; 
    } 
 
    if (Buf[510] == 0x55 && Buf[511] == 0xaa)        /* 有效标志 */ 
    if (Buf[0x1be] == 0x80 || Buf[0x1be] == 0x00)    /* 第1分区表有效 */ 
    if (Buf[0x1ce] == 0x80 || Buf[0x1ce] == 0x00)    /* 第2分区表有效 */ 
    if (Buf[0x1de] == 0x80 || Buf[0x1de] == 0x00)    /* 第3分区表有效 */ 
    if (Buf[0x1ee] == 0x80 || Buf[0x1ee] == 0x00)    /* 第4分区表有效 */ 
    { 
        temp = Buf[0x1be] + Buf[0x1ce] + Buf[0x1de] + Buf[0x1ee]; 
        if (temp == 0 || temp == 0x80) 
        { 
            HardDiskInit(DiakCommand, RsvdForLow, Buf, 0); 
            return; 
        } 
    } 
    FloppyDiskInit(DiakCommand, RsvdForLow, Buf, 0); 
} 
 
/********************************************************************************************************* 
** 函数名称: RemoveFileDriver 
** 功能描述: 删除一个底层驱动程序 
** 
** 输 入: DiakCommand:驱动程序函 
** 
** 输 出: 无 
**          
** 全局变量: DiskInfo 
** 调用模块: 无 
** 
** 作 者: 陈明计 
** 日 期: 2003年9月5日 
**------------------------------------------------------------------------------------------------------- 
** 修改人: 陈明计 
** 日 期: 2004年4月10日 
**------------------------------------------------------------------------------------------------------- 
** 修改人: 陈明计 
** 日 期: 2005年2月2日 
**------------------------------------------------------------------------------------------------------ 
********************************************************************************************************/ 
        void RemoveFileDriver(uint16  (* DiakCommand)(uint8 Cammand, void *Parameter)) 
{ 
    uint8 Drive; 
    Disk_RW_Parameter Pa; 
     
    for (Drive = 0; Drive < MAX_DRIVES; Drive++) 
    { 
        if (DiskInfo[Drive].DiakCommand != DiakCommand) 
        if (DiskInfo[Drive].Drive != EMPTY_DRIVE) 
        { 
            FsUMount(Drive); 
            Pa.RsvdForLow = DiskInfo[Drive].RsvdForLow; 
            DiskInfo[Drive].DiakCommand(DISK_CLOSE, &Pa); 
 
            DiskInfo[Drive].Drive = EMPTY_DRIVE;    // 没有分配 
            DiskInfo[Drive].FATType = 0xff;         // 无效的文件系统 
            DiskInfo[Drive].SecPerClus = 0;         // 每簇扇区数 
            DiskInfo[Drive].NumFATs = 0;            // FAT表数 
            DiskInfo[Drive].SecPerDisk = 0xffffffff;// 逻辑驱动器包含扇区数 
            DiskInfo[Drive].BytsPerSec = 0;         // 每扇区字节数 
            DiskInfo[Drive].RootDirTable = 0;       // 根目录开始扇区号(FAT32为开始簇号) 
            DiskInfo[Drive].RootSecCnt = 0;         // 根目录占用扇区数 
            DiskInfo[Drive].FATStartSec = 0;        // FAT表开始扇区号 
            DiskInfo[Drive].FATSecCnt = 0;          // 每个FAT占用扇区数 
            DiskInfo[Drive].DataStartSec = 0;       // 数据区开始扇区号 
            DiskInfo[Drive].PathClusIndex = 0;      // 当前目录 
            DiskInfo[Drive].DiakCommand = NULL;     // 驱动程序 
        } 
    } 
} 
 
/********************************************************************************************************* 
**                            End Of File 
********************************************************************************************************/