diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/plugins/iriver_flash.c | 569 |
1 files changed, 569 insertions, 0 deletions
diff --git a/apps/plugins/iriver_flash.c b/apps/plugins/iriver_flash.c new file mode 100644 index 0000000000..28734d197b --- /dev/null +++ b/apps/plugins/iriver_flash.c | |||
@@ -0,0 +1,569 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * !!! DON'T MESS WITH THIS CODE UNLESS YOU'RE ABSOLUTELY SURE WHAT YOU DO !!! | ||
11 | * | ||
12 | * Copyright (C) 2006 by Miika Pekkarinen | ||
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 | /* All CFI flash routines are copied and ported from firmware_flash.c */ | ||
24 | |||
25 | #ifndef SIMULATOR /* only for target */ | ||
26 | |||
27 | unsigned char *audiobuf; | ||
28 | int audiobuf_size; | ||
29 | |||
30 | #if defined(IRIVER_H120) | ||
31 | #define PLATFORM_ID ID_IRIVER_H100 | ||
32 | #else | ||
33 | #undef PLATFORM_ID /* this platform is not (yet) flashable */ | ||
34 | #endif | ||
35 | |||
36 | #ifdef PLATFORM_ID | ||
37 | |||
38 | PLUGIN_HEADER | ||
39 | |||
40 | #if CONFIG_KEYPAD == IRIVER_H100_PAD | ||
41 | #define KEY1 BUTTON_OFF | ||
42 | #define KEY2 BUTTON_ON | ||
43 | #define KEY3 BUTTON_SELECT | ||
44 | #define KEYNAME1 "[Stop]" | ||
45 | #define KEYNAME2 "[On]" | ||
46 | #define KEYNAME3 "[Select]" | ||
47 | #endif | ||
48 | |||
49 | struct flash_info | ||
50 | { | ||
51 | uint8_t manufacturer; | ||
52 | uint8_t id; | ||
53 | int size; | ||
54 | char name[32]; | ||
55 | }; | ||
56 | |||
57 | static struct plugin_api* rb; /* here is a global api struct pointer */ | ||
58 | |||
59 | #ifdef IRIVER_H100_SERIES | ||
60 | #define SEC_SIZE 4096 | ||
61 | #define BOOTLOADER_ERASEGUARD (BOOTLOADER_ENTRYPOINT / SEC_SIZE - 1) | ||
62 | |||
63 | static volatile uint16_t* FB = (uint16_t*)0x00000000; /* Flash base address */ | ||
64 | #endif | ||
65 | |||
66 | /* read the manufacturer and device ID */ | ||
67 | bool cfi_read_id(volatile uint16_t* pBase, uint8_t* pManufacturerID, uint8_t* pDeviceID) | ||
68 | { | ||
69 | uint8_t not_manu, not_id; /* read values before switching to ID mode */ | ||
70 | uint8_t manu, id; /* read values when in ID mode */ | ||
71 | |||
72 | pBase = (uint16_t*)((uint32_t)pBase & 0xFFF80000); /* down to 512k align */ | ||
73 | |||
74 | /* read the normal content */ | ||
75 | not_manu = pBase[0]; /* should be 'A' (0x41) and 'R' (0x52) */ | ||
76 | not_id = pBase[1]; /* from the "ARCH" marker */ | ||
77 | |||
78 | pBase[0x5555] = 0xAA; /* enter command mode */ | ||
79 | pBase[0x2AAA] = 0x55; | ||
80 | pBase[0x5555] = 0x90; /* ID command */ | ||
81 | rb->sleep(HZ/50); /* Atmel wants 20ms pause here */ | ||
82 | |||
83 | manu = pBase[0]; | ||
84 | id = pBase[1]; | ||
85 | |||
86 | pBase[0] = 0xF0; /* reset flash (back to normal read mode) */ | ||
87 | rb->sleep(HZ/50); /* Atmel wants 20ms pause here */ | ||
88 | |||
89 | /* I assume success if the obtained values are different from | ||
90 | the normal flash content. This is not perfectly bulletproof, they | ||
91 | could theoretically be the same by chance, causing us to fail. */ | ||
92 | if (not_manu != manu || not_id != id) /* a value has changed */ | ||
93 | { | ||
94 | *pManufacturerID = manu; /* return the results */ | ||
95 | *pDeviceID = id; | ||
96 | return true; /* success */ | ||
97 | } | ||
98 | return false; /* fail */ | ||
99 | } | ||
100 | |||
101 | |||
102 | /* erase the sector which contains the given address */ | ||
103 | bool cfi_erase_sector(volatile uint16_t* pAddr) | ||
104 | { | ||
105 | unsigned timeout = 430000; /* the timeout loop should be no less than 25ms */ | ||
106 | |||
107 | FB[0x5555] = 0xAA; /* enter command mode */ | ||
108 | FB[0x2AAA] = 0x55; | ||
109 | FB[0x5555] = 0x80; /* erase command */ | ||
110 | FB[0x5555] = 0xAA; /* enter command mode */ | ||
111 | FB[0x2AAA] = 0x55; | ||
112 | *pAddr = 0x30; /* erase the sector */ | ||
113 | |||
114 | /* I counted 7 instructions for this loop -> min. 0.58 us per round */ | ||
115 | /* Plus memory waitstates it will be much more, gives margin */ | ||
116 | while (*pAddr != 0xFFFF && --timeout); /* poll for erased */ | ||
117 | |||
118 | return (timeout != 0); | ||
119 | } | ||
120 | |||
121 | |||
122 | /* address must be in an erased location */ | ||
123 | inline bool cfi_program_word(volatile uint16_t* pAddr, uint16_t data) | ||
124 | { | ||
125 | unsigned timeout = 85; /* the timeout loop should be no less than 20us */ | ||
126 | |||
127 | if (~*pAddr & data) /* just a safety feature, not really necessary */ | ||
128 | return false; /* can't set any bit from 0 to 1 */ | ||
129 | |||
130 | FB[0x5555] = 0xAA; /* enter command mode */ | ||
131 | FB[0x2AAA] = 0x55; | ||
132 | FB[0x5555] = 0xA0; /* byte program command */ | ||
133 | |||
134 | *pAddr = data; | ||
135 | |||
136 | /* I counted 7 instructions for this loop -> min. 0.58 us per round */ | ||
137 | /* Plus memory waitstates it will be much more, gives margin */ | ||
138 | while (*pAddr != data && --timeout); /* poll for programmed */ | ||
139 | |||
140 | return (timeout != 0); | ||
141 | } | ||
142 | |||
143 | |||
144 | /* this returns true if supported and fills the info struct */ | ||
145 | bool cfi_get_flash_info(struct flash_info* pInfo) | ||
146 | { | ||
147 | rb->memset(pInfo, 0, sizeof(struct flash_info)); | ||
148 | |||
149 | if (!cfi_read_id(FB, &pInfo->manufacturer, &pInfo->id)) | ||
150 | return false; | ||
151 | |||
152 | if (pInfo->manufacturer == 0xBF) /* SST */ | ||
153 | { | ||
154 | if (pInfo->id == 0xD6) | ||
155 | { | ||
156 | pInfo->size = 256* 1024; /* 256k */ | ||
157 | rb->strcpy(pInfo->name, "SST39VF020"); | ||
158 | return true; | ||
159 | } | ||
160 | else if (pInfo->id == 0xD7) | ||
161 | { | ||
162 | pInfo->size = 512* 1024; /* 512k */ | ||
163 | rb->strcpy(pInfo->name, "SST39VF040"); | ||
164 | return true; | ||
165 | } | ||
166 | else if (pInfo->id == 0x82) | ||
167 | { | ||
168 | pInfo->size = 2048* 1024; /* 2 MiB */ | ||
169 | rb->strcpy(pInfo->name, "SST39VF160"); | ||
170 | return true; | ||
171 | } | ||
172 | else | ||
173 | return false; | ||
174 | } | ||
175 | return false; | ||
176 | } | ||
177 | |||
178 | |||
179 | /*********** Utility Functions ************/ | ||
180 | |||
181 | |||
182 | /* Tool function to calculate a CRC32 across some buffer */ | ||
183 | /* third argument is either 0xFFFFFFFF to start or value from last piece */ | ||
184 | unsigned crc_32(unsigned char* buf, unsigned len, unsigned crc32) | ||
185 | { | ||
186 | /* CCITT standard polynomial 0x04C11DB7 */ | ||
187 | static const unsigned crc32_lookup[16] = | ||
188 | { /* lookup table for 4 bits at a time is affordable */ | ||
189 | 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, | ||
190 | 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005, | ||
191 | 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61, | ||
192 | 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD | ||
193 | }; | ||
194 | |||
195 | unsigned char byte; | ||
196 | unsigned t; | ||
197 | |||
198 | while (len--) | ||
199 | { | ||
200 | byte = *buf++; /* get one byte of data */ | ||
201 | |||
202 | /* upper nibble of our data */ | ||
203 | t = crc32 >> 28; /* extract the 4 most significant bits */ | ||
204 | t ^= byte >> 4; /* XOR in 4 bits of data into the extracted bits */ | ||
205 | crc32 <<= 4; /* shift the CRC register left 4 bits */ | ||
206 | crc32 ^= crc32_lookup[t]; /* do the table lookup and XOR the result */ | ||
207 | |||
208 | /* lower nibble of our data */ | ||
209 | t = crc32 >> 28; /* extract the 4 most significant bits */ | ||
210 | t ^= byte & 0x0F; /* XOR in 4 bits of data into the extracted bits */ | ||
211 | crc32 <<= 4; /* shift the CRC register left 4 bits */ | ||
212 | crc32 ^= crc32_lookup[t]; /* do the table lookup and XOR the result */ | ||
213 | } | ||
214 | |||
215 | return crc32; | ||
216 | } | ||
217 | |||
218 | |||
219 | /***************** User Interface Functions *****************/ | ||
220 | int WaitForButton(void) | ||
221 | { | ||
222 | int button; | ||
223 | |||
224 | do | ||
225 | { | ||
226 | button = rb->button_get(true); | ||
227 | } while (button & BUTTON_REL); | ||
228 | |||
229 | return button; | ||
230 | } | ||
231 | |||
232 | /* helper for DoUserDialog() */ | ||
233 | void ShowFlashInfo(struct flash_info* pInfo) | ||
234 | { | ||
235 | char buf[32]; | ||
236 | |||
237 | if (!pInfo->manufacturer) | ||
238 | { | ||
239 | rb->lcd_puts(0, 0, "Flash: M=?? D=??"); | ||
240 | rb->lcd_puts(0, 1, "Impossible to program"); | ||
241 | } | ||
242 | else | ||
243 | { | ||
244 | rb->snprintf(buf, sizeof(buf), "Flash: M=%02x D=%02x", | ||
245 | pInfo->manufacturer, pInfo->id); | ||
246 | rb->lcd_puts(0, 0, buf); | ||
247 | |||
248 | |||
249 | if (pInfo->size) | ||
250 | { | ||
251 | rb->lcd_puts(0, 1, pInfo->name); | ||
252 | rb->snprintf(buf, sizeof(buf), "Size: %d KB", pInfo->size / 1024); | ||
253 | rb->lcd_puts(0, 2, buf); | ||
254 | } | ||
255 | else | ||
256 | { | ||
257 | rb->lcd_puts(0, 1, "Unsupported chip"); | ||
258 | } | ||
259 | |||
260 | } | ||
261 | |||
262 | rb->lcd_update(); | ||
263 | } | ||
264 | |||
265 | int load_firmware_file(const char *filename, uint32_t *checksum) | ||
266 | { | ||
267 | int fd; | ||
268 | int len, rc; | ||
269 | int i; | ||
270 | uint32_t sum; | ||
271 | |||
272 | fd = rb->open(filename, O_RDONLY); | ||
273 | if (fd < 0) | ||
274 | return -1; | ||
275 | |||
276 | len = rb->filesize(fd); | ||
277 | |||
278 | if (audiobuf_size < len) | ||
279 | { | ||
280 | rb->splash(HZ*3, true, "Out of memory!"); | ||
281 | rb->close(fd); | ||
282 | return -2; | ||
283 | } | ||
284 | |||
285 | rb->read(fd, checksum, 4); | ||
286 | rb->lseek(fd, FIRMWARE_OFFSET_FILE_DATA, SEEK_SET); | ||
287 | len -= FIRMWARE_OFFSET_FILE_DATA; | ||
288 | |||
289 | rc = rb->read(fd, audiobuf, len); | ||
290 | rb->close(fd); | ||
291 | if (rc != len) | ||
292 | { | ||
293 | rb->splash(HZ*3, true, "Read failure"); | ||
294 | return -3; | ||
295 | } | ||
296 | |||
297 | /* Verify the checksum */ | ||
298 | sum = 0; | ||
299 | for (i = 0; i < len; i++) | ||
300 | sum += audiobuf[i]; | ||
301 | |||
302 | if (sum != *checksum) | ||
303 | { | ||
304 | rb->splash(HZ*3, true, "Checksums mismatch!"); | ||
305 | return -4; | ||
306 | } | ||
307 | |||
308 | return len; | ||
309 | } | ||
310 | |||
311 | int flash_rockbox(const char *filename) | ||
312 | { | ||
313 | struct flash_header hdr; | ||
314 | char buf[32]; | ||
315 | int pos, i, len, rc; | ||
316 | unsigned long checksum, sum; | ||
317 | unsigned char *p8; | ||
318 | uint16_t *p16; | ||
319 | |||
320 | len = load_firmware_file(filename, &checksum); | ||
321 | if (len < 0) | ||
322 | return len * 10; | ||
323 | |||
324 | /* Erase the program flash. */ | ||
325 | for (i = 1; i < BOOTLOADER_ERASEGUARD && (i-1)*4096 < len + 32; i++) | ||
326 | { | ||
327 | rc = cfi_erase_sector(FB + (SEC_SIZE/2) * i); | ||
328 | rb->snprintf(buf, sizeof(buf), "Erase: 0x%03x (%d)", i, rc); | ||
329 | rb->lcd_puts(0, 3, buf); | ||
330 | rb->lcd_update(); | ||
331 | } | ||
332 | |||
333 | /* Write the magic and size. */ | ||
334 | rb->memset(&hdr, 0, sizeof(struct flash_header)); | ||
335 | hdr.magic = FLASH_MAGIC; | ||
336 | hdr.length = len; | ||
337 | // rb->strncpy(hdr.version, APPSVERSION, sizeof(hdr.version)-1); | ||
338 | p16 = (uint16_t *)&hdr; | ||
339 | |||
340 | rb->snprintf(buf, sizeof(buf), "Programming"); | ||
341 | rb->lcd_puts(0, 4, buf); | ||
342 | rb->lcd_update(); | ||
343 | |||
344 | pos = FLASH_ENTRYPOINT/2; | ||
345 | for (i = 0; i < (long)sizeof(struct flash_header)/2; i++) | ||
346 | { | ||
347 | cfi_program_word(FB + pos, p16[i]); | ||
348 | pos++; | ||
349 | } | ||
350 | |||
351 | p16 = (uint16_t *)audiobuf; | ||
352 | for (i = 0; i < len/2 && pos < (BOOTLOADER_ENTRYPOINT/2); i++) | ||
353 | cfi_program_word(FB + pos + i, p16[i]); | ||
354 | |||
355 | /* Verify */ | ||
356 | p8 = (char *)FLASH_ENTRYPOINT; | ||
357 | p8 += sizeof(struct flash_header); | ||
358 | sum = 0; | ||
359 | for (i = 0; i < len; i++) | ||
360 | sum += p8[i]; | ||
361 | |||
362 | if (sum != checksum) | ||
363 | { | ||
364 | rb->splash(HZ*3, true, "Verify failed!"); | ||
365 | /* Erase the magic sector so bootloader does not try to load | ||
366 | * rockbox from flash and crash. */ | ||
367 | cfi_erase_sector(FB + SEC_SIZE/2); | ||
368 | return -5; | ||
369 | } | ||
370 | |||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | void show_fatal_error(void) | ||
375 | { | ||
376 | rb->splash(HZ*30, true, "Disable idle poweroff, connect AC power and DON'T TURN PLAYER OFF!!"); | ||
377 | rb->splash(HZ*30, true, "Contact Rockbox developers as soon as possible!"); | ||
378 | rb->splash(HZ*30, true, "Your device won't be bricked unless you turn off the power"); | ||
379 | rb->splash(HZ*30, true, "Don't use the device before further instructions from Rockbox developers"); | ||
380 | } | ||
381 | |||
382 | int flash_bootloader(const char *filename) | ||
383 | { | ||
384 | // char buf[32]; | ||
385 | int pos, i, len, rc; | ||
386 | unsigned long checksum, sum, crc32; | ||
387 | unsigned char *p8; | ||
388 | uint16_t *p16; | ||
389 | |||
390 | len = load_firmware_file(filename, &checksum); | ||
391 | if (len < 0) | ||
392 | return len * 10; | ||
393 | |||
394 | if (len > 0xFFFF) | ||
395 | { | ||
396 | rb->splash(HZ*3, true, "Too big bootloader"); | ||
397 | return -1; | ||
398 | } | ||
399 | |||
400 | /* Verify the crc32 checksum also. */ | ||
401 | crc32 = crc_32(audiobuf, len, 0xffffffff); | ||
402 | // rb->snprintf(buf, sizeof buf, "crc32 = 0x%08x", crc32); | ||
403 | // rb->splash(HZ*10, true, buf); | ||
404 | |||
405 | if (crc32 != 0x5361a679) | ||
406 | { | ||
407 | rb->splash(HZ*3, true, "Untested bootloader"); | ||
408 | return -2; | ||
409 | } | ||
410 | |||
411 | rb->lcd_puts(0, 3, "Processing critical sections..."); | ||
412 | rb->lcd_update(); | ||
413 | |||
414 | /* Erase the boot sector and write a proper reset vector. */ | ||
415 | cfi_erase_sector(FB); | ||
416 | p16 = (uint16_t *)audiobuf; | ||
417 | for (i = 0; i < 4; i++) | ||
418 | cfi_program_word(FB + i, p16[i]); | ||
419 | |||
420 | /* Erase the bootloader flash section. */ | ||
421 | for (i = BOOTLOADER_ENTRYPOINT/SEC_SIZE; i < 0x200; i++) | ||
422 | rc = cfi_erase_sector(FB + (SEC_SIZE/2) * i); | ||
423 | |||
424 | pos = BOOTLOADER_ENTRYPOINT/2; | ||
425 | p16 = (uint16_t *)audiobuf; | ||
426 | for (i = 0; i < len/2; i++) | ||
427 | cfi_program_word(FB + pos + i, p16[i]); | ||
428 | |||
429 | /* Verify */ | ||
430 | p8 = (char *)BOOTLOADER_ENTRYPOINT; | ||
431 | sum = 0; | ||
432 | for (i = 0; i < len; i++) | ||
433 | sum += p8[i]; | ||
434 | |||
435 | if (sum != checksum) | ||
436 | { | ||
437 | rb->splash(HZ*3, true, "Verify failed!"); | ||
438 | show_fatal_error(); | ||
439 | return -5; | ||
440 | } | ||
441 | |||
442 | p8 = (char *)FB; | ||
443 | for (i = 0; i < 8; i++) | ||
444 | { | ||
445 | if (p8[i] != audiobuf[i]) | ||
446 | { | ||
447 | rb->splash(HZ*3, true, "Bootvector corrupt!"); | ||
448 | show_fatal_error(); | ||
449 | break; | ||
450 | } | ||
451 | } | ||
452 | |||
453 | return 0; | ||
454 | } | ||
455 | |||
456 | /* Kind of our main function, defines the application flow. */ | ||
457 | void DoUserDialog(char* filename) | ||
458 | { | ||
459 | struct flash_info fi; | ||
460 | int rc; /* generic return code */ | ||
461 | |||
462 | /* this can only work if Rockbox runs in DRAM, not flash ROM */ | ||
463 | if ((uint16_t*)rb >= FB && (uint16_t*)rb < FB + 4096*1024) /* 4 MB max */ | ||
464 | { /* we're running from flash */ | ||
465 | rb->splash(HZ*3, true, "Not from ROM"); | ||
466 | return; /* exit */ | ||
467 | } | ||
468 | |||
469 | /* refuse to work if the power may fail meanwhile */ | ||
470 | if (!rb->battery_level_safe()) | ||
471 | { | ||
472 | rb->splash(HZ*3, true, "Battery too low!"); | ||
473 | return; /* exit */ | ||
474 | } | ||
475 | |||
476 | rb->lcd_setfont(FONT_SYSFIXED); | ||
477 | |||
478 | rc = cfi_get_flash_info(&fi); | ||
479 | ShowFlashInfo(&fi); | ||
480 | if (fi.size == 0) /* no valid chip */ | ||
481 | { | ||
482 | rb->splash(HZ*3, true, "Sorry!"); | ||
483 | return; /* exit */ | ||
484 | } | ||
485 | |||
486 | /* Debug? */ | ||
487 | #if 0 | ||
488 | rb->memcpy(&hdr, (uint8_t *)(FLASH_ENTRYPOINT), sizeof(struct flash_header)); | ||
489 | rb->snprintf(buf, sizeof(buf), "Magic: 0x%03x", hdr.magic); | ||
490 | rb->lcd_puts(0, 3, buf); | ||
491 | rb->snprintf(buf, sizeof(buf), "Size: 0x%03x", hdr.length); | ||
492 | rb->lcd_puts(0, 4, buf); | ||
493 | rb->lcd_update(); | ||
494 | rb->sleep(HZ*10); | ||
495 | |||
496 | rb->memcpy(&hdr, (uint8_t *)(FLASH_ENTRYPOINT/2), sizeof(struct flash_header)); | ||
497 | rb->snprintf(buf, sizeof(buf), "Magic: 0x%03x", hdr.magic); | ||
498 | rb->lcd_puts(0, 3, buf); | ||
499 | rb->snprintf(buf, sizeof(buf), "Size: 0x%03x", hdr.length); | ||
500 | rb->lcd_puts(0, 4, buf); | ||
501 | rb->lcd_update(); | ||
502 | rb->sleep(HZ*10); | ||
503 | #endif | ||
504 | |||
505 | /* Restore? */ | ||
506 | #if 0 | ||
507 | fd = rb->open("/internal_rom_000000-1FFFFF.bin", O_RDONLY); | ||
508 | if (fd < 0) | ||
509 | return ; | ||
510 | len = rb->filesize(fd); | ||
511 | |||
512 | /* Erase the program flash. */ | ||
513 | for (i = 1; i < 0x1EF; i++) | ||
514 | { | ||
515 | rc = cfi_erase_sector(FB + (SEC_SIZE/2) * i); | ||
516 | rb->snprintf(buf, sizeof(buf), "Erase: 0x%03x (%d)", i, rc); | ||
517 | rb->lcd_puts(0, 3, buf); | ||
518 | rb->lcd_update(); | ||
519 | } | ||
520 | |||
521 | i = FLASH_ENTRYPOINT/2; | ||
522 | rb->lseek(fd, i*2, SEEK_SET); | ||
523 | len -= i*2 - 0xffff; | ||
524 | for (; len > 0 && i < (0x1F0000/2); i++) | ||
525 | { | ||
526 | rb->read(fd, bytes, 2); | ||
527 | cfi_program_word(FB + i, (bytes[0] << 8) | bytes[1]); | ||
528 | len -= 2; | ||
529 | } | ||
530 | |||
531 | rb->close(fd); | ||
532 | return ; | ||
533 | #endif | ||
534 | |||
535 | if (filename == NULL) | ||
536 | { | ||
537 | rb->splash(HZ*3, true, "Please use this plugin with \"Open with...\""); | ||
538 | return ; | ||
539 | } | ||
540 | |||
541 | audiobuf = rb->plugin_get_audio_buffer(&audiobuf_size); | ||
542 | |||
543 | if (rb->strcasestr(filename, "/rockbox.iriver")) | ||
544 | flash_rockbox(filename); | ||
545 | else if (rb->strcasestr(filename, "/bootloader.iriver")) | ||
546 | flash_bootloader(filename); | ||
547 | else | ||
548 | rb->splash(HZ*3, true, "Unknown file type"); | ||
549 | } | ||
550 | |||
551 | |||
552 | /***************** Plugin Entry Point *****************/ | ||
553 | |||
554 | enum plugin_status plugin_start(struct plugin_api* api, void* parameter) | ||
555 | { | ||
556 | int oldmode; | ||
557 | |||
558 | rb = api; /* copy to global api pointer */ | ||
559 | |||
560 | /* now go ahead and have fun! */ | ||
561 | oldmode = rb->system_memory_guard(MEMGUARD_NONE); /*disable memory guard */ | ||
562 | DoUserDialog((char*) parameter); | ||
563 | rb->system_memory_guard(oldmode); /* re-enable memory guard */ | ||
564 | |||
565 | return PLUGIN_OK; | ||
566 | } | ||
567 | |||
568 | #endif /* ifdef PLATFORM_ID */ | ||
569 | #endif /* #ifndef SIMULATOR */ | ||