Update the discussion of themeing in the manual, and put a note in the wps tags appen...
[kugel-rb.git] / apps / plugins / firmware_flash.c
blob43ed7a87d9143db9ccfe0d6def6c70f0cac21c9d
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(volatile UINT8* pAddr)
179 #ifdef DUMMY
180 (void)pAddr; /* prevents warning */
181 return true;
182 #else
183 volatile UINT8* pBase = (UINT8*)((UINT32)pAddr & 0xFFF80000); /* round down to 512k align */
184 unsigned timeout = 43000; /* the timeout loop should be no less than 25ms */
186 pBase[0x5555] = 0xAA; /* enter command mode */
187 pBase[0x2AAA] = 0x55;
188 pBase[0x5555] = 0x80; /* erase command */
189 pBase[0x5555] = 0xAA; /* enter command mode */
190 pBase[0x2AAA] = 0x55;
191 *pAddr = 0x30; /* erase the sector */
193 /* I counted 7 instructions for this loop -> min. 0.58 us per round */
194 /* Plus memory waitstates it will be much more, gives margin */
195 while (*pAddr != 0xFF && --timeout); /* poll for erased */
197 return (timeout != 0);
198 #endif
202 /* address must be in an erased location */
203 inline bool ProgramByte(volatile UINT8* pAddr, UINT8 data)
205 #ifdef DUMMY
206 (void)pAddr; /* prevents warnings */
207 (void)data;
208 return true;
209 #else
210 unsigned timeout = 35; /* the timeout loop should be no less than 20us */
212 if (~*pAddr & data) /* just a safety feature, not really necessary */
213 return false; /* can't set any bit from 0 to 1 */
215 FB[0x5555] = 0xAA; /* enter command mode */
216 FB[0x2AAA] = 0x55;
217 FB[0x5555] = 0xA0; /* byte program command */
219 *pAddr = data;
221 /* I counted 7 instructions for this loop -> min. 0.58 us per round */
222 /* Plus memory waitstates it will be much more, gives margin */
223 while (*pAddr != data && --timeout); /* poll for programmed */
225 return (timeout != 0);
226 #endif
230 /* this returns true if supported and fills the info struct */
231 bool GetFlashInfo(tFlashInfo* pInfo)
233 rb->memset(pInfo, 0, sizeof(tFlashInfo));
235 if (!ReadID(FB, &pInfo->manufacturer, &pInfo->id))
236 return false;
238 if (pInfo->manufacturer == 0xBF) /* SST */
240 if (pInfo->id == 0xD6)
242 pInfo->size = 256* 1024; /* 256k */
243 rb->strcpy(pInfo->name, "SST39VF020");
244 return true;
246 else if (pInfo->id == 0xD7)
248 pInfo->size = 512* 1024; /* 512k */
249 rb->strcpy(pInfo->name, "SST39VF040");
250 return true;
252 else
253 return false;
255 return false;
258 /*********** Firmware File Functions + helpers ************/
260 /* test if the version number is consistent with the platform */
261 bool CheckPlatform(int platform_id, UINT16 version)
263 if (version == 200)
264 { /* for my very first firmwares, I foolishly changed it to 200 */
265 return (platform_id == ID_RECORDER || platform_id == ID_FM);
267 else if (version == 123)
268 { /* it can be a FM or V2 recorder */
269 return (platform_id == ID_FM || platform_id == ID_REC_V2);
271 else if (version == 132)
272 { /* newer Ondio, and seen on a V2 recorder */
273 return (platform_id == ID_ONDIO_SP || platform_id == ID_ONDIO_FM
274 || platform_id == ID_REC_V2);
276 else if (version == 104)
277 { /* classic Ondio128 */
278 return (platform_id == ID_ONDIO_FM);
280 else if (version >= 115 && version <= 129)
281 { /* the range of Recorders seen so far */
282 return (platform_id == ID_RECORDER);
284 else if (version == 0 || (version >= 300 && version <= 508))
285 { /* for very old players, I've seen zero */
286 return (platform_id == ID_PLAYER);
289 return false; /* unknown */
293 tCheckResult CheckFirmwareFile(char* filename, int chipsize, bool is_romless)
295 int i;
296 int fd;
297 int fileleft; /* size info, how many left for reading */
298 int fileread = 0; /* total size as read from the file */
299 int read_now; /* how many to read for this sector */
300 int got_now; /* how many gotten for this sector */
301 unsigned crc32 = 0xFFFFFFFF; /* CCITT init value */
302 unsigned file_crc; /* CRC value read from file */
303 bool has_crc;
305 fd = rb->open(filename, O_RDONLY);
306 if (fd < 0)
307 return eFileNotFound;
309 fileleft = rb->filesize(fd);
310 if (fileleft > chipsize)
312 rb->close(fd);
313 return eTooBig;
315 else if (fileleft < 20000) /* give it some reasonable lower limit */
317 rb->close(fd);
318 return eTooSmall;
321 if (fileleft == 256*1024)
322 { /* original dumped firmware file has no CRC nor platform ID */
323 has_crc = false;
325 else
327 has_crc = true;
328 fileleft -= sizeof(unsigned); /* exclude the last 4 bytes */
331 /* do some sanity checks */
333 got_now = rb->read(fd, sector, SEC_SIZE); /* read first sector */
334 fileread += got_now;
335 fileleft -= got_now;
336 if (got_now != SEC_SIZE)
338 rb->close(fd);
339 return eReadErr;
342 /* version number in file plausible with this hardware? */
343 if (!CheckPlatform(PLATFORM_ID, *(UINT16*)(sector + VERSION_ADR)))
345 rb->close(fd);
346 return eBadPlatform;
349 if (has_crc)
351 crc32 = rb->crc_32(sector, SEC_SIZE, crc32); /* checksum */
353 /* in addition to the CRC, my files also have a platform ID */
354 if (sector[PLATFORM_ADR] != PLATFORM_ID) /* for our hardware? */
356 rb->close(fd);
357 return eBadPlatform;
361 if (is_romless)
362 { /* in this case, there is not much we can check */
363 if (*(UINT32*)sector != 0x00000200) /* reset vector */
365 rb->close(fd);
366 return eBadContent;
369 else
371 /* compare some bytes which have to be identical */
372 if (*(UINT32*)sector != 0x41524348) /* "ARCH" */
374 rb->close(fd);
375 return eBadContent;
378 for (i = 0x30; i<MASK_ADR-2; i++) /* leave two bytes for me */
380 if (sector[i] != FB[i])
382 rb->close(fd);
383 return eBadContent;
388 /* check if we can read the whole file, and do checksum */
391 read_now = MIN(SEC_SIZE, fileleft);
392 got_now = rb->read(fd, sector, read_now);
393 fileread += got_now;
394 fileleft -= got_now;
396 if (read_now != got_now)
398 rb->close(fd);
399 return eReadErr;
402 if (has_crc)
404 crc32 = rb->crc_32(sector, got_now, crc32); /* checksum */
406 } while (fileleft);
408 if (has_crc)
410 got_now = rb->read(fd, &file_crc, sizeof(file_crc));
411 if (got_now != sizeof(file_crc))
413 rb->close(fd);
414 return eReadErr;
418 /* must be EOF now */
419 got_now = rb->read(fd, sector, SEC_SIZE);
420 rb->close(fd);
421 if (got_now != 0)
422 return eReadErr;
424 if (has_crc && file_crc != crc32)
425 return eCrcErr;
427 return eOK;
431 /* returns the # of failures, 0 on success */
432 unsigned ProgramFirmwareFile(char* filename, int chipsize)
434 int i, j;
435 int fd;
436 int read = SEC_SIZE; /* how many for this sector */
437 UINT16 keep = *(UINT16*)(FB + KEEP); /* we must keep this! */
438 unsigned failures = 0;
440 fd = rb->open(filename, O_RDONLY);
441 if (fd < 0)
442 return false;
444 for (i=0; i<chipsize; i+=SEC_SIZE)
446 if (!EraseSector(FB + i))
448 /* nothing we can do, let the programming count the errors */
451 if (read == SEC_SIZE) /* not EOF yet */
453 read = rb->read(fd, sector, SEC_SIZE);
454 if (i==0)
455 { /* put original value back in */
456 *(UINT16*)(sector + KEEP) = keep;
459 for (j=0; j<read; j++)
461 if (!ProgramByte(FB + i + j, sector[j]))
463 failures++;
469 rb->close(fd);
471 return failures;
475 /* returns the # of failures, 0 on success */
476 unsigned VerifyFirmwareFile(char* filename)
478 int i=0, j;
479 int fd;
480 int read = SEC_SIZE; /* how many for this sector */
481 unsigned failures = 0;
483 fd = rb->open(filename, O_RDONLY);
484 if (fd < 0)
485 return false;
489 read = rb->read(fd, sector, SEC_SIZE);
491 for (j=0; j<read; j++)
493 /* position of keep value is no error */
494 if (FB[i] != sector[j] && i != KEEP && i != (KEEP+1))
496 failures++;
498 i++;
501 while (read == SEC_SIZE);
503 rb->close(fd);
505 return failures;
509 /***************** Support Functions *****************/
511 /* check if we have "normal" boot ROM or flash mirrored to zero */
512 tCheckROM CheckBootROM(void)
514 unsigned boot_crc;
515 unsigned* pFlash = (unsigned*)FB;
516 unsigned* pRom = (unsigned*)0x0;
517 unsigned i;
519 boot_crc = rb->crc_32((unsigned char*)0x0, 64*1024, 0xFFFFFFFF);
520 if (boot_crc == 0x56DBA4EE /* the known boot ROM */
521 #if PLATFORM_ID == ID_PLAYER
522 /* alternative boot ROM found in one single player so far */
523 || boot_crc == 0x358099E8
524 #endif
526 return eBootROM;
528 /* check if ROM is a flash mirror */
529 for (i=0; i<256*1024/sizeof(unsigned); i++)
531 if (*pRom++ != *pFlash++)
532 { /* difference means no mirror */
533 return eUnknown;
537 return eROMless;
541 /***************** User Interface Functions *****************/
543 int WaitForButton(void)
545 int button;
549 button = rb->button_get(true);
550 } while (IS_SYSEVENT(button) || (button & BUTTON_REL));
552 return button;
555 #ifdef HAVE_LCD_BITMAP
556 /* Recorder implementation */
558 /* helper for DoUserDialog() */
559 void ShowFlashInfo(tFlashInfo* pInfo)
561 char buf[32];
563 if (!pInfo->manufacturer)
565 rb->lcd_puts(0, 0, "Flash: M=?? D=??");
566 rb->lcd_puts(0, 1, "Impossible to program");
568 else
570 rb->snprintf(buf, sizeof(buf), "Flash: M=%02x D=%02x",
571 pInfo->manufacturer, pInfo->id);
572 rb->lcd_puts(0, 0, buf);
575 if (pInfo->size)
577 rb->lcd_puts(0, 1, pInfo->name);
578 rb->snprintf(buf, sizeof(buf), "Size: %d KB", pInfo->size / 1024);
579 rb->lcd_puts(0, 2, buf);
581 else
583 rb->lcd_puts(0, 1, "Unsupported chip");
588 rb->lcd_update();
592 /* Kind of our main function, defines the application flow. */
593 void DoUserDialog(char* filename)
595 tFlashInfo FlashInfo;
596 char buf[32];
597 char default_filename[32];
598 int button;
599 int rc; /* generic return code */
600 size_t memleft;
601 tCheckROM result;
602 bool is_romless;
604 /* this can only work if Rockbox runs in DRAM, not flash ROM */
605 if ((UINT8*)rb >= FB && (UINT8*)rb < FB + 4096*1024) /* 4 MB max */
606 { /* we're running from flash */
607 rb->splash(HZ*3, "Not from ROM");
608 return; /* exit */
611 /* test if the user is running the correct plugin for this box */
612 if (!CheckPlatform(PLATFORM_ID, *(UINT16*)(FB + VERSION_ADR)))
614 rb->splash(HZ*3, "Wrong plugin");
615 return; /* exit */
618 /* refuse to work if the power may fail meanwhile */
619 if (!rb->battery_level_safe())
621 rb->splash(HZ*3, "Battery too low!");
622 return; /* exit */
625 /* check boot ROM */
626 result = CheckBootROM();
627 if (result == eUnknown)
628 { /* no support for any other yet */
629 rb->splash(HZ*3, "Wrong boot ROM");
630 return; /* exit */
632 is_romless = (result == eROMless);
634 /* compose filename if none given */
635 if (filename == NULL)
637 rb->snprintf(
638 default_filename,
639 sizeof(default_filename),
640 "/firmware_%s%s.bin",
641 FILE_TYPE,
642 is_romless ? "_norom" : "");
643 filename = default_filename;
646 /* "allocate" memory */
647 sector = rb->plugin_get_buffer(&memleft);
648 if (memleft < SEC_SIZE) /* need buffer for a flash sector */
650 rb->splash(HZ*3, "Out of memory");
651 return; /* exit */
654 rb->lcd_setfont(FONT_SYSFIXED);
656 rc = GetFlashInfo(&FlashInfo);
657 ShowFlashInfo(&FlashInfo);
658 if (FlashInfo.size == 0) /* no valid chip */
660 rb->splash(HZ*3, "Sorry!");
661 return; /* exit */
664 rb->lcd_puts(0, 3, "using file:");
665 rb->lcd_puts_scroll(0, 4, filename);
666 rb->lcd_puts(0, 6, KEYNAME1 " to check file");
667 rb->lcd_puts(0, 7, "other key to exit");
668 rb->lcd_update();
670 button = WaitForButton();
671 if (button != KEY1)
673 return;
676 rb->lcd_clear_display();
677 rb->lcd_puts(0, 0, "checking...");
678 rb->lcd_update();
680 rc = CheckFirmwareFile(filename, FlashInfo.size, is_romless);
681 rb->lcd_puts(0, 0, "checked:");
682 switch (rc)
684 case eOK:
685 rb->lcd_puts(0, 1, "File OK.");
686 break;
687 case eFileNotFound:
688 rb->lcd_puts(0, 1, "File not found.");
689 rb->lcd_puts(0, 2, "Put this in root:");
690 rb->lcd_puts_scroll(0, 4, filename);
691 break;
692 case eTooBig:
693 rb->lcd_puts(0, 1, "File too big,");
694 rb->lcd_puts(0, 2, "larger than chip.");
695 break;
696 case eTooSmall:
697 rb->lcd_puts(0, 1, "File too small.");
698 rb->lcd_puts(0, 2, "Incomplete?");
699 break;
700 case eReadErr:
701 rb->lcd_puts(0, 1, "Read error.");
702 break;
703 case eBadContent:
704 rb->lcd_puts(0, 1, "File invalid.");
705 rb->lcd_puts(0, 2, "Sanity check fail.");
706 break;
707 case eCrcErr:
708 rb->lcd_puts(0, 1, "File invalid.");
709 rb->lcd_puts(0, 2, "CRC check failed,");
710 rb->lcd_puts(0, 3, "checksum mismatch.");
711 break;
712 case eBadPlatform:
713 rb->lcd_puts(0, 1, "Wrong file for");
714 rb->lcd_puts(0, 2, "this hardware.");
715 break;
716 default:
717 rb->lcd_puts(0, 1, "Check failed.");
718 break;
721 if (rc == eOK)
723 rb->lcd_puts(0, 6, KEYNAME2 " to program");
724 rb->lcd_puts(0, 7, "other key to exit");
726 else
727 { /* error occured */
728 rb->lcd_puts(0, 6, "Any key to exit");
731 rb->lcd_update();
733 button = WaitForButton();
734 if (button != KEY2 || rc != eOK)
736 return;
739 rb->lcd_clear_display();
740 rb->lcd_puts(0, 0, "Program all Flash?");
741 rb->lcd_puts(0, 1, "Are you sure?");
742 rb->lcd_puts(0, 2, "If it goes wrong,");
743 rb->lcd_puts(0, 3, "it kills your box!");
744 rb->lcd_puts(0, 4, "See documentation.");
746 rb->lcd_puts(0, 6, KEYNAME3 " to proceed");
747 rb->lcd_puts(0, 7, "other key to exit");
748 rb->lcd_update();
750 button = WaitForButton();
751 if (button != KEY3)
753 return;
756 rb->lcd_clear_display();
757 rb->lcd_puts(0, 0, "Programming...");
758 rb->lcd_update();
760 rc = ProgramFirmwareFile(filename, FlashInfo.size);
761 if (rc)
762 { /* errors */
763 rb->lcd_clear_display();
764 rb->lcd_puts(0, 0, "Panic:");
765 rb->lcd_puts(0, 1, "Programming fail!");
766 rb->snprintf(buf, sizeof(buf), "%d errors", rc);
767 rb->lcd_puts(0, 2, buf);
768 rb->lcd_update();
769 button = WaitForButton();
772 rb->lcd_clear_display();
773 rb->lcd_puts(0, 0, "Verifying...");
774 rb->lcd_update();
776 rc = VerifyFirmwareFile(filename);
778 rb->lcd_clear_display();
779 if (rc == 0)
781 rb->lcd_puts(0, 0, "Verify OK.");
783 else
785 rb->lcd_puts(0, 0, "Panic:");
786 rb->lcd_puts(0, 1, "Verify fail!");
787 rb->snprintf(buf, sizeof(buf), "%d errors", rc);
788 rb->lcd_puts(0, 2, buf);
790 rb->lcd_puts(0, 7, "Any key to exit");
791 rb->lcd_update();
793 button = WaitForButton();
796 #else /* HAVE_LCD_BITMAP */
797 /* Player implementation */
799 /* helper for DoUserDialog() */
800 void ShowFlashInfo(tFlashInfo* pInfo)
802 char buf[32];
804 if (!pInfo->manufacturer)
806 rb->lcd_puts_scroll(0, 0, "Flash: M=? D=?");
807 rb->lcd_puts_scroll(0, 1, "Impossible to program");
808 rb->lcd_update();
809 WaitForButton();
811 else
813 rb->snprintf(buf, sizeof(buf), "Flash: M=%02x D=%02x",
814 pInfo->manufacturer, pInfo->id);
815 rb->lcd_puts_scroll(0, 0, buf);
817 if (pInfo->size)
819 rb->snprintf(buf, sizeof(buf), "Size: %d KB", pInfo->size / 1024);
820 rb->lcd_puts_scroll(0, 1, buf);
821 rb->lcd_update();
823 else
825 rb->lcd_puts_scroll(0, 1, "Unsupported chip");
826 rb->lcd_update();
827 WaitForButton();
833 void DoUserDialog(char* filename)
835 tFlashInfo FlashInfo;
836 char buf[32];
837 char default_filename[32];
838 int button;
839 int rc; /* generic return code */
840 size_t memleft;
841 tCheckROM result;
842 bool is_romless;
844 /* this can only work if Rockbox runs in DRAM, not flash ROM */
845 if ((UINT8*)rb >= FB && (UINT8*)rb < FB + 4096*1024) /* 4 MB max */
846 { /* we're running from flash */
847 rb->splash(HZ*3, "Not from ROM");
848 return; /* exit */
851 /* test if the user is running the correct plugin for this box */
852 if (!CheckPlatform(PLATFORM_ID, *(UINT16*)(FB + VERSION_ADR)))
854 rb->splash(HZ*3, "Wrong version");
855 return; /* exit */
858 /* refuse to work if the power may fail meanwhile */
859 if (!rb->battery_level_safe())
861 rb->splash(HZ*3, "Batt. too low!");
862 return; /* exit */
865 /* check boot ROM */
866 result = CheckBootROM();
867 if (result == eUnknown)
868 { /* no support for any other yet */
869 rb->splash(HZ*3, "Wrong boot ROM");
870 return; /* exit */
872 is_romless = (result == eROMless);
874 /* compose filename if none given */
875 if (filename == NULL)
877 rb->snprintf(
878 default_filename,
879 sizeof(default_filename),
880 "/firmware_%s%s.bin",
881 FILE_TYPE,
882 is_romless ? "_norom" : "");
883 filename = default_filename;
886 /* "allocate" memory */
887 sector = rb->plugin_get_buffer(&memleft);
888 if (memleft < SEC_SIZE) /* need buffer for a flash sector */
890 rb->splash(HZ*3, "Out of memory");
891 return; /* exit */
894 rc = GetFlashInfo(&FlashInfo);
895 ShowFlashInfo(&FlashInfo);
897 if (FlashInfo.size == 0) /* no valid chip */
899 return; /* exit */
902 rb->lcd_puts_scroll(0, 0, filename);
903 rb->lcd_puts_scroll(0, 1, "[Menu] to check");
904 rb->lcd_update();
906 button = WaitForButton();
907 if (button != BUTTON_MENU)
909 return;
912 rb->lcd_clear_display();
913 rb->lcd_puts(0, 0, "Checking...");
914 rb->lcd_update();
916 rc = CheckFirmwareFile(filename, FlashInfo.size, is_romless);
917 rb->lcd_puts(0, 0, "Checked:");
918 switch (rc)
920 case eOK:
921 rb->lcd_puts(0, 1, "File OK.");
922 break;
923 case eFileNotFound:
924 rb->lcd_puts_scroll(0, 0, "File not found:");
925 rb->lcd_puts_scroll(0, 1, filename);
926 break;
927 case eTooBig:
928 rb->lcd_puts_scroll(0, 0, "File too big,");
929 rb->lcd_puts_scroll(0, 1, "larger than chip.");
930 break;
931 case eTooSmall:
932 rb->lcd_puts_scroll(0, 0, "File too small.");
933 rb->lcd_puts_scroll(0, 1, "Incomplete?");
934 break;
935 case eReadErr:
936 rb->lcd_puts_scroll(0, 0, "Read error.");
937 break;
938 case eBadContent:
939 rb->lcd_puts_scroll(0, 0, "File invalid.");
940 rb->lcd_puts_scroll(0, 1, "Sanity check failed.");
941 break;
942 case eCrcErr:
943 rb->lcd_puts_scroll(0, 0, "File invalid.");
944 rb->lcd_puts_scroll(0, 1, "CRC check failed.");
945 break;
946 case eBadPlatform:
947 rb->lcd_puts_scroll(0, 0, "Wrong file for");
948 rb->lcd_puts_scroll(0, 1, "this hardware.");
949 break;
950 default:
951 rb->lcd_puts_scroll(0, 0, "Check failed.");
952 break;
954 rb->lcd_update();
956 rb->sleep(HZ*3);
958 if (rc == eOK)
960 rb->lcd_puts_scroll(0, 0, "[On] to program,");
961 rb->lcd_puts_scroll(0, 1, "other key to exit.");
962 rb->lcd_update();
964 else
965 { /* error occured */
966 return;
969 button = WaitForButton();
971 if (button != BUTTON_ON)
973 return;
976 rb->lcd_clear_display();
977 rb->lcd_puts_scroll(0, 0, "Are you sure?");
978 rb->lcd_puts_scroll(0, 1, "[+] to proceed.");
979 rb->lcd_update();
981 button = WaitForButton();
983 if (button != BUTTON_RIGHT)
985 return;
988 rb->lcd_clear_display();
989 rb->lcd_puts_scroll(0, 0, "Programming...");
990 rb->lcd_update();
992 rc = ProgramFirmwareFile(filename, FlashInfo.size);
994 if (rc)
995 { /* errors */
996 rb->lcd_clear_display();
997 rb->lcd_puts_scroll(0, 0, "Programming failed!");
998 rb->snprintf(buf, sizeof(buf), "%d errors", rc);
999 rb->lcd_puts_scroll(0, 1, buf);
1000 rb->lcd_update();
1001 WaitForButton();
1004 rb->lcd_clear_display();
1005 rb->lcd_puts_scroll(0, 0, "Verifying...");
1006 rb->lcd_update();
1008 rc = VerifyFirmwareFile(filename);
1010 rb->lcd_clear_display();
1012 if (rc == 0)
1014 rb->lcd_puts_scroll(0, 0, "Verify OK.");
1016 else
1018 rb->snprintf(buf, sizeof(buf), "Verify failed! %d errors", rc);
1019 rb->lcd_puts_scroll(0, 0, buf);
1022 rb->lcd_puts_scroll(0, 1, "Press any key to exit.");
1023 rb->lcd_update();
1024 WaitForButton();
1027 #endif /* not HAVE_LCD_BITMAP */
1030 /***************** Plugin Entry Point *****************/
1032 enum plugin_status plugin_start(const void* parameter)
1034 int oldmode;
1036 /* now go ahead and have fun! */
1037 oldmode = rb->system_memory_guard(MEMGUARD_NONE); /*disable memory guard */
1038 DoUserDialog((char*) parameter);
1039 rb->system_memory_guard(oldmode); /* re-enable memory guard */
1041 return PLUGIN_OK;
1044 #endif /* ifdef PLATFORM_ID */