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