/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id: h10.c,v 1.4 2006-08-28 08:11:32 barrywardell Exp $ * * Copyright (C) 2006 by Barry Wardell * * Based on Rockbox iriver bootloader by Linus Nielsen Feltzing * and the ipodlinux bootloader by Daniel Palffy and Bernard Leach * * 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 "button.h" #include "panic.h" #include "power.h" #include "file.h" #define MAX_MENU_COUNT 2 int menu_count=2; int time_left=5; int lasttick; #define MENU_GLOBAL_BORDER 10 #define MENU_GLOBAL_BORDER_Y 30 #define MENU_LINE_HEIGHT 8 #define MENU_CURENT_Y_POS i*MENU_LINE_HEIGHT #define MENU_FW_LIST_HEIGHT (menu_count)*MENU_LINE_HEIGHT #define MENU_CENTER_BORDER LCD_WIDTH-2*MENU_GLOBAL_BORDER #define FW_ROCKBOX 0 #define FW_SANDISK 1 struct firmwares { char descr[32]; char filename[256]; int fw_type; bool exists; }; static struct firmwares items[MAX_MENU_COUNT] = {{"Sansa","OF.bin",FW_SANDISK,false},\ {"Rockbox",BOOTFILE,FW_ROCKBOX,false}}; /* Size of the buffer to store the loaded Rockbox/Sansa image */ #define MAX_LOADSIZE (10*1024*1024) /* A buffer to load the iriver firmware or Rockbox into */ unsigned char loadbuffer[MAX_LOADSIZE]; char version[] = APPSVERSION; /* To store the original state of the GPIOs. We only use A-F in the bootloader */ unsigned long gpio_en[7]; unsigned long gpio_output_en[7]; int curent_line = 0; #define DRAM_START 0x10000000 int line=0; /* Save the initial GPIO status from the Sansa bootloader */ void gpio_save(void) { int i = 0; gpio_en[i] = GPIOA_ENABLE; gpio_output_en[i++] = GPIOA_OUTPUT_EN; gpio_en[i] = GPIOB_ENABLE; gpio_output_en[i++] = GPIOB_OUTPUT_EN; gpio_en[i] = GPIOC_ENABLE; gpio_output_en[i++] = GPIOC_OUTPUT_EN; gpio_en[i] = GPIOD_ENABLE; gpio_output_en[i++] = GPIOD_OUTPUT_EN; gpio_en[i] = GPIOE_ENABLE; gpio_output_en[i++] = GPIOE_OUTPUT_EN; gpio_en[i] = GPIOF_ENABLE; gpio_output_en[i++] = GPIOF_OUTPUT_EN; gpio_en[i] = GPIOG_ENABLE; gpio_output_en[i++] = GPIOG_OUTPUT_EN; } /* Restore the GPIO status */ void gpio_restore(void) { int i = 0; GPIOA_ENABLE = gpio_en[i]; GPIOA_OUTPUT_EN = gpio_output_en[i++]; GPIOB_ENABLE = gpio_en[i]; GPIOB_OUTPUT_EN = gpio_output_en[i++]; GPIOC_ENABLE = gpio_en[i]; GPIOC_OUTPUT_EN = gpio_output_en[i++]; GPIOD_ENABLE = gpio_en[i]; GPIOD_OUTPUT_EN = gpio_output_en[i++]; GPIOE_ENABLE = gpio_en[i]; GPIOE_OUTPUT_EN = gpio_output_en[i++]; GPIOF_ENABLE = gpio_en[i]; GPIOF_OUTPUT_EN = gpio_output_en[i++]; GPIOG_ENABLE = gpio_en[i]; GPIOG_OUTPUT_EN = gpio_output_en[i++]; } /* Load original iriver firmware. This function expects a file called "/System/Original.mi4" on the player. It should be decrypted and have the header stripped using mi4code. It reads the file in to a memory buffer called buf. The rest of the loading is done in main() and crt0.S */ int load_iriver(unsigned char* buf) { int fd; int rc; int len; fd = open("/.rockbox/OF.bin", O_RDONLY); len = filesize(fd); if (len > MAX_LOADSIZE) return -6; rc = read(fd, buf, len); if(rc < len) return -4; close(fd); gpio_restore(); return len; } /* Load Rockbox firmware (rockbox.h10) */ int load_rockbox(unsigned char* buf) { int fd; int rc; int len; unsigned long chksum; char model[5]; unsigned long sum; int i; char str[80]; fd = open("/.rockbox/" BOOTFILE, O_RDONLY); if(fd < 0) { fd = open("/" BOOTFILE, O_RDONLY); if(fd < 0) return -1; } len = filesize(fd) - 8; snprintf(str, sizeof(str), "Length: %x", len); lcd_puts(0, line++ ,str); lcd_update(); if (len > MAX_LOADSIZE) return -6; lseek(fd, FIRMWARE_OFFSET_FILE_CRC, SEEK_SET); rc = read(fd, &chksum, 4); chksum=betoh32(chksum); /* Rockbox checksums are big-endian */ if(rc < 4) return -2; snprintf(str, sizeof(str), "Checksum: %x", chksum); lcd_puts(0, line++ ,str); lcd_update(); rc = read(fd, model, 4); if(rc < 4) return -3; model[4] = 0; snprintf(str, sizeof(str), "Model name: %s", model); lcd_puts(0, line++ ,str); lcd_update(); lseek(fd, FIRMWARE_OFFSET_FILE_DATA, SEEK_SET); rc = read(fd, buf, len); if(rc < len) return -4; close(fd); sum = MODEL_NUMBER; for(i = 0;i < len;i++) { sum += buf[i]; } /* I don't know why my checksums aren't matching. Figure this out before committing. Hack around it for now */ sum += 4; snprintf(str, sizeof(str), "Sum: %x", sum); lcd_puts(0, line++ ,str); lcd_update(); if(sum != chksum) return -5; return len; } #define MAX_LOG_COUNT 10 char sclog[MAX_LOG_COUNT][128]; int slogcount = 0; void draw_items(void) { char buf[256]; int font_h, font_w; int i; lcd_getstringsize((unsigned char *)"A", &font_w, &font_h); lcd_clear_display(); lcd_drawrect(MENU_GLOBAL_BORDER, MENU_GLOBAL_BORDER_Y, MENU_CENTER_BORDER, menu_count*MENU_LINE_HEIGHT+4); for (i=0;itype, pinfo->size / 2048); slog(buf); lasttick = current_tick; time_left = 5; while (!selected) { sleep(HZ/10); i=button_read_device(); switch (i) { case BUTTON_UP: { curent_line--; if (curent_line<0) curent_line = menu_count -1; draw_items(); time_left= -1; break; } case BUTTON_DOWN: { curent_line++; if (curent_line>menu_count-1) curent_line = 0; draw_items(); time_left= -1; break; } case BUTTON_SELECT: { selected = true; break; } } if ((time_left>0)&((current_tick - lasttick)>HZ)) { time_left--; if (time_left==0) { slog("Autoloading..."); selected=true; } draw_items(); lasttick=current_tick; } } if(curent_line==0) { slog("Loading Sansa firmware..."); rc=load_iriver(loadbuffer); } else { slog( "Loading Rockbox..."); rc=load_rockbox(loadbuffer); } if (rc < 0) { snprintf(buf, sizeof(buf), "Rockbox error: %d",rc); while(1) {} } memcpy((void*)DRAM_START,loadbuffer,rc); return (void*)DRAM_START; } /* These functions are present in the firmware library, but we reimplement them here because the originals do a lot more than we want */ void reset_poweroff_timer(void) { } int dbg_ports(void) { return 0; } void mpeg_stop(void) { } void usb_acknowledge(void) { } void usb_wait_for_disconnect(void) { } void sys_poweroff(void) { }