summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJonathan Gordon <rockbox@jdgordon.info>2006-11-06 14:24:18 +0000
committerJonathan Gordon <rockbox@jdgordon.info>2006-11-06 14:24:18 +0000
commit0b22795e26ee09de14f6ac23219adeda12f2fd5b (patch)
treec1ccbda32170de48111a4b75e1f723ba953096bf
parente543901777843a1734474aba7aa5d96cf61708ab (diff)
downloadrockbox-0b22795e26ee09de14f6ac23219adeda12f2fd5b.tar.gz
rockbox-0b22795e26ee09de14f6ac23219adeda12f2fd5b.zip
adds ata_idle_notify system which allows callbacks in apps/ to be called
when the hard disk is idle but spinning, and just before shutting down. on SWCODEC targets with > 8MB RAM the playback engine will try to refill the buffer if it is less than 75% full while the disk is spinning (temporarily disabled on the nano) git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11451 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/main.c2
-rw-r--r--apps/playback.c48
-rw-r--r--firmware/SOURCES1
-rw-r--r--firmware/ata_idle_notify.c96
-rw-r--r--firmware/drivers/ata.c15
-rw-r--r--firmware/export/ata_idle_notify.h41
6 files changed, 192 insertions, 11 deletions
diff --git a/apps/main.c b/apps/main.c
index 4249fd0b8b..c4ee45cb89 100644
--- a/apps/main.c
+++ b/apps/main.c
@@ -19,6 +19,7 @@
#include "config.h"
#include "ata.h"
+#include "ata_idle_notify.h"
#include "disk.h"
#include "fat.h"
#include "lcd.h"
@@ -364,6 +365,7 @@ void init(void)
}
#endif
+ ata_idle_notify_init();
rc = ata_init();
if(rc)
{
diff --git a/apps/playback.c b/apps/playback.c
index 6d277f7153..f8372665a4 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -74,6 +74,7 @@
#include "metadata.h"
#include "splash.h"
#include "talk.h"
+#include "ata_idle_notify.h"
#ifdef HAVE_RECORDING
#include "recording.h"
@@ -118,6 +119,9 @@ enum {
Q_AUDIO_NEW_PLAYLIST,
Q_AUDIO_POSTINIT,
Q_AUDIO_FILL_BUFFER,
+#if MEM > 8
+ Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA,
+#endif
Q_CODEC_REQUEST_PENDING,
Q_CODEC_REQUEST_COMPLETE,
@@ -2664,11 +2668,6 @@ static void audio_fill_file_buffer(
audio_generate_postbuffer_events();
filling = false;
-
-#ifndef SIMULATOR
- if (playing)
- ata_sleep();
-#endif
}
}
@@ -3228,14 +3227,30 @@ static void audio_playback_init(void)
sound_settings_apply();
}
+#if MEM > 8
+/* we dont want this rebuffering on targets with little ram
+ because the disk may never spin down */
+bool ata_fillbuffer_callback(void)
+{
+#ifndef IPOD_NANO
+ queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA, 0);
+#endif
+ return true;
+}
+#endif
static void audio_thread(void)
{
struct event ev;
-
+#if MEM > 8
+ size_t high_watermark;
+#endif
/* At first initialize audio system in background. */
audio_playback_init();
-
+#if MEM > 8
+ high_watermark = (3*filebuflen)/4;
+#endif
+
while (1)
{
if (filling)
@@ -3244,10 +3259,27 @@ static void audio_thread(void)
if (ev.id == SYS_TIMEOUT)
ev.id = Q_AUDIO_FILL_BUFFER;
}
+#if MEM > 8
else
+ {
queue_wait_w_tmo(&audio_queue, &ev, HZ/2);
-
+ if ( (ev.id == SYS_TIMEOUT) &&
+ (FILEBUFUSED < high_watermark))
+ register_ata_idle_func(ata_fillbuffer_callback);
+ }
+#else
+ queue_wait_w_tmo(&audio_queue, &ev, HZ/2);
+#endif
switch (ev.id) {
+#if MEM > 8
+ case Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA:
+ /* only fill if the disk is still spining */
+#ifndef SIMULATOR
+ if (!ata_disk_is_active())
+ break;
+#endif
+#endif /* MEM > 8 */
+ /* else fall through to Q_AUDIO_FILL_BUFFER */
case Q_AUDIO_FILL_BUFFER:
LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER");
if (!filling)
diff --git a/firmware/SOURCES b/firmware/SOURCES
index e9ce8f909b..1ec3c82616 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -95,6 +95,7 @@ drivers/lcd-h300.c
drivers/power.c
#endif
drivers/led.c
+ata_idle_notify.c
#ifndef SIMULATOR
#ifndef TARGET_TREE
drivers/adc.c
diff --git a/firmware/ata_idle_notify.c b/firmware/ata_idle_notify.c
new file mode 100644
index 0000000000..a0a56e958b
--- /dev/null
+++ b/firmware/ata_idle_notify.c
@@ -0,0 +1,96 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2006 Jonathan Gordon
+ *
+ * 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 <stdbool.h>
+#include "system.h"
+#include "ata_idle_notify.h"
+#include "logf.h"
+
+#if USING_ATA_CALLBACK
+static ata_idle_notify ata_idle_notify_funcs[MAX_ATA_CALLBACKS];
+static int ata_callback_count = 0;
+#endif
+
+bool register_ata_idle_func(ata_idle_notify function)
+{
+#if USING_ATA_CALLBACK
+ int i;
+ for (i=0; i<MAX_ATA_CALLBACKS; i++)
+ {
+ if (ata_idle_notify_funcs[i] == NULL)
+ {
+ ata_idle_notify_funcs[i] = function;
+ ata_callback_count++;
+ return true;
+ }
+ else if (ata_idle_notify_funcs[i] == function)
+ return true;
+ }
+ return false;
+#else
+ function(); /* just call the function now */
+/* this _may_ cause problems later if the calling function
+ sets a variable expecting the callback to unset it, because
+ the callback will be run before this function exits, so before the var is set */
+ return true;
+#endif
+}
+
+#if USING_ATA_CALLBACK
+void unregister_ata_idle_func(ata_idle_notify func)
+{
+ int i;
+ for (i=0; i<MAX_ATA_CALLBACKS; i++)
+ {
+ if (ata_idle_notify_funcs[i] == func)
+ {
+ ata_idle_notify_funcs[i] = NULL;
+ ata_callback_count--;
+ }
+ }
+ return;
+}
+
+bool call_ata_idle_notifys(void)
+{
+ int i;
+ ata_idle_notify function;
+ if (ata_callback_count == 0)
+ return false;
+ ata_callback_count = 0; /* so we dont re-enter every time the callbacks read/write */
+ for (i = 0; i < MAX_ATA_CALLBACKS; i++)
+ {
+ if (ata_idle_notify_funcs[i])
+ {
+ function = ata_idle_notify_funcs[i];
+ ata_idle_notify_funcs[i] = NULL;
+ function();
+ }
+ }
+ return true;
+}
+
+void ata_idle_notify_init(void)
+{
+ int i;
+ for (i=0; i<MAX_ATA_CALLBACKS; i++)
+ {
+ ata_idle_notify_funcs[i] = NULL;
+ }
+}
+#endif
diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c
index 00ef0e8eb5..249cb3934e 100644
--- a/firmware/drivers/ata.c
+++ b/firmware/drivers/ata.c
@@ -29,7 +29,7 @@
#include "power.h"
#include "string.h"
#include "hwcompat.h"
-
+#include "ata_idle_notify.h"
#ifdef TARGET_TREE
#include "ata-target.h"
#endif
@@ -1364,6 +1364,7 @@ static void ata_thread(void)
{
static long last_sleep = 0;
struct event ev;
+ static long last_callback_run = 0;
while (1) {
while ( queue_empty( &ata_queue ) ) {
@@ -1373,8 +1374,16 @@ static void ata_thread(void)
TIME_AFTER( current_tick,
last_disk_activity + sleep_timeout ) )
{
- ata_perform_sleep();
- last_sleep = current_tick;
+ if (!call_ata_idle_notifys())
+ {
+ ata_perform_sleep();
+ last_sleep = current_tick;
+ }
+ }
+ else if (TIME_AFTER(current_tick, last_callback_run+(HZ*5)))
+ {
+ last_callback_run = current_tick;
+ call_ata_idle_notifys();
}
#ifdef HAVE_ATA_POWER_OFF
diff --git a/firmware/export/ata_idle_notify.h b/firmware/export/ata_idle_notify.h
new file mode 100644
index 0000000000..f5f2a25fd9
--- /dev/null
+++ b/firmware/export/ata_idle_notify.h
@@ -0,0 +1,41 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2006 Jonathan Gordon
+ *
+ * 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.
+ *
+ ****************************************************************************/
+#ifndef __ATACALLBACK_H__
+#define __ATACALLBACK_H__
+
+#include <stdbool.h>
+#define USING_ATA_CALLBACK !defined(SIMULATOR) \
+ && !defined(HAVE_FLASH_DISK) \
+ && !defined(HAVE_MMC)
+
+#define MAX_ATA_CALLBACKS 5
+typedef bool (*ata_idle_notify)(void);
+
+extern bool register_ata_idle_func(ata_idle_notify function);
+#if USING_ATA_CALLBACK
+extern void ata_idle_notify_init(void);
+extern void unregister_ata_idle_func(ata_idle_notify function);
+extern bool call_ata_idle_notifys(void);
+#else
+#define unregister_ata_idle_func(f)
+#define call_ata_idle_notifys()
+#define ata_idle_notify_init()
+#endif
+
+#endif /* __ATACALLBACK_H__ */