A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
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) 2020 by James Buren (refactor + H300 support)
13 * Copyright (C) 2006 by Miika Pekkarinen (original + H100/H120 support)
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#include "lib/helper.h"
26#include "checksum.h"
27
28/*
29 * Flash commands may rely on null pointer dereferences to work correctly.
30 * Disable this feature of GCC that may interfere with proper code generation.
31 */
32#pragma GCC optimize "no-delete-null-pointer-checks"
33
34enum firmware
35{
36 FIRMWARE_ROCKBOX, /* all .iriver firmwares */
37 FIRMWARE_ROMDUMP, /* a debug romdump */
38 FIRMWARE_ORIGINAL, /* an unscrambled original firmware */
39};
40
41#define WORD_SIZE 2
42#define BOOT_VECTOR_SIZE 8
43#define BOOT_SECTOR_OFFSET 0
44#define FLASH_SECTOR_SIZE 4096
45#define BOOTLOADER_MAX_SIZE 65536
46#define BOOTLOADER_SECTORS (BOOTLOADER_MAX_SIZE / FLASH_SECTOR_SIZE)
47#define RAM_IMAGE_RAW_SIZE (FLASH_ROMIMAGE_ENTRY - FLASH_RAMIMAGE_ENTRY)
48#define RAM_IMAGE_MAX_SIZE (RAM_IMAGE_RAW_SIZE - sizeof(struct flash_header))
49#define RAM_IMAGE_SECTORS (RAM_IMAGE_RAW_SIZE / FLASH_SECTOR_SIZE)
50#define ROM_IMAGE_RAW_SIZE (BOOTLOADER_ENTRYPOINT - FLASH_ROMIMAGE_ENTRY)
51#define ROM_IMAGE_MAX_SIZE (ROM_IMAGE_RAW_SIZE - sizeof(struct flash_header))
52#define ROM_IMAGE_SECTORS (ROM_IMAGE_RAW_SIZE / FLASH_SECTOR_SIZE)
53#define ROM_IMAGE_RELOCATION (FLASH_ROMIMAGE_ENTRY + sizeof(struct flash_header))
54#define WHOLE_FIRMWARE_SECTORS (BOOTLOADER_ENTRYPOINT / FLASH_SECTOR_SIZE)
55#define FIRMWARE_OFFSET 544
56
57#if BOOTLOADER_ENTRYPOINT + BOOTLOADER_MAX_SIZE != FLASH_SIZE
58#error "Bootloader is not located at the end of flash."
59#endif
60
61#if FLASH_ROMIMAGE_ENTRY < FLASH_RAMIMAGE_ENTRY
62#error "RAM image must be located before the ROM image."
63#endif
64
65#if BOOTLOADER_ENTRYPOINT < FLASH_ROMIMAGE_ENTRY
66#error "ROM image must be located before the bootloader."
67#endif
68
69#if FLASH_SIZE == 2048 * 1024
70#define ROMDUMP "/internal_rom_000000-1FFFFF.bin"
71#elif FLASH_SIZE == 4096 * 1024
72#define ROMDUMP "/internal_rom_000000-3FFFFF.bin"
73#endif
74
75#ifdef IRIVER_H100
76#define MODEL (const uint8_t[]) { 'h', '1', '0', '0' }
77#define ORIGINAL "/ihp_100.bin"
78#elif defined(IRIVER_H120)
79#define MODEL (const uint8_t[]) { 'h', '1', '2', '0' }
80#define ORIGINAL "/ihp_120.bin"
81#elif defined(IRIVER_H300)
82#define MODEL (const uint8_t[]) { 'h', '3', '0', '0' }
83#define ORIGINAL "/H300.bin"
84#else
85#error "Unsupported target."
86#endif
87
88struct flash_info
89{
90 uint16_t vendor;
91 uint16_t product;
92 uint32_t size;
93 char name[16];
94};
95
96/* checks if the region has a valid bootloader */
97static bool detect_valid_bootloader(const void* ptr, uint32_t size)
98{
99 static const struct
100 {
101 uint32_t size;
102 uint32_t crc32;
103 }
104 bootloaders[] =
105 {
106#ifdef IRIVER_H100
107 { 53556, 0x76541ebd }, /* 8 */
108#elif defined(IRIVER_H120)
109 { 53556, 0xd262b12b }, /* 8 */
110#elif defined(IRIVER_H300)
111 { 57048, 0x59ba2459 }, /* 8 */
112#endif
113 {0}
114 };
115
116 for (size_t i = 0; bootloaders[i].size != 0; i++)
117 {
118 uint32_t crc32;
119
120 if (size != 0 && size != bootloaders[i].size)
121 continue;
122
123 crc32 = rb->crc_32(ptr, bootloaders[i].size, 0xFFFFFFFF);
124 if (crc32 == bootloaders[i].crc32)
125 return true;
126 }
127
128 return false;
129}
130
131/* get read-only access to flash at the given offset */
132static const void* flash(uint32_t offset)
133{
134 const uint16_t* FB = (uint16_t*) FLASH_BASE;
135 return &FB[offset / WORD_SIZE];
136}
137
138/* queries the rom for information and returns it if it is known */
139static bool flash_get_info(const struct flash_info** out_info)
140{
141 static const struct flash_info roms[] =
142 {
143#if FLASH_SIZE == 2048 * 1024
144 { 0x00BF, 0x2782, 2048 * 1024, "SST39VF160" },
145#elif FLASH_SIZE == 4096 * 1024
146 { 0x00BF, 0x235B, 4096 * 1024, "SST39VF3201" },
147#else
148#error "Unsupported rom chip."
149#endif
150 {0}
151 };
152 static struct flash_info unknown_rom = {0};
153 volatile uint16_t* FB = (uint16_t*) FLASH_BASE;
154 uint16_t vendor;
155 uint16_t product;
156
157 /* execute the software ID entry command */
158 FB[0x5555] = 0xAA;
159 FB[0x2AAA] = 0x55;
160 FB[0x5555] = 0x90;
161 rb->sleep(HZ / 100);
162
163 /* copy the IDs from the previous command */
164 vendor = FB[0];
165 product = FB[1];
166
167 /* execute the software ID exit command */
168 FB[0x5555] = 0xAA;
169 FB[0x2AAA] = 0x55;
170 FB[0x5555] = 0xF0;
171 rb->sleep(HZ / 100);
172
173 /* search for a known match */
174 for (size_t i = 0; roms[i].size != 0; i++)
175 {
176 if (roms[i].vendor == vendor && roms[i].product == product)
177 {
178 *out_info = &roms[i];
179 return true;
180 }
181 }
182
183 /* return only the vendor / product ids if unknown */
184 unknown_rom.vendor = vendor;
185 unknown_rom.product = product;
186 *out_info = &unknown_rom;
187 return false;
188}
189
190/* wait until the rom signals completion of an operation */
191static bool flash_wait_for_rom(uint32_t offset)
192{
193 const size_t MAX_TIMEOUT = 0xFFFFFF; /* should be sufficient for most targets */
194 const size_t RECOVERY_TIME = 64; /* based on 140MHz MCF 5249 */
195 volatile uint16_t* FB = (uint16_t*) FLASH_BASE;
196 uint16_t old_data = FB[offset / WORD_SIZE] & 0x0040; /* we only want DQ6 */
197 volatile size_t i; /* disables certain optimizations */
198 bool result;
199
200 /* repeat up to MAX_TIMEOUT times or until DQ6 stops flipping */
201 for (i = 0; i < MAX_TIMEOUT; i++)
202 {
203 uint16_t new_data = FB[offset / WORD_SIZE] & 0x0040; /* we only want DQ6 */
204 if (old_data == new_data)
205 break;
206 old_data = new_data;
207 }
208
209 result = i != MAX_TIMEOUT;
210
211 /* delay at least 1us to give the bus time to recover */
212 for (i = 0; i < RECOVERY_TIME; i++);
213
214 return result;
215}
216
217/* erase the sector at the given offset */
218static bool flash_erase_sector(uint32_t offset)
219{
220 volatile uint16_t* FB = (uint16_t*) FLASH_BASE;
221
222 /* execute the sector erase command */
223 FB[0x5555] = 0xAA;
224 FB[0x2AAA] = 0x55;
225 FB[0x5555] = 0x80;
226 FB[0x5555] = 0xAA;
227 FB[0x2AAA] = 0x55;
228 FB[offset / WORD_SIZE] = 0x30;
229
230 return flash_wait_for_rom(offset);
231}
232
233/* program a word at the given offset */
234static bool flash_program_word(uint32_t offset, uint16_t word)
235{
236 volatile uint16_t* FB = (uint16_t*) FLASH_BASE;
237
238 /* execute the word program command */
239 FB[0x5555] = 0xAA;
240 FB[0x2AAA] = 0x55;
241 FB[0x5555] = 0xA0;
242 FB[offset / WORD_SIZE] = word;
243
244 return flash_wait_for_rom(offset);
245}
246
247/* bulk erase of adjacent sectors */
248static void flash_erase_sectors(uint32_t offset, uint32_t sectors,
249 bool progress)
250{
251 for (uint32_t i = 0; i < sectors; i++)
252 {
253 flash_erase_sector(offset + i * FLASH_SECTOR_SIZE);
254
255 /* display a progress report if requested */
256 if (progress)
257 {
258 rb->lcd_putsf(0, 3, "Erasing... %u%%", (i + 1) * 100 / sectors);
259 rb->lcd_update();
260 }
261 }
262}
263
264/* bulk program of bytes */
265static void flash_program_bytes(uint32_t offset, const void* ptr,
266 uint32_t len, bool progress)
267{
268 const uint8_t* data = ptr;
269
270 for (uint32_t i = 0; i < len; i += WORD_SIZE)
271 {
272 uint32_t j = i + 1;
273 uint32_t k = ((j < len) ? j : i) + 1;
274 uint16_t word = (data[i] << 8) | (j < len ? data[j] : 0xFF);
275
276 flash_program_word(offset + i, word);
277
278 /* display a progress report if requested */
279 if (progress && ((i % FLASH_SECTOR_SIZE) == 0 || k == len))
280 {
281 rb->lcd_putsf(0, 4, "Programming... %u%%", k * 100 / len);
282 rb->lcd_update();
283 }
284 }
285}
286
287/* bulk verify of programmed bytes */
288static bool flash_verify_bytes(uint32_t offset, const void* ptr,
289 uint32_t len, bool progress)
290{
291 const uint8_t* FB = flash(offset);
292 const uint8_t* data = ptr;
293
294 /* don't use memcmp so we can provide progress updates */
295 for (uint32_t i = 0; i < len; i++)
296 {
297 uint32_t j = i + 1;
298
299 if (FB[i] != data[i])
300 return false;
301
302 /* display a progress report if requested */
303 if (progress && ((i % FLASH_SECTOR_SIZE) == 0 || j == len))
304 {
305 rb->lcd_putsf(0, 5, "Verifying... %u%%", j * 100 / len);
306 rb->lcd_update();
307 }
308 }
309
310 return true;
311}
312
313/* print information about the flash chip */
314static bool show_info(void)
315{
316 static const struct flash_info* fi = NULL;
317
318 rb->lcd_clear_display();
319
320 if (fi == NULL)
321 flash_get_info(&fi);
322
323 rb->lcd_putsf(0, 0, "Flash: V=%04x P=%04x", fi->vendor, fi->product);
324
325 if (fi->size != 0)
326 {
327 rb->lcd_puts(0, 1, fi->name);
328 rb->lcd_putsf(0, 2, "Size: %u KB", fi->size / 1024);
329 }
330 else
331 {
332 rb->lcd_puts(0, 1, "Unknown chip");
333 }
334
335 rb->lcd_update();
336
337 if (fi->size == 0)
338 {
339 rb->splash(HZ * 3, "Sorry!");
340 return false;
341 }
342
343 return true;
344}
345
346/* confirm a user's choice */
347static bool confirm_choice(const char* msg)
348{
349 long button;
350 rb->splashf(0, "%s ([PLAY] to CONFIRM)", msg);
351 do
352 button = rb->button_get(true);
353 while (IS_SYSEVENT(button) || (button & BUTTON_REL));
354 show_info();
355 return (button == BUTTON_ON);
356}
357
358/* all-in-one firmware loader */
359static bool load_firmware(const char* filename, enum firmware firmware,
360 const void** data, size_t* data_len)
361{
362 bool result = false;
363 const char* msg = NULL;
364 int fd = -1;
365 off_t fd_len;
366 uint8_t* buffer;
367 size_t buffer_len;
368
369 fd = rb->open(filename, O_RDONLY);
370 if (fd < 0)
371 {
372 msg = "Aborting: open failure";
373 goto bail;
374 }
375
376 /* get file and buffer lengths and acquire the buffer */
377 fd_len = rb->filesize(fd);
378 buffer = rb->plugin_get_audio_buffer(&buffer_len);
379
380 /* ensure there's enough space in the buffer */
381 if ((size_t) fd_len > buffer_len)
382 {
383 msg = "Aborting: out of memory";
384 goto bail;
385 }
386
387 /* all known firmwares are less than or equal to FLASH_SIZE */
388 if (fd_len > FLASH_SIZE)
389 {
390 msg = "Aborting: firmware too big";
391 goto bail;
392 }
393
394 /* rockbox firmware specific code */
395 if (firmware == FIRMWARE_ROCKBOX)
396 {
397 uint32_t checksum;
398 uint8_t model[4];
399
400 /* subtract the header length */
401 fd_len -= sizeof(checksum) + sizeof(model);
402
403 /* sanity check the length */
404 if (fd_len < WORD_SIZE)
405 {
406 msg = "Aborting: firmware too small";
407 goto bail;
408 }
409
410 /* read the various parts */
411 if (
412 rb->read(fd, &checksum, sizeof(checksum)) != sizeof(checksum) ||
413 rb->read(fd, model, sizeof(model)) != sizeof(model) ||
414 rb->read(fd, buffer, fd_len) != fd_len
415 )
416 {
417 msg = "Aborting: read failure";
418 goto bail;
419 }
420
421 /* verify the checksum */
422 if (!verify_checksum(checksum, buffer, fd_len))
423 {
424 msg = "Aborting: checksum mismatch";
425 goto bail;
426 }
427
428 /* verify the model */
429 if (rb->memcmp(model, MODEL, sizeof(model)) != 0)
430 {
431 msg = "Aborting: model mismatch";
432 goto bail;
433 }
434 }
435
436 /* romdump specific code */
437 if (firmware == FIRMWARE_ROMDUMP)
438 {
439 /* the romdump should be exactly the same size as the flash */
440 if (fd_len != FLASH_SIZE)
441 {
442 msg = "Aborting: firmware size incorrect";
443 goto bail;
444 }
445
446 /* exclude boot vector and boot loader regions */
447 fd_len = BOOTLOADER_ENTRYPOINT - BOOT_VECTOR_SIZE;
448
449 /* skip the boot vector */
450 if (rb->lseek(fd, BOOT_VECTOR_SIZE, SEEK_SET) != BOOT_VECTOR_SIZE)
451 {
452 msg = "Aborting: lseek failure";
453 goto bail;
454 }
455
456 /* read everything up to the boot loader */
457 if (rb->read(fd, buffer, fd_len) != fd_len)
458 {
459 msg = "Aborting: read failure";
460 goto bail;
461 }
462 }
463
464 /* original firmware specific code */
465 if (firmware == FIRMWARE_ORIGINAL)
466 {
467 uint32_t boot_vector[2];
468
469 /* subtract the offset and the size of the boot vector */
470 fd_len -= FIRMWARE_OFFSET + sizeof(boot_vector);
471
472 /* sanity check the length */
473 if (fd_len < WORD_SIZE)
474 {
475 msg = "Aborting: firmware too small";
476 goto bail;
477 }
478
479 /* skip the leading bytes, whatever they are */
480 if (rb->lseek(fd, FIRMWARE_OFFSET, SEEK_SET) != FIRMWARE_OFFSET)
481 {
482 msg = "Aborting: lseek failure";
483 goto bail;
484 }
485
486 /* read the various parts */
487 if (
488 rb->read(fd, boot_vector, sizeof(boot_vector)) != sizeof(boot_vector) ||
489 rb->read(fd, buffer, fd_len) != fd_len
490 )
491 {
492 msg = "Aborting: read failure";
493 goto bail;
494 }
495
496 /* verify the boot vector */
497 if (boot_vector[0] != 0x10017ff0 || boot_vector[1] != 0x00000008)
498 {
499 msg = "Aborting: not an original firmware";
500 goto bail;
501 }
502 }
503
504 /* write the resulting buffer and length in the output parameters */
505 *data = buffer;
506 *data_len = fd_len;
507
508 /* mark success */
509 result = true;
510
511bail: /* common exit code */
512 if (fd >= 0)
513 rb->close(fd);
514 if (msg != NULL)
515 rb->splash(HZ * 3, msg);
516 return result;
517}
518
519/* prints fatal error if a critical failure occurs */
520static void show_fatal_error(void)
521{
522 rb->splash(HZ * 30, "Disable idle poweroff, connect AC power and DON'T TURN PLAYER OFF!");
523 rb->splash(HZ * 30, "Contact Rockbox developers as soon as possible!");
524 rb->splash(HZ * 30, "Your device won't be bricked unless you turn off the power!");
525 rb->splash(HZ * 30, "Don't use the device before further instructions from Rockbox developers!");
526}
527
528/* flash a bootloader */
529static bool flash_bootloader(const char* filename)
530{
531 bool result = false;
532 const char* msg = NULL;
533 bool show_fatal = false;
534 const void* data;
535 size_t data_len;
536 static uint8_t boot_sector[FLASH_SECTOR_SIZE];
537
538 /* load the firmware */
539 if (!load_firmware(filename, FIRMWARE_ROCKBOX, &data, &data_len))
540 goto bail;
541
542 /* the bootloader can only be so big */
543 if (data_len > BOOTLOADER_MAX_SIZE)
544 {
545 msg = "Aborting: bootloader too large";
546 goto bail;
547 }
548
549 /* only support known bootloaders */
550 if (!detect_valid_bootloader(data, data_len))
551 {
552 msg = "Aborting: bootloader is invalid";
553 goto bail;
554 }
555
556 /* ask before doing anything dangerous */
557 if (!confirm_choice("Update bootloader?"))
558 goto bail;
559
560 /* copy the original boot sector */
561 rb->memcpy(boot_sector, flash(BOOT_SECTOR_OFFSET), FLASH_SECTOR_SIZE);
562
563 /* update the boot vector */
564 rb->memcpy(boot_sector, data, BOOT_VECTOR_SIZE);
565
566 /* erase the boot sector */
567 flash_erase_sector(BOOT_SECTOR_OFFSET);
568
569 /* erase the bootloader sectors */
570 flash_erase_sectors(BOOTLOADER_ENTRYPOINT, BOOTLOADER_SECTORS, false);
571
572 /* program the new boot sector */
573 flash_program_bytes(BOOT_SECTOR_OFFSET, boot_sector, FLASH_SECTOR_SIZE, false);
574
575 /* program the new bootloader */
576 flash_program_bytes(BOOTLOADER_ENTRYPOINT, data, data_len, false);
577
578 /* verify the new boot sector */
579 if (!flash_verify_bytes(BOOT_SECTOR_OFFSET, boot_sector, FLASH_SECTOR_SIZE, false))
580 {
581 msg = "Boot sector corrupt!";
582 show_fatal = true;
583 goto bail;
584 }
585
586 /* verify the new bootloader */
587 if (!flash_verify_bytes(BOOTLOADER_ENTRYPOINT, data, data_len, false))
588 {
589 msg = "Verify failed!";
590 show_fatal = true;
591 goto bail;
592 }
593
594 /* report success */
595 rb->splash(HZ * 3, "Success!");
596
597 /* mark success */
598 result = true;
599
600bail: /* common exit code */
601 if (msg != NULL)
602 rb->splash(HZ * 3, msg);
603 if (show_fatal)
604 show_fatal_error();
605 return result;
606}
607
608/* flash a rockbox ram / rom image */
609static bool flash_rockbox(const char* filename, uint32_t offset)
610{
611 bool result = false;
612 const char* msg = NULL;
613 const void* data;
614 size_t data_len;
615 struct flash_header header;
616
617 /* load the firmware */
618 if (!load_firmware(filename, FIRMWARE_ROCKBOX, &data, &data_len))
619 goto bail;
620
621 /* sanity check that the offset was set correctly */
622 if (offset != FLASH_RAMIMAGE_ENTRY && offset != FLASH_ROMIMAGE_ENTRY)
623 {
624 msg = "Aborting: invalid image offset";
625 goto bail;
626 }
627
628 /* ensure there's enough room for the ram / rom image */
629 if (
630 (offset == FLASH_RAMIMAGE_ENTRY && data_len > RAM_IMAGE_MAX_SIZE) ||
631 (offset == FLASH_ROMIMAGE_ENTRY && data_len > ROM_IMAGE_MAX_SIZE)
632 )
633 {
634 msg = "Aborting: ram / rom image too large";
635 goto bail;
636 }
637
638 /* check for bootloader that can load rockbox from ram / rom */
639 if (!detect_valid_bootloader(flash(BOOTLOADER_ENTRYPOINT), 0))
640 {
641 msg = "Aborting: incompatible bootloader";
642 goto bail;
643 }
644
645 /* rom image specific checks */
646 if (offset == FLASH_ROMIMAGE_ENTRY)
647 {
648 uint32_t relocation = *((const uint32_t*) data);
649
650 /* sanity check of the image relocation */
651 if (relocation != ROM_IMAGE_RELOCATION)
652 {
653 msg = "Aborting: invalid image relocation";
654 goto bail;
655 }
656 }
657
658 /* ask before doing anything dangerous */
659 if (!rb->detect_original_firmware())
660 {
661 if (!confirm_choice("Update Rockbox flash image?"))
662 goto bail;
663 }
664 else
665 {
666 if (!confirm_choice("Erase original firmware?"))
667 goto bail;
668 }
669
670 /* erase all ram / rom image sectors */
671 if (offset == FLASH_RAMIMAGE_ENTRY)
672 flash_erase_sectors(offset, RAM_IMAGE_SECTORS, true);
673 else if (offset == FLASH_ROMIMAGE_ENTRY)
674 flash_erase_sectors(offset, ROM_IMAGE_SECTORS, true);
675
676 /* prepare the header */
677 header.magic = FLASH_MAGIC;
678 header.length = data_len;
679 rb->memset(&header.version, 0x00, sizeof(header.version));
680
681 /* program the header */
682 flash_program_bytes(offset, &header, sizeof(header), false);
683
684 /* program the ram / rom image */
685 flash_program_bytes(offset + sizeof(header), data, data_len, true);
686
687 /* verify the header and ram / rom image */
688 if (
689 !flash_verify_bytes(offset, &header, sizeof(header), false) ||
690 !flash_verify_bytes(offset + sizeof(header), data, data_len, true)
691 )
692 {
693 msg = "Verify failed!";
694 /*
695 * erase the ram / rom image header to prevent the bootloader
696 * from trying to boot from it
697 */
698 flash_erase_sector(offset);
699 goto bail;
700 }
701
702 /* report success */
703 rb->splash(HZ * 3, "Success!");
704
705 /* mark success */
706 result = true;
707
708bail: /* common exit code */
709 if (msg != NULL)
710 rb->splash(HZ * 3, msg);
711 return result;
712}
713
714/* flash whole firmware; common code for romdump / original */
715static bool flash_whole_firmware(const void* data, size_t data_len)
716{
717 bool result = false;
718 const char* msg = NULL;
719 bool show_fatal = false;
720 uint8_t boot_vector[BOOT_VECTOR_SIZE];
721
722 /* copy the original boot vector */
723 rb->memcpy(boot_vector, flash(BOOT_SECTOR_OFFSET), BOOT_VECTOR_SIZE);
724
725 /* erase everything except the bootloader */
726 flash_erase_sectors(BOOT_SECTOR_OFFSET, WHOLE_FIRMWARE_SECTORS, true);
727
728 /* program the original boot vector */
729 flash_program_bytes(BOOT_SECTOR_OFFSET, boot_vector, BOOT_VECTOR_SIZE, false);
730
731 /* program the whole firmware */
732 flash_program_bytes(BOOT_SECTOR_OFFSET + BOOT_VECTOR_SIZE, data, data_len, true);
733
734 /* verify the new boot vector */
735 if (!flash_verify_bytes(BOOT_SECTOR_OFFSET, boot_vector, BOOT_VECTOR_SIZE, false))
736 {
737 msg = "Boot vector corrupt!";
738 show_fatal = true;
739 goto bail;
740 }
741
742 /* verify the new firmware */
743 if (!flash_verify_bytes(BOOT_SECTOR_OFFSET + BOOT_VECTOR_SIZE, data, data_len, true))
744 {
745 msg = "Verify failed!";
746 goto bail;
747 }
748
749 /* report success */
750 rb->splash(HZ * 3, "Success!");
751
752 /* mark success */
753 result = true;
754
755bail: /* common exit code */
756 if (msg != NULL)
757 rb->splash(HZ * 3, msg);
758 if (show_fatal)
759 show_fatal_error();
760 return result;
761}
762
763/* flash rom dumps */
764static bool flash_romdump(const char* filename)
765{
766 const void* data;
767 size_t data_len;
768
769 /* load the firmware */
770 if (!load_firmware(filename, FIRMWARE_ROMDUMP, &data, &data_len))
771 return false;
772
773 /* ask before doing anything dangerous */
774 if (!confirm_choice("Restore firmware section (bootloader will be kept)?"))
775 return false;
776
777 return flash_whole_firmware(data, data_len);
778}
779
780/* flash original firmware */
781static bool flash_original(const char* filename)
782{
783 const void* data;
784 size_t data_len;
785
786 /* load the firmware */
787 if (!load_firmware(filename, FIRMWARE_ORIGINAL, &data, &data_len))
788 return false;
789
790 /* ask before doing anything dangerous */
791 if (!confirm_choice("Restore original firmware (bootloader will be kept)?"))
792 return false;
793
794 return flash_whole_firmware(data, data_len);
795}
796
797/* main function of plugin */
798static void iriver_flash(const char* filename)
799{
800 /* refuse to run from ROM */
801 const uint8_t* RB = (uint8_t*) rb;
802 const uint8_t* FB = (uint8_t*) flash(0);
803 if (RB >= FB && RB < FB + FLASH_SIZE)
804 {
805 rb->splash(HZ * 3, "Refusing to run from ROM");
806 return;
807 }
808
809 /* refuse to run with low battery */
810 if (!rb->battery_level_safe())
811 {
812 rb->splash(HZ * 3, "Refusing to run with low battery");
813 return;
814 }
815
816 /* print information about flash; exit if not supported */
817 if (!show_info())
818 return;
819
820 /* exit if no filename was provided */
821 if (filename == NULL)
822 {
823 rb->splash(HZ * 3, "Please use this plugin with \"Open with...\"");
824 return;
825 }
826
827 /* choose what to do with the file */
828 if (rb->strcasestr(filename, "/bootloader.iriver") != NULL)
829 flash_bootloader(filename);
830 else if (rb->strcasestr(filename, "/rockbox.iriver") != NULL)
831 flash_rockbox(filename, FLASH_RAMIMAGE_ENTRY);
832 else if (rb->strcasestr(filename, "/rombox.iriver") != NULL)
833 flash_rockbox(filename, FLASH_ROMIMAGE_ENTRY);
834 else if (rb->strcasestr(filename, ROMDUMP) != NULL)
835 flash_romdump(filename);
836 else if (rb->strcasestr(filename, ORIGINAL) != NULL)
837 flash_original(filename);
838 else
839 rb->splash(HZ * 3, "Unknown file type");
840}
841
842/* plugin entry point */
843enum plugin_status plugin_start(const void* parameter)
844{
845 /* need to disable memguard to write to flash */
846 int mode = rb->system_memory_guard(MEMGUARD_NONE);
847
848 /* setup LCD font */
849 rb->lcd_setfont(FONT_SYSFIXED);
850
851 /* don't let the backlight turn off or it might scare people */
852 backlight_ignore_timeout();
853
854 /* run the main entry function */
855 iriver_flash(parameter);
856
857 /* restore the original backlight settings */
858 backlight_use_settings();
859
860 /* restore LCD font */
861 rb->lcd_setfont(FONT_UI);
862
863 /* restore original memory guard setting */
864 rb->system_memory_guard(mode);
865
866 return PLUGIN_OK;
867}