From d5a59301968cf98d739f6dbb167832a8ec2fb943 Mon Sep 17 00:00:00 2001 From: Thomas Martitz Date: Mon, 1 Aug 2011 16:59:49 +0200 Subject: [PATCH] Replace all direct accesses to audiobuf with buffer API functions. Namely, introduce buffer_get_buffer() and buffer_release_buffer(). buffer_get_buffer() aquires all available and grabs a lock, attempting to call buffer_alloc() or buffer_get_buffer() while this lock is locked will cause a panicf() (doesn't actually happen, but is for debugging purpose). buffer_release_buffer() unlocks that lock and can additionally increment the audiobuf buffer to make an allocation. Pass 0 to only unlock if buffer was used temporarily only. buffer_available() is a replacement function to query audiobuflen, i.e. what's left in the buffer. Further changes happened to mp3data.c and talk.c as to not call the above API functions, but get the buffer from callers. The caller is the audio system which has the buffer lock while mp3dat and talk mess with the buffer. mpeg.c now implements some buffer related functions of playback.h, that no audiobuf and audiobufend are local to buffer.c now. --- apps/filetree.c | 1 + apps/main.c | 11 +---- apps/menus/main_menu.c | 4 +- apps/misc.c | 3 ++ apps/mp3data.c | 41 +++++++++------- apps/mp3data.h | 30 ++++++------ apps/mpeg.c | 89 ++++++++++++++++++++++++++--------- apps/playback.c | 45 +++++++++++------- apps/playback.h | 1 - apps/playlist.c | 18 +------ apps/playlist_viewer.c | 3 -- apps/plugin.c | 8 +--- apps/plugin.h | 8 ++-- apps/plugins/vbrfix.c | 5 +- apps/recorder/pcm_record.c | 2 - apps/tagcache.c | 8 ++-- apps/talk.c | 111 ++++++++++++++++++++++++++++++-------------- apps/talk.h | 1 + firmware/buffer.c | 75 ++++++++++++++++++++++++++++-- firmware/common/dircache.c | 22 ++++++--- firmware/export/audio.h | 6 ++- firmware/include/buffer.h | 18 ++----- firmware/include/dircache.h | 3 +- firmware/rolo.c | 28 ++++++++--- 24 files changed, 350 insertions(+), 191 deletions(-) diff --git a/apps/filetree.c b/apps/filetree.c index a7c989fc5..1aee80b6b 100644 --- a/apps/filetree.c +++ b/apps/filetree.c @@ -600,6 +600,7 @@ int ft_enter(struct tree_context* c) /* firmware file */ case FILE_ATTR_MOD: splash(0, ID2P(LANG_WAIT)); + audio_hard_stop(); rolo_load(buf); break; #endif diff --git a/apps/main.c b/apps/main.c index 0b566b5c0..9cb724562 100644 --- a/apps/main.c +++ b/apps/main.c @@ -337,11 +337,11 @@ static void init_tagcache(void) static void init(void) { system_init(); + buffer_init(); kernel_init(); #ifdef APPLICATION paths_init(); #endif - buffer_init(); enable_irq(); lcd_init(); #ifdef HAVE_REMOTE_LCD @@ -428,13 +428,7 @@ static void init(void) #endif system_init(); -#if defined(IPOD_VIDEO) - audiobufend=(unsigned char *)audiobufend_lds; - if(MEMORYSIZE==64 && probed_ramsize!=64) - { - audiobufend -= (32<<20); - } -#endif + buffer_init(); kernel_init(); #ifdef HAVE_ADJUSTABLE_CPU_FREQ @@ -445,7 +439,6 @@ static void init(void) cpu_boost(true); #endif - buffer_init(); settings_reset(); diff --git a/apps/menus/main_menu.c b/apps/menus/main_menu.c index 6ee7ba415..c5758d127 100644 --- a/apps/menus/main_menu.c +++ b/apps/menus/main_menu.c @@ -182,7 +182,7 @@ static const char* info_getname(int selected_item, void *data, case INFO_BUFFER: /* buffer */ { - long kib = (audiobufend - audiobuf) / 1024; /* to KiB */ + long kib = buffer_available() / 1024; /* to KiB */ output_dyn_value(s1, sizeof(s1), kib, kbyte_units, true); snprintf(buffer, buffer_len, "%s %s", str(LANG_BUFFER_STAT), s1); } @@ -272,7 +272,7 @@ static int info_speak_item(int selected_item, void * data) case INFO_BUFFER: /* buffer */ { talk_id(LANG_BUFFER_STAT, false); - long kib = (audiobufend - audiobuf) / 1024; /* to KiB */ + long kib = buffer_available() / 1024; /* to KiB */ output_dyn_value(NULL, 0, kib, kbyte_units, true); break; } diff --git a/apps/misc.c b/apps/misc.c index 83e42cf3e..c8fdc9806 100644 --- a/apps/misc.c +++ b/apps/misc.c @@ -765,7 +765,10 @@ void check_bootfile(bool do_rolo) static const struct text_message message={ lines, 2 }; button_clear_queue(); /* Empty the keyboard buffer */ if(gui_syncyesno_run(&message, NULL, NULL) == YESNO_YES) + { + audio_hard_stop(); rolo_load(BOOTDIR "/" BOOTFILE); + } } } wrtdate = info.wrtdate; diff --git a/apps/mp3data.c b/apps/mp3data.c index 9fed72760..53f13f4f6 100644 --- a/apps/mp3data.c +++ b/apps/mp3data.c @@ -311,17 +311,18 @@ unsigned long find_next_frame(int fd, #ifndef __PCTOOL__ static int fnf_read_index; static int fnf_buf_len; +static unsigned char *fnf_buf; static int buf_getbyte(int fd, unsigned char *c) { if(fnf_read_index < fnf_buf_len) { - *c = audiobuf[fnf_read_index++]; + *c = fnf_buf[fnf_read_index++]; return 1; } else { - fnf_buf_len = read(fd, audiobuf, audiobufend - audiobuf); + fnf_buf_len = read(fd, fnf_buf, fnf_buf_len); if(fnf_buf_len < 0) return -1; @@ -329,7 +330,7 @@ static int buf_getbyte(int fd, unsigned char *c) if(fnf_buf_len > 0) { - *c = audiobuf[fnf_read_index++]; + *c = fnf_buf[fnf_read_index++]; return 1; } else @@ -345,7 +346,7 @@ static int buf_seek(int fd, int len) { len = fnf_read_index - fnf_buf_len; - fnf_buf_len = read(fd, audiobuf, audiobufend - audiobuf); + fnf_buf_len = read(fd, fnf_buf, fnf_buf_len); if(fnf_buf_len < 0) return -1; @@ -361,9 +362,10 @@ static int buf_seek(int fd, int len) return 0; } -static void buf_init(void) +static void buf_init(unsigned char* buf, size_t buflen) { - fnf_buf_len = 0; + fnf_buf = buf; + fnf_buf_len = buflen; fnf_read_index = 0; } @@ -372,8 +374,9 @@ static unsigned long buf_find_next_frame(int fd, long *offset, long max_offset) return __find_next_frame(fd, offset, max_offset, 0, buf_getbyte, true); } -static int audiobuflen; -static int mem_pos; +static size_t mem_buflen; +static unsigned char* mem_buf; +static size_t mem_pos; static int mem_cnt; static int mem_maxlen; @@ -381,8 +384,8 @@ static int mem_getbyte(int dummy, unsigned char *c) { dummy = dummy; - *c = audiobuf[mem_pos++]; - if(mem_pos >= audiobuflen) + *c = mem_buf[mem_pos++]; + if(mem_pos >= mem_buflen) mem_pos = 0; if(mem_cnt++ >= mem_maxlen) @@ -394,9 +397,11 @@ static int mem_getbyte(int dummy, unsigned char *c) unsigned long mem_find_next_frame(int startpos, long *offset, long max_offset, - unsigned long reference_header) + unsigned long reference_header, + unsigned char* buf, size_t buflen) { - audiobuflen = audiobufend - audiobuf; + mem_buf = buf; + mem_buflen = buflen; mem_pos = startpos; mem_cnt = 0; mem_maxlen = max_offset; @@ -620,8 +625,9 @@ static void long2bytes(unsigned char *buf, long val) buf[3] = val & 0xff; } -int count_mp3_frames(int fd, int startpos, int filesize, - void (*progressfunc)(int)) +int count_mp3_frames(int fd, int startpos, int filesize, + void (*progressfunc)(int), + unsigned char* buf, size_t buflen) { unsigned long header = 0; struct mp3info info; @@ -637,7 +643,7 @@ int count_mp3_frames(int fd, int startpos, int filesize, if(lseek(fd, startpos, SEEK_SET) < 0) return -1; - buf_init(); + buf_init(buf, buflen); /* Find out the total number of frames */ num_frames = 0; @@ -687,7 +693,8 @@ static const char cooltext[] = "Rockbox - rocks your box"; int create_xing_header(int fd, long startpos, long filesize, unsigned char *buf, unsigned long num_frames, unsigned long rec_time, unsigned long header_template, - void (*progressfunc)(int), bool generate_toc) + void (*progressfunc)(int), bool generate_toc, + unsigned char *tempbuf, size_t tempbuflen ) { struct mp3info info; unsigned char toc[100]; @@ -705,7 +712,7 @@ int create_xing_header(int fd, long startpos, long filesize, if(generate_toc) { lseek(fd, startpos, SEEK_SET); - buf_init(); + buf_init(tempbuf, tempbuflen); /* Generate filepos table */ last_pos = 0; diff --git a/apps/mp3data.h b/apps/mp3data.h index edda352aa..762c2f458 100644 --- a/apps/mp3data.h +++ b/apps/mp3data.h @@ -26,6 +26,8 @@ #define MPEG_VERSION2 1 #define MPEG_VERSION2_5 2 +#include /* size_t */ + struct mp3info { /* Standard MP3 frame header fields */ int version; @@ -63,23 +65,21 @@ unsigned long find_next_frame(int fd, unsigned long reference_header); unsigned long mem_find_next_frame(int startpos, long *offset, - long max_offset, - unsigned long reference_header); + long max_offset, + unsigned long reference_header, + unsigned char* buf, size_t buflen); int get_mp3file_info(int fd, struct mp3info *info); -int count_mp3_frames(int fd, - int startpos, - int filesize, - void (*progressfunc)(int)); -int create_xing_header(int fd, - long startpos, - long filesize, - unsigned char *buf, - unsigned long num_frames, - unsigned long rec_time, - unsigned long header_template, - void (*progressfunc)(int), - bool generate_toc); + +int count_mp3_frames(int fd, int startpos, int filesize, + void (*progressfunc)(int), + unsigned char* buf, size_t buflen); + +int create_xing_header(int fd, long startpos, long filesize, + unsigned char *buf, unsigned long num_frames, + unsigned long rec_time, unsigned long header_template, + void (*progressfunc)(int), bool generate_toc, + unsigned char *tempbuf, size_t tempbuflen ); extern unsigned long bytes2int(unsigned long b0, unsigned long b1, diff --git a/apps/mpeg.c b/apps/mpeg.c index b11445f94..a0182ad8d 100644 --- a/apps/mpeg.c +++ b/apps/mpeg.c @@ -37,6 +37,7 @@ #include "mp3data.h" #include "buffer.h" #include "mp3_playback.h" +#include "talk.h" #include "sound.h" #include "bitswap.h" #include "appevents.h" @@ -144,19 +145,19 @@ static unsigned int mpeg_errno; static bool playing = false; /* We are playing an MP3 stream */ static bool is_playing = false; /* We are (attempting to) playing MP3 files */ static bool paused; /* playback is paused */ +static char* mpeg_audiobuf; /* the audio buffer */ +static long audiobuflen; /* length of the audio buffer */ #ifdef SIMULATOR static char mpeg_stack[DEFAULT_STACK_SIZE]; static struct mp3entry taginfo; - #else /* !SIMULATOR */ static struct event_queue mpeg_queue SHAREDBSS_ATTR; static long mpeg_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)]; -static int audiobuflen; static int audiobuf_write; static int audiobuf_swapwrite; -static int audiobuf_read; +static long audiobuf_read; static int mpeg_file; @@ -490,6 +491,18 @@ unsigned long mpeg_get_last_header(void) #endif /* !SIMULATOR */ } + +unsigned char * audio_get_buffer(bool talk_buf, size_t *buffer_size) +{ + (void)talk_buf; /* always grab the voice buffer for now */ + + audio_hard_stop(); + if (buffer_size) /* special case for talk_init() */ + return buffer_get_buffer(buffer_size); + return NULL; +} + + #ifndef SIMULATOR /* Send callback events to notify about removing old tracks. */ static void generate_unbuffer_events(void) @@ -708,7 +721,7 @@ void rec_tick(void) xor_b(0x08, &PADRH); /* Set PR inactive */ - audiobuf[audiobuf_write++] = data; + mpeg_audiobuf[audiobuf_write++] = data; if (audiobuf_write >= audiobuflen) audiobuf_write = 0; @@ -825,7 +838,7 @@ static void transfer_end(unsigned char** ppbuf, size_t* psize) } *psize = last_dma_chunk_size & 0xffff; - *ppbuf = audiobuf + audiobuf_read; + *ppbuf = mpeg_audiobuf + audiobuf_read; track = get_trackdata(0); if(track) track->id3.offset += last_dma_chunk_size; @@ -1128,7 +1141,7 @@ static void start_playback_if_ready(void) playing = true; last_dma_chunk_size = MIN(0x2000, get_unplayed_space_current_song()); - mp3_play_data(audiobuf + audiobuf_read, last_dma_chunk_size, transfer_end); + mp3_play_data(mpeg_audiobuf + audiobuf_read, last_dma_chunk_size, transfer_end); dma_underrun = false; if (!paused) @@ -1173,7 +1186,7 @@ static bool swap_one_chunk(void) amount_to_swap = MIN(audiobuf_write - audiobuf_swapwrite, amount_to_swap); - bitswap(audiobuf + audiobuf_swapwrite, amount_to_swap); + bitswap(mpeg_audiobuf + audiobuf_swapwrite, amount_to_swap); audiobuf_swapwrite += amount_to_swap; if(audiobuf_swapwrite >= audiobuflen) @@ -1341,7 +1354,7 @@ static void mpeg_thread(void) track_change(); audiobuf_read = get_trackdata(0)->mempos; last_dma_chunk_size = MIN(0x2000, get_unplayed_space_current_song()); - mp3_play_data(audiobuf + audiobuf_read, last_dma_chunk_size, transfer_end); + mp3_play_data(mpeg_audiobuf + audiobuf_read, last_dma_chunk_size, transfer_end); dma_underrun = false; last_dma_tick = current_tick; @@ -1501,7 +1514,7 @@ static void mpeg_thread(void) /* resume will start at new position */ last_dma_chunk_size = MIN(0x2000, get_unplayed_space_current_song()); - mp3_play_data(audiobuf + audiobuf_read, + mp3_play_data(mpeg_audiobuf + audiobuf_read, last_dma_chunk_size, transfer_end); dma_underrun = false; } @@ -1632,7 +1645,7 @@ static void mpeg_thread(void) { DEBUGF("R\n"); t1 = current_tick; - len = read(mpeg_file, audiobuf + audiobuf_write, + len = read(mpeg_file, mpeg_audiobuf + audiobuf_write, amount_to_read); if(len > 0) { @@ -1659,7 +1672,7 @@ static void mpeg_thread(void) if(tagptr >= audiobuflen) tagptr -= audiobuflen; - if(audiobuf[tagptr] != tag[i]) + if(mpeg_audiobuf[tagptr] != tag[i]) { taglen = 0; break; @@ -1773,19 +1786,20 @@ static void mpeg_thread(void) startpos = prerecord_buffer[startpos].mempos; DEBUGF("Start looking at address %x (%x)\n", - audiobuf+startpos, startpos); + mpeg_audiobuf+startpos, startpos); saved_header = mpeg_get_last_header(); mem_find_next_frame(startpos, &offset, 1800, - saved_header); + saved_header, mpeg_audiobuf, + audiobuflen); audiobuf_read = startpos + offset; if(audiobuf_read >= audiobuflen) audiobuf_read -= audiobuflen; DEBUGF("New audiobuf_read address: %x (%x)\n", - audiobuf+audiobuf_read, audiobuf_read); + mpeg_audiobuf+audiobuf_read, audiobuf_read); level = disable_irq_save(); num_rec_bytes = get_unsaved_space(); @@ -1894,7 +1908,8 @@ static void mpeg_thread(void) save_endpos += audiobuflen; rc = mem_find_next_frame(save_endpos, &offset, 1800, - saved_header); + saved_header, mpeg_audiobuf, + audiobuflen); if (!rc) /* No header found, save whole buffer */ offset = 1800; @@ -1936,7 +1951,7 @@ static void mpeg_thread(void) #elif MEMORYSIZE == 8 amount_to_save = MIN(0x100000, amount_to_save); #endif - rc = write(mpeg_file, audiobuf + audiobuf_read, + rc = write(mpeg_file, mpeg_audiobuf + audiobuf_read, amount_to_save); if (rc < 0) { @@ -2256,21 +2271,21 @@ static void prepend_header(void) if(audiobuf_read < 0) { /* Clear the bottom half */ - memset(audiobuf, 0, audiobuf_read + MPEG_RESERVED_HEADER_SPACE); + memset(mpeg_audiobuf, 0, audiobuf_read + MPEG_RESERVED_HEADER_SPACE); /* And the top half */ audiobuf_read += audiobuflen; - memset(audiobuf + audiobuf_read, 0, audiobuflen - audiobuf_read); + memset(mpeg_audiobuf + audiobuf_read, 0, audiobuflen - audiobuf_read); } else { - memset(audiobuf + audiobuf_read, 0, MPEG_RESERVED_HEADER_SPACE); + memset(mpeg_audiobuf + audiobuf_read, 0, MPEG_RESERVED_HEADER_SPACE); } /* Copy the empty ID3 header */ startpos = audiobuf_read; for(i = 0; i < sizeof(empty_id3_header); i++) { - audiobuf[startpos++] = empty_id3_header[i]; + mpeg_audiobuf[startpos++] = empty_id3_header[i]; if(startpos == audiobuflen) startpos = 0; } @@ -2297,7 +2312,8 @@ static void update_header(void) /* saved_header is saved right before stopping the MAS */ framelen = create_xing_header(fd, 0, last_rec_bytes, xing_buffer, frames, last_rec_time * (1000/HZ), - saved_header, NULL, false); + saved_header, NULL, false, + mpeg_audiobuf, audiobuflen); lseek(fd, MPEG_RESERVED_HEADER_SPACE - framelen, SEEK_SET); write(fd, xing_buffer, framelen); @@ -2645,8 +2661,22 @@ void audio_set_recording_options(struct audio_recording_options *options) #endif /* SIMULATOR */ #endif /* CONFIG_CODEC == MAS3587F */ +static void audio_reset_buffer(void) +{ + size_t bufsize; /* dont break strict-aliasing */ + talk_buffer_steal(); /* will use the mp3 buffer */ + + /* release buffer on behalf of any audio_get_buffer() caller, + * non-fatal if there was none */ + buffer_release_buffer(0); + /* re-aquire */ + mpeg_audiobuf = buffer_get_buffer(&bufsize); + audiobuflen = bufsize; +} + void audio_play(long offset) { + audio_reset_buffer(); #ifdef SIMULATOR char name_buf[MAX_PATH+1]; const char* trackname; @@ -2676,7 +2706,6 @@ void audio_play(long offset) } while(1); #else /* !SIMULATOR */ is_playing = true; - queue_post(&mpeg_queue, MPEG_PLAY, offset); #endif /* !SIMULATOR */ @@ -2700,6 +2729,8 @@ void audio_stop(void) is_playing = false; playing = false; #endif /* SIMULATOR */ + /* give voice our entire buffer */ + talkbuf_init(mpeg_audiobuf); } /* dummy */ @@ -2708,6 +2739,14 @@ void audio_stop_recording(void) audio_stop(); } +void audio_hard_stop(void) +{ + audio_stop(); + /* tell voice we obtain the buffer before freeing */ + talk_buffer_steal(); + buffer_release_buffer(0); +} + void audio_pause(void) { #ifndef SIMULATOR @@ -2864,8 +2903,12 @@ void audio_init(void) if (global_settings.cuesheet) curr_cuesheet = (struct cuesheet*)buffer_alloc(sizeof(struct cuesheet)); + size_t bufsize; /* don't break strict-aliasing */ + mpeg_audiobuf = buffer_get_buffer(&bufsize); + audiobuflen = bufsize; + /* give voice buffer until we start to play */ + talkbuf_init(mpeg_audiobuf); #ifndef SIMULATOR - audiobuflen = audiobufend - audiobuf; queue_init(&mpeg_queue, true); #endif /* !SIMULATOR */ create_thread(mpeg_thread, mpeg_stack, diff --git a/apps/playback.c b/apps/playback.c index fe9bd579d..3f6ee71ad 100644 --- a/apps/playback.c +++ b/apps/playback.c @@ -744,16 +744,25 @@ static void audio_reset_buffer(void) /* see audio_get_recording_buffer if this is modified */ logf("%s()", __func__); + /* release the buffer on behalf of any caller of audio_get_buffer() */ + buffer_release_buffer(0); + /* If the setup of anything allocated before the file buffer is changed, do check the adjustments after the buffer_alloc call as it will likely be affected and need sliding over */ /* Initially set up file buffer as all space available */ - unsigned char *filebuf = audiobuf + talk_get_bufsize(); - size_t filebuflen = audiobufend - filebuf; - size_t allocsize; + size_t filebuflen, allocsize; + unsigned char *filebuf = buffer_get_buffer(&filebuflen); - ALIGN_BUFFER(filebuf, filebuflen, sizeof (intptr_t)); + /* Subtract whatever voice needs */ + allocsize = talkbuf_init(filebuf); + allocsize = ALIGN_UP(allocsize, sizeof (intptr_t)); + if (allocsize > filebuflen) + goto bufpanic; + + filebuf += allocsize; + filebuflen -= allocsize; if (talk_voice_required()) { @@ -3335,6 +3344,7 @@ void audio_hard_stop(void) #ifdef PLAYBACK_VOICE voice_stop(); #endif + buffer_release_buffer(0); } /* Resume playback if paused */ @@ -3441,7 +3451,7 @@ void audio_flush_and_reload_tracks(void) voicing */ unsigned char * audio_get_buffer(bool talk_buf, size_t *buffer_size) { - unsigned char *buf, *end; + unsigned char *buf; if (audio_is_initialized) { @@ -3461,7 +3471,7 @@ unsigned char * audio_get_buffer(bool talk_buf, size_t *buffer_size) || !talk_voice_required()) { logf("get buffer: talk, audio"); - /* Ok to use everything from audiobuf to audiobufend - voice is loaded, + /* Ok to use everything from audiobuf - voice is loaded, the talk buffer is not needed because voice isn't being used, or could be AUDIOBUF_STATE_TRASHED already. If state is AUDIOBUF_STATE_VOICED_ONLY, no problem as long as memory isn't @@ -3474,9 +3484,7 @@ unsigned char * audio_get_buffer(bool talk_buf, size_t *buffer_size) talk_buffer_steal(); buffer_state = AUDIOBUF_STATE_TRASHED; } - - buf = audiobuf; - end = audiobufend; + buf = buffer_get_buffer(buffer_size); } else { @@ -3485,14 +3493,18 @@ unsigned char * audio_get_buffer(bool talk_buf, size_t *buffer_size) /* Skip talk buffer and move pcm buffer to end to maximize available contiguous memory - no audio running means voice will not need the swap space */ + size_t siz, talkbuf_size; logf("get buffer: audio"); - buf = audiobuf + talk_get_bufsize(); - end = audiobufend - voicebuf_init(audiobufend); + /* call buffer_get_buffer() to make use of the locking mechanism */ + buf = buffer_get_buffer(&siz); + buf += talkbuf_size = talkbuf_init(buf); + siz -= talkbuf_size; + siz -= voicebuf_init(buf + siz); + *buffer_size = siz; + buffer_state = AUDIOBUF_STATE_VOICED_ONLY; } - *buffer_size = end - buf; - return buf; } @@ -3500,14 +3512,11 @@ unsigned char * audio_get_buffer(bool talk_buf, size_t *buffer_size) /* Stop audio, voice and obtain all available buffer space */ unsigned char * audio_get_recording_buffer(size_t *buffer_size) { - audio_hard_stop(); talk_buffer_steal(); + audio_hard_stop(); - unsigned char *end = audiobufend; buffer_state = AUDIOBUF_STATE_TRASHED; - *buffer_size = end - audiobuf; - - return (unsigned char *)audiobuf; + return buffer_get_buffer(buffer_size); } #endif /* HAVE_RECORDING */ diff --git a/apps/playback.h b/apps/playback.h index ea8718089..793055f98 100644 --- a/apps/playback.h +++ b/apps/playback.h @@ -75,7 +75,6 @@ int audio_track_count(void); long audio_filebufused(void); void audio_pre_ff_rewind(void); void audio_skip(int direction); -void audio_hard_stop(void); /* Stops audio from serving playback */ void audio_set_cuesheet(int enable); #ifdef HAVE_CROSSFADE diff --git a/apps/playlist.c b/apps/playlist.c index 564cd03d9..833426024 100644 --- a/apps/playlist.c +++ b/apps/playlist.c @@ -533,13 +533,7 @@ static int add_indices_to_playlist(struct playlist_info* playlist, { /* use mp3 buffer for maximum load speed */ audio_stop(); -#if CONFIG_CODEC != SWCODEC - talk_buffer_steal(); /* we use the mp3 buffer, need to tell */ - buflen = (audiobufend - audiobuf); - buffer = (char *)audiobuf; -#else - buffer = (char *)audio_get_buffer(false, &buflen); -#endif + buffer = audio_get_buffer(false, &buflen); } store_index = true; @@ -2018,13 +2012,7 @@ int playlist_resume(void) bool sorted = true; /* use mp3 buffer for maximum load speed */ -#if CONFIG_CODEC != SWCODEC - talk_buffer_steal(); /* we use the mp3 buffer, need to tell */ - buflen = (audiobufend - audiobuf); - buffer = (char *)audiobuf; -#else buffer = (char *)audio_get_buffer(false, &buflen); -#endif empty_playlist(playlist, true); @@ -2449,10 +2437,6 @@ void playlist_start(int start_index, int offset) playlist->index = start_index; -#if CONFIG_CODEC != SWCODEC - talk_buffer_steal(); /* will use the mp3 buffer */ -#endif - playlist->started = true; sync_control(playlist, false); audio_play(offset); diff --git a/apps/playlist_viewer.c b/apps/playlist_viewer.c index 803fba976..43c0c0142 100644 --- a/apps/playlist_viewer.c +++ b/apps/playlist_viewer.c @@ -493,9 +493,6 @@ static int onplay_menu(int index) if (current_track->display_index!=viewer.num_tracks || global_settings.repeat_mode == REPEAT_ALL) { -#if CONFIG_CODEC != SWCODEC - talk_buffer_steal(); /* will use the mp3 buffer */ -#endif audio_play(0); viewer.current_playing_track = -1; } diff --git a/apps/plugin.c b/apps/plugin.c index 50fbb3701..32b77ad28 100644 --- a/apps/plugin.c +++ b/apps/plugin.c @@ -979,14 +979,8 @@ void* plugin_get_buffer(size_t *buffer_size) */ void* plugin_get_audio_buffer(size_t *buffer_size) { -#if CONFIG_CODEC == SWCODEC - return audio_get_buffer(true, buffer_size); -#else audio_stop(); - talk_buffer_steal(); /* we use the mp3 buffer, need to tell */ - *buffer_size = audiobufend - audiobuf; - return audiobuf; -#endif + return audio_get_buffer(true, buffer_size); } /* The plugin wants to stay resident after leaving its main function, e.g. diff --git a/apps/plugin.h b/apps/plugin.h index a53df90d6..e2a5771b5 100644 --- a/apps/plugin.h +++ b/apps/plugin.h @@ -828,12 +828,14 @@ struct plugin_api { #endif /* CONFIG_CODEC == SWCODEC */ bool (*get_metadata)(struct mp3entry* id3, int fd, const char* trackname); bool (*mp3info)(struct mp3entry *entry, const char *filename); - int (*count_mp3_frames)(int fd, int startpos, int filesize, - void (*progressfunc)(int)); + int (*count_mp3_frames)(int fd, int startpos, int filesize, + void (*progressfunc)(int), + unsigned char* buf, size_t buflen); int (*create_xing_header)(int fd, long startpos, long filesize, unsigned char *buf, unsigned long num_frames, unsigned long rec_time, unsigned long header_template, - void (*progressfunc)(int), bool generate_toc); + void (*progressfunc)(int), bool generate_toc, + unsigned char* tempbuf, size_t tempbuf_len); unsigned long (*find_next_frame)(int fd, long *offset, long max_offset, unsigned long reference_header); diff --git a/apps/plugins/vbrfix.c b/apps/plugins/vbrfix.c index 98ca15b6a..af7b81700 100644 --- a/apps/plugins/vbrfix.c +++ b/apps/plugins/vbrfix.c @@ -157,14 +157,15 @@ static bool vbr_fix(const char *selected_file) xingupdate(0); num_frames = rb->count_mp3_frames(fd, entry.first_frame_offset, - flen, xingupdate); + flen, xingupdate, audiobuf, audiobuflen); if(num_frames) { /* Note: We don't need to pass a template header because it will be taken from the mpeg stream */ framelen = rb->create_xing_header(fd, entry.first_frame_offset, flen, xingbuf, num_frames, 0, - 0, xingupdate, true); + 0, xingupdate, true, + audiobuf, audiobuflen); /* Try to fit the Xing header first in the stream. Replace the existing VBR header if there is one, else see if there is room between the diff --git a/apps/recorder/pcm_record.c b/apps/recorder/pcm_record.c index 8a832e409..407a7e5f4 100644 --- a/apps/recorder/pcm_record.c +++ b/apps/recorder/pcm_record.c @@ -1643,14 +1643,12 @@ void enc_set_parameters(struct enc_parameters *params) logf("fnq files:%ld", fnq_size / MAX_PATH); #if defined(DEBUG) - logf("ab :%08lX", (uintptr_t)audiobuf); logf("pcm:%08lX", (uintptr_t)pcm_buffer); logf("enc:%08lX", (uintptr_t)enc_buffer); logf("res:%08lX", (uintptr_t)params->reserve_buffer); logf("wip:%08lX", (uintptr_t)wrap_id_p); logf("fnq:%08lX", (uintptr_t)fn_queue); logf("end:%08lX", (uintptr_t)fn_queue + fnq_size); - logf("abe:%08lX", (uintptr_t)audiobufend); #endif /* init all chunk headers and reset indexes */ diff --git a/apps/tagcache.c b/apps/tagcache.c index 6aa7709c0..0a491c58b 100644 --- a/apps/tagcache.c +++ b/apps/tagcache.c @@ -107,7 +107,7 @@ static char curpath[TAG_MAXLEN+32]; /* Used when removing duplicates. */ static char *tempbuf; /* Allocated when needed. */ static long tempbufidx; /* Current location in buffer. */ -static long tempbuf_size; /* Buffer size (TEMPBUF_SIZE). */ +static size_t tempbuf_size; /* Buffer size (TEMPBUF_SIZE). */ static long tempbuf_left; /* Buffer space left. */ static long tempbuf_pos; @@ -3089,9 +3089,7 @@ static void allocate_tempbuf(void) tempbuf_size = 32*1024*1024; tempbuf = malloc(tempbuf_size); #else - tempbuf = (char *)(((long)audiobuf & ~0x03) + 0x04); - tempbuf_size = (long)audiobufend - (long)audiobuf - 4; - audiobuf += tempbuf_size; + buffer_get_buffer(&tempbuf_size); #endif } @@ -3103,7 +3101,7 @@ static void free_tempbuf(void) #ifdef __PCTOOL__ free(tempbuf); #else - audiobuf -= tempbuf_size; + buffer_release_buffer(0); #endif tempbuf = NULL; tempbuf_size = 0; diff --git a/apps/talk.c b/apps/talk.c index 8c0f1f3a0..9fd6fb06e 100644 --- a/apps/talk.c +++ b/apps/talk.c @@ -49,7 +49,7 @@ MASCODEC | MASCODEC | SWCODEC (playing) | (stopped) | - audiobuf-----------+-----------+------------ + voicebuf-----------+-----------+------------ audio | voice | thumbnail |-----------|------------ | thumbnail | voice @@ -57,7 +57,7 @@ | | filebuf | |------------ | | audio - audiobufend----------+-----------+------------ + voicebufend----------+-----------+------------ SWCODEC allocates dedicated buffers, MASCODEC reuses audiobuf. */ @@ -128,6 +128,7 @@ static uint8_t clip_age[QUEUE_SIZE]; #endif #endif +static char* voicebuf; /* root pointer to our buffer */ static unsigned char* p_thumbnail = NULL; /* buffer for thumbnails */ /* Multiple thumbnails can be loaded back-to-back in this buffer. */ static volatile int thumbnail_buf_used SHAREDBSS_ATTR; /* length of data in @@ -281,12 +282,18 @@ static unsigned char* get_clip(long id, long* p_size) /* load the voice file into the mp3 buffer */ -static void load_voicefile(bool probe) +static void load_voicefile(bool probe, char* buf, size_t bufsize) { - int load_size; + union voicebuf { + unsigned char* buf; + struct voicefile* file; + }; + union voicebuf voicebuf; + + int load_size, alloc_size; int got_size; #ifndef TALK_PARTIAL_LOAD - int file_size; + size_t file_size; #endif #ifdef ROCKBOX_LITTLE_ENDIAN int i; @@ -297,37 +304,43 @@ static void load_voicefile(bool probe) if (filehandle < 0) /* failed to open */ goto load_err; + voicebuf.buf = buf; + if (!voicebuf.buf) + goto load_err; + #ifndef TALK_PARTIAL_LOAD file_size = filesize(filehandle); - if (file_size > audiobufend - audiobuf) /* won't fit? */ + if (file_size > bufsize) /* won't fit? */ goto load_err; #endif #if defined(TALK_PROGRESSIVE_LOAD) || defined(TALK_PARTIAL_LOAD) /* load only the header for now */ - load_size = offsetof(struct voicefile, index); + load_size = sizeof(struct voicefile); #else /* load the full file */ load_size = file_size; #endif #ifdef TALK_PARTIAL_LOAD - if (load_size > audiobufend - audiobuf) /* won't fit? */ + if (load_size > bufsize) /* won't fit? */ goto load_err; #endif - got_size = read(filehandle, audiobuf, load_size); + got_size = read(filehandle, voicebuf.buf, load_size); if (got_size != load_size /* failure */) goto load_err; + alloc_size = load_size; + #ifdef ROCKBOX_LITTLE_ENDIAN logf("Byte swapping voice file"); - structec_convert(audiobuf, "lllll", 1, true); + structec_convert(voicebuf.buf, "lllll", 1, true); #endif - if (((struct voicefile*)audiobuf)->table /* format check */ - == offsetof(struct voicefile, index)) + /* format check */ + if (voicebuf.file->table == sizeof(struct voicefile)) { - p_voicefile = (struct voicefile*)audiobuf; + p_voicefile = voicebuf.file; if (p_voicefile->version != VOICE_VERSION || p_voicefile->target_id != TARGET_ID) @@ -337,9 +350,9 @@ static void load_voicefile(bool probe) } #if CONFIG_CODEC != SWCODEC /* MASCODEC: now use audiobuf for voice then thumbnail */ - p_thumbnail = audiobuf + file_size; + p_thumbnail = voicebuf.buf + file_size; p_thumbnail += (long)p_thumbnail % 2; /* 16-bit align */ - size_for_thumbnail = audiobufend - p_thumbnail; + size_for_thumbnail = voicebuf.buf + bufsize - p_thumbnail; #endif } else @@ -351,14 +364,15 @@ static void load_voicefile(bool probe) * sizeof(struct clip_entry); #ifdef TALK_PARTIAL_LOAD - if (load_size > audiobufend - audiobuf) /* won't fit? */ + if (load_size > bufsize) /* won't fit? */ goto load_err; #endif - got_size = read(filehandle, - (unsigned char *) p_voicefile + offsetof(struct voicefile, index), load_size); + got_size = read(filehandle, &p_voicefile->index[0], load_size); if (got_size != load_size) /* read error */ goto load_err; + + alloc_size += load_size; #else close(filehandle); filehandle = -1; @@ -379,6 +393,11 @@ static void load_voicefile(bool probe) p_silence = get_clip(VOICE_PAUSE, &silence_len); } +#ifdef TALK_PARTIAL_LOAD + alloc_size += silence_len + QUEUE_SIZE; +#endif + if ((size_t)alloc_size > bufsize) + goto load_err; return; load_err: @@ -582,24 +601,31 @@ static void queue_clip(unsigned char* buf, long size, bool enqueue) } -/* common code for talk_init() and talk_buffer_steal() */ -static void reset_state(void) +static void alloc_thumbnail_buf(void) { - queue_write = queue_read = 0; /* reset the queue */ - p_voicefile = NULL; /* indicate no voicefile (trashed) */ #if CONFIG_CODEC == SWCODEC /* Allocate a dedicated thumbnail buffer - once */ if (p_thumbnail == NULL) { - size_for_thumbnail = audiobufend - audiobuf; + size_for_thumbnail = buffer_available(); if (size_for_thumbnail > MAX_THUMBNAIL_BUFSIZE) size_for_thumbnail = MAX_THUMBNAIL_BUFSIZE; p_thumbnail = buffer_alloc(size_for_thumbnail); } #else - /* Just use the audiobuf, without allocating anything */ - p_thumbnail = audiobuf; - size_for_thumbnail = audiobufend - audiobuf; + /* use the audio buffer now, need to release before loading a voice */ + p_thumbnail = voicebuf; +#endif + thumbnail_buf_used = 0; +} + +/* common code for talk_init() and talk_buffer_steal() */ +static void reset_state(void) +{ + queue_write = queue_read = 0; /* reset the queue */ + p_voicefile = NULL; /* indicate no voicefile (trashed) */ +#if CONFIG_CODEC != SWCODEC + p_thumbnail = NULL; /* don't leak buffer_alloc() for swcodec */ #endif #ifdef TALK_PARTIAL_LOAD @@ -608,8 +634,8 @@ static void reset_state(void) buffered_id[i] = -1; #endif - thumbnail_buf_used = 0; p_silence = NULL; /* pause clip not accessible */ + voicebuf = NULL; } @@ -655,12 +681,11 @@ void talk_init(void) #endif reset_state(); /* use this for most of our inits */ - /* test if we can open and if it fits in the audiobuffer */ - size_t audiobufsz = audiobufend - audiobuf; - #ifdef TALK_PARTIAL_LOAD + size_t bufsize; + char* buf = plugin_get_buffer(&bufsize); /* we won't load the full file, we only need the index */ - load_voicefile(true); + load_voicefile(true, buf, bufsize); if (!p_voicefile) return; @@ -681,6 +706,9 @@ void talk_init(void) p_voicefile = NULL; /* Don't pretend we can load talk clips just yet */ #endif + + /* test if we can open and if it fits in the audiobuffer */ + size_t audiobufsz = buffer_available(); if (voicefile_size <= audiobufsz) { has_voicefile = true; } else { @@ -688,6 +716,7 @@ void talk_init(void) voicefile_size = 0; } + alloc_thumbnail_buf(); close(filehandle); /* close again, this was just to detect presence */ filehandle = -1; } @@ -703,8 +732,22 @@ bool talk_voice_required(void) #endif /* return size of voice file */ -int talk_get_bufsize(void) +int talk_get_buffer(void) +{ + return voicefile_size; +} + +/* Sets the buffer for the voicefile and returns how many bytes of this + * buffer we will use for the voicefile */ +size_t talkbuf_init(char *bufstart) { + bool changed = voicebuf != bufstart; + + if (bufstart) + voicebuf = bufstart; + if (changed) /* must reload voice file */ + reset_state(); + return voicefile_size; } @@ -741,7 +784,7 @@ int talk_id(int32_t id, bool enqueue) #endif if (p_voicefile == NULL && has_voicefile) - load_voicefile(false); /* reload needed */ + load_voicefile(false, voicebuf, voicefile_size); /* reload needed */ if (p_voicefile == NULL) /* still no voices? */ return -1; @@ -819,7 +862,7 @@ static int _talk_file(const char* filename, #endif if (p_thumbnail == NULL || size_for_thumbnail <= 0) - return -1; + alloc_thumbnail_buf(); #if CONFIG_CODEC != SWCODEC if(mp3info(&info, filename)) /* use this to find real start */ diff --git a/apps/talk.h b/apps/talk.h index a2a9f44e4..e1702147c 100644 --- a/apps/talk.h +++ b/apps/talk.h @@ -80,6 +80,7 @@ void talk_init(void); bool talk_voice_required(void); /* returns true if voice codec required */ #endif int talk_get_bufsize(void); /* get the loaded voice file size */ +size_t talkbuf_init(char* bufstart); void talk_buffer_steal(void); /* claim the mp3 buffer e.g. for play/record */ bool is_voice_queued(void); /* Are there more voice clips to be spoken? */ int talk_id(int32_t id, bool enqueue); /* play a voice ID from voicefont */ diff --git a/firmware/buffer.c b/firmware/buffer.c index c317cec92..2168087bd 100644 --- a/firmware/buffer.c +++ b/firmware/buffer.c @@ -19,19 +19,33 @@ * ****************************************************************************/ #include +#include +#include "system.h" #include "buffer.h" #include "panic.h" #include "logf.h" #if (CONFIG_PLATFORM & PLATFORM_HOSTED) -unsigned char audiobuffer[(MEMORYSIZE*1024-256)*1024]; -unsigned char *audiobufend = audiobuffer + sizeof(audiobuffer); #else +#endif + +/* defined in linker script */ +#if (CONFIG_PLATFORM & PLATFORM_NATIVE) +#if defined(IPOD_VIDEO) +extern unsigned char *audiobufend_lds[]; +unsigned char *audiobufend; +#else /* !IPOD_VIDEO */ +extern unsigned char audiobufend[]; +#endif /* defined in linker script */ extern unsigned char audiobuffer[]; +#else /* PLATFORM_HOSTED */ +unsigned char audiobuffer[(MEMORYSIZE*1024-256)*1024]; +unsigned char *audiobufend = audiobuffer + sizeof(audiobuffer); +extern unsigned char *audiobufend; #endif -unsigned char *audiobuf; +static unsigned char *audiobuf; #ifdef BUFFER_ALLOC_DEBUG static unsigned char *audiobuf_orig_start; @@ -54,13 +68,68 @@ void buffer_init(void) { /* 32-bit aligned */ audiobuf = (void *)(((unsigned long)audiobuffer + 3) & ~3); + +#if defined(IPOD_VIDEO) + audiobufend=(unsigned char *)audiobufend_lds; + if(MEMORYSIZE==64 && probed_ramsize!=64) + { + audiobufend -= (32<<20); + } +#endif + #ifdef BUFFER_ALLOC_DEBUG audiobuf_orig_start = audiobuf; #endif /* BUFFER_ALLOC_DEBUG */ } +/* protect concurrent access */ +static volatile int lock; + +/* + * Give the entire buffer, return the size in size. + * The caller needs to make sure audiobuf is not otherwise used + * + * Note that this does not modify the buffer position (buffer_release_buffer() + * does), so call this if you want to aquire temporary memory + **/ +#define _ALIGN (sizeof(char*)) +void *buffer_get_buffer(size_t *size) +{ + if (lock) + panicf("concurrent audiobuf access"); + lock = 1; + audiobuf = ALIGN_UP(audiobuf, sizeof(intptr_t)); + *size = (audiobufend - audiobuf); + return audiobuf; +} + +/* + * Release the buffer gotten with buffer_get_buffer + * + * size should have the amount of bytes (from the front) that caller keeps for + * its own, 0 if the entire buffer is to be released + * + * safe to be called with size=0 even if the buffer wasn't claimed before + **/ +void buffer_release_buffer(size_t size) +{ + audiobuf += size; + /* ensure alignment */ + audiobuf = ALIGN_UP(audiobuf, sizeof(intptr_t)); + lock = 0; +} + +/* + * Query how much free space the buffer has */ +size_t buffer_available(void) +{ + return audiobufend - audiobuf; +} + void *buffer_alloc(size_t size) { + if (lock) /* it's not save to call this here */ + panicf("buffer_alloc(): exclusive buffer owner"); void *retval; #ifdef BUFFER_ALLOC_DEBUG struct buffer_start_marker *start; diff --git a/firmware/common/dircache.c b/firmware/common/dircache.c index 08fe5098f..d114a6ac6 100644 --- a/firmware/common/dircache.c +++ b/firmware/common/dircache.c @@ -862,22 +862,26 @@ int dircache_build(int last_size) * and their corresponding d_name from the end * after generation the buffer will be compacted with DIRCACHE_RESERVE * free bytes inbetween */ - audiobuf = ALIGN_UP(audiobuf, sizeof(struct dircache_entry)); - dircache_root = (struct dircache_entry*)audiobuf; - d_names_start = d_names_end = audiobufend - 1; + size_t got_size; + char* buf = buffer_get_buffer(&got_size); + ALIGN_BUFFER(buf, got_size, sizeof(struct dircache_entry)); + d_names_start = d_names_end = (char*)dircache_root + got_size - 1; dircache_size = 0; generate_dot_d_names(); /* Start a non-transparent rebuild. */ int res = dircache_do_rebuild(); if (res < 0) - return res; + goto fail; /* now compact the dircache buffer */ char* dst = ((char*)&dircache_root[entry_count] + DIRCACHE_RESERVE); ptrdiff_t offset = d_names_start - dst; if (offset <= 0) /* something went wrong */ - return -1; + { + res = -1; + goto fail; + } /* memmove d_names down, there's a possibility of overlap * equivaent to dircache_size - entry_count*sizeof(struct dircache_entry) */ @@ -896,15 +900,19 @@ int dircache_build(int last_size) /* equivalent to dircache_size + DIRCACHE_RESERVE */ allocated_size = (d_names_end - (char*)dircache_root); reserve_used = 0; - audiobuf += allocated_size; + buffer_release_buffer(allocated_size); + return res; +fail: + dircache_disable(); + buffer_release_buffer(0); return res; } /** * Steal the allocated dircache buffer and disable dircache. */ -void* dircache_steal_buffer(long *size) +void* dircache_steal_buffer(size_t *size) { dircache_disable(); if (dircache_size == 0) diff --git a/firmware/export/audio.h b/firmware/export/audio.h index 910791c7f..6757bf143 100644 --- a/firmware/export/audio.h +++ b/firmware/export/audio.h @@ -51,6 +51,8 @@ void audio_init(void) INIT_ATTR; void audio_play(long offset); void audio_stop(void); +/* Stops audio from serving playback and frees resources*/ +void audio_hard_stop(void); void audio_pause(void); void audio_resume(void); void audio_next(void); @@ -68,11 +70,11 @@ void audio_error_clear(void); int audio_get_file_pos(void); void audio_beep(int duration); -#if CONFIG_CODEC == SWCODEC /* Required call when audio buffer is required for some other purpose */ +/* implemented in apps but called from firmware(!) */ unsigned char *audio_get_buffer(bool talk_buf, size_t *buffer_size); -/* only implemented in playback.c, but called from firmware */ +#if CONFIG_CODEC == SWCODEC void audio_next_dir(void); void audio_prev_dir(void); diff --git a/firmware/include/buffer.h b/firmware/include/buffer.h index 18f53f000..bdf91bcb3 100644 --- a/firmware/include/buffer.h +++ b/firmware/include/buffer.h @@ -22,21 +22,13 @@ #define BUFFER_H #include "config.h" -/* defined in linker script */ -#if (CONFIG_PLATFORM & PLATFORM_NATIVE) -#if defined(IPOD_VIDEO) -extern unsigned char *audiobufend_lds[]; -unsigned char *audiobufend; -#else -extern unsigned char audiobufend[]; -#endif -#else -extern unsigned char *audiobufend; -#endif - -extern unsigned char *audiobuf; void buffer_init(void) INIT_ATTR; + +void* buffer_get_buffer(size_t *size); +void buffer_release_buffer(size_t size); +size_t buffer_available(void); + void *buffer_alloc(size_t size); #ifdef BUFFER_ALLOC_DEBUG diff --git a/firmware/include/dircache.h b/firmware/include/dircache.h index 0ac937df8..6beeeb6c2 100644 --- a/firmware/include/dircache.h +++ b/firmware/include/dircache.h @@ -23,6 +23,7 @@ #include "config.h" #include "dir_uncached.h" +#include /* size_t */ #ifdef HAVE_DIRCACHE @@ -65,7 +66,7 @@ void dircache_init(void) INIT_ATTR; int dircache_load(void); int dircache_save(void); int dircache_build(int last_size); -void* dircache_steal_buffer(long *size); +void* dircache_steal_buffer(size_t *size); bool dircache_is_enabled(void); bool dircache_is_initializing(void); void dircache_set_appflag(long mask); diff --git a/firmware/rolo.c b/firmware/rolo.c index 078a4e982..9b6f4fec4 100644 --- a/firmware/rolo.c +++ b/firmware/rolo.c @@ -99,6 +99,7 @@ void rolo_restart_cop(void) static void rolo_error(const char *text) { + buffer_release_buffer(0); lcd_clear_display(); lcd_puts(0, 0, "ROLO error:"); lcd_puts_scroll(0, 1, text); @@ -213,6 +214,8 @@ int rolo_load(const char* filename) unsigned short checksum,file_checksum; #endif unsigned char* ramstart = (void*)&loadaddress; + unsigned char* filebuf; + size_t filebuf_size; lcd_clear_display(); lcd_puts(0, 0, "ROLO..."); @@ -235,6 +238,10 @@ int rolo_load(const char* filename) length = filesize(fd) - FIRMWARE_OFFSET_FILE_DATA; + /* get the system buffer. release only in case of error, otherwise + * we don't return anyway */ + filebuf = buffer_get_buffer(&filebuf_size); + #if CONFIG_CPU != SH7034 /* Read and save checksum */ lseek(fd, FIRMWARE_OFFSET_FILE_CRC, SEEK_SET); @@ -260,7 +267,14 @@ int rolo_load(const char* filename) lseek(fd, FIRMWARE_OFFSET_FILE_DATA, SEEK_SET); - if (read(fd, audiobuf, length) != length) { + /* this shouldn't happen, but well */ + if ((long)filebuf_size < length) + { + rolo_error("File too big"); + return -1; + } + + if (read(fd, filebuf, length) != length) { rolo_error("Error Reading File"); return -1; } @@ -268,12 +282,12 @@ int rolo_load(const char* filename) #ifdef MI4_FORMAT /* Check CRC32 to see if we have a valid file */ chksum_crc32gentab(); - checksum = chksum_crc32 (audiobuf, length); + checksum = chksum_crc32 (filebuf, length); #else checksum = MODEL_NUMBER; for(i = 0;i < length;i++) { - checksum += audiobuf[i]; + checksum += filebuf[i]; } #endif @@ -329,12 +343,12 @@ int rolo_load(const char* filename) lseek(fd, FIRMWARE_OFFSET_FILE_DATA, SEEK_SET); /* verify that file can be read and descrambled */ - if ((audiobuf + (2*length)+4) >= audiobufend) { + if ((size_t)((2*length)+4) >= filebuf_size) { rolo_error("Not enough room to load file"); return -1; } - if (read(fd, &audiobuf[length], length) != (int)length) { + if (read(fd, &filebuf[length], length) != (int)length) { rolo_error("Error Reading File"); return -1; } @@ -342,7 +356,7 @@ int rolo_load(const char* filename) lcd_puts(0, 1, "Descramble"); lcd_update(); - checksum = descramble(audiobuf + length, audiobuf, length); + checksum = descramble(filebuf + length, filebuf, length); /* Verify checksum against file header */ if (checksum != file_checksum) { @@ -374,7 +388,7 @@ int rolo_load(const char* filename) PAIOR = 0x0FA0; #endif #endif - rolo_restart(audiobuf, ramstart, length); + rolo_restart(filebuf, ramstart, length); return 0; /* this is never reached */ (void)checksum; (void)file_checksum; -- 2.11.4.GIT