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