New makefile solution: A single invocation of 'make' to build the entire tree. Fully...
[kugel-rb.git] / apps / plugins / firmware_flash.c
blob376ae7f80f1ed332925e33a5f7fc6dd06d497d6f
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 #ifndef SIMULATOR /* only for target */
28 /* define DUMMY if you only want to "play" with the UI, does no harm */
29 /* #define DUMMY */
31 #ifndef UINT8
32 #define UINT8 unsigned char
33 #endif
35 #ifndef UINT16
36 #define UINT16 unsigned short
37 #endif
39 #ifndef UINT32
40 #define UINT32 unsigned long
41 #endif
43 /* platform IDs as I have used them in my firmware templates */
44 #define ID_RECORDER 0
45 #define ID_FM 1
46 #define ID_PLAYER 2
47 #define ID_REC_V2 3
48 #define ID_ONDIO_FM 4
49 #define ID_ONDIO_SP 5
51 /* Here I have to check for ARCHOS_* defines in source code, which is
52 generally strongly discouraged. But here I'm not checking for a certain
53 feature, I'm checking for the model itself. */
54 #if defined(ARCHOS_PLAYER)
55 #define FILE_TYPE "player"
56 #define KEEP VERSION_ADR /* keep the firmware version */
57 #define PLATFORM_ID ID_PLAYER
58 #elif defined(ARCHOS_RECORDER)
59 #define FILE_TYPE "rec"
60 #define KEEP MASK_ADR /* keep the mask value */
61 #define PLATFORM_ID ID_RECORDER
62 #elif defined(ARCHOS_RECORDERV2)
63 #define FILE_TYPE "v2"
64 #define KEEP MASK_ADR /* keep the mask value */
65 #define PLATFORM_ID ID_REC_V2
66 #elif defined(ARCHOS_FMRECORDER)
67 #define FILE_TYPE "fm"
68 #define KEEP MASK_ADR /* keep the mask value */
69 #define PLATFORM_ID ID_FM
70 #elif defined(ARCHOS_ONDIOFM)
71 #define FILE_TYPE "ondiofm"
72 #define KEEP MASK_ADR /* keep the mask value */
73 #define PLATFORM_ID ID_ONDIO_FM
74 #elif defined(ARCHOS_ONDIOSP)
75 #define FILE_TYPE "ondiosp"
76 #define KEEP MASK_ADR /* keep the mask value */
77 #define PLATFORM_ID ID_ONDIO_SP
78 #else
79 #undef PLATFORM_ID /* this platform is not (yet) flashable */
80 #endif
82 #ifdef PLATFORM_ID
84 PLUGIN_HEADER
86 #if CONFIG_KEYPAD == ONDIO_PAD /* limited keypad */
87 #define KEY1 BUTTON_LEFT
88 #define KEY2 BUTTON_UP
89 #define KEY3 BUTTON_RIGHT
90 #define KEYNAME1 "[Left]"
91 #define KEYNAME2 "[Up]"
92 #define KEYNAME3 "[Right]"
93 #else /* recorder keypad */
94 #define KEY1 BUTTON_F1
95 #define KEY2 BUTTON_F2
96 #define KEY3 BUTTON_F3
97 #define KEYNAME1 "[F1]"
98 #define KEYNAME2 "[F2]"
99 #define KEYNAME3 "[F3]"
100 #endif
102 /* result of the CheckFirmwareFile() function */
103 typedef enum
105 eOK = 0,
106 eFileNotFound, /* errors from here on */
107 eTooBig,
108 eTooSmall,
109 eReadErr,
110 eBadContent,
111 eCrcErr,
112 eBadPlatform,
113 } tCheckResult;
115 /* result of the CheckBootROM() function */
116 typedef enum
118 eBootROM, /* the supported boot ROM(s) */
119 eUnknown, /* unknown boot ROM */
120 eROMless, /* flash mapped to zero */
121 } tCheckROM;
123 typedef struct
125 UINT8 manufacturer;
126 UINT8 id;
127 int size;
128 char name[32];
129 } tFlashInfo;
131 static const struct plugin_api* rb; /* here is a global api struct pointer */
133 #define MASK_ADR 0xFC /* position of hardware mask value in Flash */
134 #define VERSION_ADR 0xFE /* position of firmware version value in Flash */
135 #define PLATFORM_ADR 0xFB /* position of my platform ID value in Flash */
136 #define SEC_SIZE 4096 /* size of one flash sector */
137 static UINT8* sector; /* better not place this on the stack... */
138 static volatile UINT8* FB = (UINT8*)0x02000000; /* Flash base address */
141 /***************** Flash Functions *****************/
144 /* read the manufacturer and device ID */
145 bool ReadID(volatile UINT8* pBase, UINT8* pManufacturerID, UINT8* pDeviceID)
147 UINT8 not_manu, not_id; /* read values before switching to ID mode */
148 UINT8 manu, id; /* read values when in ID mode */
150 pBase = (UINT8*)((UINT32)pBase & 0xFFF80000); /* down to 512k align */
152 /* read the normal content */
153 not_manu = pBase[0]; /* should be 'A' (0x41) and 'R' (0x52) */
154 not_id = pBase[1]; /* from the "ARCH" marker */
156 pBase[0x5555] = 0xAA; /* enter command mode */
157 pBase[0x2AAA] = 0x55;
158 pBase[0x5555] = 0x90; /* ID command */
159 rb->sleep(HZ/50); /* Atmel wants 20ms pause here */
161 manu = pBase[0];
162 id = pBase[1];
164 pBase[0] = 0xF0; /* reset flash (back to normal read mode) */
165 rb->sleep(HZ/50); /* Atmel wants 20ms pause here */
167 /* I assume success if the obtained values are different from
168 the normal flash content. This is not perfectly bulletproof, they
169 could theoretically be the same by chance, causing us to fail. */
170 if (not_manu != manu || not_id != id) /* a value has changed */
172 *pManufacturerID = manu; /* return the results */
173 *pDeviceID = id;
174 return true; /* success */
176 return false; /* fail */
180 /* erase the sector which contains the given address */
181 bool EraseSector(volatile UINT8* pAddr)
183 #ifdef DUMMY
184 (void)pAddr; /* prevents warning */
185 return true;
186 #else
187 volatile UINT8* pBase = (UINT8*)((UINT32)pAddr & 0xFFF80000); /* round down to 512k align */
188 unsigned timeout = 43000; /* the timeout loop should be no less than 25ms */
190 pBase[0x5555] = 0xAA; /* enter command mode */
191 pBase[0x2AAA] = 0x55;
192 pBase[0x5555] = 0x80; /* erase command */
193 pBase[0x5555] = 0xAA; /* enter command mode */
194 pBase[0x2AAA] = 0x55;
195 *pAddr = 0x30; /* erase the sector */
197 /* I counted 7 instructions for this loop -> min. 0.58 us per round */
198 /* Plus memory waitstates it will be much more, gives margin */
199 while (*pAddr != 0xFF && --timeout); /* poll for erased */
201 return (timeout != 0);
202 #endif
206 /* address must be in an erased location */
207 inline bool ProgramByte(volatile UINT8* pAddr, UINT8 data)
209 #ifdef DUMMY
210 (void)pAddr; /* prevents warnings */
211 (void)data;
212 return true;
213 #else
214 unsigned timeout = 35; /* the timeout loop should be no less than 20us */
216 if (~*pAddr & data) /* just a safety feature, not really necessary */
217 return false; /* can't set any bit from 0 to 1 */
219 FB[0x5555] = 0xAA; /* enter command mode */
220 FB[0x2AAA] = 0x55;
221 FB[0x5555] = 0xA0; /* byte program command */
223 *pAddr = data;
225 /* I counted 7 instructions for this loop -> min. 0.58 us per round */
226 /* Plus memory waitstates it will be much more, gives margin */
227 while (*pAddr != data && --timeout); /* poll for programmed */
229 return (timeout != 0);
230 #endif
234 /* this returns true if supported and fills the info struct */
235 bool GetFlashInfo(tFlashInfo* pInfo)
237 rb->memset(pInfo, 0, sizeof(tFlashInfo));
239 if (!ReadID(FB, &pInfo->manufacturer, &pInfo->id))
240 return false;
242 if (pInfo->manufacturer == 0xBF) /* SST */
244 if (pInfo->id == 0xD6)
246 pInfo->size = 256* 1024; /* 256k */
247 rb->strcpy(pInfo->name, "SST39VF020");
248 return true;
250 else if (pInfo->id == 0xD7)
252 pInfo->size = 512* 1024; /* 512k */
253 rb->strcpy(pInfo->name, "SST39VF040");
254 return true;
256 else
257 return false;
259 return false;
263 /*********** Utility Functions ************/
266 /* Tool function to calculate a CRC32 across some buffer */
267 /* third argument is either 0xFFFFFFFF to start or value from last piece */
268 unsigned crc_32(unsigned char* buf, unsigned len, unsigned crc32)
270 /* CCITT standard polynomial 0x04C11DB7 */
271 static const unsigned crc32_lookup[16] =
272 { /* lookup table for 4 bits at a time is affordable */
273 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9,
274 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,
275 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61,
276 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD
279 unsigned char byte;
280 unsigned t;
282 while (len--)
284 byte = *buf++; /* get one byte of data */
286 /* upper nibble of our data */
287 t = crc32 >> 28; /* extract the 4 most significant bits */
288 t ^= byte >> 4; /* 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 */
292 /* lower nibble of our data */
293 t = crc32 >> 28; /* extract the 4 most significant bits */
294 t ^= byte & 0x0F; /* XOR in 4 bits of data into the extracted bits */
295 crc32 <<= 4; /* shift the CRC register left 4 bits */
296 crc32 ^= crc32_lookup[t]; /* do the table lookup and XOR the result */
299 return crc32;
303 /*********** Firmware File Functions + helpers ************/
305 /* test if the version number is consistent with the platform */
306 bool CheckPlatform(int platform_id, UINT16 version)
308 if (version == 200)
309 { /* for my very first firmwares, I foolishly changed it to 200 */
310 return (platform_id == ID_RECORDER || platform_id == ID_FM);
312 else if (version == 123)
313 { /* it can be a FM or V2 recorder */
314 return (platform_id == ID_FM || platform_id == ID_REC_V2);
316 else if (version == 132)
317 { /* newer Ondio, and seen on a V2 recorder */
318 return (platform_id == ID_ONDIO_SP || platform_id == ID_ONDIO_FM
319 || platform_id == ID_REC_V2);
321 else if (version == 104)
322 { /* classic Ondio128 */
323 return (platform_id == ID_ONDIO_FM);
325 else if (version >= 115 && version <= 129)
326 { /* the range of Recorders seen so far */
327 return (platform_id == ID_RECORDER);
329 else if (version == 0 || (version >= 300 && version <= 508))
330 { /* for very old players, I've seen zero */
331 return (platform_id == ID_PLAYER);
334 return false; /* unknown */
338 tCheckResult CheckFirmwareFile(char* filename, int chipsize, bool is_romless)
340 int i;
341 int fd;
342 int fileleft; /* size info, how many left for reading */
343 int fileread = 0; /* total size as read from the file */
344 int read_now; /* how many to read for this sector */
345 int got_now; /* how many gotten for this sector */
346 unsigned crc32 = 0xFFFFFFFF; /* CCITT init value */
347 unsigned file_crc; /* CRC value read from file */
348 bool has_crc;
350 fd = rb->open(filename, O_RDONLY);
351 if (fd < 0)
352 return eFileNotFound;
354 fileleft = rb->filesize(fd);
355 if (fileleft > chipsize)
357 rb->close(fd);
358 return eTooBig;
360 else if (fileleft < 20000) /* give it some reasonable lower limit */
362 rb->close(fd);
363 return eTooSmall;
366 if (fileleft == 256*1024)
367 { /* original dumped firmware file has no CRC nor platform ID */
368 has_crc = false;
370 else
372 has_crc = true;
373 fileleft -= sizeof(unsigned); /* exclude the last 4 bytes */
376 /* do some sanity checks */
378 got_now = rb->read(fd, sector, SEC_SIZE); /* read first sector */
379 fileread += got_now;
380 fileleft -= got_now;
381 if (got_now != SEC_SIZE)
383 rb->close(fd);
384 return eReadErr;
387 /* version number in file plausible with this hardware? */
388 if (!CheckPlatform(PLATFORM_ID, *(UINT16*)(sector + VERSION_ADR)))
390 rb->close(fd);
391 return eBadPlatform;
394 if (has_crc)
396 crc32 = crc_32(sector, SEC_SIZE, crc32); /* checksum */
398 /* in addition to the CRC, my files also have a platform ID */
399 if (sector[PLATFORM_ADR] != PLATFORM_ID) /* for our hardware? */
401 rb->close(fd);
402 return eBadPlatform;
406 if (is_romless)
407 { /* in this case, there is not much we can check */
408 if (*(UINT32*)sector != 0x00000200) /* reset vector */
410 rb->close(fd);
411 return eBadContent;
414 else
416 /* compare some bytes which have to be identical */
417 if (*(UINT32*)sector != 0x41524348) /* "ARCH" */
419 rb->close(fd);
420 return eBadContent;
423 for (i = 0x30; i<MASK_ADR-2; i++) /* leave two bytes for me */
425 if (sector[i] != FB[i])
427 rb->close(fd);
428 return eBadContent;
433 /* check if we can read the whole file, and do checksum */
436 read_now = MIN(SEC_SIZE, fileleft);
437 got_now = rb->read(fd, sector, read_now);
438 fileread += got_now;
439 fileleft -= got_now;
441 if (read_now != got_now)
443 rb->close(fd);
444 return eReadErr;
447 if (has_crc)
449 crc32 = crc_32(sector, got_now, crc32); /* checksum */
451 } while (fileleft);
453 if (has_crc)
455 got_now = rb->read(fd, &file_crc, sizeof(file_crc));
456 if (got_now != sizeof(file_crc))
458 rb->close(fd);
459 return eReadErr;
463 /* must be EOF now */
464 got_now = rb->read(fd, sector, SEC_SIZE);
465 rb->close(fd);
466 if (got_now != 0)
467 return eReadErr;
469 if (has_crc && file_crc != crc32)
470 return eCrcErr;
472 return eOK;
476 /* returns the # of failures, 0 on success */
477 unsigned ProgramFirmwareFile(char* filename, int chipsize)
479 int i, j;
480 int fd;
481 int read = SEC_SIZE; /* how many for this sector */
482 UINT16 keep = *(UINT16*)(FB + KEEP); /* we must keep this! */
483 unsigned failures = 0;
485 fd = rb->open(filename, O_RDONLY);
486 if (fd < 0)
487 return false;
489 for (i=0; i<chipsize; i+=SEC_SIZE)
491 if (!EraseSector(FB + i))
493 /* nothing we can do, let the programming count the errors */
496 if (read == SEC_SIZE) /* not EOF yet */
498 read = rb->read(fd, sector, SEC_SIZE);
499 if (i==0)
500 { /* put original value back in */
501 *(UINT16*)(sector + KEEP) = keep;
504 for (j=0; j<read; j++)
506 if (!ProgramByte(FB + i + j, sector[j]))
508 failures++;
514 rb->close(fd);
516 return failures;
520 /* returns the # of failures, 0 on success */
521 unsigned VerifyFirmwareFile(char* filename)
523 int i=0, j;
524 int fd;
525 int read = SEC_SIZE; /* how many for this sector */
526 unsigned failures = 0;
528 fd = rb->open(filename, O_RDONLY);
529 if (fd < 0)
530 return false;
534 read = rb->read(fd, sector, SEC_SIZE);
536 for (j=0; j<read; j++)
538 /* position of keep value is no error */
539 if (FB[i] != sector[j] && i != KEEP && i != (KEEP+1))
541 failures++;
543 i++;
546 while (read == SEC_SIZE);
548 rb->close(fd);
550 return failures;
554 /***************** Support Functions *****************/
556 /* check if we have "normal" boot ROM or flash mirrored to zero */
557 tCheckROM CheckBootROM(void)
559 unsigned boot_crc;
560 unsigned* pFlash = (unsigned*)FB;
561 unsigned* pRom = (unsigned*)0x0;
562 unsigned i;
564 boot_crc = crc_32((unsigned char*)0x0, 64*1024, 0xFFFFFFFF);
565 if (boot_crc == 0x56DBA4EE /* the known boot ROM */
566 #if PLATFORM_ID == ID_PLAYER
567 /* alternative boot ROM found in one single player so far */
568 || boot_crc == 0x358099E8
569 #endif
571 return eBootROM;
573 /* check if ROM is a flash mirror */
574 for (i=0; i<256*1024/sizeof(unsigned); i++)
576 if (*pRom++ != *pFlash++)
577 { /* difference means no mirror */
578 return eUnknown;
582 return eROMless;
586 /***************** User Interface Functions *****************/
588 int WaitForButton(void)
590 int button;
594 button = rb->button_get(true);
595 } while (button & BUTTON_REL);
597 return button;
600 #ifdef HAVE_LCD_BITMAP
601 /* Recorder implementation */
603 /* helper for DoUserDialog() */
604 void ShowFlashInfo(tFlashInfo* pInfo)
606 char buf[32];
608 if (!pInfo->manufacturer)
610 rb->lcd_puts(0, 0, "Flash: M=?? D=??");
611 rb->lcd_puts(0, 1, "Impossible to program");
613 else
615 rb->snprintf(buf, sizeof(buf), "Flash: M=%02x D=%02x",
616 pInfo->manufacturer, pInfo->id);
617 rb->lcd_puts(0, 0, buf);
620 if (pInfo->size)
622 rb->lcd_puts(0, 1, pInfo->name);
623 rb->snprintf(buf, sizeof(buf), "Size: %d KB", pInfo->size / 1024);
624 rb->lcd_puts(0, 2, buf);
626 else
628 rb->lcd_puts(0, 1, "Unsupported chip");
633 rb->lcd_update();
637 /* Kind of our main function, defines the application flow. */
638 void DoUserDialog(char* filename)
640 tFlashInfo FlashInfo;
641 char buf[32];
642 char default_filename[32];
643 int button;
644 int rc; /* generic return code */
645 ssize_t memleft;
646 tCheckROM result;
647 bool is_romless;
649 /* this can only work if Rockbox runs in DRAM, not flash ROM */
650 if ((UINT8*)rb >= FB && (UINT8*)rb < FB + 4096*1024) /* 4 MB max */
651 { /* we're running from flash */
652 rb->splash(HZ*3, "Not from ROM");
653 return; /* exit */
656 /* test if the user is running the correct plugin for this box */
657 if (!CheckPlatform(PLATFORM_ID, *(UINT16*)(FB + VERSION_ADR)))
659 rb->splash(HZ*3, "Wrong plugin");
660 return; /* exit */
663 /* refuse to work if the power may fail meanwhile */
664 if (!rb->battery_level_safe())
666 rb->splash(HZ*3, "Battery too low!");
667 return; /* exit */
670 /* check boot ROM */
671 result = CheckBootROM();
672 if (result == eUnknown)
673 { /* no support for any other yet */
674 rb->splash(HZ*3, "Wrong boot ROM");
675 return; /* exit */
677 is_romless = (result == eROMless);
679 /* compose filename if none given */
680 if (filename == NULL)
682 rb->snprintf(
683 default_filename,
684 sizeof(default_filename),
685 "/firmware_%s%s.bin",
686 FILE_TYPE,
687 is_romless ? "_norom" : "");
688 filename = default_filename;
691 /* "allocate" memory */
692 sector = rb->plugin_get_buffer((size_t *)&memleft);
693 if (memleft < SEC_SIZE) /* need buffer for a flash sector */
695 rb->splash(HZ*3, "Out of memory");
696 return; /* exit */
699 rb->lcd_setfont(FONT_SYSFIXED);
701 rc = GetFlashInfo(&FlashInfo);
702 ShowFlashInfo(&FlashInfo);
703 if (FlashInfo.size == 0) /* no valid chip */
705 rb->splash(HZ*3, "Sorry!");
706 return; /* exit */
709 rb->lcd_puts(0, 3, "using file:");
710 rb->lcd_puts_scroll(0, 4, filename);
711 rb->lcd_puts(0, 6, KEYNAME1 " to check file");
712 rb->lcd_puts(0, 7, "other key to exit");
713 rb->lcd_update();
715 button = WaitForButton();
716 if (button != KEY1)
718 return;
721 rb->lcd_clear_display();
722 rb->lcd_puts(0, 0, "checking...");
723 rb->lcd_update();
725 rc = CheckFirmwareFile(filename, FlashInfo.size, is_romless);
726 rb->lcd_puts(0, 0, "checked:");
727 switch (rc)
729 case eOK:
730 rb->lcd_puts(0, 1, "File OK.");
731 break;
732 case eFileNotFound:
733 rb->lcd_puts(0, 1, "File not found.");
734 rb->lcd_puts(0, 2, "Put this in root:");
735 rb->lcd_puts_scroll(0, 4, filename);
736 break;
737 case eTooBig:
738 rb->lcd_puts(0, 1, "File too big,");
739 rb->lcd_puts(0, 2, "larger than chip.");
740 break;
741 case eTooSmall:
742 rb->lcd_puts(0, 1, "File too small.");
743 rb->lcd_puts(0, 2, "Incomplete?");
744 break;
745 case eReadErr:
746 rb->lcd_puts(0, 1, "Read error.");
747 break;
748 case eBadContent:
749 rb->lcd_puts(0, 1, "File invalid.");
750 rb->lcd_puts(0, 2, "Sanity check fail.");
751 break;
752 case eCrcErr:
753 rb->lcd_puts(0, 1, "File invalid.");
754 rb->lcd_puts(0, 2, "CRC check failed,");
755 rb->lcd_puts(0, 3, "checksum mismatch.");
756 break;
757 case eBadPlatform:
758 rb->lcd_puts(0, 1, "Wrong file for");
759 rb->lcd_puts(0, 2, "this hardware.");
760 break;
761 default:
762 rb->lcd_puts(0, 1, "Check failed.");
763 break;
766 if (rc == eOK)
768 rb->lcd_puts(0, 6, KEYNAME2 " to program");
769 rb->lcd_puts(0, 7, "other key to exit");
771 else
772 { /* error occured */
773 rb->lcd_puts(0, 6, "Any key to exit");
776 rb->lcd_update();
778 button = WaitForButton();
779 if (button != KEY2 || rc != eOK)
781 return;
784 rb->lcd_clear_display();
785 rb->lcd_puts(0, 0, "Program all Flash?");
786 rb->lcd_puts(0, 1, "Are you sure?");
787 rb->lcd_puts(0, 2, "If it goes wrong,");
788 rb->lcd_puts(0, 3, "it kills your box!");
789 rb->lcd_puts(0, 4, "See documentation.");
791 rb->lcd_puts(0, 6, KEYNAME3 " to proceed");
792 rb->lcd_puts(0, 7, "other key to exit");
793 rb->lcd_update();
795 button = WaitForButton();
796 if (button != KEY3)
798 return;
801 rb->lcd_clear_display();
802 rb->lcd_puts(0, 0, "Programming...");
803 rb->lcd_update();
805 rc = ProgramFirmwareFile(filename, FlashInfo.size);
806 if (rc)
807 { /* errors */
808 rb->lcd_clear_display();
809 rb->lcd_puts(0, 0, "Panic:");
810 rb->lcd_puts(0, 1, "Programming fail!");
811 rb->snprintf(buf, sizeof(buf), "%d errors", rc);
812 rb->lcd_puts(0, 2, buf);
813 rb->lcd_update();
814 button = WaitForButton();
817 rb->lcd_clear_display();
818 rb->lcd_puts(0, 0, "Verifying...");
819 rb->lcd_update();
821 rc = VerifyFirmwareFile(filename);
823 rb->lcd_clear_display();
824 if (rc == 0)
826 rb->lcd_puts(0, 0, "Verify OK.");
828 else
830 rb->lcd_puts(0, 0, "Panic:");
831 rb->lcd_puts(0, 1, "Verify fail!");
832 rb->snprintf(buf, sizeof(buf), "%d errors", rc);
833 rb->lcd_puts(0, 2, buf);
835 rb->lcd_puts(0, 7, "Any key to exit");
836 rb->lcd_update();
838 button = WaitForButton();
841 #else /* HAVE_LCD_BITMAP */
842 /* Player implementation */
844 /* helper for DoUserDialog() */
845 void ShowFlashInfo(tFlashInfo* pInfo)
847 char buf[32];
849 if (!pInfo->manufacturer)
851 rb->lcd_puts_scroll(0, 0, "Flash: M=? D=?");
852 rb->lcd_puts_scroll(0, 1, "Impossible to program");
853 rb->lcd_update();
854 WaitForButton();
856 else
858 rb->snprintf(buf, sizeof(buf), "Flash: M=%02x D=%02x",
859 pInfo->manufacturer, pInfo->id);
860 rb->lcd_puts_scroll(0, 0, buf);
862 if (pInfo->size)
864 rb->snprintf(buf, sizeof(buf), "Size: %d KB", pInfo->size / 1024);
865 rb->lcd_puts_scroll(0, 1, buf);
866 rb->lcd_update();
868 else
870 rb->lcd_puts_scroll(0, 1, "Unsupported chip");
871 rb->lcd_update();
872 WaitForButton();
878 void DoUserDialog(char* filename)
880 tFlashInfo FlashInfo;
881 char buf[32];
882 char default_filename[32];
883 int button;
884 int rc; /* generic return code */
885 ssize_t memleft;
886 tCheckROM result;
887 bool is_romless;
889 /* this can only work if Rockbox runs in DRAM, not flash ROM */
890 if ((UINT8*)rb >= FB && (UINT8*)rb < FB + 4096*1024) /* 4 MB max */
891 { /* we're running from flash */
892 rb->splash(HZ*3, "Not from ROM");
893 return; /* exit */
896 /* test if the user is running the correct plugin for this box */
897 if (!CheckPlatform(PLATFORM_ID, *(UINT16*)(FB + VERSION_ADR)))
899 rb->splash(HZ*3, "Wrong version");
900 return; /* exit */
903 /* refuse to work if the power may fail meanwhile */
904 if (!rb->battery_level_safe())
906 rb->splash(HZ*3, "Batt. too low!");
907 return; /* exit */
910 /* check boot ROM */
911 result = CheckBootROM();
912 if (result == eUnknown)
913 { /* no support for any other yet */
914 rb->splash(HZ*3, "Wrong boot ROM");
915 return; /* exit */
917 is_romless = (result == eROMless);
919 /* compose filename if none given */
920 if (filename == NULL)
922 rb->snprintf(
923 default_filename,
924 sizeof(default_filename),
925 "/firmware_%s%s.bin",
926 FILE_TYPE,
927 is_romless ? "_norom" : "");
928 filename = default_filename;
931 /* "allocate" memory */
932 sector = rb->plugin_get_buffer((size_t *)&memleft);
933 if (memleft < SEC_SIZE) /* need buffer for a flash sector */
935 rb->splash(HZ*3, "Out of memory");
936 return; /* exit */
939 rc = GetFlashInfo(&FlashInfo);
940 ShowFlashInfo(&FlashInfo);
942 if (FlashInfo.size == 0) /* no valid chip */
944 return; /* exit */
947 rb->lcd_puts_scroll(0, 0, filename);
948 rb->lcd_puts_scroll(0, 1, "[Menu] to check");
949 rb->lcd_update();
951 button = WaitForButton();
952 if (button != BUTTON_MENU)
954 return;
957 rb->lcd_clear_display();
958 rb->lcd_puts(0, 0, "Checking...");
959 rb->lcd_update();
961 rc = CheckFirmwareFile(filename, FlashInfo.size, is_romless);
962 rb->lcd_puts(0, 0, "Checked:");
963 switch (rc)
965 case eOK:
966 rb->lcd_puts(0, 1, "File OK.");
967 break;
968 case eFileNotFound:
969 rb->lcd_puts_scroll(0, 0, "File not found:");
970 rb->lcd_puts_scroll(0, 1, filename);
971 break;
972 case eTooBig:
973 rb->lcd_puts_scroll(0, 0, "File too big,");
974 rb->lcd_puts_scroll(0, 1, "larger than chip.");
975 break;
976 case eTooSmall:
977 rb->lcd_puts_scroll(0, 0, "File too small.");
978 rb->lcd_puts_scroll(0, 1, "Incomplete?");
979 break;
980 case eReadErr:
981 rb->lcd_puts_scroll(0, 0, "Read error.");
982 break;
983 case eBadContent:
984 rb->lcd_puts_scroll(0, 0, "File invalid.");
985 rb->lcd_puts_scroll(0, 1, "Sanity check failed.");
986 break;
987 case eCrcErr:
988 rb->lcd_puts_scroll(0, 0, "File invalid.");
989 rb->lcd_puts_scroll(0, 1, "CRC check failed.");
990 break;
991 case eBadPlatform:
992 rb->lcd_puts_scroll(0, 0, "Wrong file for");
993 rb->lcd_puts_scroll(0, 1, "this hardware.");
994 break;
995 default:
996 rb->lcd_puts_scroll(0, 0, "Check failed.");
997 break;
999 rb->lcd_update();
1001 rb->sleep(HZ*3);
1003 if (rc == eOK)
1005 rb->lcd_puts_scroll(0, 0, "[On] to program,");
1006 rb->lcd_puts_scroll(0, 1, "other key to exit.");
1007 rb->lcd_update();
1009 else
1010 { /* error occured */
1011 return;
1014 button = WaitForButton();
1016 if (button != BUTTON_ON)
1018 return;
1021 rb->lcd_clear_display();
1022 rb->lcd_puts_scroll(0, 0, "Are you sure?");
1023 rb->lcd_puts_scroll(0, 1, "[+] to proceed.");
1024 rb->lcd_update();
1026 button = WaitForButton();
1028 if (button != BUTTON_RIGHT)
1030 return;
1033 rb->lcd_clear_display();
1034 rb->lcd_puts_scroll(0, 0, "Programming...");
1035 rb->lcd_update();
1037 rc = ProgramFirmwareFile(filename, FlashInfo.size);
1039 if (rc)
1040 { /* errors */
1041 rb->lcd_clear_display();
1042 rb->lcd_puts_scroll(0, 0, "Programming failed!");
1043 rb->snprintf(buf, sizeof(buf), "%d errors", rc);
1044 rb->lcd_puts_scroll(0, 1, buf);
1045 rb->lcd_update();
1046 WaitForButton();
1049 rb->lcd_clear_display();
1050 rb->lcd_puts_scroll(0, 0, "Verifying...");
1051 rb->lcd_update();
1053 rc = VerifyFirmwareFile(filename);
1055 rb->lcd_clear_display();
1057 if (rc == 0)
1059 rb->lcd_puts_scroll(0, 0, "Verify OK.");
1061 else
1063 rb->snprintf(buf, sizeof(buf), "Verify failed! %d errors", rc);
1064 rb->lcd_puts_scroll(0, 0, buf);
1067 rb->lcd_puts_scroll(0, 1, "Press any key to exit.");
1068 rb->lcd_update();
1069 WaitForButton();
1072 #endif /* not HAVE_LCD_BITMAP */
1075 /***************** Plugin Entry Point *****************/
1077 enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter)
1079 int oldmode;
1081 rb = api; /* copy to global api pointer */
1083 /* now go ahead and have fun! */
1084 oldmode = rb->system_memory_guard(MEMGUARD_NONE); /*disable memory guard */
1085 DoUserDialog((char*) parameter);
1086 rb->system_memory_guard(oldmode); /* re-enable memory guard */
1088 return PLUGIN_OK;
1091 #endif /* ifdef PLATFORM_ID */
1092 #endif /* #ifndef SIMULATOR */