]> cloudbase.mooo.com Git - z180-stamp.git/blob - avr/cmd_fat.c
cmd_fat.c: reorg
[z180-stamp.git] / avr / cmd_fat.c
1 /*
2 * (C) Copyright 2014,2016,2018 Leo C. <erbl259-lmu@yahoo.de>
3 *
4 * SPDX-License-Identifier: GPL-2.0
5 */
6
7 /*
8 * FAT filesystem commands
9 */
10
11 #include "cmd_fat.h"
12
13 #include "ff.h"
14 #include "z80-if.h"
15 #include "eval_arg.h"
16 #include "con-utils.h"
17 #include "print-utils.h"
18 #include "time.h"
19 #include "timer.h"
20 #include "debug.h"
21 #include "env.h"
22 #include "getopt-min.h"
23
24 /* TODO: use memory size test function (detect_ramsize() in cmd_loadihex.c) */
25 /* TODO: detect_ramsize() should be moved to z80-if.c */
26 #define MAX_MEMORY CONFIG_SYS_RAMSIZE_MAX
27 #define BUFFER_SIZE 512
28
29 /*
30 * Multible (fat) partitions per physical drive are not supported,
31 * but we have up to 2 sdcard slots.
32 */
33 FATFS FatFs0;
34 FATFS FatFs1;
35
36 void setup_fatfs(void)
37 {
38 f_mount(&FatFs0, "0:", 0);
39 f_mount(&FatFs1, "1:", 0);
40 }
41
42 DWORD get_fattime (void)
43 {
44 time_t timer;
45 struct tm tm_timer;
46
47 time(&timer);
48 gmtime_r(&timer, &tm_timer);
49
50 return fatfs_time(&tm_timer);
51 }
52
53
54 static bool check_abort(void)
55 {
56 bool ret = ctrlc();
57
58 if (ret)
59 printf_P(PSTR("Abort\n"));
60
61 return ret;
62 }
63
64
65 static const FLASH char * const FLASH rc_names[] = {
66 FSTR("OK"),
67 FSTR("DISK_ERR"),
68 FSTR("INT_ERR"),
69 FSTR("NOT_READY"),
70 FSTR("NO_FILE"),
71 FSTR("NO_PATH"),
72 FSTR("INVALID_NAME"),
73 FSTR("DENIED"),
74 FSTR("EXIST"),
75 FSTR("INVALID_OBJECT"),
76 FSTR("WRITE_PROTECTED"),
77 FSTR("INVALID_DRIVE"),
78 FSTR("NOT_ENABLED"),
79 FSTR("NO_FILE_SYSTEM"),
80 FSTR("MKFS_ABORTED"),
81 FSTR("TIMEOUT"),
82 FSTR("LOCKED"),
83 FSTR("NOT_ENOUGH_CORE"),
84 FSTR("TOO_MANY_OPEN_FILES"),
85 FSTR("INVALID_PARAMETER")
86 };
87
88 static
89 void put_rc (FRESULT rc)
90 {
91 #if GCC_BUG_61443
92 printf_P(PSTR("rc=%u FR_"), rc);
93 my_puts_P(rc < ARRAY_SIZE(rc_names) ? rc_names[rc] : PSTR(" Unknown Error"));
94 my_puts_P(PSTR("\n"));
95 #else
96 printf_P(PSTR("rc=%u FR_%S\n"), rc,
97 rc < ARRAY_SIZE(rc_names) ? rc_names[rc] : PSTR(" Unknown Error"));
98 #endif
99 }
100
101
102 static void swirl(void)
103 {
104 static const FLASH char swirlchar[] = { '-','\\','|','/' };
105 static uint_fast8_t cnt;
106 static uint32_t tstamp;
107
108 if (get_timer(0) > tstamp) {
109 printf_P(PSTR("\b%c"), swirlchar[cnt]);
110 cnt = (cnt+1) % ARRAY_SIZE(swirlchar);
111 tstamp = get_timer(0) + 250;
112 }
113 }
114
115 /*
116 * pwd - Print current directory of the current drive.
117 *
118 */
119 command_ret_t do_pwd(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc UNUSED, char * const argv[] UNUSED)
120 {
121 FRESULT res;
122 char *buf;
123
124 buf = (char *) malloc(BUFFER_SIZE);
125 if (buf == NULL) {
126 printf_P(PSTR("pwd: Out of Memory!\n"));
127 free(buf);
128 return CMD_RET_FAILURE;
129 }
130
131 res = f_getcwd(buf, BUFFER_SIZE); /* Get current directory path */
132
133 if (!res) {
134 puts(buf);
135 }
136 free(buf);
137 if (res) {
138 put_rc(res);
139 return CMD_RET_FAILURE;
140 }
141 return CMD_RET_SUCCESS;
142 }
143
144
145 /*
146 * cd - Change the current/working directory.
147 *
148 */
149 command_ret_t do_cd(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[])
150 {
151 char *arg;
152 FRESULT res = 0;
153
154 if (argc < 2) {
155 arg = getenv_str(PSTR(ENV_HOME));
156 if (arg == NULL) {
157 printf_P(PSTR("%s: \"%S\" is not set\n"), argv[0], PSTR(ENV_HOME));
158 return CMD_RET_FAILURE;
159 }
160 } else
161 arg = argv[1];
162
163 if (arg[1] == ':') {
164 char drv[3];
165 drv[2] = '\0';
166 drv[1] = ':';
167 drv[0] = arg[0];
168 res = f_chdrive(drv);
169 }
170 if (!res) {
171 res = f_chdir(arg);
172 }
173
174 if (res) {
175 put_rc(res);
176 return CMD_RET_FAILURE;
177 }
178 return CMD_RET_SUCCESS;
179 }
180
181 #define MAX_PATHLEN 255
182
183 /*
184 * Remove trailing slashes,
185 * but keep a leading slash (absolute path)
186 */
187 void strip_trailing_slash_relpath(char *p)
188 {
189 int n = strlen(p);
190
191 if (n >= 2 && (p[0] & 0x38) == '0' && p[1] == ':') {
192 p += 2;
193 n -= 2;
194 }
195 if (n >= 1 && p[0] == '/') {
196 p++;
197 n--;
198 }
199 while (n-- != 0 && p[n] == '/')
200 p[n] = '\0';
201 }
202
203 int print_dirent(FILINFO *f)
204 {
205 return printf_P(PSTR("%c%c%c%c%c %u/%02u/%02u %02u:%02u %9lu %s\n"),
206 (f->fattrib & AM_DIR) ? 'D' : '-',
207 (f->fattrib & AM_RDO) ? 'R' : '-',
208 (f->fattrib & AM_HID) ? 'H' : '-',
209 (f->fattrib & AM_SYS) ? 'S' : '-',
210 (f->fattrib & AM_ARC) ? 'A' : '-',
211 (f->fdate >> 9) + 1980, (f->fdate >> 5) & 15, f->fdate & 31,
212 (f->ftime >> 11), (f->ftime >> 5) & 63,
213 f->fsize, f->fname);
214 }
215
216 /*
217 * ls path - Directory listing
218 *
219 */
220 command_ret_t do_ls(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[])
221 {
222 FATFS *fs;
223 DIR Dir; /* Directory object */
224 FILINFO Finfo;
225 unsigned long p1;
226 unsigned int s1, s2;
227 FRESULT res;
228
229 char *path = "";
230 if (argc > 1)
231 path = argv[1];
232 strip_trailing_slash_relpath(path);
233
234 char *p = strrchr(path, '/');
235 if (p)
236 p++;
237 else {
238 p = path;
239 char *q = p;
240 if ((*q++ & 0x38) == '0' && *q++ == ':')
241 p = q;
242 }
243
244 char *pattern = NULL;
245 if (strpbrk_P(p, PSTR("*?")) ||
246 (f_stat(path, &Finfo) == FR_OK && !(Finfo.fattrib & AM_DIR))) {
247 pattern = strdup(p);
248 *p = '\0';
249 }
250 strip_trailing_slash_relpath(path);
251
252 printf_P(PSTR("*: |%s| |%s|\n"), path ? path : "<NULL>", pattern ? pattern : "<NULL>");
253
254 p1 = s1 = s2 = 0;
255 res = f_findfirst(&Dir, &Finfo, path, pattern ? pattern : "*"); /* Start to search for files */
256 while (res == FR_OK && Finfo.fname[0]) {
257 if (Finfo.fattrib & AM_DIR) {
258 s2++;
259 } else {
260 s1++; p1 += Finfo.fsize;
261 }
262 print_dirent(&Finfo);
263 if (check_abort())
264 break;
265 res = f_findnext(&Dir, &Finfo);
266 }
267 f_closedir(&Dir);
268 free(pattern);
269
270 if (res == FR_OK) {
271 printf_P(PSTR("%4u File(s),%10lu bytes total\n%4u Dir(s)"), s1, p1, s2);
272 if (f_getfree(path, (DWORD*)&p1, &fs) == FR_OK)
273 printf_P(PSTR(", %10luK bytes free\n"), p1 * fs->csize / 2);
274 }
275
276 if (res) {
277 put_rc(res);
278 return CMD_RET_FAILURE;
279 }
280
281 return CMD_RET_SUCCESS;
282 }
283
284 /*
285 * tst path - for debugging: test access with different functions
286 *
287 */
288 command_ret_t do_tst(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[])
289 {
290 DIR Dir; /* Directory object */
291 FILINFO Finfo;
292 FRESULT res = FR_OK;
293 char *path;
294
295 printf_P(PSTR("sizeof DIR: %u, sizeof FIL: %u\n"), sizeof (DIR), sizeof (FILINFO));
296
297 char * buf = (char *) malloc(BUFFER_SIZE);
298 if (buf == NULL) {
299 printf_P(PSTR("pwd: Out of Memory!\n"));
300 free(buf);
301 return CMD_RET_FAILURE;
302 }
303 res = f_getcwd(buf, BUFFER_SIZE); /* Get current directory path */
304
305 if (!res) {
306 printf_P(PSTR("cwd: |%s|\n"), buf);
307 }
308 free(buf);
309 if (res) {
310 put_rc(res);
311 return CMD_RET_FAILURE;
312 }
313
314 if (argc > 1)
315 path = argv[1];
316 else
317 path = "";
318
319 printf_P(PSTR("arg: |%s|\n"), path);
320 printf_P(PSTR("==== f_stat: "));
321 res = f_stat(path, &Finfo);
322 put_rc(res);
323 if (res == FR_OK) {
324 print_dirent(&Finfo);
325 }
326
327 printf_P(PSTR("==== f_findfirst: "));
328 res = f_findfirst(&Dir, &Finfo, path, "*"); /* Start to search for files */
329 put_rc(res);
330 if (res == FR_OK) {
331 print_dirent(&Finfo);
332 }
333 f_closedir(&Dir);
334
335 printf_P(PSTR("==== f_opendir: "));
336 res = f_opendir(&Dir, path);
337 put_rc(res);
338 f_closedir(&Dir);
339
340 return CMD_RET_SUCCESS;
341 }
342
343 #if 0
344 static
345 FRESULT mkpath(TCHAR *path)
346 {
347 /* TODO: */
348 (void) path;
349 FILINFO fd
350 TCHAR *p, *q;
351 FRESULT ret;
352
353 res = f_stat (path, &fd)
354
355 p = strchr(path, ':');
356 if (p == NULL || *++p == '\0' || *p++ != '/')
357 return FR_OK;
358
359 while ((q = strchr(p, '/')) != NULL) {
360 *q = '\0';
361 ret = f_mkdir(path);
362 *q = '/';
363 if (ret != FR_OK && ret != FR_EXIST)
364 return ret;
365 p = q + 1;
366 }
367
368 return FR_OK;
369 }
370 #endif
371
372 /******************************************************************************/
373
374
375 typedef struct {
376 char *p_end; /* pointer to NULL at end of path */
377 char p_path[MAX_PATHLEN + 1]; /* pointer to the start of a path */
378 } PATH_T;
379
380 static inline void strip_trailing_slash(PATH_T *p)
381 {
382 while (p->p_end > p->p_path && p->p_end[-1] == '/')
383 *--p->p_end = 0;
384 }
385
386 /*
387 * Move specified string into path. Convert "" to "." to handle BSD
388 * semantics for a null path. Strip trailing slashes.
389 */
390 int
391 path_set(PATH_T *p, char *string)
392 {
393 if (strlen(string) > MAX_PATHLEN) {
394 //err("%s: name too long", string);
395 return(0);
396 }
397
398 (void)strcpy(p->p_path, string);
399 p->p_end = p->p_path + strlen(p->p_path);
400
401 if (p->p_path == p->p_end) {
402 *p->p_end++ = '.';
403 *p->p_end = 0;
404 }
405
406 strip_trailing_slash(p);
407 return(1);
408 }
409
410 #define R_FLAG (1<<0)
411 #define I_FLAG (1<<1)
412 #define N_FLAG (1<<2)
413 #define F_FLAG (1<<3)
414 #define P_FLAG (1<<4)
415 #define V_FLAG (1<<5)
416
417 command_ret_t do_cp(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[])
418 {
419
420 FRESULT fr; /* Return value */
421 DIR dj; /* Directory search object */
422 FILINFO fno; /* File information */
423
424 uint8_t flags = 0;
425
426
427 /* reset getopt() */
428 optind = 0;
429
430 int opt;
431 while ((opt = getopt(argc, argv, PSTR("Rrfip"))) != -1) {
432 switch (opt) {
433 case 'f':
434 flags &= I_FLAG;
435 break;
436 case 'i':
437 flags |= I_FLAG;
438 flags &= F_FLAG;
439 break;
440 case 'p':
441 flags |= P_FLAG;
442 break;
443 case 'R':
444 case 'r':
445 flags |= R_FLAG;
446 break;
447 case 'v':
448 flags |= V_FLAG;
449 break;
450 default:
451 return CMD_RET_USAGE;
452 break;
453 }
454 }
455 argc -= optind;
456 argv += optind;
457
458 if (argc < 2)
459 return CMD_RET_USAGE;
460
461 #if 0
462 /* consume last argument first. */
463 if (!path_set(&to, argv[--argc]))
464 exit(1);
465
466
467 if (flags & V_FLAG)
468 printf_P((PSTR("%s %s -> %s\n", badcp ? : "ERR:" : " ", curr->fts_path, to.p_path)));
469
470 #endif
471
472 /* Search a directory for objects and display it */
473
474
475 fr = f_findfirst(&dj, &fno, argv[1], argv[2]); /* Start to search for files */
476
477 while (fr == FR_OK && fno.fname[0]) { /* Repeat while an item is found */
478 printf_P(PSTR("%c%c%c%c%c %u/%02u/%02u %02u:%02u %9lu %s\n"),
479 (fno.fattrib & AM_DIR) ? 'D' : '-',
480 (fno.fattrib & AM_RDO) ? 'R' : '-',
481 (fno.fattrib & AM_HID) ? 'H' : '-',
482 (fno.fattrib & AM_SYS) ? 'S' : '-',
483 (fno.fattrib & AM_ARC) ? 'A' : '-',
484 (fno.fdate >> 9) + 1980, (fno.fdate >> 5) & 15, fno.fdate & 31,
485 (fno.ftime >> 11), (fno.ftime >> 5) & 63,
486 fno.fsize, fno.fname);
487 fr = f_findnext(&dj, &fno); /* Search for next item */
488 }
489
490 f_closedir(&dj);
491
492 return CMD_RET_SUCCESS;
493 }
494
495 /******************************************************************************/
496
497 /* Work register for fs command */
498 struct stat_dat_s {
499 DWORD AccSize;
500 WORD AccFiles, AccDirs;
501 FILINFO Finfo;
502 };
503
504 static
505 FRESULT scan_files (
506 char *path, /* Pointer to the working buffer with start path */
507 struct stat_dat_s *statp
508 )
509 {
510 DIR dirs;
511 FRESULT res;
512 int i;
513 char *fn;
514
515 res = f_opendir(&dirs, path);
516 swirl();
517 if (res == FR_OK) {
518 i = strlen(path);
519 while (((res = f_readdir(&dirs, &statp->Finfo)) == FR_OK) &&
520 statp->Finfo.fname[0]) {
521 if (_FS_RPATH && statp->Finfo.fname[0] == '.')
522 continue;
523 fn = statp->Finfo.fname;
524 if (statp->Finfo.fattrib & AM_DIR) {
525 statp->AccDirs++;
526 path[i] = '/';
527 strcpy(path+i+1, fn);
528 res = scan_files(path, statp);
529 path[i] = '\0';
530 if (res != FR_OK)
531 break;
532 } else {
533 //printf_P(PSTR("%s/%s\n"), path, fn);
534 statp->AccFiles++;
535 statp->AccSize += statp->Finfo.fsize;
536 }
537 if (check_abort()) {
538 res = 255;
539 break;
540 }
541 }
542 }
543
544 return res;
545 }
546
547
548 /*
549 * fatstat path - Show logical drive status
550 *
551 */
552 command_ret_t do_stat(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[])
553 {
554 FATFS *fs;
555 DWORD nfreeclst;
556 FRESULT res;
557 char *buf;
558 char *path = "";
559 struct stat_dat_s statp;
560
561 buf = (char *) malloc(BUFFER_SIZE);
562 if (buf == NULL) {
563 printf_P(PSTR("fat stat: Out of Memory!\n"));
564 return CMD_RET_FAILURE;
565 }
566
567 if (argc > 1)
568 path = argv[1];
569 res = f_getfree(path, &nfreeclst, &fs);
570 if (!res) {
571 printf_P(PSTR(
572 "FAT type: %u\n"
573 "Bytes/Cluster: %lu\n"
574 "Number of FATs: %u\n"
575 "Root DIR entries: %u\n"
576 "Sectors/FAT: %lu\n"
577 "Number of clusters: %lu\n"
578 "FAT start (lba): %lu\n"
579 "DIR start (lba,cluster): %lu\n"
580 "Data start (lba): %lu\n"),
581 fs->fs_type, (DWORD)fs->csize * 512, fs->n_fats,
582 fs->n_rootdir, fs->fsize, fs->n_fatent - 2,
583 fs->fatbase, fs->dirbase, fs->database);
584
585 #if _USE_LABEL
586 DWORD serial;
587 res = f_getlabel(path, buf, &serial);
588 if (!res) {
589 printf_P(PSTR(
590 "Volume name: %s\n"
591 "Volume S/N: %04X-%04X\n"),
592 buf, (WORD)(serial >> 16), (WORD)(serial & 0xFFFF));
593 }
594 #endif
595 if (!res) {
596 my_puts_P(PSTR("\nCounting... "));
597 statp.AccSize = statp.AccFiles = statp.AccDirs = 0;
598 strcpy(buf, path);
599
600 res = scan_files(buf, &statp);
601 }
602 if (!res) {
603 printf_P(PSTR("\r%u files, %lu bytes.\n%u folders.\n"
604 "%lu KB total disk space.\n%lu KB available.\n"),
605 statp.AccFiles, statp.AccSize, statp.AccDirs,
606 (fs->n_fatent - 2) * (fs->csize / 2), nfreeclst * (fs->csize / 2)
607 );
608 }
609 }
610
611 free(buf);
612 if (res) {
613 put_rc(res);
614 return CMD_RET_FAILURE;
615 }
616 return CMD_RET_SUCCESS;
617 }
618
619 /*
620 * fatread/write - load binary file to/from a dos filesystem
621 * read <d:/path/filename> <addr> [bytes [pos]]
622 * write <d:/path/filename> <addr> <bytes>
623 */
624 command_ret_t do_rw(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc, char * const argv[])
625 {
626 FIL File;
627 uint32_t addr;
628 unsigned long bytes;
629 unsigned long pos;
630 unsigned long bytes_rw;
631
632 bool dowrite = (argv[0][0] == 'w');
633 FRESULT res = FR_OK;
634 bool buserr = 0;
635 uint32_t timer;
636 uint8_t *buffer;
637
638 if (argc < (dowrite ? 4 : 3))
639 return CMD_RET_USAGE;
640
641 addr = eval_arg(argv[2], NULL);
642 if (addr >= MAX_MEMORY) {
643 printf_P(PSTR("address too high: 0x%0lx\n"), addr);
644 return CMD_RET_FAILURE;
645 }
646 if (argc > 3)
647 bytes = eval_arg(argv[3], NULL);
648 else
649 bytes = MAX_MEMORY;
650 if (argc > 4)
651 pos = eval_arg(argv[4], NULL);
652 else
653 pos = 0;
654
655 if (addr + bytes > MAX_MEMORY)
656 bytes = MAX_MEMORY - addr;
657
658 buffer = (uint8_t *) malloc(BUFFER_SIZE);
659 if (buffer == NULL) {
660 printf_P(PSTR("fatstat: Out of Memory!\n"));
661 free(buffer);
662 return CMD_RET_FAILURE;
663 }
664
665 if (!res) {
666 res = f_open(&File, argv[1], dowrite ? FA_WRITE | FA_CREATE_ALWAYS
667 : FA_READ );
668
669 if (!res) {
670 res = f_lseek(&File, pos);
671 if (!res) {
672 bytes_rw = 0;
673 timer = get_timer(0);
674 while (bytes) {
675 unsigned int cnt, br;
676
677 if (bytes >= BUFFER_SIZE) {
678 cnt = BUFFER_SIZE;
679 bytes -= BUFFER_SIZE;
680 } else {
681 cnt = bytes; bytes = 0;
682 }
683 if (dowrite) {
684 if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
685 buserr = 1;
686 break;
687 }
688 z80_read_block(buffer, addr, cnt);
689 z80_bus_cmd(Release);
690 res = f_write(&File, buffer, cnt, &br);
691 if (res != FR_OK)
692 break;
693 } else {
694 res = f_read(&File, buffer, cnt, &br);
695 if (res != FR_OK)
696 break;
697 if (!(z80_bus_cmd(Request) & ZST_ACQUIRED)) {
698 buserr = 1;
699 break;
700 }
701 z80_write_block(buffer, addr, br);
702 z80_bus_cmd(Release);
703 }
704 addr += br;
705
706 bytes_rw += br;
707 if (cnt != br) {
708 if (dowrite)
709 printf_P(PSTR("Disk full?\n"));
710 break;
711 }
712 if (check_abort())
713 break;
714 }
715
716 FRESULT fr = f_close(&File);
717 if (!res)
718 res = fr;
719 timer = get_timer(timer);
720 printf_P(PSTR("%lu (0x%lx) bytes read/written with %lu bytes/sec.\n"),
721 bytes_rw, bytes_rw, timer ? (bytes_rw * 1000 / timer) : 0);
722 }
723 }
724 }
725
726 free(buffer);
727
728 if (buserr)
729 my_puts_P(PSTR("Bus timeout\n"));
730 if (res)
731 put_rc(res);
732 if (buserr || res)
733 return CMD_RET_FAILURE;
734
735 return CMD_RET_SUCCESS;
736 }
737
738 /*
739 * command table for fat subcommands
740 */
741
742 cmd_tbl_t cmd_tbl_fat[] = {
743 CMD_TBL_ITEM(
744 stat, 2, CTBL_RPT, do_stat,
745 "Show logical drive status",
746 "dev"
747 ),
748 CMD_TBL_ITEM(
749 pwd, 2, CTBL_RPT, do_pwd,
750 "Print name of current/working directory",
751 ""
752 ),
753 CMD_TBL_ITEM(
754 cd, 2, 0, do_cd,
755 "Change the current/working directory.",
756 "path"
757 ),
758 CMD_TBL_ITEM(
759 ls, 2, CTBL_RPT, do_ls,
760 "Directory listing",
761 "path"
762 ),
763 CMD_TBL_ITEM(
764 tst, 2, CTBL_DBG|CTBL_RPT, do_tst,
765 "FatFS test function",
766 "path"
767 ),
768 CMD_TBL_ITEM(
769 load, 5, 0, do_rw,
770 "load binary file from a dos filesystem",
771 "<d:/path/filename> <addr> [bytes [pos]]\n"
772 " - Load binary file 'path/filename' on logical drive 'd'\n"
773 " to address 'addr' from dos filesystem.\n"
774 " 'pos' gives the file position to start loading from.\n"
775 " If 'pos' is omitted, 0 is used. 'pos' requires 'bytes'.\n"
776 " 'bytes' gives the size to load. If 'bytes' is 0 or omitted,\n"
777 " the load stops on end of file."
778 ),
779 CMD_TBL_ITEM(
780 write, 4, 0, do_rw,
781 "write file into a dos filesystem",
782 "<d:/path/filename> <addr> <bytes>\n"
783 " - Write file to 'path/filename' on logical drive 'd' from RAM\n"
784 " starting at address 'addr'.\n"
785 ),
786
787 CMD_TBL_ITEM(
788 cp, CONFIG_SYS_MAXARGS, CTBL_DBG, do_cp,
789 "copy files",
790 "[-R] [-f | -i | -n] [-aprv] source_file target_file\n"
791 " - \n"
792 ),
793
794 CMD_TBL_ITEM(
795 help, CONFIG_SYS_MAXARGS, CTBL_RPT, do_help,
796 "Print sub command description/usage",
797 "\n"
798 " - print brief description of all sub commands\n"
799 "fat help command ...\n"
800 " - print detailed usage of sub cmd 'command'"
801 ),
802
803 /* This does not use the CMD_TBL_ITEM macro as ? can't be used in symbol names */
804 {FSTR("?"), CONFIG_SYS_MAXARGS, 1, do_help,
805 FSTR("Alias for 'help'"),
806 #ifdef CONFIG_SYS_LONGHELP
807 FSTR(""),
808 #endif /* CONFIG_SYS_LONGHELP */
809 NULL,
810 #ifdef CONFIG_AUTO_COMPLETE
811 NULL,
812 #endif
813 },
814 /* Mark end of table */
815 CMD_TBL_END(cmd_tbl_fat)
816 };
817
818
819 command_ret_t do_fat(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc UNUSED, char * const argv[] UNUSED)
820 {
821 puts_P(PSTR("Huch?"));
822
823 return CMD_RET_USAGE;
824 }