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