]> git.karo-electronics.de Git - karo-tx-uboot.git/blob - common/cmd_load.c
video: ipu: ipu-bugfixes
[karo-tx-uboot.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);
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);
466
467         } else {
468
469                 printf("## Ready for binary (kermit) download "
470                         "to 0x%08lX at %d bps...\n",
471                         offset,
472                         load_baudrate);
473                 addr = load_serial_bin(offset);
474
475                 if (addr == ~0) {
476                         load_addr = 0;
477                         printf("## Binary (kermit) download aborted\n");
478                         rcode = 1;
479                 } else {
480                         printf("## Start Addr      = 0x%08lX\n", addr);
481                         load_addr = addr;
482                 }
483         }
484         if (load_baudrate != current_baudrate) {
485                 printf("## Switch baudrate to %d bps and press ESC ...\n",
486                         current_baudrate);
487                 udelay(50000);
488                 gd->baudrate = current_baudrate;
489                 serial_setbrg();
490                 udelay(50000);
491                 for (;;) {
492                         if (getc() == 0x1B) /* ESC */
493                                 break;
494                 }
495         }
496
497         return rcode;
498 }
499
500
501 static ulong load_serial_bin(ulong offset)
502 {
503         int size, i;
504
505         set_kerm_bin_mode((ulong *) offset);
506         size = k_recv();
507
508         /*
509          * Gather any trailing characters (for instance, the ^D which
510          * is sent by 'cu' after sending a file), and give the
511          * box some time (100 * 1 ms)
512          */
513         for (i=0; i<100; ++i) {
514                 if (tstc()) {
515                         (void) getc();
516                 }
517                 udelay(1000);
518         }
519
520         flush_cache(offset, size);
521
522         printf("## Total Size      = 0x%08x = %d Bytes\n", size, size);
523         setenv_hex("filesize", size);
524
525         return offset;
526 }
527
528 static void send_pad(void)
529 {
530         int count = his_pad_count;
531
532         while (count-- > 0)
533                 putc(his_pad_char);
534 }
535
536 /* converts escaped kermit char to binary char */
537 static char ktrans(char in)
538 {
539         if ((in & 0x60) == 0x40) {
540                 return (char) (in & ~0x40);
541         } else if ((in & 0x7f) == 0x3f) {
542                 return (char) (in | 0x40);
543         } else
544                 return in;
545 }
546
547 static int chk1(char *buffer)
548 {
549         int total = 0;
550
551         while (*buffer) {
552                 total += *buffer++;
553         }
554         return (int) ((total + ((total >> 6) & 0x03)) & 0x3f);
555 }
556
557 static void s1_sendpacket(char *packet)
558 {
559         send_pad();
560         while (*packet) {
561                 putc(*packet++);
562         }
563 }
564
565 static char a_b[24];
566 static void send_ack(int n)
567 {
568         a_b[0] = START_CHAR;
569         a_b[1] = tochar(3);
570         a_b[2] = tochar(n);
571         a_b[3] = ACK_TYPE;
572         a_b[4] = '\0';
573         a_b[4] = tochar(chk1(&a_b[1]));
574         a_b[5] = his_eol;
575         a_b[6] = '\0';
576         s1_sendpacket(a_b);
577 }
578
579 static void send_nack(int n)
580 {
581         a_b[0] = START_CHAR;
582         a_b[1] = tochar(3);
583         a_b[2] = tochar(n);
584         a_b[3] = NACK_TYPE;
585         a_b[4] = '\0';
586         a_b[4] = tochar(chk1(&a_b[1]));
587         a_b[5] = his_eol;
588         a_b[6] = '\0';
589         s1_sendpacket(a_b);
590 }
591
592
593 static void (*os_data_init)(void);
594 static void (*os_data_char)(char new_char);
595 static int os_data_state, os_data_state_saved;
596 static char *os_data_addr, *os_data_addr_saved;
597 static char *bin_start_address;
598
599 static void bin_data_init(void)
600 {
601         os_data_state = 0;
602         os_data_addr = bin_start_address;
603 }
604
605 static void os_data_save(void)
606 {
607         os_data_state_saved = os_data_state;
608         os_data_addr_saved = os_data_addr;
609 }
610
611 static void os_data_restore(void)
612 {
613         os_data_state = os_data_state_saved;
614         os_data_addr = os_data_addr_saved;
615 }
616
617 static void bin_data_char(char new_char)
618 {
619         switch (os_data_state) {
620         case 0:                                 /* data */
621                 *os_data_addr++ = new_char;
622                 break;
623         }
624 }
625
626 static void set_kerm_bin_mode(unsigned long *addr)
627 {
628         bin_start_address = (char *) addr;
629         os_data_init = bin_data_init;
630         os_data_char = bin_data_char;
631 }
632
633
634 /* k_data_* simply handles the kermit escape translations */
635 static int k_data_escape, k_data_escape_saved;
636 static void k_data_init(void)
637 {
638         k_data_escape = 0;
639         os_data_init();
640 }
641
642 static void k_data_save(void)
643 {
644         k_data_escape_saved = k_data_escape;
645         os_data_save();
646 }
647
648 static void k_data_restore(void)
649 {
650         k_data_escape = k_data_escape_saved;
651         os_data_restore();
652 }
653
654 static void k_data_char(char new_char)
655 {
656         if (k_data_escape) {
657                 /* last char was escape - translate this character */
658                 os_data_char(ktrans(new_char));
659                 k_data_escape = 0;
660         } else {
661                 if (new_char == his_quote) {
662                         /* this char is escape - remember */
663                         k_data_escape = 1;
664                 } else {
665                         /* otherwise send this char as-is */
666                         os_data_char(new_char);
667                 }
668         }
669 }
670
671 #define SEND_DATA_SIZE  20
672 static char send_parms[SEND_DATA_SIZE];
673 static char *send_ptr;
674
675 /* handle_send_packet interprits the protocol info and builds and
676    sends an appropriate ack for what we can do */
677 static void handle_send_packet(int n)
678 {
679         int length = 3;
680         int bytes;
681
682         /* initialize some protocol parameters */
683         his_eol = END_CHAR;             /* default end of line character */
684         his_pad_count = 0;
685         his_pad_char = '\0';
686         his_quote = K_ESCAPE;
687
688         /* ignore last character if it filled the buffer */
689         if (send_ptr == &send_parms[SEND_DATA_SIZE - 1])
690                 --send_ptr;
691         bytes = send_ptr - send_parms;  /* how many bytes we'll process */
692         do {
693                 if (bytes-- <= 0)
694                         break;
695                 /* handle MAXL - max length */
696                 /* ignore what he says - most I'll take (here) is 94 */
697                 a_b[++length] = tochar(94);
698                 if (bytes-- <= 0)
699                         break;
700                 /* handle TIME - time you should wait for my packets */
701                 /* ignore what he says - don't wait for my ack longer than 1 second */
702                 a_b[++length] = tochar(1);
703                 if (bytes-- <= 0)
704                         break;
705                 /* handle NPAD - number of pad chars I need */
706                 /* remember what he says - I need none */
707                 his_pad_count = untochar(send_parms[2]);
708                 a_b[++length] = tochar(0);
709                 if (bytes-- <= 0)
710                         break;
711                 /* handle PADC - pad chars I need */
712                 /* remember what he says - I need none */
713                 his_pad_char = ktrans(send_parms[3]);
714                 a_b[++length] = 0x40;   /* He should ignore this */
715                 if (bytes-- <= 0)
716                         break;
717                 /* handle EOL - end of line he needs */
718                 /* remember what he says - I need CR */
719                 his_eol = untochar(send_parms[4]);
720                 a_b[++length] = tochar(END_CHAR);
721                 if (bytes-- <= 0)
722                         break;
723                 /* handle QCTL - quote control char he'll use */
724                 /* remember what he says - I'll use '#' */
725                 his_quote = send_parms[5];
726                 a_b[++length] = '#';
727                 if (bytes-- <= 0)
728                         break;
729                 /* handle QBIN - 8-th bit prefixing */
730                 /* ignore what he says - I refuse */
731                 a_b[++length] = 'N';
732                 if (bytes-- <= 0)
733                         break;
734                 /* handle CHKT - the clock check type */
735                 /* ignore what he says - I do type 1 (for now) */
736                 a_b[++length] = '1';
737                 if (bytes-- <= 0)
738                         break;
739                 /* handle REPT - the repeat prefix */
740                 /* ignore what he says - I refuse (for now) */
741                 a_b[++length] = 'N';
742                 if (bytes-- <= 0)
743                         break;
744                 /* handle CAPAS - the capabilities mask */
745                 /* ignore what he says - I only do long packets - I don't do windows */
746                 a_b[++length] = tochar(2);      /* only long packets */
747                 a_b[++length] = tochar(0);      /* no windows */
748                 a_b[++length] = tochar(94);     /* large packet msb */
749                 a_b[++length] = tochar(94);     /* large packet lsb */
750         } while (0);
751
752         a_b[0] = START_CHAR;
753         a_b[1] = tochar(length);
754         a_b[2] = tochar(n);
755         a_b[3] = ACK_TYPE;
756         a_b[++length] = '\0';
757         a_b[length] = tochar(chk1(&a_b[1]));
758         a_b[++length] = his_eol;
759         a_b[++length] = '\0';
760         s1_sendpacket(a_b);
761 }
762
763 /* k_recv receives a OS Open image file over kermit line */
764 static int k_recv(void)
765 {
766         char new_char;
767         char k_state, k_state_saved;
768         int sum;
769         int done;
770         int length;
771         int n, last_n;
772         int len_lo, len_hi;
773
774         /* initialize some protocol parameters */
775         his_eol = END_CHAR;             /* default end of line character */
776         his_pad_count = 0;
777         his_pad_char = '\0';
778         his_quote = K_ESCAPE;
779
780         /* initialize the k_recv and k_data state machine */
781         done = 0;
782         k_state = 0;
783         k_data_init();
784         k_state_saved = k_state;
785         k_data_save();
786         n = 0;                          /* just to get rid of a warning */
787         last_n = -1;
788
789         /* expect this "type" sequence (but don't check):
790            S: send initiate
791            F: file header
792            D: data (multiple)
793            Z: end of file
794            B: break transmission
795          */
796
797         /* enter main loop */
798         while (!done) {
799                 /* set the send packet pointer to begining of send packet parms */
800                 send_ptr = send_parms;
801
802                 /* With each packet, start summing the bytes starting with the length.
803                    Save the current sequence number.
804                    Note the type of the packet.
805                    If a character less than SPACE (0x20) is received - error.
806                  */
807
808 #if 0
809                 /* OLD CODE, Prior to checking sequence numbers */
810                 /* first have all state machines save current states */
811                 k_state_saved = k_state;
812                 k_data_save ();
813 #endif
814
815                 /* get a packet */
816                 /* wait for the starting character or ^C */
817                 for (;;) {
818                         switch (getc ()) {
819                         case START_CHAR:        /* start packet */
820                                 goto START;
821                         case ETX_CHAR:          /* ^C waiting for packet */
822                                 return (0);
823                         default:
824                                 ;
825                         }
826                 }
827 START:
828                 /* get length of packet */
829                 sum = 0;
830                 new_char = getc();
831                 if ((new_char & 0xE0) == 0)
832                         goto packet_error;
833                 sum += new_char & 0xff;
834                 length = untochar(new_char);
835                 /* get sequence number */
836                 new_char = getc();
837                 if ((new_char & 0xE0) == 0)
838                         goto packet_error;
839                 sum += new_char & 0xff;
840                 n = untochar(new_char);
841                 --length;
842
843                 /* NEW CODE - check sequence numbers for retried packets */
844                 /* Note - this new code assumes that the sequence number is correctly
845                  * received.  Handling an invalid sequence number adds another layer
846                  * of complexity that may not be needed - yet!  At this time, I'm hoping
847                  * that I don't need to buffer the incoming data packets and can write
848                  * the data into memory in real time.
849                  */
850                 if (n == last_n) {
851                         /* same sequence number, restore the previous state */
852                         k_state = k_state_saved;
853                         k_data_restore();
854                 } else {
855                         /* new sequence number, checkpoint the download */
856                         last_n = n;
857                         k_state_saved = k_state;
858                         k_data_save();
859                 }
860                 /* END NEW CODE */
861
862                 /* get packet type */
863                 new_char = getc();
864                 if ((new_char & 0xE0) == 0)
865                         goto packet_error;
866                 sum += new_char & 0xff;
867                 k_state = new_char;
868                 --length;
869                 /* check for extended length */
870                 if (length == -2) {
871                         /* (length byte was 0, decremented twice) */
872                         /* get the two length bytes */
873                         new_char = getc();
874                         if ((new_char & 0xE0) == 0)
875                                 goto packet_error;
876                         sum += new_char & 0xff;
877                         len_hi = untochar(new_char);
878                         new_char = getc();
879                         if ((new_char & 0xE0) == 0)
880                                 goto packet_error;
881                         sum += new_char & 0xff;
882                         len_lo = untochar(new_char);
883                         length = len_hi * 95 + len_lo;
884                         /* check header checksum */
885                         new_char = getc();
886                         if ((new_char & 0xE0) == 0)
887                                 goto packet_error;
888                         if (new_char != tochar((sum + ((sum >> 6) & 0x03)) & 0x3f))
889                                 goto packet_error;
890                         sum += new_char & 0xff;
891 /* --length; */ /* new length includes only data and block check to come */
892                 }
893                 /* bring in rest of packet */
894                 while (length > 1) {
895                         new_char = getc();
896                         if ((new_char & 0xE0) == 0)
897                                 goto packet_error;
898                         sum += new_char & 0xff;
899                         --length;
900                         if (k_state == DATA_TYPE) {
901                                 /* pass on the data if this is a data packet */
902                                 k_data_char (new_char);
903                         } else if (k_state == SEND_TYPE) {
904                                 /* save send pack in buffer as is */
905                                 *send_ptr++ = new_char;
906                                 /* if too much data, back off the pointer */
907                                 if (send_ptr >= &send_parms[SEND_DATA_SIZE])
908                                         --send_ptr;
909                         }
910                 }
911                 /* get and validate checksum character */
912                 new_char = getc();
913                 if ((new_char & 0xE0) == 0)
914                         goto packet_error;
915                 if (new_char != tochar((sum + ((sum >> 6) & 0x03)) & 0x3f))
916                         goto packet_error;
917                 /* get END_CHAR */
918                 new_char = getc();
919                 if (new_char != END_CHAR) {
920                   packet_error:
921                         /* restore state machines */
922                         k_state = k_state_saved;
923                         k_data_restore();
924                         /* send a negative acknowledge packet in */
925                         send_nack(n);
926                 } else if (k_state == SEND_TYPE) {
927                         /* crack the protocol parms, build an appropriate ack packet */
928                         handle_send_packet(n);
929                 } else {
930                         /* send simple acknowledge packet in */
931                         send_ack(n);
932                         /* quit if end of transmission */
933                         if (k_state == BREAK_TYPE)
934                                 done = 1;
935                 }
936         }
937         return ((ulong) os_data_addr - (ulong) bin_start_address);
938 }
939
940 static int getcxmodem(void) {
941         if (tstc())
942                 return (getc());
943         return -1;
944 }
945 static ulong load_serial_ymodem(ulong offset)
946 {
947         int size;
948         int err;
949         int res;
950         connection_info_t info;
951         char ymodemBuf[1024];
952         ulong store_addr = ~0;
953         ulong addr = 0;
954
955         size = 0;
956         info.mode = xyzModem_ymodem;
957         res = xyzModem_stream_open(&info, &err);
958         if (!res) {
959
960                 while ((res =
961                         xyzModem_stream_read(ymodemBuf, 1024, &err)) > 0) {
962                         store_addr = addr + offset;
963                         size += res;
964                         addr += res;
965 #ifndef CONFIG_SYS_NO_FLASH
966                         if (addr2info(store_addr)) {
967                                 int rc;
968
969                                 rc = flash_write((char *) ymodemBuf,
970                                                   store_addr, res);
971                                 if (rc != 0) {
972                                         flash_perror (rc);
973                                         return (~0);
974                                 }
975                         } else
976 #endif
977                         {
978                                 memcpy((char *)(store_addr), ymodemBuf,
979                                         res);
980                         }
981
982                 }
983         } else {
984                 printf("%s\n", xyzModem_error(err));
985         }
986
987         xyzModem_stream_close(&err);
988         xyzModem_stream_terminate(false, &getcxmodem);
989
990
991         flush_cache(offset, size);
992
993         printf("## Total Size      = 0x%08x = %d Bytes\n", size, size);
994         setenv_hex("filesize", size);
995
996         return offset;
997 }
998
999 #endif
1000
1001 /* -------------------------------------------------------------------- */
1002
1003 #if defined(CONFIG_CMD_LOADS)
1004
1005 #ifdef  CONFIG_SYS_LOADS_BAUD_CHANGE
1006 U_BOOT_CMD(
1007         loads, 3, 0,    do_load_serial,
1008         "load S-Record file over serial line",
1009         "[ off ] [ baud ]\n"
1010         "    - load S-Record file over serial line"
1011         " with offset 'off' and baudrate 'baud'"
1012 );
1013
1014 #else   /* ! CONFIG_SYS_LOADS_BAUD_CHANGE */
1015 U_BOOT_CMD(
1016         loads, 2, 0,    do_load_serial,
1017         "load S-Record file over serial line",
1018         "[ off ]\n"
1019         "    - load S-Record file over serial line with offset 'off'"
1020 );
1021 #endif  /* CONFIG_SYS_LOADS_BAUD_CHANGE */
1022
1023 /*
1024  * SAVES always requires LOADS support, but not vice versa
1025  */
1026
1027
1028 #if defined(CONFIG_CMD_SAVES)
1029 #ifdef  CONFIG_SYS_LOADS_BAUD_CHANGE
1030 U_BOOT_CMD(
1031         saves, 4, 0,    do_save_serial,
1032         "save S-Record file over serial line",
1033         "[ off ] [size] [ baud ]\n"
1034         "    - save S-Record file over serial line"
1035         " with offset 'off', size 'size' and baudrate 'baud'"
1036 );
1037 #else   /* ! CONFIG_SYS_LOADS_BAUD_CHANGE */
1038 U_BOOT_CMD(
1039         saves, 3, 0,    do_save_serial,
1040         "save S-Record file over serial line",
1041         "[ off ] [size]\n"
1042         "    - save S-Record file over serial line with offset 'off' and size 'size'"
1043 );
1044 #endif  /* CONFIG_SYS_LOADS_BAUD_CHANGE */
1045 #endif  /* CONFIG_CMD_SAVES */
1046 #endif  /* CONFIG_CMD_LOADS */
1047
1048
1049 #if defined(CONFIG_CMD_LOADB)
1050 U_BOOT_CMD(
1051         loadb, 3, 0,    do_load_serial_bin,
1052         "load binary file over serial line (kermit mode)",
1053         "[ off ] [ baud ]\n"
1054         "    - load binary file over serial line"
1055         " with offset 'off' and baudrate 'baud'"
1056 );
1057
1058 U_BOOT_CMD(
1059         loady, 3, 0,    do_load_serial_bin,
1060         "load binary file over serial line (ymodem mode)",
1061         "[ off ] [ baud ]\n"
1062         "    - load binary file over serial line"
1063         " with offset 'off' and baudrate 'baud'"
1064 );
1065
1066 #endif  /* CONFIG_CMD_LOADB */
1067
1068 /* -------------------------------------------------------------------- */
1069
1070 #if defined(CONFIG_CMD_HWFLOW)
1071 int do_hwflow(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
1072 {
1073         extern int hwflow_onoff(int);
1074
1075         if (argc == 2) {
1076                 if (strcmp(argv[1], "off") == 0)
1077                         hwflow_onoff(-1);
1078                 else
1079                         if (strcmp(argv[1], "on") == 0)
1080                                 hwflow_onoff(1);
1081                         else
1082                                 return CMD_RET_USAGE;
1083         }
1084         printf("RTS/CTS hardware flow control: %s\n", hwflow_onoff(0) ? "on" : "off");
1085         return 0;
1086 }
1087
1088 /* -------------------------------------------------------------------- */
1089
1090 U_BOOT_CMD(
1091         hwflow, 2, 0,   do_hwflow,
1092         "turn RTS/CTS hardware flow control in serial line on/off",
1093         "[on|off]"
1094 );
1095
1096 #endif  /* CONFIG_CMD_HWFLOW */