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 Dave Chapman
11 *
12 * Based on Rockbox iriver bootloader by Linus Nielsen Feltzing
13 * and the ipodlinux bootloader by Daniel Palffy and Bernard Leach
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 "config.h"
25
26#include <stdlib.h>
27#include <stdio.h>
28#include <string.h>
29#include <stdarg.h>
30#include "cpu.h"
31#include "system.h"
32#include "lcd.h"
33#include "../kernel-internal.h"
34#include "ata.h"
35#include "file_internal.h"
36#include "disk.h"
37#include "storage.h"
38#include "font.h"
39#include "adc.h"
40#include "backlight.h"
41#include "panic.h"
42#include "power.h"
43#include "file.h"
44#include "common.h"
45#include "rb-loader.h"
46#include "loader_strerror.h"
47#include "hwcompat.h"
48#include "usb.h"
49#include "version.h"
50
51#define XSC(X) #X
52#define SC(X) XSC(X)
53
54/* Maximum allowed firmware image size. The largest known current
55 (December 2006) firmware is about 7.5MB (Apple's firmware for the ipod video)
56 so we set this to 8MB. */
57#define MAX_LOADSIZE (8*1024*1024)
58
59/* A buffer to load the Linux kernel or Rockbox into */
60unsigned char *loadbuffer = (unsigned char *)DRAM_START;
61
62#if CONFIG_KEYPAD == IPOD_4G_PAD && !defined(IPOD_MINI)
63/* check if number of seconds has past */
64int timer_check(int clock_start, unsigned int usecs)
65{
66 if ((USEC_TIMER - clock_start) >= usecs) {
67 return 1;
68 } else {
69 return 0;
70 }
71}
72
73static void ser_opto_keypad_cfg(int val)
74{
75 int start_time;
76
77 GPIOB_ENABLE &=~ 0x80;
78
79 outl(inl(0x7000c104) | 0xc000000, 0x7000c104);
80 outl(val, 0x7000c120);
81 outl(inl(0x7000c100) | 0x80000000, 0x7000c100);
82
83 GPIOB_OUTPUT_VAL &=~ 0x10;
84 GPIOB_OUTPUT_EN |= 0x10;
85
86 start_time = USEC_TIMER;
87 do {
88 if ((inl(0x7000c104) & 0x80000000) == 0) {
89 break;
90 }
91 } while (timer_check(start_time, 1500) != 0);
92
93 outl(inl(0x7000c100) & ~0x80000000, 0x7000c100);
94
95 GPIOB_ENABLE |= 0x80;
96 GPIOB_OUTPUT_VAL |= 0x10;
97 GPIOB_OUTPUT_EN &=~0x10;
98
99 outl(inl(0x7000c104) | 0xc000000, 0x7000c104);
100 outl(inl(0x7000c100) | 0x60000000, 0x7000c100);
101}
102
103int opto_keypad_read(void)
104{
105 int loop_cnt, had_io = 0;
106
107 for (loop_cnt = 5; loop_cnt != 0;)
108 {
109 int key_pressed = 0;
110 int start_time;
111 unsigned int key_pad_val;
112
113 ser_opto_keypad_cfg(0x8000023a);
114
115 start_time = USEC_TIMER;
116 do {
117 if (inl(0x7000c104) & 0x4000000) {
118 had_io = 1;
119 break;
120 }
121
122 if (had_io != 0) {
123 break;
124 }
125 } while (timer_check(start_time, 1500) != 0);
126
127 key_pad_val = inl(0x7000c140);
128 if ((key_pad_val & ~0x7fff0000) != 0x8000023a) {
129 loop_cnt--;
130 } else {
131 key_pad_val = (key_pad_val << 11) >> 27;
132 key_pressed = 1;
133 }
134
135 outl(inl(0x7000c100) | 0x60000000, 0x7000c100);
136 outl(inl(0x7000c104) | 0xc000000, 0x7000c104);
137
138 if (key_pressed != 0) {
139 return key_pad_val ^ 0x1f;
140 }
141 }
142
143 return 0;
144}
145#endif
146
147static int key_pressed(void)
148{
149 unsigned char state;
150
151#if CONFIG_KEYPAD == IPOD_4G_PAD
152#ifdef IPOD_MINI /* mini 1G only */
153 state = GPIOA_INPUT_VAL & 0x3f;
154 if ((state & 0x10) == 0) return BUTTON_LEFT;
155 if ((state & 0x2) == 0) return BUTTON_MENU;
156 if ((state & 0x4) == 0) return BUTTON_PLAY;
157 if ((state & 0x8) == 0) return BUTTON_RIGHT;
158#else
159 state = opto_keypad_read();
160 if ((state & 0x4) == 0) return BUTTON_LEFT;
161 if ((state & 0x10) == 0) return BUTTON_MENU;
162 if ((state & 0x8) == 0) return BUTTON_PLAY;
163 if ((state & 0x2) == 0) return BUTTON_RIGHT;
164#endif
165#elif (CONFIG_KEYPAD == IPOD_3G_PAD) || (CONFIG_KEYPAD == IPOD_1G2G_PAD)
166 state = GPIOA_INPUT_VAL;
167 if ((state & 0x08) == 0) return BUTTON_LEFT;
168 if ((state & 0x10) == 0) return BUTTON_MENU;
169 if ((state & 0x04) == 0) return BUTTON_PLAY;
170 if ((state & 0x01) == 0) return BUTTON_RIGHT;
171#endif
172 return 0;
173}
174
175bool button_hold(void)
176{
177#if CONFIG_KEYPAD == IPOD_1G2G_PAD
178 return (GPIOA_INPUT_VAL & 0x20);
179#else
180 return !(GPIOA_INPUT_VAL & 0x20);
181#endif
182}
183
184void fatal_error(void)
185{
186 extern int line;
187 bool holdstatus=false;
188
189 /* System font is 6 pixels wide */
190#if defined(IPOD_1G2G) || defined(IPOD_3G)
191 printf("Insert Firewire cable, or");
192 printf("hold MENU+PLAY to reboot");
193 printf("then REW+FF for disk mode");
194#elif LCD_WIDTH >= (30*6)
195 printf("Insert USB cable, or");
196 printf("hold MENU+SELECT to reboot");
197 printf("then SELECT+PLAY for disk mode");
198#else
199 printf("Insert USB cable, or");
200 printf("hold MENU+SELECT to");
201 printf("reboot then SELECT+PLAY");
202 printf("for disk mode");
203#endif
204 lcd_update();
205
206#if defined(MAX_VIRT_SECTOR_SIZE) && defined(DEFAULT_VIRT_SECTOR_SIZE)
207#ifdef HAVE_MULTIDRIVE
208 for (int i = 0 ; i < NUM_DRIVES ; i++)
209#endif
210 disk_set_sector_multiplier(IF_MD(i,) DEFAULT_VIRT_SECTOR_SIZE/SECTOR_SIZE);
211#endif
212
213 usb_init();
214 while (1) {
215 if (button_hold() != holdstatus) {
216 if (button_hold()) {
217 holdstatus=true;
218 lcd_puts(0, line, "Hold switch on!");
219 } else {
220 holdstatus=false;
221 lcd_puts(0, line, " ");
222 }
223 lcd_update();
224 }
225 if (usb_detect() == USB_INSERTED) {
226 ata_sleepnow(); /* Immediately spindown the disk. */
227 sleep(HZ*2);
228#if CONFIG_CPU == PP5020
229 memcpy((void *)0x40017f00, "diskmode\0\0hotstuff\0\0\1", 21);
230#elif CONFIG_CPU == PP5022
231 memcpy((void *)0x4001ff00, "diskmode\0\0hotstuff\0\0\1", 21);
232#elif CONFIG_CPU == PP5002
233 memcpy((void *)0x40017f00, "diskmodehotstuff\1", 17);
234#endif /* CONFIG_CPU */
235 system_reboot(); /* Reboot */
236 }
237 udelay(100000); /* 100ms */
238 }
239
240}
241
242/* The bootloader is started from the OSOS image on the firmware
243 * partition. There are several ways it can be installed there:
244 * appended to the Apple firmware, on its own, or appended to
245 * Rockbox itself. The Apple ROM loader loads the entire OSOS
246 * image to DRAM_START, whatever it contains. If the bootloader
247 * is appended to another image then it will've modified the
248 * entry point in the OSOS header such that the ROM will call the
249 * bootloader rather than the main image.
250 *
251 * So, once the bootloader has control:
252 *
253 * 1) If the hold switch is on, or the menu button is being held,
254 * try to boot the Apple firmware.
255 * 1a) First, it looks for apple_os.ipod on the FAT32 partition,
256 * in .rockbox or the root directory. If found it loads that
257 * without further checking and runs it.
258 * 1b) Next, it checks to see if the OSOS image already loaded
259 * into RAM is in fact the Apple firmware with the bootloader
260 * appended. It looks at DRAM_START+0x20 for the string
261 * "portalplayer", and if it's there, just jumps back to
262 * DRAM_START where the entry point was before the bootloader
263 * was appended.
264 * 1c) If neither of those worked, it displays an error and dies.
265 *
266 * 2) If the play button is being held, try to boot Linux. It looks
267 * for linux.bin in the root directory, and if it's not there,
268 * it displays an error and dies.
269 *
270 * 3) Otherwise, try to boot Rockbox.
271 * 3a) First, it looks for rockbox.ipod on the FAT32 partition,
272 * in .rockbox or the root directory. If found it loads that
273 * without further checking and runs it.
274 * 3b) Next, it checks to see if the OSOS image already loaded
275 * into RAM is in fact Rockbox with the bootloader appended.
276 * It looks at DRAM_START+0x20 for the string "Rockbox\1"
277 * (which is inserted there in crt0-pp.S), and if it's there,
278 * just humps back to DRAM_START where the entry point was
279 * before the bootloader was appended.
280 * 3c) If neither of those worked, it displays an error and dies.
281 *
282 * The result is that any of the three install configurations work,
283 * and that images of apple_os.ipod or rockbox.ipod on the FAT32
284 * partition take priority over the contents of OSOS (this avoids
285 * upgrades failing to work if OSOS is not updated).
286 *
287 * Loading from OSOS is somewhat faster than loading from FAT32,
288 * because the Apple ROM doesn't have to deal with filesystems or
289 * fragmentation, and is already loading from OSOS anyway. Thus,
290 * the fastest boot configuration that still allows dual booting
291 * is to install Rockbox into OSOS with the bootloader appended
292 * (and delete/rename rockbox.ipod from the FAT32 partition).
293 *
294 * It is of course faster to just install Rockbox to OSOS alone,
295 * but then it's impossible to boot the Apple firmware.
296 */
297
298void* main(void)
299{
300 char buf[256];
301 int i;
302 int btn;
303 int rc;
304 bool haveramos;
305 bool button_was_held;
306 struct partinfo pinfo;
307 unsigned short* identify_info;
308
309 /* Check the button hold status as soon as possible - to
310 give the user maximum chance to turn it off in order to
311 reset the settings in rockbox. */
312 button_was_held = button_hold();
313
314 system_init();
315 kernel_init();
316
317 lcd_init();
318 font_init();
319#ifndef HAVE_BACKLIGHT_INVERSION
320 backlight_init(); /* Turns on the backlight BUGFIX backlight_init MUST BE AFTER lcd_init */
321#endif
322
323#ifdef HAVE_LCD_COLOR
324 lcd_set_foreground(LCD_WHITE);
325 lcd_set_background(LCD_BLACK);
326 lcd_clear_display();
327#endif
328
329#if 0
330 /* ADC and button drivers are not yet implemented */
331 adc_init();
332 button_init();
333#endif
334
335 btn=key_pressed();
336
337 /* Enable bootloader messages */
338 if (btn==BUTTON_RIGHT)
339 verbose = true;
340
341 lcd_setfont(FONT_SYSFIXED);
342
343 printf("Rockbox boot loader");
344 printf("Version: %s", rbversion);
345 printf("IPOD version: 0x%08x", IPOD_HW_REVISION);
346
347 i=ata_init();
348 if (i==0) {
349 identify_info=ata_get_identify();
350 /* Show model */
351 for (i=0; i < 20; i++) {
352 ((unsigned short*)buf)[i]=htobe16(identify_info[i+27]);
353 }
354 buf[40]=0;
355 for (i=39; i && buf[i]==' '; i--) {
356 buf[i]=0;
357 }
358 printf(buf);
359 } else {
360 printf("ATA: %d", i);
361 }
362
363 filesystem_init();
364
365 rc = disk_mount_all();
366 if (rc<=0)
367 {
368#ifdef STORAGE_GET_INFO
369 struct storage_info sinfo;
370 storage_get_info(0, &sinfo);
371#ifdef MAX_PHYS_SECTOR_SIZE
372 printf("id: '%s' s:%u*%u", sinfo.product, sinfo.sector_size, sinfo.phys_sector_mult);
373#else
374 printf("id: '%s' s:%u", sinfo.product, sinfo.sector_size);
375#endif
376#endif
377 for (int i = 0 ; i < NUM_VOLUMES ; i++) {
378 disk_partinfo(i, &pinfo);
379 if (pinfo.type)
380 printf("P%d T%02x S%lllx",
381 i, pinfo.type, (unsigned long long)pinfo.size);
382 }
383
384 printf("No partition found");
385 fatal_error();
386 }
387
388 if (button_was_held || (btn==BUTTON_MENU)) {
389 /* If either the hold switch was on, or the Menu button was held, then
390 try the Apple firmware */
391
392 printf("Loading original firmware...");
393
394 /* First try an apple_os.ipod file on the FAT32 partition
395 (either in .rockbox or the root)
396 */
397
398 rc=load_firmware(loadbuffer, "apple_os.ipod", MAX_LOADSIZE);
399
400 if (rc > 0) {
401 printf("apple_os.ipod loaded.");
402 return (void*)DRAM_START;
403 } else if (rc == EFILE_NOT_FOUND) {
404 /* If apple_os.ipod doesn't exist, then check if there is an Apple
405 firmware image in RAM */
406 haveramos = (memcmp((void*)(DRAM_START+0x20),"portalplayer",12)==0);
407 if (haveramos) {
408 /* We have a copy of the retailos in RAM, lets just run it. */
409 return (void*)DRAM_START;
410 }
411 } else {
412 printf("Error!");
413 printf("Can't load apple_os.ipod:");
414 printf(loader_strerror(rc));
415 }
416
417 /* Everything failed - just loop forever */
418 printf("No RetailOS detected");
419
420 } else if (btn==BUTTON_PLAY) {
421 printf("Loading Linux...");
422 rc=load_raw_firmware(loadbuffer, "/linux.bin", MAX_LOADSIZE);
423 if (rc <= EFILE_EMPTY) {
424 printf("Error!");
425 printf("Can't load linux.bin:");
426 printf(loader_strerror(rc));
427 } else {
428 return (void*)DRAM_START;
429 }
430 } else {
431 printf("Loading Rockbox...");
432 rc=load_firmware(loadbuffer, BOOTFILE, MAX_LOADSIZE);
433 if (rc > 0) {
434 printf("Rockbox loaded.");
435 return (void*)DRAM_START;
436 } else if (rc == EFILE_NOT_FOUND) {
437 /* if rockbox.ipod doesn't exist, then check if there is a Rockbox
438 image in RAM */
439 haveramos = (memcmp((void*)(DRAM_START+0x20),"Rockbox\1",8)==0);
440 if (haveramos) {
441 /* We have a copy of Rockbox in RAM, lets just run it. */
442 return (void*)DRAM_START;
443 }
444 }
445
446 printf("Error!");
447 printf("Can't load " BOOTFILE ": ");
448 printf(loader_strerror(rc));
449 }
450
451 /* If we get to here, then we haven't been able to load any firmware */
452 fatal_error();
453
454 /* We never get here, but keep gcc happy */
455 return (void*)0;
456}