1 /*
2  * Copyright (c) 2016 Intel Corporation.
3  * Copyright (c) 2019-2020 Nordic Semiconductor ASA
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <sample_usbd.h>
9 
10 #include <zephyr/kernel.h>
11 #include <zephyr/logging/log.h>
12 #include <zephyr/usb/usb_device.h>
13 #include <zephyr/usb/usbd.h>
14 #include <zephyr/usb/class/usbd_msc.h>
15 #include <zephyr/fs/fs.h>
16 #include <stdio.h>
17 
18 LOG_MODULE_REGISTER(main);
19 
20 #if CONFIG_DISK_DRIVER_FLASH
21 #include <zephyr/storage/flash_map.h>
22 #endif
23 
24 #if CONFIG_FAT_FILESYSTEM_ELM
25 #include <ff.h>
26 #endif
27 
28 #if CONFIG_FILE_SYSTEM_LITTLEFS
29 #include <zephyr/fs/littlefs.h>
30 FS_LITTLEFS_DECLARE_DEFAULT_CONFIG(storage);
31 #endif
32 
33 #if !defined(CONFIG_DISK_DRIVER_FLASH) && \
34 	!defined(CONFIG_DISK_DRIVER_RAM) && \
35 	!defined(CONFIG_DISK_DRIVER_SDMMC)
36 #error No supported disk driver enabled
37 #endif
38 
39 #define STORAGE_PARTITION		storage_partition
40 #define STORAGE_PARTITION_ID		FIXED_PARTITION_ID(STORAGE_PARTITION)
41 
42 static struct fs_mount_t fs_mnt;
43 
44 #if defined(CONFIG_USB_DEVICE_STACK_NEXT)
45 static struct usbd_context *sample_usbd;
46 
47 #if CONFIG_DISK_DRIVER_RAM
48 USBD_DEFINE_MSC_LUN(ram, "RAM", "Zephyr", "RAMDisk", "0.00");
49 #endif
50 
51 #if CONFIG_DISK_DRIVER_FLASH
52 USBD_DEFINE_MSC_LUN(nand, "NAND", "Zephyr", "FlashDisk", "0.00");
53 #endif
54 
55 #if CONFIG_DISK_DRIVER_SDMMC
56 USBD_DEFINE_MSC_LUN(sd, "SD", "Zephyr", "SD", "0.00");
57 #endif
58 
enable_usb_device_next(void)59 static int enable_usb_device_next(void)
60 {
61 	int err;
62 
63 	sample_usbd = sample_usbd_init_device(NULL);
64 	if (sample_usbd == NULL) {
65 		LOG_ERR("Failed to initialize USB device");
66 		return -ENODEV;
67 	}
68 
69 	err = usbd_enable(sample_usbd);
70 	if (err) {
71 		LOG_ERR("Failed to enable device support");
72 		return err;
73 	}
74 
75 	LOG_DBG("USB device support enabled");
76 
77 	return 0;
78 }
79 #endif /* defined(CONFIG_USB_DEVICE_STACK_NEXT) */
80 
setup_flash(struct fs_mount_t * mnt)81 static int setup_flash(struct fs_mount_t *mnt)
82 {
83 	int rc = 0;
84 #if CONFIG_DISK_DRIVER_FLASH
85 	unsigned int id;
86 	const struct flash_area *pfa;
87 
88 	mnt->storage_dev = (void *)STORAGE_PARTITION_ID;
89 	id = STORAGE_PARTITION_ID;
90 
91 	rc = flash_area_open(id, &pfa);
92 	printk("Area %u at 0x%x on %s for %u bytes\n",
93 	       id, (unsigned int)pfa->fa_off, pfa->fa_dev->name,
94 	       (unsigned int)pfa->fa_size);
95 
96 	if (rc < 0 && IS_ENABLED(CONFIG_APP_WIPE_STORAGE)) {
97 		printk("Erasing flash area ... ");
98 		rc = flash_area_flatten(pfa, 0, pfa->fa_size);
99 		printk("%d\n", rc);
100 	}
101 
102 	if (rc < 0) {
103 		flash_area_close(pfa);
104 	}
105 #endif
106 	return rc;
107 }
108 
mount_app_fs(struct fs_mount_t * mnt)109 static int mount_app_fs(struct fs_mount_t *mnt)
110 {
111 	int rc;
112 
113 #if CONFIG_FAT_FILESYSTEM_ELM
114 	static FATFS fat_fs;
115 
116 	mnt->type = FS_FATFS;
117 	mnt->fs_data = &fat_fs;
118 	if (IS_ENABLED(CONFIG_DISK_DRIVER_RAM)) {
119 		mnt->mnt_point = "/RAM:";
120 	} else if (IS_ENABLED(CONFIG_DISK_DRIVER_SDMMC)) {
121 		mnt->mnt_point = "/SD:";
122 	} else {
123 		mnt->mnt_point = "/NAND:";
124 	}
125 
126 #elif CONFIG_FILE_SYSTEM_LITTLEFS
127 	mnt->type = FS_LITTLEFS;
128 	mnt->mnt_point = "/lfs";
129 	mnt->fs_data = &storage;
130 #endif
131 	rc = fs_mount(mnt);
132 
133 	return rc;
134 }
135 
setup_disk(void)136 static void setup_disk(void)
137 {
138 	struct fs_mount_t *mp = &fs_mnt;
139 	struct fs_dir_t dir;
140 	struct fs_statvfs sbuf;
141 	int rc;
142 
143 	fs_dir_t_init(&dir);
144 
145 	if (IS_ENABLED(CONFIG_DISK_DRIVER_FLASH)) {
146 		rc = setup_flash(mp);
147 		if (rc < 0) {
148 			LOG_ERR("Failed to setup flash area");
149 			return;
150 		}
151 	}
152 
153 	if (!IS_ENABLED(CONFIG_FILE_SYSTEM_LITTLEFS) &&
154 	    !IS_ENABLED(CONFIG_FAT_FILESYSTEM_ELM)) {
155 		LOG_INF("No file system selected");
156 		return;
157 	}
158 
159 	rc = mount_app_fs(mp);
160 	if (rc < 0) {
161 		LOG_ERR("Failed to mount filesystem");
162 		return;
163 	}
164 
165 	/* Allow log messages to flush to avoid interleaved output */
166 	k_sleep(K_MSEC(50));
167 
168 	printk("Mount %s: %d\n", fs_mnt.mnt_point, rc);
169 
170 	rc = fs_statvfs(mp->mnt_point, &sbuf);
171 	if (rc < 0) {
172 		printk("FAIL: statvfs: %d\n", rc);
173 		return;
174 	}
175 
176 	printk("%s: bsize = %lu ; frsize = %lu ;"
177 	       " blocks = %lu ; bfree = %lu\n",
178 	       mp->mnt_point,
179 	       sbuf.f_bsize, sbuf.f_frsize,
180 	       sbuf.f_blocks, sbuf.f_bfree);
181 
182 	rc = fs_opendir(&dir, mp->mnt_point);
183 	printk("%s opendir: %d\n", mp->mnt_point, rc);
184 
185 	if (rc < 0) {
186 		LOG_ERR("Failed to open directory");
187 	}
188 
189 	while (rc >= 0) {
190 		struct fs_dirent ent = { 0 };
191 
192 		rc = fs_readdir(&dir, &ent);
193 		if (rc < 0) {
194 			LOG_ERR("Failed to read directory entries");
195 			break;
196 		}
197 		if (ent.name[0] == 0) {
198 			printk("End of files\n");
199 			break;
200 		}
201 		printk("  %c %u %s\n",
202 		       (ent.type == FS_DIR_ENTRY_FILE) ? 'F' : 'D',
203 		       ent.size,
204 		       ent.name);
205 	}
206 
207 	(void)fs_closedir(&dir);
208 
209 	return;
210 }
211 
main(void)212 int main(void)
213 {
214 	int ret;
215 
216 	setup_disk();
217 
218 #if defined(CONFIG_USB_DEVICE_STACK_NEXT)
219 	ret = enable_usb_device_next();
220 #else
221 	ret = usb_enable(NULL);
222 #endif
223 	if (ret != 0) {
224 		LOG_ERR("Failed to enable USB");
225 		return 0;
226 	}
227 
228 	LOG_INF("The device is put in USB mass storage mode.\n");
229 	return 0;
230 }
231