From a5531fb1bec984c61bcb4526fff3f1e34dce0d28 Mon Sep 17 00:00:00 2001 From: Peter Weingartner Date: Mon, 8 Jul 2024 16:56:37 -0400 Subject: [PATCH] Updated FatFS, and new SD support... able to read directories --- .gitignore | 1 + src/dev/Makefile | 2 +- src/dev/block.c | 18 +- src/dev/fsys.c | 15 +- src/dev/rtc.c | 85 +-- src/dev/sdc.c | 2 +- src/dev/sdc_f256.c | 570 ++++++++++++++++ src/dev/sdc_f256.h | 41 ++ src/fatfs/00history.txt | 10 + src/fatfs/00readme.txt | 2 +- src/fatfs/Makefile | 20 +- src/fatfs/c256_diskio.c | 152 ----- src/fatfs/diskio.bak | 229 ------- src/fatfs/f256xe_diskio.c | 832 ++++++++++++++++++++++++ src/fatfs/{diskio.h => f256xe_diskio.h} | 0 src/fatfs/f256xe_diskio_spi.c | 548 ++++++++++++++++ src/fatfs/f256xe_diskio_spi.h | 38 ++ src/fatfs/ff.c | 600 ++++++++++------- src/fatfs/ff.h | 69 +- src/fatfs/ffconf.h | 56 +- src/fatfs/ffconf_new.h | 275 ++++++++ src/fatfs/ffsystem.c | 300 +++++---- src/fatfs/ffunicode.c | 44 +- src/fatfs/toolbox_bdev.c | 95 +++ src/fatfs/toolbox_bdev.h | 86 +++ src/include/F256/sdc_f256.h | 14 - src/include/F256/sdc_spi.h | 30 + src/include/constants.h | 16 +- src/include/errors.h | 1 + src/include/sys_types.h | 17 +- src/toolbox.c | 103 ++- 31 files changed, 3322 insertions(+), 949 deletions(-) create mode 100644 src/dev/sdc_f256.c create mode 100644 src/dev/sdc_f256.h delete mode 100644 src/fatfs/c256_diskio.c delete mode 100644 src/fatfs/diskio.bak create mode 100644 src/fatfs/f256xe_diskio.c rename src/fatfs/{diskio.h => f256xe_diskio.h} (100%) create mode 100644 src/fatfs/f256xe_diskio_spi.c create mode 100644 src/fatfs/f256xe_diskio_spi.h create mode 100644 src/fatfs/ffconf_new.h create mode 100644 src/fatfs/toolbox_bdev.c create mode 100644 src/fatfs/toolbox_bdev.h delete mode 100644 src/include/F256/sdc_f256.h create mode 100644 src/include/F256/sdc_spi.h diff --git a/.gitignore b/.gitignore index fd888cc..98c55cd 100644 --- a/.gitignore +++ b/.gitignore @@ -51,3 +51,4 @@ Module.symvers Mkfile.old dkms.conf .vscode/settings.json +/misc/F256xE_Kernal_Code diff --git a/src/dev/Makefile b/src/dev/Makefile index 00668d0..c729b3b 100644 --- a/src/dev/Makefile +++ b/src/dev/Makefile @@ -37,7 +37,7 @@ else ifeq ($(UNIT),F256) AS=as65816 AR=nlib - SRCS_FOR_UNIT=txt_f256.c kbd_f256k.c indicators_c256.c interrupts_f256.c # timers_c256.c + SRCS_FOR_UNIT=txt_f256.c kbd_f256k.c indicators_c256.c interrupts_f256.c sdc_f256.c # timers_c256.c CFLAGS_FOR_UNIT=-DMODEL=2 -DCPU=255 --code-model large --data-model large # --target Foenix endif diff --git a/src/dev/block.c b/src/dev/block.c index f38ca97..4f995ef 100644 --- a/src/dev/block.c +++ b/src/dev/block.c @@ -9,6 +9,8 @@ #include "log.h" #include "block.h" +#include "uart.h" +#include t_dev_block g_block_devs[BDEV_DEVICES_MAX]; @@ -41,6 +43,7 @@ SYSTEMCALL short bdev_register(p_dev_block device) { p_dev_block bdev = &g_block_devs[dev]; bdev->number = device->number; bdev->name = device->name; + bdev->data = device->data; bdev->init = device->init; bdev->read = device->read; bdev->write = device->write; @@ -71,8 +74,9 @@ short bdev_init(short dev) { if (dev < BDEV_DEVICES_MAX) { p_dev_block bdev = &g_block_devs[dev]; - if (bdev->number == dev) - ret = bdev->init(); + if (bdev->number == dev) { + ret = bdev->init(bdev); + } } TRACE1("bdev_init returning %d", (int)ret); @@ -99,7 +103,7 @@ SYSTEMCALL short bdev_read(short dev, long lba, unsigned char * buffer, short si if (dev < BDEV_DEVICES_MAX) { p_dev_block bdev = &g_block_devs[dev]; if (bdev->number == dev) - ret = bdev->read(lba, buffer, size); + ret = bdev->read(bdev, lba, buffer, size); } TRACE1("bdev_read returning %d", (int)ret); @@ -126,7 +130,7 @@ SYSTEMCALL short bdev_write(short dev, long lba, const unsigned char * buffer, s if (dev < BDEV_DEVICES_MAX) { p_dev_block bdev = &g_block_devs[dev]; if (bdev->number == dev) - ret = bdev->write(lba, buffer, size); + ret = bdev->write(bdev, lba, buffer, size); } TRACE1("bdev_write returning %d", (int)ret); @@ -150,7 +154,7 @@ SYSTEMCALL short bdev_status(short dev) { if (dev < BDEV_DEVICES_MAX) { p_dev_block bdev = &g_block_devs[dev]; if (bdev->number == dev) - ret = bdev->status(); + ret = bdev->status(bdev); } TRACE1("bdev_status returning %d", (int)ret); @@ -174,7 +178,7 @@ SYSTEMCALL short bdev_flush(short dev) { if (dev < BDEV_DEVICES_MAX) { p_dev_block bdev = &g_block_devs[dev]; if (bdev->number == dev) - return bdev->flush(); + return bdev->flush(bdev); } TRACE1("bdev_flush returning %d", (int)ret); @@ -201,7 +205,7 @@ SYSTEMCALL short bdev_ioctrl(short dev, short command, unsigned char * buffer, s if (dev < BDEV_DEVICES_MAX) { p_dev_block bdev = &g_block_devs[dev]; if (bdev->number == dev) - ret = bdev->ioctrl(command, buffer, size); + ret = bdev->ioctrl(bdev, command, buffer, size); } TRACE1("bdev_ioctrl returning %d", (int)ret); diff --git a/src/dev/fsys.c b/src/dev/fsys.c index c3af0e8..af4b0c2 100644 --- a/src/dev/fsys.c +++ b/src/dev/fsys.c @@ -6,6 +6,9 @@ * */ +#include "log_level.h" +#define DEFAULT_LOG_LEVEL LOG_INFO + #include #include #include @@ -239,6 +242,7 @@ SYSTEMCALL short fsys_opendir(const char * path) { } if (fres != FR_OK) { /* If there was a problem, return an error number */ + ERROR1("FATFS Error: %d", fres); return fatfs_to_foenix(fres); } else { /* Otherwise, allocate and return the handle */ @@ -827,8 +831,9 @@ short fsys_mount(short bdev) { drive[2] = 0; fres = f_mount(&g_drive[bdev], drive, 0); + INFO1("fsys_mount called f_mount: %d", fres); if (fres != FR_OK) { - DEBUG1("Unable to mount drive: %s", drive); + ERROR2("Unable to mount drive %s, FatFS Error: %d", drive, fres); return fatfs_to_foenix(fres); } else { return 0; @@ -1507,7 +1512,7 @@ short fsys_init() { /* Set the default working directory. * TODO: set this based on the boot drive. */ - strcpy(g_current_directory, "/sd"); + strcpy(g_current_directory, "/sd0"); /* Mark all directories as available */ for (i = 0; i < MAX_DIRECTORIES; i++) { @@ -1524,7 +1529,11 @@ short fsys_init() { for (i = 0; i < MAX_DRIVES; i++) { short res = sys_bdev_status((short)i); if (res >= 0) { - fsys_mount(i); + INFO1("Mounting drive #%d", i); + short result = fsys_mount(i); + if (result < 0) { + ERROR2("Could not mount device %d: %d", i, result); + } } } diff --git a/src/dev/rtc.c b/src/dev/rtc.c index 2c170a2..62d8846 100644 --- a/src/dev/rtc.c +++ b/src/dev/rtc.c @@ -2,6 +2,9 @@ * Definitions for access the bq4802LY real time clock */ +#include "log_level.h" +#define DEFAULT_LOG_LEVEL LOG_ERROR + #include "log.h" #include "interrupt.h" #include "gabe_reg.h" @@ -121,13 +124,13 @@ SYSTEMCALL void rtc_set_time(p_time time) { minute_bcd = i_to_bcd(time->minute); second_bcd = i_to_bcd(time->second); - log_num(LOG_INFO, "Century: ", century_bcd); - log_num(LOG_INFO, "Year: ", year_bcd); - log_num(LOG_INFO, "Month: ", month_bcd); - log_num(LOG_INFO, "Day: ", day_bcd); - log_num(LOG_INFO, "Hour: ", hour_bcd); - log_num(LOG_INFO, "Minute: ", minute_bcd); - log_num(LOG_INFO, "Second: ", second_bcd); + INFO1("Century: %02d", century_bcd); + INFO1("Year: %04d", year_bcd); + INFO1("Month: %02d", month_bcd); + INFO1("Day: %02d", day_bcd); + INFO1("Hour: %02d", hour_bcd); + INFO1("Minute: %02d", minute_bcd); + INFO1("Second: %02d", second_bcd); if (!time->is_24hours) { if (time->is_pm) { @@ -140,11 +143,11 @@ SYSTEMCALL void rtc_set_time(p_time time) { /* Temporarily disable updates to the clock */ ctrl = *RTC_CTRL; *RTC_CTRL = ctrl | RTC_UTI; - log(LOG_INFO, "RTC Disabled"); - log_num(LOG_INFO, "RTC Rates: ", *RTC_RATES); - log_num(LOG_INFO, "RTC Enables: ", *RTC_ENABLES); - log_num(LOG_INFO, "RTC Flags: ", *RTC_FLAGS); - log_num(LOG_INFO, "RTC Control: ", *RTC_CTRL); + INFO("RTC Disabled"); + INFO1("RTC Rates: %02x", *RTC_RATES); + INFO1("RTC Enables: %02x", *RTC_ENABLES); + INFO1("RTC Flags: %02x", *RTC_FLAGS); + INFO1("RTC Control: %02x", *RTC_CTRL); /* Set the time in the RTC */ @@ -165,13 +168,13 @@ SYSTEMCALL void rtc_set_time(p_time time) { hour_bcd = *RTC_HOUR; minute_bcd = *RTC_MIN; second_bcd = *RTC_SEC; - log_num(LOG_INFO, "REG Century: ", century_bcd); - log_num(LOG_INFO, "REG Year: ", year_bcd); - log_num(LOG_INFO, "REG Month: ", month_bcd); - log_num(LOG_INFO, "REG Day: ", day_bcd); - log_num(LOG_INFO, "REG Hour: ", hour_bcd); - log_num(LOG_INFO, "REG Minute: ", minute_bcd); - log_num(LOG_INFO, "REG Second: ", second_bcd); + INFO1("REG Century: %02d", century_bcd); + INFO1("REG Year: %02d", year_bcd); + INFO1("REG Month: %02d", month_bcd); + INFO1("REG Day: %02d", day_bcd); + INFO1("REG Hour: %02d", hour_bcd); + INFO1("REG Minute: %02d", minute_bcd); + INFO1("REG Second: %02d", second_bcd); /* Set the 24/12 hour control bit if needed */ if (time->is_24hours) { @@ -180,11 +183,11 @@ SYSTEMCALL void rtc_set_time(p_time time) { /* Re-enable updates to the clock */ *RTC_CTRL = (ctrl & 0x07) | RTC_STOP; - log(LOG_INFO, "RTC Enabled"); - log_num(LOG_INFO, "RTC Rates: ", *RTC_RATES); - log_num(LOG_INFO, "RTC Enables: ", *RTC_ENABLES); - log_num(LOG_INFO, "RTC Flags: ", *RTC_FLAGS); - log_num(LOG_INFO, "RTC Control: ", *RTC_CTRL); + INFO("RTC Enabled"); + INFO1("RTC Rates: %02x", *RTC_RATES); + INFO1("RTC Enables: %02x", *RTC_ENABLES); + INFO1("RTC Flags: %02x", *RTC_FLAGS); + INFO1("RTC Control: %02x", *RTC_CTRL); } /* @@ -201,11 +204,11 @@ SYSTEMCALL void rtc_get_time(p_time time) { /* Temporarily disable updates to the clock */ ctrl = *RTC_CTRL; *RTC_CTRL = ctrl | RTC_UTI; - log(LOG_INFO, "RTC Disabled"); - log_num(LOG_INFO, "RTC Rates: ", *RTC_RATES); - log_num(LOG_INFO, "RTC Enables: ", *RTC_ENABLES); - log_num(LOG_INFO, "RTC Flags: ", *RTC_FLAGS); - log_num(LOG_INFO, "RTC Control: ", *RTC_CTRL); + INFO("RTC Disabled"); + INFO1("RTC Rates: %02x", *RTC_RATES); + INFO1("RTC Enables: %02x", *RTC_ENABLES); + INFO1("RTC Flags: %02x", *RTC_FLAGS); + INFO1("RTC Control: %02x", *RTC_CTRL); if (*RTC_CTRL & RTC_2412) { time->is_24hours = 1; @@ -223,19 +226,19 @@ SYSTEMCALL void rtc_get_time(p_time time) { /* Re-enable updates to the clock */ *RTC_CTRL = (ctrl & 0x07) | RTC_STOP; - log(LOG_INFO, "RTC Enabled"); - log_num(LOG_INFO, "RTC Rates: ", *RTC_RATES); - log_num(LOG_INFO, "RTC Enables: ", *RTC_ENABLES); - log_num(LOG_INFO, "RTC Flags: ", *RTC_FLAGS); - log_num(LOG_INFO, "RTC Control: ", *RTC_CTRL); + INFO("RTC Enabled"); + INFO1("RTC Rates: %02x", *RTC_RATES); + INFO1("RTC Enables: %02x", *RTC_ENABLES); + INFO1("RTC Flags: %02x", *RTC_FLAGS); + INFO1("RTC Control: %02x", *RTC_CTRL); - log_num(LOG_INFO, "Century: ", century_bcd); - log_num(LOG_INFO, "Year: ", year_bcd); - log_num(LOG_INFO, "Month: ", month_bcd); - log_num(LOG_INFO, "Day: ", day_bcd); - log_num(LOG_INFO, "Hour: ", hour_bcd); - log_num(LOG_INFO, "Minute: ", minute_bcd); - log_num(LOG_INFO, "Second: ", second_bcd); + INFO1("Century: %02d", century_bcd); + INFO1("Year: %02d", year_bcd); + INFO1("Month: %02d", month_bcd); + INFO1("Day: %02d", day_bcd); + INFO1("Hour: %02d", hour_bcd); + INFO1("Minute: %02d", minute_bcd); + INFO1("Second: %02d", second_bcd); /* Fill out the time record */ diff --git a/src/dev/sdc.c b/src/dev/sdc.c index c85a80c..c8d09e9 100644 --- a/src/dev/sdc.c +++ b/src/dev/sdc.c @@ -421,7 +421,7 @@ short sdc_ioctrl(short command, unsigned char * buffer, short size) { short sdc_install() { t_dev_block dev; // bdev_register copies the data, so we'll allocate this on the stack - TRACE("sdc_install"); + INFO("old sdc_install"); /* Install an interrupt handler to catch insertion of a card */ int_register(INT_SDC_INS, sdc_handler); diff --git a/src/dev/sdc_f256.c b/src/dev/sdc_f256.c new file mode 100644 index 0000000..75e2bd6 --- /dev/null +++ b/src/dev/sdc_f256.c @@ -0,0 +1,570 @@ +/** + * @file sdc_f256.c + * @author your name (you@domain.com) + * @brief + * @version 0.1 + * @date 2024-07-05 + * + * @copyright Copyright (c) 2024 + * + */ + +#include + +#include "log_level.h" +#define DEFAULT_LOG_LEVEL LOG_ERROR + +#include "log.h" +#include "constants.h" +#include "errors.h" +#include "dev/block.h" +#include "indicators.h" +#include "interrupt.h" +#include "F256/sdc_spi.h" +#include "sdc_f256.h" + +/* MMC/SD command (SPI mode) */ +#define CMD0 (0) /* GO_IDLE_STATE */ +#define CMD1 (1) /* SEND_OP_COND */ +#define ACMD41 (0x80+41) /* SEND_OP_COND (SDC) */ +#define CMD8 (8) /* SEND_IF_COND */ +#define CMD9 (9) /* SEND_CSD */ +#define CMD10 (10) /* SEND_CID */ +#define CMD12 (12) /* STOP_TRANSMISSION */ +#define CMD13 (13) /* SEND_STATUS */ +#define ACMD13 (0x80+13) /* SD_STATUS (SDC) */ +#define CMD16 (16) /* SET_BLOCKLEN */ +#define CMD17 (17) /* READ_SINGLE_BLOCK */ +#define CMD18 (18) /* READ_MULTIPLE_BLOCK */ +#define CMD23 (23) /* SET_BLOCK_COUNT */ +#define ACMD23 (0x80+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */ +#define CMD24 (24) /* WRITE_BLOCK */ +#define CMD25 (25) /* WRITE_MULTIPLE_BLOCK */ +#define CMD32 (32) /* ERASE_ER_BLK_START */ +#define CMD33 (33) /* ERASE_ER_BLK_END */ +#define CMD38 (38) /* ERASE */ +#define CMD55 (55) /* APP_CMD */ +#define CMD58 (58) /* READ_OCR */ + +static t_sd_card_info sd0_card_info; + +/** + * @brief Transmit Busy Flag Check + * + * @param sd pointer to the SPI device to check + */ +static void SD0_Wait_SDx_Busy(p_sdc_spi sd) { + uint8_t i = (sd->ctrl & SDx_BUSY); + do { + i = (sd->ctrl & SDx_BUSY); + } while (i == SDx_BUSY); +} + +/** + * @brief Transmit bytes to the card + * + * @param sd pointer to the SPI device to write to + * @param buff buffer of data to write + * @param bc number of bytes to write + */ +static void SD0_Tx(p_sdc_spi sd, const uint8_t * buff, unsigned int bc) { + do { + uint8_t d = *buff++; // Get a byte to be sent + sd->data = d; // Set the Data in the Transmit Register + SD0_Wait_SDx_Busy(sd); // Wait for the transmit to be over with + } while (--bc); +} + +/** + * @brief Receive bytes from the card + * + * @param sd pointer to the SPI device to read from + * @param buff buffer of data to read into + * @param bc number of bytes to read + */ +static void SD0_Rx(p_sdc_spi sd, uint8_t *buff, unsigned int bc) { + do { + sd->data = 0xff; // Set the Data in the Transmit Register + SD0_Wait_SDx_Busy(sd); // Wait for the transmit to be over with + *buff++ = sd->data; // Store a received byte + } while (--bc); +} + +/* Delay n microseconds (avr-gcc -Os) */ +static void dly_us (unsigned int n) { + do { + // Add Timer Routine for 1us (6x Clock @ 6.29Mhz) + __asm(" nop\n" + " nop\n" + " nop\n" + " nop\n" + " nop\n" + " nop\n"); + } while (--n); +} + +/*-----------------------------------------------------------------------*/ +/* Wait for card ready Using - SPI Controler 0 */ +/*-----------------------------------------------------------------------*/ + +/** + * @brief Wait for card ready Using + * + * @param sd pointer to the SPI device + * @return int + */ +static int SD0_wait_ready (p_sdc_spi sd) { + uint8_t d; + int tmr; + + for (tmr = 5000; tmr; tmr--) { // Wait for ready in timeout of 500ms + SD0_Rx(sd, &d, 1); + if (d == 0xFF) break; + dly_us(100); // 100us + } + return tmr ? 1 : 0; +} + + +/** + * @brief Deselect the card and release SPI bus + * + * @param sd pointer to the SPI device + */ +static void SD0_deselect(p_sdc_spi sd) { + uint8_t d; + + ind_set(IND_SDC, IND_OFF); + + sd->ctrl = sd->ctrl & ~SDx_CS; // SDx_CS = 0 ( Disabled ), SDx = 1 (Active) + SD0_Rx(sd, &d, 1); // Dummy clock (force DO hi-z for multiple slave SPI) +} + +/*-----------------------------------------------------------------------*/ +/* Select the card and wait for ready - SPI Controler 0 */ +/*-----------------------------------------------------------------------*/ +/* */ + +/** + * @brief Select the card and wait for ready + * + * @param sd pointer to the SPI device + * @return int 1:OK, 0:Timeout + */ +static int SD0_select(p_sdc_spi sd) { + uint8_t d; + + ind_set(IND_SDC, IND_ON); + + sd->ctrl = sd->ctrl | SDx_CS; // SDx_CS = 0 ( Disabled ), SDx = 1 (Active) + SD0_Rx(sd, &d, 1); // Dummy clock (force DO enabled) + + if (SD0_wait_ready(sd)) { // Wait for card ready + return 1; + } + + SD0_deselect(sd); + return 0; // Failed +} + +/** + * @brief Receive a data packet from the card + * + * @param sd pointer to the SPI device + * @param buff buffer of bytes to read into + * @param btr number of bytes to transfer + * @return int 1 on success, 0 on failure + */ +static int SD0_Rx_datablock (p_sdc_spi sd, uint8_t * buff, unsigned int btr) { + uint8_t d[2]; + int tmr; + + for (tmr = 1000; tmr; tmr--) { // Wait for data packet in timeout of 100ms + SD0_Rx(sd, d, 1); + if (d[0] != 0xFF) { + break; + } + dly_us(100); // 100us + } + + if (d[0] != 0xFE) { // If not valid data token, return with error + return 0; + } + + SD0_Rx(sd, buff, btr); // Receive the data block into buffer + SD0_Rx(sd, d, 2); // Discard CRC + + return 1; // Return with success +} + +/** + * @brief Send a data packet to the card + * + * @param sd pointer to the SPI device + * @param buff buffer of bytes to write to the card + * @param token token byte to transmit + * @return int 1 on success, 0 on failure + */ +static int SD0_Tx_datablock (p_sdc_spi sd, const uint8_t *buff, uint8_t token) { + uint8_t d[2]; + + if (!SD0_wait_ready(sd)) { + return 0; + } + + d[0] = token; + SD0_Tx(sd, d, 1); // Xmit a token + + if (token != 0xFD) { // Is it data token? + SD0_Tx(sd, buff, 512); // Xmit the 512 byte data block to MMC + SD0_Rx(sd, d, 2); // Xmit dummy CRC (0xFF,0xFF) + SD0_Rx(sd, d, 1); // Receive data response + if ((d[0] & 0x1F) != 0x05) { // If not accepted, return with error + return 0; + } + } + + return 1; +} + +/*-----------------------------------------------------------------------*/ +/* Send a command packet to the card */ +/*-----------------------------------------------------------------------*/ +/* Returns command response (bit7==1:Send failed)*/ + +/** + * @brief Send a command packet to the card + * + * @param sd pointer to the SPI device + * @param cmd command to send + * @param arg + * @return uint8_t command response (bit7==1:Send failed) + */ +static uint8_t SD0_Tx_cmd (p_sdc_spi sd, uint8_t cmd, uint32_t arg) { + uint8_t n, d, buf[6]; + + if (cmd & 0x80) { /* ACMD is the command sequense of CMD55-CMD */ + cmd &= 0x7F; + n = SD0_Tx_cmd(sd, CMD55, 0); + if (n > 1) { + return n; + } + } + + /* Select the card and wait for ready except to stop multiple block read */ + if (cmd != CMD12) { + SD0_deselect(sd); + if (!SD0_select(sd)) { + return 0xFF; + } + } + + /* Send a command packet */ + buf[0] = 0x40 | cmd; /* Start + Command index */ + buf[1] = (uint8_t)(arg >> 24); /* Argument[31..24] */ + buf[2] = (uint8_t)(arg >> 16); /* Argument[23..16] */ + buf[3] = (uint8_t)(arg >> 8); /* Argument[15..8] */ + buf[4] = (uint8_t)arg; /* Argument[7..0] */ + n = 0x01; /* Dummy CRC + Stop */ + + if (cmd == CMD0) { + n = 0x95; /* (valid CRC for CMD0(0)) */ + } + if (cmd == CMD8) { + n = 0x87; /* (valid CRC for CMD8(0x1AA)) */ + } + + buf[5] = n; + SD0_Tx(sd, buf, 6); + + /* Receive command response */ + if (cmd == CMD12) + SD0_Rx(sd, &d, 1); /* Skip a stuff byte when stop reading */ + + n = 10; /* Wait for a valid response in timeout of 10 attempts */ + do { + SD0_Rx(sd, &d, 1); + } while ((d & 0x80) && --n); + + return d; /* Return with the response value */ +} + +/** + * @brief pointer to the device driver structure for this device + * + * @param dev initialize the device + * @return short 0 for success, negative number for error + */ +static short sdc_init(p_dev_block dev) { + p_sd_card_info card = (p_sd_card_info)dev->data; + p_sdc_spi sd = card->reg; + uint8_t n, cmd, buf[4]; + int tmr; + short s; + + + dly_us(10000); /* 10ms */ + sd->ctrl |= SDx_SLOW; // Set the SPI in Slow Mode + for (n = 10; n; n--) { + SD0_Rx(sd, buf, 1); // Apply 80 dummy clocks and the card gets ready to receive command + } + + card->type = 0; + if (SD0_Tx_cmd(sd, CMD0, 0) == 1) { /* Enter Idle state */ + if (SD0_Tx_cmd(sd, CMD8, 0x1AA) == 1) { /* SDv2? */ + SD0_Rx(sd, buf, 4); /* Get trailing return value of R7 resp */ + if (buf[2] == 0x01 && buf[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */ + for (tmr = 1000; tmr; tmr--) { /* Wait for leaving idle state (ACMD41 with HCS bit) */ + if (SD0_Tx_cmd(sd, ACMD41, 1UL << 30) == 0) { + break; + } + dly_us(1000); + } + if (tmr && SD0_Tx_cmd(sd, CMD58, 0) == 0) { /* Check CCS bit in the OCR */ + SD0_Rx(sd, buf, 4); + card->type = (buf[0] & 0x40) ? (CT_SDC2 | CT_BLOCK) : CT_SDC2; /* SDv2+ */ + } + } + + } else { /* SDv1 or MMCv3 */ + if (SD0_Tx_cmd(sd, ACMD41, 0) <= 1) { + /* SDv1 */ + card->type = CT_SDC2; + cmd = ACMD41; + + } else { + /* MMCv3 */ + card->type = CT_MMC3; + cmd = CMD1; + } + + /* Wait for leaving idle state */ + for (tmr = 1000; tmr; tmr--) { + if (SD0_Tx_cmd(sd, cmd, 0) == 0) { + break; + } + dly_us(1000); + } + + /* Set R/W block length to 512 */ + if (!tmr || SD0_Tx_cmd(sd, CMD16, 512) != 0) { + card->type = 0; + } + } + } + + sd->ctrl &= ~SDx_SLOW; // Bring back the Fast Mode - 25Mhz + card->status = card->type ? 0 : SDC_STAT_NOINIT; + + INFO1("SD0_CardType: %x", card->type); + INFO1("SD0_Stat: %x", card->status); + + SD0_deselect(sd); + + return card->status; +} + +/** + * @brief Read a block from the device + * + * @param dev pointer to the device driver structure for this device + * @param lba the LBA number of the sector to read + * @param buffer buffer to write + * @param size number of bytes to try to read + * @return short the number of bytes read (negative number for error) + */ +static short sdc_read(p_dev_block dev, long lba, uint8_t * buffer, short size) { + p_sd_card_info card = (p_sd_card_info)dev->data; + p_sdc_spi sd = card->reg; + uint8_t cmd; + short count = size % 512 + 1; + + if (card->status & SDC_STAT_NOINIT) { + return ERR_NOT_READY; + } + + if (!(card->type & CT_BLOCK)) { + lba *= 512; /* Convert LBA to byte address if needed */ + } + + cmd = (count > 1) ? CMD18 : CMD17; /* READ_MULTIPLE_BLOCK : READ_SINGLE_BLOCK */ + if (SD0_Tx_cmd(sd, cmd, (uint32_t)lba) == 0) { + do { + if (!SD0_Rx_datablock(sd, buffer, 512)) { + break; + } + buffer += 512; + } while (--count); + + if (cmd == CMD18) { + SD0_Tx_cmd(sd, CMD12, 0); /* STOP_TRANSMISSION */ + } + } + SD0_deselect(sd); + + return size; +} + +/** + * @brief Write a block to the device + * + * @param dev pointer to the device driver structure for this device + * @param lba the LBA number of the sector to write + * @param buffer buffer to read + * @param size number of bytes to try to write + * @return short the number of bytes write (negative number for error) + */ +static short sdc_write(p_dev_block dev, long lba, const uint8_t * buffer, short size) { + p_sd_card_info card = (p_sd_card_info)dev->data; + p_sdc_spi sd = card->reg; + uint8_t cmd; + short count = size % 512 + 1; + + if (card->status & SDC_STAT_NOINIT) { + return ERR_NOT_READY; + } + + if (!(card->type & CT_BLOCK)) { + /* Convert LBA to byte address if needed */ + lba *= 512; + } + + if (count == 1) { + /* Single block write */ + if ((SD0_Tx_cmd(sd, CMD24, lba) == 0) && SD0_Tx_datablock(sd, buffer, 0xFE)) { + count = 0; + } + + } else { + /* Multiple block write */ + if (card->type & CT_SDC) { + SD0_Tx_cmd(sd, ACMD23, count); + } + + if (SD0_Tx_cmd(sd, CMD25, lba) == 0) { /* WRITE_MULTIPLE_BLOCK */ + do { + if (!SD0_Tx_datablock(sd, buffer, 0xFC)) { + break; + } + buffer += 512; + } while (--count); + + if (!SD0_Tx_datablock(sd, 0, 0xFD)) { + /* STOP_TRAN token */ + count = 1; + } + } + } + SD0_deselect(sd); + + return size; +} + +/** + * @brief Get the status of the device + * + * @param dev pointer to the device driver structure for this device + * @return short the status of the driver + */ +static short sdc_status(p_dev_block dev) { + p_sd_card_info card = (p_sd_card_info)dev->data; + + return card->status; +} + +/** + * @brief Ensure that any pending writes to teh device have been completed + * + * @param dev pointer to the device driver structure for this device + * @return 0 on success, negative number for error + */ +static short sdc_flush(p_dev_block dev) { + return 0; +} + +/** + * @brief Issue a control command to the device + * + * @param dev pointer to the device driver structure for this device + * @param command + * @param buffer + * @param size + * @return short + */ +static short sdc_ioctrl(p_dev_block dev, short command, unsigned char * buffer, short size) { + p_sd_card_info card = (p_sd_card_info)dev->data; + p_sdc_spi sd = card->reg; + + uint8_t n, csd[16]; + uint32_t cs; + + if (card->status & SDC_STAT_NOINIT) { + return ERR_NOT_READY; /* Check if card is in the socket */ + } + + short res = ERR_GENERAL; + switch (command) { + case IOCTRL_CTRL_SYNC: + /* Make sure that no pending write process */ + if (SD0_select(sd)) { + res = 0; + } + break; + + case IOCTRL_GET_SECTOR_COUNT: + /* Get number of sectors on the disk (DWORD) */ + if ((SD0_Tx_cmd(sd, CMD9, 0) == 0) && SD0_Rx_datablock(sd, csd, 16)) { + if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */ + cs = csd[9] + ((uint32_t)csd[8] << 8) + ((uint32_t)(csd[7] & 63) << 16) + 1; + *(uint32_t *)buffer = cs << 10; + } else { /* SDC ver 1.XX or MMC */ + n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2; + cs = (csd[8] >> 6) + ((uint16_t)csd[7] << 2) + ((uint16_t)(csd[6] & 3) << 10) + 1; + *(uint32_t*)buffer = cs << (n - 9); + } + res = 0; + } + break; + + case IOCTRL_GET_SECTOR_SIZE: + /* Get erase block size in unit of sector (DWORD) */ + *(uint32_t*)buffer = 128; + res = 0; + break; + + default: + res = ERR_BAD_ARGUMENT; + } + SD0_deselect(sd); + + return 0; +} + +// +// Install the SDC driver +// +short sdc_install() { + t_dev_block dev; // bdev_register copies the data, so we'll allocate this on the stack + + INFO("sdc_install"); + + /* Install an interrupt handler to catch insertion of a card */ + // int_register(INT_SDC_INS, sdc_handler); + // int_enable(INT_SDC_INS); + + sd0_card_info.reg = SD1_REG; + sd0_card_info.status = 0; + sd0_card_info.type = 0; + + dev.number = BDEV_SD0; + dev.name = "SD0"; + dev.data = &sd0_card_info; + dev.init = sdc_init; + dev.read = sdc_read; + dev.write = sdc_write; + dev.flush = sdc_flush; + dev.status = sdc_status; + dev.ioctrl = sdc_ioctrl; + + return bdev_register(&dev); +} diff --git a/src/dev/sdc_f256.h b/src/dev/sdc_f256.h new file mode 100644 index 0000000..90e662a --- /dev/null +++ b/src/dev/sdc_f256.h @@ -0,0 +1,41 @@ +/** + * Definitions support low level SDC device driver for the F256 + */ + +#ifndef __SDC_F256_H +#define __SDC_F256_H + +#include "F256/sdc_spi.h" +#include "sys_types.h" + +// +// Definitions for GABE's internal SD card controller +// + +#define SDC_SECTOR_SIZE 512 // Size of a block on the SDC + +#define SDC_STAT_NOINIT 0x01 // SD has not been initialized +#define SDC_STAT_PRESENT 0x02 // SD is present +#define SDC_STAT_PROTECTED 0x04 // SD is write-protected + +/* MMC card type flags (MMC_GET_TYPE) */ +#define CT_MMC3 0x01 /* MMC ver 3 */ +#define CT_MMC4 0x02 /* MMC ver 4+ */ +#define CT_MMC 0x03 /* MMC */ +#define CT_SDC1 0x04 /* SD ver 1 */ +#define CT_SDC2 0x08 /* SD ver 2+ */ +#define CT_SDC 0x0C /* SD */ +#define CT_BLOCK 0x10 /* Block addressing */ + +typedef struct s_sd_card_info { + p_sdc_spi reg; + uint8_t type; + uint8_t status; +} t_sd_card_info, *p_sd_card_info; + +// +// Install the SDC driver +// +extern short sdc_install(); + +#endif diff --git a/src/fatfs/00history.txt b/src/fatfs/00history.txt index 8a0169b..7a153a2 100644 --- a/src/fatfs/00history.txt +++ b/src/fatfs/00history.txt @@ -357,3 +357,13 @@ R0.14b (April 17, 2021) Fixed some compiler warnings. + +R0.15 (November 6, 2022) + Changed user provided synchronization functions in order to completely eliminate the platform dependency from FatFs code. + FF_SYNC_t is removed from the configuration options. + Fixed a potential error in f_mount when FF_FS_REENTRANT. + Fixed file lock control FF_FS_LOCK is not mutal excluded when FF_FS_REENTRANT && FF_VOLUMES > 1 is true. + Fixed f_mkfs() creates broken exFAT volume when the size of volume is >= 2^32 sectors. + Fixed string functions cannot write the unicode characters not in BMP when FF_LFN_UNICODE == 2 (UTF-8). + Fixed a compatibility issue in identification of GPT header. + diff --git a/src/fatfs/00readme.txt b/src/fatfs/00readme.txt index 4960997..3de3aea 100644 --- a/src/fatfs/00readme.txt +++ b/src/fatfs/00readme.txt @@ -1,4 +1,4 @@ -FatFs Module Source Files R0.14b +FatFs Module Source Files R0.15 FILES diff --git a/src/fatfs/Makefile b/src/fatfs/Makefile index b1a47cb..3f73b09 100644 --- a/src/fatfs/Makefile +++ b/src/fatfs/Makefile @@ -1,5 +1,5 @@ -UNIT := C256U_PLUS +UNIT := F256 # Define OS-dependent variables @@ -13,19 +13,29 @@ endif ifeq ($(UNIT),C256U) CPU=w65816 - SRCS_FOR_UNIT= + SRCS_FOR_UNIT=c256_diskio.c CFLAGS_FOR_UNIT=-DMODEL=1 -DCPU=255 --target Foenix --code-model large --data-model large LDFLAGS_FOR_UNIT=C256/ld_lc_c256_u.scm clib-lc-ld.a else ifeq ($(UNIT),C256U_PLUS) CPU=w65816 - SRCS_FOR_UNIT= + SRCS_FOR_UNIT=c256_diskio.c CFLAGS_FOR_UNIT=-DMODEL=5 -DCPU=255 --target Foenix --code-model large --data-model large LDFLAGS_FOR_UNIT=C256/ld_lc_c256_fmx.scm clib-lc-ld.a --rtattr printf=medium else ifeq ($(UNIT),C256_FMX) CPU=w65816 - SRCS_FOR_UNIT= + SRCS_FOR_UNIT=c256_diskio.c CFLAGS_FOR_UNIT=-DMODEL=0 -DCPU=255 --target Foenix --code-model large --data-model large LDFLAGS_FOR_UNIT=C256/ld_lc_c256_fmx.scm clib-lc-ld.a +else ifeq ($(UNIT),F256) + CPU=w65816 + SRCS_FOR_UNIT=toolbox_bdev.c + CFLAGS_FOR_UNIT=-DMODEL=0 -DCPU=255 --code-model large --data-model large + + ifeq ($(MEMORY),ROM) + LDFLAGS_FOR_UNIT=C256/flash-f256.scm clib-lc-ld.a --rtattr printf=medium + else + LDFLAGS_FOR_UNIT=C256/ld_lc_f256.scm clib-lc-ld.a --rtattr printf=medium + endif endif ifeq ($(CPU),w65816) @@ -39,7 +49,7 @@ INCLUDES=-I.. -I../include CFLAGS=$(INCLUDES) $(CFLAGS_FOR_UNIT) -l ASFLAGS=$(INCLUDES) -SRCS = c256_diskio.c ff.c ffsystem.c ffunicode.c $(SRCS_FOR_UNIT) +SRCS = ff.c ffsystem.c ffunicode.c $(SRCS_FOR_UNIT) OBJS = $(patsubst %.c,%.o,$(SRCS)) OBJS4RM = $(subst /,\\,$(OBJS)) diff --git a/src/fatfs/c256_diskio.c b/src/fatfs/c256_diskio.c deleted file mode 100644 index 67ebc02..0000000 --- a/src/fatfs/c256_diskio.c +++ /dev/null @@ -1,152 +0,0 @@ -/*-----------------------------------------------------------------------*/ -/* Low level disk I/O module SKELETON for FatFs (C)ChaN, 2019 */ -/*-----------------------------------------------------------------------*/ -/* If a working storage control module is available, it should be */ -/* attached to the FatFs via a glue function rather than modifying it. */ -/* This is an example of glue functions to attach various exsisting */ -/* storage control modules to the FatFs module with a defined API. */ -/*-----------------------------------------------------------------------*/ - -#include "log.h" -#include "dev/block.h" -#include "ff.h" /* Obtains integer types */ -#include "diskio.h" /* Declarations of disk functions */ -#include "simpleio.h" - -/* Definitions of physical drive number for each drive */ -#define DEV_SDC 0 /* Example: Map Ramdisk to physical drive 0 */ -// #define DEV_FDC 1 -// #define DEV_HDC 2 - - -/*-----------------------------------------------------------------------*/ -/* Get Drive Status */ -/*-----------------------------------------------------------------------*/ - -DSTATUS disk_status ( - BYTE pdrv /* Physical drive nmuber to identify the drive */ -) -{ - DSTATUS stat; - int result; - - TRACE("disk_status"); - - stat = bdev_status(pdrv); - return stat; -} - - - -/*-----------------------------------------------------------------------*/ -/* Initialize a Drive */ -/*-----------------------------------------------------------------------*/ - -DSTATUS disk_initialize ( - BYTE pdrv /* Physical drive nmuber to identify the drive */ -) -{ - DSTATUS stat; - int result; - - TRACE("disk_initialize"); - - return bdev_init(pdrv); -} - - - -/*-----------------------------------------------------------------------*/ -/* Read Sector(s) */ -/*-----------------------------------------------------------------------*/ - -DRESULT disk_read ( - BYTE pdrv, /* Physical drive nmuber to identify the drive */ - BYTE *buff, /* Data buffer to store read data */ - LBA_t sector, /* Start sector in LBA */ - UINT count /* Number of sectors to read */ -) -{ - DRESULT res; - int result; - int i; - - TRACE("disk_read"); - - for (i = 0; i < count; i++) { - result = bdev_read(pdrv, sector, buff, 512); - if (result < 0) { - log_num(LOG_ERROR, "disk_read error: ", result); - if (result == ERR_MEDIA_CHANGE) { - log(LOG_ERROR, "disk changed."); - return RES_NOTRDY; - } else { - log(LOG_ERROR, "gerneral error"); - return RES_PARERR; - } - } else { - sector++; - } - } - - return RES_OK; -} - - - -/*-----------------------------------------------------------------------*/ -/* Write Sector(s) */ -/*-----------------------------------------------------------------------*/ - -#if FF_FS_READONLY == 0 - -DRESULT disk_write ( - BYTE pdrv, /* Physical drive nmuber to identify the drive */ - const BYTE *buff, /* Data to be written */ - LBA_t sector, /* Start sector in LBA */ - UINT count /* Number of sectors to write */ -) -{ - DRESULT res; - int i; - int result; - - TRACE("disk_write"); - - for (i = 0; i < count; i++) { - result = bdev_write(pdrv, sector, buff, 512); - if (result < 0) { - return RES_PARERR; - } else { - sector += result; - } - } - - return RES_OK; -} - -#endif - - -/*-----------------------------------------------------------------------*/ -/* Miscellaneous Functions */ -/*-----------------------------------------------------------------------*/ - -DRESULT disk_ioctl ( - BYTE pdrv, /* Physical drive nmuber (0..) */ - BYTE cmd, /* Control code */ - void *buff /* Buffer to send/receive control data */ -) -{ - DRESULT res; - int result; - - TRACE("disk_ioctl"); - - result = bdev_ioctrl(pdrv, cmd, buff, 0); - if (result < 0) { - return RES_PARERR; - } else { - return RES_OK; - } -} diff --git a/src/fatfs/diskio.bak b/src/fatfs/diskio.bak deleted file mode 100644 index 179e387..0000000 --- a/src/fatfs/diskio.bak +++ /dev/null @@ -1,229 +0,0 @@ -/*-----------------------------------------------------------------------*/ -/* Low level disk I/O module SKELETON for FatFs (C)ChaN, 2019 */ -/*-----------------------------------------------------------------------*/ -/* If a working storage control module is available, it should be */ -/* attached to the FatFs via a glue function rather than modifying it. */ -/* This is an example of glue functions to attach various exsisting */ -/* storage control modules to the FatFs module with a defined API. */ -/*-----------------------------------------------------------------------*/ - -#include "ff.h" /* Obtains integer types */ -#include "diskio.h" /* Declarations of disk functions */ - -/* Definitions of physical drive number for each drive */ -#define DEV_RAM 0 /* Example: Map Ramdisk to physical drive 0 */ -#define DEV_MMC 1 /* Example: Map MMC/SD card to physical drive 1 */ -#define DEV_USB 2 /* Example: Map USB MSD to physical drive 2 */ - - -/*-----------------------------------------------------------------------*/ -/* Get Drive Status */ -/*-----------------------------------------------------------------------*/ - -DSTATUS disk_status ( - BYTE pdrv /* Physical drive nmuber to identify the drive */ -) -{ - DSTATUS stat; - int result; - - switch (pdrv) { - case DEV_RAM : - result = RAM_disk_status(); - - // translate the reslut code here - - return stat; - - case DEV_MMC : - result = MMC_disk_status(); - - // translate the reslut code here - - return stat; - - case DEV_USB : - result = USB_disk_status(); - - // translate the reslut code here - - return stat; - } - return STA_NOINIT; -} - - - -/*-----------------------------------------------------------------------*/ -/* Inidialize a Drive */ -/*-----------------------------------------------------------------------*/ - -DSTATUS disk_initialize ( - BYTE pdrv /* Physical drive nmuber to identify the drive */ -) -{ - DSTATUS stat; - int result; - - switch (pdrv) { - case DEV_RAM : - result = RAM_disk_initialize(); - - // translate the reslut code here - - return stat; - - case DEV_MMC : - result = MMC_disk_initialize(); - - // translate the reslut code here - - return stat; - - case DEV_USB : - result = USB_disk_initialize(); - - // translate the reslut code here - - return stat; - } - return STA_NOINIT; -} - - - -/*-----------------------------------------------------------------------*/ -/* Read Sector(s) */ -/*-----------------------------------------------------------------------*/ - -DRESULT disk_read ( - BYTE pdrv, /* Physical drive nmuber to identify the drive */ - BYTE *buff, /* Data buffer to store read data */ - LBA_t sector, /* Start sector in LBA */ - UINT count /* Number of sectors to read */ -) -{ - DRESULT res; - int result; - - switch (pdrv) { - case DEV_RAM : - // translate the arguments here - - result = RAM_disk_read(buff, sector, count); - - // translate the reslut code here - - return res; - - case DEV_MMC : - // translate the arguments here - - result = MMC_disk_read(buff, sector, count); - - // translate the reslut code here - - return res; - - case DEV_USB : - // translate the arguments here - - result = USB_disk_read(buff, sector, count); - - // translate the reslut code here - - return res; - } - - return RES_PARERR; -} - - - -/*-----------------------------------------------------------------------*/ -/* Write Sector(s) */ -/*-----------------------------------------------------------------------*/ - -#if FF_FS_READONLY == 0 - -DRESULT disk_write ( - BYTE pdrv, /* Physical drive nmuber to identify the drive */ - const BYTE *buff, /* Data to be written */ - LBA_t sector, /* Start sector in LBA */ - UINT count /* Number of sectors to write */ -) -{ - DRESULT res; - int result; - - switch (pdrv) { - case DEV_RAM : - // translate the arguments here - - result = RAM_disk_write(buff, sector, count); - - // translate the reslut code here - - return res; - - case DEV_MMC : - // translate the arguments here - - result = MMC_disk_write(buff, sector, count); - - // translate the reslut code here - - return res; - - case DEV_USB : - // translate the arguments here - - result = USB_disk_write(buff, sector, count); - - // translate the reslut code here - - return res; - } - - return RES_PARERR; -} - -#endif - - -/*-----------------------------------------------------------------------*/ -/* Miscellaneous Functions */ -/*-----------------------------------------------------------------------*/ - -DRESULT disk_ioctl ( - BYTE pdrv, /* Physical drive nmuber (0..) */ - BYTE cmd, /* Control code */ - void *buff /* Buffer to send/receive control data */ -) -{ - DRESULT res; - int result; - - switch (pdrv) { - case DEV_RAM : - - // Process of the command for the RAM drive - - return res; - - case DEV_MMC : - - // Process of the command for the MMC/SD card - - return res; - - case DEV_USB : - - // Process of the command the USB drive - - return res; - } - - return RES_PARERR; -} - diff --git a/src/fatfs/f256xe_diskio.c b/src/fatfs/f256xe_diskio.c new file mode 100644 index 0000000..1aaee66 --- /dev/null +++ b/src/fatfs/f256xe_diskio.c @@ -0,0 +1,832 @@ +/*------------------------------------------------------------------------/ +/ Foolproof MMCv3/SDv1/SDv2 (in SPI mode) control module +/-------------------------------------------------------------------------/ +/ +/ Copyright (C) 2019, ChaN, all right reserved. +/ +/ * This software is a free software and there is NO WARRANTY. +/ * No restriction on use. You can use, modify and redistribute it for +/ personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY. +/ * Redistributions of source code must retain the above copyright notice. +/ +/-------------------------------------------------------------------------/ + Features and Limitations: + + * Easy to Port Bit-banging SPI + It uses only four GPIO pins. No complex peripheral needs to be used. + + * Platform Independent + You need to modify only a few macros to control the GPIO port. + + * Low Speed + The data transfer rate will be several times slower than hardware SPI. + + * No Media Change Detection + Application program needs to perform a f_mount() after media change. + +/-------------------------------------------------------------------------*/ + +#include +#include "ff.h" /* Obtains integer types for FatFs */ +#include "f256xe_diskio.h" /* Common include file for FatFs and disk I/O layer */ +#include "../dev/rtc.h" + +/*-------------------------------------------------------------------------*/ +/* Platform dependent macros and functions needed to be modified */ +/*-------------------------------------------------------------------------*/ +/* System Control Registers - to ger CD & WP from SD0 */ +#define SD0_STAT (*(volatile __far uint8_t *)0xF016A0) +#define SD0_STAT_CD 0x40 // When 1 = No Card, 0 = Card is Present +#define SD0_STAT_WP 0x80 // When 0 = Writeable, 1 = Card is Protected + +/* SPI Controler 0 Registers - External Access (Front of Unit)*/ +#define SD0_CTRL (*(volatile __far uint8_t *)0xF01D00) +#define SD0_DATA (*(volatile __far uint8_t *)0xF01D01) +/* SPI Controler 1 Registers - Internal Access (underneath of Unit - uSDCard) */ +// Specific to the F256xE - Internal SDCard (Permanent Disk) +#define SD1_CTRL (*(volatile __far uint8_t *)0xF01D80) +#define SD1_DATA (*(volatile __far uint8_t *)0xF01D81) + +#define SDx_CS 0x01 // 1 = Enable +#define SDx_SLOW 0x02 // 1 = Slow 400Khz, 0 = 25Mhz +#define SDx_BUSY 0x80 // 1 = Busy +// +#define DEV_SD0 0 /* Frontal SDCard - Removable Media 0 - SDCARD */ +#define DEV_SD1 1 /* Underneath SDCard - Permanent Media 1 - SDCARD */ +// +/* MMC card type flags (MMC_GET_TYPE) */ +#define CT_MMC3 0x01 /* MMC ver 3 */ +#define CT_MMC4 0x02 /* MMC ver 4+ */ +#define CT_MMC 0x03 /* MMC */ +#define CT_SDC1 0x04 /* SD ver 1 */ +#define CT_SDC2 0x08 /* SD ver 2+ */ +#define CT_SDC 0x0C /* SD */ +#define CT_BLOCK 0x10 /* Block addressing */ + +/* Delay n microseconds (avr-gcc -Os) */ +static void dly_us (UINT n) { + do { + // Add Timer Routine for 1us (6x Clock @ 6.29Mhz) + __asm(" nop\n" + " nop\n" + " nop\n" + " nop\n" + " nop\n" + " nop\n"); + } while (--n); +} +/*-------------------------------------------------------------------------- + + Module Private Functions + +---------------------------------------------------------------------------*/ + +/* MMC/SD command (SPI mode) */ +#define CMD0 (0) /* GO_IDLE_STATE */ +#define CMD1 (1) /* SEND_OP_COND */ +#define ACMD41 (0x80+41) /* SEND_OP_COND (SDC) */ +#define CMD8 (8) /* SEND_IF_COND */ +#define CMD9 (9) /* SEND_CSD */ +#define CMD10 (10) /* SEND_CID */ +#define CMD12 (12) /* STOP_TRANSMISSION */ +#define CMD13 (13) /* SEND_STATUS */ +#define ACMD13 (0x80+13) /* SD_STATUS (SDC) */ +#define CMD16 (16) /* SET_BLOCKLEN */ +#define CMD17 (17) /* READ_SINGLE_BLOCK */ +#define CMD18 (18) /* READ_MULTIPLE_BLOCK */ +#define CMD23 (23) /* SET_BLOCK_COUNT */ +#define ACMD23 (0x80+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */ +#define CMD24 (24) /* WRITE_BLOCK */ +#define CMD25 (25) /* WRITE_MULTIPLE_BLOCK */ +#define CMD32 (32) /* ERASE_ER_BLK_START */ +#define CMD33 (33) /* ERASE_ER_BLK_END */ +#define CMD38 (38) /* ERASE */ +#define CMD55 (55) /* APP_CMD */ +#define CMD58 (58) /* READ_OCR */ + + +static DSTATUS SD0_Stat = STA_NOINIT; /* Disk status */ +static DSTATUS SD1_Stat = STA_NOINIT; /* Disk status */ +static BYTE SD0_CardType; /* b0:MMC, b1:SDv1, b2:SDv2, b3:Block addressing */ +static BYTE SD1_CardType; /* b0:MMC, b1:SDv1, b2:SDv2, b3:Block addressing */ + +/*-----------------------------------------------------------------------*/ +/* Transmit Busy Flag Check - SPI Controler 0 */ +/*-----------------------------------------------------------------------*/ +static void SD0_Wait_SDx_Busy( void ) { + unsigned char i; + i = (SD0_CTRL & SDx_BUSY); + do { + i = (SD0_CTRL & SDx_BUSY); + } while (i == SDx_BUSY); +} + +/*-----------------------------------------------------------------------*/ +/* Transmit bytes to the card - SPI Controler 0 */ +/*-----------------------------------------------------------------------*/ +static void SD0_Tx ( const BYTE* buff, UINT bc ) { + BYTE d; + do { + d = *buff++; /* Get a byte to be sent */ + SD0_DATA = d; // Set the Data in the Transmit Register + SD0_Wait_SDx_Busy(); // Wait for the transmit to be over with + } while (--bc); +} + +/*-----------------------------------------------------------------------*/ +/* Receive bytes from the card - SPI Controler 0 */ +/*-----------------------------------------------------------------------*/ +static void SD0_Rx ( BYTE *buff, UINT bc ) { + BYTE r; + do { + SD0_DATA = 0xff; // Set the Data in the Transmit Register + SD0_Wait_SDx_Busy(); // Wait for the transmit to be over with + *buff++ = SD0_DATA; /* Store a received byte */ + } while (--bc); +} + +/*-----------------------------------------------------------------------*/ +/* Wait for card ready Using - SPI Controler 0 */ +/*-----------------------------------------------------------------------*/ +static int SD0_wait_ready (void) { + BYTE d; + UINT tmr; + for (tmr = 5000; tmr; tmr--) { /* Wait for ready in timeout of 500ms */ + SD0_Rx(&d, 1); + if (d == 0xFF) break; + dly_us(100); // 100us + } + return tmr ? 1 : 0; +} + +/*-----------------------------------------------------------------------*/ +/* Deselect the card and release SPI bus - SPI Controler 0 */ +/*-----------------------------------------------------------------------*/ +static void SD0_deselect ( void ) { + BYTE d; + SD0_CTRL = SD0_CTRL & ~ SDx_CS; // SDx_CS = 0 ( Disabled ), SDx = 1 (Active) + SD0_Rx(&d, 1); /* Dummy clock (force DO hi-z for multiple slave SPI) */ +} + +/*-----------------------------------------------------------------------*/ +/* Select the card and wait for ready - SPI Controler 0 */ +/*-----------------------------------------------------------------------*/ +/* 1:OK, 0:Timeout */ +static int SD0_select (void) { + BYTE d; + + SD0_CTRL = SD0_CTRL | SDx_CS; // SDx_CS = 0 ( Disabled ), SDx = 1 (Active) + SD0_Rx(&d, 1); /* Dummy clock (force DO enabled) */ + + if (SD0_wait_ready()) + return 1; /* Wait for card ready */ + + SD0_deselect(); + return 0; /* Failed */ +} + +/*-----------------------------------------------------------------------*/ +/* Receive a data packet from the card - SPI Controler 0 */ +/*-----------------------------------------------------------------------*/ +/* 1:OK, 0:Failed */ +static int SD0_Rx_datablock ( BYTE *buff, UINT btr ) { + BYTE d[2]; + UINT tmr; + + for (tmr = 1000; tmr; tmr--) { /* Wait for data packet in timeout of 100ms */ + SD0_Rx(d, 1); + if (d[0] != 0xFF) break; + dly_us(100); // 100us + } + + if (d[0] != 0xFE) + return 0; /* If not valid data token, return with error */ + + SD0_Rx(buff, btr); /* Receive the data block into buffer */ + SD0_Rx(d, 2); /* Discard CRC */ + + return 1; /* Return with success */ +} + +/*-----------------------------------------------------------------------*/ +/* Send a data packet to the card - SPI Controler 0 */ +/*-----------------------------------------------------------------------*/ +/* 1:OK, 0:Failed */ +static int SD0_Tx_datablock ( const BYTE *buff, BYTE token ) { + BYTE d[2]; + + if (!SD0_wait_ready()) + return 0; + + d[0] = token; + SD0_Tx(d, 1); /* Xmit a token */ + + if (token != 0xFD) { /* Is it data token? */ + SD0_Tx(buff, 512); /* Xmit the 512 byte data block to MMC */ + SD0_Rx(d, 2); /* Xmit dummy CRC (0xFF,0xFF) */ + SD0_Rx(d, 1); /* Receive data response */ + if ((d[0] & 0x1F) != 0x05) /* If not accepted, return with error */ + return 0; + } + + return 1; +} + +/*-----------------------------------------------------------------------*/ +/* Send a command packet to the card */ +/*-----------------------------------------------------------------------*/ +/* Returns command response (bit7==1:Send failed)*/ +static BYTE SD0_Tx_cmd ( BYTE cmd, DWORD arg ) { + BYTE n, d, buf[6]; + //printf("Processing Command: %d\r", cmd); + if (cmd & 0x80) { /* ACMD is the command sequense of CMD55-CMD */ + cmd &= 0x7F; + n = SD0_Tx_cmd(CMD55, 0); + if (n > 1) + return n; + } + + /* Select the card and wait for ready except to stop multiple block read */ + if (cmd != CMD12) { + //printf("Processing Command: %d\r", cmd); + SD0_deselect(); + if (!SD0_select()) + return 0xFF; + } + + /* Send a command packet */ + buf[0] = 0x40 | cmd; /* Start + Command index */ + buf[1] = (BYTE)(arg >> 24); /* Argument[31..24] */ + buf[2] = (BYTE)(arg >> 16); /* Argument[23..16] */ + buf[3] = (BYTE)(arg >> 8); /* Argument[15..8] */ + buf[4] = (BYTE)arg; /* Argument[7..0] */ + n = 0x01; /* Dummy CRC + Stop */ + + if (cmd == CMD0) + n = 0x95; /* (valid CRC for CMD0(0)) */ + if (cmd == CMD8) + n = 0x87; /* (valid CRC for CMD8(0x1AA)) */ + + buf[5] = n; + SD0_Tx(buf, 6); + + /* Receive command response */ + if (cmd == CMD12) + SD0_Rx(&d, 1); /* Skip a stuff byte when stop reading */ + + n = 10; /* Wait for a valid response in timeout of 10 attempts */ + do + SD0_Rx(&d, 1); + while ((d & 0x80) && --n); + + return d; /* Return with the response value */ +} + +/*-----------------------------------------------------------------------*/ +/* Transmit bytes to the card - SPI Controler 1 */ +/*-----------------------------------------------------------------------*/ +static void SD1_Tx ( const BYTE* buff, UINT bc ) { + BYTE d; + do { + d = *buff++; /* Get a byte to be sent */ + SD1_DATA = d; // Set the Data in the Transmit Register + while ( SD1_CTRL & SDx_BUSY); // Wait for the transmit to be over with + } while (--bc); +} + +/*-----------------------------------------------------------------------*/ +/* Receive bytes from the card - SPI Controler 1 */ +/*-----------------------------------------------------------------------*/ +static void SD1_Rx ( BYTE *buff, UINT bc ) { + BYTE r; + do { + SD1_DATA = 0xff; // Set the Data in the Transmit Register + while ( SD1_CTRL & SDx_BUSY); // Wait for the transmit to be over with + *buff++ = SD1_DATA; /* Store a received byte */ + } while (--bc); +} + +/*-----------------------------------------------------------------------*/ +/* Wait for card ready Using - SPI Controler 1 */ +/*-----------------------------------------------------------------------*/ +static int SD1_wait_ready (void) { + BYTE d; + UINT tmr; + for (tmr = 5000; tmr; tmr--) { /* Wait for ready in timeout of 500ms */ + SD1_Rx(&d, 1); + if (d == 0xFF) break; + dly_us(100); // 100us + } + return tmr ? 1 : 0; +} + +/*-----------------------------------------------------------------------*/ +/* Deselect the card and release SPI bus - SPI Controler 1 */ +/*-----------------------------------------------------------------------*/ +static void SD1_deselect ( void ) { + BYTE d; + SD1_CTRL = SD1_CTRL & ~ SDx_CS; // SDx_CS = 0 ( Disabled ), SDx = 1 (Active) + SD1_Rx(&d, 1); /* Dummy clock (force DO hi-z for multiple slave SPI) */ +} + +/*-----------------------------------------------------------------------*/ +/* Select the card and wait for ready - SPI Controler 1 */ +/*-----------------------------------------------------------------------*/ +/* 1:OK, 0:Timeout */ +static int SD1_select (void) { + BYTE d; + + SD1_CTRL = SD1_CTRL | SDx_CS; // SDx_CS = 0 ( Disabled ), SDx = 1 (Active) + SD1_Rx(&d, 1); /* Dummy clock (force DO enabled) */ + + if (SD1_wait_ready()) + return 1; /* Wait for card ready */ + + SD1_deselect(); + return 0; /* Failed */ +} + +/*-----------------------------------------------------------------------*/ +/* Receive a data packet from the card - SPI Controler 1 */ +/*-----------------------------------------------------------------------*/ +/* 1:OK, 0:Failed */ +static int SD1_Rx_datablock ( BYTE *buff, UINT btr ) { + BYTE d[2]; + UINT tmr; + + for (tmr = 1000; tmr; tmr--) { /* Wait for data packet in timeout of 100ms */ + SD1_Rx(d, 1); + if (d[0] != 0xFF) break; + dly_us(100); // 100us + } + + if (d[0] != 0xFE) + return 0; /* If not valid data token, return with error */ + + SD1_Rx(buff, btr); /* Receive the data block into buffer */ + SD1_Rx(d, 2); /* Discard CRC */ + + return 1; /* Return with success */ +} + +/*-----------------------------------------------------------------------*/ +/* Send a data packet to the card - SPI Controler 1 */ +/*-----------------------------------------------------------------------*/ +/* 1:OK, 0:Failed */ +static int SD1_Tx_datablock ( const BYTE *buff, BYTE token ) { + BYTE d[2]; + + if (!SD1_wait_ready()) + return 0; + + d[0] = token; + SD1_Tx(d, 1); /* Xmit a token */ + + if (token != 0xFD) { /* Is it data token? */ + SD1_Tx(buff, 512); /* Xmit the 512 byte data block to MMC */ + SD1_Rx(d, 2); /* Xmit dummy CRC (0xFF,0xFF) */ + SD1_Rx(d, 1); /* Receive data response */ + if ((d[0] & 0x1F) != 0x05) /* If not accepted, return with error */ + return 0; + } + + return 1; +} + +/*-----------------------------------------------------------------------*/ +/* Send a command packet to the card - SPI Controler 1 */ +/*-----------------------------------------------------------------------*/ +/* Returns command response (bit7==1:Send failed)*/ +static BYTE SD1_Tx_cmd ( BYTE cmd, DWORD arg ) { + BYTE n, d, buf[6]; + + //printf("Processing Command: %d\r", cmd); + if (cmd & 0x80) { /* ACMD is the command sequense of CMD55-CMD */ + cmd &= 0x7F; + n = SD1_Tx_cmd(CMD55, 0); + if (n > 1) + return n; + } + + /* Select the card and wait for ready except to stop multiple block read */ + if (cmd != CMD12) { + //printf("Enabling CSn for Command: %d\r", cmd); + SD1_deselect(); + if (!SD1_select()) { + //printf("*** Enabling CSn Timed out ***\r"); + return 0xFF; + + } + } + + /* Send a command packet */ + buf[0] = 0x40 | cmd; /* Start + Command index */ + buf[1] = (BYTE)(arg >> 24); /* Argument[31..24] */ + buf[2] = (BYTE)(arg >> 16); /* Argument[23..16] */ + buf[3] = (BYTE)(arg >> 8); /* Argument[15..8] */ + buf[4] = (BYTE)arg; /* Argument[7..0] */ + n = 0x01; /* Dummy CRC + Stop */ + + if (cmd == CMD0) + n = 0x95; /* (valid CRC for CMD0(0)) */ + if (cmd == CMD8) + n = 0x87; /* (valid CRC for CMD8(0x1AA)) */ + + buf[5] = n; + SD1_Tx(buf, 6); + + /* Receive command response */ + if (cmd == CMD12) + SD1_Rx(&d, 1); /* Skip a stuff byte when stop reading */ + + n = 10; /* Wait for a valid response in timeout of 10 attempts */ + do + SD1_Rx(&d, 1); + while ((d & 0x80) && --n); + + return d; /* Return with the response value */ +} + +/*-------------------------------------------------------------------------- + + Public Functions + +---------------------------------------------------------------------------*/ + +//#define SD0_STAT (*(volatile __far uint8_t *)0xF016A0) +//#define SD0_STAT_CD 0x40 // When 1 = No Card, 0 = Card is Present +//#define SD0_STAT_WP 0x80 // When 1 = Writeable, 0 = Card is Protected +/*-----------------------------------------------------------------------*/ +/* Get Disk Status */ +/*-----------------------------------------------------------------------*/ +/* Drive number (always 0) */ +DSTATUS disk_status ( BYTE drv ) { + + if ( drv == DEV_SD0) { + // CHeck for Card Present + if ( SD0_STAT & SD0_STAT_CD ) + SD0_Stat = SD0_Stat | STA_NODISK; + else + SD0_Stat = SD0_Stat & ~STA_NODISK; + + if ( SD0_STAT & SD0_STAT_WP ) + SD0_Stat = SD0_Stat | STA_PROTECT; + else + SD0_Stat = SD0_Stat & ~STA_PROTECT; + return SD0_Stat; + } + + if ( drv == DEV_SD1) { + //printf("Drive: %d, disk_status: %x\r", drv, SD0_Stat); + return 0x00; // There is always a card in the drive + } + + return STA_NOINIT; + + +} + + + +/*-----------------------------------------------------------------------*/ +/* Initialize Disk Drive */ +/*-----------------------------------------------------------------------*/ + +DSTATUS disk_initialize ( + BYTE drv /* Physical drive nmuber (0) */ +) +{ + BYTE n, ty, cmd, buf[4]; + UINT tmr; + DSTATUS s; + + if ( drv == DEV_SD0) { + //printf("Init Drive %d\r", drv); + dly_us(10000); /* 10ms */ + SD0_CTRL = SD0_CTRL | SDx_SLOW; // Set the SPI in Slow Mode + for (n = 10; n; n--) { + SD0_Rx(buf, 1); /* Apply 80 dummy clocks and the card gets ready to receive command */ + } + ty = 0; + if (SD0_Tx_cmd(CMD0, 0) == 1) { /* Enter Idle state */ + if (SD0_Tx_cmd(CMD8, 0x1AA) == 1) { /* SDv2? */ + SD0_Rx(buf, 4); /* Get trailing return value of R7 resp */ + if (buf[2] == 0x01 && buf[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */ + for (tmr = 1000; tmr; tmr--) { /* Wait for leaving idle state (ACMD41 with HCS bit) */ + if (SD0_Tx_cmd(ACMD41, 1UL << 30) == 0) break; + dly_us(1000); + } + if (tmr && SD0_Tx_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */ + SD0_Rx(buf, 4); + ty = (buf[0] & 0x40) ? CT_SDC2 | CT_BLOCK : CT_SDC2; /* SDv2+ */ + } + } + } else { /* SDv1 or MMCv3 */ + if (SD0_Tx_cmd(ACMD41, 0) <= 1) { + ty = CT_SDC2; cmd = ACMD41; /* SDv1 */ + } else { + ty = CT_MMC3; cmd = CMD1; /* MMCv3 */ + } + for (tmr = 1000; tmr; tmr--) { /* Wait for leaving idle state */ + if (SD0_Tx_cmd(cmd, 0) == 0) break; + dly_us(1000); + } + if (!tmr || SD0_Tx_cmd(CMD16, 512) != 0) /* Set R/W block length to 512 */ + ty = 0; + } + } + SD0_CTRL = SD0_CTRL & ~SDx_SLOW; // Bring back the Fast Mode - 25Mhz + + SD0_CardType = ty; + s = ty ? 0 : STA_NOINIT; + SD0_Stat = s; + //printf("SD0_CardType: %x\r", ty); + //printf("SD0_Stat: %x\r", SD0_Stat); + SD0_deselect(); + + return s; + } + + if ( drv == DEV_SD1) { + //printf("Initializing Internal Drive\r"); + //printf("Init Drive %d\r", drv); + dly_us(10000); /* 10ms */ + + SD1_CTRL = SD1_CTRL | SDx_SLOW; // Set the SPI in Slow Mode + + for (n = 10; n; n--) { + SD1_Rx(buf, 1); /* Apply 80 dummy clocks and the card gets ready to receive command */ + } + ty = 0; + if (SD1_Tx_cmd(CMD0, 0) == 1) { /* Enter Idle state */ + if (SD1_Tx_cmd(CMD8, 0x1AA) == 1) { /* SDv2? */ + SD1_Rx(buf, 4); /* Get trailing return value of R7 resp */ + if (buf[2] == 0x01 && buf[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */ + for (tmr = 1000; tmr; tmr--) { /* Wait for leaving idle state (ACMD41 with HCS bit) */ + if (SD1_Tx_cmd(ACMD41, 1UL << 30) == 0) break; + dly_us(1000); + } + if (tmr && SD1_Tx_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */ + SD1_Rx(buf, 4); + ty = (buf[0] & 0x40) ? CT_SDC2 | CT_BLOCK : CT_SDC2; /* SDv2+ */ + } + } + } else { /* SDv1 or MMCv3 */ + if (SD1_Tx_cmd(ACMD41, 0) <= 1) { + ty = CT_SDC2; cmd = ACMD41; /* SDv1 */ + } else { + ty = CT_MMC3; cmd = CMD1; /* MMCv3 */ + } + for (tmr = 1000; tmr; tmr--) { /* Wait for leaving idle state */ + if (SD1_Tx_cmd(cmd, 0) == 0) break; + dly_us(1000); + } + if (!tmr || SD1_Tx_cmd(CMD16, 512) != 0) /* Set R/W block length to 512 */ + ty = 0; + } + } + SD1_CTRL = SD1_CTRL & ~SDx_SLOW; // Bring back the Fast Mode - 25Mhz + //printf("SD1_CardType: %x\r", ty); + SD1_CardType = ty; + s = ty ? 0 : STA_NOINIT; + SD1_Stat = s; + //printf("SD1_Status: %x\r", SD1_Stat); + SD1_deselect(); + + return s; + } + + return RES_NOTRDY; + + +} + + + +/*-----------------------------------------------------------------------*/ +/* Read Sector(s) */ +/*-----------------------------------------------------------------------*/ + +DRESULT disk_read ( BYTE drv, BYTE *buff, LBA_t sector, UINT count ) { + BYTE cmd; + DWORD sect = (DWORD)sector; + + if ( drv == DEV_SD0) { + if (disk_status(drv) & STA_NOINIT) + return RES_NOTRDY; + + if (!(SD0_CardType & CT_BLOCK)) + sect *= 512; /* Convert LBA to byte address if needed */ + + cmd = count > 1 ? CMD18 : CMD17; /* READ_MULTIPLE_BLOCK : READ_SINGLE_BLOCK */ + if (SD0_Tx_cmd(cmd, sect) == 0) { + do { + if (!SD0_Rx_datablock(buff, 512)) + break; + buff += 512; + } while (--count); + if (cmd == CMD18) + SD0_Tx_cmd(CMD12, 0); /* STOP_TRANSMISSION */ + } + SD0_deselect(); + } + + if ( drv == DEV_SD1) { + if (disk_status(drv) & STA_NOINIT) + return RES_NOTRDY; + + if (!(SD1_CardType & CT_BLOCK)) + sect *= 512; /* Convert LBA to byte address if needed */ + + cmd = count > 1 ? CMD18 : CMD17; /* READ_MULTIPLE_BLOCK : READ_SINGLE_BLOCK */ + if (SD1_Tx_cmd(cmd, sect) == 0) { + do { + if (!SD1_Rx_datablock(buff, 512)) + break; + buff += 512; + } while (--count); + if (cmd == CMD18) + SD1_Tx_cmd(CMD12, 0); /* STOP_TRANSMISSION */ + } + SD1_deselect(); + } + + return count ? RES_ERROR : RES_OK; +} + +/*-----------------------------------------------------------------------*/ +/* Write Sector(s) */ +/*-----------------------------------------------------------------------*/ +//DRESULT disk_write ( +// BYTE drv, /* Physical drive nmuber (0) */ +// const BYTE *buff, /* Pointer to the data to be written */ +// LBA_t sector, /* Start sector number (LBA) */ +// UINT count /* Sector count (1..128) */ +//) +DRESULT disk_write ( BYTE drv, const BYTE *buff, LBA_t sector, UINT count ) { + DWORD sect = (DWORD)sector; + + if ( drv == DEV_SD0) { + if (disk_status(drv) & STA_NOINIT) + return RES_NOTRDY; + + if (!(SD0_CardType & CT_BLOCK)) sect *= 512; /* Convert LBA to byte address if needed */ + + if (count == 1) { /* Single block write */ + if ((SD0_Tx_cmd(CMD24, sect) == 0) && SD0_Tx_datablock(buff, 0xFE)) + count = 0; + } + else { /* Multiple block write */ + if (SD0_CardType & CT_SDC) + SD0_Tx_cmd(ACMD23, count); + + if (SD0_Tx_cmd(CMD25, sect) == 0) { /* WRITE_MULTIPLE_BLOCK */ + do { + if (!SD0_Tx_datablock(buff, 0xFC)) + break; + buff += 512; + } while (--count); + + if (!SD0_Tx_datablock(0, 0xFD)) /* STOP_TRAN token */ + count = 1; + } + } + SD0_deselect(); + } + + if ( drv == DEV_SD1) { + if (disk_status(drv) & STA_NOINIT) + return RES_NOTRDY; + + if (!(SD1_CardType & CT_BLOCK)) sect *= 512; /* Convert LBA to byte address if needed */ + + if (count == 1) { /* Single block write */ + if ((SD1_Tx_cmd(CMD24, sect) == 0) && SD1_Tx_datablock(buff, 0xFE)) + count = 0; + } + else { /* Multiple block write */ + if (SD1_CardType & CT_SDC) + SD1_Tx_cmd(ACMD23, count); + + if (SD1_Tx_cmd(CMD25, sect) == 0) { /* WRITE_MULTIPLE_BLOCK */ + do { + if (!SD1_Tx_datablock(buff, 0xFC)) + break; + buff += 512; + } while (--count); + + if (!SD1_Tx_datablock(0, 0xFD)) /* STOP_TRAN token */ + count = 1; + } + } + SD1_deselect(); + } + + return count ? RES_ERROR : RES_OK; +} + + +/*-----------------------------------------------------------------------*/ +/* Miscellaneous Functions */ +/*-----------------------------------------------------------------------*/ +//DRESULT disk_ioctl ( +// BYTE drv, /* Physical drive nmuber (0) */ +// BYTE ctrl, /* Control code */ +// void *buff /* Buffer to send/receive control data */ +//) +DRESULT disk_ioctl ( BYTE drv, BYTE ctrl, void *buff ) { + DRESULT res; + BYTE n, csd[16]; + DWORD cs; + + if ( drv == DEV_SD0) { + if (disk_status(drv) & STA_NOINIT) + return RES_NOTRDY; /* Check if card is in the socket */ + + res = RES_ERROR; + switch (ctrl) { + + case CTRL_SYNC : /* Make sure that no pending write process */ + if (SD0_select()) + res = RES_OK; + break; + + case GET_SECTOR_COUNT : /* Get number of sectors on the disk (DWORD) */ + if ((SD0_Tx_cmd(CMD9, 0) == 0) && SD0_Rx_datablock(csd, 16)) { + if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */ + cs = csd[9] + ((WORD)csd[8] << 8) + ((DWORD)(csd[7] & 63) << 16) + 1; + *(LBA_t*)buff = cs << 10; + } + else { /* SDC ver 1.XX or MMC */ + n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2; + cs = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1; + *(LBA_t*)buff = cs << (n - 9); + } + res = RES_OK; + } + break; + + case GET_BLOCK_SIZE : /* Get erase block size in unit of sector (DWORD) */ + *(DWORD*)buff = 128; + res = RES_OK; + break; + + default: + res = RES_PARERR; + } + SD0_deselect(); + } + + if ( drv == DEV_SD1) { + if (disk_status(drv) & STA_NOINIT) + return RES_NOTRDY; /* Check if card is in the socket */ + + res = RES_ERROR; + + switch (ctrl) { + case CTRL_SYNC : /* Make sure that no pending write process */ + if (SD1_select()) + res = RES_OK; + break; + + case GET_SECTOR_COUNT : /* Get number of sectors on the disk (DWORD) */ + if ((SD1_Tx_cmd(CMD9, 0) == 0) && SD1_Rx_datablock(csd, 16)) { + if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */ + cs = csd[9] + ((WORD)csd[8] << 8) + ((DWORD)(csd[7] & 63) << 16) + 1; + *(LBA_t*)buff = cs << 10; + } + else { /* SDC ver 1.XX or MMC */ + n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2; + cs = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1; + *(LBA_t*)buff = cs << (n - 9); + } + res = RES_OK; + } + break; + + case GET_BLOCK_SIZE : /* Get erase block size in unit of sector (DWORD) */ + *(DWORD*)buff = 128; + res = RES_OK; + break; + + default: + res = RES_PARERR; + } + SD1_deselect(); + + } + return res; +} + +DWORD get_fattime (void) +{ + t_time time; + rtc_get_time(&time); + + return (DWORD)(time.year - 80) << 25 | + (DWORD)(time.month + 1) << 21 | + (DWORD)time.day << 16 | + (DWORD)time.hour << 11 | + (DWORD)time.minute << 5 | + (DWORD)time.second >> 1; +} diff --git a/src/fatfs/diskio.h b/src/fatfs/f256xe_diskio.h similarity index 100% rename from src/fatfs/diskio.h rename to src/fatfs/f256xe_diskio.h diff --git a/src/fatfs/f256xe_diskio_spi.c b/src/fatfs/f256xe_diskio_spi.c new file mode 100644 index 0000000..f83d7fd --- /dev/null +++ b/src/fatfs/f256xe_diskio_spi.c @@ -0,0 +1,548 @@ +/** + ****************************************************************************** + * @file user_diskio_spi.c + * @brief This file contains the implementation of the user_diskio_spi FatFs + * driver. + ****************************************************************************** + * Portions copyright (C) 2014, ChaN, all rights reserved. + * Portions copyright (C) 2017, kiwih, all rights reserved. + * + * This software is a free software and there is NO WARRANTY. + * No restriction on use. You can use, modify and redistribute it for + * personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY. + * Redistributions of source code must retain the above copyright notice. + * + ****************************************************************************** + */ + +//This code was ported by kiwih from a copywrited (C) library written by ChaN +//available at http://elm-chan.org/fsw/ff/ffsample.zip +//(text at http://elm-chan.org/fsw/ff/00index_e.html) + +//This file provides the FatFs driver functions and SPI code required to manage +//an SPI-connected MMC or compatible SD card with FAT + +//It is designed to be wrapped by a cubemx generated user_diskio.c file. + +#include "stm32f3xx_hal.h" /* Provide the low-level HAL functions */ +#include "user_diskio_spi.h" + +//Make sure you set #define SD_SPI_HANDLE as some hspix in main.h +//Make sure you set #define SD_CS_GPIO_Port as some GPIO port in main.h +//Make sure you set #define SD_CS_Pin as some GPIO pin in main.h +extern SPI_HandleTypeDef SD_SPI_HANDLE; + +/* Function prototypes */ + +//(Note that the _256 is used as a mask to clear the prescalar bits as it provides binary 111 in the correct position) +#define FCLK_SLOW() { MODIFY_REG(SD_SPI_HANDLE.Instance->CR1, SPI_BAUDRATEPRESCALER_256, SPI_BAUDRATEPRESCALER_128); } /* Set SCLK = slow, approx 280 KBits/s*/ +#define FCLK_FAST() { MODIFY_REG(SD_SPI_HANDLE.Instance->CR1, SPI_BAUDRATEPRESCALER_256, SPI_BAUDRATEPRESCALER_8); } /* Set SCLK = fast, approx 4.5 MBits/s */ + +#define CS_HIGH() {HAL_GPIO_WritePin(SD_CS_GPIO_Port, SD_CS_Pin, GPIO_PIN_SET);} +#define CS_LOW() {HAL_GPIO_WritePin(SD_CS_GPIO_Port, SD_CS_Pin, GPIO_PIN_RESET);} + +/*-------------------------------------------------------------------------- + + Module Private Functions + +---------------------------------------------------------------------------*/ + +/* MMC/SD command */ +#define CMD0 (0) /* GO_IDLE_STATE */ +#define CMD1 (1) /* SEND_OP_COND (MMC) */ +#define ACMD41 (0x80+41) /* SEND_OP_COND (SDC) */ +#define CMD8 (8) /* SEND_IF_COND */ +#define CMD9 (9) /* SEND_CSD */ +#define CMD10 (10) /* SEND_CID */ +#define CMD12 (12) /* STOP_TRANSMISSION */ +#define ACMD13 (0x80+13) /* SD_STATUS (SDC) */ +#define CMD16 (16) /* SET_BLOCKLEN */ +#define CMD17 (17) /* READ_SINGLE_BLOCK */ +#define CMD18 (18) /* READ_MULTIPLE_BLOCK */ +#define CMD23 (23) /* SET_BLOCK_COUNT (MMC) */ +#define ACMD23 (0x80+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */ +#define CMD24 (24) /* WRITE_BLOCK */ +#define CMD25 (25) /* WRITE_MULTIPLE_BLOCK */ +#define CMD32 (32) /* ERASE_ER_BLK_START */ +#define CMD33 (33) /* ERASE_ER_BLK_END */ +#define CMD38 (38) /* ERASE */ +#define CMD55 (55) /* APP_CMD */ +#define CMD58 (58) /* READ_OCR */ + +/* MMC card type flags (MMC_GET_TYPE) */ +#define CT_MMC 0x01 /* MMC ver 3 */ +#define CT_SD1 0x02 /* SD ver 1 */ +#define CT_SD2 0x04 /* SD ver 2 */ +#define CT_SDC (CT_SD1|CT_SD2) /* SD */ +#define CT_BLOCK 0x08 /* Block addressing */ + +static volatile +DSTATUS Stat = STA_NOINIT; /* Physical drive status */ + + +static +BYTE CardType; /* Card type flags */ + +uint32_t spiTimerTickStart; +uint32_t spiTimerTickDelay; + +void SPI_Timer_On(uint32_t waitTicks) { + spiTimerTickStart = HAL_GetTick(); + spiTimerTickDelay = waitTicks; +} + +uint8_t SPI_Timer_Status() { + return ((HAL_GetTick() - spiTimerTickStart) < spiTimerTickDelay); +} + +/*-----------------------------------------------------------------------*/ +/* SPI controls (Platform dependent) */ +/*-----------------------------------------------------------------------*/ + +/* Exchange a byte */ +static +BYTE xchg_spi ( + BYTE dat /* Data to send */ +) +{ + BYTE rxDat; + HAL_SPI_TransmitReceive(&SD_SPI_HANDLE, &dat, &rxDat, 1, 50); + return rxDat; +} + + +/* Receive multiple byte */ +static +void rcvr_spi_multi ( + BYTE *buff, /* Pointer to data buffer */ + UINT btr /* Number of bytes to receive (even number) */ +) +{ + for(UINT i=0; i */ + cmd &= 0x7F; + res = send_cmd(CMD55, 0); + if (res > 1) return res; + } + + /* Select the card and wait for ready except to stop multiple block read */ + if (cmd != CMD12) { + despiselect(); + if (!spiselect()) return 0xFF; + } + + /* Send command packet */ + xchg_spi(0x40 | cmd); /* Start + command index */ + xchg_spi((BYTE)(arg >> 24)); /* Argument[31..24] */ + xchg_spi((BYTE)(arg >> 16)); /* Argument[23..16] */ + xchg_spi((BYTE)(arg >> 8)); /* Argument[15..8] */ + xchg_spi((BYTE)arg); /* Argument[7..0] */ + n = 0x01; /* Dummy CRC + Stop */ + if (cmd == CMD0) n = 0x95; /* Valid CRC for CMD0(0) */ + if (cmd == CMD8) n = 0x87; /* Valid CRC for CMD8(0x1AA) */ + xchg_spi(n); + + /* Receive command resp */ + if (cmd == CMD12) xchg_spi(0xFF); /* Diacard following one byte when CMD12 */ + n = 10; /* Wait for response (10 bytes max) */ + do { + res = xchg_spi(0xFF); + } while ((res & 0x80) && --n); + + return res; /* Return received response */ +} + + +/*-------------------------------------------------------------------------- + + Public FatFs Functions (wrapped in user_diskio.c) + +---------------------------------------------------------------------------*/ + +//The following functions are defined as inline because they aren't the functions that +//are passed to FatFs - they are wrapped by autogenerated (non-inline) cubemx template +//code. +//If you do not wish to use cubemx, remove the "inline" from these functions here +//and in the associated .h + + +/*-----------------------------------------------------------------------*/ +/* Initialize disk drive */ +/*-----------------------------------------------------------------------*/ + +inline DSTATUS USER_SPI_initialize ( + BYTE drv /* Physical drive number (0) */ +) +{ + BYTE n, cmd, ty, ocr[4]; + + if (drv != 0) return STA_NOINIT; /* Supports only drive 0 */ + //assume SPI already init init_spi(); /* Initialize SPI */ + + if (Stat & STA_NODISK) return Stat; /* Is card existing in the soket? */ + + FCLK_SLOW(); + for (n = 10; n; n--) xchg_spi(0xFF); /* Send 80 dummy clocks */ + + ty = 0; + if (send_cmd(CMD0, 0) == 1) { /* Put the card SPI/Idle state */ + SPI_Timer_On(1000); /* Initialization timeout = 1 sec */ + if (send_cmd(CMD8, 0x1AA) == 1) { /* SDv2? */ + for (n = 0; n < 4; n++) ocr[n] = xchg_spi(0xFF); /* Get 32 bit return value of R7 resp */ + if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* Is the card supports vcc of 2.7-3.6V? */ + while (SPI_Timer_Status() && send_cmd(ACMD41, 1UL << 30)) ; /* Wait for end of initialization with ACMD41(HCS) */ + if (SPI_Timer_Status() && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */ + for (n = 0; n < 4; n++) ocr[n] = xchg_spi(0xFF); + ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* Card id SDv2 */ + } + } + } else { /* Not SDv2 card */ + if (send_cmd(ACMD41, 0) <= 1) { /* SDv1 or MMC? */ + ty = CT_SD1; cmd = ACMD41; /* SDv1 (ACMD41(0)) */ + } else { + ty = CT_MMC; cmd = CMD1; /* MMCv3 (CMD1(0)) */ + } + while (SPI_Timer_Status() && send_cmd(cmd, 0)) ; /* Wait for end of initialization */ + if (!SPI_Timer_Status() || send_cmd(CMD16, 512) != 0) /* Set block length: 512 */ + ty = 0; + } + } + CardType = ty; /* Card type */ + despiselect(); + + if (ty) { /* OK */ + FCLK_FAST(); /* Set fast clock */ + Stat &= ~STA_NOINIT; /* Clear STA_NOINIT flag */ + } else { /* Failed */ + Stat = STA_NOINIT; + } + + return Stat; +} + + + +/*-----------------------------------------------------------------------*/ +/* Get disk status */ +/*-----------------------------------------------------------------------*/ + +inline DSTATUS USER_SPI_status ( + BYTE drv /* Physical drive number (0) */ +) +{ + if (drv) return STA_NOINIT; /* Supports only drive 0 */ + + return Stat; /* Return disk status */ +} + + + +/*-----------------------------------------------------------------------*/ +/* Read sector(s) */ +/*-----------------------------------------------------------------------*/ + +inline DRESULT USER_SPI_read ( + BYTE drv, /* Physical drive number (0) */ + BYTE *buff, /* Pointer to the data buffer to store read data */ + DWORD sector, /* Start sector number (LBA) */ + UINT count /* Number of sectors to read (1..128) */ +) +{ + if (drv || !count) return RES_PARERR; /* Check parameter */ + if (Stat & STA_NOINIT) return RES_NOTRDY; /* Check if drive is ready */ + + if (!(CardType & CT_BLOCK)) sector *= 512; /* LBA ot BA conversion (byte addressing cards) */ + + if (count == 1) { /* Single sector read */ + if ((send_cmd(CMD17, sector) == 0) /* READ_SINGLE_BLOCK */ + && rcvr_datablock(buff, 512)) { + count = 0; + } + } + else { /* Multiple sector read */ + if (send_cmd(CMD18, sector) == 0) { /* READ_MULTIPLE_BLOCK */ + do { + if (!rcvr_datablock(buff, 512)) break; + buff += 512; + } while (--count); + send_cmd(CMD12, 0); /* STOP_TRANSMISSION */ + } + } + despiselect(); + + return count ? RES_ERROR : RES_OK; /* Return result */ +} + + + +/*-----------------------------------------------------------------------*/ +/* Write sector(s) */ +/*-----------------------------------------------------------------------*/ + +#if _USE_WRITE +inline DRESULT USER_SPI_write ( + BYTE drv, /* Physical drive number (0) */ + const BYTE *buff, /* Ponter to the data to write */ + DWORD sector, /* Start sector number (LBA) */ + UINT count /* Number of sectors to write (1..128) */ +) +{ + if (drv || !count) return RES_PARERR; /* Check parameter */ + if (Stat & STA_NOINIT) return RES_NOTRDY; /* Check drive status */ + if (Stat & STA_PROTECT) return RES_WRPRT; /* Check write protect */ + + if (!(CardType & CT_BLOCK)) sector *= 512; /* LBA ==> BA conversion (byte addressing cards) */ + + if (count == 1) { /* Single sector write */ + if ((send_cmd(CMD24, sector) == 0) /* WRITE_BLOCK */ + && xmit_datablock(buff, 0xFE)) { + count = 0; + } + } + else { /* Multiple sector write */ + if (CardType & CT_SDC) send_cmd(ACMD23, count); /* Predefine number of sectors */ + if (send_cmd(CMD25, sector) == 0) { /* WRITE_MULTIPLE_BLOCK */ + do { + if (!xmit_datablock(buff, 0xFC)) break; + buff += 512; + } while (--count); + if (!xmit_datablock(0, 0xFD)) count = 1; /* STOP_TRAN token */ + } + } + despiselect(); + + return count ? RES_ERROR : RES_OK; /* Return result */ +} +#endif + + +/*-----------------------------------------------------------------------*/ +/* Miscellaneous drive controls other than data read/write */ +/*-----------------------------------------------------------------------*/ + +#if _USE_IOCTL +inline DRESULT USER_SPI_ioctl ( + BYTE drv, /* Physical drive number (0) */ + BYTE cmd, /* Control command code */ + void *buff /* Pointer to the conrtol data */ +) +{ + DRESULT res; + BYTE n, csd[16]; + DWORD *dp, st, ed, csize; + + + if (drv) return RES_PARERR; /* Check parameter */ + if (Stat & STA_NOINIT) return RES_NOTRDY; /* Check if drive is ready */ + + res = RES_ERROR; + + switch (cmd) { + case CTRL_SYNC : /* Wait for end of internal write process of the drive */ + if (spiselect()) res = RES_OK; + break; + + case GET_SECTOR_COUNT : /* Get drive capacity in unit of sector (DWORD) */ + if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { + if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */ + csize = csd[9] + ((WORD)csd[8] << 8) + ((DWORD)(csd[7] & 63) << 16) + 1; + *(DWORD*)buff = csize << 10; + } else { /* SDC ver 1.XX or MMC ver 3 */ + n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2; + csize = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1; + *(DWORD*)buff = csize << (n - 9); + } + res = RES_OK; + } + break; + + case GET_BLOCK_SIZE : /* Get erase block size in unit of sector (DWORD) */ + if (CardType & CT_SD2) { /* SDC ver 2.00 */ + if (send_cmd(ACMD13, 0) == 0) { /* Read SD status */ + xchg_spi(0xFF); + if (rcvr_datablock(csd, 16)) { /* Read partial block */ + for (n = 64 - 16; n; n--) xchg_spi(0xFF); /* Purge trailing data */ + *(DWORD*)buff = 16UL << (csd[10] >> 4); + res = RES_OK; + } + } + } else { /* SDC ver 1.XX or MMC */ + if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { /* Read CSD */ + if (CardType & CT_SD1) { /* SDC ver 1.XX */ + *(DWORD*)buff = (((csd[10] & 63) << 1) + ((WORD)(csd[11] & 128) >> 7) + 1) << ((csd[13] >> 6) - 1); + } else { /* MMC */ + *(DWORD*)buff = ((WORD)((csd[10] & 124) >> 2) + 1) * (((csd[11] & 3) << 3) + ((csd[11] & 224) >> 5) + 1); + } + res = RES_OK; + } + } + break; + + case CTRL_TRIM : /* Erase a block of sectors (used when _USE_ERASE == 1) */ + if (!(CardType & CT_SDC)) break; /* Check if the card is SDC */ + if (USER_SPI_ioctl(drv, MMC_GET_CSD, csd)) break; /* Get CSD */ + if (!(csd[0] >> 6) && !(csd[10] & 0x40)) break; /* Check if sector erase can be applied to the card */ + dp = buff; st = dp[0]; ed = dp[1]; /* Load sector block */ + if (!(CardType & CT_BLOCK)) { + st *= 512; ed *= 512; + } + if (send_cmd(CMD32, st) == 0 && send_cmd(CMD33, ed) == 0 && send_cmd(CMD38, 0) == 0 && wait_ready(30000)) { /* Erase sector block */ + res = RES_OK; /* FatFs does not check result of this command */ + } + break; + + default: + res = RES_PARERR; + } + + despiselect(); + + return res; +} +#endif \ No newline at end of file diff --git a/src/fatfs/f256xe_diskio_spi.h b/src/fatfs/f256xe_diskio_spi.h new file mode 100644 index 0000000..e86cc50 --- /dev/null +++ b/src/fatfs/f256xe_diskio_spi.h @@ -0,0 +1,38 @@ +/** + ****************************************************************************** + * @file user_diskio_spi.h + * @brief This file contains the common defines and functions prototypes for + * the user_diskio_spi driver implementation + ****************************************************************************** + * Portions copyright (C) 2014, ChaN, all rights reserved. + * Portions copyright (C) 2017, kiwih, all rights reserved. + * + * This software is a free software and there is NO WARRANTY. + * No restriction on use. You can use, modify and redistribute it for + * personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY. + * Redistributions of source code must retain the above copyright notice. + * + ****************************************************************************** + */ + +#ifndef _USER_DISKIO_SPI_H +#define _USER_DISKIO_SPI_H + +#include "integer.h" //from FatFs middleware library +#include "diskio.h" //from FatFs middleware library +#include "ff_gen_drv.h" //from FatFs middleware library + +//we define these as inline because we don't want them to be actual function calls (they get "called" from the cubemx autogenerated user_diskio file) +//we define them as extern because they are defined in a separate .c file to user_diskio.c (which #includes this .h file) + +extern DSTATUS USER_SPI_initialize (BYTE pdrv); +extern DSTATUS USER_SPI_status (BYTE pdrv); +extern DRESULT USER_SPI_read (BYTE pdrv, BYTE *buff, DWORD sector, UINT count); +#if _USE_WRITE == 1 + extern DRESULT USER_SPI_write (BYTE pdrv, const BYTE *buff, DWORD sector, UINT count); +#endif /* _USE_WRITE == 1 */ +#if _USE_IOCTL == 1 + extern DRESULT USER_SPI_ioctl (BYTE pdrv, BYTE cmd, void *buff); +#endif /* _USE_IOCTL == 1 */ + +#endif \ No newline at end of file diff --git a/src/fatfs/ff.c b/src/fatfs/ff.c index d209605..c4973c9 100644 --- a/src/fatfs/ff.c +++ b/src/fatfs/ff.c @@ -1,8 +1,8 @@ /*----------------------------------------------------------------------------/ -/ FatFs - Generic FAT Filesystem Module R0.14b / +/ FatFs - Generic FAT Filesystem Module R0.15 w/patch1 / /-----------------------------------------------------------------------------/ / -/ Copyright (C) 2021, ChaN, all right reserved. +/ Copyright (C) 2022, ChaN, all right reserved. / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided @@ -21,7 +21,7 @@ #include #include "ff.h" /* Declarations of FatFs API */ -#include "diskio.h" /* Declarations of device I/O functions */ +#include "f256xe_diskio.h" /* Declarations of device I/O functions */ /*-------------------------------------------------------------------------- @@ -30,7 +30,7 @@ ---------------------------------------------------------------------------*/ -#if FF_DEFINED != 86631 /* Revision ID */ +#if FF_DEFINED != 80286 /* Revision ID */ #error Wrong include file (ff.h). #endif @@ -208,26 +208,26 @@ #define PTE_StLba 8 /* MBR PTE: Start in LBA */ #define PTE_SizLba 12 /* MBR PTE: Size in LBA */ -#define GPTH_Sign 0 /* GPT: Header signature (8-byte) */ -#define GPTH_Rev 8 /* GPT: Revision (DWORD) */ -#define GPTH_Size 12 /* GPT: Header size (DWORD) */ -#define GPTH_Bcc 16 /* GPT: Header BCC (DWORD) */ -#define GPTH_CurLba 24 /* GPT: Main header LBA (QWORD) */ -#define GPTH_BakLba 32 /* GPT: Backup header LBA (QWORD) */ -#define GPTH_FstLba 40 /* GPT: First LBA for partitions (QWORD) */ -#define GPTH_LstLba 48 /* GPT: Last LBA for partitions (QWORD) */ -#define GPTH_DskGuid 56 /* GPT: Disk GUID (16-byte) */ -#define GPTH_PtOfs 72 /* GPT: Partation table LBA (QWORD) */ -#define GPTH_PtNum 80 /* GPT: Number of table entries (DWORD) */ -#define GPTH_PteSize 84 /* GPT: Size of table entry (DWORD) */ -#define GPTH_PtBcc 88 /* GPT: Partation table BCC (DWORD) */ -#define SZ_GPTE 128 /* GPT: Size of partition table entry */ +#define GPTH_Sign 0 /* GPT HDR: Signature (8-byte) */ +#define GPTH_Rev 8 /* GPT HDR: Revision (DWORD) */ +#define GPTH_Size 12 /* GPT HDR: Header size (DWORD) */ +#define GPTH_Bcc 16 /* GPT HDR: Header BCC (DWORD) */ +#define GPTH_CurLba 24 /* GPT HDR: This header LBA (QWORD) */ +#define GPTH_BakLba 32 /* GPT HDR: Another header LBA (QWORD) */ +#define GPTH_FstLba 40 /* GPT HDR: First LBA for partition data (QWORD) */ +#define GPTH_LstLba 48 /* GPT HDR: Last LBA for partition data (QWORD) */ +#define GPTH_DskGuid 56 /* GPT HDR: Disk GUID (16-byte) */ +#define GPTH_PtOfs 72 /* GPT HDR: Partition table LBA (QWORD) */ +#define GPTH_PtNum 80 /* GPT HDR: Number of table entries (DWORD) */ +#define GPTH_PteSize 84 /* GPT HDR: Size of table entry (DWORD) */ +#define GPTH_PtBcc 88 /* GPT HDR: Partition table BCC (DWORD) */ +#define SZ_GPTE 128 /* GPT PTE: Size of partition table entry */ #define GPTE_PtGuid 0 /* GPT PTE: Partition type GUID (16-byte) */ #define GPTE_UpGuid 16 /* GPT PTE: Partition unique GUID (16-byte) */ -#define GPTE_FstLba 32 /* GPT PTE: First LBA (QWORD) */ -#define GPTE_LstLba 40 /* GPT PTE: Last LBA inclusive (QWORD) */ -#define GPTE_Flags 48 /* GPT PTE: Flags (QWORD) */ -#define GPTE_Name 56 /* GPT PTE: Name */ +#define GPTE_FstLba 32 /* GPT PTE: First LBA of partition (QWORD) */ +#define GPTE_LstLba 40 /* GPT PTE: Last LBA of partition (QWORD) */ +#define GPTE_Flags 48 /* GPT PTE: Partition flags (QWORD) */ +#define GPTE_Name 56 /* GPT PTE: Partition name */ /* Post process on fatal error in the file operations */ @@ -239,7 +239,7 @@ #if FF_USE_LFN == 1 #error Static LFN work area cannot be used in thread-safe configuration #endif -#define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; } +#define LEAVE_FF(fs, res) { unlock_volume(fs, res); return res; } #else #define LEAVE_FF(fs, res) return res #endif @@ -278,15 +278,15 @@ /* File lock controls */ -#if FF_FS_LOCK != 0 +#if FF_FS_LOCK #if FF_FS_READONLY #error FF_FS_LOCK must be 0 at read-only configuration #endif typedef struct { - FATFS *fs; /* Object ID 1, volume (NULL:blank entry) */ + FATFS* fs; /* Object ID 1, volume (NULL:blank entry) */ DWORD clu; /* Object ID 2, containing directory (0:root) */ DWORD ofs; /* Object ID 3, offset in the directory */ - WORD ctr; /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */ + UINT ctr; /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */ } FILESEM; #endif @@ -461,20 +461,23 @@ typedef struct { #if FF_VOLUMES < 1 || FF_VOLUMES > 10 #error Wrong FF_VOLUMES setting #endif -static FATFS* FatFs[FF_VOLUMES]; /* Pointer to the filesystem objects (logical drives) */ +static FATFS *FatFs[FF_VOLUMES]; /* Pointer to the filesystem objects (logical drives) */ static WORD Fsid; /* Filesystem mount ID */ #if FF_FS_RPATH != 0 -static BYTE CurrVol; /* Current drive */ +static BYTE CurrVol; /* Current drive set by f_chdrive() */ #endif #if FF_FS_LOCK != 0 static FILESEM Files[FF_FS_LOCK]; /* Open object lock semaphores */ +#if FF_FS_REENTRANT +static BYTE SysLock; /* System lock flag (0:no mutex, 1:unlocked, 2:locked) */ +#endif #endif #if FF_STR_VOLUME_ID #ifdef FF_VOLUME_STRS -static const char* const VolumeStr[FF_VOLUMES] = {FF_VOLUME_STRS}; /* Pre-defined volume ID */ +static const char *const VolumeStr[FF_VOLUMES] = {FF_VOLUME_STRS}; /* Pre-defined volume ID */ #endif #endif @@ -563,7 +566,8 @@ static WCHAR LfnBuf[FF_MAX_LFN + 1]; /* LFN working buffer */ #if FF_CODE_PAGE == 0 /* Run-time code page configuration */ #define CODEPAGE CodePage static WORD CodePage; /* Current code page */ -static const BYTE *ExCvt, *DbcTbl; /* Pointer to current SBCS up-case table and DBCS code range table below */ +static const BYTE* ExCvt; /* Ptr to SBCS up-case table Ct???[] (null:not used) */ +static const BYTE* DbcTbl; /* Ptr to DBCS code range table Dc???[] (null:not used) */ static const BYTE Ct437[] = TBL_CT437; static const BYTE Ct720[] = TBL_CT720; @@ -887,21 +891,45 @@ static UINT put_utf ( /* Returns number of encoding units written (0:buffer over /*-----------------------------------------------------------------------*/ /* Request/Release grant to access the volume */ /*-----------------------------------------------------------------------*/ -static int lock_fs ( /* 1:Ok, 0:timeout */ - FATFS* fs /* Filesystem object */ + +static int lock_volume ( /* 1:Ok, 0:timeout */ + FATFS* fs, /* Filesystem object to lock */ + int syslock /* System lock required */ ) { - return ff_req_grant(fs->sobj); + int rv; + + +#if FF_FS_LOCK + rv = ff_mutex_take(fs->ldrv); /* Lock the volume */ + if (rv && syslock) { /* System lock reqiered? */ + rv = ff_mutex_take(FF_VOLUMES); /* Lock the system */ + if (rv) { + SysLock = 2; /* System lock succeeded */ + } else { + ff_mutex_give(fs->ldrv); /* Failed system lock */ + } + } +#else + rv = syslock ? ff_mutex_take(fs->ldrv) : ff_mutex_take(fs->ldrv); /* Lock the volume (this is to prevent compiler warning) */ +#endif + return rv; } -static void unlock_fs ( +static void unlock_volume ( FATFS* fs, /* Filesystem object */ FRESULT res /* Result code to be returned */ ) { if (fs && res != FR_NOT_ENABLED && res != FR_INVALID_DRIVE && res != FR_TIMEOUT) { - ff_rel_grant(fs->sobj); +#if FF_FS_LOCK + if (SysLock == 2) { /* Is the system locked? */ + SysLock = 1; + ff_mutex_give(FF_VOLUMES); + } +#endif + ff_mutex_give(fs->ldrv); /* Unlock the volume */ } } @@ -909,12 +937,12 @@ static void unlock_fs ( -#if FF_FS_LOCK != 0 +#if FF_FS_LOCK /*-----------------------------------------------------------------------*/ -/* File lock control functions */ +/* File shareing control functions */ /*-----------------------------------------------------------------------*/ -static FRESULT chk_lock ( /* Check if the file can be accessed */ +static FRESULT chk_share ( /* Check if the file can be accessed */ DIR* dp, /* Directory object pointing the file to be checked */ int acc /* Desired access type (0:Read mode open, 1:Write mode open, 2:Delete or rename) */ ) @@ -941,16 +969,16 @@ static FRESULT chk_lock ( /* Check if the file can be accessed */ } -static int enq_lock (void) /* Check if an entry is available for a new object */ +static int enq_share (void) /* Check if an entry is available for a new object */ { UINT i; - for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ; + for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ; /* Find a free entry */ return (i == FF_FS_LOCK) ? 0 : 1; } -static UINT inc_lock ( /* Increment object open counter and returns its index (0:Internal error) */ +static UINT inc_share ( /* Increment object open counter and returns its index (0:Internal error) */ DIR* dp, /* Directory object pointing the file to register or increment */ int acc /* Desired access (0:Read, 1:Write, 2:Delete/Rename) */ ) @@ -965,7 +993,7 @@ static UINT inc_lock ( /* Increment object open counter and returns its index (0 } if (i == FF_FS_LOCK) { /* Not opened. Register it as new. */ - for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ; + for (i = 0; i < FF_FS_LOCK && Files[i].fs; i++) ; /* Find a free entry */ if (i == FF_FS_LOCK) return 0; /* No free entry to register (int err) */ Files[i].fs = dp->obj.fs; Files[i].clu = dp->obj.sclust; @@ -981,30 +1009,32 @@ static UINT inc_lock ( /* Increment object open counter and returns its index (0 } -static FRESULT dec_lock ( /* Decrement object open counter */ +static FRESULT dec_share ( /* Decrement object open counter */ UINT i /* Semaphore index (1..) */ ) { - WORD n; + UINT n; FRESULT res; if (--i < FF_FS_LOCK) { /* Index number origin from 0 */ n = Files[i].ctr; - if (n == 0x100) n = 0; /* If write mode open, delete the entry */ + if (n == 0x100) n = 0; /* If write mode open, delete the object semaphore */ if (n > 0) n--; /* Decrement read mode open count */ Files[i].ctr = n; - if (n == 0) Files[i].fs = 0; /* Delete the entry if open count gets zero */ + if (n == 0) { /* Delete the object semaphore if open count becomes zero */ + Files[i].fs = 0; /* Free the entry << 1, there is a potential error in this process >>> */ + } res = FR_OK; } else { - res = FR_INT_ERR; /* Invalid index nunber */ + res = FR_INT_ERR; /* Invalid index number */ } return res; } -static void clear_lock ( /* Clear lock entries of the volume */ - FATFS *fs +static void clear_share ( /* Clear all lock entries of the volume */ + FATFS* fs ) { UINT i; @@ -1014,7 +1044,7 @@ static void clear_lock ( /* Clear lock entries of the volume */ } } -#endif /* FF_FS_LOCK != 0 */ +#endif /* FF_FS_LOCK */ @@ -1599,7 +1629,8 @@ static DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */ FSIZE_t ofs /* File offset to be converted to cluster# */ ) { - DWORD cl, ncl, *tbl; + DWORD cl, ncl; + DWORD *tbl; FATFS *fs = fp->obj.fs; @@ -1990,7 +2021,7 @@ static void gen_numname ( seq = (UINT)sreg; } - /* Make suffix (~ + hexdecimal) */ + /* Make suffix (~ + hexadecimal) */ i = 7; do { c = (BYTE)((seq % 16) + '0'); seq /= 16; @@ -2092,17 +2123,17 @@ static DWORD xsum32 ( /* Returns 32-bit checksum */ -/*-----------------------------------*/ -/* exFAT: Get a directry entry block */ -/*-----------------------------------*/ +/*------------------------------------*/ +/* exFAT: Get a directory entry block */ +/*------------------------------------*/ static FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ - DIR* dp /* Reading direcotry object pointing top of the entry block to load */ + DIR* dp /* Reading directory object pointing top of the entry block to load */ ) { FRESULT res; UINT i, sz_ent; - BYTE *dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory direcotry entry block 85+C0+C1s */ + BYTE *dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory directory entry block 85+C0+C1s */ /* Load file directory entry */ @@ -2166,7 +2197,7 @@ static void init_alloc_info ( /*------------------------------------------------*/ static FRESULT load_obj_xdir ( - DIR* dp, /* Blank directory object to be used to access containing direcotry */ + DIR* dp, /* Blank directory object to be used to access containing directory */ const FFOBJID* obj /* Object with its containing directory information */ ) { @@ -2195,18 +2226,18 @@ static FRESULT load_obj_xdir ( /*----------------------------------------*/ static FRESULT store_xdir ( - DIR* dp /* Pointer to the direcotry object */ + DIR* dp /* Pointer to the directory object */ ) { FRESULT res; UINT nent; - BYTE *dirb = dp->obj.fs->dirbuf; /* Pointer to the direcotry entry block 85+C0+C1s */ + BYTE *dirb = dp->obj.fs->dirbuf; /* Pointer to the directory entry block 85+C0+C1s */ /* Create set sum */ st_word(dirb + XDIR_SetSum, xdir_sum(dirb)); nent = dirb[XDIR_NumSec] + 1; - /* Store the direcotry entry block to the directory */ + /* Store the directory entry block to the directory */ res = dir_sdi(dp, dp->blk_ofs); while (res == FR_OK) { res = move_window(dp->obj.fs, dp->sect); @@ -2223,11 +2254,11 @@ static FRESULT store_xdir ( /*-------------------------------------------*/ -/* exFAT: Create a new directory enrty block */ +/* exFAT: Create a new directory entry block */ /*-------------------------------------------*/ static void create_xdir ( - BYTE* dirb, /* Pointer to the direcotry entry block buffer */ + BYTE* dirb, /* Pointer to the directory entry block buffer */ const WCHAR* lfn /* Pointer to the object name */ ) { @@ -2610,19 +2641,23 @@ static void get_fileinfo ( si = SZDIRE * 2; di = 0; /* 1st C1 entry in the entry block */ hs = 0; while (nc < fs->dirbuf[XDIR_NumName]) { - if (si >= MAXDIRB(FF_MAX_LFN)) { di = 0; break; } /* Truncated directory block? */ - if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ + if (si >= MAXDIRB(FF_MAX_LFN)) { /* Truncated directory block? */ + di = 0; break; + } + if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ wc = ld_word(fs->dirbuf + si); si += 2; nc++; /* Get a character */ - if (hs == 0 && IsSurrogate(wc)) { /* Is it a surrogate? */ - hs = wc; continue; /* Get low surrogate */ + if (hs == 0 && IsSurrogate(wc)) { /* Is it a surrogate? */ + hs = wc; continue; /* Get low surrogate */ } nw = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di); /* Store it in API encoding */ - if (nw == 0) { di = 0; break; } /* Buffer overflow or wrong char? */ + if (nw == 0) { /* Buffer overflow or wrong char? */ + di = 0; break; + } di += nw; hs = 0; } if (hs != 0) di = 0; /* Broken surrogate pair? */ - if (di == 0) fno->fname[di++] = '?'; /* Inaccessible object name? */ + if (di == 0) fno->fname[di++] = '\?'; /* Inaccessible object name? */ fno->fname[di] = 0; /* Terminate the name */ fno->altname[0] = 0; /* exFAT does not support SFN */ @@ -2643,7 +2678,9 @@ static void get_fileinfo ( hs = wc; continue; /* Get low surrogate */ } nw = put_utf((DWORD)hs << 16 | wc, &fno->fname[di], FF_LFN_BUF - di); /* Store it in API encoding */ - if (nw == 0) { di = 0; break; } /* Buffer overflow or wrong char? */ + if (nw == 0) { /* Buffer overflow or wrong char? */ + di = 0; break; + } di += nw; hs = 0; } @@ -2663,9 +2700,13 @@ static void get_fileinfo ( wc = wc << 8 | dp->dir[si++]; } wc = ff_oem2uni(wc, CODEPAGE); /* ANSI/OEM -> Unicode */ - if (wc == 0) { di = 0; break; } /* Wrong char in the current code page? */ + if (wc == 0) { /* Wrong char in the current code page? */ + di = 0; break; + } nw = put_utf(wc, &fno->altname[di], FF_SFN_BUF - di); /* Store it in API encoding */ - if (nw == 0) { di = 0; break; } /* Buffer overflow? */ + if (nw == 0) { /* Buffer overflow? */ + di = 0; break; + } di += nw; #else /* ANSI/OEM output */ fno->altname[di++] = (TCHAR)wc; /* Store it without any conversion */ @@ -2674,8 +2715,8 @@ static void get_fileinfo ( fno->altname[di] = 0; /* Terminate the SFN (null string means SFN is invalid) */ if (fno->fname[0] == 0) { /* If LFN is invalid, altname[] needs to be copied to fname[] */ - if (di == 0) { /* If LFN and SFN both are invalid, this object is inaccesible */ - fno->fname[di++] = '?'; + if (di == 0) { /* If LFN and SFN both are invalid, this object is inaccessible */ + fno->fname[di++] = '\?'; } else { for (si = di = 0, lcf = NS_BODY; fno->altname[si]; si++, di++) { /* Copy altname[] to fname[] with case information */ wc = (WCHAR)fno->altname[si]; @@ -2756,7 +2797,8 @@ static int pattern_match ( /* 0:mismatched, 1:matched */ UINT recur /* Recursion count */ ) { - const TCHAR *pptr, *nptr; + const TCHAR *pptr; + const TCHAR *nptr; DWORD pchr, nchr; UINT sk; @@ -2770,12 +2812,16 @@ static int pattern_match ( /* 0:mismatched, 1:matched */ do { pptr = pat; nptr = nam; /* Top of pattern and name to match */ for (;;) { - if (*pptr == '?' || *pptr == '*') { /* Wildcard term? */ + if (*pptr == '\?' || *pptr == '*') { /* Wildcard term? */ if (recur == 0) return 0; /* Too many wildcard terms? */ sk = 0; do { /* Analyze the wildcard term */ - if (*pptr++ == '?') sk++; else sk |= 0x100; - } while (*pptr == '?' || *pptr == '*'); + if (*pptr++ == '\?') { + sk++; + } else { + sk |= 0x100; + } + } while (*pptr == '\?' || *pptr == '*'); if (pattern_match(pptr, nptr, sk, recur - 1)) return 1; /* Test new branch (recursive call) */ nchr = *nptr; break; /* Branch mismatched */ } @@ -2805,10 +2851,11 @@ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not cr { #if FF_USE_LFN /* LFN configuration */ BYTE b, cf; - WCHAR wc, *lfn; + WCHAR wc; + WCHAR *lfn; + const TCHAR* p; DWORD uc; UINT i, ni, si, di; - const TCHAR *p; /* Create LFN into LFN working buffer */ @@ -2930,7 +2977,8 @@ static FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not cr #else /* FF_USE_LFN : Non-LFN configuration */ - BYTE c, d, *sfn; + BYTE c, d; + BYTE *sfn; UINT ni, si, i; const char *p; @@ -3091,7 +3139,8 @@ static int get_ldnumber ( /* Returns logical drive number (-1:invalid drive numb const TCHAR** path /* Pointer to pointer to the path name */ ) { - const TCHAR *tp, *tt; + const TCHAR *tp; + const TCHAR *tt; TCHAR tc; int i; int vol = -1; @@ -3102,7 +3151,9 @@ static int get_ldnumber ( /* Returns logical drive number (-1:invalid drive numb tt = tp = *path; if (!tp) return vol; /* Invalid path name? */ - do tc = *tt++; while (!IsTerminator(tc) && tc != ':'); /* Find a colon in the path */ + do { /* Find a colon in the path */ + tc = *tt++; + } while (!IsTerminator(tc) && tc != ':'); if (tc == ':') { /* DOS/Windows style volume ID? */ i = FF_VOLUMES; @@ -3190,16 +3241,18 @@ static int test_gpt_header ( /* 0:Invalid, 1:Valid */ ) { UINT i; - DWORD bcc; + DWORD bcc, hlen; - if (memcmp(gpth + GPTH_Sign, "EFI PART" "\0\0\1\0" "\x5C\0\0", 16)) return 0; /* Check sign, version (1.0) and length (92) */ - for (i = 0, bcc = 0xFFFFFFFF; i < 92; i++) { /* Check header BCC */ + if (memcmp(gpth + GPTH_Sign, "EFI PART" "\0\0\1", 12)) return 0; /* Check signature and version (1.0) */ + hlen = ld_dword(gpth + GPTH_Size); /* Check header size */ + if (hlen < 92 || hlen > FF_MIN_SS) return 0; + for (i = 0, bcc = 0xFFFFFFFF; i < hlen; i++) { /* Check header BCC */ bcc = crc32(bcc, i - GPTH_Bcc < 4 ? 0 : gpth[i]); } if (~bcc != ld_dword(gpth + GPTH_Bcc)) return 0; if (ld_dword(gpth + GPTH_PteSize) != SZ_GPTE) return 0; /* Table entry size (must be SZ_GPTE bytes) */ - if (ld_dword(gpth + GPTH_PtNum) > 128) return 0; /* Table size (must be 128 entries or less) */ + if (ld_dword(gpth + GPTH_PtNum) > 128) return 0; /* Table size (must be 128 entries or less) */ return 1; } @@ -3209,7 +3262,7 @@ static int test_gpt_header ( /* 0:Invalid, 1:Valid */ /* Generate random value */ static DWORD make_rand ( DWORD seed, /* Seed value */ - BYTE* buff, /* Output buffer */ + BYTE *buff, /* Output buffer */ UINT n /* Data length */ ) { @@ -3277,7 +3330,7 @@ static UINT check_fs ( /* 0:FAT/FAT32 VBR, 1:exFAT VBR, 2:Not FAT and valid BS, static UINT find_volume ( /* Returns BS status found in the hosting drive */ FATFS* fs, /* Filesystem object */ - UINT part /* Partition to fined = 0:auto, 1..:forced */ + UINT part /* Partition to fined = 0:find as SFD and partitions, >0:forced partition number */ ) { UINT fmt, i; @@ -3332,15 +3385,15 @@ static UINT find_volume ( /* Returns BS status found in the hosting drive */ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ const TCHAR** path, /* Pointer to pointer to the path name (drive number) */ FATFS** rfs, /* Pointer to pointer to the found filesystem object */ - BYTE mode /* !=0: Check write protection for write access */ + BYTE mode /* Desiered access mode to check write protection */ ) { int vol; + FATFS *fs; DSTATUS stat; LBA_t bsect; DWORD tsect, sysect, fasize, nclst, szbfat; WORD nrsv; - FATFS *fs; UINT fmt; @@ -3353,7 +3406,7 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ fs = FatFs[vol]; /* Get pointer to the filesystem object */ if (!fs) return FR_NOT_ENABLED; /* Is the filesystem object available? */ #if FF_FS_REENTRANT - if (!lock_fs(fs)) return FR_TIMEOUT; /* Lock the volume */ + if (!lock_volume(fs, 1)) return FR_TIMEOUT; /* Lock the volume, and system if needed */ #endif *rfs = fs; /* Return pointer to the filesystem object */ @@ -3371,9 +3424,8 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ /* The filesystem object is not valid. */ /* Following code attempts to mount the volume. (find an FAT volume, analyze the BPB and initialize the filesystem object) */ - fs->fs_type = 0; /* Clear the filesystem object */ - fs->pdrv = LD2PD(vol); /* Volume hosting physical drive */ - stat = disk_initialize(fs->pdrv); /* Initialize the physical drive */ + fs->fs_type = 0; /* Invalidate the filesystem object */ + stat = disk_initialize(fs->pdrv); /* Initialize the volume hosting physical drive */ if (stat & STA_NOINIT) { /* Check if the initialization succeeded */ return FR_NOT_READY; /* Failed to initialize due to no medium or hard error */ } @@ -3385,11 +3437,11 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ if (SS(fs) > FF_MAX_SS || SS(fs) < FF_MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR; #endif - /* Find an FAT volume on the drive */ + /* Find an FAT volume on the hosting drive */ fmt = find_volume(fs, LD2PT(vol)); - if (fmt == 4) return FR_DISK_ERR; /* An error occured in the disk I/O layer */ + if (fmt == 4) return FR_DISK_ERR; /* An error occurred in the disk I/O layer */ if (fmt >= 2) return FR_NO_FILESYSTEM; /* No FAT volume is found */ - bsect = fs->winsect; /* Volume offset */ + bsect = fs->winsect; /* Volume offset in the hosting physical drive */ /* An FAT volume is found (bsect). Following code initializes the filesystem object */ @@ -3426,7 +3478,7 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ fs->volbase = bsect; fs->database = bsect + ld_dword(fs->win + BPB_DataOfsEx); fs->fatbase = bsect + ld_dword(fs->win + BPB_FatOfsEx); - if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size requiered) */ + if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size required) */ fs->dirbase = ld_dword(fs->win + BPB_RootClusEx); /* Get bitmap location and check if it is contiguous (implementation assumption) */ @@ -3447,7 +3499,7 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ if (move_window(fs, fs->fatbase + bcl / (SS(fs) / 4)) != FR_OK) return FR_DISK_ERR; cv = ld_dword(fs->win + bcl % (SS(fs) / 4) * 4); if (cv == 0xFFFFFFFF) break; /* Last link? */ - if (cv != ++bcl) return FR_NO_FILESYSTEM; /* Fragmented? */ + if (cv != ++bcl) return FR_NO_FILESYSTEM; /* Fragmented bitmap? */ } #if !FF_FS_READONLY @@ -3534,7 +3586,7 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ #endif /* !FF_FS_READONLY */ } - fs->fs_type = (BYTE)fmt;/* FAT sub-type */ + fs->fs_type = (BYTE)fmt;/* FAT sub-type (the filesystem object gets valid) */ fs->id = ++Fsid; /* Volume mount ID */ #if FF_USE_LFN == 1 fs->lfnbuf = LfnBuf; /* Static LFN working buffer */ @@ -3545,8 +3597,8 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ #if FF_FS_RPATH != 0 fs->cdir = 0; /* Initialize current directory */ #endif -#if FF_FS_LOCK != 0 /* Clear file lock semaphores */ - clear_lock(fs); +#if FF_FS_LOCK /* Clear file lock semaphores */ + clear_share(fs); #endif return FR_OK; } @@ -3559,7 +3611,7 @@ static FRESULT mount_volume ( /* FR_OK(0): successful, !=0: an error occurred */ /*-----------------------------------------------------------------------*/ static FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ - FFOBJID* obj, /* Pointer to the FFOBJID, the 1st member in the FIL/DIR object, to check validity */ + FFOBJID* obj, /* Pointer to the FFOBJID, the 1st member in the FIL/DIR structure, to check validity */ FATFS** rfs /* Pointer to pointer to the owner filesystem object to return */ ) { @@ -3568,22 +3620,22 @@ static FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ if (obj && obj->fs && obj->fs->fs_type && obj->id == obj->fs->id) { /* Test if the object is valid */ #if FF_FS_REENTRANT - if (lock_fs(obj->fs)) { /* Obtain the filesystem object */ - if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */ + if (lock_volume(obj->fs, 0)) { /* Take a grant to access the volume */ + if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the hosting phsical drive is kept initialized */ res = FR_OK; } else { - unlock_fs(obj->fs, FR_OK); + unlock_volume(obj->fs, FR_OK); /* Invalidated volume, abort to access */ } - } else { + } else { /* Could not take */ res = FR_TIMEOUT; } #else - if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the phsical drive is kept initialized */ + if (!(disk_status(obj->fs->pdrv) & STA_NOINIT)) { /* Test if the hosting phsical drive is kept initialized */ res = FR_OK; } #endif } - *rfs = (res == FR_OK) ? obj->fs : 0; /* Corresponding filesystem object */ + *rfs = (res == FR_OK) ? obj->fs : 0; /* Return corresponding filesystem object if it is valid */ return res; } @@ -3614,30 +3666,42 @@ FRESULT f_mount ( const TCHAR *rp = path; - /* Get logical drive number */ + /* Get volume ID (logical drive number) */ vol = get_ldnumber(&rp); if (vol < 0) return FR_INVALID_DRIVE; - cfs = FatFs[vol]; /* Pointer to fs object */ + cfs = FatFs[vol]; /* Pointer to the filesystem object of the volume */ - if (cfs) { -#if FF_FS_LOCK != 0 - clear_lock(cfs); + if (cfs) { /* Unregister current filesystem object if regsitered */ + FatFs[vol] = 0; +#if FF_FS_LOCK + clear_share(cfs); #endif -#if FF_FS_REENTRANT /* Discard sync object of the current volume */ - if (!ff_del_syncobj(cfs->sobj)) return FR_INT_ERR; +#if FF_FS_REENTRANT /* Discard mutex of the current volume */ + ff_mutex_delete(vol); #endif - cfs->fs_type = 0; /* Clear old fs object */ + cfs->fs_type = 0; /* Invalidate the filesystem object to be unregistered */ } - if (fs) { - fs->fs_type = 0; /* Clear new fs object */ -#if FF_FS_REENTRANT /* Create sync object for the new volume */ - if (!ff_cre_syncobj((BYTE)vol, &fs->sobj)) return FR_INT_ERR; + if (fs) { /* Register new filesystem object */ + fs->pdrv = LD2PD(vol); /* Volume hosting physical drive */ +#if FF_FS_REENTRANT /* Create a volume mutex */ + fs->ldrv = (BYTE)vol; /* Owner volume ID */ + if (!ff_mutex_create(vol)) return FR_INT_ERR; +#if FF_FS_LOCK + if (SysLock == 0) { /* Create a system mutex if needed */ + if (!ff_mutex_create(FF_VOLUMES)) { + ff_mutex_delete(vol); + return FR_INT_ERR; + } + SysLock = 1; /* System mutex is ready */ + } #endif +#endif + fs->fs_type = 0; /* Invalidate the new filesystem object */ + FatFs[vol] = fs; /* Register new fs object */ } - FatFs[vol] = fs; /* Register new fs object */ - if (opt == 0) return FR_OK; /* Do not mount now, it will be mounted later */ + if (opt == 0) return FR_OK; /* Do not mount now, it will be mounted in subsequent file functions */ res = mount_volume(&path, &fs, 0); /* Force mounted the volume */ LEAVE_FF(fs, res); @@ -3681,9 +3745,9 @@ FRESULT f_open ( if (dj.fn[NSFLAG] & NS_NONAME) { /* Origin directory itself? */ res = FR_INVALID_NAME; } -#if FF_FS_LOCK != 0 +#if FF_FS_LOCK else { - res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0); /* Check if the file can be used */ + res = chk_share(&dj, (mode & ~FA_READ) ? 1 : 0); /* Check if the file can be used */ } #endif } @@ -3691,8 +3755,8 @@ FRESULT f_open ( if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) { if (res != FR_OK) { /* No file, create new */ if (res == FR_NO_FILE) { /* There is no file to open, create a new entry */ -#if FF_FS_LOCK != 0 - res = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES; +#if FF_FS_LOCK + res = enq_share() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES; #else res = dir_register(&dj); #endif @@ -3761,8 +3825,8 @@ FRESULT f_open ( if (mode & FA_CREATE_ALWAYS) mode |= FA_MODIFIED; /* Set file change flag if created or overwritten */ fp->dir_sect = fs->winsect; /* Pointer to the directory entry */ fp->dir_ptr = dj.dir; -#if FF_FS_LOCK != 0 - fp->obj.lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0); /* Lock the file for this session */ +#if FF_FS_LOCK + fp->obj.lockid = inc_share(&dj, (mode & ~FA_READ) ? 1 : 0); /* Lock the file for this session */ if (fp->obj.lockid == 0) res = FR_INT_ERR; #endif } @@ -3825,8 +3889,8 @@ FRESULT f_open ( #endif } } -#if FF_FS_LOCK != 0 - if (res != FR_OK) dec_lock(fp->obj.lockid); /* Decrement file open counter if seek failed */ +#if FF_FS_LOCK + if (res != FR_OK) dec_share(fp->obj.lockid); /* Decrement file open counter if seek failed */ #endif } #endif @@ -3921,7 +3985,7 @@ FRESULT f_read ( fp->flag &= (BYTE)~FA_DIRTY; } #endif - if (disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ + if (disk_read(fs->pdrv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */ } #endif fp->sect = sect; @@ -4163,14 +4227,14 @@ FRESULT f_close ( { res = validate(&fp->obj, &fs); /* Lock volume */ if (res == FR_OK) { -#if FF_FS_LOCK != 0 - res = dec_lock(fp->obj.lockid); /* Decrement file open counter */ +#if FF_FS_LOCK + res = dec_share(fp->obj.lockid); /* Decrement file open counter */ if (res == FR_OK) fp->obj.fs = 0; /* Invalidate file object */ #else fp->obj.fs = 0; /* Invalidate file object */ #endif #if FF_FS_REENTRANT - unlock_fs(fs, FR_OK); /* Unlock volume */ + unlock_volume(fs, FR_OK); /* Unlock volume */ #endif } } @@ -4344,7 +4408,9 @@ FRESULT f_getcwd ( #endif /* Add current directory path */ if (res == FR_OK) { - do *tp++ = buff[i++]; while (i < len); /* Copy stacked path string */ + do { /* Copy stacked path string */ + *tp++ = buff[i++]; + } while (i < len); } } FREE_NAMBUF(); @@ -4551,7 +4617,7 @@ FRESULT f_opendir ( if (dp->obj.attr & AM_DIR) { /* This object is a sub-directory */ #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { - dp->obj.c_scl = dp->obj.sclust; /* Get containing directory inforamation */ + dp->obj.c_scl = dp->obj.sclust; /* Get containing directory inforamation */ dp->obj.c_size = ((DWORD)dp->obj.objsize & 0xFFFFFF00) | dp->obj.stat; dp->obj.c_ofs = dp->blk_ofs; init_alloc_info(fs, &dp->obj); /* Get object allocation info */ @@ -4567,10 +4633,10 @@ FRESULT f_opendir ( if (res == FR_OK) { dp->obj.id = fs->id; res = dir_sdi(dp, 0); /* Rewind directory */ -#if FF_FS_LOCK != 0 +#if FF_FS_LOCK if (res == FR_OK) { if (dp->obj.sclust != 0) { - dp->obj.lockid = inc_lock(dp, 0); /* Lock the sub directory */ + dp->obj.lockid = inc_share(dp, 0); /* Lock the sub directory */ if (!dp->obj.lockid) res = FR_TOO_MANY_OPEN_FILES; } else { dp->obj.lockid = 0; /* Root directory need not to be locked */ @@ -4582,7 +4648,7 @@ FRESULT f_opendir ( FREE_NAMBUF(); if (res == FR_NO_FILE) res = FR_NO_PATH; } - if (res != FR_OK) dp->obj.fs = 0; /* Invalidate the directory object if function faild */ + if (res != FR_OK) dp->obj.fs = 0; /* Invalidate the directory object if function failed */ LEAVE_FF(fs, res); } @@ -4604,14 +4670,14 @@ FRESULT f_closedir ( res = validate(&dp->obj, &fs); /* Check validity of the file object */ if (res == FR_OK) { -#if FF_FS_LOCK != 0 - if (dp->obj.lockid) res = dec_lock(dp->obj.lockid); /* Decrement sub-directory open counter */ +#if FF_FS_LOCK + if (dp->obj.lockid) res = dec_share(dp->obj.lockid); /* Decrement sub-directory open counter */ if (res == FR_OK) dp->obj.fs = 0; /* Invalidate directory object */ #else dp->obj.fs = 0; /* Invalidate directory object */ #endif #if FF_FS_REENTRANT - unlock_fs(fs, FR_OK); /* Unlock volume */ + unlock_volume(fs, FR_OK); /* Unlock volume */ #endif } return res; @@ -4637,7 +4703,7 @@ FRESULT f_readdir ( res = validate(&dp->obj, &fs); /* Check validity of the directory object */ if (res == FR_OK) { if (!fno) { - res = dir_sdi(dp, 0); /* Rewind the directory object */ + res = dir_sdi(dp, 0); /* Rewind the directory object */ } else { INIT_NAMBUF(fs); res = DIR_READ_FILE(dp); /* Read an item */ @@ -4775,8 +4841,12 @@ FRESULT f_getfree ( clst = 2; obj.fs = fs; do { stat = get_fat(&obj, clst); - if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } - if (stat == 1) { res = FR_INT_ERR; break; } + if (stat == 0xFFFFFFFF) { + res = FR_DISK_ERR; break; + } + if (stat == 1) { + res = FR_INT_ERR; break; + } if (stat == 0) nfree++; } while (++clst < fs->n_fatent); } else { @@ -4789,12 +4859,12 @@ FRESULT f_getfree ( sect = fs->bitbase; /* Bitmap sector */ i = 0; /* Offset in the sector */ do { /* Counts numbuer of bits with zero in the bitmap */ - if (i == 0) { + if (i == 0) { /* New sector? */ res = move_window(fs, sect++); if (res != FR_OK) break; } - for (b = 8, bm = fs->win[i]; b && clst; b--, clst--) { - if (!(bm & 1)) nfree++; + for (b = 8, bm = ~fs->win[i]; b && clst; b--, clst--) { + nfree += bm & 1; bm >>= 1; } i = (i + 1) % SS(fs); @@ -4806,7 +4876,7 @@ FRESULT f_getfree ( sect = fs->fatbase; /* Top of the FAT */ i = 0; /* Offset in the sector */ do { /* Counts numbuer of entries with zero in the FAT */ - if (i == 0) { + if (i == 0) { /* New sector? */ res = move_window(fs, sect++); if (res != FR_OK) break; } @@ -4894,9 +4964,9 @@ FRESULT f_unlink ( ) { FRESULT res; + FATFS *fs; DIR dj, sdj; DWORD dclst = 0; - FATFS *fs; #if FF_FS_EXFAT FFOBJID obj; #endif @@ -4912,8 +4982,8 @@ FRESULT f_unlink ( if (FF_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT)) { res = FR_INVALID_NAME; /* Cannot remove dot entry */ } -#if FF_FS_LOCK != 0 - if (res == FR_OK) res = chk_lock(&dj, 2); /* Check if it is an open object */ +#if FF_FS_LOCK + if (res == FR_OK) res = chk_share(&dj, 2); /* Check if it is an open object */ #endif if (res == FR_OK) { /* The object is accessible */ if (dj.fn[NSFLAG] & NS_NONAME) { @@ -4988,9 +5058,9 @@ FRESULT f_mkdir ( ) { FRESULT res; + FATFS *fs; DIR dj; FFOBJID sobj; - FATFS *fs; DWORD dcl, pcl, tm; DEF_NAMBUF @@ -5073,8 +5143,8 @@ FRESULT f_rename ( ) { FRESULT res; - DIR djo, djn; FATFS *fs; + DIR djo, djn; BYTE buf[FF_FS_EXFAT ? SZDIRE * 2 : SZDIRE], *dir; LBA_t sect; DEF_NAMBUF @@ -5087,9 +5157,9 @@ FRESULT f_rename ( INIT_NAMBUF(fs); res = follow_path(&djo, path_old); /* Check old object */ if (res == FR_OK && (djo.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check validity of name */ -#if FF_FS_LOCK != 0 +#if FF_FS_LOCK if (res == FR_OK) { - res = chk_lock(&djo, 2); + res = chk_share(&djo, 2); } #endif if (res == FR_OK) { /* Object to be renamed is found */ @@ -5184,8 +5254,8 @@ FRESULT f_chmod ( ) { FRESULT res; - DIR dj; FATFS *fs; + DIR dj; DEF_NAMBUF @@ -5230,8 +5300,8 @@ FRESULT f_utime ( ) { FRESULT res; - DIR dj; FATFS *fs; + DIR dj; DEF_NAMBUF @@ -5278,8 +5348,8 @@ FRESULT f_getlabel ( ) { FRESULT res; - DIR dj; FATFS *fs; + DIR dj; UINT si, di; WCHAR wc; @@ -5304,7 +5374,9 @@ FRESULT f_getlabel ( hs = wc; continue; } nw = put_utf((DWORD)hs << 16 | wc, &label[di], 4); /* Store it in API encoding */ - if (nw == 0) { di = 0; break; } /* Encode error? */ + if (nw == 0) { /* Encode error? */ + di = 0; break; + } di += nw; hs = 0; } @@ -5319,7 +5391,9 @@ FRESULT f_getlabel ( #if FF_USE_LFN && FF_LFN_UNICODE >= 1 /* Unicode output */ if (dbc_1st((BYTE)wc) && si < 11) wc = wc << 8 | dj.dir[si++]; /* Is it a DBC? */ wc = ff_oem2uni(wc, CODEPAGE); /* Convert it into Unicode */ - if (wc == 0) { di = 0; break; } /* Invalid char in current code page? */ + if (wc == 0) { /* Invalid char in current code page? */ + di = 0; break; + } di += put_utf(wc, &label[di], 4); /* Store it in Unicode */ #else /* ANSI/OEM output */ label[di++] = (TCHAR)wc; @@ -5373,8 +5447,8 @@ FRESULT f_setlabel ( ) { FRESULT res; - DIR dj; FATFS *fs; + DIR dj; BYTE dirvn[22]; UINT di; WCHAR wc; @@ -5530,14 +5604,20 @@ FRESULT f_expand ( for (;;) { /* Find a contiguous cluster block */ n = get_fat(&fp->obj, clst); if (++clst >= fs->n_fatent) clst = 2; - if (n == 1) { res = FR_INT_ERR; break; } - if (n == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } + if (n == 1) { + res = FR_INT_ERR; break; + } + if (n == 0xFFFFFFFF) { + res = FR_DISK_ERR; break; + } if (n == 0) { /* Is it a free cluster? */ if (++ncl == tcl) break; /* Break if a contiguous cluster block is found */ } else { scl = clst; ncl = 0; /* Not a free cluster */ } - if (clst == stcl) { res = FR_DENIED; break; } /* No contiguous cluster? */ + if (clst == stcl) { /* No contiguous cluster? */ + res = FR_DENIED; break; + } } if (res == FR_OK) { /* A contiguous free area is found */ if (opt) { /* Allocate it now */ @@ -5659,8 +5739,8 @@ FRESULT f_forward ( static FRESULT create_partition ( BYTE drv, /* Physical drive number */ const LBA_t plst[], /* Partition list */ - BYTE sys, /* System ID (for only MBR, temp setting) */ - BYTE* buf /* Working buffer for a sector */ + BYTE sys, /* System ID for each partition (for only MBR) */ + BYTE *buf /* Working buffer for a sector */ ) { UINT i, cy; @@ -5689,7 +5769,7 @@ static FRESULT create_partition ( rnd = (DWORD)sz_drv + GET_FATTIME(); /* Random seed */ align = GPT_ALIGN / ss; /* Partition alignment for GPT [sector] */ sz_ptbl = GPT_ITEMS * SZ_GPTE / ss; /* Size of partition table [sector] */ - top_bpt = sz_drv - sz_ptbl - 1; /* Backup partiiton table start sector */ + top_bpt = sz_drv - sz_ptbl - 1; /* Backup partition table start sector */ nxt_alloc = 2 + sz_ptbl; /* First allocatable sector */ sz_pool = top_bpt - nxt_alloc; /* Size of allocatable area */ bcc = 0xFFFFFFFF; sz_part = 1; @@ -5802,14 +5882,16 @@ static FRESULT create_partition ( FRESULT f_mkfs ( const TCHAR* path, /* Logical drive number */ const MKFS_PARM* opt, /* Format options */ - void* work, /* Pointer to working buffer (null: use heap memory) */ + void* work, /* Pointer to working buffer (null: use len bytes of heap memory) */ UINT len /* Size of working buffer [byte] */ ) { static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT volume (4Ks unit) */ static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128Ks unit) */ static const MKFS_PARM defopt = {FM_ANY, 0, 0, 0, 0}; /* Default parameter */ - BYTE fsopt, fsty, sys, *buf, *pte, pdrv, ipart; + BYTE fsopt, fsty, sys, pdrv, ipart; + BYTE *buf; + BYTE *pte; WORD ss; /* Sector size */ DWORD sz_buf, sz_blk, n_clst, pau, nsect, n, vsn; LBA_t sz_vol, b_vol, b_fat, b_data; /* Size of volume, Base LBA of volume, fat, data */ @@ -5818,30 +5900,33 @@ FRESULT f_mkfs ( UINT n_fat, n_root, i; /* Index, Number of FATs and Number of roor dir entries */ int vol; DSTATUS ds; - FRESULT fr; + FRESULT res; /* Check mounted drive and clear work area */ vol = get_ldnumber(&path); /* Get target logical drive */ if (vol < 0) return FR_INVALID_DRIVE; if (FatFs[vol]) FatFs[vol]->fs_type = 0; /* Clear the fs object if mounted */ - pdrv = LD2PD(vol); /* Physical drive */ - ipart = LD2PT(vol); /* Partition (0:create as new, 1..:get from partition table) */ - if (!opt) opt = &defopt; /* Use default parameter if it is not given */ + pdrv = LD2PD(vol); /* Hosting physical drive */ + ipart = LD2PT(vol); /* Hosting partition (0:create as new, 1..:existing partition) */ - /* Get physical drive status (sz_drv, sz_blk, ss) */ + /* Initialize the hosting physical drive */ ds = disk_initialize(pdrv); if (ds & STA_NOINIT) return FR_NOT_READY; if (ds & STA_PROTECT) return FR_WRITE_PROTECTED; + + /* Get physical drive parameters (sz_drv, sz_blk and ss) */ + if (!opt) opt = &defopt; /* Use default parameter if it is not given */ sz_blk = opt->align; - if (sz_blk == 0 && disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk) != RES_OK) sz_blk = 1; - if (sz_blk == 0 || sz_blk > 0x8000 || (sz_blk & (sz_blk - 1))) sz_blk = 1; + if (sz_blk == 0) disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk); /* Block size from the paramter or lower layer */ + if (sz_blk == 0 || sz_blk > 0x8000 || (sz_blk & (sz_blk - 1))) sz_blk = 1; /* Use default if the block size is invalid */ #if FF_MAX_SS != FF_MIN_SS if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &ss) != RES_OK) return FR_DISK_ERR; if (ss > FF_MAX_SS || ss < FF_MIN_SS || (ss & (ss - 1))) return FR_DISK_ERR; #else ss = FF_MAX_SS; #endif + /* Options for FAT sub-type and FAT parameters */ fsopt = opt->fmt & (FM_ANY | FM_SFD); n_fat = (opt->n_fat >= 1 && opt->n_fat <= 2) ? opt->n_fat : 1; @@ -5957,7 +6042,7 @@ FRESULT f_mkfs ( sz_fat = (DWORD)((sz_vol / sz_au + 2) * 4 + ss - 1) / ss; /* Number of FAT sectors */ b_data = (b_fat + sz_fat + sz_blk - 1) & ~((LBA_t)sz_blk - 1); /* Align data area to the erase block boundary */ if (b_data - b_vol >= sz_vol / 2) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too small volume? */ - n_clst = (DWORD)(sz_vol - (b_data - b_vol)) / sz_au; /* Number of clusters */ + n_clst = (DWORD)((sz_vol - (b_data - b_vol)) / sz_au); /* Number of clusters */ if (n_clst <16) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too few clusters? */ if (n_clst > MAX_EXFAT) LEAVE_MKFS(FR_MKFS_ABORTED); /* Too many clusters? */ @@ -6258,32 +6343,30 @@ FRESULT f_mkfs ( /* Determine system ID in the MBR partition table */ if (FF_FS_EXFAT && fsty == FS_EXFAT) { - sys = 0x07; /* exFAT */ + sys = 0x07; /* exFAT */ + } else if (fsty == FS_FAT32) { + sys = 0x0C; /* FAT32X */ + } else if (sz_vol >= 0x10000) { + sys = 0x06; /* FAT12/16 (large) */ + } else if (fsty == FS_FAT16) { + sys = 0x04; /* FAT16 */ } else { - if (fsty == FS_FAT32) { - sys = 0x0C; /* FAT32X */ - } else { - if (sz_vol >= 0x10000) { - sys = 0x06; /* FAT12/16 (large) */ - } else { - sys = (fsty == FS_FAT16) ? 0x04 : 0x01; /* FAT16 : FAT12 */ - } - } + sys = 0x01; /* FAT12 */ } /* Update partition information */ if (FF_MULTI_PARTITION && ipart != 0) { /* Volume is in the existing partition */ - if (!FF_LBA64 || !(fsopt & 0x80)) { + if (!FF_LBA64 || !(fsopt & 0x80)) { /* Is the partition in MBR? */ /* Update system ID in the partition table */ if (disk_read(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Read the MBR */ buf[MBR_Table + (ipart - 1) * SZ_PTE + PTE_System] = sys; /* Set system ID */ if (disk_write(pdrv, buf, 0, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it back to the MBR */ } } else { /* Volume as a new single partition */ - if (!(fsopt & FM_SFD)) { /* Create partition table if not in SFD */ + if (!(fsopt & FM_SFD)) { /* Create partition table if not in SFD format */ lba[0] = sz_vol; lba[1] = 0; - fr = create_partition(pdrv, lba, sys, buf); - if (fr != FR_OK) LEAVE_MKFS(fr); + res = create_partition(pdrv, lba, sys, buf); + if (res != FR_OK) LEAVE_MKFS(res); } } @@ -6308,17 +6391,22 @@ FRESULT f_fdisk ( { BYTE *buf = (BYTE*)work; DSTATUS stat; + FRESULT res; + /* Initialize the physical drive */ stat = disk_initialize(pdrv); if (stat & STA_NOINIT) return FR_NOT_READY; if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; + #if FF_USE_LFN == 3 if (!buf) buf = ff_memalloc(FF_MAX_SS); /* Use heap memory for working buffer */ #endif if (!buf) return FR_NOT_ENOUGH_CORE; - LEAVE_MKFS(create_partition(pdrv, ptbl, 0x07, buf)); + res = create_partition(pdrv, ptbl, 0x07, buf); /* Create partitions (system ID is temporary setting and determined by f_mkfs) */ + + LEAVE_MKFS(res); } #endif /* FF_MULTI_PARTITION */ @@ -6388,9 +6476,15 @@ TCHAR* f_gets ( dc = s[0]; if (dc >= 0x80) { /* Multi-byte sequence? */ ct = 0; - if ((dc & 0xE0) == 0xC0) { dc &= 0x1F; ct = 1; } /* 2-byte sequence? */ - if ((dc & 0xF0) == 0xE0) { dc &= 0x0F; ct = 2; } /* 3-byte sequence? */ - if ((dc & 0xF8) == 0xF0) { dc &= 0x07; ct = 3; } /* 4-byte sequence? */ + if ((dc & 0xE0) == 0xC0) { /* 2-byte sequence? */ + dc &= 0x1F; ct = 1; + } + if ((dc & 0xF0) == 0xE0) { /* 3-byte sequence? */ + dc &= 0x0F; ct = 2; + } + if ((dc & 0xF8) == 0xF0) { /* 4-byte sequence? */ + dc &= 0x07; ct = 3; + } if (ct == 0) continue; f_read(fp, s, ct, &rc); /* Get trailing bytes */ if (rc != ct) break; @@ -6417,25 +6511,21 @@ TCHAR* f_gets ( *p++ = (TCHAR)dc; nc++; if (dc == '\n') break; /* End of line? */ - } else { - if (dc < 0x800) { /* 2-byte sequence? */ - *p++ = (TCHAR)(0xC0 | (dc >> 6 & 0x1F)); - *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); - nc += 2; - } else { - if (dc < 0x10000) { /* 3-byte sequence? */ - *p++ = (TCHAR)(0xE0 | (dc >> 12 & 0x0F)); - *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); - *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); - nc += 3; - } else { /* 4-byte sequence? */ - *p++ = (TCHAR)(0xF0 | (dc >> 18 & 0x07)); - *p++ = (TCHAR)(0x80 | (dc >> 12 & 0x3F)); - *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); - *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); - nc += 4; - } - } + } else if (dc < 0x800) { /* 2-byte sequence? */ + *p++ = (TCHAR)(0xC0 | (dc >> 6 & 0x1F)); + *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); + nc += 2; + } else if (dc < 0x10000) { /* 3-byte sequence? */ + *p++ = (TCHAR)(0xE0 | (dc >> 12 & 0x0F)); + *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); + *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); + nc += 3; + } else { /* 4-byte sequence */ + *p++ = (TCHAR)(0xF0 | (dc >> 18 & 0x07)); + *p++ = (TCHAR)(0x80 | (dc >> 12 & 0x3F)); + *p++ = (TCHAR)(0x80 | (dc >> 6 & 0x3F)); + *p++ = (TCHAR)(0x80 | (dc >> 0 & 0x3F)); + nc += 4; } #endif } @@ -6493,7 +6583,7 @@ static void putc_bfd (putbuff* pb, TCHAR c) WCHAR hs, wc; #if FF_LFN_UNICODE == 2 DWORD dc; - const TCHAR *tp; + const TCHAR* tp; #endif #endif @@ -6507,39 +6597,39 @@ static void putc_bfd (putbuff* pb, TCHAR c) #if FF_USE_LFN && FF_LFN_UNICODE #if FF_LFN_UNICODE == 1 /* UTF-16 input */ - if (IsSurrogateH(c)) { /* High surrogate? */ + if (IsSurrogateH(c)) { /* Is this a high-surrogate? */ pb->hs = c; return; /* Save it for next */ } hs = pb->hs; pb->hs = 0; - if (hs != 0) { /* There is a leading high surrogate */ - if (!IsSurrogateL(c)) hs = 0; /* Discard high surrogate if not a surrogate pair */ + if (hs != 0) { /* Is there a leading high-surrogate? */ + if (!IsSurrogateL(c)) hs = 0; /* Discard high-surrogate if not a surrogate pair */ } else { - if (IsSurrogateL(c)) return; /* Discard stray low surrogate */ + if (IsSurrogateL(c)) return; /* Discard stray low-surrogate */ } wc = c; #elif FF_LFN_UNICODE == 2 /* UTF-8 input */ for (;;) { if (pb->ct == 0) { /* Out of multi-byte sequence? */ pb->bs[pb->wi = 0] = (BYTE)c; /* Save 1st byte */ - if ((BYTE)c < 0x80) break; /* Single byte? */ + if ((BYTE)c < 0x80) break; /* Single byte code? */ if (((BYTE)c & 0xE0) == 0xC0) pb->ct = 1; /* 2-byte sequence? */ if (((BYTE)c & 0xF0) == 0xE0) pb->ct = 2; /* 3-byte sequence? */ - if (((BYTE)c & 0xF1) == 0xF0) pb->ct = 3; /* 4-byte sequence? */ - return; + if (((BYTE)c & 0xF8) == 0xF0) pb->ct = 3; /* 4-byte sequence? */ + return; /* Wrong leading byte (discard it) */ } else { /* In the multi-byte sequence */ if (((BYTE)c & 0xC0) != 0x80) { /* Broken sequence? */ - pb->ct = 0; continue; + pb->ct = 0; continue; /* Discard the sequense */ } pb->bs[++pb->wi] = (BYTE)c; /* Save the trailing byte */ - if (--pb->ct == 0) break; /* End of multi-byte sequence? */ + if (--pb->ct == 0) break; /* End of the sequence? */ return; } } tp = (const TCHAR*)pb->bs; - dc = tchar2uni(&tp); /* UTF-8 ==> UTF-16 */ + dc = tchar2uni(&tp); /* UTF-8 ==> UTF-16 */ if (dc == 0xFFFFFFFF) return; /* Wrong code? */ - wc = (WCHAR)dc; hs = (WCHAR)(dc >> 16); + wc = (WCHAR)dc; #elif FF_LFN_UNICODE == 3 /* UTF-32 input */ if (IsSurrogate(c) || c >= 0x110000) return; /* Discard invalid code */ if (c >= 0x10000) { /* Out of BMP? */ @@ -6742,7 +6832,7 @@ static void ftoa ( er = "NaN"; } else { if (prec < 0) prec = 6; /* Default precision? (6 fractional digits) */ - if (val < 0) { /* Nagative? */ + if (val < 0) { /* Negative? */ val = 0 - val; sign = '-'; } else { sign = '+'; @@ -6790,7 +6880,9 @@ static void ftoa ( } if (er) { /* Error condition */ if (sign) *buf++ = sign; /* Add sign if needed */ - do *buf++ = *er++; while (*er); /* Put error symbol */ + do { /* Put error symbol */ + *buf++ = *er++; + } while (*er); } *buf = 0; /* Term */ } @@ -6813,7 +6905,8 @@ int f_printf ( #else DWORD v; #endif - TCHAR tc, pad, *tp; + TCHAR *tp; + TCHAR tc, pad; TCHAR nul = 0; char d, str[SZ_NUM_BUF]; @@ -6870,17 +6963,22 @@ int f_printf ( switch (tc) { /* Atgument type is... */ case 'b': /* Unsigned binary */ r = 2; break; + case 'o': /* Unsigned octal */ r = 8; break; + case 'd': /* Signed decimal */ - case 'u': /* Unsigned decimal */ + case 'u': /* Unsigned decimal */ r = 10; break; - case 'x': /* Unsigned hexdecimal (lower case) */ - case 'X': /* Unsigned hexdecimal (upper case) */ + + case 'x': /* Unsigned hexadecimal (lower case) */ + case 'X': /* Unsigned hexadecimal (upper case) */ r = 16; break; + case 'c': /* Character */ putc_bfd(&pb, (TCHAR)va_arg(arp, int)); continue; + case 's': /* String */ tp = va_arg(arp, TCHAR*); /* Get a pointer argument */ if (!tp) tp = &nul; /* Null ptr generates a null string */ @@ -6894,7 +6992,7 @@ int f_printf ( case 'f': /* Floating point (decimal) */ case 'e': /* Floating point (e) */ case 'E': /* Floating point (E) */ - ftoa(str, va_arg(arp, double), prec, tc); /* Make a flaoting point string */ + ftoa(str, va_arg(arp, double), prec, tc); /* Make a floating point string */ for (j = strlen(str); !(f & 2) && j < w; j++) putc_bfd(&pb, pad); /* Left pads */ for (i = 0; str[i]; putc_bfd(&pb, str[i++])) ; /* Body */ while (j++ < w) putc_bfd(&pb, ' '); /* Right pads */ @@ -6906,14 +7004,12 @@ int f_printf ( /* Get an integer argument and put it in numeral */ #if FF_PRINT_LLI && FF_INTDEF == 2 - if (f & 8) { /* long long argument? */ - v = (QWORD)va_arg(arp, LONGLONG); - } else { - if (f & 4) { /* long argument? */ - v = (tc == 'd') ? (QWORD)(LONGLONG)va_arg(arp, long) : (QWORD)va_arg(arp, unsigned long); - } else { /* int/short/char argument */ - v = (tc == 'd') ? (QWORD)(LONGLONG)va_arg(arp, int) : (QWORD)va_arg(arp, unsigned int); - } + if (f & 8) { /* long long argument? */ + v = (QWORD)va_arg(arp, long long); + } else if (f & 4) { /* long argument? */ + v = (tc == 'd') ? (QWORD)(long long)va_arg(arp, long) : (QWORD)va_arg(arp, unsigned long); + } else { /* int/short/char argument */ + v = (tc == 'd') ? (QWORD)(long long)va_arg(arp, int) : (QWORD)va_arg(arp, unsigned int); } if (tc == 'd' && (v & 0x8000000000000000)) { /* Negative value? */ v = 0 - v; f |= 1; @@ -6936,9 +7032,15 @@ int f_printf ( } while (v && i < SZ_NUM_BUF); if (f & 1) str[i++] = '-'; /* Sign */ /* Write it */ - for (j = i; !(f & 2) && j < w; j++) putc_bfd(&pb, pad); /* Left pads */ - do putc_bfd(&pb, (TCHAR)str[--i]); while (i); /* Body */ - while (j++ < w) putc_bfd(&pb, ' '); /* Right pads */ + for (j = i; !(f & 2) && j < w; j++) { /* Left pads */ + putc_bfd(&pb, pad); + } + do { /* Body */ + putc_bfd(&pb, (TCHAR)str[--i]); + } while (i); + while (j++ < w) { /* Right pads */ + putc_bfd(&pb, ' '); + } } va_end(arp); @@ -6961,12 +7063,12 @@ FRESULT f_setcp ( ) { static const WORD validcp[22] = { 437, 720, 737, 771, 775, 850, 852, 855, 857, 860, 861, 862, 863, 864, 865, 866, 869, 932, 936, 949, 950, 0}; - static const BYTE* const tables[22] = {Ct437, Ct720, Ct737, Ct771, Ct775, Ct850, Ct852, Ct855, Ct857, Ct860, Ct861, Ct862, Ct863, Ct864, Ct865, Ct866, Ct869, Dc932, Dc936, Dc949, Dc950, 0}; + static const BYTE *const tables[22] = {Ct437, Ct720, Ct737, Ct771, Ct775, Ct850, Ct852, Ct855, Ct857, Ct860, Ct861, Ct862, Ct863, Ct864, Ct865, Ct866, Ct869, Dc932, Dc936, Dc949, Dc950, 0}; UINT i; for (i = 0; validcp[i] != 0 && validcp[i] != cp; i++) ; /* Find the code page */ - if (validcp[i] != cp) return FR_INVALID_PARAMETER; /* Not found? */ + if (validcp[i] != cp) return FR_INVALID_PARAMETER; /* Not found? */ CodePage = cp; if (cp >= 900) { /* DBCS */ diff --git a/src/fatfs/ff.h b/src/fatfs/ff.h index 4866576..e0a7712 100644 --- a/src/fatfs/ff.h +++ b/src/fatfs/ff.h @@ -1,8 +1,8 @@ /*----------------------------------------------------------------------------/ -/ FatFs - Generic FAT Filesystem module R0.14b / +/ FatFs - Generic FAT Filesystem module R0.15 / /-----------------------------------------------------------------------------/ / -/ Copyright (C) 2021, ChaN, all right reserved. +/ Copyright (C) 2022, ChaN, all right reserved. / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided @@ -20,7 +20,7 @@ #ifndef FF_DEFINED -#define FF_DEFINED 86631 /* Revision ID */ +#define FF_DEFINED 80286 /* Revision ID */ #ifdef __cplusplus extern "C" { @@ -131,10 +131,11 @@ extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */ typedef struct { BYTE fs_type; /* Filesystem type (0:not mounted) */ - BYTE pdrv; /* Associated physical drive */ + BYTE pdrv; /* Volume hosting physical drive */ + BYTE ldrv; /* Logical drive number (used only when FF_FS_REENTRANT) */ BYTE n_fats; /* Number of FATs (1 or 2) */ - BYTE wflag; /* win[] flag (b0:dirty) */ - BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ + BYTE wflag; /* win[] status (b0:dirty) */ + BYTE fsi_flag; /* FSINFO status (b7:disabled, b0:dirty) */ WORD id; /* Volume mount ID */ WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ WORD csize; /* Cluster size [sectors] */ @@ -147,9 +148,6 @@ typedef struct { #if FF_FS_EXFAT BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */ #endif -#if FF_FS_REENTRANT - FF_SYNC_t sobj; /* Identifier of sync object */ -#endif #if !FF_FS_READONLY DWORD last_clst; /* Last allocated cluster */ DWORD free_clst; /* Number of free clusters */ @@ -163,10 +161,10 @@ typedef struct { #endif #endif DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */ - DWORD fsize; /* Size of an FAT [sectors] */ + DWORD fsize; /* Number of sectors per FAT */ LBA_t volbase; /* Volume base sector */ LBA_t fatbase; /* FAT base sector */ - LBA_t dirbase; /* Root directory base sector/cluster */ + LBA_t dirbase; /* Root directory base sector (FAT12/16) or cluster (FAT32/exFAT) */ LBA_t database; /* Data base sector */ #if FF_FS_EXFAT LBA_t bitbase; /* Allocation bitmap base sector */ @@ -181,7 +179,7 @@ typedef struct { typedef struct { FATFS* fs; /* Pointer to the hosting volume of this object */ - WORD id; /* Hosting volume mount ID */ + WORD id; /* Hosting volume's mount ID */ BYTE attr; /* Object attribute */ BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */ DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */ @@ -250,7 +248,7 @@ typedef struct { WORD ftime; /* Modified time */ BYTE fattrib; /* File attribute */ #if FF_USE_LFN - TCHAR altname[FF_SFN_BUF + 1];/* Altenative file name */ + TCHAR altname[FF_SFN_BUF + 1];/* Alternative file name */ TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */ #else TCHAR fname[12 + 1]; /* File name */ @@ -298,8 +296,10 @@ typedef enum { + +/*--------------------------------------------------------------*/ +/* FatFs Module Application Interface */ /*--------------------------------------------------------------*/ -/* FatFs module application interface */ FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */ FRESULT f_close (FIL* fp); /* Close an open file object */ @@ -336,6 +336,8 @@ int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */ int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */ +/* Some API fucntions are implemented as macro */ + #define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize)) #define f_error(fp) ((fp)->err) #define f_tell(fp) ((fp)->fptr) @@ -349,38 +351,43 @@ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the fil /*--------------------------------------------------------------*/ -/* Additional user defined functions */ +/* Additional Functions */ +/*--------------------------------------------------------------*/ -/* RTC function */ +/* RTC function (provided by user) */ #if !FF_FS_READONLY && !FF_FS_NORTC -DWORD get_fattime (void); +DWORD get_fattime (void); /* Get current time */ #endif -/* LFN support functions */ -#if FF_USE_LFN >= 1 /* Code conversion (defined in unicode.c) */ + +/* LFN support functions (defined in ffunicode.c) */ + +#if FF_USE_LFN >= 1 WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */ WCHAR ff_uni2oem (DWORD uni, WORD cp); /* Unicode to OEM code conversion */ DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */ #endif -#if FF_USE_LFN == 3 /* Dynamic memory allocation */ -void* ff_memalloc (UINT msize); /* Allocate memory block */ -void ff_memfree (void* mblock); /* Free memory block */ -#endif -/* Sync functions */ -#if FF_FS_REENTRANT -int ff_cre_syncobj (BYTE vol, FF_SYNC_t* sobj); /* Create a sync object */ -int ff_req_grant (FF_SYNC_t sobj); /* Lock sync object */ -void ff_rel_grant (FF_SYNC_t sobj); /* Unlock sync object */ -int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */ + +/* O/S dependent functions (samples available in ffsystem.c) */ + +#if FF_USE_LFN == 3 /* Dynamic memory allocation */ +void* ff_memalloc (UINT msize); /* Allocate memory block */ +void ff_memfree (void* mblock); /* Free memory block */ +#endif +#if FF_FS_REENTRANT /* Sync functions */ +int ff_mutex_create (int vol); /* Create a sync object */ +void ff_mutex_delete (int vol); /* Delete a sync object */ +int ff_mutex_take (int vol); /* Lock sync object */ +void ff_mutex_give (int vol); /* Unlock sync object */ #endif /*--------------------------------------------------------------*/ -/* Flags and offset address */ - +/* Flags and Offset Address */ +/*--------------------------------------------------------------*/ /* File access mode and open method flags (3rd argument of f_open) */ #define FA_READ 0x01 diff --git a/src/fatfs/ffconf.h b/src/fatfs/ffconf.h index 8f4999c..2db0ba5 100644 --- a/src/fatfs/ffconf.h +++ b/src/fatfs/ffconf.h @@ -1,8 +1,8 @@ /*---------------------------------------------------------------------------/ -/ FatFs Functional Configurations +/ Configurations of FatFs Module /---------------------------------------------------------------------------*/ -#define FFCONF_DEF 86631 /* Revision ID */ +#define FFCONF_DEF 80286 /* Revision ID */ /*---------------------------------------------------------------------------/ / Function Configurations @@ -25,7 +25,7 @@ / 3: f_lseek() function is removed in addition to 2. */ -#define FF_USE_FIND 2 +#define FF_USE_FIND 1 /* This option switches filtered directory read functions, f_findfirst() and / f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ @@ -57,9 +57,9 @@ #define FF_USE_STRFUNC 1 -#define FF_PRINT_LLI 0 -#define FF_PRINT_FLOAT 0 -#define FF_STRF_ENCODE 0 +#define FF_PRINT_LLI 1 +#define FF_PRINT_FLOAT 1 +#define FF_STRF_ENCODE 3 /* FF_USE_STRFUNC switches string functions, f_gets(), f_putc(), f_puts() and / f_printf(). / @@ -68,7 +68,7 @@ / 2: Enable with LF-CRLF conversion. / / FF_PRINT_LLI = 1 makes f_printf() support long long argument and FF_PRINT_FLOAT = 1/2 - makes f_printf() support floating point argument. These features want C99 or later. +/ makes f_printf() support floating point argument. These features want C99 or later. / When FF_LFN_UNICODE >= 1 with LFN enabled, string functions convert the character / encoding in it. FF_STRF_ENCODE selects assumption of character encoding ON THE FILE / to be read/written via those functions. @@ -113,8 +113,8 @@ */ -#define FF_USE_LFN 1 -#define FF_MAX_LFN 255 +#define FF_USE_LFN 0 +#define FF_MAX_LFN 127 /* The FF_USE_LFN switches the support for LFN (long file name). / / 0: Disable LFN. FF_MAX_LFN has no effect. @@ -170,26 +170,27 @@ /* Number of volumes (logical drives) to be used. (1-10) */ -#define FF_STR_VOLUME_ID 2 -// #define FF_VOLUME_STRS "S,F,H" +#define FF_STR_VOLUME_ID 1 +// #define FF_VOLUME_STRS "SD","SD2" /* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings. / When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive / number in the path name. FF_VOLUME_STRS defines the volume ID strings for each / logical drives. Number of items must not be less than FF_VOLUMES. Valid / characters for the volume ID strings are A-Z, a-z and 0-9, however, they are / compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is -/ not defined, a user defined volume string table needs to be defined as: +/ not defined, a user defined volume string table is needed as: / / const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",... */ + #define FF_MULTI_PARTITION 0 /* This option switches support for multiple volumes on the physical drive. / By default (0), each logical drive number is bound to the same physical drive / number and only an FAT volume found on the physical drive will be mounted. / When this function is enabled (1), each logical drive number can be bound to / arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() -/ funciton will be available. */ +/ function will be available. */ #define FF_MIN_SS 512 @@ -237,12 +238,12 @@ #define FF_FS_NORTC 1 -#define FF_NORTC_MON 1 +#define FF_NORTC_MON 2 #define FF_NORTC_MDAY 1 -#define FF_NORTC_YEAR 2020 -/* The option FF_FS_NORTC switches timestamp functiton. If the system does not have -/ any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable -/ the timestamp function. Every object modified by FatFs will have a fixed timestamp +#define FF_NORTC_YEAR 2024 +/* The option FF_FS_NORTC switches timestamp feature. If the system does not have +/ an RTC or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable the +/ timestamp feature. Every object modified by FatFs will have a fixed timestamp / defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time. / To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be / added to the project to read current time form real-time clock. FF_NORTC_MON, @@ -252,7 +253,7 @@ #define FF_FS_NOFSINFO 0 /* If you need to know correct free space on the FAT32 volume, set bit 0 of this -/ option, and f_getfree() function at first time after volume mount will force +/ option, and f_getfree() function at the first time after volume mount will force / a full FAT scan. Bit 1 controls the use of last allocated cluster number. / / bit0=0: Use free cluster count in the FSINFO if available. @@ -274,26 +275,21 @@ / lock control is independent of re-entrancy. */ -/* #include // O/S definitions */ #define FF_FS_REENTRANT 0 #define FF_FS_TIMEOUT 1000 -#define FF_SYNC_t HANDLE /* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs / module itself. Note that regardless of this option, file access to different / volume is always re-entrant and volume control functions, f_mount(), f_mkfs() / and f_fdisk() function, are always not re-entrant. Only file/directory access -/ to the same volume is under control of this function. +/ to the same volume is under control of this featuer. / -/ 0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect. +/ 0: Disable re-entrancy. FF_FS_TIMEOUT have no effect. / 1: Enable re-entrancy. Also user provided synchronization handlers, -/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() -/ function, must be added to the project. Samples are available in -/ option/syscall.c. +/ ff_mutex_create(), ff_mutex_delete(), ff_mutex_take() and ff_mutex_give() +/ function, must be added to the project. Samples are available in ffsystem.c. / -/ The FF_FS_TIMEOUT defines timeout period in unit of time tick. -/ The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, -/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be -/ included somewhere in the scope of ff.h. */ +/ The FF_FS_TIMEOUT defines timeout period in unit of O/S time tick. +*/ diff --git a/src/fatfs/ffconf_new.h b/src/fatfs/ffconf_new.h new file mode 100644 index 0000000..697d5ad --- /dev/null +++ b/src/fatfs/ffconf_new.h @@ -0,0 +1,275 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * FatFs - FAT file system module configuration file R0.11 (C)ChaN, 2015 + ****************************************************************************** + * @attention + * + *

