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