~ubuntu-branches/ubuntu/maverick/u-boot-omap3/maverick

« back to all changes in this revision

Viewing changes to common/cmd_load.c

  • Committer: Bazaar Package Importer
  • Author(s): Oliver Grawert
  • Date: 2010-03-22 15:06:23 UTC
  • Revision ID: james.westby@ubuntu.com-20100322150623-i21g8rgiyl5dohag
Tags: upstream-2010.3git20100315
ImportĀ upstreamĀ versionĀ 2010.3git20100315

Show diffs side-by-side

added added

removed removed

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