| /* | 
 |  * Copyright (c) 2016 Intel Corporation. | 
 |  * Copyright 2024 NXP | 
 |  * | 
 |  * SPDX-License-Identifier: Apache-2.0 | 
 |  */ | 
 |  | 
 | #include <stdio.h> | 
 | #include <string.h> | 
 | #include <zephyr/kernel.h> | 
 | #include <zephyr/types.h> | 
 | #include <errno.h> | 
 | #include <zephyr/init.h> | 
 | #include <zephyr/fs/fs.h> | 
 | #include <zephyr/fs/fs_sys.h> | 
 | #include <zephyr/sys/__assert.h> | 
 | #include <ff.h> | 
 | #include <diskio.h> | 
 | #include <zfs_diskio.h> /* Zephyr specific FatFS API */ | 
 | #include <zephyr/logging/log.h> | 
 | LOG_MODULE_DECLARE(fs, CONFIG_FS_LOG_LEVEL); | 
 |  | 
 | #define FATFS_MAX_FILE_NAME 12 /* Uses 8.3 SFN */ | 
 |  | 
 | /* Memory pool for FatFs directory objects */ | 
 | K_MEM_SLAB_DEFINE(fatfs_dirp_pool, sizeof(DIR), | 
 | 			CONFIG_FS_FATFS_NUM_DIRS, 4); | 
 |  | 
 | /* Memory pool for FatFs file objects */ | 
 | K_MEM_SLAB_DEFINE(fatfs_filep_pool, sizeof(FIL), | 
 | 			CONFIG_FS_FATFS_NUM_FILES, 4); | 
 |  | 
 | static int translate_error(int error) | 
 | { | 
 | 	switch (error) { | 
 | 	case FR_OK: | 
 | 		return 0; | 
 | 	case FR_NO_FILE: | 
 | 	case FR_NO_PATH: | 
 | 	case FR_INVALID_NAME: | 
 | 		return -ENOENT; | 
 | 	case FR_DENIED: | 
 | 		return -EACCES; | 
 | 	case FR_EXIST: | 
 | 		return -EEXIST; | 
 | 	case FR_INVALID_OBJECT: | 
 | 		return -EBADF; | 
 | 	case FR_WRITE_PROTECTED: | 
 | 		return -EROFS; | 
 | 	case FR_INVALID_DRIVE: | 
 | 	case FR_NOT_ENABLED: | 
 | 	case FR_NO_FILESYSTEM: | 
 | 		return -ENODEV; | 
 | 	case FR_NOT_ENOUGH_CORE: | 
 | 		return -ENOMEM; | 
 | 	case FR_TOO_MANY_OPEN_FILES: | 
 | 		return -EMFILE; | 
 | 	case FR_INVALID_PARAMETER: | 
 | 		return -EINVAL; | 
 | 	case FR_LOCKED: | 
 | 	case FR_TIMEOUT: | 
 | 	case FR_MKFS_ABORTED: | 
 | 	case FR_DISK_ERR: | 
 | 	case FR_INT_ERR: | 
 | 	case FR_NOT_READY: | 
 | 		return -EIO; | 
 | 	} | 
 |  | 
 | 	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. | 
 |  */ | 
 | static const char *translate_path(const char *path) | 
 | { | 
 | 	/* this is guaranteed by the fs subsystem */ | 
 | 	__ASSERT_NO_MSG(path[0] == '/'); | 
 |  | 
 | 	return &path[1]; | 
 | } | 
 |  | 
 | static uint8_t translate_flags(fs_mode_t flags) | 
 | { | 
 | 	uint8_t fat_mode = 0; | 
 |  | 
 | 	fat_mode |= (flags & FS_O_READ) ? FA_READ : 0; | 
 | 	fat_mode |= (flags & FS_O_WRITE) ? FA_WRITE : 0; | 
 | 	fat_mode |= (flags & FS_O_CREATE) ? FA_OPEN_ALWAYS : 0; | 
 | 	/* NOTE: FA_APPEND is not translated because FAT FS does not | 
 | 	 * support append semantics of the Zephyr, where file position | 
 | 	 * is forwarded to the end before each write, the fatfs_write | 
 | 	 * will be tasked with setting a file position to the end, | 
 | 	 * if FA_APPEND flag is present. | 
 | 	 */ | 
 |  | 
 | 	return fat_mode; | 
 | } | 
 |  | 
 | static int fatfs_open(struct fs_file_t *zfp, const char *file_name, | 
 | 		      fs_mode_t mode) | 
 | { | 
 | 	FRESULT res; | 
 | 	uint8_t fs_mode; | 
 | 	void *ptr; | 
 |  | 
 | 	if (k_mem_slab_alloc(&fatfs_filep_pool, &ptr, K_NO_WAIT) == 0) { | 
 | 		(void)memset(ptr, 0, sizeof(FIL)); | 
 | 		zfp->filep = ptr; | 
 | 	} else { | 
 | 		return -ENOMEM; | 
 | 	} | 
 |  | 
 | 	fs_mode = translate_flags(mode); | 
 |  | 
 | 	res = f_open(zfp->filep, translate_path(file_name), fs_mode); | 
 |  | 
 | 	if (res != FR_OK) { | 
 | 		k_mem_slab_free(&fatfs_filep_pool, ptr); | 
 | 		zfp->filep = NULL; | 
 | 	} | 
 |  | 
 | 	return translate_error(res); | 
 | } | 
 |  | 
 | static int fatfs_close(struct fs_file_t *zfp) | 
 | { | 
 | 	FRESULT res; | 
 |  | 
 | 	res = f_close(zfp->filep); | 
 |  | 
 | 	/* Free file ptr memory */ | 
 | 	k_mem_slab_free(&fatfs_filep_pool, zfp->filep); | 
 | 	zfp->filep = NULL; | 
 |  | 
 | 	return translate_error(res); | 
 | } | 
 |  | 
 | static int fatfs_unlink(struct fs_mount_t *mountp, const char *path) | 
 | { | 
 | 	int res = -ENOTSUP; | 
 |  | 
 | #if !defined(CONFIG_FS_FATFS_READ_ONLY) | 
 | 	res = f_unlink(translate_path(path)); | 
 |  | 
 | 	res = translate_error(res); | 
 | #endif | 
 |  | 
 | 	return res; | 
 | } | 
 |  | 
 | static int fatfs_rename(struct fs_mount_t *mountp, const char *from, | 
 | 			const char *to) | 
 | { | 
 | 	int res = -ENOTSUP; | 
 |  | 
 | #if !defined(CONFIG_FS_FATFS_READ_ONLY) | 
 | 	FILINFO fno; | 
 |  | 
 | 	/* Check if 'to' path exists; remove it if it does */ | 
 | 	res = f_stat(translate_path(to), &fno); | 
 | 	if (res == FR_OK) { | 
 | 		res = f_unlink(translate_path(to)); | 
 | 		if (res != FR_OK) { | 
 | 			return translate_error(res); | 
 | 		} | 
 | 	} | 
 |  | 
 | 	res = f_rename(translate_path(from), translate_path(to)); | 
 | 	res = translate_error(res); | 
 | #endif | 
 |  | 
 | 	return res; | 
 | } | 
 |  | 
 | static ssize_t fatfs_read(struct fs_file_t *zfp, void *ptr, size_t size) | 
 | { | 
 | 	FRESULT res; | 
 | 	unsigned int br; | 
 |  | 
 | 	res = f_read(zfp->filep, ptr, size, &br); | 
 | 	if (res != FR_OK) { | 
 | 		return translate_error(res); | 
 | 	} | 
 |  | 
 | 	return br; | 
 | } | 
 |  | 
 | static ssize_t fatfs_write(struct fs_file_t *zfp, const void *ptr, size_t size) | 
 | { | 
 | 	int res = -ENOTSUP; | 
 |  | 
 | #if !defined(CONFIG_FS_FATFS_READ_ONLY) | 
 | 	unsigned int bw; | 
 | 	off_t pos = f_size((FIL *)zfp->filep); | 
 | 	res = FR_OK; | 
 |  | 
 | 	/* FA_APPEND flag means that file has been opened for append. | 
 | 	 * The FAT FS write does not support the POSIX append semantics, | 
 | 	 * to always write at the end of file, so set file position | 
 | 	 * at the end before each write if FA_APPEND is set. | 
 | 	 */ | 
 | 	if (zfp->flags & FS_O_APPEND) { | 
 | 		res = f_lseek(zfp->filep, pos); | 
 | 	} | 
 |  | 
 | 	if (res == FR_OK) { | 
 | 		res = f_write(zfp->filep, ptr, size, &bw); | 
 | 	} | 
 |  | 
 | 	if (res != FR_OK) { | 
 | 		res = translate_error(res); | 
 | 	} else { | 
 | 		res = bw; | 
 | 	} | 
 | #endif | 
 |  | 
 | 	return res; | 
 | } | 
 |  | 
 | static int fatfs_seek(struct fs_file_t *zfp, off_t offset, int whence) | 
 | { | 
 | 	FRESULT res = FR_OK; | 
 | 	off_t pos; | 
 |  | 
 | 	switch (whence) { | 
 | 	case FS_SEEK_SET: | 
 | 		pos = offset; | 
 | 		break; | 
 | 	case FS_SEEK_CUR: | 
 | 		pos = f_tell((FIL *)zfp->filep) + offset; | 
 | 		break; | 
 | 	case FS_SEEK_END: | 
 | 		pos = f_size((FIL *)zfp->filep) + offset; | 
 | 		break; | 
 | 	default: | 
 | 		return -EINVAL; | 
 | 	} | 
 |  | 
 | 	if ((pos < 0) || (pos > f_size((FIL *)zfp->filep))) { | 
 | 		return -EINVAL; | 
 | 	} | 
 |  | 
 | 	res = f_lseek(zfp->filep, pos); | 
 |  | 
 | 	return translate_error(res); | 
 | } | 
 |  | 
 | static off_t fatfs_tell(struct fs_file_t *zfp) | 
 | { | 
 | 	return f_tell((FIL *)zfp->filep); | 
 | } | 
 |  | 
 | static int fatfs_truncate(struct fs_file_t *zfp, off_t length) | 
 | { | 
 | 	int res = -ENOTSUP; | 
 |  | 
 | #if !defined(CONFIG_FS_FATFS_READ_ONLY) | 
 | 	off_t cur_length = f_size((FIL *)zfp->filep); | 
 |  | 
 | 	/* f_lseek expands file if new position is larger than file size */ | 
 | 	res = f_lseek(zfp->filep, length); | 
 | 	if (res != FR_OK) { | 
 | 		return translate_error(res); | 
 | 	} | 
 |  | 
 | 	if (length < cur_length) { | 
 | 		res = f_truncate(zfp->filep); | 
 | 	} else { | 
 | 		/* | 
 | 		 * Get actual length after expansion. This could be | 
 | 		 * less if there was not enough space in the volume | 
 | 		 * to expand to the requested length | 
 | 		 */ | 
 | 		length = f_tell((FIL *)zfp->filep); | 
 |  | 
 | 		res = f_lseek(zfp->filep, cur_length); | 
 | 		if (res != FR_OK) { | 
 | 			return translate_error(res); | 
 | 		} | 
 |  | 
 | 		/* | 
 | 		 * The FS module does caching and optimization of | 
 | 		 * writes. Here we write 1 byte at a time to avoid | 
 | 		 * using additional code and memory for doing any | 
 | 		 * optimization. | 
 | 		 */ | 
 | 		unsigned int bw; | 
 | 		uint8_t c = 0U; | 
 |  | 
 | 		for (int i = cur_length; i < length; i++) { | 
 | 			res = f_write(zfp->filep, &c, 1, &bw); | 
 | 			if (res != FR_OK) { | 
 | 				break; | 
 | 			} | 
 | 		} | 
 | 	} | 
 |  | 
 | 	res = translate_error(res); | 
 | #endif | 
 |  | 
 | 	return res; | 
 | } | 
 |  | 
 | static int fatfs_sync(struct fs_file_t *zfp) | 
 | { | 
 | 	int res = -ENOTSUP; | 
 |  | 
 | #if !defined(CONFIG_FS_FATFS_READ_ONLY) | 
 | 	res = f_sync(zfp->filep); | 
 | 	res = translate_error(res); | 
 | #endif | 
 | 	return res; | 
 | } | 
 |  | 
 | static int fatfs_mkdir(struct fs_mount_t *mountp, const char *path) | 
 | { | 
 | 	int res = -ENOTSUP; | 
 |  | 
 | #if !defined(CONFIG_FS_FATFS_READ_ONLY) | 
 | 	res = f_mkdir(translate_path(path)); | 
 | 	res = translate_error(res); | 
 | #endif | 
 |  | 
 | 	return res; | 
 | } | 
 |  | 
 | static int fatfs_opendir(struct fs_dir_t *zdp, const char *path) | 
 | { | 
 | 	FRESULT res; | 
 | 	void *ptr; | 
 |  | 
 | 	if (k_mem_slab_alloc(&fatfs_dirp_pool, &ptr, K_NO_WAIT) == 0) { | 
 | 		(void)memset(ptr, 0, sizeof(DIR)); | 
 | 		zdp->dirp = ptr; | 
 | 	} else { | 
 | 		return -ENOMEM; | 
 | 	} | 
 |  | 
 | 	res = f_opendir(zdp->dirp, translate_path(path)); | 
 |  | 
 | 	if (res != FR_OK) { | 
 | 		k_mem_slab_free(&fatfs_dirp_pool, ptr); | 
 | 		zdp->dirp = NULL; | 
 | 	} | 
 |  | 
 | 	return translate_error(res); | 
 | } | 
 |  | 
 | static int fatfs_readdir(struct fs_dir_t *zdp, struct fs_dirent *entry) | 
 | { | 
 | 	FRESULT res; | 
 | 	FILINFO fno; | 
 |  | 
 | 	res = f_readdir(zdp->dirp, &fno); | 
 | 	if (res == FR_OK) { | 
 | 		strcpy(entry->name, fno.fname); | 
 | 		if (entry->name[0] != 0) { | 
 | 			entry->type = ((fno.fattrib & AM_DIR) ? | 
 | 			       FS_DIR_ENTRY_DIR : FS_DIR_ENTRY_FILE); | 
 | 			entry->size = fno.fsize; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	return translate_error(res); | 
 | } | 
 |  | 
 | static int fatfs_closedir(struct fs_dir_t *zdp) | 
 | { | 
 | 	FRESULT res; | 
 |  | 
 | 	res = f_closedir(zdp->dirp); | 
 |  | 
 | 	/* Free file ptr memory */ | 
 | 	k_mem_slab_free(&fatfs_dirp_pool, zdp->dirp); | 
 |  | 
 | 	return translate_error(res); | 
 | } | 
 |  | 
 | static int fatfs_stat(struct fs_mount_t *mountp, | 
 | 		      const char *path, struct fs_dirent *entry) | 
 | { | 
 | 	FRESULT res; | 
 | 	FILINFO fno; | 
 |  | 
 | 	res = f_stat(translate_path(path), &fno); | 
 | 	if (res == FR_OK) { | 
 | 		entry->type = ((fno.fattrib & AM_DIR) ? | 
 | 			       FS_DIR_ENTRY_DIR : FS_DIR_ENTRY_FILE); | 
 | 		strcpy(entry->name, fno.fname); | 
 | 		entry->size = fno.fsize; | 
 | 	} | 
 |  | 
 | 	return translate_error(res); | 
 | } | 
 |  | 
 | static int fatfs_statvfs(struct fs_mount_t *mountp, | 
 | 			 const char *path, struct fs_statvfs *stat) | 
 | { | 
 | 	int res = -ENOTSUP; | 
 | #if !defined(CONFIG_FS_FATFS_READ_ONLY) | 
 | 	FATFS *fs; | 
 | 	DWORD f_bfree = 0; | 
 |  | 
 | 	res = f_getfree(translate_path(mountp->mnt_point), &f_bfree, &fs); | 
 | 	if (res != FR_OK) { | 
 | 		return -EIO; | 
 | 	} | 
 |  | 
 | 	stat->f_bfree = f_bfree; | 
 |  | 
 | 	/* | 
 | 	 * If FF_MIN_SS and FF_MAX_SS differ, variable sector size support is | 
 | 	 * enabled and the file system object structure contains the actual sector | 
 | 	 * size, otherwise it is configured to a fixed value give by FF_MIN_SS. | 
 | 	 */ | 
 | #if FF_MAX_SS != FF_MIN_SS | 
 | 	stat->f_bsize = fs->ssize; | 
 | #else | 
 | 	stat->f_bsize = FF_MIN_SS; | 
 | #endif | 
 | 	stat->f_frsize = fs->csize * stat->f_bsize; | 
 | 	stat->f_blocks = (fs->n_fatent - 2); | 
 |  | 
 | 	res = translate_error(res); | 
 | #endif | 
 | 	return res; | 
 | } | 
 |  | 
 | static int fatfs_mount(struct fs_mount_t *mountp) | 
 | { | 
 | 	FRESULT res; | 
 |  | 
 | 	res = f_mount((FATFS *)mountp->fs_data, translate_path(mountp->mnt_point), 1); | 
 |  | 
 | #if defined(CONFIG_FS_FATFS_MOUNT_MKFS) | 
 | 	if (res == FR_NO_FILESYSTEM && | 
 | 	    (mountp->flags & FS_MOUNT_FLAG_READ_ONLY) != 0) { | 
 | 		return -EROFS; | 
 | 	} | 
 | 	/* If no file system found then create one */ | 
 | 	if (res == FR_NO_FILESYSTEM && | 
 | 	    (mountp->flags & FS_MOUNT_FLAG_NO_FORMAT) == 0) { | 
 | 		uint8_t work[FF_MAX_SS]; | 
 | 		MKFS_PARM mkfs_opt = { | 
 | 			.fmt = FM_ANY | FM_SFD,	/* Any suitable FAT */ | 
 | 			.n_fat = 1,		/* One FAT fs table */ | 
 | 			.align = 0,		/* Get sector size via diskio query */ | 
 | 			.n_root = CONFIG_FS_FATFS_MAX_ROOT_ENTRIES, | 
 | 			.au_size = 0		/* Auto calculate cluster size */ | 
 | 		}; | 
 |  | 
 | 		res = f_mkfs(translate_path(mountp->mnt_point), &mkfs_opt, work, sizeof(work)); | 
 | 		if (res == FR_OK) { | 
 | 			res = f_mount((FATFS *)mountp->fs_data, | 
 | 					translate_path(mountp->mnt_point), 1); | 
 | 		} | 
 | 	} | 
 | #endif /* CONFIG_FS_FATFS_MOUNT_MKFS */ | 
 |  | 
 | 	if (res == FR_OK) { | 
 | 		mountp->flags |= FS_MOUNT_FLAG_USE_DISK_ACCESS; | 
 | 	} | 
 |  | 
 | 	return translate_error(res); | 
 |  | 
 | } | 
 |  | 
 | 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); | 
 | 	} | 
 |  | 
 | 	/* 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) | 
 |  | 
 | static MKFS_PARM def_cfg = { | 
 | 	.fmt = FM_ANY | FM_SFD,	/* Any suitable FAT */ | 
 | 	.n_fat = 1,		/* One FAT fs table */ | 
 | 	.align = 0,		/* Get sector size via diskio query */ | 
 | 	.n_root = CONFIG_FS_FATFS_MAX_ROOT_ENTRIES, | 
 | 	.au_size = 0		/* Auto calculate cluster size */ | 
 | }; | 
 |  | 
 | static int fatfs_mkfs(uintptr_t dev_id, void *cfg, int flags) | 
 | { | 
 | 	FRESULT res; | 
 | 	uint8_t work[FF_MAX_SS]; | 
 | 	MKFS_PARM *mkfs_opt = &def_cfg; | 
 |  | 
 | 	if (cfg != NULL) { | 
 | 		mkfs_opt = (MKFS_PARM *)cfg; | 
 | 	} | 
 |  | 
 | 	res = f_mkfs((char *)dev_id, mkfs_opt, work, sizeof(work)); | 
 |  | 
 | 	return translate_error(res); | 
 | } | 
 |  | 
 | #endif /* CONFIG_FILE_SYSTEM_MKFS && FS_FATFS_MKFS */ | 
 |  | 
 | /* File system interface */ | 
 | static const struct fs_file_system_t fatfs_fs = { | 
 | 	.open = fatfs_open, | 
 | 	.close = fatfs_close, | 
 | 	.read = fatfs_read, | 
 | 	.write = fatfs_write, | 
 | 	.lseek = fatfs_seek, | 
 | 	.tell = fatfs_tell, | 
 | 	.truncate = fatfs_truncate, | 
 | 	.sync = fatfs_sync, | 
 | 	.opendir = fatfs_opendir, | 
 | 	.readdir = fatfs_readdir, | 
 | 	.closedir = fatfs_closedir, | 
 | 	.mount = fatfs_mount, | 
 | 	.unmount = fatfs_unmount, | 
 | 	.unlink = fatfs_unlink, | 
 | 	.rename = fatfs_rename, | 
 | 	.mkdir = fatfs_mkdir, | 
 | 	.stat = fatfs_stat, | 
 | 	.statvfs = fatfs_statvfs, | 
 | #if defined(CONFIG_FILE_SYSTEM_MKFS) && defined(CONFIG_FS_FATFS_MKFS) | 
 | 	.mkfs = fatfs_mkfs, | 
 | #endif | 
 | }; | 
 |  | 
 | #define DT_DRV_COMPAT zephyr_fstab_fatfs | 
 |  | 
 | #define DEFINE_FS(inst)                                                                            \ | 
 | 	BUILD_ASSERT(DT_INST_PROP(inst, disk_access), "FATFS needs disk-access");                  \ | 
 | 	BUILD_ASSERT(!DT_INST_PROP(inst, read_only),                                               \ | 
 | 		     "READ_ONLY not supported for individual instances see FS_FATFS_READ_ONLY");   \ | 
 | 	BUILD_ASSERT(!DT_INST_PROP(inst, no_format),                                               \ | 
 | 		     "NO_FORMAT not supported for individual instanzes FS_FATFS_MKFS");            \ | 
 | 	static FATFS fs_data_##inst;                                                               \ | 
 | 	struct fs_mount_t FS_FSTAB_ENTRY(DT_DRV_INST(inst)) = {                                    \ | 
 | 		.type = FS_FATFS,                                                                  \ | 
 | 		.mnt_point = FSTAB_ENTRY_DT_INST_MOUNT_POINT(inst),                                \ | 
 | 		.fs_data = &fs_data_##inst,                                                        \ | 
 | 		.storage_dev = NULL,                                                               \ | 
 | 		.flags = FSTAB_ENTRY_DT_MOUNT_FLAGS(DT_DRV_INST(inst)),                            \ | 
 | 	}; | 
 |  | 
 | DT_INST_FOREACH_STATUS_OKAY(DEFINE_FS); | 
 |  | 
 | #ifdef CONFIG_FS_FATFS_FSTAB_AUTOMOUNT | 
 | #define REFERENCE_MOUNT(inst) (&FS_FSTAB_ENTRY(DT_DRV_INST(inst))), | 
 |  | 
 | static void automount_if_enabled(struct fs_mount_t *mountp) | 
 | { | 
 | 	int ret = 0; | 
 |  | 
 | 	if ((mountp->flags & FS_MOUNT_FLAG_AUTOMOUNT) != 0) { | 
 | 		ret = fs_mount(mountp); | 
 | 		if (ret < 0) { | 
 | 			LOG_ERR("Error mounting filesystem: at %s: %d", mountp->mnt_point, ret); | 
 | 		} else { | 
 | 			LOG_DBG("FATFS Filesystem \"%s\" initialized", mountp->mnt_point); | 
 | 		} | 
 | 	} | 
 | } | 
 | #endif /* CONFIG_FS_FATFS_FSTAB_AUTOMOUNT */ | 
 |  | 
 | #if CONFIG_FS_FATFS_CUSTOM_MOUNT_POINT_COUNT | 
 | const char *VolumeStr[CONFIG_FS_FATFS_CUSTOM_MOUNT_POINT_COUNT]; | 
 | #endif /* CONFIG_FS_FATFS_CUSTOM_MOUNT_POINT_COUNT */ | 
 |  | 
 | static int fatfs_init(void) | 
 | { | 
 | #if CONFIG_FS_FATFS_CUSTOM_MOUNT_POINT_COUNT | 
 | 	static char mount_points[] = CONFIG_FS_FATFS_CUSTOM_MOUNT_POINTS; | 
 | 	int mount_point_count = 0; | 
 |  | 
 | 	VolumeStr[0] = mount_points; | 
 | 	for (int i = 0; i < ARRAY_SIZE(mount_points) - 1; i++) { | 
 | 		if (mount_points[i] == ',') { | 
 | 			mount_points[i] = 0; | 
 | 			mount_point_count++; | 
 | 			if (mount_point_count >= ARRAY_SIZE(VolumeStr)) { | 
 | 				LOG_ERR("Mount point count not sufficient for defined mount " | 
 | 					"points."); | 
 | 				return -1; | 
 | 			} | 
 | 			VolumeStr[mount_point_count] = &mount_points[i + 1]; | 
 | 		} | 
 | 	} | 
 | #endif /* CONFIG_FS_FATFS_CUSTOM_MOUNT_POINT_COUNT */ | 
 | 	int rc = fs_register(FS_FATFS, &fatfs_fs); | 
 |  | 
 | #ifdef CONFIG_FS_FATFS_FSTAB_AUTOMOUNT | 
 | 	if (rc == 0) { | 
 | 		struct fs_mount_t *partitions[] = {DT_INST_FOREACH_STATUS_OKAY(REFERENCE_MOUNT)}; | 
 |  | 
 | 		for (size_t i = 0; i < ARRAY_SIZE(partitions); i++) { | 
 | 			struct fs_mount_t *mpi = partitions[i]; | 
 |  | 
 | 			automount_if_enabled(mpi); | 
 | 		} | 
 | 	} | 
 | #endif /* CONFIG_FS_FATFS_FSTAB_AUTOMOUNT */ | 
 |  | 
 | 	return rc; | 
 | } | 
 |  | 
 | SYS_INIT(fatfs_init, POST_KERNEL, CONFIG_FILE_SYSTEM_INIT_PRIORITY); |