plugin_get_buffer() makes my plugin smaller, can get the sector buffer at runtime

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@3895 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Jörg Hohensohn 2003-07-27 22:06:58 +00:00
parent 066857e9b9
commit 9d3e5c6d1d

View file

@ -7,9 +7,10 @@
* \/ \/ \/ \/ \/ * \/ \/ \/ \/ \/
* $Id$ * $Id$
* *
* Plugin for reprogramming only the second Rockbox image. * 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örg Hohensohn [IDC]Dragon * Copyright (C) 2003 Jörg Hohensohn aka [IDC]Dragon
* *
* All files in this archive are subject to the GNU General Public License. * 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. * See the file COPYING in the source tree root for full license agreement.
@ -78,8 +79,7 @@ typedef struct
static struct plugin_api* rb; /* here is a global api struct pointer */ static struct plugin_api* rb; /* here is a global api struct pointer */
#define SEC_SIZE 4096 /* size of one flash sector */ static UINT8* sector; /* better not place this on the stack... */
static UINT8 sector[SEC_SIZE]; /* better not place this on the stack... */
/***************** Flash Functions *****************/ /***************** Flash Functions *****************/
@ -89,25 +89,25 @@ bool ReadID(volatile UINT8* pBase, UINT8* pManufacturerID, UINT8* pDeviceID)
{ {
UINT8 not_manu, not_id; /* read values before switching to ID mode */ UINT8 not_manu, not_id; /* read values before switching to ID mode */
UINT8 manu, id; /* read values when in ID mode */ UINT8 manu, id; /* read values when in ID mode */
pBase = (UINT8*)((UINT32)pBase & 0xFFF80000); /* round down to 512k align, pBase = (UINT8*)((UINT32)pBase & 0xFFF80000); /* round down to 512k align,
to make sure */ to make sure */
not_manu = pBase[0]; /* read the normal content */ not_manu = pBase[0]; /* read the normal content */
not_id = pBase[1]; /* should be 'A' (0x41) and 'R' (0x52) from the not_id = pBase[1]; /* should be 'A' (0x41) and 'R' (0x52) from the
"ARCH" marker */ "ARCH" marker */
pBase[0x5555] = 0xAA; /* enter command mode */ pBase[0x5555] = 0xAA; /* enter command mode */
pBase[0x2AAA] = 0x55; pBase[0x2AAA] = 0x55;
pBase[0x5555] = 0x90; /* ID command */ pBase[0x5555] = 0x90; /* ID command */
rb->sleep(HZ/50); /* Atmel wants 20ms pause here */ rb->sleep(HZ/50); /* Atmel wants 20ms pause here */
manu = pBase[0]; manu = pBase[0];
id = pBase[1]; id = pBase[1];
pBase[0] = 0xF0; /* reset flash (back to normal read mode) */ pBase[0] = 0xF0; /* reset flash (back to normal read mode) */
rb->sleep(HZ/50); /* Atmel wants 20ms pause here */ rb->sleep(HZ/50); /* Atmel wants 20ms pause here */
/* I assume success if the obtained values are different from /* I assume success if the obtained values are different from
the normal flash content. This is not perfectly bulletproof, they the normal flash content. This is not perfectly bulletproof, they
could theoretically be the same by chance, causing us to fail. */ could theoretically be the same by chance, causing us to fail. */
@ -120,46 +120,46 @@ bool ReadID(volatile UINT8* pBase, UINT8* pManufacturerID, UINT8* pDeviceID)
return false; /* fail */ return false; /* fail */
} }
/* eraze the sector which contains the given address */ /* erase the sector which contains the given address */
bool ErazeSector(volatile UINT8* pAddr) bool EraseSector(volatile UINT8* pAddr)
{ {
volatile UINT8* pBase = volatile UINT8* pBase =
(UINT8*)((UINT32)pAddr & 0xFFF80000); /* round down to 512k align */ (UINT8*)((UINT32)pAddr & 0xFFF80000); /* round down to 512k align */
unsigned timeout = 43000; /* the timeout loop should be no less than unsigned timeout = 43000; /* the timeout loop should be no less than
25ms */ 25ms */
pBase[0x5555] = 0xAA; /* enter command mode */ pBase[0x5555] = 0xAA; /* enter command mode */
pBase[0x2AAA] = 0x55; pBase[0x2AAA] = 0x55;
pBase[0x5555] = 0x80; /* eraze command */ pBase[0x5555] = 0x80; /* erase command */
pBase[0x5555] = 0xAA; /* enter command mode */ pBase[0x5555] = 0xAA; /* enter command mode */
pBase[0x2AAA] = 0x55; pBase[0x2AAA] = 0x55;
*pAddr = 0x30; /* eraze the sector */ *pAddr = 0x30; /* erase the sector */
/* I counted 7 instructions for this loop -> min. 0.58 us per round /* I counted 7 instructions for this loop -> min. 0.58 us per round
Plus memory waitstates it will be much more, gives margin */ Plus memory waitstates it will be much more, gives margin */
while (*pAddr != 0xFF && --timeout); /* poll for erazed */ while (*pAddr != 0xFF && --timeout); /* poll for erased */
return (timeout != 0); return (timeout != 0);
} }
/* address must be in an erazed location */ /* address must be in an erased location */
inline bool ProgramByte(volatile UINT8* pAddr, UINT8 data) inline bool ProgramByte(volatile UINT8* pAddr, UINT8 data)
{ {
unsigned timeout = 35; /* the timeout loop should be no less than 20us */ unsigned timeout = 35; /* the timeout loop should be no less than 20us */
if (~*pAddr & data) /* just a safety feature, not really necessary */ if (~*pAddr & data) /* just a safety feature, not really necessary */
return false; /* can't set any bit from 0 to 1 */ return false; /* can't set any bit from 0 to 1 */
FB[0x5555] = 0xAA; /* enter command mode */ FB[0x5555] = 0xAA; /* enter command mode */
FB[0x2AAA] = 0x55; FB[0x2AAA] = 0x55;
FB[0x5555] = 0xA0; /* byte program command */ FB[0x5555] = 0xA0; /* byte program command */
*pAddr = data; *pAddr = data;
/* I counted 7 instructions for this loop -> min. 0.58 us per round /* I counted 7 instructions for this loop -> min. 0.58 us per round
Plus memory waitstates it will be much more, gives margin */ Plus memory waitstates it will be much more, gives margin */
while (*pAddr != data && --timeout); /* poll for programmed */ while (*pAddr != data && --timeout); /* poll for programmed */
return (timeout != 0); return (timeout != 0);
} }
@ -167,10 +167,10 @@ inline bool ProgramByte(volatile UINT8* pAddr, UINT8 data)
bool GetFlashInfo(tFlashInfo* pInfo) bool GetFlashInfo(tFlashInfo* pInfo)
{ {
rb->memset(pInfo, 0, sizeof(tFlashInfo)); rb->memset(pInfo, 0, sizeof(tFlashInfo));
if (!ReadID(FB, &pInfo->manufacturer, &pInfo->id)) if (!ReadID(FB, &pInfo->manufacturer, &pInfo->id))
return false; return false;
if (pInfo->manufacturer == 0xBF) /* SST */ if (pInfo->manufacturer == 0xBF) /* SST */
{ {
if (pInfo->id == 0xD6) if (pInfo->id == 0xD6)
@ -241,7 +241,7 @@ tImageHeader* GetSecondImage(void)
if (pImage1->size != 0) if (pImage1->size != 0)
{ {
/* success, we have a second image */ /* success, we have a second image */
pos = (UINT32)pImage1 + sizeof(tImageHeader) + pImage1->size; pos = (UINT32)pImage1 + sizeof(tImageHeader) + pImage1->size;
if (((pos + SECTORSIZE-1) & ~(SECTORSIZE-1)) != pos) if (((pos + SECTORSIZE-1) & ~(SECTORSIZE-1)) != pos)
{ /* not sector-aligned */ { /* not sector-aligned */
@ -264,7 +264,7 @@ tCheckResult CheckImageFile(char* filename, int space, tImageHeader* pHeader)
int fileread = 0; /* total size as read from the file */ int fileread = 0; /* total size as read from the file */
int read; /* how many for this sector */ int read; /* how many for this sector */
/* magic file header for compressed files */ /* magic file header for compressed files */
static const UINT8 magic[8] = { 0x00,0xe9,0x55,0x43,0x4c,0xff,0x01,0x1a }; static const UINT8 magic[8] = { 0x00,0xe9,0x55,0x43,0x4c,0xff,0x01,0x1a };
UINT8 ucl_header[UCL_HEADER]; UINT8 ucl_header[UCL_HEADER];
@ -272,7 +272,7 @@ tCheckResult CheckImageFile(char* filename, int space, tImageHeader* pHeader)
fd = rb->open(filename, O_RDONLY); fd = rb->open(filename, O_RDONLY);
if (fd < 0) if (fd < 0)
return eFileNotFound; return eFileNotFound;
filesize = rb->filesize(fd); filesize = rb->filesize(fd);
if (filesize - (int)sizeof(ucl_header) - 8 > space) if (filesize - (int)sizeof(ucl_header) - 8 > space)
{ {
@ -284,9 +284,9 @@ tCheckResult CheckImageFile(char* filename, int space, tImageHeader* pHeader)
rb->close(fd); rb->close(fd);
return eTooSmall; return eTooSmall;
} }
/* do some sanity checks */ /* do some sanity checks */
read = rb->read(fd, ucl_header, sizeof(ucl_header)); read = rb->read(fd, ucl_header, sizeof(ucl_header));
fileread += read; fileread += read;
if (read != sizeof(ucl_header)) if (read != sizeof(ucl_header))
@ -294,7 +294,7 @@ tCheckResult CheckImageFile(char* filename, int space, tImageHeader* pHeader)
rb->close(fd); rb->close(fd);
return eReadErr; return eReadErr;
} }
/* compare the magic header */ /* compare the magic header */
for (i=0; i<8; i++) for (i=0; i<8; i++)
{ {
@ -304,7 +304,7 @@ tCheckResult CheckImageFile(char* filename, int space, tImageHeader* pHeader)
return eNotUCL; return eNotUCL;
} }
} }
/* check for supported algorithm */ /* check for supported algorithm */
if (ucl_header[12] != 0x2E) if (ucl_header[12] != 0x2E)
{ {
@ -318,10 +318,10 @@ tCheckResult CheckImageFile(char* filename, int space, tImageHeader* pHeader)
rb->close(fd); rb->close(fd);
return eMultiBlocks; return eMultiBlocks;
} }
if (Read32(ucl_header + 18) > pHeader->size) /* compare with uncompressed if (Read32(ucl_header + 18) > pHeader->size) /* compare with uncompressed
size */ size */
{ /* normal case */ { /* normal case */
pHeader->flags = 0x00000001; /* flags for UCL compressed */ pHeader->flags = 0x00000001; /* flags for UCL compressed */
} }
else else
@ -333,12 +333,12 @@ tCheckResult CheckImageFile(char* filename, int space, tImageHeader* pHeader)
/* check if we can read the whole file */ /* check if we can read the whole file */
do do
{ {
read = rb->read(fd, sector, SEC_SIZE); read = rb->read(fd, sector, SECTORSIZE);
fileread += read; fileread += read;
} while (read == SEC_SIZE); } while (read == SECTORSIZE);
rb->close(fd); rb->close(fd);
if (fileread != filesize) if (fileread != filesize)
return eReadErr; return eReadErr;
@ -358,7 +358,7 @@ unsigned ProgramImageFile(char* filename, UINT8* pos,
int fd; int fd;
int read; /* how many for this sector */ int read; /* how many for this sector */
unsigned failures = 0; unsigned failures = 0;
fd = rb->open(filename, O_RDONLY); fd = rb->open(filename, O_RDONLY);
if (fd < 0) if (fd < 0)
return false; return false;
@ -366,17 +366,17 @@ unsigned ProgramImageFile(char* filename, UINT8* pos,
/* no error checking necessary here, we checked for minimum size /* no error checking necessary here, we checked for minimum size
already */ already */
rb->lseek(fd, start, SEEK_SET); /* go to start position */ rb->lseek(fd, start, SEEK_SET); /* go to start position */
*(tImageHeader*)sector = *pImageHeader; /* copy header into sector *(tImageHeader*)sector = *pImageHeader; /* copy header into sector
buffer */ buffer */
read = rb->read(fd, sector + sizeof(tImageHeader), read = rb->read(fd, sector + sizeof(tImageHeader),
SEC_SIZE - sizeof(tImageHeader)); /* payload behind */ SECTORSIZE - sizeof(tImageHeader)); /* payload behind */
size -= read; size -= read;
read += sizeof(tImageHeader); /* to be programmed, but not part of the read += sizeof(tImageHeader); /* to be programmed, but not part of the
file */ file */
do { do {
if (!ErazeSector(pos)) if (!EraseSector(pos))
{ {
/* nothing we can do, let the programming count the errors */ /* nothing we can do, let the programming count the errors */
} }
@ -389,14 +389,14 @@ unsigned ProgramImageFile(char* filename, UINT8* pos,
} }
} }
pos += SEC_SIZE; pos += SECTORSIZE;
read = rb->read(fd, sector, (size > SEC_SIZE) ? SEC_SIZE : size); read = rb->read(fd, sector, (size > SECTORSIZE) ? SECTORSIZE : size);
/* payload for next sector */ /* payload for next sector */
size -= read; size -= read;
} while (read > 0); } while (read > 0);
rb->close(fd); rb->close(fd);
return failures; return failures;
} }
@ -408,7 +408,7 @@ unsigned VerifyImageFile(char* filename, UINT8* pos,
int fd; int fd;
int read; /* how many for this sector */ int read; /* how many for this sector */
unsigned failures = 0; unsigned failures = 0;
fd = rb->open(filename, O_RDONLY); fd = rb->open(filename, O_RDONLY);
if (fd < 0) if (fd < 0)
return false; return false;
@ -416,11 +416,11 @@ unsigned VerifyImageFile(char* filename, UINT8* pos,
/* no error checking necessary here, we checked for minimum size /* no error checking necessary here, we checked for minimum size
already */ already */
rb->lseek(fd, start, SEEK_SET); /* go to start position */ rb->lseek(fd, start, SEEK_SET); /* go to start position */
*(tImageHeader*)sector = *pImageHeader; /* copy header into sector *(tImageHeader*)sector = *pImageHeader; /* copy header into sector
buffer */ buffer */
read = rb->read(fd, sector + sizeof(tImageHeader), read = rb->read(fd, sector + sizeof(tImageHeader),
SEC_SIZE - sizeof(tImageHeader)); /* payload behind */ SECTORSIZE - sizeof(tImageHeader)); /* payload behind */
size -= read; size -= read;
read += sizeof(tImageHeader); /* to be programmed, but not part of the read += sizeof(tImageHeader); /* to be programmed, but not part of the
@ -436,8 +436,8 @@ unsigned VerifyImageFile(char* filename, UINT8* pos,
} }
} }
pos += SEC_SIZE; pos += SECTORSIZE;
read = rb->read(fd, sector, (size > SEC_SIZE) ? SEC_SIZE : size); read = rb->read(fd, sector, (size > SECTORSIZE) ? SECTORSIZE : size);
/* payload for next sector */ /* payload for next sector */
size -= read; size -= read;
} while (read); } while (read);
@ -455,7 +455,7 @@ unsigned VerifyImageFile(char* filename, UINT8* pos,
void ShowFlashInfo(tFlashInfo* pInfo, tImageHeader* pImageHeader) void ShowFlashInfo(tFlashInfo* pInfo, tImageHeader* pImageHeader)
{ {
char buf[32]; char buf[32];
if (!pInfo->manufacturer) if (!pInfo->manufacturer)
{ {
rb->lcd_puts(0, 0, "Flash: M=?? D=??"); rb->lcd_puts(0, 0, "Flash: M=?? D=??");
@ -481,10 +481,10 @@ void ShowFlashInfo(tFlashInfo* pInfo, tImageHeader* pImageHeader)
((UINT8*)pImageHeader - FB) / 1024); ((UINT8*)pImageHeader - FB) / 1024);
rb->lcd_puts(0, 1, buf); rb->lcd_puts(0, 1, buf);
} }
else else
{ {
rb->lcd_puts(0, 1, "No image found!"); rb->lcd_puts(0, 1, "No image found!");
} }
rb->lcd_update(); rb->lcd_update();
} }
@ -500,9 +500,18 @@ void DoUserDialog(char* filename)
int rc; /* generic return code */ int rc; /* generic return code */
UINT32 space, aligned_size, true_size; UINT32 space, aligned_size, true_size;
UINT8* pos; UINT8* pos;
int memleft;
rb->lcd_setfont(FONT_SYSFIXED); rb->lcd_setfont(FONT_SYSFIXED);
/* "allocate" memory */
sector = rb->plugin_get_buffer(&memleft);
if (memleft < SECTORSIZE) /* need buffer for a flash sector */
{
rb->splash(HZ*3, 0, true, "Out of memory");
return; /* exit */
}
pos = (void*)GetSecondImage(); pos = (void*)GetSecondImage();
rc = GetFlashInfo(&FlashInfo); rc = GetFlashInfo(&FlashInfo);
@ -531,11 +540,11 @@ void DoUserDialog(char* filename)
{ {
return; return;
} }
rb->lcd_clear_display(); rb->lcd_clear_display();
rb->lcd_puts(0, 0, "checking..."); rb->lcd_puts(0, 0, "checking...");
rb->lcd_update(); rb->lcd_update();
space = FlashInfo.size - (pos-FB + sizeof(ImageHeader)); space = FlashInfo.size - (pos-FB + sizeof(ImageHeader));
/* size minus start */ /* size minus start */
@ -545,43 +554,43 @@ void DoUserDialog(char* filename)
case eOK: case eOK:
rb->lcd_puts(0, 1, "File OK."); rb->lcd_puts(0, 1, "File OK.");
break; break;
case eNotUCL: case eNotUCL:
rb->lcd_puts(0, 1, "File not UCL "); rb->lcd_puts(0, 1, "File not UCL ");
rb->lcd_puts(0, 2, "compressed."); rb->lcd_puts(0, 2, "compressed.");
rb->lcd_puts(0, 3, "Use uclpack --2e"); rb->lcd_puts(0, 3, "Use uclpack --2e");
rb->lcd_puts(0, 4, " --10 rockbox.bin"); rb->lcd_puts(0, 4, " --10 rockbox.bin");
break; break;
case eWrongAlgorithm: case eWrongAlgorithm:
rb->lcd_puts(0, 1, "Wrong algorithm"); rb->lcd_puts(0, 1, "Wrong algorithm");
rb->lcd_puts(0, 2, "for compression."); rb->lcd_puts(0, 2, "for compression.");
rb->lcd_puts(0, 3, "Use uclpack --2e"); rb->lcd_puts(0, 3, "Use uclpack --2e");
rb->lcd_puts(0, 4, " --10 rockbox.bin"); rb->lcd_puts(0, 4, " --10 rockbox.bin");
break; break;
case eFileNotFound: case eFileNotFound:
rb->lcd_puts(0, 1, "File not found:"); rb->lcd_puts(0, 1, "File not found:");
rb->lcd_puts_scroll(0, 2, filename); rb->lcd_puts_scroll(0, 2, filename);
break; break;
case eTooBig: case eTooBig:
rb->lcd_puts(0, 1, "File too big,"); rb->lcd_puts(0, 1, "File too big,");
rb->lcd_puts(0, 2, "won't fit in chip."); rb->lcd_puts(0, 2, "won't fit in chip.");
break; break;
case eTooSmall: case eTooSmall:
rb->lcd_puts(0, 1, "File too small."); rb->lcd_puts(0, 1, "File too small.");
rb->lcd_puts(0, 2, "Incomplete?"); rb->lcd_puts(0, 2, "Incomplete?");
break; break;
case eReadErr: case eReadErr:
rb->lcd_puts(0, 1, "File read error."); rb->lcd_puts(0, 1, "File read error.");
break; break;
case eMultiBlocks: case eMultiBlocks:
rb->lcd_puts(0, 1, "File invalid."); rb->lcd_puts(0, 1, "File invalid.");
rb->lcd_puts(0, 2, "Blocksize"); rb->lcd_puts(0, 2, "Blocksize");
rb->lcd_puts(0, 3, " too small?"); rb->lcd_puts(0, 3, " too small?");
break; break;
default: default:
rb->lcd_puts(0, 1, "Check failed."); rb->lcd_puts(0, 1, "Check failed.");
break; break;
} }
if (rc == eOK) if (rc == eOK)
{ /* was OK */ { /* was OK */
rb->lcd_puts(0, 6, "[F2] to program"); rb->lcd_puts(0, 6, "[F2] to program");
@ -591,7 +600,7 @@ void DoUserDialog(char* filename)
{ /* error occured */ { /* error occured */
rb->lcd_puts(0, 6, "Any key to exit"); rb->lcd_puts(0, 6, "Any key to exit");
} }
rb->lcd_update(); rb->lcd_update();
button = rb->button_get(true); button = rb->button_get(true);
@ -613,7 +622,7 @@ void DoUserDialog(char* filename)
rb->lcd_clear_display(); rb->lcd_clear_display();
rb->lcd_puts(0, 0, "Programming..."); rb->lcd_puts(0, 0, "Programming...");
rb->lcd_update(); rb->lcd_update();
rc = ProgramImageFile(filename, pos, &ImageHeader, UCL_HEADER, true_size); rc = ProgramImageFile(filename, pos, &ImageHeader, UCL_HEADER, true_size);
if (rc) if (rc)
{ /* errors */ { /* errors */
@ -630,9 +639,9 @@ void DoUserDialog(char* filename)
rb->lcd_clear_display(); rb->lcd_clear_display();
rb->lcd_puts(0, 0, "Verifying..."); rb->lcd_puts(0, 0, "Verifying...");
rb->lcd_update(); rb->lcd_update();
rc = VerifyImageFile(filename, pos, &ImageHeader, UCL_HEADER, true_size); rc = VerifyImageFile(filename, pos, &ImageHeader, UCL_HEADER, true_size);
rb->lcd_clear_display(); rb->lcd_clear_display();
if (rc == 0) if (rc == 0)
{ {
@ -665,20 +674,20 @@ enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
it test that the api version and model the plugin was compiled for it test that the api version and model the plugin was compiled for
matches the machine it is running on */ matches the machine it is running on */
TEST_PLUGIN_API(api); TEST_PLUGIN_API(api);
if (parameter == NULL) if (parameter == NULL)
filename = DEFAULT_FILENAME; filename = DEFAULT_FILENAME;
else else
filename = (char*) parameter; filename = (char*) parameter;
rb = api; /* copy to global api pointer */ rb = api; /* copy to global api pointer */
/* now go ahead and have fun! */ /* now go ahead and have fun! */
DoUserDialog(filename); DoUserDialog(filename);
return PLUGIN_OK; return PLUGIN_OK;
} }
#endif #endif // #ifdef HAVE_LCD_BITMAP
#endif #endif // #ifndef SIMULATOR