1 /*
2  * Copyright (c) 2018-2019 Jan Van Winkel <jan.van_winkel@dxplore.eu>
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <lvgl.h>
8 #include <zephyr/kernel.h>
9 #include <zephyr/fs/fs.h>
10 #include <stdlib.h>
11 #include "lvgl_fs.h"
12 
lvgl_fs_ready(struct _lv_fs_drv_t * drv)13 static bool lvgl_fs_ready(struct _lv_fs_drv_t *drv)
14 {
15 	return true;
16 }
17 
errno_to_lv_fs_res(int err)18 static lv_fs_res_t errno_to_lv_fs_res(int err)
19 {
20 	switch (err) {
21 	case 0:
22 		return LV_FS_RES_OK;
23 	case -EIO:
24 		/*Low level hardware error*/
25 		return LV_FS_RES_HW_ERR;
26 	case -EBADF:
27 		/*Error in the file system structure */
28 		return LV_FS_RES_FS_ERR;
29 	case -ENOENT:
30 		/*Driver, file or directory is not exists*/
31 		return LV_FS_RES_NOT_EX;
32 	case -EFBIG:
33 		/*Disk full*/
34 		return LV_FS_RES_FULL;
35 	case -EACCES:
36 		/*Access denied. Check 'fs_open' modes and write protect*/
37 		return LV_FS_RES_DENIED;
38 	case -EBUSY:
39 		/*The file system now can't handle it, try later*/
40 		return LV_FS_RES_BUSY;
41 	case -ENOMEM:
42 		/*Not enough memory for an internal operation*/
43 		return LV_FS_RES_OUT_OF_MEM;
44 	case -EINVAL:
45 		/*Invalid parameter among arguments*/
46 		return LV_FS_RES_INV_PARAM;
47 	default:
48 		return LV_FS_RES_UNKNOWN;
49 	}
50 }
51 
lvgl_fs_open(struct _lv_fs_drv_t * drv,const char * path,lv_fs_mode_t mode)52 static void *lvgl_fs_open(struct _lv_fs_drv_t *drv, const char *path,
53 			  lv_fs_mode_t mode)
54 {
55 	int err;
56 	int zmode = FS_O_CREATE;
57 	void *file;
58 
59 	/* LVGL is passing absolute paths without the root slash add it back
60 	 * by decrementing the path pointer.
61 	 */
62 	path--;
63 
64 	zmode |= (mode & LV_FS_MODE_WR) ? FS_O_WRITE : 0;
65 	zmode |= (mode & LV_FS_MODE_RD) ? FS_O_READ : 0;
66 
67 	file = malloc(sizeof(struct fs_file_t));
68 	if (!file)
69 		return NULL;
70 
71 	fs_file_t_init((struct fs_file_t *)file);
72 
73 	err = fs_open((struct fs_file_t *)file, path, zmode);
74 	if (err)
75 		return NULL;
76 
77 	return file;
78 }
79 
lvgl_fs_close(struct _lv_fs_drv_t * drv,void * file)80 static lv_fs_res_t lvgl_fs_close(struct _lv_fs_drv_t *drv, void *file)
81 {
82 	int err;
83 
84 	err = fs_close((struct fs_file_t *)file);
85 	return errno_to_lv_fs_res(err);
86 }
87 
lvgl_fs_read(struct _lv_fs_drv_t * drv,void * file,void * buf,uint32_t btr,uint32_t * br)88 static lv_fs_res_t lvgl_fs_read(struct _lv_fs_drv_t *drv, void *file,
89 		void *buf, uint32_t btr, uint32_t *br)
90 {
91 	int err;
92 
93 	err = fs_read((struct fs_file_t *)file, buf, btr);
94 	if (err > 0) {
95 		if (br != NULL) {
96 			*br = err;
97 		}
98 		err = 0;
99 	} else if (br != NULL) {
100 		*br = 0U;
101 	}
102 	return errno_to_lv_fs_res(err);
103 }
104 
lvgl_fs_write(struct _lv_fs_drv_t * drv,void * file,const void * buf,uint32_t btw,uint32_t * bw)105 static lv_fs_res_t lvgl_fs_write(struct _lv_fs_drv_t *drv, void *file,
106 		const void *buf, uint32_t btw, uint32_t *bw)
107 {
108 	int err;
109 
110 	err = fs_write((struct fs_file_t *)file, buf, btw);
111 	if (err == btw) {
112 		if (bw != NULL) {
113 			*bw = btw;
114 		}
115 		err = 0;
116 	} else if (err < 0) {
117 		if (bw != NULL) {
118 			*bw = 0U;
119 		}
120 	} else {
121 		if (bw != NULL) {
122 			*bw = err;
123 		}
124 		err = -EFBIG;
125 	}
126 	return errno_to_lv_fs_res(err);
127 }
128 
lvgl_fs_seek(struct _lv_fs_drv_t * drv,void * file,uint32_t pos,lv_fs_whence_t whence)129 static lv_fs_res_t lvgl_fs_seek(struct _lv_fs_drv_t *drv, void *file,
130 				uint32_t pos, lv_fs_whence_t whence)
131 {
132 	int err, fs_whence;
133 
134 	switch (whence) {
135 	case LV_FS_SEEK_END:
136 		fs_whence = FS_SEEK_END;
137 		break;
138 	case LV_FS_SEEK_CUR:
139 		fs_whence = FS_SEEK_CUR;
140 		break;
141 	case LV_FS_SEEK_SET:
142 	default:
143 		fs_whence = FS_SEEK_SET;
144 		break;
145 	}
146 
147 	err = fs_seek((struct fs_file_t *)file, pos, fs_whence);
148 	return errno_to_lv_fs_res(err);
149 }
150 
lvgl_fs_tell(struct _lv_fs_drv_t * drv,void * file,uint32_t * pos_p)151 static lv_fs_res_t lvgl_fs_tell(struct _lv_fs_drv_t *drv, void *file,
152 		uint32_t *pos_p)
153 {
154 	*pos_p = fs_tell((struct fs_file_t *)file);
155 	return LV_FS_RES_OK;
156 }
157 
lvgl_fs_dir_open(struct _lv_fs_drv_t * drv,const char * path)158 static void *lvgl_fs_dir_open(struct _lv_fs_drv_t *drv, const char *path)
159 {
160 	void *dir;
161 	int err;
162 
163 	/* LVGL is passing absolute paths without the root slash add it back
164 	 * by decrementing the path pointer.
165 	 */
166 	path--;
167 
168 	dir = malloc(sizeof(struct fs_dir_t));
169 	if (!dir)
170 		return NULL;
171 
172 	fs_dir_t_init((struct fs_dir_t *)dir);
173 	err = fs_opendir((struct fs_dir_t *)dir, path);
174 	if (err)
175 		return NULL;
176 
177 	return dir;
178 }
179 
lvgl_fs_dir_read(struct _lv_fs_drv_t * drv,void * dir,char * fn)180 static lv_fs_res_t lvgl_fs_dir_read(struct _lv_fs_drv_t *drv, void *dir,
181 		char *fn)
182 {
183 	/* LVGL expects a string as return parameter but the format of the
184 	 * string is not documented.
185 	 */
186 	return LV_FS_RES_NOT_IMP;
187 }
188 
lvgl_fs_dir_close(struct _lv_fs_drv_t * drv,void * dir)189 static lv_fs_res_t lvgl_fs_dir_close(struct _lv_fs_drv_t *drv, void *dir)
190 {
191 	int err;
192 
193 	err = fs_closedir((struct fs_dir_t *)dir);
194 	free(dir);
195 	return errno_to_lv_fs_res(err);
196 }
197 
198 static lv_fs_drv_t fs_drv;
199 
lvgl_fs_init(void)200 void lvgl_fs_init(void)
201 {
202 	lv_fs_drv_init(&fs_drv);
203 
204 	/* LVGL uses letter based mount points, just pass the root slash as a
205 	 * letter. Note that LVGL will remove the drive letter, or in this case
206 	 * the root slash, from the path passed via the FS callbacks.
207 	 * Zephyr FS API assumes this slash is present so we will need to add
208 	 * it back.
209 	 */
210 	fs_drv.letter = '/';
211 	fs_drv.ready_cb = lvgl_fs_ready;
212 
213 	fs_drv.open_cb = lvgl_fs_open;
214 	fs_drv.close_cb = lvgl_fs_close;
215 	fs_drv.read_cb = lvgl_fs_read;
216 	fs_drv.write_cb = lvgl_fs_write;
217 	fs_drv.seek_cb = lvgl_fs_seek;
218 	fs_drv.tell_cb = lvgl_fs_tell;
219 
220 	fs_drv.dir_open_cb = lvgl_fs_dir_open;
221 	fs_drv.dir_read_cb = lvgl_fs_dir_read;
222 	fs_drv.dir_close_cb = lvgl_fs_dir_close;
223 
224 	lv_fs_drv_register(&fs_drv);
225 }
226