]> git.ipfire.org Git - thirdparty/u-boot.git/blame - common/cmd_boot.c
* Patches by Robert Schwebel, 26 Jun 2003:
[thirdparty/u-boot.git] / common / cmd_boot.c
CommitLineData
fe8c2806
WD
1/*
2 * (C) Copyright 2000-2002
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
5 * See file CREDITS for list of people who contributed to this
6 * project.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 */
23
24/*
25 * Boot support
26 */
27#include <common.h>
28#include <command.h>
29#include <cmd_boot.h>
30#include <cmd_autoscript.h>
31#include <s_record.h>
32#include <net.h>
33#include <syscall.h>
34
35
36#if (CONFIG_COMMANDS & CFG_CMD_LOADS)
37static ulong load_serial (ulong offset);
38static int read_record (char *buf, ulong len);
39# if (CONFIG_COMMANDS & CFG_CMD_SAVES)
40static int save_serial (ulong offset, ulong size);
41static int write_record (char *buf);
42# endif /* CFG_CMD_SAVES */
43
44static int do_echo = 1;
45#endif /* CFG_CMD_LOADS */
46
47
48#if (CONFIG_COMMANDS & CFG_CMD_BDI)
49static void print_num(const char *, ulong);
50
51#ifndef CONFIG_ARM /* PowerPC and other */
52
4d75a504 53#ifdef CONFIG_PPC
fe8c2806
WD
54static void print_str(const char *, const char *);
55
56int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
57{
58 DECLARE_GLOBAL_DATA_PTR;
59
60 int i;
61 bd_t *bd = gd->bd;
62 char buf[32];
63
64#ifdef DEBUG
65 print_num ("bd address", (ulong)bd );
66#endif
67 print_num ("memstart", bd->bi_memstart );
68 print_num ("memsize", bd->bi_memsize );
69 print_num ("flashstart", bd->bi_flashstart );
70 print_num ("flashsize", bd->bi_flashsize );
71 print_num ("flashoffset", bd->bi_flashoffset );
72 print_num ("sramstart", bd->bi_sramstart );
73 print_num ("sramsize", bd->bi_sramsize );
0db5bca8 74#if defined(CONFIG_5xx) || defined(CONFIG_8xx) || defined(CONFIG_8260)
fe8c2806
WD
75 print_num ("immr_base", bd->bi_immr_base );
76#endif
77 print_num ("bootflags", bd->bi_bootflags );
b867d705 78#if defined(CONFIG_405GP) || defined(CONFIG_405CR) || defined(CONFIG_405EP)
fe8c2806
WD
79 print_str ("procfreq", strmhz(buf, bd->bi_procfreq));
80 print_str ("plb_busfreq", strmhz(buf, bd->bi_plb_busfreq));
b867d705 81#if defined(CONFIG_405GP) || defined(CONFIG_405EP)
fe8c2806
WD
82 print_str ("pci_busfreq", strmhz(buf, bd->bi_pci_busfreq));
83#endif
84#else
85#if defined(CONFIG_8260)
86 print_str ("vco", strmhz(buf, bd->bi_vco));
87 print_str ("sccfreq", strmhz(buf, bd->bi_sccfreq));
88 print_str ("brgfreq", strmhz(buf, bd->bi_brgfreq));
89#endif
90 print_str ("intfreq", strmhz(buf, bd->bi_intfreq));
91#if defined(CONFIG_8260)
92 print_str ("cpmfreq", strmhz(buf, bd->bi_cpmfreq));
93#endif
94 print_str ("busfreq", strmhz(buf, bd->bi_busfreq));
95#endif /* defined(CONFIG_405GP) || defined(CONFIG_405CR) */
96 printf ("ethaddr =");
97 for (i=0; i<6; ++i) {
98 printf ("%c%02X", i ? ':' : ' ', bd->bi_enetaddr[i]);
99 }
100#ifdef CONFIG_PN62
101 printf ("\neth1addr =");
102 for (i=0; i<6; ++i) {
103 printf ("%c%02X", i ? ':' : ' ', bd->bi_enet1addr[i]);
104 }
105#endif /* CONFIG_PN62 */
106#ifdef CONFIG_HERMES
107 print_str ("ethspeed", strmhz(buf, bd->bi_ethspeed));
108#endif
109 printf ("\nIP addr = "); print_IPaddr (bd->bi_ip_addr);
110 printf ("\nbaudrate = %6ld bps\n", bd->bi_baudrate );
111 return 0;
112}
113
4d75a504
WD
114#else /* MIPS */
115
116int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
117{
118 DECLARE_GLOBAL_DATA_PTR;
119
120 int i;
121 bd_t *bd = gd->bd;
122
123 print_num ("boot_params", (ulong)bd->bi_boot_params);
124 print_num ("memstart", (ulong)bd->bi_memstart);
125 print_num ("memsize", (ulong)bd->bi_memsize);
126 print_num ("flashstart", (ulong)bd->bi_flashstart);
127 print_num ("flashsize", (ulong)bd->bi_flashsize);
128 print_num ("flashoffset", (ulong)bd->bi_flashoffset);
129
130 printf ("ethaddr =");
131 for (i=0; i<6; ++i) {
132 printf ("%c%02X", i ? ':' : ' ', bd->bi_enetaddr[i]);
133 }
134 printf ("\nip_addr = ");
135 print_IPaddr (bd->bi_ip_addr);
136 printf ("\nbaudrate = %d bps\n", bd->bi_baudrate);
137
138 return 0;
139}
140#endif /* MIPS */
141
fe8c2806
WD
142#else /* ARM */
143
144int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
145{
146 DECLARE_GLOBAL_DATA_PTR;
147
148 int i;
149 bd_t *bd = gd->bd;
150
151 print_num ("arch_number", bd->bi_arch_number);
152 print_num ("env_t", (ulong)bd->bi_env);
153 print_num ("boot_params", (ulong)bd->bi_boot_params);
154
155 for (i=0; i<CONFIG_NR_DRAM_BANKS; ++i) {
dc7c9a1a
WD
156 print_num("DRAM bank", i);
157 print_num("-> start", bd->bi_dram[i].start);
158 print_num("-> size", bd->bi_dram[i].size);
fe8c2806
WD
159 }
160
161 printf ("ethaddr =");
162 for (i=0; i<6; ++i) {
163 printf ("%c%02X", i ? ':' : ' ', bd->bi_enetaddr[i]);
164 }
165 printf ("\n"
85ec0bcc 166 "ip_addr = ");
fe8c2806
WD
167 print_IPaddr (bd->bi_ip_addr);
168 printf ("\n"
85ec0bcc 169 "baudrate = %d bps\n", bd->bi_baudrate);
fe8c2806
WD
170
171 return 0;
172}
173
174#endif /* CONFIG_ARM XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
175
176static void print_num(const char *name, ulong value)
177{
178 printf ("%-12s= 0x%08lX\n", name, value);
179}
180
4d75a504 181#ifdef CONFIG_PPC
fe8c2806
WD
182static void print_str(const char *name, const char *str)
183{
184 printf ("%-12s= %6s MHz\n", name, str);
185}
4d75a504 186#endif /* CONFIG_PPC */
fe8c2806
WD
187
188#endif /* CFG_CMD_BDI */
189
190int do_go (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
191{
192 ulong addr, rc;
193 int rcode = 0;
194
195 if (argc < 2) {
196 printf ("Usage:\n%s\n", cmdtp->usage);
197 return 1;
198 }
199
200 addr = simple_strtoul(argv[1], NULL, 16);
201
dc7c9a1a 202 printf ("## Starting application at 0x%08lX ...\n", addr);
fe8c2806
WD
203
204 /*
205 * pass address parameter as argv[0] (aka command name),
206 * and all remaining args
207 */
208 rc = ((ulong (*)(int, char *[]))addr) (--argc, &argv[1]);
209 if (rc != 0) rcode = 1;
210
dc7c9a1a 211 printf ("## Application terminated, rc = 0x%lX\n", rc);
fe8c2806
WD
212 return rcode;
213}
214
215#if (CONFIG_COMMANDS & CFG_CMD_LOADS)
216int do_load_serial (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
217{
218 ulong offset = 0;
219 ulong addr;
220 int i;
221 char *env_echo;
222 int rcode = 0;
223#ifdef CFG_LOADS_BAUD_CHANGE
224 DECLARE_GLOBAL_DATA_PTR;
225 int load_baudrate, current_baudrate;
226
227 load_baudrate = current_baudrate = gd->baudrate;
228#endif
229
230 if (((env_echo = getenv("loads_echo")) != NULL) && (*env_echo == '1')) {
231 do_echo = 1;
232 } else {
233 do_echo = 0;
234 }
235
236#ifdef CFG_LOADS_BAUD_CHANGE
237 if (argc >= 2) {
238 offset = simple_strtoul(argv[1], NULL, 16);
239 }
240 if (argc == 3) {
241 load_baudrate = (int)simple_strtoul(argv[2], NULL, 10);
242
243 /* default to current baudrate */
244 if (load_baudrate == 0)
245 load_baudrate = current_baudrate;
246 }
247#else /* ! CFG_LOADS_BAUD_CHANGE */
248 if (argc == 2) {
249 offset = simple_strtoul(argv[1], NULL, 16);
250 }
251#endif /* CFG_LOADS_BAUD_CHANGE */
252
253#ifdef CFG_LOADS_BAUD_CHANGE
254 if (load_baudrate != current_baudrate) {
255 printf ("## Switch baudrate to %d bps and press ENTER ...\n",
256 load_baudrate);
257 udelay(50000);
258 gd->baudrate = load_baudrate;
259 serial_setbrg ();
260 udelay(50000);
261 for (;;) {
262 if (getc() == '\r')
263 break;
264 }
265 }
266#endif /* CFG_LOADS_BAUD_CHANGE */
267 printf ("## Ready for S-Record download ...\n");
268
269 addr = load_serial (offset);
270
271 /*
272 * Gather any trailing characters (for instance, the ^D which
273 * is sent by 'cu' after sending a file), and give the
274 * box some time (100 * 1 ms)
275 */
276 for (i=0; i<100; ++i) {
277 if (serial_tstc()) {
278 (void) serial_getc();
279 }
280 udelay(1000);
281 }
282
283 if (addr == ~0) {
284 printf ("## S-Record download aborted\n");
285 rcode = 1;
286 } else {
dc7c9a1a 287 printf ("## Start Addr = 0x%08lX\n", addr);
fe8c2806
WD
288 load_addr = addr;
289 }
290
291#ifdef CFG_LOADS_BAUD_CHANGE
292 if (load_baudrate != current_baudrate) {
293 printf ("## Switch baudrate to %d bps and press ESC ...\n",
294 current_baudrate);
295 udelay (50000);
296 gd->baudrate = current_baudrate;
297 serial_setbrg ();
298 udelay (50000);
299 for (;;) {
300 if (getc() == 0x1B) /* ESC */
301 break;
302 }
303 }
304#endif
305 return rcode;
306}
307
308static ulong
309load_serial (ulong offset)
310{
311 char record[SREC_MAXRECLEN + 1]; /* buffer for one S-Record */
312 char binbuf[SREC_MAXBINLEN]; /* buffer for binary data */
313 int binlen; /* no. of data bytes in S-Rec. */
314 int type; /* return code for record type */
315 ulong addr; /* load address from S-Record */
316 ulong size; /* number of bytes transferred */
317 char buf[32];
318 ulong store_addr;
319 ulong start_addr = ~0;
320 ulong end_addr = 0;
321 int line_count = 0;
322
323 while (read_record(record, SREC_MAXRECLEN + 1) >= 0) {
324 type = srec_decode (record, &binlen, &addr, binbuf);
325
326 if (type < 0) {
327 return (~0); /* Invalid S-Record */
328 }
329
330 switch (type) {
331 case SREC_DATA2:
332 case SREC_DATA3:
333 case SREC_DATA4:
334 store_addr = addr + offset;
59de2ed6 335#ifndef CFG_NO_FLASH
fe8c2806
WD
336 if (addr2info(store_addr)) {
337 int rc;
338
339 rc = flash_write((uchar *)binbuf,store_addr,binlen);
340 if (rc != 0) {
341 flash_perror (rc);
342 return (~0);
343 }
59de2ed6
WD
344 } else
345#endif
346 {
fe8c2806
WD
347 memcpy ((char *)(store_addr), binbuf, binlen);
348 }
349 if ((store_addr) < start_addr)
dc7c9a1a 350 start_addr = store_addr;
fe8c2806 351 if ((store_addr + binlen - 1) > end_addr)
dc7c9a1a 352 end_addr = store_addr + binlen - 1;
fe8c2806
WD
353 break;
354 case SREC_END2:
355 case SREC_END3:
356 case SREC_END4:
357 udelay (10000);
358 size = end_addr - start_addr + 1;
359 printf ("\n"
360 "## First Load Addr = 0x%08lX\n"
361 "## Last Load Addr = 0x%08lX\n"
362 "## Total Size = 0x%08lX = %ld Bytes\n",
363 start_addr, end_addr, size, size
364 );
365 flush_cache (addr, size);
366 sprintf(buf, "%lX", size);
367 setenv("filesize", buf);
368 return (addr);
369 case SREC_START:
370 break;
371 default:
372 break;
373 }
374 if (!do_echo) { /* print a '.' every 100 lines */
375 if ((++line_count % 100) == 0)
376 putc ('.');
377 }
378 }
379
380 return (~0); /* Download aborted */
381}
382
383static int
384read_record (char *buf, ulong len)
385{
386 char *p;
387 char c;
388
389 --len; /* always leave room for terminating '\0' byte */
390
391 for (p=buf; p < buf+len; ++p) {
392 c = serial_getc(); /* read character */
393 if (do_echo)
394 serial_putc (c); /* ... and echo it */
395
396 switch (c) {
397 case '\r':
398 case '\n':
399 *p = '\0';
400 return (p - buf);
401 case '\0':
402 case 0x03: /* ^C - Control C */
403 return (-1);
404 default:
405 *p = c;
406 }
407
408 /* Check for the console hangup (if any different from serial) */
52f52c14 409#ifdef CONFIG_PPC /* we don't have syscall_tbl anywhere else */
fe8c2806
WD
410 if (syscall_tbl[SYSCALL_GETC] != serial_getc) {
411 if (ctrlc()) {
412 return (-1);
413 }
414 }
52f52c14 415#endif
fe8c2806
WD
416 }
417
418 /* line too long - truncate */
419 *p = '\0';
420 return (p - buf);
421}
422
423#if (CONFIG_COMMANDS & CFG_CMD_SAVES)
424
425int do_save_serial (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
426{
427 ulong offset = 0;
428 ulong size = 0;
429#ifdef CFG_LOADS_BAUD_CHANGE
430 DECLARE_GLOBAL_DATA_PTR;
431 int save_baudrate, current_baudrate;
432
433 save_baudrate = current_baudrate = gd->baudrate;
434#endif
435
436 if (argc >= 2) {
437 offset = simple_strtoul(argv[1], NULL, 16);
438 }
439#ifdef CFG_LOADS_BAUD_CHANGE
440 if (argc >= 3) {
441 size = simple_strtoul(argv[2], NULL, 16);
442 }
443 if (argc == 4) {
444 save_baudrate = (int)simple_strtoul(argv[3], NULL, 10);
445
446 /* default to current baudrate */
447 if (save_baudrate == 0)
448 save_baudrate = current_baudrate;
449 }
450#else /* ! CFG_LOADS_BAUD_CHANGE */
451 if (argc == 3) {
452 size = simple_strtoul(argv[2], NULL, 16);
453 }
454#endif /* CFG_LOADS_BAUD_CHANGE */
455
456#ifdef CFG_LOADS_BAUD_CHANGE
457 if (save_baudrate != current_baudrate) {
458 printf ("## Switch baudrate to %d bps and press ENTER ...\n",
459 save_baudrate);
460 udelay(50000);
461 gd->baudrate = save_baudrate;
462 serial_setbrg ();
463 udelay(50000);
464 for (;;) {
465 if (getc() == '\r')
466 break;
467 }
468 }
469#endif /* CFG_LOADS_BAUD_CHANGE */
470 printf ("## Ready for S-Record upload, press ENTER to proceed ...\n");
471 for (;;) {
472 if (getc() == '\r')
473 break;
474 }
475 if(save_serial (offset, size)) {
476 printf ("## S-Record upload aborted\n");
477 } else {
478 printf ("## S-Record upload complete\n");
479 }
480#ifdef CFG_LOADS_BAUD_CHANGE
481 if (save_baudrate != current_baudrate) {
482 printf ("## Switch baudrate to %d bps and press ESC ...\n",
483 (int)current_baudrate);
484 udelay (50000);
485 gd->baudrate = current_baudrate;
486 serial_setbrg ();
487 udelay (50000);
488 for (;;) {
489 if (getc() == 0x1B) /* ESC */
490 break;
491 }
492 }
493#endif
494 return 0;
495}
496
497#define SREC3_START "S0030000FC\n"
498#define SREC3_FORMAT "S3%02X%08lX%s%02X\n"
499#define SREC3_END "S70500000000FA\n"
500#define SREC_BYTES_PER_RECORD 16
501
502static int save_serial (ulong address, ulong count)
503{
504 int i, c, reclen, checksum, length;
505 char *hex = "0123456789ABCDEF";
506 char record[2*SREC_BYTES_PER_RECORD+16]; /* buffer for one S-Record */
507 char data[2*SREC_BYTES_PER_RECORD+1]; /* buffer for hex data */
508
509 reclen = 0;
510 checksum = 0;
511
512 if(write_record(SREC3_START)) /* write the header */
513 return (-1);
514 do {
515 if(count) { /* collect hex data in the buffer */
516 c = *(volatile uchar*)(address + reclen); /* get one byte */
517 checksum += c; /* accumulate checksum */
518 data[2*reclen] = hex[(c>>4)&0x0f];
519 data[2*reclen+1] = hex[c & 0x0f];
520 data[2*reclen+2] = '\0';
521 ++reclen;
522 --count;
523 }
524 if(reclen == SREC_BYTES_PER_RECORD || count == 0) {
525 /* enough data collected for one record: dump it */
526 if(reclen) { /* build & write a data record: */
527 /* address + data + checksum */
528 length = 4 + reclen + 1;
529
530 /* accumulate length bytes into checksum */
531 for(i = 0; i < 2; i++)
532 checksum += (length >> (8*i)) & 0xff;
533
534 /* accumulate address bytes into checksum: */
535 for(i = 0; i < 4; i++)
536 checksum += (address >> (8*i)) & 0xff;
537
538 /* make proper checksum byte: */
539 checksum = ~checksum & 0xff;
540
541 /* output one record: */
542 sprintf(record, SREC3_FORMAT, length, address, data, checksum);
543 if(write_record(record))
544 return (-1);
545 }
546 address += reclen; /* increment address */
547 checksum = 0;
548 reclen = 0;
549 }
550 }
551 while(count);
552 if(write_record(SREC3_END)) /* write the final record */
553 return (-1);
554 return(0);
555}
556
557static int
558write_record (char *buf)
559{
560 char c;
561
562 while((c = *buf++))
563 serial_putc(c);
564
565 /* Check for the console hangup (if any different from serial) */
566
567 if (ctrlc()) {
568 return (-1);
569 }
570 return (0);
571}
572# endif /* CFG_CMD_SAVES */
573
574#endif /* CFG_CMD_LOADS */
575
576
577#if (CONFIG_COMMANDS & CFG_CMD_LOADB) /* loadb command (load binary) included */
578
579#define XON_CHAR 17
580#define XOFF_CHAR 19
581#define START_CHAR 0x01
85ec0bcc 582#define ETX_CHAR 0x03
fe8c2806
WD
583#define END_CHAR 0x0D
584#define SPACE 0x20
585#define K_ESCAPE 0x23
586#define SEND_TYPE 'S'
587#define DATA_TYPE 'D'
588#define ACK_TYPE 'Y'
589#define NACK_TYPE 'N'
590#define BREAK_TYPE 'B'
591#define tochar(x) ((char) (((x) + SPACE) & 0xff))
592#define untochar(x) ((int) (((x) - SPACE) & 0xff))
593
594extern int os_data_count;
595extern int os_data_header[8];
596
597static void set_kerm_bin_mode(unsigned long *);
598static int k_recv(void);
599static ulong load_serial_bin (ulong offset);
600
601
602char his_eol; /* character he needs at end of packet */
603int his_pad_count; /* number of pad chars he needs */
604char his_pad_char; /* pad chars he needs */
605char his_quote; /* quote chars he'll use */
606
607int do_load_serial_bin (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
608{
609 DECLARE_GLOBAL_DATA_PTR;
610
611 ulong offset = 0;
612 ulong addr;
fe8c2806
WD
613 int load_baudrate, current_baudrate;
614 int rcode = 0;
dc7c9a1a
WD
615 char *s;
616
617 /* pre-set offset from CFG_LOAD_ADDR */
618 offset = CFG_LOAD_ADDR;
619
620 /* pre-set offset from $loadaddr */
621 if ((s = getenv("loadaddr")) != NULL) {
622 offset = simple_strtoul(s, NULL, 16);
623 }
fe8c2806
WD
624
625 load_baudrate = current_baudrate = gd->baudrate;
626
627 if (argc >= 2) {
628 offset = simple_strtoul(argv[1], NULL, 16);
629 }
630 if (argc == 3) {
631 load_baudrate = (int)simple_strtoul(argv[2], NULL, 10);
632
633 /* default to current baudrate */
634 if (load_baudrate == 0)
635 load_baudrate = current_baudrate;
636 }
637
638 if (load_baudrate != current_baudrate) {
639 printf ("## Switch baudrate to %d bps and press ENTER ...\n",
640 load_baudrate);
641 udelay(50000);
642 gd->baudrate = load_baudrate;
643 serial_setbrg ();
644 udelay(50000);
645 for (;;) {
646 if (getc() == '\r')
647 break;
648 }
649 }
fe8c2806 650
dc7c9a1a
WD
651 printf ("## Ready for binary (kermit) download "
652 "to 0x%08lX at %d bps...\n",
653 offset,
654 current_baudrate);
fe8c2806
WD
655 addr = load_serial_bin (offset);
656
fe8c2806
WD
657 if (addr == ~0) {
658 load_addr = 0;
659 printf ("## Binary (kermit) download aborted\n");
660 rcode = 1;
661 } else {
dc7c9a1a 662 printf ("## Start Addr = 0x%08lX\n", addr);
fe8c2806
WD
663 load_addr = addr;
664 }
665
666 if (load_baudrate != current_baudrate) {
667 printf ("## Switch baudrate to %d bps and press ESC ...\n",
668 current_baudrate);
669 udelay (50000);
670 gd->baudrate = current_baudrate;
671 serial_setbrg ();
672 udelay (50000);
673 for (;;) {
674 if (getc() == 0x1B) /* ESC */
675 break;
676 }
677 }
678
679#ifdef CONFIG_AUTOSCRIPT
680 if (load_addr) {
681 char *s;
682
683 if (((s = getenv("autoscript")) != NULL) && (strcmp(s,"yes") == 0)) {
684 printf("Running autoscript at addr 0x%08lX ...\n", load_addr);
685 rcode = autoscript (load_addr);
686 }
687 }
688#endif
689 return rcode;
690}
691
692
693static ulong load_serial_bin (ulong offset)
694{
52f52c14 695 int size, i;
fe8c2806
WD
696 char buf[32];
697
698 set_kerm_bin_mode ((ulong *) offset);
699 size = k_recv ();
52f52c14
WD
700
701 /*
702 * Gather any trailing characters (for instance, the ^D which
703 * is sent by 'cu' after sending a file), and give the
704 * box some time (100 * 1 ms)
705 */
706 for (i=0; i<100; ++i) {
707 if (serial_tstc()) {
708 (void) serial_getc();
709 }
710 udelay(1000);
711 }
712
fe8c2806
WD
713 flush_cache (offset, size);
714
715 printf("## Total Size = 0x%08x = %d Bytes\n", size, size);
716 sprintf(buf, "%X", size);
717 setenv("filesize", buf);
718
719 return offset;
720}
721
722void send_pad (void)
723{
724 int count = his_pad_count;
725
726 while (count-- > 0)
727 serial_putc (his_pad_char);
728}
729
730/* converts escaped kermit char to binary char */
731char ktrans (char in)
732{
733 if ((in & 0x60) == 0x40) {
734 return (char) (in & ~0x40);
735 } else if ((in & 0x7f) == 0x3f) {
736 return (char) (in | 0x40);
737 } else
738 return in;
739}
740
741int chk1 (char *buffer)
742{
743 int total = 0;
744
745 while (*buffer) {
746 total += *buffer++;
747 }
748 return (int) ((total + ((total >> 6) & 0x03)) & 0x3f);
749}
750
751void s1_sendpacket (char *packet)
752{
753 send_pad ();
754 while (*packet) {
755 serial_putc (*packet++);
756 }
757}
758
759static char a_b[24];
760void send_ack (int n)
761{
762 a_b[0] = START_CHAR;
763 a_b[1] = tochar (3);
764 a_b[2] = tochar (n);
765 a_b[3] = ACK_TYPE;
766 a_b[4] = '\0';
767 a_b[4] = tochar (chk1 (&a_b[1]));
768 a_b[5] = his_eol;
769 a_b[6] = '\0';
770 s1_sendpacket (a_b);
771}
772
773void send_nack (int n)
774{
775 a_b[0] = START_CHAR;
776 a_b[1] = tochar (3);
777 a_b[2] = tochar (n);
778 a_b[3] = NACK_TYPE;
779 a_b[4] = '\0';
780 a_b[4] = tochar (chk1 (&a_b[1]));
781 a_b[5] = his_eol;
782 a_b[6] = '\0';
783 s1_sendpacket (a_b);
784}
785
786
787
788/* os_data_* takes an OS Open image and puts it into memory, and
789 puts the boot header in an array named os_data_header
790
791 if image is binary, no header is stored in os_data_header.
792*/
793void (*os_data_init) (void);
794void (*os_data_char) (char new_char);
795static int os_data_state, os_data_state_saved;
796int os_data_count;
797static int os_data_count_saved;
798static char *os_data_addr, *os_data_addr_saved;
799static char *bin_start_address;
800int os_data_header[8];
801static void bin_data_init (void)
802{
803 os_data_state = 0;
804 os_data_count = 0;
805 os_data_addr = bin_start_address;
806}
807static void os_data_save (void)
808{
809 os_data_state_saved = os_data_state;
810 os_data_count_saved = os_data_count;
811 os_data_addr_saved = os_data_addr;
812}
813static void os_data_restore (void)
814{
815 os_data_state = os_data_state_saved;
816 os_data_count = os_data_count_saved;
817 os_data_addr = os_data_addr_saved;
818}
819static void bin_data_char (char new_char)
820{
821 switch (os_data_state) {
822 case 0: /* data */
823 *os_data_addr++ = new_char;
824 --os_data_count;
825 break;
826 }
827}
828static void set_kerm_bin_mode (unsigned long *addr)
829{
830 bin_start_address = (char *) addr;
831 os_data_init = bin_data_init;
832 os_data_char = bin_data_char;
833}
834
835
836/* k_data_* simply handles the kermit escape translations */
837static int k_data_escape, k_data_escape_saved;
838void k_data_init (void)
839{
840 k_data_escape = 0;
841 os_data_init ();
842}
843void k_data_save (void)
844{
845 k_data_escape_saved = k_data_escape;
846 os_data_save ();
847}
848void k_data_restore (void)
849{
850 k_data_escape = k_data_escape_saved;
851 os_data_restore ();
852}
853void k_data_char (char new_char)
854{
855 if (k_data_escape) {
856 /* last char was escape - translate this character */
857 os_data_char (ktrans (new_char));
858 k_data_escape = 0;
859 } else {
860 if (new_char == his_quote) {
861 /* this char is escape - remember */
862 k_data_escape = 1;
863 } else {
864 /* otherwise send this char as-is */
865 os_data_char (new_char);
866 }
867 }
868}
869
870#define SEND_DATA_SIZE 20
871char send_parms[SEND_DATA_SIZE];
872char *send_ptr;
873
874/* handle_send_packet interprits the protocol info and builds and
875 sends an appropriate ack for what we can do */
876void handle_send_packet (int n)
877{
878 int length = 3;
879 int bytes;
880
881 /* initialize some protocol parameters */
882 his_eol = END_CHAR; /* default end of line character */
883 his_pad_count = 0;
884 his_pad_char = '\0';
885 his_quote = K_ESCAPE;
886
887 /* ignore last character if it filled the buffer */
888 if (send_ptr == &send_parms[SEND_DATA_SIZE - 1])
889 --send_ptr;
890 bytes = send_ptr - send_parms; /* how many bytes we'll process */
891 do {
892 if (bytes-- <= 0)
893 break;
894 /* handle MAXL - max length */
895 /* ignore what he says - most I'll take (here) is 94 */
896 a_b[++length] = tochar (94);
897 if (bytes-- <= 0)
898 break;
899 /* handle TIME - time you should wait for my packets */
900 /* ignore what he says - don't wait for my ack longer than 1 second */
901 a_b[++length] = tochar (1);
902 if (bytes-- <= 0)
903 break;
904 /* handle NPAD - number of pad chars I need */
905 /* remember what he says - I need none */
906 his_pad_count = untochar (send_parms[2]);
907 a_b[++length] = tochar (0);
908 if (bytes-- <= 0)
909 break;
910 /* handle PADC - pad chars I need */
911 /* remember what he says - I need none */
912 his_pad_char = ktrans (send_parms[3]);
913 a_b[++length] = 0x40; /* He should ignore this */
914 if (bytes-- <= 0)
915 break;
916 /* handle EOL - end of line he needs */
917 /* remember what he says - I need CR */
918 his_eol = untochar (send_parms[4]);
919 a_b[++length] = tochar (END_CHAR);
920 if (bytes-- <= 0)
921 break;
922 /* handle QCTL - quote control char he'll use */
923 /* remember what he says - I'll use '#' */
924 his_quote = send_parms[5];
925 a_b[++length] = '#';
926 if (bytes-- <= 0)
927 break;
928 /* handle QBIN - 8-th bit prefixing */
929 /* ignore what he says - I refuse */
930 a_b[++length] = 'N';
931 if (bytes-- <= 0)
932 break;
933 /* handle CHKT - the clock check type */
934 /* ignore what he says - I do type 1 (for now) */
935 a_b[++length] = '1';
936 if (bytes-- <= 0)
937 break;
938 /* handle REPT - the repeat prefix */
939 /* ignore what he says - I refuse (for now) */
940 a_b[++length] = 'N';
941 if (bytes-- <= 0)
942 break;
943 /* handle CAPAS - the capabilities mask */
944 /* ignore what he says - I only do long packets - I don't do windows */
945 a_b[++length] = tochar (2); /* only long packets */
946 a_b[++length] = tochar (0); /* no windows */
947 a_b[++length] = tochar (94); /* large packet msb */
948 a_b[++length] = tochar (94); /* large packet lsb */
949 } while (0);
950
951 a_b[0] = START_CHAR;
952 a_b[1] = tochar (length);
953 a_b[2] = tochar (n);
954 a_b[3] = ACK_TYPE;
955 a_b[++length] = '\0';
956 a_b[length] = tochar (chk1 (&a_b[1]));
957 a_b[++length] = his_eol;
958 a_b[++length] = '\0';
959 s1_sendpacket (a_b);
960}
961
962/* k_recv receives a OS Open image file over kermit line */
963static int k_recv (void)
964{
965 char new_char;
966 char k_state, k_state_saved;
967 int sum;
968 int done;
969 int length;
970 int n, last_n;
971 int z = 0;
972 int len_lo, len_hi;
973
974 /* initialize some protocol parameters */
975 his_eol = END_CHAR; /* default end of line character */
976 his_pad_count = 0;
977 his_pad_char = '\0';
978 his_quote = K_ESCAPE;
979
980 /* initialize the k_recv and k_data state machine */
981 done = 0;
982 k_state = 0;
983 k_data_init ();
984 k_state_saved = k_state;
985 k_data_save ();
986 n = 0; /* just to get rid of a warning */
987 last_n = -1;
988
989 /* expect this "type" sequence (but don't check):
990 S: send initiate
991 F: file header
992 D: data (multiple)
993 Z: end of file
994 B: break transmission
995 */
996
997 /* enter main loop */
998 while (!done) {
999 /* set the send packet pointer to begining of send packet parms */
1000 send_ptr = send_parms;
1001
1002 /* With each packet, start summing the bytes starting with the length.
1003 Save the current sequence number.
1004 Note the type of the packet.
1005 If a character less than SPACE (0x20) is received - error.
1006 */
1007
1008#if 0
1009 /* OLD CODE, Prior to checking sequence numbers */
1010 /* first have all state machines save current states */
1011 k_state_saved = k_state;
1012 k_data_save ();
1013#endif
1014
1015 /* get a packet */
85ec0bcc
WD
1016 /* wait for the starting character or ^C */
1017 for (;;) {
1018 switch (serial_getc ()) {
1019 case START_CHAR: /* start packet */
60fbe254 1020 goto START;
85ec0bcc
WD
1021 case ETX_CHAR: /* ^C waiting for packet */
1022 return (0);
1023 default:
1024 ;
1025 }
1026 }
60fbe254 1027START:
fe8c2806
WD
1028 /* get length of packet */
1029 sum = 0;
1030 new_char = serial_getc ();
1031 if ((new_char & 0xE0) == 0)
1032 goto packet_error;
1033 sum += new_char & 0xff;
1034 length = untochar (new_char);
1035 /* get sequence number */
1036 new_char = serial_getc ();
1037 if ((new_char & 0xE0) == 0)
1038 goto packet_error;
1039 sum += new_char & 0xff;
1040 n = untochar (new_char);
1041 --length;
1042
1043 /* NEW CODE - check sequence numbers for retried packets */
1044 /* Note - this new code assumes that the sequence number is correctly
1045 * received. Handling an invalid sequence number adds another layer
1046 * of complexity that may not be needed - yet! At this time, I'm hoping
1047 * that I don't need to buffer the incoming data packets and can write
1048 * the data into memory in real time.
1049 */
1050 if (n == last_n) {
1051 /* same sequence number, restore the previous state */
1052 k_state = k_state_saved;
1053 k_data_restore ();
1054 } else {
1055 /* new sequence number, checkpoint the download */
1056 last_n = n;
1057 k_state_saved = k_state;
1058 k_data_save ();
1059 }
1060 /* END NEW CODE */
1061
1062 /* get packet type */
1063 new_char = serial_getc ();
1064 if ((new_char & 0xE0) == 0)
1065 goto packet_error;
1066 sum += new_char & 0xff;
1067 k_state = new_char;
1068 --length;
1069 /* check for extended length */
1070 if (length == -2) {
1071 /* (length byte was 0, decremented twice) */
1072 /* get the two length bytes */
1073 new_char = serial_getc ();
1074 if ((new_char & 0xE0) == 0)
1075 goto packet_error;
1076 sum += new_char & 0xff;
1077 len_hi = untochar (new_char);
1078 new_char = serial_getc ();
1079 if ((new_char & 0xE0) == 0)
1080 goto packet_error;
1081 sum += new_char & 0xff;
1082 len_lo = untochar (new_char);
1083 length = len_hi * 95 + len_lo;
1084 /* check header checksum */
1085 new_char = serial_getc ();
1086 if ((new_char & 0xE0) == 0)
1087 goto packet_error;
1088 if (new_char != tochar ((sum + ((sum >> 6) & 0x03)) & 0x3f))
1089 goto packet_error;
1090 sum += new_char & 0xff;
1091/* --length; */ /* new length includes only data and block check to come */
1092 }
1093 /* bring in rest of packet */
1094 while (length > 1) {
1095 new_char = serial_getc ();
1096 if ((new_char & 0xE0) == 0)
1097 goto packet_error;
1098 sum += new_char & 0xff;
1099 --length;
1100 if (k_state == DATA_TYPE) {
1101 /* pass on the data if this is a data packet */
1102 k_data_char (new_char);
1103 } else if (k_state == SEND_TYPE) {
1104 /* save send pack in buffer as is */
1105 *send_ptr++ = new_char;
1106 /* if too much data, back off the pointer */
1107 if (send_ptr >= &send_parms[SEND_DATA_SIZE])
1108 --send_ptr;
1109 }
1110 }
1111 /* get and validate checksum character */
1112 new_char = serial_getc ();
1113 if ((new_char & 0xE0) == 0)
1114 goto packet_error;
1115 if (new_char != tochar ((sum + ((sum >> 6) & 0x03)) & 0x3f))
1116 goto packet_error;
1117 /* get END_CHAR */
1118 new_char = serial_getc ();
1119 if (new_char != END_CHAR) {
1120 packet_error:
1121 /* restore state machines */
1122 k_state = k_state_saved;
1123 k_data_restore ();
1124 /* send a negative acknowledge packet in */
1125 send_nack (n);
1126 } else if (k_state == SEND_TYPE) {
1127 /* crack the protocol parms, build an appropriate ack packet */
1128 handle_send_packet (n);
1129 } else {
1130 /* send simple acknowledge packet in */
1131 send_ack (n);
1132 /* quit if end of transmission */
1133 if (k_state == BREAK_TYPE)
1134 done = 1;
1135 }
1136 ++z;
1137 }
1138 return ((ulong) os_data_addr - (ulong) bin_start_address);
1139}
1140#endif /* CFG_CMD_LOADB */
1141#if (CONFIG_COMMANDS & CFG_CMD_HWFLOW)
1142int do_hwflow (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
1143{
1144 extern int hwflow_onoff(int);
1145
1146 if (argc == 2) {
1147 if (strcmp(argv[1], "off") == 0)
1148 hwflow_onoff(-1);
1149 else
1150 if (strcmp(argv[1], "on") == 0)
1151 hwflow_onoff(1);
1152 else
1153 printf("Usage: %s\n", cmdtp->usage);
1154 }
1155 printf("RTS/CTS hardware flow control: %s\n", hwflow_onoff(0) ? "on" : "off");
1156 return 0;
1157}
1158#endif /* CFG_CMD_HWFLOW */