读写SPI FLASH--应用程序部分

时间:2021-12-11 03:42:37

  驱动部分见前一篇文章: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");
       }
   }
}