Companion: Russian UI (#7180)
[opentx.git] / radio / src / targets / horus / diskio.cpp
blobb9bcda011bb8eebfe56a20e816ccf21cfdcdfebf
1 /*
2 * Copyright (C) OpenTX
4 * Based on code named
5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
21 /* Low level disk I/O module skeleton for FatFs (C)ChaN, 2007 */
22 /*-----------------------------------------------------------------------*/
23 /* This is a stub disk I/O module that acts as front end of the existing */
24 /* disk I/O modules and attach it to FatFs module with common interface. */
25 /*-----------------------------------------------------------------------*/
27 #include "diskio.h"
28 #include <string.h>
29 #include "opentx.h"
30 #include "targets/common/arm/stm32/sdio_sd.h"
32 /*-----------------------------------------------------------------------*/
33 /* Lock / unlock functions */
34 /*-----------------------------------------------------------------------*/
35 #if !defined(BOOT)
36 static RTOS_MUTEX_HANDLE ioMutex;
37 uint32_t ioMutexReq = 0, ioMutexRel = 0;
38 int ff_cre_syncobj (BYTE vol, _SYNC_t *mutex)
40 *mutex = ioMutex;
41 return 1;
44 int ff_req_grant (_SYNC_t mutex)
46 ioMutexReq += 1;
47 RTOS_LOCK_MUTEX(mutex);
48 return 1;
51 void ff_rel_grant (_SYNC_t mutex)
53 ioMutexRel += 1;
54 RTOS_UNLOCK_MUTEX(mutex);
57 int ff_del_syncobj (_SYNC_t mutex)
59 return 1;
61 #endif
64 /*-----------------------------------------------------------------------*/
65 /* Inidialize a Drive */
67 DSTATUS disk_initialize (
68 BYTE drv /* Physical drive nmuber (0..) */
71 DSTATUS stat = 0;
73 /* Supports only single drive */
74 if (drv)
76 stat |= STA_NOINIT;
79 /*-------------------------- SD Init ----------------------------- */
80 SD_Error res = SD_Init();
81 if (res != SD_OK)
83 TRACE("SD_Init() failed: %d", res);
84 stat |= STA_NOINIT;
87 TRACE("SD card info:");
88 TRACE("sectors: %u", (uint32_t)(SDCardInfo.CardCapacity / 512));
89 TRACE("type: %u", (uint32_t)(SDCardInfo.CardType));
90 TRACE("EraseGrSize: %u", (uint32_t)(SDCardInfo.SD_csd.EraseGrSize));
91 TRACE("EraseGrMul: %u", (uint32_t)(SDCardInfo.SD_csd.EraseGrMul));
92 TRACE("ManufacturerID: %u", (uint32_t)(SDCardInfo.SD_cid.ManufacturerID));
94 return(stat);
97 DWORD scratch[BLOCK_SIZE / 4] __DMA;
99 /*-----------------------------------------------------------------------*/
100 /* Return Disk Status */
102 DSTATUS disk_status (
103 BYTE drv /* Physical drive nmuber (0..) */
106 DSTATUS stat = 0;
108 if (SD_Detect() != SD_PRESENT)
109 stat |= STA_NODISK;
111 // STA_NOTINIT - Subsystem not initailized
112 // STA_PROTECTED - Write protected, MMC/SD switch if available
114 return(stat);
117 uint32_t sdReadRetries = 0;
119 /*-----------------------------------------------------------------------*/
120 /* Read Sector(s) */
123 DRESULT disk_read_dma(BYTE drv, BYTE * buff, DWORD sector, UINT count)
125 // this functions assumes that buff is properly aligned and in the right RAM segment for DMA
126 DRESULT res;
127 SD_Error Status;
128 SDTransferState State;
129 for (int retry=0; retry<3; retry++) {
130 res = RES_OK;
131 if (count == 1) {
132 Status = SD_ReadBlock(buff, sector, BLOCK_SIZE); // 4GB Compliant
134 else {
135 Status = SD_ReadMultiBlocks(buff, sector, BLOCK_SIZE, count); // 4GB Compliant
137 if (Status == SD_OK) {
138 Status = SD_WaitReadOperation(200*count); // Check if the Transfer is finished
139 while ((State = SD_GetStatus()) == SD_TRANSFER_BUSY); // BUSY, OK (DONE), ERROR (FAIL)
140 if (State == SD_TRANSFER_ERROR) {
141 TRACE("State=SD_TRANSFER_ERROR, c: %u", sector, (uint32_t)count);
142 res = RES_ERROR;
144 else if (Status != SD_OK) {
145 TRACE("Status(WaitRead)=%d, s:%u c: %u", Status, sector, (uint32_t)count);
146 res = RES_ERROR;
149 else {
150 TRACE("Status(ReadBlock)=%d, s:%u c: %u", Status, sector, (uint32_t)count);
151 res = RES_ERROR;
153 if (res == RES_OK) break;
154 sdReadRetries += 1;
156 return res;
159 DRESULT __disk_read(BYTE drv, BYTE * buff, DWORD sector, UINT count)
161 // If unaligned, do the single block reads with a scratch buffer.
162 // If aligned and single sector, do a single block read.
163 // If aligned and multiple sectors, try multi block read.
164 // If multi block read fails, try single block reads without
165 // an intermediate buffer (move trough the provided buffer)
167 // TRACE("disk_read %d %p %10d %d", drv, buff, sector, count);
168 if (SD_Detect() != SD_PRESENT) {
169 TRACE("SD_Detect() != SD_PRESENT");
170 return RES_NOTRDY;
173 DRESULT res = RES_OK;
174 if (count == 0) return res;
176 if ((DWORD)buff < 0x20000000 || ((DWORD)buff & 3)) {
177 // buffer is not aligned, use scratch buffer that is aligned
178 TRACE("disk_read bad alignment (%p)", buff);
179 while (count--) {
180 res = disk_read_dma(drv, (BYTE *)scratch, sector++, 1);
181 if (res != RES_OK) break;
182 memcpy(buff, scratch, BLOCK_SIZE);
183 buff += BLOCK_SIZE;
185 return res;
188 res = disk_read_dma(drv, buff, sector, count);
189 if (res != RES_OK && count > 1) {
190 // multi-read failed, try reading same sectors, one by one
191 TRACE("disk_read() multi-block failed, trying single block reads...");
192 while (count--) {
193 res = disk_read_dma(drv, buff, sector++, 1);
194 if (res != RES_OK) break;
195 buff += BLOCK_SIZE;
198 return res;
201 /*-----------------------------------------------------------------------*/
202 /* Write Sector(s) */
204 #if _READONLY == 0
205 DRESULT __disk_write(
206 BYTE drv, /* Physical drive nmuber (0..) */
207 const BYTE *buff, /* Data to be written */
208 DWORD sector, /* Sector address (LBA) */
209 UINT count /* Number of sectors to write (1..255) */
212 SD_Error Status;
213 DRESULT res = RES_OK;
215 // TRACE("disk_write %d %p %10d %d", drv, buff, sector, count);
217 if (SD_Detect() != SD_PRESENT)
218 return(RES_NOTRDY);
220 if ((DWORD)buff < 0x20000000 || ((DWORD)buff & 3)) {
221 TRACE("disk_write bad alignment (%p)", buff);
222 while(count--) {
223 memcpy(scratch, buff, BLOCK_SIZE);
225 res = __disk_write(drv, (BYTE *)scratch, sector++, 1);
227 if (res != RES_OK)
228 break;
230 buff += BLOCK_SIZE;
232 return(res);
235 if (count == 1) {
236 Status = SD_WriteBlock((uint8_t *)buff, sector, BLOCK_SIZE); // 4GB Compliant
238 else {
239 Status = SD_WriteMultiBlocks((uint8_t *)buff, sector, BLOCK_SIZE, count); // 4GB Compliant
242 if (Status == SD_OK) {
243 SDTransferState State;
245 Status = SD_WaitWriteOperation(500*count); // Check if the Transfer is finished
247 while((State = SD_GetStatus()) == SD_TRANSFER_BUSY); // BUSY, OK (DONE), ERROR (FAIL)
249 if ((State == SD_TRANSFER_ERROR) || (Status != SD_OK)) {
250 TRACE("__disk_write() err, st:%d,%d, s:%u c: %u", Status, State, sector, (uint32_t)count);
251 res = RES_ERROR;
254 else {
255 res = RES_ERROR;
258 // TRACE("result=%d", res);
259 return res;
261 #endif /* _READONLY */
263 /*-----------------------------------------------------------------------*/
264 /* Miscellaneous Functions */
266 DRESULT disk_ioctl (
267 BYTE drv, /* Physical drive nmuber (0..) */
268 BYTE ctrl, /* Control code */
269 void *buff /* Buffer to send/receive control data */
272 DRESULT res;
274 if (drv) return RES_PARERR;
276 res = RES_ERROR;
278 switch (ctrl) {
279 case GET_SECTOR_COUNT : /* Get number of sectors on the disk (DWORD) */
280 // use 512 for sector size, SDCardInfo.CardBlockSize is not sector size and can be 1024 for 2G SD cards!!!!
281 *(DWORD*)buff = SDCardInfo.CardCapacity / BLOCK_SIZE;
282 res = RES_OK;
283 break;
285 case GET_SECTOR_SIZE : /* Get R/W sector size (WORD) */
286 *(WORD*)buff = BLOCK_SIZE; // force sector size. SDCardInfo.CardBlockSize is not sector size and can be 1024 for 2G SD cards!!!!
287 res = RES_OK;
288 break;
290 case GET_BLOCK_SIZE : /* Get erase block size in unit of sector (DWORD) */
291 // TODO verify that this is the correct value
292 *(DWORD*)buff = (uint32_t)SDCardInfo.SD_csd.EraseGrSize * (uint32_t)SDCardInfo.SD_csd.EraseGrMul;
293 res = RES_OK;
294 break;
296 case CTRL_SYNC:
297 while (SD_GetStatus() == SD_TRANSFER_BUSY); /* Complete pending write process (needed at _FS_READONLY == 0) */
298 res = RES_OK;
299 break;
301 default:
302 res = RES_OK;
303 break;
307 return res;
310 // TODO everything here should not be in the driver layer ...
312 FATFS g_FATFS_Obj __DMA; // initialized in boardInit()
313 #if defined(LOG_TELEMETRY)
314 FIL g_telemetryFile = {};
315 #endif
317 #if defined(BOOT)
318 void sdInit(void)
320 if (f_mount(&g_FATFS_Obj, "", 1) == FR_OK) {
321 f_chdir("/");
324 #else
325 void sdInit()
327 TRACE("sdInit");
329 ioMutex = CoCreateMutex();
330 if (ioMutex >= CFG_MAX_MUTEX) {
331 // sd error
332 return;
334 sdMount();
337 void sdMount()
339 TRACE("sdMount");
341 diskCache.clear();
343 if (f_mount(&g_FATFS_Obj, "", 1) == FR_OK) {
344 // call sdGetFreeSectors() now because f_getfree() takes a long time first time it's called
345 sdGetFreeSectors();
347 #if defined(LOG_TELEMETRY)
348 f_open(&g_telemetryFile, LOGS_PATH "/telemetry.log", FA_OPEN_ALWAYS | FA_WRITE);
349 if (f_size(&g_telemetryFile) > 0) {
350 f_lseek(&g_telemetryFile, f_size(&g_telemetryFile)); // append
352 #endif
354 else {
355 TRACE("f_mount() failed");
359 void sdDone()
361 TRACE("sdDone");
363 if (sdMounted()) {
364 audioQueue.stopSD();
365 #if defined(LOG_TELEMETRY)
366 f_close(&g_telemetryFile);
367 #endif
368 f_mount(nullptr, "", 0); // unmount SD
371 #endif
373 uint32_t sdMounted()
375 return g_FATFS_Obj.fs_type != 0;
378 uint32_t sdIsHC()
380 return true; // TODO (CardType & CT_BLOCK);
383 uint32_t sdGetSpeed()
385 return 330000;