/* --------------------------------------------------------------------------- * FAT_intern.c (C)ChaN, 2008 * --------------------------------------------------------------------------- * Micro-key bv * Industrieweg 28, 9804 TG Noordhorn * Postbus 92, 9800 AB Zuidhorn * The Netherlands * Tel: +31 594 503020 * Fax: +31 594 505825 * Email: support@microkey.nl * Web: www.microkey.nl * --------------------------------------------------------------------------- * Description: FatFs - FAT file system module R0.06 * * The FatFs module is an experimenal project to implement FAT file system to * cheap microcontrollers. This is a free software and is opened for education, * research and development under license policy of following trems. * * Copyright (C) 2008, ChaN, all right reserved. * * The FatFs module is a free software and there is no warranty. * You can use, modify and/or redistribute it for personal, non-profit or * commercial use without restriction under your responsibility. * Redistributions of source code must retain the above copyright notice. * --------------------------------------------------------------------------- * Last Change: 0.2, Aug 11, 2008, MMi * Edited to fit into LAN_2636 Project * *---------------------------------------------------------------------------- * Feb 26,'06 R0.00 Prototype. * * Apr 29,'06 R0.01 First stable version. * * Jun 01,'06 R0.02 Added FAT12 support. * Removed unbuffered mode. * Fixed a problem on small (<32M) patition. * Jun 10,'06 R0.02a Added a configuration option (_FS_MINIMUM). * * Sep 22,'06 R0.03 Added f_rename(). * Changed option _FS_MINIMUM to _FS_MINIMIZE. * Dec 11,'06 R0.03a Improved cluster scan algolithm to write files fast. * Fixed f_mkdir() creates incorrect directory on FAT32. * * Feb 04,'07 R0.04 Supported multiple drive system. * Changed some interfaces for multiple drive system. * Changed f_mountdrv() to f_mount(). * Added f_mkfs(). * Apr 01,'07 R0.04a Supported multiple partitions on a plysical drive. * Added a capability of extending file size to f_lseek(). * Added minimization level 3. * Fixed an endian sensitive code in f_mkfs(). * May 05,'07 R0.04b Added a configuration option _USE_NTFLAG. * Added FSInfo support. * Fixed DBCS name can result FR_INVALID_NAME. * Fixed short seek (<= csize) collapses the file object. * * Aug 25,'07 R0.05 Changed arguments of f_read(), f_write() and f_mkfs(). * Fixed f_mkfs() on FAT32 creates incorrect FSInfo. * Fixed f_mkdir() on FAT32 creates incorrect directory. * Feb 03,'08 R0.05a Added f_truncate() and f_utime(). * Fixed off by one error at FAT sub-type determination. * Fixed btr in f_read() can be mistruncated. * Fixed cached sector is not flushed when create and close * without write. * * Apr 01,'08 R0.06 Added fputc(), fputs(), fprintf() and fgets(). * Improved performance of f_lseek() on moving to the same * or following cluster. *--------------------------------------------------------------------------- */ /* --------------------------------------------------------------------------- * System include files * --------------------------------------------------------------------------- */ /* Compiler includes */ #include #include "LPC23xx.h" #include "types.h" /* FreeRTOS includes */ #include "FreeRTOS.h" #include "task.h" /* --------------------------------------------------------------------------- * Application include files * --------------------------------------------------------------------------- */ #include "fat_intern.h" /* FatFs declarations */ #include "fat_public.h" #include "fat_diskio.h" /* Include file for user provided disk functions */ #include "fat_time.h" /* Get time from RTC */ /* --------------------------------------------------------------------------- * Local constant and macro definitions * --------------------------------------------------------------------------- */ /* --------------------------------------------------------------------------- * Global variable definitions * --------------------------------------------------------------------------- */ /* --------------------------------------------------------------------------- * Local variable definitions * --------------------------------------------------------------------------- */ FATFS *FatFs[_DRIVES] = {0,0}; /* Pointer to file system objects */ /* (logical drives) */ UINT16 fsid; /* File system mount ID */ /* --------------------------------------------------------------------------- * Local function definitions * --------------------------------------------------------------------------- */ BOOLEAN move_window (FATFS *fs, UINT32 sector) { UINT32 wsect; wsect = fs->winsect; if (wsect != sector) { /* Changed current window */ #if !_FS_READONLY /* If write-access granted */ UINT8 n; if (fs->winflag) { /* Write back dirty window if needed */ if (disk_write(fs->drive, fs->win, wsect, 1) != RES_OK) return FALSE; fs->winflag = 0; if (wsect < (fs->fatbase + fs->sects_fat)) { /* In FAT area */ for (n = fs->n_fats; n >= 2; n--) { /* Refrect the change to FAT copy */ wsect += fs->sects_fat; disk_write(fs->drive, fs->win, wsect, 1); } } } #endif if (sector) { if (disk_read(fs->drive, fs->win, sector, 1) != RES_OK) { return FALSE; } fs->winsect = sector; } } return TRUE; } #if !_FS_READONLY FRESULT sync (FATFS *fs) { fs->winflag = 1; if (!move_window(fs, 0)) return FR_RW_ERROR; #if _USE_FSINFO /* Update FSInfo sector if needed */ if (fs->fs_type == FS_FAT32 && fs->fsi_flag) { fs->winsect = 0; memset(fs->win, 0, 512); ST_WORD(&fs->win[BS_55AA], 0xAA55); ST_DWORD(&fs->win[FSI_LeadSig], 0x41615252); ST_DWORD(&fs->win[FSI_StrucSig], 0x61417272); ST_DWORD(&fs->win[FSI_Free_Count], fs->free_clust); ST_DWORD(&fs->win[FSI_Nxt_Free], fs->last_clust); disk_write(fs->drive, fs->win, fs->fsi_sector, 1); fs->fsi_flag = 0; } #endif /* Make sure that no pending write process in the physical drive */ if (disk_ioctl(fs->drive, CTRL_SYNC, NULL) != RES_OK) return FR_RW_ERROR; return FR_OK; } #endif UINT32 get_cluster (FATFS *fs, UINT32 clust) { UINT16 wc, bc; UINT32 fatsect; if (clust >= 2 && clust < fs->max_clust) { /* Is it a valid cluster number? */ fatsect = fs->fatbase; switch (fs->fs_type) { case FS_FAT12: bc = (UINT16)clust * 3 / 2; if (!move_window(fs, fatsect + (bc / SS(fs)))) break; wc = fs->win[bc & (SS(fs) - 1)]; bc++; if (!move_window(fs, fatsect + (bc / SS(fs)))) break; wc |= (UINT16)fs->win[bc & (SS(fs) - 1)] << 8; return (clust & 1) ? (wc >> 4) : (wc & 0xFFF); case FS_FAT16: if (!move_window(fs, fatsect + (clust / (SS(fs) / 2)))) break; return LD_WORD(&fs->win[((UINT16)clust * 2) & (SS(fs) - 1)]); case FS_FAT32: if (!move_window(fs, fatsect + (clust / (SS(fs) / 4)))) break; return LD_DWORD(&fs->win[((UINT16)clust * 4) & (SS(fs) - 1)]) & 0x0FFFFFFF; } } return 1; /* Out of cluster range, or an error occured */ } #if !_FS_READONLY BOOLEAN put_cluster(FATFS *fs, UINT32 clust, UINT32 val) { UINT32 fatsect; UINT16 bc; UINT8 *p; fatsect = fs->fatbase; switch (fs->fs_type) { case FS_FAT12: bc = (UINT16)clust * 3 / 2; if (!move_window(fs, fatsect + (bc / SS(fs)))) { return FALSE; } p = &fs->win[bc & (SS(fs) - 1)]; *p = (clust & 1) ? ((*p & 0x0F) | ((UINT8)val << 4)) : (UINT8)val; bc++; fs->winflag = 1; if (!move_window(fs, fatsect + (bc / SS(fs)))) { return FALSE; } p = &fs->win[bc & (SS(fs) - 1)]; *p = (clust & 1) ? (UINT8)(val >> 4) : ((*p & 0xF0) | ((UINT8)(val >> 8) & 0x0F)); break; case FS_FAT16: if (!move_window(fs, fatsect + (clust / (SS(fs) / 2)))) { return FALSE; } ST_WORD(&fs->win[((UINT16)clust * 2) & (SS(fs) - 1)], (UINT16)val); break; case FS_FAT32: if (!move_window(fs, fatsect + (clust / (SS(fs) / 4)))) { return FALSE; } ST_DWORD(&fs->win[((UINT16)clust * 4) & (SS(fs) - 1)], val); break; default: return FALSE; } fs->winflag = 1; return TRUE; } #endif /* !_FS_READONLY */ #if !_FS_READONLY BOOLEAN remove_chain (FATFS *fs, UINT32 clust) { UINT32 nxt; while (clust >= 2 && clust < fs->max_clust) { nxt = get_cluster(fs, clust); if (nxt == 1) { return FALSE; } if (!put_cluster(fs, clust, 0)) { return FALSE; } if (fs->free_clust != 0xFFFFFFFF) { fs->free_clust++; #if _USE_FSINFO fs->fsi_flag = 1; #endif } clust = nxt; } return TRUE; } #endif #if !_FS_READONLY UINT32 create_chain (FATFS *fs, UINT32 clust) { UINT32 cstat; UINT32 ncl; UINT32 scl; UINT32 mcl = fs->max_clust; if (clust == 0) { /* Create new chain */ scl = fs->last_clust; /* Get suggested start point */ if (scl == 0 || scl >= mcl) scl = 1; } else { /* Stretch existing chain */ cstat = get_cluster(fs, clust); /* Check the cluster status */ if (cstat < 2) { return 1; /* It is an invalid cluster */ } if (cstat < mcl) { return cstat; /* Is already followed by cluster */ } scl = clust; } ncl = scl; /* Start cluster */ for (;;) { ncl++; /* Next cluster */ if (ncl >= mcl) { /* Wrap around */ ncl = 2; if (ncl > scl) return 0; /* No free custer */ } cstat = get_cluster(fs, ncl); /* Get the cluster status */ if (cstat == 0) { break; /* Found a free cluster */ } if (cstat == 1) { return 1; /* Any error occured */ } if (ncl == scl) { return 0; /* No free custer */ } } if (!put_cluster(fs, ncl, 0x0FFFFFFF)) { return 1; /* Mark the new cluster "in use" */ } if (clust != 0 && !put_cluster(fs, clust, ncl)) { return 1; /* Link it to previous one if needed*/ } fs->last_clust = ncl; /* Update fsinfo */ if (fs->free_clust != 0xFFFFFFFF) { fs->free_clust--; #if _USE_FSINFO fs->fsi_flag = 1; #endif } return ncl; /* Return new cluster number */ } #endif /* !_FS_READONLY */ UINT32 clust2sect(FATFS *fs, UINT32 clust) { clust -= 2; if (clust >= (fs->max_clust - 2)) { return 0; /* Invalid cluster number */ } return (clust * fs->csize + fs->database); } BOOLEAN next_dir_entry(DIR *dj) { UINT32 clust; UINT16 idx; idx = dj->index + 1; if ((idx & ((SS(dj->fs) - 1) / 32)) == 0) { /* Table sector changed? */ dj->sect++; /* Next sector */ if (dj->clust == 0) { /* In static table */ if (idx >= dj->fs->n_rootdir) { return FALSE; /* Reached to end of table */ } } else { /* In dynamic table */ if (((idx / (SS(dj->fs) / 32)) & (dj->fs->csize - 1)) == 0) { /* Cluster changed? */ clust = get_cluster(dj->fs, dj->clust); /* Get next cluster */ if (clust < 2 || clust >= dj->fs->max_clust) { /* Reached to end of table */ return FALSE; } dj->clust = clust; /* Initialize for new cluster */ dj->sect = clust2sect(dj->fs, clust); } } } dj->index = idx; /* Lower bits of dj->index indicates*/ /* offset in dj->sect */ return TRUE; } #if _FS_MINIMIZE <= 1 void get_fileinfo (FILINFO *finfo, const UINT8 *dir) { UINT8 n; UINT8 c; UINT8 a; char *p; p = &finfo->fname[0]; a = _USE_NTFLAG ? dir[DIR_NTres] : 0; /* NT flag */ for (n = 0; n < 8; n++) { /* Convert file name (body) */ c = dir[n]; if (c == ' ') { break; } if (c == 0x05) { c = 0xE5; } if (a & 0x08 && c >= 'A' && c <= 'Z') { c += 0x20; } *p++ = c; } if (dir[8] != ' ') { /* Convert file name (extension) */ *p++ = '.'; for (n = 8; n < 11; n++) { c = dir[n]; if (c == ' ') { break; } if (a & 0x10 && c >= 'A' && c <= 'Z') { c += 0x20; } *p++ = c; } } *p = '\0'; finfo->fattrib = dir[DIR_Attr]; /* Attribute */ finfo->fsize = LD_DWORD(&dir[DIR_FileSize]); /* Size */ finfo->fdate = LD_WORD(&dir[DIR_WrtDate]); /* Date */ finfo->ftime = LD_WORD(&dir[DIR_WrtTime]); /* Time */ } #endif /* _FS_MINIMIZE <= 1 */ char make_dirfile(const char **path, char *dirname) { UINT8 n; UINT8 t; UINT8 c; UINT8 a; UINT8 b; memset(dirname, ' ', 8+3); /* Fill buffer with spaces */ a = 0; b = 0x18; /* NT flag */ n = 0; t = 8; for (;;) { c = *(*path)++; if (c == '\0' || c == '/') { /* Reached to end of str or directory separator */ if (n == 0) { break; } dirname[11] = _USE_NTFLAG ? (a & b) : 0; return c; } if (c <= ' ' || c == 0x7F) { break; /* Reject invisible chars */ } if (c == '.') { if (!(a & 1) && n >= 1 && n <= 8) { /* Enter extension part */ n = 8; t = 11; continue; } break; } if (_USE_SJIS && ((c >= 0x81 && c <= 0x9F) || /* Accept S-JIS code */ (c >= 0xE0 && c <= 0xFC))) { if (n == 0 && c == 0xE5) /* Change heading \xE5 to \x05 */ { c = 0x05; } a ^= 0x01; goto md_l2; /* LABEL SEE END OF FUNCTION */ } if (c == '"') { break; /* Reject " */ } if (c <= ')') { goto md_l1; /* LABEL SEE END OF FUNCTION */ } /* Accept ! # $ % & ' ( ) */ if (c <= ',') { break; /* Reject * + , */ } if (c <= '9') { goto md_l1; } /* Accept - 0-9 */ if (c <= '?') { break; /* Reject : ; < = > ? */ } if (!(a & 1)) { /* These checks are not applied to S-JIS 2nd byte */ if (c == '|') { break; /* Reject | */ } if (c >= '[' && c <= ']') { break; /* Reject [ \ ] */ } if (_USE_NTFLAG && c >= 'A' && c <= 'Z') { (t == 8) ? (b &= 0xF7) : (b &= 0xEF); } if (c >= 'a' && c <= 'z') { /* Convert to upper case */ c -= 0x20; if (_USE_NTFLAG) { (t == 8) ? (a |= 0x08) : (a |= 0x10); } } } /* GOTO LABELS */ md_l1: a &= 0xFE; md_l2: if (n >= t) { break; } dirname[n++] = c; } return 1; } FRESULT trace_path (DIR *dj, char *fn, const char *path, UINT8 **dir) { UINT32 clust; char ds; UINT8 *dptr = NULL; FATFS *fs = dj->fs; /* Initialize directory object */ clust = fs->dirbase; if (fs->fs_type == FS_FAT32) { dj->clust = dj->sclust = clust; dj->sect = clust2sect(fs, clust); } else { dj->clust = dj->sclust = 0; dj->sect = clust; } dj->index = 0; if (*path == '\0') { /* Null path means the root directory */ *dir = NULL; return FR_OK; } for (;;) { ds = make_dirfile(&path, fn); /* Get a paragraph into fn[] */ if (ds == 1) { return FR_INVALID_NAME; } for (;;) { if (!move_window(fs, dj->sect)) { return FR_RW_ERROR; } /* Pointer to the directory entry */ dptr = &fs->win[(dj->index & ((SS(fs) - 1) / 32)) * 32]; if (dptr[DIR_Name] == 0) /* Has it reached to end of dir? */ { return !ds ? FR_NO_FILE : FR_NO_PATH; } if (dptr[DIR_Name] != 0xE5 /* Matched? */ && !(dptr[DIR_Attr] & AR_VOL) && !memcmp(&dptr[DIR_Name], fn, 8+3)) { break; } if (!next_dir_entry(dj)) /* Next directory pointer */ { return !ds ? FR_NO_FILE : FR_NO_PATH; } } if (!ds) { *dir = dptr; return FR_OK; } /* Matched with end of path */ if (!(dptr[DIR_Attr] & AR_DIR)) { return FR_NO_PATH; /* Cannot trace because it is a file*/ } /* Get cluster# of the directory */ clust = ((UINT32)LD_WORD(&dptr[DIR_FstClusHI]) << 16) | LD_WORD(&dptr[DIR_FstClusLO]); /* Restart scanning at the new directory */ dj->clust = dj->sclust = clust; dj->sect = clust2sect(fs, clust); dj->index = 2; } } #if !_FS_READONLY FRESULT reserve_direntry (DIR *dj, UINT8 **dir) { UINT32 clust; UINT32 sector; UINT8 c; UINT8 n; UINT8 *dptr; FATFS *fs = dj->fs; /* Re-initialize directory object */ clust = dj->sclust; if (clust != 0) { /* Dyanmic directory table */ dj->clust = clust; dj->sect = clust2sect(fs, clust); } else { /* Static directory table */ dj->sect = fs->dirbase; } dj->index = 0; do { if (!move_window(fs, dj->sect)) { return FR_RW_ERROR; } /* Pointer to the directory entry */ dptr = &fs->win[(dj->index & ((SS(dj->fs) - 1) / 32)) * 32]; c = dptr[DIR_Name]; if (c == 0 || c == 0xE5) { /* Found an empty entry */ *dir = dptr; return FR_OK; } } while (next_dir_entry(dj)); /* Next directory pointer */ /* Reached to end of the directory table */ /* Abort when it is a static table or could not stretch dynamic table */ if (clust == 0 || !(clust = create_chain(fs, dj->clust))) { return FR_DENIED; } if (clust == 1 || !move_window(fs, 0)) { return FR_RW_ERROR; } /* Cleanup the expanded table */ fs->winsect = sector = clust2sect(fs, clust); memset(fs->win, 0, SS(fs)); for (n = fs->csize; n; n--) { if (disk_write(fs->drive, fs->win, sector, 1) != RES_OK) { return FR_RW_ERROR; } sector++; } fs->winflag = 1; *dir = fs->win; return FR_OK; } #endif UINT8 check_fs (FATFS *fs, UINT32 sect) { /* Load boot record */ if (disk_read(fs->drive, fs->win, sect, 1) != RES_OK) { return 2; } /* Check record signature (always placed at offset 510 even if the sector * size is >512) */ if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55) { return 2; } /* Check FAT signature */ if (!memcmp(&fs->win[BS_FilSysType], "FAT", 3)) { return 0; } if (!memcmp(&fs->win[BS_FilSysType32], "FAT32", 5) && !(fs->win[BPB_ExtFlags] & 0x80)) { return 0; } return 1; } FRESULT auto_mount (const char **path, FATFS **rfs, UINT8 chk_wp) { UINT32 bootsect; UINT32 fatsize; UINT32 totalsect; UINT32 maxclust; UINT8 drv; UINT8 fmt; UINT8 *tbl; DSTATUS stat; const char *p = *path; FATFS *fs; /* Get drive number from the path name */ while (*p == ' ') { p++; /* Strip leading spaces */ } drv = p[0] - '0'; /* Is there a drive number? */ if (drv <= 9 && p[1] == ':') { p += 2; /* Found drive number, get&strip it */ } else { drv = 0; /* No drive number is given, use */ /* drive number 0 as default */ } if (*p == '/') { p++; /* Strip heading slash */ } *path = p; /* Return pointer to the path name */ /* Check if the drive number is valid or not */ if (drv >= _DRIVES) { return FR_INVALID_DRIVE; /* Is the drive number valid? */ } *rfs = fs = FatFs[drv]; /* Returen pointer to the */ /* corresponding file system object */ if (!fs) { return FR_NOT_ENABLED; /* Is file system object registered?*/ } if (fs->fs_type) { /* If the logical drive has been mounted */ stat = disk_status(fs->drive); if (!(stat & STA_NOINIT)) { /* and physical drive is kept initialized (has not been changed)*/ #if !_FS_READONLY /* Check write protection if needed */ if (chk_wp && (stat & STA_PROTECT)) { return FR_WRITE_PROTECTED; } #endif return FR_OK; /* The file system object is valid */ } } /* The logical drive must be re-mounted. * Following code attempts to mount the logical drive */ memset(fs, 0, sizeof(FATFS)); /* Clean-up the file system object */ fs->drive = LD2PD(drv); /* Bind logical and physical drive */ stat = disk_initialize(fs->drive); /* Initialize low level I/O layer */ if (stat & STA_NOINIT) /* Check if the drive is ready */ { return FR_NOT_READY; } #if S_MAX_SIZ > 512 /* Get disk sector size if needed */ if (disk_ioctl(drv,GET_SECTOR_SIZE,&SS(fs)) != RES_OK || SS(fs)> S_MAX_SIZ) { return FR_NO_FILESYSTEM; } #endif #if !_FS_READONLY if (chk_wp && (stat & STA_PROTECT)) /* Check write protection if needed */ { return FR_WRITE_PROTECTED; } #endif /* Search FAT partition on the drive */ fmt = check_fs(fs, bootsect = 0); /* Check sector 0 as an SFD format */ if (fmt == 1) { /* Not an FAT boot record, it may be patitioned */ /* Check a partition listed in top of the partition table */ tbl = &fs->win[MBR_Table + LD2PT(drv) * 16]; /* Partition table */ if (tbl[4]) { /* Is the partition existing? */ bootsect = LD_DWORD(&tbl[8]); /* Partition offset in LBA */ fmt = check_fs(fs, bootsect); /* Check the partition */ } } /* No valid FAT patition is found */ if (fmt || LD_WORD(&fs->win[BPB_BytsPerSec]) != SS(fs)) { return FR_NO_FILESYSTEM; } /* Initialize the file system object */ fatsize = LD_WORD(&fs->win[BPB_FATSz16]); /* Number of sectors per FAT */ if (!fatsize) { fatsize = LD_DWORD(&fs->win[BPB_FATSz32]); } fs->sects_fat = fatsize; /* Number of FAT copies */ fs->n_fats = fs->win[BPB_NumFATs]; /* (Number of sectors in FAT area) */ fatsize *= fs->n_fats; /* FAT start sector (lba) */ fs->fatbase = bootsect + LD_WORD(&fs->win[BPB_RsvdSecCnt]); /* Number of sectors per cluster */ fs->csize = fs->win[BPB_SecPerClus]; /* Nmuber of root directory entries */ fs->n_rootdir = LD_WORD(&fs->win[BPB_RootEntCnt]); /* Number of sectors on the file system */ totalsect = LD_WORD(&fs->win[BPB_TotSec16]); if (!totalsect) { totalsect = LD_DWORD(&fs->win[BPB_TotSec32]); } /* max_clust = Last cluster# + 1 */ fs->max_clust = maxclust = (totalsect - LD_WORD(&fs->win[BPB_RsvdSecCnt]) - fatsize - fs->n_rootdir / (SS(fs)/32) ) / fs->csize + 2; fmt = FS_FAT12; /* Determine the FAT sub type */ if (maxclust >= 0xFF7) { fmt = FS_FAT16; } if (maxclust >= 0xFFF7) { fmt = FS_FAT32; } if (fmt == FS_FAT32) { /* Root directory start cluster */ fs->dirbase = LD_DWORD(&fs->win[BPB_RootClus]); } else { /* Root directory start sector (lba) */ fs->dirbase = fs->fatbase + fatsize; } /* Data start sector (lba) */ fs->database = fs->fatbase + fatsize + fs->n_rootdir / (SS(fs)/32); #if !_FS_READONLY /* Initialize allocation information */ fs->free_clust = 0xFFFFFFFF; #if _USE_FSINFO /* Get fsinfo if needed */ if (fmt == FS_FAT32) { fs->fsi_sector = bootsect + LD_WORD(&fs->win[BPB_FSInfo]); if (disk_read(fs->drive, fs->win, fs->fsi_sector, 1) == RES_OK && LD_WORD(&fs->win[BS_55AA]) == 0xAA55 && LD_DWORD(&fs->win[FSI_LeadSig]) == 0x41615252 && LD_DWORD(&fs->win[FSI_StrucSig]) == 0x61417272) { fs->last_clust = LD_DWORD(&fs->win[FSI_Nxt_Free]); fs->free_clust = LD_DWORD(&fs->win[FSI_Free_Count]); } } #endif #endif fs->fs_type = fmt; /* FAT syb-type */ fs->id = ++fsid; /* File system mount ID */ return FR_OK; } FRESULT validate (const FATFS *fs, UINT16 id) { if (!fs || !fs->fs_type || fs->id != id) { return FR_INVALID_OBJECT; } if (disk_status(fs->drive) & STA_NOINIT) { return FR_NOT_READY; } return FR_OK; }