Linus Nielsen Feltzing | c5df4f8 | 2007-02-23 09:30:09 +0000 | [diff] [blame] | 1 | /*************************************************************************** |
| 2 | * __________ __ ___. |
| 3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| 4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| 7 | * \/ \/ \/ \/ \/ |
| 8 | * $Id$ |
| 9 | * |
| 10 | * Copyright (C) 2006 by Greg White |
| 11 | * |
| 12 | * All files in this archive are subject to the GNU General Public License. |
| 13 | * See the file COPYING in the source tree root for full license agreement. |
| 14 | * |
| 15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| 16 | * KIND, either express or implied. |
| 17 | * |
| 18 | ****************************************************************************/ |
Marcoen Hirschberg | 0a06824 | 2006-08-12 08:27:48 +0000 | [diff] [blame] | 19 | #include "config.h" |
| 20 | |
| 21 | #include <stdlib.h> |
| 22 | #include <stdio.h> |
| 23 | #include <string.h> |
| 24 | #include "cpu.h" |
| 25 | #include "system.h" |
| 26 | #include "lcd.h" |
| 27 | #include "kernel.h" |
| 28 | #include "thread.h" |
| 29 | #include "ata.h" |
| 30 | #include "fat.h" |
| 31 | #include "disk.h" |
| 32 | #include "font.h" |
| 33 | #include "adc.h" |
| 34 | #include "backlight.h" |
| 35 | #include "panic.h" |
| 36 | #include "power.h" |
| 37 | #include "file.h" |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 38 | #include "button-target.h" |
Linus Nielsen Feltzing | 46597c9 | 2007-02-22 15:09:49 +0000 | [diff] [blame] | 39 | #include "common.h" |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 40 | |
Greg White | 8b3c879 | 2007-01-17 01:49:19 +0000 | [diff] [blame] | 41 | extern void map_memory(void); |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 42 | |
Marcoen Hirschberg | 0a06824 | 2006-08-12 08:27:48 +0000 | [diff] [blame] | 43 | char version[] = APPSVERSION; |
| 44 | |
Greg White | 8b3c879 | 2007-01-17 01:49:19 +0000 | [diff] [blame] | 45 | static void go_usb_mode(void) |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 46 | { |
Greg White | 8b3c879 | 2007-01-17 01:49:19 +0000 | [diff] [blame] | 47 | /* Drop into USB mode. This does not check for disconnection. */ |
Marcoen Hirschberg | 0a06824 | 2006-08-12 08:27:48 +0000 | [diff] [blame] | 48 | int i; |
| 49 | |
| 50 | GPBDAT &= 0x7EF; |
| 51 | GPBCON |= 1<<8; |
| 52 | |
| 53 | GPGDAT &= 0xE7FF; |
| 54 | GPGDAT |= 1<<11; |
| 55 | |
Greg White | 8b3c879 | 2007-01-17 01:49:19 +0000 | [diff] [blame] | 56 | for(i = 0; i < 10000000; i++) { |
| 57 | continue; |
| 58 | } |
Marcoen Hirschberg | 0a06824 | 2006-08-12 08:27:48 +0000 | [diff] [blame] | 59 | |
| 60 | GPBCON &= 0x2FFCFF; |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 61 | GPBDAT |= 1<<5; |
Marcoen Hirschberg | 0a06824 | 2006-08-12 08:27:48 +0000 | [diff] [blame] | 62 | GPBDAT |= 1<<6; |
| 63 | } |
| 64 | |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 65 | |
| 66 | /* Restores a factory kernel/bootloader from a known location */ |
| 67 | /* Restores the FWIMG01.DAT file back in the case of a bootloader failure */ |
| 68 | /* The factory or "good" bootloader must be in /GBSYSTEM/FWIMG/FWIMG01.DAT.ORIG */ |
| 69 | /* Returns non-zero on failure */ |
| 70 | int restore_fwimg01dat(void) |
| 71 | { |
| 72 | int orig_file = 0, dest_file = 0; |
| 73 | int size = 0, size_read; |
Greg White | 8b3c879 | 2007-01-17 01:49:19 +0000 | [diff] [blame] | 74 | static char buf[4096]; |
Linus Nielsen Feltzing | 46597c9 | 2007-02-22 15:09:49 +0000 | [diff] [blame] | 75 | |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 76 | orig_file = open("/GBSYSTEM/FWIMG/FWIMG01.DAT.ORIG", O_RDONLY); |
Greg White | 8b3c879 | 2007-01-17 01:49:19 +0000 | [diff] [blame] | 77 | if(orig_file < 0) { |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 78 | /* Couldn't open source file */ |
Linus Nielsen Feltzing | 46597c9 | 2007-02-22 15:09:49 +0000 | [diff] [blame] | 79 | printf("Couldn't open FWIMG01.DAT.ORIG for reading"); |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 80 | return(1); |
| 81 | } |
| 82 | |
Linus Nielsen Feltzing | 46597c9 | 2007-02-22 15:09:49 +0000 | [diff] [blame] | 83 | printf("FWIMG01.DAT.ORIG opened for reading"); |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 84 | |
| 85 | dest_file = open("/GBSYSTEM/FWIMG/FWIMG01.DAT", O_RDWR); |
Greg White | 8b3c879 | 2007-01-17 01:49:19 +0000 | [diff] [blame] | 86 | if(dest_file < 0) { |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 87 | /* Couldn't open destination file */ |
Linus Nielsen Feltzing | 46597c9 | 2007-02-22 15:09:49 +0000 | [diff] [blame] | 88 | printf("Couldn't open FWIMG01.DAT.ORIG for writing"); |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 89 | close(orig_file); |
| 90 | return(2); |
| 91 | } |
| 92 | |
Linus Nielsen Feltzing | 46597c9 | 2007-02-22 15:09:49 +0000 | [diff] [blame] | 93 | printf("FWIMG01.DAT opened for writing"); |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 94 | |
| 95 | do { |
| 96 | /* Copy in chunks */ |
| 97 | size_read = read(orig_file, buf, sizeof(buf)); |
Greg White | 8b3c879 | 2007-01-17 01:49:19 +0000 | [diff] [blame] | 98 | if(size_read != write(dest_file, buf, size_read)) { |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 99 | close(orig_file); |
| 100 | close(dest_file); |
| 101 | return(3); |
| 102 | } |
| 103 | size += size_read; |
| 104 | |
Greg White | 8b3c879 | 2007-01-17 01:49:19 +0000 | [diff] [blame] | 105 | } while(size_read > 0); |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 106 | |
| 107 | close(orig_file); |
| 108 | close(dest_file); |
| 109 | |
Linus Nielsen Feltzing | 46597c9 | 2007-02-22 15:09:49 +0000 | [diff] [blame] | 110 | printf("Finished copying %ld bytes from", size); |
| 111 | printf("FWIMG01.DAT.ORIG to FWIMG01.DAT"); |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 112 | |
| 113 | return(0); |
| 114 | } |
| 115 | |
Greg White | 3b65fc2 | 2007-01-17 18:31:40 +0000 | [diff] [blame] | 116 | char buf[256]; |
| 117 | |
| 118 | void display_instructions(void) |
| 119 | { |
| 120 | lcd_setfont(FONT_SYSFIXED); |
Linus Nielsen Feltzing | 46597c9 | 2007-02-22 15:09:49 +0000 | [diff] [blame] | 121 | printf("Hold MENU when booting for rescue mode."); |
| 122 | printf(" \"VOL+\" button to restore original kernel"); |
| 123 | printf(" \"A\" button to load original firmware"); |
| 124 | printf(""); |
| 125 | printf("FRAME %x TTB %x", FRAME, TTB_BASE); |
Greg White | 3b65fc2 | 2007-01-17 18:31:40 +0000 | [diff] [blame] | 126 | } |
Greg White | 8b3c879 | 2007-01-17 01:49:19 +0000 | [diff] [blame] | 127 | |
Marcoen Hirschberg | 0a06824 | 2006-08-12 08:27:48 +0000 | [diff] [blame] | 128 | void * main(void) |
| 129 | { |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 130 | int i; |
Marcoen Hirschberg | 0a06824 | 2006-08-12 08:27:48 +0000 | [diff] [blame] | 131 | struct partinfo* pinfo; |
| 132 | unsigned short* identify_info; |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 133 | unsigned char* loadbuffer; |
| 134 | int buffer_size; |
| 135 | bool load_original = false; |
| 136 | int rc; |
| 137 | int(*kernel_entry)(void); |
Marcoen Hirschberg | 0a06824 | 2006-08-12 08:27:48 +0000 | [diff] [blame] | 138 | |
Greg White | 8b3c879 | 2007-01-17 01:49:19 +0000 | [diff] [blame] | 139 | bool show_bootsplash = true; |
Marcoen Hirschberg | 0a06824 | 2006-08-12 08:27:48 +0000 | [diff] [blame] | 140 | |
Greg White | 8b3c879 | 2007-01-17 01:49:19 +0000 | [diff] [blame] | 141 | if(GPGDAT & 2) |
| 142 | show_bootsplash = false; |
Marcoen Hirschberg | 0a06824 | 2006-08-12 08:27:48 +0000 | [diff] [blame] | 143 | |
Greg White | 8b3c879 | 2007-01-17 01:49:19 +0000 | [diff] [blame] | 144 | if(!show_bootsplash) { |
Greg White | 3b65fc2 | 2007-01-17 18:31:40 +0000 | [diff] [blame] | 145 | lcd_init(); |
| 146 | display_instructions(); |
Greg White | 8b3c879 | 2007-01-17 01:49:19 +0000 | [diff] [blame] | 147 | sleep(2*HZ); |
Greg White | 3b65fc2 | 2007-01-17 18:31:40 +0000 | [diff] [blame] | 148 | } |
Greg White | 8b3c879 | 2007-01-17 01:49:19 +0000 | [diff] [blame] | 149 | if(GPGDAT & 2) { |
Greg White | 3b65fc2 | 2007-01-17 18:31:40 +0000 | [diff] [blame] | 150 | lcd_init(); |
Linus Nielsen Feltzing | 46597c9 | 2007-02-22 15:09:49 +0000 | [diff] [blame] | 151 | printf("Entering rescue mode.."); |
Marcoen Hirschberg | 0a06824 | 2006-08-12 08:27:48 +0000 | [diff] [blame] | 152 | go_usb_mode(); |
| 153 | while(1); |
| 154 | } |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 155 | if(GPGDAT & 0x10) { |
Greg White | 3b65fc2 | 2007-01-17 18:31:40 +0000 | [diff] [blame] | 156 | lcd_init(); |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 157 | load_original = true; |
Linus Nielsen Feltzing | 46597c9 | 2007-02-22 15:09:49 +0000 | [diff] [blame] | 158 | printf("Loading original firmware..."); |
Greg White | 8b3c879 | 2007-01-17 01:49:19 +0000 | [diff] [blame] | 159 | } |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 160 | |
Marcoen Hirschberg | 0a06824 | 2006-08-12 08:27:48 +0000 | [diff] [blame] | 161 | i = ata_init(); |
| 162 | i = disk_mount_all(); |
Greg White | 8b3c879 | 2007-01-17 01:49:19 +0000 | [diff] [blame] | 163 | if(!show_bootsplash) { |
Linus Nielsen Feltzing | 46597c9 | 2007-02-22 15:09:49 +0000 | [diff] [blame] | 164 | printf("disk_mount_all: %d", i); |
Greg White | 8b3c879 | 2007-01-17 01:49:19 +0000 | [diff] [blame] | 165 | } |
Greg White | 3b65fc2 | 2007-01-17 18:31:40 +0000 | [diff] [blame] | 166 | if(show_bootsplash) { |
| 167 | int fd = open("/bootsplash.raw", O_RDONLY); |
| 168 | if(fd < 0) { |
| 169 | show_bootsplash = false; |
| 170 | lcd_init(); |
| 171 | display_instructions(); |
| 172 | } |
| 173 | else { |
| 174 | read(fd, lcd_framebuffer, LCD_WIDTH*LCD_HEIGHT*2); |
| 175 | close(fd); |
| 176 | lcd_update(); |
| 177 | lcd_init(); |
| 178 | } |
| 179 | } |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 180 | /* hold VOL+ to enter rescue mode to copy old image */ |
| 181 | /* needs to be after ata_init and disk_mount_all */ |
Greg White | 8b3c879 | 2007-01-17 01:49:19 +0000 | [diff] [blame] | 182 | if(GPGDAT & 4) { |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 183 | |
| 184 | /* Try to restore the original kernel/bootloader if a copy is found */ |
Linus Nielsen Feltzing | 46597c9 | 2007-02-22 15:09:49 +0000 | [diff] [blame] | 185 | printf("Restoring FWIMG01.DAT..."); |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 186 | |
Greg White | 8b3c879 | 2007-01-17 01:49:19 +0000 | [diff] [blame] | 187 | if(!restore_fwimg01dat()) { |
Linus Nielsen Feltzing | 46597c9 | 2007-02-22 15:09:49 +0000 | [diff] [blame] | 188 | printf("Restoring FWIMG01.DAT successful."); |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 189 | } else { |
Linus Nielsen Feltzing | 46597c9 | 2007-02-22 15:09:49 +0000 | [diff] [blame] | 190 | printf("Restoring FWIMG01.DAT failed."); |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 191 | } |
| 192 | |
Linus Nielsen Feltzing | 46597c9 | 2007-02-22 15:09:49 +0000 | [diff] [blame] | 193 | printf("Now power cycle to boot original"); |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 194 | while(1); |
| 195 | } |
| 196 | |
Greg White | 8b3c879 | 2007-01-17 01:49:19 +0000 | [diff] [blame] | 197 | if(!show_bootsplash) { |
| 198 | identify_info = ata_get_identify(); |
| 199 | |
| 200 | for(i=0; i < 20; i++) |
| 201 | ((unsigned short*)buf)[i]=htobe16(identify_info[i+27]); |
| 202 | |
| 203 | buf[40]=0; |
| 204 | |
| 205 | /* kill trailing space */ |
| 206 | for(i=39; i && buf[i]==' '; i--) |
| 207 | buf[i] = 0; |
| 208 | |
Linus Nielsen Feltzing | 46597c9 | 2007-02-22 15:09:49 +0000 | [diff] [blame] | 209 | printf("Model"); |
| 210 | printf(buf); |
Greg White | 8b3c879 | 2007-01-17 01:49:19 +0000 | [diff] [blame] | 211 | |
| 212 | for(i=0; i < 4; i++) |
| 213 | ((unsigned short*)buf)[i]=htobe16(identify_info[i+23]); |
| 214 | |
| 215 | buf[8]=0; |
| 216 | |
Linus Nielsen Feltzing | 46597c9 | 2007-02-22 15:09:49 +0000 | [diff] [blame] | 217 | printf("Firmware"); |
| 218 | printf(buf); |
Greg White | 8b3c879 | 2007-01-17 01:49:19 +0000 | [diff] [blame] | 219 | |
| 220 | pinfo = disk_partinfo(0); |
Linus Nielsen Feltzing | 46597c9 | 2007-02-22 15:09:49 +0000 | [diff] [blame] | 221 | printf("Partition 0: 0x%02x %ld MB", pinfo->type, pinfo->size / 2048); |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 222 | } |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 223 | /* Load original firmware */ |
| 224 | if(load_original) { |
| 225 | loadbuffer = (unsigned char*)0x30008000; |
| 226 | buffer_size =(unsigned char*)0x31000000 - loadbuffer; |
Nicolas Pennequin | bd073cd | 2007-02-22 21:19:48 +0000 | [diff] [blame] | 227 | rc = load_raw_firmware(loadbuffer, "/rockbox.gigabeat", buffer_size); |
Linus Nielsen Feltzing | 46597c9 | 2007-02-22 15:09:49 +0000 | [diff] [blame] | 228 | if(rc < EOK) { |
| 229 | printf("Error!"); |
| 230 | printf("Failed to load original firmware:"); |
| 231 | printf(strerror(rc)); |
| 232 | printf("Loading rockbox"); |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 233 | sleep(2*HZ); |
| 234 | goto load_rockbox; |
| 235 | } |
| 236 | |
Linus Nielsen Feltzing | 46597c9 | 2007-02-22 15:09:49 +0000 | [diff] [blame] | 237 | printf("Loaded: %d", rc); |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 238 | sleep(2*HZ); |
| 239 | |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 240 | (*((int*)0x7000000)) = 333; |
| 241 | rc = *((int*)0x7000000+0x8000000); |
Linus Nielsen Feltzing | 46597c9 | 2007-02-22 15:09:49 +0000 | [diff] [blame] | 242 | printf("Bank0 mem test: %d", rc); |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 243 | sleep(3*HZ); |
| 244 | |
Linus Nielsen Feltzing | 46597c9 | 2007-02-22 15:09:49 +0000 | [diff] [blame] | 245 | printf("Woops, should not return from firmware!"); |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 246 | goto usb; |
| 247 | } |
| 248 | |
| 249 | load_rockbox: |
| 250 | map_memory(); |
Greg White | 8b3c879 | 2007-01-17 01:49:19 +0000 | [diff] [blame] | 251 | if(!show_bootsplash) { |
Linus Nielsen Feltzing | 46597c9 | 2007-02-22 15:09:49 +0000 | [diff] [blame] | 252 | printf("Loading Rockbox..."); |
Greg White | 8b3c879 | 2007-01-17 01:49:19 +0000 | [diff] [blame] | 253 | } |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 254 | |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 255 | loadbuffer = (unsigned char*) 0x100; |
| 256 | buffer_size = (unsigned char*)0x400000 - loadbuffer; |
Nicolas Pennequin | bd073cd | 2007-02-22 21:19:48 +0000 | [diff] [blame] | 257 | rc = load_raw_firmware(loadbuffer, "/rockbox.gigabeat", buffer_size); |
Linus Nielsen Feltzing | 46597c9 | 2007-02-22 15:09:49 +0000 | [diff] [blame] | 258 | if(rc < EOK) { |
| 259 | printf("Error!"); |
| 260 | printf("Can't load rockbox.gigabeat:"); |
| 261 | printf(strerror(rc)); |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 262 | } else { |
Greg White | 8b3c879 | 2007-01-17 01:49:19 +0000 | [diff] [blame] | 263 | if(!show_bootsplash) { |
Linus Nielsen Feltzing | 46597c9 | 2007-02-22 15:09:49 +0000 | [diff] [blame] | 264 | printf("Rockbox loaded."); |
Greg White | 8b3c879 | 2007-01-17 01:49:19 +0000 | [diff] [blame] | 265 | } |
Greg White | 355be50 | 2007-01-13 02:24:15 +0000 | [diff] [blame] | 266 | kernel_entry = (void*) loadbuffer; |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 267 | rc = kernel_entry(); |
Linus Nielsen Feltzing | 46597c9 | 2007-02-22 15:09:49 +0000 | [diff] [blame] | 268 | printf("Woops, should not return from firmware: %d", rc); |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 269 | goto usb; |
| 270 | } |
Marcoen Hirschberg | 2953676 | 2006-12-29 02:49:12 +0000 | [diff] [blame] | 271 | usb: |
Marcoen Hirschberg | 0a06824 | 2006-08-12 08:27:48 +0000 | [diff] [blame] | 272 | /* now wait in USB mode so the bootloader can be updated */ |
| 273 | go_usb_mode(); |
| 274 | while(1); |
| 275 | |
Greg White | 8b3c879 | 2007-01-17 01:49:19 +0000 | [diff] [blame] | 276 | return((void *)0); |
Marcoen Hirschberg | 0a06824 | 2006-08-12 08:27:48 +0000 | [diff] [blame] | 277 | } |
| 278 | |