Accept patch in FS#9637 by Keith Perri, fixing a crash when loading a cfg which speci...
[kugel-rb.git] / apps / plugins / rockbox_flash.c
blob6323ca97360ae93ca08b42d40856050bc719a4e2
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 2 /* 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 const struct plugin_api* rb; /* here is a global api struct pointer */
102 static UINT8* sector; /* better not place this on the stack... */
104 /***************** Flash Functions *****************/
107 /* read the manufacturer and device ID */
108 static bool ReadID(volatile UINT8* pBase, UINT8* pManufacturerID,
109 UINT8* pDeviceID)
111 UINT8 not_manu, not_id; /* read values before switching to ID mode */
112 UINT8 manu, id; /* read values when in ID mode */
114 pBase = (UINT8*)((UINT32)pBase & 0xFFF80000); /* round down to 512k align,
115 to make sure */
117 not_manu = pBase[0]; /* read the normal content */
118 not_id = pBase[1]; /* should be 'A' (0x41) and 'R' (0x52) from the
119 "ARCH" marker */
121 pBase[0x5555] = 0xAA; /* enter command mode */
122 pBase[0x2AAA] = 0x55;
123 pBase[0x5555] = 0x90; /* ID command */
124 rb->sleep(HZ/50); /* Atmel wants 20ms pause here */
126 manu = pBase[0];
127 id = pBase[1];
129 pBase[0] = 0xF0; /* reset flash (back to normal read mode) */
130 rb->sleep(HZ/50); /* Atmel wants 20ms pause here */
132 /* I assume success if the obtained values are different from
133 the normal flash content. This is not perfectly bulletproof, they
134 could theoretically be the same by chance, causing us to fail. */
135 if (not_manu != manu || not_id != id) /* a value has changed */
137 *pManufacturerID = manu; /* return the results */
138 *pDeviceID = id;
139 return true; /* success */
141 return false; /* fail */
144 /* erase the sector which contains the given address */
145 static bool EraseSector(volatile UINT8* pAddr)
147 #ifdef DUMMY
148 (void)pAddr; /* prevents warning */
149 return true;
150 #else
151 volatile UINT8* pBase =
152 (UINT8*)((UINT32)pAddr & 0xFFF80000); /* round down to 512k align */
153 unsigned timeout = 43000; /* the timeout loop should be no less than
154 25ms */
156 pBase[0x5555] = 0xAA; /* enter command mode */
157 pBase[0x2AAA] = 0x55;
158 pBase[0x5555] = 0x80; /* erase command */
159 pBase[0x5555] = 0xAA; /* enter command mode */
160 pBase[0x2AAA] = 0x55;
161 *pAddr = 0x30; /* erase the sector */
163 /* I counted 7 instructions for this loop -> min. 0.58 us per round
164 Plus memory waitstates it will be much more, gives margin */
165 while (*pAddr != 0xFF && --timeout); /* poll for erased */
167 return (timeout != 0);
168 #endif
171 /* address must be in an erased location */
172 static inline bool ProgramByte(volatile UINT8* pAddr, UINT8 data)
174 #ifdef DUMMY
175 (void)pAddr; /* prevents warnings */
176 (void)data;
177 return true;
178 #else
179 unsigned timeout = 35; /* the timeout loop should be no less than 20us */
181 if (~*pAddr & data) /* just a safety feature, not really necessary */
182 return false; /* can't set any bit from 0 to 1 */
184 FB[0x5555] = 0xAA; /* enter command mode */
185 FB[0x2AAA] = 0x55;
186 FB[0x5555] = 0xA0; /* byte program command */
188 *pAddr = data;
190 /* I counted 7 instructions for this loop -> min. 0.58 us per round
191 Plus memory waitstates it will be much more, gives margin */
192 while (*pAddr != data && --timeout); /* poll for programmed */
194 return (timeout != 0);
195 #endif
198 /* this returns true if supported and fills the info struct */
199 static bool GetFlashInfo(tFlashInfo* pInfo)
201 rb->memset(pInfo, 0, sizeof(tFlashInfo));
203 if (!ReadID(FB, &pInfo->manufacturer, &pInfo->id))
204 return false;
206 if (pInfo->manufacturer == 0xBF) /* SST */
208 if (pInfo->id == 0xD6)
210 pInfo->size = 256* 1024; /* 256k */
211 rb->strcpy(pInfo->name, "SST39VF020");
212 return true;
214 else if (pInfo->id == 0xD7)
216 pInfo->size = 512* 1024; /* 512k */
217 rb->strcpy(pInfo->name, "SST39VF040");
218 return true;
220 else
221 return false;
223 return false;
227 /*********** Tool Functions ************/
229 /* read a 32 bit value from memory, big endian */
230 static UINT32 Read32(UINT8* pByte)
232 UINT32 value;
234 value = (UINT32)pByte[0] << 24;
235 value |= (UINT32)pByte[1] << 16;
236 value |= (UINT32)pByte[2] << 8;
237 value |= (UINT32)pByte[3];
239 return value;
242 /* get the start address of the second image */
243 static tImageHeader* GetSecondImage(void)
245 tImageHeader* pImage1;
246 UINT32 pos = 0; /* default: not found */
247 UINT32* pFlash = (UINT32*)FB;
249 /* determine the first image position */
250 pos = pFlash[2] + pFlash[3]; /* position + size of the bootloader
251 = after it */
252 pos = (pos + 3) & ~3; /* be sure it's 32 bit aligned */
253 pImage1 = (tImageHeader*)pos;
255 if (pImage1->destination != ROCKBOX_DEST ||
256 pImage1->execute != ROCKBOX_EXEC)
257 return 0; /* seems to be no Archos/Rockbox image in here */
259 if (pImage1->size != 0)
261 /* success, we have a second image */
262 pos = (UINT32)pImage1 + sizeof(tImageHeader) + pImage1->size;
263 if (((pos + SECTORSIZE-1) & ~(SECTORSIZE-1)) != pos)
264 { /* not sector-aligned */
265 pos = 0; /* sanity check failed */
269 return (tImageHeader*)pos;
272 /* return bootloader version */
273 static inline unsigned BootloaderVersion(void)
275 return FB[BOOT_VERS_ADR];
278 /*********** Image File Functions ************/
280 /* so far, only compressed images in UCL NRV algorithm 2e supported */
281 tCheckResult CheckImageFile(char* filename, int space,
282 tImageHeader* pHeader, UINT8* pos)
284 int i;
285 int fd;
286 int filesize; /* size info */
288 int fileread = 0; /* total size as read from the file */
289 int read; /* how many for this sector */
291 /* magic file header for compressed files */
292 static const UINT8 magic[8] = { 0x00,0xe9,0x55,0x43,0x4c,0xff,0x01,0x1a };
293 UINT8 ucl_header[UCL_HEADER];
295 fd = rb->open(filename, O_RDONLY);
296 if (fd < 0)
297 return eFileNotFound;
299 filesize = rb->filesize(fd);
300 if (filesize - (int)sizeof(ucl_header) - 8 > space)
302 rb->close(fd);
303 return eTooBig;
305 else if (filesize < 10000) /* give it some reasonable lower limit */
307 rb->close(fd);
308 return eTooSmall;
311 /* do some sanity checks */
313 read = rb->read(fd, ucl_header, sizeof(ucl_header));
314 fileread += read;
315 if (read != sizeof(ucl_header))
317 rb->close(fd);
318 return eReadErr;
321 /* compare the magic header */
322 for (i=0; i<8; i++)
324 if (ucl_header[i] != magic[i])
326 rb->close(fd);
327 return eNotUCL;
331 pHeader->size = Read32(ucl_header + 22); /* compressed size */
332 if (pHeader->size != filesize - sizeof(ucl_header) - 8)
334 rb->close(fd);
335 return eMultiBlocks;
338 /* fill in the hardcoded defaults of the header */
339 pHeader->destination = ROCKBOX_DEST;
340 pHeader->execute = ROCKBOX_EXEC;
342 if (Read32(ucl_header + 18) > pHeader->size) /* compare with uncompressed
343 size */
344 { /* compressed, normal case */
345 pHeader->flags = 0x00000001; /* flags for UCL compressed */
347 /* check for supported algorithm */
348 if (ucl_header[12] != 0x2E)
350 rb->close(fd);
351 return eWrongAlgorithm;
354 else
355 { /* uncompressed, either to be copied or run directly in flash */
356 UINT32 reset_vector; /* image has to start with reset vector */
358 pHeader->flags = 0x00000000; /* uncompressed */
360 read = rb->read(fd, &reset_vector, sizeof(reset_vector));
361 fileread += read;
362 if (read != sizeof(reset_vector))
364 rb->close(fd);
365 return eReadErr;
367 if (reset_vector >= (UINT32)FB
368 && reset_vector < (UINT32)FB+512*1024) /* ROM address? */
370 /* assume in-place, executing directly in flash */
371 pHeader->destination = (UINT32)(pos + sizeof(tImageHeader));
373 /* for new RomBox, this isn't the reset vector,
374 but the link address, for us to check the position */
375 if(pHeader->destination != reset_vector) /* compare link addr. */
377 rb->close(fd);
378 return eBadRomLink; /* not matching the start address */
381 /* read the now following reset vector */
382 read = rb->read(fd, &reset_vector, sizeof(reset_vector));
383 fileread += read;
384 if (read != sizeof(reset_vector))
386 rb->close(fd);
387 return eReadErr;
391 pHeader->execute = reset_vector;
394 /* check if we can read the whole file */
397 read = rb->read(fd, sector, SECTORSIZE);
398 fileread += read;
399 } while (read == SECTORSIZE);
401 rb->close(fd);
403 if (fileread != filesize)
404 return eReadErr;
406 return eOK;
410 /* returns the # of failures, 0 on success */
411 static unsigned ProgramImageFile(char* filename, UINT8* pos,
412 tImageHeader* pImageHeader,
413 int start, int size)
415 int i;
416 int fd;
417 int read; /* how many for this sector */
418 unsigned failures = 0;
420 fd = rb->open(filename, O_RDONLY);
421 if (fd < 0)
422 return false;
424 /* no error checking necessary here, we checked for minimum size
425 already */
426 rb->lseek(fd, start, SEEK_SET); /* go to start position */
428 *(tImageHeader*)sector = *pImageHeader; /* copy header into sector
429 buffer */
430 read = rb->read(fd, sector + sizeof(tImageHeader),
431 SECTORSIZE - sizeof(tImageHeader)); /* payload behind */
432 size -= read;
433 read += sizeof(tImageHeader); /* to be programmed, but not part of the
434 file */
436 do {
437 if (!EraseSector(pos))
439 /* nothing we can do, let the programming count the errors */
442 for (i=0; i<read; i++)
444 if (!ProgramByte(pos + i, sector[i]))
446 failures++;
450 pos += SECTORSIZE;
451 read = rb->read(fd, sector, (size > SECTORSIZE) ? SECTORSIZE : size);
452 /* payload for next sector */
453 size -= read;
454 } while (read > 0);
456 rb->close(fd);
458 return failures;
461 /* returns the # of failures, 0 on success */
462 static unsigned VerifyImageFile(char* filename, UINT8* pos,
463 tImageHeader* pImageHeader,
464 int start, int size)
466 int i;
467 int fd;
468 int read; /* how many for this sector */
469 unsigned failures = 0;
471 fd = rb->open(filename, O_RDONLY);
472 if (fd < 0)
473 return false;
475 /* no error checking necessary here, we checked for minimum size
476 already */
477 rb->lseek(fd, start, SEEK_SET); /* go to start position */
479 *(tImageHeader*)sector = *pImageHeader; /* copy header into sector
480 buffer */
481 read = rb->read(fd, sector + sizeof(tImageHeader),
482 SECTORSIZE - sizeof(tImageHeader)); /* payload behind */
484 size -= read;
485 read += sizeof(tImageHeader); /* to be programmed, but not part of the
486 file */
490 for (i=0; i<read; i++)
492 if (pos[i] != sector[i])
494 failures++;
498 pos += SECTORSIZE;
499 read = rb->read(fd, sector, (size > SECTORSIZE) ? SECTORSIZE : size);
500 /* payload for next sector */
501 size -= read;
502 } while (read);
504 rb->close(fd);
506 return failures;
510 /***************** User Interface Functions *****************/
512 static int WaitForButton(void)
514 int button;
518 button = rb->button_get(true);
519 } while (button & BUTTON_REL);
521 return button;
524 #ifdef HAVE_LCD_BITMAP
525 /* helper for DoUserDialog() */
526 static void ShowFlashInfo(tFlashInfo* pInfo, tImageHeader* pImageHeader)
528 char buf[32];
530 if (!pInfo->manufacturer)
532 rb->lcd_puts_scroll(0, 0, "Flash: M=?? D=??");
534 else
536 if (pInfo->size)
538 rb->snprintf(buf, sizeof(buf), "Flash size: %d KB",
539 pInfo->size / 1024);
540 rb->lcd_puts_scroll(0, 0, buf);
542 else
544 rb->lcd_puts_scroll(0, 0, "Unsupported chip");
549 if (pImageHeader)
551 rb->snprintf(buf, sizeof(buf), "Image at %d KB",
552 ((UINT8*)pImageHeader - FB) / 1024);
553 rb->lcd_puts_scroll(0, 1, buf);
555 else
557 rb->lcd_puts_scroll(0, 1, "No image found!");
562 /* Kind of our main function, defines the application flow. */
563 /* recorder version */
564 static void DoUserDialog(char* filename)
566 tImageHeader ImageHeader;
567 tFlashInfo FlashInfo;
568 static char buf[MAX_PATH];
569 int button;
570 int rc; /* generic return code */
571 UINT32 space, aligned_size, true_size;
572 UINT8* pos;
573 ssize_t memleft;
574 unsigned bl_version;
575 bool show_greet = false;
577 /* this can only work if Rockbox runs in DRAM, not flash ROM */
578 if ((UINT8*)rb >= FB && (UINT8*)rb < FB + 4096*1024) /* 4 MB max */
579 { /* we're running from flash */
580 rb->splash(HZ*3, "Not from ROM");
581 return; /* exit */
584 /* refuse to work if the power may fail meanwhile */
585 if (!rb->battery_level_safe())
587 rb->splash(HZ*3, "Battery too low!");
588 return; /* exit */
591 /* "allocate" memory */
592 sector = rb->plugin_get_buffer((size_t *)&memleft);
593 if (memleft < SECTORSIZE) /* need buffer for a flash sector */
595 rb->splash(HZ*3, "Out of memory");
596 return; /* exit */
599 rb->lcd_setfont(FONT_SYSFIXED);
601 pos = (void*)GetSecondImage();
602 rc = GetFlashInfo(&FlashInfo);
604 ShowFlashInfo(&FlashInfo, (void*)pos);
605 rb->lcd_update();
607 if (FlashInfo.size == 0) /* no valid chip */
609 rb->splash(HZ*3, "Not flashable");
610 return; /* exit */
612 else if (pos == 0)
614 rb->splash(HZ*3, "No image");
615 return; /* exit */
618 bl_version = BootloaderVersion();
619 if (bl_version < LATEST_BOOTLOADER_VERSION)
621 rb->snprintf(buf, sizeof(buf), "Bootloader V%d", bl_version);
622 rb->lcd_puts(0, 0, buf);
623 rb->lcd_puts(0, 1, "Hint: You're not ");
624 rb->lcd_puts(0, 2, "using the latest ");
625 rb->lcd_puts(0, 3, "bootloader. ");
626 rb->lcd_puts(0, 4, "A full reflash is ");
627 rb->lcd_puts(0, 5, "recommended, but ");
628 rb->lcd_puts(0, 6, "not required. ");
629 rb->lcd_puts(0, 7, "Press " KEYNAME1 " to ignore");
630 rb->lcd_update();
632 if (WaitForButton() != KEY1)
634 return;
636 rb->lcd_clear_display();
639 rb->lcd_puts(0, show_greet ? 0 : 3, "Checking...");
640 rb->lcd_update();
642 space = FlashInfo.size - (pos-FB + sizeof(ImageHeader));
643 /* size minus start */
645 rc = CheckImageFile(filename, space, &ImageHeader, pos);
646 if (rc != eOK)
648 rb->lcd_clear_display(); /* make room for error message */
649 show_greet = true; /* verbose */
652 rb->lcd_puts(0, show_greet ? 0 : 3, "Checked:");
653 switch (rc) {
654 case eOK:
655 rb->lcd_puts(0, show_greet ? 0 : 4, "File OK.");
656 break;
657 case eNotUCL:
658 rb->lcd_puts(0, 1, "File not UCL ");
659 rb->lcd_puts(0, 2, "compressed.");
660 rb->lcd_puts(0, 3, "Use uclpack --2e");
661 rb->lcd_puts(0, 4, " --10 rockbox.bin");
662 break;
663 case eWrongAlgorithm:
664 rb->lcd_puts(0, 1, "Wrong algorithm");
665 rb->lcd_puts(0, 2, "for compression.");
666 rb->lcd_puts(0, 3, "Use uclpack --2e");
667 rb->lcd_puts(0, 4, " --10 rockbox.bin");
668 break;
669 case eFileNotFound:
670 rb->lcd_puts(0, 1, "File not found:");
671 rb->lcd_puts_scroll(0, 2, filename);
672 break;
673 case eTooBig:
674 rb->lcd_puts(0, 1, "File too big,");
675 rb->lcd_puts(0, 2, "won't fit in chip.");
676 break;
677 case eTooSmall:
678 rb->lcd_puts(0, 1, "File too small.");
679 rb->lcd_puts(0, 2, "Incomplete?");
680 break;
681 case eReadErr:
682 rb->lcd_puts(0, 1, "File read error.");
683 break;
684 case eMultiBlocks:
685 rb->lcd_puts(0, 1, "File invalid.");
686 rb->lcd_puts(0, 2, "Blocksize");
687 rb->lcd_puts(0, 3, " too small?");
688 break;
689 case eBadRomLink:
690 rb->lcd_puts(0, 1, "RomBox mismatch.");
691 rb->lcd_puts(0, 2, "Wrong ROM position");
692 break;
693 default:
694 rb->lcd_puts(0, 1, "Check failed.");
695 break;
698 if (rc == eOK)
699 { /* was OK */
700 rb->lcd_puts(0, 6, "[" KEYNAME2 "] to program");
701 rb->lcd_puts(0, 7, "other key to exit");
703 else
704 { /* error occured */
705 rb->lcd_puts(0, 6, "Any key to exit");
707 rb->lcd_update();
709 button = WaitForButton();
710 if (rc != eOK || button != KEY2)
712 return;
715 true_size = ImageHeader.size;
716 aligned_size = ((sizeof(tImageHeader) + true_size + SECTORSIZE-1) &
717 ~(SECTORSIZE-1)) - sizeof(tImageHeader); /* round up to
718 next flash
719 sector */
720 ImageHeader.size = aligned_size; /* increase image size such that we reach
721 the next sector */
723 rb->lcd_clear_display();
724 rb->lcd_puts_scroll(0, 0, "Programming...");
725 rb->lcd_update();
727 rc = ProgramImageFile(filename, pos, &ImageHeader, UCL_HEADER, true_size);
728 if (rc)
729 { /* errors */
730 rb->lcd_clear_display();
731 rb->snprintf(buf, sizeof(buf), "%d errors", rc);
732 rb->lcd_puts(0, 0, "Error:");
733 rb->lcd_puts(0, 1, "Programming fail!");
734 rb->lcd_puts(0, 2, buf);
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->snprintf(buf, sizeof(buf), "%d errors", rc);
753 rb->lcd_puts(0, 0, "Error:");
754 rb->lcd_puts(0, 1, "Verify fail!");
755 rb->lcd_puts(0, 2, buf);
756 rb->lcd_puts(0, 3, "Use safe image");
757 rb->lcd_puts(0, 4, "if booting hangs:");
758 rb->lcd_puts(0, 5, "F1 during power-on");
760 rb->lcd_puts(0, 7, "Any key to exit");
761 rb->lcd_update();
762 WaitForButton();
765 #else /* #ifdef HAVE_LCD_BITMAP */
767 /* Player version */
768 static void DoUserDialog(char* filename)
770 tImageHeader ImageHeader;
771 tFlashInfo FlashInfo;
772 static char buf[MAX_PATH];
773 int button;
774 int rc; /* generic return code */
775 UINT32 space, aligned_size, true_size;
776 UINT8* pos;
777 ssize_t memleft;
778 unsigned bl_version;
780 /* this can only work if Rockbox runs in DRAM, not flash ROM */
781 if ((UINT8*)rb >= FB && (UINT8*)rb < FB + 4096*1024) /* 4 MB max */
782 { /* we're running from flash */
783 rb->splash(HZ*3, "Not from ROM");
784 return; /* exit */
787 /* refuse to work if the power may fail meanwhile */
788 if (!rb->battery_level_safe())
790 rb->splash(HZ*3, "Batt. too low!");
791 return; /* exit */
794 /* "allocate" memory */
795 sector = rb->plugin_get_buffer((size_t *)&memleft);
796 if (memleft < SECTORSIZE) /* need buffer for a flash sector */
798 rb->splash(HZ*3, "Out of memory");
799 return; /* exit */
802 pos = (void*)GetSecondImage();
803 rc = GetFlashInfo(&FlashInfo);
805 if (FlashInfo.size == 0) /* no valid chip */
807 rb->splash(HZ*3, "Not flashable");
808 return; /* exit */
810 else if (pos == 0)
812 rb->splash(HZ*3, "No image");
813 return; /* exit */
816 bl_version = BootloaderVersion();
817 if (bl_version < LATEST_BOOTLOADER_VERSION)
819 rb->lcd_puts_scroll(0, 0, "Hint: You're not using the latest bootloader. A full reflash is recommended, but not required.");
820 rb->lcd_puts_scroll(0, 1, "Press [Menu] to ignore");
821 rb->lcd_update();
823 if (WaitForButton() != BUTTON_MENU)
825 return;
827 rb->lcd_clear_display();
830 rb->lcd_puts(0, 0, "Checking...");
831 rb->lcd_update();
833 space = FlashInfo.size - (pos-FB + sizeof(ImageHeader));
834 /* size minus start */
836 rc = CheckImageFile(filename, space, &ImageHeader, pos);
837 rb->lcd_puts(0, 0, "Checked:");
838 switch (rc) {
839 case eOK:
840 rb->lcd_puts(0, 1, "File OK.");
841 rb->sleep(HZ*1);
842 break;
843 case eNotUCL:
844 rb->lcd_puts_scroll(0, 1, "File not UCL compressed.");
845 break;
846 case eWrongAlgorithm:
847 rb->lcd_puts_scroll(0, 1, "Wrong compression algorithm.");
848 break;
849 case eFileNotFound:
850 rb->lcd_puts_scroll(0, 1, "File not found.");
851 break;
852 case eTooBig:
853 rb->lcd_puts_scroll(0, 1, "File too big.");
854 break;
855 case eTooSmall:
856 rb->lcd_puts_scroll(0, 1, "File too small. Incomplete?");
857 break;
858 case eReadErr:
859 rb->lcd_puts_scroll(0, 1, "File read error.");
860 break;
861 case eMultiBlocks:
862 rb->lcd_puts_scroll(0, 1, "File invalid. Blocksize too small?");
863 break;
864 case eBadRomLink:
865 rb->lcd_puts_scroll(0, 1, "RomBox mismatch.");
866 break;
867 default:
868 rb->lcd_puts_scroll(0, 1, "Check failed.");
869 break;
871 rb->lcd_update();
873 if (rc == eOK)
874 { /* was OK */
875 rb->lcd_clear_display();
876 rb->lcd_puts_scroll(0, 0, "[ON] to program,");
877 rb->lcd_puts_scroll(0, 1, "other key to exit.");
879 else
880 { /* error occured */
881 WaitForButton();
882 rb->lcd_clear_display();
883 rb->lcd_puts_scroll(0, 0, "Flash failed.");
884 rb->lcd_puts_scroll(0, 1, "Any key to exit.");
886 rb->lcd_update();
888 button = WaitForButton();
889 if (rc != eOK || button != BUTTON_ON)
891 return;
894 true_size = ImageHeader.size;
895 aligned_size = ((sizeof(tImageHeader) + true_size + SECTORSIZE-1) &
896 ~(SECTORSIZE-1)) - sizeof(tImageHeader); /* round up to
897 next flash
898 sector */
899 ImageHeader.size = aligned_size; /* increase image size such that we reach
900 the next sector */
902 rb->lcd_clear_display();
903 rb->lcd_puts_scroll(0, 0, "Programming...");
904 rb->lcd_update();
906 rc = ProgramImageFile(filename, pos, &ImageHeader, UCL_HEADER, true_size);
907 if (rc)
908 { /* errors */
909 rb->lcd_clear_display();
910 rb->snprintf(buf, sizeof(buf), "%d errors", rc);
911 rb->lcd_puts_scroll(0, 0, "Programming failed!");
912 rb->lcd_puts_scroll(0, 1, buf);
913 rb->lcd_update();
914 button = WaitForButton();
917 rb->lcd_clear_display();
918 rb->lcd_puts_scroll(0, 0, "Verifying...");
919 rb->lcd_update();
921 rc = VerifyImageFile(filename, pos, &ImageHeader, UCL_HEADER, true_size);
923 rb->lcd_clear_display();
924 if (rc == 0)
926 rb->lcd_puts(0, 0, "Verify OK.");
927 rb->lcd_update();
929 else
931 rb->snprintf(buf, sizeof(buf), "Verify fail! %d errors", rc);
932 rb->lcd_puts_scroll(0, 0, buf);
933 rb->lcd_puts_scroll(0, 1, "Use safe image if booting hangs: [-] during power-on");
934 rb->lcd_update();
935 button = WaitForButton();
939 #endif /* not HAVE_LCD_BITMAP */
943 /***************** Plugin Entry Point *****************/
945 enum plugin_status plugin_start(const struct plugin_api* api, const void* parameter)
947 int oldmode;
949 rb = api; /* copy to global api pointer */
951 if (parameter == NULL)
953 rb->splash(HZ*3, "Play .ucl file!");
954 return PLUGIN_OK;
957 /* now go ahead and have fun! */
958 oldmode = rb->system_memory_guard(MEMGUARD_NONE); /*disable memory guard */
959 DoUserDialog((char*) parameter);
960 rb->system_memory_guard(oldmode); /* re-enable memory guard */
962 return PLUGIN_OK;
966 #endif /* SH-target */