summaryrefslogtreecommitdiff
path: root/firmware/target
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target')
-rw-r--r--firmware/target/arm/as3525/pcm-as3525.c9
-rw-r--r--firmware/target/arm/imx31/gigabeat-s/pcm-gigabeat-s.c3
-rw-r--r--firmware/target/arm/pcm-mixer-armv4.c182
-rw-r--r--firmware/target/arm/pcm-mixer-armv5.c106
-rw-r--r--firmware/target/arm/pcm-mixer-armv6.c118
-rw-r--r--firmware/target/arm/pcm-pp.c43
-rw-r--r--firmware/target/arm/pcm-telechips.c26
-rw-r--r--firmware/target/arm/pnx0101/pcm-pnx0101.c13
-rw-r--r--firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c3
-rw-r--r--firmware/target/arm/s3c2440/gigabeat-fx/wmcodec-meg-fx.c5
-rw-r--r--firmware/target/arm/s3c2440/mini2440/pcm-mini2440.c3
-rw-r--r--firmware/target/arm/s5l8700/pcm-s5l8700.c17
-rw-r--r--firmware/target/arm/s5l8702/pcm-s5l8702.c3
-rw-r--r--firmware/target/arm/tms320dm320/creative-zvm/pcm-creativezvm.c1
-rw-r--r--firmware/target/arm/tms320dm320/mrobe-500/pcm-mr500.c3
-rw-r--r--firmware/target/coldfire/pcm-coldfire.c4
-rw-r--r--firmware/target/coldfire/pcm-mixer-coldfire.c134
-rw-r--r--firmware/target/hosted/android/pcm-android.c54
-rw-r--r--firmware/target/hosted/maemo/pcm-gstreamer.c3
-rw-r--r--firmware/target/hosted/sdl/pcm-sdl.c47
-rw-r--r--firmware/target/mips/ingenic_jz47xx/pcm-jz4740.c2
21 files changed, 754 insertions, 25 deletions
diff --git a/firmware/target/arm/as3525/pcm-as3525.c b/firmware/target/arm/as3525/pcm-as3525.c
index 469833b05c..1b22d48f7f 100644
--- a/firmware/target/arm/as3525/pcm-as3525.c
+++ b/firmware/target/arm/as3525/pcm-as3525.c
@@ -29,6 +29,7 @@
29#include "as3514.h" 29#include "as3514.h"
30#include "audiohw.h" 30#include "audiohw.h"
31#include "mmu-arm.h" 31#include "mmu-arm.h"
32#include "pcm-internal.h"
32 33
33#define MAX_TRANSFER (4*((1<<11)-1)) /* maximum data we can transfer via DMA 34#define MAX_TRANSFER (4*((1<<11)-1)) /* maximum data we can transfer via DMA
34 * i.e. 32 bits at once (size of I2SO_DATA) 35 * i.e. 32 bits at once (size of I2SO_DATA)
@@ -104,9 +105,13 @@ static void dma_callback(void)
104 105
105 /* force writeback */ 106 /* force writeback */
106 clean_dcache_range(dma_start_addr, dma_start_size); 107 clean_dcache_range(dma_start_addr, dma_start_size);
108 play_start_pcm();
109 pcm_play_dma_started_callback();
110 }
111 else
112 {
113 play_start_pcm();
107 } 114 }
108
109 play_start_pcm();
110} 115}
111 116
112void pcm_play_dma_start(const void *addr, size_t size) 117void pcm_play_dma_start(const void *addr, size_t size)
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 c8c1283d12..1f6eef435a 100644
--- a/firmware/target/arm/imx31/gigabeat-s/pcm-gigabeat-s.c
+++ b/firmware/target/arm/imx31/gigabeat-s/pcm-gigabeat-s.c
@@ -26,6 +26,7 @@
26#include "ccm-imx31.h" 26#include "ccm-imx31.h"
27#include "sdma-imx31.h" 27#include "sdma-imx31.h"
28#include "mmu-imx31.h" 28#include "mmu-imx31.h"
29#include "pcm-internal.h"
29 30
30#define DMA_PLAY_CH_NUM 2 31#define DMA_PLAY_CH_NUM 2
31#define DMA_REC_CH_NUM 1 32#define DMA_REC_CH_NUM 1
@@ -105,6 +106,8 @@ static void play_dma_callback(void)
105 dma_play_bd.mode.command = TRANSFER_16BIT; 106 dma_play_bd.mode.command = TRANSFER_16BIT;
106 dma_play_bd.mode.status = BD_DONE | BD_WRAP | BD_INTR; 107 dma_play_bd.mode.status = BD_DONE | BD_WRAP | BD_INTR;
107 sdma_channel_run(DMA_PLAY_CH_NUM); 108 sdma_channel_run(DMA_PLAY_CH_NUM);
109
110 pcm_play_dma_started_callback();
108} 111}
109 112
110void pcm_play_lock(void) 113void pcm_play_lock(void)
diff --git a/firmware/target/arm/pcm-mixer-armv4.c b/firmware/target/arm/pcm-mixer-armv4.c
new file mode 100644
index 0000000000..4818544d7b
--- /dev/null
+++ b/firmware/target/arm/pcm-mixer-armv4.c
@@ -0,0 +1,182 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2011 by Michael Sevakis
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#define MIXER_OPTIMIZED_WRITE_SAMPLES
23#define MIXER_OPTIMIZED_MIX_SAMPLES
24
25/* Mix channels' samples and apply gain factors */
26static FORCE_INLINE void mix_samples(void *out,
27 void *src0,
28 int32_t src0_amp,
29 void *src1,
30 int32_t src1_amp,
31 size_t size)
32{
33 if (src0_amp == MIX_AMP_UNITY && src1_amp == MIX_AMP_UNITY)
34 {
35 /* Both are unity amplitude */
36 int32_t l0, l1, h0, h1;
37 asm volatile (
38 "1: \n"
39 "ldrsh %4, [%1], #2 \n"
40 "ldrsh %5, [%2], #2 \n"
41 "ldrsh %6, [%1], #2 \n"
42 "ldrsh %7, [%2], #2 \n"
43 "add %4, %4, %5 \n"
44 "add %6, %6, %7 \n"
45 "mov %5, %4, asr #15 \n"
46 "teq %5, %5, asr #31 \n"
47 "eorne %4, %8, %4, asr #31 \n"
48 "mov %7, %6, asr #15 \n"
49 "teq %7, %7, asr #31 \n"
50 "eorne %6, %8, %6, asr #31 \n"
51 "subs %3, %3, #4 \n"
52 "and %4, %4, %8, lsr #16 \n"
53 "orr %6, %4, %6, lsl #16 \n"
54 "str %6, [%0], #4 \n"
55 "bhi 1b \n"
56 : "+r"(out), "+r"(src0), "+r"(src1), "+r"(size),
57 "=&r"(l0), "=&r"(l1), "=&r"(h0), "=&r"(h1)
58 : "r"(0xffff7fff));
59 }
60 else if (src0_amp != MIX_AMP_UNITY && src1_amp != MIX_AMP_UNITY)
61 {
62 /* Neither are unity amplitude */
63 int32_t l0, l1, h0, h1;
64 asm volatile (
65 "1: \n"
66 "ldrsh %4, [%1], #2 \n"
67 "ldrsh %5, [%2], #2 \n"
68 "ldrsh %6, [%1], #2 \n"
69 "ldrsh %7, [%2], #2 \n"
70 "mul %4, %8, %4 \n"
71 "mul %5, %9, %5 \n"
72 "mul %6, %8, %6 \n"
73 "mul %7, %9, %7 \n"
74 "mov %4, %4, asr #16 \n"
75 "add %4, %4, %5, asr #16 \n"
76 "mov %6, %6, asr #16 \n"
77 "add %6, %6, %7, asr #16 \n"
78 "mov %5, %4, asr #15 \n"
79 "teq %5, %5, asr #31 \n"
80 "eorne %4, %10, %4, asr #31 \n"
81 "mov %7, %6, asr #15 \n"
82 "teq %7, %7, asr #31 \n"
83 "eorne %6, %10, %6, asr #31 \n"
84 "subs %3, %3, #4 \n"
85 "and %4, %4, %10, lsr #16 \n"
86 "orr %6, %4, %6, lsl #16 \n"
87 "str %6, [%0], #4 \n"
88 "bhi 1b \n"
89 : "+r"(out), "+r"(src0), "+r"(src1), "+r"(size),
90 "=&r"(l0), "=&r"(l1), "=&r"(h0), "=&r"(h1)
91 : "r"(src0_amp), "r"(src1_amp), "r"(0xffff7fff));
92 }
93 else
94 {
95 /* One is unity amplitude */
96 if (src0_amp != MIX_AMP_UNITY)
97 {
98 /* Keep unity in src0, amp0 */
99 int16_t *src_tmp = src0;
100 src0 = src1;
101 src1 = src_tmp;
102 src1_amp = src0_amp;
103 src0_amp = MIX_AMP_UNITY;
104 }
105
106 int32_t l0, l1, h0, h1;
107 asm volatile (
108 "1: \n"
109 "ldrsh %4, [%1], #2 \n"
110 "ldrsh %5, [%2], #2 \n"
111 "ldrsh %6, [%1], #2 \n"
112 "ldrsh %7, [%2], #2 \n"
113 "mul %5, %8, %5 \n"
114 "mul %7, %8, %7 \n"
115 "add %4, %4, %5, asr #16 \n"
116 "add %6, %6, %7, asr #16 \n"
117 "mov %5, %4, asr #15 \n"
118 "teq %5, %5, asr #31 \n"
119 "eorne %4, %9, %4, asr #31 \n"
120 "mov %7, %6, asr #15 \n"
121 "teq %7, %7, asr #31 \n"
122 "eorne %6, %9, %6, asr #31 \n"
123 "subs %3, %3, #4 \n"
124 "and %4, %4, %9, lsr #16 \n"
125 "orr %6, %4, %6, lsl #16 \n"
126 "str %6, [%0], #4 \n"
127 "bhi 1b \n"
128 : "+r"(out), "+r"(src0), "+r"(src1), "+r"(size),
129 "=&r"(l0), "=&r"(l1), "=&r"(h0), "=&r"(h1)
130 : "r"(src1_amp), "r"(0xffff7fff));
131 }
132}
133
134/* Write channel's samples and apply gain factor */
135static FORCE_INLINE void write_samples(void *out,
136 void *src,
137 int32_t amp,
138 size_t size)
139{
140 if (LIKELY(amp == MIX_AMP_UNITY))
141 {
142 /* Channel is unity amplitude */
143 asm volatile (
144 "ands r1, %2, #0x1f \n"
145 "beq 2f \n"
146 "1: \n"
147 "ldr r0, [%1], #4 \n"
148 "subs r1, r1, #4 \n"
149 "str r0, [%0], #4 \n"
150 "bne 1b \n"
151 "bics %2, %2, #0x1f \n"
152 "beq 3f \n"
153 "2: \n"
154 "ldmia %1!, { r0-r7 } \n"
155 "subs %2, %2, #32 \n"
156 "stmia %0!, { r0-r7 } \n"
157 "bhi 2b \n"
158 "3: \n"
159 : "+r"(out), "+r"(src), "+r"(size)
160 :
161 : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7");
162 }
163 else
164 {
165 /* Channel needs amplitude cut */
166 uint32_t l, h;
167 asm volatile (
168 "1: \n"
169 "ldrsh %3, [%1], #2 \n"
170 "ldrsh %4, [%1], #2 \n"
171 "subs %2, %2, #4 \n"
172 "mul %3, %5, %3 \n"
173 "mul %4, %5, %4 \n"
174 "and %4, %4, %6, lsl #16 \n"
175 "orr %4, %4, %3, lsr #16 \n"
176 "str %4, [%0], #4 \n"
177 "bhi 1b \n"
178 : "+r"(out), "+r"(src), "+r"(size),
179 "=&r"(l), "=&r"(h)
180 : "r"(amp), "r"(0xffffffffu));
181 }
182}
diff --git a/firmware/target/arm/pcm-mixer-armv5.c b/firmware/target/arm/pcm-mixer-armv5.c
new file mode 100644
index 0000000000..64f2c86f52
--- /dev/null
+++ b/firmware/target/arm/pcm-mixer-armv5.c
@@ -0,0 +1,106 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2011 by Michael Sevakis
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#define MIXER_OPTIMIZED_WRITE_SAMPLES
23#define MIXER_OPTIMIZED_MIX_SAMPLES
24
25/* Mix channels' samples and apply gain factors */
26static FORCE_INLINE void mix_samples(void *out,
27 void *src0,
28 int32_t src0_amp,
29 void *src1,
30 int32_t src1_amp,
31 size_t size)
32{
33 int32_t s0, s1, tmp;
34 asm volatile (
35 "1: \n"
36 "ldr %4, [%1], #4 \n"
37 "ldr %5, [%2], #4 \n"
38 "smulwb %6, %7, %4 \n"
39 "smulwt %4, %7, %4 \n"
40 "smlawb %6, %8, %5, %6 \n"
41 "smlawt %4, %8, %5, %4 \n"
42 "mov %5, %6, asr #15 \n"
43 "teq %5, %5, asr #31 \n"
44 "eorne %6, %9, %6, asr #31 \n"
45 "mov %5, %4, asr #15 \n"
46 "teq %5, %5, asr #31 \n"
47 "eorne %4, %9, %4, asr #31 \n"
48 "subs %3, %3, #4 \n"
49 "and %6, %6, %9, lsr #16 \n"
50 "orr %6, %6, %4, lsl #16 \n"
51 "str %6, [%0], #4 \n"
52 "bhi 1b \n"
53 : "+r"(out), "+r"(src0), "+r"(src1), "+r"(size),
54 "=&r"(s0), "=&r"(s1), "=&r"(tmp)
55 : "r"(src0_amp), "r"(src1_amp), "r"(0xffff7fff));
56}
57
58/* Write channel's samples and apply gain factor */
59static FORCE_INLINE void write_samples(void *out,
60 void *src,
61 int32_t amp,
62 size_t size)
63{
64 if (LIKELY(amp == MIX_AMP_UNITY))
65 {
66 /* Channel is unity amplitude */
67 asm volatile (
68 "ands r1, %2, #0x1f \n"
69 "beq 2f \n"
70 "1: \n"
71 "ldr r0, [%1], #4 \n"
72 "subs r1, r1, #4 \n"
73 "str r0, [%0], #4 \n"
74 "bne 1b \n"
75 "bics %2, %2, #0x1f \n"
76 "beq 3f \n"
77 "2: \n"
78 "ldmia %1!, { r0-r7 } \n"
79 "subs %2, %2, #32 \n"
80 "stmia %0!, { r0-r7 } \n"
81 "bhi 2b \n"
82 "3: \n"
83 : "+r"(out), "+r"(src), "+r"(size)
84 :
85 : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7");
86 }
87 else
88 {
89 /* Channel needs amplitude cut */
90 uint32_t l, h;
91 asm volatile (
92 "1: \n"
93 "ldr %3, [%1], #4 \n"
94 "subs %2, %2, #4 \n"
95 "smulwt %4, %5, %3 \n"
96 "smulwb %3, %5, %3 \n"
97 "mov %4, %4, lsl #16 \n"
98 "mov %3, %3, lsl #16 \n"
99 "orr %4, %4, %3, lsr #16 \n"
100 "str %4, [%0], #4 \n"
101 "bhi 1b \n"
102 : "+r"(out), "+r"(src), "+r"(size),
103 "=&r"(l), "=&r"(h)
104 : "r"(amp));
105 }
106}
diff --git a/firmware/target/arm/pcm-mixer-armv6.c b/firmware/target/arm/pcm-mixer-armv6.c
new file mode 100644
index 0000000000..94eecd0f90
--- /dev/null
+++ b/firmware/target/arm/pcm-mixer-armv6.c
@@ -0,0 +1,118 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2011 by Michael Sevakis
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#define MIXER_OPTIMIZED_MIX_SAMPLES
22#define MIXER_OPTIMIZED_WRITE_SAMPLES
23
24/* Mix channels' samples and apply gain factors */
25static FORCE_INLINE void mix_samples(void *out,
26 void *src0,
27 int32_t src0_amp,
28 void *src1,
29 int32_t src1_amp,
30 size_t size)
31{
32 uint32_t s0, s1;
33
34 if (src0_amp == MIX_AMP_UNITY && src1_amp == MIX_AMP_UNITY)
35 {
36 /* Both are unity amplitude */
37 asm volatile (
38 "1: \n"
39 "ldr %4, [%1], #4 \n"
40 "ldr %5, [%2], #4 \n"
41 "subs %3, %3, #4 \n"
42 "qadd16 %5, %5, %4 \n"
43 "str %5, [%0], #4 \n"
44 "bhi 1b \n"
45 : "+r"(out), "+r"(src0), "+r"(src1), "+r"(size),
46 "=&r"(s0), "=&r"(s1));
47 }
48 else
49 {
50 /* One or neither are unity amplitude */
51 uint32_t tmp;
52 asm volatile (
53 "1: \n"
54 "ldr %4, [%1], #4 \n"
55 "ldr %5, [%2], #4 \n"
56 "subs %3, %3, #4 \n"
57 "smulwb %6, %7, %4 \n"
58 "smulwt %4, %7, %4 \n"
59 "smlawb %6, %8, %5, %6 \n"
60 "smlawt %4, %8, %5, %4 \n"
61 "ssat %6, #16, %6 \n"
62 "ssat %4, #16, %4 \n"
63 "pkhbt %6, %6, %4, asl #16 \n"
64 "str %6, [%0], #4 \n"
65 "bhi 1b \n"
66 : "+r"(out), "+r"(src0), "+r"(src1), "+r"(size),
67 "=&r"(s0), "=&r"(s1), "=&r"(tmp)
68 : "r"(src0_amp), "r"(src1_amp));
69 }
70}
71
72/* Write channel's samples and apply gain factor */
73static FORCE_INLINE void write_samples(void *out,
74 void *src,
75 int32_t amp,
76 size_t size)
77{
78 if (LIKELY(amp == MIX_AMP_UNITY))
79 {
80 /* Channel is unity amplitude */
81 asm volatile (
82 "ands r1, %2, #0x1f \n"
83 "beq 2f \n"
84 "1: \n"
85 "ldr r0, [%1], #4 \n"
86 "subs r1, r1, #4 \n"
87 "str r0, [%0], #4 \n"
88 "bne 1b \n"
89 "bics %2, %2, #0x1f \n"
90 "beq 3f \n"
91 "2: \n"
92 "ldmia %1!, { r0-r7 } \n"
93 "subs %2, %2, #32 \n"
94 "stmia %0!, { r0-r7 } \n"
95 "bhi 2b \n"
96 "3: \n"
97 : "+r"(out), "+r"(src), "+r"(size)
98 :
99 : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7");
100 }
101 else
102 {
103 /* Channel needs amplitude cut */
104 uint32_t s, tmp;
105 asm volatile(
106 "1: \n"
107 "ldr %3, [%1], #4 \n"
108 "subs %2, %2, #4 \n"
109 "smulwt %4, %5, %3 \n"
110 "smulwb %3, %5, %3 \n"
111 "pkhbt %4, %3, %4, asl #16 \n"
112 "str %4, [%0], #4 \n"
113 "bhi 1b \n"
114 : "+r"(out), "+r"(src), "+r"(size),
115 "=&r"(s), "=&r"(tmp)
116 : "r"(amp));
117 }
118}
diff --git a/firmware/target/arm/pcm-pp.c b/firmware/target/arm/pcm-pp.c
index c446f98fcf..704296d407 100644
--- a/firmware/target/arm/pcm-pp.c
+++ b/firmware/target/arm/pcm-pp.c
@@ -26,6 +26,7 @@
26#include "sound.h" 26#include "sound.h"
27#include "pcm.h" 27#include "pcm.h"
28#include "pcm_sampr.h" 28#include "pcm_sampr.h"
29#include "pcm-internal.h"
29 30
30/** DMA **/ 31/** DMA **/
31 32
@@ -115,6 +116,7 @@ void pcm_dma_apply_settings(void)
115/* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */ 116/* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */
116void ICODE_ATTR __attribute__((interrupt("FIQ"))) fiq_playback(void) 117void ICODE_ATTR __attribute__((interrupt("FIQ"))) fiq_playback(void)
117{ 118{
119 bool new_buffer = false;
118 register size_t size; 120 register size_t size;
119 121
120 DMA0_STATUS; /* Clear any pending interrupt */ 122 DMA0_STATUS; /* Clear any pending interrupt */
@@ -136,9 +138,14 @@ void ICODE_ATTR __attribute__((interrupt("FIQ"))) fiq_playback(void)
136 /* Set the new DMA values and activate channel */ 138 /* Set the new DMA values and activate channel */
137 DMA0_RAM_ADDR = dma_play_data.addr; 139 DMA0_RAM_ADDR = dma_play_data.addr;
138 DMA0_CMD = DMA_PLAY_CONFIG | (size - 4) | DMA_CMD_START; 140 DMA0_CMD = DMA_PLAY_CONFIG | (size - 4) | DMA_CMD_START;
141
142 if (new_buffer)
143 pcm_play_dma_started_callback();
139 return; 144 return;
140 } 145 }
141 146
147 new_buffer = true;
148
142 /* Buffer empty. Try to get more. */ 149 /* Buffer empty. Try to get more. */
143 pcm_play_get_more_callback((void **)&dma_play_data.addr, 150 pcm_play_get_more_callback((void **)&dma_play_data.addr,
144 &dma_play_data.size); 151 &dma_play_data.size);
@@ -181,8 +188,9 @@ void fiq_playback(void)
181 * r0-r3 and r12 is a working register. 188 * r0-r3 and r12 is a working register.
182 */ 189 */
183 asm volatile ( 190 asm volatile (
184 "stmfd sp!, { r0-r3, lr } \n" /* stack scratch regs and lr */ 191 "stmfd sp!, { r0-r4, lr } \n" /* stack scratch regs and lr */
185 192
193 "mov r4, #0 \n" /* Was the callback called? */
186#if CONFIG_CPU == PP5002 194#if CONFIG_CPU == PP5002
187 "ldr r12, =0xcf001040 \n" /* Some magic from iPodLinux */ 195 "ldr r12, =0xcf001040 \n" /* Some magic from iPodLinux */
188 "ldr r12, [r12] \n" 196 "ldr r12, [r12] \n"
@@ -212,16 +220,13 @@ void fiq_playback(void)
212 "tst r1, #1 \n" /* two samples (one word) left? */ 220 "tst r1, #1 \n" /* two samples (one word) left? */
213 "ldrne r12, [r8], #4 \n" /* load two samples */ 221 "ldrne r12, [r8], #4 \n" /* load two samples */
214 "strne r12, [r10, %[wr]] \n" /* write sample 0-1 to IISFIFO_WR */ 222 "strne r12, [r10, %[wr]] \n" /* write sample 0-1 to IISFIFO_WR */
215
216 "cmp r9, #0 \n" /* either FIFO is full or source buffer is empty */
217 "bgt .exit \n" /* if source buffer is not empty, FIFO must be full */
218#elif SAMPLE_SIZE == 32 223#elif SAMPLE_SIZE == 32
219 ".check_fifo: \n" 224 ".check_fifo: \n"
220 "ldr r0, [r10, %[cfg]] \n" /* read IISFIFO_CFG to check FIFO status */ 225 "ldr r0, [r10, %[cfg]] \n" /* read IISFIFO_CFG to check FIFO status */
221 "and r0, r0, %[mask] \n" /* r0 = IIS_TX_FREE_COUNT << 23 (PP5002) */ 226 "and r0, r0, %[mask] \n" /* r0 = IIS_TX_FREE_COUNT << 23 (PP5002) */
222 227
223 "movs r1, r0, lsr #24 \n" /* number of free pairs of FIFO slots */ 228 "movs r1, r0, lsr #24 \n" /* number of free pairs of FIFO slots */
224 "beq .exit \n" /* no complete pair? -> exit */ 229 "beq .fifo_fill_complete \n" /* no complete pair? -> exit */
225 "cmp r1, r9, lsr #2 \n" /* number of words from source */ 230 "cmp r1, r9, lsr #2 \n" /* number of words from source */
226 "movgt r1, r9, lsr #2 \n" /* r1 = amount of allowed loops */ 231 "movgt r1, r9, lsr #2 \n" /* r1 = amount of allowed loops */
227 "sub r9, r9, r1, lsl #2 \n" /* r1 words will be written in following loop */ 232 "sub r9, r9, r1, lsl #2 \n" /* r1 words will be written in following loop */
@@ -234,11 +239,23 @@ void fiq_playback(void)
234 "subs r1, r1, #1 \n" /* one more loop? */ 239 "subs r1, r1, #1 \n" /* one more loop? */
235 "bgt .fifo_loop \n" /* yes, continue */ 240 "bgt .fifo_loop \n" /* yes, continue */
236 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"
237 "cmp r9, #0 \n" /* either FIFO is full or source buffer is empty */ 254 "cmp r9, #0 \n" /* either FIFO is full or source buffer is empty */
238 "bgt .exit \n" /* if source buffer is not empty, FIFO must be full */ 255 "bgt .exit \n" /* if source buffer is not empty, FIFO must be full */
239#endif
240 256
241 ".more_data: \n" 257 ".more_data: \n"
258 "mov r4, #1 \n" /* Remember we did this */
242 "ldr r2, =pcm_play_get_more_callback \n" 259 "ldr r2, =pcm_play_get_more_callback \n"
243 "mov r0, r11 \n" /* r0 = &p */ 260 "mov r0, r11 \n" /* r0 = &p */
244 "add r1, r11, #4 \n" /* r1 = &size */ 261 "add r1, r11, #4 \n" /* r1 = &size */
@@ -250,7 +267,7 @@ void fiq_playback(void)
250 267
251 ".exit: \n" /* (r9=0 if stopping, look above) */ 268 ".exit: \n" /* (r9=0 if stopping, look above) */
252 "stmia r11, { r8-r9 } \n" /* save p and size */ 269 "stmia r11, { r8-r9 } \n" /* save p and size */
253 "ldmfd sp!, { r0-r3, lr } \n" 270 "ldmfd sp!, { r0-r4, lr } \n"
254 "subs pc, lr, #4 \n" /* FIQ specific return sequence */ 271 "subs pc, lr, #4 \n" /* FIQ specific return sequence */
255 ".ltorg \n" 272 ".ltorg \n"
256 : /* These must only be integers! No regs */ 273 : /* These must only be integers! No regs */
@@ -264,6 +281,8 @@ void fiq_playback(void) __attribute__((interrupt ("FIQ"))) ICODE_ATTR;
264/* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */ 281/* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */
265void fiq_playback(void) 282void fiq_playback(void)
266{ 283{
284 bool new_buffer = false;
285
267#if CONFIG_CPU == PP5002 286#if CONFIG_CPU == PP5002
268 inl(0xcf001040); 287 inl(0xcf001040);
269#endif 288#endif
@@ -271,6 +290,10 @@ void fiq_playback(void)
271 do { 290 do {
272 while (dma_play_data.size > 0) { 291 while (dma_play_data.size > 0) {
273 if (IIS_TX_FREE_COUNT < 2) { 292 if (IIS_TX_FREE_COUNT < 2) {
293 if (new_buffer) {
294 new_buffer = false;
295 pcm_play_dma_started_callback();
296 }
274 return; 297 return;
275 } 298 }
276#if SAMPLE_SIZE == 16 299#if SAMPLE_SIZE == 16
@@ -282,9 +305,15 @@ void fiq_playback(void)
282 dma_play_data.size -= 4; 305 dma_play_data.size -= 4;
283 } 306 }
284 307
308 if (new_buffer) {
309 new_buffer = false;
310 pcm_play_dma_started_callback();
311 }
312
285 /* p is empty, get some more data */ 313 /* p is empty, get some more data */
286 pcm_play_get_more_callback((void **)&dma_play_data.addr, 314 pcm_play_get_more_callback((void **)&dma_play_data.addr,
287 &dma_play_data.size); 315 &dma_play_data.size);
316 new_buffer = true;
288 } while (dma_play_data.size); 317 } while (dma_play_data.size);
289 318
290 /* No more data */ 319 /* No more data */
diff --git a/firmware/target/arm/pcm-telechips.c b/firmware/target/arm/pcm-telechips.c
index 851ebee7de..aff43171f6 100644
--- a/firmware/target/arm/pcm-telechips.c
+++ b/firmware/target/arm/pcm-telechips.c
@@ -27,6 +27,7 @@
27#include "sound.h" 27#include "sound.h"
28#include "i2s.h" 28#include "i2s.h"
29#include "pcm.h" 29#include "pcm.h"
30#include "pcm-internal.h"
30 31
31struct dma_data 32struct dma_data
32{ 33{
@@ -247,6 +248,8 @@ void fiq_handler(void)
247 * r0-r3 and r12 is a working register. 248 * r0-r3 and r12 is a working register.
248 */ 249 */
249 asm volatile ( 250 asm volatile (
251 "stmfd sp!, { r0-r4, lr } \n" /* stack scratch regs and lr */
252 "mov r4, #0 \n" /* Was the callback called? */
250#if defined(CPU_TCC780X) 253#if defined(CPU_TCC780X)
251 "mov r8, #0xc000 \n" /* DAI_TX_IRQ_MASK | DAI_RX_IRQ_MASK */ 254 "mov r8, #0xc000 \n" /* DAI_TX_IRQ_MASK | DAI_RX_IRQ_MASK */
252 "ldr r9, =0xf3001004 \n" /* CREQ */ 255 "ldr r9, =0xf3001004 \n" /* CREQ */
@@ -279,33 +282,41 @@ void fiq_handler(void)
279 "sub r9, r9, #0x10 \n" /* 4 words written */ 282 "sub r9, r9, #0x10 \n" /* 4 words written */
280 "stmia r11, { r8-r9 } \n" /* save p and size */ 283 "stmia r11, { r8-r9 } \n" /* save p and size */
281 284
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"
292
282 ".exit: \n" 293 ".exit: \n"
294 "ldmfd sp!, { r0-r4, lr } \n"
283 "subs pc, lr, #4 \n" /* FIQ specific return sequence */ 295 "subs pc, lr, #4 \n" /* FIQ specific return sequence */
284 296
285 ".more_data: \n" 297 ".more_data: \n"
286 "stmfd sp!, { r0-r3, lr } \n" /* stack scratch regs and lr */ 298 "mov r4, #1 \n" /* Remember we got more data in this FIQ */
287 "ldr r2, =pcm_play_get_more_callback \n" 299 "ldr r2, =pcm_play_get_more_callback \n"
288 "mov r0, r11 \n" /* r0 = &p */ 300 "mov r0, r11 \n" /* r0 = &p */
289 "add r1, r11, #4 \n" /* r1 = &size */ 301 "add r1, r11, #4 \n" /* r1 = &size */
290 "blx r2 \n" /* call pcm_play_get_more_callback */ 302 "blx r2 \n" /* call pcm_play_get_more_callback */
291 "ldmia r11, { r8-r9 } \n" /* load new p and size */ 303 "ldmia r11, { r8-r9 } \n" /* load new p and size */
292 "cmp r9, #0x10 \n" /* did we actually get enough data? */ 304 "cmp r9, #0x10 \n" /* did we actually get enough data? */
293 "ldmfd sp!, { r0-r3, lr } \n"
294 "bpl .fill_fifo \n" /* not stop and enough? refill */ 305 "bpl .fill_fifo \n" /* not stop and enough? refill */
295 "b .exit \n" 306 "b .exit \n"
296 ".ltorg \n" 307 ".ltorg \n"
297 ); 308 );
298} 309}
299#else /* C version for reference */ 310#else /* C version for reference */
300void fiq_handler(void) ICODE_ATTR __attribute__((naked)); 311void fiq_handler(void) ICODE_ATTR;
301void fiq_handler(void) 312void fiq_handler(void)
302{ 313{
303 asm volatile( "stmfd sp!, {r0-r7, ip, lr} \n" /* Store context */ 314 register bool new_buffer = false;
304 "sub sp, sp, #8 \n"); /* Reserve stack */
305 315
306 if (dma_play_data.size < 16) 316 if (dma_play_data.size < 16)
307 { 317 {
308 /* p is empty, get some more data */ 318 /* p is empty, get some more data */
319 new_buffer = true;
309 pcm_play_get_more_callback((void**)&dma_play_data.p, 320 pcm_play_get_more_callback((void**)&dma_play_data.p,
310 &dma_play_data.size); 321 &dma_play_data.size);
311 } 322 }
@@ -327,9 +338,8 @@ void fiq_handler(void)
327 /* Clear FIQ status */ 338 /* Clear FIQ status */
328 CREQ = DAI_TX_IRQ_MASK | DAI_RX_IRQ_MASK; 339 CREQ = DAI_TX_IRQ_MASK | DAI_RX_IRQ_MASK;
329 340
330 asm volatile( "add sp, sp, #8 \n" /* Cleanup stack */ 341 if (new_buffer)
331 "ldmfd sp!, {r0-r7, ip, lr} \n" /* Restore context */ 342 pcm_play_dma_started_callback();
332 "subs pc, lr, #4 \n"); /* Return from FIQ */
333} 343}
334#endif 344#endif
335 345
diff --git a/firmware/target/arm/pnx0101/pcm-pnx0101.c b/firmware/target/arm/pnx0101/pcm-pnx0101.c
index 9d4ffbd773..d4c17454ed 100644
--- a/firmware/target/arm/pnx0101/pcm-pnx0101.c
+++ b/firmware/target/arm/pnx0101/pcm-pnx0101.c
@@ -21,6 +21,7 @@
21#include "system.h" 21#include "system.h"
22#include "audio.h" 22#include "audio.h"
23#include "string.h" 23#include "string.h"
24#include "pcm-internal.h"
24 25
25#define DMA_BUF_SAMPLES 0x100 26#define DMA_BUF_SAMPLES 0x100
26 27
@@ -63,6 +64,8 @@ static inline void fill_dma_buf(int offset)
63 64
64 if (pcm_playing && !pcm_paused) 65 if (pcm_playing && !pcm_paused)
65 { 66 {
67 bool new_buffer =false;
68
66 do 69 do
67 { 70 {
68 int count; 71 int count;
@@ -102,10 +105,20 @@ static inline void fill_dma_buf(int offset)
102 count--; 105 count--;
103 } 106 }
104 p = tmp_p; 107 p = tmp_p;
108
109 if (new_buffer)
110 {
111 new_buffer = false;
112 pcm_play_dma_started_callback();
113 }
114
105 if (l >= lend) 115 if (l >= lend)
106 return; 116 return;
107 117
108 pcm_play_get_more_callback((void**)&p, &p_size); 118 pcm_play_get_more_callback((void**)&p, &p_size);
119
120 if (p_size)
121 new_buffer = true;
109 } 122 }
110 while (p_size); 123 while (p_size);
111 } 124 }
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 c1c9017fbb..33194ae5d9 100644
--- a/firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c
+++ b/firmware/target/arm/s3c2440/gigabeat-fx/pcm-meg-fx.c
@@ -25,6 +25,7 @@
25#include "audio.h" 25#include "audio.h"
26#include "sound.h" 26#include "sound.h"
27#include "file.h" 27#include "file.h"
28#include "pcm-internal.h"
28 29
29/* PCM interrupt routine lockout */ 30/* PCM interrupt routine lockout */
30static struct 31static struct
@@ -235,6 +236,8 @@ void fiq_handler(void)
235 236
236 /* Re-Activate the channel */ 237 /* Re-Activate the channel */
237 DMASKTRIG2 = 0x2; 238 DMASKTRIG2 = 0x2;
239
240 pcm_play_dma_started_callback();
238} 241}
239 242
240size_t pcm_get_bytes_waiting(void) 243size_t pcm_get_bytes_waiting(void)
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/wmcodec-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/wmcodec-meg-fx.c
index 01b177da6c..eea4c58e4b 100644
--- a/firmware/target/arm/s3c2440/gigabeat-fx/wmcodec-meg-fx.c
+++ b/firmware/target/arm/s3c2440/gigabeat-fx/wmcodec-meg-fx.c
@@ -99,14 +99,15 @@ void TIMER3(void)
99 INTPND = TIMER3_MASK; 99 INTPND = TIMER3_MASK;
100} 100}
101 101
102void pcmbuf_beep(unsigned int frequency, size_t duration, int amplitude) 102void beep_play(unsigned int frequency, unsigned int duration,
103 unsigned int amplitude)
103{ 104{
104 #define TIMER3_TICK_SEC (TIMER_FREQ / TIMER234_PRESCALE) 105 #define TIMER3_TICK_SEC (TIMER_FREQ / TIMER234_PRESCALE)
105 106
106 unsigned long tcnt, tcmp; 107 unsigned long tcnt, tcmp;
107 int oldstatus; 108 int oldstatus;
108 109
109 if (amplitude <= 0) 110 if (frequency == 0 || duration == 0 || amplitude == 0)
110 { 111 {
111 beep_stop(); /* won't hear it anyway */ 112 beep_stop(); /* won't hear it anyway */
112 return; 113 return;
diff --git a/firmware/target/arm/s3c2440/mini2440/pcm-mini2440.c b/firmware/target/arm/s3c2440/mini2440/pcm-mini2440.c
index 8a6b62f31f..0c69c1e6d3 100644
--- a/firmware/target/arm/s3c2440/mini2440/pcm-mini2440.c
+++ b/firmware/target/arm/s3c2440/mini2440/pcm-mini2440.c
@@ -26,6 +26,7 @@
26#include "audio.h" 26#include "audio.h"
27#include "sound.h" 27#include "sound.h"
28#include "file.h" 28#include "file.h"
29#include "pcm-internal.h"
29 30
30/* PCM interrupt routine lockout */ 31/* PCM interrupt routine lockout */
31static struct 32static struct
@@ -275,6 +276,8 @@ void fiq_handler(void)
275 276
276 /* Re-Activate the channel */ 277 /* Re-Activate the channel */
277 DMASKTRIG2 = 0x2; 278 DMASKTRIG2 = 0x2;
279
280 pcm_play_dma_started_callback();
278} 281}
279 282
280size_t pcm_get_bytes_waiting(void) 283size_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 08086c37d8..14c515ec47 100644
--- a/firmware/target/arm/s5l8700/pcm-s5l8700.c
+++ b/firmware/target/arm/s5l8700/pcm-s5l8700.c
@@ -27,6 +27,7 @@
27#include "panic.h" 27#include "panic.h"
28#include "audiohw.h" 28#include "audiohw.h"
29#include "pcm.h" 29#include "pcm.h"
30#include "pcm-internal.h"
30#include "pcm_sampr.h" 31#include "pcm_sampr.h"
31#include "dma-target.h" 32#include "dma-target.h"
32#include "mmu-arm.h" 33#include "mmu-arm.h"
@@ -100,6 +101,7 @@ void pcm_play_unlock(void)
100void INT_DMA(void) ICODE_ATTR; 101void INT_DMA(void) ICODE_ATTR;
101void INT_DMA(void) 102void INT_DMA(void)
102{ 103{
104 bool new_buffer = false;
103 DMACOM0 = 7; 105 DMACOM0 = 7;
104 while (!(DMACON0 & (1 << 18))) 106 while (!(DMACON0 & (1 << 18)))
105 { 107 {
@@ -112,8 +114,12 @@ void INT_DMA(void)
112 } 114 }
113 else 115 else
114 { 116 {
115 if (!nextsize) pcm_play_get_more_callback((void**)&nextbuf, &nextsize); 117 if (!nextsize)
116 if (!nextsize) break; 118 {
119 pcm_play_get_more_callback((void**)&nextbuf, &nextsize);
120 if (!nextsize) break;
121 new_buffer = true;
122 }
117 queuedsize = MIN(sizeof(dblbuf), nextsize / 2); 123 queuedsize = MIN(sizeof(dblbuf), nextsize / 2);
118 nextsize -= queuedsize; 124 nextsize -= queuedsize;
119 queuedbuf = nextbuf + nextsize; 125 queuedbuf = nextbuf + nextsize;
@@ -124,7 +130,14 @@ void INT_DMA(void)
124 clean_dcache(); 130 clean_dcache();
125 DMACOM0 = 4; 131 DMACOM0 = 4;
126 DMACOM0 = 7; 132 DMACOM0 = 7;
133
134 if (new_buffer)
135 {
136 pcm_play_dma_started_callback();
137 new_buffer = false;
138 }
127 } 139 }
140
128} 141}
129 142
130void pcm_play_dma_start(const void* addr, size_t size) 143void pcm_play_dma_start(const void* addr, size_t size)
diff --git a/firmware/target/arm/s5l8702/pcm-s5l8702.c b/firmware/target/arm/s5l8702/pcm-s5l8702.c
index c0498a9ce2..dbadf3bac0 100644
--- a/firmware/target/arm/s5l8702/pcm-s5l8702.c
+++ b/firmware/target/arm/s5l8702/pcm-s5l8702.c
@@ -27,6 +27,7 @@
27#include "panic.h" 27#include "panic.h"
28#include "audiohw.h" 28#include "audiohw.h"
29#include "pcm.h" 29#include "pcm.h"
30#include "pcm-internal.h"
30#include "pcm_sampr.h" 31#include "pcm_sampr.h"
31#include "mmu-arm.h" 32#include "mmu-arm.h"
32#include "pcm-target.h" 33#include "pcm-target.h"
@@ -113,6 +114,8 @@ void INT_DMAC0C0(void)
113 DMAC0C0CONFIG = 0x8a81; 114 DMAC0C0CONFIG = 0x8a81;
114 } 115 }
115 else DMAC0C0NEXTLLI = pcm_lli; 116 else DMAC0C0NEXTLLI = pcm_lli;
117
118 pcm_play_dma_started_callback();
116} 119}
117 120
118void pcm_play_dma_start(const void* addr, size_t size) 121void pcm_play_dma_start(const void* addr, size_t size)
diff --git a/firmware/target/arm/tms320dm320/creative-zvm/pcm-creativezvm.c b/firmware/target/arm/tms320dm320/creative-zvm/pcm-creativezvm.c
index 3c54ce81fb..5ec62cf876 100644
--- a/firmware/target/arm/tms320dm320/creative-zvm/pcm-creativezvm.c
+++ b/firmware/target/arm/tms320dm320/creative-zvm/pcm-creativezvm.c
@@ -27,6 +27,7 @@
27#include "dm320.h" 27#include "dm320.h"
28#include "audiohw.h" 28#include "audiohw.h"
29#include "dsp-target.h" 29#include "dsp-target.h"
30#include "pcm-internal.h"
30 31
31void pcm_play_dma_init(void) 32void pcm_play_dma_init(void)
32{ 33{
diff --git a/firmware/target/arm/tms320dm320/mrobe-500/pcm-mr500.c b/firmware/target/arm/tms320dm320/mrobe-500/pcm-mr500.c
index fb94adae71..90c342e868 100644
--- a/firmware/target/arm/tms320dm320/mrobe-500/pcm-mr500.c
+++ b/firmware/target/arm/tms320dm320/mrobe-500/pcm-mr500.c
@@ -28,6 +28,7 @@
28#include "dsp-target.h" 28#include "dsp-target.h"
29#include "dsp/ipc.h" 29#include "dsp/ipc.h"
30#include "mmu-arm.h" 30#include "mmu-arm.h"
31#include "pcm-internal.h"
31 32
32/* 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
33 * called. 34 * called.
@@ -178,6 +179,8 @@ void DSPHINT(void)
178 179
179 DEBUGF("pcm_sdram at 0x%08lx, sdem_addr 0x%08lx", 180 DEBUGF("pcm_sdram at 0x%08lx, sdem_addr 0x%08lx",
180 (unsigned long)start, (unsigned long)sdem_addr); 181 (unsigned long)start, (unsigned long)sdem_addr);
182
183 pcm_play_dma_started_callback();
181 } 184 }
182 185
183 break; 186 break;
diff --git a/firmware/target/coldfire/pcm-coldfire.c b/firmware/target/coldfire/pcm-coldfire.c
index a06542c31f..85eeaec815 100644
--- a/firmware/target/coldfire/pcm-coldfire.c
+++ b/firmware/target/coldfire/pcm-coldfire.c
@@ -28,6 +28,7 @@
28#if defined(HAVE_SPDIF_REC) || defined(HAVE_SPDIF_OUT) 28#if defined(HAVE_SPDIF_REC) || defined(HAVE_SPDIF_OUT)
29#include "spdif.h" 29#include "spdif.h"
30#endif 30#endif
31#include "pcm-internal.h"
31 32
32#define IIS_PLAY_DEFPARM ( (freq_ent[FPARM_CLOCKSEL] << 12) | \ 33#define IIS_PLAY_DEFPARM ( (freq_ent[FPARM_CLOCKSEL] << 12) | \
33 (IIS_PLAY & (7 << 8)) | \ 34 (IIS_PLAY & (7 << 8)) | \
@@ -318,6 +319,9 @@ void DMA0(void)
318 SAR0 = (unsigned long)start; /* Source address */ 319 SAR0 = (unsigned long)start; /* Source address */
319 BCR0 = size; /* Bytes to transfer */ 320 BCR0 = size; /* Bytes to transfer */
320 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
323 /* Call buffer callback */
324 pcm_play_dma_started_callback();
321 } 325 }
322 /* else inished playing */ 326 /* else inished playing */
323} /* DMA0 */ 327} /* DMA0 */
diff --git a/firmware/target/coldfire/pcm-mixer-coldfire.c b/firmware/target/coldfire/pcm-mixer-coldfire.c
new file mode 100644
index 0000000000..d8318fffaf
--- /dev/null
+++ b/firmware/target/coldfire/pcm-mixer-coldfire.c
@@ -0,0 +1,134 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2011 by Michael Sevakis
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#define MIXER_OPTIMIZED_MIX_SAMPLES
23#define MIXER_OPTIMIZED_WRITE_SAMPLES
24static struct emac_context
25{
26 unsigned long r[4];
27} emac_context IBSS_ATTR;
28
29/* Save emac context affected in ISR */
30static FORCE_INLINE void save_emac_context(void)
31{
32 asm volatile (
33 "move.l %%macsr, %%d0 \n"
34 "move.l %%accext01, %%d1 \n"
35 "movclr.l %%acc0, %%a0 \n"
36 "movclr.l %%acc1, %%a1 \n"
37 "movem.l %%d0-%%d1/%%a0-%%a1, (%0) \n"
38 :
39 : "a"(&emac_context)
40 : "d0", "d1", "a0", "a1");
41}
42
43/* Restore emac context affected in ISR */
44static FORCE_INLINE void restore_emac_context(void)
45{
46 asm volatile (
47 "movem.l (%0), %%d0-%%d1/%%a0-%%a1 \n"
48 "move.l %%a1, %%acc1 \n"
49 "move.l %%a0, %%acc0 \n"
50 "move.l %%d1, %%accext01 \n"
51 "move.l %%d0, %%macsr \n"
52 :
53 : "a"(&emac_context)
54 : "d0", "d1", "a0", "a1");
55}
56
57/* Mix channels' samples and apply gain factors */
58static FORCE_INLINE void mix_samples(void *out,
59 void *src0,
60 int32_t src0_amp,
61 void *src1,
62 int32_t src1_amp,
63 size_t size)
64{
65 uint32_t s0, s1, s2, s3;
66 save_emac_context();
67 coldfire_set_macsr(EMAC_ROUND | EMAC_SATURATE);
68
69 asm volatile (
70 "move.l (%1)+, %5 \n"
71 "1: \n"
72 "movea.w %5, %4 \n"
73 "asr.l %10, %5 \n"
74 "mac.l %4, %8, %%acc0 \n"
75 "mac.l %5, %8, (%2)+, %5, %%acc1 \n"
76 "movea.w %5, %4 \n"
77 "asr.l %10, %5 \n"
78 "mac.l %4, %9, %%acc0 \n"
79 "mac.l %5, %9, (%1)+, %5, %%acc1 \n"
80 "movclr.l %%acc0, %6 \n"
81 "movclr.l %%acc1, %7 \n"
82 "swap.w %6 \n"
83 "move.w %6, %7 \n"
84 "move.l %7, (%0)+ \n"
85 "subq.l #4, %3 \n"
86 "bhi.b 1b \n"
87 : "+a"(out), "+a"(src0), "+a"(src1), "+d"(size),
88 "=&a"(s0), "=&d"(s1), "=&d"(s2), "=&d"(s3)
89 : "r"(src0_amp), "r"(src1_amp), "d"(16)
90 );
91
92 restore_emac_context();
93}
94
95/* Write channel's samples and apply gain factor */
96static FORCE_INLINE void write_samples(void *out,
97 void *src,
98 int32_t amp,
99 size_t size)
100{
101 if (LIKELY(amp == MIX_AMP_UNITY))
102 {
103 /* Channel is unity amplitude */
104 memcpy(out, src, size);
105 }
106 else
107 {
108 /* Channel needs amplitude cut */
109 uint32_t s0, s1, s2, s3;
110 save_emac_context();
111 coldfire_set_macsr(EMAC_ROUND | EMAC_SATURATE);
112
113 asm volatile (
114 "move.l (%1)+, %4 \n"
115 "1: \n"
116 "movea.w %4, %3 \n"
117 "asr.l %8, %4 \n"
118 "mac.l %3, %7, %%acc0 \n"
119 "mac.l %4, %7, (%1)+, %4, %%acc1 \n"
120 "movclr.l %%acc0, %5 \n"
121 "movclr.l %%acc1, %6 \n"
122 "swap.w %5 \n"
123 "move.w %5, %6 \n"
124 "move.l %6, (%0)+ \n"
125 "subq.l #4, %2 \n"
126 "bhi.b 1b \n"
127 : "+a"(out), "+a"(src), "+d"(size),
128 "=&a"(s0), "=&d"(s1), "=&d"(s2), "=&d"(s3)
129 : "r"(amp), "d"(16)
130 );
131
132 restore_emac_context();
133 }
134}
diff --git a/firmware/target/hosted/android/pcm-android.c b/firmware/target/hosted/android/pcm-android.c
index 88792cd76f..cbd6cb3228 100644
--- a/firmware/target/hosted/android/pcm-android.c
+++ b/firmware/target/hosted/android/pcm-android.c
@@ -23,14 +23,18 @@
23#include <stdbool.h> 23#include <stdbool.h>
24#define _SYSTEM_WITH_JNI /* for getJavaEnvironment */ 24#define _SYSTEM_WITH_JNI /* for getJavaEnvironment */
25#include <system.h> 25#include <system.h>
26#include <pthread.h>
26#include "debug.h" 27#include "debug.h"
27#include "pcm.h" 28#include "pcm.h"
29#include "pcm-internal.h"
28 30
29extern JNIEnv *env_ptr; 31extern JNIEnv *env_ptr;
30 32
31/* infos about our pcm chunks */ 33/* infos about our pcm chunks */
32static size_t pcm_data_size; 34static size_t pcm_data_size;
33static char *pcm_data_start; 35static char *pcm_data_start;
36static int audio_locked = 0;
37static pthread_mutex_t audio_lock_mutex = PTHREAD_MUTEX_INITIALIZER;
34 38
35/* cache frequently called methods */ 39/* cache frequently called methods */
36static jmethodID play_pause_method; 40static jmethodID play_pause_method;
@@ -42,6 +46,20 @@ static jobject RockboxPCM_instance;
42 46
43 47
44/* 48/*
49 * mutex lock/unlock wrappers neatness' sake
50 */
51static inline void lock_audio(void)
52{
53 pthread_mutex_lock(&audio_lock_mutex);
54}
55
56static inline void unlock_audio(void)
57{
58 pthread_mutex_unlock(&audio_lock_mutex);
59}
60
61
62/*
45 * write pcm samples to the hardware. Calls AudioTrack.write directly (which 63 * write pcm samples to the hardware. Calls AudioTrack.write directly (which
46 * is usually a blocking call) 64 * is usually a blocking call)
47 * 65 *
@@ -54,10 +72,17 @@ JNIEXPORT jint JNICALL
54Java_org_rockbox_RockboxPCM_nativeWrite(JNIEnv *env, jobject this, 72Java_org_rockbox_RockboxPCM_nativeWrite(JNIEnv *env, jobject this,
55 jbyteArray temp_array, jint max_size) 73 jbyteArray temp_array, jint max_size)
56{ 74{
75 bool new_buffer = false;
76
77 lock_audio();
78
57 jint left = max_size; 79 jint left = max_size;
58 80
59 if (!pcm_data_size) /* get some initial data */ 81 if (!pcm_data_size) /* get some initial data */
82 {
83 new_buffer = true;
60 pcm_play_get_more_callback((void**) &pcm_data_start, &pcm_data_size); 84 pcm_play_get_more_callback((void**) &pcm_data_start, &pcm_data_size);
85 }
61 86
62 while(left > 0 && pcm_data_size) 87 while(left > 0 && pcm_data_size)
63 { 88 {
@@ -70,23 +95,49 @@ Java_org_rockbox_RockboxPCM_nativeWrite(JNIEnv *env, jobject this,
70 95
71 ret = (*env)->CallIntMethod(env, this, write_method, 96 ret = (*env)->CallIntMethod(env, this, write_method,
72 temp_array, 0, transfer_size); 97 temp_array, 0, transfer_size);
98
99 if (new_buffer)
100 {
101 new_buffer = false;
102 pcm_play_dma_started_callback();
103
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
106 have the mixer clocked at a regular interval */
107 }
108
73 if (ret < 0) 109 if (ret < 0)
110 {
111 unlock_audio();
74 return ret; 112 return ret;
113 }
75 114
76 if (pcm_data_size == 0) /* need new data */ 115 if (pcm_data_size == 0) /* need new data */
116 {
117 new_buffer = true;
77 pcm_play_get_more_callback((void**)&pcm_data_start, &pcm_data_size); 118 pcm_play_get_more_callback((void**)&pcm_data_start, &pcm_data_size);
119 }
78 else /* increment data pointer and feed more */ 120 else /* increment data pointer and feed more */
79 pcm_data_start += transfer_size; 121 pcm_data_start += transfer_size;
80 } 122 }
123
124 if (new_buffer && pcm_data_size)
125 pcm_play_dma_started_callback();
126
127 unlock_audio();
81 return max_size - left; 128 return max_size - left;
82} 129}
83 130
84void pcm_play_lock(void) 131void pcm_play_lock(void)
85{ 132{
133 if (++audio_locked == 1)
134 lock_audio();
86} 135}
87 136
88void pcm_play_unlock(void) 137void pcm_play_unlock(void)
89{ 138{
139 if (--audio_locked == 0)
140 unlock_audio();
90} 141}
91 142
92void pcm_dma_apply_settings(void) 143void pcm_dma_apply_settings(void)
@@ -153,8 +204,6 @@ void pcm_play_dma_init(void)
153 set_volume_method = e->GetMethodID(env_ptr, RockboxPCM_class, "set_volume", "(I)V"); 204 set_volume_method = e->GetMethodID(env_ptr, RockboxPCM_class, "set_volume", "(I)V");
154 stop_method = e->GetMethodID(env_ptr, RockboxPCM_class, "stop", "()V"); 205 stop_method = e->GetMethodID(env_ptr, RockboxPCM_class, "stop", "()V");
155 write_method = e->GetMethodID(env_ptr, RockboxPCM_class, "write", "([BII)I"); 206 write_method = e->GetMethodID(env_ptr, RockboxPCM_class, "write", "([BII)I");
156 /* get initial pcm data, if any */
157 pcm_play_get_more_callback((void*)&pcm_data_start, &pcm_data_size);
158} 207}
159 208
160void pcm_postinit(void) 209void pcm_postinit(void)
@@ -173,6 +222,7 @@ void pcm_shutdown(void)
173 JNIEnv e = *env_ptr; 222 JNIEnv e = *env_ptr;
174 jmethodID release = e->GetMethodID(env_ptr, RockboxPCM_class, "release", "()V"); 223 jmethodID release = e->GetMethodID(env_ptr, RockboxPCM_class, "release", "()V");
175 e->CallVoidMethod(env_ptr, RockboxPCM_instance, release); 224 e->CallVoidMethod(env_ptr, RockboxPCM_instance, release);
225 pthread_mutex_destroy(&audio_lock_mutex);
176} 226}
177 227
178/* Due to limitations of default_event_handler(), parameters gets swallowed when 228/* Due to limitations of default_event_handler(), parameters gets swallowed when
diff --git a/firmware/target/hosted/maemo/pcm-gstreamer.c b/firmware/target/hosted/maemo/pcm-gstreamer.c
index e3e40f0619..6069801fba 100644
--- a/firmware/target/hosted/maemo/pcm-gstreamer.c
+++ b/firmware/target/hosted/maemo/pcm-gstreamer.c
@@ -54,6 +54,7 @@
54#endif 54#endif
55 55
56#include "pcm.h" 56#include "pcm.h"
57#include "pcm-internal.h"
57#include "pcm_sampr.h" 58#include "pcm_sampr.h"
58 59
59/*#define LOGF_ENABLE*/ 60/*#define LOGF_ENABLE*/
@@ -182,6 +183,8 @@ static void feed_data(GstElement * appsrc, guint size_hint, void *unused)
182 183
183 if (ret != 0) 184 if (ret != 0)
184 DEBUGF("push-buffer error result: %d\n", ret); 185 DEBUGF("push-buffer error result: %d\n", ret);
186
187 pcm_play_dma_started_callback();
185 } else 188 } else
186 { 189 {
187 DEBUGF("feed_data: No Data.\n"); 190 DEBUGF("feed_data: No Data.\n");
diff --git a/firmware/target/hosted/sdl/pcm-sdl.c b/firmware/target/hosted/sdl/pcm-sdl.c
index 7780083b99..dfdd90f29b 100644
--- a/firmware/target/hosted/sdl/pcm-sdl.c
+++ b/firmware/target/hosted/sdl/pcm-sdl.c
@@ -30,6 +30,7 @@
30#include "sound.h" 30#include "sound.h"
31#include "audiohw.h" 31#include "audiohw.h"
32#include "system.h" 32#include "system.h"
33#include "panic.h"
33 34
34#ifdef HAVE_RECORDING 35#ifdef HAVE_RECORDING
35#include "audiohw.h" 36#include "audiohw.h"
@@ -39,6 +40,7 @@
39#endif 40#endif
40 41
41#include "pcm.h" 42#include "pcm.h"
43#include "pcm-internal.h"
42#include "pcm_sampr.h" 44#include "pcm_sampr.h"
43 45
44/*#define LOGF_ENABLE*/ 46/*#define LOGF_ENABLE*/
@@ -71,15 +73,19 @@ static struct pcm_udata
71 73
72static SDL_AudioSpec obtained; 74static SDL_AudioSpec obtained;
73static SDL_AudioCVT cvt; 75static SDL_AudioCVT cvt;
76static int audio_locked = 0;
77static SDL_mutex *audio_lock;
74 78
75void pcm_play_lock(void) 79void pcm_play_lock(void)
76{ 80{
77 SDL_LockAudio(); 81 if (++audio_locked == 1)
82 SDL_LockMutex(audio_lock);
78} 83}
79 84
80void pcm_play_unlock(void) 85void pcm_play_unlock(void)
81{ 86{
82 SDL_UnlockAudio(); 87 if (--audio_locked == 0)
88 SDL_UnlockMutex(audio_lock);
83} 89}
84 90
85static void pcm_dma_apply_settings_nolock(void) 91static void pcm_dma_apply_settings_nolock(void)
@@ -227,14 +233,19 @@ static void write_to_soundcard(struct pcm_udata *udata)
227static void sdl_audio_callback(struct pcm_udata *udata, Uint8 *stream, int len) 233static void sdl_audio_callback(struct pcm_udata *udata, Uint8 *stream, int len)
228{ 234{
229 logf("sdl_audio_callback: len %d, pcm %d\n", len, pcm_data_size); 235 logf("sdl_audio_callback: len %d, pcm %d\n", len, pcm_data_size);
236
237 bool new_buffer = false;
230 udata->stream = stream; 238 udata->stream = stream;
231 239
240 SDL_LockMutex(audio_lock);
241
232 /* Write what we have in the PCM buffer */ 242 /* Write what we have in the PCM buffer */
233 if (pcm_data_size > 0) 243 if (pcm_data_size > 0)
234 goto start; 244 goto start;
235 245
236 /* Audio card wants more? Get some more then. */ 246 /* Audio card wants more? Get some more then. */
237 while (len > 0) { 247 while (len > 0) {
248 new_buffer = true;
238 pcm_play_get_more_callback((void **)&pcm_data, &pcm_data_size); 249 pcm_play_get_more_callback((void **)&pcm_data, &pcm_data_size);
239 start: 250 start:
240 if (pcm_data_size != 0) { 251 if (pcm_data_size != 0) {
@@ -246,6 +257,28 @@ static void sdl_audio_callback(struct pcm_udata *udata, Uint8 *stream, int len)
246 udata->num_in *= pcm_sample_bytes; 257 udata->num_in *= pcm_sample_bytes;
247 udata->num_out *= pcm_sample_bytes; 258 udata->num_out *= pcm_sample_bytes;
248 259
260
261 if (new_buffer)
262 {
263 new_buffer = false;
264 pcm_play_dma_started_callback();
265
266 if ((size_t)len > udata->num_out)
267 {
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);
275
276 if (!pcm_is_playing())
277 break;
278 }
279 }
280 }
281
249 pcm_data += udata->num_in; 282 pcm_data += udata->num_in;
250 pcm_data_size -= udata->num_in; 283 pcm_data_size -= udata->num_in;
251 udata->stream += udata->num_out; 284 udata->stream += udata->num_out;
@@ -255,6 +288,8 @@ static void sdl_audio_callback(struct pcm_udata *udata, Uint8 *stream, int len)
255 break; 288 break;
256 } 289 }
257 } 290 }
291
292 SDL_UnlockMutex(audio_lock);
258} 293}
259 294
260const void * pcm_play_dma_get_peak_buffer(int *count) 295const void * pcm_play_dma_get_peak_buffer(int *count)
@@ -320,6 +355,14 @@ void pcm_play_dma_init(void)
320 return; 355 return;
321 } 356 }
322 357
358 audio_lock = SDL_CreateMutex();
359
360 if (!audio_lock)
361 {
362 panicf("Could not create audio_lock\n");
363 return;
364 }
365
323 SDL_AudioSpec wanted_spec; 366 SDL_AudioSpec wanted_spec;
324#ifdef DEBUG 367#ifdef DEBUG
325 udata.debug = NULL; 368 udata.debug = NULL;
diff --git a/firmware/target/mips/ingenic_jz47xx/pcm-jz4740.c b/firmware/target/mips/ingenic_jz47xx/pcm-jz4740.c
index 5cd9c33e18..cfc3c9ef8e 100644
--- a/firmware/target/mips/ingenic_jz47xx/pcm-jz4740.c
+++ b/firmware/target/mips/ingenic_jz47xx/pcm-jz4740.c
@@ -25,6 +25,7 @@
25#include "audio.h" 25#include "audio.h"
26#include "sound.h" 26#include "sound.h"
27#include "pcm.h" 27#include "pcm.h"
28#include "pcm-internal.h"
28#include "jz4740.h" 29#include "jz4740.h"
29 30
30 31
@@ -109,6 +110,7 @@ static inline void play_dma_callback(void)
109 { 110 {
110 set_dma(start, size); 111 set_dma(start, size);
111 REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) |= DMAC_DCCSR_EN; 112 REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) |= DMAC_DCCSR_EN;
113 pcm_play_dma_started_callback();
112 } 114 }
113} 115}
114 116