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 #if (CONFIG_CPU == SH7034) /* Only for SH targets */
30 /* define DUMMY if you only want to "play" with the UI, does no harm */
33 #define LATEST_BOOTLOADER_VERSION 1 /* update this with the bootloader */
36 #define UINT8 unsigned char
40 #define UINT16 unsigned short
44 #define UINT32 unsigned long
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"
62 #else /* recorder keypad */
63 #define KEY1 BUTTON_F1
64 #define KEY2 BUTTON_F2
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 */
78 /* result of the CheckFirmwareFile() function */
82 eFileNotFound
, /* errors from here on */
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 bool ReadID(volatile UINT8
* pBase
, UINT8
* pManufacturerID
, UINT8
* pDeviceID
)
110 UINT8 not_manu
, not_id
; /* read values before switching to ID mode */
111 UINT8 manu
, id
; /* read values when in ID mode */
113 pBase
= (UINT8
*)((UINT32
)pBase
& 0xFFF80000); /* round down to 512k align,
116 not_manu
= pBase
[0]; /* read the normal content */
117 not_id
= pBase
[1]; /* should be 'A' (0x41) and 'R' (0x52) from the
120 pBase
[0x5555] = 0xAA; /* enter command mode */
121 pBase
[0x2AAA] = 0x55;
122 pBase
[0x5555] = 0x90; /* ID command */
123 rb
->sleep(HZ
/50); /* Atmel wants 20ms pause here */
128 pBase
[0] = 0xF0; /* reset flash (back to normal read mode) */
129 rb
->sleep(HZ
/50); /* Atmel wants 20ms pause here */
131 /* I assume success if the obtained values are different from
132 the normal flash content. This is not perfectly bulletproof, they
133 could theoretically be the same by chance, causing us to fail. */
134 if (not_manu
!= manu
|| not_id
!= id
) /* a value has changed */
136 *pManufacturerID
= manu
; /* return the results */
138 return true; /* success */
140 return false; /* fail */
143 /* erase the sector which contains the given address */
144 bool EraseSector(volatile UINT8
* pAddr
)
147 (void)pAddr
; /* prevents warning */
150 volatile UINT8
* pBase
=
151 (UINT8
*)((UINT32
)pAddr
& 0xFFF80000); /* round down to 512k align */
152 unsigned timeout
= 43000; /* the timeout loop should be no less than
155 pBase
[0x5555] = 0xAA; /* enter command mode */
156 pBase
[0x2AAA] = 0x55;
157 pBase
[0x5555] = 0x80; /* erase command */
158 pBase
[0x5555] = 0xAA; /* enter command mode */
159 pBase
[0x2AAA] = 0x55;
160 *pAddr
= 0x30; /* erase the sector */
162 /* I counted 7 instructions for this loop -> min. 0.58 us per round
163 Plus memory waitstates it will be much more, gives margin */
164 while (*pAddr
!= 0xFF && --timeout
); /* poll for erased */
166 return (timeout
!= 0);
170 /* address must be in an erased location */
171 inline bool ProgramByte(volatile UINT8
* pAddr
, UINT8 data
)
174 (void)pAddr
; /* prevents warnings */
178 unsigned timeout
= 35; /* the timeout loop should be no less than 20us */
180 if (~*pAddr
& data
) /* just a safety feature, not really necessary */
181 return false; /* can't set any bit from 0 to 1 */
183 FB
[0x5555] = 0xAA; /* enter command mode */
185 FB
[0x5555] = 0xA0; /* byte program command */
189 /* I counted 7 instructions for this loop -> min. 0.58 us per round
190 Plus memory waitstates it will be much more, gives margin */
191 while (*pAddr
!= data
&& --timeout
); /* poll for programmed */
193 return (timeout
!= 0);
197 /* this returns true if supported and fills the info struct */
198 bool GetFlashInfo(tFlashInfo
* pInfo
)
200 rb
->memset(pInfo
, 0, sizeof(tFlashInfo
));
202 if (!ReadID(FB
, &pInfo
->manufacturer
, &pInfo
->id
))
205 if (pInfo
->manufacturer
== 0xBF) /* SST */
207 if (pInfo
->id
== 0xD6)
209 pInfo
->size
= 256* 1024; /* 256k */
210 rb
->strcpy(pInfo
->name
, "SST39VF020");
213 else if (pInfo
->id
== 0xD7)
215 pInfo
->size
= 512* 1024; /* 512k */
216 rb
->strcpy(pInfo
->name
, "SST39VF040");
226 /*********** Tool Functions ************/
228 /* place a 32 bit value into memory, big endian */
229 void Write32(UINT8
* pByte
, UINT32 value
)
231 pByte
[0] = (UINT8
)(value
>> 24);
232 pByte
[1] = (UINT8
)(value
>> 16);
233 pByte
[2] = (UINT8
)(value
>> 8);
234 pByte
[3] = (UINT8
)(value
);
237 /* read a 32 bit value from memory, big endian */
238 UINT32
Read32(UINT8
* pByte
)
242 value
= (UINT32
)pByte
[0] << 24;
243 value
|= (UINT32
)pByte
[1] << 16;
244 value
|= (UINT32
)pByte
[2] << 8;
245 value
|= (UINT32
)pByte
[3];
250 /* get the start address of the second image */
251 tImageHeader
* GetSecondImage(void)
253 tImageHeader
* pImage1
;
254 UINT32 pos
= 0; /* default: not found */
255 UINT32
* pFlash
= (UINT32
*)FB
;
257 /* determine the first image position */
258 pos
= pFlash
[2] + pFlash
[3]; /* position + size of the bootloader
260 pos
= (pos
+ 3) & ~3; /* be sure it's 32 bit aligned */
261 pImage1
= (tImageHeader
*)pos
;
263 if (pImage1
->destination
!= ROCKBOX_DEST
||
264 pImage1
->execute
!= ROCKBOX_EXEC
)
265 return 0; /* seems to be no Archos/Rockbox image in here */
267 if (pImage1
->size
!= 0)
269 /* success, we have a second image */
270 pos
= (UINT32
)pImage1
+ sizeof(tImageHeader
) + pImage1
->size
;
271 if (((pos
+ SECTORSIZE
-1) & ~(SECTORSIZE
-1)) != pos
)
272 { /* not sector-aligned */
273 pos
= 0; /* sanity check failed */
277 return (tImageHeader
*)pos
;
281 /* Tool function to calculate a CRC32 across some buffer */
282 /* third argument is either 0xFFFFFFFF to start or value from last piece */
283 UINT32
crc_32(unsigned char* buf
, unsigned len
, unsigned crc32
)
285 /* CCITT standard polynomial 0x04C11DB7 */
286 static const UINT32 crc32_lookup
[16] =
287 { /* lookup table for 4 bits at a time is affordable */
288 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9,
289 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,
290 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61,
291 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD
299 byte
= *buf
++; /* get one byte of data */
301 /* upper nibble of our data */
302 t
= crc32
>> 28; /* extract the 4 most significant bits */
303 t
^= byte
>> 4; /* XOR in 4 bits of data into the extracted bits */
304 crc32
<<= 4; /* shift the CRC register left 4 bits */
305 crc32
^= crc32_lookup
[t
]; /* do the table lookup and XOR the result */
307 /* lower nibble of our data */
308 t
= crc32
>> 28; /* extract the 4 most significant bits */
309 t
^= byte
& 0x0F; /* XOR in 4 bits of data into the extracted bits */
310 crc32
<<= 4; /* shift the CRC register left 4 bits */
311 crc32
^= crc32_lookup
[t
]; /* do the table lookup and XOR the result */
318 /* test if the bootloader is up-to-date, returns 0 if yes, else CRC */
319 unsigned CheckBootloader(void)
322 UINT32
* pFlash
= (UINT32
*)FB
;
323 int bootloader_version
= FB
[BOOT_VERS_ADR
];
325 if (bootloader_version
) /* this is a newer image, with a version number */
327 if (bootloader_version
< LATEST_BOOTLOADER_VERSION
)
328 return bootloader_version
;
333 /* checksum the bootloader, unfortunately I have no version info yet */
334 crc
= crc_32((unsigned char*)pFlash
[2], pFlash
[3], -1);
336 /* Here I have to check for ARCHOS_* defines in source code, which is
337 generally strongly discouraged. But here I'm not checking for a certain
338 feature, I'm checking for the model itself. */
339 #if defined(ARCHOS_PLAYER)
340 if (crc
== 0x78DAC94A)
342 #elif defined(ARCHOS_RECORDER)
343 if (crc
== 0xE968702E || crc
== 0x7C3D93B4) /* normal or ROMless each */
345 #elif defined(ARCHOS_RECORDERV2)
346 if (crc
== 0x4511E9B5 || crc
== 0x3A93DBDF)
348 #elif defined(ARCHOS_FMRECORDER)
349 if (crc
== 0x4511E9B5 || crc
== 0x3A93DBDF)
357 /*********** Image File Functions ************/
359 /* so far, only compressed images in UCL NRV algorithm 2e supported */
360 tCheckResult
CheckImageFile(char* filename
, int space
, tImageHeader
* pHeader
,
365 int filesize
; /* size info */
367 int fileread
= 0; /* total size as read from the file */
368 int read
; /* how many for this sector */
370 /* magic file header for compressed files */
371 static const UINT8 magic
[8] = { 0x00,0xe9,0x55,0x43,0x4c,0xff,0x01,0x1a };
372 UINT8 ucl_header
[UCL_HEADER
];
374 fd
= rb
->open(filename
, O_RDONLY
);
376 return eFileNotFound
;
378 filesize
= rb
->filesize(fd
);
379 if (filesize
- (int)sizeof(ucl_header
) - 8 > space
)
384 else if (filesize
< 10000) /* give it some reasonable lower limit */
390 /* do some sanity checks */
392 read
= rb
->read(fd
, ucl_header
, sizeof(ucl_header
));
394 if (read
!= sizeof(ucl_header
))
400 /* compare the magic header */
403 if (ucl_header
[i
] != magic
[i
])
410 pHeader
->size
= Read32(ucl_header
+ 22); /* compressed size */
411 if (pHeader
->size
!= filesize
- sizeof(ucl_header
) - 8)
417 /* fill in the hardcoded defaults of the header */
418 pHeader
->destination
= ROCKBOX_DEST
;
419 pHeader
->execute
= ROCKBOX_EXEC
;
421 if (Read32(ucl_header
+ 18) > pHeader
->size
) /* compare with uncompressed
423 { /* compressed, normal case */
424 pHeader
->flags
= 0x00000001; /* flags for UCL compressed */
426 /* check for supported algorithm */
427 if (ucl_header
[12] != 0x2E)
430 return eWrongAlgorithm
;
434 { /* uncompressed, either to be copied or run directly in flash */
435 UINT32 reset_vector
; /* image has to start with reset vector */
437 pHeader
->flags
= 0x00000000; /* uncompressed */
439 read
= rb
->read(fd
, &reset_vector
, sizeof(reset_vector
));
441 if (read
!= sizeof(reset_vector
))
446 if (reset_vector
>= (UINT32
)FB
447 && reset_vector
< (UINT32
)FB
+512*1024) /* ROM address? */
449 /* assume in-place, executing directly in flash */
450 pHeader
->destination
= (UINT32
)(pos
+ sizeof(tImageHeader
));
452 /* for new RomBox, this isn't the reset vector,
453 but the link address, for us to check the position */
454 if(pHeader
->destination
!= reset_vector
) /* compare link addr. */
457 return eBadRomLink
; /* not matching the start address */
460 /* read the now following reset vector */
461 read
= rb
->read(fd
, &reset_vector
, sizeof(reset_vector
));
463 if (read
!= sizeof(reset_vector
))
470 pHeader
->execute
= reset_vector
;
473 /* check if we can read the whole file */
476 read
= rb
->read(fd
, sector
, SECTORSIZE
);
478 } while (read
== SECTORSIZE
);
482 if (fileread
!= filesize
)
489 /* returns the # of failures, 0 on success */
490 unsigned ProgramImageFile(char* filename
, UINT8
* pos
,
491 tImageHeader
* pImageHeader
, int start
, int size
)
495 int read
; /* how many for this sector */
496 unsigned failures
= 0;
498 fd
= rb
->open(filename
, O_RDONLY
);
502 /* no error checking necessary here, we checked for minimum size
504 rb
->lseek(fd
, start
, SEEK_SET
); /* go to start position */
506 *(tImageHeader
*)sector
= *pImageHeader
; /* copy header into sector
508 read
= rb
->read(fd
, sector
+ sizeof(tImageHeader
),
509 SECTORSIZE
- sizeof(tImageHeader
)); /* payload behind */
511 read
+= sizeof(tImageHeader
); /* to be programmed, but not part of the
515 if (!EraseSector(pos
))
517 /* nothing we can do, let the programming count the errors */
520 for (i
=0; i
<read
; i
++)
522 if (!ProgramByte(pos
+ i
, sector
[i
]))
529 read
= rb
->read(fd
, sector
, (size
> SECTORSIZE
) ? SECTORSIZE
: size
);
530 /* payload for next sector */
539 /* returns the # of failures, 0 on success */
540 unsigned VerifyImageFile(char* filename
, UINT8
* pos
,
541 tImageHeader
* pImageHeader
, int start
, int size
)
545 int read
; /* how many for this sector */
546 unsigned failures
= 0;
548 fd
= rb
->open(filename
, O_RDONLY
);
552 /* no error checking necessary here, we checked for minimum size
554 rb
->lseek(fd
, start
, SEEK_SET
); /* go to start position */
556 *(tImageHeader
*)sector
= *pImageHeader
; /* copy header into sector
558 read
= rb
->read(fd
, sector
+ sizeof(tImageHeader
),
559 SECTORSIZE
- sizeof(tImageHeader
)); /* payload behind */
562 read
+= sizeof(tImageHeader
); /* to be programmed, but not part of the
567 for (i
=0; i
<read
; i
++)
569 if (pos
[i
] != sector
[i
])
576 read
= rb
->read(fd
, sector
, (size
> SECTORSIZE
) ? SECTORSIZE
: size
);
577 /* payload for next sector */
587 /***************** User Interface Functions *****************/
589 int WaitForButton(void)
595 button
= rb
->button_get(true);
596 } while (button
& BUTTON_REL
);
601 /* helper for DoUserDialog() */
602 void ShowFlashInfo(tFlashInfo
* pInfo
, tImageHeader
* pImageHeader
)
606 if (!pInfo
->manufacturer
)
608 rb
->lcd_puts_scroll(0, 0, "Flash: M=?? D=??");
614 rb
->snprintf(buf
, sizeof(buf
), "Flash size: %d KB",
616 rb
->lcd_puts_scroll(0, 0, buf
);
620 rb
->lcd_puts_scroll(0, 0, "Unsupported chip");
627 rb
->snprintf(buf
, sizeof(buf
), "Image at %d KB",
628 ((UINT8
*)pImageHeader
- FB
) / 1024);
629 rb
->lcd_puts_scroll(0, 1, buf
);
633 rb
->lcd_puts_scroll(0, 1, "No image found!");
638 /* Kind of our main function, defines the application flow. */
639 #ifdef HAVE_LCD_BITMAP
640 /* recorder version */
641 void DoUserDialog(char* filename
)
643 tImageHeader ImageHeader
;
644 tFlashInfo FlashInfo
;
645 static char buf
[MAX_PATH
];
647 int rc
; /* generic return code */
648 UINT32 space
, aligned_size
, true_size
;
652 bool show_greet
= false;
654 /* this can only work if Rockbox runs in DRAM, not flash ROM */
655 if ((UINT8
*)rb
>= FB
&& (UINT8
*)rb
< FB
+ 4096*1024) /* 4 MB max */
656 { /* we're running from flash */
657 rb
->splash(HZ
*3, "Not from ROM");
661 /* refuse to work if the power may fail meanwhile */
662 if (!rb
->battery_level_safe())
664 rb
->splash(HZ
*3, "Battery too low!");
668 /* "allocate" memory */
669 sector
= rb
->plugin_get_buffer((size_t *)&memleft
);
670 if (memleft
< SECTORSIZE
) /* need buffer for a flash sector */
672 rb
->splash(HZ
*3, "Out of memory");
676 rb
->lcd_setfont(FONT_SYSFIXED
);
678 pos
= (void*)GetSecondImage();
679 rc
= GetFlashInfo(&FlashInfo
);
681 ShowFlashInfo(&FlashInfo
, (void*)pos
);
684 if (FlashInfo
.size
== 0) /* no valid chip */
686 rb
->splash(HZ
*3, "Not flashable");
691 rb
->splash(HZ
*3, "No image");
695 crc
= CheckBootloader();
696 if (crc
) /* outdated version found */
698 rb
->snprintf(buf
, sizeof(buf
), "(check=0x%08lx)", crc
);
699 rb
->lcd_puts(0, 0, buf
);
700 rb
->lcd_puts(0, 1, "Hint: You're not ");
701 rb
->lcd_puts(0, 2, "using the latest ");
702 rb
->lcd_puts(0, 3, "bootloader. ");
703 rb
->lcd_puts(0, 4, "A full reflash is ");
704 rb
->lcd_puts(0, 5, "recommended, but ");
705 rb
->lcd_puts(0, 6, "not required. ");
706 rb
->lcd_puts(0, 7, "Press " KEYNAME1
" to ignore");
709 if (WaitForButton() != KEY1
)
713 rb
->lcd_clear_display();
716 rb
->lcd_puts(0, show_greet
? 0 : 3, "Checking...");
719 space
= FlashInfo
.size
- (pos
-FB
+ sizeof(ImageHeader
));
720 /* size minus start */
722 rc
= CheckImageFile(filename
, space
, &ImageHeader
, pos
);
725 rb
->lcd_clear_display(); /* make room for error message */
726 show_greet
= true; /* verbose */
729 rb
->lcd_puts(0, show_greet
? 0 : 3, "Checked:");
732 rb
->lcd_puts(0, show_greet
? 0 : 4, "File OK.");
735 rb
->lcd_puts(0, 1, "File not UCL ");
736 rb
->lcd_puts(0, 2, "compressed.");
737 rb
->lcd_puts(0, 3, "Use uclpack --2e");
738 rb
->lcd_puts(0, 4, " --10 rockbox.bin");
740 case eWrongAlgorithm
:
741 rb
->lcd_puts(0, 1, "Wrong algorithm");
742 rb
->lcd_puts(0, 2, "for compression.");
743 rb
->lcd_puts(0, 3, "Use uclpack --2e");
744 rb
->lcd_puts(0, 4, " --10 rockbox.bin");
747 rb
->lcd_puts(0, 1, "File not found:");
748 rb
->lcd_puts_scroll(0, 2, filename
);
751 rb
->lcd_puts(0, 1, "File too big,");
752 rb
->lcd_puts(0, 2, "won't fit in chip.");
755 rb
->lcd_puts(0, 1, "File too small.");
756 rb
->lcd_puts(0, 2, "Incomplete?");
759 rb
->lcd_puts(0, 1, "File read error.");
762 rb
->lcd_puts(0, 1, "File invalid.");
763 rb
->lcd_puts(0, 2, "Blocksize");
764 rb
->lcd_puts(0, 3, " too small?");
767 rb
->lcd_puts(0, 1, "RomBox mismatch.");
768 rb
->lcd_puts(0, 2, "Wrong ROM position");
771 rb
->lcd_puts(0, 1, "Check failed.");
777 rb
->lcd_puts(0, 6, "[" KEYNAME2
"] to program");
778 rb
->lcd_puts(0, 7, "other key to exit");
781 { /* error occured */
782 rb
->lcd_puts(0, 6, "Any key to exit");
786 button
= WaitForButton();
787 if (rc
!= eOK
|| button
!= KEY2
)
792 true_size
= ImageHeader
.size
;
793 aligned_size
= ((sizeof(tImageHeader
) + true_size
+ SECTORSIZE
-1) &
794 ~(SECTORSIZE
-1)) - sizeof(tImageHeader
); /* round up to
797 ImageHeader
.size
= aligned_size
; /* increase image size such that we reach
800 rb
->lcd_clear_display();
801 rb
->lcd_puts_scroll(0, 0, "Programming...");
804 rc
= ProgramImageFile(filename
, pos
, &ImageHeader
, UCL_HEADER
, true_size
);
807 rb
->lcd_clear_display();
808 rb
->snprintf(buf
, sizeof(buf
), "%d errors", rc
);
809 rb
->lcd_puts(0, 0, "Error:");
810 rb
->lcd_puts(0, 1, "Programming fail!");
811 rb
->lcd_puts(0, 2, buf
);
813 button
= WaitForButton();
816 rb
->lcd_clear_display();
817 rb
->lcd_puts_scroll(0, 0, "Verifying...");
820 rc
= VerifyImageFile(filename
, pos
, &ImageHeader
, UCL_HEADER
, true_size
);
822 rb
->lcd_clear_display();
825 rb
->lcd_puts(0, 0, "Verify OK.");
829 rb
->snprintf(buf
, sizeof(buf
), "%d errors", rc
);
830 rb
->lcd_puts(0, 0, "Error:");
831 rb
->lcd_puts(0, 1, "Verify fail!");
832 rb
->lcd_puts(0, 2, buf
);
833 rb
->lcd_puts(0, 3, "Use safe image");
834 rb
->lcd_puts(0, 4, "if booting hangs:");
835 rb
->lcd_puts(0, 5, "F1 during power-on");
837 rb
->lcd_puts(0, 7, "Any key to exit");
842 #else /* #ifdef HAVE_LCD_BITMAP */
845 void DoUserDialog(char* filename
)
847 tImageHeader ImageHeader
;
848 tFlashInfo FlashInfo
;
849 static char buf
[MAX_PATH
];
851 int rc
; /* generic return code */
852 UINT32 space
, aligned_size
, true_size
;
857 /* this can only work if Rockbox runs in DRAM, not flash ROM */
858 if ((UINT8
*)rb
>= FB
&& (UINT8
*)rb
< FB
+ 4096*1024) /* 4 MB max */
859 { /* we're running from flash */
860 rb
->splash(HZ
*3, "Not from ROM");
864 /* refuse to work if the power may fail meanwhile */
865 if (!rb
->battery_level_safe())
867 rb
->splash(HZ
*3, "Batt. too low!");
871 /* "allocate" memory */
872 sector
= rb
->plugin_get_buffer((size_t *)&memleft
);
873 if (memleft
< SECTORSIZE
) /* need buffer for a flash sector */
875 rb
->splash(HZ
*3, "Out of memory");
879 pos
= (void*)GetSecondImage();
880 rc
= GetFlashInfo(&FlashInfo
);
882 if (FlashInfo
.size
== 0) /* no valid chip */
884 rb
->splash(HZ
*3, "Not flashable");
889 rb
->splash(HZ
*3, "No image");
893 crc
= CheckBootloader();
894 if (crc
) /* outdated version found */
896 rb
->lcd_puts_scroll(0, 0, "Hint: You're not using the latest bootloader. A full reflash is recommended, but not required.");
897 rb
->lcd_puts_scroll(0, 1, "Press [Menu] to ignore");
900 if (WaitForButton() != BUTTON_MENU
)
904 rb
->lcd_clear_display();
907 rb
->lcd_puts(0, 0, "Checking...");
910 space
= FlashInfo
.size
- (pos
-FB
+ sizeof(ImageHeader
));
911 /* size minus start */
913 rc
= CheckImageFile(filename
, space
, &ImageHeader
, pos
);
914 rb
->lcd_puts(0, 0, "Checked:");
917 rb
->lcd_puts(0, 1, "File OK.");
921 rb
->lcd_puts_scroll(0, 1, "File not UCL compressed.");
923 case eWrongAlgorithm
:
924 rb
->lcd_puts_scroll(0, 1, "Wrong compression algorithm.");
927 rb
->lcd_puts_scroll(0, 1, "File not found.");
930 rb
->lcd_puts_scroll(0, 1, "File too big.");
933 rb
->lcd_puts_scroll(0, 1, "File too small. Incomplete?");
936 rb
->lcd_puts_scroll(0, 1, "File read error.");
939 rb
->lcd_puts_scroll(0, 1, "File invalid. Blocksize too small?");
942 rb
->lcd_puts_scroll(0, 1, "BootBox mismatch");
945 rb
->lcd_puts_scroll(0, 1, "Check failed.");
952 rb
->lcd_clear_display();
953 rb
->lcd_puts_scroll(0, 0, "[ON] to program,");
954 rb
->lcd_puts_scroll(0, 1, "other key to exit.");
957 { /* error occured */
959 rb
->lcd_clear_display();
960 rb
->lcd_puts_scroll(0, 0, "Flash failed.");
961 rb
->lcd_puts_scroll(0, 1, "Any key to exit.");
965 button
= WaitForButton();
966 if (rc
!= eOK
|| button
!= BUTTON_ON
)
971 true_size
= ImageHeader
.size
;
972 aligned_size
= ((sizeof(tImageHeader
) + true_size
+ SECTORSIZE
-1) &
973 ~(SECTORSIZE
-1)) - sizeof(tImageHeader
); /* round up to
976 ImageHeader
.size
= aligned_size
; /* increase image size such that we reach
979 rb
->lcd_clear_display();
980 rb
->lcd_puts_scroll(0, 0, "Programming...");
983 rc
= ProgramImageFile(filename
, pos
, &ImageHeader
, UCL_HEADER
, true_size
);
986 rb
->lcd_clear_display();
987 rb
->snprintf(buf
, sizeof(buf
), "%d errors", rc
);
988 rb
->lcd_puts_scroll(0, 0, "Programming failed!");
989 rb
->lcd_puts_scroll(0, 1, buf
);
991 button
= WaitForButton();
994 rb
->lcd_clear_display();
995 rb
->lcd_puts_scroll(0, 0, "Verifying...");
998 rc
= VerifyImageFile(filename
, pos
, &ImageHeader
, UCL_HEADER
, true_size
);
1000 rb
->lcd_clear_display();
1003 rb
->lcd_puts(0, 0, "Verify OK.");
1008 rb
->snprintf(buf
, sizeof(buf
), "Verify fail! %d errors", rc
);
1009 rb
->lcd_puts_scroll(0, 0, buf
);
1010 rb
->lcd_puts_scroll(0, 1, "Use safe image if booting hangs: [-] during power-on");
1012 button
= WaitForButton();
1016 #endif /* not HAVE_LCD_BITMAP */
1020 /***************** Plugin Entry Point *****************/
1022 enum plugin_status
plugin_start(const struct plugin_api
* api
, const void* parameter
)
1026 rb
= api
; /* copy to global api pointer */
1028 if (parameter
== NULL
)
1030 rb
->splash(HZ
*3, "Play .ucl file!");
1034 /* now go ahead and have fun! */
1035 oldmode
= rb
->system_memory_guard(MEMGUARD_NONE
); /*disable memory guard */
1036 DoUserDialog((char*) parameter
);
1037 rb
->system_memory_guard(oldmode
); /* re-enable memory guard */
1043 #endif /* SH-target */