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
This commit is contained in:
Jonathan Gordon 2006-11-06 14:24:18 +00:00
parent e543901777
commit 0b22795e26
6 changed files with 192 additions and 11 deletions

View file

@ -19,6 +19,7 @@
#include "config.h" #include "config.h"
#include "ata.h" #include "ata.h"
#include "ata_idle_notify.h"
#include "disk.h" #include "disk.h"
#include "fat.h" #include "fat.h"
#include "lcd.h" #include "lcd.h"
@ -364,6 +365,7 @@ void init(void)
} }
#endif #endif
ata_idle_notify_init();
rc = ata_init(); rc = ata_init();
if(rc) if(rc)
{ {

View file

@ -74,6 +74,7 @@
#include "metadata.h" #include "metadata.h"
#include "splash.h" #include "splash.h"
#include "talk.h" #include "talk.h"
#include "ata_idle_notify.h"
#ifdef HAVE_RECORDING #ifdef HAVE_RECORDING
#include "recording.h" #include "recording.h"
@ -118,6 +119,9 @@ enum {
Q_AUDIO_NEW_PLAYLIST, Q_AUDIO_NEW_PLAYLIST,
Q_AUDIO_POSTINIT, Q_AUDIO_POSTINIT,
Q_AUDIO_FILL_BUFFER, Q_AUDIO_FILL_BUFFER,
#if MEM > 8
Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA,
#endif
Q_CODEC_REQUEST_PENDING, Q_CODEC_REQUEST_PENDING,
Q_CODEC_REQUEST_COMPLETE, Q_CODEC_REQUEST_COMPLETE,
@ -2664,11 +2668,6 @@ static void audio_fill_file_buffer(
audio_generate_postbuffer_events(); audio_generate_postbuffer_events();
filling = false; filling = false;
#ifndef SIMULATOR
if (playing)
ata_sleep();
#endif
} }
} }
@ -3228,13 +3227,29 @@ static void audio_playback_init(void)
sound_settings_apply(); 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) static void audio_thread(void)
{ {
struct event ev; struct event ev;
#if MEM > 8
size_t high_watermark;
#endif
/* At first initialize audio system in background. */ /* At first initialize audio system in background. */
audio_playback_init(); audio_playback_init();
#if MEM > 8
high_watermark = (3*filebuflen)/4;
#endif
while (1) while (1)
{ {
@ -3244,10 +3259,27 @@ static void audio_thread(void)
if (ev.id == SYS_TIMEOUT) if (ev.id == SYS_TIMEOUT)
ev.id = Q_AUDIO_FILL_BUFFER; ev.id = Q_AUDIO_FILL_BUFFER;
} }
#if MEM > 8
else else
{
queue_wait_w_tmo(&audio_queue, &ev, HZ/2); 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) { 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: case Q_AUDIO_FILL_BUFFER:
LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER"); LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER");
if (!filling) if (!filling)

View file

@ -95,6 +95,7 @@ drivers/lcd-h300.c
drivers/power.c drivers/power.c
#endif #endif
drivers/led.c drivers/led.c
ata_idle_notify.c
#ifndef SIMULATOR #ifndef SIMULATOR
#ifndef TARGET_TREE #ifndef TARGET_TREE
drivers/adc.c drivers/adc.c

View file

@ -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

View file

@ -29,7 +29,7 @@
#include "power.h" #include "power.h"
#include "string.h" #include "string.h"
#include "hwcompat.h" #include "hwcompat.h"
#include "ata_idle_notify.h"
#ifdef TARGET_TREE #ifdef TARGET_TREE
#include "ata-target.h" #include "ata-target.h"
#endif #endif
@ -1364,6 +1364,7 @@ static void ata_thread(void)
{ {
static long last_sleep = 0; static long last_sleep = 0;
struct event ev; struct event ev;
static long last_callback_run = 0;
while (1) { while (1) {
while ( queue_empty( &ata_queue ) ) { while ( queue_empty( &ata_queue ) ) {
@ -1372,10 +1373,18 @@ static void ata_thread(void)
last_user_activity + sleep_timeout ) && last_user_activity + sleep_timeout ) &&
TIME_AFTER( current_tick, TIME_AFTER( current_tick,
last_disk_activity + sleep_timeout ) ) last_disk_activity + sleep_timeout ) )
{
if (!call_ata_idle_notifys())
{ {
ata_perform_sleep(); ata_perform_sleep();
last_sleep = current_tick; 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 #ifdef HAVE_ATA_POWER_OFF
if ( !spinup && sleeping && poweroff_timeout && !poweroff && if ( !spinup && sleeping && poweroff_timeout && !poweroff &&

View file

@ -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__ */