1 /*
2 * Copyright (c) 2018-2021 Zephyr contributors
3 * Copyright (c) 2022 Nordic Semiconductor ASA
4 * Copyright 2024 NXP
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8 /* The file is based on template file by (C)ChaN, 2019, as
9 * available from FAT FS module source:
10 * https://github.com/zephyrproject-rtos/fatfs/blob/master/diskio.c
11 * and has been previously available from directory for that module
12 * under name zfs_diskio.c.
13 */
14 #include <ff.h>
15 #include <diskio.h> /* FatFs lower layer API */
16 #include <zfs_diskio.h> /* Zephyr specific FatFS API */
17 #include <zephyr/storage/disk_access.h>
18
19 #if CONFIG_FS_FATFS_CUSTOM_MOUNT_POINT_COUNT
20 #define PDRV_STR_ARRAY VolumeStr
21 #else
22 static const char *const pdrv_str[] = {FF_VOLUME_STRS};
23 #define PDRV_STR_ARRAY pdrv_str
24 #endif /* CONFIG_FS_FATFS_CUSTOM_MOUNT_POINT_COUNT */
25
26 /* Get Drive Status */
disk_status(BYTE pdrv)27 DSTATUS disk_status(BYTE pdrv)
28 {
29 __ASSERT(pdrv < ARRAY_SIZE(PDRV_STR_ARRAY), "pdrv out-of-range\n");
30
31 if (disk_access_status(PDRV_STR_ARRAY[pdrv]) != 0) {
32 return STA_NOINIT;
33 } else {
34 return RES_OK;
35 }
36 }
37
38 /* Initialize a Drive */
disk_initialize(BYTE pdrv)39 DSTATUS disk_initialize(BYTE pdrv)
40 {
41 uint8_t param = DISK_IOCTL_POWER_ON;
42
43 return disk_ioctl(pdrv, CTRL_POWER, ¶m);
44 }
45
46 /* Read Sector(s) */
disk_read(BYTE pdrv,BYTE * buff,LBA_t sector,UINT count)47 DRESULT disk_read(BYTE pdrv, BYTE *buff, LBA_t sector, UINT count)
48 {
49 __ASSERT(pdrv < ARRAY_SIZE(PDRV_STR_ARRAY), "pdrv out-of-range\n");
50
51 if (disk_access_read(PDRV_STR_ARRAY[pdrv], buff, sector, count) != 0) {
52 return RES_ERROR;
53 } else {
54 return RES_OK;
55 }
56 }
57
58 /* Write Sector(s) */
disk_write(BYTE pdrv,const BYTE * buff,LBA_t sector,UINT count)59 DRESULT disk_write(BYTE pdrv, const BYTE *buff, LBA_t sector, UINT count)
60 {
61 __ASSERT(pdrv < ARRAY_SIZE(PDRV_STR_ARRAY), "pdrv out-of-range\n");
62
63 if (disk_access_write(PDRV_STR_ARRAY[pdrv], buff, sector, count) != 0) {
64 return RES_ERROR;
65 } else {
66 return RES_OK;
67 }
68 }
69
70 /* Miscellaneous Functions */
disk_ioctl(BYTE pdrv,BYTE cmd,void * buff)71 DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff)
72 {
73 int ret = RES_OK;
74 uint32_t sector_size = 0;
75
76 __ASSERT(pdrv < ARRAY_SIZE(PDRV_STR_ARRAY), "pdrv out-of-range\n");
77
78 switch (cmd) {
79 case CTRL_SYNC:
80 if (disk_access_ioctl(PDRV_STR_ARRAY[pdrv], DISK_IOCTL_CTRL_SYNC, buff) != 0) {
81 ret = RES_ERROR;
82 }
83 break;
84
85 case GET_SECTOR_COUNT:
86 if (disk_access_ioctl(PDRV_STR_ARRAY[pdrv], DISK_IOCTL_GET_SECTOR_COUNT, buff) !=
87 0) {
88 ret = RES_ERROR;
89 }
90 break;
91
92 case GET_SECTOR_SIZE:
93 /* Zephyr's DISK_IOCTL_GET_SECTOR_SIZE returns sector size as a
94 * 32-bit number while FatFS's GET_SECTOR_SIZE is supposed to
95 * return a 16-bit number.
96 */
97 if ((disk_access_ioctl(PDRV_STR_ARRAY[pdrv], DISK_IOCTL_GET_SECTOR_SIZE,
98 §or_size) == 0) &&
99 (sector_size == (uint16_t)sector_size)) {
100 *(uint16_t *)buff = (uint16_t)sector_size;
101 } else {
102 ret = RES_ERROR;
103 }
104 break;
105
106 case GET_BLOCK_SIZE:
107 if (disk_access_ioctl(PDRV_STR_ARRAY[pdrv], DISK_IOCTL_GET_ERASE_BLOCK_SZ, buff) !=
108 0) {
109 ret = RES_ERROR;
110 }
111 break;
112
113 /* Optional IOCTL command used by Zephyr fs_unmount implementation,
114 * not called by FATFS
115 */
116 case CTRL_POWER:
117 if (((*(uint8_t *)buff)) == DISK_IOCTL_POWER_OFF) {
118 /* Power disk off */
119 if (disk_access_ioctl(PDRV_STR_ARRAY[pdrv], DISK_IOCTL_CTRL_DEINIT, NULL) !=
120 0) {
121 ret = RES_ERROR;
122 }
123 } else {
124 /* Power disk on */
125 if (disk_access_ioctl(PDRV_STR_ARRAY[pdrv], DISK_IOCTL_CTRL_INIT, NULL) !=
126 0) {
127 ret = STA_NOINIT;
128 }
129 }
130 break;
131
132 default:
133 ret = RES_PARERR;
134 break;
135 }
136 return ret;
137 }
138