diff options
Diffstat (limited to 'bootloader')
-rw-r--r-- | bootloader/gigabeat-s.c | 112 |
1 files changed, 98 insertions, 14 deletions
diff --git a/bootloader/gigabeat-s.c b/bootloader/gigabeat-s.c index f3e2917131..eba3cd7342 100644 --- a/bootloader/gigabeat-s.c +++ b/bootloader/gigabeat-s.c @@ -47,10 +47,11 @@ #include "avic-imx31.h" #include <stdarg.h> +#define TAR_CHUNK 512 +#define TAR_HEADER_SIZE 157 + char version[] = APPSVERSION; -char buf[MAX_PATH]; char basedir[] = "/Content/0b00/00/"; /* Where files sent via MTP are stored */ -char model[5]; int (*kernel_entry)(void); extern void reference_system_c(void); @@ -61,11 +62,89 @@ void reference_files(void) reference_system_c(); } +void untar(int tar_fd) +{ + char header[TAR_HEADER_SIZE]; + char copybuf[TAR_CHUNK]; + char path[102]; + int fd, i, size = 0, pos = 0; + + while (1) + { + read(tar_fd, header, 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 */ + pos = lseek(tar_fd, TAR_CHUNK - TAR_HEADER_SIZE, SEEK_CUR); + + /* Make the path absolute */ + strcpy(path, "/"); + strcat(path, header); + + if (header[156] == '0') /* file */ + { + int rc, wc, total = 0; + + fd = creat(path); + if (fd < 0) + { + printf("failed to create file (%d)", fd); + /* Skip the file */ + lseek(tar_fd, (size + 511) & (~511), SEEK_CUR); + } + else + { + /* Copy the file over 512 bytes at a time */ + while (total < size) + { + rc = read(tar_fd, copybuf, TAR_CHUNK); + pos += rc; + + wc = write(fd, copybuf, MIN(rc, size - total)); + if (wc < 0) + { + printf("write failed (%d)", wc); + break; + } + total += wc; + } + close(fd); + } + } + 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]; + lcd_clear_display(); printf("Hello world!"); - printf("Gigabeat S Rockbox Bootloader v.00000003"); + printf("Gigabeat S Rockbox Bootloader v.00000004"); system_init(); kernel_init(); printf("kernel init done"); @@ -90,7 +169,7 @@ void main(void) error(EDISK,rc); } - /* Look for the first valid firmware file */ + /* Look for a tar file */ struct dirent_uncached* entry; DIR_UNCACHED* dir; int fd; @@ -103,26 +182,31 @@ void main(void) fd = open(buf, O_RDONLY); if (fd >= 0) { - lseek(fd, 4, SEEK_SET); - rc = read(fd, model, 4); - close(fd); - if (rc == 4) + lseek(fd, 257, SEEK_SET); + rc = read(fd, tarstring, 5); + if (rc == 5) { - model[4] = 0; - if (strcmp(model, "gigs") == 0) + 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); } } } - printf("Firmware file: %s", buf); - printf("Loading firmware"); - unsigned char *loadbuffer = (unsigned char *)0x0; int buffer_size = 31*1024*1024; - rc = load_firmware(loadbuffer, buf, buffer_size); + rc = load_firmware(loadbuffer, "/.rockbox/rockbox.gigabeat", buffer_size); if(rc < 0) error((int)buf, rc); |