From d1322b71595336740eb5e18e5deed056ddb71c7a Mon Sep 17 00:00:00 2001 From: Thomas Martitz Date: Sun, 14 Aug 2011 15:13:00 +0000 Subject: GSoC/Buflib: 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. Buffer init is moved up in the init chain and handles ipodvideo64mb internally. 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 mp3data.c and talk mess with the buffer. mpeg.c now implements some buffer related functions of playback.h, especially audio_get_buffer(), allowing to reduce #ifdef hell a tiny bit. audiobuf and audiobufend are local to buffer.c now. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30308 a1c6a512-1295-4272-9138-f99709370657 --- 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 ++++++++++++----- 6 files changed, 119 insertions(+), 33 deletions(-) (limited to 'firmware') diff --git a/firmware/buffer.c b/firmware/buffer.c index c317cec924..2168087bd9 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 08fe5098f5..d114a6ac62 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 910791c7fd..6757bf143b 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 18f53f0000..bdf91bcb3f 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 0ac937df84..6beeeb6c23 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 078a4e9827..9b6f4fec4a 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; -- cgit v1.2.3