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