summaryrefslogtreecommitdiffstats
path: root/bootloader
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2008-05-10 18:00:11 +0000
committerMichael Sevakis <jethead71@rockbox.org>2008-05-10 18:00:11 +0000
commit80278e45aa79cee66596c257c5d3870765233e00 (patch)
tree3a974d996f2bcf7f176175c904cf22edf9132ac9 /bootloader
parent6e812b1d2e7941ee1f3e7abdbc2a2eba601f17e3 (diff)
downloadrockbox-80278e45aa79cee66596c257c5d3870765233e00.tar.gz
rockbox-80278e45aa79cee66596c257c5d3870765233e00.tar.bz2
rockbox-80278e45aa79cee66596c257c5d3870765233e00.zip
Bring Gigabeat S bootloader one step close to a release version.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@17442 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'bootloader')
-rw-r--r--bootloader/gigabeat-s.c329
1 files changed, 209 insertions, 120 deletions
diff --git a/bootloader/gigabeat-s.c b/bootloader/gigabeat-s.c
index 30c2955c19..dfe13e4540 100644
--- a/bootloader/gigabeat-s.c
+++ b/bootloader/gigabeat-s.c
@@ -21,11 +21,15 @@
#include <sprintf.h>
#include "kernel.h"
#include "string.h"
+#include "adc.h"
+#include "powermgmt.h"
#include "ata.h"
#include "dir.h"
#include "disk.h"
#include "common.h"
+#include "backlight.h"
#include "usb.h"
+#include "button.h"
#include "font.h"
#include "lcd.h"
#include "usb-target.h"
@@ -39,11 +43,15 @@ static const char basedir[] = "/Content/0b00/00/";
/* Can use memory after vector table up to 0x01f00000 */
static char * const tarbuf = (char *)0x00000040;
static const size_t tarbuf_size = 0x01f00000 - 0x00000040;
-/* Queue to get notifications when in USB mode */
-static struct event_queue usb_wait_queue;
+/* Firmware data */
+static void * const load_buf = 0x00000000;
+static const size_t load_buf_size = 0x20000000 - 0x100000;
+static const void * const start_addr = 0x00000000;
static void show_splash(int timeout, const char *msg)
{
+ backlight_on();
+ reset_screen();
lcd_putsxy( (LCD_WIDTH - (SYSFONT_WIDTH * strlen(msg))) / 2,
(LCD_HEIGHT - SYSFONT_HEIGHT) / 2, msg);
lcd_update();
@@ -51,6 +59,95 @@ static void show_splash(int timeout, const char *msg)
sleep(timeout);
}
+static bool pause_if_button_pressed(bool pre_usb)
+{
+ while (1)
+ {
+ int button = button_read_device();
+
+ if (pre_usb && !usb_plugged())
+ return false;
+
+ /* Exit if no button or only the menu (settings reset) button */
+ switch (button)
+ {
+ case BUTTON_MENU:
+ case BUTTON_NONE:
+ return true;
+ }
+
+ sleep(HZ/5);
+
+ /* If the disk powers off, the firmware will lock at startup */
+ ata_spin();
+ }
+}
+
+/* TODO: Handle charging while connected */
+static void handle_usb(void)
+{
+ int button;
+
+ /* Check if plugged and pause to look at messages. If the cable was pulled
+ * while waiting, proceed as if it never was plugged. */
+ if (!usb_plugged() || !pause_if_button_pressed(true))
+ {
+ /* Bang on the controller */
+ usb_init_device();
+ return;
+ }
+
+ /** Enter USB mode **/
+
+ /* We need full button and backlight handling now */
+ backlight_init();
+ button_init();
+
+ /* Start the USB driver */
+ usb_init();
+ usb_start_monitoring();
+
+ /* Wait for threads to connect or cable is pulled */
+ show_splash(HZ/2, "Waiting for USB");
+
+ while (1)
+ {
+ button = button_get_w_tmo(HZ/2);
+
+ if (button == SYS_USB_CONNECTED)
+ break; /* Hit */
+
+ if (!usb_plugged())
+ break; /* Cable pulled */
+ }
+
+ if (button == SYS_USB_CONNECTED)
+ {
+ /* Got the message - wait for disconnect */
+ show_splash(0, "Bootloader USB mode");
+
+ usb_acknowledge(SYS_USB_CONNECTED_ACK);
+
+ while (1)
+ {
+ button = button_get(true);
+ if (button == SYS_USB_DISCONNECTED)
+ {
+ usb_acknowledge(SYS_USB_DISCONNECTED_ACK);
+ break;
+ }
+ }
+ }
+
+ /* Put drivers initialized for USB connection into a known state */
+ backlight_on();
+ usb_close();
+ button_close();
+ backlight_close();
+
+ reset_screen();
+}
+
static void untar(int tar_fd)
{
char header[TAR_HEADER_SIZE];
@@ -60,13 +157,15 @@ static void untar(int tar_fd)
int ret;
size_t size = filesize(tar_fd);
- if (size > tarbuf_size) {
+ if (size > tarbuf_size)
+ {
printf("tar file too large"); /* Paranoid but proper */
return;
}
ret = read(tar_fd, tarbuf, filesize(tar_fd));
- if (ret < 0) {
+ if (ret < 0)
+ {
printf("couldn't read tar file (%d)", ret);
return;
}
@@ -131,153 +230,91 @@ static void untar(int tar_fd)
}
}
-void main(void)
+/* Look for a tar file or rockbox binary in the MTP directory */
+static void handle_untar(void)
{
char buf[MAX_PATH];
char tarstring[6];
char model[5];
-
- /* Flush and invalidate all caches (because vectors were written) */
- invalidate_icache();
-
- lcd_clear_display();
- printf("Gigabeat S Rockbox Bootloader v.00000013");
- system_init();
- kernel_init();
- printf("kernel init done");
+ struct dirent_uncached* entry;
+ DIR_UNCACHED* dir;
+ int fd;
int rc;
- enable_interrupt(IRQ_FIQ_STATUS);
+ dir = opendir_uncached(basedir);
- rc = ata_init();
- if(rc)
+ while ((entry = readdir_uncached(dir)))
{
- reset_screen();
- error(EATA, rc);
- }
- printf("ata init done");
+ if (*entry->d_name == '.')
+ continue;
- disk_init();
- printf("disk init done");
+ snprintf(buf, sizeof(buf), "%s%s", basedir, entry->d_name);
+ fd = open(buf, O_RDONLY);
- rc = disk_mount_all();
- if (rc<=0)
- {
- error(EDISK,rc);
- }
+ if (fd < 0)
+ continue;
- /* 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 != '.')
+ /* Check whether the file is a rockbox binary. */
+ lseek(fd, 4, SEEK_SET);
+ rc = read(fd, model, 4);
+ if (rc == 4)
{
- snprintf(buf, sizeof(buf), "%s%s", basedir, entry->d_name);
- fd = open(buf, O_RDONLY);
- if (fd >= 0)
+ model[4] = 0;
+ if (strcmp(model, "gigs") == 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;
- }
- }
+ 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;
}
}
- }
-
- 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)
+ /* Check whether the file is a tar file. */
+ lseek(fd, 257, SEEK_SET);
+ rc = read(fd, tarstring, 5);
+ if (rc == 5)
{
- /* 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);
+ 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;
+ }
}
- /* No more monitoring */
- usb_stop_monitoring();
-
- reset_screen();
- }
- else
- {
- /* Bang on the controller */
- usb_init_device();
+ close(fd);
}
+}
- unsigned char *loadbuffer = (unsigned char *)0x0;
- int buffer_size = 31*1024*1024;
+/* Try to load the firmware and run it */
+static void __attribute__((noreturn)) handle_firmware_load(void)
+{
+ int rc = load_firmware(load_buf, "/.rockbox/rockbox.gigabeat",
+ load_buf_size);
- rc = load_firmware(loadbuffer, "/.rockbox/rockbox.gigabeat", buffer_size);
if(rc < 0)
error(EBOOTFILE, rc);
+ /* Pause to look at messages */
+ pause_if_button_pressed(false);
+
+ /* Put drivers into a known state */
+ button_close_device();
+ ata_close();
system_prepare_fw_start();
if (rc == EOK)
{
invalidate_icache();
- asm volatile ("bx %0": : "r"(loadbuffer));
+ asm volatile ("bx %0": : "r"(start_addr));
}
/* Halt */
@@ -285,3 +322,55 @@ void main(void)
core_idle();
}
+static void check_battery(void)
+{
+ int batt = battery_adc_voltage();
+ printf("Battery: %d.%03d V", batt / 1000, batt % 1000);
+ /* TODO: warn on low battery or shut down */
+}
+
+void main(void)
+{
+ int rc;
+
+ /* Flush and invalidate all caches (because vectors were written) */
+ invalidate_icache();
+
+ lcd_clear_display();
+ printf("Gigabeat S Rockbox Bootloader");
+ printf("Version %s", version);
+ system_init();
+ kernel_init();
+
+ enable_interrupt(IRQ_FIQ_STATUS);
+
+ /* Initialize KPP so we can poll the button states */
+ button_init_device();
+
+ adc_init();
+
+ check_battery();
+
+ rc = ata_init();
+ if(rc)
+ {
+ reset_screen();
+ error(EATA, rc);
+ }
+
+ disk_init();
+
+ rc = disk_mount_all();
+ if (rc<=0)
+ {
+ error(EDISK,rc);
+ }
+
+ printf("Init complete");
+
+ /* Do USB first since a tar or binary could be added to the MTP directory
+ * at the time and we can untar or move after unplugging. */
+ handle_usb();
+ handle_untar();
+ handle_firmware_load(); /* No return */
+}