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