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, &param);
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 				       &sector_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