1 /*
2  * Copyright (c) 2017 Linaro Limited
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <stdlib.h>
7 #include <string.h>
8 
9 #include <zephyr.h>
10 #include <sys/printk.h>
11 #include <logging/log.h>
12 #include <shell/shell.h>
13 #include <drivers/flash.h>
14 #include <device.h>
15 #include <soc.h>
16 #include <stdlib.h>
17 
18 LOG_MODULE_REGISTER(app);
19 
20 #define PR_SHELL(shell, fmt, ...)				\
21 	shell_fprintf(shell, SHELL_NORMAL, fmt, ##__VA_ARGS__)
22 #define PR_ERROR(shell, fmt, ...)				\
23 	shell_fprintf(shell, SHELL_ERROR, fmt, ##__VA_ARGS__)
24 #define PR_INFO(shell, fmt, ...)				\
25 	shell_fprintf(shell, SHELL_INFO, fmt, ##__VA_ARGS__)
26 #define PR_WARNING(shell, fmt, ...)				\
27 	shell_fprintf(shell, SHELL_WARNING, fmt, ##__VA_ARGS__)
28 /*
29  * When DT_CHOSEN_ZEPHYR_FLASH_CONTROLLER_LABEL is available, we use it here.
30  * Otherwise the device can be set at runtime with the set_device command.
31  */
32 #ifndef DT_CHOSEN_ZEPHYR_FLASH_CONTROLLER_LABEL
33 #define DT_CHOSEN_ZEPHYR_FLASH_CONTROLLER_LABEL ""
34 #endif
35 
36 /* Command usage info. */
37 #define WRITE_BLOCK_SIZE_HELP \
38 	("Print the device's write block size. This is the smallest amount" \
39 	 " of data which may be written to the device, in bytes.")
40 #define READ_HELP \
41 	("<off> <len>\n" \
42 	 "Read <len> bytes from device offset <off>.")
43 #define ERASE_HELP \
44 	("<off> <len>\n\n" \
45 	 "Erase <len> bytes from device offset <off>, " \
46 	 "subject to hardware page limitations.")
47 #define WRITE_HELP \
48 	("<off> <byte1> [... byteN]\n\n" \
49 	 "Write given bytes, starting at device offset <off>.\n" \
50 	 "Pages must be erased before they can be written.")
51 #define WRITE_UNALIGNED_HELP \
52 	("<off> <byte1> [... byteN]\n\n" \
53 	 "Write given bytes, starting at device offset <off>.\n" \
54 	 "Being unaligned, affected memory areas are backed up, erased, protected" \
55 	 " and then overwritten.\n" \
56 	 "This command is designed to test writing to large flash pages.")
57 #define WRITE_PATTERN_HELP \
58 	("<off> <len>\n\n" \
59 	 "Writes a pattern of (0x00 0x01 .. 0xFF 0x00 ..) of length" \
60 	 "<len> at the offset <off>.\n" \
61 	 "Unaligned writing is used, i.e. protection and erasing are automated." \
62 	 "This command is designed to test writing to large flash pages.")
63 #ifdef CONFIG_FLASH_PAGE_LAYOUT
64 #define PAGE_COUNT_HELP \
65 	"\n\nPrint the number of pages on the flash device."
66 #define PAGE_LAYOUT_HELP \
67 	("[start_page] [end_page]\n\n" \
68 	 "Print layout of flash pages in the range [start_page, end_page],"   \
69 	 " which is inclusive. By default, all pages are printed.")
70 #define PAGE_READ_HELP \
71 	("<page> <len> OR <page> <off> <len>\n\n" \
72 	 "Read <len> bytes from given page, starting at page offset <off>," \
73 	  "or offset 0 if not given. No checks are made that bytes read are" \
74 	 " all within the page.")
75 #define PAGE_ERASE_HELP \
76 	("<page> [num]\n\n" \
77 	 "Erase [num] pages (default 1), starting at page <page>.")
78 #define PAGE_WRITE_HELP \
79 	("<page> <off> <byte1> [... byteN]\n\n" \
80 	 "Write given bytes to given page, starting at page offset <off>." \
81 	 " No checks are made that the bytes all fall within the page." \
82 	 " Pages must be erased before they can be written.")
83 #endif
84 #define SET_DEV_HELP \
85 	("<device_name>\n\n" \
86 	 "Set flash device by name. If a flash device was not found," \
87 	 " this command must be run first to bind a device to this module.")
88 
89 #if (CONFIG_SHELL_ARGC_MAX > 4)
90 #define ARGC_MAX (CONFIG_SHELL_ARGC_MAX - 4)
91 #else
92 #error Please increase CONFIG_SHELL_ARGC_MAX parameter.
93 #endif
94 
95 static const struct device *flash_device;
96 
check_flash_device(const struct shell * shell)97 static int check_flash_device(const struct shell *shell)
98 {
99 	if (flash_device == NULL) {
100 		PR_ERROR(shell, "Flash device is unknown."
101 				" Run set_device first.\n");
102 		return -ENODEV;
103 	}
104 	return 0;
105 }
106 
dump_buffer(const struct shell * shell,uint8_t * buf,size_t size)107 static void dump_buffer(const struct shell *shell, uint8_t *buf, size_t size)
108 {
109 	bool newline = false;
110 	uint8_t *p = buf;
111 
112 	while (size >= 16) {
113 		PR_SHELL(shell, "%02x %02x %02x %02x | %02x %02x %02x %02x |" \
114 		       "%02x %02x %02x %02x | %02x %02x %02x %02x\n",
115 		       p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
116 			   p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
117 		p += 16;
118 		size -= 16;
119 	}
120 	if (size >= 8) {
121 		PR_SHELL(shell, "%02x %02x %02x %02x | %02x %02x %02x %02x\n",
122 		       p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
123 		p += 8;
124 		size -= 8;
125 		newline = true;
126 	}
127 	if (size > 4) {
128 		PR_SHELL(shell, "%02x %02x %02x %02x | ",
129 		       p[0], p[1], p[2], p[3]);
130 		p += 4;
131 		size -= 4;
132 		newline = true;
133 	}
134 	while (size--) {
135 		PR_SHELL(shell, "%02x ", *p++);
136 		newline = true;
137 	}
138 	if (newline) {
139 		PR_SHELL(shell, "\n");
140 	}
141 }
142 
parse_ul(const char * str,unsigned long * result)143 static int parse_ul(const char *str, unsigned long *result)
144 {
145 	char *end;
146 	unsigned long val;
147 
148 	val = strtoul(str, &end, 0);
149 
150 	if (*str == '\0' || *end != '\0') {
151 		return -EINVAL;
152 	}
153 
154 	*result = val;
155 	return 0;
156 }
157 
parse_u8(const char * str,uint8_t * result)158 static int parse_u8(const char *str, uint8_t *result)
159 {
160 	unsigned long val;
161 
162 	if (parse_ul(str, &val) || val > 0xff) {
163 		return -EINVAL;
164 	}
165 	*result = (uint8_t)val;
166 	return 0;
167 }
168 
169 /* Read bytes, dumping contents to console and printing on error. */
do_read(const struct shell * shell,off_t offset,size_t len)170 static int do_read(const struct shell *shell, off_t offset, size_t len)
171 {
172 	uint8_t buf[64];
173 	int ret;
174 
175 	while (len > sizeof(buf)) {
176 		ret = flash_read(flash_device, offset, buf, sizeof(buf));
177 		if (ret) {
178 			goto err_read;
179 		}
180 		dump_buffer(shell, buf, sizeof(buf));
181 		len -= sizeof(buf);
182 		offset += sizeof(buf);
183 	}
184 	ret = flash_read(flash_device, offset, buf, len);
185 	if (ret) {
186 		goto err_read;
187 	}
188 	dump_buffer(shell, buf, len);
189 	return 0;
190 
191  err_read:
192 	PR_ERROR(shell, "flash_read error: %d\n", ret);
193 	return ret;
194 }
195 
196 /* Erase area and printing on error. */
do_erase(const struct shell * shell,off_t offset,size_t size)197 static int do_erase(const struct shell *shell, off_t offset, size_t size)
198 {
199 	int ret;
200 
201 	ret = flash_erase(flash_device, offset, size);
202 	if (ret) {
203 		PR_ERROR(shell, "flash_erase failed (err:%d).\n", ret);
204 		return ret;
205 	}
206 
207 	return ret;
208 }
209 
210 /* Write bytes and printing on error. */
do_write(const struct shell * shell,off_t offset,uint8_t * buf,size_t len,bool read_back)211 static int do_write(const struct shell *shell, off_t offset, uint8_t *buf,
212 		    size_t len, bool read_back)
213 {
214 	int ret;
215 
216 	ret = flash_write(flash_device, offset, buf, len);
217 	if (ret) {
218 		PR_ERROR(shell, "flash_write failed (err:%d).\n", ret);
219 		return ret;
220 	}
221 
222 	if (read_back) {
223 		PR_SHELL(shell, "Reading back written bytes:\n");
224 		ret = do_read(shell, offset, len);
225 	}
226 	return ret;
227 }
228 
do_write_unaligned(const struct shell * shell,off_t offset,uint8_t * buf,size_t len,bool read_back)229 static int do_write_unaligned(const struct shell *shell, off_t offset, uint8_t *buf,
230 		    size_t len, bool read_back)
231 {
232 	int ret = 0;
233 	size_t page_size = flash_get_write_block_size(flash_device);
234 	size_t size_before = offset % page_size;
235 	size_t size_after = page_size - ((size_before + len) % page_size);
236 	size_t aligned_size = size_before + len + size_after;
237 	off_t  start_page = offset - size_before;
238 	off_t  last_page = start_page + aligned_size - page_size;
239 	bool single_page_write = (size_before + len < page_size);
240 
241 	char *before_data;
242 	char *after_data;
243 
244 	if (0 == size_before && 0 == size_after) {
245 		/* Aligned write */
246 		flash_erase(flash_device, offset, len);
247 		flash_write(flash_device, offset, buf, len);
248 
249 		return 0;
250 	}
251 
252 	before_data = k_malloc(page_size);
253 	after_data = k_malloc(page_size);
254 
255 	if (!before_data || !after_data) {
256 		PR_ERROR(shell, "No heap memory for flash manipulation\n");
257 		ret = -ENOMEM;
258 		goto free_buffers;
259 	}
260 
261 	/* Stash useful data from the pages that will be affected. */
262 	if (single_page_write) {
263 		/* Read old data before new data is written. */
264 		if (size_before) {
265 			flash_read(flash_device, start_page, before_data, size_before);
266 		}
267 		/* Fill the with new data. */
268 		memcpy(before_data + size_before, buf, len);
269 		/* Fill the last part of old data. */
270 		if (size_after) {
271 			flash_read(flash_device, offset + len,
272 					before_data + size_before + len,
273 					size_after);
274 		}
275 	} else {
276 		/* Multipage write, different start and end pages. */
277 		if (size_before) {
278 			flash_read(flash_device, start_page, before_data,
279 					size_before);
280 			/* Fill the rest with new data. */
281 			memcpy(before_data + size_before, buf,
282 			       page_size - size_before);
283 		}
284 		if (size_after) {
285 			/* Copy ending part of new data. */
286 			memcpy((void *)after_data,
287 			       (void *)(buf + len -
288 				   ((len + size_before) % page_size)),
289 			       page_size - size_after);
290 			/* Copy ending part of flash page. */
291 			flash_read(flash_device, offset + len,
292 					after_data + (page_size - size_after),
293 					size_after);
294 		}
295 	}
296 
297 	/* Erase all the pages that overlap with new data. */
298 	flash_erase(flash_device, start_page, aligned_size);
299 
300 	/* Write stashed and new data. */
301 	if (single_page_write || size_before > 0) {
302 		/* Write first page if available. */
303 		flash_write(flash_device, start_page, before_data,
304 				 page_size);
305 	}
306 	if (!single_page_write) {
307 		size_t middle_data_len = aligned_size;
308 		off_t middle_page_start = start_page;
309 		off_t data_offset = (off_t)buf;
310 
311 		/* Write the middle bit if available */
312 		if (size_before > 0) {
313 			middle_page_start += page_size;
314 			middle_data_len -= page_size;
315 			data_offset += (page_size - size_before);
316 		}
317 		if (size_after > 0) {
318 			middle_data_len -= page_size;
319 		}
320 		if (middle_data_len > 0) {
321 			flash_write(flash_device, middle_page_start,
322 					 (const void *)data_offset,
323 					 middle_data_len);
324 		}
325 
326 		/* Write the last page if needed. */
327 		if (size_after > 0) {
328 			flash_write(flash_device, last_page, after_data,
329 					 page_size);
330 		}
331 	}
332 
333 	if (read_back) {
334 		PR_SHELL(shell, "Reading back written bytes:\n");
335 		ret = do_read(shell, offset, len);
336 	}
337 
338 free_buffers:
339 	k_free(before_data);
340 	k_free(after_data);
341 
342 	return ret;
343 }
344 
cmd_write_block_size(const struct shell * shell,size_t argc,char ** argv)345 static int cmd_write_block_size(const struct shell *shell, size_t argc,
346 				char **argv)
347 {
348 	ARG_UNUSED(argc);
349 	ARG_UNUSED(argv);
350 
351 	int err = check_flash_device(shell);
352 
353 	if (!err) {
354 		PR_SHELL(shell, "%d\n",
355 			 flash_get_write_block_size(flash_device));
356 	}
357 
358 	return err;
359 }
360 
cmd_read(const struct shell * shell,size_t argc,char ** argv)361 static int cmd_read(const struct shell *shell, size_t argc, char **argv)
362 {
363 	int err = check_flash_device(shell);
364 	unsigned long int offset, len;
365 
366 	if (err) {
367 		goto exit;
368 	}
369 
370 	if (parse_ul(argv[1], &offset) || parse_ul(argv[2], &len)) {
371 		PR_ERROR(shell, "Invalid arguments.\n");
372 		err = -EINVAL;
373 		goto exit;
374 	}
375 
376 	err = do_read(shell, offset, len);
377 
378 exit:
379 	return err;
380 }
381 
cmd_erase(const struct shell * shell,size_t argc,char ** argv)382 static int cmd_erase(const struct shell *shell, size_t argc, char **argv)
383 {
384 	int err = check_flash_device(shell);
385 	unsigned long int offset;
386 	unsigned long int size;
387 
388 	if (err) {
389 		goto exit;
390 	}
391 
392 	if (parse_ul(argv[1], &offset) || parse_ul(argv[2], &size)) {
393 		PR_ERROR(shell, "Invalid arguments.\n");
394 		err = -EINVAL;
395 		goto exit;
396 	}
397 
398 	err = do_erase(shell, (off_t)offset, (size_t)size);
399 exit:
400 	return err;
401 }
402 
cmd_write_template(const struct shell * shell,size_t argc,char ** argv,bool unaligned)403 static int cmd_write_template(const struct shell *shell, size_t argc, char **argv, bool unaligned)
404 {
405 	unsigned long int i, offset;
406 	uint8_t buf[ARGC_MAX];
407 
408 	int err = check_flash_device(shell);
409 
410 	if (err) {
411 		goto exit;
412 	}
413 
414 	err = parse_ul(argv[1], &offset);
415 	if (err) {
416 		PR_ERROR(shell, "Invalid argument.\n");
417 		goto exit;
418 	}
419 
420 	if ((argc - 2) > ARGC_MAX) {
421 		/* Can only happen if Zephyr limit is increased. */
422 		PR_ERROR(shell, "At most %lu bytes can be written.\n"
423 				"In order to write more bytes please increase"
424 				" parameter: CONFIG_SHELL_ARGC_MAX.\n",
425 			 (unsigned long)ARGC_MAX);
426 		err = -EINVAL;
427 		goto exit;
428 	}
429 
430 	/* skip cmd name and offset */
431 	argc -= 2;
432 	argv += 2;
433 	for (i = 0; i < argc; i++) {
434 		if (parse_u8(argv[i], &buf[i])) {
435 			PR_ERROR(shell, "Argument %lu (%s) is not a byte.\n"
436 					"Bytes shall be passed in decimal"
437 					" notation.\n",
438 				 i + 1, argv[i]);
439 			err = -EINVAL;
440 			goto exit;
441 		}
442 	}
443 
444 	if (!unaligned) {
445 		err = do_write(shell, offset, buf, i, true);
446 	} else {
447 		err = do_write_unaligned(shell, offset, buf, i, true);
448 	}
449 
450 exit:
451 	return err;
452 }
453 
cmd_write(const struct shell * shell,size_t argc,char ** argv)454 static int cmd_write(const struct shell *shell, size_t argc, char **argv)
455 {
456 	return cmd_write_template(shell, argc, argv, false);
457 }
458 
cmd_write_unaligned(const struct shell * shell,size_t argc,char ** argv)459 static int cmd_write_unaligned(const struct shell *shell, size_t argc, char **argv)
460 {
461 	return cmd_write_template(shell, argc, argv, true);
462 }
463 
cmd_write_pattern(const struct shell * shell,size_t argc,char ** argv)464 static int cmd_write_pattern(const struct shell *shell, size_t argc, char **argv)
465 {
466 	int err = check_flash_device(shell);
467 	unsigned long int offset, len, i;
468 	static uint8_t *buf;
469 
470 	if (err) {
471 		goto exit;
472 	}
473 
474 	if (parse_ul(argv[1], &offset) || parse_ul(argv[2], &len)) {
475 		PR_ERROR(shell, "Invalid arguments.\n");
476 		err = -EINVAL;
477 		goto exit;
478 	}
479 
480 	buf = k_malloc(len);
481 
482 	if (!buf) {
483 		PR_ERROR(shell, "No heap memory for data pattern\n");
484 		err = -ENOMEM;
485 		goto exit;
486 	}
487 
488 	for (i = 0; i < len; i++) {
489 		buf[i] = i & 0xFF;
490 	}
491 
492 	err = do_write_unaligned(shell, offset, buf, i, true);
493 
494 	k_free(buf);
495 
496 exit:
497 	return err;
498 }
499 
500 #ifdef CONFIG_FLASH_PAGE_LAYOUT
cmd_page_count(const struct shell * shell,size_t argc,char ** argv)501 static int cmd_page_count(const struct shell *shell, size_t argc, char **argv)
502 {
503 	ARG_UNUSED(argv);
504 	ARG_UNUSED(argc);
505 
506 	int err = check_flash_device(shell);
507 	size_t page_count;
508 
509 	if (!err) {
510 		page_count = flash_get_page_count(flash_device);
511 		PR_SHELL(shell, "Flash device contains %lu pages.\n",
512 			 (unsigned long int)page_count);
513 	}
514 
515 	return err;
516 }
517 
518 struct page_layout_data {
519 	unsigned long int start_page;
520 	unsigned long int end_page;
521 	const struct shell *shell;
522 };
523 
page_layout_cb(const struct flash_pages_info * info,void * datav)524 static bool page_layout_cb(const struct flash_pages_info *info, void *datav)
525 {
526 	struct page_layout_data *data = datav;
527 	unsigned long int sz;
528 
529 	if (info->index < data->start_page) {
530 		return true;
531 	} else if (info->index > data->end_page) {
532 		return false;
533 	}
534 
535 	sz = info->size;
536 	PR_SHELL(data->shell,
537 		 "\tPage %u: start 0x%08x, length 0x%lx (%lu, %lu KB)\n",
538 		 info->index, info->start_offset, sz, sz, sz / KB(1));
539 	return true;
540 }
541 
cmd_page_layout(const struct shell * shell,size_t argc,char ** argv)542 static int cmd_page_layout(const struct shell *shell, size_t argc, char **argv)
543 {
544 	unsigned long int start_page, end_page;
545 	struct page_layout_data data;
546 
547 	int err = check_flash_device(shell);
548 
549 	if (err) {
550 		goto bail;
551 	}
552 
553 	switch (argc) {
554 	case 1:
555 		start_page = 0;
556 		end_page = flash_get_page_count(flash_device) - 1;
557 		break;
558 	case 2:
559 		if (parse_ul(argv[1], &start_page)) {
560 			err = -EINVAL;
561 			goto bail;
562 		}
563 		end_page = flash_get_page_count(flash_device) - 1;
564 		break;
565 	case 3:
566 		if (parse_ul(argv[1], &start_page) ||
567 		    parse_ul(argv[2], &end_page)) {
568 			err = -EINVAL;
569 			goto bail;
570 		}
571 		break;
572 	default:
573 		PR_ERROR(shell, "Invalid argument count.\n");
574 		return -EINVAL;
575 	}
576 
577 	data.start_page = start_page;
578 	data.end_page = end_page;
579 	data.shell = shell;
580 	flash_page_foreach(flash_device, page_layout_cb, &data);
581 	return 0;
582 
583 bail:
584 	PR_ERROR(shell, "Invalid arguments.\n");
585 	return err;
586 }
587 
cmd_page_read(const struct shell * shell,size_t argc,char ** argv)588 static int cmd_page_read(const struct shell *shell, size_t argc, char **argv)
589 {
590 	unsigned long int page, offset, len;
591 	struct flash_pages_info info;
592 	int ret;
593 
594 	ret = check_flash_device(shell);
595 	if (ret) {
596 		return ret;
597 	}
598 
599 	if (argc == 3) {
600 		if (parse_ul(argv[1], &page) || parse_ul(argv[2], &len)) {
601 			ret = -EINVAL;
602 			goto bail;
603 		}
604 		offset = 0;
605 	} else if (parse_ul(argv[1], &page) || parse_ul(argv[2], &offset) ||
606 		   parse_ul(argv[3], &len)) {
607 			ret = -EINVAL;
608 			goto bail;
609 	}
610 
611 	ret = flash_get_page_info_by_idx(flash_device, page, &info);
612 	if (ret) {
613 		PR_ERROR(shell, "Function flash_page_info_by_idx returned an"
614 				" error: %d\n", ret);
615 		return ret;
616 	}
617 	offset += info.start_offset;
618 	ret = do_read(shell, offset, len);
619 	return ret;
620 
621  bail:
622 	PR_ERROR(shell, "Invalid arguments.\n");
623 	return ret;
624 }
625 
cmd_page_erase(const struct shell * shell,size_t argc,char ** argv)626 static int cmd_page_erase(const struct shell *shell, size_t argc, char **argv)
627 {
628 	struct flash_pages_info info;
629 	unsigned long int i, page, num;
630 	int ret;
631 
632 	ret = check_flash_device(shell);
633 	if (ret) {
634 		return ret;
635 	}
636 
637 	if (parse_ul(argv[1], &page)) {
638 		ret = -EINVAL;
639 		goto bail;
640 	}
641 	if (argc == 2) {
642 		num = 1;
643 	} else if (parse_ul(argv[2], &num)) {
644 		goto bail;
645 	}
646 
647 	for (i = 0; i < num; i++) {
648 		ret = flash_get_page_info_by_idx(flash_device, page + i, &info);
649 		if (ret) {
650 			PR_ERROR(shell, "flash_get_page_info_by_idx error:"
651 				" %d\n", ret);
652 			return ret;
653 		}
654 		PR_SHELL(shell, "Erasing page %u (start offset 0x%x,"
655 				" size 0x%x)\n",
656 		       info.index, info.start_offset, info.size);
657 		ret = do_erase(shell, info.start_offset, info.size);
658 		if (ret) {
659 			return ret;
660 		}
661 	}
662 
663 	return ret;
664 
665  bail:
666 	PR_ERROR(shell, "Invalid arguments.\n");
667 	return ret;
668 }
669 
cmd_page_write(const struct shell * shell,size_t argc,char ** argv)670 static int cmd_page_write(const struct shell *shell, size_t argc, char **argv)
671 {
672 	struct flash_pages_info info;
673 	unsigned long int page, off;
674 	uint8_t buf[ARGC_MAX];
675 	size_t i;
676 	int ret;
677 
678 	ret = check_flash_device(shell);
679 	if (ret) {
680 		return ret;
681 	}
682 
683 	if (parse_ul(argv[1], &page) || parse_ul(argv[2], &off)) {
684 		ret = -EINVAL;
685 		goto bail;
686 	}
687 
688 	argc -= 3;
689 	argv += 3;
690 	for (i = 0; i < argc; i++) {
691 		if (parse_u8(argv[i], &buf[i])) {
692 			PR_ERROR(shell, "Argument %d (%s) is not a byte.\n",
693 				 i + 2, argv[i]);
694 			ret = -EINVAL;
695 			goto bail;
696 		}
697 	}
698 
699 	ret = flash_get_page_info_by_idx(flash_device, page, &info);
700 	if (ret) {
701 		PR_ERROR(shell, "flash_get_page_info_by_idx: %d\n", ret);
702 		return ret;
703 	}
704 	ret = do_write(shell, info.start_offset + off, buf, i, true);
705 	return ret;
706 
707  bail:
708 	PR_ERROR(shell, "Invalid arguments.\n");
709 	return ret;
710 }
711 #endif	/* CONFIG_FLASH_PAGE_LAYOUT */
712 
cmd_set_dev(const struct shell * shell,size_t argc,char ** argv)713 static int cmd_set_dev(const struct shell *shell, size_t argc, char **argv)
714 {
715 	const struct device *dev;
716 	const char *name;
717 
718 	name = argv[1];
719 
720 	/* Run command. */
721 	dev = device_get_binding(name);
722 	if (!dev) {
723 		PR_ERROR(shell, "No device named %s.\n", name);
724 		return -ENOEXEC;
725 	}
726 	if (flash_device) {
727 		PR_SHELL(shell, "Leaving behind device %s\n",
728 			 flash_device->name);
729 	}
730 	flash_device = dev;
731 
732 	return 0;
733 }
734 
main(void)735 void main(void)
736 {
737 	flash_device =
738 		device_get_binding(DT_CHOSEN_ZEPHYR_FLASH_CONTROLLER_LABEL);
739 	if (flash_device) {
740 		printk("Found flash controller %s.\n",
741 			DT_CHOSEN_ZEPHYR_FLASH_CONTROLLER_LABEL);
742 		printk("Flash I/O commands can be run.\n");
743 	} else {
744 		printk("**No flash controller found!**\n");
745 		printk("Run set_device <name> to specify one "
746 		       "before using other commands.\n");
747 	}
748 }
749 
750 
751 SHELL_STATIC_SUBCMD_SET_CREATE(sub_flash,
752 	/* Alphabetically sorted to ensure correct Tab autocompletion. */
753 	SHELL_CMD_ARG(erase,	NULL,	ERASE_HELP,	cmd_erase, 3, 0),
754 #ifdef CONFIG_FLASH_PAGE_LAYOUT
755 	SHELL_CMD_ARG(page_count,  NULL, PAGE_COUNT_HELP, cmd_page_count, 1, 0),
756 	SHELL_CMD_ARG(page_erase, NULL, PAGE_ERASE_HELP, cmd_page_erase, 2, 1),
757 	SHELL_CMD_ARG(page_layout, NULL, PAGE_LAYOUT_HELP,
758 		      cmd_page_layout, 1, 2),
759 	SHELL_CMD_ARG(page_read,   NULL, PAGE_READ_HELP,  cmd_page_read, 3, 1),
760 	SHELL_CMD_ARG(page_write,  NULL, PAGE_WRITE_HELP,
761 		      cmd_page_write, 3, 255),
762 #endif
763 	SHELL_CMD_ARG(read,		NULL,	READ_HELP,	cmd_read, 3, 0),
764 	SHELL_CMD_ARG(set_device, NULL, SET_DEV_HELP, cmd_set_dev, 2, 0),
765 	SHELL_CMD_ARG(write,	  NULL,	WRITE_HELP,	cmd_write, 3, 255),
766 	SHELL_CMD_ARG(write_block_size,	NULL,	WRITE_BLOCK_SIZE_HELP,
767 						    cmd_write_block_size, 1, 0),
768 	SHELL_CMD_ARG(write_unaligned,  NULL,	WRITE_UNALIGNED_HELP,
769 							cmd_write_unaligned, 3, 255),
770 	SHELL_CMD_ARG(write_pattern,  	NULL,	WRITE_PATTERN_HELP,
771 							cmd_write_pattern, 3, 255),
772 	SHELL_SUBCMD_SET_END /* Array terminated. */
773 );
774 
775 SHELL_CMD_REGISTER(flash, &sub_flash, "Flash related commands.", NULL);
776