zoukankan      html  css  js  c++  java
  • 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 Content-type: text/html Pragma: no-cache "   //网址
    "Cache-Control: no-store "                                        
    "<HTML><HEAD><TITLE>Firmware Update</TITLE></HEAD> "     //html head ,body
    "<style> 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] = '';
    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] == '')
    {
    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[]=" ";   
     
    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[]=" -----------------------------";
    int i,count = 0;
    FILE *db;
    db = fopen("/tmp/createfile.txt", "wt");    //打开文件db
    sprintf(path, "%s/%s", TEMP_PATH, pFileName);    //根据文件名字构建临时文件名字
    fprintf(db,"path=<%s> ", path);        //临时目录
    fprintf(db,"gLastRead=%d ", gLastRead);   //最后一次读
    fclose(db);                     //文件文件
    if(gLastRead <= 0)
    return ENVALID_PRM;



    i = (gLastI > 0) ? gLastI : 0;      //最后一次读
    DBG("i = %d ", i);
    strcpy(pFile->strFileName, pFileName);    //填充fileinfo
    pFile->fd = fd;
    pFile->nStartOffset = lseek(fd, 0, SEEK_CUR) - gLastRead + i;    //文件当前位置 - 最后一次读的大小 - gLastI
    do
    {
    DBG("gLastRead : %d ", gLastRead);
    for(; i < gLastRead;i++)                                 //循环处理读到的数据,去掉前面的 " -----------------------------"字符
    {
    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 ", 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 " ")
     *@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 ", IH_NMLEN, hdr->ih_name);
    OUTPUT("<H6>   Image Type:   ");print_type(hdr);
    OUTPUT ("<H6>   Data Size:    %d Bytes = ", ntohl(hdr->ih_size));
    print_size (ntohl(hdr->ih_size), " ");
    OUTPUT ("<H6>   Load Address: %08x "
    "<H6>   Entry Point:  %08x ",
    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: ");
    for (i=0; (len = ntohl(*len_ptr)); ++i, ++len_ptr) {
    OUTPUT ("<H6>   Image %d: %8ld Bytes = ", i, len);
    print_size (len, " ");
    }
    }
    }
    /**
    *@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 ", pBlockName,     // 构建执行擦除命令 : /usr/sbin/flash_eraseall -j "/dev/mtd2" /tmp "tmpfile.txt"
    TEMP_PATH, TEMP_FILE);
    if(system(cmd)){                  //执行命令
    OUTPUT("<H6>Fail on erase block ");
    ret = FAIL;
    goto EXIT_FLASHNAND;
    }
    #if 0                               //不会编译到这里
    sprintf(cmd, "/usr/sbin/nandwrite -s %ld -f -p -j %s %s/%s > %s/%s ", offset, pBlockName,
    TEMP_PATH, pFile->strFileName, TEMP_PATH, TEMP_FILE);  //构建写命令 : nandwrite 块设备写入命令  偏移   块名 临时路径 临时文件
    DBG(cmd);
    if(system(cmd)){     //执行nandwrite 写命令
    OUTPUT("<H6>Fail on update new firmware ");
    sprintf(cmd, "rm -f %s/%s ", 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 ");
    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 ");
    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) ");
    close(fd);
    ret = FAIL;
    goto EXIT_FLASHNAND;
    }
                                                              //获取/dev/mtd2设备当前oob带外数据
    if (ioctl (fd, MEMGETOOBSEL, &old_oobinfo) != 0) {
    OUTPUT("<H6>MEMGETOOBSEL error ");
    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 ");    
    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 ");
    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 ");
    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 ");
    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 ",
    imglen, pagelen, meminfo.oobblock, meminfo.size);
    OUTPUT("<H6>Input file does not fit into device error ");
    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 ", 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 ");
    ret = FAIL;
    goto restoreoob;
    }
    if (ret == 1) {                              //发现坏块,打印坏块数,地址,进行擦除坏块操作
    baderaseblock = 1;
    DBG("Bad block at %x, %u block(s) from %x will be skipped ", (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 ");
    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 ");
    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 ");
    ret = FAIL;
    goto restoreoob;
    }
    imglen -= readlen;
    offset += meminfo.oobblock;
    }
    restoreoob:
    if (oobinfochanged) {
    if (ioctl (fd, MEMSETOOBSEL, &old_oobinfo) != 0) {
    OUTPUT ("<H6>MEMSETOOBSEL error ");
    close (fd);
    ret = FAIL;
    goto EXIT_FLASHNAND;
    }
    }


    close(fd);


    if (imglen > 0) {
    OUTPUT ("<H6>Data did not fit into device, due to bad blocks ");
    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 ", KERNELBLOCK);
    fprintf(fp ,"/usr/sbin/nandwrite -p -j %s %s/%s ", 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 ");
    return FAIL;
    }
    sprintf(cmd, "%s/update.sh ", TEMP_PATH);
    return system(cmd);
    #else
    sprintf(cmd, "/usr/sbin/flash_eraseall -j %s > %s/%s ", KERNELBLOCK,
    TEMP_PATH, TEMP_FILE);
    if(system(cmd)){
    OUTPUT("<H6>Fail on erase kernel block ");
    sprintf(cmd, "rm -f %s/%s ", TEMP_PATH, TEMP_FILE);
    system(cmd);
    return FAIL;
    }
    sprintf(cmd, "/usr/sbin/nandwrite -p -j %s %s/%s > %s/%s ", KERNELBLOCK,
    TEMP_PATH, pFileName, TEMP_PATH, TEMP_FILE);
    if(system(cmd)){
    OUTPUT("<H6>Fail on update kernel ");
    sprintf(cmd, "rm -f %s/%s ", TEMP_PATH, TEMP_FILE);
    system(cmd);
    return FAIL;
    }
    sprintf(cmd, "rm -f %s/%s ", 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 ");
    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 ");
    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 ");
    ret = FAIL;
    goto EXIT_UPDATE_K;
    }
    data = (unsigned long)pImage;                  //取得映像4字节数据
    if(read(pFile->fd, pImage, len) != len){       //从文件中读取信息放入data
    DBG("<H6>File size error ");
    ret = UNKOWN;
    goto EXIT_UPDATE_K;
    }
    DBG("   Verifying Checksum ... ");
    if (crc32 (0, (unsigned char *)data, len) != ntohl(hdr.ih_dcrc)) {    //crc校验
    DBG("Bad Data CRC ");
    ret = UNKOWN;
    goto EXIT_UPDATE_K;
    }
    DBG("OK ");
    if((nFileSize = pFile->nLength) < 0){
    OUTPUT("<H6>Error on get file size ");
    ret = FAIL;
    goto EXIT_UPDATE_K;
    }
    data = nFileSize;                           //文件大小
    if(data != (len + sizeof(hdr))){
    OUTPUT("<H6>Unkown data found at tail ");
    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 ", __func__);
    if(strncmp(FILESYS_PRE, pFile->strFileName, strlen(FILESYS_PRE))){
    DBG("Not root file ");
    return UNKOWN;
    }
    DBG("File name ok ");
    #if 0
    /* CRC check */
    sprintf(cmd, "gzip -t %s/%s ", TEMP_PATH, pFileName);
    if(system(cmd)){
    DBG("Can't check ");
    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> Kernel update success, ");
    } else if(ret == UNKOWN){
    if((ret = DoRootFileSysUpdate(pFile)) == SUCCESS){
    OUTPUT("<H4>File system update success, ");
    sprintf(cmd, "rm -f %s ", SYS_FILE);
    system(cmd);
    sprintf(cmd, "rm -f %s ", 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> ",pFileName);  //向文件中写入文件名
    #endif
    gLastI = SkipHeader(STDIN_FILENO, buffer, sizeof(buffer));   //跳过包头
    #ifdef U_DEBUG
    fprintf(fp, "gLastI=%d ",gLastI);
    #endif
    if(CreateFile(pFileName, STDIN_FILENO, buffer, sizeof(buffer), &tFile)==SUCCESS){   //创建文件tFile
    OUTPUT("<H4>File create success ");
    OUTPUT("<H4> ");
    switch(DoFirmwareUpdate(&tFile)){     //更新文件tFile

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


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


    return SUCCESS;
    }

  • 相关阅读:
    第二次公共考试,判断错题集
    云助理里面查询渠道的方法
    公司第二阶段公共考试题
    云助理绑定手机及密码找回方法
    oracle的卸载
    pl/sql进阶--例外处理
    oracle--dba和表的备份与恢复
    oracle触发器
    oracle视图
    pl/sql的介绍
  • 原文地址:https://www.cnblogs.com/suncoolcat/p/3306303.html
Copyright © 2011-2022 走看看