very minor code police. also fix a possible but unlikely missed cpu_boost(false)
[Rockbox.git] / apps / plugins / rockbox_flash.c
blobd3f0aa405563f36aa090dab98f38de6656b0555c
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 1 /* 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 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,
114 to make sure */
116 not_manu = pBase[0]; /* read the normal content */
117 not_id = pBase[1]; /* should be 'A' (0x41) and 'R' (0x52) from the
118 "ARCH" marker */
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 */
125 manu = pBase[0];
126 id = pBase[1];
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 */
137 *pDeviceID = id;
138 return true; /* success */
140 return false; /* fail */
143 /* erase the sector which contains the given address */
144 bool EraseSector(volatile UINT8* pAddr)
146 #ifdef DUMMY
147 (void)pAddr; /* prevents warning */
148 return true;
149 #else
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
153 25ms */
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);
167 #endif
170 /* address must be in an erased location */
171 inline bool ProgramByte(volatile UINT8* pAddr, UINT8 data)
173 #ifdef DUMMY
174 (void)pAddr; /* prevents warnings */
175 (void)data;
176 return true;
177 #else
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 */
184 FB[0x2AAA] = 0x55;
185 FB[0x5555] = 0xA0; /* byte program command */
187 *pAddr = data;
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);
194 #endif
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))
203 return false;
205 if (pInfo->manufacturer == 0xBF) /* SST */
207 if (pInfo->id == 0xD6)
209 pInfo->size = 256* 1024; /* 256k */
210 rb->strcpy(pInfo->name, "SST39VF020");
211 return true;
213 else if (pInfo->id == 0xD7)
215 pInfo->size = 512* 1024; /* 512k */
216 rb->strcpy(pInfo->name, "SST39VF040");
217 return true;
219 else
220 return false;
222 return false;
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)
240 UINT32 value;
242 value = (UINT32)pByte[0] << 24;
243 value |= (UINT32)pByte[1] << 16;
244 value |= (UINT32)pByte[2] << 8;
245 value |= (UINT32)pByte[3];
247 return value;
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
259 = after it */
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
294 unsigned char byte;
295 UINT32 t;
297 while (len--)
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 */
314 return crc32;
318 /* test if the bootloader is up-to-date, returns 0 if yes, else CRC */
319 unsigned CheckBootloader(void)
321 unsigned crc;
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;
329 else
330 return 0;
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)
341 return 0;
342 #elif defined(ARCHOS_RECORDER)
343 if (crc == 0xE968702E || crc == 0x7C3D93B4) /* normal or ROMless each */
344 return 0;
345 #elif defined(ARCHOS_RECORDERV2)
346 if (crc == 0x4511E9B5 || crc == 0x3A93DBDF)
347 return 0;
348 #elif defined(ARCHOS_FMRECORDER)
349 if (crc == 0x4511E9B5 || crc == 0x3A93DBDF)
350 return 0;
351 #endif
353 return crc;
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,
361 UINT8* pos)
363 int i;
364 int fd;
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);
375 if (fd < 0)
376 return eFileNotFound;
378 filesize = rb->filesize(fd);
379 if (filesize - (int)sizeof(ucl_header) - 8 > space)
381 rb->close(fd);
382 return eTooBig;
384 else if (filesize < 10000) /* give it some reasonable lower limit */
386 rb->close(fd);
387 return eTooSmall;
390 /* do some sanity checks */
392 read = rb->read(fd, ucl_header, sizeof(ucl_header));
393 fileread += read;
394 if (read != sizeof(ucl_header))
396 rb->close(fd);
397 return eReadErr;
400 /* compare the magic header */
401 for (i=0; i<8; i++)
403 if (ucl_header[i] != magic[i])
405 rb->close(fd);
406 return eNotUCL;
410 pHeader->size = Read32(ucl_header + 22); /* compressed size */
411 if (pHeader->size != filesize - sizeof(ucl_header) - 8)
413 rb->close(fd);
414 return eMultiBlocks;
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
422 size */
423 { /* compressed, normal case */
424 pHeader->flags = 0x00000001; /* flags for UCL compressed */
426 /* check for supported algorithm */
427 if (ucl_header[12] != 0x2E)
429 rb->close(fd);
430 return eWrongAlgorithm;
433 else
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));
440 fileread += read;
441 if (read != sizeof(reset_vector))
443 rb->close(fd);
444 return eReadErr;
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. */
456 rb->close(fd);
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));
462 fileread += read;
463 if (read != sizeof(reset_vector))
465 rb->close(fd);
466 return eReadErr;
470 pHeader->execute = reset_vector;
473 /* check if we can read the whole file */
476 read = rb->read(fd, sector, SECTORSIZE);
477 fileread += read;
478 } while (read == SECTORSIZE);
480 rb->close(fd);
482 if (fileread != filesize)
483 return eReadErr;
485 return eOK;
489 /* returns the # of failures, 0 on success */
490 unsigned ProgramImageFile(char* filename, UINT8* pos,
491 tImageHeader* pImageHeader, int start, int size)
493 int i;
494 int fd;
495 int read; /* how many for this sector */
496 unsigned failures = 0;
498 fd = rb->open(filename, O_RDONLY);
499 if (fd < 0)
500 return false;
502 /* no error checking necessary here, we checked for minimum size
503 already */
504 rb->lseek(fd, start, SEEK_SET); /* go to start position */
506 *(tImageHeader*)sector = *pImageHeader; /* copy header into sector
507 buffer */
508 read = rb->read(fd, sector + sizeof(tImageHeader),
509 SECTORSIZE - sizeof(tImageHeader)); /* payload behind */
510 size -= read;
511 read += sizeof(tImageHeader); /* to be programmed, but not part of the
512 file */
514 do {
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]))
524 failures++;
528 pos += SECTORSIZE;
529 read = rb->read(fd, sector, (size > SECTORSIZE) ? SECTORSIZE : size);
530 /* payload for next sector */
531 size -= read;
532 } while (read > 0);
534 rb->close(fd);
536 return failures;
539 /* returns the # of failures, 0 on success */
540 unsigned VerifyImageFile(char* filename, UINT8* pos,
541 tImageHeader* pImageHeader, int start, int size)
543 int i;
544 int fd;
545 int read; /* how many for this sector */
546 unsigned failures = 0;
548 fd = rb->open(filename, O_RDONLY);
549 if (fd < 0)
550 return false;
552 /* no error checking necessary here, we checked for minimum size
553 already */
554 rb->lseek(fd, start, SEEK_SET); /* go to start position */
556 *(tImageHeader*)sector = *pImageHeader; /* copy header into sector
557 buffer */
558 read = rb->read(fd, sector + sizeof(tImageHeader),
559 SECTORSIZE - sizeof(tImageHeader)); /* payload behind */
561 size -= read;
562 read += sizeof(tImageHeader); /* to be programmed, but not part of the
563 file */
567 for (i=0; i<read; i++)
569 if (pos[i] != sector[i])
571 failures++;
575 pos += SECTORSIZE;
576 read = rb->read(fd, sector, (size > SECTORSIZE) ? SECTORSIZE : size);
577 /* payload for next sector */
578 size -= read;
579 } while (read);
581 rb->close(fd);
583 return failures;
587 /***************** User Interface Functions *****************/
589 int WaitForButton(void)
591 int button;
595 button = rb->button_get(true);
596 } while (button & BUTTON_REL);
598 return button;
601 /* helper for DoUserDialog() */
602 void ShowFlashInfo(tFlashInfo* pInfo, tImageHeader* pImageHeader)
604 char buf[32];
606 if (!pInfo->manufacturer)
608 rb->lcd_puts_scroll(0, 0, "Flash: M=?? D=??");
610 else
612 if (pInfo->size)
614 rb->snprintf(buf, sizeof(buf), "Flash size: %d KB",
615 pInfo->size / 1024);
616 rb->lcd_puts_scroll(0, 0, buf);
618 else
620 rb->lcd_puts_scroll(0, 0, "Unsupported chip");
625 if (pImageHeader)
627 rb->snprintf(buf, sizeof(buf), "Image at %d KB",
628 ((UINT8*)pImageHeader - FB) / 1024);
629 rb->lcd_puts_scroll(0, 1, buf);
631 else
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];
646 int button;
647 int rc; /* generic return code */
648 UINT32 space, aligned_size, true_size;
649 UINT8* pos;
650 ssize_t memleft;
651 UINT32 crc;
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");
658 return; /* exit */
661 /* refuse to work if the power may fail meanwhile */
662 if (!rb->battery_level_safe())
664 rb->splash(HZ*3, "Battery too low!");
665 return; /* exit */
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");
673 return; /* exit */
676 rb->lcd_setfont(FONT_SYSFIXED);
678 pos = (void*)GetSecondImage();
679 rc = GetFlashInfo(&FlashInfo);
681 ShowFlashInfo(&FlashInfo, (void*)pos);
682 rb->lcd_update();
684 if (FlashInfo.size == 0) /* no valid chip */
686 rb->splash(HZ*3, "Not flashable");
687 return; /* exit */
689 else if (pos == 0)
691 rb->splash(HZ*3, "No image");
692 return; /* exit */
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");
707 rb->lcd_update();
709 if (WaitForButton() != KEY1)
711 return;
713 rb->lcd_clear_display();
716 rb->lcd_puts(0, show_greet ? 0 : 3, "Checking...");
717 rb->lcd_update();
719 space = FlashInfo.size - (pos-FB + sizeof(ImageHeader));
720 /* size minus start */
722 rc = CheckImageFile(filename, space, &ImageHeader, pos);
723 if (rc != eOK)
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:");
730 switch (rc) {
731 case eOK:
732 rb->lcd_puts(0, show_greet ? 0 : 4, "File OK.");
733 break;
734 case eNotUCL:
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");
739 break;
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");
745 break;
746 case eFileNotFound:
747 rb->lcd_puts(0, 1, "File not found:");
748 rb->lcd_puts_scroll(0, 2, filename);
749 break;
750 case eTooBig:
751 rb->lcd_puts(0, 1, "File too big,");
752 rb->lcd_puts(0, 2, "won't fit in chip.");
753 break;
754 case eTooSmall:
755 rb->lcd_puts(0, 1, "File too small.");
756 rb->lcd_puts(0, 2, "Incomplete?");
757 break;
758 case eReadErr:
759 rb->lcd_puts(0, 1, "File read error.");
760 break;
761 case eMultiBlocks:
762 rb->lcd_puts(0, 1, "File invalid.");
763 rb->lcd_puts(0, 2, "Blocksize");
764 rb->lcd_puts(0, 3, " too small?");
765 break;
766 case eBadRomLink:
767 rb->lcd_puts(0, 1, "RomBox mismatch.");
768 rb->lcd_puts(0, 2, "Wrong ROM position");
769 break;
770 default:
771 rb->lcd_puts(0, 1, "Check failed.");
772 break;
775 if (rc == eOK)
776 { /* was OK */
777 rb->lcd_puts(0, 6, "[" KEYNAME2 "] to program");
778 rb->lcd_puts(0, 7, "other key to exit");
780 else
781 { /* error occured */
782 rb->lcd_puts(0, 6, "Any key to exit");
784 rb->lcd_update();
786 button = WaitForButton();
787 if (rc != eOK || button != KEY2)
789 return;
792 true_size = ImageHeader.size;
793 aligned_size = ((sizeof(tImageHeader) + true_size + SECTORSIZE-1) &
794 ~(SECTORSIZE-1)) - sizeof(tImageHeader); /* round up to
795 next flash
796 sector */
797 ImageHeader.size = aligned_size; /* increase image size such that we reach
798 the next sector */
800 rb->lcd_clear_display();
801 rb->lcd_puts_scroll(0, 0, "Programming...");
802 rb->lcd_update();
804 rc = ProgramImageFile(filename, pos, &ImageHeader, UCL_HEADER, true_size);
805 if (rc)
806 { /* errors */
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);
812 rb->lcd_update();
813 button = WaitForButton();
816 rb->lcd_clear_display();
817 rb->lcd_puts_scroll(0, 0, "Verifying...");
818 rb->lcd_update();
820 rc = VerifyImageFile(filename, pos, &ImageHeader, UCL_HEADER, true_size);
822 rb->lcd_clear_display();
823 if (rc == 0)
825 rb->lcd_puts(0, 0, "Verify OK.");
827 else
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");
838 rb->lcd_update();
839 WaitForButton();
842 #else /* #ifdef HAVE_LCD_BITMAP */
844 /* Player version */
845 void DoUserDialog(char* filename)
847 tImageHeader ImageHeader;
848 tFlashInfo FlashInfo;
849 static char buf[MAX_PATH];
850 int button;
851 int rc; /* generic return code */
852 UINT32 space, aligned_size, true_size;
853 UINT8* pos;
854 ssize_t memleft;
855 UINT32 crc;
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");
861 return; /* exit */
864 /* refuse to work if the power may fail meanwhile */
865 if (!rb->battery_level_safe())
867 rb->splash(HZ*3, "Batt. too low!");
868 return; /* exit */
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");
876 return; /* exit */
879 pos = (void*)GetSecondImage();
880 rc = GetFlashInfo(&FlashInfo);
882 if (FlashInfo.size == 0) /* no valid chip */
884 rb->splash(HZ*3, "Not flashable");
885 return; /* exit */
887 else if (pos == 0)
889 rb->splash(HZ*3, "No image");
890 return; /* exit */
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");
898 rb->lcd_update();
900 if (WaitForButton() != BUTTON_MENU)
902 return;
904 rb->lcd_clear_display();
907 rb->lcd_puts(0, 0, "Checking...");
908 rb->lcd_update();
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:");
915 switch (rc) {
916 case eOK:
917 rb->lcd_puts(0, 1, "File OK.");
918 rb->sleep(HZ*1);
919 break;
920 case eNotUCL:
921 rb->lcd_puts_scroll(0, 1, "File not UCL compressed.");
922 break;
923 case eWrongAlgorithm:
924 rb->lcd_puts_scroll(0, 1, "Wrong compression algorithm.");
925 break;
926 case eFileNotFound:
927 rb->lcd_puts_scroll(0, 1, "File not found.");
928 break;
929 case eTooBig:
930 rb->lcd_puts_scroll(0, 1, "File too big.");
931 break;
932 case eTooSmall:
933 rb->lcd_puts_scroll(0, 1, "File too small. Incomplete?");
934 break;
935 case eReadErr:
936 rb->lcd_puts_scroll(0, 1, "File read error.");
937 break;
938 case eMultiBlocks:
939 rb->lcd_puts_scroll(0, 1, "File invalid. Blocksize too small?");
940 break;
941 case eBadRomLink:
942 rb->lcd_puts_scroll(0, 1, "BootBox mismatch");
943 break;
944 default:
945 rb->lcd_puts_scroll(0, 1, "Check failed.");
946 break;
948 rb->lcd_update();
950 if (rc == eOK)
951 { /* was OK */
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.");
956 else
957 { /* error occured */
958 WaitForButton();
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.");
963 rb->lcd_update();
965 button = WaitForButton();
966 if (rc != eOK || button != BUTTON_ON)
968 return;
971 true_size = ImageHeader.size;
972 aligned_size = ((sizeof(tImageHeader) + true_size + SECTORSIZE-1) &
973 ~(SECTORSIZE-1)) - sizeof(tImageHeader); /* round up to
974 next flash
975 sector */
976 ImageHeader.size = aligned_size; /* increase image size such that we reach
977 the next sector */
979 rb->lcd_clear_display();
980 rb->lcd_puts_scroll(0, 0, "Programming...");
981 rb->lcd_update();
983 rc = ProgramImageFile(filename, pos, &ImageHeader, UCL_HEADER, true_size);
984 if (rc)
985 { /* errors */
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);
990 rb->lcd_update();
991 button = WaitForButton();
994 rb->lcd_clear_display();
995 rb->lcd_puts_scroll(0, 0, "Verifying...");
996 rb->lcd_update();
998 rc = VerifyImageFile(filename, pos, &ImageHeader, UCL_HEADER, true_size);
1000 rb->lcd_clear_display();
1001 if (rc == 0)
1003 rb->lcd_puts(0, 0, "Verify OK.");
1004 rb->lcd_update();
1006 else
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");
1011 rb->lcd_update();
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)
1024 int oldmode;
1026 rb = api; /* copy to global api pointer */
1028 if (parameter == NULL)
1030 rb->splash(HZ*3, "Play .ucl file!");
1031 return PLUGIN_OK;
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 */
1039 return PLUGIN_OK;
1043 #endif /* SH-target */