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