/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2006 by Greg White * * All files in this archive are subject to the GNU General Public License. * See the file COPYING in the source tree root for full license agreement. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #include "config.h" #include #include #include #include "cpu.h" #include "system.h" #include "lcd.h" #include "kernel.h" #include "thread.h" #include "ata.h" #include "fat.h" #include "disk.h" #include "font.h" #include "adc.h" #include "backlight.h" #include "panic.h" #include "power.h" #include "file.h" #include "button-target.h" #include "common.h" extern void map_memory(void); char version[] = APPSVERSION; static void go_usb_mode(void) { /* Drop into USB mode. This does not check for disconnection. */ int i; GPBDAT &= 0x7EF; GPBCON |= 1<<8; GPGDAT &= 0xE7FF; GPGDAT |= 1<<11; for(i = 0; i < 10000000; i++) { continue; } GPBCON &= 0x2FFCFF; GPBDAT |= 1<<5; GPBDAT |= 1<<6; } /* Restores a factory kernel/bootloader from a known location */ /* Restores the FWIMG01.DAT file back in the case of a bootloader failure */ /* The factory or "good" bootloader must be in /GBSYSTEM/FWIMG/FWIMG01.DAT.ORIG */ /* Returns non-zero on failure */ int restore_fwimg01dat(void) { int orig_file = 0, dest_file = 0; int size = 0, size_read; static char buf[4096]; orig_file = open("/GBSYSTEM/FWIMG/FWIMG01.DAT.ORIG", O_RDONLY); if(orig_file < 0) { /* Couldn't open source file */ printf("Couldn't open FWIMG01.DAT.ORIG for reading"); return(1); } printf("FWIMG01.DAT.ORIG opened for reading"); dest_file = open("/GBSYSTEM/FWIMG/FWIMG01.DAT", O_RDWR); if(dest_file < 0) { /* Couldn't open destination file */ printf("Couldn't open FWIMG01.DAT.ORIG for writing"); close(orig_file); return(2); } printf("FWIMG01.DAT opened for writing"); do { /* Copy in chunks */ size_read = read(orig_file, buf, sizeof(buf)); if(size_read != write(dest_file, buf, size_read)) { close(orig_file); close(dest_file); return(3); } size += size_read; } while(size_read > 0); close(orig_file); close(dest_file); printf("Finished copying %ld bytes from", size); printf("FWIMG01.DAT.ORIG to FWIMG01.DAT"); return(0); } char buf[256]; void display_instructions(void) { lcd_setfont(FONT_SYSFIXED); printf("Hold MENU when booting for rescue mode."); printf(" \"VOL+\" button to restore original kernel"); printf(" \"A\" button to load original firmware"); printf(""); printf("FRAME %x TTB %x", FRAME, TTB_BASE); } void * main(void) { int i; struct partinfo* pinfo; unsigned short* identify_info; unsigned char* loadbuffer; int buffer_size; bool load_original = false; int rc; int(*kernel_entry)(void); bool show_bootsplash = true; if(GPGDAT & 2) show_bootsplash = false; if(!show_bootsplash) { lcd_init(); display_instructions(); sleep(2*HZ); } if(GPGDAT & 2) { lcd_init(); printf("Entering rescue mode.."); go_usb_mode(); while(1); } if(GPGDAT & 0x10) { lcd_init(); load_original = true; printf("Loading original firmware..."); } i = ata_init(); i = disk_mount_all(); if(!show_bootsplash) { printf("disk_mount_all: %d", i); } if(show_bootsplash) { int fd = open("/bootsplash.raw", O_RDONLY); if(fd < 0) { show_bootsplash = false; lcd_init(); display_instructions(); } else { read(fd, lcd_framebuffer, LCD_WIDTH*LCD_HEIGHT*2); close(fd); lcd_update(); lcd_init(); } } /* hold VOL+ to enter rescue mode to copy old image */ /* needs to be after ata_init and disk_mount_all */ if(GPGDAT & 4) { /* Try to restore the original kernel/bootloader if a copy is found */ printf("Restoring FWIMG01.DAT..."); if(!restore_fwimg01dat()) { printf("Restoring FWIMG01.DAT successful."); } else { printf("Restoring FWIMG01.DAT failed."); } printf("Now power cycle to boot original"); while(1); } if(!show_bootsplash) { identify_info = ata_get_identify(); for(i=0; i < 20; i++) ((unsigned short*)buf)[i]=htobe16(identify_info[i+27]); buf[40]=0; /* kill trailing space */ for(i=39; i && buf[i]==' '; i--) buf[i] = 0; printf("Model"); printf(buf); for(i=0; i < 4; i++) ((unsigned short*)buf)[i]=htobe16(identify_info[i+23]); buf[8]=0; printf("Firmware"); printf(buf); pinfo = disk_partinfo(0); printf("Partition 0: 0x%02x %ld MB", pinfo->type, pinfo->size / 2048); } /* Load original firmware */ if(load_original) { loadbuffer = (unsigned char*)0x30008000; buffer_size =(unsigned char*)0x31000000 - loadbuffer; rc = load_raw_firmware(loadbuffer, "/rockbox.gigabeat", buffer_size); if(rc < EOK) { printf("Error!"); printf("Failed to load original firmware:"); printf(strerror(rc)); printf("Loading rockbox"); sleep(2*HZ); goto load_rockbox; } printf("Loaded: %d", rc); sleep(2*HZ); (*((int*)0x7000000)) = 333; rc = *((int*)0x7000000+0x8000000); printf("Bank0 mem test: %d", rc); sleep(3*HZ); printf("Woops, should not return from firmware!"); goto usb; } load_rockbox: map_memory(); if(!show_bootsplash) { printf("Loading Rockbox..."); } loadbuffer = (unsigned char*) 0x100; buffer_size = (unsigned char*)0x400000 - loadbuffer; rc = load_raw_firmware(loadbuffer, "/rockbox.gigabeat", buffer_size); if(rc < EOK) { printf("Error!"); printf("Can't load rockbox.gigabeat:"); printf(strerror(rc)); } else { if(!show_bootsplash) { printf("Rockbox loaded."); } kernel_entry = (void*) loadbuffer; rc = kernel_entry(); printf("Woops, should not return from firmware: %d", rc); goto usb; } usb: /* now wait in USB mode so the bootloader can be updated */ go_usb_mode(); while(1); return((void *)0); }