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

时间:2024-04-15 08:05:26

#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;

}