diff options
Diffstat (limited to 'firmware/target')
19 files changed, 520 insertions, 529 deletions
diff --git a/firmware/target/arm/as3525/pcm-as3525.c b/firmware/target/arm/as3525/pcm-as3525.c index 0ecc63d018..eb22fc2016 100644 --- a/firmware/target/arm/as3525/pcm-as3525.c +++ b/firmware/target/arm/as3525/pcm-as3525.c | |||
@@ -36,9 +36,9 @@ | |||
36 | * and the number of 32bits words has to | 36 | * and the number of 32bits words has to |
37 | * fit in 11 bits of DMA register */ | 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 | static size_t dma_start_size; /* Size of callback buffer */ | 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 | static size_t dma_rem_size; /* Remaining size - in 4*32 bits */ | 42 | static size_t dma_rem_size; /* Remaining size - in 4*32 bits */ |
43 | static size_t play_sub_size; /* size of current subtransfer */ | 43 | static size_t play_sub_size; /* size of current subtransfer */ |
44 | static void dma_callback(void); | 44 | static void dma_callback(void); |
@@ -100,9 +100,8 @@ static void dma_callback(void) | |||
100 | 100 | ||
101 | if(!dma_rem_size) | 101 | if(!dma_rem_size) |
102 | { | 102 | { |
103 | pcm_play_get_more_callback(&dma_start_addr, &dma_start_size); | 103 | if(!pcm_play_dma_complete_callback(PCM_DMAST_OK, &dma_start_addr, |
104 | 104 | &dma_start_size)) | |
105 | if (!dma_start_size) | ||
106 | return; | 105 | return; |
107 | 106 | ||
108 | dma_sub_addr = dma_start_addr; | 107 | dma_sub_addr = dma_start_addr; |
@@ -111,7 +110,7 @@ static void dma_callback(void) | |||
111 | /* force writeback */ | 110 | /* force writeback */ |
112 | commit_dcache_range(dma_start_addr, dma_start_size); | 111 | commit_dcache_range(dma_start_addr, dma_start_size); |
113 | play_start_pcm(); | 112 | play_start_pcm(); |
114 | pcm_play_dma_started_callback(); | 113 | pcm_play_dma_status_callback(PCM_DMAST_STARTED); |
115 | } | 114 | } |
116 | else | 115 | else |
117 | { | 116 | { |
@@ -123,7 +122,7 @@ void pcm_play_dma_start(const void *addr, size_t size) | |||
123 | { | 122 | { |
124 | is_playing = true; | 123 | is_playing = true; |
125 | 124 | ||
126 | dma_start_addr = (void*)addr; | 125 | dma_start_addr = addr; |
127 | dma_start_size = size; | 126 | dma_start_size = size; |
128 | dma_sub_addr = dma_start_addr; | 127 | dma_sub_addr = dma_start_addr; |
129 | dma_rem_size = size; | 128 | dma_rem_size = size; |
@@ -368,7 +367,12 @@ void INT_I2SIN(void) | |||
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 | ||
diff --git a/firmware/target/arm/imx233/pcm-imx233.c b/firmware/target/arm/imx233/pcm-imx233.c index c8b79b3875..c4c512eed6 100644 --- a/firmware/target/arm/imx233/pcm-imx233.c +++ b/firmware/target/arm/imx233/pcm-imx233.c | |||
@@ -49,15 +49,13 @@ static void play(const void *addr, size_t size) | |||
49 | 49 | ||
50 | void INT_DAC_DMA(void) | 50 | void INT_DAC_DMA(void) |
51 | { | 51 | { |
52 | void *start; | 52 | const void *start; |
53 | size_t size; | 53 | size_t size; |
54 | 54 | ||
55 | pcm_play_get_more_callback(&start, &size); | 55 | if (pcm_play_dma_complete_callback(PCM_DMAST_OK, &start, &size)) |
56 | |||
57 | if(size != 0) | ||
58 | { | 56 | { |
59 | play(start, size); | 57 | play(start, size); |
60 | pcm_play_dma_started_callback(); | 58 | pcm_play_dma_status_callback(PCM_DMAST_STARTED); |
61 | } | 59 | } |
62 | 60 | ||
63 | imx233_dma_clear_channel_interrupt(APB_AUDIO_DAC); | 61 | imx233_dma_clear_channel_interrupt(APB_AUDIO_DAC); |
@@ -65,6 +63,7 @@ void INT_DAC_DMA(void) | |||
65 | 63 | ||
66 | void INT_DAC_ERROR(void) | 64 | void INT_DAC_ERROR(void) |
67 | { | 65 | { |
66 | /* TODO: Inform of error through pcm_play_dma_complete_callback */ | ||
68 | } | 67 | } |
69 | 68 | ||
70 | void pcm_play_lock(void) | 69 | void pcm_play_lock(void) |
diff --git a/firmware/target/arm/imx31/gigabeat-s/pcm-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/pcm-gigabeat-s.c index e106cf78e3..c26349b72e 100644 --- a/firmware/target/arm/imx31/gigabeat-s/pcm-gigabeat-s.c +++ b/firmware/target/arm/imx31/gigabeat-s/pcm-gigabeat-s.c | |||
@@ -78,12 +78,20 @@ static struct dma_data dma_play_data = | |||
78 | .state = 0 | 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; | 83 | commit_dcache_range(addr, size); |
84 | size_t size; | 84 | |
85 | bool rror; | 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 | if (dma_play_data.locked != 0) | 95 | if (dma_play_data.locked != 0) |
88 | { | 96 | { |
89 | /* Callback is locked out */ | 97 | /* Callback is locked out */ |
@@ -91,22 +99,17 @@ static void play_dma_callback(void) | |||
91 | return; | 99 | return; |
92 | } | 100 | } |
93 | 101 | ||
94 | rror = dma_play_bd.mode.status & BD_RROR; | 102 | /* Inform of status and get new buffer */ |
95 | 103 | enum pcm_dma_status status = (dma_play_bd.mode.status & BD_RROR) ? | |
96 | pcm_play_get_more_callback(rror ? NULL : &start, &size); | 104 | PCM_DMAST_ERR_DMA : PCM_DMAST_OK; |
97 | 105 | const void *addr; | |
98 | if (size == 0) | 106 | size_t size; |
99 | return; | 107 | |
100 | 108 | if (pcm_play_dma_complete_callback(status, &addr, &size)) | |
101 | /* Flush any pending cache writes */ | 109 | { |
102 | commit_dcache_range(start, size); | 110 | play_start_dma(addr, size); |
103 | dma_play_bd.buf_addr = (void *)addr_virt_to_phys((unsigned long)start); | 111 | pcm_play_dma_status_callback(PCM_DMAST_STARTED); |
104 | dma_play_bd.mode.count = size; | 112 | } |
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(); | ||
110 | } | 113 | } |
111 | 114 | ||
112 | void pcm_play_lock(void) | 115 | void pcm_play_lock(void) |
@@ -221,15 +224,11 @@ void pcm_play_dma_start(const void *addr, size_t size) | |||
221 | if (!sdma_channel_reset(DMA_PLAY_CH_NUM)) | 224 | if (!sdma_channel_reset(DMA_PLAY_CH_NUM)) |
222 | return; | 225 | return; |
223 | 226 | ||
224 | commit_dcache_range(addr, size); | 227 | /* Begin I2S transmission */ |
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 | |||
231 | play_start_pcm(); | 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 | void pcm_play_dma_stop(void) | 234 | void pcm_play_dma_stop(void) |
@@ -332,37 +331,39 @@ static struct dma_data dma_rec_data = | |||
332 | .state = 0 | 331 | .state = 0 |
333 | }; | 332 | }; |
334 | 333 | ||
335 | static void rec_dma_callback(void) | 334 | static void rec_start_dma(void *addr, size_t size) |
336 | { | 335 | { |
337 | int status = 0; | 336 | discard_dcache_range(addr, size); |
338 | void *start; | 337 | |
339 | size_t size; | 338 | addr = (void *)addr_virt_to_phys((unsigned long)addr); |
340 | 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 | |||
348 | static void rec_dma_callback(void) | ||
349 | { | ||
341 | if (dma_rec_data.locked != 0) | 350 | if (dma_rec_data.locked != 0) |
342 | { | 351 | { |
343 | dma_rec_data.callback_pending = dma_rec_data.state; | 352 | dma_rec_data.callback_pending = dma_rec_data.state; |
344 | return; /* Callback is locked out */ | 353 | return; /* Callback is locked out */ |
345 | } | 354 | } |
346 | 355 | ||
347 | if (dma_rec_bd.mode.status & BD_RROR) | 356 | /* Inform middle layer */ |
348 | status = DMA_REC_ERROR_DMA; | 357 | enum pcm_dma_status status = (dma_rec_bd.mode.status & BD_RROR) ? |
349 | 358 | PCM_DMAST_ERR_DMA : PCM_DMAST_OK; | |
350 | pcm_rec_more_ready_callback(status, &start, &size); | 359 | void *addr; |
351 | 360 | size_t size; | |
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 | 361 | ||
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 | void pcm_rec_lock(void) | 369 | void pcm_rec_lock(void) |
@@ -426,29 +427,21 @@ void pcm_rec_dma_start(void *addr, size_t size) | |||
426 | 427 | ||
427 | if (!sdma_channel_reset(DMA_REC_CH_NUM)) | 428 | if (!sdma_channel_reset(DMA_REC_CH_NUM)) |
428 | return; | 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); | 431 | /* Ensure clear FIFO */ |
434 | dma_rec_bd.buf_addr = addr; | 432 | while (SSI_SFCSR1 & SSI_SFCSR_RFCNT0) |
435 | dma_rec_bd.mode.count = size; | 433 | SSI_SRX0_1; |
436 | dma_rec_bd.mode.command = TRANSFER_16BIT; | ||
437 | dma_rec_bd.mode.status = BD_DONE | BD_WRAP | BD_INTR; | ||
438 | 434 | ||
439 | dma_rec_data.state = 1; /* Check callback on unlock */ | 435 | dma_rec_data.state = 1; /* Check callback on unlock */ |
440 | 436 | ||
441 | SSI_SRCR1 |= SSI_SRCR_RFEN0; /* Enable RX FIFO */ | 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 | /* Enable receive */ | 439 | /* Enable receive */ |
448 | SSI_SCR1 |= SSI_SCR_RE; | 440 | SSI_SCR1 |= SSI_SCR_RE; |
449 | SSI_SIER1 |= SSI_SIER_RDMAE; /* Enable DMA req. */ | 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 | void pcm_rec_dma_close(void) | 447 | void pcm_rec_dma_close(void) |
diff --git a/firmware/target/arm/pcm-telechips.c b/firmware/target/arm/pcm-telechips.c index ae4aa5ef38..3d62fcd1a9 100644 --- a/firmware/target/arm/pcm-telechips.c +++ b/firmware/target/arm/pcm-telechips.c | |||
@@ -33,7 +33,12 @@ struct dma_data | |||
33 | { | 33 | { |
34 | /* NOTE: The order of size and p is important if you use assembler | 34 | /* NOTE: The order of size and p is important if you use assembler |
35 | optimised fiq handler, so don't change it. */ | 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 | size_t size; | 42 | size_t size; |
38 | #if NUM_CORES > 1 | 43 | #if NUM_CORES > 1 |
39 | unsigned core; | 44 | unsigned core; |
@@ -143,7 +148,7 @@ static void play_stop_pcm(void) | |||
143 | 148 | ||
144 | void pcm_play_dma_start(const void *addr, size_t size) | 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 | dma_play_data.size = size; | 152 | dma_play_data.size = size; |
148 | 153 | ||
149 | #if NUM_CORES > 1 | 154 | #if NUM_CORES > 1 |
@@ -248,8 +253,9 @@ void fiq_handler(void) | |||
248 | * r0-r3 and r12 is a working register. | 253 | * r0-r3 and r12 is a working register. |
249 | */ | 254 | */ |
250 | asm volatile ( | 255 | asm volatile ( |
251 | "stmfd sp!, { r0-r4, lr } \n" /* stack scratch regs and lr */ | 256 | "sub lr, lr, #4 \n" |
252 | "mov r4, #0 \n" /* Was the callback called? */ | 257 | "stmfd sp!, { r0-r3, lr } \n" /* stack scratch regs and lr */ |
258 | "mov r14, #0 \n" /* Was the callback called? */ | ||
253 | #if defined(CPU_TCC780X) | 259 | #if defined(CPU_TCC780X) |
254 | "mov r8, #0xc000 \n" /* DAI_TX_IRQ_MASK | DAI_RX_IRQ_MASK */ | 260 | "mov r8, #0xc000 \n" /* DAI_TX_IRQ_MASK | DAI_RX_IRQ_MASK */ |
255 | "ldr r9, =0xf3001004 \n" /* CREQ */ | 261 | "ldr r9, =0xf3001004 \n" /* CREQ */ |
@@ -260,7 +266,7 @@ void fiq_handler(void) | |||
260 | "str r8, [r9] \n" /* clear DAI IRQs */ | 266 | "str r8, [r9] \n" /* clear DAI IRQs */ |
261 | "ldmia r11, { r8-r9 } \n" /* r8 = p, r9 = size */ | 267 | "ldmia r11, { r8-r9 } \n" /* r8 = p, r9 = size */ |
262 | "cmp r9, #0x10 \n" /* is size <16? */ | 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 | ".fill_fifo: \n" | 271 | ".fill_fifo: \n" |
266 | "ldr r12, [r8], #4 \n" /* load two samples */ | 272 | "ldr r12, [r8], #4 \n" /* load two samples */ |
@@ -282,29 +288,30 @@ void fiq_handler(void) | |||
282 | "sub r9, r9, #0x10 \n" /* 4 words written */ | 288 | "sub r9, r9, #0x10 \n" /* 4 words written */ |
283 | "stmia r11, { r8-r9 } \n" /* save p and size */ | 289 | "stmia r11, { r8-r9 } \n" /* save p and size */ |
284 | 290 | ||
285 | "cmp r4, #0 \n" /* Callback called? */ | 291 | "cmp r14, #0 \n" /* Callback called? */ |
286 | "beq .exit \n" | 292 | "ldmeqfd sp!, { r0-r3, pc }^ \n" /* no? -> exit */ |
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" | ||
292 | 293 | ||
293 | ".exit: \n" | 294 | "ldr r1, =pcm_play_status_callback \n" |
294 | "ldmfd sp!, { r0-r4, lr } \n" | 295 | "ldr r1, [r1] \n" |
295 | "subs pc, lr, #4 \n" /* FIQ specific return sequence */ | 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 | ".more_data: \n" | 301 | ".more_data: \n" |
298 | "mov r4, #1 \n" /* Remember we got more data in this FIQ */ | 302 | "mov r14, #1 \n" /* Remember we got more data in this FIQ */ |
299 | "ldr r2, =pcm_play_get_more_callback \n" | 303 | "mov r0, %0 \n" /* r0 = status */ |
300 | "mov r0, r11 \n" /* r0 = &p */ | 304 | "mov r1, r11 \n" /* r1 = &dma_play_data.p_r */ |
301 | "add r1, r11, #4 \n" /* r1 = &size */ | 305 | "add r2, r11, #4 \n" /* r2 = &dma_play_data.size */ |
302 | "blx r2 \n" /* call pcm_play_get_more_callback */ | 306 | "mov lr, pc \n" |
303 | "ldmia r11, { r8-r9 } \n" /* load new p and size */ | 307 | "ldr pc, =pcm_play_dma_complete_callback \n" |
304 | "cmp r9, #0x10 \n" /* did we actually get enough data? */ | 308 | "cmp r0, #0 \n" /* any more to play? */ |
305 | "bpl .fill_fifo \n" /* not stop and enough? refill */ | 309 | "ldmneia r11, { r8-r9 } \n" /* load new p and size */ |
306 | "b .exit \n" | 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 | ".ltorg \n" | 313 | ".ltorg \n" |
314 | : : "i"(PCM_DMAST_OK), "i"(PCM_DMAST_STARTED) | ||
308 | ); | 315 | ); |
309 | } | 316 | } |
310 | #else /* C version for reference */ | 317 | #else /* C version for reference */ |
@@ -316,9 +323,8 @@ void fiq_handler(void) | |||
316 | if (dma_play_data.size < 16) | 323 | if (dma_play_data.size < 16) |
317 | { | 324 | { |
318 | /* p is empty, get some more data */ | 325 | /* p is empty, get some more data */ |
319 | new_buffer = true; | 326 | new_buffer = pcm_play_dma_complete_callback(&dma_play_data.p_r, |
320 | pcm_play_get_more_callback((void**)&dma_play_data.p, | 327 | &dma_play_data.size); |
321 | &dma_play_data.size); | ||
322 | } | 328 | } |
323 | 329 | ||
324 | if (dma_play_data.size >= 16) | 330 | if (dma_play_data.size >= 16) |
@@ -339,7 +345,7 @@ void fiq_handler(void) | |||
339 | CREQ = DAI_TX_IRQ_MASK | DAI_RX_IRQ_MASK; | 345 | CREQ = DAI_TX_IRQ_MASK | DAI_RX_IRQ_MASK; |
340 | 346 | ||
341 | if (new_buffer) | 347 | if (new_buffer) |
342 | pcm_play_dma_started_callback(); | 348 | pcm_play_dma_status_callback(PCM_DMAST_STARTED); |
343 | } | 349 | } |
344 | #endif | 350 | #endif |
345 | 351 | ||
diff --git a/firmware/target/arm/pnx0101/pcm-pnx0101.c b/firmware/target/arm/pnx0101/pcm-pnx0101.c index 89d56af374..bb11ad32fe 100644 --- a/firmware/target/arm/pnx0101/pcm-pnx0101.c +++ b/firmware/target/arm/pnx0101/pcm-pnx0101.c | |||
@@ -28,7 +28,7 @@ | |||
28 | short __attribute__((section(".dmabuf"))) dma_buf_left[DMA_BUF_SAMPLES]; | 28 | short __attribute__((section(".dmabuf"))) dma_buf_left[DMA_BUF_SAMPLES]; |
29 | short __attribute__((section(".dmabuf"))) dma_buf_right[DMA_BUF_SAMPLES]; | 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 | size_t p_size IBSS_ATTR; | 32 | size_t p_size IBSS_ATTR; |
33 | 33 | ||
34 | void pcm_play_lock(void) | 34 | void pcm_play_lock(void) |
@@ -41,7 +41,7 @@ void pcm_play_unlock(void) | |||
41 | 41 | ||
42 | void pcm_play_dma_start(const void *addr, size_t size) | 42 | void pcm_play_dma_start(const void *addr, size_t size) |
43 | { | 43 | { |
44 | p = (unsigned short*)addr; | 44 | p = addr; |
45 | p_size = size; | 45 | p_size = size; |
46 | } | 46 | } |
47 | 47 | ||
@@ -69,7 +69,7 @@ static inline void fill_dma_buf(int offset) | |||
69 | do | 69 | do |
70 | { | 70 | { |
71 | int count; | 71 | int count; |
72 | unsigned short *tmp_p; | 72 | const int16_t *tmp_p; |
73 | count = MIN(p_size / 4, (size_t)(lend - l)); | 73 | count = MIN(p_size / 4, (size_t)(lend - l)); |
74 | tmp_p = p; | 74 | tmp_p = p; |
75 | p_size -= count * 4; | 75 | p_size -= count * 4; |
@@ -109,16 +109,14 @@ static inline void fill_dma_buf(int offset) | |||
109 | if (new_buffer) | 109 | if (new_buffer) |
110 | { | 110 | { |
111 | new_buffer = false; | 111 | new_buffer = false; |
112 | pcm_play_dma_started_callback(); | 112 | pcm_play_dma_status_callback(PCM_DMAST_STARTED); |
113 | } | 113 | } |
114 | 114 | ||
115 | if (l >= lend) | 115 | if (l >= lend) |
116 | return; | 116 | return; |
117 | 117 | ||
118 | pcm_play_get_more_callback((void**)&p, &p_size); | 118 | new_buffer = pcm_play_dma_complete_callback(PCM_DMAST_OK, |
119 | 119 | &p, &p_size); | |
120 | if (p_size) | ||
121 | new_buffer = true; | ||
122 | } | 120 | } |
123 | while (p_size); | 121 | while (p_size); |
124 | } | 122 | } |
diff --git a/firmware/target/arm/pp/pcm-pp.c b/firmware/target/arm/pp/pcm-pp.c index 1b38994f7b..99d46a6096 100644 --- a/firmware/target/arm/pp/pcm-pp.c +++ b/firmware/target/arm/pp/pcm-pp.c | |||
@@ -30,26 +30,6 @@ | |||
30 | 30 | ||
31 | /** DMA **/ | 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 | struct dma_data | 33 | struct dma_data |
54 | { | 34 | { |
55 | /* NOTE: The order of size and p is important if you use assembler | 35 | /* NOTE: The order of size and p is important if you use assembler |
@@ -57,6 +37,8 @@ struct dma_data | |||
57 | union | 37 | union |
58 | { | 38 | { |
59 | unsigned long addr; | 39 | unsigned long addr; |
40 | const void *p_r; | ||
41 | void *p_w; | ||
60 | uint32_t *p16; /* For packed 16-16 stereo pairs */ | 42 | uint32_t *p16; /* For packed 16-16 stereo pairs */ |
61 | uint16_t *p32; /* For individual samples converted to 32-bit */ | 43 | uint16_t *p32; /* For individual samples converted to 32-bit */ |
62 | }; | 44 | }; |
@@ -113,56 +95,208 @@ void pcm_dma_apply_settings(void) | |||
113 | } | 95 | } |
114 | 96 | ||
115 | #if defined(CPU_PP502x) | 97 | #if defined(CPU_PP502x) |
116 | /* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */ | 98 | /* 16-bit, L-R packed into 32 bits with left in the least significant halfword */ |
117 | void ICODE_ATTR __attribute__((interrupt("FIQ"))) fiq_playback(void) | 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) | ||
126 | { | ||
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 | } | ||
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) | ||
118 | { | 199 | { |
119 | bool new_buffer = false; | 200 | CPU_INT_EN = DMA_MASK; |
120 | register size_t size; | 201 | } |
121 | 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 | DMA0_STATUS; /* Clear any pending interrupt */ | 207 | DMA0_STATUS; /* Clear any pending interrupt */ |
123 | 208 | ||
124 | size = (DMA0_CMD & 0xffff) + 4; /* Get size of trasfer that caused this | 209 | size_t size = (DMA0_CMD & 0xffff) + 4; /* Get size of trasfer that caused |
125 | interrupt */ | 210 | this interrupt */ |
126 | dma_play_data.addr += size; | 211 | dma_play_data.addr += size; |
127 | dma_play_data.size -= size; | 212 | dma_play_data.size -= size; |
128 | 213 | ||
129 | while (1) | 214 | if (LIKELY(dma_play_data.size != 0)) { |
130 | { | 215 | /* Begin next segment */ |
131 | if (dma_play_data.size > 0) { | 216 | dma_tx_start(false); |
132 | size = MAX_DMA_CHUNK_SIZE; | 217 | } |
133 | /* Not at least MAX_DMA_CHUNK_SIZE left or there would be less | 218 | else if (pcm_play_dma_complete_callback(PCM_DMAST_OK, &dma_play_data.p_r, |
134 | * than a FIFO's worth of data after this transfer? */ | 219 | &dma_play_data.size)) { |
135 | if (size + 16*4 > dma_play_data.size) | 220 | dma_play_data.addr = dma_tx_buf_prepare(dma_play_data.p_r); |
136 | size = dma_play_data.size; | 221 | dma_tx_start(false); |
137 | 222 | pcm_play_dma_status_callback(PCM_DMAST_STARTED); | |
138 | /* Set the new DMA values and activate channel */ | 223 | } |
139 | DMA0_RAM_ADDR = dma_play_data.addr; | 224 | } |
140 | DMA0_CMD = DMA_PLAY_CONFIG | (size - 4) | DMA_CMD_START; | ||
141 | |||
142 | if (new_buffer) | ||
143 | pcm_play_dma_started_callback(); | ||
144 | return; | ||
145 | } | ||
146 | 225 | ||
147 | new_buffer = true; | 226 | #else /* !defined (CPU_PP502x) */ |
148 | 227 | ||
149 | /* Buffer empty. Try to get more. */ | 228 | /* 32-bit, one left 32-bit sample followed by one right 32-bit sample */ |
150 | pcm_play_get_more_callback((void **)&dma_play_data.addr, | 229 | #define SAMPLE_SIZE 32 |
151 | &dma_play_data.size); | ||
152 | 230 | ||
153 | if (dma_play_data.size == 0) { | 231 | static void dma_tx_init(void) |
154 | /* No more data */ | 232 | { |
155 | return; | 233 | /* Set up banked registers for FIQ mode */ |
156 | } | ||
157 | 234 | ||
158 | if (dma_play_data.addr < UNCACHED_BASE_ADDR) { | 235 | /* Use non-banked registers for scratch. */ |
159 | /* Flush any pending cache writes */ | 236 | register volatile void *iiscfg asm("r0") = &IISCONFIG; |
160 | dma_play_data.addr = UNCACHED_ADDR(dma_play_data.addr); | 237 | register volatile void *dmapd asm("r1") = &dma_play_data; |
161 | commit_dcache(); | 238 | |
162 | } | 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"); | ||
250 | |||
251 | /* FIQ priority for I2S */ | ||
252 | CPU_INT_PRIORITY |= IIS_MASK; | ||
253 | CPU_INT_EN = IIS_MASK; | ||
254 | } | ||
255 | |||
256 | static inline void dma_tx_setup(void) | ||
257 | { | ||
258 | /* Nothing to do */ | ||
259 | } | ||
260 | |||
261 | static inline unsigned long dma_tx_buf_prepare(const void *addr) | ||
262 | { | ||
263 | return (unsigned long)addr; | ||
264 | } | ||
265 | |||
266 | static inline void dma_tx_start(bool begin) | ||
267 | { | ||
268 | if (begin) { | ||
269 | IISCONFIG &= ~IIS_TXFIFOEN; /* Stop transmitting */ | ||
163 | } | 270 | } |
271 | |||
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 | } | ||
278 | |||
279 | if (begin) { | ||
280 | IISCONFIG |= IIS_TXFIFOEN; /* Start transmitting */ | ||
281 | } | ||
282 | } | ||
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; | ||
164 | } | 298 | } |
165 | #else | 299 | |
166 | /* ASM optimised FIQ handler. Checks for the minimum allowed loop cycles by | 300 | /* ASM optimised FIQ handler. Checks for the minimum allowed loop cycles by |
167 | * evalutation of free IISFIFO-slots against available source buffer words. | 301 | * evalutation of free IISFIFO-slots against available source buffer words. |
168 | * Through this it is possible to move the check for IIS_TX_FREE_COUNT outside | 302 | * Through this it is possible to move the check for IIS_TX_FREE_COUNT outside |
@@ -173,150 +307,123 @@ void ICODE_ATTR __attribute__((interrupt("FIQ"))) fiq_playback(void) | |||
173 | * ASM implementation (not used anymore): GCC fails to make use of the fact | 307 | * ASM implementation (not used anymore): GCC fails to make use of the fact |
174 | * that FIQ mode has registers r8-r14 banked, and so does not need to be saved. | 308 | * that FIQ mode has registers r8-r14 banked, and so does not need to be saved. |
175 | * This routine uses only these registers, and so will never touch the stack | 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 | * C version is still included below for reference and testing. | 311 | * C version is still included below for reference and testing. |
178 | */ | 312 | */ |
179 | #if 1 | 313 | #if 1 |
180 | void fiq_playback(void) ICODE_ATTR __attribute__((naked)); | 314 | void fiq_playback(void) ICODE_ATTR __attribute__((naked)); |
181 | void fiq_playback(void) | 315 | void fiq_playback(void) |
182 | { | 316 | { |
183 | /* r10 contains IISCONFIG address (set in crt0.S to minimise code in actual | 317 | /* r8 and r9 contains local copies of p and size respectively. |
184 | * FIQ handler. r11 contains address of p (also set in crt0.S). Most other | 318 | * r10 contains IISCONFIG address (set during PCM init to minimize code in |
185 | * addresses we need are generated by using offsets with these two. | 319 | * FIQ handler.Most other addresses we need are generated by using offsets |
186 | * r10 + 0x40 is IISFIFO_WR, and r10 + 0x0c is IISFIFO_CFG. | 320 | * from this. |
187 | * r8 and r9 contains local copies of p and size respectively. | 321 | * r10 + 0x40 is IISFIFO_WR, and r10 + 0x1c is IISFIFO_CFG. |
188 | * r0-r3 and r12 is a working register. | 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 | asm volatile ( | 328 | asm volatile ( |
191 | "stmfd sp!, { r0-r4, lr } \n" /* stack scratch regs and lr */ | 329 | /* No external calls */ |
192 | 330 | "sub lr, lr, #4 \n" /* Prepare return address */ | |
193 | "mov r4, #0 \n" /* Was the callback called? */ | 331 | "stmfd sp!, { lr } \n" /* stack lr so we can use it */ |
194 | #if CONFIG_CPU == PP5002 | 332 | "ldr r12, =0xcf001040 \n" /* Some magic from iPodLinux ... */ |
195 | "ldr r12, =0xcf001040 \n" /* Some magic from iPodLinux */ | 333 | "ldr r12, [r12] \n" /* ... actually a DMA INT ack? */ |
196 | "ldr r12, [r12] \n" | 334 | "ldmia r11, { r8-r9 } \n" /* r8 = p, r9 = size */ |
197 | #endif | 335 | "cmp r9, #0 \n" /* is size 0? */ |
198 | "ldmia r11, { r8-r9 } \n" /* r8 = p, r9 = size */ | 336 | "beq 1f \n" /* if so, ask PCM for more data */ |
199 | "cmp r9, #0 \n" /* is size 0? */ | 337 | |
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 */ |
201 | 339 | "and r14, r14, #(0xe<<23) \n" /* r14 = (IIS_TX_FREE_COUNT & ~1) << 23 */ | |
202 | #if SAMPLE_SIZE == 16 | 340 | "cmp r9, r14, lsr #22 \n" /* number of words from source */ |
203 | ".check_fifo: \n" | 341 | "movlo r14, r9, lsl #22 \n" /* r14 = amount of allowed loops */ |
204 | "ldr r0, [r10, %[cfg]] \n" /* read IISFIFO_CFG to check FIFO status */ | 342 | "sub r9, r9, r14, lsr #22 \n" /* r14 words will be written in loop */ |
205 | "and r0, r0, %[mask] \n" /* r0 = IIS_TX_FREE_COUNT << 16 (PP502x) */ | 343 | "0: \n" |
206 | 344 | "ldr r12, [r8], #4 \n" /* load left-right pair */ | |
207 | "mov r1, r0, lsr #16 \n" /* number of free FIFO slots */ | 345 | "subs r14, r14, #(0x2<<23) \n" /* one more loop? ... */ |
208 | "cmp r1, r9, lsr #2 \n" /* number of words from source */ | 346 | "strh r12, [r10, #0x40] \n" /* left sample to IISFIFO_WR */ |
209 | "movgt r1, r9, lsr #2 \n" /* r1 = amount of allowed loops */ | 347 | "mov r12, r12, lsr #16 \n" /* put right sample in bottom 16 bits */ |
210 | "sub r9, r9, r1, lsl #2 \n" /* r1 words will be written in following loop */ | 348 | "strh r12, [r10, #0x40] \n" /* right sample to IISFIFO_WR */ |
211 | 349 | "bhi 0b \n" /* ... yes, continue */ | |
212 | "subs r1, r1, #2 \n" | 350 | |
213 | ".fifo_loop_2: \n" | 351 | "cmp r9, #0 \n" /* either FIFO full or size empty? */ |
214 | "ldmgeia r8!, {r2, r12} \n" /* load four samples */ | 352 | "stmneia r11, { r8-r9 } \n" /* save p and size, if not empty */ |
215 | "strge r2 , [r10, %[wr]] \n" /* write sample 0-1 to IISFIFO_WR */ | 353 | "ldmnefd sp!, { pc }^ \n" /* RFE if not empty */ |
216 | "strge r12, [r10, %[wr]] \n" /* write sample 2-3 to IISFIFO_WR */ | 354 | |
217 | "subges r1, r1, #2 \n" /* one more loop? */ | 355 | /* Making external calls */ |
218 | "bge .fifo_loop_2 \n" /* yes, continue */ | 356 | "1: \n" |
219 | 357 | "stmfd sp!, { r0-r3 } \n" /* Must save volatiles */ | |
220 | "tst r1, #1 \n" /* two samples (one word) left? */ | 358 | "2: \n" |
221 | "ldrne r12, [r8], #4 \n" /* load two samples */ | 359 | "mov r0, %0 \n" /* r0 = status */ |
222 | "strne r12, [r10, %[wr]] \n" /* write sample 0-1 to IISFIFO_WR */ | 360 | "mov r1, r11 \n" /* r1 = &dma_play_data.p_r */ |
223 | #elif SAMPLE_SIZE == 32 | 361 | "add r2, r11, #4 \n" /* r2 = &dma_play_data.size */ |
224 | ".check_fifo: \n" | 362 | "ldr r3, =pcm_play_dma_complete_callback \n" |
225 | "ldr r0, [r10, %[cfg]] \n" /* read IISFIFO_CFG to check FIFO status */ | 363 | "mov lr, pc \n" /* long call (not in same section) */ |
226 | "and r0, r0, %[mask] \n" /* r0 = IIS_TX_FREE_COUNT << 23 (PP5002) */ | 364 | "bx r3 \n" |
227 | 365 | "cmp r0, #0 \n" /* more data? */ | |
228 | "movs r1, r0, lsr #24 \n" /* number of free pairs of FIFO slots */ | 366 | "ldmeqfd sp!, { r0-r3, pc }^ \n" /* no? -> exit */ |
229 | "beq .fifo_fill_complete \n" /* no complete pair? -> exit */ | 367 | |
230 | "cmp r1, r9, lsr #2 \n" /* number of words from source */ | 368 | "ldr r14, [r10, #0x1c] \n" /* read IISFIFO_CFG to check FIFO status */ |
231 | "movgt r1, r9, lsr #2 \n" /* r1 = amount of allowed loops */ | 369 | "ands r14, r14, #(0xe<<23) \n" /* r14 = (IIS_TX_FREE_COUNT & ~1) << 23 */ |
232 | "sub r9, r9, r1, lsl #2 \n" /* r1 words will be written in following loop */ | 370 | "bne 4f \n" |
233 | 371 | "3: \n" /* inform of started status if registered */ | |
234 | ".fifo_loop: \n" | 372 | "ldr r1, =pcm_play_status_callback \n" |
235 | "ldr r12, [r8], #4 \n" /* load two samples */ | 373 | "ldr r1, [r1] \n" |
236 | "mov r2 , r12, lsl #16 \n" /* put left sample at the top bits */ | 374 | "cmp r1, #0 \n" |
237 | "str r2 , [r10, %[wr]] \n" /* write top sample to IISFIFO_WR */ | 375 | "movne r0, %1 \n" |
238 | "str r12, [r10, %[wr]] \n" /* write low sample to IISFIFO_WR*/ | 376 | "movne lr, pc \n" |
239 | "subs r1, r1, #1 \n" /* one more loop? */ | 377 | "bxne r1 \n" |
240 | "bgt .fifo_loop \n" /* yes, continue */ | 378 | "ldmfd sp!, { r0-r3, pc }^ \n" /* exit */ |
241 | 379 | "4: \n" | |
242 | ".fifo_fill_complete: \n" | 380 | "ldmia r11, { r8-r9 } \n" /* load new p and size */ |
243 | #endif | 381 | "cmp r9, r14, lsr #22 \n" /* number of words from source */ |
244 | "cmp r4, #0 \n" /* If fill came after get_more... */ | 382 | "movlo r14, r9, lsl #22 \n" /* r14 = amount of allowed loops */ |
245 | "beq .still_old_buffer \n" | 383 | "sub r9, r9, r14, lsr #22 \n" /* r14 words will be written in loop */ |
246 | "mov r4, #0 \n" | 384 | "0: \n" |
247 | "ldr r2, =pcm_play_dma_started \n" | 385 | "ldr r12, [r8], #4 \n" /* load left-right pair */ |
248 | "ldrne r2, [r2] \n" | 386 | "subs r14, r14, #(0x2<<23) \n" /* one more loop? ... */ |
249 | "cmp r2, #0 \n" | 387 | "strh r12, [r10, #0x40] \n" /* left sample to IISFIFO_WR */ |
250 | "movne lr, pc \n" | 388 | "mov r12, r12, lsr #16 \n" /* put right sample in bottom 16 bits */ |
251 | "bxne r2 \n" | 389 | "strh r12, [r10, #0x40] \n" /* right sample to IISFIFO_WR */ |
252 | 390 | "bhi 0b \n" /* ... yes, continue */ | |
253 | ".still_old_buffer: \n" | 391 | "stmia r11, { r8-r9 } \n" /* save p and size */ |
254 | "cmp r9, #0 \n" /* either FIFO is full or source buffer is empty */ | 392 | |
255 | "bgt .exit \n" /* if source buffer is not empty, FIFO must be full */ | 393 | "cmp r9, #0 \n" /* used up data in FIFO fill? */ |
256 | 394 | "bne 3b \n" /* no? -> go return */ | |
257 | ".more_data: \n" | 395 | "b 2b \n" /* yes -> get even more */ |
258 | "mov r4, #1 \n" /* Remember we did this */ | 396 | ".ltorg \n" |
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" | ||
273 | : /* These must only be integers! No regs */ | 397 | : /* These must only be integers! No regs */ |
274 | : [mask]"i"(IIS_TX_FREE_MASK), | 398 | : "i"(PCM_DMAST_OK), "i"(PCM_DMAST_STARTED)); |
275 | [cfg]"i"((int)&IISFIFO_CFG - (int)&IISCONFIG), | ||
276 | [wr]"i"((int)&IISFIFO_WR - (int)&IISCONFIG) | ||
277 | ); | ||
278 | } | 399 | } |
400 | |||
279 | #else /* C version for reference */ | 401 | #else /* C version for reference */ |
280 | void fiq_playback(void) __attribute__((interrupt ("FIQ"))) ICODE_ATTR; | 402 | |
281 | /* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */ | 403 | /* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */ |
404 | void fiq_playback(void) ICODE_ATTR __attribute__((interrupt ("FIQ"))); | ||
282 | void fiq_playback(void) | 405 | void fiq_playback(void) |
283 | { | 406 | { |
284 | bool new_buffer = false; | ||
285 | |||
286 | #if CONFIG_CPU == PP5002 | ||
287 | inl(0xcf001040); | 407 | inl(0xcf001040); |
288 | #endif | ||
289 | 408 | ||
290 | do { | 409 | if (LIKELY(dma_play_data.size != 0)) { |
291 | while (dma_play_data.size > 0) { | 410 | dma_tx_start(false); |
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 | } | ||
307 | 411 | ||
308 | if (new_buffer) { | 412 | if (dma_play_data.size != 0) { |
309 | new_buffer = false; | 413 | /* Still more data */ |
310 | pcm_play_dma_started_callback(); | 414 | return; |
311 | } | 415 | } |
416 | } | ||
312 | 417 | ||
313 | /* p is empty, get some more data */ | 418 | while (pcm_play_dma_complete_callback(PCM_DMAST_OK, &dma_play_data.p_r, |
314 | pcm_play_get_more_callback((void **)&dma_play_data.addr, | 419 | &dma_play_data.size)) { |
315 | &dma_play_data.size); | 420 | dma_tx_start(false); |
316 | new_buffer = true; | 421 | pcm_play_dma_status_callback(PCM_DMAST_STARTED); |
317 | } while (dma_play_data.size); | ||
318 | 422 | ||
319 | /* No more data */ | 423 | if (dma_play_data.size != 0) { |
424 | return; | ||
425 | } | ||
426 | } | ||
320 | } | 427 | } |
321 | #endif /* ASM / C selection */ | 428 | #endif /* ASM / C selection */ |
322 | #endif /* CPU_PP502x */ | 429 | #endif /* CPU_PP502x */ |
@@ -329,11 +436,7 @@ void pcm_play_lock(void) | |||
329 | int status = disable_fiq_save(); | 436 | int status = disable_fiq_save(); |
330 | 437 | ||
331 | if (++dma_play_data.locked == 1) { | 438 | if (++dma_play_data.locked == 1) { |
332 | #ifdef CPU_PP502x | 439 | dma_tx_lock(); |
333 | CPU_INT_DIS = DMA_MASK; | ||
334 | #else | ||
335 | IIS_IRQTX_REG &= ~IIS_IRQTX; | ||
336 | #endif | ||
337 | } | 440 | } |
338 | 441 | ||
339 | restore_fiq(status); | 442 | restore_fiq(status); |
@@ -341,89 +444,25 @@ void pcm_play_lock(void) | |||
341 | 444 | ||
342 | void pcm_play_unlock(void) | 445 | void pcm_play_unlock(void) |
343 | { | 446 | { |
344 | int status = disable_fiq_save(); | 447 | int status = disable_fiq_save(); |
345 | 448 | ||
346 | if (--dma_play_data.locked == 0 && dma_play_data.state != 0) { | 449 | if (--dma_play_data.locked == 0 && dma_play_data.state != 0) { |
347 | #ifdef CPU_PP502x | 450 | dma_tx_unlock(); |
348 | CPU_INT_EN = DMA_MASK; | ||
349 | #else | ||
350 | IIS_IRQTX_REG |= IIS_IRQTX; | ||
351 | #endif | ||
352 | } | 451 | } |
353 | 452 | ||
354 | restore_fiq(status); | 453 | restore_fiq(status); |
355 | } | 454 | } |
356 | 455 | ||
357 | static void play_start_pcm(void) | 456 | static void play_start_pcm(void) |
358 | { | 457 | { |
359 | fiq_function = fiq_playback; | 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 | dma_play_data.state = 1; | 459 | dma_play_data.state = 1; |
371 | #else | 460 | dma_tx_start(true); |
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 | ||
391 | } | 461 | } |
392 | 462 | ||
393 | static void play_stop_pcm(void) | 463 | static void play_stop_pcm(void) |
394 | { | 464 | { |
395 | #ifdef CPU_PP502x | 465 | dma_tx_stop(); |
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 | ||
427 | 466 | ||
428 | /* Wait for FIFO to empty */ | 467 | /* Wait for FIFO to empty */ |
429 | while (!IIS_TX_IS_EMPTY); | 468 | while (!IIS_TX_IS_EMPTY); |
@@ -433,30 +472,17 @@ static void play_stop_pcm(void) | |||
433 | 472 | ||
434 | void pcm_play_dma_start(const void *addr, size_t size) | 473 | void pcm_play_dma_start(const void *addr, size_t size) |
435 | { | 474 | { |
475 | pcm_play_dma_stop(); | ||
476 | |||
436 | #if NUM_CORES > 1 | 477 | #if NUM_CORES > 1 |
437 | /* This will become more important later - and different ! */ | 478 | /* This will become more important later - and different ! */ |
438 | dma_play_data.core = processor_id(); /* save initiating core */ | 479 | dma_play_data.core = processor_id(); /* save initiating core */ |
439 | #endif | 480 | #endif |
440 | 481 | ||
441 | pcm_play_dma_stop(); | 482 | dma_tx_setup(); |
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 | } | ||
449 | 483 | ||
450 | dma_play_data.addr = (unsigned long)addr; | 484 | dma_play_data.addr = dma_tx_buf_prepare(addr); |
451 | dma_play_data.size = size; | 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 | play_start_pcm(); | 486 | play_start_pcm(); |
461 | } | 487 | } |
462 | 488 | ||
@@ -490,39 +516,7 @@ void pcm_play_dma_init(void) | |||
490 | /* Initialize default register values. */ | 516 | /* Initialize default register values. */ |
491 | audiohw_init(); | 517 | audiohw_init(); |
492 | 518 | ||
493 | #ifdef CPU_PP502x | 519 | dma_tx_init(); |
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 | ||
526 | 520 | ||
527 | IISCONFIG |= IIS_TXFIFOEN; | 521 | IISCONFIG |= IIS_TXFIFOEN; |
528 | } | 522 | } |
@@ -649,11 +643,15 @@ void fiq_record(void) | |||
649 | } | 643 | } |
650 | } | 644 | } |
651 | 645 | ||
652 | pcm_rec_more_ready_callback(0, (void *)&dma_rec_data.addr, | 646 | if (pcm_rec_dma_complete_callback(PCM_DMAST_OK, &dma_rec_data.p_w, |
653 | &dma_rec_data.size); | 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 | void fiq_record(void) | 655 | void fiq_record(void) |
658 | { | 656 | { |
659 | while (dma_rec_data.size > 0) { | 657 | while (dma_rec_data.size > 0) { |
@@ -664,17 +662,20 @@ void fiq_record(void) | |||
664 | #if SAMPLE_SIZE == 16 | 662 | #if SAMPLE_SIZE == 16 |
665 | *dma_rec_data.p16++ = IISFIFO_RD; | 663 | *dma_rec_data.p16++ = IISFIFO_RD; |
666 | #elif SAMPLE_SIZE == 32 | 664 | #elif SAMPLE_SIZE == 32 |
667 | *dma_rec_data.p32++ = IISFIFO_RD >> 16; | 665 | *dma_rec_data.p32++ = IISFIFO_RDH; |
668 | *dma_rec_data.p32++ = IISFIFO_RD >> 16; | 666 | *dma_rec_data.p32++ = IISFIFO_RDH; |
669 | #endif | 667 | #endif |
670 | dma_rec_data.size -= 4; | 668 | dma_rec_data.size -= 4; |
671 | } | 669 | } |
672 | 670 | ||
673 | pcm_rec_more_ready_callback(0, (void *)&dma_rec_data.addr, | 671 | if (pcm_rec_dma_complete_callback(PCM_DMAST_OK, &dma_rec_data.p_w, |
674 | &dma_rec_data.size); | 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 | void pcm_rec_dma_stop(void) | 680 | void pcm_rec_dma_stop(void) |
680 | { | 681 | { |
diff --git a/firmware/target/arm/rk27xx/pcm-rk27xx.c b/firmware/target/arm/rk27xx/pcm-rk27xx.c index 80a8d462ea..e4318de408 100644 --- a/firmware/target/arm/rk27xx/pcm-rk27xx.c +++ b/firmware/target/arm/rk27xx/pcm-rk27xx.c | |||
@@ -273,15 +273,13 @@ size_t pcm_get_bytes_waiting(void) | |||
273 | /* audio DMA ISR called when chunk from callers buffer has been transfered */ | 273 | /* audio DMA ISR called when chunk from callers buffer has been transfered */ |
274 | void INT_HDMA(void) | 274 | void INT_HDMA(void) |
275 | { | 275 | { |
276 | void *start; | 276 | const void *start; |
277 | size_t size; | 277 | size_t size; |
278 | 278 | ||
279 | pcm_play_get_more_callback(&start, &size); | 279 | if (pcm_play_dma_complete_callback(PCM_DMAST_OK, &start, &size)) |
280 | |||
281 | if (size != 0) | ||
282 | { | 280 | { |
283 | hdma_i2s_transfer(start, size); | 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 | ||
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c index 35905645dd..a1c854a0df 100644 --- a/firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c +++ b/firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c | |||
@@ -215,16 +215,14 @@ void pcm_play_dma_pause(bool pause) | |||
215 | 215 | ||
216 | void fiq_handler(void) | 216 | void fiq_handler(void) |
217 | { | 217 | { |
218 | static void *start; | 218 | static const void *start; |
219 | static size_t size; | 219 | static size_t size; |
220 | 220 | ||
221 | /* clear any pending interrupt */ | 221 | /* clear any pending interrupt */ |
222 | SRCPND = DMA2_MASK; | 222 | SRCPND = DMA2_MASK; |
223 | 223 | ||
224 | /* Buffer empty. Try to get more. */ | 224 | /* Buffer empty. Try to get more. */ |
225 | pcm_play_get_more_callback(&start, &size); | 225 | if (!pcm_play_dma_complete_callback(PCM_DMAST_OK, &start, &size)) |
226 | |||
227 | if (size == 0) | ||
228 | return; | 226 | return; |
229 | 227 | ||
230 | /* Flush any pending cache writes */ | 228 | /* Flush any pending cache writes */ |
@@ -237,7 +235,7 @@ void fiq_handler(void) | |||
237 | /* Re-Activate the channel */ | 235 | /* Re-Activate the channel */ |
238 | DMASKTRIG2 = 0x2; | 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 | size_t pcm_get_bytes_waiting(void) | 241 | size_t pcm_get_bytes_waiting(void) |
diff --git a/firmware/target/arm/s3c2440/mini2440/pcm-mini2440.c b/firmware/target/arm/s3c2440/mini2440/pcm-mini2440.c index a4f58a8e06..943cbb2ade 100644 --- a/firmware/target/arm/s3c2440/mini2440/pcm-mini2440.c +++ b/firmware/target/arm/s3c2440/mini2440/pcm-mini2440.c | |||
@@ -255,16 +255,14 @@ void pcm_play_dma_pause(bool pause) | |||
255 | 255 | ||
256 | void fiq_handler(void) | 256 | void fiq_handler(void) |
257 | { | 257 | { |
258 | static void *start; | 258 | static const void *start; |
259 | static size_t size; | 259 | static size_t size; |
260 | 260 | ||
261 | /* clear any pending interrupt */ | 261 | /* clear any pending interrupt */ |
262 | SRCPND = DMA2_MASK; | 262 | SRCPND = DMA2_MASK; |
263 | 263 | ||
264 | /* Buffer empty. Try to get more. */ | 264 | /* Buffer empty. Try to get more. */ |
265 | pcm_play_get_more_callback(&start, &size); | 265 | if (!pcm_play_dma_complete_callback(PCM_DMAST_OK, &start, &size)) |
266 | |||
267 | if (size == 0) | ||
268 | return; | 266 | return; |
269 | 267 | ||
270 | /* Flush any pending cache writes */ | 268 | /* Flush any pending cache writes */ |
@@ -277,7 +275,7 @@ void fiq_handler(void) | |||
277 | /* Re-Activate the channel */ | 275 | /* Re-Activate the channel */ |
278 | DMASKTRIG2 = 0x2; | 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 | size_t pcm_get_bytes_waiting(void) | 281 | size_t pcm_get_bytes_waiting(void) |
diff --git a/firmware/target/arm/s5l8700/pcm-s5l8700.c b/firmware/target/arm/s5l8700/pcm-s5l8700.c index 7b4258fa68..c5a5bcf74f 100644 --- a/firmware/target/arm/s5l8700/pcm-s5l8700.c +++ b/firmware/target/arm/s5l8700/pcm-s5l8700.c | |||
@@ -116,9 +116,10 @@ void INT_DMA(void) | |||
116 | { | 116 | { |
117 | if (!nextsize) | 117 | if (!nextsize) |
118 | { | 118 | { |
119 | pcm_play_get_more_callback((void**)&nextbuf, &nextsize); | 119 | new_buffer = pcm_play_dma_complete_callback(PCM_DMAST_OK, |
120 | if (!nextsize) break; | 120 | (const void**)&nextbuf, &nextsize); |
121 | new_buffer = true; | 121 | if (!new_buffer) |
122 | break; | ||
122 | } | 123 | } |
123 | queuedsize = MIN(sizeof(dblbuf), nextsize / 2); | 124 | queuedsize = MIN(sizeof(dblbuf), nextsize / 2); |
124 | nextsize -= queuedsize; | 125 | nextsize -= queuedsize; |
@@ -133,7 +134,7 @@ void INT_DMA(void) | |||
133 | 134 | ||
134 | if (new_buffer) | 135 | if (new_buffer) |
135 | { | 136 | { |
136 | pcm_play_dma_started_callback(); | 137 | pcm_play_dma_status_callback(PCM_DMAST_STARTED); |
137 | new_buffer = false; | 138 | new_buffer = false; |
138 | } | 139 | } |
139 | } | 140 | } |
diff --git a/firmware/target/arm/s5l8702/pcm-s5l8702.c b/firmware/target/arm/s5l8702/pcm-s5l8702.c index b58ef0f4d3..1442afa420 100644 --- a/firmware/target/arm/s5l8702/pcm-s5l8702.c +++ b/firmware/target/arm/s5l8702/pcm-s5l8702.c | |||
@@ -65,7 +65,7 @@ void INT_DMAC0C0(void) | |||
65 | DMAC0INTTCCLR = 1; | 65 | DMAC0INTTCCLR = 1; |
66 | if (!pcm_remaining) | 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 | pcm_chunksize = pcm_remaining; | 69 | pcm_chunksize = pcm_remaining; |
70 | } | 70 | } |
71 | if (!pcm_remaining) | 71 | if (!pcm_remaining) |
@@ -115,7 +115,7 @@ void INT_DMAC0C0(void) | |||
115 | } | 115 | } |
116 | else DMAC0C0NEXTLLI = pcm_lli; | 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 | void pcm_play_dma_start(const void* addr, size_t size) | 121 | void pcm_play_dma_start(const void* addr, size_t size) |
diff --git a/firmware/target/arm/tms320dm320/mrobe-500/pcm-mr500.c b/firmware/target/arm/tms320dm320/mrobe-500/pcm-mr500.c index 91d6b66130..d23c93de39 100644 --- a/firmware/target/arm/tms320dm320/mrobe-500/pcm-mr500.c +++ b/firmware/target/arm/tms320dm320/mrobe-500/pcm-mr500.c | |||
@@ -33,7 +33,7 @@ | |||
33 | /* This is global to save some latency when pcm_play_dma_get_peak_buffer is | 33 | /* This is global to save some latency when pcm_play_dma_get_peak_buffer is |
34 | * called. | 34 | * called. |
35 | */ | 35 | */ |
36 | static void *start; | 36 | static const void *start; |
37 | 37 | ||
38 | void pcm_play_dma_postinit(void) | 38 | void pcm_play_dma_postinit(void) |
39 | { | 39 | { |
@@ -164,9 +164,7 @@ void DSPHINT(void) | |||
164 | 164 | ||
165 | case MSG_REFILL: | 165 | case MSG_REFILL: |
166 | /* Buffer empty. Try to get more. */ | 166 | /* Buffer empty. Try to get more. */ |
167 | pcm_play_get_more_callback(&start, &size); | 167 | if (pcm_play_dma_complete_callback(PCM_DMAST_OK, &start, &size)) |
168 | |||
169 | if (size != 0) | ||
170 | { | 168 | { |
171 | unsigned long sdem_addr=(unsigned long)start - CONFIG_SDRAM_START; | 169 | unsigned long sdem_addr=(unsigned long)start - CONFIG_SDRAM_START; |
172 | /* Flush any pending cache writes */ | 170 | /* Flush any pending cache writes */ |
@@ -180,7 +178,7 @@ void DSPHINT(void) | |||
180 | DEBUGF("pcm_sdram at 0x%08lx, sdem_addr 0x%08lx", | 178 | DEBUGF("pcm_sdram at 0x%08lx, sdem_addr 0x%08lx", |
181 | (unsigned long)start, (unsigned long)sdem_addr); | 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 | break; | 184 | break; |
diff --git a/firmware/target/arm/tms320dm320/sansa-connect/pcm-sansaconnect.c b/firmware/target/arm/tms320dm320/sansa-connect/pcm-sansaconnect.c index 8b1fbf95e4..6e640bdf12 100644 --- a/firmware/target/arm/tms320dm320/sansa-connect/pcm-sansaconnect.c +++ b/firmware/target/arm/tms320dm320/sansa-connect/pcm-sansaconnect.c | |||
@@ -34,7 +34,7 @@ | |||
34 | /* This is global to save some latency when pcm_play_dma_get_peak_buffer is | 34 | /* This is global to save some latency when pcm_play_dma_get_peak_buffer is |
35 | * called. | 35 | * called. |
36 | */ | 36 | */ |
37 | static void *start; | 37 | static const void *start; |
38 | static int dma_channel; | 38 | static int dma_channel; |
39 | 39 | ||
40 | void pcm_play_dma_postinit(void) | 40 | void pcm_play_dma_postinit(void) |
@@ -171,9 +171,7 @@ void DSPHINT(void) | |||
171 | 171 | ||
172 | case MSG_REFILL: | 172 | case MSG_REFILL: |
173 | /* Buffer empty. Try to get more. */ | 173 | /* Buffer empty. Try to get more. */ |
174 | pcm_play_get_more_callback(&start, &size); | 174 | if (pcm_play_dma_complete_callback(PCM_DMAST_OK, &start, &size)) |
175 | |||
176 | if (size != 0) | ||
177 | { | 175 | { |
178 | unsigned long sdem_addr=(unsigned long)start - CONFIG_SDRAM_START; | 176 | unsigned long sdem_addr=(unsigned long)start - CONFIG_SDRAM_START; |
179 | /* Flush any pending cache writes */ | 177 | /* Flush any pending cache writes */ |
@@ -187,7 +185,7 @@ void DSPHINT(void) | |||
187 | DEBUGF("pcm_sdram at 0x%08lx, sdem_addr 0x%08lx", | 185 | DEBUGF("pcm_sdram at 0x%08lx, sdem_addr 0x%08lx", |
188 | (unsigned long)start, (unsigned long)sdem_addr); | 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 | break; | 191 | break; |
diff --git a/firmware/target/coldfire/pcm-coldfire.c b/firmware/target/coldfire/pcm-coldfire.c index e95d445337..2e2312f7ae 100644 --- a/firmware/target/coldfire/pcm-coldfire.c +++ b/firmware/target/coldfire/pcm-coldfire.c | |||
@@ -294,8 +294,6 @@ void DMA0(void) __attribute__ ((interrupt_handler, section(".icode"))); | |||
294 | void DMA0(void) | 294 | void DMA0(void) |
295 | { | 295 | { |
296 | unsigned long res = DSR0; | 296 | unsigned long res = DSR0; |
297 | void *start; | ||
298 | size_t size; | ||
299 | 297 | ||
300 | and_l(~(DMA_EEXT | DMA_INT), &DCR0); /* per request and int OFF */ | 298 | and_l(~(DMA_EEXT | DMA_INT), &DCR0); /* per request and int OFF */ |
301 | DSR0 = 1; /* Clear interrupt and errors */ | 299 | DSR0 = 1; /* Clear interrupt and errors */ |
@@ -311,17 +309,18 @@ void DMA0(void) | |||
311 | #endif | 309 | #endif |
312 | } | 310 | } |
313 | 311 | ||
314 | /* Force stop on error */ | 312 | const void *addr; |
315 | pcm_play_get_more_callback((res & 0x70) ? NULL : &start, &size); | 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 */ | 319 | SAR0 = (unsigned long)addr; /* Source address */ |
320 | BCR0 = size; /* Bytes to transfer */ | 320 | BCR0 = (unsigned long)size; /* Bytes to transfer */ |
321 | or_l(DMA_EEXT | DMA_INT, &DCR0); /* per request and int ON */ | 321 | or_l(DMA_EEXT | DMA_INT, &DCR0); /* per request and int ON */ |
322 | 322 | ||
323 | /* Call buffer callback */ | 323 | pcm_play_dma_status_callback(PCM_DMAST_STARTED); |
324 | pcm_play_dma_started_callback(); | ||
325 | } | 324 | } |
326 | /* else inished playing */ | 325 | /* else inished playing */ |
327 | } /* DMA0 */ | 326 | } /* DMA0 */ |
@@ -368,7 +367,7 @@ void pcm_rec_unlock(void) | |||
368 | 367 | ||
369 | void pcm_rec_dma_start(void *addr, size_t size) | 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 | pcm_rec_dma_stop(); | 371 | pcm_rec_dma_stop(); |
373 | 372 | ||
374 | and_l(~PDIR2_FIFO_RESET, &DATAINCONTROL); | 373 | and_l(~PDIR2_FIFO_RESET, &DATAINCONTROL); |
@@ -430,16 +429,14 @@ void DMA1(void) __attribute__ ((interrupt_handler, section(".icode"))); | |||
430 | void DMA1(void) | 429 | void DMA1(void) |
431 | { | 430 | { |
432 | unsigned long res = DSR1; | 431 | unsigned long res = DSR1; |
433 | int status = 0; | 432 | enum pcm_dma_status status = PCM_DMAST_OK; |
434 | void *start; | ||
435 | size_t size; | ||
436 | 433 | ||
437 | and_l(~(DMA_EEXT | DMA_INT), &DCR1); /* per request and int OFF */ | 434 | and_l(~(DMA_EEXT | DMA_INT), &DCR1); /* per request and int OFF */ |
438 | DSR1 = 1; /* Clear interrupt and errors */ | 435 | DSR1 = 1; /* Clear interrupt and errors */ |
439 | 436 | ||
440 | if (res & 0x70) | 437 | if (res & 0x70) |
441 | { | 438 | { |
442 | status = DMA_REC_ERROR_DMA; | 439 | status = PCM_DMAST_ERR_DMA; |
443 | logf("DMA1 err: %02x", res); | 440 | logf("DMA1 err: %02x", res); |
444 | #if 0 | 441 | #if 0 |
445 | logf(" SAR1: %08x", SAR1); | 442 | logf(" SAR1: %08x", SAR1); |
@@ -456,19 +453,22 @@ void DMA1(void) | |||
456 | * Ignore valnogood since several sources don't set it properly. */ | 453 | * Ignore valnogood since several sources don't set it properly. */ |
457 | /* clear: ebu1cnew, symbolerr, parityerr */ | 454 | /* clear: ebu1cnew, symbolerr, parityerr */ |
458 | INTERRUPTCLEAR = (1 << 25) | (1 << 23) | (1 << 22); | 455 | INTERRUPTCLEAR = (1 << 25) | (1 << 23) | (1 << 22); |
459 | status = DMA_REC_ERROR_SPDIF; | 456 | status = PCM_DMAST_ERR_SPDIF; |
460 | logf("spdif err"); | 457 | logf("spdif err"); |
461 | } | 458 | } |
462 | #endif | 459 | #endif |
463 | 460 | ||
464 | /* Inform PCM we have more data (or error) */ | 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 | BCR1 = (unsigned long)size; /* Bytes to transfer */ | 468 | BCR1 = (unsigned long)size; /* Bytes to transfer */ |
471 | or_l(DMA_EEXT | DMA_INT, &DCR1); /* per request and int ON */ | 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 | } /* DMA1 */ | 473 | } /* DMA1 */ |
474 | 474 | ||
diff --git a/firmware/target/hosted/android/pcm-android.c b/firmware/target/hosted/android/pcm-android.c index 4e58707d0a..7a0f28634e 100644 --- a/firmware/target/hosted/android/pcm-android.c +++ b/firmware/target/hosted/android/pcm-android.c | |||
@@ -80,8 +80,8 @@ Java_org_rockbox_RockboxPCM_nativeWrite(JNIEnv *env, jobject this, | |||
80 | 80 | ||
81 | if (!pcm_data_size) /* get some initial data */ | 81 | if (!pcm_data_size) /* get some initial data */ |
82 | { | 82 | { |
83 | new_buffer = true; | 83 | new_buffer = pcm_play_dma_complete_callback(PCM_DMAST_OK, |
84 | pcm_play_get_more_callback((void**) &pcm_data_start, &pcm_data_size); | 84 | (const void**)&pcm_data_start, &pcm_data_size); |
85 | } | 85 | } |
86 | 86 | ||
87 | while(left > 0 && pcm_data_size) | 87 | while(left > 0 && pcm_data_size) |
@@ -99,7 +99,7 @@ Java_org_rockbox_RockboxPCM_nativeWrite(JNIEnv *env, jobject this, | |||
99 | if (new_buffer) | 99 | if (new_buffer) |
100 | { | 100 | { |
101 | new_buffer = false; | 101 | new_buffer = false; |
102 | pcm_play_dma_started_callback(); | 102 | pcm_play_dma_status_callback(PCM_DMAST_STARTED); |
103 | 103 | ||
104 | /* NOTE: might need to release the mutex and sleep here if the | 104 | /* NOTE: might need to release the mutex and sleep here if the |
105 | buffer is shorter than the required buffer (like pcm-sdl.c) to | 105 | buffer is shorter than the required buffer (like pcm-sdl.c) to |
@@ -114,15 +114,15 @@ Java_org_rockbox_RockboxPCM_nativeWrite(JNIEnv *env, jobject this, | |||
114 | 114 | ||
115 | if (pcm_data_size == 0) /* need new data */ | 115 | if (pcm_data_size == 0) /* need new data */ |
116 | { | 116 | { |
117 | new_buffer = true; | 117 | new_buffer = pcm_play_dma_complete_callback(PCM_DMAST_OK, |
118 | pcm_play_get_more_callback((void**)&pcm_data_start, &pcm_data_size); | 118 | (const void**)&pcm_data_start, &pcm_data_size); |
119 | } | 119 | } |
120 | else /* increment data pointer and feed more */ | 120 | else /* increment data pointer and feed more */ |
121 | pcm_data_start += transfer_size; | 121 | pcm_data_start += transfer_size; |
122 | } | 122 | } |
123 | 123 | ||
124 | if (new_buffer && pcm_data_size) | 124 | if (new_buffer) |
125 | pcm_play_dma_started_callback(); | 125 | pcm_play_dma_status_callback(PCM_DMAST_STARTED); |
126 | 126 | ||
127 | unlock_audio(); | 127 | unlock_audio(); |
128 | return max_size - left; | 128 | return max_size - left; |
@@ -154,7 +154,7 @@ void pcm_play_dma_start(const void *addr, size_t size) | |||
154 | 154 | ||
155 | void pcm_play_dma_stop(void) | 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 | * possibly called from nativeWrite(), i.e. another (host) thread | 158 | * possibly called from nativeWrite(), i.e. another (host) thread |
159 | * => need to discover the appropriate JNIEnv* */ | 159 | * => need to discover the appropriate JNIEnv* */ |
160 | JNIEnv* env = getJavaEnvironment(); | 160 | JNIEnv* env = getJavaEnvironment(); |
diff --git a/firmware/target/hosted/maemo/pcm-gstreamer.c b/firmware/target/hosted/maemo/pcm-gstreamer.c index e5620d0702..61f33cbadd 100644 --- a/firmware/target/hosted/maemo/pcm-gstreamer.c +++ b/firmware/target/hosted/maemo/pcm-gstreamer.c | |||
@@ -189,9 +189,8 @@ static void feed_data(GstElement * appsrc, guint size_hint, void *unused) | |||
189 | from inside gstreamer's stream thread as it will deadlock */ | 189 | from inside gstreamer's stream thread as it will deadlock */ |
190 | inside_feed_data = 1; | 190 | inside_feed_data = 1; |
191 | 191 | ||
192 | pcm_play_get_more_callback((void **)&pcm_data, &pcm_data_size); | 192 | if (pcm_play_dma_complete_callback(PCM_DMAST_OK, (const void **)&pcm_data, |
193 | 193 | &pcm_data_size)) | |
194 | if (pcm_data_size != 0) | ||
195 | { | 194 | { |
196 | GstBuffer *buffer = gst_buffer_new (); | 195 | GstBuffer *buffer = gst_buffer_new (); |
197 | GstFlowReturn ret; | 196 | GstFlowReturn ret; |
@@ -205,7 +204,7 @@ static void feed_data(GstElement * appsrc, guint size_hint, void *unused) | |||
205 | if (ret != 0) | 204 | if (ret != 0) |
206 | DEBUGF("push-buffer error result: %d\n", ret); | 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 | } else | 208 | } else |
210 | { | 209 | { |
211 | DEBUGF("feed_data: No Data.\n"); | 210 | DEBUGF("feed_data: No Data.\n"); |
diff --git a/firmware/target/hosted/pcm-alsa.c b/firmware/target/hosted/pcm-alsa.c index b78993dd0a..1385f75b34 100644 --- a/firmware/target/hosted/pcm-alsa.c +++ b/firmware/target/hosted/pcm-alsa.c | |||
@@ -223,9 +223,11 @@ static bool fill_frames(void) | |||
223 | if (!pcm_size) | 223 | if (!pcm_size) |
224 | { | 224 | { |
225 | new_buffer = true; | 225 | new_buffer = true; |
226 | pcm_play_get_more_callback((void **)&pcm_data, &pcm_size); | 226 | if (!pcm_play_dma_complete_callback(PCM_DMAST_OK, |
227 | if (!pcm_size || !pcm_data) | 227 | (const void **)&pcm_data, &pcm_size)) |
228 | { | ||
228 | return false; | 229 | return false; |
230 | } | ||
229 | } | 231 | } |
230 | copy_n = MIN((ssize_t)pcm_size, frames_left*4); | 232 | copy_n = MIN((ssize_t)pcm_size, frames_left*4); |
231 | memcpy(&frames[2*(period_size-frames_left)], pcm_data, copy_n); | 233 | memcpy(&frames[2*(period_size-frames_left)], pcm_data, copy_n); |
@@ -237,7 +239,7 @@ static bool fill_frames(void) | |||
237 | if (new_buffer) | 239 | if (new_buffer) |
238 | { | 240 | { |
239 | new_buffer = false; | 241 | new_buffer = false; |
240 | pcm_play_dma_started_callback(); | 242 | pcm_play_dma_status_callback(PCM_DMAST_STARTED); |
241 | } | 243 | } |
242 | } | 244 | } |
243 | return true; | 245 | return true; |
diff --git a/firmware/target/hosted/sdl/pcm-sdl.c b/firmware/target/hosted/sdl/pcm-sdl.c index 020928d572..2c535b2dc5 100644 --- a/firmware/target/hosted/sdl/pcm-sdl.c +++ b/firmware/target/hosted/sdl/pcm-sdl.c | |||
@@ -56,7 +56,7 @@ static int sim_volume = 0; | |||
56 | #if CONFIG_CODEC == SWCODEC | 56 | #if CONFIG_CODEC == SWCODEC |
57 | static int cvt_status = -1; | 57 | static int cvt_status = -1; |
58 | 58 | ||
59 | static Uint8* pcm_data; | 59 | static const Uint8* pcm_data; |
60 | static size_t pcm_data_size; | 60 | static size_t pcm_data_size; |
61 | static size_t pcm_sample_bytes; | 61 | static size_t pcm_sample_bytes; |
62 | static size_t pcm_channel_bytes; | 62 | static size_t pcm_channel_bytes; |
@@ -109,7 +109,7 @@ void pcm_play_dma_start(const void *addr, size_t size) | |||
109 | { | 109 | { |
110 | pcm_dma_apply_settings_nolock(); | 110 | pcm_dma_apply_settings_nolock(); |
111 | 111 | ||
112 | pcm_data = (Uint8 *) addr; | 112 | pcm_data = addr; |
113 | pcm_data_size = size; | 113 | pcm_data_size = size; |
114 | 114 | ||
115 | SDL_PauseAudio(0); | 115 | SDL_PauseAudio(0); |
@@ -245,48 +245,48 @@ static void sdl_audio_callback(struct pcm_udata *udata, Uint8 *stream, int len) | |||
245 | 245 | ||
246 | /* Audio card wants more? Get some more then. */ | 246 | /* Audio card wants more? Get some more then. */ |
247 | while (len > 0) { | 247 | while (len > 0) { |
248 | new_buffer = true; | 248 | new_buffer = pcm_play_dma_complete_callback(PCM_DMAST_OK, |
249 | pcm_play_get_more_callback((void **)&pcm_data, &pcm_data_size); | 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 | start: | 256 | start: |
251 | if (pcm_data_size != 0) { | 257 | udata->num_in = pcm_data_size / pcm_sample_bytes; |
252 | udata->num_in = pcm_data_size / pcm_sample_bytes; | 258 | udata->num_out = len / pcm_sample_bytes; |
253 | 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; | 262 | udata->num_in *= pcm_sample_bytes; |
258 | udata->num_out *= 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; | 272 | int delay = pcm_data_size*250 / pcm_sampr - 1; |
264 | pcm_play_dma_started_callback(); | ||
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; | 276 | SDL_UnlockMutex(audio_lock); |
269 | 277 | SDL_Delay(delay); | |
270 | if (delay > 0) | 278 | SDL_LockMutex(audio_lock); |
271 | { | 279 | |
272 | SDL_UnlockMutex(audio_lock); | 280 | if (!pcm_is_playing()) |
273 | SDL_Delay(delay); | 281 | break; |
274 | SDL_LockMutex(audio_lock); | ||
275 | |||
276 | if (!pcm_is_playing()) | ||
277 | break; | ||
278 | } | ||
279 | } | 282 | } |
280 | } | 283 | } |
281 | |||
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 | } | 284 | } |
285 | |||
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 | SDL_UnlockMutex(audio_lock); | 292 | SDL_UnlockMutex(audio_lock); |
diff --git a/firmware/target/mips/ingenic_jz47xx/pcm-jz4740.c b/firmware/target/mips/ingenic_jz47xx/pcm-jz4740.c index 1ed413c9ae..83d3646ed1 100644 --- a/firmware/target/mips/ingenic_jz47xx/pcm-jz4740.c +++ b/firmware/target/mips/ingenic_jz47xx/pcm-jz4740.c | |||
@@ -63,7 +63,7 @@ void pcm_dma_apply_settings(void) | |||
63 | audiohw_set_frequency(pcm_sampr); | 63 | audiohw_set_frequency(pcm_sampr); |
64 | } | 64 | } |
65 | 65 | ||
66 | static void* playback_address; | 66 | static const void* playback_address; |
67 | static inline void set_dma(const void *addr, size_t size) | 67 | static inline void set_dma(const void *addr, size_t size) |
68 | { | 68 | { |
69 | int burst_size; | 69 | int burst_size; |
@@ -96,21 +96,19 @@ static inline void set_dma(const void *addr, size_t size) | |||
96 | REG_DMAC_DRSR(DMA_AIC_TX_CHANNEL) = DMAC_DRSR_RS_AICOUT; | 96 | REG_DMAC_DRSR(DMA_AIC_TX_CHANNEL) = DMAC_DRSR_RS_AICOUT; |
97 | REG_DMAC_DCMD(DMA_AIC_TX_CHANNEL) = (DMAC_DCMD_SAI | DMAC_DCMD_SWDH_32 | burst_size | DMAC_DCMD_DWDH_16 | DMAC_DCMD_TIE); | 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 | static inline void play_dma_callback(void) | 102 | static inline void play_dma_callback(void) |
103 | { | 103 | { |
104 | void *start; | 104 | const void *start; |
105 | size_t size; | 105 | size_t size; |
106 | 106 | ||
107 | pcm_play_get_more_callback(&start, &size); | 107 | if (pcm_play_dma_complete_callback(PCM_DMAST_OK, &start, &size)) |
108 | |||
109 | if (size != 0) | ||
110 | { | 108 | { |
111 | set_dma(start, size); | 109 | set_dma(start, size); |
112 | REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) |= DMAC_DCCSR_EN; | 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 | ||