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