summaryrefslogtreecommitdiff
path: root/apps/plugins/rockbox_flash.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/rockbox_flash.c')
-rw-r--r--apps/plugins/rockbox_flash.c967
1 files changed, 0 insertions, 967 deletions
diff --git a/apps/plugins/rockbox_flash.c b/apps/plugins/rockbox_flash.c
deleted file mode 100644
index 4837b03fb5..0000000000
--- a/apps/plugins/rockbox_flash.c
+++ /dev/null
@@ -1,967 +0,0 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
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 !!!
12*
13* Copyright (C) 2003 Jörg Hohensohn aka [IDC]Dragon
14*
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.
19*
20* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21* KIND, either express or implied.
22*
23****************************************************************************/
24#include "plugin.h"
25
26/* define DUMMY if you only want to "play" with the UI, does no harm */
27/* #define DUMMY */
28
29#define LATEST_BOOTLOADER_VERSION 3 /* update this with the bootloader */
30
31#ifndef UINT8
32#define UINT8 unsigned char
33#endif
34
35#ifndef UINT16
36#define UINT16 unsigned short
37#endif
38
39#ifndef UINT32
40#define UINT32 unsigned long
41#endif
42
43/* hard-coded values */
44static volatile UINT8* FB = (UINT8*)0x02000000; /* Flash base address */
45#define SECTORSIZE 4096 /* size of one flash sector */
46
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 */
52
53#if CONFIG_KEYPAD == ONDIO_PAD /* limited keypad */
54#define KEY1 BUTTON_LEFT
55#define KEY2 BUTTON_UP
56#define KEYNAME1 "Left"
57#define KEYNAME2 "Up"
58#else /* recorder keypad */
59#define KEY1 BUTTON_F1
60#define KEY2 BUTTON_F2
61#define KEYNAME1 "F1"
62#define KEYNAME2 "F2"
63#endif
64
65typedef struct
66{
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 */
72} tImageHeader;
73
74/* result of the CheckFirmwareFile() function */
75typedef enum
76{
77 eOK = 0,
78 eFileNotFound, /* errors from here on */
79 eTooBig,
80 eTooSmall,
81 eReadErr,
82 eNotUCL,
83 eWrongAlgorithm,
84 eMultiBlocks,
85 eBadRomLink
86} tCheckResult;
87
88typedef struct
89{
90 UINT8 manufacturer;
91 UINT8 id;
92 int size;
93 char name[32];
94} tFlashInfo;
95
96static UINT8* sector; /* better not place this on the stack... */
97
98/***************** Flash Functions *****************/
99
100
101/* read the manufacturer and device ID */
102static bool ReadID(volatile UINT8* pBase, UINT8* pManufacturerID,
103 UINT8* pDeviceID)
104{
105 UINT8 not_manu, not_id; /* read values before switching to ID mode */
106 UINT8 manu, id; /* read values when in ID mode */
107
108 pBase = (UINT8*)((UINT32)pBase & 0xFFF80000); /* round down to 512k align,
109 to make sure */
110
111 not_manu = pBase[0]; /* read the normal content */
112 not_id = pBase[1]; /* should be 'A' (0x41) and 'R' (0x52) from the
113 "ARCH" marker */
114
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 */
119
120 manu = pBase[0];
121 id = pBase[1];
122
123 pBase[0] = 0xF0; /* reset flash (back to normal read mode) */
124 rb->sleep(HZ/50); /* Atmel wants 20ms pause here */
125
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 */
130 {
131 *pManufacturerID = manu; /* return the results */
132 *pDeviceID = id;
133 return true; /* success */
134 }
135 return false; /* fail */
136}
137
138/* erase the sector which contains the given address */
139static bool EraseSector(volatile UINT8* pAddr)
140{
141#ifdef DUMMY
142 (void)pAddr; /* prevents warning */
143 return true;
144#else
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
148 25ms */
149
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 */
156
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 */
160
161 return (timeout != 0);
162#endif
163}
164
165/* address must be in an erased location */
166static inline bool ProgramByte(volatile UINT8* pAddr, UINT8 data)
167{
168#ifdef DUMMY
169 (void)pAddr; /* prevents warnings */
170 (void)data;
171 return true;
172#else
173 unsigned timeout = 35; /* the timeout loop should be no less than 20us */
174
175 if (~*pAddr & data) /* just a safety feature, not really necessary */
176 return false; /* can't set any bit from 0 to 1 */
177
178 FB[0x5555] = 0xAA; /* enter command mode */
179 FB[0x2AAA] = 0x55;
180 FB[0x5555] = 0xA0; /* byte program command */
181
182 *pAddr = data;
183
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 */
187
188 return (timeout != 0);
189#endif
190}
191
192/* this returns true if supported and fills the info struct */
193static bool GetFlashInfo(tFlashInfo* pInfo)
194{
195 rb->memset(pInfo, 0, sizeof(tFlashInfo));
196
197 if (!ReadID(FB, &pInfo->manufacturer, &pInfo->id))
198 return false;
199
200 if (pInfo->manufacturer == 0xBF) /* SST */
201 {
202 if (pInfo->id == 0xD6)
203 {
204 pInfo->size = 256* 1024; /* 256k */
205 rb->strcpy(pInfo->name, "SST39VF020");
206 return true;
207 }
208 else if (pInfo->id == 0xD7)
209 {
210 pInfo->size = 512* 1024; /* 512k */
211 rb->strcpy(pInfo->name, "SST39VF040");
212 return true;
213 }
214 else
215 return false;
216 }
217 return false;
218}
219
220
221/*********** Tool Functions ************/
222
223/* read a 32 bit value from memory, big endian */
224static UINT32 Read32(UINT8* pByte)
225{
226 UINT32 value;
227
228 value = (UINT32)pByte[0] << 24;
229 value |= (UINT32)pByte[1] << 16;
230 value |= (UINT32)pByte[2] << 8;
231 value |= (UINT32)pByte[3];
232
233 return value;
234}
235
236/* get the start address of the second image */
237static tImageHeader* GetSecondImage(void)
238{
239 tImageHeader* pImage1;
240 UINT32 pos = 0; /* default: not found */
241 UINT32* pFlash = (UINT32*)FB;
242
243 /* determine the first image position */
244 pos = pFlash[2] + pFlash[3]; /* position + size of the bootloader
245 = after it */
246 pos = (pos + 3) & ~3; /* be sure it's 32 bit aligned */
247 pImage1 = (tImageHeader*)pos;
248
249 if (pImage1->destination != ROCKBOX_DEST ||
250 pImage1->execute != ROCKBOX_EXEC)
251 return 0; /* seems to be no Archos/Rockbox image in here */
252
253 if (pImage1->size != 0)
254 {
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 */
260 }
261 }
262
263 return (tImageHeader*)pos;
264}
265
266/* return bootloader version */
267static inline unsigned BootloaderVersion(void)
268{
269 return FB[BOOT_VERS_ADR];
270}
271
272/*********** Image File Functions ************/
273
274/* so far, only compressed images in UCL NRV algorithm 2e supported */
275tCheckResult CheckImageFile(char* filename, int space,
276 tImageHeader* pHeader, UINT8* pos)
277{
278 int i;
279 int fd;
280 int filesize; /* size info */
281
282 int fileread = 0; /* total size as read from the file */
283 int read; /* how many for this sector */
284
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];
288
289 fd = rb->open(filename, O_RDONLY);
290 if (fd < 0)
291 return eFileNotFound;
292
293 filesize = rb->filesize(fd);
294 if (filesize - (int)sizeof(ucl_header) - 8 > space)
295 {
296 rb->close(fd);
297 return eTooBig;
298 }
299 else if (filesize < 10000) /* give it some reasonable lower limit */
300 {
301 rb->close(fd);
302 return eTooSmall;
303 }
304
305 /* do some sanity checks */
306
307 read = rb->read(fd, ucl_header, sizeof(ucl_header));
308 fileread += read;
309 if (read != sizeof(ucl_header))
310 {
311 rb->close(fd);
312 return eReadErr;
313 }
314
315 /* compare the magic header */
316 for (i=0; i<8; i++)
317 {
318 if (ucl_header[i] != magic[i])
319 {
320 rb->close(fd);
321 return eNotUCL;
322 }
323 }
324
325 pHeader->size = Read32(ucl_header + 22); /* compressed size */
326 if (pHeader->size != filesize - sizeof(ucl_header) - 8)
327 {
328 rb->close(fd);
329 return eMultiBlocks;
330 }
331
332 /* fill in the hardcoded defaults of the header */
333 pHeader->destination = ROCKBOX_DEST;
334 pHeader->execute = ROCKBOX_EXEC;
335
336 if (Read32(ucl_header + 18) > pHeader->size) /* compare with uncompressed
337 size */
338 { /* compressed, normal case */
339 pHeader->flags = 0x00000001; /* flags for UCL compressed */
340
341 /* check for supported algorithm */
342 if (ucl_header[12] != 0x2E)
343 {
344 rb->close(fd);
345 return eWrongAlgorithm;
346 }
347 }
348 else
349 { /* uncompressed, either to be copied or run directly in flash */
350 UINT32 reset_vector; /* image has to start with reset vector */
351
352 pHeader->flags = 0x00000000; /* uncompressed */
353
354 read = rb->read(fd, &reset_vector, sizeof(reset_vector));
355 fileread += read;
356 if (read != sizeof(reset_vector))
357 {
358 rb->close(fd);
359 return eReadErr;
360 }
361 if (reset_vector >= (UINT32)FB
362 && reset_vector < (UINT32)FB+512*1024) /* ROM address? */
363 {
364 /* assume in-place, executing directly in flash */
365 pHeader->destination = (UINT32)(pos + sizeof(tImageHeader));
366
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. */
370 {
371 rb->close(fd);
372 return eBadRomLink; /* not matching the start address */
373 }
374
375 /* read the now following reset vector */
376 read = rb->read(fd, &reset_vector, sizeof(reset_vector));
377 fileread += read;
378 if (read != sizeof(reset_vector))
379 {
380 rb->close(fd);
381 return eReadErr;
382 }
383 }
384
385 pHeader->execute = reset_vector;
386 }
387
388 /* check if we can read the whole file */
389 do
390 {
391 read = rb->read(fd, sector, SECTORSIZE);
392 fileread += read;
393 } while (read == SECTORSIZE);
394
395 rb->close(fd);
396
397 if (fileread != filesize)
398 return eReadErr;
399
400 return eOK;
401}
402
403
404/* returns the # of failures, 0 on success */
405static unsigned ProgramImageFile(char* filename, UINT8* pos,
406 tImageHeader* pImageHeader,
407 int start, int size)
408{
409 int i;
410 int fd;
411 int read; /* how many for this sector */
412 unsigned failures = 0;
413
414 fd = rb->open(filename, O_RDONLY);
415 if (fd < 0)
416 return false;
417
418 /* no error checking necessary here, we checked for minimum size
419 already */
420 rb->lseek(fd, start, SEEK_SET); /* go to start position */
421
422 *(tImageHeader*)sector = *pImageHeader; /* copy header into sector
423 buffer */
424 read = rb->read(fd, sector + sizeof(tImageHeader),
425 SECTORSIZE - sizeof(tImageHeader)); /* payload behind */
426 size -= read;
427 read += sizeof(tImageHeader); /* to be programmed, but not part of the
428 file */
429
430 do {
431 if (!EraseSector(pos))
432 {
433 /* nothing we can do, let the programming count the errors */
434 }
435
436 for (i=0; i<read; i++)
437 {
438 if (!ProgramByte(pos + i, sector[i]))
439 {
440 failures++;
441 }
442 }
443
444 pos += SECTORSIZE;
445 read = rb->read(fd, sector, (size > SECTORSIZE) ? SECTORSIZE : size);
446 /* payload for next sector */
447 size -= read;
448 } while (read > 0);
449
450 rb->close(fd);
451
452 return failures;
453}
454
455/* returns the # of failures, 0 on success */
456static unsigned VerifyImageFile(char* filename, UINT8* pos,
457 tImageHeader* pImageHeader,
458 int start, int size)
459{
460 int i;
461 int fd;
462 int read; /* how many for this sector */
463 unsigned failures = 0;
464
465 fd = rb->open(filename, O_RDONLY);
466 if (fd < 0)
467 return false;
468
469 /* no error checking necessary here, we checked for minimum size
470 already */
471 rb->lseek(fd, start, SEEK_SET); /* go to start position */
472
473 *(tImageHeader*)sector = *pImageHeader; /* copy header into sector
474 buffer */
475 read = rb->read(fd, sector + sizeof(tImageHeader),
476 SECTORSIZE - sizeof(tImageHeader)); /* payload behind */
477
478 size -= read;
479 read += sizeof(tImageHeader); /* to be programmed, but not part of the
480 file */
481
482 do
483 {
484 for (i=0; i<read; i++)
485 {
486 if (pos[i] != sector[i])
487 {
488 failures++;
489 }
490 }
491
492 pos += SECTORSIZE;
493 read = rb->read(fd, sector, (size > SECTORSIZE) ? SECTORSIZE : size);
494 /* payload for next sector */
495 size -= read;
496 } while (read);
497
498 rb->close(fd);
499
500 return failures;
501}
502
503
504/***************** User Interface Functions *****************/
505
506static int WaitForButton(void)
507{
508 int button;
509
510 do
511 {
512 button = rb->button_get(true);
513 } while (IS_SYSEVENT(button) || (button & BUTTON_REL));
514
515 return button;
516}
517
518#ifdef HAVE_LCD_BITMAP
519/* helper for DoUserDialog() */
520static void ShowFlashInfo(tFlashInfo* pInfo, tImageHeader* pImageHeader)
521{
522 char buf[32];
523
524 if (!pInfo->manufacturer)
525 {
526 rb->lcd_puts_scroll(0, 0, "Flash: M=?? D=??");
527 }
528 else
529 {
530 if (pInfo->size)
531 {
532 rb->snprintf(buf, sizeof(buf), "Flash size: %d KB",
533 pInfo->size / 1024);
534 rb->lcd_puts_scroll(0, 0, buf);
535 }
536 else
537 {
538 rb->lcd_puts_scroll(0, 0, "Unsupported chip");
539 }
540
541 }
542
543 if (pImageHeader)
544 {
545 rb->snprintf(buf, sizeof(buf), "Image at %d KB",
546 ((UINT8*)pImageHeader - FB) / 1024);
547 rb->lcd_puts_scroll(0, 1, buf);
548 }
549 else
550 {
551 rb->lcd_puts_scroll(0, 1, "No image found!");
552 }
553}
554
555
556/* Kind of our main function, defines the application flow. */
557/* recorder version */
558static void DoUserDialog(char* filename)
559{
560 tImageHeader ImageHeader;
561 tFlashInfo FlashInfo;
562 int button;
563 int rc; /* generic return code */
564 UINT32 space, aligned_size, true_size;
565 UINT8* pos;
566 size_t memleft;
567 unsigned bl_version;
568 bool show_greet = false;
569
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");
574 return; /* exit */
575 }
576
577 /* refuse to work if the power may fail meanwhile */
578 if (!rb->battery_level_safe())
579 {
580 rb->splash(HZ*3, "Battery too low!");
581 return; /* exit */
582 }
583
584 /* "allocate" memory */
585 sector = rb->plugin_get_buffer(&memleft);
586 if (memleft < SECTORSIZE) /* need buffer for a flash sector */
587 {
588 rb->splash(HZ*3, "Out of memory");
589 return; /* exit */
590 }
591
592 rb->lcd_setfont(FONT_SYSFIXED);
593
594 pos = (void*)GetSecondImage();
595 rc = GetFlashInfo(&FlashInfo);
596
597 ShowFlashInfo(&FlashInfo, (void*)pos);
598 rb->lcd_update();
599
600 if (FlashInfo.size == 0) /* no valid chip */
601 {
602 rb->splash(HZ*3, "Not flashable");
603 return; /* exit */
604 }
605 else if (pos == 0)
606 {
607 rb->splash(HZ*3, "No image");
608 return; /* exit */
609 }
610
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)
616 {
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");
624 rb->lcd_update();
625
626 if (WaitForButton() != KEY1)
627 {
628 return;
629 }
630 rb->lcd_clear_display();
631 }
632#endif
633
634 rb->lcd_puts(0, show_greet ? 0 : 3, "Checking...");
635 rb->lcd_update();
636
637 space = FlashInfo.size - (pos-FB + sizeof(ImageHeader));
638 /* size minus start */
639
640 rc = CheckImageFile(filename, space, &ImageHeader, pos);
641 if (rc != eOK)
642 {
643 rb->lcd_clear_display(); /* make room for error message */
644 show_greet = true; /* verbose */
645 }
646
647 rb->lcd_puts(0, show_greet ? 0 : 3, "Checked:");
648 switch (rc) {
649 case eOK:
650 rb->lcd_puts(0, show_greet ? 0 : 4, "File OK.");
651 break;
652 case eNotUCL:
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");
657 break;
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");
663 break;
664 case eFileNotFound:
665 rb->lcd_puts(0, 1, "File not found:");
666 rb->lcd_puts_scroll(0, 2, filename);
667 break;
668 case eTooBig:
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)
672 {
673 rb->lcd_puts(0, 3, "Upgrade bootloader");
674 }
675 break;
676 case eTooSmall:
677 rb->lcd_puts(0, 1, "File too small.");
678 rb->lcd_puts(0, 2, "Incomplete?");
679 break;
680 case eReadErr:
681 rb->lcd_puts(0, 1, "File read error.");
682 break;
683 case eMultiBlocks:
684 rb->lcd_puts(0, 1, "File invalid.");
685 rb->lcd_puts(0, 2, "Blocksize");
686 rb->lcd_puts(0, 3, " too small?");
687 break;
688 case eBadRomLink:
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.");
693 break;
694 default:
695 rb->lcd_puts(0, 1, "Check failed.");
696 break;
697 }
698
699 if (rc == eOK)
700 { /* was OK */
701 rb->lcd_puts(0, 6, "[" KEYNAME2 "] to program");
702 rb->lcd_puts(0, 7, "other key to exit");
703 }
704 else
705 { /* error occured */
706 rb->lcd_puts(0, 6, "Any key to exit");
707 }
708 rb->lcd_update();
709
710 button = WaitForButton();
711 if (rc != eOK || button != KEY2)
712 {
713 return;
714 }
715
716 true_size = ImageHeader.size;
717 aligned_size = ((sizeof(tImageHeader) + true_size + SECTORSIZE-1) &
718 ~(SECTORSIZE-1)) - sizeof(tImageHeader); /* round up to
719 next flash
720 sector */
721 ImageHeader.size = aligned_size; /* increase image size such that we reach
722 the next sector */
723
724 rb->lcd_clear_display();
725 rb->lcd_puts_scroll(0, 0, "Programming...");
726 rb->lcd_update();
727
728 rc = ProgramImageFile(filename, pos, &ImageHeader, UCL_HEADER, true_size);
729 if (rc)
730 { /* errors */
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);
735 rb->lcd_update();
736 button = WaitForButton();
737 }
738
739 rb->lcd_clear_display();
740 rb->lcd_puts_scroll(0, 0, "Verifying...");
741 rb->lcd_update();
742
743 rc = VerifyImageFile(filename, pos, &ImageHeader, UCL_HEADER, true_size);
744
745 rb->lcd_clear_display();
746 if (rc == 0)
747 {
748 rb->lcd_puts(0, 0, "Verify OK.");
749 }
750 else
751 {
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");
758 }
759 rb->lcd_puts(0, 7, "Any key to exit");
760 rb->lcd_update();
761 WaitForButton();
762}
763
764#else /* #ifdef HAVE_LCD_BITMAP */
765
766/* Player version */
767static void DoUserDialog(char* filename)
768{
769 tImageHeader ImageHeader;
770 tFlashInfo FlashInfo;
771 static char buf[MAX_PATH];
772 int button;
773 int rc; /* generic return code */
774 UINT32 space, aligned_size, true_size;
775 UINT8* pos;
776 size_t memleft;
777 unsigned bl_version;
778
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");
783 return; /* exit */
784 }
785
786 /* refuse to work if the power may fail meanwhile */
787 if (!rb->battery_level_safe())
788 {
789 rb->splash(HZ*3, "Batt. too low!");
790 return; /* exit */
791 }
792
793 /* "allocate" memory */
794 sector = rb->plugin_get_buffer(&memleft);
795 if (memleft < SECTORSIZE) /* need buffer for a flash sector */
796 {
797 rb->splash(HZ*3, "Out of memory");
798 return; /* exit */
799 }
800
801 pos = (void*)GetSecondImage();
802 rc = GetFlashInfo(&FlashInfo);
803
804 if (FlashInfo.size == 0) /* no valid chip */
805 {
806 rb->splash(HZ*3, "Not flashable");
807 return; /* exit */
808 }
809 else if (pos == 0)
810 {
811 rb->splash(HZ*3, "No image");
812 return; /* exit */
813 }
814
815 bl_version = BootloaderVersion();
816 if (bl_version < LATEST_BOOTLOADER_VERSION)
817 {
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");
820 rb->lcd_update();
821
822 if (WaitForButton() != BUTTON_MENU)
823 {
824 return;
825 }
826 rb->lcd_clear_display();
827 }
828
829 rb->lcd_puts(0, 0, "Checking...");
830 rb->lcd_update();
831
832 space = FlashInfo.size - (pos-FB + sizeof(ImageHeader));
833 /* size minus start */
834
835 rc = CheckImageFile(filename, space, &ImageHeader, pos);
836 rb->lcd_puts(0, 0, "Checked:");
837 switch (rc) {
838 case eOK:
839 rb->lcd_puts(0, 1, "File OK.");
840 rb->sleep(HZ*1);
841 break;
842 case eNotUCL:
843 rb->lcd_puts_scroll(0, 1, "File not UCL compressed.");
844 break;
845 case eWrongAlgorithm:
846 rb->lcd_puts_scroll(0, 1, "Wrong compression algorithm.");
847 break;
848 case eFileNotFound:
849 rb->lcd_puts_scroll(0, 1, "File not found.");
850 break;
851 case eTooBig:
852 if (bl_version < LATEST_BOOTLOADER_VERSION)
853 {
854 rb->lcd_puts_scroll(0, 1, "File too big, upgrade bootloader.");
855 }
856 else
857 {
858 rb->lcd_puts_scroll(0, 1, "File too big.");
859 }
860 break;
861 case eTooSmall:
862 rb->lcd_puts_scroll(0, 1, "File too small. Incomplete?");
863 break;
864 case eReadErr:
865 rb->lcd_puts_scroll(0, 1, "File read error.");
866 break;
867 case eMultiBlocks:
868 rb->lcd_puts_scroll(0, 1, "File invalid. Blocksize too small?");
869 break;
870 case eBadRomLink:
871 rb->lcd_puts_scroll(0, 1, "Bootloader not compatible with RomBox.");
872 break;
873 default:
874 rb->lcd_puts_scroll(0, 1, "Check failed.");
875 break;
876 }
877 rb->lcd_update();
878
879 if (rc == eOK)
880 { /* was OK */
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.");
884 }
885 else
886 { /* error occured */
887 WaitForButton();
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.");
891 }
892 rb->lcd_update();
893
894 button = WaitForButton();
895 if (rc != eOK || button != BUTTON_ON)
896 {
897 return;
898 }
899
900 true_size = ImageHeader.size;
901 aligned_size = ((sizeof(tImageHeader) + true_size + SECTORSIZE-1) &
902 ~(SECTORSIZE-1)) - sizeof(tImageHeader); /* round up to
903 next flash
904 sector */
905 ImageHeader.size = aligned_size; /* increase image size such that we reach
906 the next sector */
907
908 rb->lcd_clear_display();
909 rb->lcd_puts_scroll(0, 0, "Programming...");
910 rb->lcd_update();
911
912 rc = ProgramImageFile(filename, pos, &ImageHeader, UCL_HEADER, true_size);
913 if (rc)
914 { /* errors */
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);
919 rb->lcd_update();
920 button = WaitForButton();
921 }
922
923 rb->lcd_clear_display();
924 rb->lcd_puts_scroll(0, 0, "Verifying...");
925 rb->lcd_update();
926
927 rc = VerifyImageFile(filename, pos, &ImageHeader, UCL_HEADER, true_size);
928
929 rb->lcd_clear_display();
930 if (rc == 0)
931 {
932 rb->lcd_puts(0, 0, "Verify OK.");
933 rb->lcd_update();
934 }
935 else
936 {
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");
940 rb->lcd_update();
941 button = WaitForButton();
942 }
943}
944
945#endif /* not HAVE_LCD_BITMAP */
946
947
948
949/***************** Plugin Entry Point *****************/
950
951enum plugin_status plugin_start(const void* parameter)
952{
953 int oldmode;
954
955 if (parameter == NULL)
956 {
957 rb->splash(HZ*3, "Play .ucl file!");
958 return PLUGIN_OK;
959 }
960
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 */
965
966 return PLUGIN_OK;
967}