⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 firmware_flash.c

📁 编译后直接运行的MP3播放器全部C语言源代码 一个包含FAT文件系统、系统引导 Boot、FLASH Driver等内容的
💻 C
📖 第 1 页 / 共 2 页
字号:
/****************************************************************************             __________               __   ___.*   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___*   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /*   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <*   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \*                     \/            \/     \/    \/            \/* $Id: firmware_flash.c,v 1.10 2004/01/08 09:58:58 bagder Exp $** Plugin for reprogramming the whole Flash ROM chip with a new content.* !!! DON'T MESS WITH THIS CODE UNLESS YOU'RE ABSOLUTELY SHURE WHAT YOU DO !!!** Copyright (C) 2003 J鰎g Hohensohn [IDC]Dragon** All files in this archive are subject to the GNU General Public License.* See the file COPYING in the source tree root for full license agreement.** This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY* KIND, either express or implied.*****************************************************************************/#include "plugin.h"#ifndef SIMULATOR /* only for target *//* define DUMMY if you only want to "play" with the UI, does no harm *//* #define DUMMY */#ifndef UINT8#define UINT8 unsigned char#endif#ifndef UINT16#define UINT16 unsigned short#endif#ifndef UINT32#define UINT32 unsigned long#endif/* platform IDs as I have used them in my firmware templates */#define ID_RECORDER 0#define ID_FM       1#define ID_PLAYER   2#define ID_REC_V2   3/* Here I have to check for ARCHOS_* defines in source code, which is    generally strongly discouraged. But here I'm not checking for a certain    feature, I'm checking for the model itself. */#if defined(ARCHOS_PLAYER)#define FILE_TYPE "player"#define KEEP VERSION_ADR /* keep the firmware version */#define PLATFORM_ID ID_PLAYER#elif defined(ARCHOS_RECORDER)#define FILE_TYPE "rec"#define KEEP MASK_ADR /* keep the mask value */#define PLATFORM_ID ID_RECORDER#elif defined(ARCHOS_RECORDERV2)#define FILE_TYPE "v2"#define KEEP MASK_ADR /* keep the mask value */#define PLATFORM_ID ID_REC_V2#elif defined(ARCHOS_FMRECORDER)#define FILE_TYPE "fm"#define KEEP MASK_ADR /* keep the mask value */#define PLATFORM_ID ID_FM#else#undef PLATFORM_ID /* this platform is not (yet) flashable */#endif#ifdef PLATFORM_ID/* result of the CheckFirmwareFile() function */typedef enum{    eOK = 0,    eFileNotFound, /* errors from here on */    eTooBig,    eTooSmall,    eReadErr,    eBadContent,    eCrcErr,    eBadPlatform,} tCheckResult;/* result of the CheckBootROM() function */typedef enum{    eBootROM, /* the supported boot ROM */    eUnknown, /* unknown boot ROM */    eROMless, /* flash mapped to zero */} tCheckROM;typedef struct {    UINT8 manufacturer;    UINT8 id;    int size;    char name[32];} tFlashInfo;static struct plugin_api* rb; /* here is a global api struct pointer */#define MASK_ADR     0xFC /* position of hardware mask value in Flash */#define VERSION_ADR  0xFE /* position of firmware version value in Flash */#define PLATFORM_ADR 0xFB /* position of my platform ID value in Flash */#define SEC_SIZE 4096 /* size of one flash sector */static UINT8* sector; /* better not place this on the stack... */static volatile UINT8* FB = (UINT8*)0x02000000; /* Flash base address *//***************** Flash Functions *****************//* read the manufacturer and device ID */bool ReadID(volatile UINT8* pBase, UINT8* pManufacturerID, UINT8* pDeviceID){    UINT8 not_manu, not_id; /* read values before switching to ID mode */    UINT8 manu, id; /* read values when in ID mode */        pBase = (UINT8*)((UINT32)pBase & 0xFFF80000); /* down to 512k align */        /* read the normal content */    not_manu = pBase[0]; /* should be 'A' (0x41) and 'R' (0x52) */    not_id   = pBase[1]; /*  from the "ARCH" marker */        pBase[0x5555] = 0xAA; /* enter command mode */    pBase[0x2AAA] = 0x55;    pBase[0x5555] = 0x90; /* ID command */    rb->sleep(HZ/50); /* Atmel wants 20ms pause here */        manu = pBase[0];    id   = pBase[1];        pBase[0] = 0xF0; /* reset flash (back to normal read mode) */    rb->sleep(HZ/50); /* Atmel wants 20ms pause here */        /* I assume success if the obtained values are different from    the normal flash content. This is not perfectly bulletproof, they     could theoretically be the same by chance, causing us to fail. */    if (not_manu != manu || not_id != id) /* a value has changed */    {        *pManufacturerID = manu; /* return the results */        *pDeviceID = id;        return true; /* success */    }    return false; /* fail */}/* erase the sector which contains the given address */bool EraseSector(volatile UINT8* pAddr){#ifdef DUMMY    (void)pAddr; /* prevents warning */    return true;#else    volatile UINT8* pBase = (UINT8*)((UINT32)pAddr & 0xFFF80000); /* round down to 512k align */    unsigned timeout = 43000; /* the timeout loop should be no less than 25ms */        pBase[0x5555] = 0xAA; /* enter command mode */    pBase[0x2AAA] = 0x55;    pBase[0x5555] = 0x80; /* erase command */    pBase[0x5555] = 0xAA; /* enter command mode */    pBase[0x2AAA] = 0x55;    *pAddr = 0x30; /* erase the sector */    /* I counted 7 instructions for this loop -> min. 0.58 us per round */    /* Plus memory waitstates it will be much more, gives margin */    while (*pAddr != 0xFF && --timeout); /* poll for erased */    return (timeout != 0);#endif}/* address must be in an erased location */inline bool ProgramByte(volatile UINT8* pAddr, UINT8 data){#ifdef DUMMY    (void)pAddr; /* prevents warnings */    (void)data;    return true;#else    unsigned timeout = 35; /* the timeout loop should be no less than 20us */        if (~*pAddr & data) /* just a safety feature, not really necessary */        return false; /* can't set any bit from 0 to 1 */        FB[0x5555] = 0xAA; /* enter command mode */    FB[0x2AAA] = 0x55;    FB[0x5555] = 0xA0; /* byte program command */        *pAddr = data;        /* I counted 7 instructions for this loop -> min. 0.58 us per round */    /* Plus memory waitstates it will be much more, gives margin */    while (*pAddr != data && --timeout); /* poll for programmed */        return (timeout != 0);#endif}/* this returns true if supported and fills the info struct */bool GetFlashInfo(tFlashInfo* pInfo){    rb->memset(pInfo, 0, sizeof(tFlashInfo));        if (!ReadID(FB, &pInfo->manufacturer, &pInfo->id))        return false;        if (pInfo->manufacturer == 0xBF) /* SST */    {        if (pInfo->id == 0xD6)        {            pInfo->size = 256* 1024; /* 256k */            rb->strcpy(pInfo->name, "SST39VF020");            return true;        }        else if (pInfo->id == 0xD7)        {            pInfo->size = 512* 1024; /* 512k */            rb->strcpy(pInfo->name, "SST39VF040");            return true;        }        else            return false;    }    return false;}/*********** Utility Functions ************//* Tool function to calculate a CRC32 across some buffer *//* third argument is either 0xFFFFFFFF to start or value from last piece */unsigned crc_32(unsigned char* buf, unsigned len, unsigned crc32){    /* CCITT standard polynomial 0x04C11DB7 */    static const unsigned crc32_lookup[16] =     {   /* lookup table for 4 bits at a time is affordable */        0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9,         0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,         0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61,         0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD    };        unsigned char byte;    unsigned t;    while (len--)    {           byte = *buf++; /* get one byte of data */        /* upper nibble of our data */        t = crc32 >> 28; /* extract the 4 most significant bits */        t ^= byte >> 4; /* XOR in 4 bits of data into the extracted bits */        crc32 <<= 4; /* shift the CRC register left 4 bits */             crc32 ^= crc32_lookup[t]; /* do the table lookup and XOR the result */        /* lower nibble of our data */        t = crc32 >> 28; /* extract the 4 most significant bits */        t ^= byte & 0x0F; /* XOR in 4 bits of data into the extracted bits */        crc32 <<= 4; /* shift the CRC register left 4 bits */             crc32 ^= crc32_lookup[t]; /* do the table lookup and XOR the result */    }        return crc32;}/*********** Firmware File Functions + helpers ************//* test if the version number is consistent with the platform */bool CheckPlatform(int platform_id, UINT16 version){    if (version == 200)    {   /* for my very first firmwares, I foolishly changed it to 200 */        return (platform_id == ID_RECORDER || platform_id == ID_FM);    }    else if (version == 123)    {   /* it can be a FM or V2 recorder */        return (platform_id == ID_FM || platform_id == ID_REC_V2);    }    else if (version == 132)    {   /* seen on a V2 recorder */        return (platform_id == ID_REC_V2);    }    else if (version >= 115 && version <= 129)    {   /* the range of Recorders seen so far */        return (platform_id == ID_RECORDER);    }    else if (version == 0 || (version >= 300 && version <= 506))    {   /* for very old players, I've seen zero */        return (platform_id == ID_PLAYER);    }    return false; /* unknown */}tCheckResult CheckFirmwareFile(char* filename, int chipsize, bool is_romless){    int i;    int fd;    int fileleft; /* size info, how many left for reading */    int fileread = 0; /* total size as read from the file */    int read_now; /* how many to read for this sector */    int got_now; /* how many gotten for this sector */    unsigned crc32 = 0xFFFFFFFF; /* CCITT init value */    unsigned file_crc; /* CRC value read from file */    bool has_crc;        fd = rb->open(filename, O_RDONLY);    if (fd < 0)        return eFileNotFound;        fileleft = rb->filesize(fd);    if (fileleft > chipsize)    {        rb->close(fd);        return eTooBig;    }    else if (fileleft < 50000) /* give it some reasonable lower limit */    {        rb->close(fd);        return eTooSmall;    }        if (fileleft == 256*1024)    {   // original dumped firmware file has no CRC nor platform ID        has_crc = false;    }    else    {        has_crc = true;        fileleft -= sizeof(unsigned); // exclude the last 4 bytes    }    /* do some sanity checks */        got_now = rb->read(fd, sector, SEC_SIZE); /* read first sector */    fileread += got_now;    fileleft -= got_now;    if (got_now != SEC_SIZE)    {        rb->close(fd);        return eReadErr;    }    /* version number in file plausible with this hardware? */    if (!CheckPlatform(PLATFORM_ID, *(UINT16*)(sector + VERSION_ADR)))    {        rb->close(fd);        return eBadPlatform;    }        if (has_crc)    {        crc32 = crc_32(sector, SEC_SIZE, crc32); /* checksum */                /* in addition to the CRC, my files also have a platform ID */        if (sector[PLATFORM_ADR] != PLATFORM_ID) /* for our hardware? */        {            rb->close(fd);            return eBadPlatform;        }    }    if (is_romless)    {   /* in this case, there is not much we can check */        if (*(UINT32*)sector != 0x00000200) /* reset vector */        {            rb->close(fd);            return eBadContent;        }    }    else    {        /* compare some bytes which have to be identical */        if (*(UINT32*)sector != 0x41524348) /* "ARCH" */        {            rb->close(fd);            return eBadContent;        }            for (i = 0x30; i<MASK_ADR-1; i++) /* leave one byte for me */        {            if (sector[i] != FB[i])            {                rb->close(fd);                return eBadContent;            }        }    }        /* check if we can read the whole file, and do checksum */    do    {        read_now = MIN(SEC_SIZE, fileleft);        got_now = rb->read(fd, sector, read_now);        fileread += got_now;        fileleft -= got_now;        if (read_now != got_now)        {            rb->close(fd);            return eReadErr;        }        if (has_crc)        {            crc32 = crc_32(sector, got_now, crc32); /* checksum */        }    } while (fileleft);    if (has_crc)    {        got_now = rb->read(fd, &file_crc, sizeof(file_crc));        if (got_now != sizeof(file_crc))        {            rb->close(fd);            return eReadErr;        }    }        /*  must be EOF now */    got_now = rb->read(fd, sector, SEC_SIZE);    rb->close(fd);    if (got_now != 0)        return eReadErr;    if (has_crc && file_crc != crc32)        return eCrcErr;        return eOK;}/* returns the # of failures, 0 on success */unsigned ProgramFirmwareFile(char* filename, int chipsize){    int i, j;    int fd;    int read = SEC_SIZE; /* how many for this sector */    UINT16 keep = *(UINT16*)(FB + KEEP); /* we must keep this! */    unsigned failures = 0;        fd = rb->open(filename, O_RDONLY);    if (fd < 0)        return false;        for (i=0; i<chipsize; i+=SEC_SIZE)    {        if (!EraseSector(FB + i))        {            /* nothing we can do, let the programming count the errors */        }                if (read == SEC_SIZE) /* not EOF yet */        {            read = rb->read(fd, sector, SEC_SIZE);            if (i==0)            {   /* put original value back in */                *(UINT16*)(sector + KEEP) = keep;            }                        for (j=0; j<read; j++)            {                if (!ProgramByte(FB + i + j, sector[j]))                {                    failures++;                }            }        }    }        rb->close(fd);        return failures;}/* returns the # of failures, 0 on success */unsigned VerifyFirmwareFile(char* filename){    int i=0, j;    int fd;    int read = SEC_SIZE; /* how many for this sector */    unsigned failures = 0;        fd = rb->open(filename, O_RDONLY);    if (fd < 0)        return false;        do    {        read = rb->read(fd, sector, SEC_SIZE);                for (j=0; j<read; j++)        {             /* position of keep value is no error */            if (FB[i] != sector[j] && i != KEEP && i != (KEEP+1))            {                failures++;            }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -