diff options
Diffstat (limited to 'firmware/target/arm')
-rw-r--r-- | firmware/target/arm/as3525/pcm-as3525.c | 72 |
1 files changed, 57 insertions, 15 deletions
diff --git a/firmware/target/arm/as3525/pcm-as3525.c b/firmware/target/arm/as3525/pcm-as3525.c index 5a403bad83..9f31d623fe 100644 --- a/firmware/target/arm/as3525/pcm-as3525.c +++ b/firmware/target/arm/as3525/pcm-as3525.c | |||
@@ -39,21 +39,28 @@ static unsigned char *dma_start_addr; | |||
39 | static size_t dma_size; /* in 4*32 bits */ | 39 | static size_t dma_size; /* in 4*32 bits */ |
40 | static void dma_callback(void); | 40 | static void dma_callback(void); |
41 | static int locked = 0; | 41 | static int locked = 0; |
42 | 42 | static bool is_playing = false; | |
43 | static int play_irq_state; | 43 | static bool play_callback_pending = false; |
44 | 44 | ||
45 | /* Mask the DMA interrupt */ | 45 | /* Mask the DMA interrupt */ |
46 | void pcm_play_lock(void) | 46 | void pcm_play_lock(void) |
47 | { | 47 | { |
48 | if(++locked == 1) | 48 | ++locked; |
49 | play_irq_state = disable_irq_save(); | ||
50 | } | 49 | } |
51 | 50 | ||
52 | /* Unmask the DMA interrupt if enabled */ | 51 | /* Unmask the DMA interrupt if enabled */ |
53 | void pcm_play_unlock(void) | 52 | void pcm_play_unlock(void) |
54 | { | 53 | { |
55 | if(--locked == 0) | 54 | if(--locked == 0 && is_playing) |
56 | restore_irq(play_irq_state); | 55 | { |
56 | int old = disable_irq_save(); | ||
57 | if(play_callback_pending) | ||
58 | { | ||
59 | play_callback_pending = false; | ||
60 | dma_callback(); | ||
61 | } | ||
62 | restore_irq(old); | ||
63 | } | ||
57 | } | 64 | } |
58 | 65 | ||
59 | static void play_start_pcm(void) | 66 | static void play_start_pcm(void) |
@@ -74,6 +81,12 @@ static void play_start_pcm(void) | |||
74 | 81 | ||
75 | static void dma_callback(void) | 82 | static void dma_callback(void) |
76 | { | 83 | { |
84 | if(locked) | ||
85 | { | ||
86 | play_callback_pending = is_playing; | ||
87 | return; | ||
88 | } | ||
89 | |||
77 | if(!dma_size) | 90 | if(!dma_size) |
78 | { | 91 | { |
79 | pcm_play_get_more_callback((void **)&dma_start_addr, &dma_size); | 92 | pcm_play_get_more_callback((void **)&dma_start_addr, &dma_size); |
@@ -95,11 +108,14 @@ void pcm_play_dma_start(const void *addr, size_t size) | |||
95 | 108 | ||
96 | dma_retain(); | 109 | dma_retain(); |
97 | 110 | ||
111 | is_playing = true; | ||
112 | |||
98 | play_start_pcm(); | 113 | play_start_pcm(); |
99 | } | 114 | } |
100 | 115 | ||
101 | void pcm_play_dma_stop(void) | 116 | void pcm_play_dma_stop(void) |
102 | { | 117 | { |
118 | is_playing = false; | ||
103 | dma_disable_channel(1); | 119 | dma_disable_channel(1); |
104 | dma_size = 0; | 120 | dma_size = 0; |
105 | 121 | ||
@@ -111,6 +127,8 @@ void pcm_play_dma_stop(void) | |||
111 | 127 | ||
112 | void pcm_play_dma_pause(bool pause) | 128 | void pcm_play_dma_pause(bool pause) |
113 | { | 129 | { |
130 | is_playing = !pause; | ||
131 | |||
114 | if(pause) | 132 | if(pause) |
115 | dma_disable_channel(1); | 133 | dma_disable_channel(1); |
116 | else | 134 | else |
@@ -192,6 +210,8 @@ void * pcm_dma_addr(void *addr) | |||
192 | #ifdef HAVE_RECORDING | 210 | #ifdef HAVE_RECORDING |
193 | 211 | ||
194 | static int rec_locked = 0; | 212 | static int rec_locked = 0; |
213 | static bool is_recording = false; | ||
214 | static bool rec_callback_pending = false; | ||
195 | static unsigned char *rec_dma_start_addr; | 215 | static unsigned char *rec_dma_start_addr; |
196 | static size_t rec_dma_size, rec_dma_transfer_size; | 216 | static size_t rec_dma_size, rec_dma_transfer_size; |
197 | static void rec_dma_callback(void); | 217 | static void rec_dma_callback(void); |
@@ -200,19 +220,25 @@ static void rec_dma_callback(void); | |||
200 | static int16_t *mono_samples; | 220 | static int16_t *mono_samples; |
201 | #endif | 221 | #endif |
202 | 222 | ||
203 | static int rec_irq_state; | ||
204 | 223 | ||
205 | void pcm_rec_lock(void) | 224 | void pcm_rec_lock(void) |
206 | { | 225 | { |
207 | if(++rec_locked == 1) | 226 | ++rec_locked; |
208 | rec_irq_state = disable_irq_save(); | ||
209 | } | 227 | } |
210 | 228 | ||
211 | 229 | ||
212 | void pcm_rec_unlock(void) | 230 | void pcm_rec_unlock(void) |
213 | { | 231 | { |
214 | if(--rec_locked == 0) | 232 | if(--rec_locked == 0 && is_recording) |
215 | restore_irq(rec_irq_state); | 233 | { |
234 | int old = disable_irq_save(); | ||
235 | if(rec_callback_pending) | ||
236 | { | ||
237 | rec_callback_pending = false; | ||
238 | rec_dma_callback(); | ||
239 | } | ||
240 | restore_irq(old); | ||
241 | } | ||
216 | } | 242 | } |
217 | 243 | ||
218 | 244 | ||
@@ -268,11 +294,24 @@ static inline void mono2stereo(int16_t *end) | |||
268 | 294 | ||
269 | static void rec_dma_callback(void) | 295 | static void rec_dma_callback(void) |
270 | { | 296 | { |
271 | rec_dma_size -= rec_dma_transfer_size; | 297 | if(rec_dma_transfer_size) |
272 | rec_dma_start_addr += rec_dma_transfer_size; | 298 | { |
299 | rec_dma_size -= rec_dma_transfer_size; | ||
300 | rec_dma_start_addr += rec_dma_transfer_size; | ||
301 | |||
302 | /* don't act like we just transferred data when we are called from | ||
303 | * pcm_rec_unlock() */ | ||
304 | rec_dma_transfer_size = 0; | ||
273 | 305 | ||
274 | /* the 2nd channel is silent when recording microphone on as3525v1 */ | 306 | /* the 2nd channel is silent when recording microphone on as3525v1 */ |
275 | mono2stereo(AS3525_UNCACHED_ADDR((int16_t*)rec_dma_start_addr)); | 307 | mono2stereo(AS3525_UNCACHED_ADDR((int16_t*)rec_dma_start_addr)); |
308 | |||
309 | if(locked) | ||
310 | { | ||
311 | rec_callback_pending = is_recording; | ||
312 | return; | ||
313 | } | ||
314 | } | ||
276 | 315 | ||
277 | if(!rec_dma_size) | 316 | if(!rec_dma_size) |
278 | { | 317 | { |
@@ -293,6 +332,7 @@ static void rec_dma_callback(void) | |||
293 | 332 | ||
294 | void pcm_rec_dma_stop(void) | 333 | void pcm_rec_dma_stop(void) |
295 | { | 334 | { |
335 | is_recording = false; | ||
296 | dma_disable_channel(1); | 336 | dma_disable_channel(1); |
297 | dma_release(); | 337 | dma_release(); |
298 | rec_dma_size = 0; | 338 | rec_dma_size = 0; |
@@ -320,6 +360,8 @@ void pcm_rec_dma_start(void *addr, size_t size) | |||
320 | 360 | ||
321 | I2SIN_CONTROL |= (1<<11)|(1<<5); /* enable dma, 14bits samples */ | 361 | I2SIN_CONTROL |= (1<<11)|(1<<5); /* enable dma, 14bits samples */ |
322 | 362 | ||
363 | is_recording = true; | ||
364 | |||
323 | rec_dma_start(); | 365 | rec_dma_start(); |
324 | } | 366 | } |
325 | 367 | ||