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

📄 rockbox_flash.c

📁 编译后直接运行的MP3播放器全部C语言源代码 一个包含FAT文件系统、系统引导 Boot、FLASH Driver等内容的
💻 C
📖 第 1 页 / 共 2 页
字号:
/****************************************************************************             __________               __   ___.*   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___*   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /*   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <*   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \*                     \/            \/     \/    \/            \/* $Id: rockbox_flash.c,v 1.14 2004/01/18 17:34:12 hohensoh Exp $** Plugin for reprogramming only the second image in Flash ROM.* !!! DON'T MESS WITH THIS CODE UNLESS YOU'RE ABSOLUTELY SHURE WHAT YOU DO !!!** Copyright (C) 2003 J鰎g Hohensohn aka [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 build 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/* hard-coded values */static volatile UINT8* FB = (UINT8*)0x02000000; /* Flash base address */#define SECTORSIZE 4096 /* size of one flash sector */#define ROCKBOX_DEST 0x09000000#define ROCKBOX_EXEC 0x09000200#define DEFAULT_FILENAME "/rockbox.ucl"#define VERS_ADR 0xFE /* position of firmware version value in Flash */#define UCL_HEADER 26 /* size of the header generated by uclpack */typedef struct {    UINT32 destination; /* address to copy it to */    UINT32 size;        /* how many bytes of payload (to the next header) */    UINT32 execute;     /* entry point */    UINT32 flags;       /* uncompressed or compressed */    /* end of header, now comes the payload */} tImageHeader;/* result of the CheckFirmwareFile() function */typedef enum{    eOK = 0,    eFileNotFound, /* errors from here on */    eTooBig,    eTooSmall,    eReadErr,    eNotUCL,    eWrongAlgorithm,    eMultiBlocks,} tCheckResult;typedef struct {    UINT8 manufacturer;    UINT8 id;    int size;    char name[32];} tFlashInfo;static struct plugin_api* rb; /* here is a global api struct pointer */static UINT8* sector; /* better not place this on the stack... *//***************** 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); /* round down to 512k align,                                                     to make sure */    not_manu = pBase[0]; /* read the normal content */    not_id   = pBase[1]; /* should be 'A' (0x41) and 'R' (0x52) 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;}/*********** Tool Functions ************//* place a 32 bit value into memory, big endian */void Write32(UINT8* pByte, UINT32 value){    pByte[0] = (UINT8)(value >> 24);        pByte[1] = (UINT8)(value >> 16);        pByte[2] = (UINT8)(value >> 8);        pByte[3] = (UINT8)(value);    }/* read a 32 bit value from memory, big endian */UINT32 Read32(UINT8* pByte){    UINT32 value;    value = (UINT32)pByte[0] << 24;    value |= (UINT32)pByte[1] << 16;    value |= (UINT32)pByte[2] << 8;    value |= (UINT32)pByte[3];    return value;}/* get the start address of the second image */tImageHeader* GetSecondImage(void){    tImageHeader* pImage1;    UINT32 pos = 0;    /* default: not found */    UINT32* pFlash = (UINT32*)FB;    /* determine the first image position */    pos = pFlash[2] + pFlash[3]; /* position + size of the bootloader                                    = after it */    pos = (pos + 3) & ~3; /* be sure it's 32 bit aligned */    pImage1 = (tImageHeader*)pos;    if (pImage1->destination != ROCKBOX_DEST ||        pImage1->execute != ROCKBOX_EXEC)        return 0; /* seems to be no Archos/Rockbox image in here */    if (pImage1->size != 0)    {        /* success, we have a second image */        pos = (UINT32)pImage1 + sizeof(tImageHeader) + pImage1->size;        if (((pos + SECTORSIZE-1) & ~(SECTORSIZE-1)) != pos)        {    /* not sector-aligned */            pos = 0; /* sanity check failed */        }    }    return (tImageHeader*)pos;}/*********** Image File Functions ************//* so far, only compressed images in UCL NRV algorithm 2e supported */tCheckResult CheckImageFile(char* filename, int space, tImageHeader* pHeader,                            UINT8* pos){    int i;    int fd;    int filesize; /* size info */    int fileread = 0; /* total size as read from the file */    int read; /* how many for this sector */    /* magic file header for compressed files */    static const UINT8 magic[8] = { 0x00,0xe9,0x55,0x43,0x4c,0xff,0x01,0x1a };    UINT8 ucl_header[UCL_HEADER];    fd = rb->open(filename, O_RDONLY);    if (fd < 0)        return eFileNotFound;    filesize = rb->filesize(fd);    if (filesize - (int)sizeof(ucl_header) - 8 > space)    {        rb->close(fd);        return eTooBig;    }    else if (filesize < 40000) /* give it some reasonable lower limit */    {        rb->close(fd);        return eTooSmall;    }    /* do some sanity checks */    read = rb->read(fd, ucl_header, sizeof(ucl_header));    fileread += read;    if (read != sizeof(ucl_header))    {        rb->close(fd);        return eReadErr;    }    /* compare the magic header */    for (i=0; i<8; i++)    {        if (ucl_header[i] != magic[i])        {            rb->close(fd);            return eNotUCL;        }    }    pHeader->size = Read32(ucl_header + 22); /* compressed size */    if (pHeader->size != filesize - sizeof(ucl_header) - 8)    {        rb->close(fd);        return eMultiBlocks;    }    /* fill in the hardcoded defaults of the header */    pHeader->destination = ROCKBOX_DEST;    pHeader->execute = ROCKBOX_EXEC;    if (Read32(ucl_header + 18) > pHeader->size) /* compare with uncompressed                                                    size */    {   /* compressed, normal case */        pHeader->flags = 0x00000001; /* flags for UCL compressed */        /* check for supported algorithm */        if (ucl_header[12] != 0x2E)        {            rb->close(fd);            return eWrongAlgorithm;        }    }    else    {   /* uncompressed, either to be copied or run directly in flash */        UINT32 reset_vector; /* image has to start with reset vector */        pHeader->flags = 0x00000000; /* uncompressed */        read = rb->read(fd, &reset_vector, sizeof(reset_vector));        fileread += read;        if (read != sizeof(reset_vector))        {            rb->close(fd);            return eReadErr;        }        pHeader->execute = reset_vector;        if (reset_vector != ROCKBOX_EXEC) /* nonstandard address? */            /* assume in-place, executing directly in flash */            pHeader->destination = (UINT32)(pos + sizeof(tImageHeader));    }        /* check if we can read the whole file */    do    {        read = rb->read(fd, sector, SECTORSIZE);        fileread += read;    } while (read == SECTORSIZE);        rb->close(fd);    if (fileread != filesize)        return eReadErr;        return eOK;}/* returns the # of failures, 0 on success */unsigned ProgramImageFile(char* filename, UINT8* pos,                          tImageHeader* pImageHeader, int start, int size){    int i;    int fd;    int read; /* how many for this sector */    unsigned failures = 0;    fd = rb->open(filename, O_RDONLY);    if (fd < 0)        return false;    /* no error checking necessary here, we checked for minimum size       already */    rb->lseek(fd, start, SEEK_SET); /* go to start position */    *(tImageHeader*)sector = *pImageHeader; /* copy header into sector                                               buffer */    read = rb->read(fd, sector + sizeof(tImageHeader),                    SECTORSIZE - sizeof(tImageHeader)); /* payload behind */    size -= read;    read += sizeof(tImageHeader); /* to be programmed, but not part of the                                     file */    do {        if (!EraseSector(pos))        {            /* nothing we can do, let the programming count the errors */        }                for (i=0; i<read; i++)        {            if (!ProgramByte(pos + i, sector[i]))            {                failures++;            }        }        pos += SECTORSIZE;        read = rb->read(fd, sector, (size > SECTORSIZE) ? SECTORSIZE : size);        /* payload for next sector */        size -= read;    } while (read > 0);        rb->close(fd);    return failures;}/* returns the # of failures, 0 on success */unsigned VerifyImageFile(char* filename, UINT8* pos,                         tImageHeader* pImageHeader, int start, int size){    int i;    int fd;    int read; /* how many for this sector */    unsigned failures = 0;    fd = rb->open(filename, O_RDONLY);    if (fd < 0)        return false;    /* no error checking necessary here, we checked for minimum size       already */    rb->lseek(fd, start, SEEK_SET); /* go to start position */    *(tImageHeader*)sector = *pImageHeader; /* copy header into sector                                               buffer */    read = rb->read(fd, sector + sizeof(tImageHeader),                    SECTORSIZE - sizeof(tImageHeader)); /* payload behind */    size -= read;

⌨️ 快捷键说明

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