© Copyright (c) 2020 STMicroelectronics. + * All rights reserved.

+ * + * This software component is licensed by ST under Ultimate Liberty license + * SLA0044, the "License"; You may not use this file except in compliance with + * the License. You may obtain a copy of the License at: + * www.st.com/SLA0044 + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +#ifndef _FFCONF +#define _FFCONF 32020 /* Revision ID */ + +/*-----------------------------------------------------------------------------/ +/ Additional user header to be used +/-----------------------------------------------------------------------------*/ +#include "main.h" +#include "stm32f3xx_hal.h" + +/*-----------------------------------------------------------------------------/ +/ Functions and Buffer Configurations +/-----------------------------------------------------------------------------*/ + +#define _FS_TINY 0 /* 0:Normal or 1:Tiny */ +/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny) +/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS +/ bytes. Instead of private sector buffer eliminated from the file object, +/ common sector buffer in the file system object (FATFS) is used for the file +/ data transfer. */ + +#define _FS_READONLY 0 /* 0:Read/Write or 1:Read only */ +/* This option switches read-only configuration. (0:Read/Write or 1:Read-only) +/ Read-only configuration removes writing API functions, f_write(), f_sync(), +/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree() +/ and optional writing functions as well. */ + +#define _FS_MINIMIZE 0 /* 0 to 3 */ +/* This option defines minimization level to remove some basic API functions. +/ +/ 0: All basic functions are enabled. +/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_chmod(), f_utime(), +/ f_truncate() and f_rename() function are removed. +/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1. +/ 3: f_lseek() function is removed in addition to 2. */ + +#define _USE_STRFUNC 2 /* 0:Disable or 1-2:Enable */ +/* This option switches string functions, f_gets(), f_putc(), f_puts() and +/ f_printf(). +/ +/ 0: Disable string functions. +/ 1: Enable without LF-CRLF conversion. +/ 2: Enable with LF-CRLF conversion. */ + +#define _USE_FIND 0 +/* This option switches filtered directory read feature and related functions, +/ f_findfirst() and f_findnext(). (0:Disable or 1:Enable) */ + +#define _USE_MKFS 1 +/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ + +#define _USE_FASTSEEK 1 +/* This option switches fast seek feature. (0:Disable or 1:Enable) */ + +#define _USE_LABEL 0 +/* This option switches volume label functions, f_getlabel() and f_setlabel(). +/ (0:Disable or 1:Enable) */ + +#define _USE_FORWARD 0 +/* This option switches f_forward() function. (0:Disable or 1:Enable) +/ To enable it, also _FS_TINY need to be set to 1. */ + +/*-----------------------------------------------------------------------------/ +/ Locale and Namespace Configurations +/-----------------------------------------------------------------------------*/ + +#define _CODE_PAGE 850 +/* This option specifies the OEM code page to be used on the target system. +/ Incorrect setting of the code page can cause a file open failure. +/ +/ 932 - Japanese Shift_JIS (DBCS, OEM, Windows) +/ 936 - Simplified Chinese GBK (DBCS, OEM, Windows) +/ 949 - Korean (DBCS, OEM, Windows) +/ 950 - Traditional Chinese Big5 (DBCS, OEM, Windows) +/ 1250 - Central Europe (Windows) +/ 1251 - Cyrillic (Windows) +/ 1252 - Latin 1 (Windows) +/ 1253 - Greek (Windows) +/ 1254 - Turkish (Windows) +/ 1255 - Hebrew (Windows) +/ 1256 - Arabic (Windows) +/ 1257 - Baltic (Windows) +/ 1258 - Vietnam (OEM, Windows) +/ 437 - U.S. (OEM) +/ 720 - Arabic (OEM) +/ 737 - Greek (OEM) +/ 775 - Baltic (OEM) +/ 850 - Multilingual Latin 1 (OEM) +/ 858 - Multilingual Latin 1 + Euro (OEM) +/ 852 - Latin 2 (OEM) +/ 855 - Cyrillic (OEM) +/ 866 - Russian (OEM) +/ 857 - Turkish (OEM) +/ 862 - Hebrew (OEM) +/ 874 - Thai (OEM, Windows) +/ 1 - ASCII (No extended character. Valid for only non-LFN configuration.) */ + +#define _USE_LFN 0 /* 0 to 3 */ +#define _MAX_LFN 255 /* Maximum LFN length to handle (12 to 255) */ +/* The _USE_LFN option switches the LFN feature. +/ +/ 0: Disable LFN feature. _MAX_LFN has no effect. +/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe. +/ 2: Enable LFN with dynamic working buffer on the STACK. +/ 3: Enable LFN with dynamic working buffer on the HEAP. +/ +/ When enable the LFN feature, Unicode handling functions (option/unicode.c) must +/ be added to the project. The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes. +/ When use stack for the working buffer, take care on stack overflow. When use heap +/ memory for the working buffer, memory management functions, ff_memalloc() and +/ ff_memfree(), must be added to the project. */ + +#define _LFN_UNICODE 0 /* 0:ANSI/OEM or 1:Unicode */ +/* This option switches character encoding on the API. (0:ANSI/OEM or 1:Unicode) +/ To use Unicode string for the path name, enable LFN feature and set _LFN_UNICODE +/ to 1. This option also affects behavior of string I/O functions. */ + +#define _STRF_ENCODE 3 +/* When _LFN_UNICODE is 1, this option selects the character encoding on the file to +/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf(). +/ +/ 0: ANSI/OEM +/ 1: UTF-16LE +/ 2: UTF-16BE +/ 3: UTF-8 +/ +/ When _LFN_UNICODE is 0, this option has no effect. */ + +#define _FS_RPATH 0 /* 0 to 2 */ +/* This option configures relative path feature. +/ +/ 0: Disable relative path feature and remove related functions. +/ 1: Enable relative path feature. f_chdir() and f_chdrive() are available. +/ 2: f_getcwd() function is available in addition to 1. +/ +/ Note that directory items read via f_readdir() are affected by this option. */ + +/*---------------------------------------------------------------------------/ +/ Drive/Volume Configurations +/----------------------------------------------------------------------------*/ + +#define _VOLUMES 1 +/* Number of volumes (logical drives) to be used. */ + +/* USER CODE BEGIN Volumes */ +#define _STR_VOLUME_ID 0 /* 0:Use only 0-9 for drive ID, 1:Use strings for drive ID */ +#define _VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3" +/* _STR_VOLUME_ID option switches string volume ID feature. +/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive +/ number in the path name. _VOLUME_STRS defines the drive ID strings for each +/ logical drives. Number of items must be equal to _VOLUMES. Valid characters for +/ the drive ID strings are: A-Z and 0-9. */ +/* USER CODE END Volumes */ + +#define _MULTI_PARTITION 0 /* 0:Single partition, 1:Multiple partition */ +/* This option switches multi-partition feature. By default (0), each logical drive +/ number is bound to the same physical drive number and only an FAT volume found on +/ the physical drive will be mounted. When multi-partition feature is enabled (1), +/ each logical drive number is bound to arbitrary physical drive and partition +/ listed in the VolToPart[]. Also f_fdisk() funciton will be available. */ + +#define _MIN_SS 512 /* 512, 1024, 2048 or 4096 */ +#define _MAX_SS 512 /* 512, 1024, 2048 or 4096 */ +/* These options configure the range of sector size to be supported. (512, 1024, +/ 2048 or 4096) Always set both 512 for most systems, all type of memory cards and +/ harddisk. But a larger value may be required for on-board flash memory and some +/ type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured +/ to variable sector size and GET_SECTOR_SIZE command must be implemented to the +/ disk_ioctl() function. */ + +#define _USE_TRIM 0 +/* This option switches ATA-TRIM feature. (0:Disable or 1:Enable) +/ To enable Trim feature, also CTRL_TRIM command should be implemented to the +/ disk_ioctl() function. */ + +#define _FS_NOFSINFO 0 /* 0,1,2 or 3 */ +/* If you need to know correct free space on the FAT32 volume, set bit 0 of this +/ option, and f_getfree() function at first time after volume mount will force +/ a full FAT scan. Bit 1 controls the use of last allocated cluster number. +/ +/ bit0=0: Use free cluster count in the FSINFO if available. +/ bit0=1: Do not trust free cluster count in the FSINFO. +/ bit1=0: Use last allocated cluster number in the FSINFO if available. +/ bit1=1: Do not trust last allocated cluster number in the FSINFO. +*/ + +/*---------------------------------------------------------------------------/ +/ System Configurations +/----------------------------------------------------------------------------*/ + +#define _FS_NORTC 0 +#define _NORTC_MON 6 +#define _NORTC_MDAY 4 +#define _NORTC_YEAR 2015 +/* The _FS_NORTC option switches timestamp feature. If the system does not have +/ an RTC function or valid timestamp is not needed, set _FS_NORTC to 1 to disable +/ the timestamp feature. All objects modified by FatFs will have a fixed timestamp +/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR. +/ When timestamp feature is enabled (_FS_NORTC == 0), get_fattime() function need +/ to be added to the project to read current time form RTC. _NORTC_MON, +/ _NORTC_MDAY and _NORTC_YEAR have no effect. +/ These options have no effect at read-only configuration (_FS_READONLY == 1). */ + +#define _FS_LOCK 2 /* 0:Disable or >=1:Enable */ +/* The _FS_LOCK option switches file lock feature to control duplicated file open +/ and illegal operation to open objects. This option must be 0 when _FS_READONLY +/ is 1. +/ +/ 0: Disable file lock feature. To avoid volume corruption, application program +/ should avoid illegal open, remove and rename to the open objects. +/ >0: Enable file lock feature. The value defines how many files/sub-directories +/ can be opened simultaneously under file lock control. Note that the file +/ lock feature is independent of re-entrancy. */ + +#define _FS_REENTRANT 0 /* 0:Disable or 1:Enable */ +#define _FS_TIMEOUT 1000 /* Timeout period in unit of time ticks */ +#define _SYNC_t NULL +/* The _FS_REENTRANT option switches the re-entrancy (thread safe) of the FatFs +/ module itself. Note that regardless of this option, file access to different +/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs() +/ and f_fdisk() function, are always not re-entrant. Only file/directory access +/ to the same volume is under control of this feature. +/ +/ 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect. +/ 1: Enable re-entrancy. Also user provided synchronization handlers, +/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() +/ function, must be added to the project. Samples are available in +/ option/syscall.c. +/ +/ The _FS_TIMEOUT defines timeout period in unit of time tick. +/ The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, +/ SemaphoreHandle_t and etc.. */ + +#define _WORD_ACCESS 0 /* 0 or 1 */ +/* The _WORD_ACCESS option is an only platform dependent option. It defines +/ which access method is used to the word data on the FAT volume. +/ +/ 0: Byte-by-byte access. Always compatible with all platforms. +/ 1: Word access. Do not choose this unless under both the following conditions. +/ +/ * Address misaligned memory access is always allowed to ALL instructions. +/ * Byte order on the memory is little-endian. +/ +/ If it is the case, _WORD_ACCESS can also be set to 1 to reduce code size. +/ Following table shows allowable settings of some processor types. +/ +/ ARM7TDMI 0 ColdFire 0 V850E 0 +/ Cortex-M3 0 Z80 0/1 V850ES 0/1 +/ Cortex-M0 0 x86 0/1 TLCS-870 0/1 +/ AVR 0/1 RX600(LE) 0/1 TLCS-900 0/1 +/ AVR32 0 RL78 0 R32C 0 +/ PIC18 0/1 SH-2 0 M16C 0/1 +/ PIC24 0 H8S 0 MSP430 0 +/ PIC32 0 H8/300H 0 8051 0/1 +*/ + +#endif /* _FFCONF */ \ No newline at end of file diff --git a/src/fatfs/ffsystem.c b/src/fatfs/ffsystem.c index b88ce15..d5c5134 100644 --- a/src/fatfs/ffsystem.c +++ b/src/fatfs/ffsystem.c @@ -1,170 +1,208 @@ /*------------------------------------------------------------------------*/ -/* Sample Code of OS Dependent Functions for FatFs */ -/* (C)ChaN, 2018 */ +/* A Sample Code of User Provided OS Dependent Functions for FatFs */ /*------------------------------------------------------------------------*/ - #include "ff.h" -#if FF_USE_LFN == 3 /* Dynamic memory allocation */ +#if FF_USE_LFN == 3 /* Use dynamic memory allocation */ /*------------------------------------------------------------------------*/ -/* Allocate a memory block */ +/* Allocate/Free a Memory Block */ /*------------------------------------------------------------------------*/ +#include /* with POSIX API */ + + void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */ UINT msize /* Number of bytes to allocate */ ) { - return malloc(msize); /* Allocate a new memory block with POSIX API */ + return malloc((size_t)msize); /* Allocate a new memory block */ } -/*------------------------------------------------------------------------*/ -/* Free a memory block */ -/*------------------------------------------------------------------------*/ - void ff_memfree ( - void* mblock /* Pointer to the memory block to free (nothing to do if null) */ + void* mblock /* Pointer to the memory block to free (no effect if null) */ ) { - free(mblock); /* Free the memory block with POSIX API */ + free(mblock); /* Free the memory block */ } #endif + #if FF_FS_REENTRANT /* Mutal exclusion */ - /*------------------------------------------------------------------------*/ -/* Create a Synchronization Object */ +/* Definitions of Mutex */ /*------------------------------------------------------------------------*/ -/* This function is called in f_mount() function to create a new -/ synchronization object for the volume, such as semaphore and mutex. -/ When a 0 is returned, the f_mount() function fails with FR_INT_ERR. -*/ -//const osMutexDef_t Mutex[FF_VOLUMES]; /* Table of CMSIS-RTOS mutex */ +#define OS_TYPE 0 /* 0:Win32, 1:uITRON4.0, 2:uC/OS-II, 3:FreeRTOS, 4:CMSIS-RTOS */ -int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */ - BYTE vol, /* Corresponding volume (logical drive number) */ - FF_SYNC_t* sobj /* Pointer to return the created sync object */ -) -{ - /* Win32 */ - *sobj = CreateMutex(NULL, FALSE, NULL); - return (int)(*sobj != INVALID_HANDLE_VALUE); +#if OS_TYPE == 0 /* Win32 */ +#include +static HANDLE Mutex[FF_VOLUMES + 1]; /* Table of mutex handle */ - /* uITRON */ -// T_CSEM csem = {TA_TPRI,1,1}; -// *sobj = acre_sem(&csem); -// return (int)(*sobj > 0); +#elif OS_TYPE == 1 /* uITRON */ +#include "itron.h" +#include "kernel.h" +static mtxid Mutex[FF_VOLUMES + 1]; /* Table of mutex ID */ - /* uC/OS-II */ -// OS_ERR err; -// *sobj = OSMutexCreate(0, &err); -// return (int)(err == OS_NO_ERR); +#elif OS_TYPE == 2 /* uc/OS-II */ +#include "includes.h" +static OS_EVENT *Mutex[FF_VOLUMES + 1]; /* Table of mutex pinter */ - /* FreeRTOS */ -// *sobj = xSemaphoreCreateMutex(); -// return (int)(*sobj != NULL); +#elif OS_TYPE == 3 /* FreeRTOS */ +#include "FreeRTOS.h" +#include "semphr.h" +static SemaphoreHandle_t Mutex[FF_VOLUMES + 1]; /* Table of mutex handle */ - /* CMSIS-RTOS */ -// *sobj = osMutexCreate(&Mutex[vol]); -// return (int)(*sobj != NULL); -} - - -/*------------------------------------------------------------------------*/ -/* Delete a Synchronization Object */ -/*------------------------------------------------------------------------*/ -/* This function is called in f_mount() function to delete a synchronization -/ object that created with ff_cre_syncobj() function. When a 0 is returned, -/ the f_mount() function fails with FR_INT_ERR. -*/ - -int ff_del_syncobj ( /* 1:Function succeeded, 0:Could not delete due to an error */ - FF_SYNC_t sobj /* Sync object tied to the logical drive to be deleted */ -) -{ - /* Win32 */ - return (int)CloseHandle(sobj); - - /* uITRON */ -// return (int)(del_sem(sobj) == E_OK); - - /* uC/OS-II */ -// OS_ERR err; -// OSMutexDel(sobj, OS_DEL_ALWAYS, &err); -// return (int)(err == OS_NO_ERR); - - /* FreeRTOS */ -// vSemaphoreDelete(sobj); -// return 1; - - /* CMSIS-RTOS */ -// return (int)(osMutexDelete(sobj) == osOK); -} - - -/*------------------------------------------------------------------------*/ -/* Request Grant to Access the Volume */ -/*------------------------------------------------------------------------*/ -/* This function is called on entering file functions to lock the volume. -/ When a 0 is returned, the file function fails with FR_TIMEOUT. -*/ - -int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */ - FF_SYNC_t sobj /* Sync object to wait */ -) -{ - /* Win32 */ - return (int)(WaitForSingleObject(sobj, FF_FS_TIMEOUT) == WAIT_OBJECT_0); - - /* uITRON */ -// return (int)(wai_sem(sobj) == E_OK); - - /* uC/OS-II */ -// OS_ERR err; -// OSMutexPend(sobj, FF_FS_TIMEOUT, &err)); -// return (int)(err == OS_NO_ERR); - - /* FreeRTOS */ -// return (int)(xSemaphoreTake(sobj, FF_FS_TIMEOUT) == pdTRUE); - - /* CMSIS-RTOS */ -// return (int)(osMutexWait(sobj, FF_FS_TIMEOUT) == osOK); -} - - -/*------------------------------------------------------------------------*/ -/* Release Grant to Access the Volume */ -/*------------------------------------------------------------------------*/ -/* This function is called on leaving file functions to unlock the volume. -*/ - -void ff_rel_grant ( - FF_SYNC_t sobj /* Sync object to be signaled */ -) -{ - /* Win32 */ - ReleaseMutex(sobj); - - /* uITRON */ -// sig_sem(sobj); - - /* uC/OS-II */ -// OSMutexPost(sobj); - - /* FreeRTOS */ -// xSemaphoreGive(sobj); - - /* CMSIS-RTOS */ -// osMutexRelease(sobj); -} +#elif OS_TYPE == 4 /* CMSIS-RTOS */ +#include "cmsis_os.h" +static osMutexId Mutex[FF_VOLUMES + 1]; /* Table of mutex ID */ #endif + + +/*------------------------------------------------------------------------*/ +/* Create a Mutex */ +/*------------------------------------------------------------------------*/ +/* This function is called in f_mount function to create a new mutex +/ or semaphore for the volume. When a 0 is returned, the f_mount function +/ fails with FR_INT_ERR. +*/ + +int ff_mutex_create ( /* Returns 1:Function succeeded or 0:Could not create the mutex */ + int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */ +) +{ +#if OS_TYPE == 0 /* Win32 */ + Mutex[vol] = CreateMutex(NULL, FALSE, NULL); + return (int)(Mutex[vol] != INVALID_HANDLE_VALUE); + +#elif OS_TYPE == 1 /* uITRON */ + T_CMTX cmtx = {TA_TPRI,1}; + + Mutex[vol] = acre_mtx(&cmtx); + return (int)(Mutex[vol] > 0); + +#elif OS_TYPE == 2 /* uC/OS-II */ + OS_ERR err; + + Mutex[vol] = OSMutexCreate(0, &err); + return (int)(err == OS_NO_ERR); + +#elif OS_TYPE == 3 /* FreeRTOS */ + Mutex[vol] = xSemaphoreCreateMutex(); + return (int)(Mutex[vol] != NULL); + +#elif OS_TYPE == 4 /* CMSIS-RTOS */ + osMutexDef(cmsis_os_mutex); + + Mutex[vol] = osMutexCreate(osMutex(cmsis_os_mutex)); + return (int)(Mutex[vol] != NULL); + +#endif +} + + +/*------------------------------------------------------------------------*/ +/* Delete a Mutex */ +/*------------------------------------------------------------------------*/ +/* This function is called in f_mount function to delete a mutex or +/ semaphore of the volume created with ff_mutex_create function. +*/ + +void ff_mutex_delete ( /* Returns 1:Function succeeded or 0:Could not delete due to an error */ + int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */ +) +{ +#if OS_TYPE == 0 /* Win32 */ + CloseHandle(Mutex[vol]); + +#elif OS_TYPE == 1 /* uITRON */ + del_mtx(Mutex[vol]); + +#elif OS_TYPE == 2 /* uC/OS-II */ + OS_ERR err; + + OSMutexDel(Mutex[vol], OS_DEL_ALWAYS, &err); + +#elif OS_TYPE == 3 /* FreeRTOS */ + vSemaphoreDelete(Mutex[vol]); + +#elif OS_TYPE == 4 /* CMSIS-RTOS */ + osMutexDelete(Mutex[vol]); + +#endif +} + + +/*------------------------------------------------------------------------*/ +/* Request a Grant to Access the Volume */ +/*------------------------------------------------------------------------*/ +/* This function is called on enter file functions to lock the volume. +/ When a 0 is returned, the file function fails with FR_TIMEOUT. +*/ + +int ff_mutex_take ( /* Returns 1:Succeeded or 0:Timeout */ + int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */ +) +{ +#if OS_TYPE == 0 /* Win32 */ + return (int)(WaitForSingleObject(Mutex[vol], FF_FS_TIMEOUT) == WAIT_OBJECT_0); + +#elif OS_TYPE == 1 /* uITRON */ + return (int)(tloc_mtx(Mutex[vol], FF_FS_TIMEOUT) == E_OK); + +#elif OS_TYPE == 2 /* uC/OS-II */ + OS_ERR err; + + OSMutexPend(Mutex[vol], FF_FS_TIMEOUT, &err)); + return (int)(err == OS_NO_ERR); + +#elif OS_TYPE == 3 /* FreeRTOS */ + return (int)(xSemaphoreTake(Mutex[vol], FF_FS_TIMEOUT) == pdTRUE); + +#elif OS_TYPE == 4 /* CMSIS-RTOS */ + return (int)(osMutexWait(Mutex[vol], FF_FS_TIMEOUT) == osOK); + +#endif +} + + + +/*------------------------------------------------------------------------*/ +/* Release a Grant to Access the Volume */ +/*------------------------------------------------------------------------*/ +/* This function is called on leave file functions to unlock the volume. +*/ + +void ff_mutex_give ( + int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */ +) +{ +#if OS_TYPE == 0 /* Win32 */ + ReleaseMutex(Mutex[vol]); + +#elif OS_TYPE == 1 /* uITRON */ + unl_mtx(Mutex[vol]); + +#elif OS_TYPE == 2 /* uC/OS-II */ + OSMutexPost(Mutex[vol]); + +#elif OS_TYPE == 3 /* FreeRTOS */ + xSemaphoreGive(Mutex[vol]); + +#elif OS_TYPE == 4 /* CMSIS-RTOS */ + osMutexRelease(Mutex[vol]); + +#endif +} + +#endif /* FF_FS_REENTRANT */ + diff --git a/src/fatfs/ffunicode.c b/src/fatfs/ffunicode.c index a69b24c..e6bcaca 100644 --- a/src/fatfs/ffunicode.c +++ b/src/fatfs/ffunicode.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------*/ -/* Unicode handling functions for FatFs R0.13+ */ +/* Unicode Handling Functions for FatFs R0.13 and Later */ +/*------------------------------------------------------------------------*/ +/* This module will occupy a huge memory in the .rodata section when the */ +/* FatFs is configured for LFN with DBCS. If the system has a Unicode */ +/* library for the code conversion, this module should be modified to use */ +/* it to avoid silly memory consumption. */ /*------------------------------------------------------------------------*/ -/* This module will occupy a huge memory in the .const section when the / -/ FatFs is configured for LFN with DBCS. If the system has any Unicode / -/ utilitiy for the code conversion, this module should be modified to use / -/ that function to avoid silly memory consumption. / -/-------------------------------------------------------------------------*/ /* -/ Copyright (C) 2014, ChaN, all right reserved. +/ Copyright (C) 2022, ChaN, all right reserved. / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided @@ -25,7 +25,7 @@ #include "ff.h" -#if FF_USE_LFN /* This module will be blanked if non-LFN configuration */ +#if FF_USE_LFN != 0 /* This module will be blanked if in non-LFN configuration */ #define MERGE2(a, b) a ## b #define CVTBL(tbl, cp) MERGE2(tbl, cp) @@ -15214,8 +15214,8 @@ static const WCHAR uc869[] = { /* CP869(Greek 2) to Unicode conversion table */ /*------------------------------------------------------------------------*/ -/* OEM <==> Unicode conversions for static code page configuration */ -/* SBCS fixed code page */ +/* OEM <==> Unicode Conversions for Static Code Page Configuration with */ +/* SBCS Fixed Code Page */ /*------------------------------------------------------------------------*/ #if FF_CODE_PAGE != 0 && FF_CODE_PAGE < 900 @@ -15225,7 +15225,7 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ ) { WCHAR c = 0; - const WCHAR *p = CVTBL(uc, FF_CODE_PAGE); + const WCHAR* p = CVTBL(uc, FF_CODE_PAGE); if (uni < 0x80) { /* ASCII? */ @@ -15247,7 +15247,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ ) { WCHAR c = 0; - const WCHAR *p = CVTBL(uc, FF_CODE_PAGE); + const WCHAR* p = CVTBL(uc, FF_CODE_PAGE); if (oem < 0x80) { /* ASCII? */ @@ -15267,8 +15267,8 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ /*------------------------------------------------------------------------*/ -/* OEM <==> Unicode conversions for static code page configuration */ -/* DBCS fixed code page */ +/* OEM <==> Unicode Conversions for Static Code Page Configuration with */ +/* DBCS Fixed Code Page */ /*------------------------------------------------------------------------*/ #if FF_CODE_PAGE >= 900 @@ -15277,7 +15277,7 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ WORD cp /* Code page for the conversion */ ) { - const WCHAR *p; + const WCHAR* p; WCHAR c = 0, uc; UINT i = 0, n, li, hi; @@ -15313,7 +15313,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ WORD cp /* Code page for the conversion */ ) { - const WCHAR *p; + const WCHAR* p; WCHAR c = 0; UINT i = 0, n, li, hi; @@ -15346,7 +15346,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ /*------------------------------------------------------------------------*/ -/* OEM <==> Unicode conversions for dynamic code page configuration */ +/* OEM <==> Unicode Conversions for Dynamic Code Page Configuration */ /*------------------------------------------------------------------------*/ #if FF_CODE_PAGE == 0 @@ -15360,7 +15360,7 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */ WORD cp /* Code page for the conversion */ ) { - const WCHAR *p; + const WCHAR* p; WCHAR c = 0, uc; UINT i, n, li, hi; @@ -15412,7 +15412,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ WORD cp /* Code page for the conversion */ ) { - const WCHAR *p; + const WCHAR* p; WCHAR c = 0; UINT i, n, li, hi; @@ -15458,14 +15458,14 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */ /*------------------------------------------------------------------------*/ -/* Unicode up-case conversion */ +/* Unicode Up-case Conversion */ /*------------------------------------------------------------------------*/ DWORD ff_wtoupper ( /* Returns up-converted code point */ DWORD uni /* Unicode code point to be up-converted */ ) { - const WORD *p; + const WORD* p; WORD uc, bc, nc, cmd; static const WORD cvt1[] = { /* Compressed up conversion table for U+0000 - U+0FFF */ /* Basic Latin */ @@ -15590,4 +15590,4 @@ DWORD ff_wtoupper ( /* Returns up-converted code point */ } -#endif /* #if FF_USE_LFN */ +#endif /* #if FF_USE_LFN != 0 */ diff --git a/src/fatfs/toolbox_bdev.c b/src/fatfs/toolbox_bdev.c new file mode 100644 index 0000000..c0c8d00 --- /dev/null +++ b/src/fatfs/toolbox_bdev.c @@ -0,0 +1,95 @@ +/** + * @file toolbox_bdev.h + * @author your name (you@domain.com) + * @brief Connector module to allow FatFS to use Foenix Toolkit block devices + * @version 0.1 + * @date 2024-07-06 + * + * @copyright Copyright (c) 2024 + * + */ + +#include "log_level.h" +#define DEFAULT_LOG_LEVEL LOG_ERROR + +#include +#include + +#include "log.h" +#include "toolbox_bdev.h" +#include "constants.h" +#include "errors.h" +#include "dev/block.h" + +/** + * @brief Convert Toolkit Block Device result codes to FatFS result codes + * + * @param result Toolkit result code + * @return DRESULT a corresponding result code + */ +static DRESULT bdev_to_fatfs(short result) { + if (result < 0) { + switch(result) { + case DEV_WRITEPROT: + return RES_WRPRT; + + case ERR_NOT_READY: + return RES_NOTRDY; + + case ERR_BAD_ARGUMENT: + return RES_PARERR; + + default: + return RES_ERROR; + } + } + + return RES_OK; +} + +DSTATUS disk_initialize(BYTE pdrv) { + return (DSTATUS)bdev_init(pdrv); +} + +DSTATUS disk_status(BYTE pdrv) { + DSTATUS result = (DSTATUS)bdev_status(pdrv); + INFO1("disk_status: %02X", result); + return result; +} + +static void sector_dump(uint8_t * buffer, int count) { + char char_buffer[17]; + + printf("Sector:\n"); + + short index = 0; + for (int i = 0; i < count; i++) { + char c = buffer[i]; + + if ((i & 0xf) == 0) { + printf("\n"); + } + + printf("%02X ", c); + } +} + +DRESULT disk_read(BYTE pdrv, BYTE* buff, LBA_t sector, UINT count) { + short result = bdev_read(pdrv, sector, buff, 512 * count); + INFO2("disk_read: sector #%u result %d", sector, result); + // sector_dump(buff, 512); + + return bdev_to_fatfs(result); +} + +DRESULT disk_write(BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count) { + short result = bdev_write(pdrv, sector, buff, 512 * count); + INFO2("disk_write: sector #%u result %d", sector, result); + return bdev_to_fatfs(result); +} + +DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void* buff) { + short result = bdev_ioctrl(pdrv, cmd, buff, 0); + INFO1("disk_ioctl: %d", result); + return bdev_to_fatfs(result); +} diff --git a/src/fatfs/toolbox_bdev.h b/src/fatfs/toolbox_bdev.h new file mode 100644 index 0000000..b8f6c3e --- /dev/null +++ b/src/fatfs/toolbox_bdev.h @@ -0,0 +1,86 @@ +/** + * @file toolbox_bdev.h + * @author your name (you@domain.com) + * @brief Connector module to allow FatFS to use Foenix Toolkit block devices + * @version 0.1 + * @date 2024-07-06 + * + * @copyright Copyright (c) 2024 + * + */ + +#ifndef __toolbox_bdev_h__ +#define __toolbox_bdev_h__ + +#include "ff.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Status of Disk Functions */ +typedef BYTE DSTATUS; + +/* Results of Disk Functions */ +typedef enum { + RES_OK = 0, /* 0: Successful */ + RES_ERROR, /* 1: R/W Error */ + RES_WRPRT, /* 2: Write Protected */ + RES_NOTRDY, /* 3: Not Ready */ + RES_PARERR /* 4: Invalid Parameter */ +} DRESULT; + + +/*---------------------------------------*/ +/* Prototypes for disk control functions */ + + +DSTATUS disk_initialize (BYTE pdrv); +DSTATUS disk_status (BYTE pdrv); +DRESULT disk_read (BYTE pdrv, BYTE* buff, LBA_t sector, UINT count); +DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count); +DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); + + +/* Disk Status Bits (DSTATUS) */ + +#define STA_NOINIT 0x01 /* Drive not initialized */ +#define STA_NODISK 0x02 /* No medium in the drive */ +#define STA_PROTECT 0x04 /* Write protected */ + + +/* Command code for disk_ioctrl fucntion */ + +/* Generic command (Used by FatFs) */ +#define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */ +#define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */ +#define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */ +#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */ +#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */ + +/* Generic command (Not used by FatFs) */ +#define CTRL_POWER 5 /* Get/Set power status */ +#define CTRL_LOCK 6 /* Lock/Unlock media removal */ +#define CTRL_EJECT 7 /* Eject media */ +#define CTRL_FORMAT 8 /* Create physical format on the media */ + +/* MMC/SDC specific ioctl command */ +#define MMC_GET_TYPE 10 /* Get card type */ +#define MMC_GET_CSD 11 /* Get CSD */ +#define MMC_GET_CID 12 /* Get CID */ +#define MMC_GET_OCR 13 /* Get OCR */ +#define MMC_GET_SDSTAT 14 /* Get SD status */ +#define ISDIO_READ 55 /* Read data form SD iSDIO register */ +#define ISDIO_WRITE 56 /* Write data to SD iSDIO register */ +#define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */ + +/* ATA/CF specific ioctl command */ +#define ATA_GET_REV 20 /* Get F/W revision */ +#define ATA_GET_MODEL 21 /* Get model name */ +#define ATA_GET_SN 22 /* Get serial number */ + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/src/include/F256/sdc_f256.h b/src/include/F256/sdc_f256.h deleted file mode 100644 index e147846..0000000 --- a/src/include/F256/sdc_f256.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Definitions for access to the SDC controller - */ - -#ifndef __SDC_C256_H -#define __SDC_C256_H - -#include - -#define SDC_BASE ((volatile uint8_t *)0xf01d00) - -// TODO: fill out with the actual registers - -#endif diff --git a/src/include/F256/sdc_spi.h b/src/include/F256/sdc_spi.h new file mode 100644 index 0000000..e214d26 --- /dev/null +++ b/src/include/F256/sdc_spi.h @@ -0,0 +1,30 @@ +/* + * Definitions for access to the SDC controller using the SPI interface + */ + +#ifndef __SDC_SPI_H +#define __SDC_SPI_H + +#include + +/** + * @brief Structure to manage the SPI driven SDC ports + * + */ +typedef struct s_sdc_spi { + uint8_t ctrl; + uint8_t data; +} t_sdc_spi, *p_sdc_spi; + +#define SDx_CS 0x01 // 1 = Enable +#define SDx_SLOW 0x02 // 1 = Slow 400Khz, 0 = 25Mhz +#define SDx_BUSY 0x80 // 1 = Busy + +#define SD0_REG ((volatile __attribute__((far)) p_sdc_spi)0xf016a0) +#define SD1_REG ((volatile __attribute__((far)) p_sdc_spi)0xf01d80) + +#define SD0_STAT (*(volatile __far uint8_t *)0xf016a0) +#define SD0_STAT_CD 0x40 // When 1 = No Card, 0 = Card is Present +#define SD0_STAT_WP 0x80 // When 0 = Writeable, 1 = Card is Protected + +#endif diff --git a/src/include/constants.h b/src/include/constants.h index 941eec1..2b7ab72 100644 --- a/src/include/constants.h +++ b/src/include/constants.h @@ -47,9 +47,10 @@ * Block devices */ -#define BDEV_SDC 0 -#define BDEV_FDC 1 -#define BDEV_HDC 2 +#define BDEV_SD0 0 +#define BDEV_SD1 1 +#define BDEV_FDC 2 +#define BDEV_HDC 3 /* * Channel devices @@ -63,4 +64,13 @@ #define CDEV_MIDI 5 #define CDEV_FILE 6 +/* + * Block Device IOCRTRL commands + */ + +#define IOCTRL_CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */ +#define IOCTRL_GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */ +#define IOCTRL_GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */ +#define IOCTRL_GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */ + #endif diff --git a/src/include/errors.h b/src/include/errors.h index 363a928..7b722cd 100644 --- a/src/include/errors.h +++ b/src/include/errors.h @@ -49,5 +49,6 @@ #define ERR_NOT_SUPPORTED -37 /* Device does not support the file or operation */ #define ERR_BAD_ARGUMENT -38 /* An invalid argument was provided */ #define ERR_MEDIA_CHANGE -39 /* Removable media has changed */ +#define ERR_NOT_READY -40 /* Media device is not ready */ #endif diff --git a/src/include/sys_types.h b/src/include/sys_types.h index cf22928..1266162 100644 --- a/src/include/sys_types.h +++ b/src/include/sys_types.h @@ -110,14 +110,15 @@ typedef struct s_sys_info { */ typedef struct s_dev_block { - short number; // The number of the device (assigned by registration) - char * name; // The name of the device - FUNC_V_2_S init; // short init() -- Initialize the device - FUNC_LBS_2_S read; // short read(long lba, byte * buffer, short size) -- Read a block from the device - FUNC_LcBS_2_S write; // short write(long lba, byte * buffer, short size) -- Write a block to the device - FUNC_V_2_S status; // short status() -- Get the status of the device - FUNC_V_2_S flush; // short flush() -- Ensure that any pending writes to teh device have been completed - FUNC_SBS_2_S ioctrl; // short ioctrl(short command, byte * buffer, short size)) -- Issue a control command to the device + short number; // The number of the device (assigned by registration) + char * name; // The name of the device + void * data; // Device-specific data block + short (*init)(struct s_dev_block *); // Initialize the device + short (*read)(struct s_dev_block *, long lba, uint8_t * buffer, short size); // Read a block from the device + short (*write)(struct s_dev_block *, long lba, const uint8_t * buffer, short size); // Write a block to the device + short (*status)(struct s_dev_block *); // Get the status of the device + short (*flush)(struct s_dev_block *); // Ensure that any pending writes to the device have been completed + short (*ioctrl)(struct s_dev_block *, short command, unsigned char * buffer, short size); // Issue a control command to the device } t_dev_block, *p_dev_block; /* diff --git a/src/toolbox.c b/src/toolbox.c index dd4fba8..85f918e 100644 --- a/src/toolbox.c +++ b/src/toolbox.c @@ -6,6 +6,7 @@ #define DEFAULT_LOG_LEVEL LOG_INFO #define LOG_CHANNEL LOG_CHANNEL_UART0 +#include #include #include #include @@ -35,6 +36,7 @@ #elif MODEL == MODEL_FOENIX_F256 || MODEL == MODEL_FOENIX_F256K || MODEL == MODEL_FOENIX_F256K2 #include "dev/txt_f256.h" #include "dev/kbd_f256k.h" +#include "dev/sdc_f256.h" #endif #include "syscalls.h" @@ -214,11 +216,11 @@ void initialize() { } #endif -// if ((res = sdc_install())) { -// ERROR1("FAILED: SDC driver installation %d", res); -// } else { -// INFO("SDC driver installed."); -// } + if ((res = sdc_install())) { + ERROR1("FAILED: SDC driver installation %d", res); + } else { + INFO("SDC driver installed."); + } #if HAS_FLOPPY if ((res = fdc_install())) { @@ -266,17 +268,41 @@ void initialize() { // log(LOG_INFO, "Serial ports initialized."); // } -// if ((res = fsys_init())) { -// log_num(LOG_ERROR, "FAILED: file system initialization", res); -// } else { -// INFO("File system initialized."); -// } + if ((res = fsys_init())) { + log_num(LOG_ERROR, "FAILED: file system initialization", res); + } else { + INFO("File system initialized."); + } } -char dec2hex(uint8_t x) { - char * hex_digits = "0123456789ABCDEF"; +t_file_info dir; +uint8_t buffer[512]; - return hex_digits[x & 0x0f]; + +void dump(uint8_t * buffer, int count) { + char char_buffer[17]; + + printf("\n"); + + short index = 0; + for (int i = 0; i < count; i++) { + if ((i > 0) && (i % 16 == 0)) { + index = 0; + char_buffer[16] = 0; + printf(" %s\n", char_buffer); + } else if (i > 0) { + char c = buffer[i]; + printf("%02X ", c); + + if (isalpha(c) || isdigit(c)) { + char_buffer[index++] = c; + } else { + char_buffer[index++] = '.'; + } + } + } + + printf(" %s\n", char_buffer); } int main(int argc, char * argv[]) { @@ -286,17 +312,52 @@ int main(int argc, char * argv[]) { initialize(); - kbd_init(); - printf("\n> "); - chan_ioctrl(0, CON_IOCTRL_ECHO_OFF, 0, 0); - while (!kbd_break()) { - char c = chan_read_b(0); - if (c != 0) { - chan_write_b(0, c); + short fd = fsys_opendir("0:/"); + if (fd > -1) { + INFO("fsys_opendir"); + + short result = fsys_readdir(fd, &dir); + while (result == 0) { + if (dir.name[0] != 0) { + printf("%s\n", dir.name); + } else { + break; + } + + result = fsys_readdir(fd, &dir); } + + fsys_closedir(fd); + INFO("fsys_closedir"); + } else { + ERROR1("Could not open directory %d", fd); } - printf("\nDone.\n"); + // kbd_init(); + // printf("\n> "); + // chan_ioctrl(0, CON_IOCTRL_ECHO_OFF, 0, 0); + // while (!kbd_break()) { + // char c = chan_read_b(0); + // if (c != 0) { + // chan_write_b(0, c); + // } + // } + + // INFO("bdev_init"); + // short status = bdev_init(BDEV_SD0); + // if (status) { + // ERROR1("bdev_init returned %d", status); + // } + // INFO("bdev_read"); + // status = bdev_read(BDEV_SD0, 97, buffer, 512); + // if (status < 512) { + // ERROR1("bdev_read returned %d", status); + // } + // INFO("Read."); + // dump(buffer, 512); + + + // printf("\nDone.\n"); // Attempt to start up the user code // log(LOG_INFO, "Looking for user startup code:");