/* * Copyright (C) 2016 Michel Rottleuthner * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level * directory for more details. */ /** * @ingroup sys_fatfs_diskio * @{ * * @file * @brief Implementation of fatfs interface that supports sdcard_spi driver * based on low level disk I/O module example for FatFs by ChaN, 2016 * * @author Michel Rottleuthner * * @} */ #include "fatfs/diskio.h" /* FatFs lower layer API */ #include "fatfs_diskio_common.h" #include "fatfs/ffconf.h" #include "fatfs/integer.h" #include "sdcard_spi.h" #include "sdcard_spi_internal.h" #include "sdcard_spi_params.h" #include #include #include "periph_conf.h" #include "periph/rtc.h" #include "xtimer.h" #include "debug.h" #define NUM_OF_SD_CARDS (sizeof(sdcard_spi_params) / sizeof(sdcard_spi_params[0])) extern sdcard_spi_t sdcard_spi_devs[NUM_OF_SD_CARDS]; static inline sdcard_spi_t *get_sd_card(int idx) { if (idx < NUM_OF_SD_CARDS) { return &(sdcard_spi_devs[idx]); } return NULL; } /** * @brief returns the status of the disk * * @param[in] pdrv drive number to identify the drive * * @return STA_NODISK if no disk exists with the given id * @return 0 if disk is initialized * @return STA_NOINIT if disk id exists, but disk isn't initialized */ DSTATUS disk_status(BYTE pdrv) { sdcard_spi_t *card = get_sd_card(pdrv); if (card == NULL) { return STA_NODISK; } else if (card->init_done) { return FATFS_DISKIO_DSTASTUS_OK; } return STA_NOINIT; } /** * @brief initializes the disk * * @param[in] pdrv drive number to identify the drive * * @return STA_NODISK if no disk exists with the given id * @return 0 if disk was initialized successfully * @return STA_NOINIT if disk id exists, but couldn't be initialized */ DSTATUS disk_initialize(BYTE pdrv) { sdcard_spi_t *card = get_sd_card(pdrv); if (card == NULL) { return STA_NODISK; } else if (sdcard_spi_init(card, &sdcard_spi_params[pdrv]) == 0) { return FATFS_DISKIO_DSTASTUS_OK; } return STA_NOINIT; } /** * @brief reads sectors from disk * * @param[in] pdrv drive number to identify the drive * @param[out] buff Data buffer to store read data * @param[in] sector Start sector in LBA * @param[in] count Number of sectors to read * * @return RES_OK if no error occurred * @return RES_NOTRDY if data wasn't read completely */ DRESULT disk_read(BYTE pdrv, BYTE *buff, DWORD sector, UINT count) { sdcard_spi_t *card = get_sd_card(pdrv); if ((card != NULL) && card->init_done) { sd_rw_response_t state; if (count != sdcard_spi_read_blocks(card, sector, (char *)buff, SD_HC_BLOCK_SIZE, count, &state)) { printf("[ERROR] disk_read: sdcard_spi_read_blocks: %d\n", state); return RES_NOTRDY; } return RES_OK; } return RES_NOTRDY; } /** * @brief writes sectors to disk * * @param[in] pdrv Physical drive nmuber to identify the drive * @param[in] buff Data to be written * @param[in] sector Start sector in LBA * @param[in] count Number of sectors to write * * @return RES_OK if no error occurred * @return RES_NOTRDY if data wasn't written completely */ DRESULT disk_write(BYTE pdrv, const BYTE *buff, DWORD sector, UINT count) { sdcard_spi_t *card = get_sd_card(pdrv); if ((card != NULL) && card->init_done) { sd_rw_response_t state; if (count != sdcard_spi_write_blocks(card, sector, (char *)buff, SD_HC_BLOCK_SIZE, count, &state)) { printf("[ERROR] disk_write: sdcard_spi_write_blocks: %d\n", state); return RES_NOTRDY; } return RES_OK; } return RES_NOTRDY; } /** * @brief perform miscellaneous low-level control functions * * @param[in] pdrv Physical drive nmuber (0..) * @param[in out] cmd Control code * @param[in] sector Buffer to send/receive control data * * @return RES_OK if no error occurred * @return RES_ERROR if an error occurred * @return RES_PARERR if an error occurred */ DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff) { #if (_USE_MKFS == 1) sdcard_spi_t *card = get_sd_card(pdrv); #endif switch (cmd) { #if (_FS_READONLY == 0) case CTRL_SYNC: /* r/w is always finished within r/w-functions of sdcard_spi */ return RES_OK; #endif #if (_USE_MKFS == 1) case GET_SECTOR_COUNT: if ((card != NULL) && card->init_done) { *(DWORD *)buff = sdcard_spi_get_sector_count(card); return RES_OK; } else { return RES_ERROR; } case GET_BLOCK_SIZE: if ((card != NULL) && card->init_done) { /* erase block size in unit of sector */ *(DWORD *)buff = sdcard_spi_get_au_size(card) / SD_HC_BLOCK_SIZE; return RES_OK; } *(DWORD *)buff = 0; return RES_ERROR; #endif #if (_MAX_SS != _MIN_SS) case GET_SECTOR_SIZE: *buff = SD_HC_BLOCK_SIZE; return RES_OK; #endif #if (_USE_TRIM == 1) case CTRL_TRIM: return RES_OK; #endif } return RES_PARERR; }