Davinci开发板DM368 nandwrite.c简要分析

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <limits.h>
#include <string.h>
#include <unistd.h>
#include <image.h>
#include <asm/types.h>
#include <asm/byteorder.h>
#include <system_default.h>
#include <ctype.h>
#include <fcntl.h>
#include <time.h>
#include <sys/ioctl.h>
#include <sys/types.h>


#include <asm/types.h>
#include "mtd/mtd-user.h"


#define SUCCESS 0
#define FAIL -1
#define ENVALID_PRM -2
#define UNKOWN -3
#define FILE_NAME_SIZE 80
#define KERNELBLOCK "/dev/mtd2"
#define FILESYSBLOCK "/dev/mtd3"
#define TEMP_PATH "/tmp"
#define TEMP_FILE "tmpfile.txt"
#define FILESYS_PRE "cramfs"


#ifdef U_DEBUG
#define DBG(fmt, args...) write(STDOUT_FILENO, out_buf, sprintf(out_buf, fmt, ##args) + 1)
#else
#define DBG(fmt, args...)
#endif


#define OUTPUT(fmt, args...) write(STDOUT_FILENO, out_buf, sprintf(out_buf, fmt, ##args) + 1)


typedef struct _FileInfo{
long nStartOffset;
long nEndOffset;
int fd;
long nLength;
char strFileName[FILE_NAME_SIZE + 1];
}FileInfo;
struct mtd_info_user {
uint8_t type;
uint32_t flags;
uint32_t size; // Total size of the MTD
uint32_t erasesize;
uint32_t oobblock;  // Size of OOB blocks (e.g. 512)          oob块大小
uint32_t oobsize;   // Amount of OOB data per block (e.g. 16) 每块的oob数据数量大小
uint32_t ecctype;
uint32_t eccsize;
};


const char update_html_head[] =                                              //更新html的头部,相当于一个一个html网页
"HTTP/1.1 200 OK\r\nContent-type: text/html\r\nPragma: no-cache\r\n"   //网址
"Cache-Control: no-store\r\n\r\n"                                        
"<HTML><HEAD><TITLE>Firmware Update</TITLE></HEAD>\n"     //html head ,body
"<style>\n BODY { PADDING-RIGHT: 0px; MARGIN-TOP: 10px; PADDING-LEFT: 10px; MARGIN-LEFT: auto; WIDTH: auto; MARGIN-RIGHT: auto; background-color:#182439; FONT-FAMILY: Tahoma, Geneva, Arial, \"Arial Narrow\", Verdana, sans-serif; font-size:14px; color:#FFFFFF;overflow-x: hidden;overflow-y: hidden} </style>";


const char update_html_end[] = "";


static int gLastI = -1, gLastRead = 0;
static char out_buf[80];


/******************************************************************************
Start of nandwrite global
******************************************************************************/
#define MAX_OOB_SIZE 64
#define MAX_PAGE_SIZE 2048


unsigned char oobbuf[MAX_OOB_SIZE];  
unsigned char oobreadbuf[MAX_OOB_SIZE];
unsigned char writebuf[MAX_PAGE_SIZE];
int blockalign = 1; /*默认使用16k的块大小 default to using 16K block size */
int forcejffs2 = 1;
int forceyaffs = 0;
int autoplace = 0;
int forcelegacy = 1;
int noecc = 0;
int writeoob = 0;
int pad = 1;


struct nand_oobinfo jffs2_oobinfo = {       
.useecc = MTD_NANDECC_PLACE,
.eccbytes = 6,
.eccpos = { 0, 1, 2, 3, 6, 7 }
};


struct nand_oobinfo yaffs_oobinfo = {
.useecc = MTD_NANDECC_PLACE,
.eccbytes = 6,
.eccpos = { 8, 9, 10, 13, 14, 15}
};
/******************************************************************************
End of nandwrite global
******************************************************************************/


