1 /*
2  * Copyright (c) 2016-2018, Texas Instruments Incorporated
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * *  Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * *  Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * *  Neither the name of Texas Instruments Incorporated nor the names of
17  *    its contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <stdbool.h>
34 #include <stdint.h>
35 #include <stdlib.h>
36 
37 /*
38  * By default disable both asserts and log for this module.
39  * This must be done before DebugP.h is included.
40  */
41 #ifndef DebugP_ASSERT_ENABLED
42 #define DebugP_ASSERT_ENABLED 0
43 #endif
44 #ifndef DebugP_LOG_ENABLED
45 #define DebugP_LOG_ENABLED 0
46 #endif
47 
48 #include <ti/drivers/dpl/DebugP.h>
49 #include <ti/drivers/dpl/HwiP.h>
50 #include <ti/drivers/SD.h>
51 #include <ti/drivers/SDFatFS.h>
52 
53 #include <third_party/fatfs/ff.h>
54 
55 /* SDFatFS Specific Defines */
56 #define DRIVE_NOT_MOUNTED    (~(0U))
57 
58 extern const SDFatFS_Config SDFatFS_config[];
59 extern const uint_least8_t SDFatFS_count;
60 
61 static bool isInitialized = false;
62 
63 /*
64  * Array of SDFatFS_Handles to determine the association of the
65  * FatFs drive number with a SDFatFS_Handle.
66  * FF_VOLUMES is defined in <third_party/fatfs/ffconf.h>.
67  */
68 static SDFatFS_Handle sdFatFSHandles[FF_VOLUMES];
69 
70 /* FatFS function prototypes */
71 DSTATUS SDFatFS_diskInitialize(BYTE drive);
72 DRESULT SDFatFS_diskIOctrl(BYTE drive, BYTE ctrl, void *buffer);
73 DRESULT SDFatFS_diskRead(BYTE drive, BYTE *buffer,
74     DWORD sector, UINT secCount);
75 DSTATUS SDFatFS_diskStatus(BYTE drive);
76 DRESULT SDFatFS_diskWrite(BYTE drive, const BYTE *buffer,
77     DWORD sector, UINT secCount);
78 
79 /*
80  *  ======== SDFatFS_close ========
81  */
SDFatFS_close(SDFatFS_Handle handle)82 void SDFatFS_close(SDFatFS_Handle handle)
83 {
84     TCHAR           path[3];
85     DRESULT         dresult;
86     FRESULT         fresult;
87     SDFatFS_Object *obj = handle->object;
88 
89     /* Construct base directory path */
90     path[0] = (TCHAR)'0' + obj->driveNum;
91     path[1] = (TCHAR)':';
92     path[2] = (TCHAR)'\0';
93 
94     /* Close the SD driver */
95     SD_close(obj->sdHandle);
96 
97     /* Unmount the FatFs drive */
98     fresult = f_mount(NULL, path, 0);
99     if (fresult != FR_OK) {
100         DebugP_log1("SDFatFS: Could not unmount FatFs volume @ drive"
101             " number %d", obj->driveNum);
102     }
103 
104     /* Unregister the disk_*() functions */
105     dresult = disk_unregister(obj->driveNum);
106     if (dresult != RES_OK) {
107         DebugP_log1("SDFatFS: Error unregistering disk"
108             " functions @ drive number %d", obj->driveNum);
109     }
110 
111     obj->driveNum = DRIVE_NOT_MOUNTED;
112     DebugP_log0("SDFatFS closed");
113 }
114 
115 /*
116  *  ======== SDFatFS_diskInitialize ========
117  */
SDFatFS_diskInitialize(BYTE drive)118 DSTATUS SDFatFS_diskInitialize(BYTE drive)
119 {
120     int_fast8_t     result;
121     SDFatFS_Object *obj = sdFatFSHandles[drive]->object;
122 
123     result = SD_initialize(obj->sdHandle);
124 
125     /* Convert lower level driver status code */
126     if (result == SD_STATUS_SUCCESS) {
127         obj->diskState = ((DSTATUS) obj->diskState) & ~((DSTATUS)STA_NOINIT);
128     }
129 
130     return (obj->diskState);
131 }
132 
133 /*
134  *  ======== SDFatFS_diskIOctrl ========
135  *  Function to perform specified disk operations. This function is called by the
136  *  FatFs module and must not be called by the application!
137  */
SDFatFS_diskIOctrl(BYTE drive,BYTE ctrl,void * buffer)138 DRESULT SDFatFS_diskIOctrl(BYTE drive, BYTE ctrl, void *buffer)
139 {
140     SDFatFS_Object *obj   = sdFatFSHandles[drive]->object;
141     DRESULT         fatfsRes = RES_ERROR;
142 
143     switch (ctrl) {
144         case CTRL_SYNC:
145             fatfsRes = RES_OK;
146             break;
147 
148         case (BYTE)GET_SECTOR_COUNT:
149             *(uint32_t*)buffer = (uint32_t)SD_getNumSectors(obj->sdHandle);
150 
151             DebugP_log1("SDFatFS: Disk IO control: sector count: %d",
152                 *(uint32_t*)buffer);
153             fatfsRes = RES_OK;
154             break;
155 
156         case (BYTE)GET_SECTOR_SIZE:
157             *(WORD*)buffer = (WORD)SD_getSectorSize(obj->sdHandle);
158             DebugP_log1("SDFatFS: Disk IO control: sector size: %d",
159                 *(WORD*)buffer);
160             fatfsRes = RES_OK;
161             break;
162 
163         case (BYTE)GET_BLOCK_SIZE:
164             *(WORD*)buffer = (WORD)SD_getSectorSize(obj->sdHandle);
165             DebugP_log1("SDFatFS: Disk IO control: block size: %d",
166                 *(WORD*)buffer);
167             fatfsRes = RES_OK;
168             break;
169 
170         default:
171             DebugP_log0("SDFatFS: Disk IO control parameter error");
172             fatfsRes = RES_PARERR;
173             break;
174     }
175     return (fatfsRes);
176 }
177 
178 /*
179  *  ======== SDFatFS_diskRead ========
180  *  Function to perform a disk read from the SDCard. This function is called by
181  *  the FatFs module and must not be called by the application!
182  */
SDFatFS_diskRead(BYTE drive,BYTE * buffer,DWORD sector,UINT secCount)183 DRESULT SDFatFS_diskRead(BYTE drive, BYTE *buffer,
184     DWORD sector, UINT secCount)
185 {
186     int_fast32_t    result;
187     DRESULT         fatfsRes = RES_ERROR;
188     SDFatFS_Object *obj   = sdFatFSHandles[drive]->object;
189 
190     /* Return if disk not initialized */
191     if ((obj->diskState & (DSTATUS)STA_NOINIT) != 0) {
192         fatfsRes = RES_PARERR;
193     }
194     else {
195         result = SD_read(obj->sdHandle, (uint_least8_t *)buffer,
196             (int_least32_t)sector, (uint_least32_t)secCount);
197 
198         /* Convert lower level driver status code */
199         if (result == SD_STATUS_SUCCESS) {
200             fatfsRes = RES_OK;
201         }
202     }
203 
204     return (fatfsRes);
205 }
206 
207 /*
208  *  ======== SDFatFS_diskStatus ========
209  *  Function to return the current disk status. This function is called by
210  *  the FatFs module and must not be called by the application!
211  */
SDFatFS_diskStatus(BYTE drive)212 DSTATUS SDFatFS_diskStatus(BYTE drive)
213 {
214     return (((SDFatFS_Object *)sdFatFSHandles[drive]->object)->diskState);
215 }
216 
217 
218 #if (_READONLY == 0)
219 /*
220  *  ======== SDFatFS_diskWrite ========
221  *  Function to perform a write to the SDCard. This function is called by
222  *  the FatFs module and must not be called by the application!
223  */
SDFatFS_diskWrite(BYTE drive,const BYTE * buffer,DWORD sector,UINT secCount)224 DRESULT SDFatFS_diskWrite(BYTE drive, const BYTE *buffer, DWORD sector,
225     UINT secCount)
226 {
227     int_fast32_t    result;
228     DRESULT         fatfsRes = RES_ERROR;
229     SDFatFS_Object *obj = sdFatFSHandles[drive]->object;
230 
231     /* Return if disk not initialized */
232     if ((obj->diskState & (DSTATUS)STA_NOINIT) != 0) {
233         fatfsRes = RES_PARERR;
234     }
235     else {
236         result = SD_write(obj->sdHandle, (const uint_least8_t *)buffer,
237             (int_least32_t)sector, (uint_least32_t)secCount);
238 
239         /* Convert lower level driver status code */
240         if (result == SD_STATUS_SUCCESS) {
241             fatfsRes = RES_OK;
242         }
243     }
244 
245     return (fatfsRes);
246 }
247 #endif
248 
249 /*
250  *  ======== SDFatFS_init ========
251  */
SDFatFS_init(void)252 void SDFatFS_init(void)
253 {
254     uint_least8_t   i;
255     uint_fast32_t   key;
256     SDFatFS_Object *obj;
257 
258     key = HwiP_disable();
259 
260     if (!isInitialized) {
261         isInitialized = (bool) true;
262 
263         /* Initialize each SDFatFS object */
264         for (i = 0; i < SDFatFS_count; i++) {
265             obj = ((SDFatFS_Handle)&(SDFatFS_config[i]))->object;
266 
267             obj->diskState = STA_NOINIT;
268             obj->driveNum = DRIVE_NOT_MOUNTED;
269         }
270 
271         /* Initialize the SD Driver */
272         SD_init();
273     }
274 
275     HwiP_restore(key);
276 }
277 
278 
279 /*
280  *  ======== SDFatFS_open ========
281  *  Note: The index passed into this function must correspond directly
282  *  to the SD driver index.
283  */
SDFatFS_open(uint_least8_t idx,uint_least8_t drive)284 SDFatFS_Handle SDFatFS_open(uint_least8_t idx, uint_least8_t drive)
285 {
286     uintptr_t       key;
287     DRESULT         dresult;
288     FRESULT         fresult;
289     TCHAR           path[3];
290     SDFatFS_Handle  handle = NULL;
291     SDFatFS_Object *obj;
292 
293     /* Verify driver index and state */
294     if (isInitialized && (idx < SDFatFS_count)) {
295         /* Get handle for this driver instance */
296         handle = (SDFatFS_Handle)&(SDFatFS_config[idx]);
297         obj = handle->object;
298 
299         /* Determine if the device was already opened */
300         key = HwiP_disable();
301         if (obj->driveNum != DRIVE_NOT_MOUNTED) {
302             HwiP_restore(key);
303             DebugP_log1("SDFatFS Drive %d already in use!", obj->driveNum);
304             handle = NULL;
305         }
306         else {
307             obj->driveNum = drive;
308 
309             /* Open SD Driver */
310             obj->sdHandle = SD_open(idx, NULL);
311 
312             HwiP_restore(key);
313 
314             if (obj->sdHandle == NULL) {
315                 obj->driveNum = DRIVE_NOT_MOUNTED;
316                 /* Error occurred in lower level driver */
317                 handle = NULL;
318             }
319             else {
320 
321                 /* Register FATFS Functions */
322                 dresult = disk_register(obj->driveNum,
323                     SDFatFS_diskInitialize,
324                     SDFatFS_diskStatus,
325                     SDFatFS_diskRead,
326                     SDFatFS_diskWrite,
327                     SDFatFS_diskIOctrl);
328 
329                 /* Check for drive errors */
330                 if (dresult != RES_OK) {
331                     DebugP_log0("SDFatFS: Disk functions not registered");
332                     SDFatFS_close(handle);
333                     handle = NULL;
334                 }
335                 else {
336 
337                     /* Construct base directory path */
338                     path[0] = (TCHAR)'0' + obj->driveNum;
339                     path[1] = (TCHAR)':';
340                     path[2] = (TCHAR)'\0';
341 
342                     /*
343                      * Register the filesystem with FatFs. This operation does
344                      * not access the SDCard yet.
345                      */
346                     fresult = f_mount(&(obj->filesystem), path, 0);
347                     if (fresult != FR_OK) {
348                         DebugP_log1("SDFatFS: Drive %d not mounted",
349                                     obj->driveNum);
350 
351                         SDFatFS_close(handle);
352                         handle = NULL;
353                     }
354                     else {
355 
356                         /*
357                          * Store the new sdfatfs handle for the input drive
358                          * number
359                          */
360                         sdFatFSHandles[obj->driveNum] = handle;
361 
362                         DebugP_log0("SDFatFS: opened");
363                     }
364                 }
365             }
366         }
367     }
368 
369     return (handle);
370 }
371