diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2008-05-10 18:00:11 +0000 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2008-05-10 18:00:11 +0000 |
commit | 80278e45aa79cee66596c257c5d3870765233e00 (patch) | |
tree | 3a974d996f2bcf7f176175c904cf22edf9132ac9 | |
parent | 6e812b1d2e7941ee1f3e7abdbc2a2eba601f17e3 (diff) |
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
-rw-r--r-- | bootloader/gigabeat-s.c | 329 | ||||
-rw-r--r-- | firmware/backlight.c | 49 | ||||
-rw-r--r-- | firmware/drivers/ata.c | 28 | ||||
-rw-r--r-- | firmware/drivers/button.c | 7 | ||||
-rw-r--r-- | firmware/export/ata.h | 1 | ||||
-rw-r--r-- | firmware/export/backlight.h | 1 | ||||
-rw-r--r-- | firmware/export/button.h | 1 | ||||
-rw-r--r-- | firmware/export/config-gigabeat-s.h | 22 | ||||
-rw-r--r-- | firmware/export/usb.h | 5 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/ata-target.h | 4 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/backlight-imx31.c | 4 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/backlight-target.h | 8 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/button-imx31.c | 38 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/button-target.h | 7 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c | 48 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/system-imx31.c | 1 | ||||
-rw-r--r-- | firmware/target/arm/imx31/gigabeat-s/usb-target.h | 4 | ||||
-rw-r--r-- | firmware/usb.c | 19 |
18 files changed, 423 insertions, 153 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 */ +} diff --git a/firmware/backlight.c b/firmware/backlight.c index 4a00f86f39..74cdee1205 100644 --- a/firmware/backlight.c +++ b/firmware/backlight.c @@ -39,6 +39,11 @@ #include "backlight-target.h" #endif +#if !defined(BOOTLOADER) +/* The whole driver should be built */ +#define BACKLIGHT_FULL_INIT +#endif + #ifdef SIMULATOR /* TODO: find a better way to do it but we need a kernel thread somewhere to handle this */ @@ -85,7 +90,7 @@ static inline void _remote_backlight_off(void) #endif /* SIMULATOR */ -#if defined(HAVE_BACKLIGHT) && !defined(BOOTLOADER) +#if defined(HAVE_BACKLIGHT) && defined(BACKLIGHT_FULL_INIT) enum { BACKLIGHT_ON, @@ -104,12 +109,18 @@ enum { BUTTON_LIGHT_ON, BUTTON_LIGHT_OFF, #endif +#ifdef BACKLIGHT_DRIVER_CLOSE + BACKLIGHT_QUIT, +#endif }; static void backlight_thread(void); static long backlight_stack[DEFAULT_STACK_SIZE/sizeof(long)]; static const char backlight_thread_name[] = "backlight"; static struct event_queue backlight_queue; +#ifdef BACKLIGHT_DRIVER_CLOSE +static struct thread_entry *backlight_thread_p = NULL; +#endif static int backlight_timer SHAREDBSS_ATTR; static int backlight_timeout SHAREDBSS_ATTR; @@ -158,7 +169,7 @@ void buttonlight_set_timeout(int value) buttonlight_update_state(); } -#endif +#endif /* HAVE_BUTTON_LIGHT */ #ifdef HAVE_REMOTE_LCD static int remote_backlight_timer; @@ -170,7 +181,7 @@ static int remote_backlight_timeout_plugged = 5*HZ; #ifdef HAS_REMOTE_BUTTON_HOLD static int remote_backlight_on_button_hold = 0; #endif -#endif +#endif /* HAVE_REMOTE_LCD */ #ifdef HAVE_LCD_SLEEP const signed char lcd_sleep_timeout_value[10] = @@ -494,6 +505,12 @@ void backlight_thread(void) case SYS_USB_DISCONNECTED: usb_acknowledge(SYS_USB_DISCONNECTED_ACK); break; + +#ifdef BACKLIGHT_DRIVER_CLOSE + /* Get out of here */ + case BACKLIGHT_QUIT: + return; +#endif } if (locked) continue; @@ -613,7 +630,9 @@ void backlight_init(void) /* Leave all lights as set by the bootloader here. The settings load will * call the appropriate backlight_set_*() functions, only changing light * status if necessary. */ - +#ifdef BACKLIGHT_DRIVER_CLOSE + backlight_thread_p = +#endif create_thread(backlight_thread, backlight_stack, sizeof(backlight_stack), 0, backlight_thread_name IF_PRIO(, PRIORITY_USER_INTERFACE) @@ -621,6 +640,22 @@ void backlight_init(void) tick_add_task(backlight_tick); } +#ifdef BACKLIGHT_DRIVER_CLOSE +void backlight_close(void) +{ + struct thread_entry *thread = backlight_thread_p; + + /* Wait for thread to exit */ + if (thread == NULL) + return; + + backlight_thread_p = NULL; + + queue_post(&backlight_queue, BACKLIGHT_QUIT, 0); + thread_wait(thread); +} +#endif /* BACKLIGHT_DRIVER_CLOSE */ + void backlight_on(void) { queue_remove_from_head(&backlight_queue, BACKLIGHT_ON); @@ -788,10 +823,10 @@ void buttonlight_set_brightness(int val) } #endif /* HAVE_BUTTONLIGHT_BRIGHTNESS */ -#else /* !defined(HAVE_BACKLIGHT) || defined(BOOTLOADER) +#else /* !defined(HAVE_BACKLIGHT) || !defined(BACKLIGHT_FULL_INIT) -- no backlight, empty dummy functions */ -#if defined(BOOTLOADER) && defined(HAVE_BACKLIGHT) +#if defined(HAVE_BACKLIGHT) && !defined(BACKLIGHT_FULL_INIT) void backlight_init(void) { (void)_backlight_init(); @@ -826,4 +861,4 @@ void backlight_set_brightness(int val) { (void)val; } #ifdef HAVE_BUTTONLIGHT_BRIGHTNESS void buttonlight_set_brightness(int val) { (void)val; } #endif -#endif /* defined(HAVE_BACKLIGHT) && !defined(BOOTLOADER) */ +#endif /* defined(HAVE_BACKLIGHT) && defined(BACKLIGHT_FULL_INIT) */ diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c index 2dca17512e..87dacc3ed0 100644 --- a/firmware/drivers/ata.c +++ b/firmware/drivers/ata.c @@ -59,6 +59,7 @@ #define CMD_SECURITY_FREEZE_LOCK 0xF5 #define Q_SLEEP 0 +#define Q_CLOSE 1 #define READ_TIMEOUT 5*HZ @@ -66,6 +67,10 @@ #define ATA_POWER_OFF_TIMEOUT 2*HZ #endif +#ifdef ATA_DRIVER_CLOSE +static struct thread_entry *ata_thread_p = NULL; +#endif + #if defined(MAX_PHYS_SECTOR_SIZE) && MEM == 64 /* Hack - what's the deal with 5g? */ struct ata_lock @@ -941,6 +946,11 @@ static void ata_thread(void) call_ata_idle_notifys(false); last_disk_activity = current_tick - sleep_timeout + (HZ/2); break; + +#ifdef ATA_DRIVER_CLOSE + case Q_CLOSE: + return; +#endif } } } @@ -1307,6 +1317,9 @@ int ata_init(void) mutex_lock(&ata_mtx); /* Balance unlock below */ last_disk_activity = current_tick; +#ifdef ATA_DRIVER_CLOSE + ata_thread_p = +#endif create_thread(ata_thread, ata_stack, sizeof(ata_stack), 0, ata_thread_name IF_PRIO(, PRIORITY_USER_INTERFACE) @@ -1322,6 +1335,21 @@ int ata_init(void) return rc; } +#ifdef ATA_DRIVER_CLOSE +void ata_close(void) +{ + struct thread_entry *thread = ata_thread_p; + + if (thread == NULL) + return; + + ata_thread_p = NULL; + + queue_post(&ata_queue, Q_CLOSE, 0); + thread_wait(thread); +} +#endif /* ATA_DRIVER_CLOSE */ + #if (CONFIG_LED == LED_REAL) void ata_set_led_enabled(bool enabled) { diff --git a/firmware/drivers/button.c b/firmware/drivers/button.c index 90ff800c88..74c5a97167 100644 --- a/firmware/drivers/button.c +++ b/firmware/drivers/button.c @@ -410,6 +410,13 @@ void button_init(void) tick_add_task(button_tick); } +#ifdef BUTTON_DRIVER_CLOSE +void button_close(void) +{ + tick_remove_task(button_tick); +} +#endif /* BUTTON_DRIVER_CLOSE */ + #ifdef HAVE_LCD_BITMAP /* only bitmap displays can be flipped */ /* * helper function to swap LEFT/RIGHT, UP/DOWN (if present), and F1/F3 (Recorder) diff --git a/firmware/export/ata.h b/firmware/export/ata.h index 35538f6354..9b5bd36a5b 100644 --- a/firmware/export/ata.h +++ b/firmware/export/ata.h @@ -48,6 +48,7 @@ extern bool ata_disk_is_active(void); extern int ata_hard_reset(void); extern int ata_soft_reset(void); extern int ata_init(void); +extern void ata_close(void); extern int ata_read_sectors(IF_MV2(int drive,) unsigned long start, int count, void* buf); extern int ata_write_sectors(IF_MV2(int drive,) unsigned long start, int count, const void* buf); extern void ata_spin(void); diff --git a/firmware/export/backlight.h b/firmware/export/backlight.h index 35c0f86178..895328d98e 100644 --- a/firmware/export/backlight.h +++ b/firmware/export/backlight.h @@ -28,6 +28,7 @@ void backlight_set_timeout(int value); #ifdef HAVE_BACKLIGHT void backlight_init(void); +void backlight_close(void); int backlight_get_current_timeout(void); diff --git a/firmware/export/button.h b/firmware/export/button.h index 6decf6ec69..82ea81ffab 100644 --- a/firmware/export/button.h +++ b/firmware/export/button.h @@ -29,6 +29,7 @@ extern struct event_queue button_queue; void button_init (void); +void button_close(void); int button_queue_count(void); long button_get (bool block); long button_get_w_tmo(int ticks); diff --git a/firmware/export/config-gigabeat-s.h b/firmware/export/config-gigabeat-s.h index d74f05ce9c..a0c05dad45 100644 --- a/firmware/export/config-gigabeat-s.h +++ b/firmware/export/config-gigabeat-s.h @@ -54,15 +54,6 @@ /* Define this for LCD backlight available */ #define HAVE_BACKLIGHT -#define HAVE_LCD_ENABLE - -#define HAVE_BACKLIGHT_BRIGHTNESS - -/* Main LCD backlight brightness range and defaults */ -#define MIN_BRIGHTNESS_SETTING 0 -#define MAX_BRIGHTNESS_SETTING 24 -#define DEFAULT_BRIGHTNESS_SETTING 12 - /* Define this if you have a software controlled poweroff */ #define HAVE_SW_POWEROFF @@ -78,7 +69,20 @@ #define HW_SAMPR_CAPS (SAMPR_CAP_88 | SAMPR_CAP_44 | SAMPR_CAP_22 | \ SAMPR_CAP_11) +#ifndef BOOTLOADER +/* Not for bootloader */ +#define HAVE_LCD_ENABLE + +#define HAVE_BACKLIGHT_BRIGHTNESS + +/* Main LCD backlight brightness range and defaults */ +#define MIN_BRIGHTNESS_SETTING 0 +#define MAX_BRIGHTNESS_SETTING 24 +#define DEFAULT_BRIGHTNESS_SETTING 12 + + #define HAVE_HEADPHONE_DETECTION +#endif /* BOOTLOADER */ #ifndef SIMULATOR diff --git a/firmware/export/usb.h b/firmware/export/usb.h index 4500cb2cde..ff1f55cd35 100644 --- a/firmware/export/usb.h +++ b/firmware/export/usb.h @@ -31,7 +31,8 @@ enum { USB_TRANSFER_COMPLETION, USB_REQUEST_DISK, USB_RELEASE_DISK, - USB_REQUEST_REBOOT + USB_REQUEST_REBOOT, + USB_QUIT, }; @@ -89,7 +90,7 @@ struct usb_transfer_completion_event_data void usb_init(void); void usb_enable(bool on); void usb_start_monitoring(void); -void usb_stop_monitoring(void); +void usb_close(void); void usb_acknowledge(long id); void usb_wait_for_disconnect(struct event_queue *q); int usb_wait_for_disconnect_w_tmo(struct event_queue *q, int ticks); diff --git a/firmware/target/arm/imx31/gigabeat-s/ata-target.h b/firmware/target/arm/imx31/gigabeat-s/ata-target.h index 6428e9f41f..8f8083dc8d 100644 --- a/firmware/target/arm/imx31/gigabeat-s/ata-target.h +++ b/firmware/target/arm/imx31/gigabeat-s/ata-target.h @@ -19,6 +19,10 @@ #ifndef ATA_TARGET_H #define ATA_TARGET_H +#ifdef BOOTLOADER +#define ATA_DRIVER_CLOSE +#endif + /* Plain C read & write loops */ #define PREFER_C_READING #define PREFER_C_WRITING diff --git a/firmware/target/arm/imx31/gigabeat-s/backlight-imx31.c b/firmware/target/arm/imx31/gigabeat-s/backlight-imx31.c index 4df9be843c..b35e3c1ad0 100644 --- a/firmware/target/arm/imx31/gigabeat-s/backlight-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/backlight-imx31.c @@ -22,6 +22,7 @@ #include "mc13783.h" #include "backlight-target.h" +#ifdef HAVE_BACKLIGHT_BRIGHTNESS /* Table that uses combinations of current level and pwm fraction to get * as many uniquely-visible brightness levels as possible. The lowest current * level for any average current is used even though many combinations give @@ -60,6 +61,7 @@ static const struct { 3, 12 }, /* 9 12 7.2 */ /* Anything higher is just too much */ }; +#endif /* HAVE_BACKLIGHT_BRIGHTNESS */ bool _backlight_init(void) { @@ -85,6 +87,7 @@ void _backlight_off(void) mc13783_clear(MC13783_LED_CONTROL0, MC13783_LEDEN); } +#ifdef HAVE_BACKLIGHT_BRIGHTNESS /* Assumes that the backlight has been initialized */ void _backlight_set_brightness(int brightness) { @@ -106,3 +109,4 @@ void _backlight_set_brightness(int brightness) mc13783_write(MC13783_LED_CONTROL2, data); } +#endif /* HAVE_BACKLIGHT_BRIGHTNESS */ diff --git a/firmware/target/arm/imx31/gigabeat-s/backlight-target.h b/firmware/target/arm/imx31/gigabeat-s/backlight-target.h index 7c4b2fa0fd..145df0d930 100644 --- a/firmware/target/arm/imx31/gigabeat-s/backlight-target.h +++ b/firmware/target/arm/imx31/gigabeat-s/backlight-target.h @@ -19,11 +19,15 @@ #ifndef BACKLIGHT_TARGET_H #define BACKLIGHT_TARGET_H +#ifdef BOOTLOADER +#define BACKLIGHT_DRIVER_CLOSE +/* Force the whole driver to be built */ +#define BACKLIGHT_FULL_INIT +#endif + bool _backlight_init(void); void _backlight_on(void); void _backlight_off(void); void _backlight_set_brightness(int brightness); -/* true: backlight fades off - false: backlight fades on */ -void __backlight_dim(bool dim); #endif diff --git a/firmware/target/arm/imx31/gigabeat-s/button-imx31.c b/firmware/target/arm/imx31/gigabeat-s/button-imx31.c index e80166bca7..746883d010 100644 --- a/firmware/target/arm/imx31/gigabeat-s/button-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/button-imx31.c @@ -29,11 +29,16 @@ /* Most code in here is taken from the Linux BSP provided by Freescale * Copyright 2004-2006 Freescale Semiconductor, Inc. All Rights Reserved. */ - +#ifdef HAVE_HEADPHONE_DETECTION static bool headphones_detect = false; +#endif static uint32_t int_btn = BUTTON_NONE; static bool hold_button = false; +#ifdef BOOTLOADER +static bool initialized = false; +#else static bool hold_button_old = false; +#endif #define _button_hold() (GPIO3_DR & 0x10) static __attribute__((interrupt("IRQ"))) void KPP_HANDLER(void) @@ -116,6 +121,14 @@ static __attribute__((interrupt("IRQ"))) void KPP_HANDLER(void) void button_init_device(void) { +#ifdef BOOTLOADER + /* Can be called more than once in the bootloader */ + if (initialized) + return; + + initialized = true; +#endif + /* Enable keypad clock */ imx31_clkctl_module_clock_gating(CG_KPP, CGM_ON_ALL); @@ -136,15 +149,26 @@ void button_init_device(void) KPP_KDDR = (KPP_KDDR | (0x7 << 8)) & ~0x1f; /* 5. Clear the KPKD Status Flag and Synchronizer chain. - * 6. Set the KDIE control bit, and set the KRIE control - * bit (to force immediate scan). */ - KPP_KPSR = KPP_KPSR_KRIE | KPP_KPSR_KDIE | KPP_KPSR_KRSS | - KPP_KPSR_KDSC | KPP_KPSR_KPKR | KPP_KPSR_KPKD; + * 6. Set the KDIE control bit bit. */ + KPP_KPSR = KPP_KPSR_KDIE | KPP_KPSR_KRSS | KPP_KPSR_KDSC | KPP_KPSR_KPKD; /* KPP IRQ at priority 3 */ avic_enable_int(KPP, IRQ, 3, KPP_HANDLER); } +#ifdef BUTTON_DRIVER_CLOSE +void button_close_device(void) +{ + int oldlevel = disable_irq_save(); + + avic_disable_int(KPP); + KPP_KPSR &= ~(KPP_KPSR_KRIE | KPP_KPSR_KDIE); + int_btn = BUTTON_NONE; + + restore_irq(oldlevel); +} +#endif /* BUTTON_DRIVER_CLOSE */ + bool button_hold(void) { return _button_hold(); @@ -155,12 +179,14 @@ int button_read_device(void) /* Simple poll of GPIO status */ hold_button = _button_hold(); +#ifndef BOOTLOADER /* Backlight hold handling */ if (hold_button != hold_button_old) { hold_button_old = hold_button; backlight_hold_changed(hold_button); } +#endif /* Enable the keypad interrupt to cause it to fire if a key is down. * KPP_HANDLER will clear and disable it after the scan. If no key @@ -190,6 +216,7 @@ void button_power_set_state(bool pressed) restore_irq(oldlevel); } +#ifdef HAVE_HEADPHONE_DETECTION /* This is called from the mc13783 interrupt thread */ void set_headphones_inserted(bool inserted) { @@ -203,3 +230,4 @@ bool headphones_inserted(void) { return headphones_detect; } +#endif /* HAVE_HEADPHONE_DETECTION */ diff --git a/firmware/target/arm/imx31/gigabeat-s/button-target.h b/firmware/target/arm/imx31/gigabeat-s/button-target.h index e2f68162f7..61d33f8e70 100644 --- a/firmware/target/arm/imx31/gigabeat-s/button-target.h +++ b/firmware/target/arm/imx31/gigabeat-s/button-target.h @@ -24,8 +24,13 @@ #define HAS_BUTTON_HOLD +#ifdef BOOTLOADER +#define BUTTON_DRIVER_CLOSE +#endif + bool button_hold(void); void button_init_device(void); +void button_close_device(void); int button_read_device(void); void button_power_set_state(bool pressed); void set_headphones_inserted(bool inserted); @@ -48,6 +53,8 @@ bool headphones_inserted(void); #define BUTTON_NEXT (1 << 11) #define BUTTON_POWER (1 << 12) /* Read from PMIC */ +#define BUTTON_MAIN (0x1fff) + #define BUTTON_REMOTE 0 #define POWEROFF_BUTTON BUTTON_POWER diff --git a/firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c b/firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c index 3af4b48b66..ddf8d1360f 100644 --- a/firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/mc13783-imx31.c @@ -29,6 +29,10 @@ #include "adc-target.h" #include "usb-target.h" +#ifdef BOOTLOADER +#define PMIC_DRIVER_CLOSE +#endif + /* This is all based on communicating with the MC13783 PMU which is on * CSPI2 with the chip select at 0. The LCD controller resides on * CSPI3 cs1, but we have no idea how to communicate to it */ @@ -48,10 +52,14 @@ static struct spi_node mc13783_spi = static int mc13783_thread_stack[DEFAULT_STACK_SIZE/sizeof(int)]; static const char *mc13783_thread_name = "pmic"; static struct wakeup mc13783_wake; +#ifdef PMIC_DRIVER_CLOSE +static bool pmic_close = false; +static struct thread_entry *mc13783_thread_p = NULL; +#endif /* The next two functions are rather target-specific but they'll just be left * here for the moment */ -static __attribute__((noreturn)) void mc13783_interrupt_thread(void) +static void mc13783_interrupt_thread(void) { const unsigned char status_regs[2] = { @@ -76,7 +84,9 @@ static __attribute__((noreturn)) void mc13783_interrupt_thread(void) value = mc13783_read(MC13783_INTERRUPT_SENSE1); button_power_set_state((value & MC13783_ONOFD1) == 0); +#ifdef HAVE_HEADPHONE_DETECTION set_headphones_inserted((value & MC13783_ONOFD2) == 0); +#endif pending[0] = pending[1] = 0xffffff; mc13783_write_regset(status_regs, pending, 2); @@ -90,6 +100,14 @@ static __attribute__((noreturn)) void mc13783_interrupt_thread(void) { wakeup_wait(&mc13783_wake, TIMEOUT_BLOCK); +#ifdef PMIC_DRIVER_CLOSE + if (pmic_close) + { + gpio_disable_event(MC13783_GPIO_NUM, MC13783_EVENT_ID); + return; + } +#endif + mc13783_read_regset(status_regs, pending, 2); mc13783_write_regset(status_regs, pending, 2); @@ -130,9 +148,10 @@ static __attribute__((noreturn)) void mc13783_interrupt_thread(void) if (pending[1] & MC13783_ONOFD1) button_power_set_state((value & MC13783_ONOFD1) == 0); - +#ifdef HAVE_HEADPHONE_DETECTION if (pending[1] & MC13783_ONOFD2) set_headphones_inserted((value & MC13783_ONOFD2) == 0); +#endif } } } @@ -161,10 +180,29 @@ void mc13783_init(void) MC13783_GPIO_ISR = (1ul << MC13783_GPIO_LINE); - create_thread(mc13783_interrupt_thread, mc13783_thread_stack, - sizeof(mc13783_thread_stack), 0, mc13783_thread_name - IF_PRIO(, PRIORITY_REALTIME) IF_COP(, CPU)); +#ifdef PMIC_DRIVER_CLOSE + mc13783_thread_p = +#endif + create_thread(mc13783_interrupt_thread, + mc13783_thread_stack, sizeof(mc13783_thread_stack), 0, + mc13783_thread_name IF_PRIO(, PRIORITY_REALTIME) IF_COP(, CPU)); +} + +#ifdef PMIC_DRIVER_CLOSE +void mc13783_close(void) +{ + struct thread_entry *thread = mc13783_thread_p; + + if (thread == NULL) + return; + + mc13783_thread_p = NULL; + + pmic_close = true; + wakeup_signal(&mc13783_wake); + thread_wait(thread); } +#endif uint32_t mc13783_set(unsigned address, uint32_t bits) { diff --git a/firmware/target/arm/imx31/gigabeat-s/system-imx31.c b/firmware/target/arm/imx31/gigabeat-s/system-imx31.c index 3ec46bae67..1c3abc64fc 100644 --- a/firmware/target/arm/imx31/gigabeat-s/system-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/system-imx31.c @@ -117,6 +117,7 @@ void system_prepare_fw_start(void) { disable_interrupt(IRQ_FIQ_STATUS); avic_disable_int(ALL); + mc13783_close(); tick_stop(); } #endif diff --git a/firmware/target/arm/imx31/gigabeat-s/usb-target.h b/firmware/target/arm/imx31/gigabeat-s/usb-target.h index 8c9dcfc65f..7ecd9a7d49 100644 --- a/firmware/target/arm/imx31/gigabeat-s/usb-target.h +++ b/firmware/target/arm/imx31/gigabeat-s/usb-target.h @@ -19,6 +19,10 @@ #ifndef USB_TARGET_H #define USB_TARGET_H +#ifdef BOOTLOADER +#define USB_DRIVER_CLOSE +#endif + void usb_set_status(bool plugged); bool usb_init_device(void); int usb_detect(void); diff --git a/firmware/usb.c b/firmware/usb.c index 3867bfb496..90991e25fd 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -172,6 +172,10 @@ static void usb_thread(void) queue_wait(&usb_queue, &ev); switch(ev.id) { +#ifdef USB_DRIVER_CLOSE + case USB_QUIT: + return; +#endif #ifdef HAVE_USBSTACK case USB_TRANSFER_COMPLETION: usb_core_handle_transfer_completion((struct usb_transfer_completion_event_data*)ev.data); @@ -531,13 +535,22 @@ void usb_start_monitoring(void) usb_monitor_enabled = true; } -#ifdef TOSHIBA_GIGABEAT_S -void usb_stop_monitoring(void) +#ifdef USB_DRIVER_CLOSE +void usb_close(void) { + struct thread_entry *thread = usb_thread_entry; + usb_thread_entry = NULL; + + if (thread == NULL) + return; + tick_remove_task(usb_tick); usb_monitor_enabled = false; + + queue_post(&usb_queue, USB_QUIT, 0); + thread_wait(thread); } -#endif +#endif /* USB_DRIVER_CLOSE */ bool usb_inserted(void) { |