A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd

Revise the PCM callback system after adding multichannel audio.

Additional status callback is added to pcm_play/rec_data instead of
using a special function to set it. Status includes DMA error
reporting to the status callback. Playback and recording callback
become more alike except playback uses "const void **addr" (because
the data should not be altered) and recording uses "void **addr".
"const" is put in place throughout where appropriate.

Most changes are fairly trivial. One that should be checked in
particular because it isn't so much is telechips, if anyone cares to
bother. PP5002 is not so trivial either but that tested as working.

Change-Id: I4928d69b3b3be7fb93e259f81635232df9bd1df2
Reviewed-on: http://gerrit.rockbox.org/166
Reviewed-by: Michael Sevakis <jethead71@rockbox.org>
Tested-by: Michael Sevakis <jethead71@rockbox.org>

+757 -710
+2 -2
apps/beep.c
··· 46 46 /* Callback to generate the beep frames - also don't want inlining of 47 47 call below in beep_play */ 48 48 static void __attribute__((noinline)) 49 - beep_get_more(unsigned char **start, size_t *size) 49 + beep_get_more(const void **start, size_t *size) 50 50 { 51 51 int count = beep_count; 52 52 ··· 87 87 #endif 88 88 89 89 /* If it fits - avoid cb overhead */ 90 - unsigned char *start; 90 + const void *start; 91 91 size_t size; 92 92 93 93 /* Generate first frame here */
+1 -1
apps/pcmbuf.c
··· 694 694 /** Playback */ 695 695 696 696 /* PCM driver callback */ 697 - static void pcmbuf_pcm_callback(unsigned char **start, size_t *size) 697 + static void pcmbuf_pcm_callback(const void **start, size_t *size) 698 698 { 699 699 /*- Process the chunk that just finished -*/ 700 700 size_t index = chunk_ridx;
+8 -5
apps/plugin.h
··· 153 153 #define PLUGIN_MAGIC 0x526F634B /* RocK */ 154 154 155 155 /* increase this every time the api struct changes */ 156 - #define PLUGIN_API_VERSION 216 156 + #define PLUGIN_API_VERSION 217 157 157 158 158 /* update this to latest version if a change to the api struct breaks 159 159 backwards compatibility (and please take the opportunity to sort in any 160 160 new function which are "waiting" at the end of the function table) */ 161 - #define PLUGIN_MIN_API_VERSION 216 161 + #define PLUGIN_MIN_API_VERSION 217 162 162 163 163 /* plugin return codes */ 164 164 /* internal returns start at 0x100 to make exit(1..255) work */ ··· 651 651 const unsigned long *hw_freq_sampr; 652 652 void (*pcm_apply_settings)(void); 653 653 void (*pcm_play_data)(pcm_play_callback_type get_more, 654 - unsigned char* start, size_t size); 654 + pcm_status_callback_type status_cb, 655 + const void *start, size_t size); 655 656 void (*pcm_play_stop)(void); 656 657 void (*pcm_set_frequency)(unsigned int frequency); 657 658 bool (*pcm_is_playing)(void); ··· 669 670 void (*pcm_init_recording)(void); 670 671 void (*pcm_close_recording)(void); 671 672 void (*pcm_record_data)(pcm_rec_callback_type more_ready, 673 + pcm_status_callback_type status_cb, 672 674 void *start, size_t size); 673 675 void (*pcm_stop_recording)(void); 674 676 void (*pcm_calculate_rec_peaks)(int *left, int *right); ··· 689 691 int (*dsp_output_count)(struct dsp_config *dsp, int count); 690 692 691 693 enum channel_status (*mixer_channel_status)(enum pcm_mixer_channel channel); 692 - void * (*mixer_channel_get_buffer)(enum pcm_mixer_channel channel, int *count); 694 + const void * (*mixer_channel_get_buffer)(enum pcm_mixer_channel channel, 695 + int *count); 693 696 void (*mixer_channel_calculate_peaks)(enum pcm_mixer_channel channel, 694 697 int *left, int *right); 695 698 void (*mixer_channel_play_data)(enum pcm_mixer_channel channel, 696 699 pcm_play_callback_type get_more, 697 - unsigned char *start, size_t size); 700 + const void *start, size_t size); 698 701 void (*mixer_channel_play_pause)(enum pcm_mixer_channel channel, bool play); 699 702 void (*mixer_channel_stop)(enum pcm_mixer_channel channel); 700 703 void (*mixer_channel_set_amplitude)(enum pcm_mixer_channel channel,
+4 -4
apps/plugins/beatbox/beatbox.c
··· 509 509 rb->lcd_update(); 510 510 } 511 511 512 - void get_more(unsigned char** start, size_t* size) 512 + void get_more(const void** start, size_t* size) 513 513 { 514 514 #ifndef SYNC 515 515 if(lastswap!=swap) ··· 523 523 524 524 *size = BUF_SIZE*sizeof(short); 525 525 #ifndef SYNC 526 - *start = (unsigned char*)((swap ? gmbuf : gmbuf + BUF_SIZE)); 526 + *start = swap ? gmbuf : gmbuf + BUF_SIZE; 527 527 swap=!swap; 528 528 #else 529 - *start = (unsigned char*)(gmbuf); 529 + *start = gmbuf; 530 530 #endif 531 531 } 532 532 ··· 537 537 538 538 numberOfSamples=44100/10; 539 539 synthbuf(); 540 - rb->pcm_play_data(&get_more, NULL, 0); 540 + rb->pcm_play_data(&get_more, NULL, NULL, 0); 541 541 542 542 rb->lcd_set_background(0x000000); 543 543 rb->lcd_clear_display();
+3 -3
apps/plugins/doom/i_sound.c
··· 457 457 // only output be done asynchronous? 458 458 // 459 459 460 - void get_more(unsigned char** start, size_t* size) 460 + void get_more(const void** start, size_t* size) 461 461 { 462 462 I_UpdateSound(); // Force sound update 463 463 464 - *start = (unsigned char*)(mixbuffer); 464 + *start = mixbuffer; 465 465 *size = SAMPLECOUNT*2*sizeof(short); 466 466 } 467 467 ··· 471 471 if (!enable_sound) 472 472 return; 473 473 474 - rb->pcm_play_data(&get_more, NULL, 0); 474 + rb->pcm_play_data(&get_more, NULL, NULL, 0); 475 475 } 476 476 477 477 void I_ShutdownSound(void)
+2 -2
apps/plugins/fft/fft.c
··· 1186 1186 static inline bool fft_get_fft(void) 1187 1187 { 1188 1188 int count; 1189 - int16_t *value = 1190 - (int16_t *) rb->mixer_channel_get_buffer(PCM_MIXER_CHAN_PLAYBACK, &count); 1189 + const int16_t *value = 1190 + rb->mixer_channel_get_buffer(PCM_MIXER_CHAN_PLAYBACK, &count); 1191 1191 /* This block can introduce discontinuities in our data. Meaning, the 1192 1192 * FFT will not be done a continuous segment of the signal. Which can 1193 1193 * be bad. Or not.
+1 -1
apps/plugins/metronome.c
··· 721 721 722 722 static void play_tock(void) 723 723 { 724 - rb->pcm_play_data(NULL,(unsigned char *)sndbuf,sizeof(sndbuf)); 724 + rb->pcm_play_data(NULL, NULL, sndbuf, sizeof(sndbuf)); 725 725 } 726 726 727 727 #endif /* CONFIG_CODEC != SWCODEC */
+7 -7
apps/plugins/midi/midiplay.c
··· 319 319 samples_in_buf = BUF_SIZE-i; 320 320 } 321 321 322 - static void get_more(unsigned char** start, size_t* size) 322 + static void get_more(const void** start, size_t* size) 323 323 { 324 324 #ifndef SYNC 325 325 if(lastswap != swap) ··· 333 333 334 334 *size = samples_in_buf*sizeof(int32_t); 335 335 #ifndef SYNC 336 - *start = (unsigned char*)((swap ? gmbuf : gmbuf + BUF_SIZE)); 336 + *start = swap ? gmbuf : gmbuf + BUF_SIZE; 337 337 swap = !swap; 338 338 #else 339 - *start = (unsigned char*)(gmbuf); 339 + *start = gmbuf; 340 340 #endif 341 341 } 342 342 ··· 396 396 samples_this_second = 0; 397 397 398 398 synthbuf(); 399 - rb->pcm_play_data(&get_more, NULL, 0); 399 + rb->pcm_play_data(&get_more, NULL, NULL, 0); 400 400 401 401 while (!quit) 402 402 { ··· 445 445 seekBackward(5); 446 446 midi_debug("Rewind to %d:%02d\n", playing_time/60, playing_time%60); 447 447 if (is_playing) 448 - rb->pcm_play_data(&get_more, NULL, 0); 448 + rb->pcm_play_data(&get_more, NULL, NULL, 0); 449 449 break; 450 450 } 451 451 ··· 455 455 seekForward(5); 456 456 midi_debug("Skip to %d:%02d\n", playing_time/60, playing_time%60); 457 457 if (is_playing) 458 - rb->pcm_play_data(&get_more, NULL, 0); 458 + rb->pcm_play_data(&get_more, NULL, NULL, 0); 459 459 break; 460 460 } 461 461 ··· 470 470 { 471 471 midi_debug("Playing from %d:%02d\n", playing_time/60, playing_time%60); 472 472 is_playing = true; 473 - rb->pcm_play_data(&get_more, NULL, 0); 473 + rb->pcm_play_data(&get_more, NULL, NULL, 0); 474 474 } 475 475 break; 476 476 }
+5 -5
apps/plugins/mikmod/mikmod.c
··· 268 268 VC_WriteBytes(outptr, BUF_SIZE); 269 269 } 270 270 271 - void get_more(unsigned char** start, size_t* size) 271 + void get_more(const void** start, size_t* size) 272 272 { 273 273 #ifndef SYNC 274 274 if (lastswap != swap) ··· 282 282 283 283 *size = BUF_SIZE; 284 284 #ifndef SYNC 285 - *start = (unsigned char*)((swap ? gmbuf : gmbuf + BUF_SIZE)); 285 + *start = swap ? gmbuf : gmbuf + BUF_SIZE; 286 286 swap = !swap; 287 287 #else 288 - *start = (unsigned char*)(gmbuf); 288 + *start = gmbuf; 289 289 #endif 290 290 } 291 291 ··· 660 660 { 661 661 display = DISPLAY_INFO; 662 662 Player_Start(module); 663 - rb->pcm_play_data(&get_more, NULL, 0); 663 + rb->pcm_play_data(&get_more, NULL, NULL, 0); 664 664 } 665 665 666 666 #ifdef HAVE_ADJUSTABLE_CPU_FREQ ··· 804 804 } 805 805 else 806 806 { 807 - rb->pcm_play_data(&get_more, NULL, 0); 807 + rb->pcm_play_data(&get_more, NULL, NULL, 0); 808 808 } 809 809 Player_TogglePause(); 810 810 break;
+1 -1
apps/plugins/mpegplayer/pcm_output.c
··· 85 85 } 86 86 87 87 /* Audio DMA handler */ 88 - static void get_more(unsigned char **start, size_t *size) 88 + static void get_more(const void **start, size_t *size) 89 89 { 90 90 ssize_t sz; 91 91
+3 -3
apps/plugins/pacbox/pacbox.c
··· 286 286 /* 287 287 Audio callback 288 288 */ 289 - static void get_more(unsigned char **start, size_t *size) 289 + static void get_more(const void **start, size_t *size) 290 290 { 291 291 int32_t *out, *outend; 292 292 int16_t *raw; ··· 306 306 } 307 307 while (out < outend); 308 308 309 - *start = (unsigned char *)sound_buf; 309 + *start = sound_buf; 310 310 *size = NBSAMPLES*sizeof(sound_buf[0]); 311 311 } 312 312 ··· 339 339 wsg3_set_sampling_rate(rb->hw_freq_sampr[sr_index]); 340 340 341 341 rb->pcm_set_frequency(rb->hw_freq_sampr[sr_index]); 342 - rb->pcm_play_data(get_more, NULL, 0); 342 + rb->pcm_play_data(get_more, NULL, NULL, 0); 343 343 344 344 sound_playing = true; 345 345 }
+4 -6
apps/plugins/pdbox/PDa/src/s_audio_rockbox.c
··· 26 26 #include "s_stuff.h" 27 27 28 28 /* Declare functions that go to IRAM. */ 29 - void pdbox_get_more(unsigned char** start, size_t* size) ICODE_ATTR; 29 + void pdbox_get_more(const void** start, size_t* size) ICODE_ATTR; 30 30 int rockbox_send_dacs(void) ICODE_ATTR; 31 31 32 32 /* Extern variables. */ ··· 90 90 } 91 91 92 92 /* Rockbox audio callback. */ 93 - void pdbox_get_more(unsigned char** start, size_t* size) 93 + void pdbox_get_more(const void** start, size_t* size) 94 94 { 95 95 if(outbuf_fill > 0) 96 96 { 97 97 /* Store output data address and size. */ 98 - *start = (unsigned char*) outbuf[outbuf_tail].data; 98 + *start = outbuf[outbuf_tail].data; 99 99 *size = sizeof(outbuf[outbuf_tail].data); 100 100 101 101 /* Free this part of output buffer. */ ··· 116 116 playing = false; 117 117 118 118 /* Nothing to play. */ 119 - *start = NULL; 120 - *size = 0; 121 119 } 122 120 } 123 121 ··· 185 183 if(!playing && outbuf_fill > 0) 186 184 { 187 185 /* Start playing. */ 188 - rb->pcm_play_data(pdbox_get_more, NULL, 0); 186 + rb->pcm_play_data(pdbox_get_more, NULL, NULL, 0); 189 187 190 188 /* Set status flag. */ 191 189 playing = true;
+3 -4
apps/plugins/pitch_detector.c
··· 952 952 } 953 953 954 954 /* Stop the recording when the buffer is full */ 955 - static void recording_callback(int status, void **start, size_t *size) 955 + static void recording_callback(void **start, size_t *size) 956 956 { 957 957 int tail = audio_tail ^ 1; 958 958 ··· 963 963 /* Always record full buffer, even if not required */ 964 964 *start = audio_data[tail]; 965 965 *size = BUFFER_SIZE * sizeof (int16_t); 966 - 967 - (void)status; 968 966 } 969 967 #endif /* SIMULATOR */ 970 968 ··· 973 971 { 974 972 #ifndef SIMULATOR 975 973 /* Always record full buffer, even if not required */ 976 - rb->pcm_record_data(recording_callback, audio_data[audio_tail], 974 + rb->pcm_record_data(recording_callback, NULL, 975 + audio_data[audio_tail], 977 976 BUFFER_SIZE * sizeof (int16_t)); 978 977 #endif 979 978 }
+3 -3
apps/plugins/rockboy/rbsound.c
··· 16 16 17 17 static bool newly_started; 18 18 19 - static void get_more(unsigned char** start, size_t* size) 19 + static void get_more(const void** start, size_t* size) 20 20 { 21 21 memcpy(hwbuf, &buf[pcm.len*doneplay], BUF_SIZE*sizeof(short)); 22 - *start = (unsigned char*)(hwbuf); 22 + *start = hwbuf; 23 23 *size = BUF_SIZE*sizeof(short); 24 24 doneplay=1; 25 25 } ··· 76 76 77 77 if(newly_started) 78 78 { 79 - rb->pcm_play_data(&get_more,NULL,0); 79 + rb->pcm_play_data(&get_more, NULL, NULL,0); 80 80 newly_started = false; 81 81 } 82 82
+3 -3
apps/plugins/test_sampr.c
··· 90 90 } 91 91 92 92 /* ISR handler to get next block of data */ 93 - static void get_more(unsigned char **start, size_t *size) 93 + static void get_more(const void **start, size_t *size) 94 94 { 95 95 /* Free previous buffer */ 96 96 output_head += output_step; 97 97 output_step = 0; 98 98 99 - *start = (unsigned char *)output_buf[output_head & OUTPUT_CHUNK_MASK]; 99 + *start = output_buf[output_head & OUTPUT_CHUNK_MASK]; 100 100 *size = OUTPUT_CHUNK_SIZE; 101 101 102 102 /* Keep repeating previous if source runs low */ ··· 236 236 IF_PRIO(, PRIORITY_PLAYBACK) 237 237 IF_COP(, CPU)); 238 238 239 - rb->pcm_play_data(get_more, NULL, 0); 239 + rb->pcm_play_data(get_more, NULL, NULL, 0); 240 240 241 241 #ifndef HAVE_VOLUME_IN_LIST 242 242 if (volume_set)
+4 -5
apps/plugins/zxbox/spsound.c
··· 189 189 } 190 190 #endif 191 191 } 192 - static void get_more(unsigned char** start, size_t* size) 192 + static void get_more(const void** start, size_t* size) 193 193 { 194 194 doneplay = 1; 195 - rb->pcm_play_stop(); 196 - (void)*start; 197 - (void)*size; 195 + (void)start; 196 + (void)size; 198 197 } 199 198 200 199 /* sp_sound_buf is Unsigned 8 bit, Rate 8000 Hz, Mono */ ··· 219 218 = my_buf[j+10] = my_buf[j+11] \ 220 219 = (((byte)sp_sound_buf[i])<<8) >> settings.volume; 221 220 222 - rb->pcm_play_data(&get_more,(unsigned char*)(my_buf),TMNUM*4*3*2); 221 + rb->pcm_play_data(&get_more,NULL,(unsigned char*)(my_buf),TMNUM*4*3*2); 223 222 224 223 #if 0 225 224 /* can use to save and later analyze what we produce */
+21 -15
apps/recorder/pcm_record.c
··· 257 257 /*******************************************************************/ 258 258 259 259 /* Callback for when more data is ready - called in interrupt context */ 260 - static void pcm_rec_have_more(int status, void **start, size_t *size) 260 + static void pcm_rec_have_more(void **start, size_t *size) 261 261 { 262 - if (status < 0) 263 - { 264 - /* some error condition */ 265 - if (status == DMA_REC_ERROR_DMA) 266 - { 267 - /* Flush recorded data to disk and stop recording */ 268 - queue_post(&pcmrec_queue, PCMREC_STOP, 0); 269 - return; 270 - } 271 - /* else try again next transmission - frame is invalid */ 272 - } 273 - else if (!dma_lock) 262 + if (!dma_lock) 274 263 { 275 264 /* advance write position */ 276 265 int next_pos = (dma_wr_pos + PCM_CHUNK_SIZE) & PCM_CHUNK_MASK; ··· 286 275 *start = GET_PCM_CHUNK(dma_wr_pos); 287 276 *size = PCM_CHUNK_SIZE; 288 277 } /* pcm_rec_have_more */ 278 + 279 + static enum pcm_dma_status pcm_rec_status_callback(enum pcm_dma_status status) 280 + { 281 + if (status < PCM_DMAST_OK) 282 + { 283 + /* some error condition */ 284 + if (status == PCM_DMAST_ERR_DMA) 285 + { 286 + /* Flush recorded data to disk and stop recording */ 287 + queue_post(&pcmrec_queue, PCMREC_STOP, 0); 288 + return status; 289 + } 290 + /* else try again next transmission - frame is invalid */ 291 + } 292 + 293 + return PCM_DMAST_OK; 294 + } /* pcm_rec_status_callback */ 289 295 290 296 static void reset_hardware(void) 291 297 { ··· 1239 1245 { 1240 1246 /* start DMA transfer */ 1241 1247 dma_lock = pre_record_ticks == 0; 1242 - pcm_record_data(pcm_rec_have_more, GET_PCM_CHUNK(dma_wr_pos), 1243 - PCM_CHUNK_SIZE); 1248 + pcm_record_data(pcm_rec_have_more, pcm_rec_status_callback, 1249 + GET_PCM_CHUNK(dma_wr_pos), PCM_CHUNK_SIZE); 1244 1250 } 1245 1251 else 1246 1252 {
+10 -7
apps/voice_thread.c
··· 116 116 /* Structure to store clip data callback info */ 117 117 struct voice_info 118 118 { 119 - pcm_play_callback_type get_more; /* Callback to get more clips */ 120 - unsigned char *start; /* Start of clip */ 121 - size_t size; /* Size of clip */ 119 + /* Callback to get more clips */ 120 + void (*get_more)(unsigned char** start, size_t* size); 121 + /* Start of clip */ 122 + unsigned char *start; 123 + /* Size of clip */ 124 + size_t size; 122 125 }; 123 126 124 127 /* Private thread data for its current state that must be passed to its ··· 148 151 } 149 152 150 153 /* Mixer channel callback */ 151 - static void voice_pcm_callback(unsigned char **start, size_t *size) 154 + static void voice_pcm_callback(const void **start, size_t *size) 152 155 { 153 156 if (voice_unplayed_frames() == 0) 154 157 return; /* Done! */ 155 158 156 159 unsigned int i = ++cur_buf_out % VOICE_FRAMES; 157 160 158 - *start = (unsigned char *)voicebuf[i]; 161 + *start = voicebuf[i]; 159 162 *size = voicebuf_sizes[i]; 160 163 } 161 164 ··· 167 170 168 171 unsigned int i = cur_buf_out % VOICE_FRAMES; 169 172 mixer_channel_play_data(PCM_MIXER_CHAN_VOICE, voice_pcm_callback, 170 - (unsigned char *)voicebuf[i], voicebuf_sizes[i]); 173 + voicebuf[i], voicebuf_sizes[i]); 171 174 } 172 175 173 176 /* Stop the voice channel */ ··· 198 201 199 202 /* Stop any current clip and start playing a new one */ 200 203 void mp3_play_data(const unsigned char* start, int size, 201 - pcm_play_callback_type get_more) 204 + void (*get_more)(unsigned char** start, size_t* size)) 202 205 { 203 206 if (get_more != NULL && start != NULL && (ssize_t)size > 0) 204 207 {
+4 -4
firmware/asm/arm/pcm-mixer-armv4.c
··· 24 24 25 25 /* Mix channels' samples and apply gain factors */ 26 26 static FORCE_INLINE void mix_samples(void *out, 27 - void *src0, 27 + const void *src0, 28 28 int32_t src0_amp, 29 - void *src1, 29 + const void *src1, 30 30 int32_t src1_amp, 31 31 size_t size) 32 32 { ··· 96 96 if (src0_amp != MIX_AMP_UNITY) 97 97 { 98 98 /* Keep unity in src0, amp0 */ 99 - int16_t *src_tmp = src0; 99 + const void *src_tmp = src0; 100 100 src0 = src1; 101 101 src1 = src_tmp; 102 102 src1_amp = src0_amp; ··· 133 133 134 134 /* Write channel's samples and apply gain factor */ 135 135 static FORCE_INLINE void write_samples(void *out, 136 - void *src, 136 + const void *src, 137 137 int32_t amp, 138 138 size_t size) 139 139 {
+3 -3
firmware/asm/arm/pcm-mixer-armv5.c
··· 24 24 25 25 /* Mix channels' samples and apply gain factors */ 26 26 static FORCE_INLINE void mix_samples(void *out, 27 - void *src0, 27 + const void *src0, 28 28 int32_t src0_amp, 29 - void *src1, 29 + const void *src1, 30 30 int32_t src1_amp, 31 31 size_t size) 32 32 { ··· 57 57 58 58 /* Write channel's samples and apply gain factor */ 59 59 static FORCE_INLINE void write_samples(void *out, 60 - void *src, 60 + const void *src, 61 61 int32_t amp, 62 62 size_t size) 63 63 {
+3 -3
firmware/asm/arm/pcm-mixer-armv6.c
··· 23 23 24 24 /* Mix channels' samples and apply gain factors */ 25 25 static FORCE_INLINE void mix_samples(void *out, 26 - void *src0, 26 + const void *src0, 27 27 int32_t src0_amp, 28 - void *src1, 28 + const void *src1, 29 29 int32_t src1_amp, 30 30 size_t size) 31 31 { ··· 71 71 72 72 /* Write channel's samples and apply gain factor */ 73 73 static FORCE_INLINE void write_samples(void *out, 74 - void *src, 74 + const void *src, 75 75 int32_t amp, 76 76 size_t size) 77 77 {
+3 -3
firmware/asm/m68k/pcm-mixer.c
··· 56 56 57 57 /* Mix channels' samples and apply gain factors */ 58 58 static FORCE_INLINE void mix_samples(void *out, 59 - void *src0, 59 + const void *src0, 60 60 int32_t src0_amp, 61 - void *src1, 61 + const void *src1, 62 62 int32_t src1_amp, 63 63 size_t size) 64 64 { ··· 94 94 95 95 /* Write channel's samples and apply gain factor */ 96 96 static FORCE_INLINE void write_samples(void *out, 97 - void *src, 97 + const void *src, 98 98 int32_t amp, 99 99 size_t size) 100 100 {
+4 -4
firmware/asm/pcm-mixer.c
··· 28 28 #include "dsp-util.h" /* for clip_sample_16 */ 29 29 /* Mix channels' samples and apply gain factors */ 30 30 static FORCE_INLINE void mix_samples(int16_t *out, 31 - int16_t *src0, 31 + const int16_t *src0, 32 32 int32_t src0_amp, 33 - int16_t *src1, 33 + const int16_t *src1, 34 34 int32_t src1_amp, 35 35 size_t size) 36 36 { ··· 64 64 if (src0_amp != MIX_AMP_UNITY) 65 65 { 66 66 /* Keep unity in src0, amp0 */ 67 - int16_t *src_tmp = src0; 67 + const int16_t *src_tmp = src0; 68 68 src0 = src1; 69 69 src1 = src_tmp; 70 70 src1_amp = src0_amp; ··· 84 84 85 85 /* Write channel's samples and apply gain factor */ 86 86 static FORCE_INLINE void write_samples(int16_t *out, 87 - int16_t *src, 87 + const int16_t *src, 88 88 int32_t amp, 89 89 size_t size) 90 90 {
+37 -14
firmware/export/pcm-internal.h
··· 41 41 42 42 /** The following are for internal use between pcm.c and target- 43 43 specific portion **/ 44 + static FORCE_INLINE enum pcm_dma_status pcm_call_status_cb( 45 + pcm_status_callback_type callback, enum pcm_dma_status status) 46 + { 47 + if (!callback) 48 + return status; 44 49 45 - /* Called by the bottom layer ISR when more data is needed. Returns non- 46 - * zero size if more data is to be played. Setting start to NULL 47 - * forces stop. */ 48 - void pcm_play_get_more_callback(void **start, size_t *size); 50 + return callback(status); 51 + } 49 52 50 - /* Called by the bottom layer ISR after next transfer has begun in order 51 - to fill more data for next "get more" callback to implement double-buffered 52 - callbacks - except for a couple ASM handlers, help drivers to implement 53 - this functionality with minimal overhead */ 54 - static FORCE_INLINE void pcm_play_dma_started_callback(void) 53 + static FORCE_INLINE enum pcm_dma_status 54 + pcm_play_dma_status_callback(enum pcm_dma_status status) 55 55 { 56 - extern void (* pcm_play_dma_started)(void); 57 - void (* callback)(void) = pcm_play_dma_started; 58 - if (callback) 59 - callback(); 56 + extern enum pcm_dma_status 57 + (* volatile pcm_play_status_callback)(enum pcm_dma_status); 58 + return pcm_call_status_cb(pcm_play_status_callback, status); 60 59 } 61 60 61 + /* Called by the bottom layer ISR when more data is needed. Returns true 62 + * if a new buffer is available, false otherwise. */ 63 + bool pcm_play_dma_complete_callback(enum pcm_dma_status status, 64 + const void **addr, size_t *size); 65 + 62 66 extern unsigned long pcm_curr_sampr; 63 67 extern unsigned long pcm_sampr; 64 68 extern int pcm_fsel; ··· 90 94 void pcm_rec_dma_init(void); 91 95 void pcm_rec_dma_close(void); 92 96 void pcm_rec_dma_start(void *addr, size_t size); 93 - void pcm_rec_dma_record_more(void *start, size_t size); 94 97 void pcm_rec_dma_stop(void); 95 98 const void * pcm_rec_dma_get_peak_buffer(void); 99 + 100 + static FORCE_INLINE enum pcm_dma_status 101 + pcm_rec_dma_status_callback(enum pcm_dma_status status) 102 + { 103 + extern enum pcm_dma_status 104 + (* volatile pcm_rec_status_callback)(enum pcm_dma_status); 105 + return pcm_call_status_cb(pcm_rec_status_callback, status); 106 + } 107 + 108 + 109 + /* Called by the bottom layer ISR when more data is needed. Returns true 110 + * if a new buffer is available, false otherwise. */ 111 + bool pcm_rec_dma_complete_callback(enum pcm_dma_status status, 112 + void **addr, size_t *size); 113 + 114 + #ifdef HAVE_PCM_REC_DMA_ADDRESS 115 + #define pcm_rec_dma_addr(addr) pcm_dma_addr(addr) 116 + #else 117 + #define pcm_rec_dma_addr(addr) addr 118 + #endif 96 119 97 120 #endif /* HAVE_RECORDING */ 98 121
+18 -13
firmware/export/pcm.h
··· 24 24 #include <string.h> /* size_t */ 25 25 #include "config.h" 26 26 27 - #define DMA_REC_ERROR_DMA (-1) 27 + enum pcm_dma_status 28 + { 28 29 #ifdef HAVE_SPDIF_REC 29 - #define DMA_REC_ERROR_SPDIF (-2) 30 + PCM_DMAST_ERR_SPDIF = -2, 30 31 #endif 32 + PCM_DMAST_ERR_DMA = -1, 33 + PCM_DMAST_OK = 0, 34 + PCM_DMAST_STARTED = 1, 35 + }; 31 36 32 37 /** RAW PCM routines used with playback and recording **/ 33 38 34 - /* Typedef for registered callbacks */ 35 - typedef void (*pcm_play_callback_type)(unsigned char **start, 36 - size_t *size); 37 - typedef void (*pcm_rec_callback_type)(int status, void **start, size_t *size); 39 + /* Typedef for registered data callback */ 40 + typedef void (*pcm_play_callback_type)(const void **start, size_t *size); 41 + 42 + /* Typedef for registered status callback */ 43 + typedef enum pcm_dma_status (*pcm_status_callback_type)(enum pcm_dma_status status); 38 44 39 45 /* set the pcm frequency - use values in hw_sampr_list 40 46 * when CONFIG_SAMPR_TYPES is #defined, or-in SAMPR_TYPE_* fields with ··· 62 68 63 69 /* This is for playing "raw" PCM data */ 64 70 void pcm_play_data(pcm_play_callback_type get_more, 65 - unsigned char* start, size_t size); 71 + pcm_status_callback_type status_cb, 72 + const void *start, size_t size); 66 73 67 74 void pcm_calculate_peaks(int *left, int *right); 68 75 const void* pcm_get_peak_buffer(int* count); ··· 73 80 bool pcm_is_paused(void); 74 81 bool pcm_is_playing(void); 75 82 76 - void pcm_play_set_dma_started_callback(void (* callback)(void)); 77 - 78 83 #ifdef HAVE_RECORDING 79 84 80 85 /** RAW PCM recording routines **/ 81 86 87 + /* Typedef for registered data callback */ 88 + typedef void (*pcm_rec_callback_type)(void **start, size_t *size); 89 + 82 90 /* Reenterable locks for locking and unlocking the recording interrupt */ 83 91 void pcm_rec_lock(void); 84 92 void pcm_rec_unlock(void); ··· 90 98 91 99 /* Start recording "raw" PCM data */ 92 100 void pcm_record_data(pcm_rec_callback_type more_ready, 101 + pcm_status_callback_type status_cb, 93 102 void *start, size_t size); 94 103 95 104 /* Stop tranferring data into supplied buffer */ ··· 97 106 98 107 /* Is pcm currently recording? */ 99 108 bool pcm_is_recording(void); 100 - 101 - /* Called by bottom layer ISR when transfer is complete. Returns non-zero 102 - * size if successful. Setting start to NULL forces stop. */ 103 - void pcm_rec_more_ready_callback(int status, void **start, size_t *size); 104 109 105 110 void pcm_calculate_rec_peaks(int *left, int *right); 106 111
+2 -2
firmware/export/pcm_mixer.h
··· 86 86 /* Start playback on a channel */ 87 87 void mixer_channel_play_data(enum pcm_mixer_channel channel, 88 88 pcm_play_callback_type get_more, 89 - unsigned char *start, size_t size); 89 + const void *start, size_t size); 90 90 91 91 /* Pause or resume a channel (when started) */ 92 92 void mixer_channel_play_pause(enum pcm_mixer_channel channel, bool play); ··· 105 105 size_t mixer_channel_get_bytes_waiting(enum pcm_mixer_channel channel); 106 106 107 107 /* Return pointer to channel's playing audio data and the size remaining */ 108 - void * mixer_channel_get_buffer(enum pcm_mixer_channel channel, int *count); 108 + const void * mixer_channel_get_buffer(enum pcm_mixer_channel channel, int *count); 109 109 110 110 /* Calculate peak values for channel */ 111 111 void mixer_channel_calculate_peaks(enum pcm_mixer_channel channel,
+2
firmware/export/pp5002.h
··· 43 43 #define IISCONFIG (*(volatile unsigned long *)(0xc0002500)) 44 44 #define IISFIFO_CFG (*(volatile unsigned long *)(0xc000251c)) 45 45 #define IISFIFO_WR (*(volatile unsigned long *)(0xc0002540)) 46 + #define IISFIFO_WRH (*(volatile unsigned short *)(0xc0002540)) 46 47 #define IISFIFO_RD (*(volatile unsigned long *)(0xc0002580)) 48 + #define IISFIFO_RDH (*(volatile unsigned short *)(0xc0002540)) 47 49 48 50 /** 49 51 * IISCONFIG bits:
+64 -51
firmware/pcm.c
··· 41 41 * pcm_play_lock 42 42 * pcm_play_unlock 43 43 * Semi-private - 44 - * pcm_play_get_more_callback 44 + * pcm_play_dma_complete_callback 45 + * pcm_play_dma_status_callback 45 46 * pcm_play_dma_init 46 47 * pcm_play_dma_postinit 47 48 * pcm_play_dma_start ··· 66 67 * pcm_rec_lock 67 68 * pcm_rec_unlock 68 69 * Semi-private - 69 - * pcm_rec_more_ready_callback 70 + * pcm_rec_dma_complete_callback 71 + * pcm_rec_dma_status_callback 70 72 * pcm_rec_dma_init 71 73 * pcm_rec_dma_close 72 74 * pcm_rec_dma_start ··· 83 85 /* 'true' when all stages of pcm initialization have completed */ 84 86 static bool pcm_is_ready = false; 85 87 86 - /* the registered callback function to ask for more mp3 data */ 87 - static pcm_play_callback_type pcm_callback_for_more SHAREDBSS_ATTR = NULL; 88 - void (* pcm_play_dma_started)(void) SHAREDBSS_ATTR = NULL; 88 + /* The registered callback function to ask for more mp3 data */ 89 + static volatile pcm_play_callback_type 90 + pcm_callback_for_more SHAREDBSS_ATTR = NULL; 91 + /* The registered callback function to inform of DMA status */ 92 + volatile pcm_status_callback_type 93 + pcm_play_status_callback SHAREDBSS_ATTR = NULL; 89 94 /* PCM playback state */ 90 95 volatile bool pcm_playing SHAREDBSS_ATTR = false; 91 96 /* PCM paused state. paused implies playing */ ··· 104 109 static void pcm_play_stopped(void) 105 110 { 106 111 pcm_callback_for_more = NULL; 107 - pcm_play_dma_started = NULL; 112 + pcm_play_status_callback = NULL; 108 113 pcm_paused = false; 109 114 pcm_playing = false; 110 115 } ··· 258 263 } 259 264 260 265 /* Common code to pcm_play_data and pcm_play_pause */ 261 - static void pcm_play_data_start(unsigned char *start, size_t size) 266 + static void pcm_play_data_start(const void *addr, size_t size) 262 267 { 263 - ALIGN_AUDIOBUF(start, size); 268 + ALIGN_AUDIOBUF(addr, size); 264 269 265 - if (!(start && size)) 270 + if (!(addr && size)) 266 271 { 267 272 pcm_play_callback_type get_more = pcm_callback_for_more; 273 + addr = NULL; 268 274 size = 0; 275 + 269 276 if (get_more) 270 277 { 271 278 logf(" get_more"); 272 - get_more(&start, &size); 273 - ALIGN_AUDIOBUF(start, size); 279 + get_more(&addr, &size); 280 + ALIGN_AUDIOBUF(addr, size); 274 281 } 275 282 } 276 283 277 - if (start && size) 284 + if (addr && size) 278 285 { 279 286 logf(" pcm_play_dma_start"); 280 287 pcm_apply_settings(); 281 - pcm_play_dma_start(start, size); 288 + pcm_play_dma_start(addr, size); 282 289 pcm_playing = true; 283 290 pcm_paused = false; 284 291 return; ··· 291 298 } 292 299 293 300 void pcm_play_data(pcm_play_callback_type get_more, 294 - unsigned char *start, size_t size) 301 + pcm_status_callback_type status_cb, 302 + const void *start, size_t size) 295 303 { 296 304 logf("pcm_play_data"); 297 305 298 306 pcm_play_lock(); 299 307 300 308 pcm_callback_for_more = get_more; 309 + pcm_play_status_callback = status_cb; 301 310 302 311 logf(" pcm_play_data_start"); 303 312 pcm_play_data_start(start, size); ··· 305 314 pcm_play_unlock(); 306 315 } 307 316 308 - void pcm_play_get_more_callback(void **start, size_t *size) 317 + bool pcm_play_dma_complete_callback(enum pcm_dma_status status, 318 + const void **addr, size_t *size) 309 319 { 310 - pcm_play_callback_type get_more = pcm_callback_for_more; 320 + /* Check status callback first if error */ 321 + if (status < PCM_DMAST_OK) 322 + status = pcm_play_dma_status_callback(status); 311 323 312 - *size = 0; 324 + pcm_play_callback_type get_more = pcm_callback_for_more; 313 325 314 - if (get_more && start) 326 + if (get_more && status >= PCM_DMAST_OK) 315 327 { 316 - /* Call registered callback */ 317 - get_more((unsigned char **)start, size); 328 + *addr = NULL; 329 + *size = 0; 318 330 319 - ALIGN_AUDIOBUF(*start, *size); 331 + /* Call registered callback to obtain next buffer */ 332 + get_more(addr, size); 333 + ALIGN_AUDIOBUF(*addr, *size); 320 334 321 - if (*start && *size) 322 - return; 335 + if (*addr && *size) 336 + return true; 323 337 } 324 338 325 339 /* Error, callback missing or no more DMA to do */ 326 340 pcm_play_dma_stop(); 327 341 pcm_play_stopped(); 342 + 343 + return false; 328 344 } 329 345 330 346 void pcm_play_pause(bool play) ··· 428 444 } 429 445 } 430 446 431 - /* register callback to buffer more data */ 432 - void pcm_play_set_dma_started_callback(void (* callback)(void)) 433 - { 434 - pcm_play_dma_started = callback; 435 - } 436 - 437 447 #ifdef HAVE_RECORDING 438 448 /** Low level pcm recording apis **/ 439 449 ··· 442 452 /* the registered callback function for when more data is available */ 443 453 static volatile pcm_rec_callback_type 444 454 pcm_callback_more_ready SHAREDBSS_ATTR = NULL; 455 + volatile pcm_status_callback_type 456 + pcm_rec_status_callback SHAREDBSS_ATTR = NULL; 445 457 /* DMA transfer in is currently active */ 446 458 volatile bool pcm_recording SHAREDBSS_ATTR = false; 447 459 ··· 450 462 { 451 463 pcm_recording = false; 452 464 pcm_callback_more_ready = NULL; 465 + pcm_rec_status_callback = NULL; 453 466 } 454 467 455 468 /** ··· 542 555 } 543 556 544 557 void pcm_record_data(pcm_rec_callback_type more_ready, 545 - void *start, size_t size) 558 + pcm_status_callback_type status_cb, 559 + void *addr, size_t size) 546 560 { 547 561 logf("pcm_record_data"); 548 562 549 - ALIGN_AUDIOBUF(start, size); 563 + ALIGN_AUDIOBUF(addr, size); 550 564 551 - if (!(start && size)) 565 + if (!(addr && size)) 552 566 { 553 567 logf(" no buffer"); 554 568 return; ··· 557 571 pcm_rec_lock(); 558 572 559 573 pcm_callback_more_ready = more_ready; 574 + pcm_rec_status_callback = status_cb; 560 575 561 - #ifdef HAVE_PCM_REC_DMA_ADDRESS 562 576 /* Need a physical DMA address translation, if not already physical. */ 563 - pcm_rec_peak_addr = pcm_dma_addr(start); 564 - #else 565 - pcm_rec_peak_addr = start; 566 - #endif 577 + pcm_rec_peak_addr = pcm_rec_dma_addr(addr); 567 578 568 579 logf(" pcm_rec_dma_start"); 569 580 pcm_apply_settings(); 570 - pcm_rec_dma_start(start, size); 581 + pcm_rec_dma_start(addr, size); 571 582 pcm_recording = true; 572 583 573 584 pcm_rec_unlock(); ··· 589 600 pcm_rec_unlock(); 590 601 } /* pcm_stop_recording */ 591 602 592 - void pcm_rec_more_ready_callback(int status, void **start, size_t *size) 603 + bool pcm_rec_dma_complete_callback(enum pcm_dma_status status, 604 + void **addr, size_t *size) 593 605 { 594 - pcm_rec_callback_type have_more = pcm_callback_more_ready; 606 + /* Check status callback first if error */ 607 + if (status < PCM_DMAST_OK) 608 + status = pcm_rec_dma_status_callback(status); 595 609 596 - *size = 0; 610 + pcm_rec_callback_type have_more = pcm_callback_more_ready; 597 611 598 - if (have_more && start) 612 + if (have_more && status >= PCM_DMAST_OK) 599 613 { 600 - have_more(status, start, size); 601 - ALIGN_AUDIOBUF(*start, *size); 614 + /* Call registered callback to obtain next buffer */ 615 + have_more(addr, size); 616 + ALIGN_AUDIOBUF(*addr, *size); 602 617 603 - if (*start && *size) 618 + if (*addr && *size) 604 619 { 605 - #ifdef HAVE_PCM_REC_DMA_ADDRESS 606 620 /* Need a physical DMA address translation, if not already 607 621 * physical. */ 608 - pcm_rec_peak_addr = pcm_dma_addr(*start); 609 - #else 610 - pcm_rec_peak_addr = *start; 611 - #endif 612 - return; 622 + pcm_rec_peak_addr = pcm_rec_dma_addr(*addr); 623 + return true; 613 624 } 614 625 } 615 626 616 627 /* Error, callback missing or no more DMA to do */ 617 628 pcm_rec_dma_stop(); 618 629 pcm_recording_stopped(); 630 + 631 + return false; 619 632 } 620 633 621 634 #endif /* HAVE_RECORDING */
+20 -15
firmware/pcm_mixer.c
··· 39 39 /* Descriptor for each channel */ 40 40 struct mixer_channel 41 41 { 42 - unsigned char *start; /* Buffer pointer */ 42 + const void *start; /* Buffer pointer */ 43 43 size_t size; /* Bytes remaining */ 44 44 size_t last_size; /* Size of consumed data in prev. cycle */ 45 45 pcm_play_callback_type get_more; /* Registered callback */ ··· 103 103 } 104 104 105 105 /* Main PCM callback - sends the current prepared frame to play */ 106 - static void mixer_pcm_callback(unsigned char **start, size_t *size) 106 + static void mixer_pcm_callback(const void **addr, size_t *size) 107 107 { 108 - *start = (unsigned char *)downmix_buf[downmix_index]; 108 + *addr = downmix_buf[downmix_index]; 109 109 *size = next_size; 110 110 } 111 111 112 112 /* Buffering callback - calls sub-callbacks and mixes the data for next 113 113 buffer to be sent from mixer_pcm_callback() */ 114 - static void MIXER_CALLBACK_ICODE mixer_buffer_callback(void) 114 + static enum pcm_dma_status MIXER_CALLBACK_ICODE 115 + mixer_buffer_callback(enum pcm_dma_status status) 115 116 { 117 + if (status != PCM_DMAST_STARTED) 118 + return status; 119 + 116 120 downmix_index ^= 1; /* Next buffer */ 117 121 118 122 void *mixptr = downmix_buf[downmix_index]; ··· 169 173 170 174 if (LIKELY(!*chan_p)) 171 175 { 172 - write_samples(mixptr, (void *)chan->start, 173 - chan->amplitude, mixsize); 176 + write_samples(mixptr, chan->start, chan->amplitude, mixsize); 174 177 } 175 178 else 176 179 { 177 - void *src0, *src1; 180 + const void *src0, *src1; 178 181 unsigned int amp0, amp1; 179 182 180 183 /* Mix first two channels with each other as the downmix */ ··· 228 231 if (next_size) 229 232 *downmix_buf[downmix_index] = downmix_index ? 0x7fff7fff : 0x80008000; 230 233 #endif 234 + 235 + return PCM_DMAST_OK; 231 236 } 232 237 233 238 /* Start PCM driver if it's not currently playing */ ··· 245 250 pcm_set_frequency(NATIVE_FREQUENCY); 246 251 247 252 /* Prepare initial frames and set up the double buffer */ 248 - mixer_buffer_callback(); 253 + mixer_buffer_callback(PCM_DMAST_STARTED); 249 254 250 255 /* Save the previous call's output */ 251 256 void *start = downmix_buf[downmix_index]; 252 257 253 - mixer_buffer_callback(); 258 + mixer_buffer_callback(PCM_DMAST_STARTED); 254 259 255 - pcm_play_set_dma_started_callback(mixer_buffer_callback); 256 - pcm_play_data(mixer_pcm_callback, start, MIX_FRAME_SIZE); 260 + pcm_play_data(mixer_pcm_callback, mixer_buffer_callback, 261 + start, MIX_FRAME_SIZE); 257 262 } 258 263 259 264 /** Public interfaces **/ ··· 261 266 /* Start playback on a channel */ 262 267 void mixer_channel_play_data(enum pcm_mixer_channel channel, 263 268 pcm_play_callback_type get_more, 264 - unsigned char *start, size_t size) 269 + const void *start, size_t size) 265 270 { 266 271 struct mixer_channel *chan = &channels[channel]; 267 272 ··· 360 365 } 361 366 362 367 /* Return pointer to channel's playing audio data and the size remaining */ 363 - void * mixer_channel_get_buffer(enum pcm_mixer_channel channel, int *count) 368 + const void * mixer_channel_get_buffer(enum pcm_mixer_channel channel, int *count) 364 369 { 365 370 struct mixer_channel *chan = &channels[channel]; 366 - void * buf = *(unsigned char * volatile *)&chan->start; 371 + const void * buf = *(const void * volatile *)&chan->start; 367 372 size_t size = *(size_t volatile *)&chan->size; 368 - void * buf2 = *(unsigned char * volatile *)&chan->start; 373 + const void * buf2 = *(const void * volatile *)&chan->start; 369 374 370 375 /* Still same buffer? */ 371 376 if (buf == buf2)
+12 -8
firmware/target/arm/as3525/pcm-as3525.c
··· 36 36 * and the number of 32bits words has to 37 37 * fit in 11 bits of DMA register */ 38 38 39 - static void *dma_start_addr; /* Pointer to callback buffer */ 39 + static const void *dma_start_addr; /* Pointer to callback buffer */ 40 40 static size_t dma_start_size; /* Size of callback buffer */ 41 - static void *dma_sub_addr; /* Pointer to sub buffer */ 41 + static const void *dma_sub_addr; /* Pointer to sub buffer */ 42 42 static size_t dma_rem_size; /* Remaining size - in 4*32 bits */ 43 43 static size_t play_sub_size; /* size of current subtransfer */ 44 44 static void dma_callback(void); ··· 100 100 101 101 if(!dma_rem_size) 102 102 { 103 - pcm_play_get_more_callback(&dma_start_addr, &dma_start_size); 104 - 105 - if (!dma_start_size) 103 + if(!pcm_play_dma_complete_callback(PCM_DMAST_OK, &dma_start_addr, 104 + &dma_start_size)) 106 105 return; 107 106 108 107 dma_sub_addr = dma_start_addr; ··· 111 110 /* force writeback */ 112 111 commit_dcache_range(dma_start_addr, dma_start_size); 113 112 play_start_pcm(); 114 - pcm_play_dma_started_callback(); 113 + pcm_play_dma_status_callback(PCM_DMAST_STARTED); 115 114 } 116 115 else 117 116 { ··· 123 122 { 124 123 is_playing = true; 125 124 126 - dma_start_addr = (void*)addr; 125 + dma_start_addr = addr; 127 126 dma_start_size = size; 128 127 dma_sub_addr = dma_start_addr; 129 128 dma_rem_size = size; ··· 368 367 } 369 368 } 370 369 371 - pcm_rec_more_ready_callback(0, (void *)&rec_dma_addr, &rec_dma_size); 370 + /* Inform middle layer */ 371 + if (pcm_rec_dma_complete_callback(PCM_DMAST_OK, (void **)&rec_dma_addr, 372 + &rec_dma_size)) 373 + { 374 + pcm_rec_dma_status_callback(PCM_DMAST_STARTED); 375 + } 372 376 } 373 377 374 378
+4 -5
firmware/target/arm/imx233/pcm-imx233.c
··· 49 49 50 50 void INT_DAC_DMA(void) 51 51 { 52 - void *start; 52 + const void *start; 53 53 size_t size; 54 54 55 - pcm_play_get_more_callback(&start, &size); 56 - 57 - if(size != 0) 55 + if (pcm_play_dma_complete_callback(PCM_DMAST_OK, &start, &size)) 58 56 { 59 57 play(start, size); 60 - pcm_play_dma_started_callback(); 58 + pcm_play_dma_status_callback(PCM_DMAST_STARTED); 61 59 } 62 60 63 61 imx233_dma_clear_channel_interrupt(APB_AUDIO_DAC); ··· 65 63 66 64 void INT_DAC_ERROR(void) 67 65 { 66 + /* TODO: Inform of error through pcm_play_dma_complete_callback */ 68 67 } 69 68 70 69 void pcm_play_lock(void)
+56 -63
firmware/target/arm/imx31/gigabeat-s/pcm-gigabeat-s.c
··· 78 78 .state = 0 79 79 }; 80 80 81 - static void play_dma_callback(void) 81 + static void play_start_dma(const void *addr, size_t size) 82 82 { 83 - void *start; 84 - size_t size; 85 - bool rror; 83 + commit_dcache_range(addr, size); 84 + 85 + dma_play_bd.buf_addr = (void *)addr_virt_to_phys((unsigned long)addr); 86 + dma_play_bd.mode.count = size; 87 + dma_play_bd.mode.command = TRANSFER_16BIT; 88 + dma_play_bd.mode.status = BD_DONE | BD_WRAP | BD_INTR; 89 + 90 + sdma_channel_run(DMA_PLAY_CH_NUM); 91 + } 86 92 93 + static void play_dma_callback(void) 94 + { 87 95 if (dma_play_data.locked != 0) 88 96 { 89 97 /* Callback is locked out */ ··· 91 99 return; 92 100 } 93 101 94 - rror = dma_play_bd.mode.status & BD_RROR; 95 - 96 - pcm_play_get_more_callback(rror ? NULL : &start, &size); 97 - 98 - if (size == 0) 99 - return; 100 - 101 - /* Flush any pending cache writes */ 102 - commit_dcache_range(start, size); 103 - dma_play_bd.buf_addr = (void *)addr_virt_to_phys((unsigned long)start); 104 - dma_play_bd.mode.count = size; 105 - dma_play_bd.mode.command = TRANSFER_16BIT; 106 - dma_play_bd.mode.status = BD_DONE | BD_WRAP | BD_INTR; 107 - sdma_channel_run(DMA_PLAY_CH_NUM); 108 - 109 - pcm_play_dma_started_callback(); 102 + /* Inform of status and get new buffer */ 103 + enum pcm_dma_status status = (dma_play_bd.mode.status & BD_RROR) ? 104 + PCM_DMAST_ERR_DMA : PCM_DMAST_OK; 105 + const void *addr; 106 + size_t size; 107 + 108 + if (pcm_play_dma_complete_callback(status, &addr, &size)) 109 + { 110 + play_start_dma(addr, size); 111 + pcm_play_dma_status_callback(PCM_DMAST_STARTED); 112 + } 110 113 } 111 114 112 115 void pcm_play_lock(void) ··· 221 224 if (!sdma_channel_reset(DMA_PLAY_CH_NUM)) 222 225 return; 223 226 224 - commit_dcache_range(addr, size); 225 - dma_play_bd.buf_addr = 226 - (void *)addr_virt_to_phys((unsigned long)(void *)addr); 227 - dma_play_bd.mode.count = size; 228 - dma_play_bd.mode.command = TRANSFER_16BIT; 229 - dma_play_bd.mode.status = BD_DONE | BD_WRAP | BD_INTR; 230 - 227 + /* Begin I2S transmission */ 231 228 play_start_pcm(); 232 - sdma_channel_run(DMA_PLAY_CH_NUM); 229 + 230 + /* Begin DMA transfer */ 231 + play_start_dma(addr, size); 233 232 } 234 233 235 234 void pcm_play_dma_stop(void) ··· 332 331 .state = 0 333 332 }; 334 333 334 + static void rec_start_dma(void *addr, size_t size) 335 + { 336 + discard_dcache_range(addr, size); 337 + 338 + addr = (void *)addr_virt_to_phys((unsigned long)addr); 339 + 340 + dma_rec_bd.buf_addr = addr; 341 + dma_rec_bd.mode.count = size; 342 + dma_rec_bd.mode.command = TRANSFER_16BIT; 343 + dma_rec_bd.mode.status = BD_DONE | BD_WRAP | BD_INTR; 344 + 345 + sdma_channel_run(DMA_REC_CH_NUM); 346 + } 347 + 335 348 static void rec_dma_callback(void) 336 349 { 337 - int status = 0; 338 - void *start; 339 - size_t size; 340 - 341 350 if (dma_rec_data.locked != 0) 342 351 { 343 352 dma_rec_data.callback_pending = dma_rec_data.state; 344 353 return; /* Callback is locked out */ 345 354 } 346 355 347 - if (dma_rec_bd.mode.status & BD_RROR) 348 - status = DMA_REC_ERROR_DMA; 356 + /* Inform middle layer */ 357 + enum pcm_dma_status status = (dma_rec_bd.mode.status & BD_RROR) ? 358 + PCM_DMAST_ERR_DMA : PCM_DMAST_OK; 359 + void *addr; 360 + size_t size; 349 361 350 - pcm_rec_more_ready_callback(status, &start, &size); 351 - 352 - if (size == 0) 353 - return; 354 - 355 - /* Invalidate - buffer must be coherent */ 356 - discard_dcache_range(start, size); 357 - 358 - start = (void *)addr_virt_to_phys((unsigned long)start); 359 - 360 - dma_rec_bd.buf_addr = start; 361 - dma_rec_bd.mode.count = size; 362 - dma_rec_bd.mode.command = TRANSFER_16BIT; 363 - dma_rec_bd.mode.status = BD_DONE | BD_WRAP | BD_INTR; 364 - 365 - sdma_channel_run(DMA_REC_CH_NUM); 362 + if (pcm_rec_dma_complete_callback(status, &addr, &size)) 363 + { 364 + rec_start_dma(addr, size); 365 + pcm_rec_dma_status_callback(PCM_DMAST_STARTED); 366 + } 366 367 } 367 368 368 369 void pcm_rec_lock(void) ··· 426 427 427 428 if (!sdma_channel_reset(DMA_REC_CH_NUM)) 428 429 return; 429 - 430 - /* Invalidate - buffer must be coherent */ 431 - discard_dcache_range(addr, size); 432 430 433 - addr = (void *)addr_virt_to_phys((unsigned long)addr); 434 - dma_rec_bd.buf_addr = addr; 435 - dma_rec_bd.mode.count = size; 436 - dma_rec_bd.mode.command = TRANSFER_16BIT; 437 - dma_rec_bd.mode.status = BD_DONE | BD_WRAP | BD_INTR; 431 + /* Ensure clear FIFO */ 432 + while (SSI_SFCSR1 & SSI_SFCSR_RFCNT0) 433 + SSI_SRX0_1; 438 434 439 435 dma_rec_data.state = 1; /* Check callback on unlock */ 440 436 441 437 SSI_SRCR1 |= SSI_SRCR_RFEN0; /* Enable RX FIFO */ 442 438 443 - /* Ensure clear FIFO */ 444 - while (SSI_SFCSR1 & SSI_SFCSR_RFCNT0) 445 - SSI_SRX0_1; 446 - 447 439 /* Enable receive */ 448 440 SSI_SCR1 |= SSI_SCR_RE; 449 441 SSI_SIER1 |= SSI_SIER_RDMAE; /* Enable DMA req. */ 450 442 451 - sdma_channel_run(DMA_REC_CH_NUM); 443 + /* Begin DMA transfer */ 444 + rec_start_dma(addr, size); 452 445 } 453 446 454 447 void pcm_rec_dma_close(void)
+34 -28
firmware/target/arm/pcm-telechips.c
··· 33 33 { 34 34 /* NOTE: The order of size and p is important if you use assembler 35 35 optimised fiq handler, so don't change it. */ 36 - uint16_t *p; 36 + union 37 + { 38 + uint16_t *p; 39 + const void *p_r; 40 + void *p_w; 41 + }; 37 42 size_t size; 38 43 #if NUM_CORES > 1 39 44 unsigned core; ··· 143 148 144 149 void pcm_play_dma_start(const void *addr, size_t size) 145 150 { 146 - dma_play_data.p = (uint16_t*)addr; 151 + dma_play_data.p_r = addr; 147 152 dma_play_data.size = size; 148 153 149 154 #if NUM_CORES > 1 ··· 248 253 * r0-r3 and r12 is a working register. 249 254 */ 250 255 asm volatile ( 251 - "stmfd sp!, { r0-r4, lr } \n" /* stack scratch regs and lr */ 252 - "mov r4, #0 \n" /* Was the callback called? */ 256 + "sub lr, lr, #4 \n" 257 + "stmfd sp!, { r0-r3, lr } \n" /* stack scratch regs and lr */ 258 + "mov r14, #0 \n" /* Was the callback called? */ 253 259 #if defined(CPU_TCC780X) 254 260 "mov r8, #0xc000 \n" /* DAI_TX_IRQ_MASK | DAI_RX_IRQ_MASK */ 255 261 "ldr r9, =0xf3001004 \n" /* CREQ */ ··· 260 266 "str r8, [r9] \n" /* clear DAI IRQs */ 261 267 "ldmia r11, { r8-r9 } \n" /* r8 = p, r9 = size */ 262 268 "cmp r9, #0x10 \n" /* is size <16? */ 263 - "blt .more_data \n" /* if so, ask pcmbuf for more data */ 269 + "blo .more_data \n" /* if so, ask pcmbuf for more data */ 264 270 265 271 ".fill_fifo: \n" 266 272 "ldr r12, [r8], #4 \n" /* load two samples */ ··· 282 288 "sub r9, r9, #0x10 \n" /* 4 words written */ 283 289 "stmia r11, { r8-r9 } \n" /* save p and size */ 284 290 285 - "cmp r4, #0 \n" /* Callback called? */ 286 - "beq .exit \n" 287 - /* "mov r4, #0 \n" If get_more could be called multiple times! */ 288 - "ldr r2, =pcm_play_dma_started\n" 289 - "ldr r2, [r2] \n" 290 - "cmp r2, #0 \n" 291 - "blxne r2 \n" 291 + "cmp r14, #0 \n" /* Callback called? */ 292 + "ldmeqfd sp!, { r0-r3, pc }^ \n" /* no? -> exit */ 292 293 293 - ".exit: \n" 294 - "ldmfd sp!, { r0-r4, lr } \n" 295 - "subs pc, lr, #4 \n" /* FIQ specific return sequence */ 294 + "ldr r1, =pcm_play_status_callback \n" 295 + "ldr r1, [r1] \n" 296 + "cmp r1, #0 \n" 297 + "movne r0, %1 \n" 298 + "blxne r1 \n" 299 + "ldmfd sp!, { r0-r3, pc }^ \n" /* exit */ 296 300 297 301 ".more_data: \n" 298 - "mov r4, #1 \n" /* Remember we got more data in this FIQ */ 299 - "ldr r2, =pcm_play_get_more_callback \n" 300 - "mov r0, r11 \n" /* r0 = &p */ 301 - "add r1, r11, #4 \n" /* r1 = &size */ 302 - "blx r2 \n" /* call pcm_play_get_more_callback */ 303 - "ldmia r11, { r8-r9 } \n" /* load new p and size */ 304 - "cmp r9, #0x10 \n" /* did we actually get enough data? */ 305 - "bpl .fill_fifo \n" /* not stop and enough? refill */ 306 - "b .exit \n" 302 + "mov r14, #1 \n" /* Remember we got more data in this FIQ */ 303 + "mov r0, %0 \n" /* r0 = status */ 304 + "mov r1, r11 \n" /* r1 = &dma_play_data.p_r */ 305 + "add r2, r11, #4 \n" /* r2 = &dma_play_data.size */ 306 + "mov lr, pc \n" 307 + "ldr pc, =pcm_play_dma_complete_callback \n" 308 + "cmp r0, #0 \n" /* any more to play? */ 309 + "ldmneia r11, { r8-r9 } \n" /* load new p and size */ 310 + "cmpne r9, #0x0f \n" /* did we actually get enough data? */ 311 + "bhi .fill_fifo \n" /* not stop and enough? refill */ 312 + "ldmfd sp!, { r0-r3, pc }^ \n" /* exit */ 307 313 ".ltorg \n" 314 + : : "i"(PCM_DMAST_OK), "i"(PCM_DMAST_STARTED) 308 315 ); 309 316 } 310 317 #else /* C version for reference */ ··· 316 323 if (dma_play_data.size < 16) 317 324 { 318 325 /* p is empty, get some more data */ 319 - new_buffer = true; 320 - pcm_play_get_more_callback((void**)&dma_play_data.p, 321 - &dma_play_data.size); 326 + new_buffer = pcm_play_dma_complete_callback(&dma_play_data.p_r, 327 + &dma_play_data.size); 322 328 } 323 329 324 330 if (dma_play_data.size >= 16) ··· 339 345 CREQ = DAI_TX_IRQ_MASK | DAI_RX_IRQ_MASK; 340 346 341 347 if (new_buffer) 342 - pcm_play_dma_started_callback(); 348 + pcm_play_dma_status_callback(PCM_DMAST_STARTED); 343 349 } 344 350 #endif 345 351
+6 -8
firmware/target/arm/pnx0101/pcm-pnx0101.c
··· 28 28 short __attribute__((section(".dmabuf"))) dma_buf_left[DMA_BUF_SAMPLES]; 29 29 short __attribute__((section(".dmabuf"))) dma_buf_right[DMA_BUF_SAMPLES]; 30 30 31 - unsigned short* p IBSS_ATTR; 31 + const int16_t* p IBSS_ATTR; 32 32 size_t p_size IBSS_ATTR; 33 33 34 34 void pcm_play_lock(void) ··· 41 41 42 42 void pcm_play_dma_start(const void *addr, size_t size) 43 43 { 44 - p = (unsigned short*)addr; 44 + p = addr; 45 45 p_size = size; 46 46 } 47 47 ··· 69 69 do 70 70 { 71 71 int count; 72 - unsigned short *tmp_p; 72 + const int16_t *tmp_p; 73 73 count = MIN(p_size / 4, (size_t)(lend - l)); 74 74 tmp_p = p; 75 75 p_size -= count * 4; ··· 109 109 if (new_buffer) 110 110 { 111 111 new_buffer = false; 112 - pcm_play_dma_started_callback(); 112 + pcm_play_dma_status_callback(PCM_DMAST_STARTED); 113 113 } 114 114 115 115 if (l >= lend) 116 116 return; 117 117 118 - pcm_play_get_more_callback((void**)&p, &p_size); 119 - 120 - if (p_size) 121 - new_buffer = true; 118 + new_buffer = pcm_play_dma_complete_callback(PCM_DMAST_OK, 119 + &p, &p_size); 122 120 } 123 121 while (p_size); 124 122 }
+307 -306
firmware/target/arm/pp/pcm-pp.c
··· 30 30 31 31 /** DMA **/ 32 32 33 - #ifdef CPU_PP502x 34 - /* 16-bit, L-R packed into 32 bits with left in the least significant halfword */ 35 - #define SAMPLE_SIZE 16 36 - /* DMA Requests from IIS, Memory to peripheral, single transfer, 37 - wait for DMA request, interrupt on complete */ 38 - #define DMA_PLAY_CONFIG ((DMA_REQ_IIS << DMA_CMD_REQ_ID_POS) | \ 39 - DMA_CMD_RAM_TO_PER | DMA_CMD_SINGLE | \ 40 - DMA_CMD_WAIT_REQ | DMA_CMD_INTR) 41 - /* DMA status cannot be viewed from outside code in control because that can 42 - * clear the interrupt from outside the handler and prevent the handler from 43 - * from being called. Split up transfers to a reasonable size that is good as 44 - * a timer, obtaining a keyclick position and peaking yet still keeps the 45 - * FIQ count low. 46 - */ 47 - #define MAX_DMA_CHUNK_SIZE (pcm_curr_sampr >> 6) /* ~1/256 seconds */ 48 - #else 49 - /* 32-bit, one left 32-bit sample followed by one right 32-bit sample */ 50 - #define SAMPLE_SIZE 32 51 - #endif 52 - 53 33 struct dma_data 54 34 { 55 35 /* NOTE: The order of size and p is important if you use assembler ··· 57 37 union 58 38 { 59 39 unsigned long addr; 40 + const void *p_r; 41 + void *p_w; 60 42 uint32_t *p16; /* For packed 16-16 stereo pairs */ 61 43 uint16_t *p32; /* For individual samples converted to 32-bit */ 62 44 }; ··· 113 95 } 114 96 115 97 #if defined(CPU_PP502x) 116 - /* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */ 117 - void ICODE_ATTR __attribute__((interrupt("FIQ"))) fiq_playback(void) 98 + /* 16-bit, L-R packed into 32 bits with left in the least significant halfword */ 99 + #define SAMPLE_SIZE 16 100 + /* DMA Requests from IIS, Memory to peripheral, single transfer, 101 + wait for DMA request, interrupt on complete */ 102 + #define DMA_PLAY_CONFIG ((DMA_REQ_IIS << DMA_CMD_REQ_ID_POS) | \ 103 + DMA_CMD_RAM_TO_PER | DMA_CMD_SINGLE | \ 104 + DMA_CMD_WAIT_REQ | DMA_CMD_INTR) 105 + /* DMA status cannot be viewed from outside code in control because that can 106 + * clear the interrupt from outside the handler and prevent the handler from 107 + * from being called. Split up transfers to a reasonable size that is good as 108 + * a timer and peaking yet still keeps the FIQ count low. 109 + */ 110 + #define MAX_DMA_CHUNK_SIZE (pcm_curr_sampr >> 6) /* ~1/256 seconds */ 111 + 112 + static inline void dma_tx_init(void) 113 + { 114 + /* Enable DMA controller */ 115 + DMA_MASTER_CONTROL |= DMA_MASTER_CONTROL_EN; 116 + /* FIQ priority for DMA */ 117 + CPU_INT_PRIORITY |= DMA_MASK; 118 + /* Enable request?? Not setting or clearing everything doesn't seem to 119 + * prevent it operating. Perhaps important for reliability (how requests 120 + * are handled). */ 121 + DMA_REQ_STATUS |= 1ul << DMA_REQ_IIS; 122 + DMA0_STATUS; 123 + } 124 + 125 + static inline void dma_tx_setup(void) 118 126 { 119 - bool new_buffer = false; 120 - register size_t size; 127 + /* Setup DMA controller */ 128 + DMA0_PER_ADDR = (unsigned long)&IISFIFO_WR; 129 + DMA0_FLAGS = DMA_FLAGS_UNK26; 130 + DMA0_INCR = DMA_INCR_RANGE_FIXED | DMA_INCR_WIDTH_32BIT; 131 + } 121 132 133 + static inline unsigned long dma_tx_buf_prepare(const void *addr) 134 + { 135 + unsigned long a = (unsigned long)addr; 136 + 137 + if (a < UNCACHED_BASE_ADDR) { 138 + /* VA in DRAM - writeback all data and get PA */ 139 + a = UNCACHED_ADDR(a); 140 + commit_dcache(); 141 + } 142 + 143 + return a; 144 + } 145 + 146 + static inline void dma_tx_start(bool begin) 147 + { 148 + size_t size = MAX_DMA_CHUNK_SIZE; 149 + 150 + /* Not at least MAX_DMA_CHUNK_SIZE left or there would be less 151 + * than a FIFO's worth of data after this transfer? */ 152 + if (size + 16*4 > dma_play_data.size) 153 + size = dma_play_data.size; 154 + 155 + /* Set the new DMA values and activate channel */ 156 + DMA0_RAM_ADDR = dma_play_data.addr; 157 + DMA0_CMD = DMA_PLAY_CONFIG | (size - 4) | DMA_CMD_START; 158 + 159 + (void)begin; 160 + } 161 + 162 + static void dma_tx_stop(void) 163 + { 164 + unsigned long status = DMA0_STATUS; /* Snapshot- resume from this point */ 165 + unsigned long cmd = DMA0_CMD; 166 + size_t size = 0; 167 + 168 + /* Stop transfer */ 169 + DMA0_CMD = cmd & ~(DMA_CMD_START | DMA_CMD_INTR); 170 + 171 + /* Wait for not busy + clear int */ 172 + while (DMA0_STATUS & (DMA_STATUS_BUSY | DMA_STATUS_INTR)); 173 + 174 + if (status & DMA_STATUS_BUSY) { 175 + /* Transfer was interrupted - leave what's left */ 176 + size = (cmd & 0xfffc) - (status & 0xfffc); 177 + } 178 + else if (status & DMA_STATUS_INTR) { 179 + /* Transfer was finished - DMA0_STATUS will have been reloaded 180 + * automatically with size in DMA0_CMD. Setup to restart on next 181 + * segment. */ 182 + size = (cmd & 0xfffc) + 4; 183 + } 184 + /* else not an active state - size = 0 */ 185 + 186 + dma_play_data.addr += size; 187 + dma_play_data.size -= size; 188 + 189 + if (dma_play_data.size == 0) 190 + dma_play_data.addr = 0; /* Entire buffer has completed. */ 191 + } 192 + 193 + static inline void dma_tx_lock(void) 194 + { 195 + CPU_INT_DIS = DMA_MASK; 196 + } 197 + 198 + static inline void dma_tx_unlock(void) 199 + { 200 + CPU_INT_EN = DMA_MASK; 201 + } 202 + 203 + /* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */ 204 + void fiq_playback(void) ICODE_ATTR __attribute__((interrupt("FIQ"))); 205 + void fiq_playback(void) 206 + { 122 207 DMA0_STATUS; /* Clear any pending interrupt */ 123 208 124 - size = (DMA0_CMD & 0xffff) + 4; /* Get size of trasfer that caused this 125 - interrupt */ 209 + size_t size = (DMA0_CMD & 0xffff) + 4; /* Get size of trasfer that caused 210 + this interrupt */ 126 211 dma_play_data.addr += size; 127 212 dma_play_data.size -= size; 128 213 129 - while (1) 130 - { 131 - if (dma_play_data.size > 0) { 132 - size = MAX_DMA_CHUNK_SIZE; 133 - /* Not at least MAX_DMA_CHUNK_SIZE left or there would be less 134 - * than a FIFO's worth of data after this transfer? */ 135 - if (size + 16*4 > dma_play_data.size) 136 - size = dma_play_data.size; 214 + if (LIKELY(dma_play_data.size != 0)) { 215 + /* Begin next segment */ 216 + dma_tx_start(false); 217 + } 218 + else if (pcm_play_dma_complete_callback(PCM_DMAST_OK, &dma_play_data.p_r, 219 + &dma_play_data.size)) { 220 + dma_play_data.addr = dma_tx_buf_prepare(dma_play_data.p_r); 221 + dma_tx_start(false); 222 + pcm_play_dma_status_callback(PCM_DMAST_STARTED); 223 + } 224 + } 225 + 226 + #else /* !defined (CPU_PP502x) */ 227 + 228 + /* 32-bit, one left 32-bit sample followed by one right 32-bit sample */ 229 + #define SAMPLE_SIZE 32 230 + 231 + static void dma_tx_init(void) 232 + { 233 + /* Set up banked registers for FIQ mode */ 234 + 235 + /* Use non-banked registers for scratch. */ 236 + register volatile void *iiscfg asm("r0") = &IISCONFIG; 237 + register volatile void *dmapd asm("r1") = &dma_play_data; 238 + 239 + asm volatile ( 240 + "mrs r2, cpsr \n" /* Save mode and interrupt status */ 241 + "msr cpsr_c, #0xd1 \n" /* Switch to FIQ mode */ 242 + "mov r8, #0 \n" 243 + "mov r9, #0 \n" 244 + "mov r10, %[iiscfg] \n" 245 + "mov r11, %[dmapd] \n" 246 + "msr cpsr_c, r2 \n" 247 + : 248 + : [iiscfg]"r"(iiscfg), [dmapd]"r"(dmapd) 249 + : "r2"); 137 250 138 - /* Set the new DMA values and activate channel */ 139 - DMA0_RAM_ADDR = dma_play_data.addr; 140 - DMA0_CMD = DMA_PLAY_CONFIG | (size - 4) | DMA_CMD_START; 251 + /* FIQ priority for I2S */ 252 + CPU_INT_PRIORITY |= IIS_MASK; 253 + CPU_INT_EN = IIS_MASK; 254 + } 141 255 142 - if (new_buffer) 143 - pcm_play_dma_started_callback(); 144 - return; 145 - } 256 + static inline void dma_tx_setup(void) 257 + { 258 + /* Nothing to do */ 259 + } 146 260 147 - new_buffer = true; 261 + static inline unsigned long dma_tx_buf_prepare(const void *addr) 262 + { 263 + return (unsigned long)addr; 264 + } 148 265 149 - /* Buffer empty. Try to get more. */ 150 - pcm_play_get_more_callback((void **)&dma_play_data.addr, 151 - &dma_play_data.size); 266 + static inline void dma_tx_start(bool begin) 267 + { 268 + if (begin) { 269 + IISCONFIG &= ~IIS_TXFIFOEN; /* Stop transmitting */ 270 + } 152 271 153 - if (dma_play_data.size == 0) { 154 - /* No more data */ 155 - return; 156 - } 272 + /* Fill the FIFO or start when data is used up */ 273 + while (IIS_TX_FREE_COUNT >= 2 && dma_play_data.size != 0) { 274 + IISFIFO_WRH = *dma_play_data.p32++; 275 + IISFIFO_WRH = *dma_play_data.p32++; 276 + dma_play_data.size -= 4; 277 + } 157 278 158 - if (dma_play_data.addr < UNCACHED_BASE_ADDR) { 159 - /* Flush any pending cache writes */ 160 - dma_play_data.addr = UNCACHED_ADDR(dma_play_data.addr); 161 - commit_dcache(); 162 - } 279 + if (begin) { 280 + IISCONFIG |= IIS_TXFIFOEN; /* Start transmitting */ 163 281 } 164 282 } 165 - #else 283 + 284 + static inline void dma_tx_stop(void) 285 + { 286 + /* Disable TX interrupt */ 287 + IIS_IRQTX_REG &= ~IIS_IRQTX; 288 + } 289 + 290 + static inline void dma_tx_lock(void) 291 + { 292 + IIS_IRQTX_REG &= ~IIS_IRQTX; 293 + } 294 + 295 + static inline void dma_tx_unlock(void) 296 + { 297 + IIS_IRQTX_REG |= IIS_IRQTX; 298 + } 299 + 166 300 /* ASM optimised FIQ handler. Checks for the minimum allowed loop cycles by 167 301 * evalutation of free IISFIFO-slots against available source buffer words. 168 302 * Through this it is possible to move the check for IIS_TX_FREE_COUNT outside ··· 173 307 * ASM implementation (not used anymore): GCC fails to make use of the fact 174 308 * that FIQ mode has registers r8-r14 banked, and so does not need to be saved. 175 309 * This routine uses only these registers, and so will never touch the stack 176 - * unless it actually needs to do so when calling pcm_callback_for_more. 310 + * unless it actually needs to do so when calling pcm_play_dma_complete_callback. 177 311 * C version is still included below for reference and testing. 178 312 */ 179 313 #if 1 180 314 void fiq_playback(void) ICODE_ATTR __attribute__((naked)); 181 315 void fiq_playback(void) 182 316 { 183 - /* r10 contains IISCONFIG address (set in crt0.S to minimise code in actual 184 - * FIQ handler. r11 contains address of p (also set in crt0.S). Most other 185 - * addresses we need are generated by using offsets with these two. 186 - * r10 + 0x40 is IISFIFO_WR, and r10 + 0x0c is IISFIFO_CFG. 187 - * r8 and r9 contains local copies of p and size respectively. 188 - * r0-r3 and r12 is a working register. 317 + /* r8 and r9 contains local copies of p and size respectively. 318 + * r10 contains IISCONFIG address (set during PCM init to minimize code in 319 + * FIQ handler.Most other addresses we need are generated by using offsets 320 + * from this. 321 + * r10 + 0x40 is IISFIFO_WR, and r10 + 0x1c is IISFIFO_CFG. 322 + * r11 contains address of dma_play_data 323 + * r12 and r14 are working registers. 324 + * 325 + * Divided into two blocks: one where no external calls are needed and 326 + * one where external callbacks are made 189 327 */ 190 328 asm volatile ( 191 - "stmfd sp!, { r0-r4, lr } \n" /* stack scratch regs and lr */ 329 + /* No external calls */ 330 + "sub lr, lr, #4 \n" /* Prepare return address */ 331 + "stmfd sp!, { lr } \n" /* stack lr so we can use it */ 332 + "ldr r12, =0xcf001040 \n" /* Some magic from iPodLinux ... */ 333 + "ldr r12, [r12] \n" /* ... actually a DMA INT ack? */ 334 + "ldmia r11, { r8-r9 } \n" /* r8 = p, r9 = size */ 335 + "cmp r9, #0 \n" /* is size 0? */ 336 + "beq 1f \n" /* if so, ask PCM for more data */ 192 337 193 - "mov r4, #0 \n" /* Was the callback called? */ 194 - #if CONFIG_CPU == PP5002 195 - "ldr r12, =0xcf001040 \n" /* Some magic from iPodLinux */ 196 - "ldr r12, [r12] \n" 197 - #endif 198 - "ldmia r11, { r8-r9 } \n" /* r8 = p, r9 = size */ 199 - "cmp r9, #0 \n" /* is size 0? */ 200 - "beq .more_data \n" /* if so, ask pcmbuf for more data */ 338 + "ldr r14, [r10, #0x1c] \n" /* read IISFIFO_CFG to check FIFO status */ 339 + "and r14, r14, #(0xe<<23) \n" /* r14 = (IIS_TX_FREE_COUNT & ~1) << 23 */ 340 + "cmp r9, r14, lsr #22 \n" /* number of words from source */ 341 + "movlo r14, r9, lsl #22 \n" /* r14 = amount of allowed loops */ 342 + "sub r9, r9, r14, lsr #22 \n" /* r14 words will be written in loop */ 343 + "0: \n" 344 + "ldr r12, [r8], #4 \n" /* load left-right pair */ 345 + "subs r14, r14, #(0x2<<23) \n" /* one more loop? ... */ 346 + "strh r12, [r10, #0x40] \n" /* left sample to IISFIFO_WR */ 347 + "mov r12, r12, lsr #16 \n" /* put right sample in bottom 16 bits */ 348 + "strh r12, [r10, #0x40] \n" /* right sample to IISFIFO_WR */ 349 + "bhi 0b \n" /* ... yes, continue */ 201 350 202 - #if SAMPLE_SIZE == 16 203 - ".check_fifo: \n" 204 - "ldr r0, [r10, %[cfg]] \n" /* read IISFIFO_CFG to check FIFO status */ 205 - "and r0, r0, %[mask] \n" /* r0 = IIS_TX_FREE_COUNT << 16 (PP502x) */ 351 + "cmp r9, #0 \n" /* either FIFO full or size empty? */ 352 + "stmneia r11, { r8-r9 } \n" /* save p and size, if not empty */ 353 + "ldmnefd sp!, { pc }^ \n" /* RFE if not empty */ 206 354 207 - "mov r1, r0, lsr #16 \n" /* number of free FIFO slots */ 208 - "cmp r1, r9, lsr #2 \n" /* number of words from source */ 209 - "movgt r1, r9, lsr #2 \n" /* r1 = amount of allowed loops */ 210 - "sub r9, r9, r1, lsl #2 \n" /* r1 words will be written in following loop */ 355 + /* Making external calls */ 356 + "1: \n" 357 + "stmfd sp!, { r0-r3 } \n" /* Must save volatiles */ 358 + "2: \n" 359 + "mov r0, %0 \n" /* r0 = status */ 360 + "mov r1, r11 \n" /* r1 = &dma_play_data.p_r */ 361 + "add r2, r11, #4 \n" /* r2 = &dma_play_data.size */ 362 + "ldr r3, =pcm_play_dma_complete_callback \n" 363 + "mov lr, pc \n" /* long call (not in same section) */ 364 + "bx r3 \n" 365 + "cmp r0, #0 \n" /* more data? */ 366 + "ldmeqfd sp!, { r0-r3, pc }^ \n" /* no? -> exit */ 211 367 212 - "subs r1, r1, #2 \n" 213 - ".fifo_loop_2: \n" 214 - "ldmgeia r8!, {r2, r12} \n" /* load four samples */ 215 - "strge r2 , [r10, %[wr]] \n" /* write sample 0-1 to IISFIFO_WR */ 216 - "strge r12, [r10, %[wr]] \n" /* write sample 2-3 to IISFIFO_WR */ 217 - "subges r1, r1, #2 \n" /* one more loop? */ 218 - "bge .fifo_loop_2 \n" /* yes, continue */ 368 + "ldr r14, [r10, #0x1c] \n" /* read IISFIFO_CFG to check FIFO status */ 369 + "ands r14, r14, #(0xe<<23) \n" /* r14 = (IIS_TX_FREE_COUNT & ~1) << 23 */ 370 + "bne 4f \n" 371 + "3: \n" /* inform of started status if registered */ 372 + "ldr r1, =pcm_play_status_callback \n" 373 + "ldr r1, [r1] \n" 374 + "cmp r1, #0 \n" 375 + "movne r0, %1 \n" 376 + "movne lr, pc \n" 377 + "bxne r1 \n" 378 + "ldmfd sp!, { r0-r3, pc }^ \n" /* exit */ 379 + "4: \n" 380 + "ldmia r11, { r8-r9 } \n" /* load new p and size */ 381 + "cmp r9, r14, lsr #22 \n" /* number of words from source */ 382 + "movlo r14, r9, lsl #22 \n" /* r14 = amount of allowed loops */ 383 + "sub r9, r9, r14, lsr #22 \n" /* r14 words will be written in loop */ 384 + "0: \n" 385 + "ldr r12, [r8], #4 \n" /* load left-right pair */ 386 + "subs r14, r14, #(0x2<<23) \n" /* one more loop? ... */ 387 + "strh r12, [r10, #0x40] \n" /* left sample to IISFIFO_WR */ 388 + "mov r12, r12, lsr #16 \n" /* put right sample in bottom 16 bits */ 389 + "strh r12, [r10, #0x40] \n" /* right sample to IISFIFO_WR */ 390 + "bhi 0b \n" /* ... yes, continue */ 391 + "stmia r11, { r8-r9 } \n" /* save p and size */ 219 392 220 - "tst r1, #1 \n" /* two samples (one word) left? */ 221 - "ldrne r12, [r8], #4 \n" /* load two samples */ 222 - "strne r12, [r10, %[wr]] \n" /* write sample 0-1 to IISFIFO_WR */ 223 - #elif SAMPLE_SIZE == 32 224 - ".check_fifo: \n" 225 - "ldr r0, [r10, %[cfg]] \n" /* read IISFIFO_CFG to check FIFO status */ 226 - "and r0, r0, %[mask] \n" /* r0 = IIS_TX_FREE_COUNT << 23 (PP5002) */ 227 - 228 - "movs r1, r0, lsr #24 \n" /* number of free pairs of FIFO slots */ 229 - "beq .fifo_fill_complete \n" /* no complete pair? -> exit */ 230 - "cmp r1, r9, lsr #2 \n" /* number of words from source */ 231 - "movgt r1, r9, lsr #2 \n" /* r1 = amount of allowed loops */ 232 - "sub r9, r9, r1, lsl #2 \n" /* r1 words will be written in following loop */ 233 - 234 - ".fifo_loop: \n" 235 - "ldr r12, [r8], #4 \n" /* load two samples */ 236 - "mov r2 , r12, lsl #16 \n" /* put left sample at the top bits */ 237 - "str r2 , [r10, %[wr]] \n" /* write top sample to IISFIFO_WR */ 238 - "str r12, [r10, %[wr]] \n" /* write low sample to IISFIFO_WR*/ 239 - "subs r1, r1, #1 \n" /* one more loop? */ 240 - "bgt .fifo_loop \n" /* yes, continue */ 241 - 242 - ".fifo_fill_complete: \n" 243 - #endif 244 - "cmp r4, #0 \n" /* If fill came after get_more... */ 245 - "beq .still_old_buffer \n" 246 - "mov r4, #0 \n" 247 - "ldr r2, =pcm_play_dma_started \n" 248 - "ldrne r2, [r2] \n" 249 - "cmp r2, #0 \n" 250 - "movne lr, pc \n" 251 - "bxne r2 \n" 252 - 253 - ".still_old_buffer: \n" 254 - "cmp r9, #0 \n" /* either FIFO is full or source buffer is empty */ 255 - "bgt .exit \n" /* if source buffer is not empty, FIFO must be full */ 256 - 257 - ".more_data: \n" 258 - "mov r4, #1 \n" /* Remember we did this */ 259 - "ldr r2, =pcm_play_get_more_callback \n" 260 - "mov r0, r11 \n" /* r0 = &p */ 261 - "add r1, r11, #4 \n" /* r1 = &size */ 262 - "mov lr, pc \n" /* call pcm_play_get_more_callback */ 263 - "bx r2 \n" 264 - "ldmia r11, { r8-r9 } \n" /* load new p and size */ 265 - "cmp r9, #0 \n" 266 - "bne .check_fifo \n" /* size != 0? refill */ 267 - 268 - ".exit: \n" /* (r9=0 if stopping, look above) */ 269 - "stmia r11, { r8-r9 } \n" /* save p and size */ 270 - "ldmfd sp!, { r0-r4, lr } \n" 271 - "subs pc, lr, #4 \n" /* FIQ specific return sequence */ 272 - ".ltorg \n" 393 + "cmp r9, #0 \n" /* used up data in FIFO fill? */ 394 + "bne 3b \n" /* no? -> go return */ 395 + "b 2b \n" /* yes -> get even more */ 396 + ".ltorg \n" 273 397 : /* These must only be integers! No regs */ 274 - : [mask]"i"(IIS_TX_FREE_MASK), 275 - [cfg]"i"((int)&IISFIFO_CFG - (int)&IISCONFIG), 276 - [wr]"i"((int)&IISFIFO_WR - (int)&IISCONFIG) 277 - ); 398 + : "i"(PCM_DMAST_OK), "i"(PCM_DMAST_STARTED)); 278 399 } 400 + 279 401 #else /* C version for reference */ 280 - void fiq_playback(void) __attribute__((interrupt ("FIQ"))) ICODE_ATTR; 402 + 281 403 /* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */ 404 + void fiq_playback(void) ICODE_ATTR __attribute__((interrupt ("FIQ"))); 282 405 void fiq_playback(void) 283 406 { 284 - bool new_buffer = false; 285 - 286 - #if CONFIG_CPU == PP5002 287 407 inl(0xcf001040); 288 - #endif 289 408 290 - do { 291 - while (dma_play_data.size > 0) { 292 - if (IIS_TX_FREE_COUNT < 2) { 293 - if (new_buffer) { 294 - new_buffer = false; 295 - pcm_play_dma_started_callback(); 296 - } 297 - return; 298 - } 299 - #if SAMPLE_SIZE == 16 300 - IISFIFO_WR = *dma_play_data.p16++; 301 - #elif SAMPLE_SIZE == 32 302 - IISFIFO_WR = *dma_play_data.p32++ << 16; 303 - IISFIFO_WR = *dma_play_data.p32++ << 16; 304 - #endif 305 - dma_play_data.size -= 4; 306 - } 409 + if (LIKELY(dma_play_data.size != 0)) { 410 + dma_tx_start(false); 307 411 308 - if (new_buffer) { 309 - new_buffer = false; 310 - pcm_play_dma_started_callback(); 412 + if (dma_play_data.size != 0) { 413 + /* Still more data */ 414 + return; 311 415 } 416 + } 312 417 313 - /* p is empty, get some more data */ 314 - pcm_play_get_more_callback((void **)&dma_play_data.addr, 315 - &dma_play_data.size); 316 - new_buffer = true; 317 - } while (dma_play_data.size); 418 + while (pcm_play_dma_complete_callback(PCM_DMAST_OK, &dma_play_data.p_r, 419 + &dma_play_data.size)) { 420 + dma_tx_start(false); 421 + pcm_play_dma_status_callback(PCM_DMAST_STARTED); 318 422 319 - /* No more data */ 423 + if (dma_play_data.size != 0) { 424 + return; 425 + } 426 + } 320 427 } 321 428 #endif /* ASM / C selection */ 322 429 #endif /* CPU_PP502x */ ··· 329 436 int status = disable_fiq_save(); 330 437 331 438 if (++dma_play_data.locked == 1) { 332 - #ifdef CPU_PP502x 333 - CPU_INT_DIS = DMA_MASK; 334 - #else 335 - IIS_IRQTX_REG &= ~IIS_IRQTX; 336 - #endif 439 + dma_tx_lock(); 337 440 } 338 441 339 442 restore_fiq(status); ··· 341 444 342 445 void pcm_play_unlock(void) 343 446 { 344 - int status = disable_fiq_save(); 447 + int status = disable_fiq_save(); 345 448 346 449 if (--dma_play_data.locked == 0 && dma_play_data.state != 0) { 347 - #ifdef CPU_PP502x 348 - CPU_INT_EN = DMA_MASK; 349 - #else 350 - IIS_IRQTX_REG |= IIS_IRQTX; 351 - #endif 450 + dma_tx_unlock(); 352 451 } 353 452 354 - restore_fiq(status); 453 + restore_fiq(status); 355 454 } 356 455 357 456 static void play_start_pcm(void) 358 457 { 359 458 fiq_function = fiq_playback; 360 - 361 - #ifdef CPU_PP502x 362 - /* Not at least MAX_DMA_CHUNK_SIZE left or there would be less than a 363 - * FIFO's worth of data after this transfer? */ 364 - size_t size = MAX_DMA_CHUNK_SIZE; 365 - if (size + 16*4 > dma_play_data.size) 366 - size = dma_play_data.size; 367 - 368 - DMA0_RAM_ADDR = dma_play_data.addr; 369 - DMA0_CMD = DMA_PLAY_CONFIG | (size - 4) | DMA_CMD_START; 370 459 dma_play_data.state = 1; 371 - #else 372 - IISCONFIG &= ~IIS_TXFIFOEN; /* Stop transmitting */ 373 - 374 - /* Fill the FIFO or start when data is used up */ 375 - while (1) { 376 - if (IIS_TX_FREE_COUNT < 2 || dma_play_data.size == 0) { 377 - IISCONFIG |= IIS_TXFIFOEN; /* Start transmitting */ 378 - dma_play_data.state = 1; 379 - return; 380 - } 381 - 382 - #if SAMPLE_SIZE == 16 383 - IISFIFO_WR = *dma_play_data.p16++; 384 - #elif SAMPLE_SIZE == 32 385 - IISFIFO_WR = *dma_play_data.p32++ << 16; 386 - IISFIFO_WR = *dma_play_data.p32++ << 16; 387 - #endif 388 - dma_play_data.size -= 4; 389 - } 390 - #endif 460 + dma_tx_start(true); 391 461 } 392 462 393 463 static void play_stop_pcm(void) 394 464 { 395 - #ifdef CPU_PP502x 396 - unsigned long status = DMA0_STATUS; /* Snapshot- resume from this point */ 397 - unsigned long cmd = DMA0_CMD; 398 - size_t size = 0; 399 - 400 - /* Stop transfer */ 401 - DMA0_CMD = cmd & ~(DMA_CMD_START | DMA_CMD_INTR); 402 - 403 - /* Wait for not busy + clear int */ 404 - while (DMA0_STATUS & (DMA_STATUS_BUSY | DMA_STATUS_INTR)); 405 - 406 - if (status & DMA_STATUS_BUSY) { 407 - /* Transfer was interrupted - leave what's left */ 408 - size = (cmd & 0xfffc) - (status & 0xfffc); 409 - } 410 - else if (status & DMA_STATUS_INTR) { 411 - /* Transfer was finished - DMA0_STATUS will have been reloaded 412 - * automatically with size in DMA0_CMD. Setup to restart on next 413 - * segment. */ 414 - size = (cmd & 0xfffc) + 4; 415 - } 416 - /* else not an active state - size = 0 */ 417 - 418 - dma_play_data.addr += size; 419 - dma_play_data.size -= size; 420 - 421 - if (dma_play_data.size == 0) 422 - dma_play_data.addr = 0; /* Entire buffer has completed. */ 423 - #else 424 - /* Disable TX interrupt */ 425 - IIS_IRQTX_REG &= ~IIS_IRQTX; 426 - #endif 465 + dma_tx_stop(); 427 466 428 467 /* Wait for FIFO to empty */ 429 468 while (!IIS_TX_IS_EMPTY); ··· 433 472 434 473 void pcm_play_dma_start(const void *addr, size_t size) 435 474 { 475 + pcm_play_dma_stop(); 476 + 436 477 #if NUM_CORES > 1 437 478 /* This will become more important later - and different ! */ 438 479 dma_play_data.core = processor_id(); /* save initiating core */ 439 480 #endif 440 481 441 - pcm_play_dma_stop(); 442 - 443 - #ifdef CPU_PP502x 444 - if ((unsigned long)addr < UNCACHED_BASE_ADDR) { 445 - /* Flush any pending cache writes */ 446 - addr = UNCACHED_ADDR(addr); 447 - commit_dcache(); 448 - } 482 + dma_tx_setup(); 449 483 450 - dma_play_data.addr = (unsigned long)addr; 484 + dma_play_data.addr = dma_tx_buf_prepare(addr); 451 485 dma_play_data.size = size; 452 - DMA0_PER_ADDR = (unsigned long)&IISFIFO_WR; 453 - DMA0_FLAGS = DMA_FLAGS_UNK26; 454 - DMA0_INCR = DMA_INCR_RANGE_FIXED | DMA_INCR_WIDTH_32BIT; 455 - #else 456 - dma_play_data.addr = (unsigned long)addr; 457 - dma_play_data.size = size; 458 - #endif 459 - 460 486 play_start_pcm(); 461 487 } 462 488 ··· 490 516 /* Initialize default register values. */ 491 517 audiohw_init(); 492 518 493 - #ifdef CPU_PP502x 494 - /* Enable DMA controller */ 495 - DMA_MASTER_CONTROL |= DMA_MASTER_CONTROL_EN; 496 - /* FIQ priority for DMA */ 497 - CPU_INT_PRIORITY |= DMA_MASK; 498 - /* Enable request?? Not setting or clearing everything doesn't seem to 499 - * prevent it operating. Perhaps important for reliability (how requests 500 - * are handled). */ 501 - DMA_REQ_STATUS |= 1ul << DMA_REQ_IIS; 502 - DMA0_STATUS; 503 - #else 504 - /* Set up banked registers for FIQ mode */ 505 - 506 - /* Use non-banked registers for scratch. */ 507 - register volatile void *iiscfg asm("r0") = &IISCONFIG; 508 - register volatile void *dmapd asm("r1") = &dma_play_data; 509 - 510 - asm volatile ( 511 - "mrs r2, cpsr \n" /* Save mode and interrupt status */ 512 - "msr cpsr_c, #0xd1 \n" /* Switch to FIQ mode */ 513 - "mov r8, #0 \n" 514 - "mov r9, #0 \n" 515 - "mov r10, %[iiscfg] \n" 516 - "mov r11, %[dmapd] \n" 517 - "msr cpsr_c, r2 \n" 518 - : 519 - : [iiscfg]"r"(iiscfg), [dmapd]"r"(dmapd) 520 - : "r2"); 521 - 522 - /* FIQ priority for I2S */ 523 - CPU_INT_PRIORITY |= IIS_MASK; 524 - CPU_INT_EN = IIS_MASK; 525 - #endif 519 + dma_tx_init(); 526 520 527 521 IISCONFIG |= IIS_TXFIFOEN; 528 522 } ··· 649 643 } 650 644 } 651 645 652 - pcm_rec_more_ready_callback(0, (void *)&dma_rec_data.addr, 653 - &dma_rec_data.size); 646 + if (pcm_rec_dma_complete_callback(PCM_DMAST_OK, &dma_rec_data.p_w, 647 + &dma_rec_data.size)) 648 + { 649 + pcm_rec_dma_status_callback(PCM_DMAST_STARTED); 650 + } 654 651 } 655 652 656 - #else 653 + #else /* !(SANSA_C200 || SANSA_E200) */ 654 + 657 655 void fiq_record(void) 658 656 { 659 657 while (dma_rec_data.size > 0) { ··· 664 662 #if SAMPLE_SIZE == 16 665 663 *dma_rec_data.p16++ = IISFIFO_RD; 666 664 #elif SAMPLE_SIZE == 32 667 - *dma_rec_data.p32++ = IISFIFO_RD >> 16; 668 - *dma_rec_data.p32++ = IISFIFO_RD >> 16; 665 + *dma_rec_data.p32++ = IISFIFO_RDH; 666 + *dma_rec_data.p32++ = IISFIFO_RDH; 669 667 #endif 670 668 dma_rec_data.size -= 4; 671 669 } 672 670 673 - pcm_rec_more_ready_callback(0, (void *)&dma_rec_data.addr, 674 - &dma_rec_data.size); 671 + if (pcm_rec_dma_complete_callback(PCM_DMAST_OK, &dma_rec_data.p_w, 672 + &dma_rec_data.size)) 673 + { 674 + pcm_rec_dma_status_callback(PCM_DMAST_STARTED); 675 + } 675 676 } 676 677 677 - #endif /* SANSA_E200 */ 678 + #endif /* SANSA_C200 || SANSA_E200 */ 678 679 679 680 void pcm_rec_dma_stop(void) 680 681 {
+3 -5
firmware/target/arm/rk27xx/pcm-rk27xx.c
··· 273 273 /* audio DMA ISR called when chunk from callers buffer has been transfered */ 274 274 void INT_HDMA(void) 275 275 { 276 - void *start; 276 + const void *start; 277 277 size_t size; 278 278 279 - pcm_play_get_more_callback(&start, &size); 280 - 281 - if (size != 0) 279 + if (pcm_play_dma_complete_callback(PCM_DMAST_OK, &start, &size)) 282 280 { 283 281 hdma_i2s_transfer(start, size); 284 - pcm_play_dma_started_callback(); 282 + pcm_play_dma_status_callback(PCM_DMAST_STARTED); 285 283 } 286 284 } 287 285
+3 -5
firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c
··· 215 215 216 216 void fiq_handler(void) 217 217 { 218 - static void *start; 218 + static const void *start; 219 219 static size_t size; 220 220 221 221 /* clear any pending interrupt */ 222 222 SRCPND = DMA2_MASK; 223 223 224 224 /* Buffer empty. Try to get more. */ 225 - pcm_play_get_more_callback(&start, &size); 226 - 227 - if (size == 0) 225 + if (!pcm_play_dma_complete_callback(PCM_DMAST_OK, &start, &size)) 228 226 return; 229 227 230 228 /* Flush any pending cache writes */ ··· 237 235 /* Re-Activate the channel */ 238 236 DMASKTRIG2 = 0x2; 239 237 240 - pcm_play_dma_started_callback(); 238 + pcm_play_dma_status_callback(PCM_DMAST_STARTED); 241 239 } 242 240 243 241 size_t pcm_get_bytes_waiting(void)
+3 -5
firmware/target/arm/s3c2440/mini2440/pcm-mini2440.c
··· 255 255 256 256 void fiq_handler(void) 257 257 { 258 - static void *start; 258 + static const void *start; 259 259 static size_t size; 260 260 261 261 /* clear any pending interrupt */ 262 262 SRCPND = DMA2_MASK; 263 263 264 264 /* Buffer empty. Try to get more. */ 265 - pcm_play_get_more_callback(&start, &size); 266 - 267 - if (size == 0) 265 + if (!pcm_play_dma_complete_callback(PCM_DMAST_OK, &start, &size)) 268 266 return; 269 267 270 268 /* Flush any pending cache writes */ ··· 277 275 /* Re-Activate the channel */ 278 276 DMASKTRIG2 = 0x2; 279 277 280 - pcm_play_dma_started_callback(); 278 + pcm_play_dma_status_callback(PCM_DMAST_STARTED); 281 279 } 282 280 283 281 size_t pcm_get_bytes_waiting(void)
+5 -4
firmware/target/arm/s5l8700/pcm-s5l8700.c
··· 116 116 { 117 117 if (!nextsize) 118 118 { 119 - pcm_play_get_more_callback((void**)&nextbuf, &nextsize); 120 - if (!nextsize) break; 121 - new_buffer = true; 119 + new_buffer = pcm_play_dma_complete_callback(PCM_DMAST_OK, 120 + (const void**)&nextbuf, &nextsize); 121 + if (!new_buffer) 122 + break; 122 123 } 123 124 queuedsize = MIN(sizeof(dblbuf), nextsize / 2); 124 125 nextsize -= queuedsize; ··· 133 134 134 135 if (new_buffer) 135 136 { 136 - pcm_play_dma_started_callback(); 137 + pcm_play_dma_status_callback(PCM_DMAST_STARTED); 137 138 new_buffer = false; 138 139 } 139 140 }
+2 -2
firmware/target/arm/s5l8702/pcm-s5l8702.c
··· 65 65 DMAC0INTTCCLR = 1; 66 66 if (!pcm_remaining) 67 67 { 68 - pcm_play_get_more_callback((void**)&dataptr, &pcm_remaining); 68 + pcm_play_dma_complete_callback((const void**)&dataptr, &pcm_remaining); 69 69 pcm_chunksize = pcm_remaining; 70 70 } 71 71 if (!pcm_remaining) ··· 115 115 } 116 116 else DMAC0C0NEXTLLI = pcm_lli; 117 117 118 - pcm_play_dma_started_callback(); 118 + pcm_play_dma_status_callback(PCM_DMAST_STARTED); 119 119 } 120 120 121 121 void pcm_play_dma_start(const void* addr, size_t size)
+3 -5
firmware/target/arm/tms320dm320/mrobe-500/pcm-mr500.c
··· 33 33 /* This is global to save some latency when pcm_play_dma_get_peak_buffer is 34 34 * called. 35 35 */ 36 - static void *start; 36 + static const void *start; 37 37 38 38 void pcm_play_dma_postinit(void) 39 39 { ··· 164 164 165 165 case MSG_REFILL: 166 166 /* Buffer empty. Try to get more. */ 167 - pcm_play_get_more_callback(&start, &size); 168 - 169 - if (size != 0) 167 + if (pcm_play_dma_complete_callback(PCM_DMAST_OK, &start, &size)) 170 168 { 171 169 unsigned long sdem_addr=(unsigned long)start - CONFIG_SDRAM_START; 172 170 /* Flush any pending cache writes */ ··· 180 178 DEBUGF("pcm_sdram at 0x%08lx, sdem_addr 0x%08lx", 181 179 (unsigned long)start, (unsigned long)sdem_addr); 182 180 183 - pcm_play_dma_started_callback(); 181 + pcm_play_dma_status_callback(PCM_DMAST_STARTED); 184 182 } 185 183 186 184 break;
+3 -5
firmware/target/arm/tms320dm320/sansa-connect/pcm-sansaconnect.c
··· 34 34 /* This is global to save some latency when pcm_play_dma_get_peak_buffer is 35 35 * called. 36 36 */ 37 - static void *start; 37 + static const void *start; 38 38 static int dma_channel; 39 39 40 40 void pcm_play_dma_postinit(void) ··· 171 171 172 172 case MSG_REFILL: 173 173 /* Buffer empty. Try to get more. */ 174 - pcm_play_get_more_callback(&start, &size); 175 - 176 - if (size != 0) 174 + if (pcm_play_dma_complete_callback(PCM_DMAST_OK, &start, &size)) 177 175 { 178 176 unsigned long sdem_addr=(unsigned long)start - CONFIG_SDRAM_START; 179 177 /* Flush any pending cache writes */ ··· 187 185 DEBUGF("pcm_sdram at 0x%08lx, sdem_addr 0x%08lx", 188 186 (unsigned long)start, (unsigned long)sdem_addr); 189 187 190 - pcm_play_dma_started_callback(); 188 + pcm_play_dma_status_callback(PCM_DMAST_STARTED); 191 189 } 192 190 193 191 break;
+18 -18
firmware/target/coldfire/pcm-coldfire.c
··· 294 294 void DMA0(void) 295 295 { 296 296 unsigned long res = DSR0; 297 - void *start; 298 - size_t size; 299 297 300 298 and_l(~(DMA_EEXT | DMA_INT), &DCR0); /* per request and int OFF */ 301 299 DSR0 = 1; /* Clear interrupt and errors */ ··· 311 309 #endif 312 310 } 313 311 314 - /* Force stop on error */ 315 - pcm_play_get_more_callback((res & 0x70) ? NULL : &start, &size); 312 + const void *addr; 313 + size_t size; 316 314 317 - if (size != 0) 315 + if (pcm_play_dma_complete_callback((res & 0x70) ? 316 + PCM_DMAST_ERR_DMA : PCM_DMAST_OK, 317 + &addr, &size)) 318 318 { 319 - SAR0 = (unsigned long)start; /* Source address */ 320 - BCR0 = size; /* Bytes to transfer */ 319 + SAR0 = (unsigned long)addr; /* Source address */ 320 + BCR0 = (unsigned long)size; /* Bytes to transfer */ 321 321 or_l(DMA_EEXT | DMA_INT, &DCR0); /* per request and int ON */ 322 322 323 - /* Call buffer callback */ 324 - pcm_play_dma_started_callback(); 323 + pcm_play_dma_status_callback(PCM_DMAST_STARTED); 325 324 } 326 325 /* else inished playing */ 327 326 } /* DMA0 */ ··· 368 367 369 368 void pcm_rec_dma_start(void *addr, size_t size) 370 369 { 371 - /* stop any DMA in progress */ 370 + /* Stop any DMA in progress */ 372 371 pcm_rec_dma_stop(); 373 372 374 373 and_l(~PDIR2_FIFO_RESET, &DATAINCONTROL); ··· 430 429 void DMA1(void) 431 430 { 432 431 unsigned long res = DSR1; 433 - int status = 0; 434 - void *start; 435 - size_t size; 432 + enum pcm_dma_status status = PCM_DMAST_OK; 436 433 437 434 and_l(~(DMA_EEXT | DMA_INT), &DCR1); /* per request and int OFF */ 438 435 DSR1 = 1; /* Clear interrupt and errors */ 439 436 440 437 if (res & 0x70) 441 438 { 442 - status = DMA_REC_ERROR_DMA; 439 + status = PCM_DMAST_ERR_DMA; 443 440 logf("DMA1 err: %02x", res); 444 441 #if 0 445 442 logf(" SAR1: %08x", SAR1); ··· 456 453 * Ignore valnogood since several sources don't set it properly. */ 457 454 /* clear: ebu1cnew, symbolerr, parityerr */ 458 455 INTERRUPTCLEAR = (1 << 25) | (1 << 23) | (1 << 22); 459 - status = DMA_REC_ERROR_SPDIF; 456 + status = PCM_DMAST_ERR_SPDIF; 460 457 logf("spdif err"); 461 458 } 462 459 #endif 463 460 464 461 /* Inform PCM we have more data (or error) */ 465 - pcm_rec_more_ready_callback(status, &start, &size); 462 + void *addr; 463 + size_t size; 466 464 467 - if (size != 0) 465 + if (pcm_rec_dma_complete_callback(status, &addr, &size)) 468 466 { 469 - DAR1 = (unsigned long)start; /* Destination address */ 467 + DAR1 = (unsigned long)addr; /* Destination address */ 470 468 BCR1 = (unsigned long)size; /* Bytes to transfer */ 471 469 or_l(DMA_EEXT | DMA_INT, &DCR1); /* per request and int ON */ 470 + 471 + pcm_rec_dma_status_callback(PCM_DMAST_STARTED); 472 472 } 473 473 } /* DMA1 */ 474 474
+8 -8
firmware/target/hosted/android/pcm-android.c
··· 80 80 81 81 if (!pcm_data_size) /* get some initial data */ 82 82 { 83 - new_buffer = true; 84 - pcm_play_get_more_callback((void**) &pcm_data_start, &pcm_data_size); 83 + new_buffer = pcm_play_dma_complete_callback(PCM_DMAST_OK, 84 + (const void**)&pcm_data_start, &pcm_data_size); 85 85 } 86 86 87 87 while(left > 0 && pcm_data_size) ··· 99 99 if (new_buffer) 100 100 { 101 101 new_buffer = false; 102 - pcm_play_dma_started_callback(); 102 + pcm_play_dma_status_callback(PCM_DMAST_STARTED); 103 103 104 104 /* NOTE: might need to release the mutex and sleep here if the 105 105 buffer is shorter than the required buffer (like pcm-sdl.c) to ··· 114 114 115 115 if (pcm_data_size == 0) /* need new data */ 116 116 { 117 - new_buffer = true; 118 - pcm_play_get_more_callback((void**)&pcm_data_start, &pcm_data_size); 117 + new_buffer = pcm_play_dma_complete_callback(PCM_DMAST_OK, 118 + (const void**)&pcm_data_start, &pcm_data_size); 119 119 } 120 120 else /* increment data pointer and feed more */ 121 121 pcm_data_start += transfer_size; 122 122 } 123 123 124 - if (new_buffer && pcm_data_size) 125 - pcm_play_dma_started_callback(); 124 + if (new_buffer) 125 + pcm_play_dma_status_callback(PCM_DMAST_STARTED); 126 126 127 127 unlock_audio(); 128 128 return max_size - left; ··· 154 154 155 155 void pcm_play_dma_stop(void) 156 156 { 157 - /* NOTE: due to how pcm_play_get_more_callback() works, this is 157 + /* NOTE: due to how pcm_play_dma_complete_callback() works, this is 158 158 * possibly called from nativeWrite(), i.e. another (host) thread 159 159 * => need to discover the appropriate JNIEnv* */ 160 160 JNIEnv* env = getJavaEnvironment();
+3 -4
firmware/target/hosted/maemo/pcm-gstreamer.c
··· 189 189 from inside gstreamer's stream thread as it will deadlock */ 190 190 inside_feed_data = 1; 191 191 192 - pcm_play_get_more_callback((void **)&pcm_data, &pcm_data_size); 193 - 194 - if (pcm_data_size != 0) 192 + if (pcm_play_dma_complete_callback(PCM_DMAST_OK, (const void **)&pcm_data, 193 + &pcm_data_size)) 195 194 { 196 195 GstBuffer *buffer = gst_buffer_new (); 197 196 GstFlowReturn ret; ··· 205 204 if (ret != 0) 206 205 DEBUGF("push-buffer error result: %d\n", ret); 207 206 208 - pcm_play_dma_started_callback(); 207 + pcm_play_dma_status_callback(PCM_DMAST_STARTED); 209 208 } else 210 209 { 211 210 DEBUGF("feed_data: No Data.\n");
+5 -3
firmware/target/hosted/pcm-alsa.c
··· 223 223 if (!pcm_size) 224 224 { 225 225 new_buffer = true; 226 - pcm_play_get_more_callback((void **)&pcm_data, &pcm_size); 227 - if (!pcm_size || !pcm_data) 226 + if (!pcm_play_dma_complete_callback(PCM_DMAST_OK, 227 + (const void **)&pcm_data, &pcm_size)) 228 + { 228 229 return false; 230 + } 229 231 } 230 232 copy_n = MIN((ssize_t)pcm_size, frames_left*4); 231 233 memcpy(&frames[2*(period_size-frames_left)], pcm_data, copy_n); ··· 237 239 if (new_buffer) 238 240 { 239 241 new_buffer = false; 240 - pcm_play_dma_started_callback(); 242 + pcm_play_dma_status_callback(PCM_DMAST_STARTED); 241 243 } 242 244 } 243 245 return true;
+32 -32
firmware/target/hosted/sdl/pcm-sdl.c
··· 56 56 #if CONFIG_CODEC == SWCODEC 57 57 static int cvt_status = -1; 58 58 59 - static Uint8* pcm_data; 59 + static const Uint8* pcm_data; 60 60 static size_t pcm_data_size; 61 61 static size_t pcm_sample_bytes; 62 62 static size_t pcm_channel_bytes; ··· 109 109 { 110 110 pcm_dma_apply_settings_nolock(); 111 111 112 - pcm_data = (Uint8 *) addr; 112 + pcm_data = addr; 113 113 pcm_data_size = size; 114 114 115 115 SDL_PauseAudio(0); ··· 245 245 246 246 /* Audio card wants more? Get some more then. */ 247 247 while (len > 0) { 248 - new_buffer = true; 249 - pcm_play_get_more_callback((void **)&pcm_data, &pcm_data_size); 248 + new_buffer = pcm_play_dma_complete_callback(PCM_DMAST_OK, 249 + (const void **)&pcm_data, &pcm_data_size); 250 + 251 + if (!new_buffer) { 252 + DEBUGF("sdl_audio_callback: No Data.\n"); 253 + break; 254 + } 255 + 250 256 start: 251 - if (pcm_data_size != 0) { 252 - udata->num_in = pcm_data_size / pcm_sample_bytes; 253 - udata->num_out = len / pcm_sample_bytes; 257 + udata->num_in = pcm_data_size / pcm_sample_bytes; 258 + udata->num_out = len / pcm_sample_bytes; 254 259 255 - write_to_soundcard(udata); 260 + write_to_soundcard(udata); 256 261 257 - udata->num_in *= pcm_sample_bytes; 258 - udata->num_out *= pcm_sample_bytes; 262 + udata->num_in *= pcm_sample_bytes; 263 + udata->num_out *= pcm_sample_bytes; 259 264 265 + if (new_buffer) 266 + { 267 + new_buffer = false; 268 + pcm_play_dma_status_callback(PCM_DMAST_STARTED); 260 269 261 - if (new_buffer) 270 + if ((size_t)len > udata->num_out) 262 271 { 263 - new_buffer = false; 264 - pcm_play_dma_started_callback(); 272 + int delay = pcm_data_size*250 / pcm_sampr - 1; 265 273 266 - if ((size_t)len > udata->num_out) 274 + if (delay > 0) 267 275 { 268 - int delay = pcm_data_size*250 / pcm_sampr - 1; 269 - 270 - if (delay > 0) 271 - { 272 - SDL_UnlockMutex(audio_lock); 273 - SDL_Delay(delay); 274 - SDL_LockMutex(audio_lock); 276 + SDL_UnlockMutex(audio_lock); 277 + SDL_Delay(delay); 278 + SDL_LockMutex(audio_lock); 275 279 276 - if (!pcm_is_playing()) 277 - break; 278 - } 280 + if (!pcm_is_playing()) 281 + break; 279 282 } 280 283 } 284 + } 281 285 282 - pcm_data += udata->num_in; 283 - pcm_data_size -= udata->num_in; 284 - udata->stream += udata->num_out; 285 - len -= udata->num_out; 286 - } else { 287 - DEBUGF("sdl_audio_callback: No Data.\n"); 288 - break; 289 - } 286 + pcm_data += udata->num_in; 287 + pcm_data_size -= udata->num_in; 288 + udata->stream += udata->num_out; 289 + len -= udata->num_out; 290 290 } 291 291 292 292 SDL_UnlockMutex(audio_lock);
+5 -7
firmware/target/mips/ingenic_jz47xx/pcm-jz4740.c
··· 63 63 audiohw_set_frequency(pcm_sampr); 64 64 } 65 65 66 - static void* playback_address; 66 + static const void* playback_address; 67 67 static inline void set_dma(const void *addr, size_t size) 68 68 { 69 69 int burst_size; ··· 96 96 REG_DMAC_DRSR(DMA_AIC_TX_CHANNEL) = DMAC_DRSR_RS_AICOUT; 97 97 REG_DMAC_DCMD(DMA_AIC_TX_CHANNEL) = (DMAC_DCMD_SAI | DMAC_DCMD_SWDH_32 | burst_size | DMAC_DCMD_DWDH_16 | DMAC_DCMD_TIE); 98 98 99 - playback_address = (void*)addr; 99 + playback_address = addr; 100 100 } 101 101 102 102 static inline void play_dma_callback(void) 103 103 { 104 - void *start; 104 + const void *start; 105 105 size_t size; 106 106 107 - pcm_play_get_more_callback(&start, &size); 108 - 109 - if (size != 0) 107 + if (pcm_play_dma_complete_callback(PCM_DMAST_OK, &start, &size)) 110 108 { 111 109 set_dma(start, size); 112 110 REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) |= DMAC_DCCSR_EN; 113 - pcm_play_dma_started_callback(); 111 + pcm_play_dma_status_callback(PCM_DMAST_STARTED); 114 112 } 115 113 } 116 114