Introduce __attribute__((unused)) (#defined to UNUSED_ATTR) to mark possibly unused...
[kugel-rb.git] / apps / plugins / firmware_flash.c
blobe8589cc76dd1ea01def768396b19e91324c95d02
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 #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 #define MASK_ADR 0xFC /* position of hardware mask value in Flash */
130 #define VERSION_ADR 0xFE /* position of firmware version value in Flash */
131 #define PLATFORM_ADR 0xFB /* position of my platform ID value in Flash */
132 #define SEC_SIZE 4096 /* size of one flash sector */
133 static UINT8* sector; /* better not place this on the stack... */
134 static volatile UINT8* FB = (UINT8*)0x02000000; /* Flash base address */
137 /***************** Flash Functions *****************/
140 /* read the manufacturer and device ID */
141 bool ReadID(volatile UINT8* pBase, UINT8* pManufacturerID, UINT8* pDeviceID)
143 UINT8 not_manu, not_id; /* read values before switching to ID mode */
144 UINT8 manu, id; /* read values when in ID mode */
146 pBase = (UINT8*)((UINT32)pBase & 0xFFF80000); /* down to 512k align */
148 /* read the normal content */
149 not_manu = pBase[0]; /* should be 'A' (0x41) and 'R' (0x52) */
150 not_id = pBase[1]; /* from the "ARCH" marker */
152 pBase[0x5555] = 0xAA; /* enter command mode */
153 pBase[0x2AAA] = 0x55;
154 pBase[0x5555] = 0x90; /* ID command */
155 rb->sleep(HZ/50); /* Atmel wants 20ms pause here */
157 manu = pBase[0];
158 id = pBase[1];
160 pBase[0] = 0xF0; /* reset flash (back to normal read mode) */
161 rb->sleep(HZ/50); /* Atmel wants 20ms pause here */
163 /* I assume success if the obtained values are different from
164 the normal flash content. This is not perfectly bulletproof, they
165 could theoretically be the same by chance, causing us to fail. */
166 if (not_manu != manu || not_id != id) /* a value has changed */
168 *pManufacturerID = manu; /* return the results */
169 *pDeviceID = id;
170 return true; /* success */
172 return false; /* fail */
176 /* erase the sector which contains the given address */
177 bool EraseSector(UNUSED_ATTR volatile UINT8* pAddr)
179 #ifdef DUMMY
180 return true;
181 #else
182 volatile UINT8* pBase = (UINT8*)((UINT32)pAddr & 0xFFF80000); /* round down to 512k align */
183 unsigned timeout = 43000; /* the timeout loop should be no less than 25ms */
185 pBase[0x5555] = 0xAA; /* enter command mode */
186 pBase[0x2AAA] = 0x55;
187 pBase[0x5555] = 0x80; /* erase command */
188 pBase[0x5555] = 0xAA; /* enter command mode */
189 pBase[0x2AAA] = 0x55;
190 *pAddr = 0x30; /* erase the sector */
192 /* I counted 7 instructions for this loop -> min. 0.58 us per round */
193 /* Plus memory waitstates it will be much more, gives margin */
194 while (*pAddr != 0xFF && --timeout); /* poll for erased */
196 return (timeout != 0);
197 #endif
201 /* address must be in an erased location */
202 inline bool ProgramByte(UNUSED_ATTR volatile UINT8* pAddr,
203 UNUSED_ATTR UINT8 data)
205 #ifdef DUMMY
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;
257 /*********** Utility Functions ************/
260 /* Tool function to calculate a CRC32 across some buffer */
261 /* third argument is either 0xFFFFFFFF to start or value from last piece */
262 unsigned crc_32(unsigned char* buf, unsigned len, unsigned crc32)
264 /* CCITT standard polynomial 0x04C11DB7 */
265 static const unsigned crc32_lookup[16] =
266 { /* lookup table for 4 bits at a time is affordable */
267 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9,
268 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,
269 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61,
270 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD
273 unsigned char byte;
274 unsigned t;
276 while (len--)
278 byte = *buf++; /* get one byte of data */
280 /* upper nibble of our data */
281 t = crc32 >> 28; /* extract the 4 most significant bits */
282 t ^= byte >> 4; /* XOR in 4 bits of data into the extracted bits */
283 crc32 <<= 4; /* shift the CRC register left 4 bits */
284 crc32 ^= crc32_lookup[t]; /* do the table lookup and XOR the result */
286 /* lower nibble of our data */
287 t = crc32 >> 28; /* extract the 4 most significant bits */
288 t ^= byte & 0x0F; /* XOR in 4 bits of data into the extracted bits */
289 crc32 <<= 4; /* shift the CRC register left 4 bits */
290 crc32 ^= crc32_lookup[t]; /* do the table lookup and XOR the result */
293 return crc32;
297 /*********** Firmware File Functions + helpers ************/
299 /* test if the version number is consistent with the platform */
300 bool CheckPlatform(int platform_id, UINT16 version)
302 if (version == 200)
303 { /* for my very first firmwares, I foolishly changed it to 200 */
304 return (platform_id == ID_RECORDER || platform_id == ID_FM);
306 else if (version == 123)
307 { /* it can be a FM or V2 recorder */
308 return (platform_id == ID_FM || platform_id == ID_REC_V2);
310 else if (version == 132)
311 { /* newer Ondio, and seen on a V2 recorder */
312 return (platform_id == ID_ONDIO_SP || platform_id == ID_ONDIO_FM
313 || platform_id == ID_REC_V2);
315 else if (version == 104)
316 { /* classic Ondio128 */
317 return (platform_id == ID_ONDIO_FM);
319 else if (version >= 115 && version <= 129)
320 { /* the range of Recorders seen so far */
321 return (platform_id == ID_RECORDER);
323 else if (version == 0 || (version >= 300 && version <= 508))
324 { /* for very old players, I've seen zero */
325 return (platform_id == ID_PLAYER);
328 return false; /* unknown */
332 tCheckResult CheckFirmwareFile(char* filename, int chipsize, bool is_romless)
334 int i;
335 int fd;
336 int fileleft; /* size info, how many left for reading */
337 int fileread = 0; /* total size as read from the file */
338 int read_now; /* how many to read for this sector */
339 int got_now; /* how many gotten for this sector */
340 unsigned crc32 = 0xFFFFFFFF; /* CCITT init value */
341 unsigned file_crc; /* CRC value read from file */
342 bool has_crc;
344 fd = rb->open(filename, O_RDONLY);
345 if (fd < 0)
346 return eFileNotFound;
348 fileleft = rb->filesize(fd);
349 if (fileleft > chipsize)
351 rb->close(fd);
352 return eTooBig;
354 else if (fileleft < 20000) /* give it some reasonable lower limit */
356 rb->close(fd);
357 return eTooSmall;
360 if (fileleft == 256*1024)
361 { /* original dumped firmware file has no CRC nor platform ID */
362 has_crc = false;
364 else
366 has_crc = true;
367 fileleft -= sizeof(unsigned); /* exclude the last 4 bytes */
370 /* do some sanity checks */
372 got_now = rb->read(fd, sector, SEC_SIZE); /* read first sector */
373 fileread += got_now;
374 fileleft -= got_now;
375 if (got_now != SEC_SIZE)
377 rb->close(fd);
378 return eReadErr;
381 /* version number in file plausible with this hardware? */
382 if (!CheckPlatform(PLATFORM_ID, *(UINT16*)(sector + VERSION_ADR)))
384 rb->close(fd);
385 return eBadPlatform;
388 if (has_crc)
390 crc32 = crc_32(sector, SEC_SIZE, crc32); /* checksum */
392 /* in addition to the CRC, my files also have a platform ID */
393 if (sector[PLATFORM_ADR] != PLATFORM_ID) /* for our hardware? */
395 rb->close(fd);
396 return eBadPlatform;
400 if (is_romless)
401 { /* in this case, there is not much we can check */
402 if (*(UINT32*)sector != 0x00000200) /* reset vector */
404 rb->close(fd);
405 return eBadContent;
408 else
410 /* compare some bytes which have to be identical */
411 if (*(UINT32*)sector != 0x41524348) /* "ARCH" */
413 rb->close(fd);
414 return eBadContent;
417 for (i = 0x30; i<MASK_ADR-2; i++) /* leave two bytes for me */
419 if (sector[i] != FB[i])
421 rb->close(fd);
422 return eBadContent;
427 /* check if we can read the whole file, and do checksum */
430 read_now = MIN(SEC_SIZE, fileleft);
431 got_now = rb->read(fd, sector, read_now);
432 fileread += got_now;
433 fileleft -= got_now;
435 if (read_now != got_now)
437 rb->close(fd);
438 return eReadErr;
441 if (has_crc)
443 crc32 = crc_32(sector, got_now, crc32); /* checksum */
445 } while (fileleft);
447 if (has_crc)
449 got_now = rb->read(fd, &file_crc, sizeof(file_crc));
450 if (got_now != sizeof(file_crc))
452 rb->close(fd);
453 return eReadErr;
457 /* must be EOF now */
458 got_now = rb->read(fd, sector, SEC_SIZE);
459 rb->close(fd);
460 if (got_now != 0)
461 return eReadErr;
463 if (has_crc && file_crc != crc32)
464 return eCrcErr;
466 return eOK;
470 /* returns the # of failures, 0 on success */
471 unsigned ProgramFirmwareFile(char* filename, int chipsize)
473 int i, j;
474 int fd;
475 int read = SEC_SIZE; /* how many for this sector */
476 UINT16 keep = *(UINT16*)(FB + KEEP); /* we must keep this! */
477 unsigned failures = 0;
479 fd = rb->open(filename, O_RDONLY);
480 if (fd < 0)
481 return false;
483 for (i=0; i<chipsize; i+=SEC_SIZE)
485 if (!EraseSector(FB + i))
487 /* nothing we can do, let the programming count the errors */
490 if (read == SEC_SIZE) /* not EOF yet */
492 read = rb->read(fd, sector, SEC_SIZE);
493 if (i==0)
494 { /* put original value back in */
495 *(UINT16*)(sector + KEEP) = keep;
498 for (j=0; j<read; j++)
500 if (!ProgramByte(FB + i + j, sector[j]))
502 failures++;
508 rb->close(fd);
510 return failures;
514 /* returns the # of failures, 0 on success */
515 unsigned VerifyFirmwareFile(char* filename)
517 int i=0, j;
518 int fd;
519 int read = SEC_SIZE; /* how many for this sector */
520 unsigned failures = 0;
522 fd = rb->open(filename, O_RDONLY);
523 if (fd < 0)
524 return false;
528 read = rb->read(fd, sector, SEC_SIZE);
530 for (j=0; j<read; j++)
532 /* position of keep value is no error */
533 if (FB[i] != sector[j] && i != KEEP && i != (KEEP+1))
535 failures++;
537 i++;
540 while (read == SEC_SIZE);
542 rb->close(fd);
544 return failures;
548 /***************** Support Functions *****************/
550 /* check if we have "normal" boot ROM or flash mirrored to zero */
551 tCheckROM CheckBootROM(void)
553 unsigned boot_crc;
554 unsigned* pFlash = (unsigned*)FB;
555 unsigned* pRom = (unsigned*)0x0;
556 unsigned i;
558 boot_crc = crc_32((unsigned char*)0x0, 64*1024, 0xFFFFFFFF);
559 if (boot_crc == 0x56DBA4EE /* the known boot ROM */
560 #if PLATFORM_ID == ID_PLAYER
561 /* alternative boot ROM found in one single player so far */
562 || boot_crc == 0x358099E8
563 #endif
565 return eBootROM;
567 /* check if ROM is a flash mirror */
568 for (i=0; i<256*1024/sizeof(unsigned); i++)
570 if (*pRom++ != *pFlash++)
571 { /* difference means no mirror */
572 return eUnknown;
576 return eROMless;
580 /***************** User Interface Functions *****************/
582 int WaitForButton(void)
584 int button;
588 button = rb->button_get(true);
589 } while (IS_SYSEVENT(button) || (button & BUTTON_REL));
591 return button;
594 #ifdef HAVE_LCD_BITMAP
595 /* Recorder implementation */
597 /* helper for DoUserDialog() */
598 void ShowFlashInfo(tFlashInfo* pInfo)
600 char buf[32];
602 if (!pInfo->manufacturer)
604 rb->lcd_puts(0, 0, "Flash: M=?? D=??");
605 rb->lcd_puts(0, 1, "Impossible to program");
607 else
609 rb->snprintf(buf, sizeof(buf), "Flash: M=%02x D=%02x",
610 pInfo->manufacturer, pInfo->id);
611 rb->lcd_puts(0, 0, buf);
614 if (pInfo->size)
616 rb->lcd_puts(0, 1, pInfo->name);
617 rb->snprintf(buf, sizeof(buf), "Size: %d KB", pInfo->size / 1024);
618 rb->lcd_puts(0, 2, buf);
620 else
622 rb->lcd_puts(0, 1, "Unsupported chip");
627 rb->lcd_update();
631 /* Kind of our main function, defines the application flow. */
632 void DoUserDialog(char* filename)
634 tFlashInfo FlashInfo;
635 char buf[32];
636 char default_filename[32];
637 int button;
638 int rc; /* generic return code */
639 ssize_t memleft;
640 tCheckROM result;
641 bool is_romless;
643 /* this can only work if Rockbox runs in DRAM, not flash ROM */
644 if ((UINT8*)rb >= FB && (UINT8*)rb < FB + 4096*1024) /* 4 MB max */
645 { /* we're running from flash */
646 rb->splash(HZ*3, "Not from ROM");
647 return; /* exit */
650 /* test if the user is running the correct plugin for this box */
651 if (!CheckPlatform(PLATFORM_ID, *(UINT16*)(FB + VERSION_ADR)))
653 rb->splash(HZ*3, "Wrong plugin");
654 return; /* exit */
657 /* refuse to work if the power may fail meanwhile */
658 if (!rb->battery_level_safe())
660 rb->splash(HZ*3, "Battery too low!");
661 return; /* exit */
664 /* check boot ROM */
665 result = CheckBootROM();
666 if (result == eUnknown)
667 { /* no support for any other yet */
668 rb->splash(HZ*3, "Wrong boot ROM");
669 return; /* exit */
671 is_romless = (result == eROMless);
673 /* compose filename if none given */
674 if (filename == NULL)
676 rb->snprintf(
677 default_filename,
678 sizeof(default_filename),
679 "/firmware_%s%s.bin",
680 FILE_TYPE,
681 is_romless ? "_norom" : "");
682 filename = default_filename;
685 /* "allocate" memory */
686 sector = rb->plugin_get_buffer((size_t *)&memleft);
687 if (memleft < SEC_SIZE) /* need buffer for a flash sector */
689 rb->splash(HZ*3, "Out of memory");
690 return; /* exit */
693 rb->lcd_setfont(FONT_SYSFIXED);
695 rc = GetFlashInfo(&FlashInfo);
696 ShowFlashInfo(&FlashInfo);
697 if (FlashInfo.size == 0) /* no valid chip */
699 rb->splash(HZ*3, "Sorry!");
700 return; /* exit */
703 rb->lcd_puts(0, 3, "using file:");
704 rb->lcd_puts_scroll(0, 4, filename);
705 rb->lcd_puts(0, 6, KEYNAME1 " to check file");
706 rb->lcd_puts(0, 7, "other key to exit");
707 rb->lcd_update();
709 button = WaitForButton();
710 if (button != KEY1)
712 return;
715 rb->lcd_clear_display();
716 rb->lcd_puts(0, 0, "checking...");
717 rb->lcd_update();
719 rc = CheckFirmwareFile(filename, FlashInfo.size, is_romless);
720 rb->lcd_puts(0, 0, "checked:");
721 switch (rc)
723 case eOK:
724 rb->lcd_puts(0, 1, "File OK.");
725 break;
726 case eFileNotFound:
727 rb->lcd_puts(0, 1, "File not found.");
728 rb->lcd_puts(0, 2, "Put this in root:");
729 rb->lcd_puts_scroll(0, 4, filename);
730 break;
731 case eTooBig:
732 rb->lcd_puts(0, 1, "File too big,");
733 rb->lcd_puts(0, 2, "larger than chip.");
734 break;
735 case eTooSmall:
736 rb->lcd_puts(0, 1, "File too small.");
737 rb->lcd_puts(0, 2, "Incomplete?");
738 break;
739 case eReadErr:
740 rb->lcd_puts(0, 1, "Read error.");
741 break;
742 case eBadContent:
743 rb->lcd_puts(0, 1, "File invalid.");
744 rb->lcd_puts(0, 2, "Sanity check fail.");
745 break;
746 case eCrcErr:
747 rb->lcd_puts(0, 1, "File invalid.");
748 rb->lcd_puts(0, 2, "CRC check failed,");
749 rb->lcd_puts(0, 3, "checksum mismatch.");
750 break;
751 case eBadPlatform:
752 rb->lcd_puts(0, 1, "Wrong file for");
753 rb->lcd_puts(0, 2, "this hardware.");
754 break;
755 default:
756 rb->lcd_puts(0, 1, "Check failed.");
757 break;
760 if (rc == eOK)
762 rb->lcd_puts(0, 6, KEYNAME2 " to program");
763 rb->lcd_puts(0, 7, "other key to exit");
765 else
766 { /* error occured */
767 rb->lcd_puts(0, 6, "Any key to exit");
770 rb->lcd_update();
772 button = WaitForButton();
773 if (button != KEY2 || rc != eOK)
775 return;
778 rb->lcd_clear_display();
779 rb->lcd_puts(0, 0, "Program all Flash?");
780 rb->lcd_puts(0, 1, "Are you sure?");
781 rb->lcd_puts(0, 2, "If it goes wrong,");
782 rb->lcd_puts(0, 3, "it kills your box!");
783 rb->lcd_puts(0, 4, "See documentation.");
785 rb->lcd_puts(0, 6, KEYNAME3 " to proceed");
786 rb->lcd_puts(0, 7, "other key to exit");
787 rb->lcd_update();
789 button = WaitForButton();
790 if (button != KEY3)
792 return;
795 rb->lcd_clear_display();
796 rb->lcd_puts(0, 0, "Programming...");
797 rb->lcd_update();
799 rc = ProgramFirmwareFile(filename, FlashInfo.size);
800 if (rc)
801 { /* errors */
802 rb->lcd_clear_display();
803 rb->lcd_puts(0, 0, "Panic:");
804 rb->lcd_puts(0, 1, "Programming fail!");
805 rb->snprintf(buf, sizeof(buf), "%d errors", rc);
806 rb->lcd_puts(0, 2, buf);
807 rb->lcd_update();
808 button = WaitForButton();
811 rb->lcd_clear_display();
812 rb->lcd_puts(0, 0, "Verifying...");
813 rb->lcd_update();
815 rc = VerifyFirmwareFile(filename);
817 rb->lcd_clear_display();
818 if (rc == 0)
820 rb->lcd_puts(0, 0, "Verify OK.");
822 else
824 rb->lcd_puts(0, 0, "Panic:");
825 rb->lcd_puts(0, 1, "Verify fail!");
826 rb->snprintf(buf, sizeof(buf), "%d errors", rc);
827 rb->lcd_puts(0, 2, buf);
829 rb->lcd_puts(0, 7, "Any key to exit");
830 rb->lcd_update();
832 button = WaitForButton();
835 #else /* HAVE_LCD_BITMAP */
836 /* Player implementation */
838 /* helper for DoUserDialog() */
839 void ShowFlashInfo(tFlashInfo* pInfo)
841 char buf[32];
843 if (!pInfo->manufacturer)
845 rb->lcd_puts_scroll(0, 0, "Flash: M=? D=?");
846 rb->lcd_puts_scroll(0, 1, "Impossible to program");
847 rb->lcd_update();
848 WaitForButton();
850 else
852 rb->snprintf(buf, sizeof(buf), "Flash: M=%02x D=%02x",
853 pInfo->manufacturer, pInfo->id);
854 rb->lcd_puts_scroll(0, 0, buf);
856 if (pInfo->size)
858 rb->snprintf(buf, sizeof(buf), "Size: %d KB", pInfo->size / 1024);
859 rb->lcd_puts_scroll(0, 1, buf);
860 rb->lcd_update();
862 else
864 rb->lcd_puts_scroll(0, 1, "Unsupported chip");
865 rb->lcd_update();
866 WaitForButton();
872 void DoUserDialog(char* filename)
874 tFlashInfo FlashInfo;
875 char buf[32];
876 char default_filename[32];
877 int button;
878 int rc; /* generic return code */
879 ssize_t memleft;
880 tCheckROM result;
881 bool is_romless;
883 /* this can only work if Rockbox runs in DRAM, not flash ROM */
884 if ((UINT8*)rb >= FB && (UINT8*)rb < FB + 4096*1024) /* 4 MB max */
885 { /* we're running from flash */
886 rb->splash(HZ*3, "Not from ROM");
887 return; /* exit */
890 /* test if the user is running the correct plugin for this box */
891 if (!CheckPlatform(PLATFORM_ID, *(UINT16*)(FB + VERSION_ADR)))
893 rb->splash(HZ*3, "Wrong version");
894 return; /* exit */
897 /* refuse to work if the power may fail meanwhile */
898 if (!rb->battery_level_safe())
900 rb->splash(HZ*3, "Batt. too low!");
901 return; /* exit */
904 /* check boot ROM */
905 result = CheckBootROM();
906 if (result == eUnknown)
907 { /* no support for any other yet */
908 rb->splash(HZ*3, "Wrong boot ROM");
909 return; /* exit */
911 is_romless = (result == eROMless);
913 /* compose filename if none given */
914 if (filename == NULL)
916 rb->snprintf(
917 default_filename,
918 sizeof(default_filename),
919 "/firmware_%s%s.bin",
920 FILE_TYPE,
921 is_romless ? "_norom" : "");
922 filename = default_filename;
925 /* "allocate" memory */
926 sector = rb->plugin_get_buffer((size_t *)&memleft);
927 if (memleft < SEC_SIZE) /* need buffer for a flash sector */
929 rb->splash(HZ*3, "Out of memory");
930 return; /* exit */
933 rc = GetFlashInfo(&FlashInfo);
934 ShowFlashInfo(&FlashInfo);
936 if (FlashInfo.size == 0) /* no valid chip */
938 return; /* exit */
941 rb->lcd_puts_scroll(0, 0, filename);
942 rb->lcd_puts_scroll(0, 1, "[Menu] to check");
943 rb->lcd_update();
945 button = WaitForButton();
946 if (button != BUTTON_MENU)
948 return;
951 rb->lcd_clear_display();
952 rb->lcd_puts(0, 0, "Checking...");
953 rb->lcd_update();
955 rc = CheckFirmwareFile(filename, FlashInfo.size, is_romless);
956 rb->lcd_puts(0, 0, "Checked:");
957 switch (rc)
959 case eOK:
960 rb->lcd_puts(0, 1, "File OK.");
961 break;
962 case eFileNotFound:
963 rb->lcd_puts_scroll(0, 0, "File not found:");
964 rb->lcd_puts_scroll(0, 1, filename);
965 break;
966 case eTooBig:
967 rb->lcd_puts_scroll(0, 0, "File too big,");
968 rb->lcd_puts_scroll(0, 1, "larger than chip.");
969 break;
970 case eTooSmall:
971 rb->lcd_puts_scroll(0, 0, "File too small.");
972 rb->lcd_puts_scroll(0, 1, "Incomplete?");
973 break;
974 case eReadErr:
975 rb->lcd_puts_scroll(0, 0, "Read error.");
976 break;
977 case eBadContent:
978 rb->lcd_puts_scroll(0, 0, "File invalid.");
979 rb->lcd_puts_scroll(0, 1, "Sanity check failed.");
980 break;
981 case eCrcErr:
982 rb->lcd_puts_scroll(0, 0, "File invalid.");
983 rb->lcd_puts_scroll(0, 1, "CRC check failed.");
984 break;
985 case eBadPlatform:
986 rb->lcd_puts_scroll(0, 0, "Wrong file for");
987 rb->lcd_puts_scroll(0, 1, "this hardware.");
988 break;
989 default:
990 rb->lcd_puts_scroll(0, 0, "Check failed.");
991 break;
993 rb->lcd_update();
995 rb->sleep(HZ*3);
997 if (rc == eOK)
999 rb->lcd_puts_scroll(0, 0, "[On] to program,");
1000 rb->lcd_puts_scroll(0, 1, "other key to exit.");
1001 rb->lcd_update();
1003 else
1004 { /* error occured */
1005 return;
1008 button = WaitForButton();
1010 if (button != BUTTON_ON)
1012 return;
1015 rb->lcd_clear_display();
1016 rb->lcd_puts_scroll(0, 0, "Are you sure?");
1017 rb->lcd_puts_scroll(0, 1, "[+] to proceed.");
1018 rb->lcd_update();
1020 button = WaitForButton();
1022 if (button != BUTTON_RIGHT)
1024 return;
1027 rb->lcd_clear_display();
1028 rb->lcd_puts_scroll(0, 0, "Programming...");
1029 rb->lcd_update();
1031 rc = ProgramFirmwareFile(filename, FlashInfo.size);
1033 if (rc)
1034 { /* errors */
1035 rb->lcd_clear_display();
1036 rb->lcd_puts_scroll(0, 0, "Programming failed!");
1037 rb->snprintf(buf, sizeof(buf), "%d errors", rc);
1038 rb->lcd_puts_scroll(0, 1, buf);
1039 rb->lcd_update();
1040 WaitForButton();
1043 rb->lcd_clear_display();
1044 rb->lcd_puts_scroll(0, 0, "Verifying...");
1045 rb->lcd_update();
1047 rc = VerifyFirmwareFile(filename);
1049 rb->lcd_clear_display();
1051 if (rc == 0)
1053 rb->lcd_puts_scroll(0, 0, "Verify OK.");
1055 else
1057 rb->snprintf(buf, sizeof(buf), "Verify failed! %d errors", rc);
1058 rb->lcd_puts_scroll(0, 0, buf);
1061 rb->lcd_puts_scroll(0, 1, "Press any key to exit.");
1062 rb->lcd_update();
1063 WaitForButton();
1066 #endif /* not HAVE_LCD_BITMAP */
1069 /***************** Plugin Entry Point *****************/
1071 enum plugin_status plugin_start(UNUSED_ATTR const void* parameter)
1073 int oldmode;
1075 /* now go ahead and have fun! */
1076 oldmode = rb->system_memory_guard(MEMGUARD_NONE); /*disable memory guard */
1077 DoUserDialog((char*) parameter);
1078 rb->system_memory_guard(oldmode); /* re-enable memory guard */
1080 return PLUGIN_OK;
1083 #endif /* ifdef PLATFORM_ID */