diff --git a/modules/fatfs/zfs_diskio.c b/modules/fatfs/zfs_diskio.c index 7a5061f15b6..2b0fa742e71 100644 --- a/modules/fatfs/zfs_diskio.c +++ b/modules/fatfs/zfs_diskio.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2018-2021 Zephyr contributors * Copyright (c) 2022 Nordic Semiconductor ASA + * Copyright 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -12,6 +13,7 @@ */ #include #include /* FatFs lower layer API */ +#include /* Zephyr specific FatFS API */ #include static const char * const pdrv_str[] = {FF_VOLUME_STRS}; @@ -31,13 +33,9 @@ DSTATUS disk_status(BYTE pdrv) /* Initialize a Drive */ DSTATUS disk_initialize(BYTE pdrv) { - __ASSERT(pdrv < ARRAY_SIZE(pdrv_str), "pdrv out-of-range\n"); + uint8_t param = DISK_IOCTL_POWER_ON; - if (disk_access_init(pdrv_str[pdrv]) != 0) { - return STA_NOINIT; - } else { - return RES_OK; - } + return disk_ioctl(pdrv, CTRL_POWER, ¶m); } /* Read Sector(s) */ @@ -109,6 +107,27 @@ DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff) } break; + /* Optional IOCTL command used by Zephyr fs_unmount implementation, + * not called by FATFS + */ + case CTRL_POWER: + if (((*(uint8_t *)buff)) == DISK_IOCTL_POWER_OFF) { + /* Power disk off */ + if (disk_access_ioctl(pdrv_str[pdrv], + DISK_IOCTL_CTRL_DEINIT, + NULL) != 0) { + ret = RES_ERROR; + } + } else { + /* Power disk on */ + if (disk_access_ioctl(pdrv_str[pdrv], + DISK_IOCTL_CTRL_INIT, + NULL) != 0) { + ret = STA_NOINIT; + } + } + break; + default: ret = RES_PARERR; break; diff --git a/modules/fatfs/zfs_diskio.h b/modules/fatfs/zfs_diskio.h new file mode 100644 index 00000000000..b22c75586be --- /dev/null +++ b/modules/fatfs/zfs_diskio.h @@ -0,0 +1,22 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_MODULES_FATFS_ZFS_DISKIO_H_ +#define ZEPHYR_MODULES_FATFS_ZFS_DISKIO_H_ +/* + * Header file for Zephyr specific portions of the FatFS disk interface. + * These APIs are internal to Zephyr's FatFS VFS implementation + */ + +/* + * Values that can be passed to buffer pointer used by disk_ioctl() when + * sending CTRL_POWER IOCTL + */ +#define DISK_IOCTL_POWER_OFF 0x0 +#define DISK_IOCTL_POWER_ON 0x1 + + +#endif /* ZEPHYR_MODULES_FATFS_ZFS_DISKIO_H_ */ diff --git a/subsys/fs/fat_fs.c b/subsys/fs/fat_fs.c index a9e5c7f93cd..2a0b7b7d486 100644 --- a/subsys/fs/fat_fs.c +++ b/subsys/fs/fat_fs.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2016 Intel Corporation. + * Copyright 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -14,6 +15,10 @@ #include #include #include +#include +#include /* Zephyr specific FatFS API */ +#include +LOG_MODULE_DECLARE(fs, CONFIG_FS_LOG_LEVEL); #define FATFS_MAX_FILE_NAME 12 /* Uses 8.3 SFN */ @@ -64,6 +69,23 @@ static int translate_error(int error) return -EIO; } +static int translate_disk_error(int error) +{ + switch (error) { + case RES_OK: + return 0; + case RES_WRPRT: + return -EPERM; + case RES_PARERR: + return -EINVAL; + case RES_NOTRDY: + case RES_ERROR: + return -EIO; + } + + return -EIO; +} + /* Converts a zephyr path like /SD:/foo into a path digestible by FATFS by stripping the * leading slash, i.e. SD:/foo. */ @@ -463,10 +485,23 @@ static int fatfs_mount(struct fs_mount_t *mountp) static int fatfs_unmount(struct fs_mount_t *mountp) { FRESULT res; + DRESULT disk_res; + uint8_t param = DISK_IOCTL_POWER_OFF; res = f_mount(NULL, translate_path(mountp->mnt_point), 0); + if (res != FR_OK) { + LOG_ERR("Unmount failed (%d)", res); + return translate_error(res); + } - return translate_error(res); + /* Make direct disk IOCTL call to deinit disk */ + disk_res = disk_ioctl(((FATFS *)mountp->fs_data)->pdrv, CTRL_POWER, ¶m); + if (disk_res != RES_OK) { + LOG_ERR("Could not power off disk (%d)", disk_res); + return translate_disk_error(disk_res); + } + + return 0; } #if defined(CONFIG_FILE_SYSTEM_MKFS) && defined(CONFIG_FS_FATFS_MKFS)