/*************************************************************************** * __________ __ ___. * 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 "inttypes.h" #include "string.h" #include "cpu.h" #include "system.h" #include "lcd.h" #include "kernel.h" #include "thread.h" #include "ata.h" #include "dir.h" #include "fat.h" #include "disk.h" #include "font.h" #include "adc.h" #include "backlight.h" #include "backlight-target.h" #include "button.h" #include "panic.h" #include "power.h" #include "file.h" #include "common.h" #include "rbunicode.h" #include "usb.h" #include "mmu-imx31.h" #include "lcd-target.h" #include "avic-imx31.h" #include #include "usb-target.h" #define TAR_CHUNK 512 #define TAR_HEADER_SIZE 157 char version[] = APPSVERSION; char basedir[] = "/Content/0b00/00/"; /* Where files sent via MTP are stored */ int (*kernel_entry)(void); char *tarbuf = (char *)0x00000040; extern void reference_system_c(void); static struct event_queue usb_wait_queue; /* Dummy stub that creates C references for C functions only used by assembly - never called */ void reference_files(void) { reference_system_c(); } void show_splash(int timeout, const char *msg) { lcd_putsxy( (LCD_WIDTH - (SYSFONT_WIDTH * strlen(msg))) / 2, (LCD_HEIGHT - SYSFONT_HEIGHT) / 2, msg); lcd_update(); sleep(timeout); } void untar(int tar_fd) { char header[TAR_HEADER_SIZE]; char *ptr; char path[102]; int fd, i, size = 0; int ret; ret = read(tar_fd, tarbuf, filesize(tar_fd)); if (ret < 0) { printf("couldn't read tar file (%d)", ret); return; } ptr = tarbuf; while (1) { memcpy(header, ptr, TAR_HEADER_SIZE); if (*header == '\0') /* Check for EOF */ break; /* Parse the size field */ size = 0; for (i = 124 ; i < 124 + 11 ; i++) { size = (8 * size) + header[i] - '0'; } /* Skip rest of header */ ptr += TAR_CHUNK; /* Make the path absolute */ strcpy(path, "/"); strcat(path, header); if (header[156] == '0') /* file */ { int wc; fd = creat(path); if (fd < 0) { printf("failed to create file (%d)", fd); } else { wc = write(fd, ptr, size); if (wc < 0) { printf("write failed (%d)", wc); break; } close(fd); } ptr += (size + TAR_CHUNK-1) & (~(TAR_CHUNK-1)); } else if (header[156] == '5') /* directory */ { int ret; /* Remove the trailing slash */ if (path[strlen(path) - 1] == '/') path[strlen(path) - 1] = '\0'; /* Create the dir */ ret = mkdir(path); if (ret < 0 && ret != -4) { printf("failed to create dir (%d)", ret); } } } } void main(void) { char buf[MAX_PATH]; char tarstring[6]; char model[5]; lcd_clear_display(); printf("Hello world!"); printf("Gigabeat S Rockbox Bootloader v.00000007"); system_init(); kernel_init(); printf("kernel init done"); int rc; enable_interrupt(IRQ_FIQ_STATUS); rc = ata_init(); if(rc) { reset_screen(); error(EATA, rc); } printf("ata init done"); disk_init(); printf("disk init done"); rc = disk_mount_all(); if (rc<=0) { error(EDISK,rc); } /* Look for a tar file */ struct dirent_uncached* entry; DIR_UNCACHED* dir; int fd; dir = opendir_uncached(basedir); while ((entry = readdir_uncached(dir))) { if (*entry->d_name != '.') { snprintf(buf, sizeof(buf), "%s%s", basedir, entry->d_name); fd = open(buf, O_RDONLY); if (fd >= 0) { /* Check whether the file is a rockbox binary. */ lseek(fd, 4, SEEK_SET); rc = read(fd, model, 4); if (rc == 4) { model[4] = 0; if (strcmp(model, "gigs") == 0) { printf("Found rockbox binary. Moving..."); close(fd); remove("/.rockbox/rockbox.gigabeat"); int ret = rename(buf, "/.rockbox/rockbox.gigabeat"); printf("returned %d", ret); sleep(HZ); break; } } /* Check whether the file is a tar file. */ lseek(fd, 257, SEEK_SET); rc = read(fd, tarstring, 5); if (rc == 5) { tarstring[5] = 0; if (strcmp(tarstring, "ustar") == 0) { printf("Found tar file. Unarchiving..."); lseek(fd, 0, SEEK_SET); untar(fd); close(fd); printf("Removing tar file"); remove(buf); break; } } close(fd); } } } if (usb_plugged()) { /* Enter USB mode */ struct queue_event ev; queue_init(&usb_wait_queue, true); /* Start the USB driver */ usb_init(); usb_start_monitoring(); /* Wait for threads to connect or cable is pulled */ reset_screen(); show_splash(0, "Waiting for USB"); while (1) { queue_wait_w_tmo(&usb_wait_queue, &ev, HZ/2); if (ev.id == SYS_USB_CONNECTED) break; /* Hit */ if (!usb_plugged()) break; /* Cable pulled */ } if (ev.id == SYS_USB_CONNECTED) { /* Got the message - wait for disconnect */ reset_screen(); show_splash(0, "Bootloader USB mode"); usb_acknowledge(SYS_USB_CONNECTED_ACK); usb_wait_for_disconnect(&usb_wait_queue); } /* No more monitoring */ usb_stop_monitoring(); reset_screen(); } unsigned char *loadbuffer = (unsigned char *)0x0; int buffer_size = 31*1024*1024; rc = load_firmware(loadbuffer, "/.rockbox/rockbox.gigabeat", buffer_size); if(rc < 0) error((int)buf, rc); system_prepare_fw_start(); if (rc == EOK) { kernel_entry = (void*) loadbuffer; invalidate_icache(); rc = kernel_entry(); } /* Halt */ while (1) core_idle(); }