Blame view

cmd/load.c 24.6 KB
8bde7f776   wdenk   * Code cleanup:
1
  /*
232c150a2   wdenk   Add support for S...
2
   * (C) Copyright 2000-2004
8bde7f776   wdenk   * Code cleanup:
3
4
   * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   *
1a4596601   Wolfgang Denk   Add GPL-2.0+ SPDX...
5
   * SPDX-License-Identifier:	GPL-2.0+
8bde7f776   wdenk   * Code cleanup:
6
7
8
9
10
11
12
   */
  
  /*
   * Serial up- and download support
   */
  #include <common.h>
  #include <command.h>
24b852a7a   Simon Glass   Move console defi...
13
  #include <console.h>
8bde7f776   wdenk   * Code cleanup:
14
15
  #include <s_record.h>
  #include <net.h>
27b207fd0   wdenk   * Implement new m...
16
  #include <exports.h>
f2841d377   Markus Klotzbuecher   Add support for y...
17
  #include <xyzModem.h>
8bde7f776   wdenk   * Code cleanup:
18

d87080b72   Wolfgang Denk   GCC-4.x fixes: cl...
19
  DECLARE_GLOBAL_DATA_PTR;
8bde7f776   wdenk   * Code cleanup:
20

c76fe4742   Jon Loeliger   common/cmd_[i-n]*...
21
  #if defined(CONFIG_CMD_LOADB)
6e66bd559   Angus Ainslie   Enable xmodem sup...
22
  static ulong load_serial_ymodem(ulong offset, int mode);
8546e2390   Wolfgang Denk   Declare load_seri...
23
  #endif
c76fe4742   Jon Loeliger   common/cmd_[i-n]*...
24
  #if defined(CONFIG_CMD_LOADS)
088f1b199   Kim Phillips   common/cmd_*.c: s...
25
26
  static ulong load_serial(long offset);
  static int read_record(char *buf, ulong len);
c76fe4742   Jon Loeliger   common/cmd_[i-n]*...
27
  # if defined(CONFIG_CMD_SAVES)
088f1b199   Kim Phillips   common/cmd_*.c: s...
28
29
  static int save_serial(ulong offset, ulong size);
  static int write_record(char *buf);
902531788   Jon Loeliger   common/: Remove l...
30
  #endif
8bde7f776   wdenk   * Code cleanup:
31
32
  
  static int do_echo = 1;
902531788   Jon Loeliger   common/: Remove l...
33
  #endif
8bde7f776   wdenk   * Code cleanup:
34
35
  
  /* -------------------------------------------------------------------- */
c76fe4742   Jon Loeliger   common/cmd_[i-n]*...
36
  #if defined(CONFIG_CMD_LOADS)
088f1b199   Kim Phillips   common/cmd_*.c: s...
37
38
  static int do_load_serial(cmd_tbl_t *cmdtp, int flag, int argc,
  			  char * const argv[])
