diff options
author | Jonathan Gordon <rockbox@jdgordon.info> | 2006-11-06 14:24:18 +0000 |
---|---|---|
committer | Jonathan Gordon <rockbox@jdgordon.info> | 2006-11-06 14:24:18 +0000 |
commit | 0b22795e26ee09de14f6ac23219adeda12f2fd5b (patch) | |
tree | c1ccbda32170de48111a4b75e1f723ba953096bf | |
parent | e543901777843a1734474aba7aa5d96cf61708ab (diff) | |
download | rockbox-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.c | 2 | ||||
-rw-r--r-- | apps/playback.c | 48 | ||||
-rw-r--r-- | firmware/SOURCES | 1 | ||||
-rw-r--r-- | firmware/ata_idle_notify.c | 96 | ||||
-rw-r--r-- | firmware/drivers/ata.c | 15 | ||||
-rw-r--r-- | firmware/export/ata_idle_notify.h | 41 |
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 @@ | |||
19 | #include "config.h" | 19 | #include "config.h" |
20 | 20 | ||
21 | #include "ata.h" | 21 | #include "ata.h" |
22 | #include "ata_idle_notify.h" | ||
22 | #include "disk.h" | 23 | #include "disk.h" |
23 | #include "fat.h" | 24 | #include "fat.h" |
24 | #include "lcd.h" | 25 | #include "lcd.h" |
@@ -364,6 +365,7 @@ void init(void) | |||
364 | } | 365 | } |
365 | #endif | 366 | #endif |
366 | 367 | ||
368 | ata_idle_notify_init(); | ||
367 | rc = ata_init(); | 369 | rc = ata_init(); |
368 | if(rc) | 370 | if(rc) |
369 | { | 371 | { |
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 @@ | |||
74 | #include "metadata.h" | 74 | #include "metadata.h" |
75 | #include "splash.h" | 75 | #include "splash.h" |
76 | #include "talk.h" | 76 | #include "talk.h" |
77 | #include "ata_idle_notify.h" | ||
77 | 78 | ||
78 | #ifdef HAVE_RECORDING | 79 | #ifdef HAVE_RECORDING |
79 | #include "recording.h" | 80 | #include "recording.h" |
@@ -118,6 +119,9 @@ enum { | |||
118 | Q_AUDIO_NEW_PLAYLIST, | 119 | Q_AUDIO_NEW_PLAYLIST, |
119 | Q_AUDIO_POSTINIT, | 120 | Q_AUDIO_POSTINIT, |
120 | Q_AUDIO_FILL_BUFFER, | 121 | Q_AUDIO_FILL_BUFFER, |
122 | #if MEM > 8 | ||
123 | Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA, | ||
124 | #endif | ||
121 | 125 | ||
122 | Q_CODEC_REQUEST_PENDING, | 126 | Q_CODEC_REQUEST_PENDING, |
123 | Q_CODEC_REQUEST_COMPLETE, | 127 | Q_CODEC_REQUEST_COMPLETE, |
@@ -2664,11 +2668,6 @@ static void audio_fill_file_buffer( | |||
2664 | 2668 | ||
2665 | audio_generate_postbuffer_events(); | 2669 | audio_generate_postbuffer_events(); |
2666 | filling = false; | 2670 | filling = false; |
2667 | |||
2668 | #ifndef SIMULATOR | ||
2669 | if (playing) | ||
2670 | ata_sleep(); | ||
2671 | #endif | ||
2672 | } | 2671 | } |
2673 | 2672 | ||
2674 | } | 2673 | } |
@@ -3228,14 +3227,30 @@ static void audio_playback_init(void) | |||
3228 | 3227 | ||
3229 | sound_settings_apply(); | 3228 | sound_settings_apply(); |
3230 | } | 3229 | } |
3230 | #if MEM > 8 | ||
3231 | /* we dont want this rebuffering on targets with little ram | ||
3232 | because the disk may never spin down */ | ||
3233 | bool ata_fillbuffer_callback(void) | ||
3234 | { | ||
3235 | #ifndef IPOD_NANO | ||
3236 | queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA, 0); | ||
3237 | #endif | ||
3238 | return true; | ||
3239 | } | ||
3240 | #endif | ||
3231 | 3241 | ||
3232 | static void audio_thread(void) | 3242 | static void audio_thread(void) |
3233 | { | 3243 | { |
3234 | struct event ev; | 3244 | struct event ev; |
3235 | 3245 | #if MEM > 8 | |
3246 | size_t high_watermark; | ||
3247 | #endif | ||
3236 | /* At first initialize audio system in background. */ | 3248 | /* At first initialize audio system in background. */ |
3237 | audio_playback_init(); | 3249 | audio_playback_init(); |
3238 | 3250 | #if MEM > 8 | |
3251 | high_watermark = (3*filebuflen)/4; | ||
3252 | #endif | ||
3253 | |||
3239 | while (1) | 3254 | while (1) |
3240 | { | 3255 | { |
3241 | if (filling) | 3256 | if (filling) |
@@ -3244,10 +3259,27 @@ static void audio_thread(void) | |||
3244 | if (ev.id == SYS_TIMEOUT) | 3259 | if (ev.id == SYS_TIMEOUT) |
3245 | ev.id = Q_AUDIO_FILL_BUFFER; | 3260 | ev.id = Q_AUDIO_FILL_BUFFER; |
3246 | } | 3261 | } |
3262 | #if MEM > 8 | ||
3247 | else | 3263 | else |
3264 | { | ||
3248 | queue_wait_w_tmo(&audio_queue, &ev, HZ/2); | 3265 | queue_wait_w_tmo(&audio_queue, &ev, HZ/2); |
3249 | 3266 | if ( (ev.id == SYS_TIMEOUT) && | |
3267 | (FILEBUFUSED < high_watermark)) | ||
3268 | register_ata_idle_func(ata_fillbuffer_callback); | ||
3269 | } | ||
3270 | #else | ||
3271 | queue_wait_w_tmo(&audio_queue, &ev, HZ/2); | ||
3272 | #endif | ||
3250 | switch (ev.id) { | 3273 | switch (ev.id) { |
3274 | #if MEM > 8 | ||
3275 | case Q_AUDIO_FILL_BUFFER_IF_ACTIVE_ATA: | ||
3276 | /* only fill if the disk is still spining */ | ||
3277 | #ifndef SIMULATOR | ||
3278 | if (!ata_disk_is_active()) | ||
3279 | break; | ||
3280 | #endif | ||
3281 | #endif /* MEM > 8 */ | ||
3282 | /* else fall through to Q_AUDIO_FILL_BUFFER */ | ||
3251 | case Q_AUDIO_FILL_BUFFER: | 3283 | case Q_AUDIO_FILL_BUFFER: |
3252 | LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER"); | 3284 | LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER"); |
3253 | if (!filling) | 3285 | 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 | |||
95 | drivers/power.c | 95 | drivers/power.c |
96 | #endif | 96 | #endif |
97 | drivers/led.c | 97 | drivers/led.c |
98 | ata_idle_notify.c | ||
98 | #ifndef SIMULATOR | 99 | #ifndef SIMULATOR |
99 | #ifndef TARGET_TREE | 100 | #ifndef TARGET_TREE |
100 | drivers/adc.c | 101 | 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 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2006 Jonathan Gordon | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | #include <stdbool.h> | ||
20 | #include "system.h" | ||
21 | #include "ata_idle_notify.h" | ||
22 | #include "logf.h" | ||
23 | |||
24 | #if USING_ATA_CALLBACK | ||
25 | static ata_idle_notify ata_idle_notify_funcs[MAX_ATA_CALLBACKS]; | ||
26 | static int ata_callback_count = 0; | ||
27 | #endif | ||
28 | |||
29 | bool register_ata_idle_func(ata_idle_notify function) | ||
30 | { | ||
31 | #if USING_ATA_CALLBACK | ||
32 | int i; | ||
33 | for (i=0; i<MAX_ATA_CALLBACKS; i++) | ||
34 | { | ||
35 | if (ata_idle_notify_funcs[i] == NULL) | ||
36 | { | ||
37 | ata_idle_notify_funcs[i] = function; | ||
38 | ata_callback_count++; | ||
39 | return true; | ||
40 | } | ||
41 | else if (ata_idle_notify_funcs[i] == function) | ||
42 | return true; | ||
43 | } | ||
44 | return false; | ||
45 | #else | ||
46 | function(); /* just call the function now */ | ||
47 | /* this _may_ cause problems later if the calling function | ||
48 | sets a variable expecting the callback to unset it, because | ||
49 | the callback will be run before this function exits, so before the var is set */ | ||
50 | return true; | ||
51 | #endif | ||
52 | } | ||
53 | |||
54 | #if USING_ATA_CALLBACK | ||
55 | void unregister_ata_idle_func(ata_idle_notify func) | ||
56 | { | ||
57 | int i; | ||
58 | for (i=0; i<MAX_ATA_CALLBACKS; i++) | ||
59 | { | ||
60 | if (ata_idle_notify_funcs[i] == func) | ||
61 | { | ||
62 | ata_idle_notify_funcs[i] = NULL; | ||
63 | ata_callback_count--; | ||
64 | } | ||
65 | } | ||
66 | return; | ||
67 | } | ||
68 | |||
69 | bool call_ata_idle_notifys(void) | ||
70 | { | ||
71 | int i; | ||
72 | ata_idle_notify function; | ||
73 | if (ata_callback_count == 0) | ||
74 | return false; | ||
75 | ata_callback_count = 0; /* so we dont re-enter every time the callbacks read/write */ | ||
76 | for (i = 0; i < MAX_ATA_CALLBACKS; i++) | ||
77 | { | ||
78 | if (ata_idle_notify_funcs[i]) | ||
79 | { | ||
80 | function = ata_idle_notify_funcs[i]; | ||
81 | ata_idle_notify_funcs[i] = NULL; | ||
82 | function(); | ||
83 | } | ||
84 | } | ||
85 | return true; | ||
86 | } | ||
87 | |||
88 | void ata_idle_notify_init(void) | ||
89 | { | ||
90 | int i; | ||
91 | for (i=0; i<MAX_ATA_CALLBACKS; i++) | ||
92 | { | ||
93 | ata_idle_notify_funcs[i] = NULL; | ||
94 | } | ||
95 | } | ||
96 | #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 @@ | |||
29 | #include "power.h" | 29 | #include "power.h" |
30 | #include "string.h" | 30 | #include "string.h" |
31 | #include "hwcompat.h" | 31 | #include "hwcompat.h" |
32 | 32 | #include "ata_idle_notify.h" | |
33 | #ifdef TARGET_TREE | 33 | #ifdef TARGET_TREE |
34 | #include "ata-target.h" | 34 | #include "ata-target.h" |
35 | #endif | 35 | #endif |
@@ -1364,6 +1364,7 @@ static void ata_thread(void) | |||
1364 | { | 1364 | { |
1365 | static long last_sleep = 0; | 1365 | static long last_sleep = 0; |
1366 | struct event ev; | 1366 | struct event ev; |
1367 | static long last_callback_run = 0; | ||
1367 | 1368 | ||
1368 | while (1) { | 1369 | while (1) { |
1369 | while ( queue_empty( &ata_queue ) ) { | 1370 | while ( queue_empty( &ata_queue ) ) { |
@@ -1373,8 +1374,16 @@ static void ata_thread(void) | |||
1373 | TIME_AFTER( current_tick, | 1374 | TIME_AFTER( current_tick, |
1374 | last_disk_activity + sleep_timeout ) ) | 1375 | last_disk_activity + sleep_timeout ) ) |
1375 | { | 1376 | { |
1376 | ata_perform_sleep(); | 1377 | if (!call_ata_idle_notifys()) |
1377 | last_sleep = current_tick; | 1378 | { |
1379 | ata_perform_sleep(); | ||
1380 | last_sleep = current_tick; | ||
1381 | } | ||
1382 | } | ||
1383 | else if (TIME_AFTER(current_tick, last_callback_run+(HZ*5))) | ||
1384 | { | ||
1385 | last_callback_run = current_tick; | ||
1386 | call_ata_idle_notifys(); | ||
1378 | } | 1387 | } |
1379 | 1388 | ||
1380 | #ifdef HAVE_ATA_POWER_OFF | 1389 | #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 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2006 Jonathan Gordon | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | #ifndef __ATACALLBACK_H__ | ||
20 | #define __ATACALLBACK_H__ | ||
21 | |||
22 | #include <stdbool.h> | ||
23 | #define USING_ATA_CALLBACK !defined(SIMULATOR) \ | ||
24 | && !defined(HAVE_FLASH_DISK) \ | ||
25 | && !defined(HAVE_MMC) | ||
26 | |||
27 | #define MAX_ATA_CALLBACKS 5 | ||
28 | typedef bool (*ata_idle_notify)(void); | ||
29 | |||
30 | extern bool register_ata_idle_func(ata_idle_notify function); | ||
31 | #if USING_ATA_CALLBACK | ||
32 | extern void ata_idle_notify_init(void); | ||
33 | extern void unregister_ata_idle_func(ata_idle_notify function); | ||
34 | extern bool call_ata_idle_notifys(void); | ||
35 | #else | ||
36 | #define unregister_ata_idle_func(f) | ||
37 | #define call_ata_idle_notifys() | ||
38 | #define ata_idle_notify_init() | ||
39 | #endif | ||
40 | |||
41 | #endif /* __ATACALLBACK_H__ */ | ||