diff options
Diffstat (limited to 'apps/plugins')
-rw-r--r-- | apps/plugins/rockbox_flash.c | 664 |
1 files changed, 664 insertions, 0 deletions
diff --git a/apps/plugins/rockbox_flash.c b/apps/plugins/rockbox_flash.c new file mode 100644 index 0000000000..829cc5a346 --- /dev/null +++ b/apps/plugins/rockbox_flash.c | |||
@@ -0,0 +1,664 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Plugin for reprogramming only the second Rockbox image. | ||
11 | * | ||
12 | * Copyright (C) 2003 Jörg Hohensohn [IDC]Dragon | ||
13 | * | ||
14 | * All files in this archive are subject to the GNU General Public License. | ||
15 | * See the file COPYING in the source tree root for full license agreement. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #include "plugin.h" | ||
22 | |||
23 | #ifndef UINT8 | ||
24 | #define UINT8 unsigned char | ||
25 | #endif | ||
26 | |||
27 | #ifndef UINT16 | ||
28 | #define UINT16 unsigned short | ||
29 | #endif | ||
30 | |||
31 | #ifndef UINT32 | ||
32 | #define UINT32 unsigned long | ||
33 | #endif | ||
34 | |||
35 | // hard-coded values | ||
36 | static volatile UINT8* FB = (UINT8*)0x02000000; // Flash base address | ||
37 | #define SECTORSIZE 4096 // size of one flash sector | ||
38 | |||
39 | #define ROCKBOX_DEST 0x09000000 | ||
40 | #define ROCKBOX_EXEC 0x09000200 | ||
41 | #define FILENAME "/rockbox.ucl" | ||
42 | #define VERS_ADR 0xFE // position of firmware version value in Flash | ||
43 | #define UCL_HEADER 26 // size of the header generated by uclpack | ||
44 | |||
45 | typedef struct | ||
46 | { | ||
47 | UINT32 destination; // address to copy it to | ||
48 | UINT32 size; // how many bytes of payload (to the next header) | ||
49 | UINT32 execute; // entry point | ||
50 | UINT32 flags; // uncompressed or compressed | ||
51 | // end of header, now comes the payload | ||
52 | } tImageHeader; | ||
53 | |||
54 | |||
55 | // result of the CheckFirmwareFile() function | ||
56 | typedef enum | ||
57 | { | ||
58 | eOK = 0, | ||
59 | eFileNotFound, // errors from here on | ||
60 | eTooBig, | ||
61 | eTooSmall, | ||
62 | eReadErr, | ||
63 | eNotUCL, | ||
64 | eWrongAlgorithm, | ||
65 | eMultiBlocks, | ||
66 | } tCheckResult; | ||
67 | |||
68 | typedef struct | ||
69 | { | ||
70 | UINT8 manufacturer; | ||
71 | UINT8 id; | ||
72 | int size; | ||
73 | char name[32]; | ||
74 | } tFlashInfo; | ||
75 | |||
76 | static struct plugin_api* rb; // here is a global api struct pointer | ||
77 | |||
78 | #define SEC_SIZE 4096 // size of one flash sector | ||
79 | static UINT8 sector[SEC_SIZE]; // better not place this on the stack... | ||
80 | |||
81 | |||
82 | /***************** Flash Functions *****************/ | ||
83 | |||
84 | |||
85 | // read the manufacturer and device ID | ||
86 | bool ReadID(volatile UINT8* pBase, UINT8* pManufacturerID, UINT8* pDeviceID) | ||
87 | { | ||
88 | UINT8 not_manu, not_id; // read values before switching to ID mode | ||
89 | UINT8 manu, id; // read values when in ID mode | ||
90 | |||
91 | pBase = (UINT8*)((UINT32)pBase & 0xFFF80000); // round down to 512k align, to make shure | ||
92 | |||
93 | not_manu = pBase[0]; // read the normal content | ||
94 | not_id = pBase[1]; // should be 'A' (0x41) and 'R' (0x52) from the "ARCH" marker | ||
95 | |||
96 | pBase[0x5555] = 0xAA; // enter command mode | ||
97 | pBase[0x2AAA] = 0x55; | ||
98 | pBase[0x5555] = 0x90; // ID command | ||
99 | rb->sleep(HZ/50); // Atmel wants 20ms pause here | ||
100 | |||
101 | manu = pBase[0]; | ||
102 | id = pBase[1]; | ||
103 | |||
104 | pBase[0] = 0xF0; // reset flash (back to normal read mode) | ||
105 | rb->sleep(HZ/50); // Atmel wants 20ms pause here | ||
106 | |||
107 | /* I assume success if the obtained values are different from | ||
108 | the normal flash content. This is not perfectly bulletproof, they | ||
109 | could theoretically be the same by chance, causing us to fail. */ | ||
110 | if (not_manu != manu || not_id != id) // a value has changed | ||
111 | { | ||
112 | *pManufacturerID = manu; // return the results | ||
113 | *pDeviceID = id; | ||
114 | return true; // success | ||
115 | } | ||
116 | return false; // fail | ||
117 | } | ||
118 | |||
119 | |||
120 | // eraze the sector which contains the given address | ||
121 | bool ErazeSector(volatile UINT8* pAddr) | ||
122 | { | ||
123 | volatile UINT8* pBase = (UINT8*)((UINT32)pAddr & 0xFFF80000); // round down to 512k align | ||
124 | unsigned timeout = 43000; // the timeout loop should be no less than 25ms | ||
125 | |||
126 | pBase[0x5555] = 0xAA; // enter command mode | ||
127 | pBase[0x2AAA] = 0x55; | ||
128 | pBase[0x5555] = 0x80; // eraze command | ||
129 | pBase[0x5555] = 0xAA; // enter command mode | ||
130 | pBase[0x2AAA] = 0x55; | ||
131 | *pAddr = 0x30; // eraze the sector | ||
132 | |||
133 | // I counted 7 instructions for this loop -> min. 0.58 us per round | ||
134 | // Plus memory waitstates it will be much more, gives margin | ||
135 | while (*pAddr != 0xFF && --timeout); // poll for erazed | ||
136 | |||
137 | return (timeout != 0); | ||
138 | } | ||
139 | |||
140 | // address must be in an erazed location | ||
141 | inline bool ProgramByte(volatile UINT8* pAddr, UINT8 data) | ||
142 | { | ||
143 | unsigned timeout = 35; // the timeout loop should be no less than 20us | ||
144 | |||
145 | if (~*pAddr & data) // just a safety feature, not really necessary | ||
146 | return false; // can't set any bit from 0 to 1 | ||
147 | |||
148 | FB[0x5555] = 0xAA; // enter command mode | ||
149 | FB[0x2AAA] = 0x55; | ||
150 | FB[0x5555] = 0xA0; // byte program command | ||
151 | |||
152 | *pAddr = data; | ||
153 | |||
154 | // I counted 7 instructions for this loop -> min. 0.58 us per round | ||
155 | // Plus memory waitstates it will be much more, gives margin | ||
156 | while (*pAddr != data && --timeout); // poll for programmed | ||
157 | |||
158 | return (timeout != 0); | ||
159 | } | ||
160 | |||
161 | // this returns true if supported and fills the info struct | ||
162 | bool GetFlashInfo(tFlashInfo* pInfo) | ||
163 | { | ||
164 | rb->memset(pInfo, 0, sizeof(tFlashInfo)); | ||
165 | |||
166 | if (!ReadID(FB, &pInfo->manufacturer, &pInfo->id)) | ||
167 | return false; | ||
168 | |||
169 | if (pInfo->manufacturer == 0xBF) // SST | ||
170 | { | ||
171 | if (pInfo->id == 0xD6) | ||
172 | { | ||
173 | pInfo->size = 256* 1024; // 256k | ||
174 | rb->strcpy(pInfo->name, "SST39VF020"); | ||
175 | return true; | ||
176 | } | ||
177 | else if (pInfo->id == 0xD7) | ||
178 | { | ||
179 | pInfo->size = 512* 1024; // 512k | ||
180 | rb->strcpy(pInfo->name, "SST39VF040"); | ||
181 | return true; | ||
182 | } | ||
183 | else | ||
184 | return false; | ||
185 | } | ||
186 | return false; | ||
187 | } | ||
188 | |||
189 | |||
190 | /*********** Tool Functions ************/ | ||
191 | |||
192 | // place a 32 bit value into memory, big endian | ||
193 | void Write32(UINT8* pByte, UINT32 value) | ||
194 | { | ||
195 | pByte[0] = (UINT8)(value >> 24); | ||
196 | pByte[1] = (UINT8)(value >> 16); | ||
197 | pByte[2] = (UINT8)(value >> 8); | ||
198 | pByte[3] = (UINT8)(value); | ||
199 | } | ||
200 | |||
201 | // read a 32 bit value from memory, big endian | ||
202 | UINT32 Read32(UINT8* pByte) | ||
203 | { | ||
204 | UINT32 value = 0; | ||
205 | |||
206 | value |= (UINT32)pByte[0] << 24; | ||
207 | value |= (UINT32)pByte[1] << 16; | ||
208 | value |= (UINT32)pByte[2] << 8; | ||
209 | value |= (UINT32)pByte[3]; | ||
210 | |||
211 | return value; | ||
212 | } | ||
213 | |||
214 | |||
215 | // get the start address of the second image | ||
216 | tImageHeader* GetSecondImage(void) | ||
217 | { | ||
218 | tImageHeader* pImage1; | ||
219 | UINT32 pos = 0; // dafault: not found | ||
220 | UINT32* pFlash = (UINT32*)FB; | ||
221 | |||
222 | UINT16 version = *(UINT16*)(FB + VERS_ADR); | ||
223 | if (version < 200) // at least 2.00 | ||
224 | { | ||
225 | return 0; // not our flash layout | ||
226 | } | ||
227 | |||
228 | // determine the first image position | ||
229 | pos = pFlash[2] + pFlash[3]; // position + size of the bootloader = after it | ||
230 | pos = (pos + 3) & ~3; // be shure it's 32 bit aligned | ||
231 | pImage1 = (tImageHeader*)pos; | ||
232 | |||
233 | if (pImage1->destination != ROCKBOX_DEST || pImage1->execute != ROCKBOX_EXEC) | ||
234 | return 0; // seems to be no Rockbox stuff in here | ||
235 | |||
236 | if (pImage1->size != 0) | ||
237 | { // success, we have a second image | ||
238 | pos = (UINT32)pImage1 + sizeof(tImageHeader) + pImage1->size; | ||
239 | if (((pos + SECTORSIZE-1) & ~(SECTORSIZE-1)) != pos) | ||
240 | { // not sector-aligned | ||
241 | pos = 0; // sanity check failed | ||
242 | } | ||
243 | } | ||
244 | |||
245 | return (tImageHeader*)pos; | ||
246 | } | ||
247 | |||
248 | |||
249 | /*********** Image File Functions ************/ | ||
250 | |||
251 | // so far, only compressed images in UCL NRV algorithm 2e supported | ||
252 | tCheckResult CheckImageFile(char* filename, int space, tImageHeader* pHeader) | ||
253 | { | ||
254 | int i; | ||
255 | int fd; | ||
256 | int filesize; // size info | ||
257 | |||
258 | int fileread = 0; // total size as read from the file | ||
259 | int read; // how many for this sector | ||
260 | |||
261 | // magic file header for compressed files | ||
262 | static const UINT8 magic[8] = { 0x00,0xe9,0x55,0x43,0x4c,0xff,0x01,0x1a }; | ||
263 | UINT8 ucl_header[UCL_HEADER]; | ||
264 | |||
265 | fd = rb->open(filename, O_RDONLY); | ||
266 | if (fd < 0) | ||
267 | return eFileNotFound; | ||
268 | |||
269 | filesize = rb->filesize(fd); | ||
270 | if (filesize - (int)sizeof(ucl_header) - 8 > space) | ||
271 | { | ||
272 | rb->close(fd); | ||
273 | return eTooBig; | ||
274 | } | ||
275 | else if (filesize < 50000) // give it some reasonable lower limit | ||
276 | { | ||
277 | rb->close(fd); | ||
278 | return eTooSmall; | ||
279 | } | ||
280 | |||
281 | // do some sanity checks | ||
282 | |||
283 | read = rb->read(fd, ucl_header, sizeof(ucl_header)); | ||
284 | fileread += read; | ||
285 | if (read != sizeof(ucl_header)) | ||
286 | { | ||
287 | rb->close(fd); | ||
288 | return eReadErr; | ||
289 | } | ||
290 | |||
291 | // compare the magic header | ||
292 | for (i=0; i<8; i++) | ||
293 | { | ||
294 | if (ucl_header[i] != magic[i]) | ||
295 | { | ||
296 | rb->close(fd); | ||
297 | return eNotUCL; | ||
298 | } | ||
299 | } | ||
300 | |||
301 | // check for supported algorithm | ||
302 | if (ucl_header[12] != 0x2E) | ||
303 | { | ||
304 | rb->close(fd); | ||
305 | return eWrongAlgorithm; | ||
306 | } | ||
307 | |||
308 | pHeader->size = Read32(ucl_header + 22); // compressed size | ||
309 | if (pHeader->size != filesize - sizeof(ucl_header) - 8) | ||
310 | { | ||
311 | rb->close(fd); | ||
312 | return eMultiBlocks; | ||
313 | } | ||
314 | |||
315 | if (Read32(ucl_header + 18) > pHeader->size) // compare with uncompressed size | ||
316 | { // normal case | ||
317 | pHeader->flags = 0x00000001; // flags for UCL compressed | ||
318 | } | ||
319 | else | ||
320 | { | ||
321 | pHeader->flags = 0x00000000; // very unlikely, content was not compressible | ||
322 | } | ||
323 | |||
324 | // check if we can read the whole file | ||
325 | do | ||
326 | { | ||
327 | read = rb->read(fd, sector, SEC_SIZE); | ||
328 | fileread += read; | ||
329 | } while (read == SEC_SIZE); | ||
330 | |||
331 | rb->close(fd); | ||
332 | |||
333 | if (fileread != filesize) | ||
334 | return eReadErr; | ||
335 | |||
336 | // fill in the hardcoded rest of the header | ||
337 | pHeader->destination = ROCKBOX_DEST; | ||
338 | pHeader->execute = ROCKBOX_EXEC; | ||
339 | |||
340 | return eOK; | ||
341 | } | ||
342 | |||
343 | |||
344 | // returns the # of failures, 0 on success | ||
345 | unsigned ProgramImageFile(char* filename, UINT8* pos, tImageHeader* pImageHeader, int start, int size) | ||
346 | { | ||
347 | int i; | ||
348 | int fd; | ||
349 | int read; // how many for this sector | ||
350 | unsigned failures = 0; | ||
351 | |||
352 | fd = rb->open(filename, O_RDONLY); | ||
353 | if (fd < 0) | ||
354 | return false; | ||
355 | |||
356 | // no error checking necessary here, we checked for minimum size already | ||
357 | rb->lseek(fd, start, SEEK_SET); // go to start position | ||
358 | |||
359 | *(tImageHeader*)sector = *pImageHeader; // copy header into sector buffer | ||
360 | read = rb->read(fd, sector + sizeof(tImageHeader), SEC_SIZE - sizeof(tImageHeader)); // payload behind | ||
361 | size -= read; | ||
362 | read += sizeof(tImageHeader); // to be programmed, but not part of the file | ||
363 | |||
364 | do | ||
365 | { | ||
366 | if (!ErazeSector(pos)) | ||
367 | { | ||
368 | // nothing we can do, let the programming count the errors | ||
369 | } | ||
370 | |||
371 | for (i=0; i<read; i++) | ||
372 | { | ||
373 | if (!ProgramByte(pos + i, sector[i])) | ||
374 | { | ||
375 | failures++; | ||
376 | } | ||
377 | } | ||
378 | |||
379 | pos += SEC_SIZE; | ||
380 | read = rb->read(fd, sector, (size > SEC_SIZE) ? SEC_SIZE : size); // payload for next sector | ||
381 | size -= read; | ||
382 | } while (read > 0); | ||
383 | |||
384 | rb->close(fd); | ||
385 | |||
386 | return failures; | ||
387 | } | ||
388 | |||
389 | // returns the # of failures, 0 on success | ||
390 | unsigned VerifyImageFile(char* filename, UINT8* pos, tImageHeader* pImageHeader, int start, int size) | ||
391 | { | ||
392 | int i; | ||
393 | int fd; | ||
394 | int read; // how many for this sector | ||
395 | unsigned failures = 0; | ||
396 | |||
397 | fd = rb->open(filename, O_RDONLY); | ||
398 | if (fd < 0) | ||
399 | return false; | ||
400 | |||
401 | // no error checking necessary here, we checked for minimum size already | ||
402 | rb->lseek(fd, start, SEEK_SET); // go to start position | ||
403 | |||
404 | *(tImageHeader*)sector = *pImageHeader; // copy header into sector buffer | ||
405 | read = rb->read(fd, sector + sizeof(tImageHeader), SEC_SIZE - sizeof(tImageHeader)); // payload behind | ||
406 | size -= read; | ||
407 | read += sizeof(tImageHeader); // to be programmed, but not part of the file | ||
408 | |||
409 | do | ||
410 | { | ||
411 | for (i=0; i<read; i++) | ||
412 | { | ||
413 | if (pos[i] != sector[i]) | ||
414 | { | ||
415 | failures++; | ||
416 | } | ||
417 | } | ||
418 | |||
419 | pos += SEC_SIZE; | ||
420 | read = rb->read(fd, sector, (size > SEC_SIZE) ? SEC_SIZE : size); // payload for next sector | ||
421 | size -= read; | ||
422 | } while (read); | ||
423 | |||
424 | rb->close(fd); | ||
425 | |||
426 | return failures; | ||
427 | } | ||
428 | |||
429 | |||
430 | /***************** User Interface Functions *****************/ | ||
431 | /* (to be changed for Player) */ | ||
432 | |||
433 | #ifdef HAVE_LCD_BITMAP | ||
434 | |||
435 | // helper for DoUserDialog() | ||
436 | void ShowFlashInfo(tFlashInfo* pInfo, tImageHeader* pImageHeader) | ||
437 | { | ||
438 | char buf[32]; | ||
439 | |||
440 | if (!pInfo->manufacturer) | ||
441 | { | ||
442 | rb->lcd_puts(0, 0, "Flash: M=?? D=??"); | ||
443 | } | ||
444 | else | ||
445 | { | ||
446 | if (pInfo->size) | ||
447 | { | ||
448 | rb->snprintf(buf, sizeof(buf), "Flash size: %d KB", pInfo->size / 1024); | ||
449 | rb->lcd_puts(0, 0, buf); | ||
450 | } | ||
451 | else | ||
452 | { | ||
453 | rb->lcd_puts(0, 0, "Unsupported chip"); | ||
454 | } | ||
455 | |||
456 | } | ||
457 | |||
458 | if (pImageHeader) | ||
459 | { | ||
460 | rb->snprintf(buf, sizeof(buf), "Image at %d KB", ((UINT8*)pImageHeader - FB) / 1024); | ||
461 | rb->lcd_puts(0, 1, buf); | ||
462 | } | ||
463 | else | ||
464 | { | ||
465 | rb->lcd_puts(0, 1, "No image found!"); | ||
466 | } | ||
467 | |||
468 | rb->lcd_update(); | ||
469 | } | ||
470 | |||
471 | |||
472 | // Kind of our main function, defines the application flow. | ||
473 | void DoUserDialog(void) | ||
474 | { | ||
475 | tImageHeader ImageHeader; | ||
476 | tFlashInfo FlashInfo; | ||
477 | char buf[32]; | ||
478 | int button; | ||
479 | int rc; // generic return code | ||
480 | UINT32 space, aligned_size, true_size; | ||
481 | UINT8* pos; | ||
482 | |||
483 | rb->lcd_setfont(FONT_SYSFIXED); | ||
484 | |||
485 | pos = (void*)GetSecondImage(); | ||
486 | rc = GetFlashInfo(&FlashInfo); | ||
487 | |||
488 | ShowFlashInfo(&FlashInfo, (void*)pos); | ||
489 | if (FlashInfo.size == 0) // no valid chip | ||
490 | { | ||
491 | rb->splash(HZ*3, 0, true, "Not flashable"); | ||
492 | return; // exit | ||
493 | } | ||
494 | else if (pos == 0) | ||
495 | { | ||
496 | rb->splash(HZ*3, 0, true, "No Image"); | ||
497 | return; // exit | ||
498 | } | ||
499 | |||
500 | rb->lcd_puts(0, 3, "using file:"); | ||
501 | rb->lcd_puts(0, 4, FILENAME); | ||
502 | rb->lcd_puts(0, 6, "[F1] to check file"); | ||
503 | rb->lcd_puts(0, 7, "other key to exit"); | ||
504 | rb->lcd_update(); | ||
505 | |||
506 | button = rb->button_get(true); | ||
507 | button = rb->button_get(true); | ||
508 | |||
509 | if (button != BUTTON_F1) | ||
510 | { | ||
511 | return; | ||
512 | } | ||
513 | |||
514 | rb->lcd_clear_display(); | ||
515 | rb->lcd_puts(0, 0, "checking..."); | ||
516 | rb->lcd_update(); | ||
517 | |||
518 | space = FlashInfo.size - (pos-FB + sizeof(ImageHeader)); // size minus start | ||
519 | rc = CheckImageFile(FILENAME, space, &ImageHeader); | ||
520 | rb->lcd_puts(0, 0, "checked:"); | ||
521 | switch (rc) | ||
522 | { | ||
523 | case eOK: | ||
524 | rb->lcd_puts(0, 1, "File OK."); | ||
525 | break; | ||
526 | case eNotUCL: | ||
527 | rb->lcd_puts(0, 1, "File not UCL "); | ||
528 | rb->lcd_puts(0, 2, "compressed."); | ||
529 | rb->lcd_puts(0, 3, "Use uclpack --2e"); | ||
530 | rb->lcd_puts(0, 4, " --10 rockbox.bin"); | ||
531 | break; | ||
532 | case eWrongAlgorithm: | ||
533 | rb->lcd_puts(0, 1, "Wrong algorithm"); | ||
534 | rb->lcd_puts(0, 2, "for compression."); | ||
535 | rb->lcd_puts(0, 3, "Use uclpack --2e"); | ||
536 | rb->lcd_puts(0, 4, " --10 rockbox.bin"); | ||
537 | break; | ||
538 | case eFileNotFound: | ||
539 | rb->lcd_puts(0, 1, "File not found."); | ||
540 | rb->lcd_puts(0, 2, "Put this in root:"); | ||
541 | rb->lcd_puts(0, 4, FILENAME); | ||
542 | break; | ||
543 | case eTooBig: | ||
544 | rb->lcd_puts(0, 1, "File too big,"); | ||
545 | rb->lcd_puts(0, 2, "won't fit in chip."); | ||
546 | break; | ||
547 | case eTooSmall: | ||
548 | rb->lcd_puts(0, 1, "File too small."); | ||
549 | rb->lcd_puts(0, 2, "Incomplete?"); | ||
550 | break; | ||
551 | case eReadErr: | ||
552 | rb->lcd_puts(0, 1, "File read error."); | ||
553 | break; | ||
554 | case eMultiBlocks: | ||
555 | rb->lcd_puts(0, 1, "File invalid."); | ||
556 | rb->lcd_puts(0, 2, "Blocksize"); | ||
557 | rb->lcd_puts(0, 3, " too small?"); | ||
558 | break; | ||
559 | default: | ||
560 | rb->lcd_puts(0, 1, "Check failed."); | ||
561 | break; | ||
562 | } | ||
563 | |||
564 | if (rc == eOK) | ||
565 | { // was OK | ||
566 | rb->lcd_puts(0, 6, "[F2] to program"); | ||
567 | rb->lcd_puts(0, 7, "other key to exit"); | ||
568 | } | ||
569 | else | ||
570 | { // error occured | ||
571 | rb->lcd_puts(0, 6, "Any key to exit"); | ||
572 | } | ||
573 | |||
574 | rb->lcd_update(); | ||
575 | |||
576 | button = rb->button_get(true); | ||
577 | button = rb->button_get(true); | ||
578 | |||
579 | if (button != BUTTON_F2) | ||
580 | { | ||
581 | return; | ||
582 | } | ||
583 | |||
584 | true_size = ImageHeader.size; | ||
585 | aligned_size = ((sizeof(tImageHeader) + true_size + SECTORSIZE-1) & ~(SECTORSIZE-1)) - sizeof(tImageHeader); // round up to next flash sector | ||
586 | ImageHeader.size = aligned_size; // increase image size such that we reach the next sector | ||
587 | |||
588 | rb->lcd_clear_display(); | ||
589 | rb->lcd_puts(0, 0, "Programming..."); | ||
590 | rb->lcd_update(); | ||
591 | |||
592 | rc = ProgramImageFile(FILENAME, pos, &ImageHeader, UCL_HEADER, true_size); | ||
593 | if (rc) | ||
594 | { // errors | ||
595 | rb->lcd_clear_display(); | ||
596 | rb->lcd_puts(0, 0, "Error:"); | ||
597 | rb->lcd_puts(0, 1, "Programming fail!"); | ||
598 | rb->snprintf(buf, sizeof(buf), "%d errors", rc); | ||
599 | rb->lcd_puts(0, 2, buf); | ||
600 | rb->lcd_update(); | ||
601 | button = rb->button_get(true); | ||
602 | button = rb->button_get(true); | ||
603 | } | ||
604 | |||
605 | rb->lcd_clear_display(); | ||
606 | rb->lcd_puts(0, 0, "Verifying..."); | ||
607 | rb->lcd_update(); | ||
608 | |||
609 | rc = VerifyImageFile(FILENAME, pos, &ImageHeader, UCL_HEADER, true_size); | ||
610 | |||
611 | rb->lcd_clear_display(); | ||
612 | if (rc == 0) | ||
613 | { | ||
614 | rb->lcd_puts(0, 0, "Verify OK."); | ||
615 | } | ||
616 | else | ||
617 | { | ||
618 | rb->lcd_puts(0, 0, "Error:"); | ||
619 | rb->lcd_puts(0, 1, "Verify fail!"); | ||
620 | rb->snprintf(buf, sizeof(buf), "%d errors", rc); | ||
621 | rb->lcd_puts(0, 2, buf); | ||
622 | rb->lcd_puts(0, 3, "Use safe image"); | ||
623 | rb->lcd_puts(0, 4, "if booting hangs:"); | ||
624 | rb->lcd_puts(0, 5, "F1 during power-on"); | ||
625 | } | ||
626 | rb->lcd_puts(0, 7, "Any key to exit"); | ||
627 | rb->lcd_update(); | ||
628 | |||
629 | button = rb->button_get(true); | ||
630 | button = rb->button_get(true); | ||
631 | } | ||
632 | |||
633 | #else // HAVE_LCD_BITMAP | ||
634 | |||
635 | // Player implementation has to go here | ||
636 | void DoUserDialog(void) | ||
637 | { | ||
638 | } | ||
639 | |||
640 | #endif // HAVE_LCD_BITMAP | ||
641 | |||
642 | |||
643 | /***************** Plugin Entry Point *****************/ | ||
644 | |||
645 | enum plugin_status plugin_start(struct plugin_api* api, void* parameter) | ||
646 | { | ||
647 | |||
648 | |||
649 | /* this macro should be called as the first thing you do in the plugin. | ||
650 | it test that the api version and model the plugin was compiled for | ||
651 | matches the machine it is running on */ | ||
652 | TEST_PLUGIN_API(api); | ||
653 | |||
654 | /* if you don't use the parameter, you can do like | ||
655 | this to avoid the compiler warning about it */ | ||
656 | (void)parameter; | ||
657 | |||
658 | rb = api; /* copy to global api pointer */ | ||
659 | |||
660 | /* now go ahead and have fun! */ | ||
661 | DoUserDialog(); | ||
662 | |||
663 | return PLUGIN_OK; | ||
664 | } | ||