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