Fix FS#11007: Lua didn't parse negative numbers correct when reading from files
[kugel-rb.git] / apps / plugins / rockbox_flash.c
blob4bdb0d2c69a81987b669f374dc8f0b701a460202
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 #if (CONFIG_CPU == SH7034) /* Only for SH targets */
28 PLUGIN_HEADER
30 /* define DUMMY if you only want to "play" with the UI, does no harm */
31 /* #define DUMMY */
33 #define LATEST_BOOTLOADER_VERSION 3 /* update this with the bootloader */
35 #ifndef UINT8
36 #define UINT8 unsigned char
37 #endif
39 #ifndef UINT16
40 #define UINT16 unsigned short
41 #endif
43 #ifndef UINT32
44 #define UINT32 unsigned long
45 #endif
47 /* hard-coded values */
48 static volatile UINT8* FB = (UINT8*)0x02000000; /* Flash base address */
49 #define SECTORSIZE 4096 /* size of one flash sector */
51 #define ROCKBOX_DEST 0x09000000
52 #define ROCKBOX_EXEC 0x09000200
53 #define BOOT_VERS_ADR 0xFA /* position of bootloader version value in Flash */
54 #define FW_VERS_ADR 0xFE /* position of firmware version value in Flash */
55 #define UCL_HEADER 26 /* size of the header generated by uclpack */
57 #if CONFIG_KEYPAD == ONDIO_PAD /* limited keypad */
58 #define KEY1 BUTTON_LEFT
59 #define KEY2 BUTTON_UP
60 #define KEYNAME1 "Left"
61 #define KEYNAME2 "Up"
62 #else /* recorder keypad */
63 #define KEY1 BUTTON_F1
64 #define KEY2 BUTTON_F2
65 #define KEYNAME1 "F1"
66 #define KEYNAME2 "F2"
67 #endif
69 typedef struct
71 UINT32 destination; /* address to copy it to */
72 UINT32 size; /* how many bytes of payload (to the next header) */
73 UINT32 execute; /* entry point */
74 UINT32 flags; /* uncompressed or compressed */
75 /* end of header, now comes the payload */
76 } tImageHeader;
78 /* result of the CheckFirmwareFile() function */
79 typedef enum
81 eOK = 0,
82 eFileNotFound, /* errors from here on */
83 eTooBig,
84 eTooSmall,
85 eReadErr,
86 eNotUCL,
87 eWrongAlgorithm,
88 eMultiBlocks,
89 eBadRomLink
90 } tCheckResult;
92 typedef struct
94 UINT8 manufacturer;
95 UINT8 id;
96 int size;
97 char name[32];
98 } tFlashInfo;
100 static UINT8* sector; /* better not place this on the stack... */
102 /***************** Flash Functions *****************/
105 /* read the manufacturer and device ID */
106 static bool ReadID(volatile UINT8* pBase, UINT8* pManufacturerID,
107 UINT8* pDeviceID)
109 UINT8 not_manu, not_id; /* read values before switching to ID mode */
110 UINT8 manu, id; /* read values when in ID mode */
112 pBase = (UINT8*)((UINT32)pBase & 0xFFF80000); /* round down to 512k align,
113 to make sure */
115 not_manu = pBase[0]; /* read the normal content */
116 not_id = pBase[1]; /* should be 'A' (0x41) and 'R' (0x52) from the
117 "ARCH" marker */
119 pBase[0x5555] = 0xAA; /* enter command mode */
120 pBase[0x2AAA] = 0x55;
121 pBase[0x5555] = 0x90; /* ID command */
122 rb->sleep(HZ/50); /* Atmel wants 20ms pause here */
124 manu = pBase[0];
125 id = pBase[1];
127 pBase[0] = 0xF0; /* reset flash (back to normal read mode) */
128 rb->sleep(HZ/50); /* Atmel wants 20ms pause here */
130 /* I assume success if the obtained values are different from
131 the normal flash content. This is not perfectly bulletproof, they
132 could theoretically be the same by chance, causing us to fail. */
133 if (not_manu != manu || not_id != id) /* a value has changed */
135 *pManufacturerID = manu; /* return the results */
136 *pDeviceID = id;
137 return true; /* success */
139 return false; /* fail */
142 /* erase the sector which contains the given address */
143 static bool EraseSector(volatile UINT8* pAddr)
145 #ifdef DUMMY
146 (void)pAddr; /* prevents warning */
147 return true;
148 #else
149 volatile UINT8* pBase =
150 (UINT8*)((UINT32)pAddr & 0xFFF80000); /* round down to 512k align */
151 unsigned timeout = 43000; /* the timeout loop should be no less than
152 25ms */
154 pBase[0x5555] = 0xAA; /* enter command mode */
155 pBase[0x2AAA] = 0x55;
156 pBase[0x5555] = 0x80; /* erase command */
157 pBase[0x5555] = 0xAA; /* enter command mode */
158 pBase[0x2AAA] = 0x55;
159 *pAddr = 0x30; /* erase the sector */
161 /* I counted 7 instructions for this loop -> min. 0.58 us per round
162 Plus memory waitstates it will be much more, gives margin */
163 while (*pAddr != 0xFF && --timeout); /* poll for erased */
165 return (timeout != 0);
166 #endif
169 /* address must be in an erased location */
170 static inline bool ProgramByte(volatile UINT8* pAddr, UINT8 data)
172 #ifdef DUMMY
173 (void)pAddr; /* prevents warnings */
174 (void)data;
175 return true;
176 #else
177 unsigned timeout = 35; /* the timeout loop should be no less than 20us */
179 if (~*pAddr & data) /* just a safety feature, not really necessary */
180 return false; /* can't set any bit from 0 to 1 */
182 FB[0x5555] = 0xAA; /* enter command mode */
183 FB[0x2AAA] = 0x55;
184 FB[0x5555] = 0xA0; /* byte program command */
186 *pAddr = data;
188 /* I counted 7 instructions for this loop -> min. 0.58 us per round
189 Plus memory waitstates it will be much more, gives margin */
190 while (*pAddr != data && --timeout); /* poll for programmed */
192 return (timeout != 0);
193 #endif
196 /* this returns true if supported and fills the info struct */
197 static bool GetFlashInfo(tFlashInfo* pInfo)
199 rb->memset(pInfo, 0, sizeof(tFlashInfo));
201 if (!ReadID(FB, &pInfo->manufacturer, &pInfo->id))
202 return false;
204 if (pInfo->manufacturer == 0xBF) /* SST */
206 if (pInfo->id == 0xD6)
208 pInfo->size = 256* 1024; /* 256k */
209 rb->strcpy(pInfo->name, "SST39VF020");
210 return true;
212 else if (pInfo->id == 0xD7)
214 pInfo->size = 512* 1024; /* 512k */
215 rb->strcpy(pInfo->name, "SST39VF040");
216 return true;
218 else
219 return false;
221 return false;
225 /*********** Tool Functions ************/
227 /* read a 32 bit value from memory, big endian */
228 static UINT32 Read32(UINT8* pByte)
230 UINT32 value;
232 value = (UINT32)pByte[0] << 24;
233 value |= (UINT32)pByte[1] << 16;
234 value |= (UINT32)pByte[2] << 8;
235 value |= (UINT32)pByte[3];
237 return value;
240 /* get the start address of the second image */
241 static tImageHeader* GetSecondImage(void)
243 tImageHeader* pImage1;
244 UINT32 pos = 0; /* default: not found */
245 UINT32* pFlash = (UINT32*)FB;
247 /* determine the first image position */
248 pos = pFlash[2] + pFlash[3]; /* position + size of the bootloader
249 = after it */
250 pos = (pos + 3) & ~3; /* be sure it's 32 bit aligned */
251 pImage1 = (tImageHeader*)pos;
253 if (pImage1->destination != ROCKBOX_DEST ||
254 pImage1->execute != ROCKBOX_EXEC)
255 return 0; /* seems to be no Archos/Rockbox image in here */
257 if (pImage1->size != 0)
259 /* success, we have a second image */
260 pos = (UINT32)pImage1 + sizeof(tImageHeader) + pImage1->size;
261 if (((pos + SECTORSIZE-1) & ~(SECTORSIZE-1)) != pos)
262 { /* not sector-aligned */
263 pos = 0; /* sanity check failed */
267 return (tImageHeader*)pos;
270 /* return bootloader version */
271 static inline unsigned BootloaderVersion(void)
273 return FB[BOOT_VERS_ADR];
276 /*********** Image File Functions ************/
278 /* so far, only compressed images in UCL NRV algorithm 2e supported */
279 tCheckResult CheckImageFile(char* filename, int space,
280 tImageHeader* pHeader, UINT8* pos)
282 int i;
283 int fd;
284 int filesize; /* size info */
286 int fileread = 0; /* total size as read from the file */
287 int read; /* how many for this sector */
289 /* magic file header for compressed files */
290 static const UINT8 magic[8] = { 0x00,0xe9,0x55,0x43,0x4c,0xff,0x01,0x1a };
291 UINT8 ucl_header[UCL_HEADER];
293 fd = rb->open(filename, O_RDONLY);
294 if (fd < 0)
295 return eFileNotFound;
297 filesize = rb->filesize(fd);
298 if (filesize - (int)sizeof(ucl_header) - 8 > space)
300 rb->close(fd);
301 return eTooBig;
303 else if (filesize < 10000) /* give it some reasonable lower limit */
305 rb->close(fd);
306 return eTooSmall;
309 /* do some sanity checks */
311 read = rb->read(fd, ucl_header, sizeof(ucl_header));
312 fileread += read;
313 if (read != sizeof(ucl_header))
315 rb->close(fd);
316 return eReadErr;
319 /* compare the magic header */
320 for (i=0; i<8; i++)
322 if (ucl_header[i] != magic[i])
324 rb->close(fd);
325 return eNotUCL;
329 pHeader->size = Read32(ucl_header + 22); /* compressed size */
330 if (pHeader->size != filesize - sizeof(ucl_header) - 8)
332 rb->close(fd);
333 return eMultiBlocks;
336 /* fill in the hardcoded defaults of the header */
337 pHeader->destination = ROCKBOX_DEST;
338 pHeader->execute = ROCKBOX_EXEC;
340 if (Read32(ucl_header + 18) > pHeader->size) /* compare with uncompressed
341 size */
342 { /* compressed, normal case */
343 pHeader->flags = 0x00000001; /* flags for UCL compressed */
345 /* check for supported algorithm */
346 if (ucl_header[12] != 0x2E)
348 rb->close(fd);
349 return eWrongAlgorithm;
352 else
353 { /* uncompressed, either to be copied or run directly in flash */
354 UINT32 reset_vector; /* image has to start with reset vector */
356 pHeader->flags = 0x00000000; /* uncompressed */
358 read = rb->read(fd, &reset_vector, sizeof(reset_vector));
359 fileread += read;
360 if (read != sizeof(reset_vector))
362 rb->close(fd);
363 return eReadErr;
365 if (reset_vector >= (UINT32)FB
366 && reset_vector < (UINT32)FB+512*1024) /* ROM address? */
368 /* assume in-place, executing directly in flash */
369 pHeader->destination = (UINT32)(pos + sizeof(tImageHeader));
371 /* for new RomBox, this isn't the reset vector,
372 but the link address, for us to check the position */
373 if(pHeader->destination != reset_vector) /* compare link addr. */
375 rb->close(fd);
376 return eBadRomLink; /* not matching the start address */
379 /* read the now following reset vector */
380 read = rb->read(fd, &reset_vector, sizeof(reset_vector));
381 fileread += read;
382 if (read != sizeof(reset_vector))
384 rb->close(fd);
385 return eReadErr;
389 pHeader->execute = reset_vector;
392 /* check if we can read the whole file */
395 read = rb->read(fd, sector, SECTORSIZE);
396 fileread += read;
397 } while (read == SECTORSIZE);
399 rb->close(fd);
401 if (fileread != filesize)
402 return eReadErr;
404 return eOK;
408 /* returns the # of failures, 0 on success */
409 static unsigned ProgramImageFile(char* filename, UINT8* pos,
410 tImageHeader* pImageHeader,
411 int start, int size)
413 int i;
414 int fd;
415 int read; /* how many for this sector */
416 unsigned failures = 0;
418 fd = rb->open(filename, O_RDONLY);
419 if (fd < 0)
420 return false;
422 /* no error checking necessary here, we checked for minimum size
423 already */
424 rb->lseek(fd, start, SEEK_SET); /* go to start position */
426 *(tImageHeader*)sector = *pImageHeader; /* copy header into sector
427 buffer */
428 read = rb->read(fd, sector + sizeof(tImageHeader),
429 SECTORSIZE - sizeof(tImageHeader)); /* payload behind */
430 size -= read;
431 read += sizeof(tImageHeader); /* to be programmed, but not part of the
432 file */
434 do {
435 if (!EraseSector(pos))
437 /* nothing we can do, let the programming count the errors */
440 for (i=0; i<read; i++)
442 if (!ProgramByte(pos + i, sector[i]))
444 failures++;
448 pos += SECTORSIZE;
449 read = rb->read(fd, sector, (size > SECTORSIZE) ? SECTORSIZE : size);
450 /* payload for next sector */
451 size -= read;
452 } while (read > 0);
454 rb->close(fd);
456 return failures;
459 /* returns the # of failures, 0 on success */
460 static unsigned VerifyImageFile(char* filename, UINT8* pos,
461 tImageHeader* pImageHeader,
462 int start, int size)
464 int i;
465 int fd;
466 int read; /* how many for this sector */
467 unsigned failures = 0;
469 fd = rb->open(filename, O_RDONLY);
470 if (fd < 0)
471 return false;
473 /* no error checking necessary here, we checked for minimum size
474 already */
475 rb->lseek(fd, start, SEEK_SET); /* go to start position */
477 *(tImageHeader*)sector = *pImageHeader; /* copy header into sector
478 buffer */
479 read = rb->read(fd, sector + sizeof(tImageHeader),
480 SECTORSIZE - sizeof(tImageHeader)); /* payload behind */
482 size -= read;
483 read += sizeof(tImageHeader); /* to be programmed, but not part of the
484 file */
488 for (i=0; i<read; i++)
490 if (pos[i] != sector[i])
492 failures++;
496 pos += SECTORSIZE;
497 read = rb->read(fd, sector, (size > SECTORSIZE) ? SECTORSIZE : size);
498 /* payload for next sector */
499 size -= read;
500 } while (read);
502 rb->close(fd);
504 return failures;
508 /***************** User Interface Functions *****************/
510 static int WaitForButton(void)
512 int button;
516 button = rb->button_get(true);
517 } while (IS_SYSEVENT(button) || (button & BUTTON_REL));
519 return button;
522 #ifdef HAVE_LCD_BITMAP
523 /* helper for DoUserDialog() */
524 static void ShowFlashInfo(tFlashInfo* pInfo, tImageHeader* pImageHeader)
526 char buf[32];
528 if (!pInfo->manufacturer)
530 rb->lcd_puts_scroll(0, 0, "Flash: M=?? D=??");
532 else
534 if (pInfo->size)
536 rb->snprintf(buf, sizeof(buf), "Flash size: %d KB",
537 pInfo->size / 1024);
538 rb->lcd_puts_scroll(0, 0, buf);
540 else
542 rb->lcd_puts_scroll(0, 0, "Unsupported chip");
547 if (pImageHeader)
549 rb->snprintf(buf, sizeof(buf), "Image at %d KB",
550 ((UINT8*)pImageHeader - FB) / 1024);
551 rb->lcd_puts_scroll(0, 1, buf);
553 else
555 rb->lcd_puts_scroll(0, 1, "No image found!");
560 /* Kind of our main function, defines the application flow. */
561 /* recorder version */
562 static void DoUserDialog(char* filename)
564 tImageHeader ImageHeader;
565 tFlashInfo FlashInfo;
566 static char buf[MAX_PATH];
567 int button;
568 int rc; /* generic return code */
569 UINT32 space, aligned_size, true_size;
570 UINT8* pos;
571 ssize_t memleft;
572 unsigned bl_version;
573 bool show_greet = false;
575 /* this can only work if Rockbox runs in DRAM, not flash ROM */
576 if ((UINT8*)rb >= FB && (UINT8*)rb < FB + 4096*1024) /* 4 MB max */
577 { /* we're running from flash */
578 rb->splash(HZ*3, "Not from ROM");
579 return; /* exit */
582 /* refuse to work if the power may fail meanwhile */
583 if (!rb->battery_level_safe())
585 rb->splash(HZ*3, "Battery too low!");
586 return; /* exit */
589 /* "allocate" memory */
590 sector = rb->plugin_get_buffer((size_t *)&memleft);
591 if (memleft < SECTORSIZE) /* need buffer for a flash sector */
593 rb->splash(HZ*3, "Out of memory");
594 return; /* exit */
597 rb->lcd_setfont(FONT_SYSFIXED);
599 pos = (void*)GetSecondImage();
600 rc = GetFlashInfo(&FlashInfo);
602 ShowFlashInfo(&FlashInfo, (void*)pos);
603 rb->lcd_update();
605 if (FlashInfo.size == 0) /* no valid chip */
607 rb->splash(HZ*3, "Not flashable");
608 return; /* exit */
610 else if (pos == 0)
612 rb->splash(HZ*3, "No image");
613 return; /* exit */
616 bl_version = BootloaderVersion();
617 if (bl_version < LATEST_BOOTLOADER_VERSION)
619 rb->snprintf(buf, sizeof(buf), "Bootloader V%d", bl_version);
620 rb->lcd_puts(0, 0, buf);
621 rb->lcd_puts(0, 1, "Hint: You're not ");
622 rb->lcd_puts(0, 2, "using the latest ");
623 rb->lcd_puts(0, 3, "bootloader. ");
624 rb->lcd_puts(0, 4, "A full reflash is ");
625 rb->lcd_puts(0, 5, "recommended, but ");
626 rb->lcd_puts(0, 6, "not required. ");
627 rb->lcd_puts(0, 7, "Press " KEYNAME1 " to ignore");
628 rb->lcd_update();
630 if (WaitForButton() != KEY1)
632 return;
634 rb->lcd_clear_display();
637 rb->lcd_puts(0, show_greet ? 0 : 3, "Checking...");
638 rb->lcd_update();
640 space = FlashInfo.size - (pos-FB + sizeof(ImageHeader));
641 /* size minus start */
643 rc = CheckImageFile(filename, space, &ImageHeader, pos);
644 if (rc != eOK)
646 rb->lcd_clear_display(); /* make room for error message */
647 show_greet = true; /* verbose */
650 rb->lcd_puts(0, show_greet ? 0 : 3, "Checked:");
651 switch (rc) {
652 case eOK:
653 rb->lcd_puts(0, show_greet ? 0 : 4, "File OK.");
654 break;
655 case eNotUCL:
656 rb->lcd_puts(0, 1, "File not UCL ");
657 rb->lcd_puts(0, 2, "compressed.");
658 rb->lcd_puts(0, 3, "Use uclpack --2e");
659 rb->lcd_puts(0, 4, " --10 rockbox.bin");
660 break;
661 case eWrongAlgorithm:
662 rb->lcd_puts(0, 1, "Wrong algorithm");
663 rb->lcd_puts(0, 2, "for compression.");
664 rb->lcd_puts(0, 3, "Use uclpack --2e");
665 rb->lcd_puts(0, 4, " --10 rockbox.bin");
666 break;
667 case eFileNotFound:
668 rb->lcd_puts(0, 1, "File not found:");
669 rb->lcd_puts_scroll(0, 2, filename);
670 break;
671 case eTooBig:
672 rb->lcd_puts(0, 1, "File too big,");
673 rb->lcd_puts(0, 2, "won't fit in chip.");
674 break;
675 case eTooSmall:
676 rb->lcd_puts(0, 1, "File too small.");
677 rb->lcd_puts(0, 2, "Incomplete?");
678 break;
679 case eReadErr:
680 rb->lcd_puts(0, 1, "File read error.");
681 break;
682 case eMultiBlocks:
683 rb->lcd_puts(0, 1, "File invalid.");
684 rb->lcd_puts(0, 2, "Blocksize");
685 rb->lcd_puts(0, 3, " too small?");
686 break;
687 case eBadRomLink:
688 rb->lcd_puts(0, 1, "RomBox mismatch.");
689 rb->lcd_puts(0, 2, "Wrong ROM position");
690 break;
691 default:
692 rb->lcd_puts(0, 1, "Check failed.");
693 break;
696 if (rc == eOK)
697 { /* was OK */
698 rb->lcd_puts(0, 6, "[" KEYNAME2 "] to program");
699 rb->lcd_puts(0, 7, "other key to exit");
701 else
702 { /* error occured */
703 rb->lcd_puts(0, 6, "Any key to exit");
705 rb->lcd_update();
707 button = WaitForButton();
708 if (rc != eOK || button != KEY2)
710 return;
713 true_size = ImageHeader.size;
714 aligned_size = ((sizeof(tImageHeader) + true_size + SECTORSIZE-1) &
715 ~(SECTORSIZE-1)) - sizeof(tImageHeader); /* round up to
716 next flash
717 sector */
718 ImageHeader.size = aligned_size; /* increase image size such that we reach
719 the next sector */
721 rb->lcd_clear_display();
722 rb->lcd_puts_scroll(0, 0, "Programming...");
723 rb->lcd_update();
725 rc = ProgramImageFile(filename, pos, &ImageHeader, UCL_HEADER, true_size);
726 if (rc)
727 { /* errors */
728 rb->lcd_clear_display();
729 rb->snprintf(buf, sizeof(buf), "%d errors", rc);
730 rb->lcd_puts(0, 0, "Error:");
731 rb->lcd_puts(0, 1, "Programming fail!");
732 rb->lcd_puts(0, 2, buf);
733 rb->lcd_update();
734 button = WaitForButton();
737 rb->lcd_clear_display();
738 rb->lcd_puts_scroll(0, 0, "Verifying...");
739 rb->lcd_update();
741 rc = VerifyImageFile(filename, pos, &ImageHeader, UCL_HEADER, true_size);
743 rb->lcd_clear_display();
744 if (rc == 0)
746 rb->lcd_puts(0, 0, "Verify OK.");
748 else
750 rb->snprintf(buf, sizeof(buf), "%d errors", rc);
751 rb->lcd_puts(0, 0, "Error:");
752 rb->lcd_puts(0, 1, "Verify fail!");
753 rb->lcd_puts(0, 2, buf);
754 rb->lcd_puts(0, 3, "Use safe image");
755 rb->lcd_puts(0, 4, "if booting hangs:");
756 rb->lcd_puts(0, 5, "F1 during power-on");
758 rb->lcd_puts(0, 7, "Any key to exit");
759 rb->lcd_update();
760 WaitForButton();
763 #else /* #ifdef HAVE_LCD_BITMAP */
765 /* Player version */
766 static void DoUserDialog(char* filename)
768 tImageHeader ImageHeader;
769 tFlashInfo FlashInfo;
770 static char buf[MAX_PATH];
771 int button;
772 int rc; /* generic return code */
773 UINT32 space, aligned_size, true_size;
774 UINT8* pos;
775 ssize_t memleft;
776 unsigned bl_version;
778 /* this can only work if Rockbox runs in DRAM, not flash ROM */
779 if ((UINT8*)rb >= FB && (UINT8*)rb < FB + 4096*1024) /* 4 MB max */
780 { /* we're running from flash */
781 rb->splash(HZ*3, "Not from ROM");
782 return; /* exit */
785 /* refuse to work if the power may fail meanwhile */
786 if (!rb->battery_level_safe())
788 rb->splash(HZ*3, "Batt. too low!");
789 return; /* exit */
792 /* "allocate" memory */
793 sector = rb->plugin_get_buffer((size_t *)&memleft);
794 if (memleft < SECTORSIZE) /* need buffer for a flash sector */
796 rb->splash(HZ*3, "Out of memory");
797 return; /* exit */
800 pos = (void*)GetSecondImage();
801 rc = GetFlashInfo(&FlashInfo);
803 if (FlashInfo.size == 0) /* no valid chip */
805 rb->splash(HZ*3, "Not flashable");
806 return; /* exit */
808 else if (pos == 0)
810 rb->splash(HZ*3, "No image");
811 return; /* exit */
814 bl_version = BootloaderVersion();
815 if (bl_version < LATEST_BOOTLOADER_VERSION)
817 rb->lcd_puts_scroll(0, 0, "Hint: You're not using the latest bootloader. A full reflash is recommended, but not required.");
818 rb->lcd_puts_scroll(0, 1, "Press [Menu] to ignore");
819 rb->lcd_update();
821 if (WaitForButton() != BUTTON_MENU)
823 return;
825 rb->lcd_clear_display();
828 rb->lcd_puts(0, 0, "Checking...");
829 rb->lcd_update();
831 space = FlashInfo.size - (pos-FB + sizeof(ImageHeader));
832 /* size minus start */
834 rc = CheckImageFile(filename, space, &ImageHeader, pos);
835 rb->lcd_puts(0, 0, "Checked:");
836 switch (rc) {
837 case eOK:
838 rb->lcd_puts(0, 1, "File OK.");
839 rb->sleep(HZ*1);
840 break;
841 case eNotUCL:
842 rb->lcd_puts_scroll(0, 1, "File not UCL compressed.");
843 break;
844 case eWrongAlgorithm:
845 rb->lcd_puts_scroll(0, 1, "Wrong compression algorithm.");
846 break;
847 case eFileNotFound:
848 rb->lcd_puts_scroll(0, 1, "File not found.");
849 break;
850 case eTooBig:
851 rb->lcd_puts_scroll(0, 1, "File too big.");
852 break;
853 case eTooSmall:
854 rb->lcd_puts_scroll(0, 1, "File too small. Incomplete?");
855 break;
856 case eReadErr:
857 rb->lcd_puts_scroll(0, 1, "File read error.");
858 break;
859 case eMultiBlocks:
860 rb->lcd_puts_scroll(0, 1, "File invalid. Blocksize too small?");
861 break;
862 case eBadRomLink:
863 rb->lcd_puts_scroll(0, 1, "RomBox mismatch.");
864 break;
865 default:
866 rb->lcd_puts_scroll(0, 1, "Check failed.");
867 break;
869 rb->lcd_update();
871 if (rc == eOK)
872 { /* was OK */
873 rb->lcd_clear_display();
874 rb->lcd_puts_scroll(0, 0, "[ON] to program,");
875 rb->lcd_puts_scroll(0, 1, "other key to exit.");
877 else
878 { /* error occured */
879 WaitForButton();
880 rb->lcd_clear_display();
881 rb->lcd_puts_scroll(0, 0, "Flash failed.");
882 rb->lcd_puts_scroll(0, 1, "Any key to exit.");
884 rb->lcd_update();
886 button = WaitForButton();
887 if (rc != eOK || button != BUTTON_ON)
889 return;
892 true_size = ImageHeader.size;
893 aligned_size = ((sizeof(tImageHeader) + true_size + SECTORSIZE-1) &
894 ~(SECTORSIZE-1)) - sizeof(tImageHeader); /* round up to
895 next flash
896 sector */
897 ImageHeader.size = aligned_size; /* increase image size such that we reach
898 the next sector */
900 rb->lcd_clear_display();
901 rb->lcd_puts_scroll(0, 0, "Programming...");
902 rb->lcd_update();
904 rc = ProgramImageFile(filename, pos, &ImageHeader, UCL_HEADER, true_size);
905 if (rc)
906 { /* errors */
907 rb->lcd_clear_display();
908 rb->snprintf(buf, sizeof(buf), "%d errors", rc);
909 rb->lcd_puts_scroll(0, 0, "Programming failed!");
910 rb->lcd_puts_scroll(0, 1, buf);
911 rb->lcd_update();
912 button = WaitForButton();
915 rb->lcd_clear_display();
916 rb->lcd_puts_scroll(0, 0, "Verifying...");
917 rb->lcd_update();
919 rc = VerifyImageFile(filename, pos, &ImageHeader, UCL_HEADER, true_size);
921 rb->lcd_clear_display();
922 if (rc == 0)
924 rb->lcd_puts(0, 0, "Verify OK.");
925 rb->lcd_update();
927 else
929 rb->snprintf(buf, sizeof(buf), "Verify fail! %d errors", rc);
930 rb->lcd_puts_scroll(0, 0, buf);
931 rb->lcd_puts_scroll(0, 1, "Use safe image if booting hangs: [-] during power-on");
932 rb->lcd_update();
933 button = WaitForButton();
937 #endif /* not HAVE_LCD_BITMAP */
941 /***************** Plugin Entry Point *****************/
943 enum plugin_status plugin_start(const void* parameter)
945 int oldmode;
947 if (parameter == NULL)
949 rb->splash(HZ*3, "Play .ucl file!");
950 return PLUGIN_OK;
953 /* now go ahead and have fun! */
954 oldmode = rb->system_memory_guard(MEMGUARD_NONE); /*disable memory guard */
955 DoUserDialog((char*) parameter);
956 rb->system_memory_guard(oldmode); /* re-enable memory guard */
958 return PLUGIN_OK;
962 #endif /* SH-target */