📄 cmd_load.c.l
字号:
01 /*02 * (C) Copyright 2000-200403 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.04 *05 * See file CREDITS for list of people who contributed to this06 * project.07 *08 * This program is free software; you can redistribute it and/or09 * modify it under the terms of the GNU General Public License as10 * published by the Free Software Foundation; either version 2 of11 * 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 of15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the16 * GNU General Public License for more details.17 *18 * You should have received a copy of the GNU General Public License19 * along with this program; if not, write to the Free Software20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,21 * MA 02111-1307 USA22 */23 24 /*25 * Serial up- and download support26 */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 (CONFIG_COMMANDS & CFG_CMD_LOADB)37 /* support xmodem, www.arm9.net */38 static ulong load_serial_xmodem (ulong offset);39 static ulong load_serial_ymodem (ulong offset);40 #endif41 42 #if (CONFIG_COMMANDS & CFG_CMD_LOADS)43 static ulong load_serial (ulong offset);44 static int read_record (char *buf, ulong len);45 # if (CONFIG_COMMANDS & CFG_CMD_SAVES)46 static int save_serial (ulong offset, ulong size);47 static int write_record (char *buf);48 # endif /* CFG_CMD_SAVES */49 50 static int do_echo = 1;51 #endif /* CFG_CMD_LOADS */52 53 /* -------------------------------------------------------------------- */54 55 #if (CONFIG_COMMANDS & CFG_CMD_LOADS)56 int do_load_serial (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])57 {58 ulong offset = 0;59 ulong addr;60 int i;61 char *env_echo;62 int rcode = 0;63 #ifdef CFG_LOADS_BAUD_CHANGE64 int load_baudrate, current_baudrate;65 66 load_baudrate = current_baudrate = gd->baudrate;67 #endif68 69 if (((env_echo = getenv("loads_echo")) != NULL) && (*env_echo == '1')) {70 do_echo = 1;71 } else {72 do_echo = 0;73 }74 75 #ifdef CFG_LOADS_BAUD_CHANGE76 if (argc >= 2) {77 offset = simple_strtoul(argv[1], NULL, 16);78 }79 if (argc == 3) {80 load_baudrate = (int)simple_strtoul(argv[2], NULL, 10);81 82 /* default to current baudrate */83 if (load_baudrate == 0)84 load_baudrate = current_baudrate;85 }86 if (load_baudrate != current_baudrate) {87 printf ("## Switch baudrate to %d bps and press ENTER ...\n",88 load_baudrate);89 udelay(50000);90 gd->baudrate = load_baudrate;91 serial_setbrg ();92 udelay(50000);93 for (;;) {94 if (getc() == '\r')95 break;96 }97 }98 #else /* ! CFG_LOADS_BAUD_CHANGE */99 if (argc == 2) {100 offset = simple_strtoul(argv[1], NULL, 16);101 }102 #endif /* CFG_LOADS_BAUD_CHANGE */103 104 printf ("## Ready for S-Record download ...\n");105 106 addr = load_serial (offset);107 108 /*109 * Gather any trailing characters (for instance, the ^D which110 * is sent by 'cu' after sending a file), and give the111 * box some time (100 * 1 ms)112 */113 for (i=0; i<100; ++i) {114 if (tstc()) {115 (void) getc();116 }117 udelay(1000);118 }119 120 if (addr == ~0) {121 printf ("## S-Record download aborted\n");122 rcode = 1;123 } else {124 printf ("## Start Addr = 0x%08lX\n", addr);125 load_addr = addr;126 }127 128 #ifdef CFG_LOADS_BAUD_CHANGE129 if (load_baudrate != current_baudrate) {130 printf ("## Switch baudrate to %d bps and press ESC ...\n",131 current_baudrate);132 udelay (50000);133 gd->baudrate = current_baudrate;134 serial_setbrg ();135 udelay (50000);136 for (;;) {137 if (getc() == 0x1B) /* ESC */138 break;139 }140 }141 #endif142 return rcode;143 }144 145 static ulong146 load_serial (ulong offset)147 {148 char record[SREC_MAXRECLEN + 1]; /* buffer for one S-Record */149 char binbuf[SREC_MAXBINLEN]; /* buffer for binary data */150 int binlen; /* no. of data bytes in S-Rec. */151 int type; /* return code for record type */152 ulong addr; /* load address from S-Record */153 ulong size; /* number of bytes transferred */154 char buf[32];155 ulong store_addr;156 ulong start_addr = ~0;157 ulong end_addr = 0;158 int line_count = 0;159 160 while (read_record(record, SREC_MAXRECLEN + 1) >= 0) {161 type = srec_decode (record, &binlen, &addr, binbuf);162 163 if (type < 0) {164 return (~0); /* Invalid S-Record */165 }166 167 switch (type) {168 case SREC_DATA2:169 case SREC_DATA3:170 case SREC_DATA4:171 store_addr = addr + offset;172 #ifndef CFG_NO_FLASH173 if (addr2info(store_addr)) {174 int rc;175 176 rc = flash_write((char *)binbuf,store_addr,binlen);177 if (rc != 0) {178 flash_perror (rc);179 return (~0);180 }181 } else182 #endif183 {184 memcpy ((char *)(store_addr), binbuf, binlen);185 }186 if ((store_addr) < start_addr)187 start_addr = store_addr;188 if ((store_addr + binlen - 1) > end_addr)189 end_addr = store_addr + binlen - 1;190 break;191 case SREC_END2:192 case SREC_END3:193 case SREC_END4:194 udelay (10000);195 size = end_addr - start_addr + 1;196 printf ("\n"197 "## First Load Addr = 0x%08lX\n"198 "## Last Load Addr = 0x%08lX\n"199 "## Total Size = 0x%08lX = %ld Bytes\n",200 start_addr, end_addr, size, size201 );202 flush_cache (start_addr, size);203 sprintf(buf, "%lX", size);204 setenv("filesize", buf);205 return (addr);206 case SREC_START:207 break;208 default:209 break;210 }211 if (!do_echo) { /* print a '.' every 100 lines */212 if ((++line_count % 100) == 0)213 putc ('.');214 }215 }216 217 return (~0); /* Download aborted */218 }219 220 static int221 read_record (char *buf, ulong len)222 {223 char *p;224 char c;225 226 --len; /* always leave room for terminating '\0' byte */227 228 for (p=buf; p < buf+len; ++p) {229 c = getc(); /* read character */230 if (do_echo)231 putc (c); /* ... and echo it */232 233 switch (c) {234 case '\r':235 case '\n':236 *p = '\0';237 return (p - buf);238 case '\0':239 case 0x03: /* ^C - Control C */240 return (-1);241 default:242 *p = c;243 }244 245 /* Check for the console hangup (if any different from serial) */246 if (gd->jt[XF_getc] != getc) {247 if (ctrlc()) {248 return (-1);249 }250 }251 }252 253 /* line too long - truncate */254 *p = '\0';255 return (p - buf);256 }257 258 #if (CONFIG_COMMANDS & CFG_CMD_SAVES)259 260 int do_save_serial (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])261 {262 ulong offset = 0;263 ulong size = 0;264 #ifdef CFG_LOADS_BAUD_CHANGE265 int save_baudrate, current_baudrate;266 267 save_baudrate = current_baudrate = gd->baudrate;268 #endif269 270 if (argc >= 2) {271 offset = simple_strtoul(argv[1], NULL, 16);272 }273 #ifdef CFG_LOADS_BAUD_CHANGE274 if (argc >= 3) {275 size = simple_strtoul(argv[2], NULL, 16);276 }277 if (argc == 4) {278 save_baudrate = (int)simple_strtoul(argv[3], NULL, 10);279 280 /* default to current baudrate */281 if (save_baudrate == 0)282 save_baudrate = current_baudrate;283 }284 if (save_baudrate != current_baudrate) {285 printf ("## Switch baudrate to %d bps and press ENTER ...\n",286 save_baudrate);287 udelay(50000);288 gd->baudrate = save_baudrate;289 serial_setbrg ();290 udelay(50000);291 for (;;) {292 if (getc() == '\r')293 break;294 }295 }296 #else /* ! CFG_LOADS_BAUD_CHANGE */297 if (argc == 3) {298 size = simple_strtoul(argv[2], NULL, 16);299 }300 #endif /* CFG_LOADS_BAUD_CHANGE */301 302 printf ("## Ready for S-Record upload, press ENTER to proceed ...\n");303 for (;;) {304 if (getc() == '\r')305 break;306 }307 if(save_serial (offset, size)) {308 printf ("## S-Record upload aborted\n");309 } else {310 printf ("## S-Record upload complete\n");311 }312 #ifdef CFG_LOADS_BAUD_CHANGE313 if (save_baudrate != current_baudrate) {314 printf ("## Switch baudrate to %d bps and press ESC ...\n",315 (int)current_baudrate);316 udelay (50000);317 gd->baudrate = current_baudrate;318 serial_setbrg ();319 udelay (50000);320 for (;;) {321 if (getc() == 0x1B) /* ESC */322 break;323 }324 }325 #endif326 return 0;327 }328 329 #define SREC3_START "S0030000FC\n"330 #define SREC3_FORMAT "S3%02X%08lX%s%02X\n"331 #define SREC3_END "S70500000000FA\n"332 #define SREC_BYTES_PER_RECORD 16333 334 static int save_serial (ulong address, ulong count)335 {336 int i, c, reclen, checksum, length;337 char *hex = "0123456789ABCDEF";338 char record[2*SREC_BYTES_PER_RECORD+16]; /* buffer for one S-Record */339 char data[2*SREC_BYTES_PER_RECORD+1]; /* buffer for hex data */340 341 reclen = 0;342 checksum = 0;343 344 if(write_record(SREC3_START)) /* write the header */345 return (-1);346 do {347 if(count) { /* collect hex data in the buffer */348 c = *(volatile uchar*)(address + reclen); /* get one byte */349 checksum += c; /* accumulate checksum */350 data[2*reclen] = hex[(c>>4)&0x0f];351 data[2*reclen+1] = hex[c & 0x0f];352 data[2*reclen+2] = '\0';353 ++reclen;354 --count;355 }356 if(reclen == SREC_BYTES_PER_RECORD || count == 0) {357 /* enough data collected for one record: dump it */358 if(reclen) { /* build & write a data record: */359 /* address + data + checksum */360 length = 4 + reclen + 1;361 362 /* accumulate length bytes into checksum */363 for(i = 0; i < 2; i++)364 checksum += (length >> (8*i)) & 0xff;365 366 /* accumulate address bytes into checksum: */367 for(i = 0; i < 4; i++)368 checksum += (address >> (8*i)) & 0xff;369 370 /* make proper checksum byte: */371 checksum = ~checksum & 0xff;372 373 /* output one record: */374 sprintf(record, SREC3_FORMAT, length, address, data, checksum);375 if(write_record(record))376 return (-1);377 }378 address += reclen; /* increment address */379 checksum = 0;380 reclen = 0;381 }382 }383 while(count);384 if(write_record(SREC3_END)) /* write the final record */385 return (-1);386 return(0);387 }388 389 static int390 write_record (char *buf)391 {392 char c;393 394 while((c = *buf++))395 putc(c);396 397 /* Check for the console hangup (if any different from serial) */398 399 if (ctrlc()) {400 return (-1);401 }402 return (0);403 }404 # endif /* CFG_CMD_SAVES */405
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -