fix FS#8701 - metronome doesnt change back to ui font after drawing
[Rockbox.git] / apps / plugins / firmware_flash.c
blobb841be91d24ed9e4250b9fa4d94b16a89caa57cc
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 * All files in this archive are subject to the GNU General Public License.
16 * See the file COPYING in the source tree root for full license agreement.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
22 #include "plugin.h"
24 #ifndef SIMULATOR /* only for target */
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 #undef PLATFORM_ID /* this platform is not (yet) flashable */
78 #endif
80 #ifdef PLATFORM_ID
82 PLUGIN_HEADER
84 #if CONFIG_KEYPAD == ONDIO_PAD /* limited keypad */
85 #define KEY1 BUTTON_LEFT
86 #define KEY2 BUTTON_UP
87 #define KEY3 BUTTON_RIGHT
88 #define KEYNAME1 "[Left]"
89 #define KEYNAME2 "[Up]"
90 #define KEYNAME3 "[Right]"
91 #else /* recorder keypad */
92 #define KEY1 BUTTON_F1
93 #define KEY2 BUTTON_F2
94 #define KEY3 BUTTON_F3
95 #define KEYNAME1 "[F1]"
96 #define KEYNAME2 "[F2]"
97 #define KEYNAME3 "[F3]"
98 #endif
100 /* result of the CheckFirmwareFile() function */
101 typedef enum
103 eOK = 0,
104 eFileNotFound, /* errors from here on */
105 eTooBig,
106 eTooSmall,
107 eReadErr,
108 eBadContent,
109 eCrcErr,
110 eBadPlatform,
111 } tCheckResult;
113 /* result of the CheckBootROM() function */
114 typedef enum
116 eBootROM, /* the supported boot ROM(s) */
117 eUnknown, /* unknown boot ROM */
118 eROMless, /* flash mapped to zero */
119 } tCheckROM;
121 typedef struct
123 UINT8 manufacturer;
124 UINT8 id;
125 int size;
126 char name[32];
127 } tFlashInfo;
129 static struct plugin_api* rb; /* here is a global api struct pointer */
131 #define MASK_ADR 0xFC /* position of hardware mask value in Flash */
132 #define VERSION_ADR 0xFE /* position of firmware version value in Flash */
133 #define PLATFORM_ADR 0xFB /* position of my platform ID value in Flash */
134 #define SEC_SIZE 4096 /* size of one flash sector */
135 static UINT8* sector; /* better not place this on the stack... */
136 static volatile UINT8* FB = (UINT8*)0x02000000; /* Flash base address */
139 /***************** Flash Functions *****************/
142 /* read the manufacturer and device ID */
143 bool ReadID(volatile UINT8* pBase, UINT8* pManufacturerID, UINT8* pDeviceID)
145 UINT8 not_manu, not_id; /* read values before switching to ID mode */
146 UINT8 manu, id; /* read values when in ID mode */
148 pBase = (UINT8*)((UINT32)pBase & 0xFFF80000); /* down to 512k align */
150 /* read the normal content */
151 not_manu = pBase[0]; /* should be 'A' (0x41) and 'R' (0x52) */
152 not_id = pBase[1]; /* from the "ARCH" marker */
154 pBase[0x5555] = 0xAA; /* enter command mode */
155 pBase[0x2AAA] = 0x55;
156 pBase[0x5555] = 0x90; /* ID command */
157 rb->sleep(HZ/50); /* Atmel wants 20ms pause here */
159 manu = pBase[0];
160 id = pBase[1];
162 pBase[0] = 0xF0; /* reset flash (back to normal read mode) */
163 rb->sleep(HZ/50); /* Atmel wants 20ms pause here */
165 /* I assume success if the obtained values are different from
166 the normal flash content. This is not perfectly bulletproof, they
167 could theoretically be the same by chance, causing us to fail. */
168 if (not_manu != manu || not_id != id) /* a value has changed */
170 *pManufacturerID = manu; /* return the results */
171 *pDeviceID = id;
172 return true; /* success */
174 return false; /* fail */
178 /* erase the sector which contains the given address */
179 bool EraseSector(volatile UINT8* pAddr)
181 #ifdef DUMMY
182 (void)pAddr; /* prevents warning */
183 return true;
184 #else
185 volatile UINT8* pBase = (UINT8*)((UINT32)pAddr & 0xFFF80000); /* round down to 512k align */
186 unsigned timeout = 43000; /* the timeout loop should be no less than 25ms */
188 pBase[0x5555] = 0xAA; /* enter command mode */
189 pBase[0x2AAA] = 0x55;
190 pBase[0x5555] = 0x80; /* erase command */
191 pBase[0x5555] = 0xAA; /* enter command mode */
192 pBase[0x2AAA] = 0x55;
193 *pAddr = 0x30; /* erase the sector */
195 /* I counted 7 instructions for this loop -> min. 0.58 us per round */
196 /* Plus memory waitstates it will be much more, gives margin */
197 while (*pAddr != 0xFF && --timeout); /* poll for erased */
199 return (timeout != 0);
200 #endif
204 /* address must be in an erased location */
205 inline bool ProgramByte(volatile UINT8* pAddr, UINT8 data)
207 #ifdef DUMMY
208 (void)pAddr; /* prevents warnings */
209 (void)data;
210 return true;
211 #else
212 unsigned timeout = 35; /* the timeout loop should be no less than 20us */
214 if (~*pAddr & data) /* just a safety feature, not really necessary */
215 return false; /* can't set any bit from 0 to 1 */
217 FB[0x5555] = 0xAA; /* enter command mode */
218 FB[0x2AAA] = 0x55;
219 FB[0x5555] = 0xA0; /* byte program command */
221 *pAddr = data;
223 /* I counted 7 instructions for this loop -> min. 0.58 us per round */
224 /* Plus memory waitstates it will be much more, gives margin */
225 while (*pAddr != data && --timeout); /* poll for programmed */
227 return (timeout != 0);
228 #endif
232 /* this returns true if supported and fills the info struct */
233 bool GetFlashInfo(tFlashInfo* pInfo)
235 rb->memset(pInfo, 0, sizeof(tFlashInfo));
237 if (!ReadID(FB, &pInfo->manufacturer, &pInfo->id))
238 return false;
240 if (pInfo->manufacturer == 0xBF) /* SST */
242 if (pInfo->id == 0xD6)
244 pInfo->size = 256* 1024; /* 256k */
245 rb->strcpy(pInfo->name, "SST39VF020");
246 return true;
248 else if (pInfo->id == 0xD7)
250 pInfo->size = 512* 1024; /* 512k */
251 rb->strcpy(pInfo->name, "SST39VF040");
252 return true;
254 else
255 return false;
257 return false;
261 /*********** Utility Functions ************/
264 /* Tool function to calculate a CRC32 across some buffer */
265 /* third argument is either 0xFFFFFFFF to start or value from last piece */
266 unsigned crc_32(unsigned char* buf, unsigned len, unsigned crc32)
268 /* CCITT standard polynomial 0x04C11DB7 */
269 static const unsigned crc32_lookup[16] =
270 { /* lookup table for 4 bits at a time is affordable */
271 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9,
272 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,
273 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61,
274 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD
277 unsigned char byte;
278 unsigned t;
280 while (len--)
282 byte = *buf++; /* get one byte of data */
284 /* upper nibble of our data */
285 t = crc32 >> 28; /* extract the 4 most significant bits */
286 t ^= byte >> 4; /* XOR in 4 bits of data into the extracted bits */
287 crc32 <<= 4; /* shift the CRC register left 4 bits */
288 crc32 ^= crc32_lookup[t]; /* do the table lookup and XOR the result */
290 /* lower nibble of our data */
291 t = crc32 >> 28; /* extract the 4 most significant bits */
292 t ^= byte & 0x0F; /* XOR in 4 bits of data into the extracted bits */
293 crc32 <<= 4; /* shift the CRC register left 4 bits */
294 crc32 ^= crc32_lookup[t]; /* do the table lookup and XOR the result */
297 return crc32;
301 /*********** Firmware File Functions + helpers ************/
303 /* test if the version number is consistent with the platform */
304 bool CheckPlatform(int platform_id, UINT16 version)
306 if (version == 200)
307 { /* for my very first firmwares, I foolishly changed it to 200 */
308 return (platform_id == ID_RECORDER || platform_id == ID_FM);
310 else if (version == 123)
311 { /* it can be a FM or V2 recorder */
312 return (platform_id == ID_FM || platform_id == ID_REC_V2);
314 else if (version == 132)
315 { /* newer Ondio, and seen on a V2 recorder */
316 return (platform_id == ID_ONDIO_SP || platform_id == ID_ONDIO_FM
317 || platform_id == ID_REC_V2);
319 else if (version == 104)
320 { /* classic Ondio128 */
321 return (platform_id == ID_ONDIO_FM);
323 else if (version >= 115 && version <= 129)
324 { /* the range of Recorders seen so far */
325 return (platform_id == ID_RECORDER);
327 else if (version == 0 || (version >= 300 && version <= 508))
328 { /* for very old players, I've seen zero */
329 return (platform_id == ID_PLAYER);
332 return false; /* unknown */
336 tCheckResult CheckFirmwareFile(char* filename, int chipsize, bool is_romless)
338 int i;
339 int fd;
340 int fileleft; /* size info, how many left for reading */
341 int fileread = 0; /* total size as read from the file */
342 int read_now; /* how many to read for this sector */
343 int got_now; /* how many gotten for this sector */
344 unsigned crc32 = 0xFFFFFFFF; /* CCITT init value */
345 unsigned file_crc; /* CRC value read from file */
346 bool has_crc;
348 fd = rb->open(filename, O_RDONLY);
349 if (fd < 0)
350 return eFileNotFound;
352 fileleft = rb->filesize(fd);
353 if (fileleft > chipsize)
355 rb->close(fd);
356 return eTooBig;
358 else if (fileleft < 20000) /* give it some reasonable lower limit */
360 rb->close(fd);
361 return eTooSmall;
364 if (fileleft == 256*1024)
365 { /* original dumped firmware file has no CRC nor platform ID */
366 has_crc = false;
368 else
370 has_crc = true;
371 fileleft -= sizeof(unsigned); /* exclude the last 4 bytes */
374 /* do some sanity checks */
376 got_now = rb->read(fd, sector, SEC_SIZE); /* read first sector */
377 fileread += got_now;
378 fileleft -= got_now;
379 if (got_now != SEC_SIZE)
381 rb->close(fd);
382 return eReadErr;
385 /* version number in file plausible with this hardware? */
386 if (!CheckPlatform(PLATFORM_ID, *(UINT16*)(sector + VERSION_ADR)))
388 rb->close(fd);
389 return eBadPlatform;
392 if (has_crc)
394 crc32 = crc_32(sector, SEC_SIZE, crc32); /* checksum */
396 /* in addition to the CRC, my files also have a platform ID */
397 if (sector[PLATFORM_ADR] != PLATFORM_ID) /* for our hardware? */
399 rb->close(fd);
400 return eBadPlatform;
404 if (is_romless)
405 { /* in this case, there is not much we can check */
406 if (*(UINT32*)sector != 0x00000200) /* reset vector */
408 rb->close(fd);
409 return eBadContent;
412 else
414 /* compare some bytes which have to be identical */
415 if (*(UINT32*)sector != 0x41524348) /* "ARCH" */
417 rb->close(fd);
418 return eBadContent;
421 for (i = 0x30; i<MASK_ADR-2; i++) /* leave two bytes for me */
423 if (sector[i] != FB[i])
425 rb->close(fd);
426 return eBadContent;
431 /* check if we can read the whole file, and do checksum */
434 read_now = MIN(SEC_SIZE, fileleft);
435 got_now = rb->read(fd, sector, read_now);
436 fileread += got_now;
437 fileleft -= got_now;
439 if (read_now != got_now)
441 rb->close(fd);
442 return eReadErr;
445 if (has_crc)
447 crc32 = crc_32(sector, got_now, crc32); /* checksum */
449 } while (fileleft);
451 if (has_crc)
453 got_now = rb->read(fd, &file_crc, sizeof(file_crc));
454 if (got_now != sizeof(file_crc))
456 rb->close(fd);
457 return eReadErr;
461 /* must be EOF now */
462 got_now = rb->read(fd, sector, SEC_SIZE);
463 rb->close(fd);
464 if (got_now != 0)
465 return eReadErr;
467 if (has_crc && file_crc != crc32)
468 return eCrcErr;
470 return eOK;
474 /* returns the # of failures, 0 on success */
475 unsigned ProgramFirmwareFile(char* filename, int chipsize)
477 int i, j;
478 int fd;
479 int read = SEC_SIZE; /* how many for this sector */
480 UINT16 keep = *(UINT16*)(FB + KEEP); /* we must keep this! */
481 unsigned failures = 0;
483 fd = rb->open(filename, O_RDONLY);
484 if (fd < 0)
485 return false;
487 for (i=0; i<chipsize; i+=SEC_SIZE)
489 if (!EraseSector(FB + i))
491 /* nothing we can do, let the programming count the errors */
494 if (read == SEC_SIZE) /* not EOF yet */
496 read = rb->read(fd, sector, SEC_SIZE);
497 if (i==0)
498 { /* put original value back in */
499 *(UINT16*)(sector + KEEP) = keep;
502 for (j=0; j<read; j++)
504 if (!ProgramByte(FB + i + j, sector[j]))
506 failures++;
512 rb->close(fd);
514 return failures;
518 /* returns the # of failures, 0 on success */
519 unsigned VerifyFirmwareFile(char* filename)
521 int i=0, j;
522 int fd;
523 int read = SEC_SIZE; /* how many for this sector */
524 unsigned failures = 0;
526 fd = rb->open(filename, O_RDONLY);
527 if (fd < 0)
528 return false;
532 read = rb->read(fd, sector, SEC_SIZE);
534 for (j=0; j<read; j++)
536 /* position of keep value is no error */
537 if (FB[i] != sector[j] && i != KEEP && i != (KEEP+1))
539 failures++;
541 i++;
544 while (read == SEC_SIZE);
546 rb->close(fd);
548 return failures;
552 /***************** Support Functions *****************/
554 /* check if we have "normal" boot ROM or flash mirrored to zero */
555 tCheckROM CheckBootROM(void)
557 unsigned boot_crc;
558 unsigned* pFlash = (unsigned*)FB;
559 unsigned* pRom = (unsigned*)0x0;
560 unsigned i;
562 boot_crc = crc_32((unsigned char*)0x0, 64*1024, 0xFFFFFFFF);
563 if (boot_crc == 0x56DBA4EE /* the known boot ROM */
564 #if PLATFORM_ID == ID_PLAYER
565 /* alternative boot ROM found in one single player so far */
566 || boot_crc == 0x358099E8
567 #endif
569 return eBootROM;
571 /* check if ROM is a flash mirror */
572 for (i=0; i<256*1024/sizeof(unsigned); i++)
574 if (*pRom++ != *pFlash++)
575 { /* difference means no mirror */
576 return eUnknown;
580 return eROMless;
584 /***************** User Interface Functions *****************/
586 int WaitForButton(void)
588 int button;
592 button = rb->button_get(true);
593 } while (button & BUTTON_REL);
595 return button;
598 #ifdef HAVE_LCD_BITMAP
599 /* Recorder implementation */
601 /* helper for DoUserDialog() */
602 void ShowFlashInfo(tFlashInfo* pInfo)
604 char buf[32];
606 if (!pInfo->manufacturer)
608 rb->lcd_puts(0, 0, "Flash: M=?? D=??");
609 rb->lcd_puts(0, 1, "Impossible to program");
611 else
613 rb->snprintf(buf, sizeof(buf), "Flash: M=%02x D=%02x",
614 pInfo->manufacturer, pInfo->id);
615 rb->lcd_puts(0, 0, buf);
618 if (pInfo->size)
620 rb->lcd_puts(0, 1, pInfo->name);
621 rb->snprintf(buf, sizeof(buf), "Size: %d KB", pInfo->size / 1024);
622 rb->lcd_puts(0, 2, buf);
624 else
626 rb->lcd_puts(0, 1, "Unsupported chip");
631 rb->lcd_update();
635 /* Kind of our main function, defines the application flow. */
636 void DoUserDialog(char* filename)
638 tFlashInfo FlashInfo;
639 char buf[32];
640 char default_filename[32];
641 int button;
642 int rc; /* generic return code */
643 ssize_t memleft;
644 tCheckROM result;
645 bool is_romless;
647 /* this can only work if Rockbox runs in DRAM, not flash ROM */
648 if ((UINT8*)rb >= FB && (UINT8*)rb < FB + 4096*1024) /* 4 MB max */
649 { /* we're running from flash */
650 rb->splash(HZ*3, "Not from ROM");
651 return; /* exit */
654 /* test if the user is running the correct plugin for this box */
655 if (!CheckPlatform(PLATFORM_ID, *(UINT16*)(FB + VERSION_ADR)))
657 rb->splash(HZ*3, "Wrong plugin");
658 return; /* exit */
661 /* refuse to work if the power may fail meanwhile */
662 if (!rb->battery_level_safe())
664 rb->splash(HZ*3, "Battery too low!");
665 return; /* exit */
668 /* check boot ROM */
669 result = CheckBootROM();
670 if (result == eUnknown)
671 { /* no support for any other yet */
672 rb->splash(HZ*3, "Wrong boot ROM");
673 return; /* exit */
675 is_romless = (result == eROMless);
677 /* compose filename if none given */
678 if (filename == NULL)
680 rb->snprintf(
681 default_filename,
682 sizeof(default_filename),
683 "/firmware_%s%s.bin",
684 FILE_TYPE,
685 is_romless ? "_norom" : "");
686 filename = default_filename;
689 /* "allocate" memory */
690 sector = rb->plugin_get_buffer((size_t *)&memleft);
691 if (memleft < SEC_SIZE) /* need buffer for a flash sector */
693 rb->splash(HZ*3, "Out of memory");
694 return; /* exit */
697 rb->lcd_setfont(FONT_SYSFIXED);
699 rc = GetFlashInfo(&FlashInfo);
700 ShowFlashInfo(&FlashInfo);
701 if (FlashInfo.size == 0) /* no valid chip */
703 rb->splash(HZ*3, "Sorry!");
704 return; /* exit */
707 rb->lcd_puts(0, 3, "using file:");
708 rb->lcd_puts_scroll(0, 4, filename);
709 rb->lcd_puts(0, 6, KEYNAME1 " to check file");
710 rb->lcd_puts(0, 7, "other key to exit");
711 rb->lcd_update();
713 button = WaitForButton();
714 if (button != KEY1)
716 return;
719 rb->lcd_clear_display();
720 rb->lcd_puts(0, 0, "checking...");
721 rb->lcd_update();
723 rc = CheckFirmwareFile(filename, FlashInfo.size, is_romless);
724 rb->lcd_puts(0, 0, "checked:");
725 switch (rc)
727 case eOK:
728 rb->lcd_puts(0, 1, "File OK.");
729 break;
730 case eFileNotFound:
731 rb->lcd_puts(0, 1, "File not found.");
732 rb->lcd_puts(0, 2, "Put this in root:");
733 rb->lcd_puts_scroll(0, 4, filename);
734 break;
735 case eTooBig:
736 rb->lcd_puts(0, 1, "File too big,");
737 rb->lcd_puts(0, 2, "larger than chip.");
738 break;
739 case eTooSmall:
740 rb->lcd_puts(0, 1, "File too small.");
741 rb->lcd_puts(0, 2, "Incomplete?");
742 break;
743 case eReadErr:
744 rb->lcd_puts(0, 1, "Read error.");
745 break;
746 case eBadContent:
747 rb->lcd_puts(0, 1, "File invalid.");
748 rb->lcd_puts(0, 2, "Sanity check fail.");
749 break;
750 case eCrcErr:
751 rb->lcd_puts(0, 1, "File invalid.");
752 rb->lcd_puts(0, 2, "CRC check failed,");
753 rb->lcd_puts(0, 3, "checksum mismatch.");
754 break;
755 case eBadPlatform:
756 rb->lcd_puts(0, 1, "Wrong file for");
757 rb->lcd_puts(0, 2, "this hardware.");
758 break;
759 default:
760 rb->lcd_puts(0, 1, "Check failed.");
761 break;
764 if (rc == eOK)
766 rb->lcd_puts(0, 6, KEYNAME2 " to program");
767 rb->lcd_puts(0, 7, "other key to exit");
769 else
770 { /* error occured */
771 rb->lcd_puts(0, 6, "Any key to exit");
774 rb->lcd_update();
776 button = WaitForButton();
777 if (button != KEY2 || rc != eOK)
779 return;
782 rb->lcd_clear_display();
783 rb->lcd_puts(0, 0, "Program all Flash?");
784 rb->lcd_puts(0, 1, "Are you sure?");
785 rb->lcd_puts(0, 2, "If it goes wrong,");
786 rb->lcd_puts(0, 3, "it kills your box!");
787 rb->lcd_puts(0, 4, "See documentation.");
789 rb->lcd_puts(0, 6, KEYNAME3 " to proceed");
790 rb->lcd_puts(0, 7, "other key to exit");
791 rb->lcd_update();
793 button = WaitForButton();
794 if (button != KEY3)
796 return;
799 rb->lcd_clear_display();
800 rb->lcd_puts(0, 0, "Programming...");
801 rb->lcd_update();
803 rc = ProgramFirmwareFile(filename, FlashInfo.size);
804 if (rc)
805 { /* errors */
806 rb->lcd_clear_display();
807 rb->lcd_puts(0, 0, "Panic:");
808 rb->lcd_puts(0, 1, "Programming fail!");
809 rb->snprintf(buf, sizeof(buf), "%d errors", rc);
810 rb->lcd_puts(0, 2, buf);
811 rb->lcd_update();
812 button = WaitForButton();
815 rb->lcd_clear_display();
816 rb->lcd_puts(0, 0, "Verifying...");
817 rb->lcd_update();
819 rc = VerifyFirmwareFile(filename);
821 rb->lcd_clear_display();
822 if (rc == 0)
824 rb->lcd_puts(0, 0, "Verify OK.");
826 else
828 rb->lcd_puts(0, 0, "Panic:");
829 rb->lcd_puts(0, 1, "Verify fail!");
830 rb->snprintf(buf, sizeof(buf), "%d errors", rc);
831 rb->lcd_puts(0, 2, buf);
833 rb->lcd_puts(0, 7, "Any key to exit");
834 rb->lcd_update();
836 button = WaitForButton();
839 #else /* HAVE_LCD_BITMAP */
840 /* Player implementation */
842 /* helper for DoUserDialog() */
843 void ShowFlashInfo(tFlashInfo* pInfo)
845 char buf[32];
847 if (!pInfo->manufacturer)
849 rb->lcd_puts_scroll(0, 0, "Flash: M=? D=?");
850 rb->lcd_puts_scroll(0, 1, "Impossible to program");
851 rb->lcd_update();
852 WaitForButton();
854 else
856 rb->snprintf(buf, sizeof(buf), "Flash: M=%02x D=%02x",
857 pInfo->manufacturer, pInfo->id);
858 rb->lcd_puts_scroll(0, 0, buf);
860 if (pInfo->size)
862 rb->snprintf(buf, sizeof(buf), "Size: %d KB", pInfo->size / 1024);
863 rb->lcd_puts_scroll(0, 1, buf);
864 rb->lcd_update();
866 else
868 rb->lcd_puts_scroll(0, 1, "Unsupported chip");
869 rb->lcd_update();
870 WaitForButton();
876 void DoUserDialog(char* filename)
878 tFlashInfo FlashInfo;
879 char buf[32];
880 char default_filename[32];
881 int button;
882 int rc; /* generic return code */
883 ssize_t memleft;
884 tCheckROM result;
885 bool is_romless;
887 /* this can only work if Rockbox runs in DRAM, not flash ROM */
888 if ((UINT8*)rb >= FB && (UINT8*)rb < FB + 4096*1024) /* 4 MB max */
889 { /* we're running from flash */
890 rb->splash(HZ*3, "Not from ROM");
891 return; /* exit */
894 /* test if the user is running the correct plugin for this box */
895 if (!CheckPlatform(PLATFORM_ID, *(UINT16*)(FB + VERSION_ADR)))
897 rb->splash(HZ*3, "Wrong version");
898 return; /* exit */
901 /* refuse to work if the power may fail meanwhile */
902 if (!rb->battery_level_safe())
904 rb->splash(HZ*3, "Batt. too low!");
905 return; /* exit */
908 /* check boot ROM */
909 result = CheckBootROM();
910 if (result == eUnknown)
911 { /* no support for any other yet */
912 rb->splash(HZ*3, "Wrong boot ROM");
913 return; /* exit */
915 is_romless = (result == eROMless);
917 /* compose filename if none given */
918 if (filename == NULL)
920 rb->snprintf(
921 default_filename,
922 sizeof(default_filename),
923 "/firmware_%s%s.bin",
924 FILE_TYPE,
925 is_romless ? "_norom" : "");
926 filename = default_filename;
929 /* "allocate" memory */
930 sector = rb->plugin_get_buffer((size_t *)&memleft);
931 if (memleft < SEC_SIZE) /* need buffer for a flash sector */
933 rb->splash(HZ*3, "Out of memory");
934 return; /* exit */
937 rc = GetFlashInfo(&FlashInfo);
938 ShowFlashInfo(&FlashInfo);
940 if (FlashInfo.size == 0) /* no valid chip */
942 return; /* exit */
945 rb->lcd_puts_scroll(0, 0, filename);
946 rb->lcd_puts_scroll(0, 1, "[Menu] to check");
947 rb->lcd_update();
949 button = WaitForButton();
950 if (button != BUTTON_MENU)
952 return;
955 rb->lcd_clear_display();
956 rb->lcd_puts(0, 0, "Checking...");
957 rb->lcd_update();
959 rc = CheckFirmwareFile(filename, FlashInfo.size, is_romless);
960 rb->lcd_puts(0, 0, "Checked:");
961 switch (rc)
963 case eOK:
964 rb->lcd_puts(0, 1, "File OK.");
965 break;
966 case eFileNotFound:
967 rb->lcd_puts_scroll(0, 0, "File not found:");
968 rb->lcd_puts_scroll(0, 1, filename);
969 break;
970 case eTooBig:
971 rb->lcd_puts_scroll(0, 0, "File too big,");
972 rb->lcd_puts_scroll(0, 1, "larger than chip.");
973 break;
974 case eTooSmall:
975 rb->lcd_puts_scroll(0, 0, "File too small.");
976 rb->lcd_puts_scroll(0, 1, "Incomplete?");
977 break;
978 case eReadErr:
979 rb->lcd_puts_scroll(0, 0, "Read error.");
980 break;
981 case eBadContent:
982 rb->lcd_puts_scroll(0, 0, "File invalid.");
983 rb->lcd_puts_scroll(0, 1, "Sanity check failed.");
984 break;
985 case eCrcErr:
986 rb->lcd_puts_scroll(0, 0, "File invalid.");
987 rb->lcd_puts_scroll(0, 1, "CRC check failed.");
988 break;
989 case eBadPlatform:
990 rb->lcd_puts_scroll(0, 0, "Wrong file for");
991 rb->lcd_puts_scroll(0, 1, "this hardware.");
992 break;
993 default:
994 rb->lcd_puts_scroll(0, 0, "Check failed.");
995 break;
997 rb->lcd_update();
999 rb->sleep(HZ*3);
1001 if (rc == eOK)
1003 rb->lcd_puts_scroll(0, 0, "[On] to program,");
1004 rb->lcd_puts_scroll(0, 1, "other key to exit.");
1005 rb->lcd_update();
1007 else
1008 { /* error occured */
1009 return;
1012 button = WaitForButton();
1014 if (button != BUTTON_ON)
1016 return;
1019 rb->lcd_clear_display();
1020 rb->lcd_puts_scroll(0, 0, "Are you sure?");
1021 rb->lcd_puts_scroll(0, 1, "[+] to proceed.");
1022 rb->lcd_update();
1024 button = WaitForButton();
1026 if (button != BUTTON_RIGHT)
1028 return;
1031 rb->lcd_clear_display();
1032 rb->lcd_puts_scroll(0, 0, "Programming...");
1033 rb->lcd_update();
1035 rc = ProgramFirmwareFile(filename, FlashInfo.size);
1037 if (rc)
1038 { /* errors */
1039 rb->lcd_clear_display();
1040 rb->lcd_puts_scroll(0, 0, "Programming failed!");
1041 rb->snprintf(buf, sizeof(buf), "%d errors", rc);
1042 rb->lcd_puts_scroll(0, 1, buf);
1043 rb->lcd_update();
1044 WaitForButton();
1047 rb->lcd_clear_display();
1048 rb->lcd_puts_scroll(0, 0, "Verifying...");
1049 rb->lcd_update();
1051 rc = VerifyFirmwareFile(filename);
1053 rb->lcd_clear_display();
1055 if (rc == 0)
1057 rb->lcd_puts_scroll(0, 0, "Verify OK.");
1059 else
1061 rb->snprintf(buf, sizeof(buf), "Verify failed! %d errors", rc);
1062 rb->lcd_puts_scroll(0, 0, buf);
1065 rb->lcd_puts_scroll(0, 1, "Press any key to exit.");
1066 rb->lcd_update();
1067 WaitForButton();
1070 #endif /* not HAVE_LCD_BITMAP */
1073 /***************** Plugin Entry Point *****************/
1075 enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
1077 int oldmode;
1079 rb = api; /* copy to global api pointer */
1081 /* now go ahead and have fun! */
1082 oldmode = rb->system_memory_guard(MEMGUARD_NONE); /*disable memory guard */
1083 DoUserDialog((char*) parameter);
1084 rb->system_memory_guard(oldmode); /* re-enable memory guard */
1086 return PLUGIN_OK;
1089 #endif /* ifdef PLATFORM_ID */
1090 #endif /* #ifndef SIMULATOR */