A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 510 lines 14 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2006 by Barry Wardell 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 <stdio.h> 25#include <stdlib.h> 26 27#include "config.h" 28#include "common.h" 29#include "cpu.h" 30#include "file.h" 31#include "system.h" 32#include "../kernel-internal.h" 33#include "lcd.h" 34#include "font.h" 35#include "storage.h" 36#include "file_internal.h" 37#include "adc.h" 38#include "button.h" 39#include "disk.h" 40#include "crc32.h" 41#include "mi4-loader.h" 42#include "loader_strerror.h" 43#include <string.h> 44#include "power.h" 45#include "version.h" 46#if defined(SANSA_E200) || defined(PHILIPS_SA9200) 47#include "i2c.h" 48#include "backlight-target.h" 49#endif 50#include "usb.h" 51#if defined(SANSA_E200) || defined(SANSA_C200) || defined(PHILIPS_SA9200) 52#include "usb_drv.h" 53#endif 54#if defined(SANSA_E200) && defined(HAVE_BOOTLOADER_USB_MODE) 55#include "core_alloc.h" 56#endif 57#if defined(SAMSUNG_YH925) 58/* this function (in lcd-yh925.c) resets the screen orientation for the OF 59 * for use with dualbooting */ 60void lcd_reset(void); 61#endif 62 63/* Show the Rockbox logo - in show_logo.c */ 64extern void show_logo(void); 65 66/* Button definitions */ 67#if CONFIG_KEYPAD == IRIVER_H10_PAD 68#define BOOTLOADER_BOOT_OF BUTTON_LEFT 69 70#elif CONFIG_KEYPAD == SANSA_E200_PAD 71#define BOOTLOADER_BOOT_OF BUTTON_LEFT 72 73#elif CONFIG_KEYPAD == SANSA_C200_PAD 74#define BOOTLOADER_BOOT_OF BUTTON_LEFT 75 76#elif CONFIG_KEYPAD == MROBE100_PAD 77#define BOOTLOADER_BOOT_OF BUTTON_POWER 78 79#elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD 80#define BOOTLOADER_BOOT_OF BUTTON_VOL_UP 81 82#elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD 83#define BOOTLOADER_BOOT_OF BUTTON_MENU 84 85#elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD 86#define BOOTLOADER_BOOT_OF BUTTON_VOL_UP 87 88#elif (CONFIG_KEYPAD == SAMSUNG_YH820_PAD) || \ 89 (CONFIG_KEYPAD == SAMSUNG_YH92X_PAD) 90#define BOOTLOADER_BOOT_OF BUTTON_LEFT 91 92#elif CONFIG_KEYPAD == SANSA_FUZE_PAD 93#define BOOTLOADER_BOOT_OF BUTTON_LEFT 94 95#elif CONFIG_KEYPAD == PBELL_VIBE500_PAD 96#define BOOTLOADER_BOOT_OF BUTTON_OK 97 98#endif 99 100/* Maximum allowed firmware image size. 10MB is more than enough */ 101#define MAX_LOADSIZE (10*1024*1024) 102 103/* A buffer to load the original firmware or Rockbox into */ 104unsigned char *loadbuffer = (unsigned char *)DRAM_START; 105 106/* Locations and sizes in hidden partition on Sansa */ 107#if (CONFIG_STORAGE & STORAGE_SD) 108#define PPMI_SECTOR_OFFSET 1024 109#define PPMI_SECTORS 1 110#define MI4_HEADER_SECTORS 1 111#define NUM_PARTITIONS 2 112 113#else 114#define NUM_PARTITIONS 1 115 116#endif 117 118#define MI4_HEADER_SIZE 0x200 119 120/* PPMI header structure */ 121struct ppmi_header_t { 122 unsigned char magic[4]; 123 uint32_t length; 124 uint32_t pad[126]; 125}; 126 127#if (CONFIG_STORAGE & STORAGE_SD) 128/* Load mi4 firmware from a hidden disk partition */ 129int load_mi4_part(unsigned char* buf, struct partinfo* pinfo, 130 unsigned int buffer_size, bool disable_rebuild) 131{ 132 struct mi4header_t mi4header; 133 struct ppmi_header_t ppmi_header; 134 unsigned long sum; 135 136 /* Read header to find out how long the mi4 file is. */ 137 storage_read_sectors(IF_MD(0,) pinfo->start + PPMI_SECTOR_OFFSET, 138 PPMI_SECTORS, &ppmi_header); 139 140 /* The first four characters at 0x80000 (sector 1024) should be PPMI*/ 141 if( memcmp(ppmi_header.magic, "PPMI", 4) ) 142 return EFILE_NOT_FOUND; 143 144 printf("BL mi4 size: %x", ppmi_header.length); 145 146 /* Read mi4 header of the OF */ 147 storage_read_sectors(IF_MD(0,) pinfo->start + PPMI_SECTOR_OFFSET + PPMI_SECTORS 148 + (ppmi_header.length/512), MI4_HEADER_SECTORS, &mi4header); 149 150 /* We don't support encrypted mi4 files yet */ 151 if( (mi4header.plaintext) != (mi4header.mi4size-MI4_HEADER_SIZE)) 152 return EINVALID_FORMAT; 153 154 /* MI4 file size */ 155 printf("OF mi4 size: %x", mi4header.mi4size); 156 157 if ((mi4header.mi4size-MI4_HEADER_SIZE) > buffer_size) 158 return EFILE_TOO_BIG; 159 160 /* CRC32 */ 161 printf("CRC32: %x", mi4header.crc32); 162 163 /* Rockbox model id */ 164 printf("Model id: %.4s", mi4header.model); 165 166 /* Read binary type (RBOS, RBBL) */ 167 printf("Binary type: %.4s", mi4header.type); 168 169 /* Load firmware */ 170 storage_read_sectors(IF_MD(0,) pinfo->start + PPMI_SECTOR_OFFSET + PPMI_SECTORS 171 + (ppmi_header.length/512) + MI4_HEADER_SECTORS, 172 (mi4header.mi4size-MI4_HEADER_SIZE)/512, buf); 173 174 /* Check CRC32 to see if we have a valid file */ 175 sum = crc_32r (buf,mi4header.mi4size-MI4_HEADER_SIZE,0); 176 177 printf("Calculated CRC32: %x", sum); 178 179 if(sum != mi4header.crc32) 180 return EBAD_CHKSUM; 181 182#ifdef SANSA_E200 183 if (disable_rebuild) 184 { 185 char block[512]; 186 187 printf("Disabling database rebuild"); 188 189 storage_read_sectors(IF_MD(0,) pinfo->start + 0x3c08, 1, block); 190 block[0xe1] = 0; 191 storage_write_sectors(IF_MD(0,) pinfo->start + 0x3c08, 1, block); 192 } 193#else 194 (void) disable_rebuild; 195#endif 196 197 return mi4header.mi4size-MI4_HEADER_SIZE; 198} 199#endif /* (CONFIG_STORAGE & STORAGE_SD) */ 200 201#ifdef HAVE_BOOTLOADER_USB_MODE 202/* Return USB_HANDLED if session took place else return USB_EXTRACTED */ 203static int handle_usb(int connect_timeout) 204{ 205 static struct event_queue q SHAREDBSS_ATTR; 206 struct queue_event ev; 207 int usb = USB_EXTRACTED; 208 long end_tick = 0; 209 210 if (!usb_plugged()) 211 return USB_EXTRACTED; 212 213 queue_init(&q, true); 214 usb_init(); 215 usb_start_monitoring(); 216 217 printf("USB: Connecting"); 218 219 if (connect_timeout != TIMEOUT_BLOCK) 220 end_tick = current_tick + connect_timeout; 221 222 while (1) 223 { 224 /* Sleep no longer than 1/2s */ 225 queue_wait_w_tmo(&q, &ev, HZ/2); 226 227 if (ev.id == SYS_USB_CONNECTED) 228 { 229 /* Switch to verbose mode if not in it so that the status updates 230 * are shown */ 231 verbose = true; 232 /* Got the message - wait for disconnect */ 233 printf("Bootloader USB mode"); 234 235 usb = USB_HANDLED; 236 usb_acknowledge(SYS_USB_CONNECTED_ACK); 237#if defined(SANSA_E200) && defined(HAVE_BOOTLOADER_USB_MODE) 238 /* E200 misses unplug randomly 239 probably fine for other targets too but needs tested */ 240 while (usb_wait_for_disconnect_w_tmo(&q, HZ * 5) > 0) 241 { 242 /* timeout */ 243 if (!usb_plugged()) 244 break; 245 } 246#else 247 usb_wait_for_disconnect(&q); 248#endif 249 break; 250 } 251 252 if (connect_timeout != TIMEOUT_BLOCK && 253 TIME_AFTER(current_tick, end_tick)) 254 { 255 /* Timed out waiting for the connect - will happen when connected 256 * to a charger instead of a host port and the charging pin is 257 * the same as the USB pin */ 258 printf("USB: Timed out"); 259 break; 260 } 261 262 if (!usb_plugged()) 263 break; /* Cable pulled */ 264 } 265 266 usb_close(); 267 queue_delete(&q); 268 269 return usb; 270} 271#elif (defined(SANSA_E200) || defined(SANSA_C200) || defined(PHILIPS_SA9200) \ 272 || defined (SANSA_VIEW)) && !defined(USE_ROCKBOX_USB) 273/* Return USB_INSERTED if cable present */ 274static int handle_usb(int connect_timeout) 275{ 276 int usb_retry = 0; 277 int usb = USB_EXTRACTED; 278 279 usb_init(); 280 while (usb_drv_powered() && usb_retry < 5 && usb != USB_INSERTED) 281 { 282 usb_retry++; 283 sleep(HZ/4); 284 usb = usb_detect(); 285 } 286 287 if (usb != USB_INSERTED) 288 usb = USB_EXTRACTED; 289 290 return usb; 291 (void)connect_timeout; 292} 293#else 294/* Ignore cable state */ 295static int handle_usb(int connect_timeout) 296{ 297 return USB_EXTRACTED; 298 (void)connect_timeout; 299} 300#endif /* HAVE_BOOTLOADER_USB_MODE */ 301 302void* main(void) 303{ 304 int i; 305 int btn; 306 int rc; 307 int num_partitions; 308 struct partinfo pinfo; 309#if !(CONFIG_STORAGE & STORAGE_SD) 310 char buf[256]; 311 unsigned short* identify_info; 312#endif 313 int usb = USB_EXTRACTED; 314 315 system_init(); 316#if defined(SANSA_E200) && defined(HAVE_BOOTLOADER_USB_MODE) 317 core_allocator_init(); 318#endif 319 kernel_init(); 320 321#ifdef HAVE_BOOTLOADER_USB_MODE 322 /* loader must service interrupts */ 323 enable_interrupt(IRQ_FIQ_STATUS); 324#endif 325 326 lcd_init(); 327 328 font_init(); 329 show_logo(); 330 331 adc_init(); 332#ifdef HAVE_BOOTLOADER_USB_MODE 333 button_init_device(); 334#else 335 button_init(); 336#endif 337#if defined(SANSA_E200) || defined(PHILIPS_SA9200) 338 i2c_init(); 339 backlight_hw_on(); 340#endif 341 342 if (button_hold()) 343 { 344 verbose = true; 345 lcd_clear_display(); 346 printf("Hold switch on"); 347 printf("Shutting down..."); 348 sleep(HZ); 349 power_off(); 350 } 351 352 btn = button_read_device(); 353 354 /* Enable bootloader messages if any button is pressed */ 355#ifdef HAVE_BOOTLOADER_USB_MODE 356 lcd_clear_display(); 357 if (btn) 358 verbose = true; 359#else 360 if (btn) { 361 lcd_clear_display(); 362 verbose = true; 363 } 364#endif 365 366 lcd_setfont(FONT_SYSFIXED); 367 368 printf("Rockbox boot loader"); 369 printf("Version: %s", rbversion); 370 printf(MODEL_NAME); 371 372 i=storage_init(); 373#if !(CONFIG_STORAGE & STORAGE_SD) 374 if (i==0) { 375 identify_info=ata_get_identify(); 376 /* Show model */ 377 for (i=0; i < 20; i++) { 378 ((unsigned short*)buf)[i]=htobe16(identify_info[i+27]); 379 } 380 buf[40]=0; 381 for (i=39; i && buf[i]==' '; i--) { 382 buf[i]=0; 383 } 384 printf(buf); 385 } else { 386 error(EATA, i, true); 387 } 388#endif 389 390 filesystem_init(); 391 num_partitions = disk_mount_all(); 392 if (num_partitions<=0) 393 { 394 error(EDISK,num_partitions, true); 395 } 396 397 /* Just list the first 2 partitions since we don't have any devices yet 398 that have more than that */ 399 for(i=0; i<NUM_PARTITIONS; i++) 400 { 401 disk_partinfo(i, &pinfo); 402 printf("Partition %d: 0x%02x %ld MB", 403 i, pinfo.type, pinfo.size / 2048); 404 } 405 406 /* Now that storage is initialized, check for USB connection */ 407 if ((btn & BOOTLOADER_BOOT_OF) == 0) 408 { 409 usb_pin_init(); 410 usb = handle_usb(HZ*2); 411 if (usb == USB_INSERTED) 412 btn |= BOOTLOADER_BOOT_OF; 413 } 414 415 /* Try loading Rockbox, if that fails, fall back to the OF */ 416 if((btn & BOOTLOADER_BOOT_OF) == 0) 417 { 418 printf("Loading Rockbox..."); 419 420 rc = load_mi4(loadbuffer, BOOTFILE, MAX_LOADSIZE); 421 if (rc <= EFILE_EMPTY) 422 { 423 bool old_verbose = verbose; 424 verbose = true; 425 printf("Can't load " BOOTFILE ": "); 426 printf(loader_strerror(rc)); 427 verbose = old_verbose; 428 btn |= BOOTLOADER_BOOT_OF; 429 sleep(5*HZ); 430 } 431 else 432 goto main_exit; 433 } 434 435 if(btn & BOOTLOADER_BOOT_OF) 436 { 437 /* Load original mi4 firmware in to a memory buffer called loadbuffer. 438 The rest of the loading is done in crt0.S. 439 1) First try reading from the hidden partition (on Sansa only). 440 2) Next try a decrypted mi4 file in /System/OF.mi4 441 3) Finally, try a raw firmware binary in /System/OF.bin. It should be 442 a mi4 firmware decrypted and header stripped using mi4code. 443 */ 444 printf("Loading original firmware..."); 445 446#if (CONFIG_STORAGE & STORAGE_SD) 447 /* First try a (hidden) firmware partition */ 448 printf("Trying firmware partition"); 449 disk_partinfo(1, &pinfo); 450 if(pinfo.type == PARTITION_TYPE_OS2_HIDDEN_C_DRIVE) 451 { 452 rc = load_mi4_part(loadbuffer, &pinfo, MAX_LOADSIZE, 453 usb == USB_INSERTED); 454 if (rc <= EFILE_EMPTY) { 455 printf("Can't load from partition"); 456 printf(loader_strerror(rc)); 457 } else { 458 goto main_exit; 459 } 460 } else { 461 printf("No hidden partition found."); 462 } 463#endif 464 465#if defined(PHILIPS_HDD1630) || defined(PHILIPS_HDD6330) || defined(PHILIPS_SA9200) 466 printf("Trying /System/OF.ebn"); 467 rc=load_mi4(loadbuffer, "/System/OF.ebn", MAX_LOADSIZE); 468 if (rc <= EFILE_EMPTY) { 469 printf("Can't load /System/OF.ebn"); 470 printf(loader_strerror(rc)); 471 } else { 472 goto main_exit; 473 } 474#endif 475 476 printf("Trying /System/OF.mi4"); 477 rc=load_mi4(loadbuffer, "/System/OF.mi4", MAX_LOADSIZE); 478 if (rc <= EFILE_EMPTY) { 479 printf("Can't load /System/OF.mi4"); 480 printf(loader_strerror(rc)); 481 } else { 482#if defined(SAMSUNG_YH925) 483 lcd_reset(); 484#endif 485 goto main_exit; 486 } 487 488 printf("Trying /System/OF.bin"); 489 rc=load_raw_firmware(loadbuffer, "/System/OF.bin", MAX_LOADSIZE); 490 if (rc <= EFILE_EMPTY) { 491 printf("Can't load /System/OF.bin"); 492 printf(loader_strerror(rc)); 493 } else { 494#if defined(SAMSUNG_YH925) 495 lcd_reset(); 496#endif 497 goto main_exit; 498 } 499 500 error(0, 0, true); 501 } 502 503main_exit: 504#ifdef HAVE_BOOTLOADER_USB_MODE 505 storage_close(); 506 system_prepare_fw_start(); 507#endif 508 509 return (void*)loadbuffer; 510}