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