Manual: Simplify Makefile htlatex call a bit.
[kugel-rb.git] / apps / plugins / firmware_flash.c
blob24fb3395b628bc67ca68f3d9029fd34a2aa6031d
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Plugin for reprogramming the whole Flash ROM chip with a new content.
11 * !!! DON'T MESS WITH THIS CODE UNLESS YOU'RE ABSOLUTELY SURE WHAT YOU DO !!!
13 * Copyright (C) 2003 Jörg Hohensohn [IDC]Dragon
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
23 ****************************************************************************/
24 #include "plugin.h"
26 /* define DUMMY if you only want to "play" with the UI, does no harm */
27 /* #define DUMMY */
29 #ifndef UINT8
30 #define UINT8 unsigned char
31 #endif
33 #ifndef UINT16
34 #define UINT16 unsigned short
35 #endif
37 #ifndef UINT32
38 #define UINT32 unsigned long
39 #endif
41 /* platform IDs as I have used them in my firmware templates */
42 #define ID_RECORDER 0
43 #define ID_FM 1
44 #define ID_PLAYER 2
45 #define ID_REC_V2 3
46 #define ID_ONDIO_FM 4
47 #define ID_ONDIO_SP 5
49 /* Here I have to check for ARCHOS_* defines in source code, which is
50 generally strongly discouraged. But here I'm not checking for a certain
51 feature, I'm checking for the model itself. */
52 #if defined(ARCHOS_PLAYER)
53 #define FILE_TYPE "player"
54 #define KEEP VERSION_ADR /* keep the firmware version */
55 #define PLATFORM_ID ID_PLAYER
56 #elif defined(ARCHOS_RECORDER)
57 #define FILE_TYPE "rec"
58 #define KEEP MASK_ADR /* keep the mask value */
59 #define PLATFORM_ID ID_RECORDER
60 #elif defined(ARCHOS_RECORDERV2)
61 #define FILE_TYPE "v2"
62 #define KEEP MASK_ADR /* keep the mask value */
63 #define PLATFORM_ID ID_REC_V2
64 #elif defined(ARCHOS_FMRECORDER)
65 #define FILE_TYPE "fm"
66 #define KEEP MASK_ADR /* keep the mask value */
67 #define PLATFORM_ID ID_FM
68 #elif defined(ARCHOS_ONDIOFM)
69 #define FILE_TYPE "ondiofm"
70 #define KEEP MASK_ADR /* keep the mask value */
71 #define PLATFORM_ID ID_ONDIO_FM
72 #elif defined(ARCHOS_ONDIOSP)
73 #define FILE_TYPE "ondiosp"
74 #define KEEP MASK_ADR /* keep the mask value */
75 #define PLATFORM_ID ID_ONDIO_SP
76 #else
77 #error this platform is not (yet) flashable
78 #endif
82 #if CONFIG_KEYPAD == ONDIO_PAD /* limited keypad */
83 #define KEY1 BUTTON_LEFT
84 #define KEY2 BUTTON_UP
85 #define KEY3 BUTTON_RIGHT
86 #define KEYNAME1 "[Left]"
87 #define KEYNAME2 "[Up]"
88 #define KEYNAME3 "[Right]"
89 #else /* recorder keypad */
90 #define KEY1 BUTTON_F1
91 #define KEY2 BUTTON_F2
92 #define KEY3 BUTTON_F3
93 #define KEYNAME1 "[F1]"
94 #define KEYNAME2 "[F2]"
95 #define KEYNAME3 "[F3]"
96 #endif
98 /* result of the CheckFirmwareFile() function */
99 typedef enum
101 eOK = 0,
102 eFileNotFound, /* errors from here on */
103 eTooBig,
104 eTooSmall,
105 eReadErr,
106 eBadContent,
107 eCrcErr,
108 eBadPlatform,
109 } tCheckResult;
111 /* result of the CheckBootROM() function */
112 typedef enum
114 eBootROM, /* the supported boot ROM(s) */
115 eUnknown, /* unknown boot ROM */
116 eROMless, /* flash mapped to zero */
117 } tCheckROM;
119 typedef struct
121 UINT8 manufacturer;
122 UINT8 id;
123 int size;
124 char name[32];
125 } tFlashInfo;
127 #define MASK_ADR 0xFC /* position of hardware mask value in Flash */
128 #define VERSION_ADR 0xFE /* position of firmware version value in Flash */
129 #define PLATFORM_ADR 0xFB /* position of my platform ID value in Flash */
130 #define SEC_SIZE 4096 /* size of one flash sector */
131 static UINT8* sector; /* better not place this on the stack... */
132 static volatile UINT8* FB = (UINT8*)0x02000000; /* Flash base address */
135 /***************** Flash Functions *****************/
138 /* read the manufacturer and device ID */
139 bool ReadID(volatile UINT8* pBase, UINT8* pManufacturerID, UINT8* pDeviceID)
141 UINT8 not_manu, not_id; /* read values before switching to ID mode */
142 UINT8 manu, id; /* read values when in ID mode */
144 pBase = (UINT8*)((UINT32)pBase & 0xFFF80000); /* down to 512k align */
146 /* read the normal content */
147 not_manu = pBase[0]; /* should be 'A' (0x41) and 'R' (0x52) */
148 not_id = pBase[1]; /* from the "ARCH" marker */
150 pBase[0x5555] = 0xAA; /* enter command mode */
151 pBase[0x2AAA] = 0x55;
152 pBase[0x5555] = 0x90; /* ID command */
153 rb->sleep(HZ/50); /* Atmel wants 20ms pause here */
155 manu = pBase[0];
156 id = pBase[1];
158 pBase[0] = 0xF0; /* reset flash (back to normal read mode) */
159 rb->sleep(HZ/50); /* Atmel wants 20ms pause here */
161 /* I assume success if the obtained values are different from
162 the normal flash content. This is not perfectly bulletproof, they
163 could theoretically be the same by chance, causing us to fail. */
164 if (not_manu != manu || not_id != id) /* a value has changed */
166 *pManufacturerID = manu; /* return the results */
167 *pDeviceID = id;
168 return true; /* success */
170 return false; /* fail */
174 /* erase the sector which contains the given address */
175 bool EraseSector(volatile UINT8* pAddr)
177 #ifdef DUMMY
178 (void)pAddr; /* prevents warning */
179 return true;
180 #else
181 volatile UINT8* pBase = (UINT8*)((UINT32)pAddr & 0xFFF80000); /* round down to 512k align */
182 unsigned timeout = 43000; /* the timeout loop should be no less than 25ms */
184 pBase[0x5555] = 0xAA; /* enter command mode */
185 pBase[0x2AAA] = 0x55;
186 pBase[0x5555] = 0x80; /* erase command */
187 pBase[0x5555] = 0xAA; /* enter command mode */
188 pBase[0x2AAA] = 0x55;
189 *pAddr = 0x30; /* erase the sector */
191 /* I counted 7 instructions for this loop -> min. 0.58 us per round */
192 /* Plus memory waitstates it will be much more, gives margin */
193 while (*pAddr != 0xFF && --timeout); /* poll for erased */
195 return (timeout != 0);
196 #endif
200 /* address must be in an erased location */
201 inline bool ProgramByte(volatile UINT8* pAddr, UINT8 data)
203 #ifdef DUMMY
204 (void)pAddr; /* prevents warnings */
205 (void)data;
206 return true;
207 #else
208 unsigned timeout = 35; /* the timeout loop should be no less than 20us */
210 if (~*pAddr & data) /* just a safety feature, not really necessary */
211 return false; /* can't set any bit from 0 to 1 */
213 FB[0x5555] = 0xAA; /* enter command mode */
214 FB[0x2AAA] = 0x55;
215 FB[0x5555] = 0xA0; /* byte program command */
217 *pAddr = data;
219 /* I counted 7 instructions for this loop -> min. 0.58 us per round */
220 /* Plus memory waitstates it will be much more, gives margin */
221 while (*pAddr != data && --timeout); /* poll for programmed */
223 return (timeout != 0);
224 #endif
228 /* this returns true if supported and fills the info struct */
229 bool GetFlashInfo(tFlashInfo* pInfo)
231 rb->memset(pInfo, 0, sizeof(tFlashInfo));
233 if (!ReadID(FB, &pInfo->manufacturer, &pInfo->id))
234 return false;
236 if (pInfo->manufacturer == 0xBF) /* SST */
238 if (pInfo->id == 0xD6)
240 pInfo->size = 256* 1024; /* 256k */
241 rb->strcpy(pInfo->name, "SST39VF020");
242 return true;
244 else if (pInfo->id == 0xD7)
246 pInfo->size = 512* 1024; /* 512k */
247 rb->strcpy(pInfo->name, "SST39VF040");
248 return true;
250 else
251 return false;
253 return false;
256 /*********** Firmware File Functions + helpers ************/
258 /* test if the version number is consistent with the platform */
259 bool CheckPlatform(int platform_id, UINT16 version)
261 if (version == 200)
262 { /* for my very first firmwares, I foolishly changed it to 200 */
263 return (platform_id == ID_RECORDER || platform_id == ID_FM);
265 else if (version == 123)
266 { /* it can be a FM or V2 recorder */
267 return (platform_id == ID_FM || platform_id == ID_REC_V2);
269 else if (version == 132)
270 { /* newer Ondio, and seen on a V2 recorder */
271 return (platform_id == ID_ONDIO_SP || platform_id == ID_ONDIO_FM
272 || platform_id == ID_REC_V2);
274 else if (version == 104)
275 { /* classic Ondio128 */
276 return (platform_id == ID_ONDIO_FM);
278 else if (version >= 115 && version <= 129)
279 { /* the range of Recorders seen so far */
280 return (platform_id == ID_RECORDER);
282 else if (version == 0 || (version >= 300 && version <= 508))
283 { /* for very old players, I've seen zero */
284 return (platform_id == ID_PLAYER);
287 return false; /* unknown */
291 tCheckResult CheckFirmwareFile(char* filename, int chipsize, bool is_romless)
293 int i;
294 int fd;
295 int fileleft; /* size info, how many left for reading */
296 int fileread = 0; /* total size as read from the file */
297 int read_now; /* how many to read for this sector */
298 int got_now; /* how many gotten for this sector */
299 unsigned crc32 = 0xFFFFFFFF; /* CCITT init value */
300 unsigned file_crc; /* CRC value read from file */
301 bool has_crc;
303 fd = rb->open(filename, O_RDONLY);
304 if (fd < 0)
305 return eFileNotFound;
307 fileleft = rb->filesize(fd);
308 if (fileleft > chipsize)
310 rb->close(fd);
311 return eTooBig;
313 else if (fileleft < 20000) /* give it some reasonable lower limit */
315 rb->close(fd);
316 return eTooSmall;
319 if (fileleft == 256*1024)
320 { /* original dumped firmware file has no CRC nor platform ID */
321 has_crc = false;
323 else
325 has_crc = true;
326 fileleft -= sizeof(unsigned); /* exclude the last 4 bytes */
329 /* do some sanity checks */
331 got_now = rb->read(fd, sector, SEC_SIZE); /* read first sector */
332 fileread += got_now;
333 fileleft -= got_now;
334 if (got_now != SEC_SIZE)
336 rb->close(fd);
337 return eReadErr;
340 /* version number in file plausible with this hardware? */
341 if (!CheckPlatform(PLATFORM_ID, *(UINT16*)(sector + VERSION_ADR)))
343 rb->close(fd);
344 return eBadPlatform;
347 if (has_crc)
349 crc32 = rb->crc_32(sector, SEC_SIZE, crc32); /* checksum */
351 /* in addition to the CRC, my files also have a platform ID */
352 if (sector[PLATFORM_ADR] != PLATFORM_ID) /* for our hardware? */
354 rb->close(fd);
355 return eBadPlatform;
359 if (is_romless)
360 { /* in this case, there is not much we can check */
361 if (*(UINT32*)sector != 0x00000200) /* reset vector */
363 rb->close(fd);
364 return eBadContent;
367 else
369 /* compare some bytes which have to be identical */
370 if (*(UINT32*)sector != 0x41524348) /* "ARCH" */
372 rb->close(fd);
373 return eBadContent;
376 for (i = 0x30; i<MASK_ADR-2; i++) /* leave two bytes for me */
378 if (sector[i] != FB[i])
380 rb->close(fd);
381 return eBadContent;
386 /* check if we can read the whole file, and do checksum */
389 read_now = MIN(SEC_SIZE, fileleft);
390 got_now = rb->read(fd, sector, read_now);
391 fileread += got_now;
392 fileleft -= got_now;
394 if (read_now != got_now)
396 rb->close(fd);
397 return eReadErr;
400 if (has_crc)
402 crc32 = rb->crc_32(sector, got_now, crc32); /* checksum */
404 } while (fileleft);
406 if (has_crc)
408 got_now = rb->read(fd, &file_crc, sizeof(file_crc));
409 if (got_now != sizeof(file_crc))
411 rb->close(fd);
412 return eReadErr;
416 /* must be EOF now */
417 got_now = rb->read(fd, sector, SEC_SIZE);
418 rb->close(fd);
419 if (got_now != 0)
420 return eReadErr;
422 if (has_crc && file_crc != crc32)
423 return eCrcErr;
425 return eOK;
429 /* returns the # of failures, 0 on success */
430 unsigned ProgramFirmwareFile(char* filename, int chipsize)
432 int i, j;
433 int fd;
434 int read = SEC_SIZE; /* how many for this sector */
435 UINT16 keep = *(UINT16*)(FB + KEEP); /* we must keep this! */
436 unsigned failures = 0;
438 fd = rb->open(filename, O_RDONLY);
439 if (fd < 0)
440 return false;
442 for (i=0; i<chipsize; i+=SEC_SIZE)
444 if (!EraseSector(FB + i))
446 /* nothing we can do, let the programming count the errors */
449 if (read == SEC_SIZE) /* not EOF yet */
451 read = rb->read(fd, sector, SEC_SIZE);
452 if (i==0)
453 { /* put original value back in */
454 *(UINT16*)(sector + KEEP) = keep;
457 for (j=0; j<read; j++)
459 if (!ProgramByte(FB + i + j, sector[j]))
461 failures++;
467 rb->close(fd);
469 return failures;
473 /* returns the # of failures, 0 on success */
474 unsigned VerifyFirmwareFile(char* filename)
476 int i=0, j;
477 int fd;
478 int read = SEC_SIZE; /* how many for this sector */
479 unsigned failures = 0;
481 fd = rb->open(filename, O_RDONLY);
482 if (fd < 0)
483 return false;
487 read = rb->read(fd, sector, SEC_SIZE);
489 for (j=0; j<read; j++)
491 /* position of keep value is no error */
492 if (FB[i] != sector[j] && i != KEEP && i != (KEEP+1))
494 failures++;
496 i++;
499 while (read == SEC_SIZE);
501 rb->close(fd);
503 return failures;
507 /***************** Support Functions *****************/
509 /* check if we have "normal" boot ROM or flash mirrored to zero */
510 tCheckROM CheckBootROM(void)
512 unsigned boot_crc;
513 unsigned* pFlash = (unsigned*)FB;
514 unsigned* pRom = (unsigned*)0x0;
515 unsigned i;
517 boot_crc = rb->crc_32((unsigned char*)0x0, 64*1024, 0xFFFFFFFF);
518 if (boot_crc == 0x56DBA4EE /* the known boot ROM */
519 #if PLATFORM_ID == ID_PLAYER
520 /* alternative boot ROM found in one single player so far */
521 || boot_crc == 0x358099E8
522 #endif
524 return eBootROM;
526 /* check if ROM is a flash mirror */
527 for (i=0; i<256*1024/sizeof(unsigned); i++)
529 if (*pRom++ != *pFlash++)
530 { /* difference means no mirror */
531 return eUnknown;
535 return eROMless;
539 /***************** User Interface Functions *****************/
541 int WaitForButton(void)
543 int button;
547 button = rb->button_get(true);
548 } while (IS_SYSEVENT(button) || (button & BUTTON_REL));
550 return button;
553 #ifdef HAVE_LCD_BITMAP
554 /* Recorder implementation */
556 /* helper for DoUserDialog() */
557 void ShowFlashInfo(tFlashInfo* pInfo)
559 if (!pInfo->manufacturer)
561 rb->lcd_puts(0, 0, "Flash: M=?? D=??");
562 rb->lcd_puts(0, 1, "Impossible to program");
564 else
566 rb->lcd_putsf(0, 0, "Flash: M=%02x D=%02x",
567 pInfo->manufacturer, pInfo->id);
570 if (pInfo->size)
572 rb->lcd_puts(0, 1, pInfo->name);
573 rb->lcd_putsf(0, 2, "Size: %d KB", pInfo->size / 1024);
575 else
577 rb->lcd_puts(0, 1, "Unsupported chip");
582 rb->lcd_update();
586 /* Kind of our main function, defines the application flow. */
587 void DoUserDialog(char* filename)
589 tFlashInfo FlashInfo;
590 char default_filename[32];
591 int button;
592 int rc; /* generic return code */
593 size_t memleft;
594 tCheckROM result;
595 bool is_romless;
597 /* this can only work if Rockbox runs in DRAM, not flash ROM */
598 if ((UINT8*)rb >= FB && (UINT8*)rb < FB + 4096*1024) /* 4 MB max */
599 { /* we're running from flash */
600 rb->splash(HZ*3, "Not from ROM");
601 return; /* exit */
604 /* test if the user is running the correct plugin for this box */
605 if (!CheckPlatform(PLATFORM_ID, *(UINT16*)(FB + VERSION_ADR)))
607 rb->splash(HZ*3, "Wrong plugin");
608 return; /* exit */
611 /* refuse to work if the power may fail meanwhile */
612 if (!rb->battery_level_safe())
614 rb->splash(HZ*3, "Battery too low!");
615 return; /* exit */
618 /* check boot ROM */
619 result = CheckBootROM();
620 if (result == eUnknown)
621 { /* no support for any other yet */
622 rb->splash(HZ*3, "Wrong boot ROM");
623 return; /* exit */
625 is_romless = (result == eROMless);
627 /* compose filename if none given */
628 if (filename == NULL)
630 rb->snprintf(
631 default_filename,
632 sizeof(default_filename),
633 "/firmware_%s%s.bin",
634 FILE_TYPE,
635 is_romless ? "_norom" : "");
636 filename = default_filename;
639 /* "allocate" memory */
640 sector = rb->plugin_get_buffer(&memleft);
641 if (memleft < SEC_SIZE) /* need buffer for a flash sector */
643 rb->splash(HZ*3, "Out of memory");
644 return; /* exit */
647 rb->lcd_setfont(FONT_SYSFIXED);
649 rc = GetFlashInfo(&FlashInfo);
650 ShowFlashInfo(&FlashInfo);
651 if (FlashInfo.size == 0) /* no valid chip */
653 rb->splash(HZ*3, "Sorry!");
654 return; /* exit */
657 rb->lcd_puts(0, 3, "using file:");
658 rb->lcd_puts_scroll(0, 4, filename);
659 rb->lcd_puts(0, 6, KEYNAME1 " to check file");
660 rb->lcd_puts(0, 7, "other key to exit");
661 rb->lcd_update();
663 button = WaitForButton();
664 if (button != KEY1)
666 return;
669 rb->lcd_clear_display();
670 rb->lcd_puts(0, 0, "checking...");
671 rb->lcd_update();
673 rc = CheckFirmwareFile(filename, FlashInfo.size, is_romless);
674 rb->lcd_puts(0, 0, "checked:");
675 switch (rc)
677 case eOK:
678 rb->lcd_puts(0, 1, "File OK.");
679 break;
680 case eFileNotFound:
681 rb->lcd_puts(0, 1, "File not found.");
682 rb->lcd_puts(0, 2, "Put this in root:");
683 rb->lcd_puts_scroll(0, 4, filename);
684 break;
685 case eTooBig:
686 rb->lcd_puts(0, 1, "File too big,");
687 rb->lcd_puts(0, 2, "larger than chip.");
688 break;
689 case eTooSmall:
690 rb->lcd_puts(0, 1, "File too small.");
691 rb->lcd_puts(0, 2, "Incomplete?");
692 break;
693 case eReadErr:
694 rb->lcd_puts(0, 1, "Read error.");
695 break;
696 case eBadContent:
697 rb->lcd_puts(0, 1, "File invalid.");
698 rb->lcd_puts(0, 2, "Sanity check fail.");
699 break;
700 case eCrcErr:
701 rb->lcd_puts(0, 1, "File invalid.");
702 rb->lcd_puts(0, 2, "CRC check failed,");
703 rb->lcd_puts(0, 3, "checksum mismatch.");
704 break;
705 case eBadPlatform:
706 rb->lcd_puts(0, 1, "Wrong file for");
707 rb->lcd_puts(0, 2, "this hardware.");
708 break;
709 default:
710 rb->lcd_puts(0, 1, "Check failed.");
711 break;
714 if (rc == eOK)
716 rb->lcd_puts(0, 6, KEYNAME2 " to program");
717 rb->lcd_puts(0, 7, "other key to exit");
719 else
720 { /* error occured */
721 rb->lcd_puts(0, 6, "Any key to exit");
724 rb->lcd_update();
726 button = WaitForButton();
727 if (button != KEY2 || rc != eOK)
729 return;
732 rb->lcd_clear_display();
733 rb->lcd_puts(0, 0, "Program all Flash?");
734 rb->lcd_puts(0, 1, "Are you sure?");
735 rb->lcd_puts(0, 2, "If it goes wrong,");
736 rb->lcd_puts(0, 3, "it kills your box!");
737 rb->lcd_puts(0, 4, "See documentation.");
739 rb->lcd_puts(0, 6, KEYNAME3 " to proceed");
740 rb->lcd_puts(0, 7, "other key to exit");
741 rb->lcd_update();
743 button = WaitForButton();
744 if (button != KEY3)
746 return;
749 rb->lcd_clear_display();
750 rb->lcd_puts(0, 0, "Programming...");
751 rb->lcd_update();
753 rc = ProgramFirmwareFile(filename, FlashInfo.size);
754 if (rc)
755 { /* errors */
756 rb->lcd_clear_display();
757 rb->lcd_puts(0, 0, "Panic:");
758 rb->lcd_puts(0, 1, "Programming fail!");
759 rb->lcd_putsf(0, 2, "%d errors", rc);
760 rb->lcd_update();
761 button = WaitForButton();
764 rb->lcd_clear_display();
765 rb->lcd_puts(0, 0, "Verifying...");
766 rb->lcd_update();
768 rc = VerifyFirmwareFile(filename);
770 rb->lcd_clear_display();
771 if (rc == 0)
773 rb->lcd_puts(0, 0, "Verify OK.");
775 else
777 rb->lcd_puts(0, 0, "Panic:");
778 rb->lcd_puts(0, 1, "Verify fail!");
779 rb->lcd_putsf(0, 2, "%d errors", rc);
781 rb->lcd_puts(0, 7, "Any key to exit");
782 rb->lcd_update();
784 button = WaitForButton();
787 #else /* HAVE_LCD_BITMAP */
788 /* Player implementation */
790 /* helper for DoUserDialog() */
791 void ShowFlashInfo(tFlashInfo* pInfo)
793 char buf[32];
795 if (!pInfo->manufacturer)
797 rb->lcd_puts_scroll(0, 0, "Flash: M=? D=?");
798 rb->lcd_puts_scroll(0, 1, "Impossible to program");
799 rb->lcd_update();
800 WaitForButton();
802 else
804 rb->snprintf(buf, sizeof(buf), "Flash: M=%02x D=%02x",
805 pInfo->manufacturer, pInfo->id);
806 rb->lcd_puts_scroll(0, 0, buf);
808 if (pInfo->size)
810 rb->snprintf(buf, sizeof(buf), "Size: %d KB", pInfo->size / 1024);
811 rb->lcd_puts_scroll(0, 1, buf);
812 rb->lcd_update();
814 else
816 rb->lcd_puts_scroll(0, 1, "Unsupported chip");
817 rb->lcd_update();
818 WaitForButton();
824 void DoUserDialog(char* filename)
826 tFlashInfo FlashInfo;
827 char buf[32];
828 char default_filename[32];
829 int button;
830 int rc; /* generic return code */
831 size_t memleft;
832 tCheckROM result;
833 bool is_romless;
835 /* this can only work if Rockbox runs in DRAM, not flash ROM */
836 if ((UINT8*)rb >= FB && (UINT8*)rb < FB + 4096*1024) /* 4 MB max */
837 { /* we're running from flash */
838 rb->splash(HZ*3, "Not from ROM");
839 return; /* exit */
842 /* test if the user is running the correct plugin for this box */
843 if (!CheckPlatform(PLATFORM_ID, *(UINT16*)(FB + VERSION_ADR)))
845 rb->splash(HZ*3, "Wrong version");
846 return; /* exit */
849 /* refuse to work if the power may fail meanwhile */
850 if (!rb->battery_level_safe())
852 rb->splash(HZ*3, "Batt. too low!");
853 return; /* exit */
856 /* check boot ROM */
857 result = CheckBootROM();
858 if (result == eUnknown)
859 { /* no support for any other yet */
860 rb->splash(HZ*3, "Wrong boot ROM");
861 return; /* exit */
863 is_romless = (result == eROMless);
865 /* compose filename if none given */
866 if (filename == NULL)
868 rb->snprintf(
869 default_filename,
870 sizeof(default_filename),
871 "/firmware_%s%s.bin",
872 FILE_TYPE,
873 is_romless ? "_norom" : "");
874 filename = default_filename;
877 /* "allocate" memory */
878 sector = rb->plugin_get_buffer(&memleft);
879 if (memleft < SEC_SIZE) /* need buffer for a flash sector */
881 rb->splash(HZ*3, "Out of memory");
882 return; /* exit */
885 rc = GetFlashInfo(&FlashInfo);
886 ShowFlashInfo(&FlashInfo);
888 if (FlashInfo.size == 0) /* no valid chip */
890 return; /* exit */
893 rb->lcd_puts_scroll(0, 0, filename);
894 rb->lcd_puts_scroll(0, 1, "[Menu] to check");
895 rb->lcd_update();
897 button = WaitForButton();
898 if (button != BUTTON_MENU)
900 return;
903 rb->lcd_clear_display();
904 rb->lcd_puts(0, 0, "Checking...");
905 rb->lcd_update();
907 rc = CheckFirmwareFile(filename, FlashInfo.size, is_romless);
908 rb->lcd_puts(0, 0, "Checked:");
909 switch (rc)
911 case eOK:
912 rb->lcd_puts(0, 1, "File OK.");
913 break;
914 case eFileNotFound:
915 rb->lcd_puts_scroll(0, 0, "File not found:");
916 rb->lcd_puts_scroll(0, 1, filename);
917 break;
918 case eTooBig:
919 rb->lcd_puts_scroll(0, 0, "File too big,");
920 rb->lcd_puts_scroll(0, 1, "larger than chip.");
921 break;
922 case eTooSmall:
923 rb->lcd_puts_scroll(0, 0, "File too small.");
924 rb->lcd_puts_scroll(0, 1, "Incomplete?");
925 break;
926 case eReadErr:
927 rb->lcd_puts_scroll(0, 0, "Read error.");
928 break;
929 case eBadContent:
930 rb->lcd_puts_scroll(0, 0, "File invalid.");
931 rb->lcd_puts_scroll(0, 1, "Sanity check failed.");
932 break;
933 case eCrcErr:
934 rb->lcd_puts_scroll(0, 0, "File invalid.");
935 rb->lcd_puts_scroll(0, 1, "CRC check failed.");
936 break;
937 case eBadPlatform:
938 rb->lcd_puts_scroll(0, 0, "Wrong file for");
939 rb->lcd_puts_scroll(0, 1, "this hardware.");
940 break;
941 default:
942 rb->lcd_puts_scroll(0, 0, "Check failed.");
943 break;
945 rb->lcd_update();
947 rb->sleep(HZ*3);
949 if (rc == eOK)
951 rb->lcd_puts_scroll(0, 0, "[On] to program,");
952 rb->lcd_puts_scroll(0, 1, "other key to exit.");
953 rb->lcd_update();
955 else
956 { /* error occured */
957 return;
960 button = WaitForButton();
962 if (button != BUTTON_ON)
964 return;
967 rb->lcd_clear_display();
968 rb->lcd_puts_scroll(0, 0, "Are you sure?");
969 rb->lcd_puts_scroll(0, 1, "[+] to proceed.");
970 rb->lcd_update();
972 button = WaitForButton();
974 if (button != BUTTON_RIGHT)
976 return;
979 rb->lcd_clear_display();
980 rb->lcd_puts_scroll(0, 0, "Programming...");
981 rb->lcd_update();
983 rc = ProgramFirmwareFile(filename, FlashInfo.size);
985 if (rc)
986 { /* errors */
987 rb->lcd_clear_display();
988 rb->lcd_puts_scroll(0, 0, "Programming failed!");
989 rb->snprintf(buf, sizeof(buf), "%d errors", rc);
990 rb->lcd_puts_scroll(0, 1, buf);
991 rb->lcd_update();
992 WaitForButton();
995 rb->lcd_clear_display();
996 rb->lcd_puts_scroll(0, 0, "Verifying...");
997 rb->lcd_update();
999 rc = VerifyFirmwareFile(filename);
1001 rb->lcd_clear_display();
1003 if (rc == 0)
1005 rb->lcd_puts_scroll(0, 0, "Verify OK.");
1007 else
1009 rb->snprintf(buf, sizeof(buf), "Verify failed! %d errors", rc);
1010 rb->lcd_puts_scroll(0, 0, buf);
1013 rb->lcd_puts_scroll(0, 1, "Press any key to exit.");
1014 rb->lcd_update();
1015 WaitForButton();
1018 #endif /* not HAVE_LCD_BITMAP */
1021 /***************** Plugin Entry Point *****************/
1023 enum plugin_status plugin_start(const void* parameter)
1025 int oldmode;
1027 /* now go ahead and have fun! */
1028 oldmode = rb->system_memory_guard(MEMGUARD_NONE); /*disable memory guard */
1029 DoUserDialog((char*) parameter);
1030 rb->system_memory_guard(oldmode); /* re-enable memory guard */
1032 return PLUGIN_OK;