summaryrefslogtreecommitdiffstats
path: root/bootloader
diff options
context:
space:
mode:
Diffstat (limited to 'bootloader')
-rw-r--r--bootloader/gigabeat-s.c112
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);