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