| @@ -1,1144 +1,1144 @@ | | | @@ -1,1144 +1,1144 @@ |
1 | /* $NetBSD: audio.c,v 1.29 2019/08/23 09:41:26 maxv Exp $ */ | | 1 | /* $NetBSD: audio.c,v 1.30 2019/08/29 13:01:07 isaki 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.29 2019/08/23 09:41:26 maxv Exp $"); | | 145 | __KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.30 2019/08/29 13:01:07 isaki 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, |
| @@ -4734,2102 +4734,2126 @@ audio_mixer_init(struct audio_softc *sc, | | | @@ -4734,2102 +4734,2126 @@ audio_mixer_init(struct audio_softc *sc, |
4734 | __func__, len); | | 4734 | __func__, len); |
4735 | error = ENOMEM; | | 4735 | error = ENOMEM; |
4736 | goto abort; | | 4736 | goto abort; |
4737 | } | | 4737 | } |
4738 | } else { | | 4738 | } else { |
4739 | /* No mixing buffer for recording */ | | 4739 | /* No mixing buffer for recording */ |
4740 | } | | 4740 | } |
4741 | | | 4741 | |
4742 | if (reg->codec) { | | 4742 | if (reg->codec) { |
4743 | mixer->codec = reg->codec; | | 4743 | mixer->codec = reg->codec; |
4744 | mixer->codecarg.context = reg->context; | | 4744 | mixer->codecarg.context = reg->context; |
4745 | if (mode == AUMODE_PLAY) { | | 4745 | if (mode == AUMODE_PLAY) { |
4746 | mixer->codecarg.srcfmt = &mixer->track_fmt; | | 4746 | mixer->codecarg.srcfmt = &mixer->track_fmt; |
4747 | mixer->codecarg.dstfmt = &mixer->hwbuf.fmt; | | 4747 | mixer->codecarg.dstfmt = &mixer->hwbuf.fmt; |
4748 | } else { | | 4748 | } else { |
4749 | mixer->codecarg.srcfmt = &mixer->hwbuf.fmt; | | 4749 | mixer->codecarg.srcfmt = &mixer->hwbuf.fmt; |
4750 | mixer->codecarg.dstfmt = &mixer->track_fmt; | | 4750 | mixer->codecarg.dstfmt = &mixer->track_fmt; |
4751 | } | | 4751 | } |
4752 | mixer->codecbuf.fmt = mixer->track_fmt; | | 4752 | mixer->codecbuf.fmt = mixer->track_fmt; |
4753 | mixer->codecbuf.capacity = mixer->frames_per_block; | | 4753 | mixer->codecbuf.capacity = mixer->frames_per_block; |
4754 | len = auring_bytelen(&mixer->codecbuf); | | 4754 | len = auring_bytelen(&mixer->codecbuf); |
4755 | mixer->codecbuf.mem = audio_realloc(mixer->codecbuf.mem, len); | | 4755 | mixer->codecbuf.mem = audio_realloc(mixer->codecbuf.mem, len); |
4756 | if (mixer->codecbuf.mem == NULL) { | | 4756 | if (mixer->codecbuf.mem == NULL) { |
4757 | device_printf(sc->sc_dev, | | 4757 | device_printf(sc->sc_dev, |
4758 | "%s: malloc codecbuf(%d) failed\n", | | 4758 | "%s: malloc codecbuf(%d) failed\n", |
4759 | __func__, len); | | 4759 | __func__, len); |
4760 | error = ENOMEM; | | 4760 | error = ENOMEM; |
4761 | goto abort; | | 4761 | goto abort; |
4762 | } | | 4762 | } |
4763 | } | | 4763 | } |
4764 | | | 4764 | |
4765 | /* Succeeded so display it. */ | | 4765 | /* Succeeded so display it. */ |
4766 | codecbuf[0] = '\0'; | | 4766 | codecbuf[0] = '\0'; |
4767 | if (mixer->codec || mixer->swap_endian) { | | 4767 | if (mixer->codec || mixer->swap_endian) { |
4768 | snprintf(codecbuf, sizeof(codecbuf), " %s %s:%d", | | 4768 | snprintf(codecbuf, sizeof(codecbuf), " %s %s:%d", |
4769 | (mode == AUMODE_PLAY) ? "->" : "<-", | | 4769 | (mode == AUMODE_PLAY) ? "->" : "<-", |
4770 | audio_encoding_name(mixer->hwbuf.fmt.encoding), | | 4770 | audio_encoding_name(mixer->hwbuf.fmt.encoding), |
4771 | mixer->hwbuf.fmt.precision); | | 4771 | mixer->hwbuf.fmt.precision); |
4772 | } | | 4772 | } |
4773 | blkms = mixer->blktime_n * 1000 / mixer->blktime_d; | | 4773 | 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", | | 4774 | aprint_normal_dev(sc->sc_dev, "%s:%d%s %dch %dHz, blk %dms for %s\n", |
4775 | audio_encoding_name(mixer->track_fmt.encoding), | | 4775 | audio_encoding_name(mixer->track_fmt.encoding), |
4776 | mixer->track_fmt.precision, | | 4776 | mixer->track_fmt.precision, |
4777 | codecbuf, | | 4777 | codecbuf, |
4778 | mixer->track_fmt.channels, | | 4778 | mixer->track_fmt.channels, |
4779 | mixer->track_fmt.sample_rate, | | 4779 | mixer->track_fmt.sample_rate, |
4780 | blkms, | | 4780 | blkms, |
4781 | (mode == AUMODE_PLAY) ? "playback" : "recording"); | | 4781 | (mode == AUMODE_PLAY) ? "playback" : "recording"); |
4782 | | | 4782 | |
4783 | return 0; | | 4783 | return 0; |
4784 | | | 4784 | |
4785 | abort: | | 4785 | abort: |
4786 | audio_mixer_destroy(sc, mixer); | | 4786 | audio_mixer_destroy(sc, mixer); |
4787 | return error; | | 4787 | return error; |
4788 | } | | 4788 | } |
4789 | | | 4789 | |
4790 | /* | | 4790 | /* |
4791 | * Releases all resources of 'mixer'. | | 4791 | * Releases all resources of 'mixer'. |
4792 | * Note that it does not release the memory area of 'mixer' itself. | | 4792 | * Note that it does not release the memory area of 'mixer' itself. |
4793 | * Must be called with sc_lock held. | | 4793 | * Must be called with sc_lock held. |
4794 | */ | | 4794 | */ |
4795 | static void | | 4795 | static void |
4796 | audio_mixer_destroy(struct audio_softc *sc, audio_trackmixer_t *mixer) | | 4796 | audio_mixer_destroy(struct audio_softc *sc, audio_trackmixer_t *mixer) |
4797 | { | | 4797 | { |
4798 | int bufsize; | | 4798 | int bufsize; |
4799 | | | 4799 | |
4800 | KASSERT(mutex_owned(sc->sc_lock)); | | 4800 | KASSERT(mutex_owned(sc->sc_lock)); |
4801 | | | 4801 | |
4802 | bufsize = frametobyte(&mixer->hwbuf.fmt, mixer->hwbuf.capacity); | | 4802 | bufsize = frametobyte(&mixer->hwbuf.fmt, mixer->hwbuf.capacity); |
4803 | | | 4803 | |
4804 | if (mixer->hwbuf.mem != NULL) { | | 4804 | if (mixer->hwbuf.mem != NULL) { |
4805 | if (sc->hw_if->freem) { | | 4805 | if (sc->hw_if->freem) { |
4806 | sc->hw_if->freem(sc->hw_hdl, mixer->hwbuf.mem, bufsize); | | 4806 | sc->hw_if->freem(sc->hw_hdl, mixer->hwbuf.mem, bufsize); |
4807 | } else { | | 4807 | } else { |
4808 | kmem_free(mixer->hwbuf.mem, bufsize); | | 4808 | kmem_free(mixer->hwbuf.mem, bufsize); |
4809 | } | | 4809 | } |
4810 | mixer->hwbuf.mem = NULL; | | 4810 | mixer->hwbuf.mem = NULL; |
4811 | } | | 4811 | } |
4812 | | | 4812 | |
4813 | audio_free(mixer->codecbuf.mem); | | 4813 | audio_free(mixer->codecbuf.mem); |
4814 | audio_free(mixer->mixsample); | | 4814 | audio_free(mixer->mixsample); |
4815 | | | 4815 | |
4816 | cv_destroy(&mixer->outcv); | | 4816 | cv_destroy(&mixer->outcv); |
4817 | | | 4817 | |
4818 | if (mixer->sih) { | | 4818 | if (mixer->sih) { |
4819 | softint_disestablish(mixer->sih); | | 4819 | softint_disestablish(mixer->sih); |
4820 | mixer->sih = NULL; | | 4820 | mixer->sih = NULL; |
4821 | } | | 4821 | } |
4822 | } | | 4822 | } |
4823 | | | 4823 | |
4824 | /* | | 4824 | /* |
4825 | * Starts playback mixer. | | 4825 | * Starts playback mixer. |
4826 | * Must be called only if sc_pbusy is false. | | 4826 | * Must be called only if sc_pbusy is false. |
4827 | * Must be called with sc_lock held. | | 4827 | * Must be called with sc_lock held. |
4828 | * Must not be called from the interrupt context. | | 4828 | * Must not be called from the interrupt context. |
4829 | */ | | 4829 | */ |
4830 | static void | | 4830 | static void |
4831 | audio_pmixer_start(struct audio_softc *sc, bool force) | | 4831 | audio_pmixer_start(struct audio_softc *sc, bool force) |
4832 | { | | 4832 | { |
4833 | audio_trackmixer_t *mixer; | | 4833 | audio_trackmixer_t *mixer; |
4834 | int minimum; | | 4834 | int minimum; |
4835 | | | 4835 | |
4836 | KASSERT(mutex_owned(sc->sc_lock)); | | 4836 | KASSERT(mutex_owned(sc->sc_lock)); |
4837 | KASSERT(sc->sc_pbusy == false); | | 4837 | KASSERT(sc->sc_pbusy == false); |
4838 | | | 4838 | |
4839 | mutex_enter(sc->sc_intr_lock); | | 4839 | mutex_enter(sc->sc_intr_lock); |
4840 | | | 4840 | |
4841 | mixer = sc->sc_pmixer; | | 4841 | mixer = sc->sc_pmixer; |
4842 | TRACE(2, "%smixseq=%d hwseq=%d hwbuf=%d/%d/%d%s", | | 4842 | TRACE(2, "%smixseq=%d hwseq=%d hwbuf=%d/%d/%d%s", |
4843 | (audiodebug >= 3) ? "begin " : "", | | 4843 | (audiodebug >= 3) ? "begin " : "", |
4844 | (int)mixer->mixseq, (int)mixer->hwseq, | | 4844 | (int)mixer->mixseq, (int)mixer->hwseq, |
4845 | mixer->hwbuf.head, mixer->hwbuf.used, mixer->hwbuf.capacity, | | 4845 | mixer->hwbuf.head, mixer->hwbuf.used, mixer->hwbuf.capacity, |
4846 | force ? " force" : ""); | | 4846 | force ? " force" : ""); |
4847 | | | 4847 | |
4848 | /* Need two blocks to start normally. */ | | 4848 | /* Need two blocks to start normally. */ |
4849 | minimum = (force) ? 1 : 2; | | 4849 | minimum = (force) ? 1 : 2; |
4850 | while (mixer->hwbuf.used < mixer->frames_per_block * minimum) { | | 4850 | while (mixer->hwbuf.used < mixer->frames_per_block * minimum) { |
4851 | audio_pmixer_process(sc); | | 4851 | audio_pmixer_process(sc); |
4852 | } | | 4852 | } |
4853 | | | 4853 | |
4854 | /* Start output */ | | 4854 | /* Start output */ |
4855 | audio_pmixer_output(sc); | | 4855 | audio_pmixer_output(sc); |
4856 | sc->sc_pbusy = true; | | 4856 | sc->sc_pbusy = true; |
4857 | | | 4857 | |
4858 | TRACE(3, "end mixseq=%d hwseq=%d hwbuf=%d/%d/%d", | | 4858 | TRACE(3, "end mixseq=%d hwseq=%d hwbuf=%d/%d/%d", |
4859 | (int)mixer->mixseq, (int)mixer->hwseq, | | 4859 | (int)mixer->mixseq, (int)mixer->hwseq, |
4860 | mixer->hwbuf.head, mixer->hwbuf.used, mixer->hwbuf.capacity); | | 4860 | mixer->hwbuf.head, mixer->hwbuf.used, mixer->hwbuf.capacity); |
4861 | | | 4861 | |
4862 | mutex_exit(sc->sc_intr_lock); | | 4862 | mutex_exit(sc->sc_intr_lock); |
4863 | } | | 4863 | } |
4864 | | | 4864 | |
4865 | /* | | 4865 | /* |
4866 | * When playing back with MD filter: | | 4866 | * When playing back with MD filter: |
4867 | * | | 4867 | * |
4868 | * track track ... | | 4868 | * track track ... |
4869 | * v v | | 4869 | * v v |
4870 | * + mix (with aint2_t) | | 4870 | * + mix (with aint2_t) |
4871 | * | master volume (with aint2_t) | | 4871 | * | master volume (with aint2_t) |
4872 | * v | | 4872 | * v |
4873 | * mixsample [::::] wide-int 1 block (ring) buffer | | 4873 | * mixsample [::::] wide-int 1 block (ring) buffer |
4874 | * | | | 4874 | * | |
4875 | * | convert aint2_t -> aint_t | | 4875 | * | convert aint2_t -> aint_t |
4876 | * v | | 4876 | * v |
4877 | * codecbuf [....] 1 block (ring) buffer | | 4877 | * codecbuf [....] 1 block (ring) buffer |
4878 | * | | | 4878 | * | |
4879 | * | convert to hw format | | 4879 | * | convert to hw format |
4880 | * v | | 4880 | * v |
4881 | * hwbuf [............] NBLKHW blocks ring buffer | | 4881 | * hwbuf [............] NBLKHW blocks ring buffer |
4882 | * | | 4882 | * |
4883 | * When playing back without MD filter: | | 4883 | * When playing back without MD filter: |
4884 | * | | 4884 | * |
4885 | * mixsample [::::] wide-int 1 block (ring) buffer | | 4885 | * mixsample [::::] wide-int 1 block (ring) buffer |
4886 | * | | | 4886 | * | |
4887 | * | convert aint2_t -> aint_t | | 4887 | * | convert aint2_t -> aint_t |
4888 | * | (with byte swap if necessary) | | 4888 | * | (with byte swap if necessary) |
4889 | * v | | 4889 | * v |
4890 | * hwbuf [............] NBLKHW blocks ring buffer | | 4890 | * hwbuf [............] NBLKHW blocks ring buffer |
4891 | * | | 4891 | * |
4892 | * mixsample: slinear_NE, wide internal precision, HW ch, HW freq. | | 4892 | * mixsample: slinear_NE, wide internal precision, HW ch, HW freq. |
4893 | * codecbuf: slinear_NE, internal precision, HW ch, HW freq. | | 4893 | * codecbuf: slinear_NE, internal precision, HW ch, HW freq. |
4894 | * hwbuf: HW encoding, HW precision, HW ch, HW freq. | | 4894 | * hwbuf: HW encoding, HW precision, HW ch, HW freq. |
4895 | */ | | 4895 | */ |
4896 | | | 4896 | |
4897 | /* | | 4897 | /* |
4898 | * Performs track mixing and converts it to hwbuf. | | 4898 | * Performs track mixing and converts it to hwbuf. |
4899 | * Note that this function doesn't transfer hwbuf to hardware. | | 4899 | * Note that this function doesn't transfer hwbuf to hardware. |
4900 | * Must be called with sc_intr_lock held. | | 4900 | * Must be called with sc_intr_lock held. |
4901 | */ | | 4901 | */ |
4902 | static void | | 4902 | static void |
4903 | audio_pmixer_process(struct audio_softc *sc) | | 4903 | audio_pmixer_process(struct audio_softc *sc) |
4904 | { | | 4904 | { |
4905 | audio_trackmixer_t *mixer; | | 4905 | audio_trackmixer_t *mixer; |
4906 | audio_file_t *f; | | 4906 | audio_file_t *f; |
4907 | int frame_count; | | 4907 | int frame_count; |
4908 | int sample_count; | | 4908 | int sample_count; |
4909 | int mixed; | | 4909 | int mixed; |
4910 | int i; | | 4910 | int i; |
4911 | aint2_t *m; | | 4911 | aint2_t *m; |
4912 | aint_t *h; | | 4912 | aint_t *h; |
4913 | | | 4913 | |
4914 | mixer = sc->sc_pmixer; | | 4914 | mixer = sc->sc_pmixer; |
4915 | | | 4915 | |
4916 | frame_count = mixer->frames_per_block; | | 4916 | frame_count = mixer->frames_per_block; |
4917 | KASSERT(auring_get_contig_free(&mixer->hwbuf) >= frame_count); | | 4917 | KASSERT(auring_get_contig_free(&mixer->hwbuf) >= frame_count); |
4918 | sample_count = frame_count * mixer->mixfmt.channels; | | 4918 | sample_count = frame_count * mixer->mixfmt.channels; |
4919 | | | 4919 | |
4920 | mixer->mixseq++; | | 4920 | mixer->mixseq++; |
4921 | | | 4921 | |
4922 | /* Mix all tracks */ | | 4922 | /* Mix all tracks */ |
4923 | mixed = 0; | | 4923 | mixed = 0; |
4924 | SLIST_FOREACH(f, &sc->sc_files, entry) { | | 4924 | SLIST_FOREACH(f, &sc->sc_files, entry) { |
4925 | audio_track_t *track = f->ptrack; | | 4925 | audio_track_t *track = f->ptrack; |
4926 | | | 4926 | |
4927 | if (track == NULL) | | 4927 | if (track == NULL) |
4928 | continue; | | 4928 | continue; |
4929 | | | 4929 | |
4930 | if (track->is_pause) { | | 4930 | if (track->is_pause) { |
4931 | TRACET(4, track, "skip; paused"); | | 4931 | TRACET(4, track, "skip; paused"); |
4932 | continue; | | 4932 | continue; |
4933 | } | | 4933 | } |
4934 | | | 4934 | |
4935 | /* Skip if the track is used by process context. */ | | 4935 | /* Skip if the track is used by process context. */ |
4936 | if (audio_track_lock_tryenter(track) == false) { | | 4936 | if (audio_track_lock_tryenter(track) == false) { |
4937 | TRACET(4, track, "skip; in use"); | | 4937 | TRACET(4, track, "skip; in use"); |
4938 | continue; | | 4938 | continue; |
4939 | } | | 4939 | } |
4940 | | | 4940 | |
4941 | /* Emulate mmap'ped track */ | | 4941 | /* Emulate mmap'ped track */ |
4942 | if (track->mmapped) { | | 4942 | if (track->mmapped) { |
4943 | auring_push(&track->usrbuf, track->usrbuf_blksize); | | 4943 | auring_push(&track->usrbuf, track->usrbuf_blksize); |
4944 | TRACET(4, track, "mmap; usr=%d/%d/C%d", | | 4944 | TRACET(4, track, "mmap; usr=%d/%d/C%d", |
4945 | track->usrbuf.head, | | 4945 | track->usrbuf.head, |
4946 | track->usrbuf.used, | | 4946 | track->usrbuf.used, |
4947 | track->usrbuf.capacity); | | 4947 | track->usrbuf.capacity); |
4948 | } | | 4948 | } |
4949 | | | 4949 | |
4950 | if (track->outbuf.used < mixer->frames_per_block && | | 4950 | if (track->outbuf.used < mixer->frames_per_block && |
4951 | track->usrbuf.used > 0) { | | 4951 | track->usrbuf.used > 0) { |
4952 | TRACET(4, track, "process"); | | 4952 | TRACET(4, track, "process"); |
4953 | audio_track_play(track); | | 4953 | audio_track_play(track); |
4954 | } | | 4954 | } |
4955 | | | 4955 | |
4956 | if (track->outbuf.used > 0) { | | 4956 | if (track->outbuf.used > 0) { |
4957 | mixed = audio_pmixer_mix_track(mixer, track, mixed); | | 4957 | mixed = audio_pmixer_mix_track(mixer, track, mixed); |
4958 | } else { | | 4958 | } else { |
4959 | TRACET(4, track, "skip; empty"); | | 4959 | TRACET(4, track, "skip; empty"); |
4960 | } | | 4960 | } |
4961 | | | 4961 | |
4962 | audio_track_lock_exit(track); | | 4962 | audio_track_lock_exit(track); |
4963 | } | | 4963 | } |
4964 | | | 4964 | |
4965 | if (mixed == 0) { | | 4965 | if (mixed == 0) { |
4966 | /* Silence */ | | 4966 | /* Silence */ |
4967 | memset(mixer->mixsample, 0, | | 4967 | memset(mixer->mixsample, 0, |
4968 | frametobyte(&mixer->mixfmt, frame_count)); | | 4968 | frametobyte(&mixer->mixfmt, frame_count)); |
4969 | } else { | | 4969 | } else { |
4970 | if (mixed > 1) { | | 4970 | if (mixed > 1) { |
4971 | /* If there are multiple tracks, do auto gain control */ | | 4971 | /* If there are multiple tracks, do auto gain control */ |
4972 | audio_pmixer_agc(mixer, sample_count); | | 4972 | audio_pmixer_agc(mixer, sample_count); |
4973 | } | | 4973 | } |
4974 | | | 4974 | |
4975 | /* Apply master volume */ | | 4975 | /* Apply master volume */ |
4976 | if (mixer->volume < 256) { | | 4976 | if (mixer->volume < 256) { |
4977 | m = mixer->mixsample; | | 4977 | m = mixer->mixsample; |
4978 | for (i = 0; i < sample_count; i++) { | | 4978 | for (i = 0; i < sample_count; i++) { |
4979 | *m = AUDIO_SCALEDOWN(*m * mixer->volume, 8); | | 4979 | *m = AUDIO_SCALEDOWN(*m * mixer->volume, 8); |
4980 | m++; | | 4980 | m++; |
4981 | } | | 4981 | } |
4982 | | | 4982 | |
4983 | /* | | 4983 | /* |
4984 | * Recover the volume gradually at the pace of | | 4984 | * Recover the volume gradually at the pace of |
4985 | * several times per second. If it's too fast, you | | 4985 | * several times per second. If it's too fast, you |
4986 | * can recognize that the volume changes up and down | | 4986 | * can recognize that the volume changes up and down |
4987 | * quickly and it's not so comfortable. | | 4987 | * quickly and it's not so comfortable. |
4988 | */ | | 4988 | */ |
4989 | mixer->voltimer += mixer->blktime_n; | | 4989 | mixer->voltimer += mixer->blktime_n; |
4990 | if (mixer->voltimer * 4 >= mixer->blktime_d) { | | 4990 | if (mixer->voltimer * 4 >= mixer->blktime_d) { |
4991 | mixer->volume++; | | 4991 | mixer->volume++; |
4992 | mixer->voltimer = 0; | | 4992 | mixer->voltimer = 0; |
4993 | #if defined(AUDIO_DEBUG_AGC) | | 4993 | #if defined(AUDIO_DEBUG_AGC) |
4994 | TRACE(1, "volume recover: %d", mixer->volume); | | 4994 | TRACE(1, "volume recover: %d", mixer->volume); |
4995 | #endif | | 4995 | #endif |
4996 | } | | 4996 | } |
4997 | } | | 4997 | } |
4998 | } | | 4998 | } |
4999 | | | 4999 | |
5000 | /* | | 5000 | /* |
5001 | * The rest is the hardware part. | | 5001 | * The rest is the hardware part. |
5002 | */ | | 5002 | */ |
5003 | | | 5003 | |
5004 | if (mixer->codec) { | | 5004 | if (mixer->codec) { |
5005 | h = auring_tailptr_aint(&mixer->codecbuf); | | 5005 | h = auring_tailptr_aint(&mixer->codecbuf); |
5006 | } else { | | 5006 | } else { |
5007 | h = auring_tailptr_aint(&mixer->hwbuf); | | 5007 | h = auring_tailptr_aint(&mixer->hwbuf); |
5008 | } | | 5008 | } |
5009 | | | 5009 | |
5010 | m = mixer->mixsample; | | 5010 | m = mixer->mixsample; |
5011 | if (mixer->swap_endian) { | | 5011 | if (mixer->swap_endian) { |
5012 | for (i = 0; i < sample_count; i++) { | | 5012 | for (i = 0; i < sample_count; i++) { |
5013 | *h++ = bswap16(*m++); | | 5013 | *h++ = bswap16(*m++); |
5014 | } | | 5014 | } |
5015 | } else { | | 5015 | } else { |
5016 | for (i = 0; i < sample_count; i++) { | | 5016 | for (i = 0; i < sample_count; i++) { |
5017 | *h++ = *m++; | | 5017 | *h++ = *m++; |
5018 | } | | 5018 | } |
5019 | } | | 5019 | } |
5020 | | | 5020 | |
5021 | /* Hardware driver's codec */ | | 5021 | /* Hardware driver's codec */ |
5022 | if (mixer->codec) { | | 5022 | if (mixer->codec) { |
5023 | auring_push(&mixer->codecbuf, frame_count); | | 5023 | auring_push(&mixer->codecbuf, frame_count); |
5024 | mixer->codecarg.src = auring_headptr(&mixer->codecbuf); | | 5024 | mixer->codecarg.src = auring_headptr(&mixer->codecbuf); |
5025 | mixer->codecarg.dst = auring_tailptr(&mixer->hwbuf); | | 5025 | mixer->codecarg.dst = auring_tailptr(&mixer->hwbuf); |
5026 | mixer->codecarg.count = frame_count; | | 5026 | mixer->codecarg.count = frame_count; |
5027 | mixer->codec(&mixer->codecarg); | | 5027 | mixer->codec(&mixer->codecarg); |
5028 | auring_take(&mixer->codecbuf, mixer->codecarg.count); | | 5028 | auring_take(&mixer->codecbuf, mixer->codecarg.count); |
5029 | } | | 5029 | } |
5030 | | | 5030 | |
5031 | auring_push(&mixer->hwbuf, frame_count); | | 5031 | auring_push(&mixer->hwbuf, frame_count); |
5032 | | | 5032 | |
5033 | TRACE(4, "done mixseq=%d hwbuf=%d/%d/%d%s", | | 5033 | TRACE(4, "done mixseq=%d hwbuf=%d/%d/%d%s", |
5034 | (int)mixer->mixseq, | | 5034 | (int)mixer->mixseq, |
5035 | mixer->hwbuf.head, mixer->hwbuf.used, mixer->hwbuf.capacity, | | 5035 | mixer->hwbuf.head, mixer->hwbuf.used, mixer->hwbuf.capacity, |
5036 | (mixed == 0) ? " silent" : ""); | | 5036 | (mixed == 0) ? " silent" : ""); |
5037 | } | | 5037 | } |
5038 | | | 5038 | |
5039 | /* | | 5039 | /* |
5040 | * Do auto gain control. | | 5040 | * Do auto gain control. |
5041 | * Must be called sc_intr_lock held. | | 5041 | * Must be called sc_intr_lock held. |
5042 | */ | | 5042 | */ |
5043 | static void | | 5043 | static void |
5044 | audio_pmixer_agc(audio_trackmixer_t *mixer, int sample_count) | | 5044 | audio_pmixer_agc(audio_trackmixer_t *mixer, int sample_count) |
5045 | { | | 5045 | { |
5046 | struct audio_softc *sc __unused; | | 5046 | struct audio_softc *sc __unused; |
5047 | aint2_t val; | | 5047 | aint2_t val; |
5048 | aint2_t maxval; | | 5048 | aint2_t maxval; |
5049 | aint2_t minval; | | 5049 | aint2_t minval; |
5050 | aint2_t over_plus; | | 5050 | aint2_t over_plus; |
5051 | aint2_t over_minus; | | 5051 | aint2_t over_minus; |
5052 | aint2_t *m; | | 5052 | aint2_t *m; |
5053 | int newvol; | | 5053 | int newvol; |
5054 | int i; | | 5054 | int i; |
5055 | | | 5055 | |
5056 | sc = mixer->sc; | | 5056 | sc = mixer->sc; |
5057 | | | 5057 | |
5058 | /* Overflow detection */ | | 5058 | /* Overflow detection */ |
5059 | maxval = AINT_T_MAX; | | 5059 | maxval = AINT_T_MAX; |
5060 | minval = AINT_T_MIN; | | 5060 | minval = AINT_T_MIN; |
5061 | m = mixer->mixsample; | | 5061 | m = mixer->mixsample; |
5062 | for (i = 0; i < sample_count; i++) { | | 5062 | for (i = 0; i < sample_count; i++) { |
5063 | val = *m++; | | 5063 | val = *m++; |
5064 | if (val > maxval) | | 5064 | if (val > maxval) |
5065 | maxval = val; | | 5065 | maxval = val; |
5066 | else if (val < minval) | | 5066 | else if (val < minval) |
5067 | minval = val; | | 5067 | minval = val; |
5068 | } | | 5068 | } |
5069 | | | 5069 | |
5070 | /* Absolute value of overflowed amount */ | | 5070 | /* Absolute value of overflowed amount */ |
5071 | over_plus = maxval - AINT_T_MAX; | | 5071 | over_plus = maxval - AINT_T_MAX; |
5072 | over_minus = AINT_T_MIN - minval; | | 5072 | over_minus = AINT_T_MIN - minval; |
5073 | | | 5073 | |
5074 | if (over_plus > 0 || over_minus > 0) { | | 5074 | if (over_plus > 0 || over_minus > 0) { |
5075 | if (over_plus > over_minus) { | | 5075 | if (over_plus > over_minus) { |
5076 | newvol = (int)((aint2_t)AINT_T_MAX * 256 / maxval); | | 5076 | newvol = (int)((aint2_t)AINT_T_MAX * 256 / maxval); |
5077 | } else { | | 5077 | } else { |
5078 | newvol = (int)((aint2_t)AINT_T_MIN * 256 / minval); | | 5078 | newvol = (int)((aint2_t)AINT_T_MIN * 256 / minval); |
5079 | } | | 5079 | } |
5080 | | | 5080 | |
5081 | /* | | 5081 | /* |
5082 | * Change the volume only if new one is smaller. | | 5082 | * Change the volume only if new one is smaller. |
5083 | * Reset the timer even if the volume isn't changed. | | 5083 | * Reset the timer even if the volume isn't changed. |
5084 | */ | | 5084 | */ |
5085 | if (newvol <= mixer->volume) { | | 5085 | if (newvol <= mixer->volume) { |
5086 | mixer->volume = newvol; | | 5086 | mixer->volume = newvol; |
5087 | mixer->voltimer = 0; | | 5087 | mixer->voltimer = 0; |
5088 | #if defined(AUDIO_DEBUG_AGC) | | 5088 | #if defined(AUDIO_DEBUG_AGC) |
5089 | TRACE(1, "auto volume adjust: %d", mixer->volume); | | 5089 | TRACE(1, "auto volume adjust: %d", mixer->volume); |
5090 | #endif | | 5090 | #endif |
5091 | } | | 5091 | } |
5092 | } | | 5092 | } |
5093 | } | | 5093 | } |
5094 | | | 5094 | |
5095 | /* | | 5095 | /* |
5096 | * Mix one track. | | 5096 | * Mix one track. |
5097 | * 'mixed' specifies the number of tracks mixed so far. | | 5097 | * 'mixed' specifies the number of tracks mixed so far. |
5098 | * It returns the number of tracks mixed. In other words, it returns | | 5098 | * It returns the number of tracks mixed. In other words, it returns |
5099 | * mixed + 1 if this track is mixed. | | 5099 | * mixed + 1 if this track is mixed. |
5100 | */ | | 5100 | */ |
5101 | static int | | 5101 | static int |
5102 | audio_pmixer_mix_track(audio_trackmixer_t *mixer, audio_track_t *track, | | 5102 | audio_pmixer_mix_track(audio_trackmixer_t *mixer, audio_track_t *track, |
5103 | int mixed) | | 5103 | int mixed) |
5104 | { | | 5104 | { |
5105 | int count; | | 5105 | int count; |
5106 | int sample_count; | | 5106 | int sample_count; |
5107 | int remain; | | 5107 | int remain; |
5108 | int i; | | 5108 | int i; |
5109 | const aint_t *s; | | 5109 | const aint_t *s; |
5110 | aint2_t *d; | | 5110 | aint2_t *d; |
5111 | | | 5111 | |
5112 | /* XXX TODO: Is this necessary for now? */ | | 5112 | /* XXX TODO: Is this necessary for now? */ |
5113 | if (mixer->mixseq < track->seq) | | 5113 | if (mixer->mixseq < track->seq) |
5114 | return mixed; | | 5114 | return mixed; |
5115 | | | 5115 | |
5116 | count = auring_get_contig_used(&track->outbuf); | | 5116 | count = auring_get_contig_used(&track->outbuf); |
5117 | count = uimin(count, mixer->frames_per_block); | | 5117 | count = uimin(count, mixer->frames_per_block); |
5118 | | | 5118 | |
5119 | s = auring_headptr_aint(&track->outbuf); | | 5119 | s = auring_headptr_aint(&track->outbuf); |
5120 | d = mixer->mixsample; | | 5120 | d = mixer->mixsample; |
5121 | | | 5121 | |
5122 | /* | | 5122 | /* |
5123 | * Apply track volume with double-sized integer and perform | | 5123 | * Apply track volume with double-sized integer and perform |
5124 | * additive synthesis. | | 5124 | * additive synthesis. |
5125 | * | | 5125 | * |
5126 | * XXX If you limit the track volume to 1.0 or less (<= 256), | | 5126 | * 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 | | 5127 | * it would be better to do this in the track conversion stage |
5128 | * rather than here. However, if you accept the volume to | | 5128 | * rather than here. However, if you accept the volume to |
5129 | * be greater than 1.0 (> 256), it's better to do it here. | | 5129 | * be greater than 1.0 (> 256), it's better to do it here. |
5130 | * Because the operation here is done by double-sized integer. | | 5130 | * Because the operation here is done by double-sized integer. |
5131 | */ | | 5131 | */ |
5132 | sample_count = count * mixer->mixfmt.channels; | | 5132 | sample_count = count * mixer->mixfmt.channels; |
5133 | if (mixed == 0) { | | 5133 | if (mixed == 0) { |
5134 | /* If this is the first track, assignment can be used. */ | | 5134 | /* If this is the first track, assignment can be used. */ |
5135 | #if defined(AUDIO_SUPPORT_TRACK_VOLUME) | | 5135 | #if defined(AUDIO_SUPPORT_TRACK_VOLUME) |
5136 | if (track->volume != 256) { | | 5136 | if (track->volume != 256) { |
5137 | for (i = 0; i < sample_count; i++) { | | 5137 | for (i = 0; i < sample_count; i++) { |
5138 | aint2_t v; | | 5138 | aint2_t v; |
5139 | v = *s++; | | 5139 | v = *s++; |
5140 | *d++ = AUDIO_SCALEDOWN(v * track->volume, 8) | | 5140 | *d++ = AUDIO_SCALEDOWN(v * track->volume, 8) |
5141 | } | | 5141 | } |
5142 | } else | | 5142 | } else |
5143 | #endif | | 5143 | #endif |
5144 | { | | 5144 | { |
5145 | for (i = 0; i < sample_count; i++) { | | 5145 | for (i = 0; i < sample_count; i++) { |
5146 | *d++ = ((aint2_t)*s++); | | 5146 | *d++ = ((aint2_t)*s++); |
5147 | } | | 5147 | } |
5148 | } | | 5148 | } |
5149 | /* Fill silence if the first track is not filled. */ | | 5149 | /* Fill silence if the first track is not filled. */ |
5150 | for (; i < mixer->frames_per_block * mixer->mixfmt.channels; i++) | | 5150 | for (; i < mixer->frames_per_block * mixer->mixfmt.channels; i++) |
5151 | *d++ = 0; | | 5151 | *d++ = 0; |
5152 | } else { | | 5152 | } else { |
5153 | /* If this is the second or later, add it. */ | | 5153 | /* If this is the second or later, add it. */ |
5154 | #if defined(AUDIO_SUPPORT_TRACK_VOLUME) | | 5154 | #if defined(AUDIO_SUPPORT_TRACK_VOLUME) |
5155 | if (track->volume != 256) { | | 5155 | if (track->volume != 256) { |
5156 | for (i = 0; i < sample_count; i++) { | | 5156 | for (i = 0; i < sample_count; i++) { |
5157 | aint2_t v; | | 5157 | aint2_t v; |
5158 | v = *s++; | | 5158 | v = *s++; |
5159 | *d++ += AUDIO_SCALEDOWN(v * track->volume, 8); | | 5159 | *d++ += AUDIO_SCALEDOWN(v * track->volume, 8); |
5160 | } | | 5160 | } |
5161 | } else | | 5161 | } else |
5162 | #endif | | 5162 | #endif |
5163 | { | | 5163 | { |
5164 | for (i = 0; i < sample_count; i++) { | | 5164 | for (i = 0; i < sample_count; i++) { |
5165 | *d++ += ((aint2_t)*s++); | | 5165 | *d++ += ((aint2_t)*s++); |
5166 | } | | 5166 | } |
5167 | } | | 5167 | } |
5168 | } | | 5168 | } |
5169 | | | 5169 | |
5170 | auring_take(&track->outbuf, count); | | 5170 | auring_take(&track->outbuf, count); |
5171 | /* | | 5171 | /* |
5172 | * The counters have to align block even if outbuf is less than | | 5172 | * The counters have to align block even if outbuf is less than |
5173 | * one block. XXX Is this still necessary? | | 5173 | * one block. XXX Is this still necessary? |
5174 | */ | | 5174 | */ |
5175 | remain = mixer->frames_per_block - count; | | 5175 | remain = mixer->frames_per_block - count; |
5176 | if (__predict_false(remain != 0)) { | | 5176 | if (__predict_false(remain != 0)) { |
5177 | auring_push(&track->outbuf, remain); | | 5177 | auring_push(&track->outbuf, remain); |
5178 | auring_take(&track->outbuf, remain); | | 5178 | auring_take(&track->outbuf, remain); |
5179 | } | | 5179 | } |
5180 | | | 5180 | |
5181 | /* | | 5181 | /* |
5182 | * Update track sequence. | | 5182 | * Update track sequence. |
5183 | * mixseq has previous value yet at this point. | | 5183 | * mixseq has previous value yet at this point. |
5184 | */ | | 5184 | */ |
5185 | track->seq = mixer->mixseq + 1; | | 5185 | track->seq = mixer->mixseq + 1; |
5186 | | | 5186 | |
5187 | return mixed + 1; | | 5187 | return mixed + 1; |
5188 | } | | 5188 | } |
5189 | | | 5189 | |
5190 | /* | | 5190 | /* |
5191 | * Output one block from hwbuf to HW. | | 5191 | * Output one block from hwbuf to HW. |
5192 | * Must be called with sc_intr_lock held. | | 5192 | * Must be called with sc_intr_lock held. |
5193 | */ | | 5193 | */ |
5194 | static void | | 5194 | static void |
5195 | audio_pmixer_output(struct audio_softc *sc) | | 5195 | audio_pmixer_output(struct audio_softc *sc) |
5196 | { | | 5196 | { |
5197 | audio_trackmixer_t *mixer; | | 5197 | audio_trackmixer_t *mixer; |
5198 | audio_params_t params; | | 5198 | audio_params_t params; |
5199 | void *start; | | 5199 | void *start; |
5200 | void *end; | | 5200 | void *end; |
5201 | int blksize; | | 5201 | int blksize; |
5202 | int error; | | 5202 | int error; |
5203 | | | 5203 | |
5204 | mixer = sc->sc_pmixer; | | 5204 | mixer = sc->sc_pmixer; |
5205 | TRACE(4, "pbusy=%d hwbuf=%d/%d/%d", | | 5205 | TRACE(4, "pbusy=%d hwbuf=%d/%d/%d", |
5206 | sc->sc_pbusy, | | 5206 | sc->sc_pbusy, |
5207 | mixer->hwbuf.head, mixer->hwbuf.used, mixer->hwbuf.capacity); | | 5207 | mixer->hwbuf.head, mixer->hwbuf.used, mixer->hwbuf.capacity); |
5208 | KASSERT(mixer->hwbuf.used >= mixer->frames_per_block); | | 5208 | KASSERT(mixer->hwbuf.used >= mixer->frames_per_block); |
5209 | | | 5209 | |
5210 | blksize = frametobyte(&mixer->hwbuf.fmt, mixer->frames_per_block); | | 5210 | blksize = frametobyte(&mixer->hwbuf.fmt, mixer->frames_per_block); |
5211 | | | 5211 | |
5212 | if (sc->hw_if->trigger_output) { | | 5212 | if (sc->hw_if->trigger_output) { |
5213 | /* trigger (at once) */ | | 5213 | /* trigger (at once) */ |
5214 | if (!sc->sc_pbusy) { | | 5214 | if (!sc->sc_pbusy) { |
5215 | start = mixer->hwbuf.mem; | | 5215 | start = mixer->hwbuf.mem; |
5216 | end = (uint8_t *)start + auring_bytelen(&mixer->hwbuf); | | 5216 | end = (uint8_t *)start + auring_bytelen(&mixer->hwbuf); |
5217 | params = format2_to_params(&mixer->hwbuf.fmt); | | 5217 | params = format2_to_params(&mixer->hwbuf.fmt); |
5218 | | | 5218 | |
5219 | error = sc->hw_if->trigger_output(sc->hw_hdl, | | 5219 | error = sc->hw_if->trigger_output(sc->hw_hdl, |
5220 | start, end, blksize, audio_pintr, sc, ¶ms); | | 5220 | start, end, blksize, audio_pintr, sc, ¶ms); |
5221 | if (error) { | | 5221 | if (error) { |
5222 | device_printf(sc->sc_dev, | | 5222 | device_printf(sc->sc_dev, |
5223 | "trigger_output failed with %d\n", error); | | 5223 | "trigger_output failed with %d\n", error); |
5224 | return; | | 5224 | return; |
5225 | } | | 5225 | } |
5226 | } | | 5226 | } |
5227 | } else { | | 5227 | } else { |
5228 | /* start (everytime) */ | | 5228 | /* start (everytime) */ |
5229 | start = auring_headptr(&mixer->hwbuf); | | 5229 | start = auring_headptr(&mixer->hwbuf); |
5230 | | | 5230 | |
5231 | error = sc->hw_if->start_output(sc->hw_hdl, | | 5231 | error = sc->hw_if->start_output(sc->hw_hdl, |
5232 | start, blksize, audio_pintr, sc); | | 5232 | start, blksize, audio_pintr, sc); |
5233 | if (error) { | | 5233 | if (error) { |
5234 | device_printf(sc->sc_dev, | | 5234 | device_printf(sc->sc_dev, |
5235 | "start_output failed with %d\n", error); | | 5235 | "start_output failed with %d\n", error); |
5236 | return; | | 5236 | return; |
5237 | } | | 5237 | } |
5238 | } | | 5238 | } |
5239 | } | | 5239 | } |
5240 | | | 5240 | |
5241 | /* | | 5241 | /* |
5242 | * This is an interrupt handler for playback. | | 5242 | * This is an interrupt handler for playback. |
5243 | * It is called with sc_intr_lock held. | | 5243 | * It is called with sc_intr_lock held. |
5244 | * | | 5244 | * |
5245 | * It is usually called from hardware interrupt. However, note that | | 5245 | * It is usually called from hardware interrupt. However, note that |
5246 | * for some drivers (e.g. uaudio) it is called from software interrupt. | | 5246 | * for some drivers (e.g. uaudio) it is called from software interrupt. |
5247 | */ | | 5247 | */ |
5248 | static void | | 5248 | static void |
5249 | audio_pintr(void *arg) | | 5249 | audio_pintr(void *arg) |
5250 | { | | 5250 | { |
5251 | struct audio_softc *sc; | | 5251 | struct audio_softc *sc; |
5252 | audio_trackmixer_t *mixer; | | 5252 | audio_trackmixer_t *mixer; |
5253 | | | 5253 | |
5254 | sc = arg; | | 5254 | sc = arg; |
5255 | KASSERT(mutex_owned(sc->sc_intr_lock)); | | 5255 | KASSERT(mutex_owned(sc->sc_intr_lock)); |
5256 | | | 5256 | |
5257 | if (sc->sc_dying) | | 5257 | if (sc->sc_dying) |
5258 | return; | | 5258 | return; |
5259 | #if defined(DIAGNOSTIC) | | 5259 | #if defined(DIAGNOSTIC) |
5260 | if (sc->sc_pbusy == false) { | | 5260 | if (sc->sc_pbusy == false) { |
5261 | device_printf(sc->sc_dev, "stray interrupt\n"); | | 5261 | device_printf(sc->sc_dev, "stray interrupt\n"); |
5262 | return; | | 5262 | return; |
5263 | } | | 5263 | } |
5264 | #endif | | 5264 | #endif |
5265 | | | 5265 | |
5266 | mixer = sc->sc_pmixer; | | 5266 | mixer = sc->sc_pmixer; |
5267 | mixer->hw_complete_counter += mixer->frames_per_block; | | 5267 | mixer->hw_complete_counter += mixer->frames_per_block; |
5268 | mixer->hwseq++; | | 5268 | mixer->hwseq++; |
5269 | | | 5269 | |
5270 | auring_take(&mixer->hwbuf, mixer->frames_per_block); | | 5270 | auring_take(&mixer->hwbuf, mixer->frames_per_block); |
5271 | | | 5271 | |
5272 | TRACE(4, | | 5272 | TRACE(4, |
5273 | "HW_INT ++hwseq=%" PRIu64 " cmplcnt=%" PRIu64 " hwbuf=%d/%d/%d", | | 5273 | "HW_INT ++hwseq=%" PRIu64 " cmplcnt=%" PRIu64 " hwbuf=%d/%d/%d", |
5274 | mixer->hwseq, mixer->hw_complete_counter, | | 5274 | mixer->hwseq, mixer->hw_complete_counter, |
5275 | mixer->hwbuf.head, mixer->hwbuf.used, mixer->hwbuf.capacity); | | 5275 | mixer->hwbuf.head, mixer->hwbuf.used, mixer->hwbuf.capacity); |
5276 | | | 5276 | |
5277 | #if !defined(_KERNEL) | | 5277 | #if !defined(_KERNEL) |
5278 | /* This is a debug code for userland test. */ | | 5278 | /* This is a debug code for userland test. */ |
5279 | return; | | 5279 | return; |
5280 | #endif | | 5280 | #endif |
5281 | | | 5281 | |
5282 | #if defined(AUDIO_HW_SINGLE_BUFFER) | | 5282 | #if defined(AUDIO_HW_SINGLE_BUFFER) |
5283 | /* | | 5283 | /* |
5284 | * Create a new block here and output it immediately. | | 5284 | * Create a new block here and output it immediately. |
5285 | * It makes a latency lower but needs machine power. | | 5285 | * It makes a latency lower but needs machine power. |
5286 | */ | | 5286 | */ |
5287 | audio_pmixer_process(sc); | | 5287 | audio_pmixer_process(sc); |
5288 | audio_pmixer_output(sc); | | 5288 | audio_pmixer_output(sc); |
5289 | #else | | 5289 | #else |
5290 | /* | | 5290 | /* |
5291 | * It is called when block N output is done. | | 5291 | * It is called when block N output is done. |
5292 | * Output immediately block N+1 created by the last interrupt. | | 5292 | * Output immediately block N+1 created by the last interrupt. |
5293 | * And then create block N+2 for the next interrupt. | | 5293 | * And then create block N+2 for the next interrupt. |
5294 | * This method makes playback robust even on slower machines. | | 5294 | * This method makes playback robust even on slower machines. |
5295 | * Instead the latency is increased by one block. | | 5295 | * Instead the latency is increased by one block. |
5296 | */ | | 5296 | */ |
5297 | | | 5297 | |
5298 | /* At first, output ready block. */ | | 5298 | /* At first, output ready block. */ |
5299 | if (mixer->hwbuf.used >= mixer->frames_per_block) { | | 5299 | if (mixer->hwbuf.used >= mixer->frames_per_block) { |
5300 | audio_pmixer_output(sc); | | 5300 | audio_pmixer_output(sc); |
5301 | } | | 5301 | } |
5302 | | | 5302 | |
5303 | bool later = false; | | 5303 | bool later = false; |
5304 | | | 5304 | |
5305 | if (mixer->hwbuf.used < mixer->frames_per_block) { | | 5305 | if (mixer->hwbuf.used < mixer->frames_per_block) { |
5306 | later = true; | | 5306 | later = true; |
5307 | } | | 5307 | } |
5308 | | | 5308 | |
5309 | /* Then, process next block. */ | | 5309 | /* Then, process next block. */ |
5310 | audio_pmixer_process(sc); | | 5310 | audio_pmixer_process(sc); |
5311 | | | 5311 | |
5312 | if (later) { | | 5312 | if (later) { |
5313 | audio_pmixer_output(sc); | | 5313 | audio_pmixer_output(sc); |
5314 | } | | 5314 | } |
5315 | #endif | | 5315 | #endif |
5316 | | | 5316 | |
5317 | /* | | 5317 | /* |
5318 | * When this interrupt is the real hardware interrupt, disabling | | 5318 | * When this interrupt is the real hardware interrupt, disabling |
5319 | * preemption here is not necessary. But some drivers (e.g. uaudio) | | 5319 | * preemption here is not necessary. But some drivers (e.g. uaudio) |
5320 | * emulate it by software interrupt, so kpreempt_disable is necessary. | | 5320 | * emulate it by software interrupt, so kpreempt_disable is necessary. |
5321 | */ | | 5321 | */ |
5322 | kpreempt_disable(); | | 5322 | kpreempt_disable(); |
5323 | softint_schedule(mixer->sih); | | 5323 | softint_schedule(mixer->sih); |
5324 | kpreempt_enable(); | | 5324 | kpreempt_enable(); |
5325 | } | | 5325 | } |
5326 | | | 5326 | |
5327 | /* | | 5327 | /* |
5328 | * Starts record mixer. | | 5328 | * Starts record mixer. |
5329 | * Must be called only if sc_rbusy is false. | | 5329 | * Must be called only if sc_rbusy is false. |
5330 | * Must be called with sc_lock held. | | 5330 | * Must be called with sc_lock held. |
5331 | * Must not be called from the interrupt context. | | 5331 | * Must not be called from the interrupt context. |
5332 | */ | | 5332 | */ |
5333 | static void | | 5333 | static void |
5334 | audio_rmixer_start(struct audio_softc *sc) | | 5334 | audio_rmixer_start(struct audio_softc *sc) |
5335 | { | | 5335 | { |
5336 | | | 5336 | |
5337 | KASSERT(mutex_owned(sc->sc_lock)); | | 5337 | KASSERT(mutex_owned(sc->sc_lock)); |
5338 | KASSERT(sc->sc_rbusy == false); | | 5338 | KASSERT(sc->sc_rbusy == false); |
5339 | | | 5339 | |
5340 | mutex_enter(sc->sc_intr_lock); | | 5340 | mutex_enter(sc->sc_intr_lock); |
5341 | | | 5341 | |
5342 | TRACE(2, "%s", (audiodebug >= 3) ? "begin" : ""); | | 5342 | TRACE(2, "%s", (audiodebug >= 3) ? "begin" : ""); |
5343 | audio_rmixer_input(sc); | | 5343 | audio_rmixer_input(sc); |
5344 | sc->sc_rbusy = true; | | 5344 | sc->sc_rbusy = true; |
5345 | TRACE(3, "end"); | | 5345 | TRACE(3, "end"); |
5346 | | | 5346 | |
5347 | mutex_exit(sc->sc_intr_lock); | | 5347 | mutex_exit(sc->sc_intr_lock); |
5348 | } | | 5348 | } |
5349 | | | 5349 | |
5350 | /* | | 5350 | /* |
5351 | * When recording with MD filter: | | 5351 | * When recording with MD filter: |
5352 | * | | 5352 | * |
5353 | * hwbuf [............] NBLKHW blocks ring buffer | | 5353 | * hwbuf [............] NBLKHW blocks ring buffer |
5354 | * | | | 5354 | * | |
5355 | * | convert from hw format | | 5355 | * | convert from hw format |
5356 | * v | | 5356 | * v |
5357 | * codecbuf [....] 1 block (ring) buffer | | 5357 | * codecbuf [....] 1 block (ring) buffer |
5358 | * | | | | 5358 | * | | |
5359 | * v v | | 5359 | * v v |
5360 | * track track ... | | 5360 | * track track ... |
5361 | * | | 5361 | * |
5362 | * When recording without MD filter: | | 5362 | * When recording without MD filter: |
5363 | * | | 5363 | * |
5364 | * hwbuf [............] NBLKHW blocks ring buffer | | 5364 | * hwbuf [............] NBLKHW blocks ring buffer |
5365 | * | | | | 5365 | * | | |
5366 | * v v | | 5366 | * v v |
5367 | * track track ... | | 5367 | * track track ... |
5368 | * | | 5368 | * |
5369 | * hwbuf: HW encoding, HW precision, HW ch, HW freq. | | 5369 | * hwbuf: HW encoding, HW precision, HW ch, HW freq. |
5370 | * codecbuf: slinear_NE, internal precision, HW ch, HW freq. | | 5370 | * codecbuf: slinear_NE, internal precision, HW ch, HW freq. |
5371 | */ | | 5371 | */ |
5372 | | | 5372 | |
5373 | /* | | 5373 | /* |
5374 | * Distribute a recorded block to all recording tracks. | | 5374 | * Distribute a recorded block to all recording tracks. |
5375 | */ | | 5375 | */ |
5376 | static void | | 5376 | static void |
5377 | audio_rmixer_process(struct audio_softc *sc) | | 5377 | audio_rmixer_process(struct audio_softc *sc) |
5378 | { | | 5378 | { |
5379 | audio_trackmixer_t *mixer; | | 5379 | audio_trackmixer_t *mixer; |
5380 | audio_ring_t *mixersrc; | | 5380 | audio_ring_t *mixersrc; |
5381 | audio_file_t *f; | | 5381 | audio_file_t *f; |
5382 | aint_t *p; | | 5382 | aint_t *p; |
5383 | int count; | | 5383 | int count; |
5384 | int bytes; | | 5384 | int bytes; |
5385 | int i; | | 5385 | int i; |
5386 | | | 5386 | |
5387 | mixer = sc->sc_rmixer; | | 5387 | mixer = sc->sc_rmixer; |
5388 | | | 5388 | |
5389 | /* | | 5389 | /* |
5390 | * count is the number of frames to be retrieved this time. | | 5390 | * count is the number of frames to be retrieved this time. |
5391 | * count should be one block. | | 5391 | * count should be one block. |
5392 | */ | | 5392 | */ |
5393 | count = auring_get_contig_used(&mixer->hwbuf); | | 5393 | count = auring_get_contig_used(&mixer->hwbuf); |
5394 | count = uimin(count, mixer->frames_per_block); | | 5394 | count = uimin(count, mixer->frames_per_block); |
5395 | if (count <= 0) { | | 5395 | if (count <= 0) { |
5396 | TRACE(4, "count %d: too short", count); | | 5396 | TRACE(4, "count %d: too short", count); |
5397 | return; | | 5397 | return; |
5398 | } | | 5398 | } |
5399 | bytes = frametobyte(&mixer->track_fmt, count); | | 5399 | bytes = frametobyte(&mixer->track_fmt, count); |
5400 | | | 5400 | |
5401 | /* Hardware driver's codec */ | | 5401 | /* Hardware driver's codec */ |
5402 | if (mixer->codec) { | | 5402 | if (mixer->codec) { |
5403 | mixer->codecarg.src = auring_headptr(&mixer->hwbuf); | | 5403 | mixer->codecarg.src = auring_headptr(&mixer->hwbuf); |
5404 | mixer->codecarg.dst = auring_tailptr(&mixer->codecbuf); | | 5404 | mixer->codecarg.dst = auring_tailptr(&mixer->codecbuf); |
5405 | mixer->codecarg.count = count; | | 5405 | mixer->codecarg.count = count; |
5406 | mixer->codec(&mixer->codecarg); | | 5406 | mixer->codec(&mixer->codecarg); |
5407 | auring_take(&mixer->hwbuf, mixer->codecarg.count); | | 5407 | auring_take(&mixer->hwbuf, mixer->codecarg.count); |
5408 | auring_push(&mixer->codecbuf, mixer->codecarg.count); | | 5408 | auring_push(&mixer->codecbuf, mixer->codecarg.count); |
5409 | mixersrc = &mixer->codecbuf; | | 5409 | mixersrc = &mixer->codecbuf; |
5410 | } else { | | 5410 | } else { |
5411 | mixersrc = &mixer->hwbuf; | | 5411 | mixersrc = &mixer->hwbuf; |
5412 | } | | 5412 | } |
5413 | | | 5413 | |
5414 | if (mixer->swap_endian) { | | 5414 | if (mixer->swap_endian) { |
5415 | /* inplace conversion */ | | 5415 | /* inplace conversion */ |
5416 | p = auring_headptr_aint(mixersrc); | | 5416 | p = auring_headptr_aint(mixersrc); |
5417 | for (i = 0; i < count * mixer->track_fmt.channels; i++, p++) { | | 5417 | for (i = 0; i < count * mixer->track_fmt.channels; i++, p++) { |
5418 | *p = bswap16(*p); | | 5418 | *p = bswap16(*p); |
5419 | } | | 5419 | } |
5420 | } | | 5420 | } |
5421 | | | 5421 | |
5422 | /* Distribute to all tracks. */ | | 5422 | /* Distribute to all tracks. */ |
5423 | SLIST_FOREACH(f, &sc->sc_files, entry) { | | 5423 | SLIST_FOREACH(f, &sc->sc_files, entry) { |
5424 | audio_track_t *track = f->rtrack; | | 5424 | audio_track_t *track = f->rtrack; |
5425 | audio_ring_t *input; | | 5425 | audio_ring_t *input; |
5426 | | | 5426 | |
5427 | if (track == NULL) | | 5427 | if (track == NULL) |
5428 | continue; | | 5428 | continue; |
5429 | | | 5429 | |
5430 | if (track->is_pause) { | | 5430 | if (track->is_pause) { |
5431 | TRACET(4, track, "skip; paused"); | | 5431 | TRACET(4, track, "skip; paused"); |
5432 | continue; | | 5432 | continue; |
5433 | } | | 5433 | } |
5434 | | | 5434 | |
5435 | if (audio_track_lock_tryenter(track) == false) { | | 5435 | if (audio_track_lock_tryenter(track) == false) { |
5436 | TRACET(4, track, "skip; in use"); | | 5436 | TRACET(4, track, "skip; in use"); |
5437 | continue; | | 5437 | continue; |
5438 | } | | 5438 | } |
5439 | | | 5439 | |
5440 | /* If the track buffer is full, discard the oldest one? */ | | 5440 | /* If the track buffer is full, discard the oldest one? */ |
5441 | input = track->input; | | 5441 | input = track->input; |
5442 | if (input->capacity - input->used < mixer->frames_per_block) { | | 5442 | if (input->capacity - input->used < mixer->frames_per_block) { |
5443 | int drops = mixer->frames_per_block - | | 5443 | int drops = mixer->frames_per_block - |
5444 | (input->capacity - input->used); | | 5444 | (input->capacity - input->used); |
5445 | track->dropframes += drops; | | 5445 | track->dropframes += drops; |
5446 | TRACET(4, track, "drop %d frames: inp=%d/%d/%d", | | 5446 | TRACET(4, track, "drop %d frames: inp=%d/%d/%d", |
5447 | drops, | | 5447 | drops, |
5448 | input->head, input->used, input->capacity); | | 5448 | input->head, input->used, input->capacity); |
5449 | auring_take(input, drops); | | 5449 | auring_take(input, drops); |
5450 | } | | 5450 | } |
5451 | KASSERT(input->used % mixer->frames_per_block == 0); | | 5451 | KASSERT(input->used % mixer->frames_per_block == 0); |
5452 | | | 5452 | |
5453 | memcpy(auring_tailptr_aint(input), | | 5453 | memcpy(auring_tailptr_aint(input), |
5454 | auring_headptr_aint(mixersrc), | | 5454 | auring_headptr_aint(mixersrc), |
5455 | bytes); | | 5455 | bytes); |
5456 | auring_push(input, count); | | 5456 | auring_push(input, count); |
5457 | | | 5457 | |
5458 | /* XXX sequence counter? */ | | 5458 | /* XXX sequence counter? */ |
5459 | | | 5459 | |
5460 | audio_track_lock_exit(track); | | 5460 | audio_track_lock_exit(track); |
5461 | } | | 5461 | } |
5462 | | | 5462 | |
5463 | auring_take(mixersrc, count); | | 5463 | auring_take(mixersrc, count); |
5464 | } | | 5464 | } |
5465 | | | 5465 | |
5466 | /* | | 5466 | /* |
5467 | * Input one block from HW to hwbuf. | | 5467 | * Input one block from HW to hwbuf. |
5468 | * Must be called with sc_intr_lock held. | | 5468 | * Must be called with sc_intr_lock held. |
5469 | */ | | 5469 | */ |
5470 | static void | | 5470 | static void |
5471 | audio_rmixer_input(struct audio_softc *sc) | | 5471 | audio_rmixer_input(struct audio_softc *sc) |
5472 | { | | 5472 | { |
5473 | audio_trackmixer_t *mixer; | | 5473 | audio_trackmixer_t *mixer; |
5474 | audio_params_t params; | | 5474 | audio_params_t params; |
5475 | void *start; | | 5475 | void *start; |
5476 | void *end; | | 5476 | void *end; |
5477 | int blksize; | | 5477 | int blksize; |
5478 | int error; | | 5478 | int error; |
5479 | | | 5479 | |
5480 | mixer = sc->sc_rmixer; | | 5480 | mixer = sc->sc_rmixer; |
5481 | blksize = frametobyte(&mixer->hwbuf.fmt, mixer->frames_per_block); | | 5481 | blksize = frametobyte(&mixer->hwbuf.fmt, mixer->frames_per_block); |
5482 | | | 5482 | |
5483 | if (sc->hw_if->trigger_input) { | | 5483 | if (sc->hw_if->trigger_input) { |
5484 | /* trigger (at once) */ | | 5484 | /* trigger (at once) */ |
5485 | if (!sc->sc_rbusy) { | | 5485 | if (!sc->sc_rbusy) { |
5486 | start = mixer->hwbuf.mem; | | 5486 | start = mixer->hwbuf.mem; |
5487 | end = (uint8_t *)start + auring_bytelen(&mixer->hwbuf); | | 5487 | end = (uint8_t *)start + auring_bytelen(&mixer->hwbuf); |
5488 | params = format2_to_params(&mixer->hwbuf.fmt); | | 5488 | params = format2_to_params(&mixer->hwbuf.fmt); |
5489 | | | 5489 | |
5490 | error = sc->hw_if->trigger_input(sc->hw_hdl, | | 5490 | error = sc->hw_if->trigger_input(sc->hw_hdl, |
5491 | start, end, blksize, audio_rintr, sc, ¶ms); | | 5491 | start, end, blksize, audio_rintr, sc, ¶ms); |
5492 | if (error) { | | 5492 | if (error) { |
5493 | device_printf(sc->sc_dev, | | 5493 | device_printf(sc->sc_dev, |
5494 | "trigger_input failed with %d\n", error); | | 5494 | "trigger_input failed with %d\n", error); |
5495 | return; | | 5495 | return; |
5496 | } | | 5496 | } |
5497 | } | | 5497 | } |
5498 | } else { | | 5498 | } else { |
5499 | /* start (everytime) */ | | 5499 | /* start (everytime) */ |
5500 | start = auring_tailptr(&mixer->hwbuf); | | 5500 | start = auring_tailptr(&mixer->hwbuf); |
5501 | | | 5501 | |
5502 | error = sc->hw_if->start_input(sc->hw_hdl, | | 5502 | error = sc->hw_if->start_input(sc->hw_hdl, |
5503 | start, blksize, audio_rintr, sc); | | 5503 | start, blksize, audio_rintr, sc); |
5504 | if (error) { | | 5504 | if (error) { |
5505 | device_printf(sc->sc_dev, | | 5505 | device_printf(sc->sc_dev, |
5506 | "start_input failed with %d\n", error); | | 5506 | "start_input failed with %d\n", error); |
5507 | return; | | 5507 | return; |
5508 | } | | 5508 | } |
5509 | } | | 5509 | } |
5510 | } | | 5510 | } |
5511 | | | 5511 | |
5512 | /* | | 5512 | /* |
5513 | * This is an interrupt handler for recording. | | 5513 | * This is an interrupt handler for recording. |
5514 | * It is called with sc_intr_lock. | | 5514 | * It is called with sc_intr_lock. |
5515 | * | | 5515 | * |
5516 | * It is usually called from hardware interrupt. However, note that | | 5516 | * It is usually called from hardware interrupt. However, note that |
5517 | * for some drivers (e.g. uaudio) it is called from software interrupt. | | 5517 | * for some drivers (e.g. uaudio) it is called from software interrupt. |
5518 | */ | | 5518 | */ |
5519 | static void | | 5519 | static void |
5520 | audio_rintr(void *arg) | | 5520 | audio_rintr(void *arg) |
5521 | { | | 5521 | { |
5522 | struct audio_softc *sc; | | 5522 | struct audio_softc *sc; |
5523 | audio_trackmixer_t *mixer; | | 5523 | audio_trackmixer_t *mixer; |
5524 | | | 5524 | |
5525 | sc = arg; | | 5525 | sc = arg; |
5526 | KASSERT(mutex_owned(sc->sc_intr_lock)); | | 5526 | KASSERT(mutex_owned(sc->sc_intr_lock)); |
5527 | | | 5527 | |
5528 | if (sc->sc_dying) | | 5528 | if (sc->sc_dying) |
5529 | return; | | 5529 | return; |
5530 | #if defined(DIAGNOSTIC) | | 5530 | #if defined(DIAGNOSTIC) |
5531 | if (sc->sc_rbusy == false) { | | 5531 | if (sc->sc_rbusy == false) { |
5532 | device_printf(sc->sc_dev, "stray interrupt\n"); | | 5532 | device_printf(sc->sc_dev, "stray interrupt\n"); |
5533 | return; | | 5533 | return; |
5534 | } | | 5534 | } |
5535 | #endif | | 5535 | #endif |
5536 | | | 5536 | |
5537 | mixer = sc->sc_rmixer; | | 5537 | mixer = sc->sc_rmixer; |
5538 | mixer->hw_complete_counter += mixer->frames_per_block; | | 5538 | mixer->hw_complete_counter += mixer->frames_per_block; |
5539 | mixer->hwseq++; | | 5539 | mixer->hwseq++; |
5540 | | | 5540 | |
5541 | auring_push(&mixer->hwbuf, mixer->frames_per_block); | | 5541 | auring_push(&mixer->hwbuf, mixer->frames_per_block); |
5542 | | | 5542 | |
5543 | TRACE(4, | | 5543 | TRACE(4, |
5544 | "HW_INT ++hwseq=%" PRIu64 " cmplcnt=%" PRIu64 " hwbuf=%d/%d/%d", | | 5544 | "HW_INT ++hwseq=%" PRIu64 " cmplcnt=%" PRIu64 " hwbuf=%d/%d/%d", |
5545 | mixer->hwseq, mixer->hw_complete_counter, | | 5545 | mixer->hwseq, mixer->hw_complete_counter, |
5546 | mixer->hwbuf.head, mixer->hwbuf.used, mixer->hwbuf.capacity); | | 5546 | mixer->hwbuf.head, mixer->hwbuf.used, mixer->hwbuf.capacity); |
5547 | | | 5547 | |
5548 | /* Distrubute recorded block */ | | 5548 | /* Distrubute recorded block */ |
5549 | audio_rmixer_process(sc); | | 5549 | audio_rmixer_process(sc); |
5550 | | | 5550 | |
5551 | /* Request next block */ | | 5551 | /* Request next block */ |
5552 | audio_rmixer_input(sc); | | 5552 | audio_rmixer_input(sc); |
5553 | | | 5553 | |
5554 | /* | | 5554 | /* |
5555 | * When this interrupt is the real hardware interrupt, disabling | | 5555 | * When this interrupt is the real hardware interrupt, disabling |
5556 | * preemption here is not necessary. But some drivers (e.g. uaudio) | | 5556 | * preemption here is not necessary. But some drivers (e.g. uaudio) |
5557 | * emulate it by software interrupt, so kpreempt_disable is necessary. | | 5557 | * emulate it by software interrupt, so kpreempt_disable is necessary. |
5558 | */ | | 5558 | */ |
5559 | kpreempt_disable(); | | 5559 | kpreempt_disable(); |
5560 | softint_schedule(mixer->sih); | | 5560 | softint_schedule(mixer->sih); |
5561 | kpreempt_enable(); | | 5561 | kpreempt_enable(); |
5562 | } | | 5562 | } |
5563 | | | 5563 | |
5564 | /* | | 5564 | /* |
5565 | * Halts playback mixer. | | 5565 | * Halts playback mixer. |
5566 | * This function also clears related parameters, so call this function | | 5566 | * This function also clears related parameters, so call this function |
5567 | * instead of calling halt_output directly. | | 5567 | * instead of calling halt_output directly. |
5568 | * Must be called only if sc_pbusy is true. | | 5568 | * Must be called only if sc_pbusy is true. |
5569 | * Must be called with sc_lock && sc_exlock held. | | 5569 | * Must be called with sc_lock && sc_exlock held. |
5570 | */ | | 5570 | */ |
5571 | static int | | 5571 | static int |
5572 | audio_pmixer_halt(struct audio_softc *sc) | | 5572 | audio_pmixer_halt(struct audio_softc *sc) |
5573 | { | | 5573 | { |
5574 | int error; | | 5574 | int error; |
5575 | | | 5575 | |
5576 | TRACE(2, ""); | | 5576 | TRACE(2, ""); |
5577 | KASSERT(mutex_owned(sc->sc_lock)); | | 5577 | KASSERT(mutex_owned(sc->sc_lock)); |
5578 | KASSERT(sc->sc_exlock); | | 5578 | KASSERT(sc->sc_exlock); |
5579 | | | 5579 | |
5580 | mutex_enter(sc->sc_intr_lock); | | 5580 | mutex_enter(sc->sc_intr_lock); |
5581 | error = sc->hw_if->halt_output(sc->hw_hdl); | | 5581 | error = sc->hw_if->halt_output(sc->hw_hdl); |
5582 | mutex_exit(sc->sc_intr_lock); | | 5582 | mutex_exit(sc->sc_intr_lock); |
5583 | | | 5583 | |
5584 | /* Halts anyway even if some error has occurred. */ | | 5584 | /* Halts anyway even if some error has occurred. */ |
5585 | sc->sc_pbusy = false; | | 5585 | sc->sc_pbusy = false; |
5586 | sc->sc_pmixer->hwbuf.head = 0; | | 5586 | sc->sc_pmixer->hwbuf.head = 0; |
5587 | sc->sc_pmixer->hwbuf.used = 0; | | 5587 | sc->sc_pmixer->hwbuf.used = 0; |
5588 | sc->sc_pmixer->mixseq = 0; | | 5588 | sc->sc_pmixer->mixseq = 0; |
5589 | sc->sc_pmixer->hwseq = 0; | | 5589 | sc->sc_pmixer->hwseq = 0; |
5590 | | | 5590 | |
5591 | return error; | | 5591 | return error; |
5592 | } | | 5592 | } |
5593 | | | 5593 | |
5594 | /* | | 5594 | /* |
5595 | * Halts recording mixer. | | 5595 | * Halts recording mixer. |
5596 | * This function also clears related parameters, so call this function | | 5596 | * This function also clears related parameters, so call this function |
5597 | * instead of calling halt_input directly. | | 5597 | * instead of calling halt_input directly. |
5598 | * Must be called only if sc_rbusy is true. | | 5598 | * Must be called only if sc_rbusy is true. |
5599 | * Must be called with sc_lock && sc_exlock held. | | 5599 | * Must be called with sc_lock && sc_exlock held. |
5600 | */ | | 5600 | */ |
5601 | static int | | 5601 | static int |
5602 | audio_rmixer_halt(struct audio_softc *sc) | | 5602 | audio_rmixer_halt(struct audio_softc *sc) |
5603 | { | | 5603 | { |
5604 | int error; | | 5604 | int error; |
5605 | | | 5605 | |
5606 | TRACE(2, ""); | | 5606 | TRACE(2, ""); |
5607 | KASSERT(mutex_owned(sc->sc_lock)); | | 5607 | KASSERT(mutex_owned(sc->sc_lock)); |
5608 | KASSERT(sc->sc_exlock); | | 5608 | KASSERT(sc->sc_exlock); |
5609 | | | 5609 | |
5610 | mutex_enter(sc->sc_intr_lock); | | 5610 | mutex_enter(sc->sc_intr_lock); |
5611 | error = sc->hw_if->halt_input(sc->hw_hdl); | | 5611 | error = sc->hw_if->halt_input(sc->hw_hdl); |
5612 | mutex_exit(sc->sc_intr_lock); | | 5612 | mutex_exit(sc->sc_intr_lock); |
5613 | | | 5613 | |
5614 | /* Halts anyway even if some error has occurred. */ | | 5614 | /* Halts anyway even if some error has occurred. */ |
5615 | sc->sc_rbusy = false; | | 5615 | sc->sc_rbusy = false; |
5616 | sc->sc_rmixer->hwbuf.head = 0; | | 5616 | sc->sc_rmixer->hwbuf.head = 0; |
5617 | sc->sc_rmixer->hwbuf.used = 0; | | 5617 | sc->sc_rmixer->hwbuf.used = 0; |
5618 | sc->sc_rmixer->mixseq = 0; | | 5618 | sc->sc_rmixer->mixseq = 0; |
5619 | sc->sc_rmixer->hwseq = 0; | | 5619 | sc->sc_rmixer->hwseq = 0; |
5620 | | | 5620 | |
5621 | return error; | | 5621 | return error; |
5622 | } | | 5622 | } |
5623 | | | 5623 | |
5624 | /* | | 5624 | /* |
5625 | * Flush this track. | | 5625 | * Flush this track. |
5626 | * Halts all operations, clears all buffers, reset error counters. | | 5626 | * Halts all operations, clears all buffers, reset error counters. |
5627 | * XXX I'm not sure... | | 5627 | * XXX I'm not sure... |
5628 | */ | | 5628 | */ |
5629 | static void | | 5629 | static void |
5630 | audio_track_clear(struct audio_softc *sc, audio_track_t *track) | | 5630 | audio_track_clear(struct audio_softc *sc, audio_track_t *track) |
5631 | { | | 5631 | { |
5632 | | | 5632 | |
5633 | KASSERT(track); | | 5633 | KASSERT(track); |
5634 | TRACET(3, track, "clear"); | | 5634 | TRACET(3, track, "clear"); |
5635 | | | 5635 | |
5636 | audio_track_lock_enter(track); | | 5636 | audio_track_lock_enter(track); |
5637 | | | 5637 | |
5638 | track->usrbuf.used = 0; | | 5638 | track->usrbuf.used = 0; |
5639 | /* Clear all internal parameters. */ | | 5639 | /* Clear all internal parameters. */ |
5640 | if (track->codec.filter) { | | 5640 | if (track->codec.filter) { |
5641 | track->codec.srcbuf.used = 0; | | 5641 | track->codec.srcbuf.used = 0; |
5642 | track->codec.srcbuf.head = 0; | | 5642 | track->codec.srcbuf.head = 0; |
5643 | } | | 5643 | } |
5644 | if (track->chvol.filter) { | | 5644 | if (track->chvol.filter) { |
5645 | track->chvol.srcbuf.used = 0; | | 5645 | track->chvol.srcbuf.used = 0; |
5646 | track->chvol.srcbuf.head = 0; | | 5646 | track->chvol.srcbuf.head = 0; |
5647 | } | | 5647 | } |
5648 | if (track->chmix.filter) { | | 5648 | if (track->chmix.filter) { |
5649 | track->chmix.srcbuf.used = 0; | | 5649 | track->chmix.srcbuf.used = 0; |
5650 | track->chmix.srcbuf.head = 0; | | 5650 | track->chmix.srcbuf.head = 0; |
5651 | } | | 5651 | } |
5652 | if (track->freq.filter) { | | 5652 | if (track->freq.filter) { |
5653 | track->freq.srcbuf.used = 0; | | 5653 | track->freq.srcbuf.used = 0; |
5654 | track->freq.srcbuf.head = 0; | | 5654 | track->freq.srcbuf.head = 0; |
5655 | if (track->freq_step < 65536) | | 5655 | if (track->freq_step < 65536) |
5656 | track->freq_current = 65536; | | 5656 | track->freq_current = 65536; |
5657 | else | | 5657 | else |
5658 | track->freq_current = 0; | | 5658 | track->freq_current = 0; |
5659 | memset(track->freq_prev, 0, sizeof(track->freq_prev)); | | 5659 | memset(track->freq_prev, 0, sizeof(track->freq_prev)); |
5660 | memset(track->freq_curr, 0, sizeof(track->freq_curr)); | | 5660 | memset(track->freq_curr, 0, sizeof(track->freq_curr)); |
5661 | } | | 5661 | } |
5662 | /* Clear buffer, then operation halts naturally. */ | | 5662 | /* Clear buffer, then operation halts naturally. */ |
5663 | track->outbuf.used = 0; | | 5663 | track->outbuf.used = 0; |
5664 | | | 5664 | |
5665 | /* Clear counters. */ | | 5665 | /* Clear counters. */ |
5666 | track->dropframes = 0; | | 5666 | track->dropframes = 0; |
5667 | | | 5667 | |
5668 | audio_track_lock_exit(track); | | 5668 | audio_track_lock_exit(track); |
5669 | } | | 5669 | } |
5670 | | | 5670 | |
5671 | /* | | 5671 | /* |
5672 | * Drain the track. | | 5672 | * Drain the track. |
5673 | * track must be present and for playback. | | 5673 | * track must be present and for playback. |
5674 | * If successful, it returns 0. Otherwise returns errno. | | 5674 | * If successful, it returns 0. Otherwise returns errno. |
5675 | * Must be called with sc_lock held. | | 5675 | * Must be called with sc_lock held. |
5676 | */ | | 5676 | */ |
5677 | static int | | 5677 | static int |
5678 | audio_track_drain(struct audio_softc *sc, audio_track_t *track) | | 5678 | audio_track_drain(struct audio_softc *sc, audio_track_t *track) |
5679 | { | | 5679 | { |
5680 | audio_trackmixer_t *mixer; | | 5680 | audio_trackmixer_t *mixer; |
5681 | int done; | | 5681 | int done; |
5682 | int error; | | 5682 | int error; |
5683 | | | 5683 | |
5684 | KASSERT(track); | | 5684 | KASSERT(track); |
5685 | TRACET(3, track, "start"); | | 5685 | TRACET(3, track, "start"); |
5686 | mixer = track->mixer; | | 5686 | mixer = track->mixer; |
5687 | KASSERT(mutex_owned(sc->sc_lock)); | | 5687 | KASSERT(mutex_owned(sc->sc_lock)); |
5688 | | | 5688 | |
5689 | /* Ignore them if pause. */ | | 5689 | /* Ignore them if pause. */ |
5690 | if (track->is_pause) { | | 5690 | if (track->is_pause) { |
5691 | TRACET(3, track, "pause -> clear"); | | 5691 | TRACET(3, track, "pause -> clear"); |
5692 | track->pstate = AUDIO_STATE_CLEAR; | | 5692 | track->pstate = AUDIO_STATE_CLEAR; |
5693 | } | | 5693 | } |
5694 | /* Terminate early here if there is no data in the track. */ | | 5694 | /* Terminate early here if there is no data in the track. */ |
5695 | if (track->pstate == AUDIO_STATE_CLEAR) { | | 5695 | if (track->pstate == AUDIO_STATE_CLEAR) { |
5696 | TRACET(3, track, "no need to drain"); | | 5696 | TRACET(3, track, "no need to drain"); |
5697 | return 0; | | 5697 | return 0; |
5698 | } | | 5698 | } |
5699 | track->pstate = AUDIO_STATE_DRAINING; | | 5699 | track->pstate = AUDIO_STATE_DRAINING; |
5700 | | | 5700 | |
5701 | for (;;) { | | 5701 | for (;;) { |
5702 | /* I want to display it before condition evaluation. */ | | 5702 | /* I want to display it before condition evaluation. */ |
5703 | TRACET(3, track, "pid=%d.%d trkseq=%d hwseq=%d out=%d/%d/%d", | | 5703 | TRACET(3, track, "pid=%d.%d trkseq=%d hwseq=%d out=%d/%d/%d", |
5704 | (int)curproc->p_pid, (int)curlwp->l_lid, | | 5704 | (int)curproc->p_pid, (int)curlwp->l_lid, |
5705 | (int)track->seq, (int)mixer->hwseq, | | 5705 | (int)track->seq, (int)mixer->hwseq, |
5706 | track->outbuf.head, track->outbuf.used, | | 5706 | track->outbuf.head, track->outbuf.used, |
5707 | track->outbuf.capacity); | | 5707 | track->outbuf.capacity); |
5708 | | | 5708 | |
5709 | /* Condition to terminate */ | | 5709 | /* Condition to terminate */ |
5710 | audio_track_lock_enter(track); | | 5710 | audio_track_lock_enter(track); |
5711 | done = (track->usrbuf.used < frametobyte(&track->inputfmt, 1) && | | 5711 | done = (track->usrbuf.used < frametobyte(&track->inputfmt, 1) && |
5712 | track->outbuf.used == 0 && | | 5712 | track->outbuf.used == 0 && |
5713 | track->seq <= mixer->hwseq); | | 5713 | track->seq <= mixer->hwseq); |
5714 | audio_track_lock_exit(track); | | 5714 | audio_track_lock_exit(track); |
5715 | if (done) | | 5715 | if (done) |
5716 | break; | | 5716 | break; |
5717 | | | 5717 | |
5718 | TRACET(3, track, "sleep"); | | 5718 | TRACET(3, track, "sleep"); |
5719 | error = audio_track_waitio(sc, track); | | 5719 | error = audio_track_waitio(sc, track); |
5720 | if (error) | | 5720 | if (error) |
5721 | return error; | | 5721 | return error; |
5722 | | | 5722 | |
5723 | /* XXX call audio_track_play here ? */ | | 5723 | /* XXX call audio_track_play here ? */ |
5724 | } | | 5724 | } |
5725 | | | 5725 | |
5726 | track->pstate = AUDIO_STATE_CLEAR; | | 5726 | track->pstate = AUDIO_STATE_CLEAR; |
5727 | TRACET(3, track, "done trk_inp=%d trk_out=%d", | | 5727 | TRACET(3, track, "done trk_inp=%d trk_out=%d", |
5728 | (int)track->inputcounter, (int)track->outputcounter); | | 5728 | (int)track->inputcounter, (int)track->outputcounter); |
5729 | return 0; | | 5729 | return 0; |
5730 | } | | 5730 | } |
5731 | | | 5731 | |
5732 | /* | | 5732 | /* |
| | | 5733 | * Send signal to process. |
| | | 5734 | * This is intended to be called only from audio_softintr_{rd,wr}. |
| | | 5735 | * Must be called with sc_lock && sc_intr_lock held. |
| | | 5736 | */ |
| | | 5737 | static inline void |
| | | 5738 | audio_psignal(struct audio_softc *sc, pid_t pid, int signum) |
| | | 5739 | { |
| | | 5740 | proc_t *p; |
| | | 5741 | |
| | | 5742 | KASSERT(mutex_owned(sc->sc_lock)); |
| | | 5743 | KASSERT(mutex_owned(sc->sc_intr_lock)); |
| | | 5744 | KASSERT(pid != 0); |
| | | 5745 | |
| | | 5746 | /* |
| | | 5747 | * psignal() must be called without spin lock held. |
| | | 5748 | * So leave intr_lock temporarily here. |
| | | 5749 | */ |
| | | 5750 | mutex_exit(sc->sc_intr_lock); |
| | | 5751 | |
| | | 5752 | mutex_enter(proc_lock); |
| | | 5753 | p = proc_find(pid); |
| | | 5754 | if (p) |
| | | 5755 | psignal(p, signum); |
| | | 5756 | mutex_exit(proc_lock); |
| | | 5757 | |
| | | 5758 | /* Enter intr_lock again */ |
| | | 5759 | mutex_enter(sc->sc_intr_lock); |
| | | 5760 | } |
| | | 5761 | |
| | | 5762 | /* |
5733 | * This is software interrupt handler for record. | | 5763 | * This is software interrupt handler for record. |
5734 | * It is called from recording hardware interrupt everytime. | | 5764 | * It is called from recording hardware interrupt everytime. |
5735 | * It does: | | 5765 | * It does: |
5736 | * - Deliver SIGIO for all async processes. | | 5766 | * - Deliver SIGIO for all async processes. |
5737 | * - Notify to audio_read() that data has arrived. | | 5767 | * - Notify to audio_read() that data has arrived. |
5738 | * - selnotify() for select/poll-ing processes. | | 5768 | * - selnotify() for select/poll-ing processes. |
5739 | */ | | 5769 | */ |
5740 | /* | | 5770 | /* |
5741 | * XXX If a process issues FIOASYNC between hardware interrupt and | | 5771 | * XXX If a process issues FIOASYNC between hardware interrupt and |
5742 | * software interrupt, (stray) SIGIO will be sent to the process | | 5772 | * software interrupt, (stray) SIGIO will be sent to the process |
5743 | * despite the fact that it has not receive recorded data yet. | | 5773 | * despite the fact that it has not receive recorded data yet. |
5744 | */ | | 5774 | */ |
5745 | static void | | 5775 | static void |
5746 | audio_softintr_rd(void *cookie) | | 5776 | audio_softintr_rd(void *cookie) |
5747 | { | | 5777 | { |
5748 | struct audio_softc *sc = cookie; | | 5778 | struct audio_softc *sc = cookie; |
5749 | audio_file_t *f; | | 5779 | audio_file_t *f; |
5750 | proc_t *p; | | | |
5751 | pid_t pid; | | 5780 | pid_t pid; |
5752 | | | 5781 | |
5753 | mutex_enter(sc->sc_lock); | | 5782 | mutex_enter(sc->sc_lock); |
5754 | mutex_enter(sc->sc_intr_lock); | | 5783 | mutex_enter(sc->sc_intr_lock); |
5755 | | | 5784 | |
5756 | SLIST_FOREACH(f, &sc->sc_files, entry) { | | 5785 | SLIST_FOREACH(f, &sc->sc_files, entry) { |
5757 | audio_track_t *track = f->rtrack; | | 5786 | audio_track_t *track = f->rtrack; |
5758 | | | 5787 | |
5759 | if (track == NULL) | | 5788 | if (track == NULL) |
5760 | continue; | | 5789 | continue; |
5761 | | | 5790 | |
5762 | TRACET(4, track, "broadcast; inp=%d/%d/%d", | | 5791 | TRACET(4, track, "broadcast; inp=%d/%d/%d", |
5763 | track->input->head, | | 5792 | track->input->head, |
5764 | track->input->used, | | 5793 | track->input->used, |
5765 | track->input->capacity); | | 5794 | track->input->capacity); |
5766 | | | 5795 | |
5767 | pid = f->async_audio; | | 5796 | pid = f->async_audio; |
5768 | if (pid != 0) { | | 5797 | if (pid != 0) { |
5769 | TRACEF(4, f, "sending SIGIO %d", pid); | | 5798 | TRACEF(4, f, "sending SIGIO %d", pid); |
5770 | mutex_enter(proc_lock); | | 5799 | audio_psignal(sc, pid, SIGIO); |
5771 | if ((p = proc_find(pid)) != NULL) | | | |
5772 | psignal(p, SIGIO); | | | |
5773 | mutex_exit(proc_lock); | | | |
5774 | } | | 5800 | } |
5775 | } | | 5801 | } |
5776 | mutex_exit(sc->sc_intr_lock); | | 5802 | mutex_exit(sc->sc_intr_lock); |
5777 | | | 5803 | |
5778 | /* Notify that data has arrived. */ | | 5804 | /* Notify that data has arrived. */ |
5779 | selnotify(&sc->sc_rsel, 0, NOTE_SUBMIT); | | 5805 | selnotify(&sc->sc_rsel, 0, NOTE_SUBMIT); |
5780 | KNOTE(&sc->sc_rsel.sel_klist, 0); | | 5806 | KNOTE(&sc->sc_rsel.sel_klist, 0); |
5781 | cv_broadcast(&sc->sc_rmixer->outcv); | | 5807 | cv_broadcast(&sc->sc_rmixer->outcv); |
5782 | | | 5808 | |
5783 | mutex_exit(sc->sc_lock); | | 5809 | mutex_exit(sc->sc_lock); |
5784 | } | | 5810 | } |
5785 | | | 5811 | |
5786 | /* | | 5812 | /* |
5787 | * This is software interrupt handler for playback. | | 5813 | * This is software interrupt handler for playback. |
5788 | * It is called from playback hardware interrupt everytime. | | 5814 | * It is called from playback hardware interrupt everytime. |
5789 | * It does: | | 5815 | * It does: |
5790 | * - Deliver SIGIO for all async and writable (used < lowat) processes. | | 5816 | * - Deliver SIGIO for all async and writable (used < lowat) processes. |
5791 | * - Notify to audio_write() that outbuf block available. | | 5817 | * - Notify to audio_write() that outbuf block available. |
5792 | * - selnotify() for select/poll-ing processes if there are any writable | | 5818 | * - selnotify() for select/poll-ing processes if there are any writable |
5793 | * (used < lowat) processes. Checking each descriptor will be done by | | 5819 | * (used < lowat) processes. Checking each descriptor will be done by |
5794 | * filt_audiowrite_event(). | | 5820 | * filt_audiowrite_event(). |
5795 | */ | | 5821 | */ |
5796 | static void | | 5822 | static void |
5797 | audio_softintr_wr(void *cookie) | | 5823 | audio_softintr_wr(void *cookie) |
5798 | { | | 5824 | { |
5799 | struct audio_softc *sc = cookie; | | 5825 | struct audio_softc *sc = cookie; |
5800 | audio_file_t *f; | | 5826 | audio_file_t *f; |
5801 | bool found; | | 5827 | bool found; |
5802 | proc_t *p; | | | |
5803 | pid_t pid; | | 5828 | pid_t pid; |
5804 | | | 5829 | |
5805 | TRACE(4, "called"); | | 5830 | TRACE(4, "called"); |
5806 | found = false; | | 5831 | found = false; |
5807 | | | 5832 | |
5808 | mutex_enter(sc->sc_lock); | | 5833 | mutex_enter(sc->sc_lock); |
5809 | mutex_enter(sc->sc_intr_lock); | | 5834 | mutex_enter(sc->sc_intr_lock); |
5810 | | | 5835 | |
5811 | SLIST_FOREACH(f, &sc->sc_files, entry) { | | 5836 | SLIST_FOREACH(f, &sc->sc_files, entry) { |
5812 | audio_track_t *track = f->ptrack; | | 5837 | audio_track_t *track = f->ptrack; |
5813 | | | 5838 | |
5814 | if (track == NULL) | | 5839 | if (track == NULL) |
5815 | continue; | | 5840 | continue; |
5816 | | | 5841 | |
5817 | TRACET(4, track, "broadcast; trseq=%d out=%d/%d/%d", | | 5842 | TRACET(4, track, "broadcast; trseq=%d out=%d/%d/%d", |
5818 | (int)track->seq, | | 5843 | (int)track->seq, |
5819 | track->outbuf.head, | | 5844 | track->outbuf.head, |
5820 | track->outbuf.used, | | 5845 | track->outbuf.used, |
5821 | track->outbuf.capacity); | | 5846 | track->outbuf.capacity); |
5822 | | | 5847 | |
5823 | /* | | 5848 | /* |
5824 | * Send a signal if the process is async mode and | | 5849 | * Send a signal if the process is async mode and |
5825 | * used is lower than lowat. | | 5850 | * used is lower than lowat. |
5826 | */ | | 5851 | */ |
5827 | if (track->usrbuf.used <= track->usrbuf_usedlow && | | 5852 | if (track->usrbuf.used <= track->usrbuf_usedlow && |
5828 | !track->is_pause) { | | 5853 | !track->is_pause) { |
| | | 5854 | /* For selnotify */ |
5829 | found = true; | | 5855 | found = true; |
| | | 5856 | /* For SIGIO */ |
5830 | pid = f->async_audio; | | 5857 | pid = f->async_audio; |
5831 | if (pid != 0) { | | 5858 | if (pid != 0) { |
5832 | TRACEF(4, f, "sending SIGIO %d", pid); | | 5859 | TRACEF(4, f, "sending SIGIO %d", pid); |
5833 | mutex_enter(proc_lock); | | 5860 | audio_psignal(sc, pid, SIGIO); |
5834 | if ((p = proc_find(pid)) != NULL) | | | |
5835 | psignal(p, SIGIO); | | | |
5836 | mutex_exit(proc_lock); | | | |
5837 | } | | 5861 | } |
5838 | } | | 5862 | } |
5839 | } | | 5863 | } |
5840 | mutex_exit(sc->sc_intr_lock); | | 5864 | mutex_exit(sc->sc_intr_lock); |
5841 | | | 5865 | |
5842 | /* | | 5866 | /* |
5843 | * Notify for select/poll when someone become writable. | | 5867 | * Notify for select/poll when someone become writable. |
5844 | * It needs sc_lock (and not sc_intr_lock). | | 5868 | * It needs sc_lock (and not sc_intr_lock). |
5845 | */ | | 5869 | */ |
5846 | if (found) { | | 5870 | if (found) { |
5847 | TRACE(4, "selnotify"); | | 5871 | TRACE(4, "selnotify"); |
5848 | selnotify(&sc->sc_wsel, 0, NOTE_SUBMIT); | | 5872 | selnotify(&sc->sc_wsel, 0, NOTE_SUBMIT); |
5849 | KNOTE(&sc->sc_wsel.sel_klist, 0); | | 5873 | KNOTE(&sc->sc_wsel.sel_klist, 0); |
5850 | } | | 5874 | } |
5851 | | | 5875 | |
5852 | /* Notify to audio_write() that outbuf available. */ | | 5876 | /* Notify to audio_write() that outbuf available. */ |
5853 | cv_broadcast(&sc->sc_pmixer->outcv); | | 5877 | cv_broadcast(&sc->sc_pmixer->outcv); |
5854 | | | 5878 | |
5855 | mutex_exit(sc->sc_lock); | | 5879 | mutex_exit(sc->sc_lock); |
5856 | } | | 5880 | } |
5857 | | | 5881 | |
5858 | /* | | 5882 | /* |
5859 | * Check (and convert) the format *p came from userland. | | 5883 | * Check (and convert) the format *p came from userland. |
5860 | * If successful, it writes back the converted format to *p if necessary | | 5884 | * If successful, it writes back the converted format to *p if necessary |
5861 | * and returns 0. Otherwise returns errno (*p may change even this case). | | 5885 | * and returns 0. Otherwise returns errno (*p may change even this case). |
5862 | */ | | 5886 | */ |
5863 | static int | | 5887 | static int |
5864 | audio_check_params(audio_format2_t *p) | | 5888 | audio_check_params(audio_format2_t *p) |
5865 | { | | 5889 | { |
5866 | | | 5890 | |
5867 | /* Convert obsoleted AUDIO_ENCODING_PCM* */ | | 5891 | /* Convert obsoleted AUDIO_ENCODING_PCM* */ |
5868 | /* XXX Is this conversion right? */ | | 5892 | /* XXX Is this conversion right? */ |
5869 | if (p->encoding == AUDIO_ENCODING_PCM16) { | | 5893 | if (p->encoding == AUDIO_ENCODING_PCM16) { |
5870 | if (p->precision == 8) | | 5894 | if (p->precision == 8) |
5871 | p->encoding = AUDIO_ENCODING_ULINEAR; | | 5895 | p->encoding = AUDIO_ENCODING_ULINEAR; |
5872 | else | | 5896 | else |
5873 | p->encoding = AUDIO_ENCODING_SLINEAR; | | 5897 | p->encoding = AUDIO_ENCODING_SLINEAR; |
5874 | } else if (p->encoding == AUDIO_ENCODING_PCM8) { | | 5898 | } else if (p->encoding == AUDIO_ENCODING_PCM8) { |
5875 | if (p->precision == 8) | | 5899 | if (p->precision == 8) |
5876 | p->encoding = AUDIO_ENCODING_ULINEAR; | | 5900 | p->encoding = AUDIO_ENCODING_ULINEAR; |
5877 | else | | 5901 | else |
5878 | return EINVAL; | | 5902 | return EINVAL; |
5879 | } | | 5903 | } |
5880 | | | 5904 | |
5881 | /* | | 5905 | /* |
5882 | * Convert obsoleted AUDIO_ENCODING_[SU]LINEAR without endianness | | 5906 | * Convert obsoleted AUDIO_ENCODING_[SU]LINEAR without endianness |
5883 | * suffix. | | 5907 | * suffix. |
5884 | */ | | 5908 | */ |
5885 | if (p->encoding == AUDIO_ENCODING_SLINEAR) | | 5909 | if (p->encoding == AUDIO_ENCODING_SLINEAR) |
5886 | p->encoding = AUDIO_ENCODING_SLINEAR_NE; | | 5910 | p->encoding = AUDIO_ENCODING_SLINEAR_NE; |
5887 | if (p->encoding == AUDIO_ENCODING_ULINEAR) | | 5911 | if (p->encoding == AUDIO_ENCODING_ULINEAR) |
5888 | p->encoding = AUDIO_ENCODING_ULINEAR_NE; | | 5912 | p->encoding = AUDIO_ENCODING_ULINEAR_NE; |
5889 | | | 5913 | |
5890 | switch (p->encoding) { | | 5914 | switch (p->encoding) { |
5891 | case AUDIO_ENCODING_ULAW: | | 5915 | case AUDIO_ENCODING_ULAW: |
5892 | case AUDIO_ENCODING_ALAW: | | 5916 | case AUDIO_ENCODING_ALAW: |
5893 | if (p->precision != 8) | | 5917 | if (p->precision != 8) |
5894 | return EINVAL; | | 5918 | return EINVAL; |
5895 | break; | | 5919 | break; |
5896 | case AUDIO_ENCODING_ADPCM: | | 5920 | case AUDIO_ENCODING_ADPCM: |
5897 | if (p->precision != 4 && p->precision != 8) | | 5921 | if (p->precision != 4 && p->precision != 8) |
5898 | return EINVAL; | | 5922 | return EINVAL; |
5899 | break; | | 5923 | break; |
5900 | case AUDIO_ENCODING_SLINEAR_LE: | | 5924 | case AUDIO_ENCODING_SLINEAR_LE: |
5901 | case AUDIO_ENCODING_SLINEAR_BE: | | 5925 | case AUDIO_ENCODING_SLINEAR_BE: |
5902 | case AUDIO_ENCODING_ULINEAR_LE: | | 5926 | case AUDIO_ENCODING_ULINEAR_LE: |
5903 | case AUDIO_ENCODING_ULINEAR_BE: | | 5927 | case AUDIO_ENCODING_ULINEAR_BE: |
5904 | if (p->precision != 8 && p->precision != 16 && | | 5928 | if (p->precision != 8 && p->precision != 16 && |
5905 | p->precision != 24 && p->precision != 32) | | 5929 | p->precision != 24 && p->precision != 32) |
5906 | return EINVAL; | | 5930 | return EINVAL; |
5907 | | | 5931 | |
5908 | /* 8bit format does not have endianness. */ | | 5932 | /* 8bit format does not have endianness. */ |
5909 | if (p->precision == 8) { | | 5933 | if (p->precision == 8) { |
5910 | if (p->encoding == AUDIO_ENCODING_SLINEAR_OE) | | 5934 | if (p->encoding == AUDIO_ENCODING_SLINEAR_OE) |
5911 | p->encoding = AUDIO_ENCODING_SLINEAR_NE; | | 5935 | p->encoding = AUDIO_ENCODING_SLINEAR_NE; |
5912 | if (p->encoding == AUDIO_ENCODING_ULINEAR_OE) | | 5936 | if (p->encoding == AUDIO_ENCODING_ULINEAR_OE) |
5913 | p->encoding = AUDIO_ENCODING_ULINEAR_NE; | | 5937 | p->encoding = AUDIO_ENCODING_ULINEAR_NE; |
5914 | } | | 5938 | } |
5915 | | | 5939 | |
5916 | if (p->precision > p->stride) | | 5940 | if (p->precision > p->stride) |
5917 | return EINVAL; | | 5941 | return EINVAL; |
5918 | break; | | 5942 | break; |
5919 | case AUDIO_ENCODING_MPEG_L1_STREAM: | | 5943 | case AUDIO_ENCODING_MPEG_L1_STREAM: |
5920 | case AUDIO_ENCODING_MPEG_L1_PACKETS: | | 5944 | case AUDIO_ENCODING_MPEG_L1_PACKETS: |
5921 | case AUDIO_ENCODING_MPEG_L1_SYSTEM: | | 5945 | case AUDIO_ENCODING_MPEG_L1_SYSTEM: |
5922 | case AUDIO_ENCODING_MPEG_L2_STREAM: | | 5946 | case AUDIO_ENCODING_MPEG_L2_STREAM: |
5923 | case AUDIO_ENCODING_MPEG_L2_PACKETS: | | 5947 | case AUDIO_ENCODING_MPEG_L2_PACKETS: |
5924 | case AUDIO_ENCODING_MPEG_L2_SYSTEM: | | 5948 | case AUDIO_ENCODING_MPEG_L2_SYSTEM: |
5925 | case AUDIO_ENCODING_AC3: | | 5949 | case AUDIO_ENCODING_AC3: |
5926 | break; | | 5950 | break; |
5927 | default: | | 5951 | default: |
5928 | return EINVAL; | | 5952 | return EINVAL; |
5929 | } | | 5953 | } |
5930 | | | 5954 | |
5931 | /* sanity check # of channels*/ | | 5955 | /* sanity check # of channels*/ |
5932 | if (p->channels < 1 || p->channels > AUDIO_MAX_CHANNELS) | | 5956 | if (p->channels < 1 || p->channels > AUDIO_MAX_CHANNELS) |
5933 | return EINVAL; | | 5957 | return EINVAL; |
5934 | | | 5958 | |
5935 | return 0; | | 5959 | return 0; |
5936 | } | | 5960 | } |
5937 | | | 5961 | |
5938 | /* | | 5962 | /* |
5939 | * Initialize playback and record mixers. | | 5963 | * Initialize playback and record mixers. |
5940 | * mode (AUMODE_{PLAY,RECORD}) indicates the mixer to be initalized. | | 5964 | * mode (AUMODE_{PLAY,RECORD}) indicates the mixer to be initalized. |
5941 | * phwfmt and rhwfmt indicate the hardware format. pfil and rfil indicate | | 5965 | * phwfmt and rhwfmt indicate the hardware format. pfil and rfil indicate |
5942 | * the filter registration information. These four must not be NULL. | | 5966 | * the filter registration information. These four must not be NULL. |
5943 | * If successful returns 0. Otherwise returns errno. | | 5967 | * If successful returns 0. Otherwise returns errno. |
5944 | * Must be called with sc_lock held. | | 5968 | * Must be called with sc_lock held. |
5945 | * Must not be called if there are any tracks. | | 5969 | * Must not be called if there are any tracks. |
5946 | * Caller should check that the initialization succeed by whether | | 5970 | * Caller should check that the initialization succeed by whether |
5947 | * sc_[pr]mixer is not NULL. | | 5971 | * sc_[pr]mixer is not NULL. |
5948 | */ | | 5972 | */ |
5949 | static int | | 5973 | static int |
5950 | audio_mixers_init(struct audio_softc *sc, int mode, | | 5974 | audio_mixers_init(struct audio_softc *sc, int mode, |
5951 | const audio_format2_t *phwfmt, const audio_format2_t *rhwfmt, | | 5975 | const audio_format2_t *phwfmt, const audio_format2_t *rhwfmt, |
5952 | const audio_filter_reg_t *pfil, const audio_filter_reg_t *rfil) | | 5976 | const audio_filter_reg_t *pfil, const audio_filter_reg_t *rfil) |
5953 | { | | 5977 | { |
5954 | int error; | | 5978 | int error; |
5955 | | | 5979 | |
5956 | KASSERT(phwfmt != NULL); | | 5980 | KASSERT(phwfmt != NULL); |
5957 | KASSERT(rhwfmt != NULL); | | 5981 | KASSERT(rhwfmt != NULL); |
5958 | KASSERT(pfil != NULL); | | 5982 | KASSERT(pfil != NULL); |
5959 | KASSERT(rfil != NULL); | | 5983 | KASSERT(rfil != NULL); |
5960 | KASSERT(mutex_owned(sc->sc_lock)); | | 5984 | KASSERT(mutex_owned(sc->sc_lock)); |
5961 | | | 5985 | |
5962 | if ((mode & AUMODE_PLAY)) { | | 5986 | if ((mode & AUMODE_PLAY)) { |
5963 | if (sc->sc_pmixer == NULL) { | | 5987 | if (sc->sc_pmixer == NULL) { |
5964 | sc->sc_pmixer = kmem_zalloc(sizeof(*sc->sc_pmixer), | | 5988 | sc->sc_pmixer = kmem_zalloc(sizeof(*sc->sc_pmixer), |
5965 | KM_SLEEP); | | 5989 | KM_SLEEP); |
5966 | } else { | | 5990 | } else { |
5967 | /* destroy() doesn't free memory. */ | | 5991 | /* destroy() doesn't free memory. */ |
5968 | audio_mixer_destroy(sc, sc->sc_pmixer); | | 5992 | audio_mixer_destroy(sc, sc->sc_pmixer); |
5969 | memset(sc->sc_pmixer, 0, sizeof(*sc->sc_pmixer)); | | 5993 | memset(sc->sc_pmixer, 0, sizeof(*sc->sc_pmixer)); |
5970 | } | | 5994 | } |
5971 | error = audio_mixer_init(sc, AUMODE_PLAY, phwfmt, pfil); | | 5995 | error = audio_mixer_init(sc, AUMODE_PLAY, phwfmt, pfil); |
5972 | if (error) { | | 5996 | if (error) { |
5973 | aprint_error_dev(sc->sc_dev, | | 5997 | aprint_error_dev(sc->sc_dev, |
5974 | "configuring playback mode failed\n"); | | 5998 | "configuring playback mode failed\n"); |
5975 | kmem_free(sc->sc_pmixer, sizeof(*sc->sc_pmixer)); | | 5999 | kmem_free(sc->sc_pmixer, sizeof(*sc->sc_pmixer)); |
5976 | sc->sc_pmixer = NULL; | | 6000 | sc->sc_pmixer = NULL; |
5977 | return error; | | 6001 | return error; |
5978 | } | | 6002 | } |
5979 | } | | 6003 | } |
5980 | if ((mode & AUMODE_RECORD)) { | | 6004 | if ((mode & AUMODE_RECORD)) { |
5981 | if (sc->sc_rmixer == NULL) { | | 6005 | if (sc->sc_rmixer == NULL) { |
5982 | sc->sc_rmixer = kmem_zalloc(sizeof(*sc->sc_rmixer), | | 6006 | sc->sc_rmixer = kmem_zalloc(sizeof(*sc->sc_rmixer), |
5983 | KM_SLEEP); | | 6007 | KM_SLEEP); |
5984 | } else { | | 6008 | } else { |
5985 | /* destroy() doesn't free memory. */ | | 6009 | /* destroy() doesn't free memory. */ |
5986 | audio_mixer_destroy(sc, sc->sc_rmixer); | | 6010 | audio_mixer_destroy(sc, sc->sc_rmixer); |
5987 | memset(sc->sc_rmixer, 0, sizeof(*sc->sc_rmixer)); | | 6011 | memset(sc->sc_rmixer, 0, sizeof(*sc->sc_rmixer)); |
5988 | } | | 6012 | } |
5989 | error = audio_mixer_init(sc, AUMODE_RECORD, rhwfmt, rfil); | | 6013 | error = audio_mixer_init(sc, AUMODE_RECORD, rhwfmt, rfil); |
5990 | if (error) { | | 6014 | if (error) { |
5991 | aprint_error_dev(sc->sc_dev, | | 6015 | aprint_error_dev(sc->sc_dev, |
5992 | "configuring record mode failed\n"); | | 6016 | "configuring record mode failed\n"); |
5993 | kmem_free(sc->sc_rmixer, sizeof(*sc->sc_rmixer)); | | 6017 | kmem_free(sc->sc_rmixer, sizeof(*sc->sc_rmixer)); |
5994 | sc->sc_rmixer = NULL; | | 6018 | sc->sc_rmixer = NULL; |
5995 | return error; | | 6019 | return error; |
5996 | } | | 6020 | } |
5997 | } | | 6021 | } |
5998 | | | 6022 | |
5999 | return 0; | | 6023 | return 0; |
6000 | } | | 6024 | } |
6001 | | | 6025 | |
6002 | /* | | 6026 | /* |
6003 | * Select a frequency. | | 6027 | * Select a frequency. |
6004 | * Prioritize 48kHz and 44.1kHz. Otherwise choose the highest one. | | 6028 | * Prioritize 48kHz and 44.1kHz. Otherwise choose the highest one. |
6005 | * XXX Better algorithm? | | 6029 | * XXX Better algorithm? |
6006 | */ | | 6030 | */ |
6007 | static int | | 6031 | static int |
6008 | audio_select_freq(const struct audio_format *fmt) | | 6032 | audio_select_freq(const struct audio_format *fmt) |
6009 | { | | 6033 | { |
6010 | int freq; | | 6034 | int freq; |
6011 | int high; | | 6035 | int high; |
6012 | int low; | | 6036 | int low; |
6013 | int j; | | 6037 | int j; |
6014 | | | 6038 | |
6015 | if (fmt->frequency_type == 0) { | | 6039 | if (fmt->frequency_type == 0) { |
6016 | low = fmt->frequency[0]; | | 6040 | low = fmt->frequency[0]; |
6017 | high = fmt->frequency[1]; | | 6041 | high = fmt->frequency[1]; |
6018 | freq = 48000; | | 6042 | freq = 48000; |
6019 | if (low <= freq && freq <= high) { | | 6043 | if (low <= freq && freq <= high) { |
6020 | return freq; | | 6044 | return freq; |
6021 | } | | 6045 | } |
6022 | freq = 44100; | | 6046 | freq = 44100; |
6023 | if (low <= freq && freq <= high) { | | 6047 | if (low <= freq && freq <= high) { |
6024 | return freq; | | 6048 | return freq; |
6025 | } | | 6049 | } |
6026 | return high; | | 6050 | return high; |
6027 | } else { | | 6051 | } else { |
6028 | for (j = 0; j < fmt->frequency_type; j++) { | | 6052 | for (j = 0; j < fmt->frequency_type; j++) { |
6029 | if (fmt->frequency[j] == 48000) { | | 6053 | if (fmt->frequency[j] == 48000) { |
6030 | return fmt->frequency[j]; | | 6054 | return fmt->frequency[j]; |
6031 | } | | 6055 | } |
6032 | } | | 6056 | } |
6033 | high = 0; | | 6057 | high = 0; |
6034 | for (j = 0; j < fmt->frequency_type; j++) { | | 6058 | for (j = 0; j < fmt->frequency_type; j++) { |
6035 | if (fmt->frequency[j] == 44100) { | | 6059 | if (fmt->frequency[j] == 44100) { |
6036 | return fmt->frequency[j]; | | 6060 | return fmt->frequency[j]; |
6037 | } | | 6061 | } |
6038 | if (fmt->frequency[j] > high) { | | 6062 | if (fmt->frequency[j] > high) { |
6039 | high = fmt->frequency[j]; | | 6063 | high = fmt->frequency[j]; |
6040 | } | | 6064 | } |
6041 | } | | 6065 | } |
6042 | return high; | | 6066 | return high; |
6043 | } | | 6067 | } |
6044 | } | | 6068 | } |
6045 | | | 6069 | |
6046 | /* | | 6070 | /* |
6047 | * Probe playback and/or recording format (depending on *modep). | | 6071 | * Probe playback and/or recording format (depending on *modep). |
6048 | * *modep is an in-out parameter. It indicates the direction to configure | | 6072 | * *modep is an in-out parameter. It indicates the direction to configure |
6049 | * as an argument, and the direction configured is written back as out | | 6073 | * as an argument, and the direction configured is written back as out |
6050 | * parameter. | | 6074 | * parameter. |
6051 | * If successful, probed hardware format is stored into *phwfmt, *rhwfmt | | 6075 | * If successful, probed hardware format is stored into *phwfmt, *rhwfmt |
6052 | * depending on *modep, and return 0. Otherwise it returns errno. | | 6076 | * depending on *modep, and return 0. Otherwise it returns errno. |
6053 | * Must be called with sc_lock held. | | 6077 | * Must be called with sc_lock held. |
6054 | */ | | 6078 | */ |
6055 | static int | | 6079 | static int |
6056 | audio_hw_probe(struct audio_softc *sc, int is_indep, int *modep, | | 6080 | audio_hw_probe(struct audio_softc *sc, int is_indep, int *modep, |
6057 | audio_format2_t *phwfmt, audio_format2_t *rhwfmt) | | 6081 | audio_format2_t *phwfmt, audio_format2_t *rhwfmt) |
6058 | { | | 6082 | { |
6059 | audio_format2_t fmt; | | 6083 | audio_format2_t fmt; |
6060 | int mode; | | 6084 | int mode; |
6061 | int error = 0; | | 6085 | int error = 0; |
6062 | | | 6086 | |
6063 | KASSERT(mutex_owned(sc->sc_lock)); | | 6087 | KASSERT(mutex_owned(sc->sc_lock)); |
6064 | | | 6088 | |
6065 | mode = *modep; | | 6089 | mode = *modep; |
6066 | KASSERTMSG((mode & (AUMODE_PLAY | AUMODE_RECORD)) != 0, | | 6090 | KASSERTMSG((mode & (AUMODE_PLAY | AUMODE_RECORD)) != 0, |
6067 | "invalid mode = %x", mode); | | 6091 | "invalid mode = %x", mode); |
6068 | | | 6092 | |
6069 | if (is_indep) { | | 6093 | if (is_indep) { |
6070 | int errorp = 0, errorr = 0; | | 6094 | int errorp = 0, errorr = 0; |
6071 | | | 6095 | |
6072 | /* On independent devices, probe separately. */ | | 6096 | /* On independent devices, probe separately. */ |
6073 | if ((mode & AUMODE_PLAY) != 0) { | | 6097 | if ((mode & AUMODE_PLAY) != 0) { |
6074 | errorp = audio_hw_probe_fmt(sc, phwfmt, AUMODE_PLAY); | | 6098 | errorp = audio_hw_probe_fmt(sc, phwfmt, AUMODE_PLAY); |
6075 | if (errorp) | | 6099 | if (errorp) |
6076 | mode &= ~AUMODE_PLAY; | | 6100 | mode &= ~AUMODE_PLAY; |
6077 | } | | 6101 | } |
6078 | if ((mode & AUMODE_RECORD) != 0) { | | 6102 | if ((mode & AUMODE_RECORD) != 0) { |
6079 | errorr = audio_hw_probe_fmt(sc, rhwfmt, AUMODE_RECORD); | | 6103 | errorr = audio_hw_probe_fmt(sc, rhwfmt, AUMODE_RECORD); |
6080 | if (errorr) | | 6104 | if (errorr) |
6081 | mode &= ~AUMODE_RECORD; | | 6105 | mode &= ~AUMODE_RECORD; |
6082 | } | | 6106 | } |
6083 | | | 6107 | |
6084 | /* Return error if both play and record probes failed. */ | | 6108 | /* Return error if both play and record probes failed. */ |
6085 | if (errorp && errorr) | | 6109 | if (errorp && errorr) |
6086 | error = errorp; | | 6110 | error = errorp; |
6087 | } else { | | 6111 | } else { |
6088 | /* On non independent devices, probe simultaneously. */ | | 6112 | /* On non independent devices, probe simultaneously. */ |
6089 | error = audio_hw_probe_fmt(sc, &fmt, mode); | | 6113 | error = audio_hw_probe_fmt(sc, &fmt, mode); |
6090 | if (error) { | | 6114 | if (error) { |
6091 | mode = 0; | | 6115 | mode = 0; |
6092 | } else { | | 6116 | } else { |
6093 | *phwfmt = fmt; | | 6117 | *phwfmt = fmt; |
6094 | *rhwfmt = fmt; | | 6118 | *rhwfmt = fmt; |
6095 | } | | 6119 | } |
6096 | } | | 6120 | } |
6097 | | | 6121 | |
6098 | *modep = mode; | | 6122 | *modep = mode; |
6099 | return error; | | 6123 | return error; |
6100 | } | | 6124 | } |
6101 | | | 6125 | |
6102 | /* | | 6126 | /* |
6103 | * Choose the most preferred hardware format. | | 6127 | * Choose the most preferred hardware format. |
6104 | * If successful, it will store the chosen format into *cand and return 0. | | 6128 | * If successful, it will store the chosen format into *cand and return 0. |
6105 | * Otherwise, return errno. | | 6129 | * Otherwise, return errno. |
6106 | * Must be called with sc_lock held. | | 6130 | * Must be called with sc_lock held. |
6107 | */ | | 6131 | */ |
6108 | static int | | 6132 | static int |
6109 | audio_hw_probe_fmt(struct audio_softc *sc, audio_format2_t *cand, int mode) | | 6133 | audio_hw_probe_fmt(struct audio_softc *sc, audio_format2_t *cand, int mode) |
6110 | { | | 6134 | { |
6111 | audio_format_query_t query; | | 6135 | audio_format_query_t query; |
6112 | int cand_score; | | 6136 | int cand_score; |
6113 | int score; | | 6137 | int score; |
6114 | int i; | | 6138 | int i; |
6115 | int error; | | 6139 | int error; |
6116 | | | 6140 | |
6117 | KASSERT(mutex_owned(sc->sc_lock)); | | 6141 | KASSERT(mutex_owned(sc->sc_lock)); |
6118 | | | 6142 | |
6119 | /* | | 6143 | /* |
6120 | * Score each formats and choose the highest one. | | 6144 | * Score each formats and choose the highest one. |
6121 | * | | 6145 | * |
6122 | * +---- priority(0-3) | | 6146 | * +---- priority(0-3) |
6123 | * |+--- encoding/precision | | 6147 | * |+--- encoding/precision |
6124 | * ||+-- channels | | 6148 | * ||+-- channels |
6125 | * score = 0x000000PEC | | 6149 | * score = 0x000000PEC |
6126 | */ | | 6150 | */ |
6127 | | | 6151 | |
6128 | cand_score = 0; | | 6152 | cand_score = 0; |
6129 | for (i = 0; ; i++) { | | 6153 | for (i = 0; ; i++) { |
6130 | memset(&query, 0, sizeof(query)); | | 6154 | memset(&query, 0, sizeof(query)); |
6131 | query.index = i; | | 6155 | query.index = i; |
6132 | | | 6156 | |
6133 | error = sc->hw_if->query_format(sc->hw_hdl, &query); | | 6157 | error = sc->hw_if->query_format(sc->hw_hdl, &query); |
6134 | if (error == EINVAL) | | 6158 | if (error == EINVAL) |
6135 | break; | | 6159 | break; |
6136 | if (error) | | 6160 | if (error) |
6137 | return error; | | 6161 | return error; |
6138 | | | 6162 | |
6139 | #if defined(AUDIO_DEBUG) | | 6163 | #if defined(AUDIO_DEBUG) |
6140 | DPRINTF(1, "fmt[%d] %c%c pri=%d %s,%d/%dbit,%dch,", i, | | 6164 | DPRINTF(1, "fmt[%d] %c%c pri=%d %s,%d/%dbit,%dch,", i, |
6141 | (query.fmt.mode & AUMODE_PLAY) ? 'P' : '-', | | 6165 | (query.fmt.mode & AUMODE_PLAY) ? 'P' : '-', |
6142 | (query.fmt.mode & AUMODE_RECORD) ? 'R' : '-', | | 6166 | (query.fmt.mode & AUMODE_RECORD) ? 'R' : '-', |
6143 | query.fmt.priority, | | 6167 | query.fmt.priority, |
6144 | audio_encoding_name(query.fmt.encoding), | | 6168 | audio_encoding_name(query.fmt.encoding), |
6145 | query.fmt.validbits, | | 6169 | query.fmt.validbits, |
6146 | query.fmt.precision, | | 6170 | query.fmt.precision, |
6147 | query.fmt.channels); | | 6171 | query.fmt.channels); |
6148 | if (query.fmt.frequency_type == 0) { | | 6172 | if (query.fmt.frequency_type == 0) { |
6149 | DPRINTF(1, "{%d-%d", | | 6173 | DPRINTF(1, "{%d-%d", |
6150 | query.fmt.frequency[0], query.fmt.frequency[1]); | | 6174 | query.fmt.frequency[0], query.fmt.frequency[1]); |
6151 | } else { | | 6175 | } else { |
6152 | int j; | | 6176 | int j; |
6153 | for (j = 0; j < query.fmt.frequency_type; j++) { | | 6177 | for (j = 0; j < query.fmt.frequency_type; j++) { |
6154 | DPRINTF(1, "%c%d", | | 6178 | DPRINTF(1, "%c%d", |
6155 | (j == 0) ? '{' : ',', | | 6179 | (j == 0) ? '{' : ',', |
6156 | query.fmt.frequency[j]); | | 6180 | query.fmt.frequency[j]); |
6157 | } | | 6181 | } |
6158 | } | | 6182 | } |
6159 | DPRINTF(1, "}\n"); | | 6183 | DPRINTF(1, "}\n"); |
6160 | #endif | | 6184 | #endif |
6161 | | | 6185 | |
6162 | if ((query.fmt.mode & mode) == 0) { | | 6186 | if ((query.fmt.mode & mode) == 0) { |
6163 | DPRINTF(1, "fmt[%d] skip; mode not match %d\n", i, | | 6187 | DPRINTF(1, "fmt[%d] skip; mode not match %d\n", i, |
6164 | mode); | | 6188 | mode); |
6165 | continue; | | 6189 | continue; |
6166 | } | | 6190 | } |
6167 | | | 6191 | |
6168 | if (query.fmt.priority < 0) { | | 6192 | if (query.fmt.priority < 0) { |
6169 | DPRINTF(1, "fmt[%d] skip; unsupported encoding\n", i); | | 6193 | DPRINTF(1, "fmt[%d] skip; unsupported encoding\n", i); |
6170 | continue; | | 6194 | continue; |
6171 | } | | 6195 | } |
6172 | | | 6196 | |
6173 | /* Score */ | | 6197 | /* Score */ |
6174 | score = (query.fmt.priority & 3) * 0x100; | | 6198 | score = (query.fmt.priority & 3) * 0x100; |
6175 | if (query.fmt.encoding == AUDIO_ENCODING_SLINEAR_NE && | | 6199 | if (query.fmt.encoding == AUDIO_ENCODING_SLINEAR_NE && |
6176 | query.fmt.validbits == AUDIO_INTERNAL_BITS && | | 6200 | query.fmt.validbits == AUDIO_INTERNAL_BITS && |
6177 | query.fmt.precision == AUDIO_INTERNAL_BITS) { | | 6201 | query.fmt.precision == AUDIO_INTERNAL_BITS) { |
6178 | score += 0x20; | | 6202 | score += 0x20; |
6179 | } else if (query.fmt.encoding == AUDIO_ENCODING_SLINEAR_OE && | | 6203 | } else if (query.fmt.encoding == AUDIO_ENCODING_SLINEAR_OE && |
6180 | query.fmt.validbits == AUDIO_INTERNAL_BITS && | | 6204 | query.fmt.validbits == AUDIO_INTERNAL_BITS && |
6181 | query.fmt.precision == AUDIO_INTERNAL_BITS) { | | 6205 | query.fmt.precision == AUDIO_INTERNAL_BITS) { |
6182 | score += 0x10; | | 6206 | score += 0x10; |
6183 | } | | 6207 | } |
6184 | score += query.fmt.channels; | | 6208 | score += query.fmt.channels; |
6185 | | | 6209 | |
6186 | if (score < cand_score) { | | 6210 | if (score < cand_score) { |
6187 | DPRINTF(1, "fmt[%d] skip; score 0x%x < 0x%x\n", i, | | 6211 | DPRINTF(1, "fmt[%d] skip; score 0x%x < 0x%x\n", i, |
6188 | score, cand_score); | | 6212 | score, cand_score); |
6189 | continue; | | 6213 | continue; |
6190 | } | | 6214 | } |
6191 | | | 6215 | |
6192 | /* Update candidate */ | | 6216 | /* Update candidate */ |
6193 | cand_score = score; | | 6217 | cand_score = score; |
6194 | cand->encoding = query.fmt.encoding; | | 6218 | cand->encoding = query.fmt.encoding; |
6195 | cand->precision = query.fmt.validbits; | | 6219 | cand->precision = query.fmt.validbits; |
6196 | cand->stride = query.fmt.precision; | | 6220 | cand->stride = query.fmt.precision; |
6197 | cand->channels = query.fmt.channels; | | 6221 | cand->channels = query.fmt.channels; |
6198 | cand->sample_rate = audio_select_freq(&query.fmt); | | 6222 | cand->sample_rate = audio_select_freq(&query.fmt); |
6199 | DPRINTF(1, "fmt[%d] candidate (score=0x%x)" | | 6223 | DPRINTF(1, "fmt[%d] candidate (score=0x%x)" |
6200 | " pri=%d %s,%d/%d,%dch,%dHz\n", i, | | 6224 | " pri=%d %s,%d/%d,%dch,%dHz\n", i, |
6201 | cand_score, query.fmt.priority, | | 6225 | cand_score, query.fmt.priority, |
6202 | audio_encoding_name(query.fmt.encoding), | | 6226 | audio_encoding_name(query.fmt.encoding), |
6203 | cand->precision, cand->stride, | | 6227 | cand->precision, cand->stride, |
6204 | cand->channels, cand->sample_rate); | | 6228 | cand->channels, cand->sample_rate); |
6205 | } | | 6229 | } |
6206 | | | 6230 | |
6207 | if (cand_score == 0) { | | 6231 | if (cand_score == 0) { |
6208 | DPRINTF(1, "%s no fmt\n", __func__); | | 6232 | DPRINTF(1, "%s no fmt\n", __func__); |
6209 | return ENXIO; | | 6233 | return ENXIO; |
6210 | } | | 6234 | } |
6211 | DPRINTF(1, "%s selected: %s,%d/%d,%dch,%dHz\n", __func__, | | 6235 | DPRINTF(1, "%s selected: %s,%d/%d,%dch,%dHz\n", __func__, |
6212 | audio_encoding_name(cand->encoding), | | 6236 | audio_encoding_name(cand->encoding), |
6213 | cand->precision, cand->stride, cand->channels, cand->sample_rate); | | 6237 | cand->precision, cand->stride, cand->channels, cand->sample_rate); |
6214 | return 0; | | 6238 | return 0; |
6215 | } | | 6239 | } |
6216 | | | 6240 | |
6217 | /* | | 6241 | /* |
6218 | * Validate fmt with query_format. | | 6242 | * Validate fmt with query_format. |
6219 | * If fmt is included in the result of query_format, returns 0. | | 6243 | * If fmt is included in the result of query_format, returns 0. |
6220 | * Otherwise returns EINVAL. | | 6244 | * Otherwise returns EINVAL. |
6221 | * Must be called with sc_lock held. | | 6245 | * Must be called with sc_lock held. |
6222 | */ | | 6246 | */ |
6223 | static int | | 6247 | static int |
6224 | audio_hw_validate_format(struct audio_softc *sc, int mode, | | 6248 | audio_hw_validate_format(struct audio_softc *sc, int mode, |
6225 | const audio_format2_t *fmt) | | 6249 | const audio_format2_t *fmt) |
6226 | { | | 6250 | { |
6227 | audio_format_query_t query; | | 6251 | audio_format_query_t query; |
6228 | struct audio_format *q; | | 6252 | struct audio_format *q; |
6229 | int index; | | 6253 | int index; |
6230 | int error; | | 6254 | int error; |
6231 | int j; | | 6255 | int j; |
6232 | | | 6256 | |
6233 | KASSERT(mutex_owned(sc->sc_lock)); | | 6257 | KASSERT(mutex_owned(sc->sc_lock)); |
6234 | | | 6258 | |
6235 | /* | | 6259 | /* |
6236 | * If query_format is not supported by hardware driver, | | 6260 | * If query_format is not supported by hardware driver, |
6237 | * a rough check instead will be performed. | | 6261 | * a rough check instead will be performed. |
6238 | * XXX This will gone in the future. | | 6262 | * XXX This will gone in the future. |
6239 | */ | | 6263 | */ |
6240 | if (sc->hw_if->query_format == NULL) { | | 6264 | if (sc->hw_if->query_format == NULL) { |
6241 | if (fmt->encoding != AUDIO_ENCODING_SLINEAR_NE) | | 6265 | if (fmt->encoding != AUDIO_ENCODING_SLINEAR_NE) |
6242 | return EINVAL; | | 6266 | return EINVAL; |
6243 | if (fmt->precision != AUDIO_INTERNAL_BITS) | | 6267 | if (fmt->precision != AUDIO_INTERNAL_BITS) |
6244 | return EINVAL; | | 6268 | return EINVAL; |
6245 | if (fmt->stride != AUDIO_INTERNAL_BITS) | | 6269 | if (fmt->stride != AUDIO_INTERNAL_BITS) |
6246 | return EINVAL; | | 6270 | return EINVAL; |
6247 | return 0; | | 6271 | return 0; |
6248 | } | | 6272 | } |
6249 | | | 6273 | |
6250 | for (index = 0; ; index++) { | | 6274 | for (index = 0; ; index++) { |
6251 | query.index = index; | | 6275 | query.index = index; |
6252 | error = sc->hw_if->query_format(sc->hw_hdl, &query); | | 6276 | error = sc->hw_if->query_format(sc->hw_hdl, &query); |
6253 | if (error == EINVAL) | | 6277 | if (error == EINVAL) |
6254 | break; | | 6278 | break; |
6255 | if (error) | | 6279 | if (error) |
6256 | return error; | | 6280 | return error; |
6257 | | | 6281 | |
6258 | q = &query.fmt; | | 6282 | q = &query.fmt; |
6259 | /* | | 6283 | /* |
6260 | * Note that fmt is audio_format2_t (precision/stride) but | | 6284 | * Note that fmt is audio_format2_t (precision/stride) but |
6261 | * q is audio_format_t (validbits/precision). | | 6285 | * q is audio_format_t (validbits/precision). |
6262 | */ | | 6286 | */ |
6263 | if ((q->mode & mode) == 0) { | | 6287 | if ((q->mode & mode) == 0) { |
6264 | continue; | | 6288 | continue; |
6265 | } | | 6289 | } |
6266 | if (fmt->encoding != q->encoding) { | | 6290 | if (fmt->encoding != q->encoding) { |
6267 | continue; | | 6291 | continue; |
6268 | } | | 6292 | } |
6269 | if (fmt->precision != q->validbits) { | | 6293 | if (fmt->precision != q->validbits) { |
6270 | continue; | | 6294 | continue; |
6271 | } | | 6295 | } |
6272 | if (fmt->stride != q->precision) { | | 6296 | if (fmt->stride != q->precision) { |
6273 | continue; | | 6297 | continue; |
6274 | } | | 6298 | } |
6275 | if (fmt->channels != q->channels) { | | 6299 | if (fmt->channels != q->channels) { |
6276 | continue; | | 6300 | continue; |
6277 | } | | 6301 | } |
6278 | if (q->frequency_type == 0) { | | 6302 | if (q->frequency_type == 0) { |
6279 | if (fmt->sample_rate < q->frequency[0] || | | 6303 | if (fmt->sample_rate < q->frequency[0] || |
6280 | fmt->sample_rate > q->frequency[1]) { | | 6304 | fmt->sample_rate > q->frequency[1]) { |
6281 | continue; | | 6305 | continue; |
6282 | } | | 6306 | } |
6283 | } else { | | 6307 | } else { |
6284 | for (j = 0; j < q->frequency_type; j++) { | | 6308 | for (j = 0; j < q->frequency_type; j++) { |
6285 | if (fmt->sample_rate == q->frequency[j]) | | 6309 | if (fmt->sample_rate == q->frequency[j]) |
6286 | break; | | 6310 | break; |
6287 | } | | 6311 | } |
6288 | if (j == query.fmt.frequency_type) { | | 6312 | if (j == query.fmt.frequency_type) { |
6289 | continue; | | 6313 | continue; |
6290 | } | | 6314 | } |
6291 | } | | 6315 | } |
6292 | | | 6316 | |
6293 | /* Matched. */ | | 6317 | /* Matched. */ |
6294 | return 0; | | 6318 | return 0; |
6295 | } | | 6319 | } |
6296 | | | 6320 | |
6297 | return EINVAL; | | 6321 | return EINVAL; |
6298 | } | | 6322 | } |
6299 | | | 6323 | |
6300 | /* | | 6324 | /* |
6301 | * Set track mixer's format depending on ai->mode. | | 6325 | * Set track mixer's format depending on ai->mode. |
6302 | * If AUMODE_PLAY is set in ai->mode, it set up the playback mixer | | 6326 | * If AUMODE_PLAY is set in ai->mode, it set up the playback mixer |
6303 | * with ai.play.{channels, sample_rate}. | | 6327 | * with ai.play.{channels, sample_rate}. |
6304 | * If AUMODE_RECORD is set in ai->mode, it set up the recording mixer | | 6328 | * If AUMODE_RECORD is set in ai->mode, it set up the recording mixer |
6305 | * with ai.record.{channels, sample_rate}. | | 6329 | * with ai.record.{channels, sample_rate}. |
6306 | * All other fields in ai are ignored. | | 6330 | * All other fields in ai are ignored. |
6307 | * If successful returns 0. Otherwise returns errno. | | 6331 | * If successful returns 0. Otherwise returns errno. |
6308 | * This function does not roll back even if it fails. | | 6332 | * This function does not roll back even if it fails. |
6309 | * Must be called with sc_lock held. | | 6333 | * Must be called with sc_lock held. |
6310 | */ | | 6334 | */ |
6311 | static int | | 6335 | static int |
6312 | audio_mixers_set_format(struct audio_softc *sc, const struct audio_info *ai) | | 6336 | audio_mixers_set_format(struct audio_softc *sc, const struct audio_info *ai) |
6313 | { | | 6337 | { |
6314 | audio_format2_t phwfmt; | | 6338 | audio_format2_t phwfmt; |
6315 | audio_format2_t rhwfmt; | | 6339 | audio_format2_t rhwfmt; |
6316 | audio_filter_reg_t pfil; | | 6340 | audio_filter_reg_t pfil; |
6317 | audio_filter_reg_t rfil; | | 6341 | audio_filter_reg_t rfil; |
6318 | int mode; | | 6342 | int mode; |
6319 | int error; | | 6343 | int error; |
6320 | | | 6344 | |
6321 | KASSERT(mutex_owned(sc->sc_lock)); | | 6345 | KASSERT(mutex_owned(sc->sc_lock)); |
6322 | | | 6346 | |
6323 | /* | | 6347 | /* |
6324 | * Even when setting either one of playback and recording, | | 6348 | * Even when setting either one of playback and recording, |
6325 | * both must be halted. | | 6349 | * both must be halted. |
6326 | */ | | 6350 | */ |
6327 | if (sc->sc_popens + sc->sc_ropens > 0) | | 6351 | if (sc->sc_popens + sc->sc_ropens > 0) |
6328 | return EBUSY; | | 6352 | return EBUSY; |
6329 | | | 6353 | |
6330 | if (!SPECIFIED(ai->mode) || ai->mode == 0) | | 6354 | if (!SPECIFIED(ai->mode) || ai->mode == 0) |
6331 | return ENOTTY; | | 6355 | return ENOTTY; |
6332 | | | 6356 | |
6333 | /* Only channels and sample_rate are changeable. */ | | 6357 | /* Only channels and sample_rate are changeable. */ |
6334 | mode = ai->mode; | | 6358 | mode = ai->mode; |
6335 | if ((mode & AUMODE_PLAY)) { | | 6359 | if ((mode & AUMODE_PLAY)) { |
6336 | phwfmt.encoding = ai->play.encoding; | | 6360 | phwfmt.encoding = ai->play.encoding; |
6337 | phwfmt.precision = ai->play.precision; | | 6361 | phwfmt.precision = ai->play.precision; |
6338 | phwfmt.stride = ai->play.precision; | | 6362 | phwfmt.stride = ai->play.precision; |
6339 | phwfmt.channels = ai->play.channels; | | 6363 | phwfmt.channels = ai->play.channels; |
6340 | phwfmt.sample_rate = ai->play.sample_rate; | | 6364 | phwfmt.sample_rate = ai->play.sample_rate; |
6341 | } | | 6365 | } |
6342 | if ((mode & AUMODE_RECORD)) { | | 6366 | if ((mode & AUMODE_RECORD)) { |
6343 | rhwfmt.encoding = ai->record.encoding; | | 6367 | rhwfmt.encoding = ai->record.encoding; |
6344 | rhwfmt.precision = ai->record.precision; | | 6368 | rhwfmt.precision = ai->record.precision; |
6345 | rhwfmt.stride = ai->record.precision; | | 6369 | rhwfmt.stride = ai->record.precision; |
6346 | rhwfmt.channels = ai->record.channels; | | 6370 | rhwfmt.channels = ai->record.channels; |
6347 | rhwfmt.sample_rate = ai->record.sample_rate; | | 6371 | rhwfmt.sample_rate = ai->record.sample_rate; |
6348 | } | | 6372 | } |
6349 | | | 6373 | |
6350 | /* On non-independent devices, use the same format for both. */ | | 6374 | /* On non-independent devices, use the same format for both. */ |
6351 | if ((sc->sc_props & AUDIO_PROP_INDEPENDENT) == 0) { | | 6375 | if ((sc->sc_props & AUDIO_PROP_INDEPENDENT) == 0) { |
6352 | if (mode == AUMODE_RECORD) { | | 6376 | if (mode == AUMODE_RECORD) { |
6353 | phwfmt = rhwfmt; | | 6377 | phwfmt = rhwfmt; |
6354 | } else { | | 6378 | } else { |
6355 | rhwfmt = phwfmt; | | 6379 | rhwfmt = phwfmt; |
6356 | } | | 6380 | } |
6357 | mode = AUMODE_PLAY | AUMODE_RECORD; | | 6381 | mode = AUMODE_PLAY | AUMODE_RECORD; |
6358 | } | | 6382 | } |
6359 | | | 6383 | |
6360 | /* Then, unset the direction not exist on the hardware. */ | | 6384 | /* Then, unset the direction not exist on the hardware. */ |
6361 | if ((sc->sc_props & AUDIO_PROP_PLAYBACK) == 0) | | 6385 | if ((sc->sc_props & AUDIO_PROP_PLAYBACK) == 0) |
6362 | mode &= ~AUMODE_PLAY; | | 6386 | mode &= ~AUMODE_PLAY; |
6363 | if ((sc->sc_props & AUDIO_PROP_CAPTURE) == 0) | | 6387 | if ((sc->sc_props & AUDIO_PROP_CAPTURE) == 0) |
6364 | mode &= ~AUMODE_RECORD; | | 6388 | mode &= ~AUMODE_RECORD; |
6365 | | | 6389 | |
6366 | /* debug */ | | 6390 | /* debug */ |
6367 | if ((mode & AUMODE_PLAY)) { | | 6391 | if ((mode & AUMODE_PLAY)) { |
6368 | TRACE(1, "play=%s/%d/%d/%dch/%dHz", | | 6392 | TRACE(1, "play=%s/%d/%d/%dch/%dHz", |
6369 | audio_encoding_name(phwfmt.encoding), | | 6393 | audio_encoding_name(phwfmt.encoding), |
6370 | phwfmt.precision, | | 6394 | phwfmt.precision, |
6371 | phwfmt.stride, | | 6395 | phwfmt.stride, |
6372 | phwfmt.channels, | | 6396 | phwfmt.channels, |
6373 | phwfmt.sample_rate); | | 6397 | phwfmt.sample_rate); |
6374 | } | | 6398 | } |
6375 | if ((mode & AUMODE_RECORD)) { | | 6399 | if ((mode & AUMODE_RECORD)) { |
6376 | TRACE(1, "rec =%s/%d/%d/%dch/%dHz", | | 6400 | TRACE(1, "rec =%s/%d/%d/%dch/%dHz", |
6377 | audio_encoding_name(rhwfmt.encoding), | | 6401 | audio_encoding_name(rhwfmt.encoding), |
6378 | rhwfmt.precision, | | 6402 | rhwfmt.precision, |
6379 | rhwfmt.stride, | | 6403 | rhwfmt.stride, |
6380 | rhwfmt.channels, | | 6404 | rhwfmt.channels, |
6381 | rhwfmt.sample_rate); | | 6405 | rhwfmt.sample_rate); |
6382 | } | | 6406 | } |
6383 | | | 6407 | |
6384 | /* Check the format */ | | 6408 | /* Check the format */ |
6385 | if ((mode & AUMODE_PLAY)) { | | 6409 | if ((mode & AUMODE_PLAY)) { |
6386 | if (audio_hw_validate_format(sc, AUMODE_PLAY, &phwfmt)) { | | 6410 | if (audio_hw_validate_format(sc, AUMODE_PLAY, &phwfmt)) { |
6387 | TRACE(1, "invalid format"); | | 6411 | TRACE(1, "invalid format"); |
6388 | return EINVAL; | | 6412 | return EINVAL; |
6389 | } | | 6413 | } |
6390 | } | | 6414 | } |
6391 | if ((mode & AUMODE_RECORD)) { | | 6415 | if ((mode & AUMODE_RECORD)) { |
6392 | if (audio_hw_validate_format(sc, AUMODE_RECORD, &rhwfmt)) { | | 6416 | if (audio_hw_validate_format(sc, AUMODE_RECORD, &rhwfmt)) { |
6393 | TRACE(1, "invalid format"); | | 6417 | TRACE(1, "invalid format"); |
6394 | return EINVAL; | | 6418 | return EINVAL; |
6395 | } | | 6419 | } |
6396 | } | | 6420 | } |
6397 | | | 6421 | |
6398 | /* Configure the mixers. */ | | 6422 | /* Configure the mixers. */ |
6399 | memset(&pfil, 0, sizeof(pfil)); | | 6423 | memset(&pfil, 0, sizeof(pfil)); |
6400 | memset(&rfil, 0, sizeof(rfil)); | | 6424 | memset(&rfil, 0, sizeof(rfil)); |
6401 | error = audio_hw_set_format(sc, mode, &phwfmt, &rhwfmt, &pfil, &rfil); | | 6425 | error = audio_hw_set_format(sc, mode, &phwfmt, &rhwfmt, &pfil, &rfil); |
6402 | if (error) | | 6426 | if (error) |
6403 | return error; | | 6427 | return error; |
6404 | | | 6428 | |
6405 | error = audio_mixers_init(sc, mode, &phwfmt, &rhwfmt, &pfil, &rfil); | | 6429 | error = audio_mixers_init(sc, mode, &phwfmt, &rhwfmt, &pfil, &rfil); |
6406 | if (error) | | 6430 | if (error) |
6407 | return error; | | 6431 | return error; |
6408 | | | 6432 | |
6409 | return 0; | | 6433 | return 0; |
6410 | } | | 6434 | } |
6411 | | | 6435 | |
6412 | /* | | 6436 | /* |
6413 | * Store current mixers format into *ai. | | 6437 | * Store current mixers format into *ai. |
6414 | */ | | 6438 | */ |
6415 | static void | | 6439 | static void |
6416 | audio_mixers_get_format(struct audio_softc *sc, struct audio_info *ai) | | 6440 | audio_mixers_get_format(struct audio_softc *sc, struct audio_info *ai) |
6417 | { | | 6441 | { |
6418 | /* | | 6442 | /* |
6419 | * There is no stride information in audio_info but it doesn't matter. | | 6443 | * There is no stride information in audio_info but it doesn't matter. |
6420 | * trackmixer always treats stride and precision as the same. | | 6444 | * trackmixer always treats stride and precision as the same. |
6421 | */ | | 6445 | */ |
6422 | AUDIO_INITINFO(ai); | | 6446 | AUDIO_INITINFO(ai); |
6423 | ai->mode = 0; | | 6447 | ai->mode = 0; |
6424 | if (sc->sc_pmixer) { | | 6448 | if (sc->sc_pmixer) { |
6425 | audio_format2_t *fmt = &sc->sc_pmixer->track_fmt; | | 6449 | audio_format2_t *fmt = &sc->sc_pmixer->track_fmt; |
6426 | ai->play.encoding = fmt->encoding; | | 6450 | ai->play.encoding = fmt->encoding; |
6427 | ai->play.precision = fmt->precision; | | 6451 | ai->play.precision = fmt->precision; |
6428 | ai->play.channels = fmt->channels; | | 6452 | ai->play.channels = fmt->channels; |
6429 | ai->play.sample_rate = fmt->sample_rate; | | 6453 | ai->play.sample_rate = fmt->sample_rate; |
6430 | ai->mode |= AUMODE_PLAY; | | 6454 | ai->mode |= AUMODE_PLAY; |
6431 | } | | 6455 | } |
6432 | if (sc->sc_rmixer) { | | 6456 | if (sc->sc_rmixer) { |
6433 | audio_format2_t *fmt = &sc->sc_rmixer->track_fmt; | | 6457 | audio_format2_t *fmt = &sc->sc_rmixer->track_fmt; |
6434 | ai->record.encoding = fmt->encoding; | | 6458 | ai->record.encoding = fmt->encoding; |
6435 | ai->record.precision = fmt->precision; | | 6459 | ai->record.precision = fmt->precision; |
6436 | ai->record.channels = fmt->channels; | | 6460 | ai->record.channels = fmt->channels; |
6437 | ai->record.sample_rate = fmt->sample_rate; | | 6461 | ai->record.sample_rate = fmt->sample_rate; |
6438 | ai->mode |= AUMODE_RECORD; | | 6462 | ai->mode |= AUMODE_RECORD; |
6439 | } | | 6463 | } |
6440 | } | | 6464 | } |
6441 | | | 6465 | |
6442 | /* | | 6466 | /* |
6443 | * audio_info details: | | 6467 | * audio_info details: |
6444 | * | | 6468 | * |
6445 | * ai.{play,record}.sample_rate (R/W) | | 6469 | * ai.{play,record}.sample_rate (R/W) |
6446 | * ai.{play,record}.encoding (R/W) | | 6470 | * ai.{play,record}.encoding (R/W) |
6447 | * ai.{play,record}.precision (R/W) | | 6471 | * ai.{play,record}.precision (R/W) |
6448 | * ai.{play,record}.channels (R/W) | | 6472 | * ai.{play,record}.channels (R/W) |
6449 | * These specify the playback or recording format. | | 6473 | * These specify the playback or recording format. |
6450 | * Ignore members within an inactive track. | | 6474 | * Ignore members within an inactive track. |
6451 | * | | 6475 | * |
6452 | * ai.mode (R/W) | | 6476 | * ai.mode (R/W) |
6453 | * It specifies the playback or recording mode, AUMODE_*. | | 6477 | * It specifies the playback or recording mode, AUMODE_*. |
6454 | * Currently, a mode change operation by ai.mode after opening is | | 6478 | * Currently, a mode change operation by ai.mode after opening is |
6455 | * prohibited. In addition, AUMODE_PLAY_ALL no longer makes sense. | | 6479 | * prohibited. In addition, AUMODE_PLAY_ALL no longer makes sense. |
6456 | * However, it's possible to get or to set for backward compatibility. | | 6480 | * However, it's possible to get or to set for backward compatibility. |
6457 | * | | 6481 | * |
6458 | * ai.{hiwat,lowat} (R/W) | | 6482 | * ai.{hiwat,lowat} (R/W) |
6459 | * These specify the high water mark and low water mark for playback | | 6483 | * These specify the high water mark and low water mark for playback |
6460 | * track. The unit is block. | | 6484 | * track. The unit is block. |
6461 | * | | 6485 | * |
6462 | * ai.{play,record}.gain (R/W) | | 6486 | * ai.{play,record}.gain (R/W) |
6463 | * It specifies the HW mixer volume in 0-255. | | 6487 | * It specifies the HW mixer volume in 0-255. |
6464 | * It is historical reason that the gain is connected to HW mixer. | | 6488 | * It is historical reason that the gain is connected to HW mixer. |
6465 | * | | 6489 | * |
6466 | * ai.{play,record}.balance (R/W) | | 6490 | * ai.{play,record}.balance (R/W) |
6467 | * It specifies the left-right balance of HW mixer in 0-64. | | 6491 | * It specifies the left-right balance of HW mixer in 0-64. |
6468 | * 32 means the center. | | 6492 | * 32 means the center. |
6469 | * It is historical reason that the balance is connected to HW mixer. | | 6493 | * It is historical reason that the balance is connected to HW mixer. |
6470 | * | | 6494 | * |
6471 | * ai.{play,record}.port (R/W) | | 6495 | * ai.{play,record}.port (R/W) |
6472 | * It specifies the input/output port of HW mixer. | | 6496 | * It specifies the input/output port of HW mixer. |
6473 | * | | 6497 | * |
6474 | * ai.monitor_gain (R/W) | | 6498 | * ai.monitor_gain (R/W) |
6475 | * It specifies the recording monitor gain(?) of HW mixer. | | 6499 | * It specifies the recording monitor gain(?) of HW mixer. |
6476 | * | | 6500 | * |
6477 | * ai.{play,record}.pause (R/W) | | 6501 | * ai.{play,record}.pause (R/W) |
6478 | * Non-zero means the track is paused. | | 6502 | * Non-zero means the track is paused. |
6479 | * | | 6503 | * |
6480 | * ai.play.seek (R/-) | | 6504 | * ai.play.seek (R/-) |
6481 | * It indicates the number of bytes written but not processed. | | 6505 | * It indicates the number of bytes written but not processed. |
6482 | * ai.record.seek (R/-) | | 6506 | * ai.record.seek (R/-) |
6483 | * It indicates the number of bytes to be able to read. | | 6507 | * It indicates the number of bytes to be able to read. |
6484 | * | | 6508 | * |
6485 | * ai.{play,record}.avail_ports (R/-) | | 6509 | * ai.{play,record}.avail_ports (R/-) |
6486 | * Mixer info. | | 6510 | * Mixer info. |
6487 | * | | 6511 | * |
6488 | * ai.{play,record}.buffer_size (R/-) | | 6512 | * ai.{play,record}.buffer_size (R/-) |
6489 | * It indicates the buffer size in bytes. Internally it means usrbuf. | | 6513 | * It indicates the buffer size in bytes. Internally it means usrbuf. |
6490 | * | | 6514 | * |
6491 | * ai.{play,record}.samples (R/-) | | 6515 | * ai.{play,record}.samples (R/-) |
6492 | * It indicates the total number of bytes played or recorded. | | 6516 | * It indicates the total number of bytes played or recorded. |
6493 | * | | 6517 | * |
6494 | * ai.{play,record}.eof (R/-) | | 6518 | * ai.{play,record}.eof (R/-) |
6495 | * It indicates the number of times reached EOF(?). | | 6519 | * It indicates the number of times reached EOF(?). |
6496 | * | | 6520 | * |
6497 | * ai.{play,record}.error (R/-) | | 6521 | * ai.{play,record}.error (R/-) |
6498 | * Non-zero indicates overflow/underflow has occured. | | 6522 | * Non-zero indicates overflow/underflow has occured. |
6499 | * | | 6523 | * |
6500 | * ai.{play,record}.waiting (R/-) | | 6524 | * ai.{play,record}.waiting (R/-) |
6501 | * Non-zero indicates that other process waits to open. | | 6525 | * Non-zero indicates that other process waits to open. |
6502 | * It will never happen anymore. | | 6526 | * It will never happen anymore. |
6503 | * | | 6527 | * |
6504 | * ai.{play,record}.open (R/-) | | 6528 | * ai.{play,record}.open (R/-) |
6505 | * Non-zero indicates the direction is opened by this process(?). | | 6529 | * Non-zero indicates the direction is opened by this process(?). |
6506 | * XXX Is this better to indicate that "the device is opened by | | 6530 | * XXX Is this better to indicate that "the device is opened by |
6507 | * at least one process"? | | 6531 | * at least one process"? |
6508 | * | | 6532 | * |
6509 | * ai.{play,record}.active (R/-) | | 6533 | * ai.{play,record}.active (R/-) |
6510 | * Non-zero indicates that I/O is currently active. | | 6534 | * Non-zero indicates that I/O is currently active. |
6511 | * | | 6535 | * |
6512 | * ai.blocksize (R/-) | | 6536 | * ai.blocksize (R/-) |
6513 | * It indicates the block size in bytes. | | 6537 | * It indicates the block size in bytes. |
6514 | * XXX The blocksize of playback and recording may be different. | | 6538 | * XXX The blocksize of playback and recording may be different. |
6515 | */ | | 6539 | */ |
6516 | | | 6540 | |
6517 | /* | | 6541 | /* |
6518 | * Pause consideration: | | 6542 | * Pause consideration: |
6519 | * | | 6543 | * |
6520 | * The introduction of these two behavior makes pause/unpause operation | | 6544 | * The introduction of these two behavior makes pause/unpause operation |
6521 | * simple. | | 6545 | * simple. |
6522 | * 1. The first read/write access of the first track makes mixer start. | | 6546 | * 1. The first read/write access of the first track makes mixer start. |
6523 | * 2. A pause of the last track doesn't make mixer stop. | | 6547 | * 2. A pause of the last track doesn't make mixer stop. |
6524 | */ | | 6548 | */ |
6525 | | | 6549 | |
6526 | /* | | 6550 | /* |
6527 | * Set both track's parameters within a file depending on ai. | | 6551 | * Set both track's parameters within a file depending on ai. |
6528 | * Update sc_sound_[pr]* if set. | | 6552 | * Update sc_sound_[pr]* if set. |
6529 | * Must be called with sc_lock and sc_exlock held. | | 6553 | * Must be called with sc_lock and sc_exlock held. |
6530 | */ | | 6554 | */ |
6531 | static int | | 6555 | static int |
6532 | audio_file_setinfo(struct audio_softc *sc, audio_file_t *file, | | 6556 | audio_file_setinfo(struct audio_softc *sc, audio_file_t *file, |
6533 | const struct audio_info *ai) | | 6557 | const struct audio_info *ai) |
6534 | { | | 6558 | { |
6535 | const struct audio_prinfo *pi; | | 6559 | const struct audio_prinfo *pi; |
6536 | const struct audio_prinfo *ri; | | 6560 | const struct audio_prinfo *ri; |
6537 | audio_track_t *ptrack; | | 6561 | audio_track_t *ptrack; |
6538 | audio_track_t *rtrack; | | 6562 | audio_track_t *rtrack; |
6539 | audio_format2_t pfmt; | | 6563 | audio_format2_t pfmt; |
6540 | audio_format2_t rfmt; | | 6564 | audio_format2_t rfmt; |
6541 | int pchanges; | | 6565 | int pchanges; |
6542 | int rchanges; | | 6566 | int rchanges; |
6543 | int mode; | | 6567 | int mode; |
6544 | struct audio_info saved_ai; | | 6568 | struct audio_info saved_ai; |
6545 | audio_format2_t saved_pfmt; | | 6569 | audio_format2_t saved_pfmt; |
6546 | audio_format2_t saved_rfmt; | | 6570 | audio_format2_t saved_rfmt; |
6547 | int error; | | 6571 | int error; |
6548 | | | 6572 | |
6549 | KASSERT(mutex_owned(sc->sc_lock)); | | 6573 | KASSERT(mutex_owned(sc->sc_lock)); |
6550 | KASSERT(sc->sc_exlock); | | 6574 | KASSERT(sc->sc_exlock); |
6551 | | | 6575 | |
6552 | pi = &ai->play; | | 6576 | pi = &ai->play; |
6553 | ri = &ai->record; | | 6577 | ri = &ai->record; |
6554 | pchanges = 0; | | 6578 | pchanges = 0; |
6555 | rchanges = 0; | | 6579 | rchanges = 0; |
6556 | | | 6580 | |
6557 | ptrack = file->ptrack; | | 6581 | ptrack = file->ptrack; |
6558 | rtrack = file->rtrack; | | 6582 | rtrack = file->rtrack; |
6559 | | | 6583 | |
6560 | #if defined(AUDIO_DEBUG) | | 6584 | #if defined(AUDIO_DEBUG) |
6561 | if (audiodebug >= 2) { | | 6585 | if (audiodebug >= 2) { |
6562 | char buf[256]; | | 6586 | char buf[256]; |
6563 | char p[64]; | | 6587 | char p[64]; |
6564 | int buflen; | | 6588 | int buflen; |
6565 | int plen; | | 6589 | int plen; |
6566 | #define SPRINTF(var, fmt...) do { \ | | 6590 | #define SPRINTF(var, fmt...) do { \ |
6567 | var##len += snprintf(var + var##len, sizeof(var) - var##len, fmt); \ | | 6591 | var##len += snprintf(var + var##len, sizeof(var) - var##len, fmt); \ |
6568 | } while (0) | | 6592 | } while (0) |
6569 | | | 6593 | |
6570 | buflen = 0; | | 6594 | buflen = 0; |
6571 | plen = 0; | | 6595 | plen = 0; |
6572 | if (SPECIFIED(pi->encoding)) | | 6596 | if (SPECIFIED(pi->encoding)) |
6573 | SPRINTF(p, "/%s", audio_encoding_name(pi->encoding)); | | 6597 | SPRINTF(p, "/%s", audio_encoding_name(pi->encoding)); |
6574 | if (SPECIFIED(pi->precision)) | | 6598 | if (SPECIFIED(pi->precision)) |
6575 | SPRINTF(p, "/%dbit", pi->precision); | | 6599 | SPRINTF(p, "/%dbit", pi->precision); |
6576 | if (SPECIFIED(pi->channels)) | | 6600 | if (SPECIFIED(pi->channels)) |
6577 | SPRINTF(p, "/%dch", pi->channels); | | 6601 | SPRINTF(p, "/%dch", pi->channels); |
6578 | if (SPECIFIED(pi->sample_rate)) | | 6602 | if (SPECIFIED(pi->sample_rate)) |
6579 | SPRINTF(p, "/%dHz", pi->sample_rate); | | 6603 | SPRINTF(p, "/%dHz", pi->sample_rate); |
6580 | if (plen > 0) | | 6604 | if (plen > 0) |
6581 | SPRINTF(buf, ",play.param=%s", p + 1); | | 6605 | SPRINTF(buf, ",play.param=%s", p + 1); |
6582 | | | 6606 | |
6583 | plen = 0; | | 6607 | plen = 0; |
6584 | if (SPECIFIED(ri->encoding)) | | 6608 | if (SPECIFIED(ri->encoding)) |
6585 | SPRINTF(p, "/%s", audio_encoding_name(ri->encoding)); | | 6609 | SPRINTF(p, "/%s", audio_encoding_name(ri->encoding)); |
6586 | if (SPECIFIED(ri->precision)) | | 6610 | if (SPECIFIED(ri->precision)) |
6587 | SPRINTF(p, "/%dbit", ri->precision); | | 6611 | SPRINTF(p, "/%dbit", ri->precision); |
6588 | if (SPECIFIED(ri->channels)) | | 6612 | if (SPECIFIED(ri->channels)) |
6589 | SPRINTF(p, "/%dch", ri->channels); | | 6613 | SPRINTF(p, "/%dch", ri->channels); |
6590 | if (SPECIFIED(ri->sample_rate)) | | 6614 | if (SPECIFIED(ri->sample_rate)) |
6591 | SPRINTF(p, "/%dHz", ri->sample_rate); | | 6615 | SPRINTF(p, "/%dHz", ri->sample_rate); |
6592 | if (plen > 0) | | 6616 | if (plen > 0) |
6593 | SPRINTF(buf, ",record.param=%s", p + 1); | | 6617 | SPRINTF(buf, ",record.param=%s", p + 1); |
6594 | | | 6618 | |
6595 | if (SPECIFIED(ai->mode)) | | 6619 | if (SPECIFIED(ai->mode)) |
6596 | SPRINTF(buf, ",mode=%d", ai->mode); | | 6620 | SPRINTF(buf, ",mode=%d", ai->mode); |
6597 | if (SPECIFIED(ai->hiwat)) | | 6621 | if (SPECIFIED(ai->hiwat)) |
6598 | SPRINTF(buf, ",hiwat=%d", ai->hiwat); | | 6622 | SPRINTF(buf, ",hiwat=%d", ai->hiwat); |
6599 | if (SPECIFIED(ai->lowat)) | | 6623 | if (SPECIFIED(ai->lowat)) |
6600 | SPRINTF(buf, ",lowat=%d", ai->lowat); | | 6624 | SPRINTF(buf, ",lowat=%d", ai->lowat); |
6601 | if (SPECIFIED(ai->play.gain)) | | 6625 | if (SPECIFIED(ai->play.gain)) |
6602 | SPRINTF(buf, ",play.gain=%d", ai->play.gain); | | 6626 | SPRINTF(buf, ",play.gain=%d", ai->play.gain); |
6603 | if (SPECIFIED(ai->record.gain)) | | 6627 | if (SPECIFIED(ai->record.gain)) |
6604 | SPRINTF(buf, ",record.gain=%d", ai->record.gain); | | 6628 | SPRINTF(buf, ",record.gain=%d", ai->record.gain); |
6605 | if (SPECIFIED_CH(ai->play.balance)) | | 6629 | if (SPECIFIED_CH(ai->play.balance)) |
6606 | SPRINTF(buf, ",play.balance=%d", ai->play.balance); | | 6630 | SPRINTF(buf, ",play.balance=%d", ai->play.balance); |
6607 | if (SPECIFIED_CH(ai->record.balance)) | | 6631 | if (SPECIFIED_CH(ai->record.balance)) |
6608 | SPRINTF(buf, ",record.balance=%d", ai->record.balance); | | 6632 | SPRINTF(buf, ",record.balance=%d", ai->record.balance); |
6609 | if (SPECIFIED(ai->play.port)) | | 6633 | if (SPECIFIED(ai->play.port)) |
6610 | SPRINTF(buf, ",play.port=%d", ai->play.port); | | 6634 | SPRINTF(buf, ",play.port=%d", ai->play.port); |
6611 | if (SPECIFIED(ai->record.port)) | | 6635 | if (SPECIFIED(ai->record.port)) |
6612 | SPRINTF(buf, ",record.port=%d", ai->record.port); | | 6636 | SPRINTF(buf, ",record.port=%d", ai->record.port); |
6613 | if (SPECIFIED(ai->monitor_gain)) | | 6637 | if (SPECIFIED(ai->monitor_gain)) |
6614 | SPRINTF(buf, ",monitor_gain=%d", ai->monitor_gain); | | 6638 | SPRINTF(buf, ",monitor_gain=%d", ai->monitor_gain); |
6615 | if (SPECIFIED_CH(ai->play.pause)) | | 6639 | if (SPECIFIED_CH(ai->play.pause)) |
6616 | SPRINTF(buf, ",play.pause=%d", ai->play.pause); | | 6640 | SPRINTF(buf, ",play.pause=%d", ai->play.pause); |
6617 | if (SPECIFIED_CH(ai->record.pause)) | | 6641 | if (SPECIFIED_CH(ai->record.pause)) |
6618 | SPRINTF(buf, ",record.pause=%d", ai->record.pause); | | 6642 | SPRINTF(buf, ",record.pause=%d", ai->record.pause); |
6619 | | | 6643 | |
6620 | if (buflen > 0) | | 6644 | if (buflen > 0) |
6621 | TRACE(2, "specified %s", buf + 1); | | 6645 | TRACE(2, "specified %s", buf + 1); |
6622 | } | | 6646 | } |
6623 | #endif | | 6647 | #endif |
6624 | | | 6648 | |
6625 | AUDIO_INITINFO(&saved_ai); | | 6649 | AUDIO_INITINFO(&saved_ai); |
6626 | /* XXX shut up gcc */ | | 6650 | /* XXX shut up gcc */ |
6627 | memset(&saved_pfmt, 0, sizeof(saved_pfmt)); | | 6651 | memset(&saved_pfmt, 0, sizeof(saved_pfmt)); |
6628 | memset(&saved_rfmt, 0, sizeof(saved_rfmt)); | | 6652 | memset(&saved_rfmt, 0, sizeof(saved_rfmt)); |
6629 | | | 6653 | |
6630 | /* Set default value and save current parameters */ | | 6654 | /* Set default value and save current parameters */ |
6631 | if (ptrack) { | | 6655 | if (ptrack) { |
6632 | pfmt = ptrack->usrbuf.fmt; | | 6656 | pfmt = ptrack->usrbuf.fmt; |
6633 | saved_pfmt = ptrack->usrbuf.fmt; | | 6657 | saved_pfmt = ptrack->usrbuf.fmt; |
6634 | saved_ai.play.pause = ptrack->is_pause; | | 6658 | saved_ai.play.pause = ptrack->is_pause; |
6635 | } | | 6659 | } |
6636 | if (rtrack) { | | 6660 | if (rtrack) { |
6637 | rfmt = rtrack->usrbuf.fmt; | | 6661 | rfmt = rtrack->usrbuf.fmt; |
6638 | saved_rfmt = rtrack->usrbuf.fmt; | | 6662 | saved_rfmt = rtrack->usrbuf.fmt; |
6639 | saved_ai.record.pause = rtrack->is_pause; | | 6663 | saved_ai.record.pause = rtrack->is_pause; |
6640 | } | | 6664 | } |
6641 | saved_ai.mode = file->mode; | | 6665 | saved_ai.mode = file->mode; |
6642 | | | 6666 | |
6643 | /* Overwrite if specified */ | | 6667 | /* Overwrite if specified */ |
6644 | mode = file->mode; | | 6668 | mode = file->mode; |
6645 | if (SPECIFIED(ai->mode)) { | | 6669 | if (SPECIFIED(ai->mode)) { |
6646 | /* | | 6670 | /* |
6647 | * Setting ai->mode no longer does anything because it's | | 6671 | * Setting ai->mode no longer does anything because it's |
6648 | * prohibited to change playback/recording mode after open | | 6672 | * prohibited to change playback/recording mode after open |
6649 | * and AUMODE_PLAY_ALL is obsoleted. However, it still | | 6673 | * and AUMODE_PLAY_ALL is obsoleted. However, it still |
6650 | * keeps the state of AUMODE_PLAY_ALL itself for backward | | 6674 | * keeps the state of AUMODE_PLAY_ALL itself for backward |
6651 | * compatibility. | | 6675 | * compatibility. |
6652 | * In the internal, only file->mode has the state of | | 6676 | * In the internal, only file->mode has the state of |
6653 | * AUMODE_PLAY_ALL flag and track->mode in both track does | | 6677 | * AUMODE_PLAY_ALL flag and track->mode in both track does |
6654 | * not have. | | 6678 | * not have. |
6655 | */ | | 6679 | */ |
6656 | if ((file->mode & AUMODE_PLAY)) { | | 6680 | if ((file->mode & AUMODE_PLAY)) { |
6657 | mode = (file->mode & (AUMODE_PLAY | AUMODE_RECORD)) | | 6681 | mode = (file->mode & (AUMODE_PLAY | AUMODE_RECORD)) |
6658 | | (ai->mode & AUMODE_PLAY_ALL); | | 6682 | | (ai->mode & AUMODE_PLAY_ALL); |
6659 | } | | 6683 | } |
6660 | } | | 6684 | } |
6661 | | | 6685 | |
6662 | if (ptrack) { | | 6686 | if (ptrack) { |
6663 | pchanges = audio_track_setinfo_check(&pfmt, pi); | | 6687 | pchanges = audio_track_setinfo_check(&pfmt, pi); |
6664 | if (pchanges == -1) { | | 6688 | if (pchanges == -1) { |
6665 | #if defined(AUDIO_DEBUG) | | 6689 | #if defined(AUDIO_DEBUG) |
6666 | char fmtbuf[64]; | | 6690 | char fmtbuf[64]; |
6667 | audio_format2_tostr(fmtbuf, sizeof(fmtbuf), &pfmt); | | 6691 | audio_format2_tostr(fmtbuf, sizeof(fmtbuf), &pfmt); |
6668 | TRACET(1, ptrack, "check play.params failed: %s", | | 6692 | TRACET(1, ptrack, "check play.params failed: %s", |
6669 | fmtbuf); | | 6693 | fmtbuf); |
6670 | #endif | | 6694 | #endif |
6671 | return EINVAL; | | 6695 | return EINVAL; |
6672 | } | | 6696 | } |
6673 | if (SPECIFIED(ai->mode)) | | 6697 | if (SPECIFIED(ai->mode)) |
6674 | pchanges = 1; | | 6698 | pchanges = 1; |
6675 | } | | 6699 | } |
6676 | if (rtrack) { | | 6700 | if (rtrack) { |
6677 | rchanges = audio_track_setinfo_check(&rfmt, ri); | | 6701 | rchanges = audio_track_setinfo_check(&rfmt, ri); |
6678 | if (rchanges == -1) { | | 6702 | if (rchanges == -1) { |
6679 | #if defined(AUDIO_DEBUG) | | 6703 | #if defined(AUDIO_DEBUG) |
6680 | char fmtbuf[64]; | | 6704 | char fmtbuf[64]; |
6681 | audio_format2_tostr(fmtbuf, sizeof(fmtbuf), &rfmt); | | 6705 | audio_format2_tostr(fmtbuf, sizeof(fmtbuf), &rfmt); |
6682 | TRACET(1, rtrack, "check record.params failed: %s", | | 6706 | TRACET(1, rtrack, "check record.params failed: %s", |
6683 | fmtbuf); | | 6707 | fmtbuf); |
6684 | #endif | | 6708 | #endif |
6685 | return EINVAL; | | 6709 | return EINVAL; |
6686 | } | | 6710 | } |
6687 | if (SPECIFIED(ai->mode)) | | 6711 | if (SPECIFIED(ai->mode)) |
6688 | rchanges = 1; | | 6712 | rchanges = 1; |
6689 | } | | 6713 | } |
6690 | | | 6714 | |
6691 | /* | | 6715 | /* |
6692 | * Even when setting either one of playback and recording, | | 6716 | * Even when setting either one of playback and recording, |
6693 | * both track must be halted. | | 6717 | * both track must be halted. |
6694 | */ | | 6718 | */ |
6695 | if (pchanges || rchanges) { | | 6719 | if (pchanges || rchanges) { |
6696 | audio_file_clear(sc, file); | | 6720 | audio_file_clear(sc, file); |
6697 | #if defined(AUDIO_DEBUG) | | 6721 | #if defined(AUDIO_DEBUG) |
6698 | char fmtbuf[64]; | | 6722 | char fmtbuf[64]; |
6699 | if (pchanges) { | | 6723 | if (pchanges) { |
6700 | audio_format2_tostr(fmtbuf, sizeof(fmtbuf), &pfmt); | | 6724 | audio_format2_tostr(fmtbuf, sizeof(fmtbuf), &pfmt); |
6701 | DPRINTF(1, "audio track#%d play mode: %s\n", | | 6725 | DPRINTF(1, "audio track#%d play mode: %s\n", |
6702 | ptrack->id, fmtbuf); | | 6726 | ptrack->id, fmtbuf); |
6703 | } | | 6727 | } |
6704 | if (rchanges) { | | 6728 | if (rchanges) { |
6705 | audio_format2_tostr(fmtbuf, sizeof(fmtbuf), &rfmt); | | 6729 | audio_format2_tostr(fmtbuf, sizeof(fmtbuf), &rfmt); |
6706 | DPRINTF(1, "audio track#%d rec mode: %s\n", | | 6730 | DPRINTF(1, "audio track#%d rec mode: %s\n", |
6707 | rtrack->id, fmtbuf); | | 6731 | rtrack->id, fmtbuf); |
6708 | } | | 6732 | } |
6709 | #endif | | 6733 | #endif |
6710 | } | | 6734 | } |
6711 | | | 6735 | |
6712 | /* Set mixer parameters */ | | 6736 | /* Set mixer parameters */ |
6713 | error = audio_hw_setinfo(sc, ai, &saved_ai); | | 6737 | error = audio_hw_setinfo(sc, ai, &saved_ai); |
6714 | if (error) | | 6738 | if (error) |
6715 | goto abort1; | | 6739 | goto abort1; |
6716 | | | 6740 | |
6717 | /* Set to track and update sticky parameters */ | | 6741 | /* Set to track and update sticky parameters */ |
6718 | error = 0; | | 6742 | error = 0; |
6719 | file->mode = mode; | | 6743 | file->mode = mode; |
6720 | if (ptrack) { | | 6744 | if (ptrack) { |
6721 | if (SPECIFIED_CH(pi->pause)) { | | 6745 | if (SPECIFIED_CH(pi->pause)) { |
6722 | ptrack->is_pause = pi->pause; | | 6746 | ptrack->is_pause = pi->pause; |
6723 | sc->sc_sound_ppause = pi->pause; | | 6747 | sc->sc_sound_ppause = pi->pause; |
6724 | } | | 6748 | } |
6725 | if (pchanges) { | | 6749 | if (pchanges) { |
6726 | audio_track_lock_enter(ptrack); | | 6750 | audio_track_lock_enter(ptrack); |
6727 | error = audio_track_set_format(ptrack, &pfmt); | | 6751 | error = audio_track_set_format(ptrack, &pfmt); |
6728 | audio_track_lock_exit(ptrack); | | 6752 | audio_track_lock_exit(ptrack); |
6729 | if (error) { | | 6753 | if (error) { |
6730 | TRACET(1, ptrack, "set play.params failed"); | | 6754 | TRACET(1, ptrack, "set play.params failed"); |
6731 | goto abort2; | | 6755 | goto abort2; |
6732 | } | | 6756 | } |
6733 | sc->sc_sound_pparams = pfmt; | | 6757 | sc->sc_sound_pparams = pfmt; |
6734 | } | | 6758 | } |
6735 | /* Change water marks after initializing the buffers. */ | | 6759 | /* Change water marks after initializing the buffers. */ |
6736 | if (SPECIFIED(ai->hiwat) || SPECIFIED(ai->lowat)) | | 6760 | if (SPECIFIED(ai->hiwat) || SPECIFIED(ai->lowat)) |
6737 | audio_track_setinfo_water(ptrack, ai); | | 6761 | audio_track_setinfo_water(ptrack, ai); |
6738 | } | | 6762 | } |
6739 | if (rtrack) { | | 6763 | if (rtrack) { |
6740 | if (SPECIFIED_CH(ri->pause)) { | | 6764 | if (SPECIFIED_CH(ri->pause)) { |
6741 | rtrack->is_pause = ri->pause; | | 6765 | rtrack->is_pause = ri->pause; |
6742 | sc->sc_sound_rpause = ri->pause; | | 6766 | sc->sc_sound_rpause = ri->pause; |
6743 | } | | 6767 | } |
6744 | if (rchanges) { | | 6768 | if (rchanges) { |
6745 | audio_track_lock_enter(rtrack); | | 6769 | audio_track_lock_enter(rtrack); |
6746 | error = audio_track_set_format(rtrack, &rfmt); | | 6770 | error = audio_track_set_format(rtrack, &rfmt); |
6747 | audio_track_lock_exit(rtrack); | | 6771 | audio_track_lock_exit(rtrack); |
6748 | if (error) { | | 6772 | if (error) { |
6749 | TRACET(1, rtrack, "set record.params failed"); | | 6773 | TRACET(1, rtrack, "set record.params failed"); |
6750 | goto abort3; | | 6774 | goto abort3; |
6751 | } | | 6775 | } |
6752 | sc->sc_sound_rparams = rfmt; | | 6776 | sc->sc_sound_rparams = rfmt; |
6753 | } | | 6777 | } |
6754 | } | | 6778 | } |
6755 | | | 6779 | |
6756 | return 0; | | 6780 | return 0; |
6757 | | | 6781 | |
6758 | /* Rollback */ | | 6782 | /* Rollback */ |
6759 | abort3: | | 6783 | abort3: |
6760 | if (error != ENOMEM) { | | 6784 | if (error != ENOMEM) { |
6761 | rtrack->is_pause = saved_ai.record.pause; | | 6785 | rtrack->is_pause = saved_ai.record.pause; |
6762 | audio_track_lock_enter(rtrack); | | 6786 | audio_track_lock_enter(rtrack); |
6763 | audio_track_set_format(rtrack, &saved_rfmt); | | 6787 | audio_track_set_format(rtrack, &saved_rfmt); |
6764 | audio_track_lock_exit(rtrack); | | 6788 | audio_track_lock_exit(rtrack); |
6765 | } | | 6789 | } |
6766 | abort2: | | 6790 | abort2: |
6767 | if (ptrack && error != ENOMEM) { | | 6791 | if (ptrack && error != ENOMEM) { |
6768 | ptrack->is_pause = saved_ai.play.pause; | | 6792 | ptrack->is_pause = saved_ai.play.pause; |
6769 | audio_track_lock_enter(ptrack); | | 6793 | audio_track_lock_enter(ptrack); |
6770 | audio_track_set_format(ptrack, &saved_pfmt); | | 6794 | audio_track_set_format(ptrack, &saved_pfmt); |
6771 | audio_track_lock_exit(ptrack); | | 6795 | audio_track_lock_exit(ptrack); |
6772 | sc->sc_sound_pparams = saved_pfmt; | | 6796 | sc->sc_sound_pparams = saved_pfmt; |
6773 | sc->sc_sound_ppause = saved_ai.play.pause; | | 6797 | sc->sc_sound_ppause = saved_ai.play.pause; |
6774 | } | | 6798 | } |
6775 | file->mode = saved_ai.mode; | | 6799 | file->mode = saved_ai.mode; |
6776 | abort1: | | 6800 | abort1: |
6777 | audio_hw_setinfo(sc, &saved_ai, NULL); | | 6801 | audio_hw_setinfo(sc, &saved_ai, NULL); |
6778 | | | 6802 | |
6779 | return error; | | 6803 | return error; |
6780 | } | | 6804 | } |
6781 | | | 6805 | |
6782 | /* | | 6806 | /* |
6783 | * Write SPECIFIED() parameters within info back to fmt. | | 6807 | * Write SPECIFIED() parameters within info back to fmt. |
6784 | * Return value of 1 indicates that fmt is modified. | | 6808 | * Return value of 1 indicates that fmt is modified. |
6785 | * Return value of 0 indicates that fmt is not modified. | | 6809 | * Return value of 0 indicates that fmt is not modified. |
6786 | * Return value of -1 indicates that error EINVAL has occurred. | | 6810 | * Return value of -1 indicates that error EINVAL has occurred. |
6787 | */ | | 6811 | */ |
6788 | static int | | 6812 | static int |
6789 | audio_track_setinfo_check(audio_format2_t *fmt, const struct audio_prinfo *info) | | 6813 | audio_track_setinfo_check(audio_format2_t *fmt, const struct audio_prinfo *info) |
6790 | { | | 6814 | { |
6791 | int changes; | | 6815 | int changes; |
6792 | | | 6816 | |
6793 | changes = 0; | | 6817 | changes = 0; |
6794 | if (SPECIFIED(info->sample_rate)) { | | 6818 | if (SPECIFIED(info->sample_rate)) { |
6795 | if (info->sample_rate < AUDIO_MIN_FREQUENCY) | | 6819 | if (info->sample_rate < AUDIO_MIN_FREQUENCY) |
6796 | return -1; | | 6820 | return -1; |
6797 | if (info->sample_rate > AUDIO_MAX_FREQUENCY) | | 6821 | if (info->sample_rate > AUDIO_MAX_FREQUENCY) |
6798 | return -1; | | 6822 | return -1; |
6799 | fmt->sample_rate = info->sample_rate; | | 6823 | fmt->sample_rate = info->sample_rate; |
6800 | changes = 1; | | 6824 | changes = 1; |
6801 | } | | 6825 | } |
6802 | if (SPECIFIED(info->encoding)) { | | 6826 | if (SPECIFIED(info->encoding)) { |
6803 | fmt->encoding = info->encoding; | | 6827 | fmt->encoding = info->encoding; |
6804 | changes = 1; | | 6828 | changes = 1; |
6805 | } | | 6829 | } |
6806 | if (SPECIFIED(info->precision)) { | | 6830 | if (SPECIFIED(info->precision)) { |
6807 | fmt->precision = info->precision; | | 6831 | fmt->precision = info->precision; |
6808 | /* we don't have API to specify stride */ | | 6832 | /* we don't have API to specify stride */ |
6809 | fmt->stride = info->precision; | | 6833 | fmt->stride = info->precision; |
6810 | changes = 1; | | 6834 | changes = 1; |
6811 | } | | 6835 | } |
6812 | if (SPECIFIED(info->channels)) { | | 6836 | if (SPECIFIED(info->channels)) { |
6813 | fmt->channels = info->channels; | | 6837 | fmt->channels = info->channels; |
6814 | changes = 1; | | 6838 | changes = 1; |
6815 | } | | 6839 | } |
6816 | | | 6840 | |
6817 | if (changes) { | | 6841 | if (changes) { |
6818 | if (audio_check_params(fmt) != 0) | | 6842 | if (audio_check_params(fmt) != 0) |
6819 | return -1; | | 6843 | return -1; |
6820 | } | | 6844 | } |
6821 | | | 6845 | |
6822 | return changes; | | 6846 | return changes; |
6823 | } | | 6847 | } |
6824 | | | 6848 | |
6825 | /* | | 6849 | /* |
6826 | * Change water marks for playback track if specfied. | | 6850 | * Change water marks for playback track if specfied. |
6827 | */ | | 6851 | */ |
6828 | static void | | 6852 | static void |
6829 | audio_track_setinfo_water(audio_track_t *track, const struct audio_info *ai) | | 6853 | audio_track_setinfo_water(audio_track_t *track, const struct audio_info *ai) |
6830 | { | | 6854 | { |
6831 | u_int blks; | | 6855 | u_int blks; |
6832 | u_int maxblks; | | 6856 | u_int maxblks; |
6833 | u_int blksize; | | 6857 | u_int blksize; |
6834 | | | 6858 | |
6835 | KASSERT(audio_track_is_playback(track)); | | 6859 | KASSERT(audio_track_is_playback(track)); |