Don't rebuild the dependency file on 'make reconf'. Build type and target won't chang...
[kugel-rb.git] / apps / plugins / firmware_flash.c
blobebf4242e2a625e795ca07666fb3260196ba3a9bc
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;
259 /*********** Utility Functions ************/
262 /* Tool function to calculate a CRC32 across some buffer */
263 /* third argument is either 0xFFFFFFFF to start or value from last piece */
264 unsigned crc_32(unsigned char* buf, unsigned len, unsigned crc32)
266 /* CCITT standard polynomial 0x04C11DB7 */
267 static const unsigned crc32_lookup[16] =
268 { /* lookup table for 4 bits at a time is affordable */
269 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9,
270 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,
271 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61,
272 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD
275 unsigned char byte;
276 unsigned t;
278 while (len--)
280 byte = *buf++; /* get one byte of data */
282 /* upper nibble of our data */
283 t = crc32 >> 28; /* extract the 4 most significant bits */
284 t ^= byte >> 4; /* XOR in 4 bits of data into the extracted bits */
285 crc32 <<= 4; /* shift the CRC register left 4 bits */
286 crc32 ^= crc32_lookup[t]; /* do the table lookup and XOR the result */
288 /* lower nibble of our data */
289 t = crc32 >> 28; /* extract the 4 most significant bits */
290 t ^= byte & 0x0F; /* XOR in 4 bits of data into the extracted bits */
291 crc32 <<= 4; /* shift the CRC register left 4 bits */
292 crc32 ^= crc32_lookup[t]; /* do the table lookup and XOR the result */
295 return crc32;
299 /*********** Firmware File Functions + helpers ************/
301 /* test if the version number is consistent with the platform */
302 bool CheckPlatform(int platform_id, UINT16 version)
304 if (version == 200)
305 { /* for my very first firmwares, I foolishly changed it to 200 */
306 return (platform_id == ID_RECORDER || platform_id == ID_FM);
308 else if (version == 123)
309 { /* it can be a FM or V2 recorder */
310 return (platform_id == ID_FM || platform_id == ID_REC_V2);
312 else if (version == 132)
313 { /* newer Ondio, and seen on a V2 recorder */
314 return (platform_id == ID_ONDIO_SP || platform_id == ID_ONDIO_FM
315 || platform_id == ID_REC_V2);
317 else if (version == 104)
318 { /* classic Ondio128 */
319 return (platform_id == ID_ONDIO_FM);
321 else if (version >= 115 && version <= 129)
322 { /* the range of Recorders seen so far */
323 return (platform_id == ID_RECORDER);
325 else if (version == 0 || (version >= 300 && version <= 508))
326 { /* for very old players, I've seen zero */
327 return (platform_id == ID_PLAYER);
330 return false; /* unknown */
334 tCheckResult CheckFirmwareFile(char* filename, int chipsize, bool is_romless)
336 int i;
337 int fd;
338 int fileleft; /* size info, how many left for reading */
339 int fileread = 0; /* total size as read from the file */
340 int read_now; /* how many to read for this sector */
341 int got_now; /* how many gotten for this sector */
342 unsigned crc32 = 0xFFFFFFFF; /* CCITT init value */
343 unsigned file_crc; /* CRC value read from file */
344 bool has_crc;
346 fd = rb->open(filename, O_RDONLY);
347 if (fd < 0)
348 return eFileNotFound;
350 fileleft = rb->filesize(fd);
351 if (fileleft > chipsize)
353 rb->close(fd);
354 return eTooBig;
356 else if (fileleft < 20000) /* give it some reasonable lower limit */
358 rb->close(fd);
359 return eTooSmall;
362 if (fileleft == 256*1024)
363 { /* original dumped firmware file has no CRC nor platform ID */
364 has_crc = false;
366 else
368 has_crc = true;
369 fileleft -= sizeof(unsigned); /* exclude the last 4 bytes */
372 /* do some sanity checks */
374 got_now = rb->read(fd, sector, SEC_SIZE); /* read first sector */
375 fileread += got_now;
376 fileleft -= got_now;
377 if (got_now != SEC_SIZE)
379 rb->close(fd);
380 return eReadErr;
383 /* version number in file plausible with this hardware? */
384 if (!CheckPlatform(PLATFORM_ID, *(UINT16*)(sector + VERSION_ADR)))
386 rb->close(fd);
387 return eBadPlatform;
390 if (has_crc)
392 crc32 = crc_32(sector, SEC_SIZE, crc32); /* checksum */
394 /* in addition to the CRC, my files also have a platform ID */
395 if (sector[PLATFORM_ADR] != PLATFORM_ID) /* for our hardware? */
397 rb->close(fd);
398 return eBadPlatform;
402 if (is_romless)
403 { /* in this case, there is not much we can check */
404 if (*(UINT32*)sector != 0x00000200) /* reset vector */
406 rb->close(fd);
407 return eBadContent;
410 else
412 /* compare some bytes which have to be identical */
413 if (*(UINT32*)sector != 0x41524348) /* "ARCH" */
415 rb->close(fd);
416 return eBadContent;
419 for (i = 0x30; i<MASK_ADR-2; i++) /* leave two bytes for me */
421 if (sector[i] != FB[i])
423 rb->close(fd);
424 return eBadContent;
429 /* check if we can read the whole file, and do checksum */
432 read_now = MIN(SEC_SIZE, fileleft);
433 got_now = rb->read(fd, sector, read_now);
434 fileread += got_now;
435 fileleft -= got_now;
437 if (read_now != got_now)
439 rb->close(fd);
440 return eReadErr;
443 if (has_crc)
445 crc32 = crc_32(sector, got_now, crc32); /* checksum */
447 } while (fileleft);
449 if (has_crc)
451 got_now = rb->read(fd, &file_crc, sizeof(file_crc));
452 if (got_now != sizeof(file_crc))
454 rb->close(fd);
455 return eReadErr;
459 /* must be EOF now */
460 got_now = rb->read(fd, sector, SEC_SIZE);
461 rb->close(fd);
462 if (got_now != 0)
463 return eReadErr;
465 if (has_crc && file_crc != crc32)
466 return eCrcErr;
468 return eOK;
472 /* returns the # of failures, 0 on success */
473 unsigned ProgramFirmwareFile(char* filename, int chipsize)
475 int i, j;
476 int fd;
477 int read = SEC_SIZE; /* how many for this sector */
478 UINT16 keep = *(UINT16*)(FB + KEEP); /* we must keep this! */
479 unsigned failures = 0;
481 fd = rb->open(filename, O_RDONLY);
482 if (fd < 0)
483 return false;
485 for (i=0; i<chipsize; i+=SEC_SIZE)
487 if (!EraseSector(FB + i))
489 /* nothing we can do, let the programming count the errors */
492 if (read == SEC_SIZE) /* not EOF yet */
494 read = rb->read(fd, sector, SEC_SIZE);
495 if (i==0)
496 { /* put original value back in */
497 *(UINT16*)(sector + KEEP) = keep;
500 for (j=0; j<read; j++)
502 if (!ProgramByte(FB + i + j, sector[j]))
504 failures++;
510 rb->close(fd);
512 return failures;
516 /* returns the # of failures, 0 on success */
517 unsigned VerifyFirmwareFile(char* filename)
519 int i=0, j;
520 int fd;
521 int read = SEC_SIZE; /* how many for this sector */
522 unsigned failures = 0;
524 fd = rb->open(filename, O_RDONLY);
525 if (fd < 0)
526 return false;
530 read = rb->read(fd, sector, SEC_SIZE);
532 for (j=0; j<read; j++)
534 /* position of keep value is no error */
535 if (FB[i] != sector[j] && i != KEEP && i != (KEEP+1))
537 failures++;
539 i++;
542 while (read == SEC_SIZE);
544 rb->close(fd);
546 return failures;
550 /***************** Support Functions *****************/
552 /* check if we have "normal" boot ROM or flash mirrored to zero */
553 tCheckROM CheckBootROM(void)
555 unsigned boot_crc;
556 unsigned* pFlash = (unsigned*)FB;
557 unsigned* pRom = (unsigned*)0x0;
558 unsigned i;
560 boot_crc = crc_32((unsigned char*)0x0, 64*1024, 0xFFFFFFFF);
561 if (boot_crc == 0x56DBA4EE /* the known boot ROM */
562 #if PLATFORM_ID == ID_PLAYER
563 /* alternative boot ROM found in one single player so far */
564 || boot_crc == 0x358099E8
565 #endif
567 return eBootROM;
569 /* check if ROM is a flash mirror */
570 for (i=0; i<256*1024/sizeof(unsigned); i++)
572 if (*pRom++ != *pFlash++)
573 { /* difference means no mirror */
574 return eUnknown;
578 return eROMless;
582 /***************** User Interface Functions *****************/
584 int WaitForButton(void)
586 int button;
590 button = rb->button_get(true);
591 } while (IS_SYSEVENT(button) || (button & BUTTON_REL));
593 return button;
596 #ifdef HAVE_LCD_BITMAP
597 /* Recorder implementation */
599 /* helper for DoUserDialog() */
600 void ShowFlashInfo(tFlashInfo* pInfo)
602 char buf[32];
604 if (!pInfo->manufacturer)
606 rb->lcd_puts(0, 0, "Flash: M=?? D=??");
607 rb->lcd_puts(0, 1, "Impossible to program");
609 else
611 rb->snprintf(buf, sizeof(buf), "Flash: M=%02x D=%02x",
612 pInfo->manufacturer, pInfo->id);
613 rb->lcd_puts(0, 0, buf);
616 if (pInfo->size)
618 rb->lcd_puts(0, 1, pInfo->name);
619 rb->snprintf(buf, sizeof(buf), "Size: %d KB", pInfo->size / 1024);
620 rb->lcd_puts(0, 2, buf);
622 else
624 rb->lcd_puts(0, 1, "Unsupported chip");
629 rb->lcd_update();
633 /* Kind of our main function, defines the application flow. */
634 void DoUserDialog(char* filename)
636 tFlashInfo FlashInfo;
637 char buf[32];
638 char default_filename[32];
639 int button;
640 int rc; /* generic return code */
641 ssize_t memleft;
642 tCheckROM result;
643 bool is_romless;
645 /* this can only work if Rockbox runs in DRAM, not flash ROM */
646 if ((UINT8*)rb >= FB && (UINT8*)rb < FB + 4096*1024) /* 4 MB max */
647 { /* we're running from flash */
648 rb->splash(HZ*3, "Not from ROM");
649 return; /* exit */
652 /* test if the user is running the correct plugin for this box */
653 if (!CheckPlatform(PLATFORM_ID, *(UINT16*)(FB + VERSION_ADR)))
655 rb->splash(HZ*3, "Wrong plugin");
656 return; /* exit */
659 /* refuse to work if the power may fail meanwhile */
660 if (!rb->battery_level_safe())
662 rb->splash(HZ*3, "Battery too low!");
663 return; /* exit */
666 /* check boot ROM */
667 result = CheckBootROM();
668 if (result == eUnknown)
669 { /* no support for any other yet */
670 rb->splash(HZ*3, "Wrong boot ROM");
671 return; /* exit */
673 is_romless = (result == eROMless);
675 /* compose filename if none given */
676 if (filename == NULL)
678 rb->snprintf(
679 default_filename,
680 sizeof(default_filename),
681 "/firmware_%s%s.bin",
682 FILE_TYPE,
683 is_romless ? "_norom" : "");
684 filename = default_filename;
687 /* "allocate" memory */
688 sector = rb->plugin_get_buffer((size_t *)&memleft);
689 if (memleft < SEC_SIZE) /* need buffer for a flash sector */
691 rb->splash(HZ*3, "Out of memory");
692 return; /* exit */
695 rb->lcd_setfont(FONT_SYSFIXED);
697 rc = GetFlashInfo(&FlashInfo);
698 ShowFlashInfo(&FlashInfo);
699 if (FlashInfo.size == 0) /* no valid chip */
701 rb->splash(HZ*3, "Sorry!");
702 return; /* exit */
705 rb->lcd_puts(0, 3, "using file:");
706 rb->lcd_puts_scroll(0, 4, filename);
707 rb->lcd_puts(0, 6, KEYNAME1 " to check file");
708 rb->lcd_puts(0, 7, "other key to exit");
709 rb->lcd_update();
711 button = WaitForButton();
712 if (button != KEY1)
714 return;
717 rb->lcd_clear_display();
718 rb->lcd_puts(0, 0, "checking...");
719 rb->lcd_update();
721 rc = CheckFirmwareFile(filename, FlashInfo.size, is_romless);
722 rb->lcd_puts(0, 0, "checked:");
723 switch (rc)
725 case eOK:
726 rb->lcd_puts(0, 1, "File OK.");
727 break;
728 case eFileNotFound:
729 rb->lcd_puts(0, 1, "File not found.");
730 rb->lcd_puts(0, 2, "Put this in root:");
731 rb->lcd_puts_scroll(0, 4, filename);
732 break;
733 case eTooBig:
734 rb->lcd_puts(0, 1, "File too big,");
735 rb->lcd_puts(0, 2, "larger than chip.");
736 break;
737 case eTooSmall:
738 rb->lcd_puts(0, 1, "File too small.");
739 rb->lcd_puts(0, 2, "Incomplete?");
740 break;
741 case eReadErr:
742 rb->lcd_puts(0, 1, "Read error.");
743 break;
744 case eBadContent:
745 rb->lcd_puts(0, 1, "File invalid.");
746 rb->lcd_puts(0, 2, "Sanity check fail.");
747 break;
748 case eCrcErr:
749 rb->lcd_puts(0, 1, "File invalid.");
750 rb->lcd_puts(0, 2, "CRC check failed,");
751 rb->lcd_puts(0, 3, "checksum mismatch.");
752 break;
753 case eBadPlatform:
754 rb->lcd_puts(0, 1, "Wrong file for");
755 rb->lcd_puts(0, 2, "this hardware.");
756 break;
757 default:
758 rb->lcd_puts(0, 1, "Check failed.");
759 break;
762 if (rc == eOK)
764 rb->lcd_puts(0, 6, KEYNAME2 " to program");
765 rb->lcd_puts(0, 7, "other key to exit");
767 else
768 { /* error occured */
769 rb->lcd_puts(0, 6, "Any key to exit");
772 rb->lcd_update();
774 button = WaitForButton();
775 if (button != KEY2 || rc != eOK)
777 return;
780 rb->lcd_clear_display();
781 rb->lcd_puts(0, 0, "Program all Flash?");
782 rb->lcd_puts(0, 1, "Are you sure?");
783 rb->lcd_puts(0, 2, "If it goes wrong,");
784 rb->lcd_puts(0, 3, "it kills your box!");
785 rb->lcd_puts(0, 4, "See documentation.");
787 rb->lcd_puts(0, 6, KEYNAME3 " to proceed");
788 rb->lcd_puts(0, 7, "other key to exit");
789 rb->lcd_update();
791 button = WaitForButton();
792 if (button != KEY3)
794 return;
797 rb->lcd_clear_display();
798 rb->lcd_puts(0, 0, "Programming...");
799 rb->lcd_update();
801 rc = ProgramFirmwareFile(filename, FlashInfo.size);
802 if (rc)
803 { /* errors */
804 rb->lcd_clear_display();
805 rb->lcd_puts(0, 0, "Panic:");
806 rb->lcd_puts(0, 1, "Programming fail!");
807 rb->snprintf(buf, sizeof(buf), "%d errors", rc);
808 rb->lcd_puts(0, 2, buf);
809 rb->lcd_update();
810 button = WaitForButton();
813 rb->lcd_clear_display();
814 rb->lcd_puts(0, 0, "Verifying...");
815 rb->lcd_update();
817 rc = VerifyFirmwareFile(filename);
819 rb->lcd_clear_display();
820 if (rc == 0)
822 rb->lcd_puts(0, 0, "Verify OK.");
824 else
826 rb->lcd_puts(0, 0, "Panic:");
827 rb->lcd_puts(0, 1, "Verify fail!");
828 rb->snprintf(buf, sizeof(buf), "%d errors", rc);
829 rb->lcd_puts(0, 2, buf);
831 rb->lcd_puts(0, 7, "Any key to exit");
832 rb->lcd_update();
834 button = WaitForButton();
837 #else /* HAVE_LCD_BITMAP */
838 /* Player implementation */
840 /* helper for DoUserDialog() */
841 void ShowFlashInfo(tFlashInfo* pInfo)
843 char buf[32];
845 if (!pInfo->manufacturer)
847 rb->lcd_puts_scroll(0, 0, "Flash: M=? D=?");
848 rb->lcd_puts_scroll(0, 1, "Impossible to program");
849 rb->lcd_update();
850 WaitForButton();
852 else
854 rb->snprintf(buf, sizeof(buf), "Flash: M=%02x D=%02x",
855 pInfo->manufacturer, pInfo->id);
856 rb->lcd_puts_scroll(0, 0, buf);
858 if (pInfo->size)
860 rb->snprintf(buf, sizeof(buf), "Size: %d KB", pInfo->size / 1024);
861 rb->lcd_puts_scroll(0, 1, buf);
862 rb->lcd_update();
864 else
866 rb->lcd_puts_scroll(0, 1, "Unsupported chip");
867 rb->lcd_update();
868 WaitForButton();
874 void DoUserDialog(char* filename)
876 tFlashInfo FlashInfo;
877 char buf[32];
878 char default_filename[32];
879 int button;
880 int rc; /* generic return code */
881 ssize_t memleft;
882 tCheckROM result;
883 bool is_romless;
885 /* this can only work if Rockbox runs in DRAM, not flash ROM */
886 if ((UINT8*)rb >= FB && (UINT8*)rb < FB + 4096*1024) /* 4 MB max */
887 { /* we're running from flash */
888 rb->splash(HZ*3, "Not from ROM");
889 return; /* exit */
892 /* test if the user is running the correct plugin for this box */
893 if (!CheckPlatform(PLATFORM_ID, *(UINT16*)(FB + VERSION_ADR)))
895 rb->splash(HZ*3, "Wrong version");
896 return; /* exit */
899 /* refuse to work if the power may fail meanwhile */
900 if (!rb->battery_level_safe())
902 rb->splash(HZ*3, "Batt. too low!");
903 return; /* exit */
906 /* check boot ROM */
907 result = CheckBootROM();
908 if (result == eUnknown)
909 { /* no support for any other yet */
910 rb->splash(HZ*3, "Wrong boot ROM");
911 return; /* exit */
913 is_romless = (result == eROMless);
915 /* compose filename if none given */
916 if (filename == NULL)
918 rb->snprintf(
919 default_filename,
920 sizeof(default_filename),
921 "/firmware_%s%s.bin",
922 FILE_TYPE,
923 is_romless ? "_norom" : "");
924 filename = default_filename;
927 /* "allocate" memory */
928 sector = rb->plugin_get_buffer((size_t *)&memleft);
929 if (memleft < SEC_SIZE) /* need buffer for a flash sector */
931 rb->splash(HZ*3, "Out of memory");
932 return; /* exit */
935 rc = GetFlashInfo(&FlashInfo);
936 ShowFlashInfo(&FlashInfo);
938 if (FlashInfo.size == 0) /* no valid chip */
940 return; /* exit */
943 rb->lcd_puts_scroll(0, 0, filename);
944 rb->lcd_puts_scroll(0, 1, "[Menu] to check");
945 rb->lcd_update();
947 button = WaitForButton();
948 if (button != BUTTON_MENU)
950 return;
953 rb->lcd_clear_display();
954 rb->lcd_puts(0, 0, "Checking...");
955 rb->lcd_update();
957 rc = CheckFirmwareFile(filename, FlashInfo.size, is_romless);
958 rb->lcd_puts(0, 0, "Checked:");
959 switch (rc)
961 case eOK:
962 rb->lcd_puts(0, 1, "File OK.");
963 break;
964 case eFileNotFound:
965 rb->lcd_puts_scroll(0, 0, "File not found:");
966 rb->lcd_puts_scroll(0, 1, filename);
967 break;
968 case eTooBig:
969 rb->lcd_puts_scroll(0, 0, "File too big,");
970 rb->lcd_puts_scroll(0, 1, "larger than chip.");
971 break;
972 case eTooSmall:
973 rb->lcd_puts_scroll(0, 0, "File too small.");
974 rb->lcd_puts_scroll(0, 1, "Incomplete?");
975 break;
976 case eReadErr:
977 rb->lcd_puts_scroll(0, 0, "Read error.");
978 break;
979 case eBadContent:
980 rb->lcd_puts_scroll(0, 0, "File invalid.");
981 rb->lcd_puts_scroll(0, 1, "Sanity check failed.");
982 break;
983 case eCrcErr:
984 rb->lcd_puts_scroll(0, 0, "File invalid.");
985 rb->lcd_puts_scroll(0, 1, "CRC check failed.");
986 break;
987 case eBadPlatform:
988 rb->lcd_puts_scroll(0, 0, "Wrong file for");
989 rb->lcd_puts_scroll(0, 1, "this hardware.");
990 break;
991 default:
992 rb->lcd_puts_scroll(0, 0, "Check failed.");
993 break;
995 rb->lcd_update();
997 rb->sleep(HZ*3);
999 if (rc == eOK)
1001 rb->lcd_puts_scroll(0, 0, "[On] to program,");
1002 rb->lcd_puts_scroll(0, 1, "other key to exit.");
1003 rb->lcd_update();
1005 else
1006 { /* error occured */
1007 return;
1010 button = WaitForButton();
1012 if (button != BUTTON_ON)
1014 return;
1017 rb->lcd_clear_display();
1018 rb->lcd_puts_scroll(0, 0, "Are you sure?");
1019 rb->lcd_puts_scroll(0, 1, "[+] to proceed.");
1020 rb->lcd_update();
1022 button = WaitForButton();
1024 if (button != BUTTON_RIGHT)
1026 return;
1029 rb->lcd_clear_display();
1030 rb->lcd_puts_scroll(0, 0, "Programming...");
1031 rb->lcd_update();
1033 rc = ProgramFirmwareFile(filename, FlashInfo.size);
1035 if (rc)
1036 { /* errors */
1037 rb->lcd_clear_display();
1038 rb->lcd_puts_scroll(0, 0, "Programming failed!");
1039 rb->snprintf(buf, sizeof(buf), "%d errors", rc);
1040 rb->lcd_puts_scroll(0, 1, buf);
1041 rb->lcd_update();
1042 WaitForButton();
1045 rb->lcd_clear_display();
1046 rb->lcd_puts_scroll(0, 0, "Verifying...");
1047 rb->lcd_update();
1049 rc = VerifyFirmwareFile(filename);
1051 rb->lcd_clear_display();
1053 if (rc == 0)
1055 rb->lcd_puts_scroll(0, 0, "Verify OK.");
1057 else
1059 rb->snprintf(buf, sizeof(buf), "Verify failed! %d errors", rc);
1060 rb->lcd_puts_scroll(0, 0, buf);
1063 rb->lcd_puts_scroll(0, 1, "Press any key to exit.");
1064 rb->lcd_update();
1065 WaitForButton();
1068 #endif /* not HAVE_LCD_BITMAP */
1071 /***************** Plugin Entry Point *****************/
1073 enum plugin_status plugin_start(const void* parameter)
1075 int oldmode;
1077 /* now go ahead and have fun! */
1078 oldmode = rb->system_memory_guard(MEMGUARD_NONE); /*disable memory guard */
1079 DoUserDialog((char*) parameter);
1080 rb->system_memory_guard(oldmode); /* re-enable memory guard */
1082 return PLUGIN_OK;
1085 #endif /* ifdef PLATFORM_ID */