2 * (C) Copyright 2000-2004
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5 * See file CREDITS for list of people who contributed to this
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.
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.
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,
25 * Serial up- and download support
34 DECLARE_GLOBAL_DATA_PTR
;
36 static ulong
load_serial (ulong offset
);
37 static int read_record (char *buf
, ulong len
);
38 static int do_echo
= 1;
40 # if (CONFIG_COMMANDS & CFG_CMD_SAVES)
41 static int save_serial (ulong offset
, ulong size
);
42 static int write_record (char *buf
);
43 # endif /* CFG_CMD_SAVES */
45 int do_load_serial (cmd_tbl_t
*cmdtp
, int argc
, char *argv
[])
52 #ifdef CFG_LOADS_BAUD_CHANGE
53 int load_baudrate
, current_baudrate
;
55 load_baudrate
= current_baudrate
= gd
->baudrate
;
58 if (((env_echo
= getenv("loads_echo")) != NULL
) && (*env_echo
== '1')) {
64 #ifdef CFG_LOADS_BAUD_CHANGE
66 offset
= simple_strtoul(argv
[1], NULL
, 16);
69 load_baudrate
= (int)simple_strtoul(argv
[2], NULL
, 10);
71 /* default to current baudrate */
72 if (load_baudrate
== 0)
73 load_baudrate
= current_baudrate
;
75 if (load_baudrate
!= current_baudrate
) {
76 printf ("## Switch baudrate to %d bps and press ENTER ...\n",
79 gd
->baudrate
= load_baudrate
;
87 #else /* ! CFG_LOADS_BAUD_CHANGE */
89 offset
= simple_strtoul(argv
[1], NULL
, 16);
91 #endif /* CFG_LOADS_BAUD_CHANGE */
93 printf ("## Ready for S-Record download ...\n");
95 addr
= load_serial (offset
);
98 * Gather any trailing characters (for instance, the ^D which
99 * is sent by 'cu' after sending a file), and give the
100 * box some time (100 * 1 ms)
102 for (i
=0; i
<100; ++i
) {
110 printf ("## S-Record download aborted\n");
113 printf ("## Start Addr = 0x%08lX\n", addr
);
117 #ifdef CFG_LOADS_BAUD_CHANGE
118 if (load_baudrate
!= current_baudrate
) {
119 printf ("## Switch baudrate to %d bps and press ESC ...\n",
122 gd
->baudrate
= current_baudrate
;
126 if (getc() == 0x1B) /* ESC */
135 load_serial (ulong offset
)
137 char record
[SREC_MAXRECLEN
+ 1]; /* buffer for one S-Record */
138 char binbuf
[SREC_MAXBINLEN
]; /* buffer for binary data */
139 int binlen
; /* no. of data bytes in S-Rec. */
140 int type
; /* return code for record type */
141 ulong addr
; /* load address from S-Record */
142 ulong size
; /* number of bytes transferred */
145 ulong start_addr
= ~0;
149 while (read_record(record
, SREC_MAXRECLEN
+ 1) >= 0) {
150 type
= srec_decode (record
, &binlen
, &addr
, binbuf
);
153 return (~0); /* Invalid S-Record */
160 store_addr
= addr
+ offset
;
161 memcpy ((char *)(store_addr
), binbuf
, binlen
);
162 if ((store_addr
) < start_addr
)
163 start_addr
= store_addr
;
164 if ((store_addr
+ binlen
- 1) > end_addr
)
165 end_addr
= store_addr
+ binlen
- 1;
171 size
= end_addr
- start_addr
+ 1;
173 "## First Load Addr = 0x%08lX\n"
174 "## Last Load Addr = 0x%08lX\n"
175 "## Total Size = 0x%08lX = %ld Bytes\n",
176 start_addr
, end_addr
, size
, size
178 flush_cache (start_addr
, size
);
179 sprintf(buf
, "%lX", size
);
180 setenv("filesize", buf
);
187 if (!do_echo
) { /* print a '.' every 100 lines */
188 if ((++line_count
% 100) == 0)
193 return (~0); /* Download aborted */
197 read_record (char *buf
, ulong len
)
202 --len
; /* always leave room for terminating '\0' byte */
204 for (p
=buf
; p
< buf
+len
; ++p
) {
205 c
= getc(); /* read character */
207 putc (c
); /* ... and echo it */
215 case 0x03: /* ^C - Control C */
221 /* Check for the console hangup (if any different from serial) */
222 if (gd
->jt
[XF_getc
] != getc
) {
229 /* line too long - truncate */
234 #if (CONFIG_COMMANDS & CFG_CMD_SAVES)
236 int do_save_serial (cmd_tbl_t
*cmdtp
, int flag
, int argc
, char *argv
[])
240 #ifdef CFG_LOADS_BAUD_CHANGE
241 int save_baudrate
, current_baudrate
;
243 save_baudrate
= current_baudrate
= gd
->baudrate
;
247 offset
= simple_strtoul(argv
[1], NULL
, 16);
249 #ifdef CFG_LOADS_BAUD_CHANGE
251 size
= simple_strtoul(argv
[2], NULL
, 16);
254 save_baudrate
= (int)simple_strtoul(argv
[3], NULL
, 10);
256 /* default to current baudrate */
257 if (save_baudrate
== 0)
258 save_baudrate
= current_baudrate
;
260 if (save_baudrate
!= current_baudrate
) {
261 printf ("## Switch baudrate to %d bps and press ENTER ...\n",
264 gd
->baudrate
= save_baudrate
;
272 #else /* ! CFG_LOADS_BAUD_CHANGE */
274 size
= simple_strtoul(argv
[2], NULL
, 16);
276 #endif /* CFG_LOADS_BAUD_CHANGE */
278 printf ("## Ready for S-Record upload, press ENTER to proceed ...\n");
283 if(save_serial (offset
, size
)) {
284 printf ("## S-Record upload aborted\n");
286 printf ("## S-Record upload complete\n");
288 #ifdef CFG_LOADS_BAUD_CHANGE
289 if (save_baudrate
!= current_baudrate
) {
290 printf ("## Switch baudrate to %d bps and press ESC ...\n",
291 (int)current_baudrate
);
293 gd
->baudrate
= current_baudrate
;
297 if (getc() == 0x1B) /* ESC */
305 #define SREC3_START "S0030000FC\n"
306 #define SREC3_FORMAT "S3%02X%08lX%s%02X\n"
307 #define SREC3_END "S70500000000FA\n"
308 #define SREC_BYTES_PER_RECORD 16
310 static int save_serial (ulong address
, ulong count
)
312 int i
, c
, reclen
, checksum
, length
;
313 char *hex
= "0123456789ABCDEF";
314 char record
[2*SREC_BYTES_PER_RECORD
+16]; /* buffer for one S-Record */
315 char data
[2*SREC_BYTES_PER_RECORD
+1]; /* buffer for hex data */
320 if(write_record(SREC3_START
)) /* write the header */
323 if(count
) { /* collect hex data in the buffer */
324 c
= *(volatile uchar
*)(address
+ reclen
); /* get one byte */
325 checksum
+= c
; /* accumulate checksum */
326 data
[2*reclen
] = hex
[(c
>>4)&0x0f];
327 data
[2*reclen
+1] = hex
[c
& 0x0f];
328 data
[2*reclen
+2] = '\0';
332 if(reclen
== SREC_BYTES_PER_RECORD
|| count
== 0) {
333 /* enough data collected for one record: dump it */
334 if(reclen
) { /* build & write a data record: */
335 /* address + data + checksum */
336 length
= 4 + reclen
+ 1;
338 /* accumulate length bytes into checksum */
339 for(i
= 0; i
< 2; i
++)
340 checksum
+= (length
>> (8*i
)) & 0xff;
342 /* accumulate address bytes into checksum: */
343 for(i
= 0; i
< 4; i
++)
344 checksum
+= (address
>> (8*i
)) & 0xff;
346 /* make proper checksum byte: */
347 checksum
= ~checksum
& 0xff;
349 /* output one record: */
350 sprintf(record
, SREC3_FORMAT
, length
, address
, data
, checksum
);
351 if(write_record(record
))
354 address
+= reclen
; /* increment address */
360 if(write_record(SREC3_END
)) /* write the final record */
366 write_record (char *buf
)
373 /* Check for the console hangup (if any different from serial) */
380 # endif /* CFG_CMD_SAVES */
382 #ifdef CFG_LOADS_BAUD_CHANGE
384 loads
, 3, 0, do_load_serial
,
385 "loads - load S-Record file over serial line\n",
387 " - load S-Record file over serial line"
388 " with offset 'off' and baudrate 'baud'\n"
391 #else /* ! CFG_LOADS_BAUD_CHANGE */
393 loads
, 2, 0, do_load_serial
,
394 "loads - load S-Record file over serial line\n",
396 " - load S-Record file over serial line with offset 'off'\n"
398 #endif /* CFG_LOADS_BAUD_CHANGE */
401 * SAVES always requires LOADS support, but not vice versa
405 #if (CONFIG_COMMANDS & CFG_CMD_SAVES)
406 #ifdef CFG_LOADS_BAUD_CHANGE
408 saves
, 4, 0, do_save_serial
,
409 "saves - save S-Record file over serial line\n",
410 "[ off ] [size] [ baud ]\n"
411 " - save S-Record file over serial line"
412 " with offset 'off', size 'size' and baudrate 'baud'\n"
414 #else /* ! CFG_LOADS_BAUD_CHANGE */
416 saves
, 3, 0, do_save_serial
,
417 "saves - save S-Record file over serial line\n",
419 " - save S-Record file over serial line with offset 'off' and size 'size'\n"
421 #endif /* CFG_LOADS_BAUD_CHANGE */
422 #endif /* CFG_CMD_SAVES */