| @@ -1,1144 +1,1144 @@ | | | @@ -1,1144 +1,1144 @@ |
1 | /* $NetBSD: audio.c,v 1.28.2.4 2019/11/19 12:58:29 martin Exp $ */ | | 1 | /* $NetBSD: audio.c,v 1.28.2.5 2020/01/02 09:18:15 martin Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 2008 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2008 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Andrew Doran. | | 8 | * by Andrew Doran. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright | | 15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the | | 16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. | | 17 | * documentation and/or other materials provided with the distribution. |
18 | * | | 18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | /* | | 32 | /* |
33 | * Copyright (c) 1991-1993 Regents of the University of California. | | 33 | * Copyright (c) 1991-1993 Regents of the University of California. |
34 | * All rights reserved. | | 34 | * All rights reserved. |
35 | * | | 35 | * |
36 | * Redistribution and use in source and binary forms, with or without | | 36 | * Redistribution and use in source and binary forms, with or without |
37 | * modification, are permitted provided that the following conditions | | 37 | * modification, are permitted provided that the following conditions |
38 | * are met: | | 38 | * are met: |
39 | * 1. Redistributions of source code must retain the above copyright | | 39 | * 1. Redistributions of source code must retain the above copyright |
40 | * notice, this list of conditions and the following disclaimer. | | 40 | * notice, this list of conditions and the following disclaimer. |
41 | * 2. Redistributions in binary form must reproduce the above copyright | | 41 | * 2. Redistributions in binary form must reproduce the above copyright |
42 | * notice, this list of conditions and the following disclaimer in the | | 42 | * notice, this list of conditions and the following disclaimer in the |
43 | * documentation and/or other materials provided with the distribution. | | 43 | * documentation and/or other materials provided with the distribution. |
44 | * 3. All advertising materials mentioning features or use of this software | | 44 | * 3. All advertising materials mentioning features or use of this software |
45 | * must display the following acknowledgement: | | 45 | * must display the following acknowledgement: |
46 | * This product includes software developed by the Computer Systems | | 46 | * This product includes software developed by the Computer Systems |
47 | * Engineering Group at Lawrence Berkeley Laboratory. | | 47 | * Engineering Group at Lawrence Berkeley Laboratory. |
48 | * 4. Neither the name of the University nor of the Laboratory may be used | | 48 | * 4. Neither the name of the University nor of the Laboratory may be used |
49 | * to endorse or promote products derived from this software without | | 49 | * to endorse or promote products derived from this software without |
50 | * specific prior written permission. | | 50 | * specific prior written permission. |
51 | * | | 51 | * |
52 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | | 52 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
53 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 53 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
54 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 54 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
55 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | | 55 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
56 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 56 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
57 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 57 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
58 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 58 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
59 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 59 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
60 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 60 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
61 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 61 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
62 | * SUCH DAMAGE. | | 62 | * SUCH DAMAGE. |
63 | */ | | 63 | */ |
64 | | | 64 | |
65 | /* | | 65 | /* |
66 | * Locking: there are three locks per device. | | 66 | * Locking: there are three locks per device. |
67 | * | | 67 | * |
68 | * - sc_lock, provided by the underlying driver. This is an adaptive lock, | | 68 | * - sc_lock, provided by the underlying driver. This is an adaptive lock, |
69 | * returned in the second parameter to hw_if->get_locks(). It is known | | 69 | * returned in the second parameter to hw_if->get_locks(). It is known |
70 | * as the "thread lock". | | 70 | * as the "thread lock". |
71 | * | | 71 | * |
72 | * It serializes access to state in all places except the | | 72 | * It serializes access to state in all places except the |
73 | * driver's interrupt service routine. This lock is taken from process | | 73 | * driver's interrupt service routine. This lock is taken from process |
74 | * context (example: access to /dev/audio). It is also taken from soft | | 74 | * context (example: access to /dev/audio). It is also taken from soft |
75 | * interrupt handlers in this module, primarily to serialize delivery of | | 75 | * interrupt handlers in this module, primarily to serialize delivery of |
76 | * wakeups. This lock may be used/provided by modules external to the | | 76 | * wakeups. This lock may be used/provided by modules external to the |
77 | * audio subsystem, so take care not to introduce a lock order problem. | | 77 | * audio subsystem, so take care not to introduce a lock order problem. |
78 | * LONG TERM SLEEPS MUST NOT OCCUR WITH THIS LOCK HELD. | | 78 | * LONG TERM SLEEPS MUST NOT OCCUR WITH THIS LOCK HELD. |
79 | * | | 79 | * |
80 | * - sc_intr_lock, provided by the underlying driver. This may be either a | | 80 | * - sc_intr_lock, provided by the underlying driver. This may be either a |
81 | * spinlock (at IPL_SCHED or IPL_VM) or an adaptive lock (IPL_NONE or | | 81 | * spinlock (at IPL_SCHED or IPL_VM) or an adaptive lock (IPL_NONE or |
82 | * IPL_SOFT*), returned in the first parameter to hw_if->get_locks(). It | | 82 | * IPL_SOFT*), returned in the first parameter to hw_if->get_locks(). It |
83 | * is known as the "interrupt lock". | | 83 | * is known as the "interrupt lock". |
84 | * | | 84 | * |
85 | * It provides atomic access to the device's hardware state, and to audio | | 85 | * It provides atomic access to the device's hardware state, and to audio |
86 | * channel data that may be accessed by the hardware driver's ISR. | | 86 | * channel data that may be accessed by the hardware driver's ISR. |
87 | * In all places outside the ISR, sc_lock must be held before taking | | 87 | * In all places outside the ISR, sc_lock must be held before taking |
88 | * sc_intr_lock. This is to ensure that groups of hardware operations are | | 88 | * sc_intr_lock. This is to ensure that groups of hardware operations are |
89 | * made atomically. SLEEPS CANNOT OCCUR WITH THIS LOCK HELD. | | 89 | * made atomically. SLEEPS CANNOT OCCUR WITH THIS LOCK HELD. |
90 | * | | 90 | * |
91 | * - sc_exlock, private to this module. This is a variable protected by | | 91 | * - sc_exlock, private to this module. This is a variable protected by |
92 | * sc_lock. It is known as the "critical section". | | 92 | * sc_lock. It is known as the "critical section". |
93 | * Some operations release sc_lock in order to allocate memory, to wait | | 93 | * Some operations release sc_lock in order to allocate memory, to wait |
94 | * for in-flight I/O to complete, to copy to/from user context, etc. | | 94 | * for in-flight I/O to complete, to copy to/from user context, etc. |
95 | * sc_exlock provides a critical section even under the circumstance. | | 95 | * sc_exlock provides a critical section even under the circumstance. |
96 | * "+" in following list indicates the interfaces which necessary to be | | 96 | * "+" in following list indicates the interfaces which necessary to be |
97 | * protected by sc_exlock. | | 97 | * protected by sc_exlock. |
98 | * | | 98 | * |
99 | * List of hardware interface methods, and which locks are held when each | | 99 | * List of hardware interface methods, and which locks are held when each |
100 | * is called by this module: | | 100 | * is called by this module: |
101 | * | | 101 | * |
102 | * METHOD INTR THREAD NOTES | | 102 | * METHOD INTR THREAD NOTES |
103 | * ----------------------- ------- ------- ------------------------- | | 103 | * ----------------------- ------- ------- ------------------------- |
104 | * open x x + | | 104 | * open x x + |
105 | * close x x + | | 105 | * close x x + |
106 | * query_format - x | | 106 | * query_format - x |
107 | * set_format - x | | 107 | * set_format - x |
108 | * round_blocksize - x | | 108 | * round_blocksize - x |
109 | * commit_settings - x | | 109 | * commit_settings - x |
110 | * init_output x x | | 110 | * init_output x x |
111 | * init_input x x | | 111 | * init_input x x |
112 | * start_output x x + | | 112 | * start_output x x + |
113 | * start_input x x + | | 113 | * start_input x x + |
114 | * halt_output x x + | | 114 | * halt_output x x + |
115 | * halt_input x x + | | 115 | * halt_input x x + |
116 | * speaker_ctl x x | | 116 | * speaker_ctl x x |
117 | * getdev - x | | 117 | * getdev - x |
118 | * set_port - x + | | 118 | * set_port - x + |
119 | * get_port - x + | | 119 | * get_port - x + |
120 | * query_devinfo - x | | 120 | * query_devinfo - x |
121 | * allocm - - + (*1) | | 121 | * allocm - - + (*1) |
122 | * freem - - + (*1) | | 122 | * freem - - + (*1) |
123 | * round_buffersize - x | | 123 | * round_buffersize - x |
124 | * get_props - x Called at attach time | | 124 | * get_props - x Called at attach time |
125 | * trigger_output x x + | | 125 | * trigger_output x x + |
126 | * trigger_input x x + | | 126 | * trigger_input x x + |
127 | * dev_ioctl - x | | 127 | * dev_ioctl - x |
128 | * get_locks - - Called at attach time | | 128 | * get_locks - - Called at attach time |
129 | * | | 129 | * |
130 | * *1 Note: Before 8.0, since these have been called only at attach time, | | 130 | * *1 Note: Before 8.0, since these have been called only at attach time, |
131 | * neither lock were necessary. Currently, on the other hand, since | | 131 | * neither lock were necessary. Currently, on the other hand, since |
132 | * these may be also called after attach, the thread lock is required. | | 132 | * these may be also called after attach, the thread lock is required. |
133 | * | | 133 | * |
134 | * In addition, there is an additional lock. | | 134 | * In addition, there is an additional lock. |
135 | * | | 135 | * |
136 | * - track->lock. This is an atomic variable and is similar to the | | 136 | * - track->lock. This is an atomic variable and is similar to the |
137 | * "interrupt lock". This is one for each track. If any thread context | | 137 | * "interrupt lock". This is one for each track. If any thread context |
138 | * (and software interrupt context) and hardware interrupt context who | | 138 | * (and software interrupt context) and hardware interrupt context who |
139 | * want to access some variables on this track, they must acquire this | | 139 | * want to access some variables on this track, they must acquire this |
140 | * lock before. It protects track's consistency between hardware | | 140 | * lock before. It protects track's consistency between hardware |
141 | * interrupt context and others. | | 141 | * interrupt context and others. |
142 | */ | | 142 | */ |
143 | | | 143 | |
144 | #include <sys/cdefs.h> | | 144 | #include <sys/cdefs.h> |
145 | __KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.28.2.4 2019/11/19 12:58:29 martin Exp $"); | | 145 | __KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.28.2.5 2020/01/02 09:18:15 martin Exp $"); |
146 | | | 146 | |
147 | #ifdef _KERNEL_OPT | | 147 | #ifdef _KERNEL_OPT |
148 | #include "audio.h" | | 148 | #include "audio.h" |
149 | #include "midi.h" | | 149 | #include "midi.h" |
150 | #endif | | 150 | #endif |
151 | | | 151 | |
152 | #if NAUDIO > 0 | | 152 | #if NAUDIO > 0 |
153 | | | 153 | |
154 | #ifdef _KERNEL | | 154 | #ifdef _KERNEL |
155 | | | 155 | |
156 | #include <sys/types.h> | | 156 | #include <sys/types.h> |
157 | #include <sys/param.h> | | 157 | #include <sys/param.h> |
158 | #include <sys/atomic.h> | | 158 | #include <sys/atomic.h> |
159 | #include <sys/audioio.h> | | 159 | #include <sys/audioio.h> |
160 | #include <sys/conf.h> | | 160 | #include <sys/conf.h> |
161 | #include <sys/cpu.h> | | 161 | #include <sys/cpu.h> |
162 | #include <sys/device.h> | | 162 | #include <sys/device.h> |
163 | #include <sys/fcntl.h> | | 163 | #include <sys/fcntl.h> |
164 | #include <sys/file.h> | | 164 | #include <sys/file.h> |
165 | #include <sys/filedesc.h> | | 165 | #include <sys/filedesc.h> |
166 | #include <sys/intr.h> | | 166 | #include <sys/intr.h> |
167 | #include <sys/ioctl.h> | | 167 | #include <sys/ioctl.h> |
168 | #include <sys/kauth.h> | | 168 | #include <sys/kauth.h> |
169 | #include <sys/kernel.h> | | 169 | #include <sys/kernel.h> |
170 | #include <sys/kmem.h> | | 170 | #include <sys/kmem.h> |
171 | #include <sys/malloc.h> | | 171 | #include <sys/malloc.h> |
172 | #include <sys/mman.h> | | 172 | #include <sys/mman.h> |
173 | #include <sys/module.h> | | 173 | #include <sys/module.h> |
174 | #include <sys/poll.h> | | 174 | #include <sys/poll.h> |
175 | #include <sys/proc.h> | | 175 | #include <sys/proc.h> |
176 | #include <sys/queue.h> | | 176 | #include <sys/queue.h> |
177 | #include <sys/select.h> | | 177 | #include <sys/select.h> |
178 | #include <sys/signalvar.h> | | 178 | #include <sys/signalvar.h> |
179 | #include <sys/stat.h> | | 179 | #include <sys/stat.h> |
180 | #include <sys/sysctl.h> | | 180 | #include <sys/sysctl.h> |
181 | #include <sys/systm.h> | | 181 | #include <sys/systm.h> |
182 | #include <sys/syslog.h> | | 182 | #include <sys/syslog.h> |
183 | #include <sys/vnode.h> | | 183 | #include <sys/vnode.h> |
184 | | | 184 | |
185 | #include <dev/audio/audio_if.h> | | 185 | #include <dev/audio/audio_if.h> |
186 | #include <dev/audio/audiovar.h> | | 186 | #include <dev/audio/audiovar.h> |
187 | #include <dev/audio/audiodef.h> | | 187 | #include <dev/audio/audiodef.h> |
188 | #include <dev/audio/linear.h> | | 188 | #include <dev/audio/linear.h> |
189 | #include <dev/audio/mulaw.h> | | 189 | #include <dev/audio/mulaw.h> |
190 | | | 190 | |
191 | #include <machine/endian.h> | | 191 | #include <machine/endian.h> |
192 | | | 192 | |
193 | #include <uvm/uvm.h> | | 193 | #include <uvm/uvm.h> |
194 | | | 194 | |
195 | #include "ioconf.h" | | 195 | #include "ioconf.h" |
196 | #endif /* _KERNEL */ | | 196 | #endif /* _KERNEL */ |
197 | | | 197 | |
198 | /* | | 198 | /* |
199 | * 0: No debug logs | | 199 | * 0: No debug logs |
200 | * 1: action changes like open/close/set_format... | | 200 | * 1: action changes like open/close/set_format... |
201 | * 2: + normal operations like read/write/ioctl... | | 201 | * 2: + normal operations like read/write/ioctl... |
202 | * 3: + TRACEs except interrupt | | 202 | * 3: + TRACEs except interrupt |
203 | * 4: + TRACEs including interrupt | | 203 | * 4: + TRACEs including interrupt |
204 | */ | | 204 | */ |
205 | //#define AUDIO_DEBUG 1 | | 205 | //#define AUDIO_DEBUG 1 |
206 | | | 206 | |
207 | #if defined(AUDIO_DEBUG) | | 207 | #if defined(AUDIO_DEBUG) |
208 | | | 208 | |
209 | int audiodebug = AUDIO_DEBUG; | | 209 | int audiodebug = AUDIO_DEBUG; |
210 | static void audio_vtrace(struct audio_softc *sc, const char *, const char *, | | 210 | static void audio_vtrace(struct audio_softc *sc, const char *, const char *, |
211 | const char *, va_list); | | 211 | const char *, va_list); |
212 | static void audio_trace(struct audio_softc *sc, const char *, const char *, ...) | | 212 | static void audio_trace(struct audio_softc *sc, const char *, const char *, ...) |
213 | __printflike(3, 4); | | 213 | __printflike(3, 4); |
214 | static void audio_tracet(const char *, audio_track_t *, const char *, ...) | | 214 | static void audio_tracet(const char *, audio_track_t *, const char *, ...) |
215 | __printflike(3, 4); | | 215 | __printflike(3, 4); |
216 | static void audio_tracef(const char *, audio_file_t *, const char *, ...) | | 216 | static void audio_tracef(const char *, audio_file_t *, const char *, ...) |
217 | __printflike(3, 4); | | 217 | __printflike(3, 4); |
218 | | | 218 | |
219 | /* XXX sloppy memory logger */ | | 219 | /* XXX sloppy memory logger */ |
220 | static void audio_mlog_init(void); | | 220 | static void audio_mlog_init(void); |
221 | static void audio_mlog_free(void); | | 221 | static void audio_mlog_free(void); |
222 | static void audio_mlog_softintr(void *); | | 222 | static void audio_mlog_softintr(void *); |
223 | extern void audio_mlog_flush(void); | | 223 | extern void audio_mlog_flush(void); |
224 | extern void audio_mlog_printf(const char *, ...); | | 224 | extern void audio_mlog_printf(const char *, ...); |
225 | | | 225 | |
226 | static int mlog_refs; /* reference counter */ | | 226 | static int mlog_refs; /* reference counter */ |
227 | static char *mlog_buf[2]; /* double buffer */ | | 227 | static char *mlog_buf[2]; /* double buffer */ |
228 | static int mlog_buflen; /* buffer length */ | | 228 | static int mlog_buflen; /* buffer length */ |
229 | static int mlog_used; /* used length */ | | 229 | static int mlog_used; /* used length */ |
230 | static int mlog_full; /* number of dropped lines by buffer full */ | | 230 | static int mlog_full; /* number of dropped lines by buffer full */ |
231 | static int mlog_drop; /* number of dropped lines by busy */ | | 231 | static int mlog_drop; /* number of dropped lines by busy */ |
232 | static volatile uint32_t mlog_inuse; /* in-use */ | | 232 | static volatile uint32_t mlog_inuse; /* in-use */ |
233 | static int mlog_wpage; /* active page */ | | 233 | static int mlog_wpage; /* active page */ |
234 | static void *mlog_sih; /* softint handle */ | | 234 | static void *mlog_sih; /* softint handle */ |
235 | | | 235 | |
236 | static void | | 236 | static void |
237 | audio_mlog_init(void) | | 237 | audio_mlog_init(void) |
238 | { | | 238 | { |
239 | mlog_refs++; | | 239 | mlog_refs++; |
240 | if (mlog_refs > 1) | | 240 | if (mlog_refs > 1) |
241 | return; | | 241 | return; |
242 | mlog_buflen = 4096; | | 242 | mlog_buflen = 4096; |
243 | mlog_buf[0] = kmem_zalloc(mlog_buflen, KM_SLEEP); | | 243 | mlog_buf[0] = kmem_zalloc(mlog_buflen, KM_SLEEP); |
244 | mlog_buf[1] = kmem_zalloc(mlog_buflen, KM_SLEEP); | | 244 | mlog_buf[1] = kmem_zalloc(mlog_buflen, KM_SLEEP); |
245 | mlog_used = 0; | | 245 | mlog_used = 0; |
246 | mlog_full = 0; | | 246 | mlog_full = 0; |
247 | mlog_drop = 0; | | 247 | mlog_drop = 0; |
248 | mlog_inuse = 0; | | 248 | mlog_inuse = 0; |
249 | mlog_wpage = 0; | | 249 | mlog_wpage = 0; |
250 | mlog_sih = softint_establish(SOFTINT_SERIAL, audio_mlog_softintr, NULL); | | 250 | mlog_sih = softint_establish(SOFTINT_SERIAL, audio_mlog_softintr, NULL); |
251 | if (mlog_sih == NULL) | | 251 | if (mlog_sih == NULL) |
252 | printf("%s: softint_establish failed\n", __func__); | | 252 | printf("%s: softint_establish failed\n", __func__); |
253 | } | | 253 | } |
254 | | | 254 | |
255 | static void | | 255 | static void |
256 | audio_mlog_free(void) | | 256 | audio_mlog_free(void) |
257 | { | | 257 | { |
258 | mlog_refs--; | | 258 | mlog_refs--; |
259 | if (mlog_refs > 0) | | 259 | if (mlog_refs > 0) |
260 | return; | | 260 | return; |
261 | | | 261 | |
262 | audio_mlog_flush(); | | 262 | audio_mlog_flush(); |
263 | if (mlog_sih) | | 263 | if (mlog_sih) |
264 | softint_disestablish(mlog_sih); | | 264 | softint_disestablish(mlog_sih); |
265 | kmem_free(mlog_buf[0], mlog_buflen); | | 265 | kmem_free(mlog_buf[0], mlog_buflen); |
266 | kmem_free(mlog_buf[1], mlog_buflen); | | 266 | kmem_free(mlog_buf[1], mlog_buflen); |
267 | } | | 267 | } |
268 | | | 268 | |
269 | /* | | 269 | /* |
270 | * Flush memory buffer. | | 270 | * Flush memory buffer. |
271 | * It must not be called from hardware interrupt context. | | 271 | * It must not be called from hardware interrupt context. |
272 | */ | | 272 | */ |
273 | void | | 273 | void |
274 | audio_mlog_flush(void) | | 274 | audio_mlog_flush(void) |
275 | { | | 275 | { |
276 | if (mlog_refs == 0) | | 276 | if (mlog_refs == 0) |
277 | return; | | 277 | return; |
278 | | | 278 | |
279 | /* Nothing to do if already in use ? */ | | 279 | /* Nothing to do if already in use ? */ |
280 | if (atomic_swap_32(&mlog_inuse, 1) == 1) | | 280 | if (atomic_swap_32(&mlog_inuse, 1) == 1) |
281 | return; | | 281 | return; |
282 | | | 282 | |
283 | int rpage = mlog_wpage; | | 283 | int rpage = mlog_wpage; |
284 | mlog_wpage ^= 1; | | 284 | mlog_wpage ^= 1; |
285 | mlog_buf[mlog_wpage][0] = '\0'; | | 285 | mlog_buf[mlog_wpage][0] = '\0'; |
286 | mlog_used = 0; | | 286 | mlog_used = 0; |
287 | | | 287 | |
288 | atomic_swap_32(&mlog_inuse, 0); | | 288 | atomic_swap_32(&mlog_inuse, 0); |
289 | | | 289 | |
290 | if (mlog_buf[rpage][0] != '\0') { | | 290 | if (mlog_buf[rpage][0] != '\0') { |
291 | printf("%s", mlog_buf[rpage]); | | 291 | printf("%s", mlog_buf[rpage]); |
292 | if (mlog_drop > 0) | | 292 | if (mlog_drop > 0) |
293 | printf("mlog_drop %d\n", mlog_drop); | | 293 | printf("mlog_drop %d\n", mlog_drop); |
294 | if (mlog_full > 0) | | 294 | if (mlog_full > 0) |
295 | printf("mlog_full %d\n", mlog_full); | | 295 | printf("mlog_full %d\n", mlog_full); |
296 | } | | 296 | } |
297 | mlog_full = 0; | | 297 | mlog_full = 0; |
298 | mlog_drop = 0; | | 298 | mlog_drop = 0; |
299 | } | | 299 | } |
300 | | | 300 | |
301 | static void | | 301 | static void |
302 | audio_mlog_softintr(void *cookie) | | 302 | audio_mlog_softintr(void *cookie) |
303 | { | | 303 | { |
304 | audio_mlog_flush(); | | 304 | audio_mlog_flush(); |
305 | } | | 305 | } |
306 | | | 306 | |
307 | void | | 307 | void |
308 | audio_mlog_printf(const char *fmt, ...) | | 308 | audio_mlog_printf(const char *fmt, ...) |
309 | { | | 309 | { |
310 | int len; | | 310 | int len; |
311 | va_list ap; | | 311 | va_list ap; |
312 | | | 312 | |
313 | if (atomic_swap_32(&mlog_inuse, 1) == 1) { | | 313 | if (atomic_swap_32(&mlog_inuse, 1) == 1) { |
314 | /* already inuse */ | | 314 | /* already inuse */ |
315 | mlog_drop++; | | 315 | mlog_drop++; |
316 | return; | | 316 | return; |
317 | } | | 317 | } |
318 | | | 318 | |
319 | va_start(ap, fmt); | | 319 | va_start(ap, fmt); |
320 | len = vsnprintf( | | 320 | len = vsnprintf( |
321 | mlog_buf[mlog_wpage] + mlog_used, | | 321 | mlog_buf[mlog_wpage] + mlog_used, |
322 | mlog_buflen - mlog_used, | | 322 | mlog_buflen - mlog_used, |
323 | fmt, ap); | | 323 | fmt, ap); |
324 | va_end(ap); | | 324 | va_end(ap); |
325 | | | 325 | |
326 | mlog_used += len; | | 326 | mlog_used += len; |
327 | if (mlog_buflen - mlog_used <= 1) { | | 327 | if (mlog_buflen - mlog_used <= 1) { |
328 | mlog_full++; | | 328 | mlog_full++; |
329 | } | | 329 | } |
330 | | | 330 | |
331 | atomic_swap_32(&mlog_inuse, 0); | | 331 | atomic_swap_32(&mlog_inuse, 0); |
332 | | | 332 | |
333 | if (mlog_sih) | | 333 | if (mlog_sih) |
334 | softint_schedule(mlog_sih); | | 334 | softint_schedule(mlog_sih); |
335 | } | | 335 | } |
336 | | | 336 | |
337 | /* trace functions */ | | 337 | /* trace functions */ |
338 | static void | | 338 | static void |
339 | audio_vtrace(struct audio_softc *sc, const char *funcname, const char *header, | | 339 | audio_vtrace(struct audio_softc *sc, const char *funcname, const char *header, |
340 | const char *fmt, va_list ap) | | 340 | const char *fmt, va_list ap) |
341 | { | | 341 | { |
342 | char buf[256]; | | 342 | char buf[256]; |
343 | int n; | | 343 | int n; |
344 | | | 344 | |
345 | n = 0; | | 345 | n = 0; |
346 | buf[0] = '\0'; | | 346 | buf[0] = '\0'; |
347 | n += snprintf(buf + n, sizeof(buf) - n, "%s@%d %s", | | 347 | n += snprintf(buf + n, sizeof(buf) - n, "%s@%d %s", |
348 | funcname, device_unit(sc->sc_dev), header); | | 348 | funcname, device_unit(sc->sc_dev), header); |
349 | n += vsnprintf(buf + n, sizeof(buf) - n, fmt, ap); | | 349 | n += vsnprintf(buf + n, sizeof(buf) - n, fmt, ap); |
350 | | | 350 | |
351 | if (cpu_intr_p()) { | | 351 | if (cpu_intr_p()) { |
352 | audio_mlog_printf("%s\n", buf); | | 352 | audio_mlog_printf("%s\n", buf); |
353 | } else { | | 353 | } else { |
354 | audio_mlog_flush(); | | 354 | audio_mlog_flush(); |
355 | printf("%s\n", buf); | | 355 | printf("%s\n", buf); |
356 | } | | 356 | } |
357 | } | | 357 | } |
358 | | | 358 | |
359 | static void | | 359 | static void |
360 | audio_trace(struct audio_softc *sc, const char *funcname, const char *fmt, ...) | | 360 | audio_trace(struct audio_softc *sc, const char *funcname, const char *fmt, ...) |
361 | { | | 361 | { |
362 | va_list ap; | | 362 | va_list ap; |
363 | | | 363 | |
364 | va_start(ap, fmt); | | 364 | va_start(ap, fmt); |
365 | audio_vtrace(sc, funcname, "", fmt, ap); | | 365 | audio_vtrace(sc, funcname, "", fmt, ap); |
366 | va_end(ap); | | 366 | va_end(ap); |
367 | } | | 367 | } |
368 | | | 368 | |
369 | static void | | 369 | static void |
370 | audio_tracet(const char *funcname, audio_track_t *track, const char *fmt, ...) | | 370 | audio_tracet(const char *funcname, audio_track_t *track, const char *fmt, ...) |
371 | { | | 371 | { |
372 | char hdr[16]; | | 372 | char hdr[16]; |
373 | va_list ap; | | 373 | va_list ap; |
374 | | | 374 | |
375 | snprintf(hdr, sizeof(hdr), "#%d ", track->id); | | 375 | snprintf(hdr, sizeof(hdr), "#%d ", track->id); |
376 | va_start(ap, fmt); | | 376 | va_start(ap, fmt); |
377 | audio_vtrace(track->mixer->sc, funcname, hdr, fmt, ap); | | 377 | audio_vtrace(track->mixer->sc, funcname, hdr, fmt, ap); |
378 | va_end(ap); | | 378 | va_end(ap); |
379 | } | | 379 | } |
380 | | | 380 | |
381 | static void | | 381 | static void |
382 | audio_tracef(const char *funcname, audio_file_t *file, const char *fmt, ...) | | 382 | audio_tracef(const char *funcname, audio_file_t *file, const char *fmt, ...) |
383 | { | | 383 | { |
384 | char hdr[32]; | | 384 | char hdr[32]; |
385 | char phdr[16], rhdr[16]; | | 385 | char phdr[16], rhdr[16]; |
386 | va_list ap; | | 386 | va_list ap; |
387 | | | 387 | |
388 | phdr[0] = '\0'; | | 388 | phdr[0] = '\0'; |
389 | rhdr[0] = '\0'; | | 389 | rhdr[0] = '\0'; |
390 | if (file->ptrack) | | 390 | if (file->ptrack) |
391 | snprintf(phdr, sizeof(phdr), "#%d", file->ptrack->id); | | 391 | snprintf(phdr, sizeof(phdr), "#%d", file->ptrack->id); |
392 | if (file->rtrack) | | 392 | if (file->rtrack) |
393 | snprintf(rhdr, sizeof(rhdr), "#%d", file->rtrack->id); | | 393 | snprintf(rhdr, sizeof(rhdr), "#%d", file->rtrack->id); |
394 | snprintf(hdr, sizeof(hdr), "{%s,%s} ", phdr, rhdr); | | 394 | snprintf(hdr, sizeof(hdr), "{%s,%s} ", phdr, rhdr); |
395 | | | 395 | |
396 | va_start(ap, fmt); | | 396 | va_start(ap, fmt); |
397 | audio_vtrace(file->sc, funcname, hdr, fmt, ap); | | 397 | audio_vtrace(file->sc, funcname, hdr, fmt, ap); |
398 | va_end(ap); | | 398 | va_end(ap); |
399 | } | | 399 | } |
400 | | | 400 | |
401 | #define DPRINTF(n, fmt...) do { \ | | 401 | #define DPRINTF(n, fmt...) do { \ |
402 | if (audiodebug >= (n)) { \ | | 402 | if (audiodebug >= (n)) { \ |
403 | audio_mlog_flush(); \ | | 403 | audio_mlog_flush(); \ |
404 | printf(fmt); \ | | 404 | printf(fmt); \ |
405 | } \ | | 405 | } \ |
406 | } while (0) | | 406 | } while (0) |
407 | #define TRACE(n, fmt...) do { \ | | 407 | #define TRACE(n, fmt...) do { \ |
408 | if (audiodebug >= (n)) audio_trace(sc, __func__, fmt); \ | | 408 | if (audiodebug >= (n)) audio_trace(sc, __func__, fmt); \ |
409 | } while (0) | | 409 | } while (0) |
410 | #define TRACET(n, t, fmt...) do { \ | | 410 | #define TRACET(n, t, fmt...) do { \ |
411 | if (audiodebug >= (n)) audio_tracet(__func__, t, fmt); \ | | 411 | if (audiodebug >= (n)) audio_tracet(__func__, t, fmt); \ |
412 | } while (0) | | 412 | } while (0) |
413 | #define TRACEF(n, f, fmt...) do { \ | | 413 | #define TRACEF(n, f, fmt...) do { \ |
414 | if (audiodebug >= (n)) audio_tracef(__func__, f, fmt); \ | | 414 | if (audiodebug >= (n)) audio_tracef(__func__, f, fmt); \ |
415 | } while (0) | | 415 | } while (0) |
416 | | | 416 | |
417 | struct audio_track_debugbuf { | | 417 | struct audio_track_debugbuf { |
418 | char usrbuf[32]; | | 418 | char usrbuf[32]; |
419 | char codec[32]; | | 419 | char codec[32]; |
420 | char chvol[32]; | | 420 | char chvol[32]; |
421 | char chmix[32]; | | 421 | char chmix[32]; |
422 | char freq[32]; | | 422 | char freq[32]; |
423 | char outbuf[32]; | | 423 | char outbuf[32]; |
424 | }; | | 424 | }; |
425 | | | 425 | |
426 | static void | | 426 | static void |
427 | audio_track_bufstat(audio_track_t *track, struct audio_track_debugbuf *buf) | | 427 | audio_track_bufstat(audio_track_t *track, struct audio_track_debugbuf *buf) |
428 | { | | 428 | { |
429 | | | 429 | |
430 | memset(buf, 0, sizeof(*buf)); | | 430 | memset(buf, 0, sizeof(*buf)); |
431 | | | 431 | |
432 | snprintf(buf->outbuf, sizeof(buf->outbuf), " out=%d/%d/%d", | | 432 | snprintf(buf->outbuf, sizeof(buf->outbuf), " out=%d/%d/%d", |
433 | track->outbuf.head, track->outbuf.used, track->outbuf.capacity); | | 433 | track->outbuf.head, track->outbuf.used, track->outbuf.capacity); |
434 | if (track->freq.filter) | | 434 | if (track->freq.filter) |
435 | snprintf(buf->freq, sizeof(buf->freq), " f=%d/%d/%d", | | 435 | snprintf(buf->freq, sizeof(buf->freq), " f=%d/%d/%d", |
436 | track->freq.srcbuf.head, | | 436 | track->freq.srcbuf.head, |
437 | track->freq.srcbuf.used, | | 437 | track->freq.srcbuf.used, |
438 | track->freq.srcbuf.capacity); | | 438 | track->freq.srcbuf.capacity); |
439 | if (track->chmix.filter) | | 439 | if (track->chmix.filter) |
440 | snprintf(buf->chmix, sizeof(buf->chmix), " m=%d", | | 440 | snprintf(buf->chmix, sizeof(buf->chmix), " m=%d", |
441 | track->chmix.srcbuf.used); | | 441 | track->chmix.srcbuf.used); |
442 | if (track->chvol.filter) | | 442 | if (track->chvol.filter) |
443 | snprintf(buf->chvol, sizeof(buf->chvol), " v=%d", | | 443 | snprintf(buf->chvol, sizeof(buf->chvol), " v=%d", |
444 | track->chvol.srcbuf.used); | | 444 | track->chvol.srcbuf.used); |
445 | if (track->codec.filter) | | 445 | if (track->codec.filter) |
446 | snprintf(buf->codec, sizeof(buf->codec), " e=%d", | | 446 | snprintf(buf->codec, sizeof(buf->codec), " e=%d", |
447 | track->codec.srcbuf.used); | | 447 | track->codec.srcbuf.used); |
448 | snprintf(buf->usrbuf, sizeof(buf->usrbuf), " usr=%d/%d/H%d", | | 448 | snprintf(buf->usrbuf, sizeof(buf->usrbuf), " usr=%d/%d/H%d", |
449 | track->usrbuf.head, track->usrbuf.used, track->usrbuf_usedhigh); | | 449 | track->usrbuf.head, track->usrbuf.used, track->usrbuf_usedhigh); |
450 | } | | 450 | } |
451 | #else | | 451 | #else |
452 | #define DPRINTF(n, fmt...) do { } while (0) | | 452 | #define DPRINTF(n, fmt...) do { } while (0) |
453 | #define TRACE(n, fmt, ...) do { } while (0) | | 453 | #define TRACE(n, fmt, ...) do { } while (0) |
454 | #define TRACET(n, t, fmt, ...) do { } while (0) | | 454 | #define TRACET(n, t, fmt, ...) do { } while (0) |
455 | #define TRACEF(n, f, fmt, ...) do { } while (0) | | 455 | #define TRACEF(n, f, fmt, ...) do { } while (0) |
456 | #endif | | 456 | #endif |
457 | | | 457 | |
458 | #define SPECIFIED(x) ((x) != ~0) | | 458 | #define SPECIFIED(x) ((x) != ~0) |
459 | #define SPECIFIED_CH(x) ((x) != (u_char)~0) | | 459 | #define SPECIFIED_CH(x) ((x) != (u_char)~0) |
460 | | | 460 | |
461 | /* Device timeout in msec */ | | 461 | /* Device timeout in msec */ |
462 | #define AUDIO_TIMEOUT (3000) | | 462 | #define AUDIO_TIMEOUT (3000) |
463 | | | 463 | |
464 | /* #define AUDIO_PM_IDLE */ | | 464 | /* #define AUDIO_PM_IDLE */ |
465 | #ifdef AUDIO_PM_IDLE | | 465 | #ifdef AUDIO_PM_IDLE |
466 | int audio_idle_timeout = 30; | | 466 | int audio_idle_timeout = 30; |
467 | #endif | | 467 | #endif |
468 | | | 468 | |
469 | struct portname { | | 469 | struct portname { |
470 | const char *name; | | 470 | const char *name; |
471 | int mask; | | 471 | int mask; |
472 | }; | | 472 | }; |
473 | | | 473 | |
474 | static int audiomatch(device_t, cfdata_t, void *); | | 474 | static int audiomatch(device_t, cfdata_t, void *); |
475 | static void audioattach(device_t, device_t, void *); | | 475 | static void audioattach(device_t, device_t, void *); |
476 | static int audiodetach(device_t, int); | | 476 | static int audiodetach(device_t, int); |
477 | static int audioactivate(device_t, enum devact); | | 477 | static int audioactivate(device_t, enum devact); |
478 | static void audiochilddet(device_t, device_t); | | 478 | static void audiochilddet(device_t, device_t); |
479 | static int audiorescan(device_t, const char *, const int *); | | 479 | static int audiorescan(device_t, const char *, const int *); |
480 | | | 480 | |
481 | static int audio_modcmd(modcmd_t, void *); | | 481 | static int audio_modcmd(modcmd_t, void *); |
482 | | | 482 | |
483 | #ifdef AUDIO_PM_IDLE | | 483 | #ifdef AUDIO_PM_IDLE |
484 | static void audio_idle(void *); | | 484 | static void audio_idle(void *); |
485 | static void audio_activity(device_t, devactive_t); | | 485 | static void audio_activity(device_t, devactive_t); |
486 | #endif | | 486 | #endif |
487 | | | 487 | |
488 | static bool audio_suspend(device_t dv, const pmf_qual_t *); | | 488 | static bool audio_suspend(device_t dv, const pmf_qual_t *); |
489 | static bool audio_resume(device_t dv, const pmf_qual_t *); | | 489 | static bool audio_resume(device_t dv, const pmf_qual_t *); |
490 | static void audio_volume_down(device_t); | | 490 | static void audio_volume_down(device_t); |
491 | static void audio_volume_up(device_t); | | 491 | static void audio_volume_up(device_t); |
492 | static void audio_volume_toggle(device_t); | | 492 | static void audio_volume_toggle(device_t); |
493 | | | 493 | |
494 | static void audio_mixer_capture(struct audio_softc *); | | 494 | static void audio_mixer_capture(struct audio_softc *); |
495 | static void audio_mixer_restore(struct audio_softc *); | | 495 | static void audio_mixer_restore(struct audio_softc *); |
496 | | | 496 | |
497 | static void audio_softintr_rd(void *); | | 497 | static void audio_softintr_rd(void *); |
498 | static void audio_softintr_wr(void *); | | 498 | static void audio_softintr_wr(void *); |
499 | | | 499 | |
500 | static int audio_enter_exclusive(struct audio_softc *); | | 500 | static int audio_enter_exclusive(struct audio_softc *); |
501 | static void audio_exit_exclusive(struct audio_softc *); | | 501 | static void audio_exit_exclusive(struct audio_softc *); |
502 | static int audio_track_waitio(struct audio_softc *, audio_track_t *); | | 502 | static int audio_track_waitio(struct audio_softc *, audio_track_t *); |
503 | | | 503 | |
504 | static int audioclose(struct file *); | | 504 | static int audioclose(struct file *); |
505 | static int audioread(struct file *, off_t *, struct uio *, kauth_cred_t, int); | | 505 | static int audioread(struct file *, off_t *, struct uio *, kauth_cred_t, int); |
506 | static int audiowrite(struct file *, off_t *, struct uio *, kauth_cred_t, int); | | 506 | static int audiowrite(struct file *, off_t *, struct uio *, kauth_cred_t, int); |
507 | static int audioioctl(struct file *, u_long, void *); | | 507 | static int audioioctl(struct file *, u_long, void *); |
508 | static int audiopoll(struct file *, int); | | 508 | static int audiopoll(struct file *, int); |
509 | static int audiokqfilter(struct file *, struct knote *); | | 509 | static int audiokqfilter(struct file *, struct knote *); |
510 | static int audiommap(struct file *, off_t *, size_t, int, int *, int *, | | 510 | static int audiommap(struct file *, off_t *, size_t, int, int *, int *, |
511 | struct uvm_object **, int *); | | 511 | struct uvm_object **, int *); |
512 | static int audiostat(struct file *, struct stat *); | | 512 | static int audiostat(struct file *, struct stat *); |
513 | | | 513 | |
514 | static void filt_audiowrite_detach(struct knote *); | | 514 | static void filt_audiowrite_detach(struct knote *); |
515 | static int filt_audiowrite_event(struct knote *, long); | | 515 | static int filt_audiowrite_event(struct knote *, long); |
516 | static void filt_audioread_detach(struct knote *); | | 516 | static void filt_audioread_detach(struct knote *); |
517 | static int filt_audioread_event(struct knote *, long); | | 517 | static int filt_audioread_event(struct knote *, long); |
518 | | | 518 | |
519 | static int audio_open(dev_t, struct audio_softc *, int, int, struct lwp *, | | 519 | static int audio_open(dev_t, struct audio_softc *, int, int, struct lwp *, |
520 | audio_file_t **); | | 520 | audio_file_t **); |
521 | static int audio_close(struct audio_softc *, audio_file_t *); | | 521 | static int audio_close(struct audio_softc *, audio_file_t *); |
522 | static int audio_read(struct audio_softc *, struct uio *, int, audio_file_t *); | | 522 | static int audio_read(struct audio_softc *, struct uio *, int, audio_file_t *); |
523 | static int audio_write(struct audio_softc *, struct uio *, int, audio_file_t *); | | 523 | static int audio_write(struct audio_softc *, struct uio *, int, audio_file_t *); |
524 | static void audio_file_clear(struct audio_softc *, audio_file_t *); | | 524 | static void audio_file_clear(struct audio_softc *, audio_file_t *); |
525 | static int audio_ioctl(dev_t, struct audio_softc *, u_long, void *, int, | | 525 | static int audio_ioctl(dev_t, struct audio_softc *, u_long, void *, int, |
526 | struct lwp *, audio_file_t *); | | 526 | struct lwp *, audio_file_t *); |
527 | static int audio_poll(struct audio_softc *, int, struct lwp *, audio_file_t *); | | 527 | static int audio_poll(struct audio_softc *, int, struct lwp *, audio_file_t *); |
528 | static int audio_kqfilter(struct audio_softc *, audio_file_t *, struct knote *); | | 528 | static int audio_kqfilter(struct audio_softc *, audio_file_t *, struct knote *); |
529 | static int audio_mmap(struct audio_softc *, off_t *, size_t, int, int *, int *, | | 529 | static int audio_mmap(struct audio_softc *, off_t *, size_t, int, int *, int *, |
530 | struct uvm_object **, int *, audio_file_t *); | | 530 | struct uvm_object **, int *, audio_file_t *); |
531 | | | 531 | |
532 | static int audioctl_open(dev_t, struct audio_softc *, int, int, struct lwp *); | | 532 | static int audioctl_open(dev_t, struct audio_softc *, int, int, struct lwp *); |
533 | | | 533 | |
534 | static void audio_pintr(void *); | | 534 | static void audio_pintr(void *); |
535 | static void audio_rintr(void *); | | 535 | static void audio_rintr(void *); |
536 | | | 536 | |
537 | static int audio_query_devinfo(struct audio_softc *, mixer_devinfo_t *); | | 537 | static int audio_query_devinfo(struct audio_softc *, mixer_devinfo_t *); |
538 | | | 538 | |
539 | static __inline int audio_track_readablebytes(const audio_track_t *); | | 539 | static __inline int audio_track_readablebytes(const audio_track_t *); |
540 | static int audio_file_setinfo(struct audio_softc *, audio_file_t *, | | 540 | static int audio_file_setinfo(struct audio_softc *, audio_file_t *, |
541 | const struct audio_info *); | | 541 | const struct audio_info *); |
542 | static int audio_track_setinfo_check(audio_format2_t *, | | 542 | static int audio_track_setinfo_check(audio_format2_t *, |
543 | const struct audio_prinfo *); | | 543 | const struct audio_prinfo *); |
544 | static void audio_track_setinfo_water(audio_track_t *, | | 544 | static void audio_track_setinfo_water(audio_track_t *, |
545 | const struct audio_info *); | | 545 | const struct audio_info *); |
546 | static int audio_hw_setinfo(struct audio_softc *, const struct audio_info *, | | 546 | static int audio_hw_setinfo(struct audio_softc *, const struct audio_info *, |
547 | struct audio_info *); | | 547 | struct audio_info *); |
548 | static int audio_hw_set_format(struct audio_softc *, int, | | 548 | static int audio_hw_set_format(struct audio_softc *, int, |
549 | audio_format2_t *, audio_format2_t *, | | 549 | audio_format2_t *, audio_format2_t *, |
550 | audio_filter_reg_t *, audio_filter_reg_t *); | | 550 | audio_filter_reg_t *, audio_filter_reg_t *); |
551 | static int audiogetinfo(struct audio_softc *, struct audio_info *, int, | | 551 | static int audiogetinfo(struct audio_softc *, struct audio_info *, int, |
552 | audio_file_t *); | | 552 | audio_file_t *); |
553 | static bool audio_can_playback(struct audio_softc *); | | 553 | static bool audio_can_playback(struct audio_softc *); |
554 | static bool audio_can_capture(struct audio_softc *); | | 554 | static bool audio_can_capture(struct audio_softc *); |
555 | static int audio_check_params(audio_format2_t *); | | 555 | static int audio_check_params(audio_format2_t *); |
556 | static int audio_mixers_init(struct audio_softc *sc, int, | | 556 | static int audio_mixers_init(struct audio_softc *sc, int, |
557 | const audio_format2_t *, const audio_format2_t *, | | 557 | const audio_format2_t *, const audio_format2_t *, |
558 | const audio_filter_reg_t *, const audio_filter_reg_t *); | | 558 | const audio_filter_reg_t *, const audio_filter_reg_t *); |
559 | static int audio_select_freq(const struct audio_format *); | | 559 | static int audio_select_freq(const struct audio_format *); |
560 | static int audio_hw_probe(struct audio_softc *, int, int *, | | 560 | static int audio_hw_probe(struct audio_softc *, int, int *, |
561 | audio_format2_t *, audio_format2_t *); | | 561 | audio_format2_t *, audio_format2_t *); |
562 | static int audio_hw_probe_fmt(struct audio_softc *, audio_format2_t *, int); | | 562 | static int audio_hw_probe_fmt(struct audio_softc *, audio_format2_t *, int); |
563 | static int audio_hw_validate_format(struct audio_softc *, int, | | 563 | static int audio_hw_validate_format(struct audio_softc *, int, |
564 | const audio_format2_t *); | | 564 | const audio_format2_t *); |
565 | static int audio_mixers_set_format(struct audio_softc *, | | 565 | static int audio_mixers_set_format(struct audio_softc *, |
566 | const struct audio_info *); | | 566 | const struct audio_info *); |
567 | static void audio_mixers_get_format(struct audio_softc *, struct audio_info *); | | 567 | static void audio_mixers_get_format(struct audio_softc *, struct audio_info *); |
568 | static int audio_sysctl_blk_ms(SYSCTLFN_PROTO); | | 568 | static int audio_sysctl_blk_ms(SYSCTLFN_PROTO); |
569 | static int audio_sysctl_multiuser(SYSCTLFN_PROTO); | | 569 | static int audio_sysctl_multiuser(SYSCTLFN_PROTO); |
570 | #if defined(AUDIO_DEBUG) | | 570 | #if defined(AUDIO_DEBUG) |
571 | static int audio_sysctl_debug(SYSCTLFN_PROTO); | | 571 | static int audio_sysctl_debug(SYSCTLFN_PROTO); |
572 | static void audio_format2_tostr(char *, size_t, const audio_format2_t *); | | 572 | static void audio_format2_tostr(char *, size_t, const audio_format2_t *); |
573 | static void audio_print_format2(const char *, const audio_format2_t *) __unused; | | 573 | static void audio_print_format2(const char *, const audio_format2_t *) __unused; |
574 | #endif | | 574 | #endif |
575 | | | 575 | |
576 | static void *audio_realloc(void *, size_t); | | 576 | static void *audio_realloc(void *, size_t); |
577 | static int audio_realloc_usrbuf(audio_track_t *, int); | | 577 | static int audio_realloc_usrbuf(audio_track_t *, int); |
578 | static void audio_free_usrbuf(audio_track_t *); | | 578 | static void audio_free_usrbuf(audio_track_t *); |
579 | | | 579 | |
580 | static audio_track_t *audio_track_create(struct audio_softc *, | | 580 | static audio_track_t *audio_track_create(struct audio_softc *, |
581 | audio_trackmixer_t *); | | 581 | audio_trackmixer_t *); |
582 | static void audio_track_destroy(audio_track_t *); | | 582 | static void audio_track_destroy(audio_track_t *); |
583 | static audio_filter_t audio_track_get_codec(audio_track_t *, | | 583 | static audio_filter_t audio_track_get_codec(audio_track_t *, |
584 | const audio_format2_t *, const audio_format2_t *); | | 584 | const audio_format2_t *, const audio_format2_t *); |
585 | static int audio_track_set_format(audio_track_t *, audio_format2_t *); | | 585 | static int audio_track_set_format(audio_track_t *, audio_format2_t *); |
586 | static void audio_track_play(audio_track_t *); | | 586 | static void audio_track_play(audio_track_t *); |
587 | static int audio_track_drain(struct audio_softc *, audio_track_t *); | | 587 | static int audio_track_drain(struct audio_softc *, audio_track_t *); |
588 | static void audio_track_record(audio_track_t *); | | 588 | static void audio_track_record(audio_track_t *); |
589 | static void audio_track_clear(struct audio_softc *, audio_track_t *); | | 589 | static void audio_track_clear(struct audio_softc *, audio_track_t *); |
590 | | | 590 | |
591 | static int audio_mixer_init(struct audio_softc *, int, | | 591 | static int audio_mixer_init(struct audio_softc *, int, |
592 | const audio_format2_t *, const audio_filter_reg_t *); | | 592 | const audio_format2_t *, const audio_filter_reg_t *); |
593 | static void audio_mixer_destroy(struct audio_softc *, audio_trackmixer_t *); | | 593 | static void audio_mixer_destroy(struct audio_softc *, audio_trackmixer_t *); |
594 | static void audio_pmixer_start(struct audio_softc *, bool); | | 594 | static void audio_pmixer_start(struct audio_softc *, bool); |
595 | static void audio_pmixer_process(struct audio_softc *); | | 595 | static void audio_pmixer_process(struct audio_softc *); |
596 | static void audio_pmixer_agc(audio_trackmixer_t *, int); | | 596 | static void audio_pmixer_agc(audio_trackmixer_t *, int); |
597 | static int audio_pmixer_mix_track(audio_trackmixer_t *, audio_track_t *, int); | | 597 | static int audio_pmixer_mix_track(audio_trackmixer_t *, audio_track_t *, int); |
598 | static void audio_pmixer_output(struct audio_softc *); | | 598 | static void audio_pmixer_output(struct audio_softc *); |
599 | static int audio_pmixer_halt(struct audio_softc *); | | 599 | static int audio_pmixer_halt(struct audio_softc *); |
600 | static void audio_rmixer_start(struct audio_softc *); | | 600 | static void audio_rmixer_start(struct audio_softc *); |
601 | static void audio_rmixer_process(struct audio_softc *); | | 601 | static void audio_rmixer_process(struct audio_softc *); |
602 | static void audio_rmixer_input(struct audio_softc *); | | 602 | static void audio_rmixer_input(struct audio_softc *); |
603 | static int audio_rmixer_halt(struct audio_softc *); | | 603 | static int audio_rmixer_halt(struct audio_softc *); |
604 | | | 604 | |
605 | static void mixer_init(struct audio_softc *); | | 605 | static void mixer_init(struct audio_softc *); |
606 | static int mixer_open(dev_t, struct audio_softc *, int, int, struct lwp *); | | 606 | static int mixer_open(dev_t, struct audio_softc *, int, int, struct lwp *); |
607 | static int mixer_close(struct audio_softc *, audio_file_t *); | | 607 | static int mixer_close(struct audio_softc *, audio_file_t *); |
608 | static int mixer_ioctl(struct audio_softc *, u_long, void *, int, struct lwp *); | | 608 | static int mixer_ioctl(struct audio_softc *, u_long, void *, int, struct lwp *); |
609 | static void mixer_remove(struct audio_softc *); | | 609 | static void mixer_remove(struct audio_softc *); |
610 | static void mixer_signal(struct audio_softc *); | | 610 | static void mixer_signal(struct audio_softc *); |
611 | | | 611 | |
612 | static int au_portof(struct audio_softc *, char *, int); | | 612 | static int au_portof(struct audio_softc *, char *, int); |
613 | | | 613 | |
614 | static void au_setup_ports(struct audio_softc *, struct au_mixer_ports *, | | 614 | static void au_setup_ports(struct audio_softc *, struct au_mixer_ports *, |
615 | mixer_devinfo_t *, const struct portname *); | | 615 | mixer_devinfo_t *, const struct portname *); |
616 | static int au_set_lr_value(struct audio_softc *, mixer_ctrl_t *, int, int); | | 616 | static int au_set_lr_value(struct audio_softc *, mixer_ctrl_t *, int, int); |
617 | static int au_get_lr_value(struct audio_softc *, mixer_ctrl_t *, int *, int *); | | 617 | static int au_get_lr_value(struct audio_softc *, mixer_ctrl_t *, int *, int *); |
618 | static int au_set_gain(struct audio_softc *, struct au_mixer_ports *, int, int); | | 618 | static int au_set_gain(struct audio_softc *, struct au_mixer_ports *, int, int); |
619 | static void au_get_gain(struct audio_softc *, struct au_mixer_ports *, | | 619 | static void au_get_gain(struct audio_softc *, struct au_mixer_ports *, |
620 | u_int *, u_char *); | | 620 | u_int *, u_char *); |
621 | static int au_set_port(struct audio_softc *, struct au_mixer_ports *, u_int); | | 621 | static int au_set_port(struct audio_softc *, struct au_mixer_ports *, u_int); |
622 | static int au_get_port(struct audio_softc *, struct au_mixer_ports *); | | 622 | static int au_get_port(struct audio_softc *, struct au_mixer_ports *); |
623 | static int au_set_monitor_gain(struct audio_softc *, int); | | 623 | static int au_set_monitor_gain(struct audio_softc *, int); |
624 | static int au_get_monitor_gain(struct audio_softc *); | | 624 | static int au_get_monitor_gain(struct audio_softc *); |
625 | static int audio_get_port(struct audio_softc *, mixer_ctrl_t *); | | 625 | static int audio_get_port(struct audio_softc *, mixer_ctrl_t *); |
626 | static int audio_set_port(struct audio_softc *, mixer_ctrl_t *); | | 626 | static int audio_set_port(struct audio_softc *, mixer_ctrl_t *); |
627 | | | 627 | |
628 | static __inline struct audio_params | | 628 | static __inline struct audio_params |
629 | format2_to_params(const audio_format2_t *f2) | | 629 | format2_to_params(const audio_format2_t *f2) |
630 | { | | 630 | { |
631 | audio_params_t p; | | 631 | audio_params_t p; |
632 | | | 632 | |
633 | /* validbits/precision <-> precision/stride */ | | 633 | /* validbits/precision <-> precision/stride */ |
634 | p.sample_rate = f2->sample_rate; | | 634 | p.sample_rate = f2->sample_rate; |
635 | p.channels = f2->channels; | | 635 | p.channels = f2->channels; |
636 | p.encoding = f2->encoding; | | 636 | p.encoding = f2->encoding; |
637 | p.validbits = f2->precision; | | 637 | p.validbits = f2->precision; |
638 | p.precision = f2->stride; | | 638 | p.precision = f2->stride; |
639 | return p; | | 639 | return p; |
640 | } | | 640 | } |
641 | | | 641 | |
642 | static __inline audio_format2_t | | 642 | static __inline audio_format2_t |
643 | params_to_format2(const struct audio_params *p) | | 643 | params_to_format2(const struct audio_params *p) |
644 | { | | 644 | { |
645 | audio_format2_t f2; | | 645 | audio_format2_t f2; |
646 | | | 646 | |
647 | /* precision/stride <-> validbits/precision */ | | 647 | /* precision/stride <-> validbits/precision */ |
648 | f2.sample_rate = p->sample_rate; | | 648 | f2.sample_rate = p->sample_rate; |
649 | f2.channels = p->channels; | | 649 | f2.channels = p->channels; |
650 | f2.encoding = p->encoding; | | 650 | f2.encoding = p->encoding; |
651 | f2.precision = p->validbits; | | 651 | f2.precision = p->validbits; |
652 | f2.stride = p->precision; | | 652 | f2.stride = p->precision; |
653 | return f2; | | 653 | return f2; |
654 | } | | 654 | } |
655 | | | 655 | |
656 | /* Return true if this track is a playback track. */ | | 656 | /* Return true if this track is a playback track. */ |
657 | static __inline bool | | 657 | static __inline bool |
658 | audio_track_is_playback(const audio_track_t *track) | | 658 | audio_track_is_playback(const audio_track_t *track) |
659 | { | | 659 | { |
660 | | | 660 | |
661 | return ((track->mode & AUMODE_PLAY) != 0); | | 661 | return ((track->mode & AUMODE_PLAY) != 0); |
662 | } | | 662 | } |
663 | | | 663 | |
664 | /* Return true if this track is a recording track. */ | | 664 | /* Return true if this track is a recording track. */ |
665 | static __inline bool | | 665 | static __inline bool |
666 | audio_track_is_record(const audio_track_t *track) | | 666 | audio_track_is_record(const audio_track_t *track) |
667 | { | | 667 | { |
668 | | | 668 | |
669 | return ((track->mode & AUMODE_RECORD) != 0); | | 669 | return ((track->mode & AUMODE_RECORD) != 0); |
670 | } | | 670 | } |
671 | | | 671 | |
672 | #if 0 /* XXX Not used yet */ | | 672 | #if 0 /* XXX Not used yet */ |
673 | /* | | 673 | /* |
674 | * Convert 0..255 volume used in userland to internal presentation 0..256. | | 674 | * Convert 0..255 volume used in userland to internal presentation 0..256. |
675 | */ | | 675 | */ |
676 | static __inline u_int | | 676 | static __inline u_int |
677 | audio_volume_to_inner(u_int v) | | 677 | audio_volume_to_inner(u_int v) |
678 | { | | 678 | { |
679 | | | 679 | |
680 | return v < 127 ? v : v + 1; | | 680 | return v < 127 ? v : v + 1; |
681 | } | | 681 | } |
682 | | | 682 | |
683 | /* | | 683 | /* |
684 | * Convert 0..256 internal presentation to 0..255 volume used in userland. | | 684 | * Convert 0..256 internal presentation to 0..255 volume used in userland. |
685 | */ | | 685 | */ |
686 | static __inline u_int | | 686 | static __inline u_int |
687 | audio_volume_to_outer(u_int v) | | 687 | audio_volume_to_outer(u_int v) |
688 | { | | 688 | { |
689 | | | 689 | |
690 | return v < 127 ? v : v - 1; | | 690 | return v < 127 ? v : v - 1; |
691 | } | | 691 | } |
692 | #endif /* 0 */ | | 692 | #endif /* 0 */ |
693 | | | 693 | |
694 | static dev_type_open(audioopen); | | 694 | static dev_type_open(audioopen); |
695 | /* XXXMRG use more dev_type_xxx */ | | 695 | /* XXXMRG use more dev_type_xxx */ |
696 | | | 696 | |
697 | const struct cdevsw audio_cdevsw = { | | 697 | const struct cdevsw audio_cdevsw = { |
698 | .d_open = audioopen, | | 698 | .d_open = audioopen, |
699 | .d_close = noclose, | | 699 | .d_close = noclose, |
700 | .d_read = noread, | | 700 | .d_read = noread, |
701 | .d_write = nowrite, | | 701 | .d_write = nowrite, |
702 | .d_ioctl = noioctl, | | 702 | .d_ioctl = noioctl, |
703 | .d_stop = nostop, | | 703 | .d_stop = nostop, |
704 | .d_tty = notty, | | 704 | .d_tty = notty, |
705 | .d_poll = nopoll, | | 705 | .d_poll = nopoll, |
706 | .d_mmap = nommap, | | 706 | .d_mmap = nommap, |
707 | .d_kqfilter = nokqfilter, | | 707 | .d_kqfilter = nokqfilter, |
708 | .d_discard = nodiscard, | | 708 | .d_discard = nodiscard, |
709 | .d_flag = D_OTHER | D_MPSAFE | | 709 | .d_flag = D_OTHER | D_MPSAFE |
710 | }; | | 710 | }; |
711 | | | 711 | |
712 | const struct fileops audio_fileops = { | | 712 | const struct fileops audio_fileops = { |
713 | .fo_name = "audio", | | 713 | .fo_name = "audio", |
714 | .fo_read = audioread, | | 714 | .fo_read = audioread, |
715 | .fo_write = audiowrite, | | 715 | .fo_write = audiowrite, |
716 | .fo_ioctl = audioioctl, | | 716 | .fo_ioctl = audioioctl, |
717 | .fo_fcntl = fnullop_fcntl, | | 717 | .fo_fcntl = fnullop_fcntl, |
718 | .fo_stat = audiostat, | | 718 | .fo_stat = audiostat, |
719 | .fo_poll = audiopoll, | | 719 | .fo_poll = audiopoll, |
720 | .fo_close = audioclose, | | 720 | .fo_close = audioclose, |
721 | .fo_mmap = audiommap, | | 721 | .fo_mmap = audiommap, |
722 | .fo_kqfilter = audiokqfilter, | | 722 | .fo_kqfilter = audiokqfilter, |
723 | .fo_restart = fnullop_restart | | 723 | .fo_restart = fnullop_restart |
724 | }; | | 724 | }; |
725 | | | 725 | |
726 | /* The default audio mode: 8 kHz mono mu-law */ | | 726 | /* The default audio mode: 8 kHz mono mu-law */ |
727 | static const struct audio_params audio_default = { | | 727 | static const struct audio_params audio_default = { |
728 | .sample_rate = 8000, | | 728 | .sample_rate = 8000, |
729 | .encoding = AUDIO_ENCODING_ULAW, | | 729 | .encoding = AUDIO_ENCODING_ULAW, |
730 | .precision = 8, | | 730 | .precision = 8, |
731 | .validbits = 8, | | 731 | .validbits = 8, |
732 | .channels = 1, | | 732 | .channels = 1, |
733 | }; | | 733 | }; |
734 | | | 734 | |
735 | static const char *encoding_names[] = { | | 735 | static const char *encoding_names[] = { |
736 | "none", | | 736 | "none", |
737 | AudioEmulaw, | | 737 | AudioEmulaw, |
738 | AudioEalaw, | | 738 | AudioEalaw, |
739 | "pcm16", | | 739 | "pcm16", |
740 | "pcm8", | | 740 | "pcm8", |
741 | AudioEadpcm, | | 741 | AudioEadpcm, |
742 | AudioEslinear_le, | | 742 | AudioEslinear_le, |
743 | AudioEslinear_be, | | 743 | AudioEslinear_be, |
744 | AudioEulinear_le, | | 744 | AudioEulinear_le, |
745 | AudioEulinear_be, | | 745 | AudioEulinear_be, |
746 | AudioEslinear, | | 746 | AudioEslinear, |
747 | AudioEulinear, | | 747 | AudioEulinear, |
748 | AudioEmpeg_l1_stream, | | 748 | AudioEmpeg_l1_stream, |
749 | AudioEmpeg_l1_packets, | | 749 | AudioEmpeg_l1_packets, |
750 | AudioEmpeg_l1_system, | | 750 | AudioEmpeg_l1_system, |
751 | AudioEmpeg_l2_stream, | | 751 | AudioEmpeg_l2_stream, |
752 | AudioEmpeg_l2_packets, | | 752 | AudioEmpeg_l2_packets, |
753 | AudioEmpeg_l2_system, | | 753 | AudioEmpeg_l2_system, |
754 | AudioEac3, | | 754 | AudioEac3, |
755 | }; | | 755 | }; |
756 | | | 756 | |
757 | /* | | 757 | /* |
758 | * Returns encoding name corresponding to AUDIO_ENCODING_*. | | 758 | * Returns encoding name corresponding to AUDIO_ENCODING_*. |
759 | * Note that it may return a local buffer because it is mainly for debugging. | | 759 | * Note that it may return a local buffer because it is mainly for debugging. |
760 | */ | | 760 | */ |
761 | const char * | | 761 | const char * |
762 | audio_encoding_name(int encoding) | | 762 | audio_encoding_name(int encoding) |
763 | { | | 763 | { |
764 | static char buf[16]; | | 764 | static char buf[16]; |
765 | | | 765 | |
766 | if (0 <= encoding && encoding < __arraycount(encoding_names)) { | | 766 | if (0 <= encoding && encoding < __arraycount(encoding_names)) { |
767 | return encoding_names[encoding]; | | 767 | return encoding_names[encoding]; |
768 | } else { | | 768 | } else { |
769 | snprintf(buf, sizeof(buf), "enc=%d", encoding); | | 769 | snprintf(buf, sizeof(buf), "enc=%d", encoding); |
770 | return buf; | | 770 | return buf; |
771 | } | | 771 | } |
772 | } | | 772 | } |
773 | | | 773 | |
774 | /* | | 774 | /* |
775 | * Supported encodings used by AUDIO_GETENC. | | 775 | * Supported encodings used by AUDIO_GETENC. |
776 | * index and flags are set by code. | | 776 | * index and flags are set by code. |
777 | * XXX is there any needs for SLINEAR_OE:>=16/ULINEAR_OE:>=16 ? | | 777 | * XXX is there any needs for SLINEAR_OE:>=16/ULINEAR_OE:>=16 ? |
778 | */ | | 778 | */ |
779 | static const audio_encoding_t audio_encodings[] = { | | 779 | static const audio_encoding_t audio_encodings[] = { |
780 | { 0, AudioEmulaw, AUDIO_ENCODING_ULAW, 8, 0 }, | | 780 | { 0, AudioEmulaw, AUDIO_ENCODING_ULAW, 8, 0 }, |
781 | { 0, AudioEalaw, AUDIO_ENCODING_ALAW, 8, 0 }, | | 781 | { 0, AudioEalaw, AUDIO_ENCODING_ALAW, 8, 0 }, |
782 | { 0, AudioEslinear, AUDIO_ENCODING_SLINEAR, 8, 0 }, | | 782 | { 0, AudioEslinear, AUDIO_ENCODING_SLINEAR, 8, 0 }, |
783 | { 0, AudioEulinear, AUDIO_ENCODING_ULINEAR, 8, 0 }, | | 783 | { 0, AudioEulinear, AUDIO_ENCODING_ULINEAR, 8, 0 }, |
784 | { 0, AudioEslinear_le, AUDIO_ENCODING_SLINEAR_LE, 16, 0 }, | | 784 | { 0, AudioEslinear_le, AUDIO_ENCODING_SLINEAR_LE, 16, 0 }, |
785 | { 0, AudioEulinear_le, AUDIO_ENCODING_ULINEAR_LE, 16, 0 }, | | 785 | { 0, AudioEulinear_le, AUDIO_ENCODING_ULINEAR_LE, 16, 0 }, |
786 | { 0, AudioEslinear_be, AUDIO_ENCODING_SLINEAR_BE, 16, 0 }, | | 786 | { 0, AudioEslinear_be, AUDIO_ENCODING_SLINEAR_BE, 16, 0 }, |
787 | { 0, AudioEulinear_be, AUDIO_ENCODING_ULINEAR_BE, 16, 0 }, | | 787 | { 0, AudioEulinear_be, AUDIO_ENCODING_ULINEAR_BE, 16, 0 }, |
788 | #if defined(AUDIO_SUPPORT_LINEAR24) | | 788 | #if defined(AUDIO_SUPPORT_LINEAR24) |
789 | { 0, AudioEslinear_le, AUDIO_ENCODING_SLINEAR_LE, 24, 0 }, | | 789 | { 0, AudioEslinear_le, AUDIO_ENCODING_SLINEAR_LE, 24, 0 }, |
790 | { 0, AudioEulinear_le, AUDIO_ENCODING_ULINEAR_LE, 24, 0 }, | | 790 | { 0, AudioEulinear_le, AUDIO_ENCODING_ULINEAR_LE, 24, 0 }, |
791 | { 0, AudioEslinear_be, AUDIO_ENCODING_SLINEAR_BE, 24, 0 }, | | 791 | { 0, AudioEslinear_be, AUDIO_ENCODING_SLINEAR_BE, 24, 0 }, |
792 | { 0, AudioEulinear_be, AUDIO_ENCODING_ULINEAR_BE, 24, 0 }, | | 792 | { 0, AudioEulinear_be, AUDIO_ENCODING_ULINEAR_BE, 24, 0 }, |
793 | #endif | | 793 | #endif |
794 | { 0, AudioEslinear_le, AUDIO_ENCODING_SLINEAR_LE, 32, 0 }, | | 794 | { 0, AudioEslinear_le, AUDIO_ENCODING_SLINEAR_LE, 32, 0 }, |
795 | { 0, AudioEulinear_le, AUDIO_ENCODING_ULINEAR_LE, 32, 0 }, | | 795 | { 0, AudioEulinear_le, AUDIO_ENCODING_ULINEAR_LE, 32, 0 }, |
796 | { 0, AudioEslinear_be, AUDIO_ENCODING_SLINEAR_BE, 32, 0 }, | | 796 | { 0, AudioEslinear_be, AUDIO_ENCODING_SLINEAR_BE, 32, 0 }, |
797 | { 0, AudioEulinear_be, AUDIO_ENCODING_ULINEAR_BE, 32, 0 }, | | 797 | { 0, AudioEulinear_be, AUDIO_ENCODING_ULINEAR_BE, 32, 0 }, |
798 | }; | | 798 | }; |
799 | | | 799 | |
800 | static const struct portname itable[] = { | | 800 | static const struct portname itable[] = { |
801 | { AudioNmicrophone, AUDIO_MICROPHONE }, | | 801 | { AudioNmicrophone, AUDIO_MICROPHONE }, |
802 | { AudioNline, AUDIO_LINE_IN }, | | 802 | { AudioNline, AUDIO_LINE_IN }, |
803 | { AudioNcd, AUDIO_CD }, | | 803 | { AudioNcd, AUDIO_CD }, |
804 | { 0, 0 } | | 804 | { 0, 0 } |
805 | }; | | 805 | }; |
806 | static const struct portname otable[] = { | | 806 | static const struct portname otable[] = { |
807 | { AudioNspeaker, AUDIO_SPEAKER }, | | 807 | { AudioNspeaker, AUDIO_SPEAKER }, |
808 | { AudioNheadphone, AUDIO_HEADPHONE }, | | 808 | { AudioNheadphone, AUDIO_HEADPHONE }, |
809 | { AudioNline, AUDIO_LINE_OUT }, | | 809 | { AudioNline, AUDIO_LINE_OUT }, |
810 | { 0, 0 } | | 810 | { 0, 0 } |
811 | }; | | 811 | }; |
812 | | | 812 | |
813 | CFATTACH_DECL3_NEW(audio, sizeof(struct audio_softc), | | 813 | CFATTACH_DECL3_NEW(audio, sizeof(struct audio_softc), |
814 | audiomatch, audioattach, audiodetach, audioactivate, audiorescan, | | 814 | audiomatch, audioattach, audiodetach, audioactivate, audiorescan, |
815 | audiochilddet, DVF_DETACH_SHUTDOWN); | | 815 | audiochilddet, DVF_DETACH_SHUTDOWN); |
816 | | | 816 | |
817 | static int | | 817 | static int |
818 | audiomatch(device_t parent, cfdata_t match, void *aux) | | 818 | audiomatch(device_t parent, cfdata_t match, void *aux) |
819 | { | | 819 | { |
820 | struct audio_attach_args *sa; | | 820 | struct audio_attach_args *sa; |
821 | | | 821 | |
822 | sa = aux; | | 822 | sa = aux; |
823 | DPRINTF(1, "%s: type=%d sa=%p hw=%p\n", | | 823 | DPRINTF(1, "%s: type=%d sa=%p hw=%p\n", |
824 | __func__, sa->type, sa, sa->hwif); | | 824 | __func__, sa->type, sa, sa->hwif); |
825 | return (sa->type == AUDIODEV_TYPE_AUDIO) ? 1 : 0; | | 825 | return (sa->type == AUDIODEV_TYPE_AUDIO) ? 1 : 0; |
826 | } | | 826 | } |
827 | | | 827 | |
828 | static void | | 828 | static void |
829 | audioattach(device_t parent, device_t self, void *aux) | | 829 | audioattach(device_t parent, device_t self, void *aux) |
830 | { | | 830 | { |
831 | struct audio_softc *sc; | | 831 | struct audio_softc *sc; |
832 | struct audio_attach_args *sa; | | 832 | struct audio_attach_args *sa; |
833 | const struct audio_hw_if *hw_if; | | 833 | const struct audio_hw_if *hw_if; |
834 | audio_format2_t phwfmt; | | 834 | audio_format2_t phwfmt; |
835 | audio_format2_t rhwfmt; | | 835 | audio_format2_t rhwfmt; |
836 | audio_filter_reg_t pfil; | | 836 | audio_filter_reg_t pfil; |
837 | audio_filter_reg_t rfil; | | 837 | audio_filter_reg_t rfil; |
838 | const struct sysctlnode *node; | | 838 | const struct sysctlnode *node; |
839 | void *hdlp; | | 839 | void *hdlp; |
840 | bool has_playback; | | 840 | bool has_playback; |
841 | bool has_capture; | | 841 | bool has_capture; |
842 | bool has_indep; | | 842 | bool has_indep; |
843 | bool has_fulldup; | | 843 | bool has_fulldup; |
844 | int mode; | | 844 | int mode; |
845 | int error; | | 845 | int error; |
846 | | | 846 | |
847 | sc = device_private(self); | | 847 | sc = device_private(self); |
848 | sc->sc_dev = self; | | 848 | sc->sc_dev = self; |
849 | sa = (struct audio_attach_args *)aux; | | 849 | sa = (struct audio_attach_args *)aux; |
850 | hw_if = sa->hwif; | | 850 | hw_if = sa->hwif; |
851 | hdlp = sa->hdl; | | 851 | hdlp = sa->hdl; |
852 | | | 852 | |
853 | if (hw_if == NULL || hw_if->get_locks == NULL) { | | 853 | if (hw_if == NULL || hw_if->get_locks == NULL) { |
854 | panic("audioattach: missing hw_if method"); | | 854 | panic("audioattach: missing hw_if method"); |
855 | } | | 855 | } |
856 | | | 856 | |
857 | hw_if->get_locks(hdlp, &sc->sc_intr_lock, &sc->sc_lock); | | 857 | hw_if->get_locks(hdlp, &sc->sc_intr_lock, &sc->sc_lock); |
858 | | | 858 | |
859 | #ifdef DIAGNOSTIC | | 859 | #ifdef DIAGNOSTIC |
860 | if (hw_if->query_format == NULL || | | 860 | if (hw_if->query_format == NULL || |
861 | hw_if->set_format == NULL || | | 861 | hw_if->set_format == NULL || |
862 | (hw_if->start_output == NULL && hw_if->trigger_output == NULL) || | | 862 | (hw_if->start_output == NULL && hw_if->trigger_output == NULL) || |
863 | (hw_if->start_input == NULL && hw_if->trigger_input == NULL) || | | 863 | (hw_if->start_input == NULL && hw_if->trigger_input == NULL) || |
864 | hw_if->halt_output == NULL || | | 864 | hw_if->halt_output == NULL || |
865 | hw_if->halt_input == NULL || | | 865 | hw_if->halt_input == NULL || |
866 | hw_if->getdev == NULL || | | 866 | hw_if->getdev == NULL || |
867 | hw_if->set_port == NULL || | | 867 | hw_if->set_port == NULL || |
868 | hw_if->get_port == NULL || | | 868 | hw_if->get_port == NULL || |
869 | hw_if->query_devinfo == NULL || | | 869 | hw_if->query_devinfo == NULL || |
870 | hw_if->get_props == NULL) { | | 870 | hw_if->get_props == NULL) { |
871 | aprint_error(": missing method\n"); | | 871 | aprint_error(": missing method\n"); |
872 | return; | | 872 | return; |
873 | } | | 873 | } |
874 | #endif | | 874 | #endif |
875 | | | 875 | |
876 | sc->hw_if = hw_if; | | 876 | sc->hw_if = hw_if; |
877 | sc->hw_hdl = hdlp; | | 877 | sc->hw_hdl = hdlp; |
878 | sc->hw_dev = parent; | | 878 | sc->hw_dev = parent; |
879 | | | 879 | |
880 | sc->sc_blk_ms = AUDIO_BLK_MS; | | 880 | sc->sc_blk_ms = AUDIO_BLK_MS; |
881 | SLIST_INIT(&sc->sc_files); | | 881 | SLIST_INIT(&sc->sc_files); |
882 | cv_init(&sc->sc_exlockcv, "audiolk"); | | 882 | cv_init(&sc->sc_exlockcv, "audiolk"); |
883 | | | 883 | |
884 | mutex_enter(sc->sc_lock); | | 884 | mutex_enter(sc->sc_lock); |
885 | sc->sc_props = hw_if->get_props(sc->hw_hdl); | | 885 | sc->sc_props = hw_if->get_props(sc->hw_hdl); |
886 | mutex_exit(sc->sc_lock); | | 886 | mutex_exit(sc->sc_lock); |
887 | | | 887 | |
888 | /* MMAP is now supported by upper layer. */ | | 888 | /* MMAP is now supported by upper layer. */ |
889 | sc->sc_props |= AUDIO_PROP_MMAP; | | 889 | sc->sc_props |= AUDIO_PROP_MMAP; |
890 | | | 890 | |
891 | has_playback = (sc->sc_props & AUDIO_PROP_PLAYBACK); | | 891 | has_playback = (sc->sc_props & AUDIO_PROP_PLAYBACK); |
892 | has_capture = (sc->sc_props & AUDIO_PROP_CAPTURE); | | 892 | has_capture = (sc->sc_props & AUDIO_PROP_CAPTURE); |
893 | has_indep = (sc->sc_props & AUDIO_PROP_INDEPENDENT); | | 893 | has_indep = (sc->sc_props & AUDIO_PROP_INDEPENDENT); |
894 | has_fulldup = (sc->sc_props & AUDIO_PROP_FULLDUPLEX); | | 894 | has_fulldup = (sc->sc_props & AUDIO_PROP_FULLDUPLEX); |
895 | | | 895 | |
896 | KASSERT(has_playback || has_capture); | | 896 | KASSERT(has_playback || has_capture); |
897 | /* Unidirectional device must have neither FULLDUP nor INDEPENDENT. */ | | 897 | /* Unidirectional device must have neither FULLDUP nor INDEPENDENT. */ |
898 | if (!has_playback || !has_capture) { | | 898 | if (!has_playback || !has_capture) { |
899 | KASSERT(!has_indep); | | 899 | KASSERT(!has_indep); |
900 | KASSERT(!has_fulldup); | | 900 | KASSERT(!has_fulldup); |
901 | } | | 901 | } |
902 | | | 902 | |
903 | mode = 0; | | 903 | mode = 0; |
904 | if (has_playback) { | | 904 | if (has_playback) { |
905 | aprint_normal(": playback"); | | 905 | aprint_normal(": playback"); |
906 | mode |= AUMODE_PLAY; | | 906 | mode |= AUMODE_PLAY; |
907 | } | | 907 | } |
908 | if (has_capture) { | | 908 | if (has_capture) { |
909 | aprint_normal("%c capture", has_playback ? ',' : ':'); | | 909 | aprint_normal("%c capture", has_playback ? ',' : ':'); |
910 | mode |= AUMODE_RECORD; | | 910 | mode |= AUMODE_RECORD; |
911 | } | | 911 | } |
912 | if (has_playback && has_capture) { | | 912 | if (has_playback && has_capture) { |
913 | if (has_fulldup) | | 913 | if (has_fulldup) |
914 | aprint_normal(", full duplex"); | | 914 | aprint_normal(", full duplex"); |
915 | else | | 915 | else |
916 | aprint_normal(", half duplex"); | | 916 | aprint_normal(", half duplex"); |
917 | | | 917 | |
918 | if (has_indep) | | 918 | if (has_indep) |
919 | aprint_normal(", independent"); | | 919 | aprint_normal(", independent"); |
920 | } | | 920 | } |
921 | | | 921 | |
922 | aprint_naive("\n"); | | 922 | aprint_naive("\n"); |
923 | aprint_normal("\n"); | | 923 | aprint_normal("\n"); |
924 | | | 924 | |
925 | /* probe hw params */ | | 925 | /* probe hw params */ |
926 | memset(&phwfmt, 0, sizeof(phwfmt)); | | 926 | memset(&phwfmt, 0, sizeof(phwfmt)); |
927 | memset(&rhwfmt, 0, sizeof(rhwfmt)); | | 927 | memset(&rhwfmt, 0, sizeof(rhwfmt)); |
928 | memset(&pfil, 0, sizeof(pfil)); | | 928 | memset(&pfil, 0, sizeof(pfil)); |
929 | memset(&rfil, 0, sizeof(rfil)); | | 929 | memset(&rfil, 0, sizeof(rfil)); |
930 | mutex_enter(sc->sc_lock); | | 930 | mutex_enter(sc->sc_lock); |
931 | error = audio_hw_probe(sc, has_indep, &mode, &phwfmt, &rhwfmt); | | 931 | error = audio_hw_probe(sc, has_indep, &mode, &phwfmt, &rhwfmt); |
932 | if (error) { | | 932 | if (error) { |
933 | mutex_exit(sc->sc_lock); | | 933 | mutex_exit(sc->sc_lock); |
934 | aprint_error_dev(self, "audio_hw_probe failed, " | | 934 | aprint_error_dev(self, "audio_hw_probe failed, " |
935 | "error = %d\n", error); | | 935 | "error = %d\n", error); |
936 | goto bad; | | 936 | goto bad; |
937 | } | | 937 | } |
938 | if (mode == 0) { | | 938 | if (mode == 0) { |
939 | mutex_exit(sc->sc_lock); | | 939 | mutex_exit(sc->sc_lock); |
940 | aprint_error_dev(self, "audio_hw_probe failed, no mode\n"); | | 940 | aprint_error_dev(self, "audio_hw_probe failed, no mode\n"); |
941 | goto bad; | | 941 | goto bad; |
942 | } | | 942 | } |
943 | /* Init hardware. */ | | 943 | /* Init hardware. */ |
944 | /* hw_probe() also validates [pr]hwfmt. */ | | 944 | /* hw_probe() also validates [pr]hwfmt. */ |
945 | error = audio_hw_set_format(sc, mode, &phwfmt, &rhwfmt, &pfil, &rfil); | | 945 | error = audio_hw_set_format(sc, mode, &phwfmt, &rhwfmt, &pfil, &rfil); |
946 | if (error) { | | 946 | if (error) { |
947 | mutex_exit(sc->sc_lock); | | 947 | mutex_exit(sc->sc_lock); |
948 | aprint_error_dev(self, "audio_hw_set_format failed, " | | 948 | aprint_error_dev(self, "audio_hw_set_format failed, " |
949 | "error = %d\n", error); | | 949 | "error = %d\n", error); |
950 | goto bad; | | 950 | goto bad; |
951 | } | | 951 | } |
952 | | | 952 | |
953 | /* | | 953 | /* |
954 | * Init track mixers. If at least one direction is available on | | 954 | * Init track mixers. If at least one direction is available on |
955 | * attach time, we assume a success. | | 955 | * attach time, we assume a success. |
956 | */ | | 956 | */ |
957 | error = audio_mixers_init(sc, mode, &phwfmt, &rhwfmt, &pfil, &rfil); | | 957 | error = audio_mixers_init(sc, mode, &phwfmt, &rhwfmt, &pfil, &rfil); |
958 | mutex_exit(sc->sc_lock); | | 958 | mutex_exit(sc->sc_lock); |
959 | if (sc->sc_pmixer == NULL && sc->sc_rmixer == NULL) { | | 959 | if (sc->sc_pmixer == NULL && sc->sc_rmixer == NULL) { |
960 | aprint_error_dev(self, "audio_mixers_init failed, " | | 960 | aprint_error_dev(self, "audio_mixers_init failed, " |
961 | "error = %d\n", error); | | 961 | "error = %d\n", error); |
962 | goto bad; | | 962 | goto bad; |
963 | } | | 963 | } |
964 | | | 964 | |
965 | selinit(&sc->sc_wsel); | | 965 | selinit(&sc->sc_wsel); |
966 | selinit(&sc->sc_rsel); | | 966 | selinit(&sc->sc_rsel); |
967 | | | 967 | |
968 | /* Initial parameter of /dev/sound */ | | 968 | /* Initial parameter of /dev/sound */ |
969 | sc->sc_sound_pparams = params_to_format2(&audio_default); | | 969 | sc->sc_sound_pparams = params_to_format2(&audio_default); |
970 | sc->sc_sound_rparams = params_to_format2(&audio_default); | | 970 | sc->sc_sound_rparams = params_to_format2(&audio_default); |
971 | sc->sc_sound_ppause = false; | | 971 | sc->sc_sound_ppause = false; |
972 | sc->sc_sound_rpause = false; | | 972 | sc->sc_sound_rpause = false; |
973 | | | 973 | |
974 | /* XXX TODO: consider about sc_ai */ | | 974 | /* XXX TODO: consider about sc_ai */ |
975 | | | 975 | |
976 | mixer_init(sc); | | 976 | mixer_init(sc); |
977 | TRACE(2, "inputs ports=0x%x, input master=%d, " | | 977 | TRACE(2, "inputs ports=0x%x, input master=%d, " |
978 | "output ports=0x%x, output master=%d", | | 978 | "output ports=0x%x, output master=%d", |
979 | sc->sc_inports.allports, sc->sc_inports.master, | | 979 | sc->sc_inports.allports, sc->sc_inports.master, |
980 | sc->sc_outports.allports, sc->sc_outports.master); | | 980 | sc->sc_outports.allports, sc->sc_outports.master); |
981 | | | 981 | |
982 | sysctl_createv(&sc->sc_log, 0, NULL, &node, | | 982 | sysctl_createv(&sc->sc_log, 0, NULL, &node, |
983 | 0, | | 983 | 0, |
984 | CTLTYPE_NODE, device_xname(sc->sc_dev), | | 984 | CTLTYPE_NODE, device_xname(sc->sc_dev), |
985 | SYSCTL_DESCR("audio test"), | | 985 | SYSCTL_DESCR("audio test"), |
986 | NULL, 0, | | 986 | NULL, 0, |
987 | NULL, 0, | | 987 | NULL, 0, |
988 | CTL_HW, | | 988 | CTL_HW, |
989 | CTL_CREATE, CTL_EOL); | | 989 | CTL_CREATE, CTL_EOL); |
990 | | | 990 | |
991 | if (node != NULL) { | | 991 | if (node != NULL) { |
992 | sysctl_createv(&sc->sc_log, 0, NULL, NULL, | | 992 | sysctl_createv(&sc->sc_log, 0, NULL, NULL, |
993 | CTLFLAG_READWRITE, | | 993 | CTLFLAG_READWRITE, |
994 | CTLTYPE_INT, "blk_ms", | | 994 | CTLTYPE_INT, "blk_ms", |
995 | SYSCTL_DESCR("blocksize in msec"), | | 995 | SYSCTL_DESCR("blocksize in msec"), |
996 | audio_sysctl_blk_ms, 0, (void *)sc, 0, | | 996 | audio_sysctl_blk_ms, 0, (void *)sc, 0, |
997 | CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL); | | 997 | CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL); |
998 | | | 998 | |
999 | sysctl_createv(&sc->sc_log, 0, NULL, NULL, | | 999 | sysctl_createv(&sc->sc_log, 0, NULL, NULL, |
1000 | CTLFLAG_READWRITE, | | 1000 | CTLFLAG_READWRITE, |
1001 | CTLTYPE_BOOL, "multiuser", | | 1001 | CTLTYPE_BOOL, "multiuser", |
1002 | SYSCTL_DESCR("allow multiple user access"), | | 1002 | SYSCTL_DESCR("allow multiple user access"), |
1003 | audio_sysctl_multiuser, 0, (void *)sc, 0, | | 1003 | audio_sysctl_multiuser, 0, (void *)sc, 0, |
1004 | CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL); | | 1004 | CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL); |
1005 | | | 1005 | |
1006 | #if defined(AUDIO_DEBUG) | | 1006 | #if defined(AUDIO_DEBUG) |
1007 | sysctl_createv(&sc->sc_log, 0, NULL, NULL, | | 1007 | sysctl_createv(&sc->sc_log, 0, NULL, NULL, |
1008 | CTLFLAG_READWRITE, | | 1008 | CTLFLAG_READWRITE, |
1009 | CTLTYPE_INT, "debug", | | 1009 | CTLTYPE_INT, "debug", |
1010 | SYSCTL_DESCR("debug level (0..4)"), | | 1010 | SYSCTL_DESCR("debug level (0..4)"), |
1011 | audio_sysctl_debug, 0, (void *)sc, 0, | | 1011 | audio_sysctl_debug, 0, (void *)sc, 0, |
1012 | CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL); | | 1012 | CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL); |
1013 | #endif | | 1013 | #endif |
1014 | } | | 1014 | } |
1015 | | | 1015 | |
1016 | #ifdef AUDIO_PM_IDLE | | 1016 | #ifdef AUDIO_PM_IDLE |
1017 | callout_init(&sc->sc_idle_counter, 0); | | 1017 | callout_init(&sc->sc_idle_counter, 0); |
1018 | callout_setfunc(&sc->sc_idle_counter, audio_idle, self); | | 1018 | callout_setfunc(&sc->sc_idle_counter, audio_idle, self); |
1019 | #endif | | 1019 | #endif |
1020 | | | 1020 | |
1021 | if (!pmf_device_register(self, audio_suspend, audio_resume)) | | 1021 | if (!pmf_device_register(self, audio_suspend, audio_resume)) |
1022 | aprint_error_dev(self, "couldn't establish power handler\n"); | | 1022 | aprint_error_dev(self, "couldn't establish power handler\n"); |
1023 | #ifdef AUDIO_PM_IDLE | | 1023 | #ifdef AUDIO_PM_IDLE |
1024 | if (!device_active_register(self, audio_activity)) | | 1024 | if (!device_active_register(self, audio_activity)) |
1025 | aprint_error_dev(self, "couldn't register activity handler\n"); | | 1025 | aprint_error_dev(self, "couldn't register activity handler\n"); |
1026 | #endif | | 1026 | #endif |
1027 | | | 1027 | |
1028 | if (!pmf_event_register(self, PMFE_AUDIO_VOLUME_DOWN, | | 1028 | if (!pmf_event_register(self, PMFE_AUDIO_VOLUME_DOWN, |
1029 | audio_volume_down, true)) | | 1029 | audio_volume_down, true)) |
1030 | aprint_error_dev(self, "couldn't add volume down handler\n"); | | 1030 | aprint_error_dev(self, "couldn't add volume down handler\n"); |
1031 | if (!pmf_event_register(self, PMFE_AUDIO_VOLUME_UP, | | 1031 | if (!pmf_event_register(self, PMFE_AUDIO_VOLUME_UP, |
1032 | audio_volume_up, true)) | | 1032 | audio_volume_up, true)) |
1033 | aprint_error_dev(self, "couldn't add volume up handler\n"); | | 1033 | aprint_error_dev(self, "couldn't add volume up handler\n"); |
1034 | if (!pmf_event_register(self, PMFE_AUDIO_VOLUME_TOGGLE, | | 1034 | if (!pmf_event_register(self, PMFE_AUDIO_VOLUME_TOGGLE, |
1035 | audio_volume_toggle, true)) | | 1035 | audio_volume_toggle, true)) |
1036 | aprint_error_dev(self, "couldn't add volume toggle handler\n"); | | 1036 | aprint_error_dev(self, "couldn't add volume toggle handler\n"); |
1037 | | | 1037 | |
1038 | #ifdef AUDIO_PM_IDLE | | 1038 | #ifdef AUDIO_PM_IDLE |
1039 | callout_schedule(&sc->sc_idle_counter, audio_idle_timeout * hz); | | 1039 | callout_schedule(&sc->sc_idle_counter, audio_idle_timeout * hz); |
1040 | #endif | | 1040 | #endif |
1041 | | | 1041 | |
1042 | #if defined(AUDIO_DEBUG) | | 1042 | #if defined(AUDIO_DEBUG) |
1043 | audio_mlog_init(); | | 1043 | audio_mlog_init(); |
1044 | #endif | | 1044 | #endif |
1045 | | | 1045 | |
1046 | audiorescan(self, "audio", NULL); | | 1046 | audiorescan(self, "audio", NULL); |
1047 | return; | | 1047 | return; |
1048 | | | 1048 | |
1049 | bad: | | 1049 | bad: |
1050 | /* Clearing hw_if means that device is attached but disabled. */ | | 1050 | /* Clearing hw_if means that device is attached but disabled. */ |
1051 | sc->hw_if = NULL; | | 1051 | sc->hw_if = NULL; |
1052 | aprint_error_dev(sc->sc_dev, "disabled\n"); | | 1052 | aprint_error_dev(sc->sc_dev, "disabled\n"); |
1053 | return; | | 1053 | return; |
1054 | } | | 1054 | } |
1055 | | | 1055 | |
1056 | /* | | 1056 | /* |
1057 | * Initialize hardware mixer. | | 1057 | * Initialize hardware mixer. |
1058 | * This function is called from audioattach(). | | 1058 | * This function is called from audioattach(). |
1059 | */ | | 1059 | */ |
1060 | static void | | 1060 | static void |
1061 | mixer_init(struct audio_softc *sc) | | 1061 | mixer_init(struct audio_softc *sc) |
1062 | { | | 1062 | { |
1063 | mixer_devinfo_t mi; | | 1063 | mixer_devinfo_t mi; |
1064 | int iclass, mclass, oclass, rclass; | | 1064 | int iclass, mclass, oclass, rclass; |
1065 | int record_master_found, record_source_found; | | 1065 | int record_master_found, record_source_found; |
1066 | | | 1066 | |
1067 | iclass = mclass = oclass = rclass = -1; | | 1067 | iclass = mclass = oclass = rclass = -1; |
1068 | sc->sc_inports.index = -1; | | 1068 | sc->sc_inports.index = -1; |
1069 | sc->sc_inports.master = -1; | | 1069 | sc->sc_inports.master = -1; |
1070 | sc->sc_inports.nports = 0; | | 1070 | sc->sc_inports.nports = 0; |
1071 | sc->sc_inports.isenum = false; | | 1071 | sc->sc_inports.isenum = false; |
1072 | sc->sc_inports.allports = 0; | | 1072 | sc->sc_inports.allports = 0; |
1073 | sc->sc_inports.isdual = false; | | 1073 | sc->sc_inports.isdual = false; |
1074 | sc->sc_inports.mixerout = -1; | | 1074 | sc->sc_inports.mixerout = -1; |
1075 | sc->sc_inports.cur_port = -1; | | 1075 | sc->sc_inports.cur_port = -1; |
1076 | sc->sc_outports.index = -1; | | 1076 | sc->sc_outports.index = -1; |
1077 | sc->sc_outports.master = -1; | | 1077 | sc->sc_outports.master = -1; |
1078 | sc->sc_outports.nports = 0; | | 1078 | sc->sc_outports.nports = 0; |
1079 | sc->sc_outports.isenum = false; | | 1079 | sc->sc_outports.isenum = false; |
1080 | sc->sc_outports.allports = 0; | | 1080 | sc->sc_outports.allports = 0; |
1081 | sc->sc_outports.isdual = false; | | 1081 | sc->sc_outports.isdual = false; |
1082 | sc->sc_outports.mixerout = -1; | | 1082 | sc->sc_outports.mixerout = -1; |
1083 | sc->sc_outports.cur_port = -1; | | 1083 | sc->sc_outports.cur_port = -1; |
1084 | sc->sc_monitor_port = -1; | | 1084 | sc->sc_monitor_port = -1; |
1085 | /* | | 1085 | /* |
1086 | * Read through the underlying driver's list, picking out the class | | 1086 | * Read through the underlying driver's list, picking out the class |
1087 | * names from the mixer descriptions. We'll need them to decode the | | 1087 | * names from the mixer descriptions. We'll need them to decode the |
1088 | * mixer descriptions on the next pass through the loop. | | 1088 | * mixer descriptions on the next pass through the loop. |
1089 | */ | | 1089 | */ |
1090 | mutex_enter(sc->sc_lock); | | 1090 | mutex_enter(sc->sc_lock); |
1091 | for(mi.index = 0; ; mi.index++) { | | 1091 | for(mi.index = 0; ; mi.index++) { |
1092 | if (audio_query_devinfo(sc, &mi) != 0) | | 1092 | if (audio_query_devinfo(sc, &mi) != 0) |
1093 | break; | | 1093 | break; |
1094 | /* | | 1094 | /* |
1095 | * The type of AUDIO_MIXER_CLASS merely introduces a class. | | 1095 | * The type of AUDIO_MIXER_CLASS merely introduces a class. |
1096 | * All the other types describe an actual mixer. | | 1096 | * All the other types describe an actual mixer. |
1097 | */ | | 1097 | */ |
1098 | if (mi.type == AUDIO_MIXER_CLASS) { | | 1098 | if (mi.type == AUDIO_MIXER_CLASS) { |
1099 | if (strcmp(mi.label.name, AudioCinputs) == 0) | | 1099 | if (strcmp(mi.label.name, AudioCinputs) == 0) |
1100 | iclass = mi.mixer_class; | | 1100 | iclass = mi.mixer_class; |
1101 | if (strcmp(mi.label.name, AudioCmonitor) == 0) | | 1101 | if (strcmp(mi.label.name, AudioCmonitor) == 0) |
1102 | mclass = mi.mixer_class; | | 1102 | mclass = mi.mixer_class; |
1103 | if (strcmp(mi.label.name, AudioCoutputs) == 0) | | 1103 | if (strcmp(mi.label.name, AudioCoutputs) == 0) |
1104 | oclass = mi.mixer_class; | | 1104 | oclass = mi.mixer_class; |
1105 | if (strcmp(mi.label.name, AudioCrecord) == 0) | | 1105 | if (strcmp(mi.label.name, AudioCrecord) == 0) |
1106 | rclass = mi.mixer_class; | | 1106 | rclass = mi.mixer_class; |
1107 | } | | 1107 | } |
1108 | } | | 1108 | } |
1109 | mutex_exit(sc->sc_lock); | | 1109 | mutex_exit(sc->sc_lock); |
1110 | | | 1110 | |
1111 | /* Allocate save area. Ensure non-zero allocation. */ | | 1111 | /* Allocate save area. Ensure non-zero allocation. */ |
1112 | sc->sc_nmixer_states = mi.index; | | 1112 | sc->sc_nmixer_states = mi.index; |
1113 | sc->sc_mixer_state = kmem_zalloc(sizeof(mixer_ctrl_t) * | | 1113 | sc->sc_mixer_state = kmem_zalloc(sizeof(mixer_ctrl_t) * |
1114 | (sc->sc_nmixer_states + 1), KM_SLEEP); | | 1114 | (sc->sc_nmixer_states + 1), KM_SLEEP); |
1115 | | | 1115 | |
1116 | /* | | 1116 | /* |
1117 | * This is where we assign each control in the "audio" model, to the | | 1117 | * This is where we assign each control in the "audio" model, to the |
1118 | * underlying "mixer" control. We walk through the whole list once, | | 1118 | * underlying "mixer" control. We walk through the whole list once, |
1119 | * assigning likely candidates as we come across them. | | 1119 | * assigning likely candidates as we come across them. |
1120 | */ | | 1120 | */ |
1121 | record_master_found = 0; | | 1121 | record_master_found = 0; |
1122 | record_source_found = 0; | | 1122 | record_source_found = 0; |
1123 | mutex_enter(sc->sc_lock); | | 1123 | mutex_enter(sc->sc_lock); |
1124 | for(mi.index = 0; ; mi.index++) { | | 1124 | for(mi.index = 0; ; mi.index++) { |
1125 | if (audio_query_devinfo(sc, &mi) != 0) | | 1125 | if (audio_query_devinfo(sc, &mi) != 0) |
1126 | break; | | 1126 | break; |
1127 | KASSERT(mi.index < sc->sc_nmixer_states); | | 1127 | KASSERT(mi.index < sc->sc_nmixer_states); |
1128 | if (mi.type == AUDIO_MIXER_CLASS) | | 1128 | if (mi.type == AUDIO_MIXER_CLASS) |
1129 | continue; | | 1129 | continue; |
1130 | if (mi.mixer_class == iclass) { | | 1130 | if (mi.mixer_class == iclass) { |
1131 | /* | | 1131 | /* |
1132 | * AudioCinputs is only a fallback, when we don't | | 1132 | * AudioCinputs is only a fallback, when we don't |
1133 | * find what we're looking for in AudioCrecord, so | | 1133 | * find what we're looking for in AudioCrecord, so |
1134 | * check the flags before accepting one of these. | | 1134 | * check the flags before accepting one of these. |
1135 | */ | | 1135 | */ |
1136 | if (strcmp(mi.label.name, AudioNmaster) == 0 | | 1136 | if (strcmp(mi.label.name, AudioNmaster) == 0 |
1137 | && record_master_found == 0) | | 1137 | && record_master_found == 0) |
1138 | sc->sc_inports.master = mi.index; | | 1138 | sc->sc_inports.master = mi.index; |
1139 | if (strcmp(mi.label.name, AudioNsource) == 0 | | 1139 | if (strcmp(mi.label.name, AudioNsource) == 0 |
1140 | && record_source_found == 0) { | | 1140 | && record_source_found == 0) { |
1141 | if (mi.type == AUDIO_MIXER_ENUM) { | | 1141 | if (mi.type == AUDIO_MIXER_ENUM) { |
1142 | int i; | | 1142 | int i; |
1143 | for(i = 0; i < mi.un.e.num_mem; i++) | | 1143 | for(i = 0; i < mi.un.e.num_mem; i++) |
1144 | if (strcmp(mi.un.e.member[i].label.name, | | 1144 | if (strcmp(mi.un.e.member[i].label.name, |
| @@ -2065,3672 +2065,3614 @@ audio_open(dev_t dev, struct audio_softc | | | @@ -2065,3672 +2065,3614 @@ audio_open(dev_t dev, struct audio_softc |
2065 | error = fd_clone(fp, fd, flags, &audio_fileops, af); | | 2065 | error = fd_clone(fp, fd, flags, &audio_fileops, af); |
2066 | KASSERT(error == EMOVEFD); | | 2066 | KASSERT(error == EMOVEFD); |
2067 | } | | 2067 | } |
2068 | | | 2068 | |
2069 | TRACEF(3, af, "done"); | | 2069 | TRACEF(3, af, "done"); |
2070 | return error; | | 2070 | return error; |
2071 | | | 2071 | |
2072 | /* | | 2072 | /* |
2073 | * Since track here is not yet linked to sc_files, | | 2073 | * Since track here is not yet linked to sc_files, |
2074 | * you can call track_destroy() without sc_intr_lock. | | 2074 | * you can call track_destroy() without sc_intr_lock. |
2075 | */ | | 2075 | */ |
2076 | bad3: | | 2076 | bad3: |
2077 | if (sc->sc_popens + sc->sc_ropens == 0) { | | 2077 | if (sc->sc_popens + sc->sc_ropens == 0) { |
2078 | if (sc->hw_if->close) { | | 2078 | if (sc->hw_if->close) { |
2079 | mutex_enter(sc->sc_intr_lock); | | 2079 | mutex_enter(sc->sc_intr_lock); |
2080 | sc->hw_if->close(sc->hw_hdl); | | 2080 | sc->hw_if->close(sc->hw_hdl); |
2081 | mutex_exit(sc->sc_intr_lock); | | 2081 | mutex_exit(sc->sc_intr_lock); |
2082 | } | | 2082 | } |
2083 | } | | 2083 | } |
2084 | bad2: | | 2084 | bad2: |
2085 | if (af->rtrack) { | | 2085 | if (af->rtrack) { |
2086 | audio_track_destroy(af->rtrack); | | 2086 | audio_track_destroy(af->rtrack); |
2087 | af->rtrack = NULL; | | 2087 | af->rtrack = NULL; |
2088 | } | | 2088 | } |
2089 | if (af->ptrack) { | | 2089 | if (af->ptrack) { |
2090 | audio_track_destroy(af->ptrack); | | 2090 | audio_track_destroy(af->ptrack); |
2091 | af->ptrack = NULL; | | 2091 | af->ptrack = NULL; |
2092 | } | | 2092 | } |
2093 | bad1: | | 2093 | bad1: |
2094 | kmem_free(af, sizeof(*af)); | | 2094 | kmem_free(af, sizeof(*af)); |
2095 | return error; | | 2095 | return error; |
2096 | } | | 2096 | } |
2097 | | | 2097 | |
2098 | /* | | 2098 | /* |
2099 | * Must NOT called with sc_lock nor sc_exlock held. | | 2099 | * Must NOT called with sc_lock nor sc_exlock held. |
2100 | */ | | 2100 | */ |
2101 | int | | 2101 | int |
2102 | audio_close(struct audio_softc *sc, audio_file_t *file) | | 2102 | audio_close(struct audio_softc *sc, audio_file_t *file) |
2103 | { | | 2103 | { |
2104 | audio_track_t *oldtrack; | | 2104 | audio_track_t *oldtrack; |
2105 | int error; | | 2105 | int error; |
2106 | | | 2106 | |
2107 | KASSERT(!mutex_owned(sc->sc_lock)); | | 2107 | KASSERT(!mutex_owned(sc->sc_lock)); |
2108 | | | 2108 | |
2109 | TRACEF(1, file, "%spid=%d.%d po=%d ro=%d", | | 2109 | TRACEF(1, file, "%spid=%d.%d po=%d ro=%d", |
2110 | (audiodebug >= 3) ? "start " : "", | | 2110 | (audiodebug >= 3) ? "start " : "", |
2111 | (int)curproc->p_pid, (int)curlwp->l_lid, | | 2111 | (int)curproc->p_pid, (int)curlwp->l_lid, |
2112 | sc->sc_popens, sc->sc_ropens); | | 2112 | sc->sc_popens, sc->sc_ropens); |
2113 | KASSERTMSG(sc->sc_popens + sc->sc_ropens > 0, | | 2113 | KASSERTMSG(sc->sc_popens + sc->sc_ropens > 0, |
2114 | "sc->sc_popens=%d, sc->sc_ropens=%d", | | 2114 | "sc->sc_popens=%d, sc->sc_ropens=%d", |
2115 | sc->sc_popens, sc->sc_ropens); | | 2115 | sc->sc_popens, sc->sc_ropens); |
2116 | | | 2116 | |
2117 | /* | | 2117 | /* |
2118 | * Drain first. | | 2118 | * Drain first. |
2119 | * It must be done before acquiring exclusive lock. | | 2119 | * It must be done before acquiring exclusive lock. |
2120 | */ | | 2120 | */ |
2121 | if (file->ptrack) { | | 2121 | if (file->ptrack) { |
2122 | mutex_enter(sc->sc_lock); | | 2122 | mutex_enter(sc->sc_lock); |
2123 | audio_track_drain(sc, file->ptrack); | | 2123 | audio_track_drain(sc, file->ptrack); |
2124 | mutex_exit(sc->sc_lock); | | 2124 | mutex_exit(sc->sc_lock); |
2125 | } | | 2125 | } |
2126 | | | 2126 | |
2127 | /* Then, acquire exclusive lock to protect counters. */ | | 2127 | /* Then, acquire exclusive lock to protect counters. */ |
2128 | /* XXX what should I do when an error occurs? */ | | 2128 | /* XXX what should I do when an error occurs? */ |
2129 | error = audio_enter_exclusive(sc); | | 2129 | error = audio_enter_exclusive(sc); |
2130 | if (error) | | 2130 | if (error) |
2131 | return error; | | 2131 | return error; |
2132 | | | 2132 | |
2133 | if (file->ptrack) { | | 2133 | if (file->ptrack) { |
2134 | /* Call hw halt_output if this is the last playback track. */ | | 2134 | /* Call hw halt_output if this is the last playback track. */ |
2135 | if (sc->sc_popens == 1 && sc->sc_pbusy) { | | 2135 | if (sc->sc_popens == 1 && sc->sc_pbusy) { |
2136 | error = audio_pmixer_halt(sc); | | 2136 | error = audio_pmixer_halt(sc); |
2137 | if (error) { | | 2137 | if (error) { |
2138 | device_printf(sc->sc_dev, | | 2138 | device_printf(sc->sc_dev, |
2139 | "halt_output failed with %d\n", error); | | 2139 | "halt_output failed with %d\n", error); |
2140 | } | | 2140 | } |
2141 | } | | 2141 | } |
2142 | | | 2142 | |
2143 | /* Destroy the track. */ | | 2143 | /* Destroy the track. */ |
2144 | oldtrack = file->ptrack; | | 2144 | oldtrack = file->ptrack; |
2145 | mutex_enter(sc->sc_intr_lock); | | 2145 | mutex_enter(sc->sc_intr_lock); |
2146 | file->ptrack = NULL; | | 2146 | file->ptrack = NULL; |
2147 | mutex_exit(sc->sc_intr_lock); | | 2147 | mutex_exit(sc->sc_intr_lock); |
2148 | TRACET(3, oldtrack, "dropframes=%" PRIu64, | | 2148 | TRACET(3, oldtrack, "dropframes=%" PRIu64, |
2149 | oldtrack->dropframes); | | 2149 | oldtrack->dropframes); |
2150 | audio_track_destroy(oldtrack); | | 2150 | audio_track_destroy(oldtrack); |
2151 | | | 2151 | |
2152 | KASSERT(sc->sc_popens > 0); | | 2152 | KASSERT(sc->sc_popens > 0); |
2153 | sc->sc_popens--; | | 2153 | sc->sc_popens--; |
2154 | | | 2154 | |
2155 | /* Restore mixing volume if all tracks are gone. */ | | 2155 | /* Restore mixing volume if all tracks are gone. */ |
2156 | if (sc->sc_popens == 0) { | | 2156 | if (sc->sc_popens == 0) { |
2157 | mutex_enter(sc->sc_intr_lock); | | 2157 | mutex_enter(sc->sc_intr_lock); |
2158 | sc->sc_pmixer->volume = 256; | | 2158 | sc->sc_pmixer->volume = 256; |
2159 | sc->sc_pmixer->voltimer = 0; | | 2159 | sc->sc_pmixer->voltimer = 0; |
2160 | mutex_exit(sc->sc_intr_lock); | | 2160 | mutex_exit(sc->sc_intr_lock); |
2161 | } | | 2161 | } |
2162 | } | | 2162 | } |
2163 | if (file->rtrack) { | | 2163 | if (file->rtrack) { |
2164 | /* Call hw halt_input if this is the last recording track. */ | | 2164 | /* Call hw halt_input if this is the last recording track. */ |
2165 | if (sc->sc_ropens == 1 && sc->sc_rbusy) { | | 2165 | if (sc->sc_ropens == 1 && sc->sc_rbusy) { |
2166 | error = audio_rmixer_halt(sc); | | 2166 | error = audio_rmixer_halt(sc); |
2167 | if (error) { | | 2167 | if (error) { |
2168 | device_printf(sc->sc_dev, | | 2168 | device_printf(sc->sc_dev, |
2169 | "halt_input failed with %d\n", error); | | 2169 | "halt_input failed with %d\n", error); |
2170 | } | | 2170 | } |
2171 | } | | 2171 | } |
2172 | | | 2172 | |
2173 | /* Destroy the track. */ | | 2173 | /* Destroy the track. */ |
2174 | oldtrack = file->rtrack; | | 2174 | oldtrack = file->rtrack; |
2175 | mutex_enter(sc->sc_intr_lock); | | 2175 | mutex_enter(sc->sc_intr_lock); |
2176 | file->rtrack = NULL; | | 2176 | file->rtrack = NULL; |
2177 | mutex_exit(sc->sc_intr_lock); | | 2177 | mutex_exit(sc->sc_intr_lock); |
2178 | TRACET(3, oldtrack, "dropframes=%" PRIu64, | | 2178 | TRACET(3, oldtrack, "dropframes=%" PRIu64, |
2179 | oldtrack->dropframes); | | 2179 | oldtrack->dropframes); |
2180 | audio_track_destroy(oldtrack); | | 2180 | audio_track_destroy(oldtrack); |
2181 | | | 2181 | |
2182 | KASSERT(sc->sc_ropens > 0); | | 2182 | KASSERT(sc->sc_ropens > 0); |
2183 | sc->sc_ropens--; | | 2183 | sc->sc_ropens--; |
2184 | } | | 2184 | } |
2185 | | | 2185 | |
2186 | /* Call hw close if this is the last track. */ | | 2186 | /* Call hw close if this is the last track. */ |
2187 | if (sc->sc_popens + sc->sc_ropens == 0) { | | 2187 | if (sc->sc_popens + sc->sc_ropens == 0) { |
2188 | if (sc->hw_if->close) { | | 2188 | if (sc->hw_if->close) { |
2189 | TRACE(2, "hw_if close"); | | 2189 | TRACE(2, "hw_if close"); |
2190 | mutex_enter(sc->sc_intr_lock); | | 2190 | mutex_enter(sc->sc_intr_lock); |
2191 | sc->hw_if->close(sc->hw_hdl); | | 2191 | sc->hw_if->close(sc->hw_hdl); |
2192 | mutex_exit(sc->sc_intr_lock); | | 2192 | mutex_exit(sc->sc_intr_lock); |
2193 | } | | 2193 | } |
2194 | | | 2194 | |
2195 | kauth_cred_free(sc->sc_cred); | | 2195 | kauth_cred_free(sc->sc_cred); |
2196 | } | | 2196 | } |
2197 | | | 2197 | |
2198 | mutex_enter(sc->sc_intr_lock); | | 2198 | mutex_enter(sc->sc_intr_lock); |
2199 | SLIST_REMOVE(&sc->sc_files, file, audio_file, entry); | | 2199 | SLIST_REMOVE(&sc->sc_files, file, audio_file, entry); |
2200 | mutex_exit(sc->sc_intr_lock); | | 2200 | mutex_exit(sc->sc_intr_lock); |
2201 | | | 2201 | |
2202 | TRACE(3, "done"); | | 2202 | TRACE(3, "done"); |
2203 | audio_exit_exclusive(sc); | | 2203 | audio_exit_exclusive(sc); |
2204 | return 0; | | 2204 | return 0; |
2205 | } | | 2205 | } |
2206 | | | 2206 | |
2207 | int | | 2207 | int |
2208 | audio_read(struct audio_softc *sc, struct uio *uio, int ioflag, | | 2208 | audio_read(struct audio_softc *sc, struct uio *uio, int ioflag, |
2209 | audio_file_t *file) | | 2209 | audio_file_t *file) |
2210 | { | | 2210 | { |
2211 | audio_track_t *track; | | 2211 | audio_track_t *track; |
2212 | audio_ring_t *usrbuf; | | 2212 | audio_ring_t *usrbuf; |
2213 | audio_ring_t *input; | | 2213 | audio_ring_t *input; |
2214 | int error; | | 2214 | int error; |
2215 | | | 2215 | |
2216 | KASSERT(!mutex_owned(sc->sc_lock)); | | 2216 | KASSERT(!mutex_owned(sc->sc_lock)); |
2217 | | | 2217 | |
2218 | /* | | 2218 | /* |
2219 | * On half-duplex hardware, O_RDWR is treated as O_WRONLY. | | 2219 | * On half-duplex hardware, O_RDWR is treated as O_WRONLY. |
2220 | * However read() system call itself can be called because it's | | 2220 | * However read() system call itself can be called because it's |
2221 | * opened with O_RDWR. So in this case, deny this read(). | | 2221 | * opened with O_RDWR. So in this case, deny this read(). |
2222 | */ | | 2222 | */ |
2223 | track = file->rtrack; | | 2223 | track = file->rtrack; |
2224 | if (track == NULL) { | | 2224 | if (track == NULL) { |
2225 | return EBADF; | | 2225 | return EBADF; |
2226 | } | | 2226 | } |
2227 | | | 2227 | |
2228 | /* I think it's better than EINVAL. */ | | 2228 | /* I think it's better than EINVAL. */ |
2229 | if (track->mmapped) | | 2229 | if (track->mmapped) |
2230 | return EPERM; | | 2230 | return EPERM; |
2231 | | | 2231 | |
2232 | TRACET(2, track, "resid=%zd", uio->uio_resid); | | 2232 | TRACET(2, track, "resid=%zd", uio->uio_resid); |
2233 | | | 2233 | |
2234 | #ifdef AUDIO_PM_IDLE | | 2234 | #ifdef AUDIO_PM_IDLE |
2235 | mutex_enter(sc->sc_lock); | | 2235 | mutex_enter(sc->sc_lock); |
2236 | if (device_is_active(&sc->sc_dev) || sc->sc_idle) | | 2236 | if (device_is_active(&sc->sc_dev) || sc->sc_idle) |
2237 | device_active(&sc->sc_dev, DVA_SYSTEM); | | 2237 | device_active(&sc->sc_dev, DVA_SYSTEM); |
2238 | mutex_exit(sc->sc_lock); | | 2238 | mutex_exit(sc->sc_lock); |
2239 | #endif | | 2239 | #endif |
2240 | | | 2240 | |
2241 | usrbuf = &track->usrbuf; | | 2241 | usrbuf = &track->usrbuf; |
2242 | input = track->input; | | 2242 | input = track->input; |
2243 | | | 2243 | |
2244 | /* | | 2244 | /* |
2245 | * The first read starts rmixer. | | 2245 | * The first read starts rmixer. |
2246 | */ | | 2246 | */ |
2247 | error = audio_enter_exclusive(sc); | | 2247 | error = audio_enter_exclusive(sc); |
2248 | if (error) | | 2248 | if (error) |
2249 | return error; | | 2249 | return error; |
2250 | if (sc->sc_rbusy == false) | | 2250 | if (sc->sc_rbusy == false) |
2251 | audio_rmixer_start(sc); | | 2251 | audio_rmixer_start(sc); |
2252 | audio_exit_exclusive(sc); | | 2252 | audio_exit_exclusive(sc); |
2253 | | | 2253 | |
2254 | error = 0; | | 2254 | error = 0; |
2255 | while (uio->uio_resid > 0 && error == 0) { | | 2255 | while (uio->uio_resid > 0 && error == 0) { |
2256 | int bytes; | | 2256 | int bytes; |
2257 | | | 2257 | |
2258 | TRACET(3, track, | | 2258 | TRACET(3, track, |
2259 | "while resid=%zd input=%d/%d/%d usrbuf=%d/%d/H%d", | | 2259 | "while resid=%zd input=%d/%d/%d usrbuf=%d/%d/H%d", |
2260 | uio->uio_resid, | | 2260 | uio->uio_resid, |
2261 | input->head, input->used, input->capacity, | | 2261 | input->head, input->used, input->capacity, |
2262 | usrbuf->head, usrbuf->used, track->usrbuf_usedhigh); | | 2262 | usrbuf->head, usrbuf->used, track->usrbuf_usedhigh); |
2263 | | | 2263 | |
2264 | /* Wait when buffers are empty. */ | | 2264 | /* Wait when buffers are empty. */ |
2265 | mutex_enter(sc->sc_lock); | | 2265 | mutex_enter(sc->sc_lock); |
2266 | for (;;) { | | 2266 | for (;;) { |
2267 | bool empty; | | 2267 | bool empty; |
2268 | audio_track_lock_enter(track); | | 2268 | audio_track_lock_enter(track); |
2269 | empty = (input->used == 0 && usrbuf->used == 0); | | 2269 | empty = (input->used == 0 && usrbuf->used == 0); |
2270 | audio_track_lock_exit(track); | | 2270 | audio_track_lock_exit(track); |
2271 | if (!empty) | | 2271 | if (!empty) |
2272 | break; | | 2272 | break; |
2273 | | | 2273 | |
2274 | if ((ioflag & IO_NDELAY)) { | | 2274 | if ((ioflag & IO_NDELAY)) { |
2275 | mutex_exit(sc->sc_lock); | | 2275 | mutex_exit(sc->sc_lock); |
2276 | return EWOULDBLOCK; | | 2276 | return EWOULDBLOCK; |
2277 | } | | 2277 | } |
2278 | | | 2278 | |
2279 | TRACET(3, track, "sleep"); | | 2279 | TRACET(3, track, "sleep"); |
2280 | error = audio_track_waitio(sc, track); | | 2280 | error = audio_track_waitio(sc, track); |
2281 | if (error) { | | 2281 | if (error) { |
2282 | mutex_exit(sc->sc_lock); | | 2282 | mutex_exit(sc->sc_lock); |
2283 | return error; | | 2283 | return error; |
2284 | } | | 2284 | } |
2285 | } | | 2285 | } |
2286 | mutex_exit(sc->sc_lock); | | 2286 | mutex_exit(sc->sc_lock); |
2287 | | | 2287 | |
2288 | audio_track_lock_enter(track); | | 2288 | audio_track_lock_enter(track); |
2289 | audio_track_record(track); | | 2289 | audio_track_record(track); |
2290 | | | 2290 | |
2291 | /* uiomove from usrbuf as much as possible. */ | | 2291 | /* uiomove from usrbuf as much as possible. */ |
2292 | bytes = uimin(usrbuf->used, uio->uio_resid); | | 2292 | bytes = uimin(usrbuf->used, uio->uio_resid); |
2293 | while (bytes > 0) { | | 2293 | while (bytes > 0) { |
2294 | int head = usrbuf->head; | | 2294 | int head = usrbuf->head; |
2295 | int len = uimin(bytes, usrbuf->capacity - head); | | 2295 | int len = uimin(bytes, usrbuf->capacity - head); |
2296 | error = uiomove((uint8_t *)usrbuf->mem + head, len, | | 2296 | error = uiomove((uint8_t *)usrbuf->mem + head, len, |
2297 | uio); | | 2297 | uio); |
2298 | if (error) { | | 2298 | if (error) { |
2299 | audio_track_lock_exit(track); | | 2299 | audio_track_lock_exit(track); |
2300 | device_printf(sc->sc_dev, | | 2300 | device_printf(sc->sc_dev, |
2301 | "uiomove(len=%d) failed with %d\n", | | 2301 | "uiomove(len=%d) failed with %d\n", |
2302 | len, error); | | 2302 | len, error); |
2303 | goto abort; | | 2303 | goto abort; |
2304 | } | | 2304 | } |
2305 | auring_take(usrbuf, len); | | 2305 | auring_take(usrbuf, len); |
2306 | track->useriobytes += len; | | 2306 | track->useriobytes += len; |
2307 | TRACET(3, track, "uiomove(len=%d) usrbuf=%d/%d/C%d", | | 2307 | TRACET(3, track, "uiomove(len=%d) usrbuf=%d/%d/C%d", |
2308 | len, | | 2308 | len, |
2309 | usrbuf->head, usrbuf->used, usrbuf->capacity); | | 2309 | usrbuf->head, usrbuf->used, usrbuf->capacity); |
2310 | bytes -= len; | | 2310 | bytes -= len; |
2311 | } | | 2311 | } |
2312 | | | 2312 | |
2313 | audio_track_lock_exit(track); | | 2313 | audio_track_lock_exit(track); |
2314 | } | | 2314 | } |
2315 | | | 2315 | |
2316 | abort: | | 2316 | abort: |
2317 | return error; | | 2317 | return error; |
2318 | } | | 2318 | } |
2319 | | | 2319 | |
2320 | | | 2320 | |
2321 | /* | | 2321 | /* |
2322 | * Clear file's playback and/or record track buffer immediately. | | 2322 | * Clear file's playback and/or record track buffer immediately. |
2323 | */ | | 2323 | */ |
2324 | static void | | 2324 | static void |
2325 | audio_file_clear(struct audio_softc *sc, audio_file_t *file) | | 2325 | audio_file_clear(struct audio_softc *sc, audio_file_t *file) |
2326 | { | | 2326 | { |
2327 | | | 2327 | |
2328 | if (file->ptrack) | | 2328 | if (file->ptrack) |
2329 | audio_track_clear(sc, file->ptrack); | | 2329 | audio_track_clear(sc, file->ptrack); |
2330 | if (file->rtrack) | | 2330 | if (file->rtrack) |
2331 | audio_track_clear(sc, file->rtrack); | | 2331 | audio_track_clear(sc, file->rtrack); |
2332 | } | | 2332 | } |
2333 | | | 2333 | |
2334 | int | | 2334 | int |
2335 | audio_write(struct audio_softc *sc, struct uio *uio, int ioflag, | | 2335 | audio_write(struct audio_softc *sc, struct uio *uio, int ioflag, |
2336 | audio_file_t *file) | | 2336 | audio_file_t *file) |
2337 | { | | 2337 | { |
2338 | audio_track_t *track; | | 2338 | audio_track_t *track; |
2339 | audio_ring_t *usrbuf; | | 2339 | audio_ring_t *usrbuf; |
2340 | audio_ring_t *outbuf; | | 2340 | audio_ring_t *outbuf; |
2341 | int error; | | 2341 | int error; |
2342 | | | 2342 | |
2343 | KASSERT(!mutex_owned(sc->sc_lock)); | | 2343 | KASSERT(!mutex_owned(sc->sc_lock)); |
2344 | | | 2344 | |
2345 | track = file->ptrack; | | 2345 | track = file->ptrack; |
2346 | KASSERT(track); | | 2346 | KASSERT(track); |
2347 | | | 2347 | |
2348 | /* I think it's better than EINVAL. */ | | 2348 | /* I think it's better than EINVAL. */ |
2349 | if (track->mmapped) | | 2349 | if (track->mmapped) |
2350 | return EPERM; | | 2350 | return EPERM; |
2351 | | | 2351 | |
2352 | TRACET(2, track, "%sresid=%zd pid=%d.%d ioflag=0x%x", | | 2352 | TRACET(2, track, "%sresid=%zd pid=%d.%d ioflag=0x%x", |
2353 | audiodebug >= 3 ? "begin " : "", | | 2353 | audiodebug >= 3 ? "begin " : "", |
2354 | uio->uio_resid, (int)curproc->p_pid, (int)curlwp->l_lid, ioflag); | | 2354 | uio->uio_resid, (int)curproc->p_pid, (int)curlwp->l_lid, ioflag); |
2355 | | | 2355 | |
2356 | if (uio->uio_resid == 0) { | | 2356 | if (uio->uio_resid == 0) { |
2357 | track->eofcounter++; | | 2357 | track->eofcounter++; |
2358 | return 0; | | 2358 | return 0; |
2359 | } | | 2359 | } |
2360 | | | 2360 | |
2361 | #ifdef AUDIO_PM_IDLE | | 2361 | #ifdef AUDIO_PM_IDLE |
2362 | mutex_enter(sc->sc_lock); | | 2362 | mutex_enter(sc->sc_lock); |
2363 | if (device_is_active(&sc->sc_dev) || sc->sc_idle) | | 2363 | if (device_is_active(&sc->sc_dev) || sc->sc_idle) |
2364 | device_active(&sc->sc_dev, DVA_SYSTEM); | | 2364 | device_active(&sc->sc_dev, DVA_SYSTEM); |
2365 | mutex_exit(sc->sc_lock); | | 2365 | mutex_exit(sc->sc_lock); |
2366 | #endif | | 2366 | #endif |
2367 | | | 2367 | |
2368 | usrbuf = &track->usrbuf; | | 2368 | usrbuf = &track->usrbuf; |
2369 | outbuf = &track->outbuf; | | 2369 | outbuf = &track->outbuf; |
2370 | | | 2370 | |
2371 | /* | | 2371 | /* |
2372 | * The first write starts pmixer. | | 2372 | * The first write starts pmixer. |
2373 | */ | | 2373 | */ |
2374 | error = audio_enter_exclusive(sc); | | 2374 | error = audio_enter_exclusive(sc); |
2375 | if (error) | | 2375 | if (error) |
2376 | return error; | | 2376 | return error; |
2377 | if (sc->sc_pbusy == false) | | 2377 | if (sc->sc_pbusy == false) |
2378 | audio_pmixer_start(sc, false); | | 2378 | audio_pmixer_start(sc, false); |
2379 | audio_exit_exclusive(sc); | | 2379 | audio_exit_exclusive(sc); |
2380 | | | 2380 | |
2381 | track->pstate = AUDIO_STATE_RUNNING; | | 2381 | track->pstate = AUDIO_STATE_RUNNING; |
2382 | error = 0; | | 2382 | error = 0; |
2383 | while (uio->uio_resid > 0 && error == 0) { | | 2383 | while (uio->uio_resid > 0 && error == 0) { |
2384 | int bytes; | | 2384 | int bytes; |
2385 | | | 2385 | |
2386 | TRACET(3, track, "while resid=%zd usrbuf=%d/%d/H%d", | | 2386 | TRACET(3, track, "while resid=%zd usrbuf=%d/%d/H%d", |
2387 | uio->uio_resid, | | 2387 | uio->uio_resid, |
2388 | usrbuf->head, usrbuf->used, track->usrbuf_usedhigh); | | 2388 | usrbuf->head, usrbuf->used, track->usrbuf_usedhigh); |
2389 | | | 2389 | |
2390 | /* Wait when buffers are full. */ | | 2390 | /* Wait when buffers are full. */ |
2391 | mutex_enter(sc->sc_lock); | | 2391 | mutex_enter(sc->sc_lock); |
2392 | for (;;) { | | 2392 | for (;;) { |
2393 | bool full; | | 2393 | bool full; |
2394 | audio_track_lock_enter(track); | | 2394 | audio_track_lock_enter(track); |
2395 | full = (usrbuf->used >= track->usrbuf_usedhigh && | | 2395 | full = (usrbuf->used >= track->usrbuf_usedhigh && |
2396 | outbuf->used >= outbuf->capacity); | | 2396 | outbuf->used >= outbuf->capacity); |
2397 | audio_track_lock_exit(track); | | 2397 | audio_track_lock_exit(track); |
2398 | if (!full) | | 2398 | if (!full) |
2399 | break; | | 2399 | break; |
2400 | | | 2400 | |
2401 | if ((ioflag & IO_NDELAY)) { | | 2401 | if ((ioflag & IO_NDELAY)) { |
2402 | error = EWOULDBLOCK; | | 2402 | error = EWOULDBLOCK; |
2403 | mutex_exit(sc->sc_lock); | | 2403 | mutex_exit(sc->sc_lock); |
2404 | goto abort; | | 2404 | goto abort; |
2405 | } | | 2405 | } |
2406 | | | 2406 | |
2407 | TRACET(3, track, "sleep usrbuf=%d/H%d", | | 2407 | TRACET(3, track, "sleep usrbuf=%d/H%d", |
2408 | usrbuf->used, track->usrbuf_usedhigh); | | 2408 | usrbuf->used, track->usrbuf_usedhigh); |
2409 | error = audio_track_waitio(sc, track); | | 2409 | error = audio_track_waitio(sc, track); |
2410 | if (error) { | | 2410 | if (error) { |
2411 | mutex_exit(sc->sc_lock); | | 2411 | mutex_exit(sc->sc_lock); |
2412 | goto abort; | | 2412 | goto abort; |
2413 | } | | 2413 | } |
2414 | } | | 2414 | } |
2415 | mutex_exit(sc->sc_lock); | | 2415 | mutex_exit(sc->sc_lock); |
2416 | | | 2416 | |
2417 | audio_track_lock_enter(track); | | 2417 | audio_track_lock_enter(track); |
2418 | | | 2418 | |
2419 | /* uiomove to usrbuf as much as possible. */ | | 2419 | /* uiomove to usrbuf as much as possible. */ |
2420 | bytes = uimin(track->usrbuf_usedhigh - usrbuf->used, | | 2420 | bytes = uimin(track->usrbuf_usedhigh - usrbuf->used, |
2421 | uio->uio_resid); | | 2421 | uio->uio_resid); |
2422 | while (bytes > 0) { | | 2422 | while (bytes > 0) { |
2423 | int tail = auring_tail(usrbuf); | | 2423 | int tail = auring_tail(usrbuf); |
2424 | int len = uimin(bytes, usrbuf->capacity - tail); | | 2424 | int len = uimin(bytes, usrbuf->capacity - tail); |
2425 | error = uiomove((uint8_t *)usrbuf->mem + tail, len, | | 2425 | error = uiomove((uint8_t *)usrbuf->mem + tail, len, |
2426 | uio); | | 2426 | uio); |
2427 | if (error) { | | 2427 | if (error) { |
2428 | audio_track_lock_exit(track); | | 2428 | audio_track_lock_exit(track); |
2429 | device_printf(sc->sc_dev, | | 2429 | device_printf(sc->sc_dev, |
2430 | "uiomove(len=%d) failed with %d\n", | | 2430 | "uiomove(len=%d) failed with %d\n", |
2431 | len, error); | | 2431 | len, error); |
2432 | goto abort; | | 2432 | goto abort; |
2433 | } | | 2433 | } |
2434 | auring_push(usrbuf, len); | | 2434 | auring_push(usrbuf, len); |
2435 | track->useriobytes += len; | | 2435 | track->useriobytes += len; |
2436 | TRACET(3, track, "uiomove(len=%d) usrbuf=%d/%d/C%d", | | 2436 | TRACET(3, track, "uiomove(len=%d) usrbuf=%d/%d/C%d", |
2437 | len, | | 2437 | len, |
2438 | usrbuf->head, usrbuf->used, usrbuf->capacity); | | 2438 | usrbuf->head, usrbuf->used, usrbuf->capacity); |
2439 | bytes -= len; | | 2439 | bytes -= len; |
2440 | } | | 2440 | } |
2441 | | | 2441 | |
2442 | /* Convert them as much as possible. */ | | 2442 | /* Convert them as much as possible. */ |
2443 | while (usrbuf->used >= track->usrbuf_blksize && | | 2443 | while (usrbuf->used >= track->usrbuf_blksize && |
2444 | outbuf->used < outbuf->capacity) { | | 2444 | outbuf->used < outbuf->capacity) { |
2445 | audio_track_play(track); | | 2445 | audio_track_play(track); |
2446 | } | | 2446 | } |
2447 | | | 2447 | |
2448 | audio_track_lock_exit(track); | | 2448 | audio_track_lock_exit(track); |
2449 | } | | 2449 | } |
2450 | | | 2450 | |
2451 | abort: | | 2451 | abort: |
2452 | TRACET(3, track, "done error=%d", error); | | 2452 | TRACET(3, track, "done error=%d", error); |
2453 | return error; | | 2453 | return error; |
2454 | } | | 2454 | } |
2455 | | | 2455 | |
2456 | int | | 2456 | int |
2457 | audio_ioctl(dev_t dev, struct audio_softc *sc, u_long cmd, void *addr, int flag, | | 2457 | audio_ioctl(dev_t dev, struct audio_softc *sc, u_long cmd, void *addr, int flag, |
2458 | struct lwp *l, audio_file_t *file) | | 2458 | struct lwp *l, audio_file_t *file) |
2459 | { | | 2459 | { |
2460 | struct audio_offset *ao; | | 2460 | struct audio_offset *ao; |
2461 | struct audio_info ai; | | 2461 | struct audio_info ai; |
2462 | audio_track_t *track; | | 2462 | audio_track_t *track; |
2463 | audio_encoding_t *ae; | | 2463 | audio_encoding_t *ae; |
2464 | audio_format_query_t *query; | | 2464 | audio_format_query_t *query; |
2465 | u_int stamp; | | 2465 | u_int stamp; |
2466 | u_int offs; | | 2466 | u_int offs; |
2467 | int fd; | | 2467 | int fd; |
2468 | int index; | | 2468 | int index; |
2469 | int error; | | 2469 | int error; |
2470 | | | 2470 | |
2471 | KASSERT(!mutex_owned(sc->sc_lock)); | | 2471 | KASSERT(!mutex_owned(sc->sc_lock)); |
2472 | | | 2472 | |
2473 | #if defined(AUDIO_DEBUG) | | 2473 | #if defined(AUDIO_DEBUG) |
2474 | const char *ioctlnames[] = { | | 2474 | const char *ioctlnames[] = { |
2475 | " AUDIO_GETINFO", /* 21 */ | | 2475 | " AUDIO_GETINFO", /* 21 */ |
2476 | " AUDIO_SETINFO", /* 22 */ | | 2476 | " AUDIO_SETINFO", /* 22 */ |
2477 | " AUDIO_DRAIN", /* 23 */ | | 2477 | " AUDIO_DRAIN", /* 23 */ |
2478 | " AUDIO_FLUSH", /* 24 */ | | 2478 | " AUDIO_FLUSH", /* 24 */ |
2479 | " AUDIO_WSEEK", /* 25 */ | | 2479 | " AUDIO_WSEEK", /* 25 */ |
2480 | " AUDIO_RERROR", /* 26 */ | | 2480 | " AUDIO_RERROR", /* 26 */ |
2481 | " AUDIO_GETDEV", /* 27 */ | | 2481 | " AUDIO_GETDEV", /* 27 */ |
2482 | " AUDIO_GETENC", /* 28 */ | | 2482 | " AUDIO_GETENC", /* 28 */ |
2483 | " AUDIO_GETFD", /* 29 */ | | 2483 | " AUDIO_GETFD", /* 29 */ |
2484 | " AUDIO_SETFD", /* 30 */ | | 2484 | " AUDIO_SETFD", /* 30 */ |
2485 | " AUDIO_PERROR", /* 31 */ | | 2485 | " AUDIO_PERROR", /* 31 */ |
2486 | " AUDIO_GETIOFFS", /* 32 */ | | 2486 | " AUDIO_GETIOFFS", /* 32 */ |
2487 | " AUDIO_GETOOFFS", /* 33 */ | | 2487 | " AUDIO_GETOOFFS", /* 33 */ |
2488 | " AUDIO_GETPROPS", /* 34 */ | | 2488 | " AUDIO_GETPROPS", /* 34 */ |
2489 | " AUDIO_GETBUFINFO", /* 35 */ | | 2489 | " AUDIO_GETBUFINFO", /* 35 */ |
2490 | " AUDIO_SETCHAN", /* 36 */ | | 2490 | " AUDIO_SETCHAN", /* 36 */ |
2491 | " AUDIO_GETCHAN", /* 37 */ | | 2491 | " AUDIO_GETCHAN", /* 37 */ |
2492 | " AUDIO_QUERYFORMAT", /* 38 */ | | 2492 | " AUDIO_QUERYFORMAT", /* 38 */ |
2493 | " AUDIO_GETFORMAT", /* 39 */ | | 2493 | " AUDIO_GETFORMAT", /* 39 */ |
2494 | " AUDIO_SETFORMAT", /* 40 */ | | 2494 | " AUDIO_SETFORMAT", /* 40 */ |
2495 | }; | | 2495 | }; |
2496 | int nameidx = (cmd & 0xff); | | 2496 | int nameidx = (cmd & 0xff); |
2497 | const char *ioctlname = ""; | | 2497 | const char *ioctlname = ""; |
2498 | if (21 <= nameidx && nameidx <= 21 + __arraycount(ioctlnames)) | | 2498 | if (21 <= nameidx && nameidx <= 21 + __arraycount(ioctlnames)) |
2499 | ioctlname = ioctlnames[nameidx - 21]; | | 2499 | ioctlname = ioctlnames[nameidx - 21]; |
2500 | TRACEF(2, file, "(%lu,'%c',%lu)%s pid=%d.%d", | | 2500 | TRACEF(2, file, "(%lu,'%c',%lu)%s pid=%d.%d", |
2501 | IOCPARM_LEN(cmd), (char)IOCGROUP(cmd), cmd&0xff, ioctlname, | | 2501 | IOCPARM_LEN(cmd), (char)IOCGROUP(cmd), cmd&0xff, ioctlname, |
2502 | (int)curproc->p_pid, (int)l->l_lid); | | 2502 | (int)curproc->p_pid, (int)l->l_lid); |
2503 | #endif | | 2503 | #endif |
2504 | | | 2504 | |
2505 | error = 0; | | 2505 | error = 0; |
2506 | switch (cmd) { | | 2506 | switch (cmd) { |
2507 | case FIONBIO: | | 2507 | case FIONBIO: |
2508 | /* All handled in the upper FS layer. */ | | 2508 | /* All handled in the upper FS layer. */ |
2509 | break; | | 2509 | break; |
2510 | | | 2510 | |
2511 | case FIONREAD: | | 2511 | case FIONREAD: |
2512 | /* Get the number of bytes that can be read. */ | | 2512 | /* Get the number of bytes that can be read. */ |
2513 | if (file->rtrack) { | | 2513 | if (file->rtrack) { |
2514 | *(int *)addr = audio_track_readablebytes(file->rtrack); | | 2514 | *(int *)addr = audio_track_readablebytes(file->rtrack); |
2515 | } else { | | 2515 | } else { |
2516 | *(int *)addr = 0; | | 2516 | *(int *)addr = 0; |
2517 | } | | 2517 | } |
2518 | break; | | 2518 | break; |
2519 | | | 2519 | |
2520 | case FIOASYNC: | | 2520 | case FIOASYNC: |
2521 | /* Set/Clear ASYNC I/O. */ | | 2521 | /* Set/Clear ASYNC I/O. */ |
2522 | if (*(int *)addr) { | | 2522 | if (*(int *)addr) { |
2523 | file->async_audio = curproc->p_pid; | | 2523 | file->async_audio = curproc->p_pid; |
2524 | TRACEF(2, file, "FIOASYNC pid %d", file->async_audio); | | 2524 | TRACEF(2, file, "FIOASYNC pid %d", file->async_audio); |
2525 | } else { | | 2525 | } else { |
2526 | file->async_audio = 0; | | 2526 | file->async_audio = 0; |
2527 | TRACEF(2, file, "FIOASYNC off"); | | 2527 | TRACEF(2, file, "FIOASYNC off"); |
2528 | } | | 2528 | } |
2529 | break; | | 2529 | break; |
2530 | | | 2530 | |
2531 | case AUDIO_FLUSH: | | 2531 | case AUDIO_FLUSH: |
2532 | /* XXX TODO: clear errors and restart? */ | | 2532 | /* XXX TODO: clear errors and restart? */ |
2533 | audio_file_clear(sc, file); | | 2533 | audio_file_clear(sc, file); |
2534 | break; | | 2534 | break; |
2535 | | | 2535 | |
2536 | case AUDIO_RERROR: | | 2536 | case AUDIO_RERROR: |
2537 | /* | | 2537 | /* |
2538 | * Number of read bytes dropped. We don't know where | | 2538 | * Number of read bytes dropped. We don't know where |
2539 | * or when they were dropped (including conversion stage). | | 2539 | * or when they were dropped (including conversion stage). |
2540 | * Therefore, the number of accurate bytes or samples is | | 2540 | * Therefore, the number of accurate bytes or samples is |
2541 | * also unknown. | | 2541 | * also unknown. |
2542 | */ | | 2542 | */ |
2543 | track = file->rtrack; | | 2543 | track = file->rtrack; |
2544 | if (track) { | | 2544 | if (track) { |
2545 | *(int *)addr = frametobyte(&track->usrbuf.fmt, | | 2545 | *(int *)addr = frametobyte(&track->usrbuf.fmt, |
2546 | track->dropframes); | | 2546 | track->dropframes); |
2547 | } | | 2547 | } |
2548 | break; | | 2548 | break; |
2549 | | | 2549 | |
2550 | case AUDIO_PERROR: | | 2550 | case AUDIO_PERROR: |
2551 | /* | | 2551 | /* |
2552 | * Number of write bytes dropped. We don't know where | | 2552 | * Number of write bytes dropped. We don't know where |
2553 | * or when they were dropped (including conversion stage). | | 2553 | * or when they were dropped (including conversion stage). |
2554 | * Therefore, the number of accurate bytes or samples is | | 2554 | * Therefore, the number of accurate bytes or samples is |
2555 | * also unknown. | | 2555 | * also unknown. |
2556 | */ | | 2556 | */ |
2557 | track = file->ptrack; | | 2557 | track = file->ptrack; |
2558 | if (track) { | | 2558 | if (track) { |
2559 | *(int *)addr = frametobyte(&track->usrbuf.fmt, | | 2559 | *(int *)addr = frametobyte(&track->usrbuf.fmt, |
2560 | track->dropframes); | | 2560 | track->dropframes); |
2561 | } | | 2561 | } |
2562 | break; | | 2562 | break; |
2563 | | | 2563 | |
2564 | case AUDIO_GETIOFFS: | | 2564 | case AUDIO_GETIOFFS: |
2565 | /* XXX TODO */ | | 2565 | /* XXX TODO */ |
2566 | ao = (struct audio_offset *)addr; | | 2566 | ao = (struct audio_offset *)addr; |
2567 | ao->samples = 0; | | 2567 | ao->samples = 0; |
2568 | ao->deltablks = 0; | | 2568 | ao->deltablks = 0; |
2569 | ao->offset = 0; | | 2569 | ao->offset = 0; |
2570 | break; | | 2570 | break; |
2571 | | | 2571 | |
2572 | case AUDIO_GETOOFFS: | | 2572 | case AUDIO_GETOOFFS: |
2573 | ao = (struct audio_offset *)addr; | | 2573 | ao = (struct audio_offset *)addr; |
2574 | track = file->ptrack; | | 2574 | track = file->ptrack; |
2575 | if (track == NULL) { | | 2575 | if (track == NULL) { |
2576 | ao->samples = 0; | | 2576 | ao->samples = 0; |
2577 | ao->deltablks = 0; | | 2577 | ao->deltablks = 0; |
2578 | ao->offset = 0; | | 2578 | ao->offset = 0; |
2579 | break; | | 2579 | break; |
2580 | } | | 2580 | } |
2581 | mutex_enter(sc->sc_lock); | | 2581 | mutex_enter(sc->sc_lock); |
2582 | mutex_enter(sc->sc_intr_lock); | | 2582 | mutex_enter(sc->sc_intr_lock); |
2583 | /* figure out where next DMA will start */ | | 2583 | /* figure out where next DMA will start */ |
2584 | stamp = track->usrbuf_stamp; | | 2584 | stamp = track->usrbuf_stamp; |
2585 | offs = track->usrbuf.head; | | 2585 | offs = track->usrbuf.head; |
2586 | mutex_exit(sc->sc_intr_lock); | | 2586 | mutex_exit(sc->sc_intr_lock); |
2587 | mutex_exit(sc->sc_lock); | | 2587 | mutex_exit(sc->sc_lock); |
2588 | | | 2588 | |
2589 | ao->samples = stamp; | | 2589 | ao->samples = stamp; |
2590 | ao->deltablks = (stamp / track->usrbuf_blksize) - | | 2590 | ao->deltablks = (stamp / track->usrbuf_blksize) - |
2591 | (track->usrbuf_stamp_last / track->usrbuf_blksize); | | 2591 | (track->usrbuf_stamp_last / track->usrbuf_blksize); |
2592 | track->usrbuf_stamp_last = stamp; | | 2592 | track->usrbuf_stamp_last = stamp; |
2593 | offs = rounddown(offs, track->usrbuf_blksize) | | 2593 | offs = rounddown(offs, track->usrbuf_blksize) |
2594 | + track->usrbuf_blksize; | | 2594 | + track->usrbuf_blksize; |
2595 | if (offs >= track->usrbuf.capacity) | | 2595 | if (offs >= track->usrbuf.capacity) |
2596 | offs -= track->usrbuf.capacity; | | 2596 | offs -= track->usrbuf.capacity; |
2597 | ao->offset = offs; | | 2597 | ao->offset = offs; |
2598 | | | 2598 | |
2599 | TRACET(3, track, "GETOOFFS: samples=%u deltablks=%u offset=%u", | | 2599 | TRACET(3, track, "GETOOFFS: samples=%u deltablks=%u offset=%u", |
2600 | ao->samples, ao->deltablks, ao->offset); | | 2600 | ao->samples, ao->deltablks, ao->offset); |
2601 | break; | | 2601 | break; |
2602 | | | 2602 | |
2603 | case AUDIO_WSEEK: | | 2603 | case AUDIO_WSEEK: |
2604 | /* XXX return value does not include outbuf one. */ | | 2604 | /* XXX return value does not include outbuf one. */ |
2605 | if (file->ptrack) | | 2605 | if (file->ptrack) |
2606 | *(u_long *)addr = file->ptrack->usrbuf.used; | | 2606 | *(u_long *)addr = file->ptrack->usrbuf.used; |
2607 | break; | | 2607 | break; |
2608 | | | 2608 | |
2609 | case AUDIO_SETINFO: | | 2609 | case AUDIO_SETINFO: |
2610 | error = audio_enter_exclusive(sc); | | 2610 | error = audio_enter_exclusive(sc); |
2611 | if (error) | | 2611 | if (error) |
2612 | break; | | 2612 | break; |
2613 | error = audio_file_setinfo(sc, file, (struct audio_info *)addr); | | 2613 | error = audio_file_setinfo(sc, file, (struct audio_info *)addr); |
2614 | if (error) { | | 2614 | if (error) { |
2615 | audio_exit_exclusive(sc); | | 2615 | audio_exit_exclusive(sc); |
2616 | break; | | 2616 | break; |
2617 | } | | 2617 | } |
2618 | /* XXX TODO: update last_ai if /dev/sound ? */ | | 2618 | /* XXX TODO: update last_ai if /dev/sound ? */ |
2619 | if (ISDEVSOUND(dev)) | | 2619 | if (ISDEVSOUND(dev)) |
2620 | error = audiogetinfo(sc, &sc->sc_ai, 0, file); | | 2620 | error = audiogetinfo(sc, &sc->sc_ai, 0, file); |
2621 | audio_exit_exclusive(sc); | | 2621 | audio_exit_exclusive(sc); |
2622 | break; | | 2622 | break; |
2623 | | | 2623 | |
2624 | case AUDIO_GETINFO: | | 2624 | case AUDIO_GETINFO: |
2625 | error = audio_enter_exclusive(sc); | | 2625 | error = audio_enter_exclusive(sc); |
2626 | if (error) | | 2626 | if (error) |
2627 | break; | | 2627 | break; |
2628 | error = audiogetinfo(sc, (struct audio_info *)addr, 1, file); | | 2628 | error = audiogetinfo(sc, (struct audio_info *)addr, 1, file); |
2629 | audio_exit_exclusive(sc); | | 2629 | audio_exit_exclusive(sc); |
2630 | break; | | 2630 | break; |
2631 | | | 2631 | |
2632 | case AUDIO_GETBUFINFO: | | 2632 | case AUDIO_GETBUFINFO: |
2633 | mutex_enter(sc->sc_lock); | | 2633 | mutex_enter(sc->sc_lock); |
2634 | error = audiogetinfo(sc, (struct audio_info *)addr, 0, file); | | 2634 | error = audiogetinfo(sc, (struct audio_info *)addr, 0, file); |
2635 | mutex_exit(sc->sc_lock); | | 2635 | mutex_exit(sc->sc_lock); |
2636 | break; | | 2636 | break; |
2637 | | | 2637 | |
2638 | case AUDIO_DRAIN: | | 2638 | case AUDIO_DRAIN: |
2639 | if (file->ptrack) { | | 2639 | if (file->ptrack) { |
2640 | mutex_enter(sc->sc_lock); | | 2640 | mutex_enter(sc->sc_lock); |
2641 | error = audio_track_drain(sc, file->ptrack); | | 2641 | error = audio_track_drain(sc, file->ptrack); |
2642 | mutex_exit(sc->sc_lock); | | 2642 | mutex_exit(sc->sc_lock); |
2643 | } | | 2643 | } |
2644 | break; | | 2644 | break; |
2645 | | | 2645 | |
2646 | case AUDIO_GETDEV: | | 2646 | case AUDIO_GETDEV: |
2647 | mutex_enter(sc->sc_lock); | | 2647 | mutex_enter(sc->sc_lock); |
2648 | error = sc->hw_if->getdev(sc->hw_hdl, (audio_device_t *)addr); | | 2648 | error = sc->hw_if->getdev(sc->hw_hdl, (audio_device_t *)addr); |
2649 | mutex_exit(sc->sc_lock); | | 2649 | mutex_exit(sc->sc_lock); |
2650 | break; | | 2650 | break; |
2651 | | | 2651 | |
2652 | case AUDIO_GETENC: | | 2652 | case AUDIO_GETENC: |
2653 | ae = (audio_encoding_t *)addr; | | 2653 | ae = (audio_encoding_t *)addr; |
2654 | index = ae->index; | | 2654 | index = ae->index; |
2655 | if (index < 0 || index >= __arraycount(audio_encodings)) { | | 2655 | if (index < 0 || index >= __arraycount(audio_encodings)) { |
2656 | error = EINVAL; | | 2656 | error = EINVAL; |
2657 | break; | | 2657 | break; |
2658 | } | | 2658 | } |
2659 | *ae = audio_encodings[index]; | | 2659 | *ae = audio_encodings[index]; |
2660 | ae->index = index; | | 2660 | ae->index = index; |
2661 | /* | | 2661 | /* |
2662 | * EMULATED always. | | 2662 | * EMULATED always. |
2663 | * EMULATED flag at that time used to mean that it could | | 2663 | * EMULATED flag at that time used to mean that it could |
2664 | * not be passed directly to the hardware as-is. But | | 2664 | * not be passed directly to the hardware as-is. But |
2665 | * currently, all formats including hardware native is not | | 2665 | * currently, all formats including hardware native is not |
2666 | * passed directly to the hardware. So I set EMULATED | | 2666 | * passed directly to the hardware. So I set EMULATED |
2667 | * flag for all formats. | | 2667 | * flag for all formats. |
2668 | */ | | 2668 | */ |
2669 | ae->flags = AUDIO_ENCODINGFLAG_EMULATED; | | 2669 | ae->flags = AUDIO_ENCODINGFLAG_EMULATED; |
2670 | break; | | 2670 | break; |
2671 | | | 2671 | |
2672 | case AUDIO_GETFD: | | 2672 | case AUDIO_GETFD: |
2673 | /* | | 2673 | /* |
2674 | * Returns the current setting of full duplex mode. | | 2674 | * Returns the current setting of full duplex mode. |
2675 | * If HW has full duplex mode and there are two mixers, | | 2675 | * If HW has full duplex mode and there are two mixers, |
2676 | * it is full duplex. Otherwise half duplex. | | 2676 | * it is full duplex. Otherwise half duplex. |
2677 | */ | | 2677 | */ |
2678 | mutex_enter(sc->sc_lock); | | 2678 | mutex_enter(sc->sc_lock); |
2679 | fd = (sc->sc_props & AUDIO_PROP_FULLDUPLEX) | | 2679 | fd = (sc->sc_props & AUDIO_PROP_FULLDUPLEX) |
2680 | && (sc->sc_pmixer && sc->sc_rmixer); | | 2680 | && (sc->sc_pmixer && sc->sc_rmixer); |
2681 | mutex_exit(sc->sc_lock); | | 2681 | mutex_exit(sc->sc_lock); |
2682 | *(int *)addr = fd; | | 2682 | *(int *)addr = fd; |
2683 | break; | | 2683 | break; |
2684 | | | 2684 | |
2685 | case AUDIO_GETPROPS: | | 2685 | case AUDIO_GETPROPS: |
2686 | *(int *)addr = sc->sc_props; | | 2686 | *(int *)addr = sc->sc_props; |
2687 | break; | | 2687 | break; |
2688 | | | 2688 | |
2689 | case AUDIO_QUERYFORMAT: | | 2689 | case AUDIO_QUERYFORMAT: |
2690 | query = (audio_format_query_t *)addr; | | 2690 | query = (audio_format_query_t *)addr; |
2691 | if (sc->hw_if->query_format) { | | 2691 | if (sc->hw_if->query_format) { |
2692 | mutex_enter(sc->sc_lock); | | 2692 | mutex_enter(sc->sc_lock); |
2693 | error = sc->hw_if->query_format(sc->hw_hdl, query); | | 2693 | error = sc->hw_if->query_format(sc->hw_hdl, query); |
2694 | mutex_exit(sc->sc_lock); | | 2694 | mutex_exit(sc->sc_lock); |
2695 | /* Hide internal infomations */ | | 2695 | /* Hide internal infomations */ |
2696 | query->fmt.driver_data = NULL; | | 2696 | query->fmt.driver_data = NULL; |
2697 | } else { | | 2697 | } else { |
2698 | error = ENODEV; | | 2698 | error = ENODEV; |
2699 | } | | 2699 | } |
2700 | break; | | 2700 | break; |
2701 | | | 2701 | |
2702 | case AUDIO_GETFORMAT: | | 2702 | case AUDIO_GETFORMAT: |
2703 | audio_mixers_get_format(sc, (struct audio_info *)addr); | | 2703 | audio_mixers_get_format(sc, (struct audio_info *)addr); |
2704 | break; | | 2704 | break; |
2705 | | | 2705 | |
2706 | case AUDIO_SETFORMAT: | | 2706 | case AUDIO_SETFORMAT: |
2707 | mutex_enter(sc->sc_lock); | | 2707 | mutex_enter(sc->sc_lock); |
2708 | audio_mixers_get_format(sc, &ai); | | 2708 | audio_mixers_get_format(sc, &ai); |
2709 | error = audio_mixers_set_format(sc, (struct audio_info *)addr); | | 2709 | error = audio_mixers_set_format(sc, (struct audio_info *)addr); |
2710 | if (error) { | | 2710 | if (error) { |
2711 | /* Rollback */ | | 2711 | /* Rollback */ |
2712 | audio_mixers_set_format(sc, &ai); | | 2712 | audio_mixers_set_format(sc, &ai); |
2713 | } | | 2713 | } |
2714 | mutex_exit(sc->sc_lock); | | 2714 | mutex_exit(sc->sc_lock); |
2715 | break; | | 2715 | break; |
2716 | | | 2716 | |
2717 | case AUDIO_SETFD: | | 2717 | case AUDIO_SETFD: |
2718 | case AUDIO_SETCHAN: | | 2718 | case AUDIO_SETCHAN: |
2719 | case AUDIO_GETCHAN: | | 2719 | case AUDIO_GETCHAN: |
2720 | /* Obsoleted */ | | 2720 | /* Obsoleted */ |
2721 | break; | | 2721 | break; |
2722 | | | 2722 | |
2723 | default: | | 2723 | default: |
2724 | if (sc->hw_if->dev_ioctl) { | | 2724 | if (sc->hw_if->dev_ioctl) { |
2725 | error = audio_enter_exclusive(sc); | | 2725 | error = audio_enter_exclusive(sc); |
2726 | if (error) | | 2726 | if (error) |
2727 | break; | | 2727 | break; |
2728 | error = sc->hw_if->dev_ioctl(sc->hw_hdl, | | 2728 | error = sc->hw_if->dev_ioctl(sc->hw_hdl, |
2729 | cmd, addr, flag, l); | | 2729 | cmd, addr, flag, l); |
2730 | audio_exit_exclusive(sc); | | 2730 | audio_exit_exclusive(sc); |
2731 | } else { | | 2731 | } else { |
2732 | TRACEF(2, file, "unknown ioctl"); | | 2732 | TRACEF(2, file, "unknown ioctl"); |
2733 | error = EINVAL; | | 2733 | error = EINVAL; |
2734 | } | | 2734 | } |
2735 | break; | | 2735 | break; |
2736 | } | | 2736 | } |
2737 | TRACEF(2, file, "(%lu,'%c',%lu)%s result %d", | | 2737 | TRACEF(2, file, "(%lu,'%c',%lu)%s result %d", |
2738 | IOCPARM_LEN(cmd), (char)IOCGROUP(cmd), cmd&0xff, ioctlname, | | 2738 | IOCPARM_LEN(cmd), (char)IOCGROUP(cmd), cmd&0xff, ioctlname, |
2739 | error); | | 2739 | error); |
2740 | return error; | | 2740 | return error; |
2741 | } | | 2741 | } |
2742 | | | 2742 | |
2743 | /* | | 2743 | /* |
2744 | * Returns the number of bytes that can be read on recording buffer. | | 2744 | * Returns the number of bytes that can be read on recording buffer. |
2745 | */ | | 2745 | */ |
2746 | static __inline int | | 2746 | static __inline int |
2747 | audio_track_readablebytes(const audio_track_t *track) | | 2747 | audio_track_readablebytes(const audio_track_t *track) |
2748 | { | | 2748 | { |
2749 | int bytes; | | 2749 | int bytes; |
2750 | | | 2750 | |
2751 | KASSERT(track); | | 2751 | KASSERT(track); |
2752 | KASSERT(track->mode == AUMODE_RECORD); | | 2752 | KASSERT(track->mode == AUMODE_RECORD); |
2753 | | | 2753 | |
2754 | /* | | 2754 | /* |
2755 | * Although usrbuf is primarily readable data, recorded data | | 2755 | * Although usrbuf is primarily readable data, recorded data |
2756 | * also stays in track->input until reading. So it is necessary | | 2756 | * also stays in track->input until reading. So it is necessary |
2757 | * to add it. track->input is in frame, usrbuf is in byte. | | 2757 | * to add it. track->input is in frame, usrbuf is in byte. |
2758 | */ | | 2758 | */ |
2759 | bytes = track->usrbuf.used + | | 2759 | bytes = track->usrbuf.used + |
2760 | track->input->used * frametobyte(&track->usrbuf.fmt, 1); | | 2760 | track->input->used * frametobyte(&track->usrbuf.fmt, 1); |
2761 | return bytes; | | 2761 | return bytes; |
2762 | } | | 2762 | } |
2763 | | | 2763 | |
2764 | int | | 2764 | int |
2765 | audio_poll(struct audio_softc *sc, int events, struct lwp *l, | | 2765 | audio_poll(struct audio_softc *sc, int events, struct lwp *l, |
2766 | audio_file_t *file) | | 2766 | audio_file_t *file) |
2767 | { | | 2767 | { |
2768 | audio_track_t *track; | | 2768 | audio_track_t *track; |
2769 | int revents; | | 2769 | int revents; |
2770 | bool in_is_valid; | | 2770 | bool in_is_valid; |
2771 | bool out_is_valid; | | 2771 | bool out_is_valid; |
2772 | | | 2772 | |
2773 | KASSERT(!mutex_owned(sc->sc_lock)); | | 2773 | KASSERT(!mutex_owned(sc->sc_lock)); |
2774 | | | 2774 | |
2775 | #if defined(AUDIO_DEBUG) | | 2775 | #if defined(AUDIO_DEBUG) |
2776 | #define POLLEV_BITMAP "\177\020" \ | | 2776 | #define POLLEV_BITMAP "\177\020" \ |
2777 | "b\10WRBAND\0" \ | | 2777 | "b\10WRBAND\0" \ |
2778 | "b\7RDBAND\0" "b\6RDNORM\0" "b\5NVAL\0" "b\4HUP\0" \ | | 2778 | "b\7RDBAND\0" "b\6RDNORM\0" "b\5NVAL\0" "b\4HUP\0" \ |
2779 | "b\3ERR\0" "b\2OUT\0" "b\1PRI\0" "b\0IN\0" | | 2779 | "b\3ERR\0" "b\2OUT\0" "b\1PRI\0" "b\0IN\0" |
2780 | char evbuf[64]; | | 2780 | char evbuf[64]; |
2781 | snprintb(evbuf, sizeof(evbuf), POLLEV_BITMAP, events); | | 2781 | snprintb(evbuf, sizeof(evbuf), POLLEV_BITMAP, events); |
2782 | TRACEF(2, file, "pid=%d.%d events=%s", | | 2782 | TRACEF(2, file, "pid=%d.%d events=%s", |
2783 | (int)curproc->p_pid, (int)l->l_lid, evbuf); | | 2783 | (int)curproc->p_pid, (int)l->l_lid, evbuf); |
2784 | #endif | | 2784 | #endif |
2785 | | | 2785 | |
2786 | revents = 0; | | 2786 | revents = 0; |
2787 | in_is_valid = false; | | 2787 | in_is_valid = false; |
2788 | out_is_valid = false; | | 2788 | out_is_valid = false; |
2789 | if (events & (POLLIN | POLLRDNORM)) { | | 2789 | if (events & (POLLIN | POLLRDNORM)) { |
2790 | track = file->rtrack; | | 2790 | track = file->rtrack; |
2791 | if (track) { | | 2791 | if (track) { |
2792 | int used; | | 2792 | int used; |
2793 | in_is_valid = true; | | 2793 | in_is_valid = true; |
2794 | used = audio_track_readablebytes(track); | | 2794 | used = audio_track_readablebytes(track); |
2795 | if (used > 0) | | 2795 | if (used > 0) |
2796 | revents |= events & (POLLIN | POLLRDNORM); | | 2796 | revents |= events & (POLLIN | POLLRDNORM); |
2797 | } | | 2797 | } |
2798 | } | | 2798 | } |
2799 | if (events & (POLLOUT | POLLWRNORM)) { | | 2799 | if (events & (POLLOUT | POLLWRNORM)) { |
2800 | track = file->ptrack; | | 2800 | track = file->ptrack; |
2801 | if (track) { | | 2801 | if (track) { |
2802 | out_is_valid = true; | | 2802 | out_is_valid = true; |
2803 | if (track->usrbuf.used <= track->usrbuf_usedlow) | | 2803 | if (track->usrbuf.used <= track->usrbuf_usedlow) |
2804 | revents |= events & (POLLOUT | POLLWRNORM); | | 2804 | revents |= events & (POLLOUT | POLLWRNORM); |
2805 | } | | 2805 | } |
2806 | } | | 2806 | } |
2807 | | | 2807 | |
2808 | if (revents == 0) { | | 2808 | if (revents == 0) { |
2809 | mutex_enter(sc->sc_lock); | | 2809 | mutex_enter(sc->sc_lock); |
2810 | if (in_is_valid) { | | 2810 | if (in_is_valid) { |
2811 | TRACEF(3, file, "selrecord rsel"); | | 2811 | TRACEF(3, file, "selrecord rsel"); |
2812 | selrecord(l, &sc->sc_rsel); | | 2812 | selrecord(l, &sc->sc_rsel); |
2813 | } | | 2813 | } |
2814 | if (out_is_valid) { | | 2814 | if (out_is_valid) { |
2815 | TRACEF(3, file, "selrecord wsel"); | | 2815 | TRACEF(3, file, "selrecord wsel"); |
2816 | selrecord(l, &sc->sc_wsel); | | 2816 | selrecord(l, &sc->sc_wsel); |
2817 | } | | 2817 | } |
2818 | mutex_exit(sc->sc_lock); | | 2818 | mutex_exit(sc->sc_lock); |
2819 | } | | 2819 | } |
2820 | | | 2820 | |
2821 | #if defined(AUDIO_DEBUG) | | 2821 | #if defined(AUDIO_DEBUG) |
2822 | snprintb(evbuf, sizeof(evbuf), POLLEV_BITMAP, revents); | | 2822 | snprintb(evbuf, sizeof(evbuf), POLLEV_BITMAP, revents); |
2823 | TRACEF(2, file, "revents=%s", evbuf); | | 2823 | TRACEF(2, file, "revents=%s", evbuf); |
2824 | #endif | | 2824 | #endif |
2825 | return revents; | | 2825 | return revents; |
2826 | } | | 2826 | } |
2827 | | | 2827 | |
2828 | static const struct filterops audioread_filtops = { | | 2828 | static const struct filterops audioread_filtops = { |
2829 | .f_isfd = 1, | | 2829 | .f_isfd = 1, |
2830 | .f_attach = NULL, | | 2830 | .f_attach = NULL, |
2831 | .f_detach = filt_audioread_detach, | | 2831 | .f_detach = filt_audioread_detach, |
2832 | .f_event = filt_audioread_event, | | 2832 | .f_event = filt_audioread_event, |
2833 | }; | | 2833 | }; |
2834 | | | 2834 | |
2835 | static void | | 2835 | static void |
2836 | filt_audioread_detach(struct knote *kn) | | 2836 | filt_audioread_detach(struct knote *kn) |
2837 | { | | 2837 | { |
2838 | struct audio_softc *sc; | | 2838 | struct audio_softc *sc; |
2839 | audio_file_t *file; | | 2839 | audio_file_t *file; |
2840 | | | 2840 | |
2841 | file = kn->kn_hook; | | 2841 | file = kn->kn_hook; |
2842 | sc = file->sc; | | 2842 | sc = file->sc; |
2843 | TRACEF(3, file, ""); | | 2843 | TRACEF(3, file, ""); |
2844 | | | 2844 | |
2845 | mutex_enter(sc->sc_lock); | | 2845 | mutex_enter(sc->sc_lock); |
2846 | SLIST_REMOVE(&sc->sc_rsel.sel_klist, kn, knote, kn_selnext); | | 2846 | SLIST_REMOVE(&sc->sc_rsel.sel_klist, kn, knote, kn_selnext); |
2847 | mutex_exit(sc->sc_lock); | | 2847 | mutex_exit(sc->sc_lock); |
2848 | } | | 2848 | } |
2849 | | | 2849 | |
2850 | static int | | 2850 | static int |
2851 | filt_audioread_event(struct knote *kn, long hint) | | 2851 | filt_audioread_event(struct knote *kn, long hint) |
2852 | { | | 2852 | { |
2853 | audio_file_t *file; | | 2853 | audio_file_t *file; |
2854 | audio_track_t *track; | | 2854 | audio_track_t *track; |
2855 | | | 2855 | |
2856 | file = kn->kn_hook; | | 2856 | file = kn->kn_hook; |
2857 | track = file->rtrack; | | 2857 | track = file->rtrack; |
2858 | | | 2858 | |
2859 | /* | | 2859 | /* |
2860 | * kn_data must contain the number of bytes can be read. | | 2860 | * kn_data must contain the number of bytes can be read. |
2861 | * The return value indicates whether the event occurs or not. | | 2861 | * The return value indicates whether the event occurs or not. |
2862 | */ | | 2862 | */ |
2863 | | | 2863 | |
2864 | if (track == NULL) { | | 2864 | if (track == NULL) { |
2865 | /* can not read with this descriptor. */ | | 2865 | /* can not read with this descriptor. */ |
2866 | kn->kn_data = 0; | | 2866 | kn->kn_data = 0; |
2867 | return 0; | | 2867 | return 0; |
2868 | } | | 2868 | } |
2869 | | | 2869 | |
2870 | kn->kn_data = audio_track_readablebytes(track); | | 2870 | kn->kn_data = audio_track_readablebytes(track); |
2871 | TRACEF(3, file, "data=%" PRId64, kn->kn_data); | | 2871 | TRACEF(3, file, "data=%" PRId64, kn->kn_data); |
2872 | return kn->kn_data > 0; | | 2872 | return kn->kn_data > 0; |
2873 | } | | 2873 | } |
2874 | | | 2874 | |
2875 | static const struct filterops audiowrite_filtops = { | | 2875 | static const struct filterops audiowrite_filtops = { |
2876 | .f_isfd = 1, | | 2876 | .f_isfd = 1, |
2877 | .f_attach = NULL, | | 2877 | .f_attach = NULL, |
2878 | .f_detach = filt_audiowrite_detach, | | 2878 | .f_detach = filt_audiowrite_detach, |
2879 | .f_event = filt_audiowrite_event, | | 2879 | .f_event = filt_audiowrite_event, |
2880 | }; | | 2880 | }; |
2881 | | | 2881 | |
2882 | static void | | 2882 | static void |
2883 | filt_audiowrite_detach(struct knote *kn) | | 2883 | filt_audiowrite_detach(struct knote *kn) |
2884 | { | | 2884 | { |
2885 | struct audio_softc *sc; | | 2885 | struct audio_softc *sc; |
2886 | audio_file_t *file; | | 2886 | audio_file_t *file; |
2887 | | | 2887 | |
2888 | file = kn->kn_hook; | | 2888 | file = kn->kn_hook; |
2889 | sc = file->sc; | | 2889 | sc = file->sc; |
2890 | TRACEF(3, file, ""); | | 2890 | TRACEF(3, file, ""); |
2891 | | | 2891 | |
2892 | mutex_enter(sc->sc_lock); | | 2892 | mutex_enter(sc->sc_lock); |
2893 | SLIST_REMOVE(&sc->sc_wsel.sel_klist, kn, knote, kn_selnext); | | 2893 | SLIST_REMOVE(&sc->sc_wsel.sel_klist, kn, knote, kn_selnext); |
2894 | mutex_exit(sc->sc_lock); | | 2894 | mutex_exit(sc->sc_lock); |
2895 | } | | 2895 | } |
2896 | | | 2896 | |
2897 | static int | | 2897 | static int |
2898 | filt_audiowrite_event(struct knote *kn, long hint) | | 2898 | filt_audiowrite_event(struct knote *kn, long hint) |
2899 | { | | 2899 | { |
2900 | audio_file_t *file; | | 2900 | audio_file_t *file; |
2901 | audio_track_t *track; | | 2901 | audio_track_t *track; |
2902 | | | 2902 | |
2903 | file = kn->kn_hook; | | 2903 | file = kn->kn_hook; |
2904 | track = file->ptrack; | | 2904 | track = file->ptrack; |
2905 | | | 2905 | |
2906 | /* | | 2906 | /* |
2907 | * kn_data must contain the number of bytes can be write. | | 2907 | * kn_data must contain the number of bytes can be write. |
2908 | * The return value indicates whether the event occurs or not. | | 2908 | * The return value indicates whether the event occurs or not. |
2909 | */ | | 2909 | */ |
2910 | | | 2910 | |
2911 | if (track == NULL) { | | 2911 | if (track == NULL) { |
2912 | /* can not write with this descriptor. */ | | 2912 | /* can not write with this descriptor. */ |
2913 | kn->kn_data = 0; | | 2913 | kn->kn_data = 0; |
2914 | return 0; | | 2914 | return 0; |
2915 | } | | 2915 | } |
2916 | | | 2916 | |
2917 | kn->kn_data = track->usrbuf_usedhigh - track->usrbuf.used; | | 2917 | kn->kn_data = track->usrbuf_usedhigh - track->usrbuf.used; |
2918 | TRACEF(3, file, "data=%" PRId64, kn->kn_data); | | 2918 | TRACEF(3, file, "data=%" PRId64, kn->kn_data); |
2919 | return (track->usrbuf.used < track->usrbuf_usedlow); | | 2919 | return (track->usrbuf.used < track->usrbuf_usedlow); |
2920 | } | | 2920 | } |
2921 | | | 2921 | |
2922 | int | | 2922 | int |
2923 | audio_kqfilter(struct audio_softc *sc, audio_file_t *file, struct knote *kn) | | 2923 | audio_kqfilter(struct audio_softc *sc, audio_file_t *file, struct knote *kn) |
2924 | { | | 2924 | { |
2925 | struct klist *klist; | | 2925 | struct klist *klist; |
2926 | | | 2926 | |
2927 | KASSERT(!mutex_owned(sc->sc_lock)); | | 2927 | KASSERT(!mutex_owned(sc->sc_lock)); |
2928 | | | 2928 | |
2929 | TRACEF(3, file, "kn=%p kn_filter=%x", kn, (int)kn->kn_filter); | | 2929 | TRACEF(3, file, "kn=%p kn_filter=%x", kn, (int)kn->kn_filter); |
2930 | | | 2930 | |
2931 | switch (kn->kn_filter) { | | 2931 | switch (kn->kn_filter) { |
2932 | case EVFILT_READ: | | 2932 | case EVFILT_READ: |
2933 | klist = &sc->sc_rsel.sel_klist; | | 2933 | klist = &sc->sc_rsel.sel_klist; |
2934 | kn->kn_fop = &audioread_filtops; | | 2934 | kn->kn_fop = &audioread_filtops; |
2935 | break; | | 2935 | break; |
2936 | | | 2936 | |
2937 | case EVFILT_WRITE: | | 2937 | case EVFILT_WRITE: |
2938 | klist = &sc->sc_wsel.sel_klist; | | 2938 | klist = &sc->sc_wsel.sel_klist; |
2939 | kn->kn_fop = &audiowrite_filtops; | | 2939 | kn->kn_fop = &audiowrite_filtops; |
2940 | break; | | 2940 | break; |
2941 | | | 2941 | |
2942 | default: | | 2942 | default: |
2943 | return EINVAL; | | 2943 | return EINVAL; |
2944 | } | | 2944 | } |
2945 | | | 2945 | |
2946 | kn->kn_hook = file; | | 2946 | kn->kn_hook = file; |
2947 | | | 2947 | |
2948 | mutex_enter(sc->sc_lock); | | 2948 | mutex_enter(sc->sc_lock); |
2949 | SLIST_INSERT_HEAD(klist, kn, kn_selnext); | | 2949 | SLIST_INSERT_HEAD(klist, kn, kn_selnext); |
2950 | mutex_exit(sc->sc_lock); | | 2950 | mutex_exit(sc->sc_lock); |
2951 | | | 2951 | |
2952 | return 0; | | 2952 | return 0; |
2953 | } | | 2953 | } |
2954 | | | 2954 | |
2955 | int | | 2955 | int |
2956 | audio_mmap(struct audio_softc *sc, off_t *offp, size_t len, int prot, | | 2956 | audio_mmap(struct audio_softc *sc, off_t *offp, size_t len, int prot, |
2957 | int *flagsp, int *advicep, struct uvm_object **uobjp, int *maxprotp, | | 2957 | int *flagsp, int *advicep, struct uvm_object **uobjp, int *maxprotp, |
2958 | audio_file_t *file) | | 2958 | audio_file_t *file) |
2959 | { | | 2959 | { |
2960 | audio_track_t *track; | | 2960 | audio_track_t *track; |
2961 | vsize_t vsize; | | 2961 | vsize_t vsize; |
2962 | int error; | | 2962 | int error; |
2963 | | | 2963 | |
2964 | KASSERT(!mutex_owned(sc->sc_lock)); | | 2964 | KASSERT(!mutex_owned(sc->sc_lock)); |
2965 | | | 2965 | |
2966 | TRACEF(2, file, "off=%lld, prot=%d", (long long)(*offp), prot); | | 2966 | TRACEF(2, file, "off=%lld, prot=%d", (long long)(*offp), prot); |
2967 | | | 2967 | |
2968 | if (*offp < 0) | | 2968 | if (*offp < 0) |
2969 | return EINVAL; | | 2969 | return EINVAL; |
2970 | | | 2970 | |
2971 | #if 0 | | 2971 | #if 0 |
2972 | /* XXX | | 2972 | /* XXX |
2973 | * The idea here was to use the protection to determine if | | 2973 | * The idea here was to use the protection to determine if |
2974 | * we are mapping the read or write buffer, but it fails. | | 2974 | * we are mapping the read or write buffer, but it fails. |
2975 | * The VM system is broken in (at least) two ways. | | 2975 | * The VM system is broken in (at least) two ways. |
2976 | * 1) If you map memory VM_PROT_WRITE you SIGSEGV | | 2976 | * 1) If you map memory VM_PROT_WRITE you SIGSEGV |
2977 | * when writing to it, so VM_PROT_READ|VM_PROT_WRITE | | 2977 | * when writing to it, so VM_PROT_READ|VM_PROT_WRITE |
2978 | * has to be used for mmapping the play buffer. | | 2978 | * has to be used for mmapping the play buffer. |
2979 | * 2) Even if calling mmap() with VM_PROT_READ|VM_PROT_WRITE | | 2979 | * 2) Even if calling mmap() with VM_PROT_READ|VM_PROT_WRITE |
2980 | * audio_mmap will get called at some point with VM_PROT_READ | | 2980 | * audio_mmap will get called at some point with VM_PROT_READ |
2981 | * only. | | 2981 | * only. |
2982 | * So, alas, we always map the play buffer for now. | | 2982 | * So, alas, we always map the play buffer for now. |
2983 | */ | | 2983 | */ |
2984 | if (prot == (VM_PROT_READ|VM_PROT_WRITE) || | | 2984 | if (prot == (VM_PROT_READ|VM_PROT_WRITE) || |
2985 | prot == VM_PROT_WRITE) | | 2985 | prot == VM_PROT_WRITE) |
2986 | track = file->ptrack; | | 2986 | track = file->ptrack; |
2987 | else if (prot == VM_PROT_READ) | | 2987 | else if (prot == VM_PROT_READ) |
2988 | track = file->rtrack; | | 2988 | track = file->rtrack; |
2989 | else | | 2989 | else |
2990 | return EINVAL; | | 2990 | return EINVAL; |
2991 | #else | | 2991 | #else |
2992 | track = file->ptrack; | | 2992 | track = file->ptrack; |
2993 | #endif | | 2993 | #endif |
2994 | if (track == NULL) | | 2994 | if (track == NULL) |
2995 | return EACCES; | | 2995 | return EACCES; |
2996 | | | 2996 | |
2997 | vsize = roundup2(MAX(track->usrbuf.capacity, PAGE_SIZE), PAGE_SIZE); | | 2997 | vsize = roundup2(MAX(track->usrbuf.capacity, PAGE_SIZE), PAGE_SIZE); |
2998 | if (len > vsize) | | 2998 | if (len > vsize) |
2999 | return EOVERFLOW; | | 2999 | return EOVERFLOW; |
3000 | if (*offp > (uint)(vsize - len)) | | 3000 | if (*offp > (uint)(vsize - len)) |
3001 | return EOVERFLOW; | | 3001 | return EOVERFLOW; |
3002 | | | 3002 | |
3003 | /* XXX TODO: what happens when mmap twice. */ | | 3003 | /* XXX TODO: what happens when mmap twice. */ |
3004 | if (!track->mmapped) { | | 3004 | if (!track->mmapped) { |
3005 | track->mmapped = true; | | 3005 | track->mmapped = true; |
3006 | | | 3006 | |
3007 | if (!track->is_pause) { | | 3007 | if (!track->is_pause) { |
3008 | error = audio_enter_exclusive(sc); | | 3008 | error = audio_enter_exclusive(sc); |
3009 | if (error) | | 3009 | if (error) |
3010 | return error; | | 3010 | return error; |
3011 | if (sc->sc_pbusy == false) | | 3011 | if (sc->sc_pbusy == false) |
3012 | audio_pmixer_start(sc, true); | | 3012 | audio_pmixer_start(sc, true); |
3013 | audio_exit_exclusive(sc); | | 3013 | audio_exit_exclusive(sc); |
3014 | } | | 3014 | } |
3015 | /* XXX mmapping record buffer is not supported */ | | 3015 | /* XXX mmapping record buffer is not supported */ |
3016 | } | | 3016 | } |
3017 | | | 3017 | |
3018 | /* get ringbuffer */ | | 3018 | /* get ringbuffer */ |
3019 | *uobjp = track->uobj; | | 3019 | *uobjp = track->uobj; |
3020 | | | 3020 | |
3021 | /* Acquire a reference for the mmap. munmap will release. */ | | 3021 | /* Acquire a reference for the mmap. munmap will release. */ |
3022 | uao_reference(*uobjp); | | 3022 | uao_reference(*uobjp); |
3023 | *maxprotp = prot; | | 3023 | *maxprotp = prot; |
3024 | *advicep = UVM_ADV_RANDOM; | | 3024 | *advicep = UVM_ADV_RANDOM; |
3025 | *flagsp = MAP_SHARED; | | 3025 | *flagsp = MAP_SHARED; |
3026 | return 0; | | 3026 | return 0; |
3027 | } | | 3027 | } |
3028 | | | 3028 | |
3029 | /* | | 3029 | /* |
3030 | * /dev/audioctl has to be able to open at any time without interference | | 3030 | * /dev/audioctl has to be able to open at any time without interference |
3031 | * with any /dev/audio or /dev/sound. | | 3031 | * with any /dev/audio or /dev/sound. |
3032 | */ | | 3032 | */ |
3033 | static int | | 3033 | static int |
3034 | audioctl_open(dev_t dev, struct audio_softc *sc, int flags, int ifmt, | | 3034 | audioctl_open(dev_t dev, struct audio_softc *sc, int flags, int ifmt, |
3035 | struct lwp *l) | | 3035 | struct lwp *l) |
3036 | { | | 3036 | { |
3037 | struct file *fp; | | 3037 | struct file *fp; |
3038 | audio_file_t *af; | | 3038 | audio_file_t *af; |
3039 | int fd; | | 3039 | int fd; |
3040 | int error; | | 3040 | int error; |
3041 | | | 3041 | |
3042 | KASSERT(mutex_owned(sc->sc_lock)); | | 3042 | KASSERT(mutex_owned(sc->sc_lock)); |
3043 | KASSERT(sc->sc_exlock); | | 3043 | KASSERT(sc->sc_exlock); |
3044 | | | 3044 | |
3045 | TRACE(1, ""); | | 3045 | TRACE(1, ""); |
3046 | | | 3046 | |
3047 | error = fd_allocfile(&fp, &fd); | | 3047 | error = fd_allocfile(&fp, &fd); |
3048 | if (error) | | 3048 | if (error) |
3049 | return error; | | 3049 | return error; |
3050 | | | 3050 | |
3051 | af = kmem_zalloc(sizeof(audio_file_t), KM_SLEEP); | | 3051 | af = kmem_zalloc(sizeof(audio_file_t), KM_SLEEP); |
3052 | af->sc = sc; | | 3052 | af->sc = sc; |
3053 | af->dev = dev; | | 3053 | af->dev = dev; |
3054 | | | 3054 | |
3055 | /* Not necessary to insert sc_files. */ | | 3055 | /* Not necessary to insert sc_files. */ |
3056 | | | 3056 | |
3057 | error = fd_clone(fp, fd, flags, &audio_fileops, af); | | 3057 | error = fd_clone(fp, fd, flags, &audio_fileops, af); |
3058 | KASSERT(error == EMOVEFD); | | 3058 | KASSERT(error == EMOVEFD); |
3059 | | | 3059 | |
3060 | return error; | | 3060 | return error; |
3061 | } | | 3061 | } |
3062 | | | 3062 | |
3063 | /* | | 3063 | /* |
3064 | * Reallocate 'memblock' with specified 'bytes' if 'bytes' > 0. | | | |
3065 | * Or free 'memblock' and return NULL if 'byte' is zero. | | | |
3066 | */ | | | |
3067 | static void * | | | |
3068 | audio_realloc(void *memblock, size_t bytes) | | | |
3069 | { | | | |
3070 | | | | |
3071 | if (memblock != NULL) { | | | |
3072 | if (bytes != 0) { | | | |
3073 | return kern_realloc(memblock, bytes, M_NOWAIT); | | | |
3074 | } else { | | | |
3075 | kern_free(memblock); | | | |
3076 | return NULL; | | | |
3077 | } | | | |
3078 | } else { | | | |
3079 | if (bytes != 0) { | | | |
3080 | return kern_malloc(bytes, M_NOWAIT); | | | |
3081 | } else { | | | |
3082 | return NULL; | | | |
3083 | } | | | |
3084 | } | | | |
3085 | } | | | |
3086 | | | | |
3087 | /* | | | |
3088 | * Free 'mem' if available, and initialize the pointer. | | 3064 | * Free 'mem' if available, and initialize the pointer. |
3089 | * For this reason, this is implemented as macro. | | 3065 | * For this reason, this is implemented as macro. |
3090 | */ | | 3066 | */ |
3091 | #define audio_free(mem) do { \ | | 3067 | #define audio_free(mem) do { \ |
3092 | if (mem != NULL) { \ | | 3068 | if (mem != NULL) { \ |
3093 | kern_free(mem); \ | | 3069 | kern_free(mem); \ |
3094 | mem = NULL; \ | | 3070 | mem = NULL; \ |
3095 | } \ | | 3071 | } \ |
3096 | } while (0) | | 3072 | } while (0) |
3097 | | | 3073 | |
3098 | /* | | 3074 | /* |
| | | 3075 | * (Re)allocate 'memblock' with specified 'bytes'. |
| | | 3076 | * bytes must not be 0. |
| | | 3077 | * This function never returns NULL. |
| | | 3078 | */ |
| | | 3079 | static void * |
| | | 3080 | audio_realloc(void *memblock, size_t bytes) |
| | | 3081 | { |
| | | 3082 | |
| | | 3083 | KASSERT(bytes != 0); |
| | | 3084 | audio_free(memblock); |
| | | 3085 | return kern_malloc(bytes, M_WAITOK); |
| | | 3086 | } |
| | | 3087 | |
| | | 3088 | /* |
3099 | * (Re)allocate usrbuf with 'newbufsize' bytes. | | 3089 | * (Re)allocate usrbuf with 'newbufsize' bytes. |
3100 | * Use this function for usrbuf because only usrbuf can be mmapped. | | 3090 | * Use this function for usrbuf because only usrbuf can be mmapped. |
3101 | * If successful, it updates track->usrbuf.mem, track->usrbuf.capacity and | | 3091 | * If successful, it updates track->usrbuf.mem, track->usrbuf.capacity and |
3102 | * returns 0. Otherwise, it clears track->usrbuf.mem, track->usrbuf.capacity | | 3092 | * returns 0. Otherwise, it clears track->usrbuf.mem, track->usrbuf.capacity |
3103 | * and returns errno. | | 3093 | * and returns errno. |
3104 | * It must be called before updating usrbuf.capacity. | | 3094 | * It must be called before updating usrbuf.capacity. |
3105 | */ | | 3095 | */ |
3106 | static int | | 3096 | static int |
3107 | audio_realloc_usrbuf(audio_track_t *track, int newbufsize) | | 3097 | audio_realloc_usrbuf(audio_track_t *track, int newbufsize) |
3108 | { | | 3098 | { |
3109 | struct audio_softc *sc; | | 3099 | struct audio_softc *sc; |
3110 | vaddr_t vstart; | | 3100 | vaddr_t vstart; |
3111 | vsize_t oldvsize; | | 3101 | vsize_t oldvsize; |
3112 | vsize_t newvsize; | | 3102 | vsize_t newvsize; |
3113 | int error; | | 3103 | int error; |
3114 | | | 3104 | |
3115 | KASSERT(newbufsize > 0); | | 3105 | KASSERT(newbufsize > 0); |
3116 | sc = track->mixer->sc; | | 3106 | sc = track->mixer->sc; |
3117 | | | 3107 | |
3118 | /* Get a nonzero multiple of PAGE_SIZE */ | | 3108 | /* Get a nonzero multiple of PAGE_SIZE */ |
3119 | newvsize = roundup2(MAX(newbufsize, PAGE_SIZE), PAGE_SIZE); | | 3109 | newvsize = roundup2(MAX(newbufsize, PAGE_SIZE), PAGE_SIZE); |
3120 | | | 3110 | |
3121 | if (track->usrbuf.mem != NULL) { | | 3111 | if (track->usrbuf.mem != NULL) { |
3122 | oldvsize = roundup2(MAX(track->usrbuf.capacity, PAGE_SIZE), | | 3112 | oldvsize = roundup2(MAX(track->usrbuf.capacity, PAGE_SIZE), |
3123 | PAGE_SIZE); | | 3113 | PAGE_SIZE); |
3124 | if (oldvsize == newvsize) { | | 3114 | if (oldvsize == newvsize) { |
3125 | track->usrbuf.capacity = newbufsize; | | 3115 | track->usrbuf.capacity = newbufsize; |
3126 | return 0; | | 3116 | return 0; |
3127 | } | | 3117 | } |
3128 | vstart = (vaddr_t)track->usrbuf.mem; | | 3118 | vstart = (vaddr_t)track->usrbuf.mem; |
3129 | uvm_unmap(kernel_map, vstart, vstart + oldvsize); | | 3119 | uvm_unmap(kernel_map, vstart, vstart + oldvsize); |
3130 | /* uvm_unmap also detach uobj */ | | 3120 | /* uvm_unmap also detach uobj */ |
3131 | track->uobj = NULL; /* paranoia */ | | 3121 | track->uobj = NULL; /* paranoia */ |
3132 | track->usrbuf.mem = NULL; | | 3122 | track->usrbuf.mem = NULL; |
3133 | } | | 3123 | } |
3134 | | | 3124 | |
3135 | /* Create a uvm anonymous object */ | | 3125 | /* Create a uvm anonymous object */ |
3136 | track->uobj = uao_create(newvsize, 0); | | 3126 | track->uobj = uao_create(newvsize, 0); |
3137 | | | 3127 | |
3138 | /* Map it into the kernel virtual address space */ | | 3128 | /* Map it into the kernel virtual address space */ |
3139 | vstart = 0; | | 3129 | vstart = 0; |
3140 | error = uvm_map(kernel_map, &vstart, newvsize, track->uobj, 0, 0, | | 3130 | error = uvm_map(kernel_map, &vstart, newvsize, track->uobj, 0, 0, |
3141 | UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_RW, UVM_INH_NONE, | | 3131 | UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_RW, UVM_INH_NONE, |
3142 | UVM_ADV_RANDOM, 0)); | | 3132 | UVM_ADV_RANDOM, 0)); |
3143 | if (error) { | | 3133 | if (error) { |
3144 | device_printf(sc->sc_dev, "uvm_map failed with %d\n", error); | | 3134 | device_printf(sc->sc_dev, "uvm_map failed with %d\n", error); |
3145 | uao_detach(track->uobj); /* release reference */ | | 3135 | uao_detach(track->uobj); /* release reference */ |
3146 | goto abort; | | 3136 | goto abort; |
3147 | } | | 3137 | } |
3148 | | | 3138 | |
3149 | error = uvm_map_pageable(kernel_map, vstart, vstart + newvsize, | | 3139 | error = uvm_map_pageable(kernel_map, vstart, vstart + newvsize, |
3150 | false, 0); | | 3140 | false, 0); |
3151 | if (error) { | | 3141 | if (error) { |
3152 | device_printf(sc->sc_dev, "uvm_map_pageable failed with %d\n", | | 3142 | device_printf(sc->sc_dev, "uvm_map_pageable failed with %d\n", |
3153 | error); | | 3143 | error); |
3154 | uvm_unmap(kernel_map, vstart, vstart + newvsize); | | 3144 | uvm_unmap(kernel_map, vstart, vstart + newvsize); |
3155 | /* uvm_unmap also detach uobj */ | | 3145 | /* uvm_unmap also detach uobj */ |
3156 | goto abort; | | 3146 | goto abort; |
3157 | } | | 3147 | } |
3158 | | | 3148 | |
3159 | track->usrbuf.mem = (void *)vstart; | | 3149 | track->usrbuf.mem = (void *)vstart; |
3160 | track->usrbuf.capacity = newbufsize; | | 3150 | track->usrbuf.capacity = newbufsize; |
3161 | memset(track->usrbuf.mem, 0, newvsize); | | 3151 | memset(track->usrbuf.mem, 0, newvsize); |
3162 | return 0; | | 3152 | return 0; |
3163 | | | 3153 | |
3164 | /* failure */ | | 3154 | /* failure */ |
3165 | abort: | | 3155 | abort: |
3166 | track->uobj = NULL; /* paranoia */ | | 3156 | track->uobj = NULL; /* paranoia */ |
3167 | track->usrbuf.mem = NULL; | | 3157 | track->usrbuf.mem = NULL; |
3168 | track->usrbuf.capacity = 0; | | 3158 | track->usrbuf.capacity = 0; |
3169 | return error; | | 3159 | return error; |
3170 | } | | 3160 | } |
3171 | | | 3161 | |
3172 | /* | | 3162 | /* |
3173 | * Free usrbuf (if available). | | 3163 | * Free usrbuf (if available). |
3174 | */ | | 3164 | */ |
3175 | static void | | 3165 | static void |
3176 | audio_free_usrbuf(audio_track_t *track) | | 3166 | audio_free_usrbuf(audio_track_t *track) |
3177 | { | | 3167 | { |
3178 | vaddr_t vstart; | | 3168 | vaddr_t vstart; |
3179 | vsize_t vsize; | | 3169 | vsize_t vsize; |
3180 | | | 3170 | |
3181 | vstart = (vaddr_t)track->usrbuf.mem; | | 3171 | vstart = (vaddr_t)track->usrbuf.mem; |
3182 | vsize = roundup2(MAX(track->usrbuf.capacity, PAGE_SIZE), PAGE_SIZE); | | 3172 | vsize = roundup2(MAX(track->usrbuf.capacity, PAGE_SIZE), PAGE_SIZE); |
3183 | if (track->usrbuf.mem != NULL) { | | 3173 | if (track->usrbuf.mem != NULL) { |
3184 | /* | | 3174 | /* |
3185 | * Unmap the kernel mapping. uvm_unmap releases the | | 3175 | * Unmap the kernel mapping. uvm_unmap releases the |
3186 | * reference to the uvm object, and this should be the | | 3176 | * reference to the uvm object, and this should be the |
3187 | * last virtual mapping of the uvm object, so no need | | 3177 | * last virtual mapping of the uvm object, so no need |
3188 | * to explicitly release (`detach') the object. | | 3178 | * to explicitly release (`detach') the object. |
3189 | */ | | 3179 | */ |
3190 | uvm_unmap(kernel_map, vstart, vstart + vsize); | | 3180 | uvm_unmap(kernel_map, vstart, vstart + vsize); |
3191 | | | 3181 | |
3192 | track->uobj = NULL; | | 3182 | track->uobj = NULL; |
3193 | track->usrbuf.mem = NULL; | | 3183 | track->usrbuf.mem = NULL; |
3194 | track->usrbuf.capacity = 0; | | 3184 | track->usrbuf.capacity = 0; |
3195 | } | | 3185 | } |
3196 | } | | 3186 | } |
3197 | | | 3187 | |
3198 | /* | | 3188 | /* |
3199 | * This filter changes the volume for each channel. | | 3189 | * This filter changes the volume for each channel. |
3200 | * arg->context points track->ch_volume[]. | | 3190 | * arg->context points track->ch_volume[]. |
3201 | */ | | 3191 | */ |
3202 | static void | | 3192 | static void |
3203 | audio_track_chvol(audio_filter_arg_t *arg) | | 3193 | audio_track_chvol(audio_filter_arg_t *arg) |
3204 | { | | 3194 | { |
3205 | int16_t *ch_volume; | | 3195 | int16_t *ch_volume; |
3206 | const aint_t *s; | | 3196 | const aint_t *s; |
3207 | aint_t *d; | | 3197 | aint_t *d; |
3208 | u_int i; | | 3198 | u_int i; |
3209 | u_int ch; | | 3199 | u_int ch; |
3210 | u_int channels; | | 3200 | u_int channels; |
3211 | | | 3201 | |
3212 | DIAGNOSTIC_filter_arg(arg); | | 3202 | DIAGNOSTIC_filter_arg(arg); |
3213 | KASSERT(arg->srcfmt->channels == arg->dstfmt->channels); | | 3203 | KASSERT(arg->srcfmt->channels == arg->dstfmt->channels); |
3214 | KASSERT(arg->context != NULL); | | 3204 | KASSERT(arg->context != NULL); |
3215 | KASSERT(arg->srcfmt->channels <= AUDIO_MAX_CHANNELS); | | 3205 | KASSERT(arg->srcfmt->channels <= AUDIO_MAX_CHANNELS); |
3216 | | | 3206 | |
3217 | s = arg->src; | | 3207 | s = arg->src; |
3218 | d = arg->dst; | | 3208 | d = arg->dst; |
3219 | ch_volume = arg->context; | | 3209 | ch_volume = arg->context; |
3220 | | | 3210 | |
3221 | channels = arg->srcfmt->channels; | | 3211 | channels = arg->srcfmt->channels; |
3222 | for (i = 0; i < arg->count; i++) { | | 3212 | for (i = 0; i < arg->count; i++) { |
3223 | for (ch = 0; ch < channels; ch++) { | | 3213 | for (ch = 0; ch < channels; ch++) { |
3224 | aint2_t val; | | 3214 | aint2_t val; |
3225 | val = *s++; | | 3215 | val = *s++; |
3226 | val = AUDIO_SCALEDOWN(val * ch_volume[ch], 8); | | 3216 | val = AUDIO_SCALEDOWN(val * ch_volume[ch], 8); |
3227 | *d++ = (aint_t)val; | | 3217 | *d++ = (aint_t)val; |
3228 | } | | 3218 | } |
3229 | } | | 3219 | } |
3230 | } | | 3220 | } |
3231 | | | 3221 | |
3232 | /* | | 3222 | /* |
3233 | * This filter performs conversion from stereo (or more channels) to mono. | | 3223 | * This filter performs conversion from stereo (or more channels) to mono. |
3234 | */ | | 3224 | */ |
3235 | static void | | 3225 | static void |
3236 | audio_track_chmix_mixLR(audio_filter_arg_t *arg) | | 3226 | audio_track_chmix_mixLR(audio_filter_arg_t *arg) |
3237 | { | | 3227 | { |
3238 | const aint_t *s; | | 3228 | const aint_t *s; |
3239 | aint_t *d; | | 3229 | aint_t *d; |
3240 | u_int i; | | 3230 | u_int i; |
3241 | | | 3231 | |
3242 | DIAGNOSTIC_filter_arg(arg); | | 3232 | DIAGNOSTIC_filter_arg(arg); |
3243 | | | 3233 | |
3244 | s = arg->src; | | 3234 | s = arg->src; |
3245 | d = arg->dst; | | 3235 | d = arg->dst; |
3246 | | | 3236 | |
3247 | for (i = 0; i < arg->count; i++) { | | 3237 | for (i = 0; i < arg->count; i++) { |
3248 | *d++ = AUDIO_SCALEDOWN(s[0], 1) + AUDIO_SCALEDOWN(s[1], 1); | | 3238 | *d++ = AUDIO_SCALEDOWN(s[0], 1) + AUDIO_SCALEDOWN(s[1], 1); |
3249 | s += arg->srcfmt->channels; | | 3239 | s += arg->srcfmt->channels; |
3250 | } | | 3240 | } |
3251 | } | | 3241 | } |
3252 | | | 3242 | |
3253 | /* | | 3243 | /* |
3254 | * This filter performs conversion from mono to stereo (or more channels). | | 3244 | * This filter performs conversion from mono to stereo (or more channels). |
3255 | */ | | 3245 | */ |
3256 | static void | | 3246 | static void |
3257 | audio_track_chmix_dupLR(audio_filter_arg_t *arg) | | 3247 | audio_track_chmix_dupLR(audio_filter_arg_t *arg) |
3258 | { | | 3248 | { |
3259 | const aint_t *s; | | 3249 | const aint_t *s; |
3260 | aint_t *d; | | 3250 | aint_t *d; |
3261 | u_int i; | | 3251 | u_int i; |
3262 | u_int ch; | | 3252 | u_int ch; |
3263 | u_int dstchannels; | | 3253 | u_int dstchannels; |
3264 | | | 3254 | |
3265 | DIAGNOSTIC_filter_arg(arg); | | 3255 | DIAGNOSTIC_filter_arg(arg); |
3266 | | | 3256 | |
3267 | s = arg->src; | | 3257 | s = arg->src; |
3268 | d = arg->dst; | | 3258 | d = arg->dst; |
3269 | dstchannels = arg->dstfmt->channels; | | 3259 | dstchannels = arg->dstfmt->channels; |
3270 | | | 3260 | |
3271 | for (i = 0; i < arg->count; i++) { | | 3261 | for (i = 0; i < arg->count; i++) { |
3272 | d[0] = s[0]; | | 3262 | d[0] = s[0]; |
3273 | d[1] = s[0]; | | 3263 | d[1] = s[0]; |
3274 | s++; | | 3264 | s++; |
3275 | d += dstchannels; | | 3265 | d += dstchannels; |
3276 | } | | 3266 | } |
3277 | if (dstchannels > 2) { | | 3267 | if (dstchannels > 2) { |
3278 | d = arg->dst; | | 3268 | d = arg->dst; |
3279 | for (i = 0; i < arg->count; i++) { | | 3269 | for (i = 0; i < arg->count; i++) { |
3280 | for (ch = 2; ch < dstchannels; ch++) { | | 3270 | for (ch = 2; ch < dstchannels; ch++) { |
3281 | d[ch] = 0; | | 3271 | d[ch] = 0; |
3282 | } | | 3272 | } |
3283 | d += dstchannels; | | 3273 | d += dstchannels; |
3284 | } | | 3274 | } |
3285 | } | | 3275 | } |
3286 | } | | 3276 | } |
3287 | | | 3277 | |
3288 | /* | | 3278 | /* |
3289 | * This filter shrinks M channels into N channels. | | 3279 | * This filter shrinks M channels into N channels. |
3290 | * Extra channels are discarded. | | 3280 | * Extra channels are discarded. |
3291 | */ | | 3281 | */ |
3292 | static void | | 3282 | static void |
3293 | audio_track_chmix_shrink(audio_filter_arg_t *arg) | | 3283 | audio_track_chmix_shrink(audio_filter_arg_t *arg) |
3294 | { | | 3284 | { |
3295 | const aint_t *s; | | 3285 | const aint_t *s; |
3296 | aint_t *d; | | 3286 | aint_t *d; |
3297 | u_int i; | | 3287 | u_int i; |
3298 | u_int ch; | | 3288 | u_int ch; |
3299 | | | 3289 | |
3300 | DIAGNOSTIC_filter_arg(arg); | | 3290 | DIAGNOSTIC_filter_arg(arg); |
3301 | | | 3291 | |
3302 | s = arg->src; | | 3292 | s = arg->src; |
3303 | d = arg->dst; | | 3293 | d = arg->dst; |
3304 | | | 3294 | |
3305 | for (i = 0; i < arg->count; i++) { | | 3295 | for (i = 0; i < arg->count; i++) { |
3306 | for (ch = 0; ch < arg->dstfmt->channels; ch++) { | | 3296 | for (ch = 0; ch < arg->dstfmt->channels; ch++) { |
3307 | *d++ = s[ch]; | | 3297 | *d++ = s[ch]; |
3308 | } | | 3298 | } |
3309 | s += arg->srcfmt->channels; | | 3299 | s += arg->srcfmt->channels; |
3310 | } | | 3300 | } |
3311 | } | | 3301 | } |
3312 | | | 3302 | |
3313 | /* | | 3303 | /* |
3314 | * This filter expands M channels into N channels. | | 3304 | * This filter expands M channels into N channels. |
3315 | * Silence is inserted for missing channels. | | 3305 | * Silence is inserted for missing channels. |
3316 | */ | | 3306 | */ |
3317 | static void | | 3307 | static void |
3318 | audio_track_chmix_expand(audio_filter_arg_t *arg) | | 3308 | audio_track_chmix_expand(audio_filter_arg_t *arg) |
3319 | { | | 3309 | { |
3320 | const aint_t *s; | | 3310 | const aint_t *s; |
3321 | aint_t *d; | | 3311 | aint_t *d; |
3322 | u_int i; | | 3312 | u_int i; |
3323 | u_int ch; | | 3313 | u_int ch; |
3324 | u_int srcchannels; | | 3314 | u_int srcchannels; |
3325 | u_int dstchannels; | | 3315 | u_int dstchannels; |
3326 | | | 3316 | |
3327 | DIAGNOSTIC_filter_arg(arg); | | 3317 | DIAGNOSTIC_filter_arg(arg); |
3328 | | | 3318 | |
3329 | s = arg->src; | | 3319 | s = arg->src; |
3330 | d = arg->dst; | | 3320 | d = arg->dst; |
3331 | | | 3321 | |
3332 | srcchannels = arg->srcfmt->channels; | | 3322 | srcchannels = arg->srcfmt->channels; |
3333 | dstchannels = arg->dstfmt->channels; | | 3323 | dstchannels = arg->dstfmt->channels; |
3334 | for (i = 0; i < arg->count; i++) { | | 3324 | for (i = 0; i < arg->count; i++) { |
3335 | for (ch = 0; ch < srcchannels; ch++) { | | 3325 | for (ch = 0; ch < srcchannels; ch++) { |
3336 | *d++ = *s++; | | 3326 | *d++ = *s++; |
3337 | } | | 3327 | } |
3338 | for (; ch < dstchannels; ch++) { | | 3328 | for (; ch < dstchannels; ch++) { |
3339 | *d++ = 0; | | 3329 | *d++ = 0; |
3340 | } | | 3330 | } |
3341 | } | | 3331 | } |
3342 | } | | 3332 | } |
3343 | | | 3333 | |
3344 | /* | | 3334 | /* |
3345 | * This filter performs frequency conversion (up sampling). | | 3335 | * This filter performs frequency conversion (up sampling). |
3346 | * It uses linear interpolation. | | 3336 | * It uses linear interpolation. |
3347 | */ | | 3337 | */ |
3348 | static void | | 3338 | static void |
3349 | audio_track_freq_up(audio_filter_arg_t *arg) | | 3339 | audio_track_freq_up(audio_filter_arg_t *arg) |
3350 | { | | 3340 | { |
3351 | audio_track_t *track; | | 3341 | audio_track_t *track; |
3352 | audio_ring_t *src; | | 3342 | audio_ring_t *src; |
3353 | audio_ring_t *dst; | | 3343 | audio_ring_t *dst; |
3354 | const aint_t *s; | | 3344 | const aint_t *s; |
3355 | aint_t *d; | | 3345 | aint_t *d; |
3356 | aint_t prev[AUDIO_MAX_CHANNELS]; | | 3346 | aint_t prev[AUDIO_MAX_CHANNELS]; |
3357 | aint_t curr[AUDIO_MAX_CHANNELS]; | | 3347 | aint_t curr[AUDIO_MAX_CHANNELS]; |
3358 | aint_t grad[AUDIO_MAX_CHANNELS]; | | 3348 | aint_t grad[AUDIO_MAX_CHANNELS]; |
3359 | u_int i; | | 3349 | u_int i; |
3360 | u_int t; | | 3350 | u_int t; |
3361 | u_int step; | | 3351 | u_int step; |
3362 | u_int channels; | | 3352 | u_int channels; |
3363 | u_int ch; | | 3353 | u_int ch; |
3364 | int srcused; | | 3354 | int srcused; |
3365 | | | 3355 | |
3366 | track = arg->context; | | 3356 | track = arg->context; |
3367 | KASSERT(track); | | 3357 | KASSERT(track); |
3368 | src = &track->freq.srcbuf; | | 3358 | src = &track->freq.srcbuf; |
3369 | dst = track->freq.dst; | | 3359 | dst = track->freq.dst; |
3370 | DIAGNOSTIC_ring(dst); | | 3360 | DIAGNOSTIC_ring(dst); |
3371 | DIAGNOSTIC_ring(src); | | 3361 | DIAGNOSTIC_ring(src); |
3372 | KASSERT(src->used > 0); | | 3362 | KASSERT(src->used > 0); |
3373 | KASSERT(src->fmt.channels == dst->fmt.channels); | | 3363 | KASSERT(src->fmt.channels == dst->fmt.channels); |
3374 | KASSERT(src->head % track->mixer->frames_per_block == 0); | | 3364 | KASSERT(src->head % track->mixer->frames_per_block == 0); |
3375 | | | 3365 | |
3376 | s = arg->src; | | 3366 | s = arg->src; |
3377 | d = arg->dst; | | 3367 | d = arg->dst; |
3378 | | | 3368 | |
3379 | /* | | 3369 | /* |
3380 | * In order to faciliate interpolation for each block, slide (delay) | | 3370 | * In order to faciliate interpolation for each block, slide (delay) |
3381 | * input by one sample. As a result, strictly speaking, the output | | 3371 | * input by one sample. As a result, strictly speaking, the output |
3382 | * phase is delayed by 1/dstfreq. However, I believe there is no | | 3372 | * phase is delayed by 1/dstfreq. However, I believe there is no |
3383 | * observable impact. | | 3373 | * observable impact. |
3384 | * | | 3374 | * |
3385 | * Example) | | 3375 | * Example) |
3386 | * srcfreq:dstfreq = 1:3 | | 3376 | * srcfreq:dstfreq = 1:3 |
3387 | * | | 3377 | * |
3388 | * A - - | | 3378 | * A - - |
3389 | * | | | 3379 | * | |
3390 | * | | | 3380 | * | |
3391 | * | B - - | | 3381 | * | B - - |
3392 | * +-----+-----> input timeframe | | 3382 | * +-----+-----> input timeframe |
3393 | * 0 1 | | 3383 | * 0 1 |
3394 | * | | 3384 | * |
3395 | * 0 1 | | 3385 | * 0 1 |
3396 | * +-----+-----> input timeframe | | 3386 | * +-----+-----> input timeframe |
3397 | * | A | | 3387 | * | A |
3398 | * | x x | | 3388 | * | x x |
3399 | * | x x | | 3389 | * | x x |
3400 | * x (B) | | 3390 | * x (B) |
3401 | * +-+-+-+-+-+-> output timeframe | | 3391 | * +-+-+-+-+-+-> output timeframe |
3402 | * 0 1 2 3 4 5 | | 3392 | * 0 1 2 3 4 5 |
3403 | */ | | 3393 | */ |
3404 | | | 3394 | |
3405 | /* Last samples in previous block */ | | 3395 | /* Last samples in previous block */ |
3406 | channels = src->fmt.channels; | | 3396 | channels = src->fmt.channels; |
3407 | for (ch = 0; ch < channels; ch++) { | | 3397 | for (ch = 0; ch < channels; ch++) { |
3408 | prev[ch] = track->freq_prev[ch]; | | 3398 | prev[ch] = track->freq_prev[ch]; |
3409 | curr[ch] = track->freq_curr[ch]; | | 3399 | curr[ch] = track->freq_curr[ch]; |
3410 | grad[ch] = curr[ch] - prev[ch]; | | 3400 | grad[ch] = curr[ch] - prev[ch]; |
3411 | } | | 3401 | } |
3412 | | | 3402 | |
3413 | step = track->freq_step; | | 3403 | step = track->freq_step; |
3414 | t = track->freq_current; | | 3404 | t = track->freq_current; |
3415 | //#define FREQ_DEBUG | | 3405 | //#define FREQ_DEBUG |
3416 | #if defined(FREQ_DEBUG) | | 3406 | #if defined(FREQ_DEBUG) |
3417 | #define PRINTF(fmt...) printf(fmt) | | 3407 | #define PRINTF(fmt...) printf(fmt) |
3418 | #else | | 3408 | #else |
3419 | #define PRINTF(fmt...) do { } while (0) | | 3409 | #define PRINTF(fmt...) do { } while (0) |
3420 | #endif | | 3410 | #endif |
3421 | srcused = src->used; | | 3411 | srcused = src->used; |
3422 | PRINTF("upstart step=%d leap=%d", step, track->freq_leap); | | 3412 | PRINTF("upstart step=%d leap=%d", step, track->freq_leap); |
3423 | PRINTF(" srcused=%d arg->count=%u", src->used, arg->count); | | 3413 | PRINTF(" srcused=%d arg->count=%u", src->used, arg->count); |
3424 | PRINTF(" prev=%d curr=%d grad=%d", prev[0], curr[0], grad[0]); | | 3414 | PRINTF(" prev=%d curr=%d grad=%d", prev[0], curr[0], grad[0]); |
3425 | PRINTF(" t=%d\n", t); | | 3415 | PRINTF(" t=%d\n", t); |
3426 | | | 3416 | |
3427 | for (i = 0; i < arg->count; i++) { | | 3417 | for (i = 0; i < arg->count; i++) { |
3428 | PRINTF("i=%d t=%5d", i, t); | | 3418 | PRINTF("i=%d t=%5d", i, t); |
3429 | if (t >= 65536) { | | 3419 | if (t >= 65536) { |
3430 | for (ch = 0; ch < channels; ch++) { | | 3420 | for (ch = 0; ch < channels; ch++) { |
3431 | prev[ch] = curr[ch]; | | 3421 | prev[ch] = curr[ch]; |
3432 | curr[ch] = *s++; | | 3422 | curr[ch] = *s++; |
3433 | grad[ch] = curr[ch] - prev[ch]; | | 3423 | grad[ch] = curr[ch] - prev[ch]; |
3434 | } | | 3424 | } |
3435 | PRINTF(" prev=%d s[%d]=%d", | | 3425 | PRINTF(" prev=%d s[%d]=%d", |
3436 | prev[0], src->used - srcused, curr[0]); | | 3426 | prev[0], src->used - srcused, curr[0]); |
3437 | | | 3427 | |
3438 | /* Update */ | | 3428 | /* Update */ |
3439 | t -= 65536; | | 3429 | t -= 65536; |
3440 | srcused--; | | 3430 | srcused--; |
3441 | if (srcused < 0) { | | 3431 | if (srcused < 0) { |
3442 | PRINTF(" break\n"); | | 3432 | PRINTF(" break\n"); |
3443 | break; | | 3433 | break; |
3444 | } | | 3434 | } |
3445 | } | | 3435 | } |
3446 | | | 3436 | |
3447 | for (ch = 0; ch < channels; ch++) { | | 3437 | for (ch = 0; ch < channels; ch++) { |
3448 | *d++ = prev[ch] + (aint2_t)grad[ch] * t / 65536; | | 3438 | *d++ = prev[ch] + (aint2_t)grad[ch] * t / 65536; |
3449 | #if defined(FREQ_DEBUG) | | 3439 | #if defined(FREQ_DEBUG) |
3450 | if (ch == 0) | | 3440 | if (ch == 0) |
3451 | printf(" t=%5d *d=%d", t, d[-1]); | | 3441 | printf(" t=%5d *d=%d", t, d[-1]); |
3452 | #endif | | 3442 | #endif |
3453 | } | | 3443 | } |
3454 | t += step; | | 3444 | t += step; |
3455 | | | 3445 | |
3456 | PRINTF("\n"); | | 3446 | PRINTF("\n"); |
3457 | } | | 3447 | } |
3458 | PRINTF("end prev=%d curr=%d\n", prev[0], curr[0]); | | 3448 | PRINTF("end prev=%d curr=%d\n", prev[0], curr[0]); |
3459 | | | 3449 | |
3460 | auring_take(src, src->used); | | 3450 | auring_take(src, src->used); |
3461 | auring_push(dst, i); | | 3451 | auring_push(dst, i); |
3462 | | | 3452 | |
3463 | /* Adjust */ | | 3453 | /* Adjust */ |
3464 | t += track->freq_leap; | | 3454 | t += track->freq_leap; |
3465 | | | 3455 | |
3466 | track->freq_current = t; | | 3456 | track->freq_current = t; |
3467 | for (ch = 0; ch < channels; ch++) { | | 3457 | for (ch = 0; ch < channels; ch++) { |
3468 | track->freq_prev[ch] = prev[ch]; | | 3458 | track->freq_prev[ch] = prev[ch]; |
3469 | track->freq_curr[ch] = curr[ch]; | | 3459 | track->freq_curr[ch] = curr[ch]; |
3470 | } | | 3460 | } |
3471 | } | | 3461 | } |
3472 | | | 3462 | |
3473 | /* | | 3463 | /* |
3474 | * This filter performs frequency conversion (down sampling). | | 3464 | * This filter performs frequency conversion (down sampling). |
3475 | * It uses simple thinning. | | 3465 | * It uses simple thinning. |
3476 | */ | | 3466 | */ |
3477 | static void | | 3467 | static void |
3478 | audio_track_freq_down(audio_filter_arg_t *arg) | | 3468 | audio_track_freq_down(audio_filter_arg_t *arg) |
3479 | { | | 3469 | { |
3480 | audio_track_t *track; | | 3470 | audio_track_t *track; |
3481 | audio_ring_t *src; | | 3471 | audio_ring_t *src; |
3482 | audio_ring_t *dst; | | 3472 | audio_ring_t *dst; |
3483 | const aint_t *s0; | | 3473 | const aint_t *s0; |
3484 | aint_t *d; | | 3474 | aint_t *d; |
3485 | u_int i; | | 3475 | u_int i; |
3486 | u_int t; | | 3476 | u_int t; |
3487 | u_int step; | | 3477 | u_int step; |
3488 | u_int ch; | | 3478 | u_int ch; |
3489 | u_int channels; | | 3479 | u_int channels; |
3490 | | | 3480 | |
3491 | track = arg->context; | | 3481 | track = arg->context; |
3492 | KASSERT(track); | | 3482 | KASSERT(track); |
3493 | src = &track->freq.srcbuf; | | 3483 | src = &track->freq.srcbuf; |
3494 | dst = track->freq.dst; | | 3484 | dst = track->freq.dst; |
3495 | | | 3485 | |
3496 | DIAGNOSTIC_ring(dst); | | 3486 | DIAGNOSTIC_ring(dst); |
3497 | DIAGNOSTIC_ring(src); | | 3487 | DIAGNOSTIC_ring(src); |
3498 | KASSERT(src->used > 0); | | 3488 | KASSERT(src->used > 0); |
3499 | KASSERT(src->fmt.channels == dst->fmt.channels); | | 3489 | KASSERT(src->fmt.channels == dst->fmt.channels); |
3500 | KASSERTMSG(src->head % track->mixer->frames_per_block == 0, | | 3490 | KASSERTMSG(src->head % track->mixer->frames_per_block == 0, |
3501 | "src->head=%d fpb=%d", | | 3491 | "src->head=%d fpb=%d", |
3502 | src->head, track->mixer->frames_per_block); | | 3492 | src->head, track->mixer->frames_per_block); |
3503 | | | 3493 | |
3504 | s0 = arg->src; | | 3494 | s0 = arg->src; |
3505 | d = arg->dst; | | 3495 | d = arg->dst; |
3506 | t = track->freq_current; | | 3496 | t = track->freq_current; |
3507 | step = track->freq_step; | | 3497 | step = track->freq_step; |
3508 | channels = dst->fmt.channels; | | 3498 | channels = dst->fmt.channels; |
3509 | PRINTF("downstart step=%d leap=%d", step, track->freq_leap); | | 3499 | PRINTF("downstart step=%d leap=%d", step, track->freq_leap); |
3510 | PRINTF(" srcused=%d arg->count=%u", src->used, arg->count); | | 3500 | PRINTF(" srcused=%d arg->count=%u", src->used, arg->count); |
3511 | PRINTF(" t=%d\n", t); | | 3501 | PRINTF(" t=%d\n", t); |
3512 | | | 3502 | |
3513 | for (i = 0; i < arg->count && t / 65536 < src->used; i++) { | | 3503 | for (i = 0; i < arg->count && t / 65536 < src->used; i++) { |
3514 | const aint_t *s; | | 3504 | const aint_t *s; |
3515 | PRINTF("i=%4d t=%10d", i, t); | | 3505 | PRINTF("i=%4d t=%10d", i, t); |
3516 | s = s0 + (t / 65536) * channels; | | 3506 | s = s0 + (t / 65536) * channels; |
3517 | PRINTF(" s=%5ld", (s - s0) / channels); | | 3507 | PRINTF(" s=%5ld", (s - s0) / channels); |
3518 | for (ch = 0; ch < channels; ch++) { | | 3508 | for (ch = 0; ch < channels; ch++) { |
3519 | if (ch == 0) PRINTF(" *s=%d", s[ch]); | | 3509 | if (ch == 0) PRINTF(" *s=%d", s[ch]); |
3520 | *d++ = s[ch]; | | 3510 | *d++ = s[ch]; |
3521 | } | | 3511 | } |
3522 | PRINTF("\n"); | | 3512 | PRINTF("\n"); |
3523 | t += step; | | 3513 | t += step; |
3524 | } | | 3514 | } |
3525 | t += track->freq_leap; | | 3515 | t += track->freq_leap; |
3526 | PRINTF("end t=%d\n", t); | | 3516 | PRINTF("end t=%d\n", t); |
3527 | auring_take(src, src->used); | | 3517 | auring_take(src, src->used); |
3528 | auring_push(dst, i); | | 3518 | auring_push(dst, i); |
3529 | track->freq_current = t % 65536; | | 3519 | track->freq_current = t % 65536; |
3530 | } | | 3520 | } |
3531 | | | 3521 | |
3532 | /* | | 3522 | /* |
3533 | * Creates track and returns it. | | 3523 | * Creates track and returns it. |
3534 | */ | | 3524 | */ |
3535 | audio_track_t * | | 3525 | audio_track_t * |
3536 | audio_track_create(struct audio_softc *sc, audio_trackmixer_t *mixer) | | 3526 | audio_track_create(struct audio_softc *sc, audio_trackmixer_t *mixer) |
3537 | { | | 3527 | { |
3538 | audio_track_t *track; | | 3528 | audio_track_t *track; |
3539 | static int newid = 0; | | 3529 | static int newid = 0; |
3540 | | | 3530 | |
3541 | track = kmem_zalloc(sizeof(*track), KM_SLEEP); | | 3531 | track = kmem_zalloc(sizeof(*track), KM_SLEEP); |
3542 | | | 3532 | |
3543 | track->id = newid++; | | 3533 | track->id = newid++; |
3544 | track->mixer = mixer; | | 3534 | track->mixer = mixer; |
3545 | track->mode = mixer->mode; | | 3535 | track->mode = mixer->mode; |
3546 | | | 3536 | |
3547 | /* Do TRACE after id is assigned. */ | | 3537 | /* Do TRACE after id is assigned. */ |
3548 | TRACET(3, track, "for %s", | | 3538 | TRACET(3, track, "for %s", |
3549 | mixer->mode == AUMODE_PLAY ? "playback" : "recording"); | | 3539 | mixer->mode == AUMODE_PLAY ? "playback" : "recording"); |
3550 | | | 3540 | |
3551 | #if defined(AUDIO_SUPPORT_TRACK_VOLUME) | | 3541 | #if defined(AUDIO_SUPPORT_TRACK_VOLUME) |
3552 | track->volume = 256; | | 3542 | track->volume = 256; |
3553 | #endif | | 3543 | #endif |
3554 | for (int i = 0; i < AUDIO_MAX_CHANNELS; i++) { | | 3544 | for (int i = 0; i < AUDIO_MAX_CHANNELS; i++) { |
3555 | track->ch_volume[i] = 256; | | 3545 | track->ch_volume[i] = 256; |
3556 | } | | 3546 | } |
3557 | | | 3547 | |
3558 | return track; | | 3548 | return track; |
3559 | } | | 3549 | } |
3560 | | | 3550 | |
3561 | /* | | 3551 | /* |
3562 | * Release all resources of the track and track itself. | | 3552 | * Release all resources of the track and track itself. |
3563 | * track must not be NULL. Don't specify the track within the file | | 3553 | * track must not be NULL. Don't specify the track within the file |
3564 | * structure linked from sc->sc_files. | | 3554 | * structure linked from sc->sc_files. |
3565 | */ | | 3555 | */ |
3566 | static void | | 3556 | static void |
3567 | audio_track_destroy(audio_track_t *track) | | 3557 | audio_track_destroy(audio_track_t *track) |
3568 | { | | 3558 | { |
3569 | | | 3559 | |
3570 | KASSERT(track); | | 3560 | KASSERT(track); |
3571 | | | 3561 | |
3572 | audio_free_usrbuf(track); | | 3562 | audio_free_usrbuf(track); |
3573 | audio_free(track->codec.srcbuf.mem); | | 3563 | audio_free(track->codec.srcbuf.mem); |
3574 | audio_free(track->chvol.srcbuf.mem); | | 3564 | audio_free(track->chvol.srcbuf.mem); |
3575 | audio_free(track->chmix.srcbuf.mem); | | 3565 | audio_free(track->chmix.srcbuf.mem); |
3576 | audio_free(track->freq.srcbuf.mem); | | 3566 | audio_free(track->freq.srcbuf.mem); |
3577 | audio_free(track->outbuf.mem); | | 3567 | audio_free(track->outbuf.mem); |
3578 | | | 3568 | |
3579 | kmem_free(track, sizeof(*track)); | | 3569 | kmem_free(track, sizeof(*track)); |
3580 | } | | 3570 | } |
3581 | | | 3571 | |
3582 | /* | | 3572 | /* |
3583 | * It returns encoding conversion filter according to src and dst format. | | 3573 | * It returns encoding conversion filter according to src and dst format. |
3584 | * If it is not a convertible pair, it returns NULL. Either src or dst | | 3574 | * If it is not a convertible pair, it returns NULL. Either src or dst |
3585 | * must be internal format. | | 3575 | * must be internal format. |
3586 | */ | | 3576 | */ |
3587 | static audio_filter_t | | 3577 | static audio_filter_t |
3588 | audio_track_get_codec(audio_track_t *track, const audio_format2_t *src, | | 3578 | audio_track_get_codec(audio_track_t *track, const audio_format2_t *src, |
3589 | const audio_format2_t *dst) | | 3579 | const audio_format2_t *dst) |
3590 | { | | 3580 | { |
3591 | | | 3581 | |
3592 | if (audio_format2_is_internal(src)) { | | 3582 | if (audio_format2_is_internal(src)) { |
3593 | if (dst->encoding == AUDIO_ENCODING_ULAW) { | | 3583 | if (dst->encoding == AUDIO_ENCODING_ULAW) { |
3594 | return audio_internal_to_mulaw; | | 3584 | return audio_internal_to_mulaw; |
3595 | } else if (dst->encoding == AUDIO_ENCODING_ALAW) { | | 3585 | } else if (dst->encoding == AUDIO_ENCODING_ALAW) { |
3596 | return audio_internal_to_alaw; | | 3586 | return audio_internal_to_alaw; |
3597 | } else if (audio_format2_is_linear(dst)) { | | 3587 | } else if (audio_format2_is_linear(dst)) { |
3598 | switch (dst->stride) { | | 3588 | switch (dst->stride) { |
3599 | case 8: | | 3589 | case 8: |
3600 | return audio_internal_to_linear8; | | 3590 | return audio_internal_to_linear8; |
3601 | case 16: | | 3591 | case 16: |
3602 | return audio_internal_to_linear16; | | 3592 | return audio_internal_to_linear16; |
3603 | #if defined(AUDIO_SUPPORT_LINEAR24) | | 3593 | #if defined(AUDIO_SUPPORT_LINEAR24) |
3604 | case 24: | | 3594 | case 24: |
3605 | return audio_internal_to_linear24; | | 3595 | return audio_internal_to_linear24; |
3606 | #endif | | 3596 | #endif |
3607 | case 32: | | 3597 | case 32: |
3608 | return audio_internal_to_linear32; | | 3598 | return audio_internal_to_linear32; |
3609 | default: | | 3599 | default: |
3610 | TRACET(1, track, "unsupported %s stride %d", | | 3600 | TRACET(1, track, "unsupported %s stride %d", |
3611 | "dst", dst->stride); | | 3601 | "dst", dst->stride); |
3612 | goto abort; | | 3602 | goto abort; |
3613 | } | | 3603 | } |
3614 | } | | 3604 | } |
3615 | } else if (audio_format2_is_internal(dst)) { | | 3605 | } else if (audio_format2_is_internal(dst)) { |
3616 | if (src->encoding == AUDIO_ENCODING_ULAW) { | | 3606 | if (src->encoding == AUDIO_ENCODING_ULAW) { |
3617 | return audio_mulaw_to_internal; | | 3607 | return audio_mulaw_to_internal; |
3618 | } else if (src->encoding == AUDIO_ENCODING_ALAW) { | | 3608 | } else if (src->encoding == AUDIO_ENCODING_ALAW) { |
3619 | return audio_alaw_to_internal; | | 3609 | return audio_alaw_to_internal; |
3620 | } else if (audio_format2_is_linear(src)) { | | 3610 | } else if (audio_format2_is_linear(src)) { |
3621 | switch (src->stride) { | | 3611 | switch (src->stride) { |
3622 | case 8: | | 3612 | case 8: |
3623 | return audio_linear8_to_internal; | | 3613 | return audio_linear8_to_internal; |
3624 | case 16: | | 3614 | case 16: |
3625 | return audio_linear16_to_internal; | | 3615 | return audio_linear16_to_internal; |
3626 | #if defined(AUDIO_SUPPORT_LINEAR24) | | 3616 | #if defined(AUDIO_SUPPORT_LINEAR24) |
3627 | case 24: | | 3617 | case 24: |
3628 | return audio_linear24_to_internal; | | 3618 | return audio_linear24_to_internal; |
3629 | #endif | | 3619 | #endif |
3630 | case 32: | | 3620 | case 32: |
3631 | return audio_linear32_to_internal; | | 3621 | return audio_linear32_to_internal; |
3632 | default: | | 3622 | default: |
3633 | TRACET(1, track, "unsupported %s stride %d", | | 3623 | TRACET(1, track, "unsupported %s stride %d", |
3634 | "src", src->stride); | | 3624 | "src", src->stride); |
3635 | goto abort; | | 3625 | goto abort; |
3636 | } | | 3626 | } |
3637 | } | | 3627 | } |
3638 | } | | 3628 | } |
3639 | | | 3629 | |
3640 | TRACET(1, track, "unsupported encoding"); | | 3630 | TRACET(1, track, "unsupported encoding"); |
3641 | abort: | | 3631 | abort: |
3642 | #if defined(AUDIO_DEBUG) | | 3632 | #if defined(AUDIO_DEBUG) |
3643 | if (audiodebug >= 2) { | | 3633 | if (audiodebug >= 2) { |
3644 | char buf[100]; | | 3634 | char buf[100]; |
3645 | audio_format2_tostr(buf, sizeof(buf), src); | | 3635 | audio_format2_tostr(buf, sizeof(buf), src); |
3646 | TRACET(2, track, "src %s", buf); | | 3636 | TRACET(2, track, "src %s", buf); |
3647 | audio_format2_tostr(buf, sizeof(buf), dst); | | 3637 | audio_format2_tostr(buf, sizeof(buf), dst); |
3648 | TRACET(2, track, "dst %s", buf); | | 3638 | TRACET(2, track, "dst %s", buf); |
3649 | } | | 3639 | } |
3650 | #endif | | 3640 | #endif |
3651 | return NULL; | | 3641 | return NULL; |
3652 | } | | 3642 | } |
3653 | | | 3643 | |
3654 | /* | | 3644 | /* |
3655 | * Initialize the codec stage of this track as necessary. | | 3645 | * Initialize the codec stage of this track as necessary. |
3656 | * If successful, it initializes the codec stage as necessary, stores updated | | 3646 | * If successful, it initializes the codec stage as necessary, stores updated |
3657 | * last_dst in *last_dstp in any case, and returns 0. | | 3647 | * last_dst in *last_dstp in any case, and returns 0. |
3658 | * Otherwise, it returns errno without modifying *last_dstp. | | 3648 | * Otherwise, it returns errno without modifying *last_dstp. |
3659 | */ | | 3649 | */ |
3660 | static int | | 3650 | static int |
3661 | audio_track_init_codec(audio_track_t *track, audio_ring_t **last_dstp) | | 3651 | audio_track_init_codec(audio_track_t *track, audio_ring_t **last_dstp) |
3662 | { | | 3652 | { |
3663 | struct audio_softc *sc; | | | |
3664 | audio_ring_t *last_dst; | | 3653 | audio_ring_t *last_dst; |
3665 | audio_ring_t *srcbuf; | | 3654 | audio_ring_t *srcbuf; |
3666 | audio_format2_t *srcfmt; | | 3655 | audio_format2_t *srcfmt; |
3667 | audio_format2_t *dstfmt; | | 3656 | audio_format2_t *dstfmt; |
3668 | audio_filter_arg_t *arg; | | 3657 | audio_filter_arg_t *arg; |
3669 | u_int len; | | 3658 | u_int len; |
3670 | int error; | | 3659 | int error; |
3671 | | | 3660 | |
3672 | KASSERT(track); | | 3661 | KASSERT(track); |
3673 | | | 3662 | |
3674 | sc = track->mixer->sc; | | | |
3675 | last_dst = *last_dstp; | | 3663 | last_dst = *last_dstp; |
3676 | dstfmt = &last_dst->fmt; | | 3664 | dstfmt = &last_dst->fmt; |
3677 | srcfmt = &track->inputfmt; | | 3665 | srcfmt = &track->inputfmt; |
3678 | srcbuf = &track->codec.srcbuf; | | 3666 | srcbuf = &track->codec.srcbuf; |
3679 | error = 0; | | 3667 | error = 0; |
3680 | | | 3668 | |
3681 | if (srcfmt->encoding != dstfmt->encoding | | 3669 | if (srcfmt->encoding != dstfmt->encoding |
3682 | || srcfmt->precision != dstfmt->precision | | 3670 | || srcfmt->precision != dstfmt->precision |
3683 | || srcfmt->stride != dstfmt->stride) { | | 3671 | || srcfmt->stride != dstfmt->stride) { |
3684 | track->codec.dst = last_dst; | | 3672 | track->codec.dst = last_dst; |
3685 | | | 3673 | |
3686 | srcbuf->fmt = *dstfmt; | | 3674 | srcbuf->fmt = *dstfmt; |
3687 | srcbuf->fmt.encoding = srcfmt->encoding; | | 3675 | srcbuf->fmt.encoding = srcfmt->encoding; |
3688 | srcbuf->fmt.precision = srcfmt->precision; | | 3676 | srcbuf->fmt.precision = srcfmt->precision; |
3689 | srcbuf->fmt.stride = srcfmt->stride; | | 3677 | srcbuf->fmt.stride = srcfmt->stride; |
3690 | | | 3678 | |
3691 | track->codec.filter = audio_track_get_codec(track, | | 3679 | track->codec.filter = audio_track_get_codec(track, |
3692 | &srcbuf->fmt, dstfmt); | | 3680 | &srcbuf->fmt, dstfmt); |
3693 | if (track->codec.filter == NULL) { | | 3681 | if (track->codec.filter == NULL) { |
3694 | error = EINVAL; | | 3682 | error = EINVAL; |
3695 | goto abort; | | 3683 | goto abort; |
3696 | } | | 3684 | } |
3697 | | | 3685 | |
3698 | srcbuf->head = 0; | | 3686 | srcbuf->head = 0; |
3699 | srcbuf->used = 0; | | 3687 | srcbuf->used = 0; |
3700 | srcbuf->capacity = frame_per_block(track->mixer, &srcbuf->fmt); | | 3688 | srcbuf->capacity = frame_per_block(track->mixer, &srcbuf->fmt); |
3701 | len = auring_bytelen(srcbuf); | | 3689 | len = auring_bytelen(srcbuf); |
3702 | srcbuf->mem = audio_realloc(srcbuf->mem, len); | | 3690 | srcbuf->mem = audio_realloc(srcbuf->mem, len); |
3703 | if (srcbuf->mem == NULL) { | | | |
3704 | device_printf(sc->sc_dev, "%s: malloc(%d) failed\n", | | | |
3705 | __func__, len); | | | |
3706 | error = ENOMEM; | | | |
3707 | goto abort; | | | |
3708 | } | | | |
3709 | | | 3691 | |
3710 | arg = &track->codec.arg; | | 3692 | arg = &track->codec.arg; |
3711 | arg->srcfmt = &srcbuf->fmt; | | 3693 | arg->srcfmt = &srcbuf->fmt; |
3712 | arg->dstfmt = dstfmt; | | 3694 | arg->dstfmt = dstfmt; |
3713 | arg->context = NULL; | | 3695 | arg->context = NULL; |
3714 | | | 3696 | |
3715 | *last_dstp = srcbuf; | | 3697 | *last_dstp = srcbuf; |
3716 | return 0; | | 3698 | return 0; |
3717 | } | | 3699 | } |
3718 | | | 3700 | |
3719 | abort: | | 3701 | abort: |
3720 | track->codec.filter = NULL; | | 3702 | track->codec.filter = NULL; |
3721 | audio_free(srcbuf->mem); | | 3703 | audio_free(srcbuf->mem); |
3722 | return error; | | 3704 | return error; |
3723 | } | | 3705 | } |
3724 | | | 3706 | |
3725 | /* | | 3707 | /* |
3726 | * Initialize the chvol stage of this track as necessary. | | 3708 | * Initialize the chvol stage of this track as necessary. |
3727 | * If successful, it initializes the chvol stage as necessary, stores updated | | 3709 | * If successful, it initializes the chvol stage as necessary, stores updated |
3728 | * last_dst in *last_dstp in any case, and returns 0. | | 3710 | * last_dst in *last_dstp in any case, and returns 0. |
3729 | * Otherwise, it returns errno without modifying *last_dstp. | | 3711 | * Otherwise, it returns errno without modifying *last_dstp. |
3730 | */ | | 3712 | */ |
3731 | static int | | 3713 | static int |
3732 | audio_track_init_chvol(audio_track_t *track, audio_ring_t **last_dstp) | | 3714 | audio_track_init_chvol(audio_track_t *track, audio_ring_t **last_dstp) |
3733 | { | | 3715 | { |
3734 | struct audio_softc *sc; | | | |
3735 | audio_ring_t *last_dst; | | 3716 | audio_ring_t *last_dst; |
3736 | audio_ring_t *srcbuf; | | 3717 | audio_ring_t *srcbuf; |
3737 | audio_format2_t *srcfmt; | | 3718 | audio_format2_t *srcfmt; |
3738 | audio_format2_t *dstfmt; | | 3719 | audio_format2_t *dstfmt; |
3739 | audio_filter_arg_t *arg; | | 3720 | audio_filter_arg_t *arg; |
3740 | u_int len; | | 3721 | u_int len; |
3741 | int error; | | 3722 | int error; |
3742 | | | 3723 | |
3743 | KASSERT(track); | | 3724 | KASSERT(track); |
3744 | | | 3725 | |
3745 | sc = track->mixer->sc; | | | |
3746 | last_dst = *last_dstp; | | 3726 | last_dst = *last_dstp; |
3747 | dstfmt = &last_dst->fmt; | | 3727 | dstfmt = &last_dst->fmt; |
3748 | srcfmt = &track->inputfmt; | | 3728 | srcfmt = &track->inputfmt; |
3749 | srcbuf = &track->chvol.srcbuf; | | 3729 | srcbuf = &track->chvol.srcbuf; |
3750 | error = 0; | | 3730 | error = 0; |
3751 | | | 3731 | |
3752 | /* Check whether channel volume conversion is necessary. */ | | 3732 | /* Check whether channel volume conversion is necessary. */ |
3753 | bool use_chvol = false; | | 3733 | bool use_chvol = false; |
3754 | for (int ch = 0; ch < srcfmt->channels; ch++) { | | 3734 | for (int ch = 0; ch < srcfmt->channels; ch++) { |
3755 | if (track->ch_volume[ch] != 256) { | | 3735 | if (track->ch_volume[ch] != 256) { |
3756 | use_chvol = true; | | 3736 | use_chvol = true; |
3757 | break; | | 3737 | break; |
3758 | } | | 3738 | } |
3759 | } | | 3739 | } |
3760 | | | 3740 | |
3761 | if (use_chvol == true) { | | 3741 | if (use_chvol == true) { |
3762 | track->chvol.dst = last_dst; | | 3742 | track->chvol.dst = last_dst; |
3763 | track->chvol.filter = audio_track_chvol; | | 3743 | track->chvol.filter = audio_track_chvol; |
3764 | | | 3744 | |
3765 | srcbuf->fmt = *dstfmt; | | 3745 | srcbuf->fmt = *dstfmt; |
3766 | /* no format conversion occurs */ | | 3746 | /* no format conversion occurs */ |
3767 | | | 3747 | |
3768 | srcbuf->head = 0; | | 3748 | srcbuf->head = 0; |
3769 | srcbuf->used = 0; | | 3749 | srcbuf->used = 0; |
3770 | srcbuf->capacity = frame_per_block(track->mixer, &srcbuf->fmt); | | 3750 | srcbuf->capacity = frame_per_block(track->mixer, &srcbuf->fmt); |
3771 | len = auring_bytelen(srcbuf); | | 3751 | len = auring_bytelen(srcbuf); |
3772 | srcbuf->mem = audio_realloc(srcbuf->mem, len); | | 3752 | srcbuf->mem = audio_realloc(srcbuf->mem, len); |
3773 | if (srcbuf->mem == NULL) { | | | |
3774 | device_printf(sc->sc_dev, "%s: malloc(%d) failed\n", | | | |
3775 | __func__, len); | | | |
3776 | error = ENOMEM; | | | |
3777 | goto abort; | | | |
3778 | } | | | |
3779 | | | 3753 | |
3780 | arg = &track->chvol.arg; | | 3754 | arg = &track->chvol.arg; |
3781 | arg->srcfmt = &srcbuf->fmt; | | 3755 | arg->srcfmt = &srcbuf->fmt; |
3782 | arg->dstfmt = dstfmt; | | 3756 | arg->dstfmt = dstfmt; |
3783 | arg->context = track->ch_volume; | | 3757 | arg->context = track->ch_volume; |
3784 | | | 3758 | |
3785 | *last_dstp = srcbuf; | | 3759 | *last_dstp = srcbuf; |
3786 | return 0; | | 3760 | return 0; |
3787 | } | | 3761 | } |
3788 | | | 3762 | |
3789 | abort: | | | |
3790 | track->chvol.filter = NULL; | | 3763 | track->chvol.filter = NULL; |
3791 | audio_free(srcbuf->mem); | | 3764 | audio_free(srcbuf->mem); |
3792 | return error; | | 3765 | return error; |
3793 | } | | 3766 | } |
3794 | | | 3767 | |
3795 | /* | | 3768 | /* |
3796 | * Initialize the chmix stage of this track as necessary. | | 3769 | * Initialize the chmix stage of this track as necessary. |
3797 | * If successful, it initializes the chmix stage as necessary, stores updated | | 3770 | * If successful, it initializes the chmix stage as necessary, stores updated |
3798 | * last_dst in *last_dstp in any case, and returns 0. | | 3771 | * last_dst in *last_dstp in any case, and returns 0. |
3799 | * Otherwise, it returns errno without modifying *last_dstp. | | 3772 | * Otherwise, it returns errno without modifying *last_dstp. |
3800 | */ | | 3773 | */ |
3801 | static int | | 3774 | static int |
3802 | audio_track_init_chmix(audio_track_t *track, audio_ring_t **last_dstp) | | 3775 | audio_track_init_chmix(audio_track_t *track, audio_ring_t **last_dstp) |
3803 | { | | 3776 | { |
3804 | struct audio_softc *sc; | | | |
3805 | audio_ring_t *last_dst; | | 3777 | audio_ring_t *last_dst; |
3806 | audio_ring_t *srcbuf; | | 3778 | audio_ring_t *srcbuf; |
3807 | audio_format2_t *srcfmt; | | 3779 | audio_format2_t *srcfmt; |
3808 | audio_format2_t *dstfmt; | | 3780 | audio_format2_t *dstfmt; |
3809 | audio_filter_arg_t *arg; | | 3781 | audio_filter_arg_t *arg; |
3810 | u_int srcch; | | 3782 | u_int srcch; |
3811 | u_int dstch; | | 3783 | u_int dstch; |
3812 | u_int len; | | 3784 | u_int len; |
3813 | int error; | | 3785 | int error; |
3814 | | | 3786 | |
3815 | KASSERT(track); | | 3787 | KASSERT(track); |
3816 | | | 3788 | |
3817 | sc = track->mixer->sc; | | | |
3818 | last_dst = *last_dstp; | | 3789 | last_dst = *last_dstp; |
3819 | dstfmt = &last_dst->fmt; | | 3790 | dstfmt = &last_dst->fmt; |
3820 | srcfmt = &track->inputfmt; | | 3791 | srcfmt = &track->inputfmt; |
3821 | srcbuf = &track->chmix.srcbuf; | | 3792 | srcbuf = &track->chmix.srcbuf; |
3822 | error = 0; | | 3793 | error = 0; |
3823 | | | 3794 | |
3824 | srcch = srcfmt->channels; | | 3795 | srcch = srcfmt->channels; |
3825 | dstch = dstfmt->channels; | | 3796 | dstch = dstfmt->channels; |
3826 | if (srcch != dstch) { | | 3797 | if (srcch != dstch) { |
3827 | track->chmix.dst = last_dst; | | 3798 | track->chmix.dst = last_dst; |
3828 | | | 3799 | |
3829 | if (srcch >= 2 && dstch == 1) { | | 3800 | if (srcch >= 2 && dstch == 1) { |
3830 | track->chmix.filter = audio_track_chmix_mixLR; | | 3801 | track->chmix.filter = audio_track_chmix_mixLR; |
3831 | } else if (srcch == 1 && dstch >= 2) { | | 3802 | } else if (srcch == 1 && dstch >= 2) { |
3832 | track->chmix.filter = audio_track_chmix_dupLR; | | 3803 | track->chmix.filter = audio_track_chmix_dupLR; |
3833 | } else if (srcch > dstch) { | | 3804 | } else if (srcch > dstch) { |
3834 | track->chmix.filter = audio_track_chmix_shrink; | | 3805 | track->chmix.filter = audio_track_chmix_shrink; |
3835 | } else { | | 3806 | } else { |
3836 | track->chmix.filter = audio_track_chmix_expand; | | 3807 | track->chmix.filter = audio_track_chmix_expand; |
3837 | } | | 3808 | } |
3838 | | | 3809 | |
3839 | srcbuf->fmt = *dstfmt; | | 3810 | srcbuf->fmt = *dstfmt; |
3840 | srcbuf->fmt.channels = srcch; | | 3811 | srcbuf->fmt.channels = srcch; |
3841 | | | 3812 | |
3842 | srcbuf->head = 0; | | 3813 | srcbuf->head = 0; |
3843 | srcbuf->used = 0; | | 3814 | srcbuf->used = 0; |
3844 | /* XXX The buffer size should be able to calculate. */ | | 3815 | /* XXX The buffer size should be able to calculate. */ |
3845 | srcbuf->capacity = frame_per_block(track->mixer, &srcbuf->fmt); | | 3816 | srcbuf->capacity = frame_per_block(track->mixer, &srcbuf->fmt); |
3846 | len = auring_bytelen(srcbuf); | | 3817 | len = auring_bytelen(srcbuf); |
3847 | srcbuf->mem = audio_realloc(srcbuf->mem, len); | | 3818 | srcbuf->mem = audio_realloc(srcbuf->mem, len); |
3848 | if (srcbuf->mem == NULL) { | | | |
3849 | device_printf(sc->sc_dev, "%s: malloc(%d) failed\n", | | | |
3850 | __func__, len); | | | |
3851 | error = ENOMEM; | | | |
3852 | goto abort; | | | |
3853 | } | | | |
3854 | | | 3819 | |
3855 | arg = &track->chmix.arg; | | 3820 | arg = &track->chmix.arg; |
3856 | arg->srcfmt = &srcbuf->fmt; | | 3821 | arg->srcfmt = &srcbuf->fmt; |
3857 | arg->dstfmt = dstfmt; | | 3822 | arg->dstfmt = dstfmt; |
3858 | arg->context = NULL; | | 3823 | arg->context = NULL; |
3859 | | | 3824 | |
3860 | *last_dstp = srcbuf; | | 3825 | *last_dstp = srcbuf; |
3861 | return 0; | | 3826 | return 0; |
3862 | } | | 3827 | } |
3863 | | | 3828 | |
3864 | abort: | | | |
3865 | track->chmix.filter = NULL; | | 3829 | track->chmix.filter = NULL; |
3866 | audio_free(srcbuf->mem); | | 3830 | audio_free(srcbuf->mem); |
3867 | return error; | | 3831 | return error; |
3868 | } | | 3832 | } |
3869 | | | 3833 | |
3870 | /* | | 3834 | /* |
3871 | * Initialize the freq stage of this track as necessary. | | 3835 | * Initialize the freq stage of this track as necessary. |
3872 | * If successful, it initializes the freq stage as necessary, stores updated | | 3836 | * If successful, it initializes the freq stage as necessary, stores updated |
3873 | * last_dst in *last_dstp in any case, and returns 0. | | 3837 | * last_dst in *last_dstp in any case, and returns 0. |
3874 | * Otherwise, it returns errno without modifying *last_dstp. | | 3838 | * Otherwise, it returns errno without modifying *last_dstp. |
3875 | */ | | 3839 | */ |
3876 | static int | | 3840 | static int |
3877 | audio_track_init_freq(audio_track_t *track, audio_ring_t **last_dstp) | | 3841 | audio_track_init_freq(audio_track_t *track, audio_ring_t **last_dstp) |
3878 | { | | 3842 | { |
3879 | struct audio_softc *sc; | | | |
3880 | audio_ring_t *last_dst; | | 3843 | audio_ring_t *last_dst; |
3881 | audio_ring_t *srcbuf; | | 3844 | audio_ring_t *srcbuf; |
3882 | audio_format2_t *srcfmt; | | 3845 | audio_format2_t *srcfmt; |
3883 | audio_format2_t *dstfmt; | | 3846 | audio_format2_t *dstfmt; |
3884 | audio_filter_arg_t *arg; | | 3847 | audio_filter_arg_t *arg; |
3885 | uint32_t srcfreq; | | 3848 | uint32_t srcfreq; |
3886 | uint32_t dstfreq; | | 3849 | uint32_t dstfreq; |
3887 | u_int dst_capacity; | | 3850 | u_int dst_capacity; |
3888 | u_int mod; | | 3851 | u_int mod; |
3889 | u_int len; | | 3852 | u_int len; |
3890 | int error; | | 3853 | int error; |
3891 | | | 3854 | |
3892 | KASSERT(track); | | 3855 | KASSERT(track); |
3893 | | | 3856 | |
3894 | sc = track->mixer->sc; | | | |
3895 | last_dst = *last_dstp; | | 3857 | last_dst = *last_dstp; |
3896 | dstfmt = &last_dst->fmt; | | 3858 | dstfmt = &last_dst->fmt; |
3897 | srcfmt = &track->inputfmt; | | 3859 | srcfmt = &track->inputfmt; |
3898 | srcbuf = &track->freq.srcbuf; | | 3860 | srcbuf = &track->freq.srcbuf; |
3899 | error = 0; | | 3861 | error = 0; |
3900 | | | 3862 | |
3901 | srcfreq = srcfmt->sample_rate; | | 3863 | srcfreq = srcfmt->sample_rate; |
3902 | dstfreq = dstfmt->sample_rate; | | 3864 | dstfreq = dstfmt->sample_rate; |
3903 | if (srcfreq != dstfreq) { | | 3865 | if (srcfreq != dstfreq) { |
3904 | track->freq.dst = last_dst; | | 3866 | track->freq.dst = last_dst; |
3905 | | | 3867 | |
3906 | memset(track->freq_prev, 0, sizeof(track->freq_prev)); | | 3868 | memset(track->freq_prev, 0, sizeof(track->freq_prev)); |
3907 | memset(track->freq_curr, 0, sizeof(track->freq_curr)); | | 3869 | memset(track->freq_curr, 0, sizeof(track->freq_curr)); |
3908 | | | 3870 | |
3909 | /* freq_step is the ratio of src/dst when let dst 65536. */ | | 3871 | /* freq_step is the ratio of src/dst when let dst 65536. */ |
3910 | track->freq_step = (uint64_t)srcfreq * 65536 / dstfreq; | | 3872 | track->freq_step = (uint64_t)srcfreq * 65536 / dstfreq; |
3911 | | | 3873 | |
3912 | dst_capacity = frame_per_block(track->mixer, dstfmt); | | 3874 | dst_capacity = frame_per_block(track->mixer, dstfmt); |
3913 | mod = (uint64_t)srcfreq * 65536 % dstfreq; | | 3875 | mod = (uint64_t)srcfreq * 65536 % dstfreq; |
3914 | track->freq_leap = (mod * dst_capacity + dstfreq / 2) / dstfreq; | | 3876 | track->freq_leap = (mod * dst_capacity + dstfreq / 2) / dstfreq; |
3915 | | | 3877 | |
3916 | if (track->freq_step < 65536) { | | 3878 | if (track->freq_step < 65536) { |
3917 | track->freq.filter = audio_track_freq_up; | | 3879 | track->freq.filter = audio_track_freq_up; |
3918 | /* In order to carry at the first time. */ | | 3880 | /* In order to carry at the first time. */ |
3919 | track->freq_current = 65536; | | 3881 | track->freq_current = 65536; |
3920 | } else { | | 3882 | } else { |
3921 | track->freq.filter = audio_track_freq_down; | | 3883 | track->freq.filter = audio_track_freq_down; |
3922 | track->freq_current = 0; | | 3884 | track->freq_current = 0; |
3923 | } | | 3885 | } |
3924 | | | 3886 | |
3925 | srcbuf->fmt = *dstfmt; | | 3887 | srcbuf->fmt = *dstfmt; |
3926 | srcbuf->fmt.sample_rate = srcfreq; | | 3888 | srcbuf->fmt.sample_rate = srcfreq; |
3927 | | | 3889 | |
3928 | srcbuf->head = 0; | | 3890 | srcbuf->head = 0; |
3929 | srcbuf->used = 0; | | 3891 | srcbuf->used = 0; |
3930 | srcbuf->capacity = frame_per_block(track->mixer, &srcbuf->fmt); | | 3892 | srcbuf->capacity = frame_per_block(track->mixer, &srcbuf->fmt); |
3931 | len = auring_bytelen(srcbuf); | | 3893 | len = auring_bytelen(srcbuf); |
3932 | srcbuf->mem = audio_realloc(srcbuf->mem, len); | | 3894 | srcbuf->mem = audio_realloc(srcbuf->mem, len); |
3933 | if (srcbuf->mem == NULL) { | | | |
3934 | device_printf(sc->sc_dev, "%s: malloc(%d) failed\n", | | | |
3935 | __func__, len); | | | |
3936 | error = ENOMEM; | | | |
3937 | goto abort; | | | |
3938 | } | | | |
3939 | | | 3895 | |
3940 | arg = &track->freq.arg; | | 3896 | arg = &track->freq.arg; |
3941 | arg->srcfmt = &srcbuf->fmt; | | 3897 | arg->srcfmt = &srcbuf->fmt; |
3942 | arg->dstfmt = dstfmt;/*&last_dst->fmt;*/ | | 3898 | arg->dstfmt = dstfmt;/*&last_dst->fmt;*/ |
3943 | arg->context = track; | | 3899 | arg->context = track; |
3944 | | | 3900 | |
3945 | *last_dstp = srcbuf; | | 3901 | *last_dstp = srcbuf; |
3946 | return 0; | | 3902 | return 0; |
3947 | } | | 3903 | } |
3948 | | | 3904 | |
3949 | abort: | | | |
3950 | track->freq.filter = NULL; | | 3905 | track->freq.filter = NULL; |
3951 | audio_free(srcbuf->mem); | | 3906 | audio_free(srcbuf->mem); |
3952 | return error; | | 3907 | return error; |
3953 | } | | 3908 | } |
3954 | | | 3909 | |
3955 | /* | | 3910 | /* |
3956 | * When playing back: (e.g. if codec and freq stage are valid) | | 3911 | * When playing back: (e.g. if codec and freq stage are valid) |
3957 | * | | 3912 | * |
3958 | * write | | 3913 | * write |
3959 | * | uiomove | | 3914 | * | uiomove |
3960 | * v | | 3915 | * v |
3961 | * usrbuf [...............] byte ring buffer (mmap-able) | | 3916 | * usrbuf [...............] byte ring buffer (mmap-able) |
3962 | * | memcpy | | 3917 | * | memcpy |
3963 | * v | | 3918 | * v |
3964 | * codec.srcbuf[....] 1 block (ring) buffer <-- stage input | | 3919 | * codec.srcbuf[....] 1 block (ring) buffer <-- stage input |
3965 | * .dst ----+ | | 3920 | * .dst ----+ |
3966 | * | convert | | 3921 | * | convert |
3967 | * v | | 3922 | * v |
3968 | * freq.srcbuf [....] 1 block (ring) buffer | | 3923 | * freq.srcbuf [....] 1 block (ring) buffer |
3969 | * .dst ----+ | | 3924 | * .dst ----+ |
3970 | * | convert | | 3925 | * | convert |
3971 | * v | | 3926 | * v |
3972 | * outbuf [...............] NBLKOUT blocks ring buffer | | 3927 | * outbuf [...............] NBLKOUT blocks ring buffer |
3973 | * | | 3928 | * |
3974 | * | | 3929 | * |
3975 | * When recording: | | 3930 | * When recording: |
3976 | * | | 3931 | * |
3977 | * freq.srcbuf [...............] NBLKOUT blocks ring buffer <-- stage input | | 3932 | * freq.srcbuf [...............] NBLKOUT blocks ring buffer <-- stage input |
3978 | * .dst ----+ | | 3933 | * .dst ----+ |
3979 | * | convert | | 3934 | * | convert |
3980 | * v | | 3935 | * v |
3981 | * codec.srcbuf[.....] 1 block (ring) buffer | | 3936 | * codec.srcbuf[.....] 1 block (ring) buffer |
3982 | * .dst ----+ | | 3937 | * .dst ----+ |
3983 | * | convert | | 3938 | * | convert |
3984 | * v | | 3939 | * v |
3985 | * outbuf [.....] 1 block (ring) buffer | | 3940 | * outbuf [.....] 1 block (ring) buffer |
3986 | * | memcpy | | 3941 | * | memcpy |
3987 | * v | | 3942 | * v |
3988 | * usrbuf [...............] byte ring buffer (mmap-able *) | | 3943 | * usrbuf [...............] byte ring buffer (mmap-able *) |
3989 | * | uiomove | | 3944 | * | uiomove |
3990 | * v | | 3945 | * v |
3991 | * read | | 3946 | * read |
3992 | * | | 3947 | * |
3993 | * *: usrbuf for recording is also mmap-able due to symmetry with | | 3948 | * *: usrbuf for recording is also mmap-able due to symmetry with |
3994 | * playback buffer, but for now mmap will never happen for recording. | | 3949 | * playback buffer, but for now mmap will never happen for recording. |
3995 | */ | | 3950 | */ |
3996 | | | 3951 | |
3997 | /* | | 3952 | /* |
3998 | * Set the userland format of this track. | | 3953 | * Set the userland format of this track. |
3999 | * usrfmt argument should be parameter verified with audio_check_params(). | | 3954 | * usrfmt argument should be parameter verified with audio_check_params(). |
4000 | * It will release and reallocate all internal conversion buffers. | | 3955 | * It will release and reallocate all internal conversion buffers. |
4001 | * It returns 0 if successful. Otherwise it returns errno with clearing all | | 3956 | * It returns 0 if successful. Otherwise it returns errno with clearing all |
4002 | * internal buffers. | | 3957 | * internal buffers. |
4003 | * It must be called without sc_intr_lock since uvm_* routines require non | | 3958 | * It must be called without sc_intr_lock since uvm_* routines require non |
4004 | * intr_lock state. | | 3959 | * intr_lock state. |
4005 | * It must be called with track lock held since it may release and reallocate | | 3960 | * It must be called with track lock held since it may release and reallocate |
4006 | * outbuf. | | 3961 | * outbuf. |
4007 | */ | | 3962 | */ |
4008 | static int | | 3963 | static int |
4009 | audio_track_set_format(audio_track_t *track, audio_format2_t *usrfmt) | | 3964 | audio_track_set_format(audio_track_t *track, audio_format2_t *usrfmt) |
4010 | { | | 3965 | { |
4011 | struct audio_softc *sc; | | 3966 | struct audio_softc *sc; |
4012 | u_int newbufsize; | | 3967 | u_int newbufsize; |
4013 | u_int oldblksize; | | 3968 | u_int oldblksize; |
4014 | u_int len; | | 3969 | u_int len; |
4015 | int error; | | 3970 | int error; |
4016 | | | 3971 | |
4017 | KASSERT(track); | | 3972 | KASSERT(track); |
4018 | sc = track->mixer->sc; | | 3973 | sc = track->mixer->sc; |
4019 | | | 3974 | |
4020 | /* usrbuf is the closest buffer to the userland. */ | | 3975 | /* usrbuf is the closest buffer to the userland. */ |
4021 | track->usrbuf.fmt = *usrfmt; | | 3976 | track->usrbuf.fmt = *usrfmt; |
4022 | | | 3977 | |
4023 | /* | | 3978 | /* |
4024 | * For references, one block size (in 40msec) is: | | 3979 | * For references, one block size (in 40msec) is: |
4025 | * 320 bytes = 204 blocks/64KB for mulaw/8kHz/1ch | | 3980 | * 320 bytes = 204 blocks/64KB for mulaw/8kHz/1ch |
4026 | * 7680 bytes = 8 blocks/64KB for s16/48kHz/2ch | | 3981 | * 7680 bytes = 8 blocks/64KB for s16/48kHz/2ch |
4027 | * 30720 bytes = 90 KB/3blocks for s16/48kHz/8ch | | 3982 | * 30720 bytes = 90 KB/3blocks for s16/48kHz/8ch |
4028 | * 61440 bytes = 180 KB/3blocks for s16/96kHz/8ch | | 3983 | * 61440 bytes = 180 KB/3blocks for s16/96kHz/8ch |
4029 | * 245760 bytes = 720 KB/3blocks for s32/192kHz/8ch | | 3984 | * 245760 bytes = 720 KB/3blocks for s32/192kHz/8ch |
4030 | * | | 3985 | * |
4031 | * For example, | | 3986 | * For example, |
4032 | * 1) If usrbuf_blksize = 7056 (s16/44.1k/2ch) and PAGE_SIZE = 8192, | | 3987 | * 1) If usrbuf_blksize = 7056 (s16/44.1k/2ch) and PAGE_SIZE = 8192, |
4033 | * newbufsize = rounddown(65536 / 7056) = 63504 | | 3988 | * newbufsize = rounddown(65536 / 7056) = 63504 |
4034 | * newvsize = roundup2(63504, PAGE_SIZE) = 65536 | | 3989 | * newvsize = roundup2(63504, PAGE_SIZE) = 65536 |
4035 | * Therefore it maps 8 * 8K pages and usrbuf->capacity = 63504. | | 3990 | * Therefore it maps 8 * 8K pages and usrbuf->capacity = 63504. |
4036 | * | | 3991 | * |
4037 | * 2) If usrbuf_blksize = 7680 (s16/48k/2ch) and PAGE_SIZE = 4096, | | 3992 | * 2) If usrbuf_blksize = 7680 (s16/48k/2ch) and PAGE_SIZE = 4096, |
4038 | * newbufsize = rounddown(65536 / 7680) = 61440 | | 3993 | * newbufsize = rounddown(65536 / 7680) = 61440 |
4039 | * newvsize = roundup2(61440, PAGE_SIZE) = 61440 (= 15 pages) | | 3994 | * newvsize = roundup2(61440, PAGE_SIZE) = 61440 (= 15 pages) |
4040 | * Therefore it maps 15 * 4K pages and usrbuf->capacity = 61440. | | 3995 | * Therefore it maps 15 * 4K pages and usrbuf->capacity = 61440. |
4041 | */ | | 3996 | */ |
4042 | oldblksize = track->usrbuf_blksize; | | 3997 | oldblksize = track->usrbuf_blksize; |
4043 | track->usrbuf_blksize = frametobyte(&track->usrbuf.fmt, | | 3998 | track->usrbuf_blksize = frametobyte(&track->usrbuf.fmt, |
4044 | frame_per_block(track->mixer, &track->usrbuf.fmt)); | | 3999 | frame_per_block(track->mixer, &track->usrbuf.fmt)); |
4045 | track->usrbuf.head = 0; | | 4000 | track->usrbuf.head = 0; |
4046 | track->usrbuf.used = 0; | | 4001 | track->usrbuf.used = 0; |
4047 | newbufsize = MAX(track->usrbuf_blksize * AUMINNOBLK, 65536); | | 4002 | newbufsize = MAX(track->usrbuf_blksize * AUMINNOBLK, 65536); |
4048 | newbufsize = rounddown(newbufsize, track->usrbuf_blksize); | | 4003 | newbufsize = rounddown(newbufsize, track->usrbuf_blksize); |
4049 | error = audio_realloc_usrbuf(track, newbufsize); | | 4004 | error = audio_realloc_usrbuf(track, newbufsize); |
4050 | if (error) { | | 4005 | if (error) { |
4051 | device_printf(sc->sc_dev, "malloc usrbuf(%d) failed\n", | | 4006 | device_printf(sc->sc_dev, "malloc usrbuf(%d) failed\n", |
4052 | newbufsize); | | 4007 | newbufsize); |
4053 | goto error; | | 4008 | goto error; |
4054 | } | | 4009 | } |
4055 | | | 4010 | |
4056 | /* Recalc water mark. */ | | 4011 | /* Recalc water mark. */ |
4057 | if (track->usrbuf_blksize != oldblksize) { | | 4012 | if (track->usrbuf_blksize != oldblksize) { |
4058 | if (audio_track_is_playback(track)) { | | 4013 | if (audio_track_is_playback(track)) { |
4059 | /* Set high at 100%, low at 75%. */ | | 4014 | /* Set high at 100%, low at 75%. */ |
4060 | track->usrbuf_usedhigh = track->usrbuf.capacity; | | 4015 | track->usrbuf_usedhigh = track->usrbuf.capacity; |
4061 | track->usrbuf_usedlow = track->usrbuf.capacity * 3 / 4; | | 4016 | track->usrbuf_usedlow = track->usrbuf.capacity * 3 / 4; |
4062 | } else { | | 4017 | } else { |
4063 | /* Set high at 100% minus 1block(?), low at 0% */ | | 4018 | /* Set high at 100% minus 1block(?), low at 0% */ |
4064 | track->usrbuf_usedhigh = track->usrbuf.capacity - | | 4019 | track->usrbuf_usedhigh = track->usrbuf.capacity - |
4065 | track->usrbuf_blksize; | | 4020 | track->usrbuf_blksize; |
4066 | track->usrbuf_usedlow = 0; | | 4021 | track->usrbuf_usedlow = 0; |
4067 | } | | 4022 | } |
4068 | } | | 4023 | } |
4069 | | | 4024 | |
4070 | /* Stage buffer */ | | 4025 | /* Stage buffer */ |
4071 | audio_ring_t *last_dst = &track->outbuf; | | 4026 | audio_ring_t *last_dst = &track->outbuf; |
4072 | if (audio_track_is_playback(track)) { | | 4027 | if (audio_track_is_playback(track)) { |
4073 | /* On playback, initialize from the mixer side in order. */ | | 4028 | /* On playback, initialize from the mixer side in order. */ |
4074 | track->inputfmt = *usrfmt; | | 4029 | track->inputfmt = *usrfmt; |
4075 | track->outbuf.fmt = track->mixer->track_fmt; | | 4030 | track->outbuf.fmt = track->mixer->track_fmt; |
4076 | | | 4031 | |
4077 | if ((error = audio_track_init_freq(track, &last_dst)) != 0) | | 4032 | if ((error = audio_track_init_freq(track, &last_dst)) != 0) |
4078 | goto error; | | 4033 | goto error; |
4079 | if ((error = audio_track_init_chmix(track, &last_dst)) != 0) | | 4034 | if ((error = audio_track_init_chmix(track, &last_dst)) != 0) |
4080 | goto error; | | 4035 | goto error; |
4081 | if ((error = audio_track_init_chvol(track, &last_dst)) != 0) | | 4036 | if ((error = audio_track_init_chvol(track, &last_dst)) != 0) |
4082 | goto error; | | 4037 | goto error; |
4083 | if ((error = audio_track_init_codec(track, &last_dst)) != 0) | | 4038 | if ((error = audio_track_init_codec(track, &last_dst)) != 0) |
4084 | goto error; | | 4039 | goto error; |
4085 | } else { | | 4040 | } else { |
4086 | /* On recording, initialize from userland side in order. */ | | 4041 | /* On recording, initialize from userland side in order. */ |
4087 | track->inputfmt = track->mixer->track_fmt; | | 4042 | track->inputfmt = track->mixer->track_fmt; |
4088 | track->outbuf.fmt = *usrfmt; | | 4043 | track->outbuf.fmt = *usrfmt; |
4089 | | | 4044 | |
4090 | if ((error = audio_track_init_codec(track, &last_dst)) != 0) | | 4045 | if ((error = audio_track_init_codec(track, &last_dst)) != 0) |
4091 | goto error; | | 4046 | goto error; |
4092 | if ((error = audio_track_init_chvol(track, &last_dst)) != 0) | | 4047 | if ((error = audio_track_init_chvol(track, &last_dst)) != 0) |
4093 | goto error; | | 4048 | goto error; |
4094 | if ((error = audio_track_init_chmix(track, &last_dst)) != 0) | | 4049 | if ((error = audio_track_init_chmix(track, &last_dst)) != 0) |
4095 | goto error; | | 4050 | goto error; |
4096 | if ((error = audio_track_init_freq(track, &last_dst)) != 0) | | 4051 | if ((error = audio_track_init_freq(track, &last_dst)) != 0) |
4097 | goto error; | | 4052 | goto error; |
4098 | } | | 4053 | } |
4099 | #if 0 | | 4054 | #if 0 |
4100 | /* debug */ | | 4055 | /* debug */ |
4101 | if (track->freq.filter) { | | 4056 | if (track->freq.filter) { |
4102 | audio_print_format2("freq src", &track->freq.srcbuf.fmt); | | 4057 | audio_print_format2("freq src", &track->freq.srcbuf.fmt); |
4103 | audio_print_format2("freq dst", &track->freq.dst->fmt); | | 4058 | audio_print_format2("freq dst", &track->freq.dst->fmt); |
4104 | } | | 4059 | } |
4105 | if (track->chmix.filter) { | | 4060 | if (track->chmix.filter) { |
4106 | audio_print_format2("chmix src", &track->chmix.srcbuf.fmt); | | 4061 | audio_print_format2("chmix src", &track->chmix.srcbuf.fmt); |
4107 | audio_print_format2("chmix dst", &track->chmix.dst->fmt); | | 4062 | audio_print_format2("chmix dst", &track->chmix.dst->fmt); |
4108 | } | | 4063 | } |
4109 | if (track->chvol.filter) { | | 4064 | if (track->chvol.filter) { |
4110 | audio_print_format2("chvol src", &track->chvol.srcbuf.fmt); | | 4065 | audio_print_format2("chvol src", &track->chvol.srcbuf.fmt); |
4111 | audio_print_format2("chvol dst", &track->chvol.dst->fmt); | | 4066 | audio_print_format2("chvol dst", &track->chvol.dst->fmt); |
4112 | } | | 4067 | } |
4113 | if (track->codec.filter) { | | 4068 | if (track->codec.filter) { |
4114 | audio_print_format2("codec src", &track->codec.srcbuf.fmt); | | 4069 | audio_print_format2("codec src", &track->codec.srcbuf.fmt); |
4115 | audio_print_format2("codec dst", &track->codec.dst->fmt); | | 4070 | audio_print_format2("codec dst", &track->codec.dst->fmt); |
4116 | } | | 4071 | } |
4117 | #endif | | 4072 | #endif |
4118 | | | 4073 | |
4119 | /* Stage input buffer */ | | 4074 | /* Stage input buffer */ |
4120 | track->input = last_dst; | | 4075 | track->input = last_dst; |
4121 | | | 4076 | |
4122 | /* | | 4077 | /* |
4123 | * On the recording track, make the first stage a ring buffer. | | 4078 | * On the recording track, make the first stage a ring buffer. |
4124 | * XXX is there a better way? | | 4079 | * XXX is there a better way? |
4125 | */ | | 4080 | */ |
4126 | if (audio_track_is_record(track)) { | | 4081 | if (audio_track_is_record(track)) { |
4127 | track->input->capacity = NBLKOUT * | | 4082 | track->input->capacity = NBLKOUT * |
4128 | frame_per_block(track->mixer, &track->input->fmt); | | 4083 | frame_per_block(track->mixer, &track->input->fmt); |
4129 | len = auring_bytelen(track->input); | | 4084 | len = auring_bytelen(track->input); |
4130 | track->input->mem = audio_realloc(track->input->mem, len); | | 4085 | track->input->mem = audio_realloc(track->input->mem, len); |
4131 | if (track->input->mem == NULL) { | | | |
4132 | device_printf(sc->sc_dev, "malloc input(%d) failed\n", | | | |
4133 | len); | | | |
4134 | error = ENOMEM; | | | |
4135 | goto error; | | | |
4136 | } | | | |
4137 | } | | 4086 | } |
4138 | | | 4087 | |
4139 | /* | | 4088 | /* |
4140 | * Output buffer. | | 4089 | * Output buffer. |
4141 | * On the playback track, its capacity is NBLKOUT blocks. | | 4090 | * On the playback track, its capacity is NBLKOUT blocks. |
4142 | * On the recording track, its capacity is 1 block. | | 4091 | * On the recording track, its capacity is 1 block. |
4143 | */ | | 4092 | */ |
4144 | track->outbuf.head = 0; | | 4093 | track->outbuf.head = 0; |
4145 | track->outbuf.used = 0; | | 4094 | track->outbuf.used = 0; |
4146 | track->outbuf.capacity = frame_per_block(track->mixer, | | 4095 | track->outbuf.capacity = frame_per_block(track->mixer, |
4147 | &track->outbuf.fmt); | | 4096 | &track->outbuf.fmt); |
4148 | if (audio_track_is_playback(track)) | | 4097 | if (audio_track_is_playback(track)) |
4149 | track->outbuf.capacity *= NBLKOUT; | | 4098 | track->outbuf.capacity *= NBLKOUT; |
4150 | len = auring_bytelen(&track->outbuf); | | 4099 | len = auring_bytelen(&track->outbuf); |
4151 | track->outbuf.mem = audio_realloc(track->outbuf.mem, len); | | 4100 | track->outbuf.mem = audio_realloc(track->outbuf.mem, len); |
4152 | if (track->outbuf.mem == NULL) { | | 4101 | if (track->outbuf.mem == NULL) { |
4153 | device_printf(sc->sc_dev, "malloc outbuf(%d) failed\n", len); | | 4102 | device_printf(sc->sc_dev, "malloc outbuf(%d) failed\n", len); |
4154 | error = ENOMEM; | | 4103 | error = ENOMEM; |
4155 | goto error; | | 4104 | goto error; |
4156 | } | | 4105 | } |
4157 | | | 4106 | |
4158 | #if defined(AUDIO_DEBUG) | | 4107 | #if defined(AUDIO_DEBUG) |
4159 | if (audiodebug >= 3) { | | 4108 | if (audiodebug >= 3) { |
4160 | struct audio_track_debugbuf m; | | 4109 | struct audio_track_debugbuf m; |
4161 | | | 4110 | |
4162 | memset(&m, 0, sizeof(m)); | | 4111 | memset(&m, 0, sizeof(m)); |
4163 | snprintf(m.outbuf, sizeof(m.outbuf), " out=%d", | | 4112 | snprintf(m.outbuf, sizeof(m.outbuf), " out=%d", |
4164 | track->outbuf.capacity * frametobyte(&track->outbuf.fmt,1)); | | 4113 | track->outbuf.capacity * frametobyte(&track->outbuf.fmt,1)); |
4165 | if (track->freq.filter) | | 4114 | if (track->freq.filter) |
4166 | snprintf(m.freq, sizeof(m.freq), " freq=%d", | | 4115 | snprintf(m.freq, sizeof(m.freq), " freq=%d", |
4167 | track->freq.srcbuf.capacity * | | 4116 | track->freq.srcbuf.capacity * |
4168 | frametobyte(&track->freq.srcbuf.fmt, 1)); | | 4117 | frametobyte(&track->freq.srcbuf.fmt, 1)); |
4169 | if (track->chmix.filter) | | 4118 | if (track->chmix.filter) |
4170 | snprintf(m.chmix, sizeof(m.chmix), " chmix=%d", | | 4119 | snprintf(m.chmix, sizeof(m.chmix), " chmix=%d", |
4171 | track->chmix.srcbuf.capacity * | | 4120 | track->chmix.srcbuf.capacity * |
4172 | frametobyte(&track->chmix.srcbuf.fmt, 1)); | | 4121 | frametobyte(&track->chmix.srcbuf.fmt, 1)); |
4173 | if (track->chvol.filter) | | 4122 | if (track->chvol.filter) |
4174 | snprintf(m.chvol, sizeof(m.chvol), " chvol=%d", | | 4123 | snprintf(m.chvol, sizeof(m.chvol), " chvol=%d", |
4175 | track->chvol.srcbuf.capacity * | | 4124 | track->chvol.srcbuf.capacity * |
4176 | frametobyte(&track->chvol.srcbuf.fmt, 1)); | | 4125 | frametobyte(&track->chvol.srcbuf.fmt, 1)); |
4177 | if (track->codec.filter) | | 4126 | if (track->codec.filter) |
4178 | snprintf(m.codec, sizeof(m.codec), " codec=%d", | | 4127 | snprintf(m.codec, sizeof(m.codec), " codec=%d", |
4179 | track->codec.srcbuf.capacity * | | 4128 | track->codec.srcbuf.capacity * |
4180 | frametobyte(&track->codec.srcbuf.fmt, 1)); | | 4129 | frametobyte(&track->codec.srcbuf.fmt, 1)); |
4181 | snprintf(m.usrbuf, sizeof(m.usrbuf), | | 4130 | snprintf(m.usrbuf, sizeof(m.usrbuf), |
4182 | " usr=%d", track->usrbuf.capacity); | | 4131 | " usr=%d", track->usrbuf.capacity); |
4183 | | | 4132 | |
4184 | if (audio_track_is_playback(track)) { | | 4133 | if (audio_track_is_playback(track)) { |
4185 | TRACET(0, track, "bufsize%s%s%s%s%s%s", | | 4134 | TRACET(0, track, "bufsize%s%s%s%s%s%s", |
4186 | m.outbuf, m.freq, m.chmix, | | 4135 | m.outbuf, m.freq, m.chmix, |
4187 | m.chvol, m.codec, m.usrbuf); | | 4136 | m.chvol, m.codec, m.usrbuf); |
4188 | } else { | | 4137 | } else { |
4189 | TRACET(0, track, "bufsize%s%s%s%s%s%s", | | 4138 | TRACET(0, track, "bufsize%s%s%s%s%s%s", |
4190 | m.freq, m.chmix, m.chvol, | | 4139 | m.freq, m.chmix, m.chvol, |
4191 | m.codec, m.outbuf, m.usrbuf); | | 4140 | m.codec, m.outbuf, m.usrbuf); |
4192 | } | | 4141 | } |
4193 | } | | 4142 | } |
4194 | #endif | | 4143 | #endif |
4195 | return 0; | | 4144 | return 0; |
4196 | | | 4145 | |
4197 | error: | | 4146 | error: |
4198 | audio_free_usrbuf(track); | | 4147 | audio_free_usrbuf(track); |
4199 | audio_free(track->codec.srcbuf.mem); | | 4148 | audio_free(track->codec.srcbuf.mem); |
4200 | audio_free(track->chvol.srcbuf.mem); | | 4149 | audio_free(track->chvol.srcbuf.mem); |
4201 | audio_free(track->chmix.srcbuf.mem); | | 4150 | audio_free(track->chmix.srcbuf.mem); |
4202 | audio_free(track->freq.srcbuf.mem); | | 4151 | audio_free(track->freq.srcbuf.mem); |
4203 | audio_free(track->outbuf.mem); | | 4152 | audio_free(track->outbuf.mem); |
4204 | return error; | | 4153 | return error; |
4205 | } | | 4154 | } |
4206 | | | 4155 | |
4207 | /* | | 4156 | /* |
4208 | * Fill silence frames (as the internal format) up to 1 block | | 4157 | * Fill silence frames (as the internal format) up to 1 block |
4209 | * if the ring is not empty and less than 1 block. | | 4158 | * if the ring is not empty and less than 1 block. |
4210 | * It returns the number of appended frames. | | 4159 | * It returns the number of appended frames. |
4211 | */ | | 4160 | */ |
4212 | static int | | 4161 | static int |
4213 | audio_append_silence(audio_track_t *track, audio_ring_t *ring) | | 4162 | audio_append_silence(audio_track_t *track, audio_ring_t *ring) |
4214 | { | | 4163 | { |
4215 | int fpb; | | 4164 | int fpb; |
4216 | int n; | | 4165 | int n; |
4217 | | | 4166 | |
4218 | KASSERT(track); | | 4167 | KASSERT(track); |
4219 | KASSERT(audio_format2_is_internal(&ring->fmt)); | | 4168 | KASSERT(audio_format2_is_internal(&ring->fmt)); |
4220 | | | 4169 | |
4221 | /* XXX is n correct? */ | | 4170 | /* XXX is n correct? */ |
4222 | /* XXX memset uses frametobyte()? */ | | 4171 | /* XXX memset uses frametobyte()? */ |
4223 | | | 4172 | |
4224 | if (ring->used == 0) | | 4173 | if (ring->used == 0) |
4225 | return 0; | | 4174 | return 0; |
4226 | | | 4175 | |
4227 | fpb = frame_per_block(track->mixer, &ring->fmt); | | 4176 | fpb = frame_per_block(track->mixer, &ring->fmt); |
4228 | if (ring->used >= fpb) | | 4177 | if (ring->used >= fpb) |
4229 | return 0; | | 4178 | return 0; |
4230 | | | 4179 | |
4231 | n = (ring->capacity - ring->used) % fpb; | | 4180 | n = (ring->capacity - ring->used) % fpb; |
4232 | | | 4181 | |
4233 | KASSERT(auring_get_contig_free(ring) >= n); | | 4182 | KASSERT(auring_get_contig_free(ring) >= n); |
4234 | | | 4183 | |
4235 | memset(auring_tailptr_aint(ring), 0, | | 4184 | memset(auring_tailptr_aint(ring), 0, |
4236 | n * ring->fmt.channels * sizeof(aint_t)); | | 4185 | n * ring->fmt.channels * sizeof(aint_t)); |
4237 | auring_push(ring, n); | | 4186 | auring_push(ring, n); |
4238 | return n; | | 4187 | return n; |
4239 | } | | 4188 | } |
4240 | | | 4189 | |
4241 | /* | | 4190 | /* |
4242 | * Execute the conversion stage. | | 4191 | * Execute the conversion stage. |
4243 | * It prepares arg from this stage and executes stage->filter. | | 4192 | * It prepares arg from this stage and executes stage->filter. |
4244 | * It must be called only if stage->filter is not NULL. | | 4193 | * It must be called only if stage->filter is not NULL. |
4245 | * | | 4194 | * |
4246 | * For stages other than frequency conversion, the function increments | | 4195 | * For stages other than frequency conversion, the function increments |
4247 | * src and dst counters here. For frequency conversion stage, on the | | 4196 | * src and dst counters here. For frequency conversion stage, on the |
4248 | * other hand, the function does not touch src and dst counters and | | 4197 | * other hand, the function does not touch src and dst counters and |
4249 | * filter side has to increment them. | | 4198 | * filter side has to increment them. |
4250 | */ | | 4199 | */ |
4251 | static void | | 4200 | static void |
4252 | audio_apply_stage(audio_track_t *track, audio_stage_t *stage, bool isfreq) | | 4201 | audio_apply_stage(audio_track_t *track, audio_stage_t *stage, bool isfreq) |
4253 | { | | 4202 | { |
4254 | audio_filter_arg_t *arg; | | 4203 | audio_filter_arg_t *arg; |
4255 | int srccount; | | 4204 | int srccount; |
4256 | int dstcount; | | 4205 | int dstcount; |
4257 | int count; | | 4206 | int count; |
4258 | | | 4207 | |
4259 | KASSERT(track); | | 4208 | KASSERT(track); |
4260 | KASSERT(stage->filter); | | 4209 | KASSERT(stage->filter); |
4261 | | | 4210 | |
4262 | srccount = auring_get_contig_used(&stage->srcbuf); | | 4211 | srccount = auring_get_contig_used(&stage->srcbuf); |
4263 | dstcount = auring_get_contig_free(stage->dst); | | 4212 | dstcount = auring_get_contig_free(stage->dst); |
4264 | | | 4213 | |
4265 | if (isfreq) { | | 4214 | if (isfreq) { |
4266 | KASSERTMSG(srccount > 0, "freq but srccount == %d", srccount); | | 4215 | KASSERTMSG(srccount > 0, "freq but srccount == %d", srccount); |
4267 | count = uimin(dstcount, track->mixer->frames_per_block); | | 4216 | count = uimin(dstcount, track->mixer->frames_per_block); |
4268 | } else { | | 4217 | } else { |
4269 | count = uimin(srccount, dstcount); | | 4218 | count = uimin(srccount, dstcount); |
4270 | } | | 4219 | } |
4271 | | | 4220 | |
4272 | if (count > 0) { | | 4221 | if (count > 0) { |
4273 | arg = &stage->arg; | | 4222 | arg = &stage->arg; |
4274 | arg->src = auring_headptr(&stage->srcbuf); | | 4223 | arg->src = auring_headptr(&stage->srcbuf); |
4275 | arg->dst = auring_tailptr(stage->dst); | | 4224 | arg->dst = auring_tailptr(stage->dst); |
4276 | arg->count = count; | | 4225 | arg->count = count; |
4277 | | | 4226 | |
4278 | stage->filter(arg); | | 4227 | stage->filter(arg); |
4279 | | | 4228 | |
4280 | if (!isfreq) { | | 4229 | if (!isfreq) { |
4281 | auring_take(&stage->srcbuf, count); | | 4230 | auring_take(&stage->srcbuf, count); |
4282 | auring_push(stage->dst, count); | | 4231 | auring_push(stage->dst, count); |
4283 | } | | 4232 | } |
4284 | } | | 4233 | } |
4285 | } | | 4234 | } |
4286 | | | 4235 | |
4287 | /* | | 4236 | /* |
4288 | * Produce output buffer for playback from user input buffer. | | 4237 | * Produce output buffer for playback from user input buffer. |
4289 | * It must be called only if usrbuf is not empty and outbuf is | | 4238 | * It must be called only if usrbuf is not empty and outbuf is |
4290 | * available at least one free block. | | 4239 | * available at least one free block. |
4291 | */ | | 4240 | */ |
4292 | static void | | 4241 | static void |
4293 | audio_track_play(audio_track_t *track) | | 4242 | audio_track_play(audio_track_t *track) |
4294 | { | | 4243 | { |
4295 | audio_ring_t *usrbuf; | | 4244 | audio_ring_t *usrbuf; |
4296 | audio_ring_t *input; | | 4245 | audio_ring_t *input; |
4297 | int count; | | 4246 | int count; |
4298 | int framesize; | | 4247 | int framesize; |
4299 | int bytes; | | 4248 | int bytes; |
4300 | | | 4249 | |
4301 | KASSERT(track); | | 4250 | KASSERT(track); |
4302 | KASSERT(track->lock); | | 4251 | KASSERT(track->lock); |
4303 | TRACET(4, track, "start pstate=%d", track->pstate); | | 4252 | TRACET(4, track, "start pstate=%d", track->pstate); |
4304 | | | 4253 | |
4305 | /* At this point usrbuf must not be empty. */ | | 4254 | /* At this point usrbuf must not be empty. */ |
4306 | KASSERT(track->usrbuf.used > 0); | | 4255 | KASSERT(track->usrbuf.used > 0); |
4307 | /* Also, outbuf must be available at least one block. */ | | 4256 | /* Also, outbuf must be available at least one block. */ |
4308 | count = auring_get_contig_free(&track->outbuf); | | 4257 | count = auring_get_contig_free(&track->outbuf); |
4309 | KASSERTMSG(count >= frame_per_block(track->mixer, &track->outbuf.fmt), | | 4258 | KASSERTMSG(count >= frame_per_block(track->mixer, &track->outbuf.fmt), |
4310 | "count=%d fpb=%d", | | 4259 | "count=%d fpb=%d", |
4311 | count, frame_per_block(track->mixer, &track->outbuf.fmt)); | | 4260 | count, frame_per_block(track->mixer, &track->outbuf.fmt)); |
4312 | | | 4261 | |
4313 | /* XXX TODO: is this necessary for now? */ | | 4262 | /* XXX TODO: is this necessary for now? */ |
4314 | int track_count_0 = track->outbuf.used; | | 4263 | int track_count_0 = track->outbuf.used; |
4315 | | | 4264 | |
4316 | usrbuf = &track->usrbuf; | | 4265 | usrbuf = &track->usrbuf; |
4317 | input = track->input; | | 4266 | input = track->input; |
4318 | | | 4267 | |
4319 | /* | | 4268 | /* |
4320 | * framesize is always 1 byte or more since all formats supported as | | 4269 | * framesize is always 1 byte or more since all formats supported as |
4321 | * usrfmt(=input) have 8bit or more stride. | | 4270 | * usrfmt(=input) have 8bit or more stride. |
4322 | */ | | 4271 | */ |
4323 | framesize = frametobyte(&input->fmt, 1); | | 4272 | framesize = frametobyte(&input->fmt, 1); |
4324 | KASSERT(framesize >= 1); | | 4273 | KASSERT(framesize >= 1); |
4325 | | | 4274 | |
4326 | /* The next stage of usrbuf (=input) must be available. */ | | 4275 | /* The next stage of usrbuf (=input) must be available. */ |
4327 | KASSERT(auring_get_contig_free(input) > 0); | | 4276 | KASSERT(auring_get_contig_free(input) > 0); |
4328 | | | 4277 | |
4329 | /* | | 4278 | /* |
4330 | * Copy usrbuf up to 1block to input buffer. | | 4279 | * Copy usrbuf up to 1block to input buffer. |
4331 | * count is the number of frames to copy from usrbuf. | | 4280 | * count is the number of frames to copy from usrbuf. |
4332 | * bytes is the number of bytes to copy from usrbuf. However it is | | 4281 | * bytes is the number of bytes to copy from usrbuf. However it is |
4333 | * not copied less than one frame. | | 4282 | * not copied less than one frame. |
4334 | */ | | 4283 | */ |
4335 | count = uimin(usrbuf->used, track->usrbuf_blksize) / framesize; | | 4284 | count = uimin(usrbuf->used, track->usrbuf_blksize) / framesize; |
4336 | bytes = count * framesize; | | 4285 | bytes = count * framesize; |
4337 | | | 4286 | |
4338 | track->usrbuf_stamp += bytes; | | 4287 | track->usrbuf_stamp += bytes; |
4339 | | | 4288 | |
4340 | if (usrbuf->head + bytes < usrbuf->capacity) { | | 4289 | if (usrbuf->head + bytes < usrbuf->capacity) { |
4341 | memcpy((uint8_t *)input->mem + auring_tail(input) * framesize, | | 4290 | memcpy((uint8_t *)input->mem + auring_tail(input) * framesize, |
4342 | (uint8_t *)usrbuf->mem + usrbuf->head, | | 4291 | (uint8_t *)usrbuf->mem + usrbuf->head, |
4343 | bytes); | | 4292 | bytes); |
4344 | auring_push(input, count); | | 4293 | auring_push(input, count); |
4345 | auring_take(usrbuf, bytes); | | 4294 | auring_take(usrbuf, bytes); |
4346 | } else { | | 4295 | } else { |
4347 | int bytes1; | | 4296 | int bytes1; |
4348 | int bytes2; | | 4297 | int bytes2; |
4349 | | | 4298 | |
4350 | bytes1 = auring_get_contig_used(usrbuf); | | 4299 | bytes1 = auring_get_contig_used(usrbuf); |
4351 | KASSERT(bytes1 % framesize == 0); | | 4300 | KASSERT(bytes1 % framesize == 0); |
4352 | memcpy((uint8_t *)input->mem + auring_tail(input) * framesize, | | 4301 | memcpy((uint8_t *)input->mem + auring_tail(input) * framesize, |
4353 | (uint8_t *)usrbuf->mem + usrbuf->head, | | 4302 | (uint8_t *)usrbuf->mem + usrbuf->head, |
4354 | bytes1); | | 4303 | bytes1); |
4355 | auring_push(input, bytes1 / framesize); | | 4304 | auring_push(input, bytes1 / framesize); |
4356 | auring_take(usrbuf, bytes1); | | 4305 | auring_take(usrbuf, bytes1); |
4357 | | | 4306 | |
4358 | bytes2 = bytes - bytes1; | | 4307 | bytes2 = bytes - bytes1; |
4359 | memcpy((uint8_t *)input->mem + auring_tail(input) * framesize, | | 4308 | memcpy((uint8_t *)input->mem + auring_tail(input) * framesize, |
4360 | (uint8_t *)usrbuf->mem + usrbuf->head, | | 4309 | (uint8_t *)usrbuf->mem + usrbuf->head, |
4361 | bytes2); | | 4310 | bytes2); |
4362 | auring_push(input, bytes2 / framesize); | | 4311 | auring_push(input, bytes2 / framesize); |
4363 | auring_take(usrbuf, bytes2); | | 4312 | auring_take(usrbuf, bytes2); |
4364 | } | | 4313 | } |
4365 | | | 4314 | |
4366 | /* Encoding conversion */ | | 4315 | /* Encoding conversion */ |
4367 | if (track->codec.filter) | | 4316 | if (track->codec.filter) |
4368 | audio_apply_stage(track, &track->codec, false); | | 4317 | audio_apply_stage(track, &track->codec, false); |
4369 | | | 4318 | |
4370 | /* Channel volume */ | | 4319 | /* Channel volume */ |
4371 | if (track->chvol.filter) | | 4320 | if (track->chvol.filter) |
4372 | audio_apply_stage(track, &track->chvol, false); | | 4321 | audio_apply_stage(track, &track->chvol, false); |
4373 | | | 4322 | |
4374 | /* Channel mix */ | | 4323 | /* Channel mix */ |
4375 | if (track->chmix.filter) | | 4324 | if (track->chmix.filter) |
4376 | audio_apply_stage(track, &track->chmix, false); | | 4325 | audio_apply_stage(track, &track->chmix, false); |
4377 | | | 4326 | |
4378 | /* Frequency conversion */ | | 4327 | /* Frequency conversion */ |
4379 | /* | | 4328 | /* |
4380 | * Since the frequency conversion needs correction for each block, | | 4329 | * Since the frequency conversion needs correction for each block, |
4381 | * it rounds up to 1 block. | | 4330 | * it rounds up to 1 block. |
4382 | */ | | 4331 | */ |
4383 | if (track->freq.filter) { | | 4332 | if (track->freq.filter) { |
4384 | int n; | | 4333 | int n; |
4385 | n = audio_append_silence(track, &track->freq.srcbuf); | | 4334 | n = audio_append_silence(track, &track->freq.srcbuf); |
4386 | if (n > 0) { | | 4335 | if (n > 0) { |
4387 | TRACET(4, track, | | 4336 | TRACET(4, track, |
4388 | "freq.srcbuf add silence %d -> %d/%d/%d", | | 4337 | "freq.srcbuf add silence %d -> %d/%d/%d", |
4389 | n, | | 4338 | n, |
4390 | track->freq.srcbuf.head, | | 4339 | track->freq.srcbuf.head, |
4391 | track->freq.srcbuf.used, | | 4340 | track->freq.srcbuf.used, |
4392 | track->freq.srcbuf.capacity); | | 4341 | track->freq.srcbuf.capacity); |
4393 | } | | 4342 | } |
4394 | if (track->freq.srcbuf.used > 0) { | | 4343 | if (track->freq.srcbuf.used > 0) { |
4395 | audio_apply_stage(track, &track->freq, true); | | 4344 | audio_apply_stage(track, &track->freq, true); |
4396 | } | | 4345 | } |
4397 | } | | 4346 | } |
4398 | | | 4347 | |
4399 | if (bytes < track->usrbuf_blksize) { | | 4348 | if (bytes < track->usrbuf_blksize) { |
4400 | /* | | 4349 | /* |
4401 | * Clear all conversion buffer pointer if the conversion was | | 4350 | * Clear all conversion buffer pointer if the conversion was |
4402 | * not exactly one block. These conversion stage buffers are | | 4351 | * not exactly one block. These conversion stage buffers are |
4403 | * certainly circular buffers because of symmetry with the | | 4352 | * certainly circular buffers because of symmetry with the |
4404 | * previous and next stage buffer. However, since they are | | 4353 | * previous and next stage buffer. However, since they are |
4405 | * treated as simple contiguous buffers in operation, so head | | 4354 | * treated as simple contiguous buffers in operation, so head |
4406 | * always should point 0. This may happen during drain-age. | | 4355 | * always should point 0. This may happen during drain-age. |
4407 | */ | | 4356 | */ |
4408 | TRACET(4, track, "reset stage"); | | 4357 | TRACET(4, track, "reset stage"); |
4409 | if (track->codec.filter) { | | 4358 | if (track->codec.filter) { |
4410 | KASSERT(track->codec.srcbuf.used == 0); | | 4359 | KASSERT(track->codec.srcbuf.used == 0); |
4411 | track->codec.srcbuf.head = 0; | | 4360 | track->codec.srcbuf.head = 0; |
4412 | } | | 4361 | } |
4413 | if (track->chvol.filter) { | | 4362 | if (track->chvol.filter) { |
4414 | KASSERT(track->chvol.srcbuf.used == 0); | | 4363 | KASSERT(track->chvol.srcbuf.used == 0); |
4415 | track->chvol.srcbuf.head = 0; | | 4364 | track->chvol.srcbuf.head = 0; |
4416 | } | | 4365 | } |
4417 | if (track->chmix.filter) { | | 4366 | if (track->chmix.filter) { |
4418 | KASSERT(track->chmix.srcbuf.used == 0); | | 4367 | KASSERT(track->chmix.srcbuf.used == 0); |
4419 | track->chmix.srcbuf.head = 0; | | 4368 | track->chmix.srcbuf.head = 0; |
4420 | } | | 4369 | } |
4421 | if (track->freq.filter) { | | 4370 | if (track->freq.filter) { |
4422 | KASSERT(track->freq.srcbuf.used == 0); | | 4371 | KASSERT(track->freq.srcbuf.used == 0); |
4423 | track->freq.srcbuf.head = 0; | | 4372 | track->freq.srcbuf.head = 0; |
4424 | } | | 4373 | } |
4425 | } | | 4374 | } |
4426 | | | 4375 | |
4427 | if (track->input == &track->outbuf) { | | 4376 | if (track->input == &track->outbuf) { |
4428 | track->outputcounter = track->inputcounter; | | 4377 | track->outputcounter = track->inputcounter; |
4429 | } else { | | 4378 | } else { |
4430 | track->outputcounter += track->outbuf.used - track_count_0; | | 4379 | track->outputcounter += track->outbuf.used - track_count_0; |
4431 | } | | 4380 | } |
4432 | | | 4381 | |
4433 | #if defined(AUDIO_DEBUG) | | 4382 | #if defined(AUDIO_DEBUG) |
4434 | if (audiodebug >= 3) { | | 4383 | if (audiodebug >= 3) { |
4435 | struct audio_track_debugbuf m; | | 4384 | struct audio_track_debugbuf m; |
4436 | audio_track_bufstat(track, &m); | | 4385 | audio_track_bufstat(track, &m); |
4437 | TRACET(0, track, "end%s%s%s%s%s%s", | | 4386 | TRACET(0, track, "end%s%s%s%s%s%s", |
4438 | m.outbuf, m.freq, m.chvol, m.chmix, m.codec, m.usrbuf); | | 4387 | m.outbuf, m.freq, m.chvol, m.chmix, m.codec, m.usrbuf); |
4439 | } | | 4388 | } |
4440 | #endif | | 4389 | #endif |
4441 | } | | 4390 | } |
4442 | | | 4391 | |
4443 | /* | | 4392 | /* |
4444 | * Produce user output buffer for recording from input buffer. | | 4393 | * Produce user output buffer for recording from input buffer. |
4445 | */ | | 4394 | */ |
4446 | static void | | 4395 | static void |
4447 | audio_track_record(audio_track_t *track) | | 4396 | audio_track_record(audio_track_t *track) |
4448 | { | | 4397 | { |
4449 | audio_ring_t *outbuf; | | 4398 | audio_ring_t *outbuf; |
4450 | audio_ring_t *usrbuf; | | 4399 | audio_ring_t *usrbuf; |
4451 | int count; | | 4400 | int count; |
4452 | int bytes; | | 4401 | int bytes; |
4453 | int framesize; | | 4402 | int framesize; |
4454 | | | 4403 | |
4455 | KASSERT(track); | | 4404 | KASSERT(track); |
4456 | KASSERT(track->lock); | | 4405 | KASSERT(track->lock); |
4457 | | | 4406 | |
4458 | /* Number of frames to process */ | | 4407 | /* Number of frames to process */ |
4459 | count = auring_get_contig_used(track->input); | | 4408 | count = auring_get_contig_used(track->input); |
4460 | count = uimin(count, track->mixer->frames_per_block); | | 4409 | count = uimin(count, track->mixer->frames_per_block); |
4461 | if (count == 0) { | | 4410 | if (count == 0) { |
4462 | TRACET(4, track, "count == 0"); | | 4411 | TRACET(4, track, "count == 0"); |
4463 | return; | | 4412 | return; |
4464 | } | | 4413 | } |
4465 | | | 4414 | |
4466 | /* Frequency conversion */ | | 4415 | /* Frequency conversion */ |
4467 | if (track->freq.filter) { | | 4416 | if (track->freq.filter) { |
4468 | if (track->freq.srcbuf.used > 0) { | | 4417 | if (track->freq.srcbuf.used > 0) { |
4469 | audio_apply_stage(track, &track->freq, true); | | 4418 | audio_apply_stage(track, &track->freq, true); |
4470 | /* XXX should input of freq be from beginning of buf? */ | | 4419 | /* XXX should input of freq be from beginning of buf? */ |
4471 | } | | 4420 | } |
4472 | } | | 4421 | } |
4473 | | | 4422 | |
4474 | /* Channel mix */ | | 4423 | /* Channel mix */ |
4475 | if (track->chmix.filter) | | 4424 | if (track->chmix.filter) |
4476 | audio_apply_stage(track, &track->chmix, false); | | 4425 | audio_apply_stage(track, &track->chmix, false); |
4477 | | | 4426 | |
4478 | /* Channel volume */ | | 4427 | /* Channel volume */ |
4479 | if (track->chvol.filter) | | 4428 | if (track->chvol.filter) |
4480 | audio_apply_stage(track, &track->chvol, false); | | 4429 | audio_apply_stage(track, &track->chvol, false); |
4481 | | | 4430 | |
4482 | /* Encoding conversion */ | | 4431 | /* Encoding conversion */ |
4483 | if (track->codec.filter) | | 4432 | if (track->codec.filter) |
4484 | audio_apply_stage(track, &track->codec, false); | | 4433 | audio_apply_stage(track, &track->codec, false); |
4485 | | | 4434 | |
4486 | /* Copy outbuf to usrbuf */ | | 4435 | /* Copy outbuf to usrbuf */ |
4487 | outbuf = &track->outbuf; | | 4436 | outbuf = &track->outbuf; |
4488 | usrbuf = &track->usrbuf; | | 4437 | usrbuf = &track->usrbuf; |
4489 | /* | | 4438 | /* |
4490 | * framesize is always 1 byte or more since all formats supported | | 4439 | * framesize is always 1 byte or more since all formats supported |
4491 | * as usrfmt(=output) have 8bit or more stride. | | 4440 | * as usrfmt(=output) have 8bit or more stride. |
4492 | */ | | 4441 | */ |
4493 | framesize = frametobyte(&outbuf->fmt, 1); | | 4442 | framesize = frametobyte(&outbuf->fmt, 1); |
4494 | KASSERT(framesize >= 1); | | 4443 | KASSERT(framesize >= 1); |
4495 | /* | | 4444 | /* |
4496 | * count is the number of frames to copy to usrbuf. | | 4445 | * count is the number of frames to copy to usrbuf. |
4497 | * bytes is the number of bytes to copy to usrbuf. | | 4446 | * bytes is the number of bytes to copy to usrbuf. |
4498 | */ | | 4447 | */ |
4499 | count = outbuf->used; | | 4448 | count = outbuf->used; |
4500 | count = uimin(count, | | 4449 | count = uimin(count, |
4501 | (track->usrbuf_usedhigh - usrbuf->used) / framesize); | | 4450 | (track->usrbuf_usedhigh - usrbuf->used) / framesize); |
4502 | bytes = count * framesize; | | 4451 | bytes = count * framesize; |
4503 | if (auring_tail(usrbuf) + bytes < usrbuf->capacity) { | | 4452 | if (auring_tail(usrbuf) + bytes < usrbuf->capacity) { |
4504 | memcpy((uint8_t *)usrbuf->mem + auring_tail(usrbuf), | | 4453 | memcpy((uint8_t *)usrbuf->mem + auring_tail(usrbuf), |
4505 | (uint8_t *)outbuf->mem + outbuf->head * framesize, | | 4454 | (uint8_t *)outbuf->mem + outbuf->head * framesize, |
4506 | bytes); | | 4455 | bytes); |
4507 | auring_push(usrbuf, bytes); | | 4456 | auring_push(usrbuf, bytes); |
4508 | auring_take(outbuf, count); | | 4457 | auring_take(outbuf, count); |
4509 | } else { | | 4458 | } else { |
4510 | int bytes1; | | 4459 | int bytes1; |
4511 | int bytes2; | | 4460 | int bytes2; |
4512 | | | 4461 | |
4513 | bytes1 = auring_get_contig_free(usrbuf); | | 4462 | bytes1 = auring_get_contig_free(usrbuf); |
4514 | KASSERT(bytes1 % framesize == 0); | | 4463 | KASSERT(bytes1 % framesize == 0); |
4515 | memcpy((uint8_t *)usrbuf->mem + auring_tail(usrbuf), | | 4464 | memcpy((uint8_t *)usrbuf->mem + auring_tail(usrbuf), |
4516 | (uint8_t *)outbuf->mem + outbuf->head * framesize, | | 4465 | (uint8_t *)outbuf->mem + outbuf->head * framesize, |
4517 | bytes1); | | 4466 | bytes1); |
4518 | auring_push(usrbuf, bytes1); | | 4467 | auring_push(usrbuf, bytes1); |
4519 | auring_take(outbuf, bytes1 / framesize); | | 4468 | auring_take(outbuf, bytes1 / framesize); |
4520 | | | 4469 | |
4521 | bytes2 = bytes - bytes1; | | 4470 | bytes2 = bytes - bytes1; |
4522 | memcpy((uint8_t *)usrbuf->mem + auring_tail(usrbuf), | | 4471 | memcpy((uint8_t *)usrbuf->mem + auring_tail(usrbuf), |
4523 | (uint8_t *)outbuf->mem + outbuf->head * framesize, | | 4472 | (uint8_t *)outbuf->mem + outbuf->head * framesize, |
4524 | bytes2); | | 4473 | bytes2); |
4525 | auring_push(usrbuf, bytes2); | | 4474 | auring_push(usrbuf, bytes2); |
4526 | auring_take(outbuf, bytes2 / framesize); | | 4475 | auring_take(outbuf, bytes2 / framesize); |
4527 | } | | 4476 | } |
4528 | | | 4477 | |
4529 | /* XXX TODO: any counters here? */ | | 4478 | /* XXX TODO: any counters here? */ |
4530 | | | 4479 | |
4531 | #if defined(AUDIO_DEBUG) | | 4480 | #if defined(AUDIO_DEBUG) |
4532 | if (audiodebug >= 3) { | | 4481 | if (audiodebug >= 3) { |
4533 | struct audio_track_debugbuf m; | | 4482 | struct audio_track_debugbuf m; |
4534 | audio_track_bufstat(track, &m); | | 4483 | audio_track_bufstat(track, &m); |
4535 | TRACET(0, track, "end%s%s%s%s%s%s", | | 4484 | TRACET(0, track, "end%s%s%s%s%s%s", |
4536 | m.freq, m.chvol, m.chmix, m.codec, m.outbuf, m.usrbuf); | | 4485 | m.freq, m.chvol, m.chmix, m.codec, m.outbuf, m.usrbuf); |
4537 | } | | 4486 | } |
4538 | #endif | | 4487 | #endif |
4539 | } | | 4488 | } |
4540 | | | 4489 | |
4541 | /* | | 4490 | /* |
4542 | * Calcurate blktime [msec] from mixer(.hwbuf.fmt). | | 4491 | * Calcurate blktime [msec] from mixer(.hwbuf.fmt). |
4543 | * Must be called with sc_lock held. | | 4492 | * Must be called with sc_lock held. |
4544 | */ | | 4493 | */ |
4545 | static u_int | | 4494 | static u_int |
4546 | audio_mixer_calc_blktime(struct audio_softc *sc, audio_trackmixer_t *mixer) | | 4495 | audio_mixer_calc_blktime(struct audio_softc *sc, audio_trackmixer_t *mixer) |
4547 | { | | 4496 | { |
4548 | audio_format2_t *fmt; | | 4497 | audio_format2_t *fmt; |
4549 | u_int blktime; | | 4498 | u_int blktime; |
4550 | u_int frames_per_block; | | 4499 | u_int frames_per_block; |
4551 | | | 4500 | |
4552 | KASSERT(mutex_owned(sc->sc_lock)); | | 4501 | KASSERT(mutex_owned(sc->sc_lock)); |
4553 | | | 4502 | |
4554 | fmt = &mixer->hwbuf.fmt; | | 4503 | fmt = &mixer->hwbuf.fmt; |
4555 | blktime = sc->sc_blk_ms; | | 4504 | blktime = sc->sc_blk_ms; |
4556 | | | 4505 | |
4557 | /* | | 4506 | /* |
4558 | * If stride is not multiples of 8, special treatment is necessary. | | 4507 | * If stride is not multiples of 8, special treatment is necessary. |
4559 | * For now, it is only x68k's vs(4), 4 bit/sample ADPCM. | | 4508 | * For now, it is only x68k's vs(4), 4 bit/sample ADPCM. |
4560 | */ | | 4509 | */ |
4561 | if (fmt->stride == 4) { | | 4510 | if (fmt->stride == 4) { |
4562 | frames_per_block = fmt->sample_rate * blktime / 1000; | | 4511 | frames_per_block = fmt->sample_rate * blktime / 1000; |
4563 | if ((frames_per_block & 1) != 0) | | 4512 | if ((frames_per_block & 1) != 0) |
4564 | blktime *= 2; | | 4513 | blktime *= 2; |
4565 | } | | 4514 | } |
4566 | #ifdef DIAGNOSTIC | | 4515 | #ifdef DIAGNOSTIC |
4567 | else if (fmt->stride % NBBY != 0) { | | 4516 | else if (fmt->stride % NBBY != 0) { |
4568 | panic("unsupported HW stride %d", fmt->stride); | | 4517 | panic("unsupported HW stride %d", fmt->stride); |
4569 | } | | 4518 | } |
4570 | #endif | | 4519 | #endif |
4571 | | | 4520 | |
4572 | return blktime; | | 4521 | return blktime; |
4573 | } | | 4522 | } |
4574 | | | 4523 | |
4575 | /* | | 4524 | /* |
4576 | * Initialize the mixer corresponding to the mode. | | 4525 | * Initialize the mixer corresponding to the mode. |
4577 | * Set AUMODE_PLAY to the 'mode' for playback or AUMODE_RECORD for recording. | | 4526 | * Set AUMODE_PLAY to the 'mode' for playback or AUMODE_RECORD for recording. |
4578 | * sc->sc_[pr]mixer (corresponding to the 'mode') must be zero-filled. | | 4527 | * sc->sc_[pr]mixer (corresponding to the 'mode') must be zero-filled. |
4579 | * This function returns 0 on sucessful. Otherwise returns errno. | | 4528 | * This function returns 0 on sucessful. Otherwise returns errno. |
4580 | * Must be called with sc_lock held. | | 4529 | * Must be called with sc_lock held. |
4581 | */ | | 4530 | */ |
4582 | static int | | 4531 | static int |
4583 | audio_mixer_init(struct audio_softc *sc, int mode, | | 4532 | audio_mixer_init(struct audio_softc *sc, int mode, |
4584 | const audio_format2_t *hwfmt, const audio_filter_reg_t *reg) | | 4533 | const audio_format2_t *hwfmt, const audio_filter_reg_t *reg) |
4585 | { | | 4534 | { |
4586 | char codecbuf[64]; | | 4535 | char codecbuf[64]; |
4587 | audio_trackmixer_t *mixer; | | 4536 | audio_trackmixer_t *mixer; |
4588 | void (*softint_handler)(void *); | | 4537 | void (*softint_handler)(void *); |
4589 | int len; | | 4538 | int len; |
4590 | int blksize; | | 4539 | int blksize; |
4591 | int capacity; | | 4540 | int capacity; |
4592 | size_t bufsize; | | 4541 | size_t bufsize; |
4593 | int hwblks; | | 4542 | int hwblks; |
4594 | int blkms; | | 4543 | int blkms; |
4595 | int error; | | 4544 | int error; |
4596 | | | 4545 | |
4597 | KASSERT(hwfmt != NULL); | | 4546 | KASSERT(hwfmt != NULL); |
4598 | KASSERT(reg != NULL); | | 4547 | KASSERT(reg != NULL); |
4599 | KASSERT(mutex_owned(sc->sc_lock)); | | 4548 | KASSERT(mutex_owned(sc->sc_lock)); |
4600 | | | 4549 | |
4601 | error = 0; | | 4550 | error = 0; |
4602 | if (mode == AUMODE_PLAY) | | 4551 | if (mode == AUMODE_PLAY) |
4603 | mixer = sc->sc_pmixer; | | 4552 | mixer = sc->sc_pmixer; |
4604 | else | | 4553 | else |
4605 | mixer = sc->sc_rmixer; | | 4554 | mixer = sc->sc_rmixer; |
4606 | | | 4555 | |
4607 | mixer->sc = sc; | | 4556 | mixer->sc = sc; |
4608 | mixer->mode = mode; | | 4557 | mixer->mode = mode; |
4609 | | | 4558 | |
4610 | mixer->hwbuf.fmt = *hwfmt; | | 4559 | mixer->hwbuf.fmt = *hwfmt; |
4611 | mixer->volume = 256; | | 4560 | mixer->volume = 256; |
4612 | mixer->blktime_d = 1000; | | 4561 | mixer->blktime_d = 1000; |
4613 | mixer->blktime_n = audio_mixer_calc_blktime(sc, mixer); | | 4562 | mixer->blktime_n = audio_mixer_calc_blktime(sc, mixer); |
4614 | sc->sc_blk_ms = mixer->blktime_n; | | 4563 | sc->sc_blk_ms = mixer->blktime_n; |
4615 | hwblks = NBLKHW; | | 4564 | hwblks = NBLKHW; |
4616 | | | 4565 | |
4617 | mixer->frames_per_block = frame_per_block(mixer, &mixer->hwbuf.fmt); | | 4566 | mixer->frames_per_block = frame_per_block(mixer, &mixer->hwbuf.fmt); |
4618 | blksize = frametobyte(&mixer->hwbuf.fmt, mixer->frames_per_block); | | 4567 | blksize = frametobyte(&mixer->hwbuf.fmt, mixer->frames_per_block); |
4619 | if (sc->hw_if->round_blocksize) { | | 4568 | if (sc->hw_if->round_blocksize) { |
4620 | int rounded; | | 4569 | int rounded; |
4621 | audio_params_t p = format2_to_params(&mixer->hwbuf.fmt); | | 4570 | audio_params_t p = format2_to_params(&mixer->hwbuf.fmt); |
4622 | rounded = sc->hw_if->round_blocksize(sc->hw_hdl, blksize, | | 4571 | rounded = sc->hw_if->round_blocksize(sc->hw_hdl, blksize, |
4623 | mode, &p); | | 4572 | mode, &p); |
4624 | TRACE(1, "round_blocksize %d -> %d", blksize, rounded); | | 4573 | TRACE(1, "round_blocksize %d -> %d", blksize, rounded); |
4625 | if (rounded != blksize) { | | 4574 | if (rounded != blksize) { |
4626 | if ((rounded * NBBY) % (mixer->hwbuf.fmt.stride * | | 4575 | if ((rounded * NBBY) % (mixer->hwbuf.fmt.stride * |
4627 | mixer->hwbuf.fmt.channels) != 0) { | | 4576 | mixer->hwbuf.fmt.channels) != 0) { |
4628 | device_printf(sc->sc_dev, | | 4577 | device_printf(sc->sc_dev, |
4629 | "blksize not configured %d -> %d\n", | | 4578 | "blksize not configured %d -> %d\n", |
4630 | blksize, rounded); | | 4579 | blksize, rounded); |
4631 | return EINVAL; | | 4580 | return EINVAL; |
4632 | } | | 4581 | } |
4633 | /* Recalculation */ | | 4582 | /* Recalculation */ |
4634 | blksize = rounded; | | 4583 | blksize = rounded; |
4635 | mixer->frames_per_block = blksize * NBBY / | | 4584 | mixer->frames_per_block = blksize * NBBY / |
4636 | (mixer->hwbuf.fmt.stride * | | 4585 | (mixer->hwbuf.fmt.stride * |
4637 | mixer->hwbuf.fmt.channels); | | 4586 | mixer->hwbuf.fmt.channels); |
4638 | } | | 4587 | } |
4639 | } | | 4588 | } |
4640 | mixer->blktime_n = mixer->frames_per_block; | | 4589 | mixer->blktime_n = mixer->frames_per_block; |
4641 | mixer->blktime_d = mixer->hwbuf.fmt.sample_rate; | | 4590 | mixer->blktime_d = mixer->hwbuf.fmt.sample_rate; |
4642 | | | 4591 | |
4643 | capacity = mixer->frames_per_block * hwblks; | | 4592 | capacity = mixer->frames_per_block * hwblks; |
4644 | bufsize = frametobyte(&mixer->hwbuf.fmt, capacity); | | 4593 | bufsize = frametobyte(&mixer->hwbuf.fmt, capacity); |
4645 | if (sc->hw_if->round_buffersize) { | | 4594 | if (sc->hw_if->round_buffersize) { |
4646 | size_t rounded; | | 4595 | size_t rounded; |
4647 | rounded = sc->hw_if->round_buffersize(sc->hw_hdl, mode, | | 4596 | rounded = sc->hw_if->round_buffersize(sc->hw_hdl, mode, |
4648 | bufsize); | | 4597 | bufsize); |
4649 | TRACE(1, "round_buffersize %zd -> %zd", bufsize, rounded); | | 4598 | TRACE(1, "round_buffersize %zd -> %zd", bufsize, rounded); |
4650 | if (rounded < bufsize) { | | 4599 | if (rounded < bufsize) { |
4651 | /* buffersize needs NBLKHW blocks at least. */ | | 4600 | /* buffersize needs NBLKHW blocks at least. */ |
4652 | device_printf(sc->sc_dev, | | 4601 | device_printf(sc->sc_dev, |
4653 | "buffersize too small: buffersize=%zd blksize=%d\n", | | 4602 | "buffersize too small: buffersize=%zd blksize=%d\n", |
4654 | rounded, blksize); | | 4603 | rounded, blksize); |
4655 | return EINVAL; | | 4604 | return EINVAL; |
4656 | } | | 4605 | } |
4657 | if (rounded % blksize != 0) { | | 4606 | if (rounded % blksize != 0) { |
4658 | /* buffersize/blksize constraint mismatch? */ | | 4607 | /* buffersize/blksize constraint mismatch? */ |
4659 | device_printf(sc->sc_dev, | | 4608 | device_printf(sc->sc_dev, |
4660 | "buffersize must be multiple of blksize: " | | 4609 | "buffersize must be multiple of blksize: " |
4661 | "buffersize=%zu blksize=%d\n", | | 4610 | "buffersize=%zu blksize=%d\n", |
4662 | rounded, blksize); | | 4611 | rounded, blksize); |
4663 | return EINVAL; | | 4612 | return EINVAL; |
4664 | } | | 4613 | } |
4665 | if (rounded != bufsize) { | | 4614 | if (rounded != bufsize) { |
4666 | /* Recalcuration */ | | 4615 | /* Recalcuration */ |
4667 | bufsize = rounded; | | 4616 | bufsize = rounded; |
4668 | hwblks = bufsize / blksize; | | 4617 | hwblks = bufsize / blksize; |
4669 | capacity = mixer->frames_per_block * hwblks; | | 4618 | capacity = mixer->frames_per_block * hwblks; |
4670 | } | | 4619 | } |
4671 | } | | 4620 | } |
4672 | TRACE(1, "buffersize for %s = %zu", | | 4621 | TRACE(1, "buffersize for %s = %zu", |
4673 | (mode == AUMODE_PLAY) ? "playback" : "recording", | | 4622 | (mode == AUMODE_PLAY) ? "playback" : "recording", |
4674 | bufsize); | | 4623 | bufsize); |
4675 | mixer->hwbuf.capacity = capacity; | | 4624 | mixer->hwbuf.capacity = capacity; |
4676 | | | 4625 | |
4677 | /* | | 4626 | /* |
4678 | * XXX need to release sc_lock for compatibility? | | 4627 | * XXX need to release sc_lock for compatibility? |
4679 | */ | | 4628 | */ |
4680 | if (sc->hw_if->allocm) { | | 4629 | if (sc->hw_if->allocm) { |
4681 | mixer->hwbuf.mem = sc->hw_if->allocm(sc->hw_hdl, mode, bufsize); | | 4630 | mixer->hwbuf.mem = sc->hw_if->allocm(sc->hw_hdl, mode, bufsize); |
4682 | if (mixer->hwbuf.mem == NULL) { | | 4631 | if (mixer->hwbuf.mem == NULL) { |
4683 | device_printf(sc->sc_dev, "%s: allocm(%zu) failed\n", | | 4632 | device_printf(sc->sc_dev, "%s: allocm(%zu) failed\n", |
4684 | __func__, bufsize); | | 4633 | __func__, bufsize); |
4685 | return ENOMEM; | | 4634 | return ENOMEM; |
4686 | } | | 4635 | } |
4687 | } else { | | 4636 | } else { |
4688 | mixer->hwbuf.mem = kmem_alloc(bufsize, KM_SLEEP); | | 4637 | mixer->hwbuf.mem = kmem_alloc(bufsize, KM_SLEEP); |
4689 | } | | 4638 | } |
4690 | | | 4639 | |
4691 | /* From here, audio_mixer_destroy is necessary to exit. */ | | 4640 | /* From here, audio_mixer_destroy is necessary to exit. */ |
4692 | if (mode == AUMODE_PLAY) { | | 4641 | if (mode == AUMODE_PLAY) { |
4693 | cv_init(&mixer->outcv, "audiowr"); | | 4642 | cv_init(&mixer->outcv, "audiowr"); |
4694 | } else { | | 4643 | } else { |
4695 | cv_init(&mixer->outcv, "audiord"); | | 4644 | cv_init(&mixer->outcv, "audiord"); |
4696 | } | | 4645 | } |
4697 | | | 4646 | |
4698 | if (mode == AUMODE_PLAY) { | | 4647 | if (mode == AUMODE_PLAY) { |
4699 | softint_handler = audio_softintr_wr; | | 4648 | softint_handler = audio_softintr_wr; |
4700 | } else { | | 4649 | } else { |
4701 | softint_handler = audio_softintr_rd; | | 4650 | softint_handler = audio_softintr_rd; |
4702 | } | | 4651 | } |
4703 | mixer->sih = softint_establish(SOFTINT_SERIAL | SOFTINT_MPSAFE, | | 4652 | mixer->sih = softint_establish(SOFTINT_SERIAL | SOFTINT_MPSAFE, |
4704 | softint_handler, sc); | | 4653 | softint_handler, sc); |
4705 | if (mixer->sih == NULL) { | | 4654 | if (mixer->sih == NULL) { |
4706 | device_printf(sc->sc_dev, "softint_establish failed\n"); | | 4655 | device_printf(sc->sc_dev, "softint_establish failed\n"); |
4707 | goto abort; | | 4656 | goto abort; |
4708 | } | | 4657 | } |
4709 | | | 4658 | |
4710 | mixer->track_fmt.encoding = AUDIO_ENCODING_SLINEAR_NE; | | 4659 | mixer->track_fmt.encoding = AUDIO_ENCODING_SLINEAR_NE; |
4711 | mixer->track_fmt.precision = AUDIO_INTERNAL_BITS; | | 4660 | mixer->track_fmt.precision = AUDIO_INTERNAL_BITS; |
4712 | mixer->track_fmt.stride = AUDIO_INTERNAL_BITS; | | 4661 | mixer->track_fmt.stride = AUDIO_INTERNAL_BITS; |
4713 | mixer->track_fmt.channels = mixer->hwbuf.fmt.channels; | | 4662 | mixer->track_fmt.channels = mixer->hwbuf.fmt.channels; |
4714 | mixer->track_fmt.sample_rate = mixer->hwbuf.fmt.sample_rate; | | 4663 | mixer->track_fmt.sample_rate = mixer->hwbuf.fmt.sample_rate; |
4715 | | | 4664 | |
4716 | if (mixer->hwbuf.fmt.encoding == AUDIO_ENCODING_SLINEAR_OE && | | 4665 | if (mixer->hwbuf.fmt.encoding == AUDIO_ENCODING_SLINEAR_OE && |
4717 | mixer->hwbuf.fmt.precision == AUDIO_INTERNAL_BITS) { | | 4666 | mixer->hwbuf.fmt.precision == AUDIO_INTERNAL_BITS) { |
4718 | mixer->swap_endian = true; | | 4667 | mixer->swap_endian = true; |
4719 | TRACE(1, "swap_endian"); | | 4668 | TRACE(1, "swap_endian"); |
4720 | } | | 4669 | } |
4721 | | | 4670 | |
4722 | if (mode == AUMODE_PLAY) { | | 4671 | if (mode == AUMODE_PLAY) { |
4723 | /* Mixing buffer */ | | 4672 | /* Mixing buffer */ |
4724 | mixer->mixfmt = mixer->track_fmt; | | 4673 | mixer->mixfmt = mixer->track_fmt; |
4725 | mixer->mixfmt.precision *= 2; | | 4674 | mixer->mixfmt.precision *= 2; |
4726 | mixer->mixfmt.stride *= 2; | | 4675 | mixer->mixfmt.stride *= 2; |
4727 | /* XXX TODO: use some macros? */ | | 4676 | /* XXX TODO: use some macros? */ |
4728 | len = mixer->frames_per_block * mixer->mixfmt.channels * | | 4677 | len = mixer->frames_per_block * mixer->mixfmt.channels * |
4729 | mixer->mixfmt.stride / NBBY; | | 4678 | mixer->mixfmt.stride / NBBY; |
4730 | mixer->mixsample = audio_realloc(mixer->mixsample, len); | | 4679 | mixer->mixsample = audio_realloc(mixer->mixsample, len); |
4731 | if (mixer->mixsample == NULL) { | | | |
4732 | device_printf(sc->sc_dev, | | | |
4733 | "%s: malloc mixsample(%d) failed\n", | | | |
4734 | __func__, len); | | | |
4735 | error = ENOMEM; | | | |
4736 | goto abort; | | | |
4737 | } | | | |
4738 | } else { | | 4680 | } else { |
4739 | /* No mixing buffer for recording */ | | 4681 | /* No mixing buffer for recording */ |
4740 | } | | 4682 | } |
4741 | | | 4683 | |
4742 | if (reg->codec) { | | 4684 | if (reg->codec) { |
4743 | mixer->codec = reg->codec; | | 4685 | mixer->codec = reg->codec; |
4744 | mixer->codecarg.context = reg->context; | | 4686 | mixer->codecarg.context = reg->context; |
4745 | if (mode == AUMODE_PLAY) { | | 4687 | if (mode == AUMODE_PLAY) { |
4746 | mixer->codecarg.srcfmt = &mixer->track_fmt; | | 4688 | mixer->codecarg.srcfmt = &mixer->track_fmt; |
4747 | mixer->codecarg.dstfmt = &mixer->hwbuf.fmt; | | 4689 | mixer->codecarg.dstfmt = &mixer->hwbuf.fmt; |
4748 | } else { | | 4690 | } else { |
4749 | mixer->codecarg.srcfmt = &mixer->hwbuf.fmt; | | 4691 | mixer->codecarg.srcfmt = &mixer->hwbuf.fmt; |
4750 | mixer->codecarg.dstfmt = &mixer->track_fmt; | | 4692 | mixer->codecarg.dstfmt = &mixer->track_fmt; |
4751 | } | | 4693 | } |
4752 | mixer->codecbuf.fmt = mixer->track_fmt; | | 4694 | mixer->codecbuf.fmt = mixer->track_fmt; |
4753 | mixer->codecbuf.capacity = mixer->frames_per_block; | | 4695 | mixer->codecbuf.capacity = mixer->frames_per_block; |
4754 | len = auring_bytelen(&mixer->codecbuf); | | 4696 | len = auring_bytelen(&mixer->codecbuf); |
4755 | mixer->codecbuf.mem = audio_realloc(mixer->codecbuf.mem, len); | | 4697 | mixer->codecbuf.mem = audio_realloc(mixer->codecbuf.mem, len); |
4756 | if (mixer->codecbuf.mem == NULL) { | | 4698 | if (mixer->codecbuf.mem == NULL) { |
4757 | device_printf(sc->sc_dev, | | 4699 | device_printf(sc->sc_dev, |
4758 | "%s: malloc codecbuf(%d) failed\n", | | 4700 | "%s: malloc codecbuf(%d) failed\n", |
4759 | __func__, len); | | 4701 | __func__, len); |
4760 | error = ENOMEM; | | 4702 | error = ENOMEM; |
4761 | goto abort; | | 4703 | goto abort; |
4762 | } | | 4704 | } |
4763 | } | | 4705 | } |
4764 | | | 4706 | |
4765 | /* Succeeded so display it. */ | | 4707 | /* Succeeded so display it. */ |
4766 | codecbuf[0] = '\0'; | | 4708 | codecbuf[0] = '\0'; |
4767 | if (mixer->codec || mixer->swap_endian) { | | 4709 | if (mixer->codec || mixer->swap_endian) { |
4768 | snprintf(codecbuf, sizeof(codecbuf), " %s %s:%d", | | 4710 | snprintf(codecbuf, sizeof(codecbuf), " %s %s:%d", |
4769 | (mode == AUMODE_PLAY) ? "->" : "<-", | | 4711 | (mode == AUMODE_PLAY) ? "->" : "<-", |
4770 | audio_encoding_name(mixer->hwbuf.fmt.encoding), | | 4712 | audio_encoding_name(mixer->hwbuf.fmt.encoding), |
4771 | mixer->hwbuf.fmt.precision); | | 4713 | mixer->hwbuf.fmt.precision); |
4772 | } | | 4714 | } |
4773 | blkms = mixer->blktime_n * 1000 / mixer->blktime_d; | | 4715 | blkms = mixer->blktime_n * 1000 / mixer->blktime_d; |
4774 | aprint_normal_dev(sc->sc_dev, "%s:%d%s %dch %dHz, blk %dms for %s\n", | | 4716 | aprint_normal_dev(sc->sc_dev, "%s:%d%s %dch %dHz, blk %dms for %s\n", |
4775 | audio_encoding_name(mixer->track_fmt.encoding), | | 4717 | audio_encoding_name(mixer->track_fmt.encoding), |
4776 | mixer->track_fmt.precision, | | 4718 | mixer->track_fmt.precision, |
4777 | codecbuf, | | 4719 | codecbuf, |
4778 | mixer->track_fmt.channels, | | 4720 | mixer->track_fmt.channels, |
4779 | mixer->track_fmt.sample_rate, | | 4721 | mixer->track_fmt.sample_rate, |
4780 | blkms, | | 4722 | blkms, |
4781 | (mode == AUMODE_PLAY) ? "playback" : "recording"); | | 4723 | (mode == AUMODE_PLAY) ? "playback" : "recording"); |
4782 | | | 4724 | |
4783 | return 0; | | 4725 | return 0; |
4784 | | | 4726 | |
4785 | abort: | | 4727 | abort: |
4786 | audio_mixer_destroy(sc, mixer); | | 4728 | audio_mixer_destroy(sc, mixer); |
4787 | return error; | | 4729 | return error; |
4788 | } | | 4730 | } |
4789 | | | 4731 | |
4790 | /* | | 4732 | /* |
4791 | * Releases all resources of 'mixer'. | | 4733 | * Releases all resources of 'mixer'. |
4792 | * Note that it does not release the memory area of 'mixer' itself. | | 4734 | * Note that it does not release the memory area of 'mixer' itself. |
4793 | * Must be called with sc_lock held. | | 4735 | * Must be called with sc_lock held. |
4794 | */ | | 4736 | */ |
4795 | static void | | 4737 | static void |
4796 | audio_mixer_destroy(struct audio_softc *sc, audio_trackmixer_t *mixer) | | 4738 | audio_mixer_destroy(struct audio_softc *sc, audio_trackmixer_t *mixer) |
4797 | { | | 4739 | { |
4798 | int bufsize; | | 4740 | int bufsize; |
4799 | | | 4741 | |
4800 | KASSERT(mutex_owned(sc->sc_lock)); | | 4742 | KASSERT(mutex_owned(sc->sc_lock)); |
4801 | | | 4743 | |
4802 | bufsize = frametobyte(&mixer->hwbuf.fmt, mixer->hwbuf.capacity); | | 4744 | bufsize = frametobyte(&mixer->hwbuf.fmt, mixer->hwbuf.capacity); |
4803 | | | 4745 | |
4804 | if (mixer->hwbuf.mem != NULL) { | | 4746 | if (mixer->hwbuf.mem != NULL) { |
4805 | if (sc->hw_if->freem) { | | 4747 | if (sc->hw_if->freem) { |
4806 | sc->hw_if->freem(sc->hw_hdl, mixer->hwbuf.mem, bufsize); | | 4748 | sc->hw_if->freem(sc->hw_hdl, mixer->hwbuf.mem, bufsize); |
4807 | } else { | | 4749 | } else { |
4808 | kmem_free(mixer->hwbuf.mem, bufsize); | | 4750 | kmem_free(mixer->hwbuf.mem, bufsize); |
4809 | } | | 4751 | } |
4810 | mixer->hwbuf.mem = NULL; | | 4752 | mixer->hwbuf.mem = NULL; |
4811 | } | | 4753 | } |
4812 | | | 4754 | |
4813 | audio_free(mixer->codecbuf.mem); | | 4755 | audio_free(mixer->codecbuf.mem); |
4814 | audio_free(mixer->mixsample); | | 4756 | audio_free(mixer->mixsample); |
4815 | | | 4757 | |
4816 | cv_destroy(&mixer->outcv); | | 4758 | cv_destroy(&mixer->outcv); |
4817 | | | 4759 | |
4818 | if (mixer->sih) { | | 4760 | if (mixer->sih) { |
4819 | softint_disestablish(mixer->sih); | | 4761 | softint_disestablish(mixer->sih); |
4820 | mixer->sih = NULL; | | 4762 | mixer->sih = NULL; |
4821 | } | | 4763 | } |
4822 | } | | 4764 | } |
4823 | | | 4765 | |
4824 | /* | | 4766 | /* |
4825 | * Starts playback mixer. | | 4767 | * Starts playback mixer. |
4826 | * Must be called only if sc_pbusy is false. | | 4768 | * Must be called only if sc_pbusy is false. |
4827 | * Must be called with sc_lock held. | | 4769 | * Must be called with sc_lock held. |
4828 | * Must not be called from the interrupt context. | | 4770 | * Must not be called from the interrupt context. |
4829 | */ | | 4771 | */ |
4830 | static void | | 4772 | static void |
4831 | audio_pmixer_start(struct audio_softc *sc, bool force) | | 4773 | audio_pmixer_start(struct audio_softc *sc, bool force) |
4832 | { | | 4774 | { |
4833 | audio_trackmixer_t *mixer; | | 4775 | audio_trackmixer_t *mixer; |
4834 | int minimum; | | 4776 | int minimum; |
4835 | | | 4777 | |
4836 | KASSERT(mutex_owned(sc->sc_lock)); | | 4778 | KASSERT(mutex_owned(sc->sc_lock)); |
4837 | KASSERT(sc->sc_pbusy == false); | | 4779 | KASSERT(sc->sc_pbusy == false); |
4838 | | | 4780 | |
4839 | mutex_enter(sc->sc_intr_lock); | | 4781 | mutex_enter(sc->sc_intr_lock); |
4840 | | | 4782 | |
4841 | mixer = sc->sc_pmixer; | | 4783 | mixer = sc->sc_pmixer; |
4842 | TRACE(2, "%smixseq=%d hwseq=%d hwbuf=%d/%d/%d%s", | | 4784 | TRACE(2, "%smixseq=%d hwseq=%d hwbuf=%d/%d/%d%s", |
4843 | (audiodebug >= 3) ? "begin " : "", | | 4785 | (audiodebug >= 3) ? "begin " : "", |
4844 | (int)mixer->mixseq, (int)mixer->hwseq, | | 4786 | (int)mixer->mixseq, (int)mixer->hwseq, |
4845 | mixer->hwbuf.head, mixer->hwbuf.used, mixer->hwbuf.capacity, | | 4787 | mixer->hwbuf.head, mixer->hwbuf.used, mixer->hwbuf.capacity, |
4846 | force ? " force" : ""); | | 4788 | force ? " force" : ""); |
4847 | | | 4789 | |
4848 | /* Need two blocks to start normally. */ | | 4790 | /* Need two blocks to start normally. */ |
4849 | minimum = (force) ? 1 : 2; | | 4791 | minimum = (force) ? 1 : 2; |
4850 | while (mixer->hwbuf.used < mixer->frames_per_block * minimum) { | | 4792 | while (mixer->hwbuf.used < mixer->frames_per_block * minimum) { |
4851 | audio_pmixer_process(sc); | | 4793 | audio_pmixer_process(sc); |
4852 | } | | 4794 | } |
4853 | | | 4795 | |
4854 | /* Start output */ | | 4796 | /* Start output */ |
4855 | audio_pmixer_output(sc); | | 4797 | audio_pmixer_output(sc); |
4856 | sc->sc_pbusy = true; | | 4798 | sc->sc_pbusy = true; |
4857 | | | 4799 | |
4858 | TRACE(3, "end mixseq=%d hwseq=%d hwbuf=%d/%d/%d", | | 4800 | TRACE(3, "end mixseq=%d hwseq=%d hwbuf=%d/%d/%d", |
4859 | (int)mixer->mixseq, (int)mixer->hwseq, | | 4801 | (int)mixer->mixseq, (int)mixer->hwseq, |
4860 | mixer->hwbuf.head, mixer->hwbuf.used, mixer->hwbuf.capacity); | | 4802 | mixer->hwbuf.head, mixer->hwbuf.used, mixer->hwbuf.capacity); |
4861 | | | 4803 | |
4862 | mutex_exit(sc->sc_intr_lock); | | 4804 | mutex_exit(sc->sc_intr_lock); |
4863 | } | | 4805 | } |
4864 | | | 4806 | |
4865 | /* | | 4807 | /* |
4866 | * When playing back with MD filter: | | 4808 | * When playing back with MD filter: |
4867 | * | | 4809 | * |
4868 | * track track ... | | 4810 | * track track ... |
4869 | * v v | | 4811 | * v v |
4870 | * + mix (with aint2_t) | | 4812 | * + mix (with aint2_t) |
4871 | * | master volume (with aint2_t) | | 4813 | * | master volume (with aint2_t) |
4872 | * v | | 4814 | * v |
4873 | * mixsample [::::] wide-int 1 block (ring) buffer | | 4815 | * mixsample [::::] wide-int 1 block (ring) buffer |
4874 | * | | | 4816 | * | |
4875 | * | convert aint2_t -> aint_t | | 4817 | * | convert aint2_t -> aint_t |
4876 | * v | | 4818 | * v |
4877 | * codecbuf [....] 1 block (ring) buffer | | 4819 | * codecbuf [....] 1 block (ring) buffer |
4878 | * | | | 4820 | * | |
4879 | * | convert to hw format | | 4821 | * | convert to hw format |
4880 | * v | | 4822 | * v |
4881 | * hwbuf [............] NBLKHW blocks ring buffer | | 4823 | * hwbuf [............] NBLKHW blocks ring buffer |
4882 | * | | 4824 | * |
4883 | * When playing back without MD filter: | | 4825 | * When playing back without MD filter: |
4884 | * | | 4826 | * |
4885 | * mixsample [::::] wide-int 1 block (ring) buffer | | 4827 | * mixsample [::::] wide-int 1 block (ring) buffer |
4886 | * | | | 4828 | * | |
4887 | * | convert aint2_t -> aint_t | | 4829 | * | convert aint2_t -> aint_t |
4888 | * | (with byte swap if necessary) | | 4830 | * | (with byte swap if necessary) |
4889 | * v | | 4831 | * v |
4890 | * hwbuf [............] NBLKHW blocks ring buffer | | 4832 | * hwbuf [............] NBLKHW blocks ring buffer |
4891 | * | | 4833 | * |
4892 | * mixsample: slinear_NE, wide internal precision, HW ch, HW freq. | | 4834 | * mixsample: slinear_NE, wide internal precision, HW ch, HW freq. |
4893 | * codecbuf: slinear_NE, internal precision, HW ch, HW freq. | | 4835 | * codecbuf: slinear_NE, internal precision, HW ch, HW freq. |
4894 | * hwbuf: HW encoding, HW precision, HW ch, HW freq. | | 4836 | * hwbuf: HW encoding, HW precision, HW ch, HW freq. |
4895 | */ | | 4837 | */ |
4896 | | | 4838 | |
4897 | /* | | 4839 | /* |
4898 | * Performs track mixing and converts it to hwbuf. | | 4840 | * Performs track mixing and converts it to hwbuf. |
4899 | * Note that this function doesn't transfer hwbuf to hardware. | | 4841 | * Note that this function doesn't transfer hwbuf to hardware. |
4900 | * Must be called with sc_intr_lock held. | | 4842 | * Must be called with sc_intr_lock held. |
4901 | */ | | 4843 | */ |
4902 | static void | | 4844 | static void |
4903 | audio_pmixer_process(struct audio_softc *sc) | | 4845 | audio_pmixer_process(struct audio_softc *sc) |
4904 | { | | 4846 | { |
4905 | audio_trackmixer_t *mixer; | | 4847 | audio_trackmixer_t *mixer; |
4906 | audio_file_t *f; | | 4848 | audio_file_t *f; |
4907 | int frame_count; | | 4849 | int frame_count; |
4908 | int sample_count; | | 4850 | int sample_count; |
4909 | int mixed; | | 4851 | int mixed; |
4910 | int i; | | 4852 | int i; |
4911 | aint2_t *m; | | 4853 | aint2_t *m; |
4912 | aint_t *h; | | 4854 | aint_t *h; |
4913 | | | 4855 | |
4914 | mixer = sc->sc_pmixer; | | 4856 | mixer = sc->sc_pmixer; |
4915 | | | 4857 | |
4916 | frame_count = mixer->frames_per_block; | | 4858 | frame_count = mixer->frames_per_block; |
4917 | KASSERT(auring_get_contig_free(&mixer->hwbuf) >= frame_count); | | 4859 | KASSERT(auring_get_contig_free(&mixer->hwbuf) >= frame_count); |
4918 | sample_count = frame_count * mixer->mixfmt.channels; | | 4860 | sample_count = frame_count * mixer->mixfmt.channels; |
4919 | | | 4861 | |
4920 | mixer->mixseq++; | | 4862 | mixer->mixseq++; |
4921 | | | 4863 | |
4922 | /* Mix all tracks */ | | 4864 | /* Mix all tracks */ |
4923 | mixed = 0; | | 4865 | mixed = 0; |
4924 | SLIST_FOREACH(f, &sc->sc_files, entry) { | | 4866 | SLIST_FOREACH(f, &sc->sc_files, entry) { |
4925 | audio_track_t *track = f->ptrack; | | 4867 | audio_track_t *track = f->ptrack; |
4926 | | | 4868 | |
4927 | if (track == NULL) | | 4869 | if (track == NULL) |
4928 | continue; | | 4870 | continue; |
4929 | | | 4871 | |
4930 | if (track->is_pause) { | | 4872 | if (track->is_pause) { |
4931 | TRACET(4, track, "skip; paused"); | | 4873 | TRACET(4, track, "skip; paused"); |
4932 | continue; | | 4874 | continue; |
4933 | } | | 4875 | } |
4934 | | | 4876 | |
4935 | /* Skip if the track is used by process context. */ | | 4877 | /* Skip if the track is used by process context. */ |
4936 | if (audio_track_lock_tryenter(track) == false) { | | 4878 | if (audio_track_lock_tryenter(track) == false) { |
4937 | TRACET(4, track, "skip; in use"); | | 4879 | TRACET(4, track, "skip; in use"); |
4938 | continue; | | 4880 | continue; |
4939 | } | | 4881 | } |
4940 | | | 4882 | |
4941 | /* Emulate mmap'ped track */ | | 4883 | /* Emulate mmap'ped track */ |
4942 | if (track->mmapped) { | | 4884 | if (track->mmapped) { |
4943 | auring_push(&track->usrbuf, track->usrbuf_blksize); | | 4885 | auring_push(&track->usrbuf, track->usrbuf_blksize); |
4944 | TRACET(4, track, "mmap; usr=%d/%d/C%d", | | 4886 | TRACET(4, track, "mmap; usr=%d/%d/C%d", |
4945 | track->usrbuf.head, | | 4887 | track->usrbuf.head, |
4946 | track->usrbuf.used, | | 4888 | track->usrbuf.used, |
4947 | track->usrbuf.capacity); | | 4889 | track->usrbuf.capacity); |
4948 | } | | 4890 | } |
4949 | | | 4891 | |
4950 | if (track->outbuf.used < mixer->frames_per_block && | | 4892 | if (track->outbuf.used < mixer->frames_per_block && |
4951 | track->usrbuf.used > 0) { | | 4893 | track->usrbuf.used > 0) { |
4952 | TRACET(4, track, "process"); | | 4894 | TRACET(4, track, "process"); |
4953 | audio_track_play(track); | | 4895 | audio_track_play(track); |
4954 | } | | 4896 | } |
4955 | | | 4897 | |
4956 | if (track->outbuf.used > 0) { | | 4898 | if (track->outbuf.used > 0) { |
4957 | mixed = audio_pmixer_mix_track(mixer, track, mixed); | | 4899 | mixed = audio_pmixer_mix_track(mixer, track, mixed); |
4958 | } else { | | 4900 | } else { |
4959 | TRACET(4, track, "skip; empty"); | | 4901 | TRACET(4, track, "skip; empty"); |
4960 | } | | 4902 | } |
4961 | | | 4903 | |
4962 | audio_track_lock_exit(track); | | 4904 | audio_track_lock_exit(track); |
4963 | } | | 4905 | } |
4964 | | | 4906 | |
4965 | if (mixed == 0) { | | 4907 | if (mixed == 0) { |
4966 | /* Silence */ | | 4908 | /* Silence */ |
4967 | memset(mixer->mixsample, 0, | | 4909 | memset(mixer->mixsample, 0, |
4968 | frametobyte(&mixer->mixfmt, frame_count)); | | 4910 | frametobyte(&mixer->mixfmt, frame_count)); |
4969 | } else { | | 4911 | } else { |
4970 | if (mixed > 1) { | | 4912 | if (mixed > 1) { |
4971 | /* If there are multiple tracks, do auto gain control */ | | 4913 | /* If there are multiple tracks, do auto gain control */ |
4972 | audio_pmixer_agc(mixer, sample_count); | | 4914 | audio_pmixer_agc(mixer, sample_count); |
4973 | } | | 4915 | } |
4974 | | | 4916 | |
4975 | /* Apply master volume */ | | 4917 | /* Apply master volume */ |
4976 | if (mixer->volume < 256) { | | 4918 | if (mixer->volume < 256) { |
4977 | m = mixer->mixsample; | | 4919 | m = mixer->mixsample; |
4978 | for (i = 0; i < sample_count; i++) { | | 4920 | for (i = 0; i < sample_count; i++) { |
4979 | *m = AUDIO_SCALEDOWN(*m * mixer->volume, 8); | | 4921 | *m = AUDIO_SCALEDOWN(*m * mixer->volume, 8); |
4980 | m++; | | 4922 | m++; |
4981 | } | | 4923 | } |
4982 | | | 4924 | |
4983 | /* | | 4925 | /* |
4984 | * Recover the volume gradually at the pace of | | 4926 | * Recover the volume gradually at the pace of |
4985 | * several times per second. If it's too fast, you | | 4927 | * several times per second. If it's too fast, you |
4986 | * can recognize that the volume changes up and down | | 4928 | * can recognize that the volume changes up and down |
4987 | * quickly and it's not so comfortable. | | 4929 | * quickly and it's not so comfortable. |
4988 | */ | | 4930 | */ |
4989 | mixer->voltimer += mixer->blktime_n; | | 4931 | mixer->voltimer += mixer->blktime_n; |
4990 | if (mixer->voltimer * 4 >= mixer->blktime_d) { | | 4932 | if (mixer->voltimer * 4 >= mixer->blktime_d) { |
4991 | mixer->volume++; | | 4933 | mixer->volume++; |
4992 | mixer->voltimer = 0; | | 4934 | mixer->voltimer = 0; |
4993 | #if defined(AUDIO_DEBUG_AGC) | | 4935 | #if defined(AUDIO_DEBUG_AGC) |
4994 | TRACE(1, "volume recover: %d", mixer->volume); | | 4936 | TRACE(1, "volume recover: %d", mixer->volume); |
4995 | #endif | | 4937 | #endif |
4996 | } | | 4938 | } |
4997 | } | | 4939 | } |
4998 | } | | 4940 | } |
4999 | | | 4941 | |
5000 | /* | | 4942 | /* |
5001 | * The rest is the hardware part. | | 4943 | * The rest is the hardware part. |
5002 | */ | | 4944 | */ |
5003 | | | 4945 | |
5004 | if (mixer->codec) { | | 4946 | if (mixer->codec) { |
5005 | h = auring_tailptr_aint(&mixer->codecbuf); | | 4947 | h = auring_tailptr_aint(&mixer->codecbuf); |
5006 | } else { | | 4948 | } else { |
5007 | h = auring_tailptr_aint(&mixer->hwbuf); | | 4949 | h = auring_tailptr_aint(&mixer->hwbuf); |
5008 | } | | 4950 | } |
5009 | | | 4951 | |
5010 | m = mixer->mixsample; | | 4952 | m = mixer->mixsample; |
5011 | if (mixer->swap_endian) { | | 4953 | if (mixer->swap_endian) { |
5012 | for (i = 0; i < sample_count; i++) { | | 4954 | for (i = 0; i < sample_count; i++) { |
5013 | *h++ = bswap16(*m++); | | 4955 | *h++ = bswap16(*m++); |
5014 | } | | 4956 | } |
5015 | } else { | | 4957 | } else { |
5016 | for (i = 0; i < sample_count; i++) { | | 4958 | for (i = 0; i < sample_count; i++) { |
5017 | *h++ = *m++; | | 4959 | *h++ = *m++; |
5018 | } | | 4960 | } |
5019 | } | | 4961 | } |
5020 | | | 4962 | |
5021 | /* Hardware driver's codec */ | | 4963 | /* Hardware driver's codec */ |
5022 | if (mixer->codec) { | | 4964 | if (mixer->codec) { |
5023 | auring_push(&mixer->codecbuf, frame_count); | | 4965 | auring_push(&mixer->codecbuf, frame_count); |
5024 | mixer->codecarg.src = auring_headptr(&mixer->codecbuf); | | 4966 | mixer->codecarg.src = auring_headptr(&mixer->codecbuf); |
5025 | mixer->codecarg.dst = auring_tailptr(&mixer->hwbuf); | | 4967 | mixer->codecarg.dst = auring_tailptr(&mixer->hwbuf); |
5026 | mixer->codecarg.count = frame_count; | | 4968 | mixer->codecarg.count = frame_count; |
5027 | mixer->codec(&mixer->codecarg); | | 4969 | mixer->codec(&mixer->codecarg); |
5028 | auring_take(&mixer->codecbuf, mixer->codecarg.count); | | 4970 | auring_take(&mixer->codecbuf, mixer->codecarg.count); |
5029 | } | | 4971 | } |
5030 | | | 4972 | |
5031 | auring_push(&mixer->hwbuf, frame_count); | | 4973 | auring_push(&mixer->hwbuf, frame_count); |
5032 | | | 4974 | |
5033 | TRACE(4, "done mixseq=%d hwbuf=%d/%d/%d%s", | | 4975 | TRACE(4, "done mixseq=%d hwbuf=%d/%d/%d%s", |
5034 | (int)mixer->mixseq, | | 4976 | (int)mixer->mixseq, |
5035 | mixer->hwbuf.head, mixer->hwbuf.used, mixer->hwbuf.capacity, | | 4977 | mixer->hwbuf.head, mixer->hwbuf.used, mixer->hwbuf.capacity, |
5036 | (mixed == 0) ? " silent" : ""); | | 4978 | (mixed == 0) ? " silent" : ""); |
5037 | } | | 4979 | } |
5038 | | | 4980 | |
5039 | /* | | 4981 | /* |
5040 | * Do auto gain control. | | 4982 | * Do auto gain control. |
5041 | * Must be called sc_intr_lock held. | | 4983 | * Must be called sc_intr_lock held. |
5042 | */ | | 4984 | */ |
5043 | static void | | 4985 | static void |
5044 | audio_pmixer_agc(audio_trackmixer_t *mixer, int sample_count) | | 4986 | audio_pmixer_agc(audio_trackmixer_t *mixer, int sample_count) |
5045 | { | | 4987 | { |
5046 | struct audio_softc *sc __unused; | | 4988 | struct audio_softc *sc __unused; |
5047 | aint2_t val; | | 4989 | aint2_t val; |
5048 | aint2_t maxval; | | 4990 | aint2_t maxval; |
5049 | aint2_t minval; | | 4991 | aint2_t minval; |
5050 | aint2_t over_plus; | | 4992 | aint2_t over_plus; |
5051 | aint2_t over_minus; | | 4993 | aint2_t over_minus; |
5052 | aint2_t *m; | | 4994 | aint2_t *m; |
5053 | int newvol; | | 4995 | int newvol; |
5054 | int i; | | 4996 | int i; |
5055 | | | 4997 | |
5056 | sc = mixer->sc; | | 4998 | sc = mixer->sc; |
5057 | | | 4999 | |
5058 | /* Overflow detection */ | | 5000 | /* Overflow detection */ |
5059 | maxval = AINT_T_MAX; | | 5001 | maxval = AINT_T_MAX; |
5060 | minval = AINT_T_MIN; | | 5002 | minval = AINT_T_MIN; |
5061 | m = mixer->mixsample; | | 5003 | m = mixer->mixsample; |
5062 | for (i = 0; i < sample_count; i++) { | | 5004 | for (i = 0; i < sample_count; i++) { |
5063 | val = *m++; | | 5005 | val = *m++; |
5064 | if (val > maxval) | | 5006 | if (val > maxval) |
5065 | maxval = val; | | 5007 | maxval = val; |
5066 | else if (val < minval) | | 5008 | else if (val < minval) |
5067 | minval = val; | | 5009 | minval = val; |
5068 | } | | 5010 | } |
5069 | | | 5011 | |
5070 | /* Absolute value of overflowed amount */ | | 5012 | /* Absolute value of overflowed amount */ |
5071 | over_plus = maxval - AINT_T_MAX; | | 5013 | over_plus = maxval - AINT_T_MAX; |
5072 | over_minus = AINT_T_MIN - minval; | | 5014 | over_minus = AINT_T_MIN - minval; |
5073 | | | 5015 | |
5074 | if (over_plus > 0 || over_minus > 0) { | | 5016 | if (over_plus > 0 || over_minus > 0) { |
5075 | if (over_plus > over_minus) { | | 5017 | if (over_plus > over_minus) { |
5076 | newvol = (int)((aint2_t)AINT_T_MAX * 256 / maxval); | | 5018 | newvol = (int)((aint2_t)AINT_T_MAX * 256 / maxval); |
5077 | } else { | | 5019 | } else { |
5078 | newvol = (int)((aint2_t)AINT_T_MIN * 256 / minval); | | 5020 | newvol = (int)((aint2_t)AINT_T_MIN * 256 / minval); |
5079 | } | | 5021 | } |
5080 | | | 5022 | |
5081 | /* | | 5023 | /* |
5082 | * Change the volume only if new one is smaller. | | 5024 | * Change the volume only if new one is smaller. |
5083 | * Reset the timer even if the volume isn't changed. | | 5025 | * Reset the timer even if the volume isn't changed. |
5084 | */ | | 5026 | */ |
5085 | if (newvol <= mixer->volume) { | | 5027 | if (newvol <= mixer->volume) { |
5086 | mixer->volume = newvol; | | 5028 | mixer->volume = newvol; |
5087 | mixer->voltimer = 0; | | 5029 | mixer->voltimer = 0; |
5088 | #if defined(AUDIO_DEBUG_AGC) | | 5030 | #if defined(AUDIO_DEBUG_AGC) |
5089 | TRACE(1, "auto volume adjust: %d", mixer->volume); | | 5031 | TRACE(1, "auto volume adjust: %d", mixer->volume); |
5090 | #endif | | 5032 | #endif |
5091 | } | | 5033 | } |
5092 | } | | 5034 | } |
5093 | } | | 5035 | } |
5094 | | | 5036 | |
5095 | /* | | 5037 | /* |
5096 | * Mix one track. | | 5038 | * Mix one track. |
5097 | * 'mixed' specifies the number of tracks mixed so far. | | 5039 | * 'mixed' specifies the number of tracks mixed so far. |
5098 | * It returns the number of tracks mixed. In other words, it returns | | 5040 | * It returns the number of tracks mixed. In other words, it returns |
5099 | * mixed + 1 if this track is mixed. | | 5041 | * mixed + 1 if this track is mixed. |
5100 | */ | | 5042 | */ |
5101 | static int | | 5043 | static int |
5102 | audio_pmixer_mix_track(audio_trackmixer_t *mixer, audio_track_t *track, | | 5044 | audio_pmixer_mix_track(audio_trackmixer_t *mixer, audio_track_t *track, |
5103 | int mixed) | | 5045 | int mixed) |
5104 | { | | 5046 | { |
5105 | int count; | | 5047 | int count; |
5106 | int sample_count; | | 5048 | int sample_count; |
5107 | int remain; | | 5049 | int remain; |
5108 | int i; | | 5050 | int i; |
5109 | const aint_t *s; | | 5051 | const aint_t *s; |
5110 | aint2_t *d; | | 5052 | aint2_t *d; |
5111 | | | 5053 | |
5112 | /* XXX TODO: Is this necessary for now? */ | | 5054 | /* XXX TODO: Is this necessary for now? */ |
5113 | if (mixer->mixseq < track->seq) | | 5055 | if (mixer->mixseq < track->seq) |
5114 | return mixed; | | 5056 | return mixed; |
5115 | | | 5057 | |
5116 | count = auring_get_contig_used(&track->outbuf); | | 5058 | count = auring_get_contig_used(&track->outbuf); |
5117 | count = uimin(count, mixer->frames_per_block); | | 5059 | count = uimin(count, mixer->frames_per_block); |
5118 | | | 5060 | |
5119 | s = auring_headptr_aint(&track->outbuf); | | 5061 | s = auring_headptr_aint(&track->outbuf); |
5120 | d = mixer->mixsample; | | 5062 | d = mixer->mixsample; |
5121 | | | 5063 | |
5122 | /* | | 5064 | /* |
5123 | * Apply track volume with double-sized integer and perform | | 5065 | * Apply track volume with double-sized integer and perform |
5124 | * additive synthesis. | | 5066 | * additive synthesis. |
5125 | * | | 5067 | * |
5126 | * XXX If you limit the track volume to 1.0 or less (<= 256), | | 5068 | * XXX If you limit the track volume to 1.0 or less (<= 256), |
5127 | * it would be better to do this in the track conversion stage | | 5069 | * it would be better to do this in the track conversion stage |
5128 | * rather than here. However, if you accept the volume to | | 5070 | * rather than here. However, if you accept the volume to |
5129 | * be greater than 1.0 (> 256), it's better to do it here. | | 5071 | * be greater than 1.0 (> 256), it's better to do it here. |
5130 | * Because the operation here is done by double-sized integer. | | 5072 | * Because the operation here is done by double-sized integer. |
5131 | */ | | 5073 | */ |
5132 | sample_count = count * mixer->mixfmt.channels; | | 5074 | sample_count = count * mixer->mixfmt.channels; |
5133 | if (mixed == 0) { | | 5075 | if (mixed == 0) { |
5134 | /* If this is the first track, assignment can be used. */ | | 5076 | /* If this is the first track, assignment can be used. */ |
5135 | #if defined(AUDIO_SUPPORT_TRACK_VOLUME) | | 5077 | #if defined(AUDIO_SUPPORT_TRACK_VOLUME) |
5136 | if (track->volume != 256) { | | 5078 | if (track->volume != 256) { |
5137 | for (i = 0; i < sample_count; i++) { | | 5079 | for (i = 0; i < sample_count; i++) { |
5138 | aint2_t v; | | 5080 | aint2_t v; |
5139 | v = *s++; | | 5081 | v = *s++; |
5140 | *d++ = AUDIO_SCALEDOWN(v * track->volume, 8) | | 5082 | *d++ = AUDIO_SCALEDOWN(v * track->volume, 8) |
5141 | } | | 5083 | } |
5142 | } else | | 5084 | } else |
5143 | #endif | | 5085 | #endif |
5144 | { | | 5086 | { |
5145 | for (i = 0; i < sample_count; i++) { | | 5087 | for (i = 0; i < sample_count; i++) { |
5146 | *d++ = ((aint2_t)*s++); | | 5088 | *d++ = ((aint2_t)*s++); |
5147 | } | | 5089 | } |
5148 | } | | 5090 | } |
5149 | /* Fill silence if the first track is not filled. */ | | 5091 | /* Fill silence if the first track is not filled. */ |
5150 | for (; i < mixer->frames_per_block * mixer->mixfmt.channels; i++) | | 5092 | for (; i < mixer->frames_per_block * mixer->mixfmt.channels; i++) |
5151 | *d++ = 0; | | 5093 | *d++ = 0; |
5152 | } else { | | 5094 | } else { |
5153 | /* If this is the second or later, add it. */ | | 5095 | /* If this is the second or later, add it. */ |
5154 | #if defined(AUDIO_SUPPORT_TRACK_VOLUME) | | 5096 | #if defined(AUDIO_SUPPORT_TRACK_VOLUME) |
5155 | if (track->volume != 256) { | | 5097 | if (track->volume != 256) { |
5156 | for (i = 0; i < sample_count; i++) { | | 5098 | for (i = 0; i < sample_count; i++) { |
5157 | aint2_t v; | | 5099 | aint2_t v; |
5158 | v = *s++; | | 5100 | v = *s++; |
5159 | *d++ += AUDIO_SCALEDOWN(v * track->volume, 8); | | 5101 | *d++ += AUDIO_SCALEDOWN(v * track->volume, 8); |
5160 | } | | 5102 | } |
5161 | } else | | 5103 | } else |
5162 | #endif | | 5104 | #endif |
5163 | { | | 5105 | { |
5164 | for (i = 0; i < sample_count; i++) { | | 5106 | for (i = 0; i < sample_count; i++) { |
5165 | *d++ += ((aint2_t)*s++); | | 5107 | *d++ += ((aint2_t)*s++); |
5166 | } | | 5108 | } |
5167 | } | | 5109 | } |
5168 | } | | 5110 | } |
5169 | | | 5111 | |
5170 | auring_take(&track->outbuf, count); | | 5112 | auring_take(&track->outbuf, count); |
5171 | /* | | 5113 | /* |
5172 | * The counters have to align block even if outbuf is less than | | 5114 | * The counters have to align block even if outbuf is less than |
5173 | * one block. XXX Is this still necessary? | | 5115 | * one block. XXX Is this still necessary? |
5174 | */ | | 5116 | */ |
5175 | remain = mixer->frames_per_block - count; | | 5117 | remain = mixer->frames_per_block - count; |
5176 | if (__predict_false(remain != 0)) { | | 5118 | if (__predict_false(remain != 0)) { |
5177 | auring_push(&track->outbuf, remain); | | 5119 | auring_push(&track->outbuf, remain); |
5178 | auring_take(&track->outbuf, remain); | | 5120 | auring_take(&track->outbuf, remain); |
5179 | } | | 5121 | } |
5180 | | | 5122 | |
5181 | /* | | 5123 | /* |
5182 | * Update track sequence. | | 5124 | * Update track sequence. |
5183 | * mixseq has previous value yet at this point. | | 5125 | * mixseq has previous value yet at this point. |
5184 | */ | | 5126 | */ |
5185 | track->seq = mixer->mixseq + 1; | | 5127 | track->seq = mixer->mixseq + 1; |
5186 | | | 5128 | |
5187 | return mixed + 1; | | 5129 | return mixed + 1; |
5188 | } | | 5130 | } |
5189 | | | 5131 | |
5190 | /* | | 5132 | /* |
5191 | * Output one block from hwbuf to HW. | | 5133 | * Output one block from hwbuf to HW. |
5192 | * Must be called with sc_intr_lock held. | | 5134 | * Must be called with sc_intr_lock held. |
5193 | */ | | 5135 | */ |
5194 | static void | | 5136 | static void |
5195 | audio_pmixer_output(struct audio_softc *sc) | | 5137 | audio_pmixer_output(struct audio_softc *sc) |
5196 | { | | 5138 | { |
5197 | audio_trackmixer_t *mixer; | | 5139 | audio_trackmixer_t *mixer; |
5198 | audio_params_t params; | | 5140 | audio_params_t params; |
5199 | void *start; | | 5141 | void *start; |
5200 | void *end; | | 5142 | void *end; |
5201 | int blksize; | | 5143 | int blksize; |
5202 | int error; | | 5144 | int error; |
5203 | | | 5145 | |
5204 | mixer = sc->sc_pmixer; | | 5146 | mixer = sc->sc_pmixer; |
5205 | TRACE(4, "pbusy=%d hwbuf=%d/%d/%d", | | 5147 | TRACE(4, "pbusy=%d hwbuf=%d/%d/%d", |
5206 | sc->sc_pbusy, | | 5148 | sc->sc_pbusy, |
5207 | mixer->hwbuf.head, mixer->hwbuf.used, mixer->hwbuf.capacity); | | 5149 | mixer->hwbuf.head, mixer->hwbuf.used, mixer->hwbuf.capacity); |
5208 | KASSERT(mixer->hwbuf.used >= mixer->frames_per_block); | | 5150 | KASSERT(mixer->hwbuf.used >= mixer->frames_per_block); |
5209 | | | 5151 | |
5210 | blksize = frametobyte(&mixer->hwbuf.fmt, mixer->frames_per_block); | | 5152 | blksize = frametobyte(&mixer->hwbuf.fmt, mixer->frames_per_block); |
5211 | | | 5153 | |
5212 | if (sc->hw_if->trigger_output) { | | 5154 | if (sc->hw_if->trigger_output) { |
5213 | /* trigger (at once) */ | | 5155 | /* trigger (at once) */ |
5214 | if (!sc->sc_pbusy) { | | 5156 | if (!sc->sc_pbusy) { |
5215 | start = mixer->hwbuf.mem; | | 5157 | start = mixer->hwbuf.mem; |
5216 | end = (uint8_t *)start + auring_bytelen(&mixer->hwbuf); | | 5158 | end = (uint8_t *)start + auring_bytelen(&mixer->hwbuf); |
5217 | params = format2_to_params(&mixer->hwbuf.fmt); | | 5159 | params = format2_to_params(&mixer->hwbuf.fmt); |
5218 | | | 5160 | |
5219 | error = sc->hw_if->trigger_output(sc->hw_hdl, | | 5161 | error = sc->hw_if->trigger_output(sc->hw_hdl, |
5220 | start, end, blksize, audio_pintr, sc, ¶ms); | | 5162 | start, end, blksize, audio_pintr, sc, ¶ms); |
5221 | if (error) { | | 5163 | if (error) { |
5222 | device_printf(sc->sc_dev, | | 5164 | device_printf(sc->sc_dev, |
5223 | "trigger_output failed with %d\n", error); | | 5165 | "trigger_output failed with %d\n", error); |
5224 | return; | | 5166 | return; |
5225 | } | | 5167 | } |
5226 | } | | 5168 | } |
5227 | } else { | | 5169 | } else { |
5228 | /* start (everytime) */ | | 5170 | /* start (everytime) */ |
5229 | start = auring_headptr(&mixer->hwbuf); | | 5171 | start = auring_headptr(&mixer->hwbuf); |
5230 | | | 5172 | |
5231 | error = sc->hw_if->start_output(sc->hw_hdl, | | 5173 | error = sc->hw_if->start_output(sc->hw_hdl, |
5232 | start, blksize, audio_pintr, sc); | | 5174 | start, blksize, audio_pintr, sc); |
5233 | if (error) { | | 5175 | if (error) { |
5234 | device_printf(sc->sc_dev, | | 5176 | device_printf(sc->sc_dev, |
5235 | "start_output failed with %d\n", error); | | 5177 | "start_output failed with %d\n", error); |
5236 | return; | | 5178 | return; |
5237 | } | | 5179 | } |
5238 | } | | 5180 | } |
5239 | } | | 5181 | } |
5240 | | | 5182 | |
5241 | /* | | 5183 | /* |
5242 | * This is an interrupt handler for playback. | | 5184 | * This is an interrupt handler for playback. |
5243 | * It is called with sc_intr_lock held. | | 5185 | * It is called with sc_intr_lock held. |
5244 | * | | 5186 | * |
5245 | * It is usually called from hardware interrupt. However, note that | | 5187 | * It is usually called from hardware interrupt. However, note that |
5246 | * for some drivers (e.g. uaudio) it is called from software interrupt. | | 5188 | * for some drivers (e.g. uaudio) it is called from software interrupt. |
5247 | */ | | 5189 | */ |
5248 | static void | | 5190 | static void |
5249 | audio_pintr(void *arg) | | 5191 | audio_pintr(void *arg) |
5250 | { | | 5192 | { |
5251 | struct audio_softc *sc; | | 5193 | struct audio_softc *sc; |
5252 | audio_trackmixer_t *mixer; | | 5194 | audio_trackmixer_t *mixer; |
5253 | | | 5195 | |
5254 | sc = arg; | | 5196 | sc = arg; |
5255 | KASSERT(mutex_owned(sc->sc_intr_lock)); | | 5197 | KASSERT(mutex_owned(sc->sc_intr_lock)); |
5256 | | | 5198 | |
5257 | if (sc->sc_dying) | | 5199 | if (sc->sc_dying) |
5258 | return; | | 5200 | return; |
5259 | #if defined(DIAGNOSTIC) | | 5201 | #if defined(DIAGNOSTIC) |
5260 | if (sc->sc_pbusy == false) { | | 5202 | if (sc->sc_pbusy == false) { |
5261 | device_printf(sc->sc_dev, "stray interrupt\n"); | | 5203 | device_printf(sc->sc_dev, "stray interrupt\n"); |
5262 | return; | | 5204 | return; |
5263 | } | | 5205 | } |
5264 | #endif | | 5206 | #endif |
5265 | | | 5207 | |
5266 | mixer = sc->sc_pmixer; | | 5208 | mixer = sc->sc_pmixer; |
5267 | mixer->hw_complete_counter += mixer->frames_per_block; | | 5209 | mixer->hw_complete_counter += mixer->frames_per_block; |
5268 | mixer->hwseq++; | | 5210 | mixer->hwseq++; |
5269 | | | 5211 | |
5270 | auring_take(&mixer->hwbuf, mixer->frames_per_block); | | 5212 | auring_take(&mixer->hwbuf, mixer->frames_per_block); |
5271 | | | 5213 | |
5272 | TRACE(4, | | 5214 | TRACE(4, |
5273 | "HW_INT ++hwseq=%" PRIu64 " cmplcnt=%" PRIu64 " hwbuf=%d/%d/%d", | | 5215 | "HW_INT ++hwseq=%" PRIu64 " cmplcnt=%" PRIu64 " hwbuf=%d/%d/%d", |
5274 | mixer->hwseq, mixer->hw_complete_counter, | | 5216 | mixer->hwseq, mixer->hw_complete_counter, |
5275 | mixer->hwbuf.head, mixer->hwbuf.used, mixer->hwbuf.capacity); | | 5217 | mixer->hwbuf.head, mixer->hwbuf.used, mixer->hwbuf.capacity); |
5276 | | | 5218 | |
5277 | #if !defined(_KERNEL) | | 5219 | #if !defined(_KERNEL) |
5278 | /* This is a debug code for userland test. */ | | 5220 | /* This is a debug code for userland test. */ |
5279 | return; | | 5221 | return; |
5280 | #endif | | 5222 | #endif |
5281 | | | 5223 | |
5282 | #if defined(AUDIO_HW_SINGLE_BUFFER) | | 5224 | #if defined(AUDIO_HW_SINGLE_BUFFER) |
5283 | /* | | 5225 | /* |
5284 | * Create a new block here and output it immediately. | | 5226 | * Create a new block here and output it immediately. |
5285 | * It makes a latency lower but needs machine power. | | 5227 | * It makes a latency lower but needs machine power. |
5286 | */ | | 5228 | */ |
5287 | audio_pmixer_process(sc); | | 5229 | audio_pmixer_process(sc); |
5288 | audio_pmixer_output(sc); | | 5230 | audio_pmixer_output(sc); |
5289 | #else | | 5231 | #else |
5290 | /* | | 5232 | /* |
5291 | * It is called when block N output is done. | | 5233 | * It is called when block N output is done. |
5292 | * Output immediately block N+1 created by the last interrupt. | | 5234 | * Output immediately block N+1 created by the last interrupt. |
5293 | * And then create block N+2 for the next interrupt. | | 5235 | * And then create block N+2 for the next interrupt. |
5294 | * This method makes playback robust even on slower machines. | | 5236 | * This method makes playback robust even on slower machines. |
5295 | * Instead the latency is increased by one block. | | 5237 | * Instead the latency is increased by one block. |
5296 | */ | | 5238 | */ |
5297 | | | 5239 | |
5298 | /* At first, output ready block. */ | | 5240 | /* At first, output ready block. */ |
5299 | if (mixer->hwbuf.used >= mixer->frames_per_block) { | | 5241 | if (mixer->hwbuf.used >= mixer->frames_per_block) { |
5300 | audio_pmixer_output(sc); | | 5242 | audio_pmixer_output(sc); |
5301 | } | | 5243 | } |
5302 | | | 5244 | |
5303 | bool later = false; | | 5245 | bool later = false; |
5304 | | | 5246 | |
5305 | if (mixer->hwbuf.used < mixer->frames_per_block) { | | 5247 | if (mixer->hwbuf.used < mixer->frames_per_block) { |
5306 | later = true; | | 5248 | later = true; |
5307 | } | | 5249 | } |
5308 | | | 5250 | |
5309 | /* Then, process next block. */ | | 5251 | /* Then, process next block. */ |
5310 | audio_pmixer_process(sc); | | 5252 | audio_pmixer_process(sc); |
5311 | | | 5253 | |
5312 | if (later) { | | 5254 | if (later) { |
5313 | audio_pmixer_output(sc); | | 5255 | audio_pmixer_output(sc); |
5314 | } | | 5256 | } |
5315 | #endif | | 5257 | #endif |
5316 | | | 5258 | |
5317 | /* | | 5259 | /* |
5318 | * When this interrupt is the real hardware interrupt, disabling | | 5260 | * When this interrupt is the real hardware interrupt, disabling |
5319 | * preemption here is not necessary. But some drivers (e.g. uaudio) | | 5261 | * preemption here is not necessary. But some drivers (e.g. uaudio) |
5320 | * emulate it by software interrupt, so kpreempt_disable is necessary. | | 5262 | * emulate it by software interrupt, so kpreempt_disable is necessary. |
5321 | */ | | 5263 | */ |
5322 | kpreempt_disable(); | | 5264 | kpreempt_disable(); |
5323 | softint_schedule(mixer->sih); | | 5265 | softint_schedule(mixer->sih); |
5324 | kpreempt_enable(); | | 5266 | kpreempt_enable(); |
5325 | } | | 5267 | } |
5326 | | | 5268 | |
5327 | /* | | 5269 | /* |
5328 | * Starts record mixer. | | 5270 | * Starts record mixer. |
5329 | * Must be called only if sc_rbusy is false. | | 5271 | * Must be called only if sc_rbusy is false. |
5330 | * Must be called with sc_lock held. | | 5272 | * Must be called with sc_lock held. |
5331 | * Must not be called from the interrupt context. | | 5273 | * Must not be called from the interrupt context. |
5332 | */ | | 5274 | */ |
5333 | static void | | 5275 | static void |
5334 | audio_rmixer_start(struct audio_softc *sc) | | 5276 | audio_rmixer_start(struct audio_softc *sc) |
5335 | { | | 5277 | { |
5336 | | | 5278 | |
5337 | KASSERT(mutex_owned(sc->sc_lock)); | | 5279 | KASSERT(mutex_owned(sc->sc_lock)); |
5338 | KASSERT(sc->sc_rbusy == false); | | 5280 | KASSERT(sc->sc_rbusy == false); |
5339 | | | 5281 | |
5340 | mutex_enter(sc->sc_intr_lock); | | 5282 | mutex_enter(sc->sc_intr_lock); |
5341 | | | 5283 | |
5342 | TRACE(2, "%s", (audiodebug >= 3) ? "begin" : ""); | | 5284 | TRACE(2, "%s", (audiodebug >= 3) ? "begin" : ""); |
5343 | audio_rmixer_input(sc); | | 5285 | audio_rmixer_input(sc); |
5344 | sc->sc_rbusy = true; | | 5286 | sc->sc_rbusy = true; |
5345 | TRACE(3, "end"); | | 5287 | TRACE(3, "end"); |
5346 | | | 5288 | |
5347 | mutex_exit(sc->sc_intr_lock); | | 5289 | mutex_exit(sc->sc_intr_lock); |
5348 | } | | 5290 | } |
5349 | | | 5291 | |
5350 | /* | | 5292 | /* |
5351 | * When recording with MD filter: | | 5293 | * When recording with MD filter: |
5352 | * | | 5294 | * |
5353 | * hwbuf [............] NBLKHW blocks ring buffer | | 5295 | * hwbuf [............] NBLKHW blocks ring buffer |
5354 | * | | | 5296 | * | |
5355 | * | convert from hw format | | 5297 | * | convert from hw format |
5356 | * v | | 5298 | * v |
5357 | * codecbuf [....] 1 block (ring) buffer | | 5299 | * codecbuf [....] 1 block (ring) buffer |
5358 | * | | | | 5300 | * | | |
5359 | * v v | | 5301 | * v v |
5360 | * track track ... | | 5302 | * track track ... |
5361 | * | | 5303 | * |
5362 | * When recording without MD filter: | | 5304 | * When recording without MD filter: |
5363 | * | | 5305 | * |
5364 | * hwbuf [............] NBLKHW blocks ring buffer | | 5306 | * hwbuf [............] NBLKHW blocks ring buffer |
5365 | * | | | | 5307 | * | | |
5366 | * v v | | 5308 | * v v |
5367 | * track track ... | | 5309 | * track track ... |
5368 | * | | 5310 | * |
5369 | * hwbuf: HW encoding, HW precision, HW ch, HW freq. | | 5311 | * hwbuf: HW encoding, HW precision, HW ch, HW freq. |
5370 | * codecbuf: slinear_NE, internal precision, HW ch, HW freq. | | 5312 | * codecbuf: slinear_NE, internal precision, HW ch, HW freq. |
5371 | */ | | 5313 | */ |
5372 | | | 5314 | |
5373 | /* | | 5315 | /* |
5374 | * Distribute a recorded block to all recording tracks. | | 5316 | * Distribute a recorded block to all recording tracks. |
5375 | */ | | 5317 | */ |
5376 | static void | | 5318 | static void |
5377 | audio_rmixer_process(struct audio_softc *sc) | | 5319 | audio_rmixer_process(struct audio_softc *sc) |
5378 | { | | 5320 | { |
5379 | audio_trackmixer_t *mixer; | | 5321 | audio_trackmixer_t *mixer; |
5380 | audio_ring_t *mixersrc; | | 5322 | audio_ring_t *mixersrc; |
5381 | audio_file_t *f; | | 5323 | audio_file_t *f; |
5382 | aint_t *p; | | 5324 | aint_t *p; |
5383 | int count; | | 5325 | int count; |
5384 | int bytes; | | 5326 | int bytes; |
5385 | int i; | | 5327 | int i; |
5386 | | | 5328 | |
5387 | mixer = sc->sc_rmixer; | | 5329 | mixer = sc->sc_rmixer; |
5388 | | | 5330 | |
5389 | /* | | 5331 | /* |
5390 | * count is the number of frames to be retrieved this time. | | 5332 | * count is the number of frames to be retrieved this time. |
5391 | * count should be one block. | | 5333 | * count should be one block. |
5392 | */ | | 5334 | */ |
5393 | count = auring_get_contig_used(&mixer->hwbuf); | | 5335 | count = auring_get_contig_used(&mixer->hwbuf); |
5394 | count = uimin(count, mixer->frames_per_block); | | 5336 | count = uimin(count, mixer->frames_per_block); |
5395 | if (count <= 0) { | | 5337 | if (count <= 0) { |
5396 | TRACE(4, "count %d: too short", count); | | 5338 | TRACE(4, "count %d: too short", count); |
5397 | return; | | 5339 | return; |
5398 | } | | 5340 | } |
5399 | bytes = frametobyte(&mixer->track_fmt, count); | | 5341 | bytes = frametobyte(&mixer->track_fmt, count); |
5400 | | | 5342 | |
5401 | /* Hardware driver's codec */ | | 5343 | /* Hardware driver's codec */ |
5402 | if (mixer->codec) { | | 5344 | if (mixer->codec) { |
5403 | mixer->codecarg.src = auring_headptr(&mixer->hwbuf); | | 5345 | mixer->codecarg.src = auring_headptr(&mixer->hwbuf); |
5404 | mixer->codecarg.dst = auring_tailptr(&mixer->codecbuf); | | 5346 | mixer->codecarg.dst = auring_tailptr(&mixer->codecbuf); |
5405 | mixer->codecarg.count = count; | | 5347 | mixer->codecarg.count = count; |
5406 | mixer->codec(&mixer->codecarg); | | 5348 | mixer->codec(&mixer->codecarg); |
5407 | auring_take(&mixer->hwbuf, mixer->codecarg.count); | | 5349 | auring_take(&mixer->hwbuf, mixer->codecarg.count); |
5408 | auring_push(&mixer->codecbuf, mixer->codecarg.count); | | 5350 | auring_push(&mixer->codecbuf, mixer->codecarg.count); |
5409 | mixersrc = &mixer->codecbuf; | | 5351 | mixersrc = &mixer->codecbuf; |
5410 | } else { | | 5352 | } else { |
5411 | mixersrc = &mixer->hwbuf; | | 5353 | mixersrc = &mixer->hwbuf; |
5412 | } | | 5354 | } |
5413 | | | 5355 | |
5414 | if (mixer->swap_endian) { | | 5356 | if (mixer->swap_endian) { |
5415 | /* inplace conversion */ | | 5357 | /* inplace conversion */ |
5416 | p = auring_headptr_aint(mixersrc); | | 5358 | p = auring_headptr_aint(mixersrc); |
5417 | for (i = 0; i < count * mixer->track_fmt.channels; i++, p++) { | | 5359 | for (i = 0; i < count * mixer->track_fmt.channels; i++, p++) { |
5418 | *p = bswap16(*p); | | 5360 | *p = bswap16(*p); |
5419 | } | | 5361 | } |
5420 | } | | 5362 | } |
5421 | | | 5363 | |
5422 | /* Distribute to all tracks. */ | | 5364 | /* Distribute to all tracks. */ |
5423 | SLIST_FOREACH(f, &sc->sc_files, entry) { | | 5365 | SLIST_FOREACH(f, &sc->sc_files, entry) { |
5424 | audio_track_t *track = f->rtrack; | | 5366 | audio_track_t *track = f->rtrack; |
5425 | audio_ring_t *input; | | 5367 | audio_ring_t *input; |
5426 | | | 5368 | |
5427 | if (track == NULL) | | 5369 | if (track == NULL) |
5428 | continue; | | 5370 | continue; |
5429 | | | 5371 | |
5430 | if (track->is_pause) { | | 5372 | if (track->is_pause) { |
5431 | TRACET(4, track, "skip; paused"); | | 5373 | TRACET(4, track, "skip; paused"); |
5432 | continue; | | 5374 | continue; |
5433 | } | | 5375 | } |
5434 | | | 5376 | |
5435 | if (audio_track_lock_tryenter(track) == false) { | | 5377 | if (audio_track_lock_tryenter(track) == false) { |
5436 | TRACET(4, track, "skip; in use"); | | 5378 | TRACET(4, track, "skip; in use"); |
5437 | continue; | | 5379 | continue; |
5438 | } | | 5380 | } |
5439 | | | 5381 | |
5440 | /* If the track buffer is full, discard the oldest one? */ | | 5382 | /* If the track buffer is full, discard the oldest one? */ |
5441 | input = track->input; | | 5383 | input = track->input; |
5442 | if (input->capacity - input->used < mixer->frames_per_block) { | | 5384 | if (input->capacity - input->used < mixer->frames_per_block) { |
5443 | int drops = mixer->frames_per_block - | | 5385 | int drops = mixer->frames_per_block - |
5444 | (input->capacity - input->used); | | 5386 | (input->capacity - input->used); |
5445 | track->dropframes += drops; | | 5387 | track->dropframes += drops; |
5446 | TRACET(4, track, "drop %d frames: inp=%d/%d/%d", | | 5388 | TRACET(4, track, "drop %d frames: inp=%d/%d/%d", |
5447 | drops, | | 5389 | drops, |
5448 | input->head, input->used, input->capacity); | | 5390 | input->head, input->used, input->capacity); |
5449 | auring_take(input, drops); | | 5391 | auring_take(input, drops); |
5450 | } | | 5392 | } |
5451 | KASSERT(input->used % mixer->frames_per_block == 0); | | 5393 | KASSERT(input->used % mixer->frames_per_block == 0); |
5452 | | | 5394 | |
5453 | memcpy(auring_tailptr_aint(input), | | 5395 | memcpy(auring_tailptr_aint(input), |
5454 | auring_headptr_aint(mixersrc), | | 5396 | auring_headptr_aint(mixersrc), |
5455 | bytes); | | 5397 | bytes); |
5456 | auring_push(input, count); | | 5398 | auring_push(input, count); |
5457 | | | 5399 | |
5458 | /* XXX sequence counter? */ | | 5400 | /* XXX sequence counter? */ |
5459 | | | 5401 | |
5460 | audio_track_lock_exit(track); | | 5402 | audio_track_lock_exit(track); |
5461 | } | | 5403 | } |
5462 | | | 5404 | |
5463 | auring_take(mixersrc, count); | | 5405 | auring_take(mixersrc, count); |
5464 | } | | 5406 | } |
5465 | | | 5407 | |
5466 | /* | | 5408 | /* |
5467 | * Input one block from HW to hwbuf. | | 5409 | * Input one block from HW to hwbuf. |
5468 | * Must be called with sc_intr_lock held. | | 5410 | * Must be called with sc_intr_lock held. |
5469 | */ | | 5411 | */ |
5470 | static void | | 5412 | static void |
5471 | audio_rmixer_input(struct audio_softc *sc) | | 5413 | audio_rmixer_input(struct audio_softc *sc) |
5472 | { | | 5414 | { |
5473 | audio_trackmixer_t *mixer; | | 5415 | audio_trackmixer_t *mixer; |
5474 | audio_params_t params; | | 5416 | audio_params_t params; |
5475 | void *start; | | 5417 | void *start; |
5476 | void *end; | | 5418 | void *end; |
5477 | int blksize; | | 5419 | int blksize; |
5478 | int error; | | 5420 | int error; |
5479 | | | 5421 | |
5480 | mixer = sc->sc_rmixer; | | 5422 | mixer = sc->sc_rmixer; |
5481 | blksize = frametobyte(&mixer->hwbuf.fmt, mixer->frames_per_block); | | 5423 | blksize = frametobyte(&mixer->hwbuf.fmt, mixer->frames_per_block); |
5482 | | | 5424 | |
5483 | if (sc->hw_if->trigger_input) { | | 5425 | if (sc->hw_if->trigger_input) { |
5484 | /* trigger (at once) */ | | 5426 | /* trigger (at once) */ |
5485 | if (!sc->sc_rbusy) { | | 5427 | if (!sc->sc_rbusy) { |
5486 | start = mixer->hwbuf.mem; | | 5428 | start = mixer->hwbuf.mem; |
5487 | end = (uint8_t *)start + auring_bytelen(&mixer->hwbuf); | | 5429 | end = (uint8_t *)start + auring_bytelen(&mixer->hwbuf); |
5488 | params = format2_to_params(&mixer->hwbuf.fmt); | | 5430 | params = format2_to_params(&mixer->hwbuf.fmt); |
5489 | | | 5431 | |
5490 | error = sc->hw_if->trigger_input(sc->hw_hdl, | | 5432 | error = sc->hw_if->trigger_input(sc->hw_hdl, |
5491 | start, end, blksize, audio_rintr, sc, ¶ms); | | 5433 | start, end, blksize, audio_rintr, sc, ¶ms); |
5492 | if (error) { | | 5434 | if (error) { |
5493 | device_printf(sc->sc_dev, | | 5435 | device_printf(sc->sc_dev, |
5494 | "trigger_input failed with %d\n", error); | | 5436 | "trigger_input failed with %d\n", error); |
5495 | return; | | 5437 | return; |
5496 | } | | 5438 | } |
5497 | } | | 5439 | } |
5498 | } else { | | 5440 | } else { |
5499 | /* start (everytime) */ | | 5441 | /* start (everytime) */ |
5500 | start = auring_tailptr(&mixer->hwbuf); | | 5442 | start = auring_tailptr(&mixer->hwbuf); |
5501 | | | 5443 | |
5502 | error = sc->hw_if->start_input(sc->hw_hdl, | | 5444 | error = sc->hw_if->start_input(sc->hw_hdl, |
5503 | start, blksize, audio_rintr, sc); | | 5445 | start, blksize, audio_rintr, sc); |
5504 | if (error) { | | 5446 | if (error) { |
5505 | device_printf(sc->sc_dev, | | 5447 | device_printf(sc->sc_dev, |
5506 | "start_input failed with %d\n", error); | | 5448 | "start_input failed with %d\n", error); |
5507 | return; | | 5449 | return; |
5508 | } | | 5450 | } |
5509 | } | | 5451 | } |
5510 | } | | 5452 | } |
5511 | | | 5453 | |
5512 | /* | | 5454 | /* |
5513 | * This is an interrupt handler for recording. | | 5455 | * This is an interrupt handler for recording. |
5514 | * It is called with sc_intr_lock. | | 5456 | * It is called with sc_intr_lock. |
5515 | * | | 5457 | * |
5516 | * It is usually called from hardware interrupt. However, note that | | 5458 | * It is usually called from hardware interrupt. However, note that |
5517 | * for some drivers (e.g. uaudio) it is called from software interrupt. | | 5459 | * for some drivers (e.g. uaudio) it is called from software interrupt. |
5518 | */ | | 5460 | */ |
5519 | static void | | 5461 | static void |
5520 | audio_rintr(void *arg) | | 5462 | audio_rintr(void *arg) |
5521 | { | | 5463 | { |
5522 | struct audio_softc *sc; | | 5464 | struct audio_softc *sc; |
5523 | audio_trackmixer_t *mixer; | | 5465 | audio_trackmixer_t *mixer; |
5524 | | | 5466 | |
5525 | sc = arg; | | 5467 | sc = arg; |
5526 | KASSERT(mutex_owned(sc->sc_intr_lock)); | | 5468 | KASSERT(mutex_owned(sc->sc_intr_lock)); |
5527 | | | 5469 | |
5528 | if (sc->sc_dying) | | 5470 | if (sc->sc_dying) |
5529 | return; | | 5471 | return; |
5530 | #if defined(DIAGNOSTIC) | | 5472 | #if defined(DIAGNOSTIC) |
5531 | if (sc->sc_rbusy == false) { | | 5473 | if (sc->sc_rbusy == false) { |
5532 | device_printf(sc->sc_dev, "stray interrupt\n"); | | 5474 | device_printf(sc->sc_dev, "stray interrupt\n"); |
5533 | return; | | 5475 | return; |
5534 | } | | 5476 | } |
5535 | #endif | | 5477 | #endif |
5536 | | | 5478 | |
5537 | mixer = sc->sc_rmixer; | | 5479 | mixer = sc->sc_rmixer; |
5538 | mixer->hw_complete_counter += mixer->frames_per_block; | | 5480 | mixer->hw_complete_counter += mixer->frames_per_block; |
5539 | mixer->hwseq++; | | 5481 | mixer->hwseq++; |
5540 | | | 5482 | |
5541 | auring_push(&mixer->hwbuf, mixer->frames_per_block); | | 5483 | auring_push(&mixer->hwbuf, mixer->frames_per_block); |
5542 | | | 5484 | |
5543 | TRACE(4, | | 5485 | TRACE(4, |
5544 | "HW_INT ++hwseq=%" PRIu64 " cmplcnt=%" PRIu64 " hwbuf=%d/%d/%d", | | 5486 | "HW_INT ++hwseq=%" PRIu64 " cmplcnt=%" PRIu64 " hwbuf=%d/%d/%d", |
5545 | mixer->hwseq, mixer->hw_complete_counter, | | 5487 | mixer->hwseq, mixer->hw_complete_counter, |
5546 | mixer->hwbuf.head, mixer->hwbuf.used, mixer->hwbuf.capacity); | | 5488 | mixer->hwbuf.head, mixer->hwbuf.used, mixer->hwbuf.capacity); |
5547 | | | 5489 | |
5548 | /* Distrubute recorded block */ | | 5490 | /* Distrubute recorded block */ |
5549 | audio_rmixer_process(sc); | | 5491 | audio_rmixer_process(sc); |
5550 | | | 5492 | |
5551 | /* Request next block */ | | 5493 | /* Request next block */ |
5552 | audio_rmixer_input(sc); | | 5494 | audio_rmixer_input(sc); |
5553 | | | 5495 | |
5554 | /* | | 5496 | /* |
5555 | * When this interrupt is the real hardware interrupt, disabling | | 5497 | * When this interrupt is the real hardware interrupt, disabling |
5556 | * preemption here is not necessary. But some drivers (e.g. uaudio) | | 5498 | * preemption here is not necessary. But some drivers (e.g. uaudio) |
5557 | * emulate it by software interrupt, so kpreempt_disable is necessary. | | 5499 | * emulate it by software interrupt, so kpreempt_disable is necessary. |
5558 | */ | | 5500 | */ |
5559 | kpreempt_disable(); | | 5501 | kpreempt_disable(); |
5560 | softint_schedule(mixer->sih); | | 5502 | softint_schedule(mixer->sih); |
5561 | kpreempt_enable(); | | 5503 | kpreempt_enable(); |
5562 | } | | 5504 | } |
5563 | | | 5505 | |
5564 | /* | | 5506 | /* |
5565 | * Halts playback mixer. | | 5507 | * Halts playback mixer. |
5566 | * This function also clears related parameters, so call this function | | 5508 | * This function also clears related parameters, so call this function |
5567 | * instead of calling halt_output directly. | | 5509 | * instead of calling halt_output directly. |
5568 | * Must be called only if sc_pbusy is true. | | 5510 | * Must be called only if sc_pbusy is true. |
5569 | * Must be called with sc_lock && sc_exlock held. | | 5511 | * Must be called with sc_lock && sc_exlock held. |
5570 | */ | | 5512 | */ |
5571 | static int | | 5513 | static int |
5572 | audio_pmixer_halt(struct audio_softc *sc) | | 5514 | audio_pmixer_halt(struct audio_softc *sc) |
5573 | { | | 5515 | { |
5574 | int error; | | 5516 | int error; |
5575 | | | 5517 | |
5576 | TRACE(2, ""); | | 5518 | TRACE(2, ""); |
5577 | KASSERT(mutex_owned(sc->sc_lock)); | | 5519 | KASSERT(mutex_owned(sc->sc_lock)); |
5578 | KASSERT(sc->sc_exlock); | | 5520 | KASSERT(sc->sc_exlock); |
5579 | | | 5521 | |
5580 | mutex_enter(sc->sc_intr_lock); | | 5522 | mutex_enter(sc->sc_intr_lock); |
5581 | error = sc->hw_if->halt_output(sc->hw_hdl); | | 5523 | error = sc->hw_if->halt_output(sc->hw_hdl); |
5582 | mutex_exit(sc->sc_intr_lock); | | 5524 | mutex_exit(sc->sc_intr_lock); |
5583 | | | 5525 | |
5584 | /* Halts anyway even if some error has occurred. */ | | 5526 | /* Halts anyway even if some error has occurred. */ |
5585 | sc->sc_pbusy = false; | | 5527 | sc->sc_pbusy = false; |
5586 | sc->sc_pmixer->hwbuf.head = 0; | | 5528 | sc->sc_pmixer->hwbuf.head = 0; |
5587 | sc->sc_pmixer->hwbuf.used = 0; | | 5529 | sc->sc_pmixer->hwbuf.used = 0; |
5588 | sc->sc_pmixer->mixseq = 0; | | 5530 | sc->sc_pmixer->mixseq = 0; |
5589 | sc->sc_pmixer->hwseq = 0; | | 5531 | sc->sc_pmixer->hwseq = 0; |
5590 | | | 5532 | |
5591 | return error; | | 5533 | return error; |
5592 | } | | 5534 | } |
5593 | | | 5535 | |
5594 | /* | | 5536 | /* |
5595 | * Halts recording mixer. | | 5537 | * Halts recording mixer. |
5596 | * This function also clears related parameters, so call this function | | 5538 | * This function also clears related parameters, so call this function |
5597 | * instead of calling halt_input directly. | | 5539 | * instead of calling halt_input directly. |
5598 | * Must be called only if sc_rbusy is true. | | 5540 | * Must be called only if sc_rbusy is true. |
5599 | * Must be called with sc_lock && sc_exlock held. | | 5541 | * Must be called with sc_lock && sc_exlock held. |
5600 | */ | | 5542 | */ |
5601 | static int | | 5543 | static int |
5602 | audio_rmixer_halt(struct audio_softc *sc) | | 5544 | audio_rmixer_halt(struct audio_softc *sc) |
5603 | { | | 5545 | { |
5604 | int error; | | 5546 | int error; |
5605 | | | 5547 | |
5606 | TRACE(2, ""); | | 5548 | TRACE(2, ""); |
5607 | KASSERT(mutex_owned(sc->sc_lock)); | | 5549 | KASSERT(mutex_owned(sc->sc_lock)); |
5608 | KASSERT(sc->sc_exlock); | | 5550 | KASSERT(sc->sc_exlock); |
5609 | | | 5551 | |
5610 | mutex_enter(sc->sc_intr_lock); | | 5552 | mutex_enter(sc->sc_intr_lock); |
5611 | error = sc->hw_if->halt_input(sc->hw_hdl); | | 5553 | error = sc->hw_if->halt_input(sc->hw_hdl); |
5612 | mutex_exit(sc->sc_intr_lock); | | 5554 | mutex_exit(sc->sc_intr_lock); |
5613 | | | 5555 | |
5614 | /* Halts anyway even if some error has occurred. */ | | 5556 | /* Halts anyway even if some error has occurred. */ |
5615 | sc->sc_rbusy = false; | | 5557 | sc->sc_rbusy = false; |
5616 | sc->sc_rmixer->hwbuf.head = 0; | | 5558 | sc->sc_rmixer->hwbuf.head = 0; |
5617 | sc->sc_rmixer->hwbuf.used = 0; | | 5559 | sc->sc_rmixer->hwbuf.used = 0; |
5618 | sc->sc_rmixer->mixseq = 0; | | 5560 | sc->sc_rmixer->mixseq = 0; |
5619 | sc->sc_rmixer->hwseq = 0; | | 5561 | sc->sc_rmixer->hwseq = 0; |
5620 | | | 5562 | |
5621 | return error; | | 5563 | return error; |
5622 | } | | 5564 | } |
5623 | | | 5565 | |
5624 | /* | | 5566 | /* |
5625 | * Flush this track. | | 5567 | * Flush this track. |
5626 | * Halts all operations, clears all buffers, reset error counters. | | 5568 | * Halts all operations, clears all buffers, reset error counters. |
5627 | * XXX I'm not sure... | | 5569 | * XXX I'm not sure... |
5628 | */ | | 5570 | */ |
5629 | static void | | 5571 | static void |
5630 | audio_track_clear(struct audio_softc *sc, audio_track_t *track) | | 5572 | audio_track_clear(struct audio_softc *sc, audio_track_t *track) |
5631 | { | | 5573 | { |
5632 | | | 5574 | |
5633 | KASSERT(track); | | 5575 | KASSERT(track); |
5634 | TRACET(3, track, "clear"); | | 5576 | TRACET(3, track, "clear"); |
5635 | | | 5577 | |
5636 | audio_track_lock_enter(track); | | 5578 | audio_track_lock_enter(track); |
5637 | | | 5579 | |
5638 | track->usrbuf.used = 0; | | 5580 | track->usrbuf.used = 0; |
5639 | /* Clear all internal parameters. */ | | 5581 | /* Clear all internal parameters. */ |
5640 | if (track->codec.filter) { | | 5582 | if (track->codec.filter) { |
5641 | track->codec.srcbuf.used = 0; | | 5583 | track->codec.srcbuf.used = 0; |
5642 | track->codec.srcbuf.head = 0; | | 5584 | track->codec.srcbuf.head = 0; |
5643 | } | | 5585 | } |
5644 | if (track->chvol.filter) { | | 5586 | if (track->chvol.filter) { |
5645 | track->chvol.srcbuf.used = 0; | | 5587 | track->chvol.srcbuf.used = 0; |
5646 | track->chvol.srcbuf.head = 0; | | 5588 | track->chvol.srcbuf.head = 0; |
5647 | } | | 5589 | } |
5648 | if (track->chmix.filter) { | | 5590 | if (track->chmix.filter) { |
5649 | track->chmix.srcbuf.used = 0; | | 5591 | track->chmix.srcbuf.used = 0; |
5650 | track->chmix.srcbuf.head = 0; | | 5592 | track->chmix.srcbuf.head = 0; |
5651 | } | | 5593 | } |
5652 | if (track->freq.filter) { | | 5594 | if (track->freq.filter) { |
5653 | track->freq.srcbuf.used = 0; | | 5595 | track->freq.srcbuf.used = 0; |
5654 | track->freq.srcbuf.head = 0; | | 5596 | track->freq.srcbuf.head = 0; |
5655 | if (track->freq_step < 65536) | | 5597 | if (track->freq_step < 65536) |
5656 | track->freq_current = 65536; | | 5598 | track->freq_current = 65536; |
5657 | else | | 5599 | else |
5658 | track->freq_current = 0; | | 5600 | track->freq_current = 0; |
5659 | memset(track->freq_prev, 0, sizeof(track->freq_prev)); | | 5601 | memset(track->freq_prev, 0, sizeof(track->freq_prev)); |
5660 | memset(track->freq_curr, 0, sizeof(track->freq_curr)); | | 5602 | memset(track->freq_curr, 0, sizeof(track->freq_curr)); |
5661 | } | | 5603 | } |
5662 | /* Clear buffer, then operation halts naturally. */ | | 5604 | /* Clear buffer, then operation halts naturally. */ |
5663 | track->outbuf.used = 0; | | 5605 | track->outbuf.used = 0; |
5664 | | | 5606 | |
5665 | /* Clear counters. */ | | 5607 | /* Clear counters. */ |
5666 | track->dropframes = 0; | | 5608 | track->dropframes = 0; |
5667 | | | 5609 | |
5668 | audio_track_lock_exit(track); | | 5610 | audio_track_lock_exit(track); |
5669 | } | | 5611 | } |
5670 | | | 5612 | |
5671 | /* | | 5613 | /* |
5672 | * Drain the track. | | 5614 | * Drain the track. |
5673 | * track must be present and for playback. | | 5615 | * track must be present and for playback. |
5674 | * If successful, it returns 0. Otherwise returns errno. | | 5616 | * If successful, it returns 0. Otherwise returns errno. |
5675 | * Must be called with sc_lock held. | | 5617 | * Must be called with sc_lock held. |
5676 | */ | | 5618 | */ |
5677 | static int | | 5619 | static int |
5678 | audio_track_drain(struct audio_softc *sc, audio_track_t *track) | | 5620 | audio_track_drain(struct audio_softc *sc, audio_track_t *track) |
5679 | { | | 5621 | { |
5680 | audio_trackmixer_t *mixer; | | 5622 | audio_trackmixer_t *mixer; |
5681 | int done; | | 5623 | int done; |
5682 | int error; | | 5624 | int error; |
5683 | | | 5625 | |
5684 | KASSERT(track); | | 5626 | KASSERT(track); |
5685 | TRACET(3, track, "start"); | | 5627 | TRACET(3, track, "start"); |
5686 | mixer = track->mixer; | | 5628 | mixer = track->mixer; |
5687 | KASSERT(mutex_owned(sc->sc_lock)); | | 5629 | KASSERT(mutex_owned(sc->sc_lock)); |
5688 | | | 5630 | |
5689 | /* Ignore them if pause. */ | | 5631 | /* Ignore them if pause. */ |
5690 | if (track->is_pause) { | | 5632 | if (track->is_pause) { |
5691 | TRACET(3, track, "pause -> clear"); | | 5633 | TRACET(3, track, "pause -> clear"); |
5692 | track->pstate = AUDIO_STATE_CLEAR; | | 5634 | track->pstate = AUDIO_STATE_CLEAR; |
5693 | } | | 5635 | } |
5694 | /* Terminate early here if there is no data in the track. */ | | 5636 | /* Terminate early here if there is no data in the track. */ |
5695 | if (track->pstate == AUDIO_STATE_CLEAR) { | | 5637 | if (track->pstate == AUDIO_STATE_CLEAR) { |
5696 | TRACET(3, track, "no need to drain"); | | 5638 | TRACET(3, track, "no need to drain"); |
5697 | return 0; | | 5639 | return 0; |
5698 | } | | 5640 | } |
5699 | track->pstate = AUDIO_STATE_DRAINING; | | 5641 | track->pstate = AUDIO_STATE_DRAINING; |
5700 | | | 5642 | |
5701 | for (;;) { | | 5643 | for (;;) { |
5702 | /* I want to display it before condition evaluation. */ | | 5644 | /* I want to display it before condition evaluation. */ |
5703 | TRACET(3, track, "pid=%d.%d trkseq=%d hwseq=%d out=%d/%d/%d", | | 5645 | TRACET(3, track, "pid=%d.%d trkseq=%d hwseq=%d out=%d/%d/%d", |
5704 | (int)curproc->p_pid, (int)curlwp->l_lid, | | 5646 | (int)curproc->p_pid, (int)curlwp->l_lid, |
5705 | (int)track->seq, (int)mixer->hwseq, | | 5647 | (int)track->seq, (int)mixer->hwseq, |
5706 | track->outbuf.head, track->outbuf.used, | | 5648 | track->outbuf.head, track->outbuf.used, |
5707 | track->outbuf.capacity); | | 5649 | track->outbuf.capacity); |
5708 | | | 5650 | |
5709 | /* Condition to terminate */ | | 5651 | /* Condition to terminate */ |
5710 | audio_track_lock_enter(track); | | 5652 | audio_track_lock_enter(track); |
5711 | done = (track->usrbuf.used < frametobyte(&track->inputfmt, 1) && | | 5653 | done = (track->usrbuf.used < frametobyte(&track->inputfmt, 1) && |
5712 | track->outbuf.used == 0 && | | 5654 | track->outbuf.used == 0 && |
5713 | track->seq <= mixer->hwseq); | | 5655 | track->seq <= mixer->hwseq); |
5714 | audio_track_lock_exit(track); | | 5656 | audio_track_lock_exit(track); |
5715 | if (done) | | 5657 | if (done) |
5716 | break; | | 5658 | break; |
5717 | | | 5659 | |
5718 | TRACET(3, track, "sleep"); | | 5660 | TRACET(3, track, "sleep"); |
5719 | error = audio_track_waitio(sc, track); | | 5661 | error = audio_track_waitio(sc, track); |
5720 | if (error) | | 5662 | if (error) |
5721 | return error; | | 5663 | return error; |
5722 | | | 5664 | |
5723 | /* XXX call audio_track_play here ? */ | | 5665 | /* XXX call audio_track_play here ? */ |
5724 | } | | 5666 | } |
5725 | | | 5667 | |
5726 | track->pstate = AUDIO_STATE_CLEAR; | | 5668 | track->pstate = AUDIO_STATE_CLEAR; |
5727 | TRACET(3, track, "done trk_inp=%d trk_out=%d", | | 5669 | TRACET(3, track, "done trk_inp=%d trk_out=%d", |
5728 | (int)track->inputcounter, (int)track->outputcounter); | | 5670 | (int)track->inputcounter, (int)track->outputcounter); |
5729 | return 0; | | 5671 | return 0; |
5730 | } | | 5672 | } |
5731 | | | 5673 | |
5732 | /* | | 5674 | /* |
5733 | * Send signal to process. | | 5675 | * Send signal to process. |
5734 | * This is intended to be called only from audio_softintr_{rd,wr}. | | 5676 | * This is intended to be called only from audio_softintr_{rd,wr}. |
5735 | * Must be called with sc_lock && sc_intr_lock held. | | 5677 | * Must be called with sc_lock && sc_intr_lock held. |
5736 | */ | | 5678 | */ |