diff options
Diffstat (limited to 'apps/plugins/firmware_flash.c')
-rw-r--r-- | apps/plugins/firmware_flash.c | 854 |
1 files changed, 854 insertions, 0 deletions
diff --git a/apps/plugins/firmware_flash.c b/apps/plugins/firmware_flash.c new file mode 100644 index 0000000000..d24a174c12 --- /dev/null +++ b/apps/plugins/firmware_flash.c | |||
@@ -0,0 +1,854 @@ | |||
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 SHURE WHAT YOU DO !!! | ||
12 | * | ||
13 | * Copyright (C) 2003 Jörg Hohensohn [IDC]Dragon | ||
14 | * | ||
15 | * All files in this archive are subject to the GNU General Public License. | ||
16 | * See the file COPYING in the source tree root for full license agreement. | ||
17 | * | ||
18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
19 | * KIND, either express or implied. | ||
20 | * | ||
21 | ****************************************************************************/ | ||
22 | #include "plugin.h" | ||
23 | |||
24 | #ifndef SIMULATOR | ||
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 | #if defined(ARCHOS_PLAYER) | ||
42 | #define FILENAME "/firmware_play.bin" | ||
43 | #define KEEP VERSION_ADR /* keep the firmware version */ | ||
44 | #elif defined(ARCHOS_RECORDER) | ||
45 | #define FILENAME "/firmware_rec.bin" | ||
46 | #define KEEP MASK_ADR /* keep the mask value */ | ||
47 | #elif defined(ARCHOS_FMRECORDER) | ||
48 | #define FILENAME "/firmware_fm.bin" | ||
49 | #define KEEP MASK_ADR /* keep the mask value */ | ||
50 | #else | ||
51 | #error ("No known platform given!") | ||
52 | #endif | ||
53 | |||
54 | /* result of the CheckFirmwareFile() function */ | ||
55 | typedef enum | ||
56 | { | ||
57 | eOK = 0, | ||
58 | eFileNotFound, /* errors from here on */ | ||
59 | eTooBig, | ||
60 | eTooSmall, | ||
61 | eReadErr, | ||
62 | eBadContent, | ||
63 | eCrcErr, | ||
64 | } tCheckResult; | ||
65 | |||
66 | typedef struct | ||
67 | { | ||
68 | UINT8 manufacturer; | ||
69 | UINT8 id; | ||
70 | int size; | ||
71 | char name[32]; | ||
72 | } tFlashInfo; | ||
73 | |||
74 | static struct plugin_api* rb; /* here is a global api struct pointer */ | ||
75 | |||
76 | #define MASK_ADR 0xFC /* position of hardware mask value in Flash */ | ||
77 | #define VERSION_ADR 0xFE /* position of firmware version value in Flash */ | ||
78 | #define SEC_SIZE 4096 /* size of one flash sector */ | ||
79 | static UINT8* sector; /* better not place this on the stack... */ | ||
80 | static volatile UINT8* FB = (UINT8*)0x02000000; /* Flash base address */ | ||
81 | |||
82 | |||
83 | /***************** Flash Functions *****************/ | ||
84 | |||
85 | |||
86 | /* read the manufacturer and device ID */ | ||
87 | bool ReadID(volatile UINT8* pBase, UINT8* pManufacturerID, UINT8* pDeviceID) | ||
88 | { | ||
89 | UINT8 not_manu, not_id; /* read values before switching to ID mode */ | ||
90 | UINT8 manu, id; /* read values when in ID mode */ | ||
91 | |||
92 | pBase = (UINT8*)((UINT32)pBase & 0xFFF80000); /* down to 512k align */ | ||
93 | |||
94 | /* read the normal content */ | ||
95 | not_manu = pBase[0]; /* should be 'A' (0x41) and 'R' (0x52) */ | ||
96 | not_id = pBase[1]; /* from the "ARCH" marker */ | ||
97 | |||
98 | pBase[0x5555] = 0xAA; /* enter command mode */ | ||
99 | pBase[0x2AAA] = 0x55; | ||
100 | pBase[0x5555] = 0x90; /* ID command */ | ||
101 | rb->sleep(HZ/50); /* Atmel wants 20ms pause here */ | ||
102 | |||
103 | manu = pBase[0]; | ||
104 | id = pBase[1]; | ||
105 | |||
106 | pBase[0] = 0xF0; /* reset flash (back to normal read mode) */ | ||
107 | rb->sleep(HZ/50); /* Atmel wants 20ms pause here */ | ||
108 | |||
109 | /* I assume success if the obtained values are different from | ||
110 | the normal flash content. This is not perfectly bulletproof, they | ||
111 | could theoretically be the same by chance, causing us to fail. */ | ||
112 | if (not_manu != manu || not_id != id) /* a value has changed */ | ||
113 | { | ||
114 | *pManufacturerID = manu; /* return the results */ | ||
115 | *pDeviceID = id; | ||
116 | return true; /* success */ | ||
117 | } | ||
118 | return false; /* fail */ | ||
119 | } | ||
120 | |||
121 | |||
122 | /* erase the sector which contains the given address */ | ||
123 | bool EraseSector(volatile UINT8* pAddr) | ||
124 | { | ||
125 | #ifdef DUMMY | ||
126 | (void)pAddr; /* prevents warning */ | ||
127 | return true; | ||
128 | #else | ||
129 | volatile UINT8* pBase = (UINT8*)((UINT32)pAddr & 0xFFF80000); /* round down to 512k align */ | ||
130 | unsigned timeout = 43000; /* the timeout loop should be no less than 25ms */ | ||
131 | |||
132 | pBase[0x5555] = 0xAA; /* enter command mode */ | ||
133 | pBase[0x2AAA] = 0x55; | ||
134 | pBase[0x5555] = 0x80; /* erase command */ | ||
135 | pBase[0x5555] = 0xAA; /* enter command mode */ | ||
136 | pBase[0x2AAA] = 0x55; | ||
137 | *pAddr = 0x30; /* erase the sector */ | ||
138 | |||
139 | /* I counted 7 instructions for this loop -> min. 0.58 us per round */ | ||
140 | /* Plus memory waitstates it will be much more, gives margin */ | ||
141 | while (*pAddr != 0xFF && --timeout); /* poll for erased */ | ||
142 | |||
143 | return (timeout != 0); | ||
144 | #endif | ||
145 | } | ||
146 | |||
147 | |||
148 | /* address must be in an erased location */ | ||
149 | inline bool ProgramByte(volatile UINT8* pAddr, UINT8 data) | ||
150 | { | ||
151 | #ifdef DUMMY | ||
152 | (void)pAddr; /* prevents warnings */ | ||
153 | (void)data; | ||
154 | return true; | ||
155 | #else | ||
156 | unsigned timeout = 35; /* the timeout loop should be no less than 20us */ | ||
157 | |||
158 | if (~*pAddr & data) /* just a safety feature, not really necessary */ | ||
159 | return false; /* can't set any bit from 0 to 1 */ | ||
160 | |||
161 | FB[0x5555] = 0xAA; /* enter command mode */ | ||
162 | FB[0x2AAA] = 0x55; | ||
163 | FB[0x5555] = 0xA0; /* byte program command */ | ||
164 | |||
165 | *pAddr = data; | ||
166 | |||
167 | /* I counted 7 instructions for this loop -> min. 0.58 us per round */ | ||
168 | /* Plus memory waitstates it will be much more, gives margin */ | ||
169 | while (*pAddr != data && --timeout); /* poll for programmed */ | ||
170 | |||
171 | return (timeout != 0); | ||
172 | #endif | ||
173 | } | ||
174 | |||
175 | |||
176 | /* this returns true if supported and fills the info struct */ | ||
177 | bool GetFlashInfo(tFlashInfo* pInfo) | ||
178 | { | ||
179 | rb->memset(pInfo, 0, sizeof(tFlashInfo)); | ||
180 | |||
181 | if (!ReadID(FB, &pInfo->manufacturer, &pInfo->id)) | ||
182 | return false; | ||
183 | |||
184 | if (pInfo->manufacturer == 0xBF) /* SST */ | ||
185 | { | ||
186 | if (pInfo->id == 0xD6) | ||
187 | { | ||
188 | pInfo->size = 256* 1024; /* 256k */ | ||
189 | rb->strcpy(pInfo->name, "SST39VF020"); | ||
190 | return true; | ||
191 | } | ||
192 | else if (pInfo->id == 0xD7) | ||
193 | { | ||
194 | pInfo->size = 512* 1024; /* 512k */ | ||
195 | rb->strcpy(pInfo->name, "SST39VF040"); | ||
196 | return true; | ||
197 | } | ||
198 | else | ||
199 | return false; | ||
200 | } | ||
201 | return false; | ||
202 | } | ||
203 | |||
204 | |||
205 | /*********** Utility Functions ************/ | ||
206 | |||
207 | |||
208 | /* Tool function to calculate a CRC32 across some buffer */ | ||
209 | /* third argument is either 0xFFFFFFFF to start or value from last piece */ | ||
210 | unsigned crc_32(unsigned char* buf, unsigned len, unsigned crc32) | ||
211 | { | ||
212 | /* CCITT standard polynomial 0x04C11DB7 */ | ||
213 | static const unsigned crc32_lookup[16] = | ||
214 | { /* lookup table for 4 bits at a time is affordable */ | ||
215 | 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, | ||
216 | 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005, | ||
217 | 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61, | ||
218 | 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD | ||
219 | }; | ||
220 | |||
221 | unsigned char byte; | ||
222 | unsigned t; | ||
223 | |||
224 | while (len--) | ||
225 | { | ||
226 | byte = *buf++; /* get one byte of data */ | ||
227 | |||
228 | /* upper nibble of our data */ | ||
229 | t = crc32 >> 28; /* extract the 4 most significant bits */ | ||
230 | t ^= byte >> 4; /* XOR in 4 bits of data into the extracted bits */ | ||
231 | crc32 <<= 4; /* shift the CRC register left 4 bits */ | ||
232 | crc32 ^= crc32_lookup[t]; /* do the table lookup and XOR the result */ | ||
233 | |||
234 | /* lower nibble of our data */ | ||
235 | t = crc32 >> 28; /* extract the 4 most significant bits */ | ||
236 | t ^= byte & 0x0F; /* XOR in 4 bits of data into the extracted bits */ | ||
237 | crc32 <<= 4; /* shift the CRC register left 4 bits */ | ||
238 | crc32 ^= crc32_lookup[t]; /* do the table lookup and XOR the result */ | ||
239 | } | ||
240 | |||
241 | return crc32; | ||
242 | } | ||
243 | |||
244 | |||
245 | /*********** Firmware File Functions ************/ | ||
246 | |||
247 | tCheckResult CheckFirmwareFile(char* filename, int chipsize) | ||
248 | { | ||
249 | int i; | ||
250 | int fd; | ||
251 | int fileleft; /* size info, how many left for reading */ | ||
252 | int fileread = 0; /* total size as read from the file */ | ||
253 | int read_now; /* how many to read for this sector */ | ||
254 | int got_now; /* how many gotten for this sector */ | ||
255 | unsigned crc32 = 0xFFFFFFFF; /* CCITT init value */ | ||
256 | unsigned file_crc; /* CRC value read from file */ | ||
257 | bool has_crc; | ||
258 | |||
259 | fd = rb->open(filename, O_RDONLY); | ||
260 | if (fd < 0) | ||
261 | return eFileNotFound; | ||
262 | |||
263 | fileleft = rb->filesize(fd); | ||
264 | if (fileleft > chipsize) | ||
265 | { | ||
266 | rb->close(fd); | ||
267 | return eTooBig; | ||
268 | } | ||
269 | else if (fileleft < 50000) /* give it some reasonable lower limit */ | ||
270 | { | ||
271 | rb->close(fd); | ||
272 | return eTooSmall; | ||
273 | } | ||
274 | |||
275 | if (fileleft == 256*1024) | ||
276 | { // original dumped firmware file has no CRC | ||
277 | has_crc = false; | ||
278 | } | ||
279 | else | ||
280 | { | ||
281 | has_crc = true; | ||
282 | fileleft -= sizeof(unsigned); // exclude the last 4 bytes | ||
283 | } | ||
284 | |||
285 | /* do some sanity checks */ | ||
286 | |||
287 | got_now = rb->read(fd, sector, SEC_SIZE); /* read first sector */ | ||
288 | fileread += got_now; | ||
289 | fileleft -= got_now; | ||
290 | if (got_now != SEC_SIZE) | ||
291 | { | ||
292 | rb->close(fd); | ||
293 | return eReadErr; | ||
294 | } | ||
295 | |||
296 | if (has_crc) | ||
297 | crc32 = crc_32(sector, SEC_SIZE, crc32); /* checksum */ | ||
298 | |||
299 | /* compare some bytes which have to be identical */ | ||
300 | if (*(UINT32*)sector != 0x41524348) /* "ARCH" */ | ||
301 | { | ||
302 | rb->close(fd); | ||
303 | return eBadContent; | ||
304 | } | ||
305 | |||
306 | for (i = 0x30; i<MASK_ADR-1; i++) /* leave one byte for me */ | ||
307 | { | ||
308 | if (sector[i] != FB[i]) | ||
309 | { | ||
310 | rb->close(fd); | ||
311 | return eBadContent; | ||
312 | } | ||
313 | } | ||
314 | |||
315 | /* check if we can read the whole file, and do checksum */ | ||
316 | do | ||
317 | { | ||
318 | read_now = MIN(SEC_SIZE, fileleft); | ||
319 | got_now = rb->read(fd, sector, read_now); | ||
320 | fileread += got_now; | ||
321 | fileleft -= got_now; | ||
322 | |||
323 | if (read_now != got_now) | ||
324 | { | ||
325 | rb->close(fd); | ||
326 | return eReadErr; | ||
327 | } | ||
328 | |||
329 | if (has_crc) | ||
330 | { | ||
331 | crc32 = crc_32(sector, got_now, crc32); /* checksum */ | ||
332 | } | ||
333 | } while (fileleft); | ||
334 | |||
335 | if (has_crc) | ||
336 | { | ||
337 | got_now = rb->read(fd, &file_crc, sizeof(file_crc)); | ||
338 | if (got_now != sizeof(file_crc)) | ||
339 | { | ||
340 | rb->close(fd); | ||
341 | return eReadErr; | ||
342 | } | ||
343 | } | ||
344 | |||
345 | /* must be EOF now */ | ||
346 | got_now = rb->read(fd, sector, SEC_SIZE); | ||
347 | rb->close(fd); | ||
348 | if (got_now != 0) | ||
349 | return eReadErr; | ||
350 | |||
351 | if (has_crc && file_crc != crc32) | ||
352 | return eCrcErr; | ||
353 | |||
354 | return eOK; | ||
355 | } | ||
356 | |||
357 | |||
358 | /* returns the # of failures, 0 on success */ | ||
359 | unsigned ProgramFirmwareFile(char* filename, int chipsize) | ||
360 | { | ||
361 | int i, j; | ||
362 | int fd; | ||
363 | int read = SEC_SIZE; /* how many for this sector */ | ||
364 | UINT16 keep = *(UINT16*)(FB + KEEP); /* we must keep this! */ | ||
365 | unsigned failures = 0; | ||
366 | |||
367 | fd = rb->open(filename, O_RDONLY); | ||
368 | if (fd < 0) | ||
369 | return false; | ||
370 | |||
371 | for (i=0; i<chipsize; i+=SEC_SIZE) | ||
372 | { | ||
373 | if (!EraseSector(FB + i)) | ||
374 | { | ||
375 | /* nothing we can do, let the programming count the errors */ | ||
376 | } | ||
377 | |||
378 | if (read == SEC_SIZE) /* not EOF yet */ | ||
379 | { | ||
380 | read = rb->read(fd, sector, SEC_SIZE); | ||
381 | if (i==0) | ||
382 | { /* put original value back in */ | ||
383 | *(UINT16*)(sector + KEEP) = keep; | ||
384 | } | ||
385 | |||
386 | for (j=0; j<read; j++) | ||
387 | { | ||
388 | if (!ProgramByte(FB + i + j, sector[j])) | ||
389 | { | ||
390 | failures++; | ||
391 | } | ||
392 | } | ||
393 | } | ||
394 | } | ||
395 | |||
396 | rb->close(fd); | ||
397 | |||
398 | return failures; | ||
399 | } | ||
400 | |||
401 | /* returns the # of failures, 0 on success */ | ||
402 | unsigned VerifyFirmwareFile(char* filename) | ||
403 | { | ||
404 | int i=0, j; | ||
405 | int fd; | ||
406 | int read = SEC_SIZE; /* how many for this sector */ | ||
407 | unsigned failures = 0; | ||
408 | |||
409 | fd = rb->open(filename, O_RDONLY); | ||
410 | if (fd < 0) | ||
411 | return false; | ||
412 | |||
413 | do | ||
414 | { | ||
415 | read = rb->read(fd, sector, SEC_SIZE); | ||
416 | |||
417 | for (j=0; j<read; j++) | ||
418 | { | ||
419 | /* position of keep value is no error */ | ||
420 | if (FB[i] != sector[j] && i != KEEP && i != (KEEP+1)) | ||
421 | { | ||
422 | failures++; | ||
423 | } | ||
424 | i++; | ||
425 | } | ||
426 | } | ||
427 | while (read == SEC_SIZE); | ||
428 | |||
429 | rb->close(fd); | ||
430 | |||
431 | return failures; | ||
432 | } | ||
433 | |||
434 | |||
435 | /***************** User Interface Functions *****************/ | ||
436 | |||
437 | int WaitForButton(void) | ||
438 | { | ||
439 | int button; | ||
440 | |||
441 | do | ||
442 | { | ||
443 | button = rb->button_get(true); | ||
444 | } while (button & BUTTON_REL); | ||
445 | |||
446 | return button; | ||
447 | } | ||
448 | |||
449 | #ifdef HAVE_LCD_BITMAP | ||
450 | /* Recorder implementation */ | ||
451 | |||
452 | /* helper for DoUserDialog() */ | ||
453 | void ShowFlashInfo(tFlashInfo* pInfo) | ||
454 | { | ||
455 | char buf[32]; | ||
456 | |||
457 | if (!pInfo->manufacturer) | ||
458 | { | ||
459 | rb->lcd_puts(0, 0, "Flash: M=?? D=??"); | ||
460 | rb->lcd_puts(0, 1, "Impossible to program"); | ||
461 | } | ||
462 | else | ||
463 | { | ||
464 | rb->snprintf(buf, sizeof(buf), "Flash: M=%02x D=%02x", | ||
465 | pInfo->manufacturer, pInfo->id); | ||
466 | rb->lcd_puts(0, 0, buf); | ||
467 | |||
468 | |||
469 | if (pInfo->size) | ||
470 | { | ||
471 | rb->lcd_puts(0, 1, pInfo->name); | ||
472 | rb->snprintf(buf, sizeof(buf), "Size: %d KB", pInfo->size / 1024); | ||
473 | rb->lcd_puts(0, 2, buf); | ||
474 | } | ||
475 | else | ||
476 | { | ||
477 | rb->lcd_puts(0, 1, "Unsupported chip"); | ||
478 | } | ||
479 | |||
480 | } | ||
481 | |||
482 | rb->lcd_update(); | ||
483 | } | ||
484 | |||
485 | |||
486 | /* Kind of our main function, defines the application flow. */ | ||
487 | void DoUserDialog(void) | ||
488 | { | ||
489 | tFlashInfo FlashInfo; | ||
490 | char buf[32]; | ||
491 | int button; | ||
492 | int rc; /* generic return code */ | ||
493 | int memleft; | ||
494 | unsigned boot_crc; | ||
495 | |||
496 | rb->lcd_setfont(FONT_SYSFIXED); | ||
497 | |||
498 | /* check boot ROM */ | ||
499 | boot_crc = crc_32((unsigned char*)0x0, 64*1024, 0xFFFFFFFF); | ||
500 | if (boot_crc != 0x56DBA4EE) /* Version 1 */ | ||
501 | { /* no support for any other yet */ | ||
502 | rb->splash(HZ*3, 0, true, "Wrong boot ROM"); | ||
503 | return; /* exit */ | ||
504 | } | ||
505 | |||
506 | /* "allocate" memory */ | ||
507 | sector = rb->plugin_get_buffer(&memleft); | ||
508 | if (memleft < SEC_SIZE) /* need buffer for a flash sector */ | ||
509 | { | ||
510 | rb->splash(HZ*3, 0, true, "Out of memory"); | ||
511 | return; /* exit */ | ||
512 | } | ||
513 | |||
514 | rc = GetFlashInfo(&FlashInfo); | ||
515 | ShowFlashInfo(&FlashInfo); | ||
516 | if (FlashInfo.size == 0) /* no valid chip */ | ||
517 | { | ||
518 | rb->splash(HZ*3, 0, true, "Sorry!"); | ||
519 | return; /* exit */ | ||
520 | } | ||
521 | |||
522 | rb->lcd_puts(0, 3, "using file:"); | ||
523 | rb->lcd_puts(0, 4, FILENAME); | ||
524 | rb->lcd_puts(0, 6, "[F1] to check file"); | ||
525 | rb->lcd_puts(0, 7, "other key to exit"); | ||
526 | rb->lcd_update(); | ||
527 | |||
528 | button = WaitForButton(); | ||
529 | if (button != BUTTON_F1) | ||
530 | { | ||
531 | return; | ||
532 | } | ||
533 | |||
534 | rb->lcd_clear_display(); | ||
535 | rb->lcd_puts(0, 0, "checking..."); | ||
536 | rb->lcd_update(); | ||
537 | |||
538 | rc = CheckFirmwareFile(FILENAME, FlashInfo.size); | ||
539 | rb->lcd_puts(0, 0, "checked:"); | ||
540 | switch (rc) | ||
541 | { | ||
542 | case eOK: | ||
543 | rb->lcd_puts(0, 1, "File OK."); | ||
544 | break; | ||
545 | case eFileNotFound: | ||
546 | rb->lcd_puts(0, 1, "File not found."); | ||
547 | rb->lcd_puts(0, 2, "Put this in root:"); | ||
548 | rb->lcd_puts(0, 4, FILENAME); | ||
549 | break; | ||
550 | case eTooBig: | ||
551 | rb->lcd_puts(0, 1, "File too big,"); | ||
552 | rb->lcd_puts(0, 2, "larger than chip."); | ||
553 | break; | ||
554 | case eTooSmall: | ||
555 | rb->lcd_puts(0, 1, "File too small."); | ||
556 | rb->lcd_puts(0, 2, "Incomplete?"); | ||
557 | break; | ||
558 | case eReadErr: | ||
559 | rb->lcd_puts(0, 1, "Read error."); | ||
560 | break; | ||
561 | case eBadContent: | ||
562 | rb->lcd_puts(0, 1, "File invalid."); | ||
563 | rb->lcd_puts(0, 2, "Sanity check fail."); | ||
564 | break; | ||
565 | case eCrcErr: | ||
566 | rb->lcd_puts(0, 1, "File invalid."); | ||
567 | rb->lcd_puts(0, 2, "CRC check failed,"); | ||
568 | rb->lcd_puts(0, 3, "checksum mismatch."); | ||
569 | break; | ||
570 | default: | ||
571 | rb->lcd_puts(0, 1, "Check failed."); | ||
572 | break; | ||
573 | } | ||
574 | |||
575 | if (rc == eOK) | ||
576 | { | ||
577 | rb->lcd_puts(0, 6, "[F2] to program"); | ||
578 | rb->lcd_puts(0, 7, "other key to exit"); | ||
579 | } | ||
580 | else | ||
581 | { /* error occured */ | ||
582 | rb->lcd_puts(0, 6, "Any key to exit"); | ||
583 | } | ||
584 | |||
585 | rb->lcd_update(); | ||
586 | |||
587 | button = WaitForButton(); | ||
588 | if (button != BUTTON_F2 || rc != eOK) | ||
589 | { | ||
590 | return; | ||
591 | } | ||
592 | |||
593 | rb->lcd_clear_display(); | ||
594 | rb->lcd_puts(0, 0, "Program all Flash?"); | ||
595 | rb->lcd_puts(0, 1, "Are you shure?"); | ||
596 | rb->lcd_puts(0, 2, "If it goes wrong,"); | ||
597 | rb->lcd_puts(0, 3, "it kills your box!"); | ||
598 | rb->lcd_puts(0, 4, "See documentation."); | ||
599 | |||
600 | rb->lcd_puts(0, 6, "[F3] to proceed"); | ||
601 | rb->lcd_puts(0, 7, "other key to exit"); | ||
602 | rb->lcd_update(); | ||
603 | |||
604 | button = WaitForButton(); | ||
605 | if (button != BUTTON_F3) | ||
606 | { | ||
607 | return; | ||
608 | } | ||
609 | |||
610 | rb->lcd_clear_display(); | ||
611 | rb->lcd_puts(0, 0, "Programming..."); | ||
612 | rb->lcd_update(); | ||
613 | |||
614 | rc = ProgramFirmwareFile(FILENAME, FlashInfo.size); | ||
615 | if (rc) | ||
616 | { /* errors */ | ||
617 | rb->lcd_clear_display(); | ||
618 | rb->lcd_puts(0, 0, "Panic:"); | ||
619 | rb->lcd_puts(0, 1, "Programming fail!"); | ||
620 | rb->snprintf(buf, sizeof(buf), "%d errors", rc); | ||
621 | rb->lcd_puts(0, 2, buf); | ||
622 | rb->lcd_update(); | ||
623 | button = WaitForButton(); | ||
624 | } | ||
625 | |||
626 | rb->lcd_clear_display(); | ||
627 | rb->lcd_puts(0, 0, "Verifying..."); | ||
628 | rb->lcd_update(); | ||
629 | |||
630 | rc = VerifyFirmwareFile(FILENAME); | ||
631 | |||
632 | rb->lcd_clear_display(); | ||
633 | if (rc == 0) | ||
634 | { | ||
635 | rb->lcd_puts(0, 0, "Verify OK."); | ||
636 | } | ||
637 | else | ||
638 | { | ||
639 | rb->lcd_puts(0, 0, "Panic:"); | ||
640 | rb->lcd_puts(0, 1, "Verify fail!"); | ||
641 | rb->snprintf(buf, sizeof(buf), "%d errors", rc); | ||
642 | rb->lcd_puts(0, 2, buf); | ||
643 | } | ||
644 | rb->lcd_puts(0, 7, "Any key to exit"); | ||
645 | rb->lcd_update(); | ||
646 | |||
647 | button = WaitForButton(); | ||
648 | } | ||
649 | |||
650 | #else /* HAVE_LCD_BITMAP */ | ||
651 | /* Player implementation */ | ||
652 | |||
653 | /* helper for DoUserDialog() */ | ||
654 | void ShowFlashInfo(tFlashInfo* pInfo) | ||
655 | { | ||
656 | char buf[32]; | ||
657 | |||
658 | if (!pInfo->manufacturer) | ||
659 | { | ||
660 | rb->lcd_puts_scroll(0, 0, "Flash: M=? D=?"); | ||
661 | rb->lcd_puts_scroll(0, 1, "Impossible to program"); | ||
662 | WaitForButton(); | ||
663 | } | ||
664 | else | ||
665 | { | ||
666 | rb->snprintf(buf, sizeof(buf), "Flash: M=%02x D=%02x", | ||
667 | pInfo->manufacturer, pInfo->id); | ||
668 | rb->lcd_puts_scroll(0, 0, buf); | ||
669 | |||
670 | if (pInfo->size) | ||
671 | { | ||
672 | rb->snprintf(buf, sizeof(buf), "Size: %d KB", pInfo->size / 1024); | ||
673 | rb->lcd_puts_scroll(0, 1, buf); | ||
674 | } | ||
675 | else | ||
676 | { | ||
677 | rb->lcd_puts_scroll(0, 1, "Unsupported chip"); | ||
678 | WaitForButton(); | ||
679 | } | ||
680 | } | ||
681 | } | ||
682 | |||
683 | |||
684 | void DoUserDialog(void) | ||
685 | { | ||
686 | tFlashInfo FlashInfo; | ||
687 | char buf[32]; | ||
688 | int button; | ||
689 | int rc; /* generic return code */ | ||
690 | int memleft; | ||
691 | unsigned boot_crc; | ||
692 | |||
693 | /* check boot ROM */ | ||
694 | boot_crc = crc_32((unsigned char*)0x0, 64*1024, 0xFFFFFFFF); | ||
695 | if (boot_crc != 0x56DBA4EE) /* Version 1 */ | ||
696 | { /* no support for any other yet */ | ||
697 | rb->splash(HZ*3, 0, true, "Wrong boot ROM"); | ||
698 | return; /* exit */ | ||
699 | } | ||
700 | |||
701 | /* "allocate" memory */ | ||
702 | sector = rb->plugin_get_buffer(&memleft); | ||
703 | if (memleft < SEC_SIZE) /* need buffer for a flash sector */ | ||
704 | { | ||
705 | rb->splash(HZ*3, 0, true, "Out of memory"); | ||
706 | return; /* exit */ | ||
707 | } | ||
708 | |||
709 | rc = GetFlashInfo(&FlashInfo); | ||
710 | ShowFlashInfo(&FlashInfo); | ||
711 | |||
712 | if (FlashInfo.size == 0) /* no valid chip */ | ||
713 | { | ||
714 | return; /* exit */ | ||
715 | } | ||
716 | |||
717 | rb->lcd_puts_scroll(0, 0, FILENAME); | ||
718 | rb->lcd_puts_scroll(0, 1, "[Menu] to check"); | ||
719 | |||
720 | button = WaitForButton(); | ||
721 | if (button != BUTTON_MENU) | ||
722 | { | ||
723 | return; | ||
724 | } | ||
725 | |||
726 | rb->lcd_clear_display(); | ||
727 | rb->lcd_puts(0, 0, "Checking..."); | ||
728 | |||
729 | rc = CheckFirmwareFile(FILENAME, FlashInfo.size); | ||
730 | rb->lcd_puts(0, 0, "Checked:"); | ||
731 | switch (rc) | ||
732 | { | ||
733 | case eOK: | ||
734 | rb->lcd_puts(0, 1, "File OK."); | ||
735 | break; | ||
736 | case eFileNotFound: | ||
737 | rb->lcd_puts_scroll(0, 0, "File not found:"); | ||
738 | rb->lcd_puts_scroll(0, 1, FILENAME); | ||
739 | break; | ||
740 | case eTooBig: | ||
741 | rb->lcd_puts_scroll(0, 0, "File too big,"); | ||
742 | rb->lcd_puts_scroll(0, 1, "larger than chip."); | ||
743 | break; | ||
744 | case eTooSmall: | ||
745 | rb->lcd_puts_scroll(0, 0, "File too small."); | ||
746 | rb->lcd_puts_scroll(0, 1, "Incomplete?"); | ||
747 | break; | ||
748 | case eReadErr: | ||
749 | rb->lcd_puts_scroll(0, 0, "Read error."); | ||
750 | break; | ||
751 | case eBadContent: | ||
752 | rb->lcd_puts_scroll(0, 0, "File invalid."); | ||
753 | rb->lcd_puts_scroll(0, 1, "Sanity check failed."); | ||
754 | break; | ||
755 | case eCrcErr: | ||
756 | rb->lcd_puts_scroll(0, 0, "File invalid."); | ||
757 | rb->lcd_puts_scroll(0, 1, "CRC check failed."); | ||
758 | break; | ||
759 | default: | ||
760 | rb->lcd_puts_scroll(0, 0, "Check failed."); | ||
761 | break; | ||
762 | } | ||
763 | |||
764 | rb->sleep(HZ*3); | ||
765 | |||
766 | if (rc == eOK) | ||
767 | { | ||
768 | rb->lcd_puts_scroll(0, 0, "[On] to program,"); | ||
769 | rb->lcd_puts_scroll(0, 1, "other key to exit."); | ||
770 | } | ||
771 | else | ||
772 | { /* error occured */ | ||
773 | return; | ||
774 | } | ||
775 | |||
776 | button = WaitForButton(); | ||
777 | |||
778 | if (button != BUTTON_ON) | ||
779 | { | ||
780 | return; | ||
781 | } | ||
782 | |||
783 | rb->lcd_clear_display(); | ||
784 | rb->lcd_puts_scroll(0, 0, "Are you sure?"); | ||
785 | rb->lcd_puts_scroll(0, 1, "[+] to proceed."); | ||
786 | |||
787 | button = WaitForButton(); | ||
788 | |||
789 | if (button != BUTTON_RIGHT) | ||
790 | { | ||
791 | return; | ||
792 | } | ||
793 | |||
794 | rb->lcd_clear_display(); | ||
795 | rb->lcd_puts_scroll(0, 0, "Programming..."); | ||
796 | |||
797 | rc = ProgramFirmwareFile(FILENAME, FlashInfo.size); | ||
798 | |||
799 | if (rc) | ||
800 | { /* errors */ | ||
801 | rb->lcd_clear_display(); | ||
802 | rb->lcd_puts_scroll(0, 0, "Programming failed!"); | ||
803 | rb->snprintf(buf, sizeof(buf), "%d errors", rc); | ||
804 | rb->lcd_puts_scroll(0, 1, buf); | ||
805 | WaitForButton(); | ||
806 | } | ||
807 | |||
808 | rb->lcd_clear_display(); | ||
809 | rb->lcd_puts_scroll(0, 0, "Verifying..."); | ||
810 | |||
811 | rc = VerifyFirmwareFile(FILENAME); | ||
812 | |||
813 | rb->lcd_clear_display(); | ||
814 | |||
815 | if (rc == 0) | ||
816 | { | ||
817 | rb->lcd_puts_scroll(0, 0, "Verify OK."); | ||
818 | } | ||
819 | else | ||
820 | { | ||
821 | rb->snprintf(buf, sizeof(buf), "Verify failed! %d errors", rc); | ||
822 | rb->lcd_puts_scroll(0, 0, buf); | ||
823 | } | ||
824 | |||
825 | rb->lcd_puts_scroll(0, 1, "Press any key to exit."); | ||
826 | WaitForButton(); | ||
827 | } | ||
828 | |||
829 | #endif /* not HAVE_LCD_BITMAP */ | ||
830 | |||
831 | |||
832 | /***************** Plugin Entry Point *****************/ | ||
833 | |||
834 | enum plugin_status plugin_start(struct plugin_api* api, void* parameter) | ||
835 | { | ||
836 | /* this macro should be called as the first thing you do in the plugin. | ||
837 | it test that the api version and model the plugin was compiled for | ||
838 | matches the machine it is running on */ | ||
839 | TEST_PLUGIN_API(api); | ||
840 | |||
841 | /* if you don't use the parameter, you can do like | ||
842 | this to avoid the compiler warning about it */ | ||
843 | (void)parameter; | ||
844 | |||
845 | rb = api; /* copy to global api pointer */ | ||
846 | |||
847 | /* now go ahead and have fun! */ | ||
848 | DoUserDialog(); | ||
849 | |||
850 | return PLUGIN_OK; | ||
851 | } | ||
852 | |||
853 | #endif /* #ifndef SIMULATOR */ | ||
854 | |||