/* * flashwrite.c: programming the flash memory on a NetWinder * Copyright 1998, 1999 Rebel.com * * History * Oct 27, 1999 - woody - reinstated interactive file info. * Fixed report for starting offset > 0 * Added checking the flash size, close all files on error. * * Jun 24, 1999 - Ralph Siemsen * Added are-you-sure question and override (-yes) option. * More verbose reporting of offset range errors. * * May 16, 1999 - Andrew E. Mileski * Cleanup and made to safely flash any amount at any offset. * * ?, 1998 - Woody Suwalski * Original writing. * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include #include #include "nwflash.h" /* These must be powers of 2 */ #define FLASH_BANK (64 * 1024) #define MAX_FLASH (4 * 1024 * 1024) #define FLASH_MASK (FLASH_BANK - 1) int flashsize(int fd) { int size = 0; if (lseek(fd, 4*1024*1024, SEEK_SET) > 0) size = 4*1024*1024; else if (lseek(fd, 1024*1024, SEEK_SET) > 0) size = 1024*1024; return size; } void fatal_error(void) { fprintf(stderr, "Fatal error! Try again!\n"); } int flashwrite(char *datafile, int flash_offset, int base64_ok) { int buf_offset, data_fd, flash_fd, flash_size, rc, written; char *buf; /* Writing to first 64k only if enabled */ if (!base64_ok && flash_offset < FLASH_BANK) { fprintf(stderr, "Writes to the first 64k not permitted " "unless -base64 specified\n"); return 1; } /* Writing to negative offset is illegal */ if (flash_offset < 0) { fprintf(stderr, "Invalid offset\n"); return 1; } flash_fd = open("/dev/nwflash", O_RDWR); if (flash_fd <= 0) { perror("Error opening flash device"); return 1; } /* Warn if writing beyond 4MB */ flash_size = flashsize(flash_fd); if (flash_offset >= flash_size) { fprintf(stderr, "Error: offset above %dMB > flash size %dMB!\n", (flash_offset / 1024) / 1024, (flash_size / 1024) / 1024); close(flash_fd); return 1; } if (base64_ok) ioctl(flash_fd, CMD_WRITE_BASE64K_ENABLE); buf = (char *)malloc(FLASH_BANK); if (!buf) { perror("Can't allocate a buffer"); close(flash_fd); return 1; } data_fd = open(datafile, O_RDONLY); if (data_fd <= 0) { perror("Error opening data file"); close(flash_fd); return 1; } /* Start at the beginning of a bank */ buf_offset = flash_offset & FLASH_MASK; flash_offset -= buf_offset; lseek(flash_fd, flash_offset, SEEK_SET); /* Make the first bank's data complete */ if (buf_offset) { read(flash_fd, buf, buf_offset); lseek(flash_fd, flash_offset, SEEK_SET); } rc = read(data_fd, buf + buf_offset, FLASH_BANK - buf_offset); written = rc; /* Write complete banks of data */ do { ioctl(flash_fd, CMD_WRITE_ENABLE); rc = write(flash_fd, buf, FLASH_BANK); ioctl(flash_fd, CMD_WRITE_DISABLE); if (rc != FLASH_BANK) { fatal_error(); close(flash_fd); close(data_fd); return 1; } flash_offset += FLASH_BANK; rc = read(data_fd, buf, FLASH_BANK); written += rc; } while (rc == FLASH_BANK); flash_size = flash_offset + rc; /* Write the last incomplete bank (if any) */ if (rc > 0) { lseek(flash_fd, flash_offset + rc, SEEK_SET); read(flash_fd, buf + rc, FLASH_BANK - rc); lseek(flash_fd, flash_offset, SEEK_SET); ioctl(flash_fd, CMD_WRITE_ENABLE); rc = write(flash_fd, buf, FLASH_BANK); ioctl(flash_fd, CMD_WRITE_DISABLE); if (rc != FLASH_BANK) { fatal_error(); return 1; } } close(flash_fd); close(data_fd); fprintf(stderr, "Successfully wrote %d bytes to flash.\n", written); return 0; } int main (int argc, char **argv) { int i, rc; char *our_name; /* Command line args */ int base64_ok = 0; int show_prompt = 1; char *datafile = NULL; int offset = 0; int retry = 1; int data_fd; int data_size; /* Get our executable's name (should be "flashwrite") */ our_name = (our_name = strrchr(argv[0], '/')) ? our_name + 1: argv[0]; /* Parse the command line args */ for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-base64")) { base64_ok = 1; continue; } if (!strcmp(argv[i], "-yes")) { show_prompt = 0; retry = 10; continue; } if (!datafile) { datafile = argv[i]; continue; } if (!offset) { offset = strtol(argv[i], NULL, 0); continue; } } if(!datafile) { fprintf(stderr, "\n" "NetWinder Flash Memory update program," " Rebel.com 1998,1999.\n" "Usage: %s datafile [offset]\n" "offset is in bytes, or 0xNNN for hex\n" "optional flags:\n" " -base64 enables writing to first 64kB\n" " -yes does not prompt for confirmation\n" "\n", our_name ); return 1; } data_fd = open(datafile, O_RDONLY); if (data_fd <= 0) { perror("Error opening data file"); return 1; } data_size = lseek(data_fd,0,2); close(data_fd); if (!data_size) { perror("Zero length data file"); return 1; } if (show_prompt) { int ch; fprintf(stderr, "\n%s: ready to write into flash memory\n" " file : \"%s\"\n" " size : %d bytes\n" " offset : 0x%X.\n\n" "Enter Y to continue, or anything else to abort...\n", our_name,datafile,data_size,offset); ch = getchar(); if (!((ch == 'y') || (ch == 'Y'))) { fprintf(stderr, "Not this time... aborted.\n"); exit (0); } } fprintf(stderr, "\n" "Please wait...\n" "Yellow LED - erasing, Red LED - writing, Green LED - verifying" "...\n" ); /* Write to the data to the flash */ while (retry-- && (rc = flashwrite(datafile, offset, base64_ok))) { /* Repeat */ } return rc; }