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 * All files in this archive are subject to the GNU General Public License.
16 * See the file COPYING in the source tree root for full license agreement.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
24 #if (CONFIG_CPU == SH7034) /* Only for SH targets */
28 /* define DUMMY if you only want to "play" with the UI, does no harm */
31 #define LATEST_BOOTLOADER_VERSION 1 /* update this with the bootloader */
34 #define UINT8 unsigned char
38 #define UINT16 unsigned short
42 #define UINT32 unsigned long
45 /* hard-coded values */
46 static volatile UINT8
* FB
= (UINT8
*)0x02000000; /* Flash base address */
47 #define SECTORSIZE 4096 /* size of one flash sector */
49 #define ROCKBOX_DEST 0x09000000
50 #define ROCKBOX_EXEC 0x09000200
51 #define BOOT_VERS_ADR 0xFA /* position of bootloader version value in Flash */
52 #define FW_VERS_ADR 0xFE /* position of firmware version value in Flash */
53 #define UCL_HEADER 26 /* size of the header generated by uclpack */
55 #if CONFIG_KEYPAD == ONDIO_PAD /* limited keypad */
56 #define KEY1 BUTTON_LEFT
57 #define KEY2 BUTTON_UP
58 #define KEYNAME1 "Left"
60 #else /* recorder keypad */
61 #define KEY1 BUTTON_F1
62 #define KEY2 BUTTON_F2
69 UINT32 destination
; /* address to copy it to */
70 UINT32 size
; /* how many bytes of payload (to the next header) */
71 UINT32 execute
; /* entry point */
72 UINT32 flags
; /* uncompressed or compressed */
73 /* end of header, now comes the payload */
76 /* result of the CheckFirmwareFile() function */
80 eFileNotFound
, /* errors from here on */
98 static struct plugin_api
* rb
; /* here is a global api struct pointer */
100 static UINT8
* sector
; /* better not place this on the stack... */
102 /***************** Flash Functions *****************/
105 /* read the manufacturer and device ID */
106 bool ReadID(volatile UINT8
* pBase
, UINT8
* pManufacturerID
, UINT8
* pDeviceID
)
108 UINT8 not_manu
, not_id
; /* read values before switching to ID mode */
109 UINT8 manu
, id
; /* read values when in ID mode */
111 pBase
= (UINT8
*)((UINT32
)pBase
& 0xFFF80000); /* round down to 512k align,
114 not_manu
= pBase
[0]; /* read the normal content */
115 not_id
= pBase
[1]; /* should be 'A' (0x41) and 'R' (0x52) from the
118 pBase
[0x5555] = 0xAA; /* enter command mode */
119 pBase
[0x2AAA] = 0x55;
120 pBase
[0x5555] = 0x90; /* ID command */
121 rb
->sleep(HZ
/50); /* Atmel wants 20ms pause here */
126 pBase
[0] = 0xF0; /* reset flash (back to normal read mode) */
127 rb
->sleep(HZ
/50); /* Atmel wants 20ms pause here */
129 /* I assume success if the obtained values are different from
130 the normal flash content. This is not perfectly bulletproof, they
131 could theoretically be the same by chance, causing us to fail. */
132 if (not_manu
!= manu
|| not_id
!= id
) /* a value has changed */
134 *pManufacturerID
= manu
; /* return the results */
136 return true; /* success */
138 return false; /* fail */
141 /* erase the sector which contains the given address */
142 bool EraseSector(volatile UINT8
* pAddr
)
145 (void)pAddr
; /* prevents warning */
148 volatile UINT8
* pBase
=
149 (UINT8
*)((UINT32
)pAddr
& 0xFFF80000); /* round down to 512k align */
150 unsigned timeout
= 43000; /* the timeout loop should be no less than
153 pBase
[0x5555] = 0xAA; /* enter command mode */
154 pBase
[0x2AAA] = 0x55;
155 pBase
[0x5555] = 0x80; /* erase command */
156 pBase
[0x5555] = 0xAA; /* enter command mode */
157 pBase
[0x2AAA] = 0x55;
158 *pAddr
= 0x30; /* erase the sector */
160 /* I counted 7 instructions for this loop -> min. 0.58 us per round
161 Plus memory waitstates it will be much more, gives margin */
162 while (*pAddr
!= 0xFF && --timeout
); /* poll for erased */
164 return (timeout
!= 0);
168 /* address must be in an erased location */
169 inline bool ProgramByte(volatile UINT8
* pAddr
, UINT8 data
)
172 (void)pAddr
; /* prevents warnings */
176 unsigned timeout
= 35; /* the timeout loop should be no less than 20us */
178 if (~*pAddr
& data
) /* just a safety feature, not really necessary */
179 return false; /* can't set any bit from 0 to 1 */
181 FB
[0x5555] = 0xAA; /* enter command mode */
183 FB
[0x5555] = 0xA0; /* byte program command */
187 /* I counted 7 instructions for this loop -> min. 0.58 us per round
188 Plus memory waitstates it will be much more, gives margin */
189 while (*pAddr
!= data
&& --timeout
); /* poll for programmed */
191 return (timeout
!= 0);
195 /* this returns true if supported and fills the info struct */
196 bool GetFlashInfo(tFlashInfo
* pInfo
)
198 rb
->memset(pInfo
, 0, sizeof(tFlashInfo
));
200 if (!ReadID(FB
, &pInfo
->manufacturer
, &pInfo
->id
))
203 if (pInfo
->manufacturer
== 0xBF) /* SST */
205 if (pInfo
->id
== 0xD6)
207 pInfo
->size
= 256* 1024; /* 256k */
208 rb
->strcpy(pInfo
->name
, "SST39VF020");
211 else if (pInfo
->id
== 0xD7)
213 pInfo
->size
= 512* 1024; /* 512k */
214 rb
->strcpy(pInfo
->name
, "SST39VF040");
224 /*********** Tool Functions ************/
226 /* place a 32 bit value into memory, big endian */
227 void Write32(UINT8
* pByte
, UINT32 value
)
229 pByte
[0] = (UINT8
)(value
>> 24);
230 pByte
[1] = (UINT8
)(value
>> 16);
231 pByte
[2] = (UINT8
)(value
>> 8);
232 pByte
[3] = (UINT8
)(value
);
235 /* read a 32 bit value from memory, big endian */
236 UINT32
Read32(UINT8
* pByte
)
240 value
= (UINT32
)pByte
[0] << 24;
241 value
|= (UINT32
)pByte
[1] << 16;
242 value
|= (UINT32
)pByte
[2] << 8;
243 value
|= (UINT32
)pByte
[3];
248 /* get the start address of the second image */
249 tImageHeader
* GetSecondImage(void)
251 tImageHeader
* pImage1
;
252 UINT32 pos
= 0; /* default: not found */
253 UINT32
* pFlash
= (UINT32
*)FB
;
255 /* determine the first image position */
256 pos
= pFlash
[2] + pFlash
[3]; /* position + size of the bootloader
258 pos
= (pos
+ 3) & ~3; /* be sure it's 32 bit aligned */
259 pImage1
= (tImageHeader
*)pos
;
261 if (pImage1
->destination
!= ROCKBOX_DEST
||
262 pImage1
->execute
!= ROCKBOX_EXEC
)
263 return 0; /* seems to be no Archos/Rockbox image in here */
265 if (pImage1
->size
!= 0)
267 /* success, we have a second image */
268 pos
= (UINT32
)pImage1
+ sizeof(tImageHeader
) + pImage1
->size
;
269 if (((pos
+ SECTORSIZE
-1) & ~(SECTORSIZE
-1)) != pos
)
270 { /* not sector-aligned */
271 pos
= 0; /* sanity check failed */
275 return (tImageHeader
*)pos
;
279 /* Tool function to calculate a CRC32 across some buffer */
280 /* third argument is either 0xFFFFFFFF to start or value from last piece */
281 UINT32
crc_32(unsigned char* buf
, unsigned len
, unsigned crc32
)
283 /* CCITT standard polynomial 0x04C11DB7 */
284 static const UINT32 crc32_lookup
[16] =
285 { /* lookup table for 4 bits at a time is affordable */
286 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9,
287 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,
288 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61,
289 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD
297 byte
= *buf
++; /* get one byte of data */
299 /* upper nibble of our data */
300 t
= crc32
>> 28; /* extract the 4 most significant bits */
301 t
^= byte
>> 4; /* XOR in 4 bits of data into the extracted bits */
302 crc32
<<= 4; /* shift the CRC register left 4 bits */
303 crc32
^= crc32_lookup
[t
]; /* do the table lookup and XOR the result */
305 /* lower nibble of our data */
306 t
= crc32
>> 28; /* extract the 4 most significant bits */
307 t
^= byte
& 0x0F; /* XOR in 4 bits of data into the extracted bits */
308 crc32
<<= 4; /* shift the CRC register left 4 bits */
309 crc32
^= crc32_lookup
[t
]; /* do the table lookup and XOR the result */
316 /* test if the bootloader is up-to-date, returns 0 if yes, else CRC */
317 unsigned CheckBootloader(void)
320 UINT32
* pFlash
= (UINT32
*)FB
;
321 int bootloader_version
= FB
[BOOT_VERS_ADR
];
323 if (bootloader_version
) /* this is a newer image, with a version number */
325 if (bootloader_version
< LATEST_BOOTLOADER_VERSION
)
326 return bootloader_version
;
331 /* checksum the bootloader, unfortunately I have no version info yet */
332 crc
= crc_32((unsigned char*)pFlash
[2], pFlash
[3], -1);
334 /* Here I have to check for ARCHOS_* defines in source code, which is
335 generally strongly discouraged. But here I'm not checking for a certain
336 feature, I'm checking for the model itself. */
337 #if defined(ARCHOS_PLAYER)
338 if (crc
== 0x78DAC94A)
340 #elif defined(ARCHOS_RECORDER)
341 if (crc
== 0xE968702E || crc
== 0x7C3D93B4) /* normal or ROMless each */
343 #elif defined(ARCHOS_RECORDERV2)
344 if (crc
== 0x4511E9B5 || crc
== 0x3A93DBDF)
346 #elif defined(ARCHOS_FMRECORDER)
347 if (crc
== 0x4511E9B5 || crc
== 0x3A93DBDF)
355 /*********** Image File Functions ************/
357 /* so far, only compressed images in UCL NRV algorithm 2e supported */
358 tCheckResult
CheckImageFile(char* filename
, int space
, tImageHeader
* pHeader
,
363 int filesize
; /* size info */
365 int fileread
= 0; /* total size as read from the file */
366 int read
; /* how many for this sector */
368 /* magic file header for compressed files */
369 static const UINT8 magic
[8] = { 0x00,0xe9,0x55,0x43,0x4c,0xff,0x01,0x1a };
370 UINT8 ucl_header
[UCL_HEADER
];
372 fd
= rb
->open(filename
, O_RDONLY
);
374 return eFileNotFound
;
376 filesize
= rb
->filesize(fd
);
377 if (filesize
- (int)sizeof(ucl_header
) - 8 > space
)
382 else if (filesize
< 10000) /* give it some reasonable lower limit */
388 /* do some sanity checks */
390 read
= rb
->read(fd
, ucl_header
, sizeof(ucl_header
));
392 if (read
!= sizeof(ucl_header
))
398 /* compare the magic header */
401 if (ucl_header
[i
] != magic
[i
])
408 pHeader
->size
= Read32(ucl_header
+ 22); /* compressed size */
409 if (pHeader
->size
!= filesize
- sizeof(ucl_header
) - 8)
415 /* fill in the hardcoded defaults of the header */
416 pHeader
->destination
= ROCKBOX_DEST
;
417 pHeader
->execute
= ROCKBOX_EXEC
;
419 if (Read32(ucl_header
+ 18) > pHeader
->size
) /* compare with uncompressed
421 { /* compressed, normal case */
422 pHeader
->flags
= 0x00000001; /* flags for UCL compressed */
424 /* check for supported algorithm */
425 if (ucl_header
[12] != 0x2E)
428 return eWrongAlgorithm
;
432 { /* uncompressed, either to be copied or run directly in flash */
433 UINT32 reset_vector
; /* image has to start with reset vector */
435 pHeader
->flags
= 0x00000000; /* uncompressed */
437 read
= rb
->read(fd
, &reset_vector
, sizeof(reset_vector
));
439 if (read
!= sizeof(reset_vector
))
444 if (reset_vector
>= (UINT32
)FB
445 && reset_vector
< (UINT32
)FB
+512*1024) /* ROM address? */
447 /* assume in-place, executing directly in flash */
448 pHeader
->destination
= (UINT32
)(pos
+ sizeof(tImageHeader
));
450 /* for new RomBox, this isn't the reset vector,
451 but the link address, for us to check the position */
452 if(pHeader
->destination
!= reset_vector
) /* compare link addr. */
455 return eBadRomLink
; /* not matching the start address */
458 /* read the now following reset vector */
459 read
= rb
->read(fd
, &reset_vector
, sizeof(reset_vector
));
461 if (read
!= sizeof(reset_vector
))
468 pHeader
->execute
= reset_vector
;
471 /* check if we can read the whole file */
474 read
= rb
->read(fd
, sector
, SECTORSIZE
);
476 } while (read
== SECTORSIZE
);
480 if (fileread
!= filesize
)
487 /* returns the # of failures, 0 on success */
488 unsigned ProgramImageFile(char* filename
, UINT8
* pos
,
489 tImageHeader
* pImageHeader
, int start
, int size
)
493 int read
; /* how many for this sector */
494 unsigned failures
= 0;
496 fd
= rb
->open(filename
, O_RDONLY
);
500 /* no error checking necessary here, we checked for minimum size
502 rb
->lseek(fd
, start
, SEEK_SET
); /* go to start position */
504 *(tImageHeader
*)sector
= *pImageHeader
; /* copy header into sector
506 read
= rb
->read(fd
, sector
+ sizeof(tImageHeader
),
507 SECTORSIZE
- sizeof(tImageHeader
)); /* payload behind */
509 read
+= sizeof(tImageHeader
); /* to be programmed, but not part of the
513 if (!EraseSector(pos
))
515 /* nothing we can do, let the programming count the errors */
518 for (i
=0; i
<read
; i
++)
520 if (!ProgramByte(pos
+ i
, sector
[i
]))
527 read
= rb
->read(fd
, sector
, (size
> SECTORSIZE
) ? SECTORSIZE
: size
);
528 /* payload for next sector */
537 /* returns the # of failures, 0 on success */
538 unsigned VerifyImageFile(char* filename
, UINT8
* pos
,
539 tImageHeader
* pImageHeader
, int start
, int size
)
543 int read
; /* how many for this sector */
544 unsigned failures
= 0;
546 fd
= rb
->open(filename
, O_RDONLY
);
550 /* no error checking necessary here, we checked for minimum size
552 rb
->lseek(fd
, start
, SEEK_SET
); /* go to start position */
554 *(tImageHeader
*)sector
= *pImageHeader
; /* copy header into sector
556 read
= rb
->read(fd
, sector
+ sizeof(tImageHeader
),
557 SECTORSIZE
- sizeof(tImageHeader
)); /* payload behind */
560 read
+= sizeof(tImageHeader
); /* to be programmed, but not part of the
565 for (i
=0; i
<read
; i
++)
567 if (pos
[i
] != sector
[i
])
574 read
= rb
->read(fd
, sector
, (size
> SECTORSIZE
) ? SECTORSIZE
: size
);
575 /* payload for next sector */
585 /***************** User Interface Functions *****************/
587 int WaitForButton(void)
593 button
= rb
->button_get(true);
594 } while (button
& BUTTON_REL
);
599 /* helper for DoUserDialog() */
600 void ShowFlashInfo(tFlashInfo
* pInfo
, tImageHeader
* pImageHeader
)
604 if (!pInfo
->manufacturer
)
606 rb
->lcd_puts_scroll(0, 0, "Flash: M=?? D=??");
612 rb
->snprintf(buf
, sizeof(buf
), "Flash size: %d KB",
614 rb
->lcd_puts_scroll(0, 0, buf
);
618 rb
->lcd_puts_scroll(0, 0, "Unsupported chip");
625 rb
->snprintf(buf
, sizeof(buf
), "Image at %d KB",
626 ((UINT8
*)pImageHeader
- FB
) / 1024);
627 rb
->lcd_puts_scroll(0, 1, buf
);
631 rb
->lcd_puts_scroll(0, 1, "No image found!");
636 /* Kind of our main function, defines the application flow. */
637 #ifdef HAVE_LCD_BITMAP
638 /* recorder version */
639 void DoUserDialog(char* filename
)
641 tImageHeader ImageHeader
;
642 tFlashInfo FlashInfo
;
643 static char buf
[MAX_PATH
];
645 int rc
; /* generic return code */
646 UINT32 space
, aligned_size
, true_size
;
650 bool show_greet
= false;
652 /* this can only work if Rockbox runs in DRAM, not flash ROM */
653 if ((UINT8
*)rb
>= FB
&& (UINT8
*)rb
< FB
+ 4096*1024) /* 4 MB max */
654 { /* we're running from flash */
655 rb
->splash(HZ
*3, "Not from ROM");
659 /* refuse to work if the power may fail meanwhile */
660 if (!rb
->battery_level_safe())
662 rb
->splash(HZ
*3, "Battery too low!");
666 /* "allocate" memory */
667 sector
= rb
->plugin_get_buffer((size_t *)&memleft
);
668 if (memleft
< SECTORSIZE
) /* need buffer for a flash sector */
670 rb
->splash(HZ
*3, "Out of memory");
674 rb
->lcd_setfont(FONT_SYSFIXED
);
676 pos
= (void*)GetSecondImage();
677 rc
= GetFlashInfo(&FlashInfo
);
679 ShowFlashInfo(&FlashInfo
, (void*)pos
);
682 if (FlashInfo
.size
== 0) /* no valid chip */
684 rb
->splash(HZ
*3, "Not flashable");
689 rb
->splash(HZ
*3, "No image");
693 crc
= CheckBootloader();
694 if (crc
) /* outdated version found */
696 rb
->snprintf(buf
, sizeof(buf
), "(check=0x%08lx)", crc
);
697 rb
->lcd_puts(0, 0, buf
);
698 rb
->lcd_puts(0, 1, "Hint: You're not ");
699 rb
->lcd_puts(0, 2, "using the latest ");
700 rb
->lcd_puts(0, 3, "bootloader. ");
701 rb
->lcd_puts(0, 4, "A full reflash is ");
702 rb
->lcd_puts(0, 5, "recommended, but ");
703 rb
->lcd_puts(0, 6, "not required. ");
704 rb
->lcd_puts(0, 7, "Press " KEYNAME1
" to ignore");
707 if (WaitForButton() != KEY1
)
711 rb
->lcd_clear_display();
714 rb
->lcd_puts(0, show_greet
? 0 : 3, "Checking...");
717 space
= FlashInfo
.size
- (pos
-FB
+ sizeof(ImageHeader
));
718 /* size minus start */
720 rc
= CheckImageFile(filename
, space
, &ImageHeader
, pos
);
723 rb
->lcd_clear_display(); /* make room for error message */
724 show_greet
= true; /* verbose */
727 rb
->lcd_puts(0, show_greet
? 0 : 3, "Checked:");
730 rb
->lcd_puts(0, show_greet
? 0 : 4, "File OK.");
733 rb
->lcd_puts(0, 1, "File not UCL ");
734 rb
->lcd_puts(0, 2, "compressed.");
735 rb
->lcd_puts(0, 3, "Use uclpack --2e");
736 rb
->lcd_puts(0, 4, " --10 rockbox.bin");
738 case eWrongAlgorithm
:
739 rb
->lcd_puts(0, 1, "Wrong algorithm");
740 rb
->lcd_puts(0, 2, "for compression.");
741 rb
->lcd_puts(0, 3, "Use uclpack --2e");
742 rb
->lcd_puts(0, 4, " --10 rockbox.bin");
745 rb
->lcd_puts(0, 1, "File not found:");
746 rb
->lcd_puts_scroll(0, 2, filename
);
749 rb
->lcd_puts(0, 1, "File too big,");
750 rb
->lcd_puts(0, 2, "won't fit in chip.");
753 rb
->lcd_puts(0, 1, "File too small.");
754 rb
->lcd_puts(0, 2, "Incomplete?");
757 rb
->lcd_puts(0, 1, "File read error.");
760 rb
->lcd_puts(0, 1, "File invalid.");
761 rb
->lcd_puts(0, 2, "Blocksize");
762 rb
->lcd_puts(0, 3, " too small?");
765 rb
->lcd_puts(0, 1, "RomBox mismatch.");
766 rb
->lcd_puts(0, 2, "Wrong ROM position");
769 rb
->lcd_puts(0, 1, "Check failed.");
775 rb
->lcd_puts(0, 6, "[" KEYNAME2
"] to program");
776 rb
->lcd_puts(0, 7, "other key to exit");
779 { /* error occured */
780 rb
->lcd_puts(0, 6, "Any key to exit");
784 button
= WaitForButton();
785 if (rc
!= eOK
|| button
!= KEY2
)
790 true_size
= ImageHeader
.size
;
791 aligned_size
= ((sizeof(tImageHeader
) + true_size
+ SECTORSIZE
-1) &
792 ~(SECTORSIZE
-1)) - sizeof(tImageHeader
); /* round up to
795 ImageHeader
.size
= aligned_size
; /* increase image size such that we reach
798 rb
->lcd_clear_display();
799 rb
->lcd_puts_scroll(0, 0, "Programming...");
802 rc
= ProgramImageFile(filename
, pos
, &ImageHeader
, UCL_HEADER
, true_size
);
805 rb
->lcd_clear_display();
806 rb
->snprintf(buf
, sizeof(buf
), "%d errors", rc
);
807 rb
->lcd_puts(0, 0, "Error:");
808 rb
->lcd_puts(0, 1, "Programming fail!");
809 rb
->lcd_puts(0, 2, buf
);
811 button
= WaitForButton();
814 rb
->lcd_clear_display();
815 rb
->lcd_puts_scroll(0, 0, "Verifying...");
818 rc
= VerifyImageFile(filename
, pos
, &ImageHeader
, UCL_HEADER
, true_size
);
820 rb
->lcd_clear_display();
823 rb
->lcd_puts(0, 0, "Verify OK.");
827 rb
->snprintf(buf
, sizeof(buf
), "%d errors", rc
);
828 rb
->lcd_puts(0, 0, "Error:");
829 rb
->lcd_puts(0, 1, "Verify fail!");
830 rb
->lcd_puts(0, 2, buf
);
831 rb
->lcd_puts(0, 3, "Use safe image");
832 rb
->lcd_puts(0, 4, "if booting hangs:");
833 rb
->lcd_puts(0, 5, "F1 during power-on");
835 rb
->lcd_puts(0, 7, "Any key to exit");
840 #else /* #ifdef HAVE_LCD_BITMAP */
843 void DoUserDialog(char* filename
)
845 tImageHeader ImageHeader
;
846 tFlashInfo FlashInfo
;
847 static char buf
[MAX_PATH
];
849 int rc
; /* generic return code */
850 UINT32 space
, aligned_size
, true_size
;
855 /* this can only work if Rockbox runs in DRAM, not flash ROM */
856 if ((UINT8
*)rb
>= FB
&& (UINT8
*)rb
< FB
+ 4096*1024) /* 4 MB max */
857 { /* we're running from flash */
858 rb
->splash(HZ
*3, "Not from ROM");
862 /* refuse to work if the power may fail meanwhile */
863 if (!rb
->battery_level_safe())
865 rb
->splash(HZ
*3, "Batt. too low!");
869 /* "allocate" memory */
870 sector
= rb
->plugin_get_buffer((size_t *)&memleft
);
871 if (memleft
< SECTORSIZE
) /* need buffer for a flash sector */
873 rb
->splash(HZ
*3, "Out of memory");
877 pos
= (void*)GetSecondImage();
878 rc
= GetFlashInfo(&FlashInfo
);
880 if (FlashInfo
.size
== 0) /* no valid chip */
882 rb
->splash(HZ
*3, "Not flashable");
887 rb
->splash(HZ
*3, "No image");
891 crc
= CheckBootloader();
892 if (crc
) /* outdated version found */
894 rb
->lcd_puts_scroll(0, 0, "Hint: You're not using the latest bootloader. A full reflash is recommended, but not required.");
895 rb
->lcd_puts_scroll(0, 1, "Press [Menu] to ignore");
898 if (WaitForButton() != BUTTON_MENU
)
902 rb
->lcd_clear_display();
905 rb
->lcd_puts(0, 0, "Checking...");
908 space
= FlashInfo
.size
- (pos
-FB
+ sizeof(ImageHeader
));
909 /* size minus start */
911 rc
= CheckImageFile(filename
, space
, &ImageHeader
, pos
);
912 rb
->lcd_puts(0, 0, "Checked:");
915 rb
->lcd_puts(0, 1, "File OK.");
919 rb
->lcd_puts_scroll(0, 1, "File not UCL compressed.");
921 case eWrongAlgorithm
:
922 rb
->lcd_puts_scroll(0, 1, "Wrong compression algorithm.");
925 rb
->lcd_puts_scroll(0, 1, "File not found.");
928 rb
->lcd_puts_scroll(0, 1, "File too big.");
931 rb
->lcd_puts_scroll(0, 1, "File too small. Incomplete?");
934 rb
->lcd_puts_scroll(0, 1, "File read error.");
937 rb
->lcd_puts_scroll(0, 1, "File invalid. Blocksize too small?");
940 rb
->lcd_puts_scroll(0, 1, "BootBox mismatch");
943 rb
->lcd_puts_scroll(0, 1, "Check failed.");
950 rb
->lcd_clear_display();
951 rb
->lcd_puts_scroll(0, 0, "[ON] to program,");
952 rb
->lcd_puts_scroll(0, 1, "other key to exit.");
955 { /* error occured */
957 rb
->lcd_clear_display();
958 rb
->lcd_puts_scroll(0, 0, "Flash failed.");
959 rb
->lcd_puts_scroll(0, 1, "Any key to exit.");
963 button
= WaitForButton();
964 if (rc
!= eOK
|| button
!= BUTTON_ON
)
969 true_size
= ImageHeader
.size
;
970 aligned_size
= ((sizeof(tImageHeader
) + true_size
+ SECTORSIZE
-1) &
971 ~(SECTORSIZE
-1)) - sizeof(tImageHeader
); /* round up to
974 ImageHeader
.size
= aligned_size
; /* increase image size such that we reach
977 rb
->lcd_clear_display();
978 rb
->lcd_puts_scroll(0, 0, "Programming...");
981 rc
= ProgramImageFile(filename
, pos
, &ImageHeader
, UCL_HEADER
, true_size
);
984 rb
->lcd_clear_display();
985 rb
->snprintf(buf
, sizeof(buf
), "%d errors", rc
);
986 rb
->lcd_puts_scroll(0, 0, "Programming failed!");
987 rb
->lcd_puts_scroll(0, 1, buf
);
989 button
= WaitForButton();
992 rb
->lcd_clear_display();
993 rb
->lcd_puts_scroll(0, 0, "Verifying...");
996 rc
= VerifyImageFile(filename
, pos
, &ImageHeader
, UCL_HEADER
, true_size
);
998 rb
->lcd_clear_display();
1001 rb
->lcd_puts(0, 0, "Verify OK.");
1006 rb
->snprintf(buf
, sizeof(buf
), "Verify fail! %d errors", rc
);
1007 rb
->lcd_puts_scroll(0, 0, buf
);
1008 rb
->lcd_puts_scroll(0, 1, "Use safe image if booting hangs: [-] during power-on");
1010 button
= WaitForButton();
1014 #endif /* not HAVE_LCD_BITMAP */
1018 /***************** Plugin Entry Point *****************/
1020 enum plugin_status
plugin_start(struct plugin_api
* api
, void* parameter
)
1024 rb
= api
; /* copy to global api pointer */
1026 if (parameter
== NULL
)
1028 rb
->splash(HZ
*3, "Play .ucl file!");
1032 /* now go ahead and have fun! */
1033 oldmode
= rb
->system_memory_guard(MEMGUARD_NONE
); /*disable memory guard */
1034 DoUserDialog((char*) parameter
);
1035 rb
->system_memory_guard(oldmode
); /* re-enable memory guard */
1041 #endif /* SH-target */