Home | History | Annotate | Download | only in cmd
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * (C) Copyright 2000-2004
      4  * Wolfgang Denk, DENX Software Engineering, wd (at) 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