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 avaialble 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 static const char * const pdrv_str[] = {FF_VOLUME_STRS};
20 
21 /* Get Drive Status */
disk_status(BYTE pdrv)22 DSTATUS disk_status(BYTE pdrv)
23 {
24 	__ASSERT(pdrv < ARRAY_SIZE(pdrv_str), "pdrv out-of-range\n");
25 
26 	if (disk_access_status(pdrv_str[pdrv]) != 0) {
27 		return STA_NOINIT;
28 	} else {
29 		return RES_OK;
30 	}
31 }
32 
33 /* Initialize a Drive */
disk_initialize(BYTE pdrv)34 DSTATUS disk_initialize(BYTE pdrv)
35 {
36 	uint8_t param = DISK_IOCTL_POWER_ON;
37 
38 	return disk_ioctl(pdrv, CTRL_POWER, &param);
39 }
40 
41 /* Read Sector(s) */
disk_read(BYTE pdrv,BYTE * buff,LBA_t sector,UINT count)42 DRESULT disk_read(BYTE pdrv, BYTE *buff, LBA_t sector, UINT count)
43 {
44 	__ASSERT(pdrv < ARRAY_SIZE(pdrv_str), "pdrv out-of-range\n");
45 
46 	if (disk_access_read(pdrv_str[pdrv], buff, sector, count) != 0) {
47 		return RES_ERROR;
48 	} else {
49 		return RES_OK;
50 	}
51 
52 }
53 
54 /* Write Sector(s) */
disk_write(BYTE pdrv,const BYTE * buff,LBA_t sector,UINT count)55 DRESULT disk_write(BYTE pdrv, const BYTE *buff, LBA_t sector, UINT count)
56 {
57 	__ASSERT(pdrv < ARRAY_SIZE(pdrv_str), "pdrv out-of-range\n");
58 
59 	if (disk_access_write(pdrv_str[pdrv], buff, sector, count) != 0) {
60 		return RES_ERROR;
61 	} else {
62 		return RES_OK;
63 	}
64 }
65 
66 /* Miscellaneous Functions */
disk_ioctl(BYTE pdrv,BYTE cmd,void * buff)67 DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff)
68 {
69 	int ret = RES_OK;
70 	uint32_t sector_size = 0;
71 
72 	__ASSERT(pdrv < ARRAY_SIZE(pdrv_str), "pdrv out-of-range\n");
73 
74 	switch (cmd) {
75 	case CTRL_SYNC:
76 		if (disk_access_ioctl(pdrv_str[pdrv],
77 				DISK_IOCTL_CTRL_SYNC, buff) != 0) {
78 			ret = RES_ERROR;
79 		}
80 		break;
81 
82 	case GET_SECTOR_COUNT:
83 		if (disk_access_ioctl(pdrv_str[pdrv],
84 				DISK_IOCTL_GET_SECTOR_COUNT, buff) != 0) {
85 			ret = RES_ERROR;
86 		}
87 		break;
88 
89 	case GET_SECTOR_SIZE:
90 		/* Zephyr's DISK_IOCTL_GET_SECTOR_SIZE returns sector size as a
91 		 * 32-bit number while FatFS's GET_SECTOR_SIZE is supposed to
92 		 * return a 16-bit number.
93 		 */
94 		if ((disk_access_ioctl(pdrv_str[pdrv],
95 				DISK_IOCTL_GET_SECTOR_SIZE, &sector_size) == 0) &&
96 			(sector_size == (uint16_t)sector_size)) {
97 			*(uint16_t *)buff = (uint16_t)sector_size;
98 		} else {
99 			ret = RES_ERROR;
100 		}
101 		break;
102 
103 	case GET_BLOCK_SIZE:
104 		if (disk_access_ioctl(pdrv_str[pdrv],
105 				DISK_IOCTL_GET_ERASE_BLOCK_SZ, buff) != 0) {
106 			ret = RES_ERROR;
107 		}
108 		break;
109 
110 	/* Optional IOCTL command used by Zephyr fs_unmount implementation,
111 	 * not called by FATFS
112 	 */
113 	case CTRL_POWER:
114 		if (((*(uint8_t *)buff)) == DISK_IOCTL_POWER_OFF) {
115 			/* Power disk off */
116 			if (disk_access_ioctl(pdrv_str[pdrv],
117 					      DISK_IOCTL_CTRL_DEINIT,
118 					      NULL) != 0) {
119 				ret = RES_ERROR;
120 			}
121 		} else {
122 			/* Power disk on */
123 			if (disk_access_ioctl(pdrv_str[pdrv],
124 					      DISK_IOCTL_CTRL_INIT,
125 					      NULL) != 0) {
126 				ret = STA_NOINIT;
127 			}
128 		}
129 		break;
130 
131 	default:
132 		ret = RES_PARERR;
133 		break;
134 	}
135 	return ret;
136 }
137