驱动部分见前一篇文章:http://blog.csdn.net/bripengandre/archive/2009/03/20/4009615.aspx
应用程序部分很简单:读取新的BIOS文件 ,以及flash中的当前内容,如果两者有差异,则将相关扇区先擦掉,然后再将新的BIOS内容写进去.即程序的擦写策略为:只有有差异时,才擦写,这能减小程序在擦写时,突然断电带来的坏作用.
不说什么了,直接看源码.
/****************************RefreshBIOS.h*****************************************/
#ifndef _REFRESH_BIOS_H_
#define _REFRESH_BIOS_H_
#define SPI_IOCTL_BASE 0xDE
#define IOCTL_ERASE_CHIP _IOWR(SPI_IOCTL_BASE, 0, ioctl_arg_t)
#define IOCTL_ERASE_BLOCK _IOWR(SPI_IOCTL_BASE, 1, ioctl_arg_t)
#define SPI_NAME "/dev/spi_name"
#define MAJOR_ID 252
#define MINOR_ID 0
#define CMD_SIZE 250
#define BUF_SIZE 500
#define SPI_FLASH_SIZE (2048*1024)
#define SPI_SECTOR_SIZE 0x1000
typedef struct _erase_block
{
int start;
int end;
}erase_block_t;
typedef struct _ioctl_arg
{
unsigned int type;
union
{
struct
{
unsigned int start;
unsigned int end;
}erase_range;
}data;
}ioctl_arg_t;
#endif /* _REFRESH_BIOS_H_ */
/**************************RefreshBIOS.c*****************************************/
#include "RefreshBIOS.h"
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ioctl.h>
static int write_range(int start, int end);
static int check_block(erase_block_t *block_old, erase_block_t *block_new);
static ssize_t readn(int fd, void *buf, size_t n);
static ssize_t writen(int fd, const void *buf, size_t n);
static void dbg_print(char *buf_s, char *buf_d, int cnt);
static int fd_s, fd_d;
static char buf_s[BUF_SIZE], buf_d[BUF_SIZE];
int main(int argc, char *argv[])
{
int total, cnt;
ioctl_arg_t arg;
erase_block_t block_old, block_new;
char cmd[CMD_SIZE];
if(argc != 2)
{
fprintf(stderr, "Usage: %s <file_name>/n", argv[0]);
return (1);
}
snprintf(cmd, sizeof(cmd), "rm -f %s ", SPI_NAME);
if(system(cmd) < 0)
{
fprintf(stderr, "%s error: %s/n", cmd, strerror(errno));
return (1);
}
snprintf(cmd, sizeof(cmd), "mknod %s c %d %d ", SPI_NAME, MAJOR_ID, MINOR_ID);
if(system(cmd) < 0)
{
fprintf(stderr, "%s error: %s/n", cmd, strerror(errno));
return (1);
}
if( (fd_d = open(SPI_NAME, O_RDWR)) < 0)
{
fprintf(stderr, "open %s error: %s/n", SPI_NAME, strerror(errno));
return (1);
}
if( (fd_s = open(argv[1], O_RDONLY)) < 0)
{
fprintf(stderr, "open %s error: %s/n", argv[0], strerror(errno));
return (1);
}
block_old.start = -1;
block_old.end = -1;
total = 0;
while(total < SPI_FLASH_SIZE)
{
cnt = (total + BUF_SIZE > SPI_FLASH_SIZE) ? SPI_FLASH_SIZE-total: BUF_SIZE;
if((readn(fd_d, buf_d, cnt)) < cnt)
{
fprintf(stderr, "%s::readn error: %s/n", argv[0], strerror(errno));
return (1);
}
if((readn(fd_s, buf_s, cnt)) < cnt)
{
fprintf(stderr, "%s::readn error: %s/n", argv[0], strerror(errno));
return (1);
}
if(memcmp(buf_s, buf_d, cnt) == 0)
{
total += cnt;
continue;
}
//dbg_print(buf_s, buf_d, cnt);
block_new.start = total;
block_new.end = total+cnt-1;
if(check_block(&block_old, &block_new))
{
arg.data.erase_range.start = block_new.start;
arg.data.erase_range.end = block_new.end;
ioctl(fd_d, IOCTL_ERASE_BLOCK, &arg);
//lseek(fd_s, block_new.start, SEEK_SET);
//lseek(fd_d, block_new.start, SEEK_SET);
if(write_range(block_new.start, block_new.end) < 0)
{
fprintf(stderr, "write_range error. /n");
return (1);
}
total = block_new.end+1;
}
else
{
total += cnt;
}
}
return (0);
}
static int write_range(int start, int end)
{
int cnt, total;
int len = end-start+1;
lseek(fd_s, start, SEEK_SET);
lseek(fd_d, start, SEEK_SET);
total = 0;
while(total < len)
{
cnt = (total + BUF_SIZE > len) ? len-total: BUF_SIZE;
if((readn(fd_s, buf_s, cnt)) < cnt)
{
fprintf(stderr, "write_range::readn error: %s/n", strerror(errno));
return (-1);
}
if((writen(fd_d, buf_s, cnt)) < cnt)
{
fprintf(stderr, "write_range::readn error: %s/n", strerror(errno));
return (-1);
}
total += cnt;
}
return (total);
}
static int check_block(erase_block_t *block_old, erase_block_t *block_new)
{
int start_old, end_old, start_new, end_new;
if(block_old->start == -1 && block_old->end == -1) /* at the beginning */
{
start_old = -1;
end_old = -1;
}
else
{
start_old = block_old->start/SPI_SECTOR_SIZE;
end_old = block_old->end/SPI_SECTOR_SIZE;
}
start_new = block_new->start/SPI_SECTOR_SIZE;
end_new = block_new->end/SPI_SECTOR_SIZE;
if(end_new <= end_old)
{
return 0;
}
if(start_new <= end_old)
{
start_new = end_old+1;
}
block_new->start = start_new*SPI_SECTOR_SIZE;
block_new->end = (end_new+1)*SPI_SECTOR_SIZE - 1;
block_old->start = block_new->start;
block_old->end = block_new->end;
return (1);
}
ssize_t readn(int fd, void *buf, size_t n)
{
size_t nleft;
size_t nread;
char *ptr;
ptr = buf;
nleft = n;
while(nleft > 0)
{
if( (nread = read(fd, ptr, nleft)) < 0)
{
if(errno == EINTR)
{
nread = 0; /* and call read() again */
}
else
{
return (-1);
}
}
else if(nread == 0)
{
break; /* end of file */
}
nleft -= nread;
ptr += nread;
}
return(n - nleft);
}
ssize_t writen(int fd, const void *buf, size_t n)
{
size_t nleft;
ssize_t nwritten;
const char *ptr;
ptr = buf;
nleft = n;
while(nleft > 0)
{
if( (nwritten = write(fd, ptr, nleft)) < 0)
{
if(errno == EINTR)
{
nwritten = 0;
}
else
{
return (-1);
}
}
/* else if(nwritten == 0)
{
break;
} */
nleft -= nwritten;
ptr += nwritten;
}
return (n);
}
static void dbg_print(char *buf_s, char *buf_d, int cnt)
{
int i;
if(buf_s == NULL || buf_d == NULL)
{
return;
}
printf("************buf_s***********/n");
for(i = 0; i < cnt; i++)
{
printf("%c ", buf_s[i]);
if((i+1) % 16 == 0)
{
printf("/n");
}
}
printf("************buf_d***********/n");
for(i = 0; i < cnt; i++)
{
printf("%c ", buf_d[i]);
if((i+1) % 16 == 0)
{
printf("/n");
}
}
}