Show update.c syntax highlighted
/*
update.c - userspace front-end to flash device.
Copyright (C) 2001-2001 Instant 802 Networks, All Rights Reserved.
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <time.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
#include <sys/types.h>
#include <sys/signal.h>
#include <string.h>
#include <linux/mtd/mtd.h>
#ifndef DEBUG
/* 0 - no messages, 1 - only error messages, 2 - all messages */
#define DEBUG 1
#endif
#if DEBUG < 2
#define printf(arg, ...) ;
#endif
#if DEBUG < 1
#define fprintf(arg, ...) ;
#define perror(arg) ;
#endif
// returns if the offset is on a block boundary or not
int boundary_check(region_info_t *regioninfo, unsigned int region_count,
unsigned int offset,
unsigned int *ret_region, unsigned int *ret_block) {
region_info_t *r = NULL;
unsigned int region_start = 0;
unsigned int region_end = 0;
unsigned int region_blocksize = 0;
int i = 0;
for (i=0; i<region_count; i++) {
r = ®ioninfo[i];
region_start = r->offset;
region_end = r->offset + (r->numblocks * r->erasesize);
region_blocksize = r->erasesize;
// we need a special case if the offset is at the very end of the flash
if ( (offset == region_end) && (i == region_count-1) ) {
if (ret_region)
*ret_region = i;
if (ret_block)
*ret_block = r->numblocks;
goto success;
}
// if offset is at the beginning or within this current region
else if( (offset >= region_start) && (offset < region_end) )
{
// and if offset lands on a block boundary
if ( ((region_end - offset) % region_blocksize) == 0) {
if (ret_region)
*ret_region = i;
if (ret_block)
*ret_block = (offset - region_start) / region_blocksize;
goto success;
}
}
}
//fail:
printf("boundary check for offset %d(0x%x) failed\n",
offset, offset);
return 0; // fail
success:
//printf("boundary check for offset %d(0x%x) returning region %d block %d\n",
// offset, offset, i, (offset - region_start) / region_blocksize);
return 1; // success
}
int region_erase(int fd, int start, int length)
{
region_info_t *regioninfo = NULL;
region_info_t *r = NULL;
int region_count = 0;
int i = 0;
// find the region count
if (ioctl(fd,MEMGETREGIONCOUNT, ®ion_count)) {
printf("there are no regions in this mtd device\n");
return 1;
}
printf("%d regions found in this mtd device\n", region_count);
// allocate and clear the regioninfo
regioninfo = malloc(sizeof(region_info_t)*region_count);
// memset(regioninfo, 0, sizeof(region_info_t)*region_count);
// get the info for each region
for (i=0; i<region_count; i++) {
r = ®ioninfo[i];
// read in the region info
r->regionindex = i;
if (ioctl(fd, MEMGETREGIONINFO, r) != 0) {
printf("failed printing out region summaries\n");
free(regioninfo);
return 1;
}
// print out the region info
printf("region %d is at %d(0x%x) of %d sectors "
"with sector size %d(0x%x)\n",
i, r->offset, r->offset,
r->numblocks,
r->erasesize, r->erasesize);
}
// safety checks
if (!boundary_check(regioninfo, region_count, start, NULL, NULL)) {
printf("start %d(0x%x)is not on a boundary\n",
start, start);
return 1;
}
if (!boundary_check(regioninfo, region_count, start+length, NULL, NULL)) {
printf("start+length %d(0x%x)is not on a boundary\n",
start+length, start+length);
return 1;
}
// do the erasing
{
// region_info_t * r = NULL;
erase_info_t erase;
u_int32_t region_num = 0;
u_int32_t block_num = 0;
u_int32_t offset = start; // increment as we go
while (offset < start+length)
{
// memset(&erase, 0, sizeof(erase_info_t));
if (!boundary_check(regioninfo, region_count, offset,
®ion_num, &block_num))
{
printf("could not find region in middle of erase\n");
printf("we are fucked!\n");
close(fd);
return 1;
}
printf("boundary check for offset %d(0x%x) returning region %d block %d\n",
offset, offset, region_num, block_num);
erase.start = offset;
erase.length = regioninfo[region_num].erasesize;
printf("erasing region %d block %d at offset %d(0x%x) length %d(0x%x)\n",
region_num, block_num,
erase.start, erase.start,
erase.length, erase.length);
if( ioctl(fd, MEMERASE, &erase) )
{
perror("region block erase failure\n");
close(fd);
return 1;
}
offset += erase.length;
}
}
return 0;
}
int copy(int to, int from, int start)
{
char buf[1024];
off_t of;
ssize_t s, w;
of = lseek(to, 0, SEEK_SET);
if (of != start) return 2;
for(;;) {
s = read(from, buf, sizeof(buf));
if (s == -1) return 3;
if (s == 0) break;
w = write(to, buf, s);
if (s != w) return 4;
}
return 0;
}
void usage() {
printf("update <device> <start> <length> { - | <filename> }\n"
"Erases the bytes specified in the mtd device, and optionally\n"
"writes new data from a file or stdin. Start and length must\n"
"be on sector boundries\n");
}
int main(int argc,char *argv[])
{
int fd = 0;
int fd2 = -1;
int start = 0;
int length = 0;
int res = 0;
if (argc < 4) {
usage();
return 1;
}
start = strtol(argv[2], NULL, 0);
length = strtol(argv[3], NULL, 0);
// open the device
if ((fd = open(argv[1],O_RDWR)) < 0) {
perror("device open error");
return 1;
}
// open the file
if (argc == 5) {
if (strcmp(argv[4],"-") == 0)
fd2 = 0;
else {
fd2 = open(argv[4],O_RDONLY);
if (fd2 < 0) {
perror("file open error");
return 1;
}
}
}
printf("MTD start erase\n");
res = region_erase(fd, start, length);
printf("MTD finish erase\n");
if (res) return res;
if (fd2 >= 0) {
int ret = 0;
printf("MTD start write\n");
ret = copy(fd, fd2, start);
printf("MTD finish write\n");
if (ret) return ret;
}
if (length == 1048576 ) {
printf("rebooting: killing init\n");
return(kill(1, SIGTERM));
}
return 0;
}
See more files for this project here