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