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