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