1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
26 /* define DUMMY if you only want to "play" with the UI, does no harm */
29 #define LATEST_BOOTLOADER_VERSION 3 /* update this with the bootloader */
32 #define UINT8 unsigned char
36 #define UINT16 unsigned short
40 #define UINT32 unsigned long
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"
58 #else /* recorder keypad */
59 #define KEY1 BUTTON_F1
60 #define KEY2 BUTTON_F2
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 */
74 /* result of the CheckFirmwareFile() function */
78 eFileNotFound
, /* errors from here on */
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
,
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,
111 not_manu
= pBase
[0]; /* read the normal content */
112 not_id
= pBase
[1]; /* should be 'A' (0x41) and 'R' (0x52) from the
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 */
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 */
133 return true; /* success */
135 return false; /* fail */
138 /* erase the sector which contains the given address */
139 static bool EraseSector(volatile UINT8
* pAddr
)
142 (void)pAddr
; /* prevents warning */
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
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);
165 /* address must be in an erased location */
166 static inline bool ProgramByte(volatile UINT8
* pAddr
, UINT8 data
)
169 (void)pAddr
; /* prevents warnings */
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 */
180 FB
[0x5555] = 0xA0; /* byte program command */
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);
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
))
200 if (pInfo
->manufacturer
== 0xBF) /* SST */
202 if (pInfo
->id
== 0xD6)
204 pInfo
->size
= 256* 1024; /* 256k */
205 rb
->strcpy(pInfo
->name
, "SST39VF020");
208 else if (pInfo
->id
== 0xD7)
210 pInfo
->size
= 512* 1024; /* 512k */
211 rb
->strcpy(pInfo
->name
, "SST39VF040");
221 /*********** Tool Functions ************/
223 /* read a 32 bit value from memory, big endian */
224 static UINT32
Read32(UINT8
* pByte
)
228 value
= (UINT32
)pByte
[0] << 24;
229 value
|= (UINT32
)pByte
[1] << 16;
230 value
|= (UINT32
)pByte
[2] << 8;
231 value
|= (UINT32
)pByte
[3];
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
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
)
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
);
291 return eFileNotFound
;
293 filesize
= rb
->filesize(fd
);
294 if (filesize
- (int)sizeof(ucl_header
) - 8 > space
)
299 else if (filesize
< 10000) /* give it some reasonable lower limit */
305 /* do some sanity checks */
307 read
= rb
->read(fd
, ucl_header
, sizeof(ucl_header
));
309 if (read
!= sizeof(ucl_header
))
315 /* compare the magic header */
318 if (ucl_header
[i
] != magic
[i
])
325 pHeader
->size
= Read32(ucl_header
+ 22); /* compressed size */
326 if (pHeader
->size
!= filesize
- sizeof(ucl_header
) - 8)
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
338 { /* compressed, normal case */
339 pHeader
->flags
= 0x00000001; /* flags for UCL compressed */
341 /* check for supported algorithm */
342 if (ucl_header
[12] != 0x2E)
345 return eWrongAlgorithm
;
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
));
356 if (read
!= sizeof(reset_vector
))
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. */
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
));
378 if (read
!= sizeof(reset_vector
))
385 pHeader
->execute
= reset_vector
;
388 /* check if we can read the whole file */
391 read
= rb
->read(fd
, sector
, SECTORSIZE
);
393 } while (read
== SECTORSIZE
);
397 if (fileread
!= filesize
)
404 /* returns the # of failures, 0 on success */
405 static unsigned ProgramImageFile(char* filename
, UINT8
* pos
,
406 tImageHeader
* pImageHeader
,
411 int read
; /* how many for this sector */
412 unsigned failures
= 0;
414 fd
= rb
->open(filename
, O_RDONLY
);
418 /* no error checking necessary here, we checked for minimum size
420 rb
->lseek(fd
, start
, SEEK_SET
); /* go to start position */
422 *(tImageHeader
*)sector
= *pImageHeader
; /* copy header into sector
424 read
= rb
->read(fd
, sector
+ sizeof(tImageHeader
),
425 SECTORSIZE
- sizeof(tImageHeader
)); /* payload behind */
427 read
+= sizeof(tImageHeader
); /* to be programmed, but not part of the
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
]))
445 read
= rb
->read(fd
, sector
, (size
> SECTORSIZE
) ? SECTORSIZE
: size
);
446 /* payload for next sector */
455 /* returns the # of failures, 0 on success */
456 static unsigned VerifyImageFile(char* filename
, UINT8
* pos
,
457 tImageHeader
* pImageHeader
,
462 int read
; /* how many for this sector */
463 unsigned failures
= 0;
465 fd
= rb
->open(filename
, O_RDONLY
);
469 /* no error checking necessary here, we checked for minimum size
471 rb
->lseek(fd
, start
, SEEK_SET
); /* go to start position */
473 *(tImageHeader
*)sector
= *pImageHeader
; /* copy header into sector
475 read
= rb
->read(fd
, sector
+ sizeof(tImageHeader
),
476 SECTORSIZE
- sizeof(tImageHeader
)); /* payload behind */
479 read
+= sizeof(tImageHeader
); /* to be programmed, but not part of the
484 for (i
=0; i
<read
; i
++)
486 if (pos
[i
] != sector
[i
])
493 read
= rb
->read(fd
, sector
, (size
> SECTORSIZE
) ? SECTORSIZE
: size
);
494 /* payload for next sector */
504 /***************** User Interface Functions *****************/
506 static int WaitForButton(void)
512 button
= rb
->button_get(true);
513 } while (IS_SYSEVENT(button
) || (button
& BUTTON_REL
));
518 #ifdef HAVE_LCD_BITMAP
519 /* helper for DoUserDialog() */
520 static void ShowFlashInfo(tFlashInfo
* pInfo
, tImageHeader
* pImageHeader
)
524 if (!pInfo
->manufacturer
)
526 rb
->lcd_puts_scroll(0, 0, "Flash: M=?? D=??");
532 rb
->snprintf(buf
, sizeof(buf
), "Flash size: %d KB",
534 rb
->lcd_puts_scroll(0, 0, buf
);
538 rb
->lcd_puts_scroll(0, 0, "Unsupported chip");
545 rb
->snprintf(buf
, sizeof(buf
), "Image at %d KB",
546 ((UINT8
*)pImageHeader
- FB
) / 1024);
547 rb
->lcd_puts_scroll(0, 1, buf
);
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
;
563 int rc
; /* generic return code */
564 UINT32 space
, aligned_size
, true_size
;
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");
577 /* refuse to work if the power may fail meanwhile */
578 if (!rb
->battery_level_safe())
580 rb
->splash(HZ
*3, "Battery too low!");
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");
592 rb
->lcd_setfont(FONT_SYSFIXED
);
594 pos
= (void*)GetSecondImage();
595 rc
= GetFlashInfo(&FlashInfo
);
597 ShowFlashInfo(&FlashInfo
, (void*)pos
);
600 if (FlashInfo
.size
== 0) /* no valid chip */
602 rb
->splash(HZ
*3, "Not flashable");
607 rb
->splash(HZ
*3, "No image");
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");
626 if (WaitForButton() != KEY1
)
630 rb
->lcd_clear_display();
634 rb
->lcd_puts(0, show_greet
? 0 : 3, "Checking...");
637 space
= FlashInfo
.size
- (pos
-FB
+ sizeof(ImageHeader
));
638 /* size minus start */
640 rc
= CheckImageFile(filename
, space
, &ImageHeader
, pos
);
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:");
650 rb
->lcd_puts(0, show_greet
? 0 : 4, "File OK.");
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");
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");
665 rb
->lcd_puts(0, 1, "File not found:");
666 rb
->lcd_puts_scroll(0, 2, filename
);
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");
677 rb
->lcd_puts(0, 1, "File too small.");
678 rb
->lcd_puts(0, 2, "Incomplete?");
681 rb
->lcd_puts(0, 1, "File read error.");
684 rb
->lcd_puts(0, 1, "File invalid.");
685 rb
->lcd_puts(0, 2, "Blocksize");
686 rb
->lcd_puts(0, 3, " too small?");
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.");
695 rb
->lcd_puts(0, 1, "Check failed.");
701 rb
->lcd_puts(0, 6, "[" KEYNAME2
"] to program");
702 rb
->lcd_puts(0, 7, "other key to exit");
705 { /* error occured */
706 rb
->lcd_puts(0, 6, "Any key to exit");
710 button
= WaitForButton();
711 if (rc
!= eOK
|| button
!= KEY2
)
716 true_size
= ImageHeader
.size
;
717 aligned_size
= ((sizeof(tImageHeader
) + true_size
+ SECTORSIZE
-1) &
718 ~(SECTORSIZE
-1)) - sizeof(tImageHeader
); /* round up to
721 ImageHeader
.size
= aligned_size
; /* increase image size such that we reach
724 rb
->lcd_clear_display();
725 rb
->lcd_puts_scroll(0, 0, "Programming...");
728 rc
= ProgramImageFile(filename
, pos
, &ImageHeader
, UCL_HEADER
, true_size
);
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
);
736 button
= WaitForButton();
739 rb
->lcd_clear_display();
740 rb
->lcd_puts_scroll(0, 0, "Verifying...");
743 rc
= VerifyImageFile(filename
, pos
, &ImageHeader
, UCL_HEADER
, true_size
);
745 rb
->lcd_clear_display();
748 rb
->lcd_puts(0, 0, "Verify OK.");
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");
764 #else /* #ifdef HAVE_LCD_BITMAP */
767 static void DoUserDialog(char* filename
)
769 tImageHeader ImageHeader
;
770 tFlashInfo FlashInfo
;
771 static char buf
[MAX_PATH
];
773 int rc
; /* generic return code */
774 UINT32 space
, aligned_size
, true_size
;
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");
786 /* refuse to work if the power may fail meanwhile */
787 if (!rb
->battery_level_safe())
789 rb
->splash(HZ
*3, "Batt. too low!");
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");
801 pos
= (void*)GetSecondImage();
802 rc
= GetFlashInfo(&FlashInfo
);
804 if (FlashInfo
.size
== 0) /* no valid chip */
806 rb
->splash(HZ
*3, "Not flashable");
811 rb
->splash(HZ
*3, "No image");
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");
822 if (WaitForButton() != BUTTON_MENU
)
826 rb
->lcd_clear_display();
829 rb
->lcd_puts(0, 0, "Checking...");
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:");
839 rb
->lcd_puts(0, 1, "File OK.");
843 rb
->lcd_puts_scroll(0, 1, "File not UCL compressed.");
845 case eWrongAlgorithm
:
846 rb
->lcd_puts_scroll(0, 1, "Wrong compression algorithm.");
849 rb
->lcd_puts_scroll(0, 1, "File not found.");
852 if (bl_version
< LATEST_BOOTLOADER_VERSION
)
854 rb
->lcd_puts_scroll(0, 1, "File too big, upgrade bootloader.");
858 rb
->lcd_puts_scroll(0, 1, "File too big.");
862 rb
->lcd_puts_scroll(0, 1, "File too small. Incomplete?");
865 rb
->lcd_puts_scroll(0, 1, "File read error.");
868 rb
->lcd_puts_scroll(0, 1, "File invalid. Blocksize too small?");
871 rb
->lcd_puts_scroll(0, 1, "Bootloader not compatible with RomBox.");
874 rb
->lcd_puts_scroll(0, 1, "Check failed.");
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.");
886 { /* error occured */
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.");
894 button
= WaitForButton();
895 if (rc
!= eOK
|| button
!= BUTTON_ON
)
900 true_size
= ImageHeader
.size
;
901 aligned_size
= ((sizeof(tImageHeader
) + true_size
+ SECTORSIZE
-1) &
902 ~(SECTORSIZE
-1)) - sizeof(tImageHeader
); /* round up to
905 ImageHeader
.size
= aligned_size
; /* increase image size such that we reach
908 rb
->lcd_clear_display();
909 rb
->lcd_puts_scroll(0, 0, "Programming...");
912 rc
= ProgramImageFile(filename
, pos
, &ImageHeader
, UCL_HEADER
, true_size
);
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
);
920 button
= WaitForButton();
923 rb
->lcd_clear_display();
924 rb
->lcd_puts_scroll(0, 0, "Verifying...");
927 rc
= VerifyImageFile(filename
, pos
, &ImageHeader
, UCL_HEADER
, true_size
);
929 rb
->lcd_clear_display();
932 rb
->lcd_puts(0, 0, "Verify OK.");
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");
941 button
= WaitForButton();
945 #endif /* not HAVE_LCD_BITMAP */
949 /***************** Plugin Entry Point *****************/
951 enum plugin_status
plugin_start(const void* parameter
)
955 if (parameter
== NULL
)
957 rb
->splash(HZ
*3, "Play .ucl file!");
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 */