Prepare new maemo release
[maemo-rb.git] / apps / plugins / rockbox_flash.c
blob4837b03fb5d3623264c4d7ead279e538805f9b07
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Plugin for reprogramming only the second image in Flash ROM.
11 * !!! DON'T MESS WITH THIS CODE UNLESS YOU'RE ABSOLUTELY SURE WHAT YOU DO !!!
13 * Copyright (C) 2003 Jörg Hohensohn aka [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 #define LATEST_BOOTLOADER_VERSION 3 /* update this with the bootloader */
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 /* hard-coded values */
44 static volatile UINT8* FB = (UINT8*)0x02000000; /* Flash base address */
45 #define SECTORSIZE 4096 /* size of one flash sector */
47 #define ROCKBOX_DEST 0x09000000
48 #define ROCKBOX_EXEC 0x09000200
49 #define BOOT_VERS_ADR 0xFA /* position of bootloader version value in Flash */
50 #define FW_VERS_ADR 0xFE /* position of firmware version value in Flash */
51 #define UCL_HEADER 26 /* size of the header generated by uclpack */
53 #if CONFIG_KEYPAD == ONDIO_PAD /* limited keypad */
54 #define KEY1 BUTTON_LEFT
55 #define KEY2 BUTTON_UP
56 #define KEYNAME1 "Left"
57 #define KEYNAME2 "Up"
58 #else /* recorder keypad */
59 #define KEY1 BUTTON_F1
60 #define KEY2 BUTTON_F2
61 #define KEYNAME1 "F1"
62 #define KEYNAME2 "F2"
63 #endif
65 typedef struct
67 UINT32 destination; /* address to copy it to */
68 UINT32 size; /* how many bytes of payload (to the next header) */
69 UINT32 execute; /* entry point */
70 UINT32 flags; /* uncompressed or compressed */
71 /* end of header, now comes the payload */
72 } tImageHeader;
74 /* result of the CheckFirmwareFile() function */
75 typedef enum
77 eOK = 0,
78 eFileNotFound, /* errors from here on */
79 eTooBig,
80 eTooSmall,
81 eReadErr,
82 eNotUCL,
83 eWrongAlgorithm,
84 eMultiBlocks,
85 eBadRomLink
86 } tCheckResult;
88 typedef struct
90 UINT8 manufacturer;
91 UINT8 id;
92 int size;
93 char name[32];
94 } tFlashInfo;
96 static UINT8* sector; /* better not place this on the stack... */
98 /***************** Flash Functions *****************/
101 /* read the manufacturer and device ID */
102 static bool ReadID(volatile UINT8* pBase, UINT8* pManufacturerID,
103 UINT8* pDeviceID)
105 UINT8 not_manu, not_id; /* read values before switching to ID mode */
106 UINT8 manu, id; /* read values when in ID mode */
108 pBase = (UINT8*)((UINT32)pBase & 0xFFF80000); /* round down to 512k align,
109 to make sure */
111 not_manu = pBase[0]; /* read the normal content */
112 not_id = pBase[1]; /* should be 'A' (0x41) and 'R' (0x52) from the
113 "ARCH" marker */
115 pBase[0x5555] = 0xAA; /* enter command mode */
116 pBase[0x2AAA] = 0x55;
117 pBase[0x5555] = 0x90; /* ID command */
118 rb->sleep(HZ/50); /* Atmel wants 20ms pause here */
120 manu = pBase[0];
121 id = pBase[1];
123 pBase[0] = 0xF0; /* reset flash (back to normal read mode) */
124 rb->sleep(HZ/50); /* Atmel wants 20ms pause here */
126 /* I assume success if the obtained values are different from
127 the normal flash content. This is not perfectly bulletproof, they
128 could theoretically be the same by chance, causing us to fail. */
129 if (not_manu != manu || not_id != id) /* a value has changed */
131 *pManufacturerID = manu; /* return the results */
132 *pDeviceID = id;
133 return true; /* success */
135 return false; /* fail */
138 /* erase the sector which contains the given address */
139 static bool EraseSector(volatile UINT8* pAddr)
141 #ifdef DUMMY
142 (void)pAddr; /* prevents warning */
143 return true;
144 #else
145 volatile UINT8* pBase =
146 (UINT8*)((UINT32)pAddr & 0xFFF80000); /* round down to 512k align */
147 unsigned timeout = 43000; /* the timeout loop should be no less than
148 25ms */
150 pBase[0x5555] = 0xAA; /* enter command mode */
151 pBase[0x2AAA] = 0x55;
152 pBase[0x5555] = 0x80; /* erase command */
153 pBase[0x5555] = 0xAA; /* enter command mode */
154 pBase[0x2AAA] = 0x55;
155 *pAddr = 0x30; /* erase the sector */
157 /* I counted 7 instructions for this loop -> min. 0.58 us per round
158 Plus memory waitstates it will be much more, gives margin */
159 while (*pAddr != 0xFF && --timeout); /* poll for erased */
161 return (timeout != 0);
162 #endif
165 /* address must be in an erased location */
166 static inline bool ProgramByte(volatile UINT8* pAddr, UINT8 data)
168 #ifdef DUMMY
169 (void)pAddr; /* prevents warnings */
170 (void)data;
171 return true;
172 #else
173 unsigned timeout = 35; /* the timeout loop should be no less than 20us */
175 if (~*pAddr & data) /* just a safety feature, not really necessary */
176 return false; /* can't set any bit from 0 to 1 */
178 FB[0x5555] = 0xAA; /* enter command mode */
179 FB[0x2AAA] = 0x55;
180 FB[0x5555] = 0xA0; /* byte program command */
182 *pAddr = data;
184 /* I counted 7 instructions for this loop -> min. 0.58 us per round
185 Plus memory waitstates it will be much more, gives margin */
186 while (*pAddr != data && --timeout); /* poll for programmed */
188 return (timeout != 0);
189 #endif
192 /* this returns true if supported and fills the info struct */
193 static bool GetFlashInfo(tFlashInfo* pInfo)
195 rb->memset(pInfo, 0, sizeof(tFlashInfo));
197 if (!ReadID(FB, &pInfo->manufacturer, &pInfo->id))
198 return false;
200 if (pInfo->manufacturer == 0xBF) /* SST */
202 if (pInfo->id == 0xD6)
204 pInfo->size = 256* 1024; /* 256k */
205 rb->strcpy(pInfo->name, "SST39VF020");
206 return true;
208 else if (pInfo->id == 0xD7)
210 pInfo->size = 512* 1024; /* 512k */
211 rb->strcpy(pInfo->name, "SST39VF040");
212 return true;
214 else
215 return false;
217 return false;
221 /*********** Tool Functions ************/
223 /* read a 32 bit value from memory, big endian */
224 static UINT32 Read32(UINT8* pByte)
226 UINT32 value;
228 value = (UINT32)pByte[0] << 24;
229 value |= (UINT32)pByte[1] << 16;
230 value |= (UINT32)pByte[2] << 8;
231 value |= (UINT32)pByte[3];
233 return value;
236 /* get the start address of the second image */
237 static tImageHeader* GetSecondImage(void)
239 tImageHeader* pImage1;
240 UINT32 pos = 0; /* default: not found */
241 UINT32* pFlash = (UINT32*)FB;
243 /* determine the first image position */
244 pos = pFlash[2] + pFlash[3]; /* position + size of the bootloader
245 = after it */
246 pos = (pos + 3) & ~3; /* be sure it's 32 bit aligned */
247 pImage1 = (tImageHeader*)pos;
249 if (pImage1->destination != ROCKBOX_DEST ||
250 pImage1->execute != ROCKBOX_EXEC)
251 return 0; /* seems to be no Archos/Rockbox image in here */
253 if (pImage1->size != 0)
255 /* success, we have a second image */
256 pos = (UINT32)pImage1 + sizeof(tImageHeader) + pImage1->size;
257 if (((pos + SECTORSIZE-1) & ~(SECTORSIZE-1)) != pos)
258 { /* not sector-aligned */
259 pos = 0; /* sanity check failed */
263 return (tImageHeader*)pos;
266 /* return bootloader version */
267 static inline unsigned BootloaderVersion(void)
269 return FB[BOOT_VERS_ADR];
272 /*********** Image File Functions ************/
274 /* so far, only compressed images in UCL NRV algorithm 2e supported */
275 tCheckResult CheckImageFile(char* filename, int space,
276 tImageHeader* pHeader, UINT8* pos)
278 int i;
279 int fd;
280 int filesize; /* size info */
282 int fileread = 0; /* total size as read from the file */
283 int read; /* how many for this sector */
285 /* magic file header for compressed files */
286 static const UINT8 magic[8] = { 0x00,0xe9,0x55,0x43,0x4c,0xff,0x01,0x1a };
287 UINT8 ucl_header[UCL_HEADER];
289 fd = rb->open(filename, O_RDONLY);
290 if (fd < 0)
291 return eFileNotFound;
293 filesize = rb->filesize(fd);
294 if (filesize - (int)sizeof(ucl_header) - 8 > space)
296 rb->close(fd);
297 return eTooBig;
299 else if (filesize < 10000) /* give it some reasonable lower limit */
301 rb->close(fd);
302 return eTooSmall;
305 /* do some sanity checks */
307 read = rb->read(fd, ucl_header, sizeof(ucl_header));
308 fileread += read;
309 if (read != sizeof(ucl_header))
311 rb->close(fd);
312 return eReadErr;
315 /* compare the magic header */
316 for (i=0; i<8; i++)
318 if (ucl_header[i] != magic[i])
320 rb->close(fd);
321 return eNotUCL;
325 pHeader->size = Read32(ucl_header + 22); /* compressed size */
326 if (pHeader->size != filesize - sizeof(ucl_header) - 8)
328 rb->close(fd);
329 return eMultiBlocks;
332 /* fill in the hardcoded defaults of the header */
333 pHeader->destination = ROCKBOX_DEST;
334 pHeader->execute = ROCKBOX_EXEC;
336 if (Read32(ucl_header + 18) > pHeader->size) /* compare with uncompressed
337 size */
338 { /* compressed, normal case */
339 pHeader->flags = 0x00000001; /* flags for UCL compressed */
341 /* check for supported algorithm */
342 if (ucl_header[12] != 0x2E)
344 rb->close(fd);
345 return eWrongAlgorithm;
348 else
349 { /* uncompressed, either to be copied or run directly in flash */
350 UINT32 reset_vector; /* image has to start with reset vector */
352 pHeader->flags = 0x00000000; /* uncompressed */
354 read = rb->read(fd, &reset_vector, sizeof(reset_vector));
355 fileread += read;
356 if (read != sizeof(reset_vector))
358 rb->close(fd);
359 return eReadErr;
361 if (reset_vector >= (UINT32)FB
362 && reset_vector < (UINT32)FB+512*1024) /* ROM address? */
364 /* assume in-place, executing directly in flash */
365 pHeader->destination = (UINT32)(pos + sizeof(tImageHeader));
367 /* for new RomBox, this isn't the reset vector,
368 but the link address, for us to check the position */
369 if(pHeader->destination != reset_vector) /* compare link addr. */
371 rb->close(fd);
372 return eBadRomLink; /* not matching the start address */
375 /* read the now following reset vector */
376 read = rb->read(fd, &reset_vector, sizeof(reset_vector));
377 fileread += read;
378 if (read != sizeof(reset_vector))
380 rb->close(fd);
381 return eReadErr;
385 pHeader->execute = reset_vector;
388 /* check if we can read the whole file */
391 read = rb->read(fd, sector, SECTORSIZE);
392 fileread += read;
393 } while (read == SECTORSIZE);
395 rb->close(fd);
397 if (fileread != filesize)
398 return eReadErr;
400 return eOK;
404 /* returns the # of failures, 0 on success */
405 static unsigned ProgramImageFile(char* filename, UINT8* pos,
406 tImageHeader* pImageHeader,
407 int start, int size)
409 int i;
410 int fd;
411 int read; /* how many for this sector */
412 unsigned failures = 0;
414 fd = rb->open(filename, O_RDONLY);
415 if (fd < 0)
416 return false;
418 /* no error checking necessary here, we checked for minimum size
419 already */
420 rb->lseek(fd, start, SEEK_SET); /* go to start position */
422 *(tImageHeader*)sector = *pImageHeader; /* copy header into sector
423 buffer */
424 read = rb->read(fd, sector + sizeof(tImageHeader),
425 SECTORSIZE - sizeof(tImageHeader)); /* payload behind */
426 size -= read;
427 read += sizeof(tImageHeader); /* to be programmed, but not part of the
428 file */
430 do {
431 if (!EraseSector(pos))
433 /* nothing we can do, let the programming count the errors */
436 for (i=0; i<read; i++)
438 if (!ProgramByte(pos + i, sector[i]))
440 failures++;
444 pos += SECTORSIZE;
445 read = rb->read(fd, sector, (size > SECTORSIZE) ? SECTORSIZE : size);
446 /* payload for next sector */
447 size -= read;
448 } while (read > 0);
450 rb->close(fd);
452 return failures;
455 /* returns the # of failures, 0 on success */
456 static unsigned VerifyImageFile(char* filename, UINT8* pos,
457 tImageHeader* pImageHeader,
458 int start, int size)
460 int i;
461 int fd;
462 int read; /* how many for this sector */
463 unsigned failures = 0;
465 fd = rb->open(filename, O_RDONLY);
466 if (fd < 0)
467 return false;
469 /* no error checking necessary here, we checked for minimum size
470 already */
471 rb->lseek(fd, start, SEEK_SET); /* go to start position */
473 *(tImageHeader*)sector = *pImageHeader; /* copy header into sector
474 buffer */
475 read = rb->read(fd, sector + sizeof(tImageHeader),
476 SECTORSIZE - sizeof(tImageHeader)); /* payload behind */
478 size -= read;
479 read += sizeof(tImageHeader); /* to be programmed, but not part of the
480 file */
484 for (i=0; i<read; i++)
486 if (pos[i] != sector[i])
488 failures++;
492 pos += SECTORSIZE;
493 read = rb->read(fd, sector, (size > SECTORSIZE) ? SECTORSIZE : size);
494 /* payload for next sector */
495 size -= read;
496 } while (read);
498 rb->close(fd);
500 return failures;
504 /***************** User Interface Functions *****************/
506 static int WaitForButton(void)
508 int button;
512 button = rb->button_get(true);
513 } while (IS_SYSEVENT(button) || (button & BUTTON_REL));
515 return button;
518 #ifdef HAVE_LCD_BITMAP
519 /* helper for DoUserDialog() */
520 static void ShowFlashInfo(tFlashInfo* pInfo, tImageHeader* pImageHeader)
522 char buf[32];
524 if (!pInfo->manufacturer)
526 rb->lcd_puts_scroll(0, 0, "Flash: M=?? D=??");
528 else
530 if (pInfo->size)
532 rb->snprintf(buf, sizeof(buf), "Flash size: %d KB",
533 pInfo->size / 1024);
534 rb->lcd_puts_scroll(0, 0, buf);
536 else
538 rb->lcd_puts_scroll(0, 0, "Unsupported chip");
543 if (pImageHeader)
545 rb->snprintf(buf, sizeof(buf), "Image at %d KB",
546 ((UINT8*)pImageHeader - FB) / 1024);
547 rb->lcd_puts_scroll(0, 1, buf);
549 else
551 rb->lcd_puts_scroll(0, 1, "No image found!");
556 /* Kind of our main function, defines the application flow. */
557 /* recorder version */
558 static void DoUserDialog(char* filename)
560 tImageHeader ImageHeader;
561 tFlashInfo FlashInfo;
562 int button;
563 int rc; /* generic return code */
564 UINT32 space, aligned_size, true_size;
565 UINT8* pos;
566 size_t memleft;
567 unsigned bl_version;
568 bool show_greet = false;
570 /* this can only work if Rockbox runs in DRAM, not flash ROM */
571 if ((UINT8*)rb >= FB && (UINT8*)rb < FB + 4096*1024) /* 4 MB max */
572 { /* we're running from flash */
573 rb->splash(HZ*3, "Not from ROM");
574 return; /* exit */
577 /* refuse to work if the power may fail meanwhile */
578 if (!rb->battery_level_safe())
580 rb->splash(HZ*3, "Battery too low!");
581 return; /* exit */
584 /* "allocate" memory */
585 sector = rb->plugin_get_buffer(&memleft);
586 if (memleft < SECTORSIZE) /* need buffer for a flash sector */
588 rb->splash(HZ*3, "Out of memory");
589 return; /* exit */
592 rb->lcd_setfont(FONT_SYSFIXED);
594 pos = (void*)GetSecondImage();
595 rc = GetFlashInfo(&FlashInfo);
597 ShowFlashInfo(&FlashInfo, (void*)pos);
598 rb->lcd_update();
600 if (FlashInfo.size == 0) /* no valid chip */
602 rb->splash(HZ*3, "Not flashable");
603 return; /* exit */
605 else if (pos == 0)
607 rb->splash(HZ*3, "No image");
608 return; /* exit */
611 bl_version = BootloaderVersion();
612 /* Upgrade currently not recommended for FM and V2
613 recorder due to bugs in V3 BootBox. (FS#12426) */
614 #if !defined(ARCHOS_FMRECORDER) && !defined(ARCHOS_RECORDERV2)
615 if (bl_version < LATEST_BOOTLOADER_VERSION)
617 rb->lcd_putsf(0, 0, "Bootloader V%d", bl_version);
618 rb->lcd_puts(0, 1, "Hint: You're not ");
619 rb->lcd_puts(0, 2, "using the latest ");
620 rb->lcd_puts(0, 3, "bootloader. ");
621 rb->lcd_puts(0, 4, "A full reflash is ");
622 rb->lcd_puts(0, 5, "recommended. ");
623 rb->lcd_puts(0, 6, "Press " KEYNAME1 " to ignore");
624 rb->lcd_update();
626 if (WaitForButton() != KEY1)
628 return;
630 rb->lcd_clear_display();
632 #endif
634 rb->lcd_puts(0, show_greet ? 0 : 3, "Checking...");
635 rb->lcd_update();
637 space = FlashInfo.size - (pos-FB + sizeof(ImageHeader));
638 /* size minus start */
640 rc = CheckImageFile(filename, space, &ImageHeader, pos);
641 if (rc != eOK)
643 rb->lcd_clear_display(); /* make room for error message */
644 show_greet = true; /* verbose */
647 rb->lcd_puts(0, show_greet ? 0 : 3, "Checked:");
648 switch (rc) {
649 case eOK:
650 rb->lcd_puts(0, show_greet ? 0 : 4, "File OK.");
651 break;
652 case eNotUCL:
653 rb->lcd_puts(0, 1, "File not UCL ");
654 rb->lcd_puts(0, 2, "compressed.");
655 rb->lcd_puts(0, 3, "Use uclpack --2e");
656 rb->lcd_puts(0, 4, " --10 rockbox.bin");
657 break;
658 case eWrongAlgorithm:
659 rb->lcd_puts(0, 1, "Wrong algorithm");
660 rb->lcd_puts(0, 2, "for compression.");
661 rb->lcd_puts(0, 3, "Use uclpack --2e");
662 rb->lcd_puts(0, 4, " --10 rockbox.bin");
663 break;
664 case eFileNotFound:
665 rb->lcd_puts(0, 1, "File not found:");
666 rb->lcd_puts_scroll(0, 2, filename);
667 break;
668 case eTooBig:
669 rb->lcd_puts(0, 1, "File too big,");
670 rb->lcd_puts(0, 2, "won't fit in chip.");
671 if (bl_version < LATEST_BOOTLOADER_VERSION)
673 rb->lcd_puts(0, 3, "Upgrade bootloader");
675 break;
676 case eTooSmall:
677 rb->lcd_puts(0, 1, "File too small.");
678 rb->lcd_puts(0, 2, "Incomplete?");
679 break;
680 case eReadErr:
681 rb->lcd_puts(0, 1, "File read error.");
682 break;
683 case eMultiBlocks:
684 rb->lcd_puts(0, 1, "File invalid.");
685 rb->lcd_puts(0, 2, "Blocksize");
686 rb->lcd_puts(0, 3, " too small?");
687 break;
688 case eBadRomLink:
689 rb->lcd_puts(0, 1, "Bootloader not");
690 rb->lcd_puts(0, 2, "compatible with");
691 rb->lcd_puts(0, 3, "RomBox. Start");
692 rb->lcd_puts(0, 4, "address mismatch.");
693 break;
694 default:
695 rb->lcd_puts(0, 1, "Check failed.");
696 break;
699 if (rc == eOK)
700 { /* was OK */
701 rb->lcd_puts(0, 6, "[" KEYNAME2 "] to program");
702 rb->lcd_puts(0, 7, "other key to exit");
704 else
705 { /* error occured */
706 rb->lcd_puts(0, 6, "Any key to exit");
708 rb->lcd_update();
710 button = WaitForButton();
711 if (rc != eOK || button != KEY2)
713 return;
716 true_size = ImageHeader.size;
717 aligned_size = ((sizeof(tImageHeader) + true_size + SECTORSIZE-1) &
718 ~(SECTORSIZE-1)) - sizeof(tImageHeader); /* round up to
719 next flash
720 sector */
721 ImageHeader.size = aligned_size; /* increase image size such that we reach
722 the next sector */
724 rb->lcd_clear_display();
725 rb->lcd_puts_scroll(0, 0, "Programming...");
726 rb->lcd_update();
728 rc = ProgramImageFile(filename, pos, &ImageHeader, UCL_HEADER, true_size);
729 if (rc)
730 { /* errors */
731 rb->lcd_clear_display();
732 rb->lcd_puts(0, 0, "Error:");
733 rb->lcd_puts(0, 1, "Programming fail!");
734 rb->lcd_putsf(0, 2, "%d errors", rc);
735 rb->lcd_update();
736 button = WaitForButton();
739 rb->lcd_clear_display();
740 rb->lcd_puts_scroll(0, 0, "Verifying...");
741 rb->lcd_update();
743 rc = VerifyImageFile(filename, pos, &ImageHeader, UCL_HEADER, true_size);
745 rb->lcd_clear_display();
746 if (rc == 0)
748 rb->lcd_puts(0, 0, "Verify OK.");
750 else
752 rb->lcd_puts(0, 0, "Error:");
753 rb->lcd_puts(0, 1, "Verify fail!");
754 rb->lcd_putsf(0, 2, "%d errors", rc);
755 rb->lcd_puts(0, 3, "Use safe image");
756 rb->lcd_puts(0, 4, "if booting hangs:");
757 rb->lcd_puts(0, 5, "F1 during power-on");
759 rb->lcd_puts(0, 7, "Any key to exit");
760 rb->lcd_update();
761 WaitForButton();
764 #else /* #ifdef HAVE_LCD_BITMAP */
766 /* Player version */
767 static void DoUserDialog(char* filename)
769 tImageHeader ImageHeader;
770 tFlashInfo FlashInfo;
771 static char buf[MAX_PATH];
772 int button;
773 int rc; /* generic return code */
774 UINT32 space, aligned_size, true_size;
775 UINT8* pos;
776 size_t memleft;
777 unsigned bl_version;
779 /* this can only work if Rockbox runs in DRAM, not flash ROM */
780 if ((UINT8*)rb >= FB && (UINT8*)rb < FB + 4096*1024) /* 4 MB max */
781 { /* we're running from flash */
782 rb->splash(HZ*3, "Not from ROM");
783 return; /* exit */
786 /* refuse to work if the power may fail meanwhile */
787 if (!rb->battery_level_safe())
789 rb->splash(HZ*3, "Batt. too low!");
790 return; /* exit */
793 /* "allocate" memory */
794 sector = rb->plugin_get_buffer(&memleft);
795 if (memleft < SECTORSIZE) /* need buffer for a flash sector */
797 rb->splash(HZ*3, "Out of memory");
798 return; /* exit */
801 pos = (void*)GetSecondImage();
802 rc = GetFlashInfo(&FlashInfo);
804 if (FlashInfo.size == 0) /* no valid chip */
806 rb->splash(HZ*3, "Not flashable");
807 return; /* exit */
809 else if (pos == 0)
811 rb->splash(HZ*3, "No image");
812 return; /* exit */
815 bl_version = BootloaderVersion();
816 if (bl_version < LATEST_BOOTLOADER_VERSION)
818 rb->lcd_puts_scroll(0, 0, "Hint: You're not using the latest bootloader. A full reflash is recommended, but not required.");
819 rb->lcd_puts_scroll(0, 1, "Press [Menu] to ignore");
820 rb->lcd_update();
822 if (WaitForButton() != BUTTON_MENU)
824 return;
826 rb->lcd_clear_display();
829 rb->lcd_puts(0, 0, "Checking...");
830 rb->lcd_update();
832 space = FlashInfo.size - (pos-FB + sizeof(ImageHeader));
833 /* size minus start */
835 rc = CheckImageFile(filename, space, &ImageHeader, pos);
836 rb->lcd_puts(0, 0, "Checked:");
837 switch (rc) {
838 case eOK:
839 rb->lcd_puts(0, 1, "File OK.");
840 rb->sleep(HZ*1);
841 break;
842 case eNotUCL:
843 rb->lcd_puts_scroll(0, 1, "File not UCL compressed.");
844 break;
845 case eWrongAlgorithm:
846 rb->lcd_puts_scroll(0, 1, "Wrong compression algorithm.");
847 break;
848 case eFileNotFound:
849 rb->lcd_puts_scroll(0, 1, "File not found.");
850 break;
851 case eTooBig:
852 if (bl_version < LATEST_BOOTLOADER_VERSION)
854 rb->lcd_puts_scroll(0, 1, "File too big, upgrade bootloader.");
856 else
858 rb->lcd_puts_scroll(0, 1, "File too big.");
860 break;
861 case eTooSmall:
862 rb->lcd_puts_scroll(0, 1, "File too small. Incomplete?");
863 break;
864 case eReadErr:
865 rb->lcd_puts_scroll(0, 1, "File read error.");
866 break;
867 case eMultiBlocks:
868 rb->lcd_puts_scroll(0, 1, "File invalid. Blocksize too small?");
869 break;
870 case eBadRomLink:
871 rb->lcd_puts_scroll(0, 1, "Bootloader not compatible with RomBox.");
872 break;
873 default:
874 rb->lcd_puts_scroll(0, 1, "Check failed.");
875 break;
877 rb->lcd_update();
879 if (rc == eOK)
880 { /* was OK */
881 rb->lcd_clear_display();
882 rb->lcd_puts_scroll(0, 0, "[ON] to program,");
883 rb->lcd_puts_scroll(0, 1, "other key to exit.");
885 else
886 { /* error occured */
887 WaitForButton();
888 rb->lcd_clear_display();
889 rb->lcd_puts_scroll(0, 0, "Flash failed.");
890 rb->lcd_puts_scroll(0, 1, "Any key to exit.");
892 rb->lcd_update();
894 button = WaitForButton();
895 if (rc != eOK || button != BUTTON_ON)
897 return;
900 true_size = ImageHeader.size;
901 aligned_size = ((sizeof(tImageHeader) + true_size + SECTORSIZE-1) &
902 ~(SECTORSIZE-1)) - sizeof(tImageHeader); /* round up to
903 next flash
904 sector */
905 ImageHeader.size = aligned_size; /* increase image size such that we reach
906 the next sector */
908 rb->lcd_clear_display();
909 rb->lcd_puts_scroll(0, 0, "Programming...");
910 rb->lcd_update();
912 rc = ProgramImageFile(filename, pos, &ImageHeader, UCL_HEADER, true_size);
913 if (rc)
914 { /* errors */
915 rb->lcd_clear_display();
916 rb->snprintf(buf, sizeof(buf), "%d errors", rc);
917 rb->lcd_puts_scroll(0, 0, "Programming failed!");
918 rb->lcd_puts_scroll(0, 1, buf);
919 rb->lcd_update();
920 button = WaitForButton();
923 rb->lcd_clear_display();
924 rb->lcd_puts_scroll(0, 0, "Verifying...");
925 rb->lcd_update();
927 rc = VerifyImageFile(filename, pos, &ImageHeader, UCL_HEADER, true_size);
929 rb->lcd_clear_display();
930 if (rc == 0)
932 rb->lcd_puts(0, 0, "Verify OK.");
933 rb->lcd_update();
935 else
937 rb->snprintf(buf, sizeof(buf), "Verify fail! %d errors", rc);
938 rb->lcd_puts_scroll(0, 0, buf);
939 rb->lcd_puts_scroll(0, 1, "Use safe image if booting hangs: [-] during power-on");
940 rb->lcd_update();
941 button = WaitForButton();
945 #endif /* not HAVE_LCD_BITMAP */
949 /***************** Plugin Entry Point *****************/
951 enum plugin_status plugin_start(const void* parameter)
953 int oldmode;
955 if (parameter == NULL)
957 rb->splash(HZ*3, "Play .ucl file!");
958 return PLUGIN_OK;
961 /* now go ahead and have fun! */
962 oldmode = rb->system_memory_guard(MEMGUARD_NONE); /*disable memory guard */
963 DoUserDialog((char*) parameter);
964 rb->system_memory_guard(oldmode); /* re-enable memory guard */
966 return PLUGIN_OK;