cfi new: fix new disabling buffer support
[barebox-mini2440.git] / commands / loads.c
blob0d03597585f0f8f5a5d51e11b3c63d9406a9aa03
1 /*
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
6 * project.
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,
21 * MA 02111-1307 USA
25 * Serial up- and download support
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>
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[])
47 ulong offset = 0;
48 ulong addr;
49 int i;
50 char *env_echo;
51 int rcode = 0;
52 #ifdef CFG_LOADS_BAUD_CHANGE
53 int load_baudrate, current_baudrate;
55 load_baudrate = current_baudrate = gd->baudrate;
56 #endif
58 if (((env_echo = getenv("loads_echo")) != NULL) && (*env_echo == '1')) {
59 do_echo = 1;
60 } else {
61 do_echo = 0;
64 #ifdef CFG_LOADS_BAUD_CHANGE
65 if (argc >= 2) {
66 offset = simple_strtoul(argv[1], NULL, 16);
68 if (argc == 3) {
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",
77 load_baudrate);
78 udelay(50000);
79 gd->baudrate = load_baudrate;
80 serial_setbrg ();
81 udelay(50000);
82 for (;;) {
83 if (getc() == '\r')
84 break;
87 #else /* ! CFG_LOADS_BAUD_CHANGE */
88 if (argc == 2) {
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) {
103 if (tstc()) {
104 (void) getc();
106 udelay(1000);
109 if (addr == ~0) {
110 printf ("## S-Record download aborted\n");
111 rcode = 1;
112 } else {
113 printf ("## Start Addr = 0x%08lX\n", addr);
114 load_addr = addr;
117 #ifdef CFG_LOADS_BAUD_CHANGE
118 if (load_baudrate != current_baudrate) {
119 printf ("## Switch baudrate to %d bps and press ESC ...\n",
120 current_baudrate);
121 udelay (50000);
122 gd->baudrate = current_baudrate;
123 serial_setbrg ();
124 udelay (50000);
125 for (;;) {
126 if (getc() == 0x1B) /* ESC */
127 break;
130 #endif
131 return rcode;
134 static ulong
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 */
143 char buf[32];
144 ulong store_addr;
145 ulong start_addr = ~0;
146 ulong end_addr = 0;
147 int line_count = 0;
149 while (read_record(record, SREC_MAXRECLEN + 1) >= 0) {
150 type = srec_decode (record, &binlen, &addr, binbuf);
152 if (type < 0) {
153 return (~0); /* Invalid S-Record */
156 switch (type) {
157 case SREC_DATA2:
158 case SREC_DATA3:
159 case SREC_DATA4:
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;
166 break;
167 case SREC_END2:
168 case SREC_END3:
169 case SREC_END4:
170 udelay (10000);
171 size = end_addr - start_addr + 1;
172 printf ("\n"
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);
181 return (addr);
182 case SREC_START:
183 break;
184 default:
185 break;
187 if (!do_echo) { /* print a '.' every 100 lines */
188 if ((++line_count % 100) == 0)
189 putc ('.');
193 return (~0); /* Download aborted */
196 static int
197 read_record (char *buf, ulong len)
199 char *p;
200 char c;
202 --len; /* always leave room for terminating '\0' byte */
204 for (p=buf; p < buf+len; ++p) {
205 c = getc(); /* read character */
206 if (do_echo)
207 putc (c); /* ... and echo it */
209 switch (c) {
210 case '\r':
211 case '\n':
212 *p = '\0';
213 return (p - buf);
214 case '\0':
215 case 0x03: /* ^C - Control C */
216 return (-1);
217 default:
218 *p = c;
221 /* Check for the console hangup (if any different from serial) */
222 if (gd->jt[XF_getc] != getc) {
223 if (ctrlc()) {
224 return (-1);
229 /* line too long - truncate */
230 *p = '\0';
231 return (p - buf);
234 #if (CONFIG_COMMANDS & CFG_CMD_SAVES)
236 int do_save_serial (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
238 ulong offset = 0;
239 ulong size = 0;
240 #ifdef CFG_LOADS_BAUD_CHANGE
241 int save_baudrate, current_baudrate;
243 save_baudrate = current_baudrate = gd->baudrate;
244 #endif
246 if (argc >= 2) {
247 offset = simple_strtoul(argv[1], NULL, 16);
249 #ifdef CFG_LOADS_BAUD_CHANGE
250 if (argc >= 3) {
251 size = simple_strtoul(argv[2], NULL, 16);
253 if (argc == 4) {
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",
262 save_baudrate);
263 udelay(50000);
264 gd->baudrate = save_baudrate;
265 serial_setbrg ();
266 udelay(50000);
267 for (;;) {
268 if (getc() == '\r')
269 break;
272 #else /* ! CFG_LOADS_BAUD_CHANGE */
273 if (argc == 3) {
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");
279 for (;;) {
280 if (getc() == '\r')
281 break;
283 if(save_serial (offset, size)) {
284 printf ("## S-Record upload aborted\n");
285 } else {
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);
292 udelay (50000);
293 gd->baudrate = current_baudrate;
294 serial_setbrg ();
295 udelay (50000);
296 for (;;) {
297 if (getc() == 0x1B) /* ESC */
298 break;
301 #endif
302 return 0;
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 */
317 reclen = 0;
318 checksum = 0;
320 if(write_record(SREC3_START)) /* write the header */
321 return (-1);
322 do {
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';
329 ++reclen;
330 --count;
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))
352 return (-1);
354 address += reclen; /* increment address */
355 checksum = 0;
356 reclen = 0;
359 while(count);
360 if(write_record(SREC3_END)) /* write the final record */
361 return (-1);
362 return(0);
365 static int
366 write_record (char *buf)
368 char c;
370 while((c = *buf++))
371 putc(c);
373 /* Check for the console hangup (if any different from serial) */
375 if (ctrlc()) {
376 return (-1);
378 return (0);
380 # endif /* CFG_CMD_SAVES */
382 #ifdef CFG_LOADS_BAUD_CHANGE
383 U_BOOT_CMD(
384 loads, 3, 0, do_load_serial,
385 "loads - load S-Record file over serial line\n",
386 "[ off ] [ baud ]\n"
387 " - load S-Record file over serial line"
388 " with offset 'off' and baudrate 'baud'\n"
391 #else /* ! CFG_LOADS_BAUD_CHANGE */
392 U_BOOT_CMD(
393 loads, 2, 0, do_load_serial,
394 "loads - load S-Record file over serial line\n",
395 "[ off ]\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
407 U_BOOT_CMD(
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 */
415 U_BOOT_CMD(
416 saves, 3, 0, do_save_serial,
417 "saves - save S-Record file over serial line\n",
418 "[ off ] [size]\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 */