summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/beep.c4
-rw-r--r--apps/pcmbuf.c2
-rw-r--r--apps/plugin.h13
-rw-r--r--apps/plugins/beatbox/beatbox.c8
-rw-r--r--apps/plugins/doom/i_sound.c6
-rw-r--r--apps/plugins/fft/fft.c4
-rw-r--r--apps/plugins/metronome.c2
-rw-r--r--apps/plugins/midi/midiplay.c14
-rw-r--r--apps/plugins/mikmod/mikmod.c10
-rw-r--r--apps/plugins/mpegplayer/pcm_output.c2
-rw-r--r--apps/plugins/pacbox/pacbox.c6
-rw-r--r--apps/plugins/pdbox/PDa/src/s_audio_rockbox.c10
-rw-r--r--apps/plugins/pitch_detector.c7
-rw-r--r--apps/plugins/rockboy/rbsound.c6
-rw-r--r--apps/plugins/test_sampr.c6
-rw-r--r--apps/plugins/zxbox/spsound.c9
-rw-r--r--apps/recorder/pcm_record.c36
-rw-r--r--apps/voice_thread.c17
-rw-r--r--firmware/asm/arm/pcm-mixer-armv4.c8
-rw-r--r--firmware/asm/arm/pcm-mixer-armv5.c6
-rw-r--r--firmware/asm/arm/pcm-mixer-armv6.c6
-rw-r--r--firmware/asm/m68k/pcm-mixer.c6
-rw-r--r--firmware/asm/pcm-mixer.c8
-rw-r--r--firmware/export/pcm-internal.h51
-rw-r--r--firmware/export/pcm.h31
-rw-r--r--firmware/export/pcm_mixer.h4
-rw-r--r--firmware/export/pp5002.h2
-rw-r--r--firmware/pcm.c115
-rw-r--r--firmware/pcm_mixer.c35
-rw-r--r--firmware/target/arm/as3525/pcm-as3525.c20
-rw-r--r--firmware/target/arm/imx233/pcm-imx233.c9
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/pcm-gigabeat-s.c119
-rw-r--r--firmware/target/arm/pcm-telechips.c62
-rw-r--r--firmware/target/arm/pnx0101/pcm-pnx0101.c14
-rw-r--r--firmware/target/arm/pp/pcm-pp.c627
-rw-r--r--firmware/target/arm/rk27xx/pcm-rk27xx.c8
-rw-r--r--firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c8
-rw-r--r--firmware/target/arm/s3c2440/mini2440/pcm-mini2440.c8
-rw-r--r--firmware/target/arm/s5l8700/pcm-s5l8700.c9
-rw-r--r--firmware/target/arm/s5l8702/pcm-s5l8702.c4
-rw-r--r--firmware/target/arm/tms320dm320/mrobe-500/pcm-mr500.c8
-rw-r--r--firmware/target/arm/tms320dm320/sansa-connect/pcm-sansaconnect.c8
-rw-r--r--firmware/target/coldfire/pcm-coldfire.c36
-rw-r--r--firmware/target/hosted/android/pcm-android.c16
-rw-r--r--firmware/target/hosted/maemo/pcm-gstreamer.c7
-rw-r--r--firmware/target/hosted/pcm-alsa.c8
-rw-r--r--firmware/target/hosted/sdl/pcm-sdl.c66
-rw-r--r--firmware/target/mips/ingenic_jz47xx/pcm-jz4740.c12
48 files changed, 765 insertions, 718 deletions
diff --git a/apps/beep.c b/apps/beep.c
index d3345afdf9..3b02e5d8a3 100644
--- a/apps/beep.c
+++ b/apps/beep.c
@@ -46,7 +46,7 @@ static int16_t beep_buf[BEEP_BUF_COUNT*2] IBSS_ATTR __attribute__((aligned(4)));
/* Callback to generate the beep frames - also don't want inlining of
call below in beep_play */
static void __attribute__((noinline))
-beep_get_more(unsigned char **start, size_t *size)
+beep_get_more(const void **start, size_t *size)
{
int count = beep_count;
@@ -87,7 +87,7 @@ void beep_play(unsigned int frequency, unsigned int duration,
#endif
/* If it fits - avoid cb overhead */
- unsigned char *start;
+ const void *start;
size_t size;
/* Generate first frame here */
diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c
index e0bfa1f62a..7ba4eeef8e 100644
--- a/apps/pcmbuf.c
+++ b/apps/pcmbuf.c
@@ -694,7 +694,7 @@ void pcmbuf_start_track_change(enum pcm_track_change_type type)
/** Playback */
/* PCM driver callback */
-static void pcmbuf_pcm_callback(unsigned char **start, size_t *size)
+static void pcmbuf_pcm_callback(const void **start, size_t *size)
{
/*- Process the chunk that just finished -*/
size_t index = chunk_ridx;
diff --git a/apps/plugin.h b/apps/plugin.h
index 2fb085de6d..e07ec92c08 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -153,12 +153,12 @@ void* plugin_get_buffer(size_t *buffer_size);
#define PLUGIN_MAGIC 0x526F634B /* RocK */
/* increase this every time the api struct changes */
-#define PLUGIN_API_VERSION 216
+#define PLUGIN_API_VERSION 217
/* update this to latest version if a change to the api struct breaks
backwards compatibility (and please take the opportunity to sort in any
new function which are "waiting" at the end of the function table) */
-#define PLUGIN_MIN_API_VERSION 216
+#define PLUGIN_MIN_API_VERSION 217
/* plugin return codes */
/* internal returns start at 0x100 to make exit(1..255) work */
@@ -651,7 +651,8 @@ struct plugin_api {
const unsigned long *hw_freq_sampr;
void (*pcm_apply_settings)(void);
void (*pcm_play_data)(pcm_play_callback_type get_more,
- unsigned char* start, size_t size);
+ pcm_status_callback_type status_cb,
+ const void *start, size_t size);
void (*pcm_play_stop)(void);
void (*pcm_set_frequency)(unsigned int frequency);
bool (*pcm_is_playing)(void);
@@ -669,6 +670,7 @@ struct plugin_api {
void (*pcm_init_recording)(void);
void (*pcm_close_recording)(void);
void (*pcm_record_data)(pcm_rec_callback_type more_ready,
+ pcm_status_callback_type status_cb,
void *start, size_t size);
void (*pcm_stop_recording)(void);
void (*pcm_calculate_rec_peaks)(int *left, int *right);
@@ -689,12 +691,13 @@ struct plugin_api {
int (*dsp_output_count)(struct dsp_config *dsp, int count);
enum channel_status (*mixer_channel_status)(enum pcm_mixer_channel channel);
- void * (*mixer_channel_get_buffer)(enum pcm_mixer_channel channel, int *count);
+ const void * (*mixer_channel_get_buffer)(enum pcm_mixer_channel channel,
+ int *count);
void (*mixer_channel_calculate_peaks)(enum pcm_mixer_channel channel,
int *left, int *right);
void (*mixer_channel_play_data)(enum pcm_mixer_channel channel,
pcm_play_callback_type get_more,
- unsigned char *start, size_t size);
+ const void *start, size_t size);
void (*mixer_channel_play_pause)(enum pcm_mixer_channel channel, bool play);
void (*mixer_channel_stop)(enum pcm_mixer_channel channel);
void (*mixer_channel_set_amplitude)(enum pcm_mixer_channel channel,
diff --git a/apps/plugins/beatbox/beatbox.c b/apps/plugins/beatbox/beatbox.c
index 8ecbabd1e5..8c7413cc99 100644
--- a/apps/plugins/beatbox/beatbox.c
+++ b/apps/plugins/beatbox/beatbox.c
@@ -509,7 +509,7 @@ void redrawScreen(unsigned char force)
rb->lcd_update();
}
-void get_more(unsigned char** start, size_t* size)
+void get_more(const void** start, size_t* size)
{
#ifndef SYNC
if(lastswap!=swap)
@@ -523,10 +523,10 @@ void get_more(unsigned char** start, size_t* size)
*size = BUF_SIZE*sizeof(short);
#ifndef SYNC
- *start = (unsigned char*)((swap ? gmbuf : gmbuf + BUF_SIZE));
+ *start = swap ? gmbuf : gmbuf + BUF_SIZE;
swap=!swap;
#else
- *start = (unsigned char*)(gmbuf);
+ *start = gmbuf;
#endif
}
@@ -537,7 +537,7 @@ int beatboxmain()
numberOfSamples=44100/10;
synthbuf();
- rb->pcm_play_data(&get_more, NULL, 0);
+ rb->pcm_play_data(&get_more, NULL, NULL, 0);
rb->lcd_set_background(0x000000);
rb->lcd_clear_display();
diff --git a/apps/plugins/doom/i_sound.c b/apps/plugins/doom/i_sound.c
index 2d7b592818..bdf70c1215 100644
--- a/apps/plugins/doom/i_sound.c
+++ b/apps/plugins/doom/i_sound.c
@@ -457,11 +457,11 @@ void I_UpdateSound( void )
// only output be done asynchronous?
//
-void get_more(unsigned char** start, size_t* size)
+void get_more(const void** start, size_t* size)
{
I_UpdateSound(); // Force sound update
- *start = (unsigned char*)(mixbuffer);
+ *start = mixbuffer;
*size = SAMPLECOUNT*2*sizeof(short);
}
@@ -471,7 +471,7 @@ void I_SubmitSound(void)
if (!enable_sound)
return;
- rb->pcm_play_data(&get_more, NULL, 0);
+ rb->pcm_play_data(&get_more, NULL, NULL, 0);
}
void I_ShutdownSound(void)
diff --git a/apps/plugins/fft/fft.c b/apps/plugins/fft/fft.c
index 1c4e1b4c20..f7d8943576 100644
--- a/apps/plugins/fft/fft.c
+++ b/apps/plugins/fft/fft.c
@@ -1186,8 +1186,8 @@ static inline bool fft_init_fft_lib(void)
static inline bool fft_get_fft(void)
{
int count;
- int16_t *value =
- (int16_t *) rb->mixer_channel_get_buffer(PCM_MIXER_CHAN_PLAYBACK, &count);
+ const int16_t *value =
+ rb->mixer_channel_get_buffer(PCM_MIXER_CHAN_PLAYBACK, &count);
/* This block can introduce discontinuities in our data. Meaning, the
* FFT will not be done a continuous segment of the signal. Which can
* be bad. Or not.
diff --git a/apps/plugins/metronome.c b/apps/plugins/metronome.c
index da035a7688..297405571f 100644
--- a/apps/plugins/metronome.c
+++ b/apps/plugins/metronome.c
@@ -721,7 +721,7 @@ static void prepare_tock(void)
static void play_tock(void)
{
- rb->pcm_play_data(NULL,(unsigned char *)sndbuf,sizeof(sndbuf));
+ rb->pcm_play_data(NULL, NULL, sndbuf, sizeof(sndbuf));
}
#endif /* CONFIG_CODEC != SWCODEC */
diff --git a/apps/plugins/midi/midiplay.c b/apps/plugins/midi/midiplay.c
index 40b4f1c83c..1412d4c742 100644
--- a/apps/plugins/midi/midiplay.c
+++ b/apps/plugins/midi/midiplay.c
@@ -319,7 +319,7 @@ static inline void synthbuf(void)
samples_in_buf = BUF_SIZE-i;
}
-static void get_more(unsigned char** start, size_t* size)
+static void get_more(const void** start, size_t* size)
{
#ifndef SYNC
if(lastswap != swap)
@@ -333,10 +333,10 @@ static void get_more(unsigned char** start, size_t* size)
*size = samples_in_buf*sizeof(int32_t);
#ifndef SYNC
- *start = (unsigned char*)((swap ? gmbuf : gmbuf + BUF_SIZE));
+ *start = swap ? gmbuf : gmbuf + BUF_SIZE;
swap = !swap;
#else
- *start = (unsigned char*)(gmbuf);
+ *start = gmbuf;
#endif
}
@@ -396,7 +396,7 @@ static int midimain(const void * filename)
samples_this_second = 0;
synthbuf();
- rb->pcm_play_data(&get_more, NULL, 0);
+ rb->pcm_play_data(&get_more, NULL, NULL, 0);
while (!quit)
{
@@ -445,7 +445,7 @@ static int midimain(const void * filename)
seekBackward(5);
midi_debug("Rewind to %d:%02d\n", playing_time/60, playing_time%60);
if (is_playing)
- rb->pcm_play_data(&get_more, NULL, 0);
+ rb->pcm_play_data(&get_more, NULL, NULL, 0);
break;
}
@@ -455,7 +455,7 @@ static int midimain(const void * filename)
seekForward(5);
midi_debug("Skip to %d:%02d\n", playing_time/60, playing_time%60);
if (is_playing)
- rb->pcm_play_data(&get_more, NULL, 0);
+ rb->pcm_play_data(&get_more, NULL, NULL, 0);
break;
}
@@ -470,7 +470,7 @@ static int midimain(const void * filename)
{
midi_debug("Playing from %d:%02d\n", playing_time/60, playing_time%60);
is_playing = true;
- rb->pcm_play_data(&get_more, NULL, 0);
+ rb->pcm_play_data(&get_more, NULL, NULL, 0);
}
break;
}
diff --git a/apps/plugins/mikmod/mikmod.c b/apps/plugins/mikmod/mikmod.c
index a7eeb5019f..eb3be13140 100644
--- a/apps/plugins/mikmod/mikmod.c
+++ b/apps/plugins/mikmod/mikmod.c
@@ -268,7 +268,7 @@ static inline void synthbuf(void)
VC_WriteBytes(outptr, BUF_SIZE);
}
-void get_more(unsigned char** start, size_t* size)
+void get_more(const void** start, size_t* size)
{
#ifndef SYNC
if (lastswap != swap)
@@ -282,10 +282,10 @@ void get_more(unsigned char** start, size_t* size)
*size = BUF_SIZE;
#ifndef SYNC
- *start = (unsigned char*)((swap ? gmbuf : gmbuf + BUF_SIZE));
+ *start = swap ? gmbuf : gmbuf + BUF_SIZE;
swap = !swap;
#else
- *start = (unsigned char*)(gmbuf);
+ *start = gmbuf;
#endif
}
@@ -660,7 +660,7 @@ int playfile(char* filename)
{
display = DISPLAY_INFO;
Player_Start(module);
- rb->pcm_play_data(&get_more, NULL, 0);
+ rb->pcm_play_data(&get_more, NULL, NULL, 0);
}
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
@@ -804,7 +804,7 @@ int playfile(char* filename)
}
else
{
- rb->pcm_play_data(&get_more, NULL, 0);
+ rb->pcm_play_data(&get_more, NULL, NULL, 0);
}
Player_TogglePause();
break;
diff --git a/apps/plugins/mpegplayer/pcm_output.c b/apps/plugins/mpegplayer/pcm_output.c
index 8db9531049..8694ae4a69 100644
--- a/apps/plugins/mpegplayer/pcm_output.c
+++ b/apps/plugins/mpegplayer/pcm_output.c
@@ -85,7 +85,7 @@ static inline ssize_t pcm_output_bytes_free(void)
}
/* Audio DMA handler */
-static void get_more(unsigned char **start, size_t *size)
+static void get_more(const void **start, size_t *size)
{
ssize_t sz;
diff --git a/apps/plugins/pacbox/pacbox.c b/apps/plugins/pacbox/pacbox.c
index 5165ff3047..efba47b576 100644
--- a/apps/plugins/pacbox/pacbox.c
+++ b/apps/plugins/pacbox/pacbox.c
@@ -286,7 +286,7 @@ static int16_t raw_buf[NBSAMPLES] IBSS_ATTR;
/*
Audio callback
*/
-static void get_more(unsigned char **start, size_t *size)
+static void get_more(const void **start, size_t *size)
{
int32_t *out, *outend;
int16_t *raw;
@@ -306,7 +306,7 @@ static void get_more(unsigned char **start, size_t *size)
}
while (out < outend);
- *start = (unsigned char *)sound_buf;
+ *start = sound_buf;
*size = NBSAMPLES*sizeof(sound_buf[0]);
}
@@ -339,7 +339,7 @@ static void start_sound(void)
wsg3_set_sampling_rate(rb->hw_freq_sampr[sr_index]);
rb->pcm_set_frequency(rb->hw_freq_sampr[sr_index]);
- rb->pcm_play_data(get_more, NULL, 0);
+ rb->pcm_play_data(get_more, NULL, NULL, 0);
sound_playing = true;
}
diff --git a/apps/plugins/pdbox/PDa/src/s_audio_rockbox.c b/apps/plugins/pdbox/PDa/src/s_audio_rockbox.c
index 76a50fa075..6571f74edf 100644
--- a/apps/plugins/pdbox/PDa/src/s_audio_rockbox.c
+++ b/apps/plugins/pdbox/PDa/src/s_audio_rockbox.c
@@ -26,7 +26,7 @@
#include "s_stuff.h"
/* Declare functions that go to IRAM. */
-void pdbox_get_more(unsigned char** start, size_t* size) ICODE_ATTR;
+void pdbox_get_more(const void** start, size_t* size) ICODE_ATTR;
int rockbox_send_dacs(void) ICODE_ATTR;
/* Extern variables. */
@@ -90,12 +90,12 @@ void rockbox_close_audio(void)
}
/* Rockbox audio callback. */
-void pdbox_get_more(unsigned char** start, size_t* size)
+void pdbox_get_more(const void** start, size_t* size)
{
if(outbuf_fill > 0)
{
/* Store output data address and size. */
- *start = (unsigned char*) outbuf[outbuf_tail].data;
+ *start = outbuf[outbuf_tail].data;
*size = sizeof(outbuf[outbuf_tail].data);
/* Free this part of output buffer. */
@@ -116,8 +116,6 @@ void pdbox_get_more(unsigned char** start, size_t* size)
playing = false;
/* Nothing to play. */
- *start = NULL;
- *size = 0;
}
}
@@ -185,7 +183,7 @@ int rockbox_send_dacs(void)
if(!playing && outbuf_fill > 0)
{
/* Start playing. */
- rb->pcm_play_data(pdbox_get_more, NULL, 0);
+ rb->pcm_play_data(pdbox_get_more, NULL, NULL, 0);
/* Set status flag. */
playing = true;
diff --git a/apps/plugins/pitch_detector.c b/apps/plugins/pitch_detector.c
index c30d48a025..4ae43b3236 100644
--- a/apps/plugins/pitch_detector.c
+++ b/apps/plugins/pitch_detector.c
@@ -952,7 +952,7 @@ static uint32_t ICODE_ATTR buffer_magnitude(int16_t *input)
}
/* Stop the recording when the buffer is full */
-static void recording_callback(int status, void **start, size_t *size)
+static void recording_callback(void **start, size_t *size)
{
int tail = audio_tail ^ 1;
@@ -963,8 +963,6 @@ static void recording_callback(int status, void **start, size_t *size)
/* Always record full buffer, even if not required */
*start = audio_data[tail];
*size = BUFFER_SIZE * sizeof (int16_t);
-
- (void)status;
}
#endif /* SIMULATOR */
@@ -973,7 +971,8 @@ static void record_data(void)
{
#ifndef SIMULATOR
/* Always record full buffer, even if not required */
- rb->pcm_record_data(recording_callback, audio_data[audio_tail],
+ rb->pcm_record_data(recording_callback, NULL,
+ audio_data[audio_tail],
BUFFER_SIZE * sizeof (int16_t));
#endif
}
diff --git a/apps/plugins/rockboy/rbsound.c b/apps/plugins/rockboy/rbsound.c
index c0d0277915..628879b4b7 100644
--- a/apps/plugins/rockboy/rbsound.c
+++ b/apps/plugins/rockboy/rbsound.c
@@ -16,10 +16,10 @@ static unsigned short *buf=0, *hwbuf=0;
static bool newly_started;
-static void get_more(unsigned char** start, size_t* size)
+static void get_more(const void** start, size_t* size)
{
memcpy(hwbuf, &buf[pcm.len*doneplay], BUF_SIZE*sizeof(short));
- *start = (unsigned char*)(hwbuf);
+ *start = hwbuf;
*size = BUF_SIZE*sizeof(short);
doneplay=1;
}
@@ -76,7 +76,7 @@ int rockboy_pcm_submit(void)
if(newly_started)
{
- rb->pcm_play_data(&get_more,NULL,0);
+ rb->pcm_play_data(&get_more, NULL, NULL,0);
newly_started = false;
}
diff --git a/apps/plugins/test_sampr.c b/apps/plugins/test_sampr.c
index db8301bba6..fc2f695c70 100644
--- a/apps/plugins/test_sampr.c
+++ b/apps/plugins/test_sampr.c
@@ -90,13 +90,13 @@ static int16_t ICODE_ATTR fsin(uint32_t phase)
}
/* ISR handler to get next block of data */
-static void get_more(unsigned char **start, size_t *size)
+static void get_more(const void **start, size_t *size)
{
/* Free previous buffer */
output_head += output_step;
output_step = 0;
- *start = (unsigned char *)output_buf[output_head & OUTPUT_CHUNK_MASK];
+ *start = output_buf[output_head & OUTPUT_CHUNK_MASK];
*size = OUTPUT_CHUNK_SIZE;
/* Keep repeating previous if source runs low */
@@ -236,7 +236,7 @@ static void play_tone(bool volume_set)
IF_PRIO(, PRIORITY_PLAYBACK)
IF_COP(, CPU));
- rb->pcm_play_data(get_more, NULL, 0);
+ rb->pcm_play_data(get_more, NULL, NULL, 0);
#ifndef HAVE_VOLUME_IN_LIST
if (volume_set)
diff --git a/apps/plugins/zxbox/spsound.c b/apps/plugins/zxbox/spsound.c
index 8b3aa3d84f..9d3eefa87f 100644
--- a/apps/plugins/zxbox/spsound.c
+++ b/apps/plugins/zxbox/spsound.c
@@ -189,12 +189,11 @@ void autoclose_sound(void)
}
#endif
}
-static void get_more(unsigned char** start, size_t* size)
+static void get_more(const void** start, size_t* size)
{
doneplay = 1;
- rb->pcm_play_stop();
- (void)*start;
- (void)*size;
+ (void)start;
+ (void)size;
}
/* sp_sound_buf is Unsigned 8 bit, Rate 8000 Hz, Mono */
@@ -219,7 +218,7 @@ static void write_buf(void){
= my_buf[j+10] = my_buf[j+11] \
= (((byte)sp_sound_buf[i])<<8) >> settings.volume;
- rb->pcm_play_data(&get_more,(unsigned char*)(my_buf),TMNUM*4*3*2);
+ rb->pcm_play_data(&get_more,NULL,(unsigned char*)(my_buf),TMNUM*4*3*2);
#if 0
/* can use to save and later analyze what we produce */
diff --git a/apps/recorder/pcm_record.c b/apps/recorder/pcm_record.c
index 90a6163b8f..d904be9a4e 100644
--- a/apps/recorder/pcm_record.c
+++ b/apps/recorder/pcm_record.c
@@ -257,20 +257,9 @@ enum
/*******************************************************************/
/* Callback for when more data is ready - called in interrupt context */
-static void pcm_rec_have_more(int status, void **start, size_t *size)
+static void pcm_rec_have_more(void **start, size_t *size)
{
- if (status < 0)
- {
- /* some error condition */
- if (status == DMA_REC_ERROR_DMA)
- {
- /* Flush recorded data to disk and stop recording */
- queue_post(&pcmrec_queue, PCMREC_STOP, 0);
- return;
- }
- /* else try again next transmission - frame is invalid */
- }
- else if (!dma_lock)
+ if (!dma_lock)
{
/* advance write position */
int next_pos = (dma_wr_pos + PCM_CHUNK_SIZE) & PCM_CHUNK_MASK;
@@ -287,6 +276,23 @@ static void pcm_rec_have_more(int status, void **start, size_t *size)
*size = PCM_CHUNK_SIZE;
} /* pcm_rec_have_more */
+static enum pcm_dma_status pcm_rec_status_callback(enum pcm_dma_status status)
+{
+ if (status < PCM_DMAST_OK)
+ {
+ /* some error condition */
+ if (status == PCM_DMAST_ERR_DMA)
+ {
+ /* Flush recorded data to disk and stop recording */
+ queue_post(&pcmrec_queue, PCMREC_STOP, 0);
+ return status;
+ }
+ /* else try again next transmission - frame is invalid */
+ }
+
+ return PCM_DMAST_OK;
+} /* pcm_rec_status_callback */
+
static void reset_hardware(void)
{
/* reset pcm to defaults */
@@ -1239,8 +1245,8 @@ static void pcmrec_set_recording_options(
{
/* start DMA transfer */
dma_lock = pre_record_ticks == 0;
- pcm_record_data(pcm_rec_have_more, GET_PCM_CHUNK(dma_wr_pos),
- PCM_CHUNK_SIZE);
+ pcm_record_data(pcm_rec_have_more, pcm_rec_status_callback,
+ GET_PCM_CHUNK(dma_wr_pos), PCM_CHUNK_SIZE);
}
else
{
diff --git a/apps/voice_thread.c b/apps/voice_thread.c
index 2f216cde9d..5d23a74cbc 100644
--- a/apps/voice_thread.c
+++ b/apps/voice_thread.c
@@ -116,9 +116,12 @@ enum voice_thread_messages
/* Structure to store clip data callback info */
struct voice_info
{
- pcm_play_callback_type get_more; /* Callback to get more clips */
- unsigned char *start; /* Start of clip */
- size_t size; /* Size of clip */
+ /* Callback to get more clips */
+ void (*get_more)(unsigned char** start, size_t* size);
+ /* Start of clip */
+ unsigned char *start;
+ /* Size of clip */
+ size_t size;
};
/* Private thread data for its current state that must be passed to its
@@ -148,14 +151,14 @@ static inline int voice_unplayed_frames(void)
}
/* Mixer channel callback */
-static void voice_pcm_callback(unsigned char **start, size_t *size)
+static void voice_pcm_callback(const void **start, size_t *size)
{
if (voice_unplayed_frames() == 0)
return; /* Done! */
unsigned int i = ++cur_buf_out % VOICE_FRAMES;
- *start = (unsigned char *)voicebuf[i];
+ *start = voicebuf[i];
*size = voicebuf_sizes[i];
}
@@ -167,7 +170,7 @@ static void voice_start_playback(void)
unsigned int i = cur_buf_out % VOICE_FRAMES;
mixer_channel_play_data(PCM_MIXER_CHAN_VOICE, voice_pcm_callback,
- (unsigned char *)voicebuf[i], voicebuf_sizes[i]);
+ voicebuf[i], voicebuf_sizes[i]);
}
/* Stop the voice channel */
@@ -198,7 +201,7 @@ static void voice_buf_commit(size_t size)
/* Stop any current clip and start playing a new one */
void mp3_play_data(const unsigned char* start, int size,
- pcm_play_callback_type get_more)
+ void (*get_more)(unsigned char** start, size_t* size))
{
if (get_more != NULL && start != NULL && (ssize_t)size > 0)
{
diff --git a/firmware/asm/arm/pcm-mixer-armv4.c b/firmware/asm/arm/pcm-mixer-armv4.c
index 4818544d7b..dc2edb781c 100644
--- a/firmware/asm/arm/pcm-mixer-armv4.c
+++ b/firmware/asm/arm/pcm-mixer-armv4.c
@@ -24,9 +24,9 @@
/* Mix channels' samples and apply gain factors */
static FORCE_INLINE void mix_samples(void *out,
- void *src0,
+ const void *src0,
int32_t src0_amp,
- void *src1,
+ const void *src1,
int32_t src1_amp,
size_t size)
{
@@ -96,7 +96,7 @@ static FORCE_INLINE void mix_samples(void *out,
if (src0_amp != MIX_AMP_UNITY)
{
/* Keep unity in src0, amp0 */
- int16_t *src_tmp = src0;
+ const void *src_tmp = src0;
src0 = src1;
src1 = src_tmp;
src1_amp = src0_amp;
@@ -133,7 +133,7 @@ static FORCE_INLINE void mix_samples(void *out,
/* Write channel's samples and apply gain factor */
static FORCE_INLINE void write_samples(void *out,
- void *src,
+ const void *src,
int32_t amp,
size_t size)
{
diff --git a/firmware/asm/arm/pcm-mixer-armv5.c b/firmware/asm/arm/pcm-mixer-armv5.c
index 64f2c86f52..add1522fd9 100644
--- a/firmware/asm/arm/pcm-mixer-armv5.c
+++ b/firmware/asm/arm/pcm-mixer-armv5.c
@@ -24,9 +24,9 @@
/* Mix channels' samples and apply gain factors */
static FORCE_INLINE void mix_samples(void *out,
- void *src0,
+ const void *src0,
int32_t src0_amp,
- void *src1,
+ const void *src1,
int32_t src1_amp,
size_t size)
{
@@ -57,7 +57,7 @@ static FORCE_INLINE void mix_samples(void *out,
/* Write channel's samples and apply gain factor */
static FORCE_INLINE void write_samples(void *out,
- void *src,
+ const void *src,
int32_t amp,
size_t size)
{
diff --git a/firmware/asm/arm/pcm-mixer-armv6.c b/firmware/asm/arm/pcm-mixer-armv6.c
index 94eecd0f90..9da5b40ef1 100644
--- a/firmware/asm/arm/pcm-mixer-armv6.c
+++ b/firmware/asm/arm/pcm-mixer-armv6.c
@@ -23,9 +23,9 @@
/* Mix channels' samples and apply gain factors */
static FORCE_INLINE void mix_samples(void *out,
- void *src0,
+ const void *src0,
int32_t src0_amp,
- void *src1,
+ const void *src1,
int32_t src1_amp,
size_t size)
{
@@ -71,7 +71,7 @@ static FORCE_INLINE void mix_samples(void *out,
/* Write channel's samples and apply gain factor */
static FORCE_INLINE void write_samples(void *out,
- void *src,
+ const void *src,
int32_t amp,
size_t size)
{
diff --git a/firmware/asm/m68k/pcm-mixer.c b/firmware/asm/m68k/pcm-mixer.c
index d8318fffaf..730ae4ace7 100644
--- a/firmware/asm/m68k/pcm-mixer.c
+++ b/firmware/asm/m68k/pcm-mixer.c
@@ -56,9 +56,9 @@ static FORCE_INLINE void restore_emac_context(void)
/* Mix channels' samples and apply gain factors */
static FORCE_INLINE void mix_samples(void *out,
- void *src0,
+ const void *src0,
int32_t src0_amp,
- void *src1,
+ const void *src1,
int32_t src1_amp,
size_t size)
{
@@ -94,7 +94,7 @@ static FORCE_INLINE void mix_samples(void *out,
/* Write channel's samples and apply gain factor */
static FORCE_INLINE void write_samples(void *out,
- void *src,
+ const void *src,
int32_t amp,
size_t size)
{
diff --git a/firmware/asm/pcm-mixer.c b/firmware/asm/pcm-mixer.c
index 62dfa3e9db..3e6e2fff78 100644
--- a/firmware/asm/pcm-mixer.c
+++ b/firmware/asm/pcm-mixer.c
@@ -28,9 +28,9 @@
#include "dsp-util.h" /* for clip_sample_16 */
/* Mix channels' samples and apply gain factors */
static FORCE_INLINE void mix_samples(int16_t *out,
- int16_t *src0,
+ const int16_t *src0,
int32_t src0_amp,
- int16_t *src1,
+ const int16_t *src1,
int32_t src1_amp,
size_t size)
{
@@ -64,7 +64,7 @@ static FORCE_INLINE void mix_samples(int16_t *out,
if (src0_amp != MIX_AMP_UNITY)
{
/* Keep unity in src0, amp0 */
- int16_t *src_tmp = src0;
+ const int16_t *src_tmp = src0;
src0 = src1;
src1 = src_tmp;
src1_amp = src0_amp;
@@ -84,7 +84,7 @@ static FORCE_INLINE void mix_samples(int16_t *out,
/* Write channel's samples and apply gain factor */
static FORCE_INLINE void write_samples(int16_t *out,
- int16_t *src,
+ const int16_t *src,
int32_t amp,
size_t size)
{
diff --git a/firmware/export/pcm-internal.h b/firmware/export/pcm-internal.h
index 89d895fe4b..abe3fe08dc 100644
--- a/firmware/export/pcm-internal.h
+++ b/firmware/export/pcm-internal.h
@@ -41,24 +41,28 @@ void pcm_do_peak_calculation(struct pcm_peaks *peaks, bool active,
/** The following are for internal use between pcm.c and target-
specific portion **/
+static FORCE_INLINE enum pcm_dma_status pcm_call_status_cb(
+ pcm_status_callback_type callback, enum pcm_dma_status status)
+{
+ if (!callback)
+ return status;
-/* Called by the bottom layer ISR when more data is needed. Returns non-
- * zero size if more data is to be played. Setting start to NULL
- * forces stop. */
-void pcm_play_get_more_callback(void **start, size_t *size);
+ return callback(status);
+}
-/* Called by the bottom layer ISR after next transfer has begun in order
- to fill more data for next "get more" callback to implement double-buffered
- callbacks - except for a couple ASM handlers, help drivers to implement
- this functionality with minimal overhead */
-static FORCE_INLINE void pcm_play_dma_started_callback(void)
+static FORCE_INLINE enum pcm_dma_status
+pcm_play_dma_status_callback(enum pcm_dma_status status)
{
- extern void (* pcm_play_dma_started)(void);
- void (* callback)(void) = pcm_play_dma_started;
- if (callback)
- callback();
+ extern enum pcm_dma_status
+ (* volatile pcm_play_status_callback)(enum pcm_dma_status);
+ return pcm_call_status_cb(pcm_play_status_callback, status);
}
+/* Called by the bottom layer ISR when more data is needed. Returns true
+ * if a new buffer is available, false otherwise. */
+bool pcm_play_dma_complete_callback(enum pcm_dma_status status,
+ const void **addr, size_t *size);
+
extern unsigned long pcm_curr_sampr;
extern unsigned long pcm_sampr;
extern int pcm_fsel;
@@ -90,10 +94,29 @@ extern volatile bool pcm_recording;
void pcm_rec_dma_init(void);
void pcm_rec_dma_close(void);
void pcm_rec_dma_start(void *addr, size_t size);
-void pcm_rec_dma_record_more(void *start, size_t size);
void pcm_rec_dma_stop(void);
const void * pcm_rec_dma_get_peak_buffer(void);
+static FORCE_INLINE enum pcm_dma_status
+pcm_rec_dma_status_callback(enum pcm_dma_status status)
+{
+ extern enum pcm_dma_status
+ (* volatile pcm_rec_status_callback)(enum pcm_dma_status);
+ return pcm_call_status_cb(pcm_rec_status_callback, status);
+}
+
+
+/* Called by the bottom layer ISR when more data is needed. Returns true
+ * if a new buffer is available, false otherwise. */
+bool pcm_rec_dma_complete_callback(enum pcm_dma_status status,
+ void **addr, size_t *size);
+
+#ifdef HAVE_PCM_REC_DMA_ADDRESS
+#define pcm_rec_dma_addr(addr) pcm_dma_addr(addr)
+#else
+#define pcm_rec_dma_addr(addr) addr
+#endif
+
#endif /* HAVE_RECORDING */
#endif /* PCM_INTERNAL_H */
diff --git a/firmware/export/pcm.h b/firmware/export/pcm.h
index 4a7a5b3193..df82c6092d 100644
--- a/firmware/export/pcm.h
+++ b/firmware/export/pcm.h
@@ -24,17 +24,23 @@
#include <string.h> /* size_t */
#include "config.h"
-#define DMA_REC_ERROR_DMA (-1)
+enum pcm_dma_status
+{
#ifdef HAVE_SPDIF_REC
-#define DMA_REC_ERROR_SPDIF (-2)
+ PCM_DMAST_ERR_SPDIF = -2,
#endif
+ PCM_DMAST_ERR_DMA = -1,
+ PCM_DMAST_OK = 0,
+ PCM_DMAST_STARTED = 1,
+};
/** RAW PCM routines used with playback and recording **/
-/* Typedef for registered callbacks */
-typedef void (*pcm_play_callback_type)(unsigned char **start,
- size_t *size);
-typedef void (*pcm_rec_callback_type)(int status, void **start, size_t *size);
+/* Typedef for registered data callback */
+typedef void (*pcm_play_callback_type)(const void **start, size_t *size);
+
+/* Typedef for registered status callback */
+typedef enum pcm_dma_status (*pcm_status_callback_type)(enum pcm_dma_status status);
/* set the pcm frequency - use values in hw_sampr_list
* when CONFIG_SAMPR_TYPES is #defined, or-in SAMPR_TYPE_* fields with
@@ -62,7 +68,8 @@ bool pcm_is_initialized(void);
/* This is for playing "raw" PCM data */
void pcm_play_data(pcm_play_callback_type get_more,
- unsigned char* start, size_t size);
+ pcm_status_callback_type status_cb,
+ const void *start, size_t size);
void pcm_calculate_peaks(int *left, int *right);
const void* pcm_get_peak_buffer(int* count);
@@ -73,12 +80,13 @@ void pcm_play_pause(bool play);
bool pcm_is_paused(void);
bool pcm_is_playing(void);
-void pcm_play_set_dma_started_callback(void (* callback)(void));
-
#ifdef HAVE_RECORDING
/** RAW PCM recording routines **/
+/* Typedef for registered data callback */
+typedef void (*pcm_rec_callback_type)(void **start, size_t *size);
+
/* Reenterable locks for locking and unlocking the recording interrupt */
void pcm_rec_lock(void);
void pcm_rec_unlock(void);
@@ -90,6 +98,7 @@ void pcm_close_recording(void);
/* Start recording "raw" PCM data */
void pcm_record_data(pcm_rec_callback_type more_ready,
+ pcm_status_callback_type status_cb,
void *start, size_t size);
/* Stop tranferring data into supplied buffer */
@@ -98,10 +107,6 @@ void pcm_stop_recording(void);
/* Is pcm currently recording? */
bool pcm_is_recording(void);
-/* Called by bottom layer ISR when transfer is complete. Returns non-zero
- * size if successful. Setting start to NULL forces stop. */
-void pcm_rec_more_ready_callback(int status, void **start, size_t *size);
-
void pcm_calculate_rec_peaks(int *left, int *right);
#endif /* HAVE_RECORDING */
diff --git a/firmware/export/pcm_mixer.h b/firmware/export/pcm_mixer.h
index ea26060452..6e1632d5ae 100644
--- a/firmware/export/pcm_mixer.h
+++ b/firmware/export/pcm_mixer.h
@@ -86,7 +86,7 @@ enum channel_status
/* Start playback on a channel */
void mixer_channel_play_data(enum pcm_mixer_channel channel,
pcm_play_callback_type get_more,
- unsigned char *start, size_t size);
+ const void *start, size_t size);
/* Pause or resume a channel (when started) */
void mixer_channel_play_pause(enum pcm_mixer_channel channel, bool play);
@@ -105,7 +105,7 @@ enum channel_status mixer_channel_status(enum pcm_mixer_channel channel);
size_t mixer_channel_get_bytes_waiting(enum pcm_mixer_channel channel);
/* Return pointer to channel's playing audio data and the size remaining */
-void * mixer_channel_get_buffer(enum pcm_mixer_channel channel, int *count);
+const void * mixer_channel_get_buffer(enum pcm_mixer_channel channel, int *count);
/* Calculate peak values for channel */
void mixer_channel_calculate_peaks(enum pcm_mixer_channel channel,
diff --git a/firmware/export/pp5002.h b/firmware/export/pp5002.h
index 95cc8d5058..5966f10d08 100644
--- a/firmware/export/pp5002.h
+++ b/firmware/export/pp5002.h
@@ -43,7 +43,9 @@
#define IISCONFIG (*(volatile unsigned long *)(0xc0002500))
#define IISFIFO_CFG (*(volatile unsigned long *)(0xc000251c))
#define IISFIFO_WR (*(volatile unsigned long *)(0xc0002540))
+#define IISFIFO_WRH (*(volatile unsigned short *)(0xc0002540))
#define IISFIFO_RD (*(volatile unsigned long *)(0xc0002580))
+#define IISFIFO_RDH (*(volatile unsigned short *)(0xc0002540))
/**
* IISCONFIG bits:
diff --git a/firmware/pcm.c b/firmware/pcm.c
index d1a897dcab..621ed56e0d 100644
--- a/firmware/pcm.c
+++ b/firmware/pcm.c
@@ -41,7 +41,8 @@
* pcm_play_lock
* pcm_play_unlock
* Semi-private -
- * pcm_play_get_more_callback
+ * pcm_play_dma_complete_callback
+ * pcm_play_dma_status_callback
* pcm_play_dma_init
* pcm_play_dma_postinit
* pcm_play_dma_start
@@ -66,7 +67,8 @@
* pcm_rec_lock
* pcm_rec_unlock
* Semi-private -
- * pcm_rec_more_ready_callback
+ * pcm_rec_dma_complete_callback
+ * pcm_rec_dma_status_callback
* pcm_rec_dma_init
* pcm_rec_dma_close
* pcm_rec_dma_start
@@ -83,9 +85,12 @@
/* 'true' when all stages of pcm initialization have completed */
static bool pcm_is_ready = false;
-/* the registered callback function to ask for more mp3 data */
-static pcm_play_callback_type pcm_callback_for_more SHAREDBSS_ATTR = NULL;
-void (* pcm_play_dma_started)(void) SHAREDBSS_ATTR = NULL;
+/* The registered callback function to ask for more mp3 data */
+static volatile pcm_play_callback_type
+ pcm_callback_for_more SHAREDBSS_ATTR = NULL;
+/* The registered callback function to inform of DMA status */
+volatile pcm_status_callback_type
+ pcm_play_status_callback SHAREDBSS_ATTR = NULL;
/* PCM playback state */
volatile bool pcm_playing SHAREDBSS_ATTR = false;
/* PCM paused state. paused implies playing */
@@ -104,7 +109,7 @@ static struct pcm_peaks global_peaks;
static void pcm_play_stopped(void)
{
pcm_callback_for_more = NULL;
- pcm_play_dma_started = NULL;
+ pcm_play_status_callback = NULL;
pcm_paused = false;
pcm_playing = false;
}
@@ -258,27 +263,29 @@ bool pcm_is_initialized(void)
}
/* Common code to pcm_play_data and pcm_play_pause */
-static void pcm_play_data_start(unsigned char *start, size_t size)
+static void pcm_play_data_start(const void *addr, size_t size)
{
- ALIGN_AUDIOBUF(start, size);
+ ALIGN_AUDIOBUF(addr, size);
- if (!(start && size))
+ if (!(addr && size))
{
pcm_play_callback_type get_more = pcm_callback_for_more;
+ addr = NULL;
size = 0;
+
if (get_more)
{
logf(" get_more");
- get_more(&start, &size);
- ALIGN_AUDIOBUF(start, size);
+ get_more(&addr, &size);
+ ALIGN_AUDIOBUF(addr, size);
}
}
- if (start && size)
+ if (addr && size)
{
logf(" pcm_play_dma_start");
pcm_apply_settings();
- pcm_play_dma_start(start, size);
+ pcm_play_dma_start(addr, size);
pcm_playing = true;
pcm_paused = false;
return;
@@ -291,13 +298,15 @@ static void pcm_play_data_start(unsigned char *start, size_t size)
}
void pcm_play_data(pcm_play_callback_type get_more,
- unsigned char *start, size_t size)
+ pcm_status_callback_type status_cb,
+ const void *start, size_t size)
{
logf("pcm_play_data");
pcm_play_lock();
pcm_callback_for_more = get_more;
+ pcm_play_status_callback = status_cb;
logf(" pcm_play_data_start");
pcm_play_data_start(start, size);
@@ -305,26 +314,33 @@ void pcm_play_data(pcm_play_callback_type get_more,
pcm_play_unlock();
}
-void pcm_play_get_more_callback(void **start, size_t *size)
+bool pcm_play_dma_complete_callback(enum pcm_dma_status status,
+ const void **addr, size_t *size)
{
- pcm_play_callback_type get_more = pcm_callback_for_more;
+ /* Check status callback first if error */
+ if (status < PCM_DMAST_OK)
+ status = pcm_play_dma_status_callback(status);
- *size = 0;
+ pcm_play_callback_type get_more = pcm_callback_for_more;
- if (get_more && start)
+ if (get_more && status >= PCM_DMAST_OK)
{
- /* Call registered callback */
- get_more((unsigned char **)start, size);
+ *addr = NULL;
+ *size = 0;
- ALIGN_AUDIOBUF(*start, *size);
+ /* Call registered callback to obtain next buffer */
+ get_more(addr, size);
+ ALIGN_AUDIOBUF(*addr, *size);
- if (*start && *size)
- return;
+ if (*addr && *size)
+ return true;
}
/* Error, callback missing or no more DMA to do */
pcm_play_dma_stop();
pcm_play_stopped();
+
+ return false;
}
void pcm_play_pause(bool play)
@@ -428,12 +444,6 @@ void pcm_apply_settings(void)
}
}
-/* register callback to buffer more data */
-void pcm_play_set_dma_started_callback(void (* callback)(void))
-{
- pcm_play_dma_started = callback;
-}
-
#ifdef HAVE_RECORDING
/** Low level pcm recording apis **/
@@ -442,6 +452,8 @@ static const void * volatile pcm_rec_peak_addr SHAREDBSS_ATTR = NULL;
/* the registered callback function for when more data is available */
static volatile pcm_rec_callback_type
pcm_callback_more_ready SHAREDBSS_ATTR = NULL;
+volatile pcm_status_callback_type
+ pcm_rec_status_callback SHAREDBSS_ATTR = NULL;
/* DMA transfer in is currently active */
volatile bool pcm_recording SHAREDBSS_ATTR = false;
@@ -450,6 +462,7 @@ static void pcm_recording_stopped(void)
{
pcm_recording = false;
pcm_callback_more_ready = NULL;
+ pcm_rec_status_callback = NULL;
}
/**
@@ -542,13 +555,14 @@ void pcm_close_recording(void)
}
void pcm_record_data(pcm_rec_callback_type more_ready,
- void *start, size_t size)
+ pcm_status_callback_type status_cb,
+ void *addr, size_t size)
{
logf("pcm_record_data");
- ALIGN_AUDIOBUF(start, size);
+ ALIGN_AUDIOBUF(addr, size);
- if (!(start && size))
+ if (!(addr && size))
{
logf(" no buffer");
return;
@@ -557,17 +571,14 @@ void pcm_record_data(pcm_rec_callback_type more_ready,
pcm_rec_lock();
pcm_callback_more_ready = more_ready;
+ pcm_rec_status_callback = status_cb;
-#ifdef HAVE_PCM_REC_DMA_ADDRESS
/* Need a physical DMA address translation, if not already physical. */
- pcm_rec_peak_addr = pcm_dma_addr(start);
-#else
- pcm_rec_peak_addr = start;
-#endif
+ pcm_rec_peak_addr = pcm_rec_dma_addr(addr);
logf(" pcm_rec_dma_start");
pcm_apply_settings();
- pcm_rec_dma_start(start, size);
+ pcm_rec_dma_start(addr, size);
pcm_recording = true;
pcm_rec_unlock();
@@ -589,33 +600,35 @@ void pcm_stop_recording(void)
pcm_rec_unlock();
} /* pcm_stop_recording */
-void pcm_rec_more_ready_callback(int status, void **start, size_t *size)
+bool pcm_rec_dma_complete_callback(enum pcm_dma_status status,
+ void **addr, size_t *size)
{
- pcm_rec_callback_type have_more = pcm_callback_more_ready;
+ /* Check status callback first if error */
+ if (status < PCM_DMAST_OK)
+ status = pcm_rec_dma_status_callback(status);
- *size = 0;
+ pcm_rec_callback_type have_more = pcm_callback_more_ready;
- if (have_more && start)
+ if (have_more && status >= PCM_DMAST_OK)
{
- have_more(status, start, size);
- ALIGN_AUDIOBUF(*start, *size);
+ /* Call registered callback to obtain next buffer */
+ have_more(addr, size);
+ ALIGN_AUDIOBUF(*addr, *size);
- if (*start && *size)
+ if (*addr && *size)
{
- #ifdef HAVE_PCM_REC_DMA_ADDRESS
/* Need a physical DMA address translation, if not already
* physical. */
- pcm_rec_peak_addr = pcm_dma_addr(*start);
- #else
- pcm_rec_peak_addr = *start;
- #endif
- return;
+ pcm_rec_peak_addr = pcm_rec_dma_addr(*addr);
+ return true;
}
}
/* Error, callback missing or no more DMA to do */
pcm_rec_dma_stop();
pcm_recording_stopped();
+
+ return false;
}
#endif /* HAVE_RECORDING */
diff --git a/firmware/pcm_mixer.c b/firmware/pcm_mixer.c
index 4fd96bc97c..9077c6f271 100644
--- a/firmware/pcm_mixer.c
+++ b/firmware/pcm_mixer.c
@@ -39,7 +39,7 @@
/* Descriptor for each channel */
struct mixer_channel
{
- unsigned char *start; /* Buffer pointer */
+ const void *start; /* Buffer pointer */
size_t size; /* Bytes remaining */
size_t last_size; /* Size of consumed data in prev. cycle */
pcm_play_callback_type get_more; /* Registered callback */
@@ -103,16 +103,20 @@ static void channel_stopped(struct mixer_channel *chan)
}
/* Main PCM callback - sends the current prepared frame to play */
-static void mixer_pcm_callback(unsigned char **start, size_t *size)
+static void mixer_pcm_callback(const void **addr, size_t *size)
{
- *start = (unsigned char *)downmix_buf[downmix_index];
+ *addr = downmix_buf[downmix_index];
*size = next_size;
}
/* Buffering callback - calls sub-callbacks and mixes the data for next
buffer to be sent from mixer_pcm_callback() */
-static void MIXER_CALLBACK_ICODE mixer_buffer_callback(void)
+static enum pcm_dma_status MIXER_CALLBACK_ICODE
+mixer_buffer_callback(enum pcm_dma_status status)
{
+ if (status != PCM_DMAST_STARTED)
+ return status;
+
downmix_index ^= 1; /* Next buffer */
void *mixptr = downmix_buf[downmix_index];
@@ -169,12 +173,11 @@ fill_frame:
if (LIKELY(!*chan_p))
{
- write_samples(mixptr, (void *)chan->start,
- chan->amplitude, mixsize);
+ write_samples(mixptr, chan->start, chan->amplitude, mixsize);
}
else
{
- void *src0, *src1;
+ const void *src0, *src1;
unsigned int amp0, amp1;
/* Mix first two channels with each other as the downmix */
@@ -228,6 +231,8 @@ fill_frame:
if (next_size)
*downmix_buf[downmix_index] = downmix_index ? 0x7fff7fff : 0x80008000;
#endif
+
+ return PCM_DMAST_OK;
}
/* Start PCM driver if it's not currently playing */
@@ -245,15 +250,15 @@ static void mixer_start_pcm(void)
pcm_set_frequency(NATIVE_FREQUENCY);
/* Prepare initial frames and set up the double buffer */
- mixer_buffer_callback();
+ mixer_buffer_callback(PCM_DMAST_STARTED);
/* Save the previous call's output */
void *start = downmix_buf[downmix_index];
- mixer_buffer_callback();
+ mixer_buffer_callback(PCM_DMAST_STARTED);
- pcm_play_set_dma_started_callback(mixer_buffer_callback);
- pcm_play_data(mixer_pcm_callback, start, MIX_FRAME_SIZE);
+ pcm_play_data(mixer_pcm_callback, mixer_buffer_callback,
+ start, MIX_FRAME_SIZE);
}
/** Public interfaces **/
@@ -261,7 +266,7 @@ static void mixer_start_pcm(void)
/* Start playback on a channel */
void mixer_channel_play_data(enum pcm_mixer_channel channel,
pcm_play_callback_type get_more,
- unsigned char *start, size_t size)
+ const void *start, size_t size)
{
struct mixer_channel *chan = &channels[channel];
@@ -360,12 +365,12 @@ size_t mixer_channel_get_bytes_waiting(enum pcm_mixer_channel channel)
}
/* Return pointer to channel's playing audio data and the size remaining */
-void * mixer_channel_get_buffer(enum pcm_mixer_channel channel, int *count)
+const void * mixer_channel_get_buffer(enum pcm_mixer_channel channel, int *count)
{
struct mixer_channel *chan = &channels[channel];
- void * buf = *(unsigned char * volatile *)&chan->start;
+ const void * buf = *(const void * volatile *)&chan->start;
size_t size = *(size_t volatile *)&chan->size;
- void * buf2 = *(unsigned char * volatile *)&chan->start;
+ const void * buf2 = *(const void * volatile *)&chan->start;
/* Still same buffer? */
if (buf == buf2)
diff --git a/firmware/target/arm/as3525/pcm-as3525.c b/firmware/target/arm/as3525/pcm-as3525.c
index 0ecc63d018..eb22fc2016 100644
--- a/firmware/target/arm/as3525/pcm-as3525.c
+++ b/firmware/target/arm/as3525/pcm-as3525.c
@@ -36,9 +36,9 @@
* and the number of 32bits words has to
* fit in 11 bits of DMA register */
-static void *dma_start_addr; /* Pointer to callback buffer */
+static const void *dma_start_addr; /* Pointer to callback buffer */
static size_t dma_start_size; /* Size of callback buffer */
-static void *dma_sub_addr; /* Pointer to sub buffer */
+static const void *dma_sub_addr; /* Pointer to sub buffer */
static size_t dma_rem_size; /* Remaining size - in 4*32 bits */
static size_t play_sub_size; /* size of current subtransfer */
static void dma_callback(void);
@@ -100,9 +100,8 @@ static void dma_callback(void)
if(!dma_rem_size)
{
- pcm_play_get_more_callback(&dma_start_addr, &dma_start_size);
-
- if (!dma_start_size)
+ if(!pcm_play_dma_complete_callback(PCM_DMAST_OK, &dma_start_addr,
+ &dma_start_size))
return;
dma_sub_addr = dma_start_addr;
@@ -111,7 +110,7 @@ static void dma_callback(void)
/* force writeback */
commit_dcache_range(dma_start_addr, dma_start_size);
play_start_pcm();
- pcm_play_dma_started_callback();
+ pcm_play_dma_status_callback(PCM_DMAST_STARTED);
}
else
{
@@ -123,7 +122,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
{
is_playing = true;
- dma_start_addr = (void*)addr;
+ dma_start_addr = addr;
dma_start_size = size;
dma_sub_addr = dma_start_addr;
dma_rem_size = size;
@@ -368,7 +367,12 @@ void INT_I2SIN(void)
}
}
- pcm_rec_more_ready_callback(0, (void *)&rec_dma_addr, &rec_dma_size);
+ /* Inform middle layer */
+ if (pcm_rec_dma_complete_callback(PCM_DMAST_OK, (void **)&rec_dma_addr,
+ &rec_dma_size))
+ {
+ pcm_rec_dma_status_callback(PCM_DMAST_STARTED);
+ }
}
diff --git a/firmware/target/arm/imx233/pcm-imx233.c b/firmware/target/arm/imx233/pcm-imx233.c
index c8b79b3875..c4c512eed6 100644
--- a/firmware/target/arm/imx233/pcm-imx233.c
+++ b/firmware/target/arm/imx233/pcm-imx233.c
@@ -49,15 +49,13 @@ static void play(const void *addr, size_t size)
void INT_DAC_DMA(void)
{
- void *start;
+ const void *start;
size_t size;
- pcm_play_get_more_callback(&start, &size);
-
- if(size != 0)
+ if (pcm_play_dma_complete_callback(PCM_DMAST_OK, &start, &size))
{
play(start, size);
- pcm_play_dma_started_callback();
+ pcm_play_dma_status_callback(PCM_DMAST_STARTED);
}
imx233_dma_clear_channel_interrupt(APB_AUDIO_DAC);
@@ -65,6 +63,7 @@ void INT_DAC_DMA(void)
void INT_DAC_ERROR(void)
{
+ /* TODO: Inform of error through pcm_play_dma_complete_callback */
}
void pcm_play_lock(void)
diff --git a/firmware/target/arm/imx31/gigabeat-s/pcm-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/pcm-gigabeat-s.c
index e106cf78e3..c26349b72e 100644
--- a/firmware/target/arm/imx31/gigabeat-s/pcm-gigabeat-s.c
+++ b/firmware/target/arm/imx31/gigabeat-s/pcm-gigabeat-s.c
@@ -78,12 +78,20 @@ static struct dma_data dma_play_data =
.state = 0
};
-static void play_dma_callback(void)
+static void play_start_dma(const void *addr, size_t size)
{
- void *start;
- size_t size;
- bool rror;
+ commit_dcache_range(addr, size);
+
+ dma_play_bd.buf_addr = (void *)addr_virt_to_phys((unsigned long)addr);
+ dma_play_bd.mode.count = size;
+ dma_play_bd.mode.command = TRANSFER_16BIT;
+ dma_play_bd.mode.status = BD_DONE | BD_WRAP | BD_INTR;
+
+ sdma_channel_run(DMA_PLAY_CH_NUM);
+}
+static void play_dma_callback(void)
+{
if (dma_play_data.locked != 0)
{
/* Callback is locked out */
@@ -91,22 +99,17 @@ static void play_dma_callback(void)
return;
}
- rror = dma_play_bd.mode.status & BD_RROR;
-
- pcm_play_get_more_callback(rror ? NULL : &start, &size);
-
- if (size == 0)
- return;
-
- /* Flush any pending cache writes */
- commit_dcache_range(start, size);
- dma_play_bd.buf_addr = (void *)addr_virt_to_phys((unsigned long)start);
- dma_play_bd.mode.count = size;
- dma_play_bd.mode.command = TRANSFER_16BIT;
- dma_play_bd.mode.status = BD_DONE | BD_WRAP | BD_INTR;
- sdma_channel_run(DMA_PLAY_CH_NUM);
-
- pcm_play_dma_started_callback();
+ /* Inform of status and get new buffer */
+ enum pcm_dma_status status = (dma_play_bd.mode.status & BD_RROR) ?
+ PCM_DMAST_ERR_DMA : PCM_DMAST_OK;
+ const void *addr;
+ size_t size;
+
+ if (pcm_play_dma_complete_callback(status, &addr, &size))
+ {
+ play_start_dma(addr, size);
+ pcm_play_dma_status_callback(PCM_DMAST_STARTED);
+ }
}
void pcm_play_lock(void)
@@ -221,15 +224,11 @@ void pcm_play_dma_start(const void *addr, size_t size)
if (!sdma_channel_reset(DMA_PLAY_CH_NUM))
return;
- commit_dcache_range(addr, size);
- dma_play_bd.buf_addr =
- (void *)addr_virt_to_phys((unsigned long)(void *)addr);
- dma_play_bd.mode.count = size;
- dma_play_bd.mode.command = TRANSFER_16BIT;
- dma_play_bd.mode.status = BD_DONE | BD_WRAP | BD_INTR;
-
+ /* Begin I2S transmission */
play_start_pcm();
- sdma_channel_run(DMA_PLAY_CH_NUM);
+
+ /* Begin DMA transfer */
+ play_start_dma(addr, size);
}
void pcm_play_dma_stop(void)
@@ -332,37 +331,39 @@ static struct dma_data dma_rec_data =
.state = 0
};
-static void rec_dma_callback(void)
+static void rec_start_dma(void *addr, size_t size)
{
- int status = 0;
- void *start;
- size_t size;
+ discard_dcache_range(addr, size);
+
+ addr = (void *)addr_virt_to_phys((unsigned long)addr);
+ dma_rec_bd.buf_addr = addr;
+ dma_rec_bd.mode.count = size;
+ dma_rec_bd.mode.command = TRANSFER_16BIT;
+ dma_rec_bd.mode.status = BD_DONE | BD_WRAP | BD_INTR;
+
+ sdma_channel_run(DMA_REC_CH_NUM);
+}
+
+static void rec_dma_callback(void)
+{
if (dma_rec_data.locked != 0)
{
dma_rec_data.callback_pending = dma_rec_data.state;
return; /* Callback is locked out */
}
- if (dma_rec_bd.mode.status & BD_RROR)
- status = DMA_REC_ERROR_DMA;
-
- pcm_rec_more_ready_callback(status, &start, &size);
-
- if (size == 0)
- return;
-
- /* Invalidate - buffer must be coherent */
- discard_dcache_range(start, size);
-
- start = (void *)addr_virt_to_phys((unsigned long)start);
-
- dma_rec_bd.buf_addr = start;
- dma_rec_bd.mode.count = size;
- dma_rec_bd.mode.command = TRANSFER_16BIT;
- dma_rec_bd.mode.status = BD_DONE | BD_WRAP | BD_INTR;
+ /* Inform middle layer */
+ enum pcm_dma_status status = (dma_rec_bd.mode.status & BD_RROR) ?
+ PCM_DMAST_ERR_DMA : PCM_DMAST_OK;
+ void *addr;
+ size_t size;
- sdma_channel_run(DMA_REC_CH_NUM);
+ if (pcm_rec_dma_complete_callback(status, &addr, &size))
+ {
+ rec_start_dma(addr, size);
+ pcm_rec_dma_status_callback(PCM_DMAST_STARTED);
+ }
}
void pcm_rec_lock(void)
@@ -426,29 +427,21 @@ void pcm_rec_dma_start(void *addr, size_t size)
if (!sdma_channel_reset(DMA_REC_CH_NUM))
return;
-
- /* Invalidate - buffer must be coherent */
- discard_dcache_range(addr, size);
- addr = (void *)addr_virt_to_phys((unsigned long)addr);
- dma_rec_bd.buf_addr = addr;
- dma_rec_bd.mode.count = size;
- dma_rec_bd.mode.command = TRANSFER_16BIT;
- dma_rec_bd.mode.status = BD_DONE | BD_WRAP | BD_INTR;
+ /* Ensure clear FIFO */
+ while (SSI_SFCSR1 & SSI_SFCSR_RFCNT0)
+ SSI_SRX0_1;
dma_rec_data.state = 1; /* Check callback on unlock */
SSI_SRCR1 |= SSI_SRCR_RFEN0; /* Enable RX FIFO */
- /* Ensure clear FIFO */
- while (SSI_SFCSR1 & SSI_SFCSR_RFCNT0)
- SSI_SRX0_1;
-
/* Enable receive */
SSI_SCR1 |= SSI_SCR_RE;
SSI_SIER1 |= SSI_SIER_RDMAE; /* Enable DMA req. */
- sdma_channel_run(DMA_REC_CH_NUM);
+ /* Begin DMA transfer */
+ rec_start_dma(addr, size);
}
void pcm_rec_dma_close(void)
diff --git a/firmware/target/arm/pcm-telechips.c b/firmware/target/arm/pcm-telechips.c
index ae4aa5ef38..3d62fcd1a9 100644
--- a/firmware/target/arm/pcm-telechips.c
+++ b/firmware/target/arm/pcm-telechips.c
@@ -33,7 +33,12 @@ struct dma_data
{
/* NOTE: The order of size and p is important if you use assembler
optimised fiq handler, so don't change it. */
- uint16_t *p;
+ union
+ {
+ uint16_t *p;
+ const void *p_r;
+ void *p_w;
+ };
size_t size;
#if NUM_CORES > 1
unsigned core;
@@ -143,7 +148,7 @@ static void play_stop_pcm(void)
void pcm_play_dma_start(const void *addr, size_t size)
{
- dma_play_data.p = (uint16_t*)addr;
+ dma_play_data.p_r = addr;
dma_play_data.size = size;
#if NUM_CORES > 1
@@ -248,8 +253,9 @@ void fiq_handler(void)
* r0-r3 and r12 is a working register.
*/
asm volatile (
- "stmfd sp!, { r0-r4, lr } \n" /* stack scratch regs and lr */
- "mov r4, #0 \n" /* Was the callback called? */
+ "sub lr, lr, #4 \n"
+ "stmfd sp!, { r0-r3, lr } \n" /* stack scratch regs and lr */
+ "mov r14, #0 \n" /* Was the callback called? */
#if defined(CPU_TCC780X)
"mov r8, #0xc000 \n" /* DAI_TX_IRQ_MASK | DAI_RX_IRQ_MASK */
"ldr r9, =0xf3001004 \n" /* CREQ */
@@ -260,7 +266,7 @@ void fiq_handler(void)
"str r8, [r9] \n" /* clear DAI IRQs */
"ldmia r11, { r8-r9 } \n" /* r8 = p, r9 = size */
"cmp r9, #0x10 \n" /* is size <16? */
- "blt .more_data \n" /* if so, ask pcmbuf for more data */
+ "blo .more_data \n" /* if so, ask pcmbuf for more data */
".fill_fifo: \n"
"ldr r12, [r8], #4 \n" /* load two samples */
@@ -282,29 +288,30 @@ void fiq_handler(void)
"sub r9, r9, #0x10 \n" /* 4 words written */
"stmia r11, { r8-r9 } \n" /* save p and size */
- "cmp r4, #0 \n" /* Callback called? */
- "beq .exit \n"
- /* "mov r4, #0 \n" If get_more could be called multiple times! */
- "ldr r2, =pcm_play_dma_started\n"
- "ldr r2, [r2] \n"
- "cmp r2, #0 \n"
- "blxne r2 \n"
+ "cmp r14, #0 \n" /* Callback called? */
+ "ldmeqfd sp!, { r0-r3, pc }^ \n" /* no? -> exit */
- ".exit: \n"
- "ldmfd sp!, { r0-r4, lr } \n"
- "subs pc, lr, #4 \n" /* FIQ specific return sequence */
+ "ldr r1, =pcm_play_status_callback \n"
+ "ldr r1, [r1] \n"
+ "cmp r1, #0 \n"
+ "movne r0, %1 \n"
+ "blxne r1 \n"
+ "ldmfd sp!, { r0-r3, pc }^ \n" /* exit */
".more_data: \n"
- "mov r4, #1 \n" /* Remember we got more data in this FIQ */
- "ldr r2, =pcm_play_get_more_callback \n"
- "mov r0, r11 \n" /* r0 = &p */
- "add r1, r11, #4 \n" /* r1 = &size */
- "blx r2 \n" /* call pcm_play_get_more_callback */
- "ldmia r11, { r8-r9 } \n" /* load new p and size */
- "cmp r9, #0x10 \n" /* did we actually get enough data? */
- "bpl .fill_fifo \n" /* not stop and enough? refill */
- "b .exit \n"
+ "mov r14, #1 \n" /* Remember we got more data in this FIQ */
+ "mov r0, %0 \n" /* r0 = status */
+ "mov r1, r11 \n" /* r1 = &dma_play_data.p_r */
+ "add r2, r11, #4 \n" /* r2 = &dma_play_data.size */
+ "mov lr, pc \n"
+ "ldr pc, =pcm_play_dma_complete_callback \n"
+ "cmp r0, #0 \n" /* any more to play? */
+ "ldmneia r11, { r8-r9 } \n" /* load new p and size */
+ "cmpne r9, #0x0f \n" /* did we actually get enough data? */
+ "bhi .fill_fifo \n" /* not stop and enough? refill */
+ "ldmfd sp!, { r0-r3, pc }^ \n" /* exit */
".ltorg \n"
+ : : "i"(PCM_DMAST_OK), "i"(PCM_DMAST_STARTED)
);
}
#else /* C version for reference */
@@ -316,9 +323,8 @@ void fiq_handler(void)
if (dma_play_data.size < 16)
{
/* p is empty, get some more data */
- new_buffer = true;
- pcm_play_get_more_callback((void**)&dma_play_data.p,
- &dma_play_data.size);
+ new_buffer = pcm_play_dma_complete_callback(&dma_play_data.p_r,
+ &dma_play_data.size);
}
if (dma_play_data.size >= 16)
@@ -339,7 +345,7 @@ void fiq_handler(void)
CREQ = DAI_TX_IRQ_MASK | DAI_RX_IRQ_MASK;
if (new_buffer)
- pcm_play_dma_started_callback();
+ pcm_play_dma_status_callback(PCM_DMAST_STARTED);
}
#endif
diff --git a/firmware/target/arm/pnx0101/pcm-pnx0101.c b/firmware/target/arm/pnx0101/pcm-pnx0101.c
index 89d56af374..bb11ad32fe 100644
--- a/firmware/target/arm/pnx0101/pcm-pnx0101.c
+++ b/firmware/target/arm/pnx0101/pcm-pnx0101.c
@@ -28,7 +28,7 @@
short __attribute__((section(".dmabuf"))) dma_buf_left[DMA_BUF_SAMPLES];
short __attribute__((section(".dmabuf"))) dma_buf_right[DMA_BUF_SAMPLES];
-unsigned short* p IBSS_ATTR;
+const int16_t* p IBSS_ATTR;
size_t p_size IBSS_ATTR;
void pcm_play_lock(void)
@@ -41,7 +41,7 @@ void pcm_play_unlock(void)
void pcm_play_dma_start(const void *addr, size_t size)
{
- p = (unsigned short*)addr;
+ p = addr;
p_size = size;
}
@@ -69,7 +69,7 @@ static inline void fill_dma_buf(int offset)
do
{
int count;
- unsigned short *tmp_p;
+ const int16_t *tmp_p;
count = MIN(p_size / 4, (size_t)(lend - l));
tmp_p = p;
p_size -= count * 4;
@@ -109,16 +109,14 @@ static inline void fill_dma_buf(int offset)
if (new_buffer)
{
new_buffer = false;
- pcm_play_dma_started_callback();
+ pcm_play_dma_status_callback(PCM_DMAST_STARTED);
}
if (l >= lend)
return;
- pcm_play_get_more_callback((void**)&p, &p_size);
-
- if (p_size)
- new_buffer = true;
+ new_buffer = pcm_play_dma_complete_callback(PCM_DMAST_OK,
+ &p, &p_size);
}
while (p_size);
}
diff --git a/firmware/target/arm/pp/pcm-pp.c b/firmware/target/arm/pp/pcm-pp.c
index 1b38994f7b..99d46a6096 100644
--- a/firmware/target/arm/pp/pcm-pp.c
+++ b/firmware/target/arm/pp/pcm-pp.c
@@ -30,26 +30,6 @@
/** DMA **/
-#ifdef CPU_PP502x
-/* 16-bit, L-R packed into 32 bits with left in the least significant halfword */
-#define SAMPLE_SIZE 16
-/* DMA Requests from IIS, Memory to peripheral, single transfer,
- wait for DMA request, interrupt on complete */
-#define DMA_PLAY_CONFIG ((DMA_REQ_IIS << DMA_CMD_REQ_ID_POS) | \
- DMA_CMD_RAM_TO_PER | DMA_CMD_SINGLE | \
- DMA_CMD_WAIT_REQ | DMA_CMD_INTR)
-/* DMA status cannot be viewed from outside code in control because that can
- * clear the interrupt from outside the handler and prevent the handler from
- * from being called. Split up transfers to a reasonable size that is good as
- * a timer, obtaining a keyclick position and peaking yet still keeps the
- * FIQ count low.
- */
-#define MAX_DMA_CHUNK_SIZE (pcm_curr_sampr >> 6) /* ~1/256 seconds */
-#else
-/* 32-bit, one left 32-bit sample followed by one right 32-bit sample */
-#define SAMPLE_SIZE 32
-#endif
-
struct dma_data
{
/* NOTE: The order of size and p is important if you use assembler
@@ -57,6 +37,8 @@ struct dma_data
union
{
unsigned long addr;
+ const void *p_r;
+ void *p_w;
uint32_t *p16; /* For packed 16-16 stereo pairs */
uint16_t *p32; /* For individual samples converted to 32-bit */
};
@@ -113,56 +95,208 @@ void pcm_dma_apply_settings(void)
}
#if defined(CPU_PP502x)
-/* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */
-void ICODE_ATTR __attribute__((interrupt("FIQ"))) fiq_playback(void)
+/* 16-bit, L-R packed into 32 bits with left in the least significant halfword */
+#define SAMPLE_SIZE 16
+/* DMA Requests from IIS, Memory to peripheral, single transfer,
+ wait for DMA request, interrupt on complete */
+#define DMA_PLAY_CONFIG ((DMA_REQ_IIS << DMA_CMD_REQ_ID_POS) | \
+ DMA_CMD_RAM_TO_PER | DMA_CMD_SINGLE | \
+ DMA_CMD_WAIT_REQ | DMA_CMD_INTR)
+/* DMA status cannot be viewed from outside code in control because that can
+ * clear the interrupt from outside the handler and prevent the handler from
+ * from being called. Split up transfers to a reasonable size that is good as
+ * a timer and peaking yet still keeps the FIQ count low.
+ */
+#define MAX_DMA_CHUNK_SIZE (pcm_curr_sampr >> 6) /* ~1/256 seconds */
+
+static inline void dma_tx_init(void)
+{
+ /* Enable DMA controller */
+ DMA_MASTER_CONTROL |= DMA_MASTER_CONTROL_EN;
+ /* FIQ priority for DMA */
+ CPU_INT_PRIORITY |= DMA_MASK;
+ /* Enable request?? Not setting or clearing everything doesn't seem to
+ * prevent it operating. Perhaps important for reliability (how requests
+ * are handled). */
+ DMA_REQ_STATUS |= 1ul << DMA_REQ_IIS;
+ DMA0_STATUS;
+}
+
+static inline void dma_tx_setup(void)
+{
+ /* Setup DMA controller */
+ DMA0_PER_ADDR = (unsigned long)&IISFIFO_WR;
+ DMA0_FLAGS = DMA_FLAGS_UNK26;
+ DMA0_INCR = DMA_INCR_RANGE_FIXED | DMA_INCR_WIDTH_32BIT;
+}
+
+static inline unsigned long dma_tx_buf_prepare(const void *addr)
+{
+ unsigned long a = (unsigned long)addr;
+
+ if (a < UNCACHED_BASE_ADDR) {
+ /* VA in DRAM - writeback all data and get PA */
+ a = UNCACHED_ADDR(a);
+ commit_dcache();
+ }
+
+ return a;
+}
+
+static inline void dma_tx_start(bool begin)
+{
+ size_t size = MAX_DMA_CHUNK_SIZE;
+
+ /* Not at least MAX_DMA_CHUNK_SIZE left or there would be less
+ * than a FIFO's worth of data after this transfer? */
+ if (size + 16*4 > dma_play_data.size)
+ size = dma_play_data.size;
+
+ /* Set the new DMA values and activate channel */
+ DMA0_RAM_ADDR = dma_play_data.addr;
+ DMA0_CMD = DMA_PLAY_CONFIG | (size - 4) | DMA_CMD_START;
+
+ (void)begin;
+}
+
+static void dma_tx_stop(void)
+{
+ unsigned long status = DMA0_STATUS; /* Snapshot- resume from this point */
+ unsigned long cmd = DMA0_CMD;
+ size_t size = 0;
+
+ /* Stop transfer */
+ DMA0_CMD = cmd & ~(DMA_CMD_START | DMA_CMD_INTR);
+
+ /* Wait for not busy + clear int */
+ while (DMA0_STATUS & (DMA_STATUS_BUSY | DMA_STATUS_INTR));
+
+ if (status & DMA_STATUS_BUSY) {
+ /* Transfer was interrupted - leave what's left */
+ size = (cmd & 0xfffc) - (status & 0xfffc);
+ }
+ else if (status & DMA_STATUS_INTR) {
+ /* Transfer was finished - DMA0_STATUS will have been reloaded
+ * automatically with size in DMA0_CMD. Setup to restart on next
+ * segment. */
+ size = (cmd & 0xfffc) + 4;
+ }
+ /* else not an active state - size = 0 */
+
+ dma_play_data.addr += size;
+ dma_play_data.size -= size;
+
+ if (dma_play_data.size == 0)
+ dma_play_data.addr = 0; /* Entire buffer has completed. */
+}
+
+static inline void dma_tx_lock(void)
+{
+ CPU_INT_DIS = DMA_MASK;
+}
+
+static inline void dma_tx_unlock(void)
{
- bool new_buffer = false;
- register size_t size;
+ CPU_INT_EN = DMA_MASK;
+}
+/* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */
+void fiq_playback(void) ICODE_ATTR __attribute__((interrupt("FIQ")));
+void fiq_playback(void)
+{
DMA0_STATUS; /* Clear any pending interrupt */
- size = (DMA0_CMD & 0xffff) + 4; /* Get size of trasfer that caused this
- interrupt */
+ size_t size = (DMA0_CMD & 0xffff) + 4; /* Get size of trasfer that caused
+ this interrupt */
dma_play_data.addr += size;
dma_play_data.size -= size;
- while (1)
- {
- if (dma_play_data.size > 0) {
- size = MAX_DMA_CHUNK_SIZE;
- /* Not at least MAX_DMA_CHUNK_SIZE left or there would be less
- * than a FIFO's worth of data after this transfer? */
- if (size + 16*4 > dma_play_data.size)
- size = dma_play_data.size;
-
- /* Set the new DMA values and activate channel */
- DMA0_RAM_ADDR = dma_play_data.addr;
- DMA0_CMD = DMA_PLAY_CONFIG | (size - 4) | DMA_CMD_START;
-
- if (new_buffer)
- pcm_play_dma_started_callback();
- return;
- }
+ if (LIKELY(dma_play_data.size != 0)) {
+ /* Begin next segment */
+ dma_tx_start(false);
+ }
+ else if (pcm_play_dma_complete_callback(PCM_DMAST_OK, &dma_play_data.p_r,
+ &dma_play_data.size)) {
+ dma_play_data.addr = dma_tx_buf_prepare(dma_play_data.p_r);
+ dma_tx_start(false);
+ pcm_play_dma_status_callback(PCM_DMAST_STARTED);
+ }
+}
- new_buffer = true;
+#else /* !defined (CPU_PP502x) */
- /* Buffer empty. Try to get more. */
- pcm_play_get_more_callback((void **)&dma_play_data.addr,
- &dma_play_data.size);
+/* 32-bit, one left 32-bit sample followed by one right 32-bit sample */
+#define SAMPLE_SIZE 32
- if (dma_play_data.size == 0) {
- /* No more data */
- return;
- }
+static void dma_tx_init(void)
+{
+ /* Set up banked registers for FIQ mode */
- if (dma_play_data.addr < UNCACHED_BASE_ADDR) {
- /* Flush any pending cache writes */
- dma_play_data.addr = UNCACHED_ADDR(dma_play_data.addr);
- commit_dcache();
- }
+ /* Use non-banked registers for scratch. */
+ register volatile void *iiscfg asm("r0") = &IISCONFIG;
+ register volatile void *dmapd asm("r1") = &dma_play_data;
+
+ asm volatile (
+ "mrs r2, cpsr \n" /* Save mode and interrupt status */
+ "msr cpsr_c, #0xd1 \n" /* Switch to FIQ mode */
+ "mov r8, #0 \n"
+ "mov r9, #0 \n"
+ "mov r10, %[iiscfg] \n"
+ "mov r11, %[dmapd] \n"
+ "msr cpsr_c, r2 \n"
+ :
+ : [iiscfg]"r"(iiscfg), [dmapd]"r"(dmapd)
+ : "r2");
+
+ /* FIQ priority for I2S */
+ CPU_INT_PRIORITY |= IIS_MASK;
+ CPU_INT_EN = IIS_MASK;
+}
+
+static inline void dma_tx_setup(void)
+{
+ /* Nothing to do */
+}
+
+static inline unsigned long dma_tx_buf_prepare(const void *addr)
+{
+ return (unsigned long)addr;
+}
+
+static inline void dma_tx_start(bool begin)
+{
+ if (begin) {
+ IISCONFIG &= ~IIS_TXFIFOEN; /* Stop transmitting */
}
+
+ /* Fill the FIFO or start when data is used up */
+ while (IIS_TX_FREE_COUNT >= 2 && dma_play_data.size != 0) {
+ IISFIFO_WRH = *dma_play_data.p32++;
+ IISFIFO_WRH = *dma_play_data.p32++;
+ dma_play_data.size -= 4;
+ }
+
+ if (begin) {
+ IISCONFIG |= IIS_TXFIFOEN; /* Start transmitting */
+ }
+}
+
+static inline void dma_tx_stop(void)
+{
+ /* Disable TX interrupt */
+ IIS_IRQTX_REG &= ~IIS_IRQTX;
+}
+
+static inline void dma_tx_lock(void)
+{
+ IIS_IRQTX_REG &= ~IIS_IRQTX;
+}
+
+static inline void dma_tx_unlock(void)
+{
+ IIS_IRQTX_REG |= IIS_IRQTX;
}
-#else
+
/* ASM optimised FIQ handler. Checks for the minimum allowed loop cycles by
* evalutation of free IISFIFO-slots against available source buffer words.
* Through this it is possible to move the check for IIS_TX_FREE_COUNT outside
@@ -173,150 +307,123 @@ void ICODE_ATTR __attribute__((interrupt("FIQ"))) fiq_playback(void)
* ASM implementation (not used anymore): GCC fails to make use of the fact
* that FIQ mode has registers r8-r14 banked, and so does not need to be saved.
* This routine uses only these registers, and so will never touch the stack
- * unless it actually needs to do so when calling pcm_callback_for_more.
+ * unless it actually needs to do so when calling pcm_play_dma_complete_callback.
* C version is still included below for reference and testing.
*/
#if 1
void fiq_playback(void) ICODE_ATTR __attribute__((naked));
void fiq_playback(void)
{
- /* r10 contains IISCONFIG address (set in crt0.S to minimise code in actual
- * FIQ handler. r11 contains address of p (also set in crt0.S). Most other
- * addresses we need are generated by using offsets with these two.
- * r10 + 0x40 is IISFIFO_WR, and r10 + 0x0c is IISFIFO_CFG.
- * r8 and r9 contains local copies of p and size respectively.
- * r0-r3 and r12 is a working register.
+ /* r8 and r9 contains local copies of p and size respectively.
+ * r10 contains IISCONFIG address (set during PCM init to minimize code in
+ * FIQ handler.Most other addresses we need are generated by using offsets
+ * from this.
+ * r10 + 0x40 is IISFIFO_WR, and r10 + 0x1c is IISFIFO_CFG.
+ * r11 contains address of dma_play_data
+ * r12 and r14 are working registers.
+ *
+ * Divided into two blocks: one where no external calls are needed and
+ * one where external callbacks are made
*/
asm volatile (
- "stmfd sp!, { r0-r4, lr } \n" /* stack scratch regs and lr */
-
- "mov r4, #0 \n" /* Was the callback called? */
-#if CONFIG_CPU == PP5002
- "ldr r12, =0xcf001040 \n" /* Some magic from iPodLinux */
- "ldr r12, [r12] \n"
-#endif
- "ldmia r11, { r8-r9 } \n" /* r8 = p, r9 = size */
- "cmp r9, #0 \n" /* is size 0? */
- "beq .more_data \n" /* if so, ask pcmbuf for more data */
-
-#if SAMPLE_SIZE == 16
- ".check_fifo: \n"
- "ldr r0, [r10, %[cfg]] \n" /* read IISFIFO_CFG to check FIFO status */
- "and r0, r0, %[mask] \n" /* r0 = IIS_TX_FREE_COUNT << 16 (PP502x) */
-
- "mov r1, r0, lsr #16 \n" /* number of free FIFO slots */
- "cmp r1, r9, lsr #2 \n" /* number of words from source */
- "movgt r1, r9, lsr #2 \n" /* r1 = amount of allowed loops */
- "sub r9, r9, r1, lsl #2 \n" /* r1 words will be written in following loop */
-
- "subs r1, r1, #2 \n"
- ".fifo_loop_2: \n"
- "ldmgeia r8!, {r2, r12} \n" /* load four samples */
- "strge r2 , [r10, %[wr]] \n" /* write sample 0-1 to IISFIFO_WR */
- "strge r12, [r10, %[wr]] \n" /* write sample 2-3 to IISFIFO_WR */
- "subges r1, r1, #2 \n" /* one more loop? */
- "bge .fifo_loop_2 \n" /* yes, continue */
-
- "tst r1, #1 \n" /* two samples (one word) left? */
- "ldrne r12, [r8], #4 \n" /* load two samples */
- "strne r12, [r10, %[wr]] \n" /* write sample 0-1 to IISFIFO_WR */
-#elif SAMPLE_SIZE == 32
- ".check_fifo: \n"
- "ldr r0, [r10, %[cfg]] \n" /* read IISFIFO_CFG to check FIFO status */
- "and r0, r0, %[mask] \n" /* r0 = IIS_TX_FREE_COUNT << 23 (PP5002) */
-
- "movs r1, r0, lsr #24 \n" /* number of free pairs of FIFO slots */
- "beq .fifo_fill_complete \n" /* no complete pair? -> exit */
- "cmp r1, r9, lsr #2 \n" /* number of words from source */
- "movgt r1, r9, lsr #2 \n" /* r1 = amount of allowed loops */
- "sub r9, r9, r1, lsl #2 \n" /* r1 words will be written in following loop */
-
- ".fifo_loop: \n"
- "ldr r12, [r8], #4 \n" /* load two samples */
- "mov r2 , r12, lsl #16 \n" /* put left sample at the top bits */
- "str r2 , [r10, %[wr]] \n" /* write top sample to IISFIFO_WR */
- "str r12, [r10, %[wr]] \n" /* write low sample to IISFIFO_WR*/
- "subs r1, r1, #1 \n" /* one more loop? */
- "bgt .fifo_loop \n" /* yes, continue */
-
- ".fifo_fill_complete: \n"
-#endif
- "cmp r4, #0 \n" /* If fill came after get_more... */
- "beq .still_old_buffer \n"
- "mov r4, #0 \n"
- "ldr r2, =pcm_play_dma_started \n"
- "ldrne r2, [r2] \n"
- "cmp r2, #0 \n"
- "movne lr, pc \n"
- "bxne r2 \n"
-
- ".still_old_buffer: \n"
- "cmp r9, #0 \n" /* either FIFO is full or source buffer is empty */
- "bgt .exit \n" /* if source buffer is not empty, FIFO must be full */
-
- ".more_data: \n"
- "mov r4, #1 \n" /* Remember we did this */
- "ldr r2, =pcm_play_get_more_callback \n"
- "mov r0, r11 \n" /* r0 = &p */
- "add r1, r11, #4 \n" /* r1 = &size */
- "mov lr, pc \n" /* call pcm_play_get_more_callback */
- "bx r2 \n"
- "ldmia r11, { r8-r9 } \n" /* load new p and size */
- "cmp r9, #0 \n"
- "bne .check_fifo \n" /* size != 0? refill */
-
- ".exit: \n" /* (r9=0 if stopping, look above) */
- "stmia r11, { r8-r9 } \n" /* save p and size */
- "ldmfd sp!, { r0-r4, lr } \n"
- "subs pc, lr, #4 \n" /* FIQ specific return sequence */
- ".ltorg \n"
+ /* No external calls */
+ "sub lr, lr, #4 \n" /* Prepare return address */
+ "stmfd sp!, { lr } \n" /* stack lr so we can use it */
+ "ldr r12, =0xcf001040 \n" /* Some magic from iPodLinux ... */
+ "ldr r12, [r12] \n" /* ... actually a DMA INT ack? */
+ "ldmia r11, { r8-r9 } \n" /* r8 = p, r9 = size */
+ "cmp r9, #0 \n" /* is size 0? */
+ "beq 1f \n" /* if so, ask PCM for more data */
+
+ "ldr r14, [r10, #0x1c] \n" /* read IISFIFO_CFG to check FIFO status */
+ "and r14, r14, #(0xe<<23) \n" /* r14 = (IIS_TX_FREE_COUNT & ~1) << 23 */
+ "cmp r9, r14, lsr #22 \n" /* number of words from source */
+ "movlo r14, r9, lsl #22 \n" /* r14 = amount of allowed loops */
+ "sub r9, r9, r14, lsr #22 \n" /* r14 words will be written in loop */
+ "0: \n"
+ "ldr r12, [r8], #4 \n" /* load left-right pair */
+ "subs r14, r14, #(0x2<<23) \n" /* one more loop? ... */
+ "strh r12, [r10, #0x40] \n" /* left sample to IISFIFO_WR */
+ "mov r12, r12, lsr #16 \n" /* put right sample in bottom 16 bits */
+ "strh r12, [r10, #0x40] \n" /* right sample to IISFIFO_WR */
+ "bhi 0b \n" /* ... yes, continue */
+
+ "cmp r9, #0 \n" /* either FIFO full or size empty? */
+ "stmneia r11, { r8-r9 } \n" /* save p and size, if not empty */
+ "ldmnefd sp!, { pc }^ \n" /* RFE if not empty */
+
+ /* Making external calls */
+ "1: \n"
+ "stmfd sp!, { r0-r3 } \n" /* Must save volatiles */
+ "2: \n"
+ "mov r0, %0 \n" /* r0 = status */
+ "mov r1, r11 \n" /* r1 = &dma_play_data.p_r */
+ "add r2, r11, #4 \n" /* r2 = &dma_play_data.size */
+ "ldr r3, =pcm_play_dma_complete_callback \n"
+ "mov lr, pc \n" /* long call (not in same section) */
+ "bx r3 \n"
+ "cmp r0, #0 \n" /* more data? */
+ "ldmeqfd sp!, { r0-r3, pc }^ \n" /* no? -> exit */
+
+ "ldr r14, [r10, #0x1c] \n" /* read IISFIFO_CFG to check FIFO status */
+ "ands r14, r14, #(0xe<<23) \n" /* r14 = (IIS_TX_FREE_COUNT & ~1) << 23 */
+ "bne 4f \n"
+ "3: \n" /* inform of started status if registered */
+ "ldr r1, =pcm_play_status_callback \n"
+ "ldr r1, [r1] \n"
+ "cmp r1, #0 \n"
+ "movne r0, %1 \n"
+ "movne lr, pc \n"
+ "bxne r1 \n"
+ "ldmfd sp!, { r0-r3, pc }^ \n" /* exit */
+ "4: \n"
+ "ldmia r11, { r8-r9 } \n" /* load new p and size */
+ "cmp r9, r14, lsr #22 \n" /* number of words from source */
+ "movlo r14, r9, lsl #22 \n" /* r14 = amount of allowed loops */
+ "sub r9, r9, r14, lsr #22 \n" /* r14 words will be written in loop */
+ "0: \n"
+ "ldr r12, [r8], #4 \n" /* load left-right pair */
+ "subs r14, r14, #(0x2<<23) \n" /* one more loop? ... */
+ "strh r12, [r10, #0x40] \n" /* left sample to IISFIFO_WR */
+ "mov r12, r12, lsr #16 \n" /* put right sample in bottom 16 bits */
+ "strh r12, [r10, #0x40] \n" /* right sample to IISFIFO_WR */
+ "bhi 0b \n" /* ... yes, continue */
+ "stmia r11, { r8-r9 } \n" /* save p and size */
+
+ "cmp r9, #0 \n" /* used up data in FIFO fill? */
+ "bne 3b \n" /* no? -> go return */
+ "b 2b \n" /* yes -> get even more */
+ ".ltorg \n"
: /* These must only be integers! No regs */
- : [mask]"i"(IIS_TX_FREE_MASK),
- [cfg]"i"((int)&IISFIFO_CFG - (int)&IISCONFIG),
- [wr]"i"((int)&IISFIFO_WR - (int)&IISCONFIG)
- );
+ : "i"(PCM_DMAST_OK), "i"(PCM_DMAST_STARTED));
}
+
#else /* C version for reference */
-void fiq_playback(void) __attribute__((interrupt ("FIQ"))) ICODE_ATTR;
+
/* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */
+void fiq_playback(void) ICODE_ATTR __attribute__((interrupt ("FIQ")));
void fiq_playback(void)
{
- bool new_buffer = false;
-
-#if CONFIG_CPU == PP5002
inl(0xcf001040);
-#endif
- do {
- while (dma_play_data.size > 0) {
- if (IIS_TX_FREE_COUNT < 2) {
- if (new_buffer) {
- new_buffer = false;
- pcm_play_dma_started_callback();
- }
- return;
- }
-#if SAMPLE_SIZE == 16
- IISFIFO_WR = *dma_play_data.p16++;
-#elif SAMPLE_SIZE == 32
- IISFIFO_WR = *dma_play_data.p32++ << 16;
- IISFIFO_WR = *dma_play_data.p32++ << 16;
-#endif
- dma_play_data.size -= 4;
- }
+ if (LIKELY(dma_play_data.size != 0)) {
+ dma_tx_start(false);
- if (new_buffer) {
- new_buffer = false;
- pcm_play_dma_started_callback();
+ if (dma_play_data.size != 0) {
+ /* Still more data */
+ return;
}
+ }
- /* p is empty, get some more data */
- pcm_play_get_more_callback((void **)&dma_play_data.addr,
- &dma_play_data.size);
- new_buffer = true;
- } while (dma_play_data.size);
+ while (pcm_play_dma_complete_callback(PCM_DMAST_OK, &dma_play_data.p_r,
+ &dma_play_data.size)) {
+ dma_tx_start(false);
+ pcm_play_dma_status_callback(PCM_DMAST_STARTED);
- /* No more data */
+ if (dma_play_data.size != 0) {
+ return;
+ }
+ }
}
#endif /* ASM / C selection */
#endif /* CPU_PP502x */
@@ -329,11 +436,7 @@ void pcm_play_lock(void)
int status = disable_fiq_save();
if (++dma_play_data.locked == 1) {
-#ifdef CPU_PP502x
- CPU_INT_DIS = DMA_MASK;
-#else
- IIS_IRQTX_REG &= ~IIS_IRQTX;
-#endif
+ dma_tx_lock();
}
restore_fiq(status);
@@ -341,89 +444,25 @@ void pcm_play_lock(void)
void pcm_play_unlock(void)
{
- int status = disable_fiq_save();
+ int status = disable_fiq_save();
if (--dma_play_data.locked == 0 && dma_play_data.state != 0) {
-#ifdef CPU_PP502x
- CPU_INT_EN = DMA_MASK;
-#else
- IIS_IRQTX_REG |= IIS_IRQTX;
-#endif
+ dma_tx_unlock();
}
- restore_fiq(status);
+ restore_fiq(status);
}
static void play_start_pcm(void)
{
fiq_function = fiq_playback;
-
-#ifdef CPU_PP502x
- /* Not at least MAX_DMA_CHUNK_SIZE left or there would be less than a
- * FIFO's worth of data after this transfer? */
- size_t size = MAX_DMA_CHUNK_SIZE;
- if (size + 16*4 > dma_play_data.size)
- size = dma_play_data.size;
-
- DMA0_RAM_ADDR = dma_play_data.addr;
- DMA0_CMD = DMA_PLAY_CONFIG | (size - 4) | DMA_CMD_START;
dma_play_data.state = 1;
-#else
- IISCONFIG &= ~IIS_TXFIFOEN; /* Stop transmitting */
-
- /* Fill the FIFO or start when data is used up */
- while (1) {
- if (IIS_TX_FREE_COUNT < 2 || dma_play_data.size == 0) {
- IISCONFIG |= IIS_TXFIFOEN; /* Start transmitting */
- dma_play_data.state = 1;
- return;
- }
-
-#if SAMPLE_SIZE == 16
- IISFIFO_WR = *dma_play_data.p16++;
-#elif SAMPLE_SIZE == 32
- IISFIFO_WR = *dma_play_data.p32++ << 16;
- IISFIFO_WR = *dma_play_data.p32++ << 16;
-#endif
- dma_play_data.size -= 4;
- }
-#endif
+ dma_tx_start(true);
}
static void play_stop_pcm(void)
{
-#ifdef CPU_PP502x
- unsigned long status = DMA0_STATUS; /* Snapshot- resume from this point */
- unsigned long cmd = DMA0_CMD;
- size_t size = 0;
-
- /* Stop transfer */
- DMA0_CMD = cmd & ~(DMA_CMD_START | DMA_CMD_INTR);
-
- /* Wait for not busy + clear int */
- while (DMA0_STATUS & (DMA_STATUS_BUSY | DMA_STATUS_INTR));
-
- if (status & DMA_STATUS_BUSY) {
- /* Transfer was interrupted - leave what's left */
- size = (cmd & 0xfffc) - (status & 0xfffc);
- }
- else if (status & DMA_STATUS_INTR) {
- /* Transfer was finished - DMA0_STATUS will have been reloaded
- * automatically with size in DMA0_CMD. Setup to restart on next
- * segment. */
- size = (cmd & 0xfffc) + 4;
- }
- /* else not an active state - size = 0 */
-
- dma_play_data.addr += size;
- dma_play_data.size -= size;
-
- if (dma_play_data.size == 0)
- dma_play_data.addr = 0; /* Entire buffer has completed. */
-#else
- /* Disable TX interrupt */
- IIS_IRQTX_REG &= ~IIS_IRQTX;
-#endif
+ dma_tx_stop();
/* Wait for FIFO to empty */
while (!IIS_TX_IS_EMPTY);
@@ -433,30 +472,17 @@ static void play_stop_pcm(void)
void pcm_play_dma_start(const void *addr, size_t size)
{
+ pcm_play_dma_stop();
+
#if NUM_CORES > 1
/* This will become more important later - and different ! */
dma_play_data.core = processor_id(); /* save initiating core */
#endif
- pcm_play_dma_stop();
-
-#ifdef CPU_PP502x
- if ((unsigned long)addr < UNCACHED_BASE_ADDR) {
- /* Flush any pending cache writes */
- addr = UNCACHED_ADDR(addr);
- commit_dcache();
- }
+ dma_tx_setup();
- dma_play_data.addr = (unsigned long)addr;
+ dma_play_data.addr = dma_tx_buf_prepare(addr);
dma_play_data.size = size;
- DMA0_PER_ADDR = (unsigned long)&IISFIFO_WR;
- DMA0_FLAGS = DMA_FLAGS_UNK26;
- DMA0_INCR = DMA_INCR_RANGE_FIXED | DMA_INCR_WIDTH_32BIT;
-#else
- dma_play_data.addr = (unsigned long)addr;
- dma_play_data.size = size;
-#endif
-
play_start_pcm();
}
@@ -490,39 +516,7 @@ void pcm_play_dma_init(void)
/* Initialize default register values. */
audiohw_init();
-#ifdef CPU_PP502x
- /* Enable DMA controller */
- DMA_MASTER_CONTROL |= DMA_MASTER_CONTROL_EN;
- /* FIQ priority for DMA */
- CPU_INT_PRIORITY |= DMA_MASK;
- /* Enable request?? Not setting or clearing everything doesn't seem to
- * prevent it operating. Perhaps important for reliability (how requests
- * are handled). */
- DMA_REQ_STATUS |= 1ul << DMA_REQ_IIS;
- DMA0_STATUS;
-#else
- /* Set up banked registers for FIQ mode */
-
- /* Use non-banked registers for scratch. */
- register volatile void *iiscfg asm("r0") = &IISCONFIG;
- register volatile void *dmapd asm("r1") = &dma_play_data;
-
- asm volatile (
- "mrs r2, cpsr \n" /* Save mode and interrupt status */
- "msr cpsr_c, #0xd1 \n" /* Switch to FIQ mode */
- "mov r8, #0 \n"
- "mov r9, #0 \n"
- "mov r10, %[iiscfg] \n"
- "mov r11, %[dmapd] \n"
- "msr cpsr_c, r2 \n"
- :
- : [iiscfg]"r"(iiscfg), [dmapd]"r"(dmapd)
- : "r2");
-
- /* FIQ priority for I2S */
- CPU_INT_PRIORITY |= IIS_MASK;
- CPU_INT_EN = IIS_MASK;
-#endif
+ dma_tx_init();
IISCONFIG |= IIS_TXFIFOEN;
}
@@ -649,11 +643,15 @@ void fiq_record(void)
}
}
- pcm_rec_more_ready_callback(0, (void *)&dma_rec_data.addr,
- &dma_rec_data.size);
+ if (pcm_rec_dma_complete_callback(PCM_DMAST_OK, &dma_rec_data.p_w,
+ &dma_rec_data.size))
+ {
+ pcm_rec_dma_status_callback(PCM_DMAST_STARTED);
+ }
}
-#else
+#else /* !(SANSA_C200 || SANSA_E200) */
+
void fiq_record(void)
{
while (dma_rec_data.size > 0) {
@@ -664,17 +662,20 @@ void fiq_record(void)
#if SAMPLE_SIZE == 16
*dma_rec_data.p16++ = IISFIFO_RD;
#elif SAMPLE_SIZE == 32
- *dma_rec_data.p32++ = IISFIFO_RD >> 16;
- *dma_rec_data.p32++ = IISFIFO_RD >> 16;
+ *dma_rec_data.p32++ = IISFIFO_RDH;
+ *dma_rec_data.p32++ = IISFIFO_RDH;
#endif
dma_rec_data.size -= 4;
}
- pcm_rec_more_ready_callback(0, (void *)&dma_rec_data.addr,
- &dma_rec_data.size);
+ if (pcm_rec_dma_complete_callback(PCM_DMAST_OK, &dma_rec_data.p_w,
+ &dma_rec_data.size))
+ {
+ pcm_rec_dma_status_callback(PCM_DMAST_STARTED);
+ }
}
-#endif /* SANSA_E200 */
+#endif /* SANSA_C200 || SANSA_E200 */
void pcm_rec_dma_stop(void)
{
diff --git a/firmware/target/arm/rk27xx/pcm-rk27xx.c b/firmware/target/arm/rk27xx/pcm-rk27xx.c
index 80a8d462ea..e4318de408 100644
--- a/firmware/target/arm/rk27xx/pcm-rk27xx.c
+++ b/firmware/target/arm/rk27xx/pcm-rk27xx.c
@@ -273,15 +273,13 @@ size_t pcm_get_bytes_waiting(void)
/* audio DMA ISR called when chunk from callers buffer has been transfered */
void INT_HDMA(void)
{
- void *start;
+ const void *start;
size_t size;
- pcm_play_get_more_callback(&start, &size);
-
- if (size != 0)
+ if (pcm_play_dma_complete_callback(PCM_DMAST_OK, &start, &size))
{
hdma_i2s_transfer(start, size);
- pcm_play_dma_started_callback();
+ pcm_play_dma_status_callback(PCM_DMAST_STARTED);
}
}
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c
index 35905645dd..a1c854a0df 100644
--- a/firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c
+++ b/firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c
@@ -215,16 +215,14 @@ void pcm_play_dma_pause(bool pause)
void fiq_handler(void)
{
- static void *start;
+ static const void *start;
static size_t size;
/* clear any pending interrupt */
SRCPND = DMA2_MASK;
/* Buffer empty. Try to get more. */
- pcm_play_get_more_callback(&start, &size);
-
- if (size == 0)
+ if (!pcm_play_dma_complete_callback(PCM_DMAST_OK, &start, &size))
return;
/* Flush any pending cache writes */
@@ -237,7 +235,7 @@ void fiq_handler(void)
/* Re-Activate the channel */
DMASKTRIG2 = 0x2;
- pcm_play_dma_started_callback();
+ pcm_play_dma_status_callback(PCM_DMAST_STARTED);
}
size_t pcm_get_bytes_waiting(void)
diff --git a/firmware/target/arm/s3c2440/mini2440/pcm-mini2440.c b/firmware/target/arm/s3c2440/mini2440/pcm-mini2440.c
index a4f58a8e06..943cbb2ade 100644
--- a/firmware/target/arm/s3c2440/mini2440/pcm-mini2440.c
+++ b/firmware/target/arm/s3c2440/mini2440/pcm-mini2440.c
@@ -255,16 +255,14 @@ void pcm_play_dma_pause(bool pause)
void fiq_handler(void)
{
- static void *start;
+ static const void *start;
static size_t size;
/* clear any pending interrupt */
SRCPND = DMA2_MASK;
/* Buffer empty. Try to get more. */
- pcm_play_get_more_callback(&start, &size);
-
- if (size == 0)
+ if (!pcm_play_dma_complete_callback(PCM_DMAST_OK, &start, &size))
return;
/* Flush any pending cache writes */
@@ -277,7 +275,7 @@ void fiq_handler(void)
/* Re-Activate the channel */
DMASKTRIG2 = 0x2;
- pcm_play_dma_started_callback();
+ pcm_play_dma_status_callback(PCM_DMAST_STARTED);
}
size_t pcm_get_bytes_waiting(void)
diff --git a/firmware/target/arm/s5l8700/pcm-s5l8700.c b/firmware/target/arm/s5l8700/pcm-s5l8700.c
index 7b4258fa68..c5a5bcf74f 100644
--- a/firmware/target/arm/s5l8700/pcm-s5l8700.c
+++ b/firmware/target/arm/s5l8700/pcm-s5l8700.c
@@ -116,9 +116,10 @@ void INT_DMA(void)
{
if (!nextsize)
{
- pcm_play_get_more_callback((void**)&nextbuf, &nextsize);
- if (!nextsize) break;
- new_buffer = true;
+ new_buffer = pcm_play_dma_complete_callback(PCM_DMAST_OK,
+ (const void**)&nextbuf, &nextsize);
+ if (!new_buffer)
+ break;
}
queuedsize = MIN(sizeof(dblbuf), nextsize / 2);
nextsize -= queuedsize;
@@ -133,7 +134,7 @@ void INT_DMA(void)
if (new_buffer)
{
- pcm_play_dma_started_callback();
+ pcm_play_dma_status_callback(PCM_DMAST_STARTED);
new_buffer = false;
}
}
diff --git a/firmware/target/arm/s5l8702/pcm-s5l8702.c b/firmware/target/arm/s5l8702/pcm-s5l8702.c
index b58ef0f4d3..1442afa420 100644
--- a/firmware/target/arm/s5l8702/pcm-s5l8702.c
+++ b/firmware/target/arm/s5l8702/pcm-s5l8702.c
@@ -65,7 +65,7 @@ void INT_DMAC0C0(void)
DMAC0INTTCCLR = 1;
if (!pcm_remaining)
{
- pcm_play_get_more_callback((void**)&dataptr, &pcm_remaining);
+ pcm_play_dma_complete_callback((const void**)&dataptr, &pcm_remaining);
pcm_chunksize = pcm_remaining;
}
if (!pcm_remaining)
@@ -115,7 +115,7 @@ void INT_DMAC0C0(void)
}
else DMAC0C0NEXTLLI = pcm_lli;
- pcm_play_dma_started_callback();
+ pcm_play_dma_status_callback(PCM_DMAST_STARTED);
}
void pcm_play_dma_start(const void* addr, size_t size)
diff --git a/firmware/target/arm/tms320dm320/mrobe-500/pcm-mr500.c b/firmware/target/arm/tms320dm320/mrobe-500/pcm-mr500.c
index 91d6b66130..d23c93de39 100644
--- a/firmware/target/arm/tms320dm320/mrobe-500/pcm-mr500.c
+++ b/firmware/target/arm/tms320dm320/mrobe-500/pcm-mr500.c
@@ -33,7 +33,7 @@
/* This is global to save some latency when pcm_play_dma_get_peak_buffer is
* called.
*/
-static void *start;
+static const void *start;
void pcm_play_dma_postinit(void)
{
@@ -164,9 +164,7 @@ void DSPHINT(void)
case MSG_REFILL:
/* Buffer empty. Try to get more. */
- pcm_play_get_more_callback(&start, &size);
-
- if (size != 0)
+ if (pcm_play_dma_complete_callback(PCM_DMAST_OK, &start, &size))
{
unsigned long sdem_addr=(unsigned long)start - CONFIG_SDRAM_START;
/* Flush any pending cache writes */
@@ -180,7 +178,7 @@ void DSPHINT(void)
DEBUGF("pcm_sdram at 0x%08lx, sdem_addr 0x%08lx",
(unsigned long)start, (unsigned long)sdem_addr);
- pcm_play_dma_started_callback();
+ pcm_play_dma_status_callback(PCM_DMAST_STARTED);
}
break;
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/pcm-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/pcm-sansaconnect.c
index 8b1fbf95e4..6e640bdf12 100644
--- a/firmware/target/arm/tms320dm320/sansa-connect/pcm-sansaconnect.c
+++ b/firmware/target/arm/tms320dm320/sansa-connect/pcm-sansaconnect.c
@@ -34,7 +34,7 @@
/* This is global to save some latency when pcm_play_dma_get_peak_buffer is
* called.
*/
-static void *start;
+static const void *start;
static int dma_channel;
void pcm_play_dma_postinit(void)
@@ -171,9 +171,7 @@ void DSPHINT(void)
case MSG_REFILL:
/* Buffer empty. Try to get more. */
- pcm_play_get_more_callback(&start, &size);
-
- if (size != 0)
+ if (pcm_play_dma_complete_callback(PCM_DMAST_OK, &start, &size))
{
unsigned long sdem_addr=(unsigned long)start - CONFIG_SDRAM_START;
/* Flush any pending cache writes */
@@ -187,7 +185,7 @@ void DSPHINT(void)
DEBUGF("pcm_sdram at 0x%08lx, sdem_addr 0x%08lx",
(unsigned long)start, (unsigned long)sdem_addr);
- pcm_play_dma_started_callback();
+ pcm_play_dma_status_callback(PCM_DMAST_STARTED);
}
break;
diff --git a/firmware/target/coldfire/pcm-coldfire.c b/firmware/target/coldfire/pcm-coldfire.c
index e95d445337..2e2312f7ae 100644
--- a/firmware/target/coldfire/pcm-coldfire.c
+++ b/firmware/target/coldfire/pcm-coldfire.c
@@ -294,8 +294,6 @@ void DMA0(void) __attribute__ ((interrupt_handler, section(".icode")));
void DMA0(void)
{
unsigned long res = DSR0;
- void *start;
- size_t size;
and_l(~(DMA_EEXT | DMA_INT), &DCR0); /* per request and int OFF */
DSR0 = 1; /* Clear interrupt and errors */
@@ -311,17 +309,18 @@ void DMA0(void)
#endif
}
- /* Force stop on error */
- pcm_play_get_more_callback((res & 0x70) ? NULL : &start, &size);
+ const void *addr;
+ size_t size;
- if (size != 0)
+ if (pcm_play_dma_complete_callback((res & 0x70) ?
+ PCM_DMAST_ERR_DMA : PCM_DMAST_OK,
+ &addr, &size))
{
- SAR0 = (unsigned long)start; /* Source address */
- BCR0 = size; /* Bytes to transfer */
+ SAR0 = (unsigned long)addr; /* Source address */
+ BCR0 = (unsigned long)size; /* Bytes to transfer */
or_l(DMA_EEXT | DMA_INT, &DCR0); /* per request and int ON */
- /* Call buffer callback */
- pcm_play_dma_started_callback();
+ pcm_play_dma_status_callback(PCM_DMAST_STARTED);
}
/* else inished playing */
} /* DMA0 */
@@ -368,7 +367,7 @@ void pcm_rec_unlock(void)
void pcm_rec_dma_start(void *addr, size_t size)
{
- /* stop any DMA in progress */
+ /* Stop any DMA in progress */
pcm_rec_dma_stop();
and_l(~PDIR2_FIFO_RESET, &DATAINCONTROL);
@@ -430,16 +429,14 @@ void DMA1(void) __attribute__ ((interrupt_handler, section(".icode")));
void DMA1(void)
{
unsigned long res = DSR1;
- int status = 0;
- void *start;
- size_t size;
+ enum pcm_dma_status status = PCM_DMAST_OK;
and_l(~(DMA_EEXT | DMA_INT), &DCR1); /* per request and int OFF */
DSR1 = 1; /* Clear interrupt and errors */
if (res & 0x70)
{
- status = DMA_REC_ERROR_DMA;
+ status = PCM_DMAST_ERR_DMA;
logf("DMA1 err: %02x", res);
#if 0
logf(" SAR1: %08x", SAR1);
@@ -456,19 +453,22 @@ void DMA1(void)
* Ignore valnogood since several sources don't set it properly. */
/* clear: ebu1cnew, symbolerr, parityerr */
INTERRUPTCLEAR = (1 << 25) | (1 << 23) | (1 << 22);
- status = DMA_REC_ERROR_SPDIF;
+ status = PCM_DMAST_ERR_SPDIF;
logf("spdif err");
}
#endif
/* Inform PCM we have more data (or error) */
- pcm_rec_more_ready_callback(status, &start, &size);
+ void *addr;
+ size_t size;
- if (size != 0)
+ if (pcm_rec_dma_complete_callback(status, &addr, &size))
{
- DAR1 = (unsigned long)start; /* Destination address */
+ DAR1 = (unsigned long)addr; /* Destination address */
BCR1 = (unsigned long)size; /* Bytes to transfer */
or_l(DMA_EEXT | DMA_INT, &DCR1); /* per request and int ON */
+
+ pcm_rec_dma_status_callback(PCM_DMAST_STARTED);
}
} /* DMA1 */
diff --git a/firmware/target/hosted/android/pcm-android.c b/firmware/target/hosted/android/pcm-android.c
index 4e58707d0a..7a0f28634e 100644
--- a/firmware/target/hosted/android/pcm-android.c
+++ b/firmware/target/hosted/android/pcm-android.c
@@ -80,8 +80,8 @@ Java_org_rockbox_RockboxPCM_nativeWrite(JNIEnv *env, jobject this,
if (!pcm_data_size) /* get some initial data */
{
- new_buffer = true;
- pcm_play_get_more_callback((void**) &pcm_data_start, &pcm_data_size);
+ new_buffer = pcm_play_dma_complete_callback(PCM_DMAST_OK,
+ (const void**)&pcm_data_start, &pcm_data_size);
}
while(left > 0 && pcm_data_size)
@@ -99,7 +99,7 @@ Java_org_rockbox_RockboxPCM_nativeWrite(JNIEnv *env, jobject this,
if (new_buffer)
{
new_buffer = false;
- pcm_play_dma_started_callback();
+ pcm_play_dma_status_callback(PCM_DMAST_STARTED);
/* NOTE: might need to release the mutex and sleep here if the
buffer is shorter than the required buffer (like pcm-sdl.c) to
@@ -114,15 +114,15 @@ Java_org_rockbox_RockboxPCM_nativeWrite(JNIEnv *env, jobject this,
if (pcm_data_size == 0) /* need new data */
{
- new_buffer = true;
- pcm_play_get_more_callback((void**)&pcm_data_start, &pcm_data_size);
+ new_buffer = pcm_play_dma_complete_callback(PCM_DMAST_OK,
+ (const void**)&pcm_data_start, &pcm_data_size);
}
else /* increment data pointer and feed more */
pcm_data_start += transfer_size;
}
- if (new_buffer && pcm_data_size)
- pcm_play_dma_started_callback();
+ if (new_buffer)
+ pcm_play_dma_status_callback(PCM_DMAST_STARTED);
unlock_audio();
return max_size - left;
@@ -154,7 +154,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
void pcm_play_dma_stop(void)
{
- /* NOTE: due to how pcm_play_get_more_callback() works, this is
+ /* NOTE: due to how pcm_play_dma_complete_callback() works, this is
* possibly called from nativeWrite(), i.e. another (host) thread
* => need to discover the appropriate JNIEnv* */
JNIEnv* env = getJavaEnvironment();
diff --git a/firmware/target/hosted/maemo/pcm-gstreamer.c b/firmware/target/hosted/maemo/pcm-gstreamer.c
index e5620d0702..61f33cbadd 100644
--- a/firmware/target/hosted/maemo/pcm-gstreamer.c
+++ b/firmware/target/hosted/maemo/pcm-gstreamer.c
@@ -189,9 +189,8 @@ static void feed_data(GstElement * appsrc, guint size_hint, void *unused)
from inside gstreamer's stream thread as it will deadlock */
inside_feed_data = 1;
- pcm_play_get_more_callback((void **)&pcm_data, &pcm_data_size);
-
- if (pcm_data_size != 0)
+ if (pcm_play_dma_complete_callback(PCM_DMAST_OK, (const void **)&pcm_data,
+ &pcm_data_size))
{
GstBuffer *buffer = gst_buffer_new ();
GstFlowReturn ret;
@@ -205,7 +204,7 @@ static void feed_data(GstElement * appsrc, guint size_hint, void *unused)
if (ret != 0)
DEBUGF("push-buffer error result: %d\n", ret);
- pcm_play_dma_started_callback();
+ pcm_play_dma_status_callback(PCM_DMAST_STARTED);
} else
{
DEBUGF("feed_data: No Data.\n");
diff --git a/firmware/target/hosted/pcm-alsa.c b/firmware/target/hosted/pcm-alsa.c
index b78993dd0a..1385f75b34 100644
--- a/firmware/target/hosted/pcm-alsa.c
+++ b/firmware/target/hosted/pcm-alsa.c
@@ -223,9 +223,11 @@ static bool fill_frames(void)
if (!pcm_size)
{
new_buffer = true;
- pcm_play_get_more_callback((void **)&pcm_data, &pcm_size);
- if (!pcm_size || !pcm_data)
+ if (!pcm_play_dma_complete_callback(PCM_DMAST_OK,
+ (const void **)&pcm_data, &pcm_size))
+ {
return false;
+ }
}
copy_n = MIN((ssize_t)pcm_size, frames_left*4);
memcpy(&frames[2*(period_size-frames_left)], pcm_data, copy_n);
@@ -237,7 +239,7 @@ static bool fill_frames(void)
if (new_buffer)
{
new_buffer = false;
- pcm_play_dma_started_callback();
+ pcm_play_dma_status_callback(PCM_DMAST_STARTED);
}
}
return true;
diff --git a/firmware/target/hosted/sdl/pcm-sdl.c b/firmware/target/hosted/sdl/pcm-sdl.c
index 020928d572..2c535b2dc5 100644
--- a/firmware/target/hosted/sdl/pcm-sdl.c
+++ b/firmware/target/hosted/sdl/pcm-sdl.c
@@ -56,7 +56,7 @@ static int sim_volume = 0;
#if CONFIG_CODEC == SWCODEC
static int cvt_status = -1;
-static Uint8* pcm_data;
+static const Uint8* pcm_data;
static size_t pcm_data_size;
static size_t pcm_sample_bytes;
static size_t pcm_channel_bytes;
@@ -109,7 +109,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
{
pcm_dma_apply_settings_nolock();
- pcm_data = (Uint8 *) addr;
+ pcm_data = addr;
pcm_data_size = size;
SDL_PauseAudio(0);
@@ -245,48 +245,48 @@ static void sdl_audio_callback(struct pcm_udata *udata, Uint8 *stream, int len)
/* Audio card wants more? Get some more then. */
while (len > 0) {
- new_buffer = true;
- pcm_play_get_more_callback((void **)&pcm_data, &pcm_data_size);
+ new_buffer = pcm_play_dma_complete_callback(PCM_DMAST_OK,
+ (const void **)&pcm_data, &pcm_data_size);
+
+ if (!new_buffer) {
+ DEBUGF("sdl_audio_callback: No Data.\n");
+ break;
+ }
+
start:
- if (pcm_data_size != 0) {
- udata->num_in = pcm_data_size / pcm_sample_bytes;
- udata->num_out = len / pcm_sample_bytes;
+ udata->num_in = pcm_data_size / pcm_sample_bytes;
+ udata->num_out = len / pcm_sample_bytes;
- write_to_soundcard(udata);
+ write_to_soundcard(udata);
- udata->num_in *= pcm_sample_bytes;
- udata->num_out *= pcm_sample_bytes;
+ udata->num_in *= pcm_sample_bytes;
+ udata->num_out *= pcm_sample_bytes;
+ if (new_buffer)
+ {
+ new_buffer = false;
+ pcm_play_dma_status_callback(PCM_DMAST_STARTED);
- if (new_buffer)
+ if ((size_t)len > udata->num_out)
{
- new_buffer = false;
- pcm_play_dma_started_callback();
+ int delay = pcm_data_size*250 / pcm_sampr - 1;
- if ((size_t)len > udata->num_out)
+ if (delay > 0)
{
- int delay = pcm_data_size*250 / pcm_sampr - 1;
-
- if (delay > 0)
- {
- SDL_UnlockMutex(audio_lock);
- SDL_Delay(delay);
- SDL_LockMutex(audio_lock);
-
- if (!pcm_is_playing())
- break;
- }
+ SDL_UnlockMutex(audio_lock);
+ SDL_Delay(delay);
+ SDL_LockMutex(audio_lock);
+
+ if (!pcm_is_playing())
+ break;
}
}
-
- pcm_data += udata->num_in;
- pcm_data_size -= udata->num_in;
- udata->stream += udata->num_out;
- len -= udata->num_out;
- } else {
- DEBUGF("sdl_audio_callback: No Data.\n");
- break;
}
+
+ pcm_data += udata->num_in;
+ pcm_data_size -= udata->num_in;
+ udata->stream += udata->num_out;
+ len -= udata->num_out;
}
SDL_UnlockMutex(audio_lock);
diff --git a/firmware/target/mips/ingenic_jz47xx/pcm-jz4740.c b/firmware/target/mips/ingenic_jz47xx/pcm-jz4740.c
index 1ed413c9ae..83d3646ed1 100644
--- a/firmware/target/mips/ingenic_jz47xx/pcm-jz4740.c
+++ b/firmware/target/mips/ingenic_jz47xx/pcm-jz4740.c
@@ -63,7 +63,7 @@ void pcm_dma_apply_settings(void)
audiohw_set_frequency(pcm_sampr);
}
-static void* playback_address;
+static const void* playback_address;
static inline void set_dma(const void *addr, size_t size)
{
int burst_size;
@@ -96,21 +96,19 @@ static inline void set_dma(const void *addr, size_t size)
REG_DMAC_DRSR(DMA_AIC_TX_CHANNEL) = DMAC_DRSR_RS_AICOUT;
REG_DMAC_DCMD(DMA_AIC_TX_CHANNEL) = (DMAC_DCMD_SAI | DMAC_DCMD_SWDH_32 | burst_size | DMAC_DCMD_DWDH_16 | DMAC_DCMD_TIE);
- playback_address = (void*)addr;
+ playback_address = addr;
}
static inline void play_dma_callback(void)
{
- void *start;
+ const void *start;
size_t size;
- pcm_play_get_more_callback(&start, &size);
-
- if (size != 0)
+ if (pcm_play_dma_complete_callback(PCM_DMAST_OK, &start, &size))
{
set_dma(start, size);
REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) |= DMAC_DCCSR_EN;
- pcm_play_dma_started_callback();
+ pcm_play_dma_status_callback(PCM_DMAST_STARTED);
}
}