8bde7f776   wdenk   * Code cleanup:
39
  {
2b22d608f   Ricardo Ribalda Delgado   loads: allow nega...
40
  	long offset = 0;
8bde7f776   wdenk   * Code cleanup:
41
42
43
44
  	ulong addr;
  	int i;
  	char *env_echo;
  	int rcode = 0;
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
45
  #ifdef	CONFIG_SYS_LOADS_BAUD_CHANGE
8bde7f776   wdenk   * Code cleanup:
46
47
48
49
  	int load_baudrate, current_baudrate;
  
  	load_baudrate = current_baudrate = gd->baudrate;
  #endif
00caae6d4   Simon Glass   env: Rename geten...
50
51
  	env_echo = env_get("loads_echo");
  	if (env_echo && *env_echo == '1')
8bde7f776   wdenk   * Code cleanup:
52
  		do_echo = 1;
00caae6d4   Simon Glass   env: Rename geten...
53
  	else
8bde7f776   wdenk   * Code cleanup:
54
  		do_echo = 0;
8bde7f776   wdenk   * Code cleanup:
55

6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
56
  #ifdef	CONFIG_SYS_LOADS_BAUD_CHANGE
8bde7f776   wdenk   * Code cleanup:
57
  	if (argc >= 2) {
2b22d608f   Ricardo Ribalda Delgado   loads: allow nega...
58
  		offset = simple_strtol(argv[1], NULL, 16);
8bde7f776   wdenk   * Code cleanup:
59
60
61
62
63
64
65
66
67
  	}
  	if (argc == 3) {
  		load_baudrate = (int)simple_strtoul(argv[2], NULL, 10);
  
  		/* default to current baudrate */
  		if (load_baudrate == 0)
  			load_baudrate = current_baudrate;
  	}
  	if (load_baudrate != current_baudrate) {
088f1b199   Kim Phillips   common/cmd_*.c: s...
68
69
  		printf("## Switch baudrate to %d bps and press ENTER ...
  ",
8bde7f776   wdenk   * Code cleanup:
70
71
72
  			load_baudrate);
  		udelay(50000);
  		gd->baudrate = load_baudrate;
088f1b199   Kim Phillips   common/cmd_*.c: s...
73
  		serial_setbrg();
8bde7f776   wdenk   * Code cleanup:
74
75
76
77
78
79
  		udelay(50000);
  		for (;;) {
  			if (getc() == '\r')
  				break;
  		}
  	}
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
80
  #else	/* ! CONFIG_SYS_LOADS_BAUD_CHANGE */
8bde7f776   wdenk   * Code cleanup:
81
  	if (argc == 2) {
2b22d608f   Ricardo Ribalda Delgado   loads: allow nega...
82
  		offset = simple_strtol(argv[1], NULL, 16);
8bde7f776   wdenk   * Code cleanup:
83
  	}
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
84
  #endif	/* CONFIG_SYS_LOADS_BAUD_CHANGE */
8bde7f776   wdenk   * Code cleanup:
85

088f1b199   Kim Phillips   common/cmd_*.c: s...
86
87
  	printf("## Ready for S-Record download ...
  ");
8bde7f776   wdenk   * Code cleanup:
88

088f1b199   Kim Phillips   common/cmd_*.c: s...
89
  	addr = load_serial(offset);
8bde7f776   wdenk   * Code cleanup:
90
91
92
93
94
95
96
  
  	/*
  	 * Gather any trailing characters (for instance, the ^D which
  	 * is sent by 'cu' after sending a file), and give the
  	 * box some time (100 * 1 ms)
  	 */
  	for (i=0; i<100; ++i) {
232c150a2   wdenk   Add support for S...
97
98
  		if (tstc()) {
  			(void) getc();
8bde7f776   wdenk   * Code cleanup:
99
100
101
102
103
  		}
  		udelay(1000);
  	}
  
  	if (addr == ~0) {
088f1b199   Kim Phillips   common/cmd_*.c: s...
104
105
  		printf("## S-Record download aborted
  ");
8bde7f776   wdenk   * Code cleanup:
106
107
  		rcode = 1;
  	} else {
088f1b199   Kim Phillips   common/cmd_*.c: s...
108
109
  		printf("## Start Addr      = 0x%08lX
  ", addr);
8bde7f776   wdenk   * Code cleanup:
110
111
  		load_addr = addr;
  	}
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
112
  #ifdef	CONFIG_SYS_LOADS_BAUD_CHANGE
8bde7f776   wdenk   * Code cleanup:
113
  	if (load_baudrate != current_baudrate) {
088f1b199   Kim Phillips   common/cmd_*.c: s...
114
115
  		printf("## Switch baudrate to %d bps and press ESC ...
  ",
8bde7f776   wdenk   * Code cleanup:
116
  			current_baudrate);
088f1b199   Kim Phillips   common/cmd_*.c: s...
117
  		udelay(50000);
8bde7f776   wdenk   * Code cleanup:
118
  		gd->baudrate = current_baudrate;
088f1b199   Kim Phillips   common/cmd_*.c: s...
119
120
  		serial_setbrg();
  		udelay(50000);
8bde7f776   wdenk   * Code cleanup:
121
122
123
124
125
126
127
128
  		for (;;) {
  			if (getc() == 0x1B) /* ESC */
  				break;
  		}
  	}
  #endif
  	return rcode;
  }
088f1b199   Kim Phillips   common/cmd_*.c: s...
129
  static ulong load_serial(long offset)
8bde7f776   wdenk   * Code cleanup:
130
131
132
133
134
135
136
  {
  	char	record[SREC_MAXRECLEN + 1];	/* buffer for one S-Record	*/
  	char	binbuf[SREC_MAXBINLEN];		/* buffer for binary data	*/
  	int	binlen;				/* no. of data bytes in S-Rec.	*/
  	int	type;				/* return code for record type	*/
  	ulong	addr;				/* load address from S-Record	*/
  	ulong	size;				/* number of bytes transferred	*/
8bde7f776   wdenk   * Code cleanup:
137
138
139
140
141
142
  	ulong	store_addr;
  	ulong	start_addr = ~0;
  	ulong	end_addr   =  0;
  	int	line_count =  0;
  
  	while (read_record(record, SREC_MAXRECLEN + 1) >= 0) {
088f1b199   Kim Phillips   common/cmd_*.c: s...
143
  		type = srec_decode(record, &binlen, &addr, binbuf);
8bde7f776   wdenk   * Code cleanup:
144
145
146
147
148
149
150
151
152
153
  
  		if (type < 0) {
  			return (~0);		/* Invalid S-Record		*/
  		}
  
  		switch (type) {
  		case SREC_DATA2:
  		case SREC_DATA3:
  		case SREC_DATA4:
  		    store_addr = addr + offset;
e856bdcfb   Masahiro Yamada   flash: complete C...
154
  #ifdef CONFIG_MTD_NOR_FLASH
8bde7f776   wdenk   * Code cleanup:
155
156
  		    if (addr2info(store_addr)) {
  			int rc;
77ddac948   Wolfgang Denk   Cleanup for GCC-4.x
157
  			rc = flash_write((char *)binbuf,store_addr,binlen);
8bde7f776   wdenk   * Code cleanup:
158
  			if (rc != 0) {
088f1b199   Kim Phillips   common/cmd_*.c: s...
159
  				flash_perror(rc);
8bde7f776   wdenk   * Code cleanup:
160
161
162
163
164
  				return (~0);
  			}
  		    } else
  #endif
  		    {
088f1b199   Kim Phillips   common/cmd_*.c: s...
165
  			memcpy((char *)(store_addr), binbuf, binlen);
8bde7f776   wdenk   * Code cleanup:
166
167
168
169
170
171
172
173
174
  		    }
  		    if ((store_addr) < start_addr)
  			start_addr = store_addr;
  		    if ((store_addr + binlen - 1) > end_addr)
  			end_addr = store_addr + binlen - 1;
  		    break;
  		case SREC_END2:
  		case SREC_END3:
  		case SREC_END4:
088f1b199   Kim Phillips   common/cmd_*.c: s...
175
  		    udelay(10000);
8bde7f776   wdenk   * Code cleanup:
176
  		    size = end_addr - start_addr + 1;
088f1b199   Kim Phillips   common/cmd_*.c: s...
177
178
  		    printf("
  "
8bde7f776   wdenk   * Code cleanup:
179
180
181
182
183
184
185
186
  			    "## First Load Addr = 0x%08lX
  "
  			    "## Last  Load Addr = 0x%08lX
  "
  			    "## Total Size      = 0x%08lX = %ld Bytes
  ",
  			    start_addr, end_addr, size, size
  		    );
088f1b199   Kim Phillips   common/cmd_*.c: s...
187
  		    flush_cache(start_addr, size);
018f53032   Simon Glass   env: Rename commo...
188
  		    env_set_hex("filesize", size);
8bde7f776   wdenk   * Code cleanup:
189
190
191
192
193
194
195
196
  		    return (addr);
  		case SREC_START:
  		    break;
  		default:
  		    break;
  		}
  		if (!do_echo) {	/* print a '.' every 100 lines */
  			if ((++line_count % 100) == 0)
088f1b199   Kim Phillips   common/cmd_*.c: s...
197
  				putc('.');
8bde7f776   wdenk   * Code cleanup:
198
199
200
201
202
  		}
  	}
  
  	return (~0);			/* Download aborted		*/
  }
088f1b199   Kim Phillips   common/cmd_*.c: s...
203
  static int read_record(char *buf, ulong len)
8bde7f776   wdenk   * Code cleanup:
204
205
206
207
208
209
210
  {
  	char *p;
  	char c;
  
  	--len;	/* always leave room for terminating '\0' byte */
  
  	for (p=buf; p < buf+len; ++p) {
232c150a2   wdenk   Add support for S...
211
  		c = getc();		/* read character		*/
8bde7f776   wdenk   * Code cleanup:
212
  		if (do_echo)
088f1b199   Kim Phillips   common/cmd_*.c: s...
213
  			putc(c);	/* ... and echo it		*/
8bde7f776   wdenk   * Code cleanup:
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
  
  		switch (c) {
  		case '\r':
  		case '
  ':
  			*p = '\0';
  			return (p - buf);
  		case '\0':
  		case 0x03:			/* ^C - Control C		*/
  			return (-1);
  		default:
  			*p = c;
  		}
  
  	    /* Check for the console hangup (if any different from serial) */
49cad5478   Martin Dorwig   Export redesign
229
  	    if (gd->jt->getc != getc) {
8bde7f776   wdenk   * Code cleanup:
230
231
232
233
  		if (ctrlc()) {
  		    return (-1);
  		}
  	    }
8bde7f776   wdenk   * Code cleanup:
234
235
236
237
238
239
  	}
  
  	/* line too long - truncate */
  	*p = '\0';
  	return (p - buf);
  }
c76fe4742   Jon Loeliger   common/cmd_[i-n]*...
240
  #if defined(CONFIG_CMD_SAVES)
8bde7f776   wdenk   * Code cleanup:
241

54841ab50   Wolfgang Denk   Make sure that ar...
242
  int do_save_serial (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
8bde7f776   wdenk   * Code cleanup:
243
244
245
  {
  	ulong offset = 0;
  	ulong size   = 0;
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
246
  #ifdef	CONFIG_SYS_LOADS_BAUD_CHANGE
8bde7f776   wdenk   * Code cleanup:
247
248
249
250
251
252
253
254
  	int save_baudrate, current_baudrate;
  
  	save_baudrate = current_baudrate = gd->baudrate;
  #endif
  
  	if (argc >= 2) {
  		offset = simple_strtoul(argv[1], NULL, 16);
  	}
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
255
  #ifdef	CONFIG_SYS_LOADS_BAUD_CHANGE
8bde7f776   wdenk   * Code cleanup:
256
257
258
259
260
261
262
263
264
265
266
  	if (argc >= 3) {
  		size = simple_strtoul(argv[2], NULL, 16);
  	}
  	if (argc == 4) {
  		save_baudrate = (int)simple_strtoul(argv[3], NULL, 10);
  
  		/* default to current baudrate */
  		if (save_baudrate == 0)
  			save_baudrate = current_baudrate;
  	}
  	if (save_baudrate != current_baudrate) {
088f1b199   Kim Phillips   common/cmd_*.c: s...
267
268
  		printf("## Switch baudrate to %d bps and press ENTER ...
  ",
8bde7f776   wdenk   * Code cleanup:
269
270
271
  			save_baudrate);
  		udelay(50000);
  		gd->baudrate = save_baudrate;
088f1b199   Kim Phillips   common/cmd_*.c: s...
272
  		serial_setbrg();
8bde7f776   wdenk   * Code cleanup:
273
274
275
276
277
278
  		udelay(50000);
  		for (;;) {
  			if (getc() == '\r')
  				break;
  		}
  	}
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
279
  #else	/* ! CONFIG_SYS_LOADS_BAUD_CHANGE */
8bde7f776   wdenk   * Code cleanup:
280
281
282
  	if (argc == 3) {
  		size = simple_strtoul(argv[2], NULL, 16);
  	}
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
283
  #endif	/* CONFIG_SYS_LOADS_BAUD_CHANGE */
8bde7f776   wdenk   * Code cleanup:
284

088f1b199   Kim Phillips   common/cmd_*.c: s...
285
286
  	printf("## Ready for S-Record upload, press ENTER to proceed ...
  ");
8bde7f776   wdenk   * Code cleanup:
287
288
289
290
  	for (;;) {
  		if (getc() == '\r')
  			break;
  	}
088f1b199   Kim Phillips   common/cmd_*.c: s...
291
292
293
  	if (save_serial(offset, size)) {
  		printf("## S-Record upload aborted
  ");
8bde7f776   wdenk   * Code cleanup:
294
  	} else {
088f1b199   Kim Phillips   common/cmd_*.c: s...
295
296
  		printf("## S-Record upload complete
  ");
8bde7f776   wdenk   * Code cleanup:
297
  	}
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
298
  #ifdef	CONFIG_SYS_LOADS_BAUD_CHANGE
8bde7f776   wdenk   * Code cleanup:
299
  	if (save_baudrate != current_baudrate) {
088f1b199   Kim Phillips   common/cmd_*.c: s...
300
301
  		printf("## Switch baudrate to %d bps and press ESC ...
  ",
8bde7f776   wdenk   * Code cleanup:
302
  			(int)current_baudrate);
088f1b199   Kim Phillips   common/cmd_*.c: s...
303
  		udelay(50000);
8bde7f776   wdenk   * Code cleanup:
304
  		gd->baudrate = current_baudrate;
088f1b199   Kim Phillips   common/cmd_*.c: s...
305
306
  		serial_setbrg();
  		udelay(50000);
8bde7f776   wdenk   * Code cleanup:
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
  		for (;;) {
  			if (getc() == 0x1B) /* ESC */
  				break;
  		}
  	}
  #endif
  	return 0;
  }
  
  #define SREC3_START				"S0030000FC
  "
  #define SREC3_FORMAT			"S3%02X%08lX%s%02X
  "
  #define SREC3_END				"S70500000000FA
  "
  #define SREC_BYTES_PER_RECORD	16
088f1b199   Kim Phillips   common/cmd_*.c: s...
323
  static int save_serial(ulong address, ulong count)
8bde7f776   wdenk   * Code cleanup:
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
  {
  	int i, c, reclen, checksum, length;
  	char *hex = "0123456789ABCDEF";
  	char	record[2*SREC_BYTES_PER_RECORD+16];	/* buffer for one S-Record	*/
  	char	data[2*SREC_BYTES_PER_RECORD+1];	/* buffer for hex data	*/
  
  	reclen = 0;
  	checksum  = 0;
  
  	if(write_record(SREC3_START))			/* write the header */
  		return (-1);
  	do {
  		if(count) {						/* collect hex data in the buffer  */
  			c = *(volatile uchar*)(address + reclen);	/* get one byte    */
  			checksum += c;							/* accumulate checksum */
  			data[2*reclen]   = hex[(c>>4)&0x0f];
  			data[2*reclen+1] = hex[c & 0x0f];
  			data[2*reclen+2] = '\0';
  			++reclen;
  			--count;
  		}
  		if(reclen == SREC_BYTES_PER_RECORD || count == 0) {
  			/* enough data collected for one record: dump it */
  			if(reclen) {	/* build & write a data record: */
  				/* address + data + checksum */
  				length = 4 + reclen + 1;
  
  				/* accumulate length bytes into checksum */
  				for(i = 0; i < 2; i++)
  					checksum += (length >> (8*i)) & 0xff;
  
  				/* accumulate address bytes into checksum: */
  				for(i = 0; i < 4; i++)
  					checksum += (address >> (8*i)) & 0xff;
  
  				/* make proper checksum byte: */
  				checksum = ~checksum & 0xff;
  
  				/* output one record: */
  				sprintf(record, SREC3_FORMAT, length, address, data, checksum);
  				if(write_record(record))
  					return (-1);
  			}
  			address  += reclen;  /* increment address */
  			checksum  = 0;
  			reclen    = 0;
  		}
  	}
  	while(count);
  	if(write_record(SREC3_END))	/* write the final record */
  		return (-1);
  	return(0);
  }
088f1b199   Kim Phillips   common/cmd_*.c: s...
377
  static int write_record(char *buf)
8bde7f776   wdenk   * Code cleanup:
378
379
380
381
  {
  	char c;
  
  	while((c = *buf++))
232c150a2   wdenk   Add support for S...
382
  		putc(c);
8bde7f776   wdenk   * Code cleanup:
383
384
385
386
387
388
389
390
  
  	/* Check for the console hangup (if any different from serial) */
  
  	if (ctrlc()) {
  	    return (-1);
  	}
  	return (0);
  }
902531788   Jon Loeliger   common/: Remove l...
391
  # endif
8bde7f776   wdenk   * Code cleanup:
392

902531788   Jon Loeliger   common/: Remove l...
393
  #endif
8bde7f776   wdenk   * Code cleanup:
394

c76fe4742   Jon Loeliger   common/cmd_[i-n]*...
395
  #if defined(CONFIG_CMD_LOADB)
65c450b47   Jon Loeliger   common/cmd_[i-z]*...
396
397
398
  /*
   * loadb command (load binary) included
   */
8bde7f776   wdenk   * Code cleanup:
399
400
401
402
403
404
405
406
407
408
409
410
411
412
  #define XON_CHAR        17
  #define XOFF_CHAR       19
  #define START_CHAR      0x01
  #define ETX_CHAR	0x03
  #define END_CHAR        0x0D
  #define SPACE           0x20
  #define K_ESCAPE        0x23
  #define SEND_TYPE       'S'
  #define DATA_TYPE       'D'
  #define ACK_TYPE        'Y'
  #define NACK_TYPE       'N'
  #define BREAK_TYPE      'B'
  #define tochar(x) ((char) (((x) + SPACE) & 0xff))
  #define untochar(x) ((int) (((x) - SPACE) & 0xff))
8bde7f776   wdenk   * Code cleanup:
413
414
  static void set_kerm_bin_mode(unsigned long *);
  static int k_recv(void);
088f1b199   Kim Phillips   common/cmd_*.c: s...
415
  static ulong load_serial_bin(ulong offset);
8bde7f776   wdenk   * Code cleanup:
416

088f1b199   Kim Phillips   common/cmd_*.c: s...
417
418
419
420
  static char his_eol;        /* character he needs at end of packet */
  static int  his_pad_count;  /* number of pad chars he needs */
  static char his_pad_char;   /* pad chars he needs */
  static char his_quote;      /* quote chars he'll use */
8bde7f776   wdenk   * Code cleanup:
421

088f1b199   Kim Phillips   common/cmd_*.c: s...
422
423
  static int do_load_serial_bin(cmd_tbl_t *cmdtp, int flag, int argc,
  			      char * const argv[])
8bde7f776   wdenk   * Code cleanup:
424
  {
8bde7f776   wdenk   * Code cleanup:
425
426
427
428
429
  	ulong offset = 0;
  	ulong addr;
  	int load_baudrate, current_baudrate;
  	int rcode = 0;
  	char *s;
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
430
431
  	/* pre-set offset from CONFIG_SYS_LOAD_ADDR */
  	offset = CONFIG_SYS_LOAD_ADDR;
8bde7f776   wdenk   * Code cleanup:
432
433
  
  	/* pre-set offset from $loadaddr */
00caae6d4   Simon Glass   env: Rename geten...
434
435
  	s = env_get("loadaddr");
  	if (s)
8bde7f776   wdenk   * Code cleanup:
436
  		offset = simple_strtoul(s, NULL, 16);
8bde7f776   wdenk   * Code cleanup:
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
  
  	load_baudrate = current_baudrate = gd->baudrate;
  
  	if (argc >= 2) {
  		offset = simple_strtoul(argv[1], NULL, 16);
  	}
  	if (argc == 3) {
  		load_baudrate = (int)simple_strtoul(argv[2], NULL, 10);
  
  		/* default to current baudrate */
  		if (load_baudrate == 0)
  			load_baudrate = current_baudrate;
  	}
  
  	if (load_baudrate != current_baudrate) {
088f1b199   Kim Phillips   common/cmd_*.c: s...
452
453
  		printf("## Switch baudrate to %d bps and press ENTER ...
  ",
8bde7f776   wdenk   * Code cleanup:
454
455
456
  			load_baudrate);
  		udelay(50000);
  		gd->baudrate = load_baudrate;
088f1b199   Kim Phillips   common/cmd_*.c: s...
457
  		serial_setbrg();
8bde7f776   wdenk   * Code cleanup:
458
459
460
461
462
463
  		udelay(50000);
  		for (;;) {
  			if (getc() == '\r')
  				break;
  		}
  	}
f2841d377   Markus Klotzbuecher   Add support for y...
464
  	if (strcmp(argv[0],"loady")==0) {
088f1b199   Kim Phillips   common/cmd_*.c: s...
465
  		printf("## Ready for binary (ymodem) download "
f2841d377   Markus Klotzbuecher   Add support for y...
466
467
468
469
  			"to 0x%08lX at %d bps...
  ",
  			offset,
  			load_baudrate);
6e66bd559   Angus Ainslie   Enable xmodem sup...
470
471
472
473
474
475
476
477
478
479
  		addr = load_serial_ymodem(offset, xyzModem_ymodem);
  
  	} else if (strcmp(argv[0],"loadx")==0) {
  		printf("## Ready for binary (xmodem) download "
  			"to 0x%08lX at %d bps...
  ",
  			offset,
  			load_baudrate);
  
  		addr = load_serial_ymodem(offset, xyzModem_xmodem);
8bde7f776   wdenk   * Code cleanup:
480

8bde7f776   wdenk   * Code cleanup:
481
  	} else {
8bde7f776   wdenk   * Code cleanup:
482

088f1b199   Kim Phillips   common/cmd_*.c: s...
483
  		printf("## Ready for binary (kermit) download "
f2841d377   Markus Klotzbuecher   Add support for y...
484
485
486
487
  			"to 0x%08lX at %d bps...
  ",
  			offset,
  			load_baudrate);
088f1b199   Kim Phillips   common/cmd_*.c: s...
488
  		addr = load_serial_bin(offset);
f2841d377   Markus Klotzbuecher   Add support for y...
489
490
491
  
  		if (addr == ~0) {
  			load_addr = 0;
088f1b199   Kim Phillips   common/cmd_*.c: s...
492
493
  			printf("## Binary (kermit) download aborted
  ");
f2841d377   Markus Klotzbuecher   Add support for y...
494
495
  			rcode = 1;
  		} else {
088f1b199   Kim Phillips   common/cmd_*.c: s...
496
497
  			printf("## Start Addr      = 0x%08lX
  ", addr);
f2841d377   Markus Klotzbuecher   Add support for y...
498
499
500
  			load_addr = addr;
  		}
  	}
8bde7f776   wdenk   * Code cleanup:
501
  	if (load_baudrate != current_baudrate) {
088f1b199   Kim Phillips   common/cmd_*.c: s...
502
503
  		printf("## Switch baudrate to %d bps and press ESC ...
  ",
8bde7f776   wdenk   * Code cleanup:
504
  			current_baudrate);
088f1b199   Kim Phillips   common/cmd_*.c: s...
505
  		udelay(50000);
8bde7f776   wdenk   * Code cleanup:
506
  		gd->baudrate = current_baudrate;
088f1b199   Kim Phillips   common/cmd_*.c: s...
507
508
  		serial_setbrg();
  		udelay(50000);
8bde7f776   wdenk   * Code cleanup:
509
510
511
512
513
  		for (;;) {
  			if (getc() == 0x1B) /* ESC */
  				break;
  		}
  	}
8bde7f776   wdenk   * Code cleanup:
514
515
  	return rcode;
  }
088f1b199   Kim Phillips   common/cmd_*.c: s...
516
  static ulong load_serial_bin(ulong offset)
8bde7f776   wdenk   * Code cleanup:
517
518
  {
  	int size, i;
8bde7f776   wdenk   * Code cleanup:
519

088f1b199   Kim Phillips   common/cmd_*.c: s...
520
521
  	set_kerm_bin_mode((ulong *) offset);
  	size = k_recv();
8bde7f776   wdenk   * Code cleanup:
522
523
524
525
526
527
528
  
  	/*
  	 * Gather any trailing characters (for instance, the ^D which
  	 * is sent by 'cu' after sending a file), and give the
  	 * box some time (100 * 1 ms)
  	 */
  	for (i=0; i<100; ++i) {
232c150a2   wdenk   Add support for S...
529
530
  		if (tstc()) {
  			(void) getc();
8bde7f776   wdenk   * Code cleanup:
531
532
533
  		}
  		udelay(1000);
  	}
088f1b199   Kim Phillips   common/cmd_*.c: s...
534
  	flush_cache(offset, size);
8bde7f776   wdenk   * Code cleanup:
535
536
537
  
  	printf("## Total Size      = 0x%08x = %d Bytes
  ", size, size);
018f53032   Simon Glass   env: Rename commo...
538
  	env_set_hex("filesize", size);
8bde7f776   wdenk   * Code cleanup:
539
540
541
  
  	return offset;
  }
088f1b199   Kim Phillips   common/cmd_*.c: s...
542
  static void send_pad(void)
8bde7f776   wdenk   * Code cleanup:
543
544
545
546
  {
  	int count = his_pad_count;
  
  	while (count-- > 0)
088f1b199   Kim Phillips   common/cmd_*.c: s...
547
  		putc(his_pad_char);
8bde7f776   wdenk   * Code cleanup:
548
549
550
  }
  
  /* converts escaped kermit char to binary char */
088f1b199   Kim Phillips   common/cmd_*.c: s...
551
  static char ktrans(char in)
8bde7f776   wdenk   * Code cleanup:
552
553
554
555
556
557
558
559
  {
  	if ((in & 0x60) == 0x40) {
  		return (char) (in & ~0x40);
  	} else if ((in & 0x7f) == 0x3f) {
  		return (char) (in | 0x40);
  	} else
  		return in;
  }
088f1b199   Kim Phillips   common/cmd_*.c: s...
560
  static int chk1(char *buffer)
8bde7f776   wdenk   * Code cleanup:
561
562
563
564
565
566
567
568
  {
  	int total = 0;
  
  	while (*buffer) {
  		total += *buffer++;
  	}
  	return (int) ((total + ((total >> 6) & 0x03)) & 0x3f);
  }
088f1b199   Kim Phillips   common/cmd_*.c: s...
569
  static void s1_sendpacket(char *packet)
8bde7f776   wdenk   * Code cleanup:
570
  {
088f1b199   Kim Phillips   common/cmd_*.c: s...
571
  	send_pad();
8bde7f776   wdenk   * Code cleanup:
572
  	while (*packet) {
088f1b199   Kim Phillips   common/cmd_*.c: s...
573
  		putc(*packet++);
8bde7f776   wdenk   * Code cleanup:
574
575
576
577
  	}
  }
  
  static char a_b[24];
088f1b199   Kim Phillips   common/cmd_*.c: s...
578
  static void send_ack(int n)
8bde7f776   wdenk   * Code cleanup:
579
580
  {
  	a_b[0] = START_CHAR;
088f1b199   Kim Phillips   common/cmd_*.c: s...
581
582
  	a_b[1] = tochar(3);
  	a_b[2] = tochar(n);
8bde7f776   wdenk   * Code cleanup:
583
584
  	a_b[3] = ACK_TYPE;
  	a_b[4] = '\0';
088f1b199   Kim Phillips   common/cmd_*.c: s...
585
  	a_b[4] = tochar(chk1(&a_b[1]));
8bde7f776   wdenk   * Code cleanup:
586
587
  	a_b[5] = his_eol;
  	a_b[6] = '\0';
088f1b199   Kim Phillips   common/cmd_*.c: s...
588
  	s1_sendpacket(a_b);
8bde7f776   wdenk   * Code cleanup:
589
  }
088f1b199   Kim Phillips   common/cmd_*.c: s...
590
  static void send_nack(int n)
8bde7f776   wdenk   * Code cleanup:
591
592
  {
  	a_b[0] = START_CHAR;
088f1b199   Kim Phillips   common/cmd_*.c: s...
593
594
  	a_b[1] = tochar(3);
  	a_b[2] = tochar(n);
8bde7f776   wdenk   * Code cleanup:
595
596
  	a_b[3] = NACK_TYPE;
  	a_b[4] = '\0';
088f1b199   Kim Phillips   common/cmd_*.c: s...
597
  	a_b[4] = tochar(chk1(&a_b[1]));
8bde7f776   wdenk   * Code cleanup:
598
599
  	a_b[5] = his_eol;
  	a_b[6] = '\0';
088f1b199   Kim Phillips   common/cmd_*.c: s...
600
  	s1_sendpacket(a_b);
8bde7f776   wdenk   * Code cleanup:
601
  }
088f1b199   Kim Phillips   common/cmd_*.c: s...
602
603
  static void (*os_data_init)(void);
  static void (*os_data_char)(char new_char);
8bde7f776   wdenk   * Code cleanup:
604
  static int os_data_state, os_data_state_saved;
8bde7f776   wdenk   * Code cleanup:
605
606
  static char *os_data_addr, *os_data_addr_saved;
  static char *bin_start_address;
a9fe0c3e7   Gururaja Hebbar K R   common/cmd_load.c...
607

088f1b199   Kim Phillips   common/cmd_*.c: s...
608
  static void bin_data_init(void)
8bde7f776   wdenk   * Code cleanup:
609
610
  {
  	os_data_state = 0;
8bde7f776   wdenk   * Code cleanup:
611
612
  	os_data_addr = bin_start_address;
  }
a9fe0c3e7   Gururaja Hebbar K R   common/cmd_load.c...
613

088f1b199   Kim Phillips   common/cmd_*.c: s...
614
  static void os_data_save(void)
8bde7f776   wdenk   * Code cleanup:
615
616
  {
  	os_data_state_saved = os_data_state;
8bde7f776   wdenk   * Code cleanup:
617
618
  	os_data_addr_saved = os_data_addr;
  }
a9fe0c3e7   Gururaja Hebbar K R   common/cmd_load.c...
619

088f1b199   Kim Phillips   common/cmd_*.c: s...
620
  static void os_data_restore(void)
8bde7f776   wdenk   * Code cleanup:
621
622
  {
  	os_data_state = os_data_state_saved;
8bde7f776   wdenk   * Code cleanup:
623
624
  	os_data_addr = os_data_addr_saved;
  }
a9fe0c3e7   Gururaja Hebbar K R   common/cmd_load.c...
625

088f1b199   Kim Phillips   common/cmd_*.c: s...
626
  static void bin_data_char(char new_char)
8bde7f776   wdenk   * Code cleanup:
627
628
629
630
  {
  	switch (os_data_state) {
  	case 0:					/* data */
  		*os_data_addr++ = new_char;
8bde7f776   wdenk   * Code cleanup:
631
632
633
  		break;
  	}
  }
a9fe0c3e7   Gururaja Hebbar K R   common/cmd_load.c...
634

088f1b199   Kim Phillips   common/cmd_*.c: s...
635
  static void set_kerm_bin_mode(unsigned long *addr)
8bde7f776   wdenk   * Code cleanup:
636
637
638
639
640
641
642
643
644
  {
  	bin_start_address = (char *) addr;
  	os_data_init = bin_data_init;
  	os_data_char = bin_data_char;
  }
  
  
  /* k_data_* simply handles the kermit escape translations */
  static int k_data_escape, k_data_escape_saved;
088f1b199   Kim Phillips   common/cmd_*.c: s...
645
  static void k_data_init(void)
8bde7f776   wdenk   * Code cleanup:
646
647
  {
  	k_data_escape = 0;
088f1b199   Kim Phillips   common/cmd_*.c: s...
648
  	os_data_init();
8bde7f776   wdenk   * Code cleanup:
649
  }
a9fe0c3e7   Gururaja Hebbar K R   common/cmd_load.c...
650

088f1b199   Kim Phillips   common/cmd_*.c: s...
651
  static void k_data_save(void)
8bde7f776   wdenk   * Code cleanup:
652
653
  {
  	k_data_escape_saved = k_data_escape;
088f1b199   Kim Phillips   common/cmd_*.c: s...
654
  	os_data_save();
8bde7f776   wdenk   * Code cleanup:
655
  }
a9fe0c3e7   Gururaja Hebbar K R   common/cmd_load.c...
656

088f1b199   Kim Phillips   common/cmd_*.c: s...
657
  static void k_data_restore(void)
8bde7f776   wdenk   * Code cleanup:
658
659
  {
  	k_data_escape = k_data_escape_saved;
088f1b199   Kim Phillips   common/cmd_*.c: s...
660
  	os_data_restore();
8bde7f776   wdenk   * Code cleanup:
661
  }
a9fe0c3e7   Gururaja Hebbar K R   common/cmd_load.c...
662

088f1b199   Kim Phillips   common/cmd_*.c: s...
663
  static void k_data_char(char new_char)
8bde7f776   wdenk   * Code cleanup:
664
665
666
  {
  	if (k_data_escape) {
  		/* last char was escape - translate this character */
088f1b199   Kim Phillips   common/cmd_*.c: s...
667
  		os_data_char(ktrans(new_char));
8bde7f776   wdenk   * Code cleanup:
668
669
670
671
672
673
674
  		k_data_escape = 0;
  	} else {
  		if (new_char == his_quote) {
  			/* this char is escape - remember */
  			k_data_escape = 1;
  		} else {
  			/* otherwise send this char as-is */
088f1b199   Kim Phillips   common/cmd_*.c: s...
675
  			os_data_char(new_char);
8bde7f776   wdenk   * Code cleanup:
676
677
678
679
680
  		}
  	}
  }
  
  #define SEND_DATA_SIZE  20
088f1b199   Kim Phillips   common/cmd_*.c: s...
681
682
  static char send_parms[SEND_DATA_SIZE];
  static char *send_ptr;
8bde7f776   wdenk   * Code cleanup:
683
684
685
  
  /* handle_send_packet interprits the protocol info and builds and
     sends an appropriate ack for what we can do */
088f1b199   Kim Phillips   common/cmd_*.c: s...
686
  static void handle_send_packet(int n)
8bde7f776   wdenk   * Code cleanup:
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
  {
  	int length = 3;
  	int bytes;
  
  	/* initialize some protocol parameters */
  	his_eol = END_CHAR;		/* default end of line character */
  	his_pad_count = 0;
  	his_pad_char = '\0';
  	his_quote = K_ESCAPE;
  
  	/* ignore last character if it filled the buffer */
  	if (send_ptr == &send_parms[SEND_DATA_SIZE - 1])
  		--send_ptr;
  	bytes = send_ptr - send_parms;	/* how many bytes we'll process */
  	do {
  		if (bytes-- <= 0)
  			break;
  		/* handle MAXL - max length */
  		/* ignore what he says - most I'll take (here) is 94 */
088f1b199   Kim Phillips   common/cmd_*.c: s...
706
  		a_b[++length] = tochar(94);
8bde7f776   wdenk   * Code cleanup:
707
708
709
710
  		if (bytes-- <= 0)
  			break;
  		/* handle TIME - time you should wait for my packets */
  		/* ignore what he says - don't wait for my ack longer than 1 second */
088f1b199   Kim Phillips   common/cmd_*.c: s...
711
  		a_b[++length] = tochar(1);
8bde7f776   wdenk   * Code cleanup:
712
713
714
715
  		if (bytes-- <= 0)
  			break;
  		/* handle NPAD - number of pad chars I need */
  		/* remember what he says - I need none */
088f1b199   Kim Phillips   common/cmd_*.c: s...
716
717
  		his_pad_count = untochar(send_parms[2]);
  		a_b[++length] = tochar(0);
8bde7f776   wdenk   * Code cleanup:
718
719
720
721
  		if (bytes-- <= 0)
  			break;
  		/* handle PADC - pad chars I need */
  		/* remember what he says - I need none */
088f1b199   Kim Phillips   common/cmd_*.c: s...
722
  		his_pad_char = ktrans(send_parms[3]);
8bde7f776   wdenk   * Code cleanup:
723
724
725
726
727
  		a_b[++length] = 0x40;	/* He should ignore this */
  		if (bytes-- <= 0)
  			break;
  		/* handle EOL - end of line he needs */
  		/* remember what he says - I need CR */
088f1b199   Kim Phillips   common/cmd_*.c: s...
728
729
  		his_eol = untochar(send_parms[4]);
  		a_b[++length] = tochar(END_CHAR);
8bde7f776   wdenk   * Code cleanup:
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
  		if (bytes-- <= 0)
  			break;
  		/* handle QCTL - quote control char he'll use */
  		/* remember what he says - I'll use '#' */
  		his_quote = send_parms[5];
  		a_b[++length] = '#';
  		if (bytes-- <= 0)
  			break;
  		/* handle QBIN - 8-th bit prefixing */
  		/* ignore what he says - I refuse */
  		a_b[++length] = 'N';
  		if (bytes-- <= 0)
  			break;
  		/* handle CHKT - the clock check type */
  		/* ignore what he says - I do type 1 (for now) */
  		a_b[++length] = '1';
  		if (bytes-- <= 0)
  			break;
  		/* handle REPT - the repeat prefix */
  		/* ignore what he says - I refuse (for now) */
  		a_b[++length] = 'N';
  		if (bytes-- <= 0)
  			break;
  		/* handle CAPAS - the capabilities mask */
  		/* ignore what he says - I only do long packets - I don't do windows */
088f1b199   Kim Phillips   common/cmd_*.c: s...
755
756
757
758
  		a_b[++length] = tochar(2);	/* only long packets */
  		a_b[++length] = tochar(0);	/* no windows */
  		a_b[++length] = tochar(94);	/* large packet msb */
  		a_b[++length] = tochar(94);	/* large packet lsb */
8bde7f776   wdenk   * Code cleanup:
759
760
761
  	} while (0);
  
  	a_b[0] = START_CHAR;
088f1b199   Kim Phillips   common/cmd_*.c: s...
762
763
  	a_b[1] = tochar(length);
  	a_b[2] = tochar(n);
8bde7f776   wdenk   * Code cleanup:
764
765
  	a_b[3] = ACK_TYPE;
  	a_b[++length] = '\0';
088f1b199   Kim Phillips   common/cmd_*.c: s...
766
  	a_b[length] = tochar(chk1(&a_b[1]));
8bde7f776   wdenk   * Code cleanup:
767
768
  	a_b[++length] = his_eol;
  	a_b[++length] = '\0';
088f1b199   Kim Phillips   common/cmd_*.c: s...
769
  	s1_sendpacket(a_b);
8bde7f776   wdenk   * Code cleanup:
770
771
772
  }
  
  /* k_recv receives a OS Open image file over kermit line */
088f1b199   Kim Phillips   common/cmd_*.c: s...
773
  static int k_recv(void)
8bde7f776   wdenk   * Code cleanup:
774
775
776
777
778
779
780
  {
  	char new_char;
  	char k_state, k_state_saved;
  	int sum;
  	int done;
  	int length;
  	int n, last_n;
8bde7f776   wdenk   * Code cleanup:
781
782
783
784
785
786
787
788
789
790
791
  	int len_lo, len_hi;
  
  	/* initialize some protocol parameters */
  	his_eol = END_CHAR;		/* default end of line character */
  	his_pad_count = 0;
  	his_pad_char = '\0';
  	his_quote = K_ESCAPE;
  
  	/* initialize the k_recv and k_data state machine */
  	done = 0;
  	k_state = 0;
088f1b199   Kim Phillips   common/cmd_*.c: s...
792
  	k_data_init();
8bde7f776   wdenk   * Code cleanup:
793
  	k_state_saved = k_state;
088f1b199   Kim Phillips   common/cmd_*.c: s...
794
  	k_data_save();
8bde7f776   wdenk   * Code cleanup:
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
  	n = 0;				/* just to get rid of a warning */
  	last_n = -1;
  
  	/* expect this "type" sequence (but don't check):
  	   S: send initiate
  	   F: file header
  	   D: data (multiple)
  	   Z: end of file
  	   B: break transmission
  	 */
  
  	/* enter main loop */
  	while (!done) {
  		/* set the send packet pointer to begining of send packet parms */
  		send_ptr = send_parms;
  
  		/* With each packet, start summing the bytes starting with the length.
  		   Save the current sequence number.
  		   Note the type of the packet.
  		   If a character less than SPACE (0x20) is received - error.
  		 */
  
  #if 0
  		/* OLD CODE, Prior to checking sequence numbers */
  		/* first have all state machines save current states */
  		k_state_saved = k_state;
  		k_data_save ();
  #endif
  
  		/* get a packet */
  		/* wait for the starting character or ^C */
  		for (;;) {
232c150a2   wdenk   Add support for S...
827
  			switch (getc ()) {
8bde7f776   wdenk   * Code cleanup:
828
829
830
831
832
833
834
835
836
837
838
  			case START_CHAR:	/* start packet */
  				goto START;
  			case ETX_CHAR:		/* ^C waiting for packet */
  				return (0);
  			default:
  				;
  			}
  		}
  START:
  		/* get length of packet */
  		sum = 0;
088f1b199   Kim Phillips   common/cmd_*.c: s...
839
  		new_char = getc();
8bde7f776   wdenk   * Code cleanup:
840
841
842
  		if ((new_char & 0xE0) == 0)
  			goto packet_error;
  		sum += new_char & 0xff;
088f1b199   Kim Phillips   common/cmd_*.c: s...
843
  		length = untochar(new_char);
8bde7f776   wdenk   * Code cleanup:
844
  		/* get sequence number */
088f1b199   Kim Phillips   common/cmd_*.c: s...
845
  		new_char = getc();
8bde7f776   wdenk   * Code cleanup:
846
847
848
  		if ((new_char & 0xE0) == 0)
  			goto packet_error;
  		sum += new_char & 0xff;
088f1b199   Kim Phillips   common/cmd_*.c: s...
849
  		n = untochar(new_char);
8bde7f776   wdenk   * Code cleanup:
850
851
852
853
854
855
856
857
858
859
860
861
  		--length;
  
  		/* NEW CODE - check sequence numbers for retried packets */
  		/* Note - this new code assumes that the sequence number is correctly
  		 * received.  Handling an invalid sequence number adds another layer
  		 * of complexity that may not be needed - yet!  At this time, I'm hoping
  		 * that I don't need to buffer the incoming data packets and can write
  		 * the data into memory in real time.
  		 */
  		if (n == last_n) {
  			/* same sequence number, restore the previous state */
  			k_state = k_state_saved;
088f1b199   Kim Phillips   common/cmd_*.c: s...
862
  			k_data_restore();
8bde7f776   wdenk   * Code cleanup:
863
864
865
866
  		} else {
  			/* new sequence number, checkpoint the download */
  			last_n = n;
  			k_state_saved = k_state;
088f1b199   Kim Phillips   common/cmd_*.c: s...
867
  			k_data_save();
8bde7f776   wdenk   * Code cleanup:
868
869
870
871
  		}
  		/* END NEW CODE */
  
  		/* get packet type */
088f1b199   Kim Phillips   common/cmd_*.c: s...
872
  		new_char = getc();
8bde7f776   wdenk   * Code cleanup:
873
874
875
876
877
878
879
880
881
  		if ((new_char & 0xE0) == 0)
  			goto packet_error;
  		sum += new_char & 0xff;
  		k_state = new_char;
  		--length;
  		/* check for extended length */
  		if (length == -2) {
  			/* (length byte was 0, decremented twice) */
  			/* get the two length bytes */
088f1b199   Kim Phillips   common/cmd_*.c: s...
882
  			new_char = getc();
8bde7f776   wdenk   * Code cleanup:
883
884
885
  			if ((new_char & 0xE0) == 0)
  				goto packet_error;
  			sum += new_char & 0xff;
088f1b199   Kim Phillips   common/cmd_*.c: s...
886
887
  			len_hi = untochar(new_char);
  			new_char = getc();
8bde7f776   wdenk   * Code cleanup:
888
889
890
  			if ((new_char & 0xE0) == 0)
  				goto packet_error;
  			sum += new_char & 0xff;
088f1b199   Kim Phillips   common/cmd_*.c: s...
891
  			len_lo = untochar(new_char);
8bde7f776   wdenk   * Code cleanup:
892
893
  			length = len_hi * 95 + len_lo;
  			/* check header checksum */
088f1b199   Kim Phillips   common/cmd_*.c: s...
894
  			new_char = getc();
8bde7f776   wdenk   * Code cleanup:
895
896
  			if ((new_char & 0xE0) == 0)
  				goto packet_error;
088f1b199   Kim Phillips   common/cmd_*.c: s...
897
  			if (new_char != tochar((sum + ((sum >> 6) & 0x03)) & 0x3f))
8bde7f776   wdenk   * Code cleanup:
898
899
900
901
902
903
  				goto packet_error;
  			sum += new_char & 0xff;
  /* --length; */ /* new length includes only data and block check to come */
  		}
  		/* bring in rest of packet */
  		while (length > 1) {
088f1b199   Kim Phillips   common/cmd_*.c: s...
904
  			new_char = getc();
8bde7f776   wdenk   * Code cleanup:
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
  			if ((new_char & 0xE0) == 0)
  				goto packet_error;
  			sum += new_char & 0xff;
  			--length;
  			if (k_state == DATA_TYPE) {
  				/* pass on the data if this is a data packet */
  				k_data_char (new_char);
  			} else if (k_state == SEND_TYPE) {
  				/* save send pack in buffer as is */
  				*send_ptr++ = new_char;
  				/* if too much data, back off the pointer */
  				if (send_ptr >= &send_parms[SEND_DATA_SIZE])
  					--send_ptr;
  			}
  		}
  		/* get and validate checksum character */
088f1b199   Kim Phillips   common/cmd_*.c: s...
921
  		new_char = getc();
8bde7f776   wdenk   * Code cleanup:
922
923
  		if ((new_char & 0xE0) == 0)
  			goto packet_error;
088f1b199   Kim Phillips   common/cmd_*.c: s...
924
  		if (new_char != tochar((sum + ((sum >> 6) & 0x03)) & 0x3f))
8bde7f776   wdenk   * Code cleanup:
925
926
  			goto packet_error;
  		/* get END_CHAR */
088f1b199   Kim Phillips   common/cmd_*.c: s...
927
  		new_char = getc();
8bde7f776   wdenk   * Code cleanup:
928
929
930
931
  		if (new_char != END_CHAR) {
  		  packet_error:
  			/* restore state machines */
  			k_state = k_state_saved;
088f1b199   Kim Phillips   common/cmd_*.c: s...
932
  			k_data_restore();
8bde7f776   wdenk   * Code cleanup:
933
  			/* send a negative acknowledge packet in */
088f1b199   Kim Phillips   common/cmd_*.c: s...
934
  			send_nack(n);
8bde7f776   wdenk   * Code cleanup:
935
936
  		} else if (k_state == SEND_TYPE) {
  			/* crack the protocol parms, build an appropriate ack packet */
088f1b199   Kim Phillips   common/cmd_*.c: s...
937
  			handle_send_packet(n);
8bde7f776   wdenk   * Code cleanup:
938
939
  		} else {
  			/* send simple acknowledge packet in */
088f1b199   Kim Phillips   common/cmd_*.c: s...
940
  			send_ack(n);
8bde7f776   wdenk   * Code cleanup:
941
942
943
944
  			/* quit if end of transmission */
  			if (k_state == BREAK_TYPE)
  				done = 1;
  		}
8bde7f776   wdenk   * Code cleanup:
945
946
947
  	}
  	return ((ulong) os_data_addr - (ulong) bin_start_address);
  }
f2841d377   Markus Klotzbuecher   Add support for y...
948
949
  
  static int getcxmodem(void) {
cf48eb9ab   Wolfgang Denk   Some code cleanup
950
  	if (tstc())
f2841d377   Markus Klotzbuecher   Add support for y...
951
952
953
  		return (getc());
  	return -1;
  }
6e66bd559   Angus Ainslie   Enable xmodem sup...
954
  static ulong load_serial_ymodem(ulong offset, int mode)
f2841d377   Markus Klotzbuecher   Add support for y...
955
956
  {
  	int size;
f2841d377   Markus Klotzbuecher   Add support for y...
957
958
959
  	int err;
  	int res;
  	connection_info_t info;
cf48eb9ab   Wolfgang Denk   Some code cleanup
960
961
962
  	char ymodemBuf[1024];
  	ulong store_addr = ~0;
  	ulong addr = 0;
f2841d377   Markus Klotzbuecher   Add support for y...
963

cf48eb9ab   Wolfgang Denk   Some code cleanup
964
  	size = 0;
6e66bd559   Angus Ainslie   Enable xmodem sup...
965
  	info.mode = mode;
088f1b199   Kim Phillips   common/cmd_*.c: s...
966
  	res = xyzModem_stream_open(&info, &err);
f2841d377   Markus Klotzbuecher   Add support for y...
967
  	if (!res) {
f2841d377   Markus Klotzbuecher   Add support for y...
968

cf48eb9ab   Wolfgang Denk   Some code cleanup
969
  		while ((res =
088f1b199   Kim Phillips   common/cmd_*.c: s...
970
  			xyzModem_stream_read(ymodemBuf, 1024, &err)) > 0) {
cf48eb9ab   Wolfgang Denk   Some code cleanup
971
972
973
  			store_addr = addr + offset;
  			size += res;
  			addr += res;
e856bdcfb   Masahiro Yamada   flash: complete C...
974
  #ifdef CONFIG_MTD_NOR_FLASH
088f1b199   Kim Phillips   common/cmd_*.c: s...
975
  			if (addr2info(store_addr)) {
cf48eb9ab   Wolfgang Denk   Some code cleanup
976
  				int rc;
088f1b199   Kim Phillips   common/cmd_*.c: s...
977
  				rc = flash_write((char *) ymodemBuf,
cf48eb9ab   Wolfgang Denk   Some code cleanup
978
979
980
981
982
983
  						  store_addr, res);
  				if (rc != 0) {
  					flash_perror (rc);
  					return (~0);
  				}
  			} else
f2841d377   Markus Klotzbuecher   Add support for y...
984
  #endif
cf48eb9ab   Wolfgang Denk   Some code cleanup
985
  			{
088f1b199   Kim Phillips   common/cmd_*.c: s...
986
  				memcpy((char *)(store_addr), ymodemBuf,
cf48eb9ab   Wolfgang Denk   Some code cleanup
987
988
989
990
991
  					res);
  			}
  
  		}
  	} else {
088f1b199   Kim Phillips   common/cmd_*.c: s...
992
993
  		printf("%s
  ", xyzModem_error(err));
f2841d377   Markus Klotzbuecher   Add support for y...
994
  	}
cf48eb9ab   Wolfgang Denk   Some code cleanup
995

088f1b199   Kim Phillips   common/cmd_*.c: s...
996
997
  	xyzModem_stream_close(&err);
  	xyzModem_stream_terminate(false, &getcxmodem);
f2841d377   Markus Klotzbuecher   Add support for y...
998

0a6036da6   Chris Packham   cmd: load: align ...
999
  	flush_cache(offset, ALIGN(size, ARCH_DMA_MINALIGN));
f2841d377   Markus Klotzbuecher   Add support for y...
1000

088f1b199   Kim Phillips   common/cmd_*.c: s...
1001
1002
  	printf("## Total Size      = 0x%08x = %d Bytes
  ", size, size);
018f53032   Simon Glass   env: Rename commo...
1003
  	env_set_hex("filesize", size);
f2841d377   Markus Klotzbuecher   Add support for y...
1004
1005
1006
  
  	return offset;
  }
902531788   Jon Loeliger   common/: Remove l...
1007
  #endif
8bde7f776   wdenk   * Code cleanup:
1008
1009
  
  /* -------------------------------------------------------------------- */
c76fe4742   Jon Loeliger   common/cmd_[i-n]*...
1010
  #if defined(CONFIG_CMD_LOADS)
8bde7f776   wdenk   * Code cleanup:
1011

6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
1012
  #ifdef	CONFIG_SYS_LOADS_BAUD_CHANGE
0d4983930   wdenk   Patch by Kenneth ...
1013
1014
  U_BOOT_CMD(
  	loads, 3, 0,	do_load_serial,
2fb2604d5   Peter Tyser   Command usage cle...
1015
  	"load S-Record file over serial line",
8bde7f776   wdenk   * Code cleanup:
1016
1017
1018
  	"[ off ] [ baud ]
  "
  	"    - load S-Record file over serial line"
a89c33db9   Wolfgang Denk   General help mess...
1019
  	" with offset 'off' and baudrate 'baud'"
8bde7f776   wdenk   * Code cleanup:
1020
  );
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
1021
  #else	/* ! CONFIG_SYS_LOADS_BAUD_CHANGE */
0d4983930   wdenk   Patch by Kenneth ...
1022
1023
  U_BOOT_CMD(
  	loads, 2, 0,	do_load_serial,
2fb2604d5   Peter Tyser   Command usage cle...
1024
  	"load S-Record file over serial line",
8bde7f776   wdenk   * Code cleanup:
1025
1026
  	"[ off ]
  "
a89c33db9   Wolfgang Denk   General help mess...
1027
  	"    - load S-Record file over serial line with offset 'off'"
8bde7f776   wdenk   * Code cleanup:
1028
  );
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
1029
  #endif	/* CONFIG_SYS_LOADS_BAUD_CHANGE */
8bde7f776   wdenk   * Code cleanup:
1030
1031
1032
1033
  
  /*
   * SAVES always requires LOADS support, but not vice versa
   */
c76fe4742   Jon Loeliger   common/cmd_[i-n]*...
1034
  #if defined(CONFIG_CMD_SAVES)
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
1035
  #ifdef	CONFIG_SYS_LOADS_BAUD_CHANGE
0d4983930   wdenk   Patch by Kenneth ...
1036
1037
  U_BOOT_CMD(
  	saves, 4, 0,	do_save_serial,
2fb2604d5   Peter Tyser   Command usage cle...
1038
  	"save S-Record file over serial line",
8bde7f776   wdenk   * Code cleanup:
1039
1040
1041
  	"[ off ] [size] [ baud ]
  "
  	"    - save S-Record file over serial line"
a89c33db9   Wolfgang Denk   General help mess...
1042
  	" with offset 'off', size 'size' and baudrate 'baud'"
8bde7f776   wdenk   * Code cleanup:
1043
  );
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
1044
  #else	/* ! CONFIG_SYS_LOADS_BAUD_CHANGE */
0d4983930   wdenk   Patch by Kenneth ...
1045
1046
  U_BOOT_CMD(
  	saves, 3, 0,	do_save_serial,
2fb2604d5   Peter Tyser   Command usage cle...
1047
  	"save S-Record file over serial line",
8bde7f776   wdenk   * Code cleanup:
1048
1049
  	"[ off ] [size]
  "
a89c33db9   Wolfgang Denk   General help mess...
1050
  	"    - save S-Record file over serial line with offset 'off' and size 'size'"
8bde7f776   wdenk   * Code cleanup:
1051
  );
6d0f6bcf3   Jean-Christophe PLAGNIOL-VILLARD   rename CFG_ macro...
1052
  #endif	/* CONFIG_SYS_LOADS_BAUD_CHANGE */
70d7cb925   Robert P. J. Day   cmd_load.c: Add #...
1053
1054
  #endif	/* CONFIG_CMD_SAVES */
  #endif	/* CONFIG_CMD_LOADS */
8bde7f776   wdenk   * Code cleanup:
1055

c76fe4742   Jon Loeliger   common/cmd_[i-n]*...
1056
  #if defined(CONFIG_CMD_LOADB)
0d4983930   wdenk   Patch by Kenneth ...
1057
1058
  U_BOOT_CMD(
  	loadb, 3, 0,	do_load_serial_bin,
2fb2604d5   Peter Tyser   Command usage cle...
1059
  	"load binary file over serial line (kermit mode)",
8bde7f776   wdenk   * Code cleanup:
1060
1061
1062
  	"[ off ] [ baud ]
  "
  	"    - load binary file over serial line"
6e66bd559   Angus Ainslie   Enable xmodem sup...
1063
1064
1065
1066
1067
1068
1069
1070
1071
  	" with offset 'off' and baudrate 'baud'"
  );
  
  U_BOOT_CMD(
  	loadx, 3, 0,	do_load_serial_bin,
  	"load binary file over serial line (xmodem mode)",
  	"[ off ] [ baud ]
  "
  	"    - load binary file over serial line"
a89c33db9   Wolfgang Denk   General help mess...
1072
  	" with offset 'off' and baudrate 'baud'"
8bde7f776   wdenk   * Code cleanup:
1073
  );
f2841d377   Markus Klotzbuecher   Add support for y...
1074
1075
  U_BOOT_CMD(
  	loady, 3, 0,	do_load_serial_bin,
2fb2604d5   Peter Tyser   Command usage cle...
1076
  	"load binary file over serial line (ymodem mode)",
f2841d377   Markus Klotzbuecher   Add support for y...
1077
1078
1079
  	"[ off ] [ baud ]
  "
  	"    - load binary file over serial line"
a89c33db9   Wolfgang Denk   General help mess...
1080
  	" with offset 'off' and baudrate 'baud'"
f2841d377   Markus Klotzbuecher   Add support for y...
1081
  );
70d7cb925   Robert P. J. Day   cmd_load.c: Add #...
1082
  #endif	/* CONFIG_CMD_LOADB */