Milos RTOS v0.3.4a
Real Time Operating System
fat.c
Go to the documentation of this file.
00001 /***************************************************************************
00002  * fat.c
00003  * (C) 2010 Ivan Meleca
00004  * Based on original code written by Ruben Meleca
00005  * www.milos.it
00006  *
00007  *
00008  * Interface between ChaN's FatFs and Milos (EXPERIMENTAL) *
00009  *
00010  * FatFS Copyright (C) 2010, ChaN, all right reserved.
00011  * http://elm-chan.org/fsw/ff/00index_e.html
00012  *
00013 
00014 #   This program is free software; you can redistribute it and/or modify
00015 #   it under the terms of the GNU General Public License as published by
00016 #   the Free Software Foundation; either version 2 of the License, or
00017 #   (at your option) any later version.
00018 #
00019 #   This program is distributed in the hope that it will be useful,
00020 #   but WITHOUT ANY WARRANTY; without even the implied warranty of
00021 #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022 #   GNU General Public License for more details.
00023 #
00024 #   You should have received a copy of the GNU General Public License
00025 #   along with this program; if not, write to the Free Software
00026 #   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00027 
00028  *
00029  * The function names and some types names are the same as previous versions
00030  * of Milos (to keep compatibility).
00031  * This file intends to "glue" the Milos implementation with the FatFS file
00032  * system. Some types (mostly error codes)are the same from FatFS, so expect
00033  * naming differences (by default all Milos names start with a double underscore
00034  * character to differentiate them from user (app) functions and avoid renaming).
00035  * Let's say this file will suffer modifications: one issue is the mentioned
00036  * above. The other is that someday we will (hopefully) implement diverse
00037  * file systems, and the __fileXXXXX functions should be the same for different
00038  * file system types.
00039  *
00040 ***************************************************************************/
00041 
00042 #include "fat.h"
00043 #include <core/heap.h>
00044 #include <core/device.h>
00045 #include <drivers/sd/sd.h>
00046 #include <common/mem.h>
00047 #include <common/string.h>
00048 #include <core/dbgterm.h>
00049 #include <core/rtc.h>
00050 
00051 #if __CONFIG_COMPILE_FAT
00052 
00070 __PFAT_VOLUME   __fatVolumes;       
00081  __PFAT_VOLUME __fatGetVolumeFromFatFS(__PFAT_FATFS fs)
00082 {
00083     __PFAT_VOLUME vol = __fatVolumes;
00084     while (vol)
00085     {
00086         if (vol->fat == fs) return vol;
00087         vol = vol->next;
00088     }
00089 
00090     return __NULL;
00091 }
00092 
00102 __STATIC __PDEVICE __fatGetDevice(u8 drv)
00103 {
00104     __PFAT_VOLUME vol = __fatVolumes;
00105     while (vol)
00106     {
00107         if (vol->num == drv) return vol->dv;
00108         vol = vol->next;
00109     }
00110 
00111     return __NULL;
00112 }
00113 
00129 __STATIC __PFAT_VOLUME __fatCreateVolume(u8 num, __PFAT_FATFS fat, __PDEVICE dv)
00130 {
00131     __PFAT_VOLUME ptr = __fatVolumes;
00132     __PFAT_VOLUME last = ptr;
00133 
00134     __systemStop();
00135 
00136     /* Find a position */
00137     while (ptr)
00138     {
00139         last = ptr;
00140         ptr = ptr->next;
00141     }
00142 
00143     ptr = (__PFAT_VOLUME) __heapAllocZero(sizeof(__FAT_VOLUME));
00144     if (!ptr) return __NULL;
00145 
00146     ptr->num = num;
00147     ptr->fat = fat;
00148     ptr->dv = dv;
00149     ptr->next = __NULL;
00150 
00151     if (!last)
00152     {
00153         __fatVolumes = ptr;
00154     } else
00155     {
00156         last->next = ptr;
00157     }
00158 
00159     __systemStart();
00160 
00161     return ptr;
00162 }
00163 
00176 __STATIC __VOID __fatFreeVolume(__PFAT_VOLUME vol)
00177 {
00178     __PFAT_VOLUME ptr = __fatVolumes;
00179     __PFAT_VOLUME last = ptr;
00180 
00181     __systemStop();
00182 
00183     /* Find the position */
00184     while (ptr) {
00185         if (ptr == vol)
00186         {
00187             if (vol == __fatVolumes)
00188             {
00189                 __fatVolumes = __fatVolumes->next;
00190             } else
00191             {
00192                 last->next = ptr->next;
00193             }
00194 
00195             __heapFree(vol);
00196         }
00197         last = ptr;
00198         ptr = ptr->next;
00199     }
00200 }
00201 
00222 __PFAT_VOLUME __fatMount(u8 num, __PDEVICE dv)
00223 {
00224     __PFAT_VOLUME ptr = __fatVolumes;
00225     __PFAT_FATFS fat;
00226 
00227     /* Check if num is already mounted */
00228     while (ptr)
00229     {
00230         if (ptr->num == num) return ptr;
00231         ptr = ptr->next;
00232     }
00233 
00234     /* Create a new __PFAT_FATFS, the object that FatFS uses to store
00235      * FAT information.
00236      */
00237     fat = (__PFAT_FATFS) __heapAllocZero(sizeof(__FAT_FATFS));
00238     if (!fat) return __NULL;
00239 
00240     /* Call FatFS f_mount */
00241     if (f_mount(num, fat) != FR_OK)
00242     {
00243         __heapFree(fat);
00244         return __NULL;
00245     }
00246 
00247     /* Create and store a new volume */
00248     ptr = __fatCreateVolume(num, fat, dv);
00249 
00250     /* Return valid pointer on success, otherwise __FALSE */
00251     return ptr;
00252 }
00253 
00261 __VOID __fatDismount(__PFAT_VOLUME vol)
00262 {
00263     /* Save fat pointer*/
00264     __PFAT_FATFS fat = vol->fat;
00265 
00266     /* Call f_mount */
00267     f_mount(vol->num, __NULL);
00268 
00269     __fatFreeVolume(vol);
00270     __heapFree(fat);
00271 }
00272 
00273 /* TODO */
00274 u32 __fatGetFreeClusters(__CONST __PSTRING part, __PFAT_VOLUME* vol);
00275 
00304 __FILE_RES __dirCreate(__CONST __PSTRING name)
00305 {
00306     return f_mkdir(name);
00307 }
00308 
00333 __FILE_RES __dirOpen(__PDIR dir, __CONST __PSTRING name)
00334 {
00335     return f_opendir(dir, name);
00336 }
00337 
00368 __FILE_RES __dirRead(__PDIR dir, __PFILEINFO fi)
00369 {
00370     return f_readdir(dir, fi);
00371 }
00372 
00382 #if __CONFIG_COMPILE_DBGTERM
00383 
00392 __VOID __fatDirCmd(__PTERMINAL term)
00393 {
00394     __DIR dir;
00395     __FILEINFO fi;
00396     __PSTRING str;
00397     u32 count = 0;
00398     u32 bytes = 0;
00399 
00400     /* String buffer */
00401     str = __heapAllocZero(64);
00402     if (!str) return;
00403 
00404     /* Clean */
00405     __memSet(&dir, 0, sizeof(dir));
00406     __memSet(&fi, 0, sizeof(fi));
00407 
00408     /* Call root __dirOpen() */
00409     if (__dirOpen(&dir, "") == FR_OK)
00410     {
00411         __terminalWriteLine(term, "\r\nFiles in FAT:\r\n");
00412         __terminalWriteLine(term, "Name           Size");
00413         __terminalWriteLine(term, "-------------------------");
00414 
00415         /* First call to __dirRead() with __NULL fi */
00416         __dirRead(&dir, __NULL);
00417 
00418         /* While files in dir */
00419         while (__dirRead(&dir, &fi) == FR_OK && dir.sect > 0)
00420         {
00421             count++;
00422             bytes += fi.fsize;
00423             __strFmt(str, "%12s   %lu bytes", fi.fname, (u32) fi.fsize);
00424             __terminalWriteLine(term, str);
00425         }
00426 
00427         __terminalWriteLine(term, "\r\n%lu file(s) %lu bytes\r\n", count, bytes);
00428     } else
00429     {
00430         __terminalWriteLine(term, "Error calling __dirOpen()");
00431     }
00432 
00433     __heapFree(str);
00434 }
00435 
00436 #endif /* __CONFIG_COMPILE_DBGTERM */
00437 
00470 __PFILE __fileOpen(__CONST __PSTRING file, u8 mode)
00471 {
00472     __PFILE ptr;
00473 
00474     ptr = (__PFILE) __heapAllocZero(sizeof(__FILE));
00475     if (!ptr) return __NULL;
00476 
00477     if (f_open(ptr, file, mode) != FR_OK)
00478     {
00479         __heapFree(ptr);
00480         return __NULL;
00481     }
00482 
00483     return ptr;
00484 }
00485 
00496 u32 __fileRead(__PFILE file, __PVOID buf, u32 qty)
00497 {
00498     UINT ret = 0;
00499 
00500     f_read(file, buf, qty, &ret);
00501     return ret;
00502 }
00503 
00538 __FILE_RES  __fileSeek(__PFILE file, u32 offs)
00539 {
00540     return f_lseek(file, offs);
00541 }
00542 
00560 __FILE_RES  __fileClose(__PFILE file)
00561 {
00562     __FILE_RES ret;
00563     ret = f_close(file);
00564     if (ret == FR_OK) {
00565         __heapFree(file);
00566     }
00567 
00568     return ret;
00569 }
00570 
00595 __FILE_RES  __fileGetStatus(__CONST __PSTRING file, __PFILEINFO fi)
00596 {
00597     return f_stat(file, fi);
00598 }
00599 
00616 u32 __fileWrite(__PFILE file, __PVOID buf, u32 qty)
00617 {
00618     UINT ret;
00619     f_write(file, buf, qty, &ret);
00620     return ret;
00621 }
00622 
00644 __FILE_RES __fileFlush(__PFILE file)
00645 {
00646     return f_sync(file);
00647 }
00648 
00666 __FILE_RES  __fileTruncate(__PFILE file)
00667 {
00668     return f_truncate(file);
00669 }
00670 
00697 __FILE_RES  __fileDelete(__CONST __PSTRING file)
00698 {
00699     return f_unlink(file);
00700 }
00701 
00728 __FILE_RES  __fileChmod(__CONST __PSTRING file, u8 value, u8 mask)
00729 {
00730     return f_chmod(file, value, mask);
00731 }
00732 
00754 __FILE_RES  __fileChangeTime(__CONST __PSTRING file, __CONST __PFILEINFO fi)
00755 {
00756     return f_utime(file, fi);
00757 }
00758 
00783 __FILE_RES  __fileRename(__CONST __PSTRING name1, __CONST __PSTRING name2);
00784 
00809 __FATFS_STATUS disk_initialize (u8 drv)
00810 {
00811     /* Get the device */
00812     __PDEVICE dv = __fatGetDevice(drv);
00813     if (!dv) return RES_NOTRDY;
00814 
00815     /* Call __deviceOpen. The device should return 0 on success.
00816      * The device should be already registered with __deviceRegister().
00817      */
00818     if (__deviceOpen(dv, 0) == 0) return RES_OK;
00819     return RES_ERROR;
00820 }
00821 
00842 __FATFS_STATUS disk_status (BYTE drv)
00843 {
00844     __FATFS_STATUS ret = 0;
00845     __PDEVICE dv;
00846 
00847     /* Get the device */
00848     dv = __fatGetDevice(drv);
00849     if (!dv) return ret;
00850 
00851     switch (dv->dv_type)
00852     {
00853         /* SD/CF? */
00854         case __DEV_CFSD:
00855             if (__deviceIOCtl(dv, __IOCTL_WRITE_PROTECTED, 0, __NULL, 0))
00856             {
00857                 ret |= STA_PROTECT;
00858             }
00859 
00860             if (!__deviceIOCtl(dv, __IOCTL_MEDIA_AVAILABLE, 0, __NULL, 0))
00861             {
00862                 ret |= STA_NODISK;
00863             }
00864             break;
00865         default:
00866             /* TODO */
00867             ret = STA_NOINIT;
00868             break;
00869     }
00870 
00871     if (!dv->dv_initd || !dv->dv_opcnt)
00872     {
00873         ret |= STA_NOINIT;
00874     }
00875     return ret;
00876 }
00877 
00907 __FATFS_RES disk_ioctl (u8 drv, u8 ctrl, __PVOID buff)
00908 {
00909     __FATFS_RES res = RES_ERROR;
00910     u8* ptr = (u8*) buff;
00911     __PDEVICE dv;
00912 
00913     /* Get the device */
00914     dv = __fatGetDevice(drv);
00915     if (!dv) return res;
00916 
00917     /* SC/CF? */
00918     if (dv->dv_type == __DEV_CFSD)
00919     {
00920         /* Power control code */
00921         if (ctrl == CTRL_POWER)
00922         {
00923             switch (*ptr) {
00924                 /* Power off */
00925                 case 0:
00926                     if (__deviceIOCtl(dv, __IOCTL_GET_POWER_STATUS, 0, __NULL, 0)) {
00927                         __deviceIOCtl(dv, __IOCTL_SET_POWER_STATUS, 0, __NULL, 0);
00928                     }
00929                     res = RES_OK;
00930                     break;
00931 
00932                 /* Power on */
00933                 case 1:
00934                     __deviceIOCtl(dv, __IOCTL_SET_POWER_STATUS, 1, __NULL, 0);
00935                     res = RES_OK;
00936                     break;
00937 
00938                 /* Get power status */
00939                 case 2:
00940                     *(ptr+1) = (u8) __deviceIOCtl(dv, __IOCTL_GET_POWER_STATUS, 0, __NULL, 0);
00941                     res = RES_OK;
00942                     break;
00943 
00944                 default:
00945                     res = RES_PARERR;
00946                     break;
00947             }
00948         } else
00949         {
00950             /* The next control codes need the device in ready state */
00951             if (disk_status(drv) & STA_NOINIT) return RES_NOTRDY;
00952 
00953             switch (ctrl)
00954             {
00955                 /* Make sure that the disk drive has finished pending write process.
00956                  * When the disk I/O module has a write back cache, flush the dirty
00957                  * sector immediately. This command is not used in read-only configuration.
00958                  */
00959                 case CTRL_SYNC:
00960                     /* TODO flush cache */
00961                     res = RES_OK;
00962                     break;
00963 
00964                 /* Returns number of available sectors on the drive into the DWORD variable
00965                  * pointed by Buffer. This command is used by only f_mkfs function to determine
00966                  * the volume size to be created.
00967                  */
00968                 case GET_SECTOR_COUNT:
00969                     *(u32*) buff = __deviceIOCtl(dv, __IOCTL_GET_SECTOR_COUNT, 0, __NULL, 0);
00970                     res = RES_OK;
00971                     break;
00972 
00973                 /* Returns sector size of the drive into the WORD variable pointed by Buffer.
00974                  * This command is not used in fixed sector size configuration, _MAX_SS is 512.
00975                  */
00976                 case GET_SECTOR_SIZE:
00977                     *(u16*) buff = 512;
00978                     res = RES_OK;
00979                     break;
00980 
00981                 /* Returns erase block size of the flash memory in unit of sector into the
00982                  * DWORD variable pointed by Buffer. The allowable value is 1 to 32768 in power
00983                  * of 2. Return 1 if the erase block size is unknown or disk devices. This command
00984                  * is used by only f_mkfs function and it attempts to align data area to the erase
00985                  * block boundary.
00986                  */
00987                 case GET_BLOCK_SIZE:
00988                     *(u32*) buff = __deviceIOCtl(dv, __IOCTL_GET_BLOCK_SIZE, 0, __NULL, 0);
00989                     res = RES_OK;
00990                     break;
00991 
00992                 /* Get card type */
00993                 case MMC_GET_TYPE:
00994                     *ptr = (u8) __deviceIOCtl(dv, __IOCTL_GET_CARD_TYPE, 0, __NULL, 0);
00995                     res = RES_OK;
00996                     break;
00997 
00998                 case MMC_GET_CSD:
00999                      __deviceIOCtl(dv, __IOCTL_GET_CSD, 0, __NULL, 0);
01000                     res = RES_OK;
01001                     break;
01002 
01003                 case MMC_GET_CID:
01004                     __deviceIOCtl(dv, __IOCTL_GET_CID, 0, __NULL, 0);
01005                     res = RES_OK;
01006                     break;
01007 
01008                 case MMC_GET_OCR:
01009                     __deviceIOCtl(dv, __IOCTL_GET_OCR, 0, __NULL, 0);
01010                     res = RES_OK;
01011                     break;
01012 
01013                 case MMC_GET_SDSTAT:
01014                     __deviceIOCtl(dv, __IOCTL_GET_SDSTAT, 0, __NULL, 0);
01015                     res = RES_OK;
01016                     break;
01017 
01018                 default:
01019                     res = RES_PARERR;
01020                     break;
01021             }
01022         }
01023     }
01024 
01025     return res;
01026 }
01027 
01052 __FATFS_RES disk_read (u8 drv, u8 *buff, u32 sector, u8 count)
01053 {
01054     __PDEVICE dv;
01055 
01056     /* Get the device */
01057     dv = __fatGetDevice(drv);
01058     if (!dv) return RES_PARERR;
01059 
01060     /* Set the sector to read */
01061     if (dv->dv_type == __DEV_CFSD) __deviceIOCtl(dv, __IOCTL_SET_SECTOR, sector, __NULL, 0);
01062     if (__deviceRead(dv, buff, count) == 0) return RES_OK;
01063 
01064     return RES_ERROR;
01065 }
01066 
01093 __FATFS_RES disk_write (BYTE drv, __CONST u8 *buff, u32 sector, u8 count)
01094 {
01095     __PDEVICE dv;
01096 
01097     /* Get the device */
01098     dv = __fatGetDevice(drv);
01099     if (!dv) return RES_PARERR;
01100 
01101     if (dv->dv_type == __DEV_CFSD)
01102     {
01103         if (__deviceIOCtl(dv, __IOCTL_WRITE_PROTECTED, 0, __NULL, 0))
01104         {
01105             return RES_WRPRT;
01106         }
01107     }
01108 
01109     /* Set the sector to write */
01110     if (dv->dv_type == __DEV_CFSD)
01111     {
01112         __deviceIOCtl(dv, __IOCTL_SET_SECTOR, sector, __NULL, 0);
01113     }
01114 
01115     /* Write */
01116     if (__deviceWrite(dv, buff, count) == 0) return RES_OK;
01117 
01118     return RES_ERROR;
01119 }
01120 
01143 u32 get_fattime (__VOID)
01144 {
01145 
01146 #if __CONFIG_COMPILE_RTC
01147     __DATETIME dt;
01148 
01149     __rtcGetDateTime(&dt);
01150 
01151     return ((dt.year - 1980) << 25  |
01152              dt.month << 21         |
01153              dt.day << 16           |
01154              dt.hour << 11          |
01155              dt.min << 5            |
01156              dt.sec);
01157 
01158 #else
01159 
01160     /* fixed date-time */
01161     return (30 << 25 | 12 << 21 | 30 << 16 | 19 << 11 | 2 << 5 | 50);
01162 
01163 #endif /* __CONFIG_COMPILE_RTC */
01164 
01165 }
01166 
01167 #if _FS_REENTRANT
01168 
01181 __BOOL ff_cre_syncobj (u8 vol, _SYNC_t *sobj)
01182 {
01183     __BOOL ret = __FALSE;
01184 
01185     *sobj = __lockCreate();
01186     ret = (*sobj != __NULL) ? __TRUE : __FALSE;
01187 
01188     return ret;
01189 }
01190 
01191 
01204 BOOL ff_del_syncobj (_SYNC_t sobj) {
01205     __lockDestroy(sobj);
01206     return __TRUE;
01207 }
01208 
01221 BOOL ff_req_grant(_SYNC_t sobj) {
01222 __BOOL ret;
01223 
01224     ret = __lockOwn(sobj, _FS_TIMEOUT);
01225     return ret;
01226 }
01227 
01239 __VOID ff_rel_grant (_SYNC_t sobj)
01240 {
01241     __lockRelease(sobj);
01242 }
01243 
01244 #endif
01245 
01246 
01247 #if _USE_LFN == 3   /* LFN with a working buffer on the heap */
01248 
01260 __PVOID ff_memalloc (UINT size)
01261 {
01262     return __heapAlloc(size);
01263 }
01264 
01274 __VOID ff_memfree(__PVOID mblock)
01275 {
01276     __heapFree(mblock);
01277 }
01278 
01279 #endif // _USE_LFN
01280 
01297 #endif // __CONFIG_COMPILE_FAT
 All Data Structures Files Functions Variables Typedefs Defines