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 * Copyright (C) 2007 by Linus Nielsen Feltzing
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
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 "config.h"
22
23#include <stdlib.h>
24#include <stdio.h>
25#include "inttypes.h"
26#include "string.h"
27#include "cpu.h"
28#include "system.h"
29#include "lcd.h"
30#include "lcd-remote.h"
31#include "scroll_engine.h"
32#include "../kernel-internal.h"
33#include "storage.h"
34#include "file_internal.h"
35#include "usb.h"
36#include "disk.h"
37#include "font.h"
38#include "adc.h"
39#include "backlight.h"
40#include "backlight-target.h"
41#include "button.h"
42#include "panic.h"
43#include "power.h"
44#include "powermgmt.h"
45#include "file.h"
46#include "eeprom_settings.h"
47#include "rbunicode.h"
48#include "pcf50606.h"
49#include "common.h"
50#include "rb-loader.h"
51#include "loader_strerror.h"
52#include "isp1362.h"
53#include "version.h"
54
55#include <stdarg.h>
56
57/* Maximum allowed firmware image size. 10MB is more than enough */
58#define MAX_LOADSIZE (10*1024*1024)
59
60#define DRAM_START 0x31000000
61
62/* From common.c */
63extern int line;
64extern int remote_line;
65
66static bool recovery_mode = false;
67
68/* Reset the cookie for the crt0 crash check */
69static inline void __reset_cookie(void)
70{
71 asm(" move.l #0,%d0");
72 asm(" move.l %d0,0x10017ffc");
73}
74
75void start_iriver_fw(void)
76{
77 asm(" move.w #0x2700,%sr");
78 __reset_cookie();
79 asm(" movec.l %d0,%vbr");
80 asm(" move.l 0,%sp");
81 asm(" lea.l 8,%a0");
82 asm(" jmp (%a0)");
83}
84
85void start_firmware(void)
86{
87 asm(" move.w #0x2700,%sr");
88 __reset_cookie();
89 asm(" move.l %0,%%d0" :: "i"(DRAM_START));
90 asm(" movec.l %d0,%vbr");
91 asm(" move.l %0,%%sp" :: "m"(*(int *)DRAM_START));
92 asm(" move.l %0,%%a0" :: "m"(*(int *)(DRAM_START+4)));
93 asm(" jmp (%a0)");
94}
95
96void start_flashed_romimage(void)
97{
98 uint8_t *src = (uint8_t *)FLASH_ROMIMAGE_ENTRY;
99 uint32_t *reset_vector;
100
101 if (!detect_flashed_romimage())
102 return ;
103
104 reset_vector = (uint32_t *)(&src[sizeof(struct flash_header)+sizeof(uint32_t)]);
105
106 asm(" move.w #0x2700,%sr");
107 __reset_cookie();
108
109 asm(" move.l %0,%%d0" :: "i"(DRAM_START));
110 asm(" movec.l %d0,%vbr");
111 asm(" move.l %0,%%sp" :: "m"(reset_vector[0]));
112 asm(" move.l %0,%%a0" :: "m"(reset_vector[1]));
113 asm(" jmp (%a0)");
114
115 /* Failure */
116 power_off();
117}
118
119void start_flashed_ramimage(void)
120{
121 struct flash_header hdr;
122 uint8_t *buf = (uint8_t *)DRAM_START;
123 uint8_t *src = (uint8_t *)FLASH_RAMIMAGE_ENTRY;
124
125 if (!detect_flashed_ramimage())
126 return;
127
128 /* Load firmware from flash */
129 cpu_boost(true);
130 memcpy(&hdr, src, sizeof(struct flash_header));
131 src += sizeof(struct flash_header);
132 memcpy(buf, src, hdr.length);
133 cpu_boost(false);
134
135 start_firmware();
136
137 /* Failure */
138 power_off();
139}
140
141void shutdown(void)
142{
143 printf("Shutting down...");
144 /* Reset the rockbox crash check. */
145 firmware_settings.bl_version = 0;
146 eeprom_settings_store();
147
148 /* We need to gracefully spin down the disk to prevent clicks. */
149 if (ide_powered())
150 {
151 /* Make sure ATA has been initialized. */
152 storage_init();
153
154 /* And put the disk into sleep immediately. */
155 storage_sleepnow();
156 }
157
158 sleep(HZ*2);
159
160 /* Backlight OFF */
161 backlight_hw_off();
162 remote_backlight_hw_off();
163
164 __reset_cookie();
165 power_off();
166}
167
168/* Print the battery voltage (and a warning message). */
169void check_battery(void)
170{
171 int battery_voltage, batt_int, batt_frac;
172
173 battery_voltage = _battery_voltage();
174 batt_int = battery_voltage / 1000;
175 batt_frac = (battery_voltage % 1000) / 10;
176
177 printf("Batt: %d.%02dV", batt_int, batt_frac);
178
179 if (battery_voltage <= 310)
180 {
181 printf("WARNING! BATTERY LOW!!");
182 sleep(HZ*2);
183 }
184}
185
186void initialize_eeprom(void)
187{
188 if (detect_original_firmware())
189 return ;
190
191 if (!eeprom_settings_init())
192 {
193 recovery_mode = true;
194 return ;
195 }
196
197 /* If bootloader version has not been reset, disk might
198 * not be intact. */
199 if (firmware_settings.bl_version || !firmware_settings.disk_clean)
200 {
201 firmware_settings.disk_clean = false;
202 recovery_mode = true;
203 }
204
205 firmware_settings.bl_version = EEPROM_SETTINGS_BL_MINVER;
206 eeprom_settings_store();
207}
208
209void try_flashboot(void)
210{
211 if (!firmware_settings.initialized)
212 return ;
213
214 switch (firmware_settings.bootmethod)
215 {
216 case BOOT_DISK:
217 return;
218
219 case BOOT_ROM:
220 start_flashed_romimage();
221 break;
222
223 case BOOT_RAM:
224 start_flashed_ramimage();
225 break;
226
227 case BOOT_RECOVERY:
228 break;
229 }
230
231 recovery_mode = true;
232}
233
234void failsafe_menu(void)
235{
236 static const char *options[] =
237 {
238 "Boot from disk",
239 "Boot RAM image",
240 "Boot ROM image",
241 "Shutdown"
242 };
243 const int FAILSAFE_OPTIONS = sizeof(options) / sizeof(*options);
244 const long TIMEOUT = 15 * HZ;
245 long start_tick = current_tick;
246 int option = 3;
247 int button;
248 int defopt = -1;
249 char buf[32];
250 int i;
251
252 reset_screen();
253 printf("Bootloader %s", rbversion);
254 check_battery();
255 printf("=========================");
256 line += FAILSAFE_OPTIONS;
257 printf("");
258 printf(" [NAVI] to confirm.");
259 printf(" [REC] to set as default.");
260 printf("");
261
262 if (firmware_settings.initialized)
263 {
264 defopt = firmware_settings.bootmethod;
265 if (defopt < 0 || defopt >= FAILSAFE_OPTIONS)
266 defopt = option;
267 }
268
269 while (current_tick - start_tick < TIMEOUT)
270 {
271 /* Draw the menu. */
272 line = 3;
273 for (i = 0; i < FAILSAFE_OPTIONS; i++)
274 {
275 char *def = "[DEF]";
276 char *arrow = "->";
277
278 if (i != defopt)
279 def = "";
280 if (i != option)
281 arrow = " ";
282
283 printf("%s %s %s", arrow, options[i], def);
284 }
285
286 snprintf(buf, sizeof(buf), "Time left: %lds",
287 (TIMEOUT - (current_tick - start_tick)) / HZ);
288 lcd_puts(0, 10, buf);
289 lcd_update();
290 button = button_get_w_tmo(HZ);
291
292 if (button == BUTTON_NONE || button & SYS_EVENT)
293 continue ;
294
295 start_tick = current_tick;
296
297 /* Ignore the ON/PLAY -button because it can cause trouble
298 with the RTC alarm mod. */
299 switch (button & ~(BUTTON_ON))
300 {
301 case BUTTON_UP:
302 case BUTTON_RC_REW:
303 if (option > 0)
304 option--;
305 break ;
306
307 case BUTTON_DOWN:
308 case BUTTON_RC_FF:
309 if (option < FAILSAFE_OPTIONS-1)
310 option++;
311 break ;
312
313 case BUTTON_SELECT:
314 case BUTTON_RC_ON:
315 goto execute;
316
317 case BUTTON_REC:
318 case BUTTON_RC_REC:
319 if (firmware_settings.initialized)
320 {
321 firmware_settings.bootmethod = option;
322 eeprom_settings_store();
323 defopt = option;
324 }
325 break ;
326 }
327 }
328
329 execute:
330
331 lcd_puts(0, 10, "Executing command...");
332 lcd_update();
333 sleep(HZ);
334 reset_screen();
335
336 switch (option)
337 {
338 case BOOT_DISK:
339 return ;
340
341 case BOOT_RAM:
342 start_flashed_ramimage();
343 printf("Image not found");
344 break;
345
346 case BOOT_ROM:
347 start_flashed_romimage();
348 printf("Image not found");
349 break;
350 }
351
352 shutdown();
353}
354
355/* From the pcf50606 driver */
356extern unsigned char pcf50606_intregs[3];
357
358void main(void)
359{
360 int i;
361 int rc;
362 bool rc_on_button = false;
363 bool on_button = false;
364 bool rec_button = false;
365 bool hold_status = false;
366 int data;
367 bool rtc_alarm;
368 int mask;
369 bool usb_charge = false;
370
371 /* We want to read the buttons as early as possible, before the user
372 releases the ON button */
373
374 /* Set GPIO33, GPIO37, GPIO38 and GPIO52 as general purpose inputs
375 (The ON and Hold buttons on the main unit and the remote) */
376 or_l(0x00100062, &GPIO1_FUNCTION);
377 and_l(~0x00100062, &GPIO1_ENABLE);
378
379 data = GPIO1_READ;
380 if ((data & 0x20) == 0)
381 on_button = true;
382
383 if ((data & 0x40) == 0)
384 rc_on_button = true;
385
386 /* Set the default state of the hard drive power to OFF */
387 ide_power_enable(false);
388
389 power_init();
390
391 /* Check the interrupt registers if it was an RTC alarm */
392 rtc_alarm = (pcf50606_intregs[0] & 0x80)?true:false;
393
394 /* Turn off if we believe the start was accidental */
395 if(!(rtc_alarm || on_button || rc_on_button ||
396 (usb_detect() == USB_INSERTED) || charger_inserted())) {
397 __reset_cookie();
398 power_off();
399 }
400
401 /* get rid of a nasty humming sound during boot */
402 mask = disable_irq_save();
403 pcf50606_write(0x3b, 0x00); /* GPOOD2 high Z */
404 pcf50606_write(0x3b, 0x07); /* GPOOD2 low */
405 restore_irq(mask);
406
407 /* Start with the main backlight OFF. */
408 backlight_hw_init();
409 backlight_hw_off();
410
411 /* Remote backlight ON */
412 remote_backlight_hw_on();
413
414 system_init();
415 kernel_init();
416
417 /* Set up waitstates for the peripherals */
418 set_cpu_frequency(0); /* PLL off */
419 coldfire_set_pllcr_audio_bits(DEFAULT_PLLCR_AUDIO_BITS);
420 enable_irq();
421
422 initialize_eeprom();
423
424 isp1362_init();
425
426 adc_init();
427 button_init();
428 sleep(HZ/50); /* Allow the button driver to check the buttons */
429
430 /* Only check remote hold status if remote power button was actually used. */
431 if (rc_on_button)
432 {
433 lcd_remote_init();
434
435 if (remote_button_hold())
436 hold_status = true;
437 }
438
439 /* Check main hold switch status too. */
440 if (on_button && button_hold())
441 {
442 hold_status = true;
443 }
444
445 /* Power on the hard drive early, to speed up the loading. */
446 if (!hold_status && !recovery_mode)
447 {
448 ide_power_enable(true);
449
450 if (usb_detect() != USB_INSERTED)
451 try_flashboot();
452 }
453
454 lcd_init();
455
456 if (!rc_on_button)
457 lcd_remote_init();
458
459 font_init();
460
461 lcd_setfont(FONT_SYSFIXED);
462
463 backlight_init(); /* BUGFIX backlight_init MUST BE AFTER lcd_init */
464
465 printf("Rockbox boot loader");
466 printf("Version %s", rbversion);
467
468 rec_button = ((button_status() & BUTTON_REC) == BUTTON_REC)
469 || ((button_status() & BUTTON_RC_REC) == BUTTON_RC_REC);
470
471 check_battery();
472
473 if(rtc_alarm)
474 printf("RTC alarm detected");
475
476 /* Holding REC while starting runs the original firmware */
477 if (detect_original_firmware() && rec_button)
478 {
479 printf("Starting original firmware...");
480 start_iriver_fw();
481 }
482
483 /* enable usb charging for charge mode and disk mode */
484 if (usb_detect() == USB_INSERTED)
485 {
486 usb_charging_enable(USB_CHARGING_ENABLE);
487 usb_charge = true;
488 }
489
490 if(charger_inserted())
491 {
492 const char charging_msg[] = "Charging...";
493 const char complete_msg[] = "Charging complete";
494 const char *msg;
495 int w, h;
496 bool blink_toggle = false;
497 bool request_start = false;
498
499 cpu_idle_mode(true);
500
501 while(charger_inserted() && !request_start)
502 {
503 long button = button_get_w_tmo(HZ);
504
505 switch(button)
506 {
507 case BUTTON_ON:
508 request_start = true;
509 break;
510
511 case BUTTON_NONE: /* Timeout */
512
513 if(charging_state())
514 {
515 /* To be replaced with a nice animation */
516 blink_toggle = !blink_toggle;
517 msg = charging_msg;
518 }
519 else
520 {
521 blink_toggle = true;
522 msg = complete_msg;
523 }
524
525 font_getstringsize(msg, &w, &h, FONT_SYSFIXED);
526 reset_screen();
527 if(blink_toggle)
528 lcd_putsxy((LCD_WIDTH-w)/2, (LCD_HEIGHT-h)/2, msg);
529
530 check_battery();
531 break;
532 }
533 }
534 if(!request_start)
535 {
536 __reset_cookie();
537 power_off();
538 }
539
540 cpu_idle_mode(false);
541 }
542
543 usb_init();
544
545 /* A hack to enter USB mode without using the USB thread */
546 if(usb_detect() == USB_INSERTED)
547 {
548 const char msg[] = "Bootloader USB mode";
549 int w, h;
550 font_getstringsize(msg, &w, &h, FONT_SYSFIXED);
551 reset_screen();
552 lcd_putsxy((LCD_WIDTH-w)/2, (LCD_HEIGHT-h)/2, msg);
553 lcd_update();
554
555 lcd_remote_puts(0, 3, msg);
556 lcd_remote_update();
557
558 if (firmware_settings.initialized)
559 {
560 firmware_settings.disk_clean = false;
561 eeprom_settings_store();
562 }
563
564 ide_power_enable(true);
565 storage_enable(false);
566 sleep(HZ/20);
567 usb_enable(true);
568 cpu_idle_mode(true);
569 while (usb_detect() == USB_INSERTED)
570 {
571 /* Print the battery status. */
572 line = 0;
573 remote_line = 0;
574 check_battery();
575
576 storage_spin(); /* Prevent the drive from spinning down */
577 sleep(HZ);
578 }
579
580 cpu_idle_mode(false);
581 usb_enable(false);
582
583 reset_screen();
584 lcd_update();
585 }
586
587 /* disable usb charging if we enabled it earlier */
588 if (usb_charge)
589 {
590 usb_charging_enable(USB_CHARGING_DISABLE);
591 usb_charge = false;
592 }
593
594 /* recheck the hold switch status as it may have changed */
595 hold_status = (button_hold() || remote_button_hold());
596
597 /* hold switch shutdown or failsafe recovery mode */
598 if (hold_status || recovery_mode)
599 {
600 if (detect_original_firmware())
601 {
602 printf("Hold switch on");
603 shutdown();
604 }
605
606 failsafe_menu();
607 }
608
609 rc = storage_init();
610 if(rc)
611 {
612 reset_screen();
613 printf("ATA error: %d", rc);
614 printf("Insert USB cable and press");
615 printf("a button");
616 while(!(button_get(true) & BUTTON_REL));
617 }
618
619 filesystem_init();
620
621 rc = disk_mount_all();
622 if (rc<=0)
623 {
624 struct partinfo pinfo;
625 reset_screen();
626 printf("No partition found");
627 for (int i = 0 ; i < NUM_VOLUMES ; i++) {
628 disk_partinfo(i, &pinfo);
629 if (pinfo.type)
630 printf("P%d T%02x S%llx",
631 i, pinfo.type, (unsigned long long)pinfo.size);
632 }
633 while(button_get(true) != SYS_USB_CONNECTED) {};
634 }
635
636 printf("Loading firmware");
637 i = load_firmware((unsigned char *)DRAM_START, BOOTFILE, MAX_LOADSIZE);
638 if(i <= EFILE_EMPTY)
639 printf("Error: %s", loader_strerror(i));
640
641 if (i > 0)
642 start_firmware();
643
644 if (!detect_original_firmware())
645 {
646 printf("No firmware found on disk");
647 sleep(HZ*2);
648 shutdown();
649 }
650 else {
651 sleep(HZ*2);
652 start_iriver_fw();
653 }
654}
655
656/* These functions are present in the firmware library, but we reimplement
657 them here because the originals do a lot more than we want */
658int usb_screen(void)
659{
660 return 0;
661}
662
663ucschar_t *bidi_l2v(const unsigned char *str, int orientation)
664{
665 static ucschar_t utf_buf[SCROLL_LINE_SIZE];
666 ucschar_t *target;
667 (void)orientation;
668
669 target = utf_buf;
670
671 while (*str)
672 str = utf8decode(str, target++);
673 *target = 0;
674 return utf_buf;
675}