From: Erik M. <er...@us...> - 2002-01-05 20:21:52
|
Update of /cvsroot/blob/blob/src/blob In directory usw-pr-cvs1:/tmp/cvs-serv7208/src/blob Modified Files: Makefile.am main.c Added Files: xmodem.c Log Message: Add xmodem download (from Christopher Hoover) Get rid of old xmodem files --- NEW FILE: xmodem.c --- /*------------------------------------------------------------------------- * Filename: xmodem.c * Version: $Id: xmodem.c,v 1.1 2002/01/05 20:21:49 erikm Exp $ * Copyright: Copyright (C) 2001, Hewlett-Packard Company * Author: Christopher Hoover <ch...@hp...> * Description: xmodem functionality for uploading of kernels * and the like * Created at: Thu Dec 20 01:58:08 PST 2001 *-----------------------------------------------------------------------*/ /* * xmodem.c: xmodem functionality for uploading of kernels and * the like * * Copyright (C) 2001 Hewlett-Packard Laboratories * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ident "$Id: xmodem.c,v 1.1 2002/01/05 20:21:49 erikm Exp $" #ifdef HAVE_CONFIG_H # include <blob/config.h> #endif #include <blob/errno.h> #include <blob/serial.h> #include <blob/util.h> #define SOH 0x01 #define STX 0x02 #define EOT 0x04 #define ACK 0x06 #define NAK 0x15 #define CAN 0x18 #define BS 0x08 /* Cf: http://www.textfiles.com/apple/xmodem http://www.phys.washington.edu/~belonis/xmodem/docxmodem.txt http://www.phys.washington.edu/~belonis/xmodem/docymodem.txt http://www.phys.washington.edu/~belonis/xmodem/modmprot.col */ #define TIMEOUT 10 #define MAXERRORS 5 #define ERROR(...) do { } while (0) static inline void WriteByte(char cc) { serial_write_raw(cc); } static inline void ReadFlush() { serial_flush_input(); } int ReadByteWithTimeout(unsigned int timeout) { char buf[1]; int n; n = SerialInputBlock(buf, 1, timeout); if (n == 1) return buf[0] & 0xff; else return -1; } int XModemReceive(char *bufBase, int bufLen) { char blockBuf[1024]; unsigned int errors = 0; unsigned int wantBlockNo = 1; unsigned int length = 0; int crc = 1; char nak = 'C'; ReadFlush(); /* Ask for CRC; if we get errors, we will go with checksum */ WriteByte(nak); for (;;) { int blockBegin; int blockNo, blockNoOnesCompl; int blockLength; int cksum = 0; int crcHi = 0; int crcLo = 0; blockBegin = ReadByteWithTimeout(TIMEOUT); if (blockBegin < 0) goto timeout; nak = NAK; switch (blockBegin) { case SOH: case STX: break; case EOT: WriteByte(ACK); goto done; default: goto error; } /* block no */ blockNo = ReadByteWithTimeout(TIMEOUT); if (blockNo < 0) goto timeout; /* block no one's compliment */ blockNoOnesCompl = ReadByteWithTimeout(TIMEOUT); if (blockNoOnesCompl < 0) goto timeout; if (blockNo != (255 - blockNoOnesCompl)) { ERROR("bad block ones compl\n"); goto error; } blockLength = (blockBegin == SOH) ? 128 : 1024; { int i; for (i = 0; i < blockLength; i++) { int cc = ReadByteWithTimeout(TIMEOUT); if (cc < 0) goto timeout; blockBuf[i] = cc; } } if (crc) { crcHi = ReadByteWithTimeout(TIMEOUT); if (crcHi < 0) goto timeout; crcLo = ReadByteWithTimeout(TIMEOUT); if (crcLo < 0) goto timeout; } else { cksum = ReadByteWithTimeout(TIMEOUT); if (cksum < 0) goto timeout; } if (blockNo == ((wantBlockNo - 1) & 0xff)) { /* a repeat of the last block is ok, just ignore it. */ /* this also ignores the initial block 0 which is */ /* meta data. */ goto next; } else if (blockNo != (wantBlockNo & 0xff)) { ERROR("unexpected block no, 0x%08x, expecting 0x%08x\n", blockNo, wantBlockNo); goto error; } if (crc) { int crc = 0; int i, j; int expectedCrcHi; int expectedCrcLo; for (i = 0; i < blockLength; i++) { crc = crc ^ (int) blockBuf[i] << 8; for (j = 0; j < 8; j++) if (crc & 0x8000) crc = crc << 1 ^ 0x1021; else crc = crc << 1; } expectedCrcHi = (crc >> 8) & 0xff; expectedCrcLo = crc & 0xff; if ((crcHi != expectedCrcHi) || (crcLo != expectedCrcLo)) { ERROR("crc error, expected 0x%02x 0x%02x, got 0x%02x 0x%02x\n", expectedCrcHi, expectedCrcLo, crcHi, crcLo); goto error; } } else { unsigned char expectedCksum = 0; int i; for (i = 0; i < blockLength; i++) expectedCksum += blockBuf[i]; if (cksum != expectedCksum) { ERROR("checksum error, expected 0x%02x, got 0x%02x\n", expectedCksum, cksum); goto error; } } wantBlockNo++; length += blockLength; if (length > bufLen) { ERROR("out of space\n"); goto error; } { int i; for (i = 0; i < blockLength; i++) *bufBase++ = blockBuf[i]; } next: errors = 0; WriteByte(ACK); continue; error: timeout: errors++; if (errors == MAXERRORS) { /* Abort */ int i; // if using crc, try again w/o crc if (nak == 'C') { nak = NAK; errors = 0; crc = 0; goto timeout; } ERROR("too many errors; giving up\n"); for (i = 0; i < 5; i ++) WriteByte(CAN); for (i = 0; i < 5; i ++) WriteByte(BS); return -1; } ReadFlush(); WriteByte(nak); } done: return length; } Index: Makefile.am =================================================================== RCS file: /cvsroot/blob/blob/src/blob/Makefile.am,v retrieving revision 1.13 retrieving revision 1.14 diff -u -d -r1.13 -r1.14 --- Makefile.am 2001/12/27 18:27:37 1.13 +++ Makefile.am 2002/01/05 20:21:49 1.14 @@ -130,7 +130,8 @@ param_block.c \ partition.c \ reboot.c \ - uucodec.c + uucodec.c \ + xmodem.c # conditionally compiled sources Index: main.c =================================================================== RCS file: /cvsroot/blob/blob/src/blob/main.c,v retrieving revision 1.20 retrieving revision 1.21 diff -u -d -r1.20 -r1.21 --- main.c 2002/01/03 16:07:18 1.20 +++ main.c 2002/01/05 20:21:49 1.21 @@ -53,6 +53,7 @@ #include <blob/time.h> #include <blob/util.h> #include <blob/uucodec.h> +#include <blob/xmodem.h> @@ -182,48 +183,59 @@ -static int Download(int argc, char *argv[]) +static int set_download_parameters(char *name, u32 *startAddress, + int *bufLen, int **numRead) { - u32 startAddress = 0; - int bufLen; - int *numRead = 0; - int retval; - - if(argc < 2) - return -ENOPARAMS; - - if(strncmp(argv[1], "blob", 5) == 0) { + if(strncmp(name, "blob", 5) == 0) { /* download blob */ - startAddress = BLOB_RAM_BASE; - bufLen = BLOB_FLASH_LEN; - numRead = &blob_status.blobSize; + *startAddress = BLOB_RAM_BASE; + *bufLen = BLOB_FLASH_LEN; + *numRead = &blob_status.blobSize; blob_status.blobType = fromDownload; #ifdef PARAM_START - } else if(strncmp(argv[1], "param", 6) == 0) { + } else if(strncmp(name, "param", 6) == 0) { /* download param */ - startAddress = PARAM_RAM_BASE; - bufLen = PARAM_FLASH_LEN; - numRead = &blob_status.paramSize; + *startAddress = PARAM_RAM_BASE; + *bufLen = PARAM_FLASH_LEN; + *numRead = &blob_status.paramSize; blob_status.paramType = fromDownload; #endif - } else if(strncmp(argv[1], "kernel", 7) == 0) { + } else if(strncmp(name, "kernel", 7) == 0) { /* download kernel */ - startAddress = KERNEL_RAM_BASE; - bufLen = KERNEL_FLASH_LEN; - numRead = &blob_status.kernelSize; + *startAddress = KERNEL_RAM_BASE; + *bufLen = KERNEL_FLASH_LEN; + *numRead = &blob_status.kernelSize; blob_status.kernelType = fromDownload; - } else if(strncmp(argv[1], "ramdisk", 8) == 0) { + } else if(strncmp(name, "ramdisk", 8) == 0) { /* download ramdisk */ - startAddress = RAMDISK_RAM_BASE; - bufLen = RAMDISK_FLASH_LEN; - numRead = &blob_status.ramdiskSize; + *startAddress = RAMDISK_RAM_BASE; + *bufLen = RAMDISK_FLASH_LEN; + *numRead = &blob_status.ramdiskSize; blob_status.ramdiskType = fromDownload; } else { - printerror(EINVAL, argv[1]); - return 0; + printerror(-EINVAL, name); + return -EINVAL; } + return 0; +} + + + +static int Download(int argc, char *argv[]) +{ + u32 startAddress = 0; + int bufLen; + int *numRead = 0; + int retval; + + if(argc < 2) + return -ENOPARAMS; + + retval = set_download_parameters(argv[1], &startAddress, + &bufLen, &numRead); + if (blob_status.terminalSpeed != blob_status.downloadSpeed) { SerialOutputString("Switching to "); PrintSerialSpeed(blob_status.downloadSpeed); @@ -275,9 +287,88 @@ } static char downloadhelp[] = "download {blob|param|kernel|ramdisk}\n" -"Download <argument> image to RAM\n"; +"Download <argument> image to RAM using uuencode\n"; __commandlist(Download, "download", downloadhelp); + + + + +static int xdownload(int argc, char *argv[]) +{ + u32 startAddress = 0; + int bufLen; + int *numRead = 0; + int retval; + + if(argc < 2) + return -ENOPARAMS; + + retval = set_download_parameters(argv[1], &startAddress, + &bufLen, &numRead); + + if (blob_status.terminalSpeed != blob_status.downloadSpeed) { + SerialOutputString("Switching to "); + PrintSerialSpeed(blob_status.downloadSpeed); + SerialOutputString(" baud\n"); + + SerialOutputString("Switch your terminal emulator to the same speed and\n"); + SerialOutputString("start sending using the XMODEM protocl (repeated ^X) to quit.\n"); + SerialOutputString(PACKAGE " will switch back to "); + PrintSerialSpeed(blob_status.terminalSpeed); + SerialOutputString(" baud after XMODEM succeeds or times out.\n"); + + serial_init(blob_status.downloadSpeed); + } else { + SerialOutputString("Start sending using the XMODEM protocol (repeated ^X to quit).\n\n"); + } + + *numRead = XModemReceive((char *) startAddress, bufLen); + + SerialOutputString("\n\n\n"); + + if (blob_status.terminalSpeed != blob_status.downloadSpeed) { + SerialOutputString("\n(Please switch your terminal emulator back to "); + PrintSerialSpeed(blob_status.terminalSpeed); + SerialOutputString(" baud)\n"); + } + + if(*numRead < 0) { + /* something went wrong */ + retval = *numRead; + + /* reload the correct memory */ + do_reload(argv[1]); + + serial_init(blob_status.terminalSpeed); + return retval; + } + SerialOutputString("Received "); + SerialOutputDec(*numRead); + SerialOutputString(" (0x"); + SerialOutputHex(*numRead); + SerialOutputString(") bytes"); +#ifdef BLOB_DEBUG + SerialOutputString(" at 0x"); + SerialOutputHex((u32) startAddress); +#endif + SerialOutputString(".\n"); + + + serial_init(blob_status.terminalSpeed); + + return 0; +} + +static char xdownloadhelp[] = "xdownload {blob|param|kernel|ramdisk}\n" +"Download <argument> image to RAM using xmodem\n"; + +__commandlist(xdownload, "xdownload", xdownloadhelp); + + + + + |