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