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