summaryrefslogtreecommitdiff
path: root/apps/plugins/firmware_flash.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/firmware_flash.c')
-rw-r--r--apps/plugins/firmware_flash.c1033
1 files changed, 0 insertions, 1033 deletions
diff --git a/apps/plugins/firmware_flash.c b/apps/plugins/firmware_flash.c
deleted file mode 100644
index 36b8873a8c..0000000000
--- a/apps/plugins/firmware_flash.c
+++ /dev/null
@@ -1,1033 +0,0 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Plugin for reprogramming the whole Flash ROM chip with a new content.
11* !!! DON'T MESS WITH THIS CODE UNLESS YOU'RE ABSOLUTELY SURE WHAT YOU DO !!!
12*
13* Copyright (C) 2003 Jörg Hohensohn [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#ifndef UINT8
30#define UINT8 unsigned char
31#endif
32
33#ifndef UINT16
34#define UINT16 unsigned short
35#endif
36
37#ifndef UINT32
38#define UINT32 unsigned long
39#endif
40
41/* platform IDs as I have used them in my firmware templates */
42#define ID_RECORDER 0
43#define ID_FM 1
44#define ID_PLAYER 2
45#define ID_REC_V2 3
46#define ID_ONDIO_FM 4
47#define ID_ONDIO_SP 5
48
49/* Here I have to check for ARCHOS_* defines in source code, which is
50 generally strongly discouraged. But here I'm not checking for a certain
51 feature, I'm checking for the model itself. */
52#if defined(ARCHOS_PLAYER)
53#define FILE_TYPE "player"
54#define KEEP VERSION_ADR /* keep the firmware version */
55#define PLATFORM_ID ID_PLAYER
56#elif defined(ARCHOS_RECORDER)
57#define FILE_TYPE "rec"
58#define KEEP MASK_ADR /* keep the mask value */
59#define PLATFORM_ID ID_RECORDER
60#elif defined(ARCHOS_RECORDERV2)
61#define FILE_TYPE "v2"
62#define KEEP MASK_ADR /* keep the mask value */
63#define PLATFORM_ID ID_REC_V2
64#elif defined(ARCHOS_FMRECORDER)
65#define FILE_TYPE "fm"
66#define KEEP MASK_ADR /* keep the mask value */
67#define PLATFORM_ID ID_FM
68#elif defined(ARCHOS_ONDIOFM)
69#define FILE_TYPE "ondiofm"
70#define KEEP MASK_ADR /* keep the mask value */
71#define PLATFORM_ID ID_ONDIO_FM
72#elif defined(ARCHOS_ONDIOSP)
73#define FILE_TYPE "ondiosp"
74#define KEEP MASK_ADR /* keep the mask value */
75#define PLATFORM_ID ID_ONDIO_SP
76#else
77#error this platform is not (yet) flashable
78#endif
79
80
81
82#if CONFIG_KEYPAD == ONDIO_PAD /* limited keypad */
83#define KEY1 BUTTON_LEFT
84#define KEY2 BUTTON_UP
85#define KEY3 BUTTON_RIGHT
86#define KEYNAME1 "[Left]"
87#define KEYNAME2 "[Up]"
88#define KEYNAME3 "[Right]"
89#else /* recorder keypad */
90#define KEY1 BUTTON_F1
91#define KEY2 BUTTON_F2
92#define KEY3 BUTTON_F3
93#define KEYNAME1 "[F1]"
94#define KEYNAME2 "[F2]"
95#define KEYNAME3 "[F3]"
96#endif
97
98/* result of the CheckFirmwareFile() function */
99typedef enum
100{
101 eOK = 0,
102 eFileNotFound, /* errors from here on */
103 eTooBig,
104 eTooSmall,
105 eReadErr,
106 eBadContent,
107 eCrcErr,
108 eBadPlatform,
109} tCheckResult;
110
111/* result of the CheckBootROM() function */
112typedef enum
113{
114 eBootROM, /* the supported boot ROM(s) */
115 eUnknown, /* unknown boot ROM */
116 eROMless, /* flash mapped to zero */
117} tCheckROM;
118
119typedef struct
120{
121 UINT8 manufacturer;
122 UINT8 id;
123 int size;
124 char name[32];
125} tFlashInfo;
126
127#define MASK_ADR 0xFC /* position of hardware mask value in Flash */
128#define VERSION_ADR 0xFE /* position of firmware version value in Flash */
129#define PLATFORM_ADR 0xFB /* position of my platform ID value in Flash */
130#define SEC_SIZE 4096 /* size of one flash sector */
131static UINT8* sector; /* better not place this on the stack... */
132static volatile UINT8* FB = (UINT8*)0x02000000; /* Flash base address */
133
134
135/***************** Flash Functions *****************/
136
137
138/* read the manufacturer and device ID */
139bool ReadID(volatile UINT8* pBase, UINT8* pManufacturerID, UINT8* pDeviceID)
140{
141 UINT8 not_manu, not_id; /* read values before switching to ID mode */
142 UINT8 manu, id; /* read values when in ID mode */
143
144 pBase = (UINT8*)((UINT32)pBase & 0xFFF80000); /* down to 512k align */
145
146 /* read the normal content */
147 not_manu = pBase[0]; /* should be 'A' (0x41) and 'R' (0x52) */
148 not_id = pBase[1]; /* from the "ARCH" marker */
149
150 pBase[0x5555] = 0xAA; /* enter command mode */
151 pBase[0x2AAA] = 0x55;
152 pBase[0x5555] = 0x90; /* ID command */
153 rb->sleep(HZ/50); /* Atmel wants 20ms pause here */
154
155 manu = pBase[0];
156 id = pBase[1];
157
158 pBase[0] = 0xF0; /* reset flash (back to normal read mode) */
159 rb->sleep(HZ/50); /* Atmel wants 20ms pause here */
160
161 /* I assume success if the obtained values are different from
162 the normal flash content. This is not perfectly bulletproof, they
163 could theoretically be the same by chance, causing us to fail. */
164 if (not_manu != manu || not_id != id) /* a value has changed */
165 {
166 *pManufacturerID = manu; /* return the results */
167 *pDeviceID = id;
168 return true; /* success */
169 }
170 return false; /* fail */
171}
172
173
174/* erase the sector which contains the given address */
175bool EraseSector(volatile UINT8* pAddr)
176{
177#ifdef DUMMY
178 (void)pAddr; /* prevents warning */
179 return true;
180#else
181 volatile UINT8* pBase = (UINT8*)((UINT32)pAddr & 0xFFF80000); /* round down to 512k align */
182 unsigned timeout = 43000; /* the timeout loop should be no less than 25ms */
183
184 pBase[0x5555] = 0xAA; /* enter command mode */
185 pBase[0x2AAA] = 0x55;
186 pBase[0x5555] = 0x80; /* erase command */
187 pBase[0x5555] = 0xAA; /* enter command mode */
188 pBase[0x2AAA] = 0x55;
189 *pAddr = 0x30; /* erase the sector */
190
191 /* I counted 7 instructions for this loop -> min. 0.58 us per round */
192 /* Plus memory waitstates it will be much more, gives margin */
193 while (*pAddr != 0xFF && --timeout); /* poll for erased */
194
195 return (timeout != 0);
196#endif
197}
198
199
200/* address must be in an erased location */
201static inline bool ProgramByte(volatile UINT8* pAddr, UINT8 data)
202{
203#ifdef DUMMY
204 (void)pAddr; /* prevents warnings */
205 (void)data;
206 return true;
207#else
208 unsigned timeout = 35; /* the timeout loop should be no less than 20us */
209
210 if (~*pAddr & data) /* just a safety feature, not really necessary */
211 return false; /* can't set any bit from 0 to 1 */
212
213 FB[0x5555] = 0xAA; /* enter command mode */
214 FB[0x2AAA] = 0x55;
215 FB[0x5555] = 0xA0; /* byte program command */
216
217 *pAddr = data;
218
219 /* I counted 7 instructions for this loop -> min. 0.58 us per round */
220 /* Plus memory waitstates it will be much more, gives margin */
221 while (*pAddr != data && --timeout); /* poll for programmed */
222
223 return (timeout != 0);
224#endif
225}
226
227
228/* this returns true if supported and fills the info struct */
229bool GetFlashInfo(tFlashInfo* pInfo)
230{
231 rb->memset(pInfo, 0, sizeof(tFlashInfo));
232
233 if (!ReadID(FB, &pInfo->manufacturer, &pInfo->id))
234 return false;
235
236 if (pInfo->manufacturer == 0xBF) /* SST */
237 {
238 if (pInfo->id == 0xD6)
239 {
240 pInfo->size = 256* 1024; /* 256k */
241 rb->strcpy(pInfo->name, "SST39VF020");
242 return true;
243 }
244 else if (pInfo->id == 0xD7)
245 {
246 pInfo->size = 512* 1024; /* 512k */
247 rb->strcpy(pInfo->name, "SST39VF040");
248 return true;
249 }
250 else
251 return false;
252 }
253 return false;
254}
255
256/*********** Firmware File Functions + helpers ************/
257
258/* test if the version number is consistent with the platform */
259bool CheckPlatform(int platform_id, UINT16 version)
260{
261 if (version == 200)
262 { /* for my very first firmwares, I foolishly changed it to 200 */
263 return (platform_id == ID_RECORDER || platform_id == ID_FM);
264 }
265 else if (version == 123)
266 { /* it can be a FM or V2 recorder */
267 return (platform_id == ID_FM || platform_id == ID_REC_V2);
268 }
269 else if (version == 132)
270 { /* newer Ondio, and seen on a V2 recorder */
271 return (platform_id == ID_ONDIO_SP || platform_id == ID_ONDIO_FM
272 || platform_id == ID_REC_V2);
273 }
274 else if (version == 104)
275 { /* classic Ondio128 */
276 return (platform_id == ID_ONDIO_FM);
277 }
278 else if (version >= 115 && version <= 129)
279 { /* the range of Recorders seen so far */
280 return (platform_id == ID_RECORDER);
281 }
282 else if (version == 0 || (version >= 300 && version <= 508))
283 { /* for very old players, I've seen zero */
284 return (platform_id == ID_PLAYER);
285 }
286
287 return false; /* unknown */
288}
289
290
291tCheckResult CheckFirmwareFile(char* filename, int chipsize, bool is_romless)
292{
293 int i;
294 int fd;
295 int fileleft; /* size info, how many left for reading */
296 int fileread = 0; /* total size as read from the file */
297 int read_now; /* how many to read for this sector */
298 int got_now; /* how many gotten for this sector */
299 unsigned crc32 = 0xFFFFFFFF; /* CCITT init value */
300 unsigned file_crc; /* CRC value read from file */
301 bool has_crc;
302
303 fd = rb->open(filename, O_RDONLY);
304 if (fd < 0)
305 return eFileNotFound;
306
307 fileleft = rb->filesize(fd);
308 if (fileleft > chipsize)
309 {
310 rb->close(fd);
311 return eTooBig;
312 }
313 else if (fileleft < 20000) /* give it some reasonable lower limit */
314 {
315 rb->close(fd);
316 return eTooSmall;
317 }
318
319 if (fileleft == 256*1024)
320 { /* original dumped firmware file has no CRC nor platform ID */
321 has_crc = false;
322 }
323 else
324 {
325 has_crc = true;
326 fileleft -= sizeof(unsigned); /* exclude the last 4 bytes */
327 }
328
329 /* do some sanity checks */
330
331 got_now = rb->read(fd, sector, SEC_SIZE); /* read first sector */
332 fileread += got_now;
333 fileleft -= got_now;
334 if (got_now != SEC_SIZE)
335 {
336 rb->close(fd);
337 return eReadErr;
338 }
339
340 /* version number in file plausible with this hardware? */
341 if (!CheckPlatform(PLATFORM_ID, *(UINT16*)(sector + VERSION_ADR)))
342 {
343 rb->close(fd);
344 return eBadPlatform;
345 }
346
347 if (has_crc)
348 {
349 crc32 = rb->crc_32(sector, SEC_SIZE, crc32); /* checksum */
350
351 /* in addition to the CRC, my files also have a platform ID */
352 if (sector[PLATFORM_ADR] != PLATFORM_ID) /* for our hardware? */
353 {
354 rb->close(fd);
355 return eBadPlatform;
356 }
357 }
358
359 if (is_romless)
360 { /* in this case, there is not much we can check */
361 if (*(UINT32*)sector != 0x00000200) /* reset vector */
362 {
363 rb->close(fd);
364 return eBadContent;
365 }
366 }
367 else
368 {
369 /* compare some bytes which have to be identical */
370 if (*(UINT32*)sector != 0x41524348) /* "ARCH" */
371 {
372 rb->close(fd);
373 return eBadContent;
374 }
375
376 for (i = 0x30; i<MASK_ADR-2; i++) /* leave two bytes for me */
377 {
378 if (sector[i] != FB[i])
379 {
380 rb->close(fd);
381 return eBadContent;
382 }
383 }
384 }
385
386 /* check if we can read the whole file, and do checksum */
387 do
388 {
389 read_now = MIN(SEC_SIZE, fileleft);
390 got_now = rb->read(fd, sector, read_now);
391 fileread += got_now;
392 fileleft -= got_now;
393
394 if (read_now != got_now)
395 {
396 rb->close(fd);
397 return eReadErr;
398 }
399
400 if (has_crc)
401 {
402 crc32 = rb->crc_32(sector, got_now, crc32); /* checksum */
403 }
404 } while (fileleft);
405
406 if (has_crc)
407 {
408 got_now = rb->read(fd, &file_crc, sizeof(file_crc));
409 if (got_now != sizeof(file_crc))
410 {
411 rb->close(fd);
412 return eReadErr;
413 }
414 }
415
416 /* must be EOF now */
417 got_now = rb->read(fd, sector, SEC_SIZE);
418 rb->close(fd);
419 if (got_now != 0)
420 return eReadErr;
421
422 if (has_crc && file_crc != crc32)
423 return eCrcErr;
424
425 return eOK;
426}
427
428
429/* returns the # of failures, 0 on success */
430unsigned ProgramFirmwareFile(char* filename, int chipsize)
431{
432 int i, j;
433 int fd;
434 int read = SEC_SIZE; /* how many for this sector */
435 UINT16 keep = *(UINT16*)(FB + KEEP); /* we must keep this! */
436 unsigned failures = 0;
437
438 fd = rb->open(filename, O_RDONLY);
439 if (fd < 0)
440 return false;
441
442 for (i=0; i<chipsize; i+=SEC_SIZE)
443 {
444 if (!EraseSector(FB + i))
445 {
446 /* nothing we can do, let the programming count the errors */
447 }
448
449 if (read == SEC_SIZE) /* not EOF yet */
450 {
451 read = rb->read(fd, sector, SEC_SIZE);
452 if (i==0)
453 { /* put original value back in */
454 *(UINT16*)(sector + KEEP) = keep;
455 }
456
457 for (j=0; j<read; j++)
458 {
459 if (!ProgramByte(FB + i + j, sector[j]))
460 {
461 failures++;
462 }
463 }
464 }
465 }
466
467 rb->close(fd);
468
469 return failures;
470}
471
472
473/* returns the # of failures, 0 on success */
474unsigned VerifyFirmwareFile(char* filename)
475{
476 int i=0, j;
477 int fd;
478 int read = SEC_SIZE; /* how many for this sector */
479 unsigned failures = 0;
480
481 fd = rb->open(filename, O_RDONLY);
482 if (fd < 0)
483 return false;
484
485 do
486 {
487 read = rb->read(fd, sector, SEC_SIZE);
488
489 for (j=0; j<read; j++)
490 {
491 /* position of keep value is no error */
492 if (FB[i] != sector[j] && i != KEEP && i != (KEEP+1))
493 {
494 failures++;
495 }
496 i++;
497 }
498 }
499 while (read == SEC_SIZE);
500
501 rb->close(fd);
502
503 return failures;
504}
505
506
507/***************** Support Functions *****************/
508
509/* check if we have "normal" boot ROM or flash mirrored to zero */
510tCheckROM CheckBootROM(void)
511{
512 unsigned boot_crc;
513 unsigned* pFlash = (unsigned*)FB;
514 unsigned* pRom = (unsigned*)0x0;
515 unsigned i;
516
517 boot_crc = rb->crc_32((unsigned char*)0x0, 64*1024, 0xFFFFFFFF);
518 if (boot_crc == 0x56DBA4EE /* the known boot ROM */
519#if PLATFORM_ID == ID_PLAYER
520 /* alternative boot ROM found in one single player so far */
521 || boot_crc == 0x358099E8
522#endif
523 )
524 return eBootROM;
525
526 /* check if ROM is a flash mirror */
527 for (i=0; i<256*1024/sizeof(unsigned); i++)
528 {
529 if (*pRom++ != *pFlash++)
530 { /* difference means no mirror */
531 return eUnknown;
532 }
533 }
534
535 return eROMless;
536}
537
538
539/***************** User Interface Functions *****************/
540
541int WaitForButton(void)
542{
543 int button;
544
545 do
546 {
547 button = rb->button_get(true);
548 } while (IS_SYSEVENT(button) || (button & BUTTON_REL));
549
550 return button;
551}
552
553#ifdef HAVE_LCD_BITMAP
554/* Recorder implementation */
555
556/* helper for DoUserDialog() */
557void ShowFlashInfo(tFlashInfo* pInfo)
558{
559 if (!pInfo->manufacturer)
560 {
561 rb->lcd_puts(0, 0, "Flash: M=?? D=??");
562 rb->lcd_puts(0, 1, "Impossible to program");
563 }
564 else
565 {
566 rb->lcd_putsf(0, 0, "Flash: M=%02x D=%02x",
567 pInfo->manufacturer, pInfo->id);
568
569
570 if (pInfo->size)
571 {
572 rb->lcd_puts(0, 1, pInfo->name);
573 rb->lcd_putsf(0, 2, "Size: %d KB", pInfo->size / 1024);
574 }
575 else
576 {
577 rb->lcd_puts(0, 1, "Unsupported chip");
578 }
579
580 }
581
582 rb->lcd_update();
583}
584
585
586/* Kind of our main function, defines the application flow. */
587void DoUserDialog(char* filename)
588{
589 tFlashInfo FlashInfo;
590 char default_filename[32];
591 int button;
592 int rc; /* generic return code */
593 size_t memleft;
594 tCheckROM result;
595 bool is_romless;
596
597 /* this can only work if Rockbox runs in DRAM, not flash ROM */
598 if ((UINT8*)rb >= FB && (UINT8*)rb < FB + 4096*1024) /* 4 MB max */
599 { /* we're running from flash */
600 rb->splash(HZ*3, "Not from ROM");
601 return; /* exit */
602 }
603
604 /* test if the user is running the correct plugin for this box */
605 if (!CheckPlatform(PLATFORM_ID, *(UINT16*)(FB + VERSION_ADR)))
606 {
607 rb->splash(HZ*3, "Wrong plugin");
608 return; /* exit */
609 }
610
611 /* refuse to work if the power may fail meanwhile */
612 if (!rb->battery_level_safe())
613 {
614 rb->splash(HZ*3, "Battery too low!");
615 return; /* exit */
616 }
617
618 /* check boot ROM */
619 result = CheckBootROM();
620 if (result == eUnknown)
621 { /* no support for any other yet */
622 rb->splash(HZ*3, "Wrong boot ROM");
623 return; /* exit */
624 }
625 is_romless = (result == eROMless);
626
627 /* compose filename if none given */
628 if (filename == NULL)
629 {
630 rb->snprintf(
631 default_filename,
632 sizeof(default_filename),
633 "/firmware_%s%s.bin",
634 FILE_TYPE,
635 is_romless ? "_norom" : "");
636 filename = default_filename;
637 }
638
639 /* "allocate" memory */
640 sector = rb->plugin_get_buffer(&memleft);
641 if (memleft < SEC_SIZE) /* need buffer for a flash sector */
642 {
643 rb->splash(HZ*3, "Out of memory");
644 return; /* exit */
645 }
646
647 rb->lcd_setfont(FONT_SYSFIXED);
648
649 rc = GetFlashInfo(&FlashInfo);
650 ShowFlashInfo(&FlashInfo);
651 if (FlashInfo.size == 0) /* no valid chip */
652 {
653 rb->splash(HZ*3, "Sorry!");
654 return; /* exit */
655 }
656
657 rb->lcd_puts(0, 3, "using file:");
658 rb->lcd_puts_scroll(0, 4, filename);
659 rb->lcd_puts(0, 6, KEYNAME1 " to check file");
660 rb->lcd_puts(0, 7, "other key to exit");
661 rb->lcd_update();
662
663 button = WaitForButton();
664 if (button != KEY1)
665 {
666 return;
667 }
668
669 rb->lcd_clear_display();
670 rb->lcd_puts(0, 0, "checking...");
671 rb->lcd_update();
672
673 rc = CheckFirmwareFile(filename, FlashInfo.size, is_romless);
674 rb->lcd_puts(0, 0, "checked:");
675 switch (rc)
676 {
677 case eOK:
678 rb->lcd_puts(0, 1, "File OK.");
679 break;
680 case eFileNotFound:
681 rb->lcd_puts(0, 1, "File not found.");
682 rb->lcd_puts(0, 2, "Put this in root:");
683 rb->lcd_puts_scroll(0, 4, filename);
684 break;
685 case eTooBig:
686 rb->lcd_puts(0, 1, "File too big,");
687 rb->lcd_puts(0, 2, "larger than chip.");
688 break;
689 case eTooSmall:
690 rb->lcd_puts(0, 1, "File too small.");
691 rb->lcd_puts(0, 2, "Incomplete?");
692 break;
693 case eReadErr:
694 rb->lcd_puts(0, 1, "Read error.");
695 break;
696 case eBadContent:
697 rb->lcd_puts(0, 1, "File invalid.");
698 rb->lcd_puts(0, 2, "Sanity check fail.");
699 break;
700 case eCrcErr:
701 rb->lcd_puts(0, 1, "File invalid.");
702 rb->lcd_puts(0, 2, "CRC check failed,");
703 rb->lcd_puts(0, 3, "checksum mismatch.");
704 break;
705 case eBadPlatform:
706 rb->lcd_puts(0, 1, "Wrong file for");
707 rb->lcd_puts(0, 2, "this hardware.");
708 break;
709 default:
710 rb->lcd_puts(0, 1, "Check failed.");
711 break;
712 }
713
714 if (rc == eOK)
715 {
716 rb->lcd_puts(0, 6, KEYNAME2 " to program");
717 rb->lcd_puts(0, 7, "other key to exit");
718 }
719 else
720 { /* error occured */
721 rb->lcd_puts(0, 6, "Any key to exit");
722 }
723
724 rb->lcd_update();
725
726 button = WaitForButton();
727 if (button != KEY2 || rc != eOK)
728 {
729 return;
730 }
731
732 rb->lcd_clear_display();
733 rb->lcd_puts(0, 0, "Program all Flash?");
734 rb->lcd_puts(0, 1, "Are you sure?");
735 rb->lcd_puts(0, 2, "If it goes wrong,");
736 rb->lcd_puts(0, 3, "it kills your box!");
737 rb->lcd_puts(0, 4, "See documentation.");
738
739 rb->lcd_puts(0, 6, KEYNAME3 " to proceed");
740 rb->lcd_puts(0, 7, "other key to exit");
741 rb->lcd_update();
742
743 button = WaitForButton();
744 if (button != KEY3)
745 {
746 return;
747 }
748
749 rb->lcd_clear_display();
750 rb->lcd_puts(0, 0, "Programming...");
751 rb->lcd_update();
752
753 rc = ProgramFirmwareFile(filename, FlashInfo.size);
754 if (rc)
755 { /* errors */
756 rb->lcd_clear_display();
757 rb->lcd_puts(0, 0, "Panic:");
758 rb->lcd_puts(0, 1, "Programming fail!");
759 rb->lcd_putsf(0, 2, "%d errors", rc);
760 rb->lcd_update();
761 button = WaitForButton();
762 }
763
764 rb->lcd_clear_display();
765 rb->lcd_puts(0, 0, "Verifying...");
766 rb->lcd_update();
767
768 rc = VerifyFirmwareFile(filename);
769
770 rb->lcd_clear_display();
771 if (rc == 0)
772 {
773 rb->lcd_puts(0, 0, "Verify OK.");
774 }
775 else
776 {
777 rb->lcd_puts(0, 0, "Panic:");
778 rb->lcd_puts(0, 1, "Verify fail!");
779 rb->lcd_putsf(0, 2, "%d errors", rc);
780 }
781 rb->lcd_puts(0, 7, "Any key to exit");
782 rb->lcd_update();
783
784 button = WaitForButton();
785}
786
787#else /* HAVE_LCD_BITMAP */
788/* Player implementation */
789
790/* helper for DoUserDialog() */
791void ShowFlashInfo(tFlashInfo* pInfo)
792{
793 char buf[32];
794
795 if (!pInfo->manufacturer)
796 {
797 rb->lcd_puts_scroll(0, 0, "Flash: M=? D=?");
798 rb->lcd_puts_scroll(0, 1, "Impossible to program");
799 rb->lcd_update();
800 WaitForButton();
801 }
802 else
803 {
804 rb->snprintf(buf, sizeof(buf), "Flash: M=%02x D=%02x",
805 pInfo->manufacturer, pInfo->id);
806 rb->lcd_puts_scroll(0, 0, buf);
807
808 if (pInfo->size)
809 {
810 rb->snprintf(buf, sizeof(buf), "Size: %d KB", pInfo->size / 1024);
811 rb->lcd_puts_scroll(0, 1, buf);
812 rb->lcd_update();
813 }
814 else
815 {
816 rb->lcd_puts_scroll(0, 1, "Unsupported chip");
817 rb->lcd_update();
818 WaitForButton();
819 }
820 }
821}
822
823
824void DoUserDialog(char* filename)
825{
826 tFlashInfo FlashInfo;
827 char buf[32];
828 char default_filename[32];
829 int button;
830 int rc; /* generic return code */
831 size_t memleft;
832 tCheckROM result;
833 bool is_romless;
834
835 /* this can only work if Rockbox runs in DRAM, not flash ROM */
836 if ((UINT8*)rb >= FB && (UINT8*)rb < FB + 4096*1024) /* 4 MB max */
837 { /* we're running from flash */
838 rb->splash(HZ*3, "Not from ROM");
839 return; /* exit */
840 }
841
842 /* test if the user is running the correct plugin for this box */
843 if (!CheckPlatform(PLATFORM_ID, *(UINT16*)(FB + VERSION_ADR)))
844 {
845 rb->splash(HZ*3, "Wrong version");
846 return; /* exit */
847 }
848
849 /* refuse to work if the power may fail meanwhile */
850 if (!rb->battery_level_safe())
851 {
852 rb->splash(HZ*3, "Batt. too low!");
853 return; /* exit */
854 }
855
856 /* check boot ROM */
857 result = CheckBootROM();
858 if (result == eUnknown)
859 { /* no support for any other yet */
860 rb->splash(HZ*3, "Wrong boot ROM");
861 return; /* exit */
862 }
863 is_romless = (result == eROMless);
864
865 /* compose filename if none given */
866 if (filename == NULL)
867 {
868 rb->snprintf(
869 default_filename,
870 sizeof(default_filename),
871 "/firmware_%s%s.bin",
872 FILE_TYPE,
873 is_romless ? "_norom" : "");
874 filename = default_filename;
875 }
876
877 /* "allocate" memory */
878 sector = rb->plugin_get_buffer(&memleft);
879 if (memleft < SEC_SIZE) /* need buffer for a flash sector */
880 {
881 rb->splash(HZ*3, "Out of memory");
882 return; /* exit */
883 }
884
885 rc = GetFlashInfo(&FlashInfo);
886 ShowFlashInfo(&FlashInfo);
887
888 if (FlashInfo.size == 0) /* no valid chip */
889 {
890 return; /* exit */
891 }
892
893 rb->lcd_puts_scroll(0, 0, filename);
894 rb->lcd_puts_scroll(0, 1, "[Menu] to check");
895 rb->lcd_update();
896
897 button = WaitForButton();
898 if (button != BUTTON_MENU)
899 {
900 return;
901 }
902
903 rb->lcd_clear_display();
904 rb->lcd_puts(0, 0, "Checking...");
905 rb->lcd_update();
906
907 rc = CheckFirmwareFile(filename, FlashInfo.size, is_romless);
908 rb->lcd_puts(0, 0, "Checked:");
909 switch (rc)
910 {
911 case eOK:
912 rb->lcd_puts(0, 1, "File OK.");
913 break;
914 case eFileNotFound:
915 rb->lcd_puts_scroll(0, 0, "File not found:");
916 rb->lcd_puts_scroll(0, 1, filename);
917 break;
918 case eTooBig:
919 rb->lcd_puts_scroll(0, 0, "File too big,");
920 rb->lcd_puts_scroll(0, 1, "larger than chip.");
921 break;
922 case eTooSmall:
923 rb->lcd_puts_scroll(0, 0, "File too small.");
924 rb->lcd_puts_scroll(0, 1, "Incomplete?");
925 break;
926 case eReadErr:
927 rb->lcd_puts_scroll(0, 0, "Read error.");
928 break;
929 case eBadContent:
930 rb->lcd_puts_scroll(0, 0, "File invalid.");
931 rb->lcd_puts_scroll(0, 1, "Sanity check failed.");
932 break;
933 case eCrcErr:
934 rb->lcd_puts_scroll(0, 0, "File invalid.");
935 rb->lcd_puts_scroll(0, 1, "CRC check failed.");
936 break;
937 case eBadPlatform:
938 rb->lcd_puts_scroll(0, 0, "Wrong file for");
939 rb->lcd_puts_scroll(0, 1, "this hardware.");
940 break;
941 default:
942 rb->lcd_puts_scroll(0, 0, "Check failed.");
943 break;
944 }
945 rb->lcd_update();
946
947 rb->sleep(HZ*3);
948
949 if (rc == eOK)
950 {
951 rb->lcd_puts_scroll(0, 0, "[On] to program,");
952 rb->lcd_puts_scroll(0, 1, "other key to exit.");
953 rb->lcd_update();
954 }
955 else
956 { /* error occured */
957 return;
958 }
959
960 button = WaitForButton();
961
962 if (button != BUTTON_ON)
963 {
964 return;
965 }
966
967 rb->lcd_clear_display();
968 rb->lcd_puts_scroll(0, 0, "Are you sure?");
969 rb->lcd_puts_scroll(0, 1, "[+] to proceed.");
970 rb->lcd_update();
971
972 button = WaitForButton();
973
974 if (button != BUTTON_RIGHT)
975 {
976 return;
977 }
978
979 rb->lcd_clear_display();
980 rb->lcd_puts_scroll(0, 0, "Programming...");
981 rb->lcd_update();
982
983 rc = ProgramFirmwareFile(filename, FlashInfo.size);
984
985 if (rc)
986 { /* errors */
987 rb->lcd_clear_display();
988 rb->lcd_puts_scroll(0, 0, "Programming failed!");
989 rb->snprintf(buf, sizeof(buf), "%d errors", rc);
990 rb->lcd_puts_scroll(0, 1, buf);
991 rb->lcd_update();
992 WaitForButton();
993 }
994
995 rb->lcd_clear_display();
996 rb->lcd_puts_scroll(0, 0, "Verifying...");
997 rb->lcd_update();
998
999 rc = VerifyFirmwareFile(filename);
1000
1001 rb->lcd_clear_display();
1002
1003 if (rc == 0)
1004 {
1005 rb->lcd_puts_scroll(0, 0, "Verify OK.");
1006 }
1007 else
1008 {
1009 rb->snprintf(buf, sizeof(buf), "Verify failed! %d errors", rc);
1010 rb->lcd_puts_scroll(0, 0, buf);
1011 }
1012
1013 rb->lcd_puts_scroll(0, 1, "Press any key to exit.");
1014 rb->lcd_update();
1015 WaitForButton();
1016}
1017
1018#endif /* not HAVE_LCD_BITMAP */
1019
1020
1021/***************** Plugin Entry Point *****************/
1022
1023enum plugin_status plugin_start(const void* parameter)
1024{
1025 int oldmode;
1026
1027 /* now go ahead and have fun! */
1028 oldmode = rb->system_memory_guard(MEMGUARD_NONE); /*disable memory guard */
1029 DoUserDialog((char*) parameter);
1030 rb->system_memory_guard(oldmode); /* re-enable memory guard */
1031
1032 return PLUGIN_OK;
1033}