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