A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 456 lines 14 kB view raw
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}