extern unsigned long crc32 (unsigned long, const unsigned char *, unsigned int);
/**
*@brief Reverse a string
*@param[in,out] pStr String to reverse.
*/
void Reverse(char *pStr)
{
int i,j;
char temp;
for(i = 0,j = strlen(pStr) - 1;i < j; i++, j--){
temp = pStr[i];
pStr[i] = pStr[j];
pStr[j] = temp;
}
}
/**
*@brief Take the file name from string      复制pbuf字符串到pFileName
*@param[in] pbuf String include file name in it.
*@param[in] nBufSize String size.
*@param[out] pFileName File name get from string.
*/
void TakeFileName(char *pbuf, int nBufSize, char *pFileName)        
{
int i,count = 0;
for(i = 0;i < nBufSize;i++){        //总共nBuffer字节
if(pbuf[i] != '"')                 //遇到“”就跳过,直到末尾
continue;
gLastI = i;
while(--i >= 0 )        
{
if(pbuf[i] == '/' || pbuf[i] == '\\')       
break;
pFileName[count++] = pbuf[i];      
}
break;
}
pFileName[count] = '\0';
Reverse(pFileName);
return ;
}
/**
*@brief Get file name from stdin 从标准输入获取文件名字?*@param[in] fd File fd.
*@param[in] pBuf Buffer to store temp date.
*@param[in] nBufSize Buffer size.
*@return File name.
*/
char* GetFileName(int fd, char *pBuf, int nBufSize)
{
static char strFileName[FILE_NAME_SIZE + 1];           //文件名strFileName[81]
const char target[]="filename=\";                      //目标字符串,需要删除的字符串,过滤
int nReadBytes = 0, count = 0, i,tempI = gLastI; 
while((nReadBytes = read(fd, pBuf, nBufSize)) > 0)     //读取输入,存到pBuf中,每次读取nBuffer字节,每次512字节
{   
for(i = 0;i < nBufSize;i++)                          //对读到的buffer进行操作,512字节
{
if(count == strlen(target))          
{
gLastI = i;      
TakeFileName(&pBuf[i], nReadBytes - i, strFileName); //当前i下下标开始为真正的文件名?  //长为nReadBytes - i字节,从pBuf值
if(strFileName[0] == '\0')
{
count = 0;
gLastI = tempI;
}else{
gLastRead = nReadBytes;
return strFileName;
}
}
else if(pBuf[i] == target[count])                  //过滤掉"filename=\"字符串
count++;
else              
count = 0;
}
}
return NULL;
}
/**
*@brief Skip package header    跳过包头
*@param[in] fd File fd.
*@param[in] pBuf Buffer to store temp date.
*@param[in] nBufSize Buffer size.
*@return Value of buffer index
*/
int SkipHeader(int fd, char *pBuf, int nBufSize)         //跳过包头
{
int i,count = 0;
const char target[]="\r\n\r\n";   
 
if(gLastRead > 0)                 //最后一次读 >0
{
i = (gLastI > 0) ? gLastI : 0; 
do 
{
for(; i < gLastRead;i++){                           //对读到的nBufsize数据进行操作
if(count == strlen(target))     
{
return i;
} else if(pBuf[i] == target[count])
count++;
else
count = 0;
}
i = 0;
}while((gLastRead = read(fd, pBuf, nBufSize)) > 0);   //从标准输入中、读取nBufsize数据,其实也就是跳到target的末尾

else      //最后一次读 == 0 
{
while((gLastRead = read(fd, pBuf, nBufSize)) > 0)       //从标准输入中、读取nBufsize数据,其实也就是跳到target的末尾
{
for(i = 0; i < gLastRead;i++){
if(count == strlen(target)){
return i;
} else if(pBuf[i] == target[count])
count++;
else
count = 0;
}
}
}
return -1;
}
/**
*@brief Create a file                
*@param[in] pFileName File name.          文件名
*@param[in] fd File fd.                    文件句柄
*@param[in] pBuf Buffer to store temp date.      缓冲区 存放临时数据
*@param[in] nBufSize Buffer size.       总的大小
*@param[out] pFile File information to new file.   新文件的文件信息
*@retval ENVALID_PRM gLastRead is not set correctly.
*@retval FAIL File create fail.
*@retval SUCCESS File create success.
*/
int CreateFile(char *pFileName, int fd, char *pBuf, int nBufSize, FileInfo* pFile)   //创建文件,读取输入,填充pFile
{
char path[100];
const char target[]="\r\n-----------------------------";
int i,count = 0;
FILE *db;
db = fopen("/tmp/createfile.txt", "wt");    //打开文件db
sprintf(path, "%s/%s", TEMP_PATH, pFileName);    //根据文件名字构建临时文件名字
fprintf(db,"path=<%s>\n", path);        //临时目录
fprintf(db,"gLastRead=%d\n", gLastRead);   //最后一次读
fclose(db);                     //文件文件
if(gLastRead <= 0)
return ENVALID_PRM;



i = (gLastI > 0) ? gLastI : 0;      //最后一次读
DBG("i = %d\n", i);
strcpy(pFile->strFileName, pFileName);    //填充fileinfo
pFile->fd = fd;
pFile->nStartOffset = lseek(fd, 0, SEEK_CUR) - gLastRead + i;    //文件当前位置 - 最后一次读的大小 - gLastI
do
{
DBG("gLastRead : %d\n", gLastRead);
for(; i < gLastRead;i++)                                 //循环处理读到的数据,去掉前面的 "\r\n-----------------------------"字符
{
if(count == strlen(target)){
gLastI = i;                                                //到第i下标
pFile->nEndOffset = lseek(fd, 0, SEEK_CUR) - gLastRead + i - count;
pFile->nLength = pFile->nEndOffset - pFile->nStartOffset;        //实际读到的大小
DBG("File length = %ld\n", pFile->nLength);
return SUCCESS;
} else if(pBuf[i] == target[count]){
count++;
} else if(count > 0){
count = 0;
i--;
} else {
// putc(pBuf[i], fp);
}
}
i = 0;
}while((gLastRead = read(fd, pBuf, nBufSize)) > 0);    //继续从标准输入中读取数据
gLastI = -1;
return FAIL;
}
/**
*@brief Print image type
*@param[in] hdr uImage header.
*/
static void print_type (image_header_t *hdr)
{
char *os, *arch, *type, *comp;       


switch (hdr->ih_os) {
case IH_OS_INVALID: os = "Invalid OS"; break;
case IH_OS_NETBSD: os = "NetBSD"; break;
case IH_OS_LINUX: os = "Linux"; break;
case IH_OS_VXWORKS: os = "VxWorks"; break;
case IH_OS_QNX: os = "QNX"; break;
case IH_OS_U_BOOT: os = "U-Boot"; break;
case IH_OS_RTEMS: os = "RTEMS"; break;
default: os = "Unknown OS"; break;
}


switch (hdr->ih_arch) {
case IH_CPU_INVALID: arch = "Invalid CPU"; break;
case IH_CPU_ALPHA: arch = "Alpha"; break;
case IH_CPU_ARM: arch = "ARM"; break;
case IH_CPU_AVR32: arch = "AVR32"; break;
case IH_CPU_I386: arch = "Intel x86"; break;
case IH_CPU_IA64: arch = "IA64"; break;
case IH_CPU_MIPS: arch = "MIPS"; break;
case IH_CPU_MIPS64: arch = "MIPS 64 Bit"; break;
case IH_CPU_PPC: arch = "PowerPC"; break;
case IH_CPU_S390: arch = "IBM S390"; break;
case IH_CPU_SH: arch = "SuperH"; break;
case IH_CPU_SPARC: arch = "SPARC"; break;
case IH_CPU_SPARC64: arch = "SPARC 64 Bit"; break;
case IH_CPU_M68K: arch = "M68K"; break;
case IH_CPU_MICROBLAZE: arch = "Microblaze"; break;
case IH_CPU_NIOS: arch = "Nios"; break;
case IH_CPU_NIOS2: arch = "Nios-II"; break;
default: arch = "Unknown Architecture"; break;
}


switch (hdr->ih_type) {
case IH_TYPE_INVALID: type = "Invalid Image"; break;
case IH_TYPE_STANDALONE:type = "Standalone Program"; break;
case IH_TYPE_KERNEL: type = "Kernel Image"; break;
case IH_TYPE_RAMDISK: type = "RAMDisk Image"; break;
case IH_TYPE_MULTI: type = "Multi-File Image"; break;
case IH_TYPE_FIRMWARE: type = "Firmware"; break;
case IH_TYPE_SCRIPT: type = "Script"; break;
case IH_TYPE_FLATDT: type = "Flat Device Tree"; break;
default: type = "Unknown Image"; break;
}


switch (hdr->ih_comp) {
case IH_COMP_NONE: comp = "uncompressed"; break;
case IH_COMP_GZIP: comp = "gzip compressed"; break;
case IH_COMP_BZIP2: comp = "bzip2 compressed"; break;
default: comp = "unknown compression"; break;
}


OUTPUT("%s %s %s (%s)", arch, os, type, comp);
}
/**
 *@brief Print size


 * print sizes as "xxx kB", "xxx.y kB", "xxx MB" or "xxx.y MB" as needed;
 * allow for optional trailing string (like "\n")
 *@param[in] size Size to print.
 *@param[in] s Tailing string.
 */
void print_size (unsigned long size, const char *s)
{
unsigned long m, n;
unsigned long d = 1 << 20; /* 1 MB */
char  c = 'M';


if (size < d) { /* print in kB */
c = 'k';
d = 1 << 10;
}


n = size / d;


m = (10 * (size - (n * d)) + (d / 2) ) / d;


if (m >= 10) {
m -= 10;
n += 1;
}


OUTPUT ("%2ld", n);
if (m) {
OUTPUT (".%ld", m);
}
OUTPUT (" %cB%s", c, s);
}
/**
*@brief Print image header
*@param[in] hdr uImage header.
*/
void print_image_hdr (image_header_t *hdr)
{
OUTPUT("<H6>   Image Name:   %.*s\n", IH_NMLEN, hdr->ih_name);
OUTPUT("<H6>   Image Type:   ");print_type(hdr);
OUTPUT ("<H6>\n   Data Size:    %d Bytes = ", ntohl(hdr->ih_size));
print_size (ntohl(hdr->ih_size), "\n");
OUTPUT ("<H6>   Load Address: %08x\n"
"<H6>   Entry Point:  %08x\n",
ntohl(hdr->ih_load), ntohl(hdr->ih_ep));


if (hdr->ih_type == IH_TYPE_MULTI) {
int i;
unsigned long len;
unsigned long *len_ptr;
len_ptr = (unsigned long *)
((unsigned long)hdr + sizeof(image_header_t));


OUTPUT("<H6>   Contents:\n");
for (i=0; (len = ntohl(*len_ptr)); ++i, ++len_ptr) {
OUTPUT ("<H6>   Image %d: %8ld Bytes = ", i, len);
print_size (len, "\n");
}
}
}
/**
*@brief Write file to nand
*@param[in] pFile File to write.
*@param[in] pBlockName Block device name.
*@param[in] offset Offset to block start.
*@retval SUCCESS Nand write complete.
*@retval FAIL Error occures.
*/
//FlashNand(pFile, FILESYSBLOCK, 0);
int FlashNand(FileInfo* pFile, char *pBlockName, unsigned long offset)     //写文件内容到nand flash
{
char cmd[100];                                                           //命令
int cnt, fd, imglen = 0, pagelen, baderaseblock, blockstart = -1;   
struct mtd_info_user meminfo;                                            //mtd的分区信息
struct mtd_oob_buf oob;                                                  //mtd的带外数据
loff_t offs;                                                             //偏移值
int ret, readlen;               
int oobinfochanged = 0;                                                  //带外数据信息改变标志
struct nand_oobinfo old_oobinfo;                                         //nand的带外数据信息
ret = SUCCESS;
sprintf(cmd, "/usr/sbin/flash_eraseall -j %s > %s/%s\n", pBlockName,     // 构建执行擦除命令 : /usr/sbin/flash_eraseall -j "/dev/mtd2" /tmp "tmpfile.txt"
TEMP_PATH, TEMP_FILE);
if(system(cmd)){                  //执行命令
OUTPUT("<H6>Fail on erase block\r\n");
ret = FAIL;
goto EXIT_FLASHNAND;
}
#if 0                               //不会编译到这里
sprintf(cmd, "/usr/sbin/nandwrite -s %ld -f -p -j %s %s/%s > %s/%s\n", offset, pBlockName,
TEMP_PATH, pFile->strFileName, TEMP_PATH, TEMP_FILE);  //构建写命令 : nandwrite 块设备写入命令  偏移   块名 临时路径 临时文件
DBG(cmd);
if(system(cmd)){     //执行nandwrite 写命令
OUTPUT("<H6>Fail on update new firmware\r\n");
sprintf(cmd, "rm -f %s/%s\n", TEMP_PATH, TEMP_FILE);
system(cmd);
return FAIL;
}
#else
/* mtdoffset = offset, forcelegacy = 1, pad = 1, forcejffs2 = 1,
mtd_device = pBlockName, img = pFile */
                                                          //mtd的偏移,pad, jffs2, 设备名,映像
memset(oobbuf, 0xff, sizeof(oobbuf));                      //清空带外数据 //unsigned char oobbuf[64];

if ((fd = open(pBlockName, O_RDWR)) == -1) {               //打开/dev/mtd2块设备
OUTPUT("<H6>open flash error\r\n");
ret = FAIL;
goto EXIT_FLASHNAND;
}
/* Fill in MTD device capability structure */              //获得mtd块设备的内容,
if (ioctl(fd, MEMGETINFO, &meminfo) != 0) {                //struct mtd_info_user meminfo; /dev/mtd2的分区信息
OUTPUT("<H6>MEMGETINFO error\r\n");
close(fd);
ret = FAIL;
goto EXIT_FLASHNAND;
}
                                                            //设置指定mtd设备块数目的擦除大小,匹配jifs2虚拟系统的块大小
  meminfo.erasesize *= blockalign;                          //默认使用16k的块大小
/* Make sure device page sizes are valid */               //确保设备页大小是有效的,
if (!(meminfo.oobsize == 16 && meminfo.oobblock == 512)   //mtd_info_user分区中的oob数据大小和块
   && !(meminfo.oobsize == 8 && meminfo.oobblock == 256) && //oob块大小和每块oob的数据数量大小
   !(meminfo.oobsize == 64 && meminfo.oobblock == 2048)) {
OUTPUT("<H6>Unknown flash (not normal NAND)\r\n");
close(fd);
ret = FAIL;
goto EXIT_FLASHNAND;
}
                                                          //获取/dev/mtd2设备当前oob带外数据
if (ioctl (fd, MEMGETOOBSEL, &old_oobinfo) != 0) {
OUTPUT("<H6>MEMGETOOBSEL error\r\n");
close (fd);
ret = FAIL;
goto EXIT_FLASHNAND;
}

                                                 //强制带外数据安排给jifs2或者yaffs,
                                                 //force oob layout for jffs2 or yaffs ? 
if (forcejffs2 || forceyaffs)                     
{                                                 //根据jifs2或者yaffs选择不同的oob数据,ecc校验不同
struct nand_oobinfo *oobsel = forcejffs2 ? &jffs2_oobinfo : &yaffs_oobinfo;   


if (autoplace) {                                // 对于预留的-j/y选项,不允许自动布局,autoplace为0
OUTPUT("<H6>Autoplacement is not possible for legacy -j/-y options\n");    
ret = FAIL;
goto restoreoob;
}                                                //当前不强制预留,而且为MTD设备的nand ecc自动布局,失败
if ((old_oobinfo.useecc == MTD_NANDECC_AUTOPLACE) && !forcelegacy) {    
OUTPUT("<H6>Use -f option to enforce legacy placement on autoplacement enabled mtd device\n");
ret = FAIL;
goto restoreoob;
}
if (meminfo.oobsize == 8) {                     //如果/dev/mtd2的每块oob的数据大小为8字节,不允许使用yaffs 
     if (forceyaffs)    
{
OUTPUT("<H6>YAFSS cannot operate on 256 Byte page size");
ret = FAIL;
goto restoreoob;
}
                                             //则将ecc的字节改为3字节,适应
jffs2_oobinfo.eccbytes = 3;
}


if (ioctl (fd, MEMSETOOBSEL, oobsel) != 0) {    //向mtd设备设置带外数据
OUTPUT("<H6>MEMSETOOBSEL error\r\n");
ret = FAIL;
goto restoreoob;
}
}
oob.length = meminfo.oobsize;                     //dev/mtd2的每块oob的数据大小,设置mtd_oob_buf和内存
oob.ptr = noecc ? oobreadbuf : oobbuf;


                                                 //设置文件开始读,设置映像文件偏移为开始位置
lseek(pFile->fd, pFile->nStartOffset, SEEK_SET);
                                                 //获得映像文件的长度
  imglen = pFile->nLength;
                                                    //一页的大小=/dev/mtd2中oob块大小 + 0
pagelen = meminfo.oobblock + ((writeoob == 1) ? meminfo.oobsize : 0);     


if ((!pad) && ((imglen % pagelen) != 0)) {        //检查是否页对齐,映像文件的长度/一页的大小
OUTPUT("<H6>Input file is not page aligned\n");
ret = FAIL;
goto restoreoob;
}


                                                    //页数 = 映像文件长度 / 1页的大小
                                                 //检查长度和设备适应    Check, if length fits into device 
                                               //页数*mtd2中oob块大小   > (/dev/mtd的总大小 - 偏移0)
                                               //表示不够内存能够装下映像文件
if ( ((imglen / pagelen) * meminfo.oobblock) > (meminfo.size - offset)) {
OUTPUT("<H6>Image %d bytes, NAND page %d bytes, OOB area %u bytes, device size %u bytes\n",
imglen, pagelen, meminfo.oobblock, meminfo.size);
OUTPUT("<H6>Input file does not fit into device error\r\n");
ret = FAIL;
goto restoreoob;
}
                                                  //从输入输出到nand设备中获取数据 Get data from input and write to the device 
while (imglen && (offset < meminfo.size)) {


                                                //新的eraseblock,检查坏块,一直循环去确保如果mtd偏移因为
                                                //一个坏块改变,然后下一个块将被写入也会被检查.防止了跳过块后出现错误
while (blockstart != (offset & (~meminfo.erasesize + 1))) {
blockstart = offset & (~meminfo.erasesize + 1);
offs = blockstart;                             //快起始,快偏移
 baderaseblock = 0;                             //擦除坏块数
DBG("Writing data to block %x\n", blockstart); //写数据到起始块


                                                //对于坏块,检查一个擦除块中的所有块 /* Check all the blocks in an erase block for bad blocks */
do {
  if ((ret = ioctl(fd, MEMGETBADBLOCK, &offs)) < 0) {
OUTPUT("<H6>ioctl(MEMGETBADBLOCK) error\r\n");
ret = FAIL;
goto restoreoob;
}
if (ret == 1) {                              //发现坏块,打印坏块数,地址,进行擦除坏块操作
baderaseblock = 1;
DBG("Bad block at %x, %u block(s) from %x will be skipped\n", (int) offs, blockalign, blockstart);
}


if (baderaseblock) {                         
offset = blockstart + meminfo.erasesize;   
}
    offs +=  meminfo.erasesize / blockalign ;  //擦除位置后移
} while ( offs < blockstart + meminfo.erasesize );


}


readlen = meminfo.oobblock;                       //mtd的块大小
if (pad && (imglen < readlen))                    //如果映像文件的大小小于/dev/mtd2的块大小,
                                                 //将多余的内存置为0xff             
{
readlen = imglen;
memset(writebuf + readlen, 0xff, meminfo.oobblock - readlen);
}


                                                 //从映像文件中读页数据 Read Page Data from input file 
if ((cnt = read(pFile->fd, writebuf, readlen)) != readlen) {
if (cnt == 0) // EOF
break;
OUTPUT("<H6>File I/O error on input file\r\n");
ret =FAIL;
goto restoreoob;
}


if (writeoob) {
                                               //从映像文件中读带外数据 Read OOB data from input file, exit on failure 
                                               //读一块oob数据的大小的内容
if ((cnt = read(pFile->fd, oobreadbuf, meminfo.oobsize)) != meminfo.oobsize) {
OUTPUT("<H6>File I/O error on input file");
ret = FAIL;
goto restoreoob;
}
if (!noecc) {    
int i, start, len;
/*
*  We use autoplacement and have the oobinfo with the autoplacement
* information from the kernel available
*
* Modified to support out of order oobfree segments,
* such as the layout used by diskonchip.c
*/
if (!oobinfochanged && (old_oobinfo.useecc == MTD_NANDECC_AUTOPLACE)) {
for (i = 0;old_oobinfo.oobfree[i][1]; i++) {
/* Set the reserved bytes to 0xff */
start = old_oobinfo.oobfree[i][0];
len = old_oobinfo.oobfree[i][1];
memcpy(oobbuf + start,
oobreadbuf + start,
len);
}
} else {
/* Set at least the ecc byte positions to 0xff */
start = old_oobinfo.eccbytes;
len = meminfo.oobsize - start;
memcpy(oobbuf + start,
oobreadbuf + start,
len);
}
}
                                               //写入oob数据首先,eec也将被写入这里
oob.start = offset;
if (ioctl(fd, MEMWRITEOOB, &oob) != 0) {
OUTPUT("<H6>ioctl(MEMWRITEOOB) error\r\n");
ret = FAIL;
goto restoreoob;
}
imglen -= meminfo.oobsize;                      //映像文件长度减去mtd减去1块oob的数据长度
}


                                                 //将页数据全部写入/dev/mtd
if (pwrite(fd, writebuf, meminfo.oobblock, offset) != meminfo.oobblock) {
OUTPUT("<H6>pwrite error\r\n");
ret = FAIL;
goto restoreoob;
}
imglen -= readlen;
offset += meminfo.oobblock;
}
restoreoob:
if (oobinfochanged) {
if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) {
OUTPUT ("<H6>MEMSETOOBSEL error\r\n");
close (fd);
ret = FAIL;
goto EXIT_FLASHNAND;
}
}


close(fd);


if (imglen > 0) {
OUTPUT ("<H6>Data did not fit into device, due to bad blocks\n");
ret = FAIL;
}
#endif
EXIT_FLASHNAND:
return ret;
}
/**
*@brief Write kernel to flash
*@param[in] pFileName Kernel file name.
*@retval SUCCESS Kernel write success.
*@retval FAIL Error occures.
*/
int FlashKernel(char *pFileName)
{
char cmd[80], path[100];
// FILE* fp;
sprintf(path, "%s/update.sh", TEMP_PATH);
#if 0
fp = fopen(path, "wt");
if(fp){
fprintf(fp, "/usr/sbin/flash_eraseall -j %s\n", KERNELBLOCK);
fprintf(fp ,"/usr/sbin/nandwrite -p -j %s %s/%s\n", KERNELBLOCK, TEMP_PATH,
pFileName);
fclose(fp);
} else
return FAIL;
sprintf(cmd, "chmod 700 %s/update.sh", TEMP_PATH);
if(system(cmd)){
OUTPUT("<H6>Can't change mode\r\n");
return FAIL;
}
sprintf(cmd, "%s/update.sh\n", TEMP_PATH);
return system(cmd);
#else
sprintf(cmd, "/usr/sbin/flash_eraseall -j %s > %s/%s\n", KERNELBLOCK,
TEMP_PATH, TEMP_FILE);
if(system(cmd)){
OUTPUT("<H6>Fail on erase kernel block\r\n");
sprintf(cmd, "rm -f %s/%s\n", TEMP_PATH, TEMP_FILE);
system(cmd);
return FAIL;
}
sprintf(cmd, "/usr/sbin/nandwrite -p -j %s %s/%s > %s/%s\n", KERNELBLOCK,
TEMP_PATH, pFileName, TEMP_PATH, TEMP_FILE);
if(system(cmd)){
OUTPUT("<H6>Fail on update kernel\r\n");
sprintf(cmd, "rm -f %s/%s\n", TEMP_PATH, TEMP_FILE);
system(cmd);
return FAIL;
}
sprintf(cmd, "rm -f %s/%s\n", TEMP_PATH, TEMP_FILE);
system(cmd);
return SUCCESS;
#endif
}
/**
*@brief Do kernel update
*@param[in] pFile Kernel file information.
*@retval SUCCESS Update success.
*@retval FAIL Fail to update.
*@retval UNKOWN Unkown file format.
*/
int DoKernelUpdate(FileInfo* pFile)                     //内核更新文件
{
image_header_t hdr;
unsigned long checksum,len, data;                     //校验和,长度,数据
long nFileSize;                                       //文件大小
void *pImage = NULL;                                  //映像
int ret = SUCCESS;
lseek(pFile->fd, pFile->nStartOffset, SEEK_SET);      //设置当前文件的开始位置
if(read(pFile->fd, &hdr, sizeof(hdr)) != sizeof(hdr)){    //读取映像文件的hdr
ret = UNKOWN;
goto EXIT_UPDATE_K;
}
if(ntohl(hdr.ih_magic) != IH_MAGIC){        //将一个无符号长整形数从网络字节顺序转换为主机字节顺序,确保正确
ret = UNKOWN;
goto EXIT_UPDATE_K;
}
DBG("Valid magic number\r\n");
data = (unsigned long)&hdr;                //取得4字节数据
len = sizeof(hdr);     //hdr的大小
checksum = ntohl(hdr.ih_hcrc);             //校验crc
hdr.ih_hcrc = 0;
if (crc32 (0, (unsigned char *)data, len) != checksum) {      
DBG ("Bad Header Checksum\n");
ret = UNKOWN;
goto EXIT_UPDATE_K;
}
print_image_hdr(&hdr);                     //打印映像内核信息
len  = ntohl(hdr.ih_size);                 //分配  映像指针
pImage = malloc(len);    
if(pImage == NULL){
OUTPUT("<H6>No enough memory to cache uImage\r\n");
ret = FAIL;
goto EXIT_UPDATE_K;
}
data = (unsigned long)pImage;                  //取得映像4字节数据
if(read(pFile->fd, pImage, len) != len){       //从文件中读取信息放入data
DBG("<H6>File size error\r\n");
ret = UNKOWN;
goto EXIT_UPDATE_K;
}
DBG("   Verifying Checksum ... \r\n");
if (crc32 (0, (unsigned char *)data, len) != ntohl(hdr.ih_dcrc)) {    //crc校验
DBG("Bad Data CRC\n");
ret = UNKOWN;
goto EXIT_UPDATE_K;
}
DBG("OK\n");
if((nFileSize = pFile->nLength) < 0){
OUTPUT("<H6>Error on get file size\r\n");
ret = FAIL;
goto EXIT_UPDATE_K;
}
data = nFileSize;                           //文件大小
if(data != (len + sizeof(hdr))){
OUTPUT("<H6>Unkown data found at tail\r\n");
ret = FAIL;
goto EXIT_UPDATE_K;
}
if(FlashNand(pFile, KERNELBLOCK, 0) != SUCCESS){
ret = FAIL;
goto EXIT_UPDATE_K;
}
EXIT_UPDATE_K:
if(pImage)
free(pImage);
return ret;
}
/**
*@brief Root file system update
*@param[in] pFile File information.
*@retval SUCCESS Update success.
*@retval FAIL Update fail.
*@retval UNKOWN Unkown file format.
*/
int DoRootFileSysUpdate(FileInfo* pFile)
{
// char cmd[80];
/* We only check filename */
DBG("Enter %s\r\n", __func__);
if(strncmp(FILESYS_PRE, pFile->strFileName, strlen(FILESYS_PRE))){
DBG("Not root file\r\n");
return UNKOWN;
}
DBG("File name ok\r\n");
#if 0
/* CRC check */
sprintf(cmd, "gzip -t %s/%s\n", TEMP_PATH, pFileName);
if(system(cmd)){
DBG("Can't check\r\n");
return FAIL;
}
#endif
return FlashNand(pFile, FILESYSBLOCK, 0);
}
/**
*@brief Firmware update
*@param[in] pFile File information.
*@retval SUCCESS Firmware update successfully.
*@retval FAIL Firmware update failed.
*@retval UNKOWN Unkown file format.
*/
int DoFirmwareUpdate(FileInfo* pFile)
{
int ret;
char cmd[80];
ret = DoKernelUpdate(pFile);          //内核更新 文件
if(ret == SUCCESS){
OUTPUT("<H4>\nKernel update success,\r\n");
} else if(ret == UNKOWN){
if((ret = DoRootFileSysUpdate(pFile)) == SUCCESS){
OUTPUT("<H4>File system update success,\r\n");
sprintf(cmd, "rm -f %s\n", SYS_FILE);
system(cmd);
sprintf(cmd, "rm -f %s\n", LOG_FILE);
system(cmd);
}
}
return ret;
}
/**
*
*/
int main(int argc, char **argv)
{
char buffer[512],*pFileName;
struct stat st;      //文件状态
FileInfo tFile;
#ifdef U_DEBUG
FILE *fp;
#endif


fstat(STDIN_FILENO, &st);    //由文件描述词取得文件状态,STDIN_FILENO就是标准输入设备(一般是键盘)
write(STDOUT_FILENO, update_html_head, sizeof(update_html_head));     //将网页写到终端,显示
if((pFileName = GetFileName(STDIN_FILENO, buffer, sizeof(buffer))) != NULL)   //从标准输入中获取文件名字
{
#ifdef U_DEBUG
fp = fopen("/tmp/main.dbg", "wt");      //以写的方式打开文件 /tmp/main.dbg
fprintf(fp, "pFileName=<%s>\n",pFileName);  //向文件中写入文件名
#endif
gLastI = SkipHeader(STDIN_FILENO, buffer, sizeof(buffer));   //跳过包头
#ifdef U_DEBUG
fprintf(fp, "gLastI=%d\n",gLastI);
#endif
if(CreateFile(pFileName, STDIN_FILENO, buffer, sizeof(buffer), &tFile)==SUCCESS){   //创建文件tFile
OUTPUT("<H4>File create success\r\n");
OUTPUT("<H4>\r\n");
switch(DoFirmwareUpdate(&tFile)){     //更新文件tFile

case SUCCESS:
OUTPUT("Firmware update success\r\n");
OUTPUT("<H4> Please Restart IPNC by Clicking on \"Restart Camera\" Button\r\n");
break;
case UNKOWN:
OUTPUT("<H4>Unknown file format\r\n");
break;
default:
OUTPUT("<H4>Unknown error\r\n");
break;
}


}else
OUTPUT("<H4>Fail to create file\r\n");
#ifdef U_DEBUG
fclose(fp);
#endif
} else {
OUTPUT("<H3>Unknown file.</H3>\r\n");
}
write(STDOUT_FILENO, update_html_end, sizeof(update_html_end));


return SUCCESS;
}

posted on 2013-09-06 21:43  新一  阅读(738)  评论(0编辑  收藏  举报

导航