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