diff options
Diffstat (limited to 'apps/plugins/firmware_flash.c')
-rw-r--r-- | apps/plugins/firmware_flash.c | 1033 |
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 */ | ||
99 | typedef 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 */ | ||
112 | typedef enum | ||
113 | { | ||
114 | eBootROM, /* the supported boot ROM(s) */ | ||
115 | eUnknown, /* unknown boot ROM */ | ||
116 | eROMless, /* flash mapped to zero */ | ||
117 | } tCheckROM; | ||
118 | |||
119 | typedef 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 */ | ||
131 | static UINT8* sector; /* better not place this on the stack... */ | ||
132 | static volatile UINT8* FB = (UINT8*)0x02000000; /* Flash base address */ | ||
133 | |||
134 | |||
135 | /***************** Flash Functions *****************/ | ||
136 | |||
137 | |||
138 | /* read the manufacturer and device ID */ | ||
139 | bool 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 */ | ||
175 | bool 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 */ | ||
201 | static 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 */ | ||
229 | bool 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 */ | ||
259 | bool 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 | |||
291 | tCheckResult 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 */ | ||
430 | unsigned 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 */ | ||
474 | unsigned 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 */ | ||
510 | tCheckROM 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 | |||
541 | int 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() */ | ||
557 | void 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. */ | ||
587 | void 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() */ | ||
791 | void 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 | |||
824 | void 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 | |||
1023 | enum 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 | } | ||