| @@ -1,2419 +1,2417 @@ | | | @@ -1,2419 +1,2417 @@ |
1 | /* $NetBSD: audio.c,v 1.91.2.3 2021/03/21 21:09:09 thorpej Exp $ */ | | 1 | /* $NetBSD: audio.c,v 1.91.2.4 2021/03/28 19:55:37 thorpej 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 - - + | | 121 | * allocm - - + |
122 | * freem - - + | | 122 | * freem - - + |
123 | * round_buffersize - x | | 123 | * round_buffersize - x |
124 | * get_props - - Called at attach time | | 124 | * get_props - - 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 | * In addition, there is an additional lock. | | 130 | * In addition, there is an additional lock. |
131 | * | | 131 | * |
132 | * - track->lock. This is an atomic variable and is similar to the | | 132 | * - track->lock. This is an atomic variable and is similar to the |
133 | * "interrupt lock". This is one for each track. If any thread context | | 133 | * "interrupt lock". This is one for each track. If any thread context |
134 | * (and software interrupt context) and hardware interrupt context who | | 134 | * (and software interrupt context) and hardware interrupt context who |
135 | * want to access some variables on this track, they must acquire this | | 135 | * want to access some variables on this track, they must acquire this |
136 | * lock before. It protects track's consistency between hardware | | 136 | * lock before. It protects track's consistency between hardware |
137 | * interrupt context and others. | | 137 | * interrupt context and others. |
138 | */ | | 138 | */ |
139 | | | 139 | |
140 | #include <sys/cdefs.h> | | 140 | #include <sys/cdefs.h> |
141 | __KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.91.2.3 2021/03/21 21:09:09 thorpej Exp $"); | | 141 | __KERNEL_RCSID(0, "$NetBSD: audio.c,v 1.91.2.4 2021/03/28 19:55:37 thorpej Exp $"); |
142 | | | 142 | |
143 | #ifdef _KERNEL_OPT | | 143 | #ifdef _KERNEL_OPT |
144 | #include "audio.h" | | 144 | #include "audio.h" |
145 | #include "midi.h" | | 145 | #include "midi.h" |
146 | #endif | | 146 | #endif |
147 | | | 147 | |
148 | #if NAUDIO > 0 | | 148 | #if NAUDIO > 0 |
149 | | | 149 | |
150 | #include <sys/types.h> | | 150 | #include <sys/types.h> |
151 | #include <sys/param.h> | | 151 | #include <sys/param.h> |
152 | #include <sys/atomic.h> | | 152 | #include <sys/atomic.h> |
153 | #include <sys/audioio.h> | | 153 | #include <sys/audioio.h> |
154 | #include <sys/conf.h> | | 154 | #include <sys/conf.h> |
155 | #include <sys/cpu.h> | | 155 | #include <sys/cpu.h> |
156 | #include <sys/device.h> | | 156 | #include <sys/device.h> |
157 | #include <sys/fcntl.h> | | 157 | #include <sys/fcntl.h> |
158 | #include <sys/file.h> | | 158 | #include <sys/file.h> |
159 | #include <sys/filedesc.h> | | 159 | #include <sys/filedesc.h> |
160 | #include <sys/intr.h> | | 160 | #include <sys/intr.h> |
161 | #include <sys/ioctl.h> | | 161 | #include <sys/ioctl.h> |
162 | #include <sys/kauth.h> | | 162 | #include <sys/kauth.h> |
163 | #include <sys/kernel.h> | | 163 | #include <sys/kernel.h> |
164 | #include <sys/kmem.h> | | 164 | #include <sys/kmem.h> |
165 | #include <sys/malloc.h> | | 165 | #include <sys/malloc.h> |
166 | #include <sys/mman.h> | | 166 | #include <sys/mman.h> |
167 | #include <sys/module.h> | | 167 | #include <sys/module.h> |
168 | #include <sys/poll.h> | | 168 | #include <sys/poll.h> |
169 | #include <sys/proc.h> | | 169 | #include <sys/proc.h> |
170 | #include <sys/queue.h> | | 170 | #include <sys/queue.h> |
171 | #include <sys/select.h> | | 171 | #include <sys/select.h> |
172 | #include <sys/signalvar.h> | | 172 | #include <sys/signalvar.h> |
173 | #include <sys/stat.h> | | 173 | #include <sys/stat.h> |
174 | #include <sys/sysctl.h> | | 174 | #include <sys/sysctl.h> |
175 | #include <sys/systm.h> | | 175 | #include <sys/systm.h> |
176 | #include <sys/syslog.h> | | 176 | #include <sys/syslog.h> |
177 | #include <sys/vnode.h> | | 177 | #include <sys/vnode.h> |
178 | | | 178 | |
179 | #include <dev/audio/audio_if.h> | | 179 | #include <dev/audio/audio_if.h> |
180 | #include <dev/audio/audiovar.h> | | 180 | #include <dev/audio/audiovar.h> |
181 | #include <dev/audio/audiodef.h> | | 181 | #include <dev/audio/audiodef.h> |
182 | #include <dev/audio/linear.h> | | 182 | #include <dev/audio/linear.h> |
183 | #include <dev/audio/mulaw.h> | | 183 | #include <dev/audio/mulaw.h> |
184 | | | 184 | |
185 | #include <machine/endian.h> | | 185 | #include <machine/endian.h> |
186 | | | 186 | |
187 | #include <uvm/uvm_extern.h> | | 187 | #include <uvm/uvm_extern.h> |
188 | | | 188 | |
189 | #include "ioconf.h" | | 189 | #include "ioconf.h" |
190 | | | 190 | |
191 | /* | | 191 | /* |
192 | * 0: No debug logs | | 192 | * 0: No debug logs |
193 | * 1: action changes like open/close/set_format... | | 193 | * 1: action changes like open/close/set_format... |
194 | * 2: + normal operations like read/write/ioctl... | | 194 | * 2: + normal operations like read/write/ioctl... |
195 | * 3: + TRACEs except interrupt | | 195 | * 3: + TRACEs except interrupt |
196 | * 4: + TRACEs including interrupt | | 196 | * 4: + TRACEs including interrupt |
197 | */ | | 197 | */ |
198 | //#define AUDIO_DEBUG 1 | | 198 | //#define AUDIO_DEBUG 1 |
199 | | | 199 | |
200 | #if defined(AUDIO_DEBUG) | | 200 | #if defined(AUDIO_DEBUG) |
201 | | | 201 | |
202 | int audiodebug = AUDIO_DEBUG; | | 202 | int audiodebug = AUDIO_DEBUG; |
203 | static void audio_vtrace(struct audio_softc *sc, const char *, const char *, | | 203 | static void audio_vtrace(struct audio_softc *sc, const char *, const char *, |
204 | const char *, va_list); | | 204 | const char *, va_list); |
205 | static void audio_trace(struct audio_softc *sc, const char *, const char *, ...) | | 205 | static void audio_trace(struct audio_softc *sc, const char *, const char *, ...) |
206 | __printflike(3, 4); | | 206 | __printflike(3, 4); |
207 | static void audio_tracet(const char *, audio_track_t *, const char *, ...) | | 207 | static void audio_tracet(const char *, audio_track_t *, const char *, ...) |
208 | __printflike(3, 4); | | 208 | __printflike(3, 4); |
209 | static void audio_tracef(const char *, audio_file_t *, const char *, ...) | | 209 | static void audio_tracef(const char *, audio_file_t *, const char *, ...) |
210 | __printflike(3, 4); | | 210 | __printflike(3, 4); |
211 | | | 211 | |
212 | /* XXX sloppy memory logger */ | | 212 | /* XXX sloppy memory logger */ |
213 | static void audio_mlog_init(void); | | 213 | static void audio_mlog_init(void); |
214 | static void audio_mlog_free(void); | | 214 | static void audio_mlog_free(void); |
215 | static void audio_mlog_softintr(void *); | | 215 | static void audio_mlog_softintr(void *); |
216 | extern void audio_mlog_flush(void); | | 216 | extern void audio_mlog_flush(void); |
217 | extern void audio_mlog_printf(const char *, ...); | | 217 | extern void audio_mlog_printf(const char *, ...); |
218 | | | 218 | |
219 | static int mlog_refs; /* reference counter */ | | 219 | static int mlog_refs; /* reference counter */ |
220 | static char *mlog_buf[2]; /* double buffer */ | | 220 | static char *mlog_buf[2]; /* double buffer */ |
221 | static int mlog_buflen; /* buffer length */ | | 221 | static int mlog_buflen; /* buffer length */ |
222 | static int mlog_used; /* used length */ | | 222 | static int mlog_used; /* used length */ |
223 | static int mlog_full; /* number of dropped lines by buffer full */ | | 223 | static int mlog_full; /* number of dropped lines by buffer full */ |
224 | static int mlog_drop; /* number of dropped lines by busy */ | | 224 | static int mlog_drop; /* number of dropped lines by busy */ |
225 | static volatile uint32_t mlog_inuse; /* in-use */ | | 225 | static volatile uint32_t mlog_inuse; /* in-use */ |
226 | static int mlog_wpage; /* active page */ | | 226 | static int mlog_wpage; /* active page */ |
227 | static void *mlog_sih; /* softint handle */ | | 227 | static void *mlog_sih; /* softint handle */ |
228 | | | 228 | |
229 | static void | | 229 | static void |
230 | audio_mlog_init(void) | | 230 | audio_mlog_init(void) |
231 | { | | 231 | { |
232 | mlog_refs++; | | 232 | mlog_refs++; |
233 | if (mlog_refs > 1) | | 233 | if (mlog_refs > 1) |
234 | return; | | 234 | return; |
235 | mlog_buflen = 4096; | | 235 | mlog_buflen = 4096; |
236 | mlog_buf[0] = kmem_zalloc(mlog_buflen, KM_SLEEP); | | 236 | mlog_buf[0] = kmem_zalloc(mlog_buflen, KM_SLEEP); |
237 | mlog_buf[1] = kmem_zalloc(mlog_buflen, KM_SLEEP); | | 237 | mlog_buf[1] = kmem_zalloc(mlog_buflen, KM_SLEEP); |
238 | mlog_used = 0; | | 238 | mlog_used = 0; |
239 | mlog_full = 0; | | 239 | mlog_full = 0; |
240 | mlog_drop = 0; | | 240 | mlog_drop = 0; |
241 | mlog_inuse = 0; | | 241 | mlog_inuse = 0; |
242 | mlog_wpage = 0; | | 242 | mlog_wpage = 0; |
243 | mlog_sih = softint_establish(SOFTINT_SERIAL, audio_mlog_softintr, NULL); | | 243 | mlog_sih = softint_establish(SOFTINT_SERIAL, audio_mlog_softintr, NULL); |
244 | if (mlog_sih == NULL) | | 244 | if (mlog_sih == NULL) |
245 | printf("%s: softint_establish failed\n", __func__); | | 245 | printf("%s: softint_establish failed\n", __func__); |
246 | } | | 246 | } |
247 | | | 247 | |
248 | static void | | 248 | static void |
249 | audio_mlog_free(void) | | 249 | audio_mlog_free(void) |
250 | { | | 250 | { |
251 | mlog_refs--; | | 251 | mlog_refs--; |
252 | if (mlog_refs > 0) | | 252 | if (mlog_refs > 0) |
253 | return; | | 253 | return; |
254 | | | 254 | |
255 | audio_mlog_flush(); | | 255 | audio_mlog_flush(); |
256 | if (mlog_sih) | | 256 | if (mlog_sih) |
257 | softint_disestablish(mlog_sih); | | 257 | softint_disestablish(mlog_sih); |
258 | kmem_free(mlog_buf[0], mlog_buflen); | | 258 | kmem_free(mlog_buf[0], mlog_buflen); |
259 | kmem_free(mlog_buf[1], mlog_buflen); | | 259 | kmem_free(mlog_buf[1], mlog_buflen); |
260 | } | | 260 | } |
261 | | | 261 | |
262 | /* | | 262 | /* |
263 | * Flush memory buffer. | | 263 | * Flush memory buffer. |
264 | * It must not be called from hardware interrupt context. | | 264 | * It must not be called from hardware interrupt context. |
265 | */ | | 265 | */ |
266 | void | | 266 | void |
267 | audio_mlog_flush(void) | | 267 | audio_mlog_flush(void) |
268 | { | | 268 | { |
269 | if (mlog_refs == 0) | | 269 | if (mlog_refs == 0) |
270 | return; | | 270 | return; |
271 | | | 271 | |
272 | /* Nothing to do if already in use ? */ | | 272 | /* Nothing to do if already in use ? */ |
273 | if (atomic_swap_32(&mlog_inuse, 1) == 1) | | 273 | if (atomic_swap_32(&mlog_inuse, 1) == 1) |
274 | return; | | 274 | return; |
275 | | | 275 | |
276 | int rpage = mlog_wpage; | | 276 | int rpage = mlog_wpage; |
277 | mlog_wpage ^= 1; | | 277 | mlog_wpage ^= 1; |
278 | mlog_buf[mlog_wpage][0] = '\0'; | | 278 | mlog_buf[mlog_wpage][0] = '\0'; |
279 | mlog_used = 0; | | 279 | mlog_used = 0; |
280 | | | 280 | |
281 | atomic_swap_32(&mlog_inuse, 0); | | 281 | atomic_swap_32(&mlog_inuse, 0); |
282 | | | 282 | |
283 | if (mlog_buf[rpage][0] != '\0') { | | 283 | if (mlog_buf[rpage][0] != '\0') { |
284 | printf("%s", mlog_buf[rpage]); | | 284 | printf("%s", mlog_buf[rpage]); |
285 | if (mlog_drop > 0) | | 285 | if (mlog_drop > 0) |
286 | printf("mlog_drop %d\n", mlog_drop); | | 286 | printf("mlog_drop %d\n", mlog_drop); |
287 | if (mlog_full > 0) | | 287 | if (mlog_full > 0) |
288 | printf("mlog_full %d\n", mlog_full); | | 288 | printf("mlog_full %d\n", mlog_full); |
289 | } | | 289 | } |
290 | mlog_full = 0; | | 290 | mlog_full = 0; |
291 | mlog_drop = 0; | | 291 | mlog_drop = 0; |
292 | } | | 292 | } |
293 | | | 293 | |
294 | static void | | 294 | static void |
295 | audio_mlog_softintr(void *cookie) | | 295 | audio_mlog_softintr(void *cookie) |
296 | { | | 296 | { |
297 | audio_mlog_flush(); | | 297 | audio_mlog_flush(); |
298 | } | | 298 | } |
299 | | | 299 | |
300 | void | | 300 | void |
301 | audio_mlog_printf(const char *fmt, ...) | | 301 | audio_mlog_printf(const char *fmt, ...) |
302 | { | | 302 | { |
303 | int len; | | 303 | int len; |
304 | va_list ap; | | 304 | va_list ap; |
305 | | | 305 | |
306 | if (atomic_swap_32(&mlog_inuse, 1) == 1) { | | 306 | if (atomic_swap_32(&mlog_inuse, 1) == 1) { |
307 | /* already inuse */ | | 307 | /* already inuse */ |
308 | mlog_drop++; | | 308 | mlog_drop++; |
309 | return; | | 309 | return; |
310 | } | | 310 | } |
311 | | | 311 | |
312 | va_start(ap, fmt); | | 312 | va_start(ap, fmt); |
313 | len = vsnprintf( | | 313 | len = vsnprintf( |
314 | mlog_buf[mlog_wpage] + mlog_used, | | 314 | mlog_buf[mlog_wpage] + mlog_used, |
315 | mlog_buflen - mlog_used, | | 315 | mlog_buflen - mlog_used, |
316 | fmt, ap); | | 316 | fmt, ap); |
317 | va_end(ap); | | 317 | va_end(ap); |
318 | | | 318 | |
319 | mlog_used += len; | | 319 | mlog_used += len; |
320 | if (mlog_buflen - mlog_used <= 1) { | | 320 | if (mlog_buflen - mlog_used <= 1) { |
321 | mlog_full++; | | 321 | mlog_full++; |
322 | } | | 322 | } |
323 | | | 323 | |
324 | atomic_swap_32(&mlog_inuse, 0); | | 324 | atomic_swap_32(&mlog_inuse, 0); |
325 | | | 325 | |
326 | if (mlog_sih) | | 326 | if (mlog_sih) |
327 | softint_schedule(mlog_sih); | | 327 | softint_schedule(mlog_sih); |
328 | } | | 328 | } |
329 | | | 329 | |
330 | /* trace functions */ | | 330 | /* trace functions */ |
331 | static void | | 331 | static void |
332 | audio_vtrace(struct audio_softc *sc, const char *funcname, const char *header, | | 332 | audio_vtrace(struct audio_softc *sc, const char *funcname, const char *header, |
333 | const char *fmt, va_list ap) | | 333 | const char *fmt, va_list ap) |
334 | { | | 334 | { |
335 | char buf[256]; | | 335 | char buf[256]; |
336 | int n; | | 336 | int n; |
337 | | | 337 | |
338 | n = 0; | | 338 | n = 0; |
339 | buf[0] = '\0'; | | 339 | buf[0] = '\0'; |
340 | n += snprintf(buf + n, sizeof(buf) - n, "%s@%d %s", | | 340 | n += snprintf(buf + n, sizeof(buf) - n, "%s@%d %s", |
341 | funcname, device_unit(sc->sc_dev), header); | | 341 | funcname, device_unit(sc->sc_dev), header); |
342 | n += vsnprintf(buf + n, sizeof(buf) - n, fmt, ap); | | 342 | n += vsnprintf(buf + n, sizeof(buf) - n, fmt, ap); |
343 | | | 343 | |
344 | if (cpu_intr_p()) { | | 344 | if (cpu_intr_p()) { |
345 | audio_mlog_printf("%s\n", buf); | | 345 | audio_mlog_printf("%s\n", buf); |
346 | } else { | | 346 | } else { |
347 | audio_mlog_flush(); | | 347 | audio_mlog_flush(); |
348 | printf("%s\n", buf); | | 348 | printf("%s\n", buf); |
349 | } | | 349 | } |
350 | } | | 350 | } |
351 | | | 351 | |
352 | static void | | 352 | static void |
353 | audio_trace(struct audio_softc *sc, const char *funcname, const char *fmt, ...) | | 353 | audio_trace(struct audio_softc *sc, const char *funcname, const char *fmt, ...) |
354 | { | | 354 | { |
355 | va_list ap; | | 355 | va_list ap; |
356 | | | 356 | |
357 | va_start(ap, fmt); | | 357 | va_start(ap, fmt); |
358 | audio_vtrace(sc, funcname, "", fmt, ap); | | 358 | audio_vtrace(sc, funcname, "", fmt, ap); |
359 | va_end(ap); | | 359 | va_end(ap); |
360 | } | | 360 | } |
361 | | | 361 | |
362 | static void | | 362 | static void |
363 | audio_tracet(const char *funcname, audio_track_t *track, const char *fmt, ...) | | 363 | audio_tracet(const char *funcname, audio_track_t *track, const char *fmt, ...) |
364 | { | | 364 | { |
365 | char hdr[16]; | | 365 | char hdr[16]; |
366 | va_list ap; | | 366 | va_list ap; |
367 | | | 367 | |
368 | snprintf(hdr, sizeof(hdr), "#%d ", track->id); | | 368 | snprintf(hdr, sizeof(hdr), "#%d ", track->id); |
369 | va_start(ap, fmt); | | 369 | va_start(ap, fmt); |
370 | audio_vtrace(track->mixer->sc, funcname, hdr, fmt, ap); | | 370 | audio_vtrace(track->mixer->sc, funcname, hdr, fmt, ap); |
371 | va_end(ap); | | 371 | va_end(ap); |
372 | } | | 372 | } |
373 | | | 373 | |
374 | static void | | 374 | static void |
375 | audio_tracef(const char *funcname, audio_file_t *file, const char *fmt, ...) | | 375 | audio_tracef(const char *funcname, audio_file_t *file, const char *fmt, ...) |
376 | { | | 376 | { |
377 | char hdr[32]; | | 377 | char hdr[32]; |
378 | char phdr[16], rhdr[16]; | | 378 | char phdr[16], rhdr[16]; |
379 | va_list ap; | | 379 | va_list ap; |
380 | | | 380 | |
381 | phdr[0] = '\0'; | | 381 | phdr[0] = '\0'; |
382 | rhdr[0] = '\0'; | | 382 | rhdr[0] = '\0'; |
383 | if (file->ptrack) | | 383 | if (file->ptrack) |
384 | snprintf(phdr, sizeof(phdr), "#%d", file->ptrack->id); | | 384 | snprintf(phdr, sizeof(phdr), "#%d", file->ptrack->id); |
385 | if (file->rtrack) | | 385 | if (file->rtrack) |
386 | snprintf(rhdr, sizeof(rhdr), "#%d", file->rtrack->id); | | 386 | snprintf(rhdr, sizeof(rhdr), "#%d", file->rtrack->id); |
387 | snprintf(hdr, sizeof(hdr), "{%s,%s} ", phdr, rhdr); | | 387 | snprintf(hdr, sizeof(hdr), "{%s,%s} ", phdr, rhdr); |
388 | | | 388 | |
389 | va_start(ap, fmt); | | 389 | va_start(ap, fmt); |
390 | audio_vtrace(file->sc, funcname, hdr, fmt, ap); | | 390 | audio_vtrace(file->sc, funcname, hdr, fmt, ap); |
391 | va_end(ap); | | 391 | va_end(ap); |
392 | } | | 392 | } |
393 | | | 393 | |
394 | #define DPRINTF(n, fmt...) do { \ | | 394 | #define DPRINTF(n, fmt...) do { \ |
395 | if (audiodebug >= (n)) { \ | | 395 | if (audiodebug >= (n)) { \ |
396 | audio_mlog_flush(); \ | | 396 | audio_mlog_flush(); \ |
397 | printf(fmt); \ | | 397 | printf(fmt); \ |
398 | } \ | | 398 | } \ |
399 | } while (0) | | 399 | } while (0) |
400 | #define TRACE(n, fmt...) do { \ | | 400 | #define TRACE(n, fmt...) do { \ |
401 | if (audiodebug >= (n)) audio_trace(sc, __func__, fmt); \ | | 401 | if (audiodebug >= (n)) audio_trace(sc, __func__, fmt); \ |
402 | } while (0) | | 402 | } while (0) |
403 | #define TRACET(n, t, fmt...) do { \ | | 403 | #define TRACET(n, t, fmt...) do { \ |
404 | if (audiodebug >= (n)) audio_tracet(__func__, t, fmt); \ | | 404 | if (audiodebug >= (n)) audio_tracet(__func__, t, fmt); \ |
405 | } while (0) | | 405 | } while (0) |
406 | #define TRACEF(n, f, fmt...) do { \ | | 406 | #define TRACEF(n, f, fmt...) do { \ |
407 | if (audiodebug >= (n)) audio_tracef(__func__, f, fmt); \ | | 407 | if (audiodebug >= (n)) audio_tracef(__func__, f, fmt); \ |
408 | } while (0) | | 408 | } while (0) |
409 | | | 409 | |
410 | struct audio_track_debugbuf { | | 410 | struct audio_track_debugbuf { |
411 | char usrbuf[32]; | | 411 | char usrbuf[32]; |
412 | char codec[32]; | | 412 | char codec[32]; |
413 | char chvol[32]; | | 413 | char chvol[32]; |
414 | char chmix[32]; | | 414 | char chmix[32]; |
415 | char freq[32]; | | 415 | char freq[32]; |
416 | char outbuf[32]; | | 416 | char outbuf[32]; |
417 | }; | | 417 | }; |
418 | | | 418 | |
419 | static void | | 419 | static void |
420 | audio_track_bufstat(audio_track_t *track, struct audio_track_debugbuf *buf) | | 420 | audio_track_bufstat(audio_track_t *track, struct audio_track_debugbuf *buf) |
421 | { | | 421 | { |
422 | | | 422 | |
423 | memset(buf, 0, sizeof(*buf)); | | 423 | memset(buf, 0, sizeof(*buf)); |
424 | | | 424 | |
425 | snprintf(buf->outbuf, sizeof(buf->outbuf), " out=%d/%d/%d", | | 425 | snprintf(buf->outbuf, sizeof(buf->outbuf), " out=%d/%d/%d", |
426 | track->outbuf.head, track->outbuf.used, track->outbuf.capacity); | | 426 | track->outbuf.head, track->outbuf.used, track->outbuf.capacity); |
427 | if (track->freq.filter) | | 427 | if (track->freq.filter) |
428 | snprintf(buf->freq, sizeof(buf->freq), " f=%d/%d/%d", | | 428 | snprintf(buf->freq, sizeof(buf->freq), " f=%d/%d/%d", |
429 | track->freq.srcbuf.head, | | 429 | track->freq.srcbuf.head, |
430 | track->freq.srcbuf.used, | | 430 | track->freq.srcbuf.used, |
431 | track->freq.srcbuf.capacity); | | 431 | track->freq.srcbuf.capacity); |
432 | if (track->chmix.filter) | | 432 | if (track->chmix.filter) |
433 | snprintf(buf->chmix, sizeof(buf->chmix), " m=%d", | | 433 | snprintf(buf->chmix, sizeof(buf->chmix), " m=%d", |
434 | track->chmix.srcbuf.used); | | 434 | track->chmix.srcbuf.used); |
435 | if (track->chvol.filter) | | 435 | if (track->chvol.filter) |
436 | snprintf(buf->chvol, sizeof(buf->chvol), " v=%d", | | 436 | snprintf(buf->chvol, sizeof(buf->chvol), " v=%d", |
437 | track->chvol.srcbuf.used); | | 437 | track->chvol.srcbuf.used); |
438 | if (track->codec.filter) | | 438 | if (track->codec.filter) |
439 | snprintf(buf->codec, sizeof(buf->codec), " e=%d", | | 439 | snprintf(buf->codec, sizeof(buf->codec), " e=%d", |
440 | track->codec.srcbuf.used); | | 440 | track->codec.srcbuf.used); |
441 | snprintf(buf->usrbuf, sizeof(buf->usrbuf), " usr=%d/%d/H%d", | | 441 | snprintf(buf->usrbuf, sizeof(buf->usrbuf), " usr=%d/%d/H%d", |
442 | track->usrbuf.head, track->usrbuf.used, track->usrbuf_usedhigh); | | 442 | track->usrbuf.head, track->usrbuf.used, track->usrbuf_usedhigh); |
443 | } | | 443 | } |
444 | #else | | 444 | #else |
445 | #define DPRINTF(n, fmt...) do { } while (0) | | 445 | #define DPRINTF(n, fmt...) do { } while (0) |
446 | #define TRACE(n, fmt, ...) do { } while (0) | | 446 | #define TRACE(n, fmt, ...) do { } while (0) |
447 | #define TRACET(n, t, fmt, ...) do { } while (0) | | 447 | #define TRACET(n, t, fmt, ...) do { } while (0) |
448 | #define TRACEF(n, f, fmt, ...) do { } while (0) | | 448 | #define TRACEF(n, f, fmt, ...) do { } while (0) |
449 | #endif | | 449 | #endif |
450 | | | 450 | |
451 | #define SPECIFIED(x) ((x) != ~0) | | 451 | #define SPECIFIED(x) ((x) != ~0) |
452 | #define SPECIFIED_CH(x) ((x) != (u_char)~0) | | 452 | #define SPECIFIED_CH(x) ((x) != (u_char)~0) |
453 | | | 453 | |
454 | /* | | 454 | /* |
455 | * Default hardware blocksize in msec. | | 455 | * Default hardware blocksize in msec. |
456 | * | | 456 | * |
457 | * We use 10 msec for most modern platforms. This period is good enough to | | 457 | * We use 10 msec for most modern platforms. This period is good enough to |
458 | * play audio and video synchronizely. | | 458 | * play audio and video synchronizely. |
459 | * In contrast, for very old platforms, this is usually too short and too | | 459 | * In contrast, for very old platforms, this is usually too short and too |
460 | * severe. Also such platforms usually can not play video confortably, so | | 460 | * severe. Also such platforms usually can not play video confortably, so |
461 | * it's not so important to make the blocksize shorter. If the platform | | 461 | * it's not so important to make the blocksize shorter. If the platform |
462 | * defines its own value as __AUDIO_BLK_MS in its <machine/param.h>, it | | 462 | * defines its own value as __AUDIO_BLK_MS in its <machine/param.h>, it |
463 | * uses this instead. | | 463 | * uses this instead. |
464 | * | | 464 | * |
465 | * In either case, you can overwrite AUDIO_BLK_MS by your kernel | | 465 | * In either case, you can overwrite AUDIO_BLK_MS by your kernel |
466 | * configuration file if you wish. | | 466 | * configuration file if you wish. |
467 | */ | | 467 | */ |
468 | #if !defined(AUDIO_BLK_MS) | | 468 | #if !defined(AUDIO_BLK_MS) |
469 | # if defined(__AUDIO_BLK_MS) | | 469 | # if defined(__AUDIO_BLK_MS) |
470 | # define AUDIO_BLK_MS __AUDIO_BLK_MS | | 470 | # define AUDIO_BLK_MS __AUDIO_BLK_MS |
471 | # else | | 471 | # else |
472 | # define AUDIO_BLK_MS (10) | | 472 | # define AUDIO_BLK_MS (10) |
473 | # endif | | 473 | # endif |
474 | #endif | | 474 | #endif |
475 | | | 475 | |
476 | /* Device timeout in msec */ | | 476 | /* Device timeout in msec */ |
477 | #define AUDIO_TIMEOUT (3000) | | 477 | #define AUDIO_TIMEOUT (3000) |
478 | | | 478 | |
479 | /* #define AUDIO_PM_IDLE */ | | 479 | /* #define AUDIO_PM_IDLE */ |
480 | #ifdef AUDIO_PM_IDLE | | 480 | #ifdef AUDIO_PM_IDLE |
481 | int audio_idle_timeout = 30; | | 481 | int audio_idle_timeout = 30; |
482 | #endif | | 482 | #endif |
483 | | | 483 | |
484 | /* Number of elements of async mixer's pid */ | | 484 | /* Number of elements of async mixer's pid */ |
485 | #define AM_CAPACITY (4) | | 485 | #define AM_CAPACITY (4) |
486 | | | 486 | |
487 | struct portname { | | 487 | struct portname { |
488 | const char *name; | | 488 | const char *name; |
489 | int mask; | | 489 | int mask; |
490 | }; | | 490 | }; |
491 | | | 491 | |
492 | static int audiomatch(device_t, cfdata_t, void *); | | 492 | static int audiomatch(device_t, cfdata_t, void *); |
493 | static void audioattach(device_t, device_t, void *); | | 493 | static void audioattach(device_t, device_t, void *); |
494 | static int audiodetach(device_t, int); | | 494 | static int audiodetach(device_t, int); |
495 | static int audioactivate(device_t, enum devact); | | 495 | static int audioactivate(device_t, enum devact); |
496 | static void audiochilddet(device_t, device_t); | | 496 | static void audiochilddet(device_t, device_t); |
497 | static int audiorescan(device_t, const char *, const int *); | | 497 | static int audiorescan(device_t, const char *, const int *); |
498 | | | 498 | |
499 | static int audio_modcmd(modcmd_t, void *); | | 499 | static int audio_modcmd(modcmd_t, void *); |
500 | | | 500 | |
501 | #ifdef AUDIO_PM_IDLE | | 501 | #ifdef AUDIO_PM_IDLE |
502 | static void audio_idle(void *); | | 502 | static void audio_idle(void *); |
503 | static void audio_activity(device_t, devactive_t); | | 503 | static void audio_activity(device_t, devactive_t); |
504 | #endif | | 504 | #endif |
505 | | | 505 | |
506 | static bool audio_suspend(device_t dv, const pmf_qual_t *); | | 506 | static bool audio_suspend(device_t dv, const pmf_qual_t *); |
507 | static bool audio_resume(device_t dv, const pmf_qual_t *); | | 507 | static bool audio_resume(device_t dv, const pmf_qual_t *); |
508 | static void audio_volume_down(device_t); | | 508 | static void audio_volume_down(device_t); |
509 | static void audio_volume_up(device_t); | | 509 | static void audio_volume_up(device_t); |
510 | static void audio_volume_toggle(device_t); | | 510 | static void audio_volume_toggle(device_t); |
511 | | | 511 | |
512 | static void audio_mixer_capture(struct audio_softc *); | | 512 | static void audio_mixer_capture(struct audio_softc *); |
513 | static void audio_mixer_restore(struct audio_softc *); | | 513 | static void audio_mixer_restore(struct audio_softc *); |
514 | | | 514 | |
515 | static void audio_softintr_rd(void *); | | 515 | static void audio_softintr_rd(void *); |
516 | static void audio_softintr_wr(void *); | | 516 | static void audio_softintr_wr(void *); |
517 | | | 517 | |
518 | static void audio_printf(struct audio_softc *, const char *, ...) | | 518 | static void audio_printf(struct audio_softc *, const char *, ...) |
519 | __printflike(2, 3); | | 519 | __printflike(2, 3); |
520 | static int audio_exlock_mutex_enter(struct audio_softc *); | | 520 | static int audio_exlock_mutex_enter(struct audio_softc *); |
521 | static void audio_exlock_mutex_exit(struct audio_softc *); | | 521 | static void audio_exlock_mutex_exit(struct audio_softc *); |
522 | static int audio_exlock_enter(struct audio_softc *); | | 522 | static int audio_exlock_enter(struct audio_softc *); |
523 | static void audio_exlock_exit(struct audio_softc *); | | 523 | static void audio_exlock_exit(struct audio_softc *); |
524 | static void audio_sc_acquire_foropen(struct audio_softc *, struct psref *); | | 524 | static void audio_sc_acquire_foropen(struct audio_softc *, struct psref *); |
525 | static struct audio_softc *audio_sc_acquire_fromfile(audio_file_t *, | | 525 | static struct audio_softc *audio_sc_acquire_fromfile(audio_file_t *, |
526 | struct psref *); | | 526 | struct psref *); |
527 | static void audio_sc_release(struct audio_softc *, struct psref *); | | 527 | static void audio_sc_release(struct audio_softc *, struct psref *); |
528 | static int audio_track_waitio(struct audio_softc *, audio_track_t *); | | 528 | static int audio_track_waitio(struct audio_softc *, audio_track_t *); |
529 | | | 529 | |
530 | static int audioclose(struct file *); | | 530 | static int audioclose(struct file *); |
531 | static int audioread(struct file *, off_t *, struct uio *, kauth_cred_t, int); | | 531 | static int audioread(struct file *, off_t *, struct uio *, kauth_cred_t, int); |
532 | static int audiowrite(struct file *, off_t *, struct uio *, kauth_cred_t, int); | | 532 | static int audiowrite(struct file *, off_t *, struct uio *, kauth_cred_t, int); |
533 | static int audioioctl(struct file *, u_long, void *); | | 533 | static int audioioctl(struct file *, u_long, void *); |
534 | static int audiopoll(struct file *, int); | | 534 | static int audiopoll(struct file *, int); |
535 | static int audiokqfilter(struct file *, struct knote *); | | 535 | static int audiokqfilter(struct file *, struct knote *); |
536 | static int audiommap(struct file *, off_t *, size_t, int, int *, int *, | | 536 | static int audiommap(struct file *, off_t *, size_t, int, int *, int *, |
537 | struct uvm_object **, int *); | | 537 | struct uvm_object **, int *); |
538 | static int audiostat(struct file *, struct stat *); | | 538 | static int audiostat(struct file *, struct stat *); |
539 | | | 539 | |
540 | static void filt_audiowrite_detach(struct knote *); | | 540 | static void filt_audiowrite_detach(struct knote *); |
541 | static int filt_audiowrite_event(struct knote *, long); | | 541 | static int filt_audiowrite_event(struct knote *, long); |
542 | static void filt_audioread_detach(struct knote *); | | 542 | static void filt_audioread_detach(struct knote *); |
543 | static int filt_audioread_event(struct knote *, long); | | 543 | static int filt_audioread_event(struct knote *, long); |
544 | | | 544 | |
545 | static int audio_open(dev_t, struct audio_softc *, int, int, struct lwp *, | | 545 | static int audio_open(dev_t, struct audio_softc *, int, int, struct lwp *, |
546 | audio_file_t **); | | 546 | audio_file_t **); |
547 | static int audio_close(struct audio_softc *, audio_file_t *); | | 547 | static int audio_close(struct audio_softc *, audio_file_t *); |
548 | static int audio_unlink(struct audio_softc *, audio_file_t *); | | 548 | static int audio_unlink(struct audio_softc *, audio_file_t *); |
549 | static int audio_read(struct audio_softc *, struct uio *, int, audio_file_t *); | | 549 | static int audio_read(struct audio_softc *, struct uio *, int, audio_file_t *); |
550 | static int audio_write(struct audio_softc *, struct uio *, int, audio_file_t *); | | 550 | static int audio_write(struct audio_softc *, struct uio *, int, audio_file_t *); |
551 | static void audio_file_clear(struct audio_softc *, audio_file_t *); | | 551 | static void audio_file_clear(struct audio_softc *, audio_file_t *); |
552 | static int audio_ioctl(dev_t, struct audio_softc *, u_long, void *, int, | | 552 | static int audio_ioctl(dev_t, struct audio_softc *, u_long, void *, int, |
553 | struct lwp *, audio_file_t *); | | 553 | struct lwp *, audio_file_t *); |
554 | static int audio_poll(struct audio_softc *, int, struct lwp *, audio_file_t *); | | 554 | static int audio_poll(struct audio_softc *, int, struct lwp *, audio_file_t *); |
555 | static int audio_kqfilter(struct audio_softc *, audio_file_t *, struct knote *); | | 555 | static int audio_kqfilter(struct audio_softc *, audio_file_t *, struct knote *); |
556 | static int audio_mmap(struct audio_softc *, off_t *, size_t, int, int *, int *, | | 556 | static int audio_mmap(struct audio_softc *, off_t *, size_t, int, int *, int *, |
557 | struct uvm_object **, int *, audio_file_t *); | | 557 | struct uvm_object **, int *, audio_file_t *); |
558 | | | 558 | |
559 | static int audioctl_open(dev_t, struct audio_softc *, int, int, struct lwp *); | | 559 | static int audioctl_open(dev_t, struct audio_softc *, int, int, struct lwp *); |
560 | | | 560 | |
561 | static void audio_pintr(void *); | | 561 | static void audio_pintr(void *); |
562 | static void audio_rintr(void *); | | 562 | static void audio_rintr(void *); |
563 | | | 563 | |
564 | static int audio_query_devinfo(struct audio_softc *, mixer_devinfo_t *); | | 564 | static int audio_query_devinfo(struct audio_softc *, mixer_devinfo_t *); |
565 | | | 565 | |
566 | static __inline int audio_track_readablebytes(const audio_track_t *); | | 566 | static __inline int audio_track_readablebytes(const audio_track_t *); |
567 | static int audio_file_setinfo(struct audio_softc *, audio_file_t *, | | 567 | static int audio_file_setinfo(struct audio_softc *, audio_file_t *, |
568 | const struct audio_info *); | | 568 | const struct audio_info *); |
569 | static int audio_track_setinfo_check(audio_track_t *, | | 569 | static int audio_track_setinfo_check(audio_track_t *, |
570 | audio_format2_t *, const struct audio_prinfo *); | | 570 | audio_format2_t *, const struct audio_prinfo *); |
571 | static void audio_track_setinfo_water(audio_track_t *, | | 571 | static void audio_track_setinfo_water(audio_track_t *, |
572 | const struct audio_info *); | | 572 | const struct audio_info *); |
573 | static int audio_hw_setinfo(struct audio_softc *, const struct audio_info *, | | 573 | static int audio_hw_setinfo(struct audio_softc *, const struct audio_info *, |
574 | struct audio_info *); | | 574 | struct audio_info *); |
575 | static int audio_hw_set_format(struct audio_softc *, int, | | 575 | static int audio_hw_set_format(struct audio_softc *, int, |
576 | const audio_format2_t *, const audio_format2_t *, | | 576 | const audio_format2_t *, const audio_format2_t *, |
577 | audio_filter_reg_t *, audio_filter_reg_t *); | | 577 | audio_filter_reg_t *, audio_filter_reg_t *); |
578 | static int audiogetinfo(struct audio_softc *, struct audio_info *, int, | | 578 | static int audiogetinfo(struct audio_softc *, struct audio_info *, int, |
579 | audio_file_t *); | | 579 | audio_file_t *); |
580 | static bool audio_can_playback(struct audio_softc *); | | 580 | static bool audio_can_playback(struct audio_softc *); |
581 | static bool audio_can_capture(struct audio_softc *); | | 581 | static bool audio_can_capture(struct audio_softc *); |
582 | static int audio_check_params(audio_format2_t *); | | 582 | static int audio_check_params(audio_format2_t *); |
583 | static int audio_mixers_init(struct audio_softc *sc, int, | | 583 | static int audio_mixers_init(struct audio_softc *sc, int, |
584 | const audio_format2_t *, const audio_format2_t *, | | 584 | const audio_format2_t *, const audio_format2_t *, |
585 | const audio_filter_reg_t *, const audio_filter_reg_t *); | | 585 | const audio_filter_reg_t *, const audio_filter_reg_t *); |
586 | static int audio_select_freq(const struct audio_format *); | | 586 | static int audio_select_freq(const struct audio_format *); |
587 | static int audio_hw_probe(struct audio_softc *, audio_format2_t *, int); | | 587 | static int audio_hw_probe(struct audio_softc *, audio_format2_t *, int); |
588 | static int audio_hw_validate_format(struct audio_softc *, int, | | 588 | static int audio_hw_validate_format(struct audio_softc *, int, |
589 | const audio_format2_t *); | | 589 | const audio_format2_t *); |
590 | static int audio_mixers_set_format(struct audio_softc *, | | 590 | static int audio_mixers_set_format(struct audio_softc *, |
591 | const struct audio_info *); | | 591 | const struct audio_info *); |
592 | static void audio_mixers_get_format(struct audio_softc *, struct audio_info *); | | 592 | static void audio_mixers_get_format(struct audio_softc *, struct audio_info *); |
593 | static int audio_sysctl_blk_ms(SYSCTLFN_PROTO); | | 593 | static int audio_sysctl_blk_ms(SYSCTLFN_PROTO); |
594 | static int audio_sysctl_multiuser(SYSCTLFN_PROTO); | | 594 | static int audio_sysctl_multiuser(SYSCTLFN_PROTO); |
595 | #if defined(AUDIO_DEBUG) | | 595 | #if defined(AUDIO_DEBUG) |
596 | static int audio_sysctl_debug(SYSCTLFN_PROTO); | | 596 | static int audio_sysctl_debug(SYSCTLFN_PROTO); |
597 | static void audio_format2_tostr(char *, size_t, const audio_format2_t *); | | 597 | static void audio_format2_tostr(char *, size_t, const audio_format2_t *); |
598 | static void audio_print_format2(const char *, const audio_format2_t *) __unused; | | 598 | static void audio_print_format2(const char *, const audio_format2_t *) __unused; |
599 | #endif | | 599 | #endif |
600 | | | 600 | |
601 | static void *audio_realloc(void *, size_t); | | 601 | static void *audio_realloc(void *, size_t); |
602 | static int audio_realloc_usrbuf(audio_track_t *, int); | | 602 | static int audio_realloc_usrbuf(audio_track_t *, int); |
603 | static void audio_free_usrbuf(audio_track_t *); | | 603 | static void audio_free_usrbuf(audio_track_t *); |
604 | | | 604 | |
605 | static audio_track_t *audio_track_create(struct audio_softc *, | | 605 | static audio_track_t *audio_track_create(struct audio_softc *, |
606 | audio_trackmixer_t *); | | 606 | audio_trackmixer_t *); |
607 | static void audio_track_destroy(audio_track_t *); | | 607 | static void audio_track_destroy(audio_track_t *); |
608 | static audio_filter_t audio_track_get_codec(audio_track_t *, | | 608 | static audio_filter_t audio_track_get_codec(audio_track_t *, |
609 | const audio_format2_t *, const audio_format2_t *); | | 609 | const audio_format2_t *, const audio_format2_t *); |
610 | static int audio_track_set_format(audio_track_t *, audio_format2_t *); | | 610 | static int audio_track_set_format(audio_track_t *, audio_format2_t *); |
611 | static void audio_track_play(audio_track_t *); | | 611 | static void audio_track_play(audio_track_t *); |
612 | static int audio_track_drain(struct audio_softc *, audio_track_t *); | | 612 | static int audio_track_drain(struct audio_softc *, audio_track_t *); |
613 | static void audio_track_record(audio_track_t *); | | 613 | static void audio_track_record(audio_track_t *); |
614 | static void audio_track_clear(struct audio_softc *, audio_track_t *); | | 614 | static void audio_track_clear(struct audio_softc *, audio_track_t *); |
615 | | | 615 | |
616 | static int audio_mixer_init(struct audio_softc *, int, | | 616 | static int audio_mixer_init(struct audio_softc *, int, |
617 | const audio_format2_t *, const audio_filter_reg_t *); | | 617 | const audio_format2_t *, const audio_filter_reg_t *); |
618 | static void audio_mixer_destroy(struct audio_softc *, audio_trackmixer_t *); | | 618 | static void audio_mixer_destroy(struct audio_softc *, audio_trackmixer_t *); |
619 | static void audio_pmixer_start(struct audio_softc *, bool); | | 619 | static void audio_pmixer_start(struct audio_softc *, bool); |
620 | static void audio_pmixer_process(struct audio_softc *); | | 620 | static void audio_pmixer_process(struct audio_softc *); |
621 | static void audio_pmixer_agc(audio_trackmixer_t *, int); | | 621 | static void audio_pmixer_agc(audio_trackmixer_t *, int); |
622 | static int audio_pmixer_mix_track(audio_trackmixer_t *, audio_track_t *, int); | | 622 | static int audio_pmixer_mix_track(audio_trackmixer_t *, audio_track_t *, int); |
623 | static void audio_pmixer_output(struct audio_softc *); | | 623 | static void audio_pmixer_output(struct audio_softc *); |
624 | static int audio_pmixer_halt(struct audio_softc *); | | 624 | static int audio_pmixer_halt(struct audio_softc *); |
625 | static void audio_rmixer_start(struct audio_softc *); | | 625 | static void audio_rmixer_start(struct audio_softc *); |
626 | static void audio_rmixer_process(struct audio_softc *); | | 626 | static void audio_rmixer_process(struct audio_softc *); |
627 | static void audio_rmixer_input(struct audio_softc *); | | 627 | static void audio_rmixer_input(struct audio_softc *); |
628 | static int audio_rmixer_halt(struct audio_softc *); | | 628 | static int audio_rmixer_halt(struct audio_softc *); |
629 | | | 629 | |
630 | static void mixer_init(struct audio_softc *); | | 630 | static void mixer_init(struct audio_softc *); |
631 | static int mixer_open(dev_t, struct audio_softc *, int, int, struct lwp *); | | 631 | static int mixer_open(dev_t, struct audio_softc *, int, int, struct lwp *); |
632 | static int mixer_close(struct audio_softc *, audio_file_t *); | | 632 | static int mixer_close(struct audio_softc *, audio_file_t *); |
633 | static int mixer_ioctl(struct audio_softc *, u_long, void *, int, struct lwp *); | | 633 | static int mixer_ioctl(struct audio_softc *, u_long, void *, int, struct lwp *); |
634 | static void mixer_async_add(struct audio_softc *, pid_t); | | 634 | static void mixer_async_add(struct audio_softc *, pid_t); |
635 | static void mixer_async_remove(struct audio_softc *, pid_t); | | 635 | static void mixer_async_remove(struct audio_softc *, pid_t); |
636 | static void mixer_signal(struct audio_softc *); | | 636 | static void mixer_signal(struct audio_softc *); |
637 | | | 637 | |
638 | static int au_portof(struct audio_softc *, char *, int); | | 638 | static int au_portof(struct audio_softc *, char *, int); |
639 | | | 639 | |
640 | static void au_setup_ports(struct audio_softc *, struct au_mixer_ports *, | | 640 | static void au_setup_ports(struct audio_softc *, struct au_mixer_ports *, |
641 | mixer_devinfo_t *, const struct portname *); | | 641 | mixer_devinfo_t *, const struct portname *); |
642 | static int au_set_lr_value(struct audio_softc *, mixer_ctrl_t *, int, int); | | 642 | static int au_set_lr_value(struct audio_softc *, mixer_ctrl_t *, int, int); |
643 | static int au_get_lr_value(struct audio_softc *, mixer_ctrl_t *, int *, int *); | | 643 | static int au_get_lr_value(struct audio_softc *, mixer_ctrl_t *, int *, int *); |
644 | static int au_set_gain(struct audio_softc *, struct au_mixer_ports *, int, int); | | 644 | static int au_set_gain(struct audio_softc *, struct au_mixer_ports *, int, int); |
645 | static void au_get_gain(struct audio_softc *, struct au_mixer_ports *, | | 645 | static void au_get_gain(struct audio_softc *, struct au_mixer_ports *, |
646 | u_int *, u_char *); | | 646 | u_int *, u_char *); |
647 | static int au_set_port(struct audio_softc *, struct au_mixer_ports *, u_int); | | 647 | static int au_set_port(struct audio_softc *, struct au_mixer_ports *, u_int); |
648 | static int au_get_port(struct audio_softc *, struct au_mixer_ports *); | | 648 | static int au_get_port(struct audio_softc *, struct au_mixer_ports *); |
649 | static int au_set_monitor_gain(struct audio_softc *, int); | | 649 | static int au_set_monitor_gain(struct audio_softc *, int); |
650 | static int au_get_monitor_gain(struct audio_softc *); | | 650 | static int au_get_monitor_gain(struct audio_softc *); |
651 | static int audio_get_port(struct audio_softc *, mixer_ctrl_t *); | | 651 | static int audio_get_port(struct audio_softc *, mixer_ctrl_t *); |
652 | static int audio_set_port(struct audio_softc *, mixer_ctrl_t *); | | 652 | static int audio_set_port(struct audio_softc *, mixer_ctrl_t *); |
653 | | | 653 | |
654 | static __inline struct audio_params | | 654 | static __inline struct audio_params |
655 | format2_to_params(const audio_format2_t *f2) | | 655 | format2_to_params(const audio_format2_t *f2) |
656 | { | | 656 | { |
657 | audio_params_t p; | | 657 | audio_params_t p; |
658 | | | 658 | |
659 | /* validbits/precision <-> precision/stride */ | | 659 | /* validbits/precision <-> precision/stride */ |
660 | p.sample_rate = f2->sample_rate; | | 660 | p.sample_rate = f2->sample_rate; |
661 | p.channels = f2->channels; | | 661 | p.channels = f2->channels; |
662 | p.encoding = f2->encoding; | | 662 | p.encoding = f2->encoding; |
663 | p.validbits = f2->precision; | | 663 | p.validbits = f2->precision; |
664 | p.precision = f2->stride; | | 664 | p.precision = f2->stride; |
665 | return p; | | 665 | return p; |
666 | } | | 666 | } |
667 | | | 667 | |
668 | static __inline audio_format2_t | | 668 | static __inline audio_format2_t |
669 | params_to_format2(const struct audio_params *p) | | 669 | params_to_format2(const struct audio_params *p) |
670 | { | | 670 | { |
671 | audio_format2_t f2; | | 671 | audio_format2_t f2; |
672 | | | 672 | |
673 | /* precision/stride <-> validbits/precision */ | | 673 | /* precision/stride <-> validbits/precision */ |
674 | f2.sample_rate = p->sample_rate; | | 674 | f2.sample_rate = p->sample_rate; |
675 | f2.channels = p->channels; | | 675 | f2.channels = p->channels; |
676 | f2.encoding = p->encoding; | | 676 | f2.encoding = p->encoding; |
677 | f2.precision = p->validbits; | | 677 | f2.precision = p->validbits; |
678 | f2.stride = p->precision; | | 678 | f2.stride = p->precision; |
679 | return f2; | | 679 | return f2; |
680 | } | | 680 | } |
681 | | | 681 | |
682 | /* Return true if this track is a playback track. */ | | 682 | /* Return true if this track is a playback track. */ |
683 | static __inline bool | | 683 | static __inline bool |
684 | audio_track_is_playback(const audio_track_t *track) | | 684 | audio_track_is_playback(const audio_track_t *track) |
685 | { | | 685 | { |
686 | | | 686 | |
687 | return ((track->mode & AUMODE_PLAY) != 0); | | 687 | return ((track->mode & AUMODE_PLAY) != 0); |
688 | } | | 688 | } |
689 | | | 689 | |
690 | /* Return true if this track is a recording track. */ | | 690 | /* Return true if this track is a recording track. */ |
691 | static __inline bool | | 691 | static __inline bool |
692 | audio_track_is_record(const audio_track_t *track) | | 692 | audio_track_is_record(const audio_track_t *track) |
693 | { | | 693 | { |
694 | | | 694 | |
695 | return ((track->mode & AUMODE_RECORD) != 0); | | 695 | return ((track->mode & AUMODE_RECORD) != 0); |
696 | } | | 696 | } |
697 | | | 697 | |
698 | #if 0 /* XXX Not used yet */ | | 698 | #if 0 /* XXX Not used yet */ |
699 | /* | | 699 | /* |
700 | * Convert 0..255 volume used in userland to internal presentation 0..256. | | 700 | * Convert 0..255 volume used in userland to internal presentation 0..256. |
701 | */ | | 701 | */ |
702 | static __inline u_int | | 702 | static __inline u_int |
703 | audio_volume_to_inner(u_int v) | | 703 | audio_volume_to_inner(u_int v) |
704 | { | | 704 | { |
705 | | | 705 | |
706 | return v < 127 ? v : v + 1; | | 706 | return v < 127 ? v : v + 1; |
707 | } | | 707 | } |
708 | | | 708 | |
709 | /* | | 709 | /* |
710 | * Convert 0..256 internal presentation to 0..255 volume used in userland. | | 710 | * Convert 0..256 internal presentation to 0..255 volume used in userland. |
711 | */ | | 711 | */ |
712 | static __inline u_int | | 712 | static __inline u_int |
713 | audio_volume_to_outer(u_int v) | | 713 | audio_volume_to_outer(u_int v) |
714 | { | | 714 | { |
715 | | | 715 | |
716 | return v < 127 ? v : v - 1; | | 716 | return v < 127 ? v : v - 1; |
717 | } | | 717 | } |
718 | #endif /* 0 */ | | 718 | #endif /* 0 */ |
719 | | | 719 | |
720 | static dev_type_open(audioopen); | | 720 | static dev_type_open(audioopen); |
721 | /* XXXMRG use more dev_type_xxx */ | | 721 | /* XXXMRG use more dev_type_xxx */ |
722 | | | 722 | |
723 | const struct cdevsw audio_cdevsw = { | | 723 | const struct cdevsw audio_cdevsw = { |
724 | .d_open = audioopen, | | 724 | .d_open = audioopen, |
725 | .d_close = noclose, | | 725 | .d_close = noclose, |
726 | .d_read = noread, | | 726 | .d_read = noread, |
727 | .d_write = nowrite, | | 727 | .d_write = nowrite, |
728 | .d_ioctl = noioctl, | | 728 | .d_ioctl = noioctl, |
729 | .d_stop = nostop, | | 729 | .d_stop = nostop, |
730 | .d_tty = notty, | | 730 | .d_tty = notty, |
731 | .d_poll = nopoll, | | 731 | .d_poll = nopoll, |
732 | .d_mmap = nommap, | | 732 | .d_mmap = nommap, |
733 | .d_kqfilter = nokqfilter, | | 733 | .d_kqfilter = nokqfilter, |
734 | .d_discard = nodiscard, | | 734 | .d_discard = nodiscard, |
735 | .d_flag = D_OTHER | D_MPSAFE | | 735 | .d_flag = D_OTHER | D_MPSAFE |
736 | }; | | 736 | }; |
737 | | | 737 | |
738 | const struct fileops audio_fileops = { | | 738 | const struct fileops audio_fileops = { |
739 | .fo_name = "audio", | | 739 | .fo_name = "audio", |
740 | .fo_read = audioread, | | 740 | .fo_read = audioread, |
741 | .fo_write = audiowrite, | | 741 | .fo_write = audiowrite, |
742 | .fo_ioctl = audioioctl, | | 742 | .fo_ioctl = audioioctl, |
743 | .fo_fcntl = fnullop_fcntl, | | 743 | .fo_fcntl = fnullop_fcntl, |
744 | .fo_stat = audiostat, | | 744 | .fo_stat = audiostat, |
745 | .fo_poll = audiopoll, | | 745 | .fo_poll = audiopoll, |
746 | .fo_close = audioclose, | | 746 | .fo_close = audioclose, |
747 | .fo_mmap = audiommap, | | 747 | .fo_mmap = audiommap, |
748 | .fo_kqfilter = audiokqfilter, | | 748 | .fo_kqfilter = audiokqfilter, |
749 | .fo_restart = fnullop_restart | | 749 | .fo_restart = fnullop_restart |
750 | }; | | 750 | }; |
751 | | | 751 | |
752 | /* The default audio mode: 8 kHz mono mu-law */ | | 752 | /* The default audio mode: 8 kHz mono mu-law */ |
753 | static const struct audio_params audio_default = { | | 753 | static const struct audio_params audio_default = { |
754 | .sample_rate = 8000, | | 754 | .sample_rate = 8000, |
755 | .encoding = AUDIO_ENCODING_ULAW, | | 755 | .encoding = AUDIO_ENCODING_ULAW, |
756 | .precision = 8, | | 756 | .precision = 8, |
757 | .validbits = 8, | | 757 | .validbits = 8, |
758 | .channels = 1, | | 758 | .channels = 1, |
759 | }; | | 759 | }; |
760 | | | 760 | |
761 | static const char *encoding_names[] = { | | 761 | static const char *encoding_names[] = { |
762 | "none", | | 762 | "none", |
763 | AudioEmulaw, | | 763 | AudioEmulaw, |
764 | AudioEalaw, | | 764 | AudioEalaw, |
765 | "pcm16", | | 765 | "pcm16", |
766 | "pcm8", | | 766 | "pcm8", |
767 | AudioEadpcm, | | 767 | AudioEadpcm, |
768 | AudioEslinear_le, | | 768 | AudioEslinear_le, |
769 | AudioEslinear_be, | | 769 | AudioEslinear_be, |
770 | AudioEulinear_le, | | 770 | AudioEulinear_le, |
771 | AudioEulinear_be, | | 771 | AudioEulinear_be, |
772 | AudioEslinear, | | 772 | AudioEslinear, |
773 | AudioEulinear, | | 773 | AudioEulinear, |
774 | AudioEmpeg_l1_stream, | | 774 | AudioEmpeg_l1_stream, |
775 | AudioEmpeg_l1_packets, | | 775 | AudioEmpeg_l1_packets, |
776 | AudioEmpeg_l1_system, | | 776 | AudioEmpeg_l1_system, |
777 | AudioEmpeg_l2_stream, | | 777 | AudioEmpeg_l2_stream, |
778 | AudioEmpeg_l2_packets, | | 778 | AudioEmpeg_l2_packets, |
779 | AudioEmpeg_l2_system, | | 779 | AudioEmpeg_l2_system, |
780 | AudioEac3, | | 780 | AudioEac3, |
781 | }; | | 781 | }; |
782 | | | 782 | |
783 | /* | | 783 | /* |
784 | * Returns encoding name corresponding to AUDIO_ENCODING_*. | | 784 | * Returns encoding name corresponding to AUDIO_ENCODING_*. |
785 | * Note that it may return a local buffer because it is mainly for debugging. | | 785 | * Note that it may return a local buffer because it is mainly for debugging. |
786 | */ | | 786 | */ |
787 | const char * | | 787 | const char * |
788 | audio_encoding_name(int encoding) | | 788 | audio_encoding_name(int encoding) |
789 | { | | 789 | { |
790 | static char buf[16]; | | 790 | static char buf[16]; |
791 | | | 791 | |
792 | if (0 <= encoding && encoding < __arraycount(encoding_names)) { | | 792 | if (0 <= encoding && encoding < __arraycount(encoding_names)) { |
793 | return encoding_names[encoding]; | | 793 | return encoding_names[encoding]; |
794 | } else { | | 794 | } else { |
795 | snprintf(buf, sizeof(buf), "enc=%d", encoding); | | 795 | snprintf(buf, sizeof(buf), "enc=%d", encoding); |
796 | return buf; | | 796 | return buf; |
797 | } | | 797 | } |
798 | } | | 798 | } |
799 | | | 799 | |
800 | /* | | 800 | /* |
801 | * Supported encodings used by AUDIO_GETENC. | | 801 | * Supported encodings used by AUDIO_GETENC. |
802 | * index and flags are set by code. | | 802 | * index and flags are set by code. |
803 | * XXX is there any needs for SLINEAR_OE:>=16/ULINEAR_OE:>=16 ? | | 803 | * XXX is there any needs for SLINEAR_OE:>=16/ULINEAR_OE:>=16 ? |
804 | */ | | 804 | */ |
805 | static const audio_encoding_t audio_encodings[] = { | | 805 | static const audio_encoding_t audio_encodings[] = { |
806 | { 0, AudioEmulaw, AUDIO_ENCODING_ULAW, 8, 0 }, | | 806 | { 0, AudioEmulaw, AUDIO_ENCODING_ULAW, 8, 0 }, |
807 | { 0, AudioEalaw, AUDIO_ENCODING_ALAW, 8, 0 }, | | 807 | { 0, AudioEalaw, AUDIO_ENCODING_ALAW, 8, 0 }, |
808 | { 0, AudioEslinear, AUDIO_ENCODING_SLINEAR, 8, 0 }, | | 808 | { 0, AudioEslinear, AUDIO_ENCODING_SLINEAR, 8, 0 }, |
809 | { 0, AudioEulinear, AUDIO_ENCODING_ULINEAR, 8, 0 }, | | 809 | { 0, AudioEulinear, AUDIO_ENCODING_ULINEAR, 8, 0 }, |
810 | { 0, AudioEslinear_le, AUDIO_ENCODING_SLINEAR_LE, 16, 0 }, | | 810 | { 0, AudioEslinear_le, AUDIO_ENCODING_SLINEAR_LE, 16, 0 }, |
811 | { 0, AudioEulinear_le, AUDIO_ENCODING_ULINEAR_LE, 16, 0 }, | | 811 | { 0, AudioEulinear_le, AUDIO_ENCODING_ULINEAR_LE, 16, 0 }, |
812 | { 0, AudioEslinear_be, AUDIO_ENCODING_SLINEAR_BE, 16, 0 }, | | 812 | { 0, AudioEslinear_be, AUDIO_ENCODING_SLINEAR_BE, 16, 0 }, |
813 | { 0, AudioEulinear_be, AUDIO_ENCODING_ULINEAR_BE, 16, 0 }, | | 813 | { 0, AudioEulinear_be, AUDIO_ENCODING_ULINEAR_BE, 16, 0 }, |
814 | #if defined(AUDIO_SUPPORT_LINEAR24) | | 814 | #if defined(AUDIO_SUPPORT_LINEAR24) |
815 | { 0, AudioEslinear_le, AUDIO_ENCODING_SLINEAR_LE, 24, 0 }, | | 815 | { 0, AudioEslinear_le, AUDIO_ENCODING_SLINEAR_LE, 24, 0 }, |
816 | { 0, AudioEulinear_le, AUDIO_ENCODING_ULINEAR_LE, 24, 0 }, | | 816 | { 0, AudioEulinear_le, AUDIO_ENCODING_ULINEAR_LE, 24, 0 }, |
817 | { 0, AudioEslinear_be, AUDIO_ENCODING_SLINEAR_BE, 24, 0 }, | | 817 | { 0, AudioEslinear_be, AUDIO_ENCODING_SLINEAR_BE, 24, 0 }, |
818 | { 0, AudioEulinear_be, AUDIO_ENCODING_ULINEAR_BE, 24, 0 }, | | 818 | { 0, AudioEulinear_be, AUDIO_ENCODING_ULINEAR_BE, 24, 0 }, |
819 | #endif | | 819 | #endif |
820 | { 0, AudioEslinear_le, AUDIO_ENCODING_SLINEAR_LE, 32, 0 }, | | 820 | { 0, AudioEslinear_le, AUDIO_ENCODING_SLINEAR_LE, 32, 0 }, |
821 | { 0, AudioEulinear_le, AUDIO_ENCODING_ULINEAR_LE, 32, 0 }, | | 821 | { 0, AudioEulinear_le, AUDIO_ENCODING_ULINEAR_LE, 32, 0 }, |
822 | { 0, AudioEslinear_be, AUDIO_ENCODING_SLINEAR_BE, 32, 0 }, | | 822 | { 0, AudioEslinear_be, AUDIO_ENCODING_SLINEAR_BE, 32, 0 }, |
823 | { 0, AudioEulinear_be, AUDIO_ENCODING_ULINEAR_BE, 32, 0 }, | | 823 | { 0, AudioEulinear_be, AUDIO_ENCODING_ULINEAR_BE, 32, 0 }, |
824 | }; | | 824 | }; |
825 | | | 825 | |
826 | static const struct portname itable[] = { | | 826 | static const struct portname itable[] = { |
827 | { AudioNmicrophone, AUDIO_MICROPHONE }, | | 827 | { AudioNmicrophone, AUDIO_MICROPHONE }, |
828 | { AudioNline, AUDIO_LINE_IN }, | | 828 | { AudioNline, AUDIO_LINE_IN }, |
829 | { AudioNcd, AUDIO_CD }, | | 829 | { AudioNcd, AUDIO_CD }, |
830 | { 0, 0 } | | 830 | { 0, 0 } |
831 | }; | | 831 | }; |
832 | static const struct portname otable[] = { | | 832 | static const struct portname otable[] = { |
833 | { AudioNspeaker, AUDIO_SPEAKER }, | | 833 | { AudioNspeaker, AUDIO_SPEAKER }, |
834 | { AudioNheadphone, AUDIO_HEADPHONE }, | | 834 | { AudioNheadphone, AUDIO_HEADPHONE }, |
835 | { AudioNline, AUDIO_LINE_OUT }, | | 835 | { AudioNline, AUDIO_LINE_OUT }, |
836 | { 0, 0 } | | 836 | { 0, 0 } |
837 | }; | | 837 | }; |
838 | | | 838 | |
839 | static struct psref_class *audio_psref_class __read_mostly; | | 839 | static struct psref_class *audio_psref_class __read_mostly; |
840 | | | 840 | |
841 | CFATTACH_DECL3_NEW(audio, sizeof(struct audio_softc), | | 841 | CFATTACH_DECL3_NEW(audio, sizeof(struct audio_softc), |
842 | audiomatch, audioattach, audiodetach, audioactivate, audiorescan, | | 842 | audiomatch, audioattach, audiodetach, audioactivate, audiorescan, |
843 | audiochilddet, DVF_DETACH_SHUTDOWN); | | 843 | audiochilddet, DVF_DETACH_SHUTDOWN); |
844 | | | 844 | |
845 | static int | | 845 | static int |
846 | audiomatch(device_t parent, cfdata_t match, void *aux) | | 846 | audiomatch(device_t parent, cfdata_t match, void *aux) |
847 | { | | 847 | { |
848 | struct audio_attach_args *sa; | | 848 | struct audio_attach_args *sa; |
849 | | | 849 | |
850 | sa = aux; | | 850 | sa = aux; |
851 | DPRINTF(1, "%s: type=%d sa=%p hw=%p\n", | | 851 | DPRINTF(1, "%s: type=%d sa=%p hw=%p\n", |
852 | __func__, sa->type, sa, sa->hwif); | | 852 | __func__, sa->type, sa, sa->hwif); |
853 | return (sa->type == AUDIODEV_TYPE_AUDIO) ? 1 : 0; | | 853 | return (sa->type == AUDIODEV_TYPE_AUDIO) ? 1 : 0; |
854 | } | | 854 | } |
855 | | | 855 | |
856 | static void | | 856 | static void |
857 | audioattach(device_t parent, device_t self, void *aux) | | 857 | audioattach(device_t parent, device_t self, void *aux) |
858 | { | | 858 | { |
859 | struct audio_softc *sc; | | 859 | struct audio_softc *sc; |
860 | struct audio_attach_args *sa; | | 860 | struct audio_attach_args *sa; |
861 | const struct audio_hw_if *hw_if; | | 861 | const struct audio_hw_if *hw_if; |
862 | audio_format2_t phwfmt; | | 862 | audio_format2_t phwfmt; |
863 | audio_format2_t rhwfmt; | | 863 | audio_format2_t rhwfmt; |
864 | audio_filter_reg_t pfil; | | 864 | audio_filter_reg_t pfil; |
865 | audio_filter_reg_t rfil; | | 865 | audio_filter_reg_t rfil; |
866 | const struct sysctlnode *node; | | 866 | const struct sysctlnode *node; |
867 | void *hdlp; | | 867 | void *hdlp; |
868 | bool has_playback; | | 868 | bool has_playback; |
869 | bool has_capture; | | 869 | bool has_capture; |
870 | bool has_indep; | | 870 | bool has_indep; |
871 | bool has_fulldup; | | 871 | bool has_fulldup; |
872 | int mode; | | 872 | int mode; |
873 | int error; | | 873 | int error; |
874 | | | 874 | |
875 | sc = device_private(self); | | 875 | sc = device_private(self); |
876 | sc->sc_dev = self; | | 876 | sc->sc_dev = self; |
877 | sa = (struct audio_attach_args *)aux; | | 877 | sa = (struct audio_attach_args *)aux; |
878 | hw_if = sa->hwif; | | 878 | hw_if = sa->hwif; |
879 | hdlp = sa->hdl; | | 879 | hdlp = sa->hdl; |
880 | | | 880 | |
881 | if (hw_if == NULL) { | | 881 | if (hw_if == NULL) { |
882 | panic("audioattach: missing hw_if method"); | | 882 | panic("audioattach: missing hw_if method"); |
883 | } | | 883 | } |
884 | if (hw_if->get_locks == NULL || hw_if->get_props == NULL) { | | 884 | if (hw_if->get_locks == NULL || hw_if->get_props == NULL) { |
885 | aprint_error(": missing mandatory method\n"); | | 885 | aprint_error(": missing mandatory method\n"); |
886 | return; | | 886 | return; |
887 | } | | 887 | } |
888 | | | 888 | |
889 | hw_if->get_locks(hdlp, &sc->sc_intr_lock, &sc->sc_lock); | | 889 | hw_if->get_locks(hdlp, &sc->sc_intr_lock, &sc->sc_lock); |
890 | sc->sc_props = hw_if->get_props(hdlp); | | 890 | sc->sc_props = hw_if->get_props(hdlp); |
891 | | | 891 | |
892 | has_playback = (sc->sc_props & AUDIO_PROP_PLAYBACK); | | 892 | has_playback = (sc->sc_props & AUDIO_PROP_PLAYBACK); |
893 | has_capture = (sc->sc_props & AUDIO_PROP_CAPTURE); | | 893 | has_capture = (sc->sc_props & AUDIO_PROP_CAPTURE); |
894 | has_indep = (sc->sc_props & AUDIO_PROP_INDEPENDENT); | | 894 | has_indep = (sc->sc_props & AUDIO_PROP_INDEPENDENT); |
895 | has_fulldup = (sc->sc_props & AUDIO_PROP_FULLDUPLEX); | | 895 | has_fulldup = (sc->sc_props & AUDIO_PROP_FULLDUPLEX); |
896 | | | 896 | |
897 | #ifdef DIAGNOSTIC | | 897 | #ifdef DIAGNOSTIC |
898 | if (hw_if->query_format == NULL || | | 898 | if (hw_if->query_format == NULL || |
899 | hw_if->set_format == NULL || | | 899 | hw_if->set_format == NULL || |
900 | hw_if->getdev == NULL || | | 900 | hw_if->getdev == NULL || |
901 | hw_if->set_port == NULL || | | 901 | hw_if->set_port == NULL || |
902 | hw_if->get_port == NULL || | | 902 | hw_if->get_port == NULL || |
903 | hw_if->query_devinfo == NULL) { | | 903 | hw_if->query_devinfo == NULL) { |
904 | aprint_error(": missing mandatory method\n"); | | 904 | aprint_error(": missing mandatory method\n"); |
905 | return; | | 905 | return; |
906 | } | | 906 | } |
907 | if (has_playback) { | | 907 | if (has_playback) { |
908 | if ((hw_if->start_output == NULL && | | 908 | if ((hw_if->start_output == NULL && |
909 | hw_if->trigger_output == NULL) || | | 909 | hw_if->trigger_output == NULL) || |
910 | hw_if->halt_output == NULL) { | | 910 | hw_if->halt_output == NULL) { |
911 | aprint_error(": missing playback method\n"); | | 911 | aprint_error(": missing playback method\n"); |
912 | } | | 912 | } |
913 | } | | 913 | } |
914 | if (has_capture) { | | 914 | if (has_capture) { |
915 | if ((hw_if->start_input == NULL && | | 915 | if ((hw_if->start_input == NULL && |
916 | hw_if->trigger_input == NULL) || | | 916 | hw_if->trigger_input == NULL) || |
917 | hw_if->halt_input == NULL) { | | 917 | hw_if->halt_input == NULL) { |
918 | aprint_error(": missing capture method\n"); | | 918 | aprint_error(": missing capture method\n"); |
919 | } | | 919 | } |
920 | } | | 920 | } |
921 | #endif | | 921 | #endif |
922 | | | 922 | |
923 | sc->hw_if = hw_if; | | 923 | sc->hw_if = hw_if; |
924 | sc->hw_hdl = hdlp; | | 924 | sc->hw_hdl = hdlp; |
925 | sc->hw_dev = parent; | | 925 | sc->hw_dev = parent; |
926 | | | 926 | |
927 | sc->sc_exlock = 1; | | 927 | sc->sc_exlock = 1; |
928 | sc->sc_blk_ms = AUDIO_BLK_MS; | | 928 | sc->sc_blk_ms = AUDIO_BLK_MS; |
929 | SLIST_INIT(&sc->sc_files); | | 929 | SLIST_INIT(&sc->sc_files); |
930 | cv_init(&sc->sc_exlockcv, "audiolk"); | | 930 | cv_init(&sc->sc_exlockcv, "audiolk"); |
931 | sc->sc_am_capacity = 0; | | 931 | sc->sc_am_capacity = 0; |
932 | sc->sc_am_used = 0; | | 932 | sc->sc_am_used = 0; |
933 | sc->sc_am = NULL; | | 933 | sc->sc_am = NULL; |
934 | | | 934 | |
935 | /* MMAP is now supported by upper layer. */ | | 935 | /* MMAP is now supported by upper layer. */ |
936 | sc->sc_props |= AUDIO_PROP_MMAP; | | 936 | sc->sc_props |= AUDIO_PROP_MMAP; |
937 | | | 937 | |
938 | KASSERT(has_playback || has_capture); | | 938 | KASSERT(has_playback || has_capture); |
939 | /* Unidirectional device must have neither FULLDUP nor INDEPENDENT. */ | | 939 | /* Unidirectional device must have neither FULLDUP nor INDEPENDENT. */ |
940 | if (!has_playback || !has_capture) { | | 940 | if (!has_playback || !has_capture) { |
941 | KASSERT(!has_indep); | | 941 | KASSERT(!has_indep); |
942 | KASSERT(!has_fulldup); | | 942 | KASSERT(!has_fulldup); |
943 | } | | 943 | } |
944 | | | 944 | |
945 | mode = 0; | | 945 | mode = 0; |
946 | if (has_playback) { | | 946 | if (has_playback) { |
947 | aprint_normal(": playback"); | | 947 | aprint_normal(": playback"); |
948 | mode |= AUMODE_PLAY; | | 948 | mode |= AUMODE_PLAY; |
949 | } | | 949 | } |
950 | if (has_capture) { | | 950 | if (has_capture) { |
951 | aprint_normal("%c capture", has_playback ? ',' : ':'); | | 951 | aprint_normal("%c capture", has_playback ? ',' : ':'); |
952 | mode |= AUMODE_RECORD; | | 952 | mode |= AUMODE_RECORD; |
953 | } | | 953 | } |
954 | if (has_playback && has_capture) { | | 954 | if (has_playback && has_capture) { |
955 | if (has_fulldup) | | 955 | if (has_fulldup) |
956 | aprint_normal(", full duplex"); | | 956 | aprint_normal(", full duplex"); |
957 | else | | 957 | else |
958 | aprint_normal(", half duplex"); | | 958 | aprint_normal(", half duplex"); |
959 | | | 959 | |
960 | if (has_indep) | | 960 | if (has_indep) |
961 | aprint_normal(", independent"); | | 961 | aprint_normal(", independent"); |
962 | } | | 962 | } |
963 | | | 963 | |
964 | aprint_naive("\n"); | | 964 | aprint_naive("\n"); |
965 | aprint_normal("\n"); | | 965 | aprint_normal("\n"); |
966 | | | 966 | |
967 | /* probe hw params */ | | 967 | /* probe hw params */ |
968 | memset(&phwfmt, 0, sizeof(phwfmt)); | | 968 | memset(&phwfmt, 0, sizeof(phwfmt)); |
969 | memset(&rhwfmt, 0, sizeof(rhwfmt)); | | 969 | memset(&rhwfmt, 0, sizeof(rhwfmt)); |
970 | memset(&pfil, 0, sizeof(pfil)); | | 970 | memset(&pfil, 0, sizeof(pfil)); |
971 | memset(&rfil, 0, sizeof(rfil)); | | 971 | memset(&rfil, 0, sizeof(rfil)); |
972 | if (has_indep) { | | 972 | if (has_indep) { |
973 | int perror, rerror; | | 973 | int perror, rerror; |
974 | | | 974 | |
975 | /* On independent devices, probe separately. */ | | 975 | /* On independent devices, probe separately. */ |
976 | perror = audio_hw_probe(sc, &phwfmt, AUMODE_PLAY); | | 976 | perror = audio_hw_probe(sc, &phwfmt, AUMODE_PLAY); |
977 | rerror = audio_hw_probe(sc, &rhwfmt, AUMODE_RECORD); | | 977 | rerror = audio_hw_probe(sc, &rhwfmt, AUMODE_RECORD); |
978 | if (perror && rerror) { | | 978 | if (perror && rerror) { |
979 | aprint_error_dev(self, | | 979 | aprint_error_dev(self, |
980 | "audio_hw_probe failed: perror=%d, rerror=%d\n", | | 980 | "audio_hw_probe failed: perror=%d, rerror=%d\n", |
981 | perror, rerror); | | 981 | perror, rerror); |
982 | goto bad; | | 982 | goto bad; |
983 | } | | 983 | } |
984 | if (perror) { | | 984 | if (perror) { |
985 | mode &= ~AUMODE_PLAY; | | 985 | mode &= ~AUMODE_PLAY; |
986 | aprint_error_dev(self, "audio_hw_probe failed: " | | 986 | aprint_error_dev(self, "audio_hw_probe failed: " |
987 | "errno=%d, playback disabled\n", perror); | | 987 | "errno=%d, playback disabled\n", perror); |
988 | } | | 988 | } |
989 | if (rerror) { | | 989 | if (rerror) { |
990 | mode &= ~AUMODE_RECORD; | | 990 | mode &= ~AUMODE_RECORD; |
991 | aprint_error_dev(self, "audio_hw_probe failed: " | | 991 | aprint_error_dev(self, "audio_hw_probe failed: " |
992 | "errno=%d, capture disabled\n", rerror); | | 992 | "errno=%d, capture disabled\n", rerror); |
993 | } | | 993 | } |
994 | } else { | | 994 | } else { |
995 | /* | | 995 | /* |
996 | * On non independent devices or uni-directional devices, | | 996 | * On non independent devices or uni-directional devices, |
997 | * probe once (simultaneously). | | 997 | * probe once (simultaneously). |
998 | */ | | 998 | */ |
999 | audio_format2_t *fmt = has_playback ? &phwfmt : &rhwfmt; | | 999 | audio_format2_t *fmt = has_playback ? &phwfmt : &rhwfmt; |
1000 | error = audio_hw_probe(sc, fmt, mode); | | 1000 | error = audio_hw_probe(sc, fmt, mode); |
1001 | if (error) { | | 1001 | if (error) { |
1002 | aprint_error_dev(self, | | 1002 | aprint_error_dev(self, |
1003 | "audio_hw_probe failed: errno=%d\n", error); | | 1003 | "audio_hw_probe failed: errno=%d\n", error); |
1004 | goto bad; | | 1004 | goto bad; |
1005 | } | | 1005 | } |
1006 | if (has_playback && has_capture) | | 1006 | if (has_playback && has_capture) |
1007 | rhwfmt = phwfmt; | | 1007 | rhwfmt = phwfmt; |
1008 | } | | 1008 | } |
1009 | | | 1009 | |
1010 | /* Init hardware. */ | | 1010 | /* Init hardware. */ |
1011 | /* hw_probe() also validates [pr]hwfmt. */ | | 1011 | /* hw_probe() also validates [pr]hwfmt. */ |
1012 | error = audio_hw_set_format(sc, mode, &phwfmt, &rhwfmt, &pfil, &rfil); | | 1012 | error = audio_hw_set_format(sc, mode, &phwfmt, &rhwfmt, &pfil, &rfil); |
1013 | if (error) { | | 1013 | if (error) { |
1014 | aprint_error_dev(self, | | 1014 | aprint_error_dev(self, |
1015 | "audio_hw_set_format failed: errno=%d\n", error); | | 1015 | "audio_hw_set_format failed: errno=%d\n", error); |
1016 | goto bad; | | 1016 | goto bad; |
1017 | } | | 1017 | } |
1018 | | | 1018 | |
1019 | /* | | 1019 | /* |
1020 | * Init track mixers. If at least one direction is available on | | 1020 | * Init track mixers. If at least one direction is available on |
1021 | * attach time, we assume a success. | | 1021 | * attach time, we assume a success. |
1022 | */ | | 1022 | */ |
1023 | error = audio_mixers_init(sc, mode, &phwfmt, &rhwfmt, &pfil, &rfil); | | 1023 | error = audio_mixers_init(sc, mode, &phwfmt, &rhwfmt, &pfil, &rfil); |
1024 | if (sc->sc_pmixer == NULL && sc->sc_rmixer == NULL) { | | 1024 | if (sc->sc_pmixer == NULL && sc->sc_rmixer == NULL) { |
1025 | aprint_error_dev(self, | | 1025 | aprint_error_dev(self, |
1026 | "audio_mixers_init failed: errno=%d\n", error); | | 1026 | "audio_mixers_init failed: errno=%d\n", error); |
1027 | goto bad; | | 1027 | goto bad; |
1028 | } | | 1028 | } |
1029 | | | 1029 | |
1030 | sc->sc_psz = pserialize_create(); | | 1030 | sc->sc_psz = pserialize_create(); |
1031 | psref_target_init(&sc->sc_psref, audio_psref_class); | | 1031 | psref_target_init(&sc->sc_psref, audio_psref_class); |
1032 | | | 1032 | |
1033 | selinit(&sc->sc_wsel); | | 1033 | selinit(&sc->sc_wsel); |
1034 | selinit(&sc->sc_rsel); | | 1034 | selinit(&sc->sc_rsel); |
1035 | | | 1035 | |
1036 | /* Initial parameter of /dev/sound */ | | 1036 | /* Initial parameter of /dev/sound */ |
1037 | sc->sc_sound_pparams = params_to_format2(&audio_default); | | 1037 | sc->sc_sound_pparams = params_to_format2(&audio_default); |
1038 | sc->sc_sound_rparams = params_to_format2(&audio_default); | | 1038 | sc->sc_sound_rparams = params_to_format2(&audio_default); |
1039 | sc->sc_sound_ppause = false; | | 1039 | sc->sc_sound_ppause = false; |
1040 | sc->sc_sound_rpause = false; | | 1040 | sc->sc_sound_rpause = false; |
1041 | | | 1041 | |
1042 | /* XXX TODO: consider about sc_ai */ | | 1042 | /* XXX TODO: consider about sc_ai */ |
1043 | | | 1043 | |
1044 | mixer_init(sc); | | 1044 | mixer_init(sc); |
1045 | TRACE(2, "inputs ports=0x%x, input master=%d, " | | 1045 | TRACE(2, "inputs ports=0x%x, input master=%d, " |
1046 | "output ports=0x%x, output master=%d", | | 1046 | "output ports=0x%x, output master=%d", |
1047 | sc->sc_inports.allports, sc->sc_inports.master, | | 1047 | sc->sc_inports.allports, sc->sc_inports.master, |
1048 | sc->sc_outports.allports, sc->sc_outports.master); | | 1048 | sc->sc_outports.allports, sc->sc_outports.master); |
1049 | | | 1049 | |
1050 | sysctl_createv(&sc->sc_log, 0, NULL, &node, | | 1050 | sysctl_createv(&sc->sc_log, 0, NULL, &node, |
1051 | 0, | | 1051 | 0, |
1052 | CTLTYPE_NODE, device_xname(sc->sc_dev), | | 1052 | CTLTYPE_NODE, device_xname(sc->sc_dev), |
1053 | SYSCTL_DESCR("audio test"), | | 1053 | SYSCTL_DESCR("audio test"), |
1054 | NULL, 0, | | 1054 | NULL, 0, |
1055 | NULL, 0, | | 1055 | NULL, 0, |
1056 | CTL_HW, | | 1056 | CTL_HW, |
1057 | CTL_CREATE, CTL_EOL); | | 1057 | CTL_CREATE, CTL_EOL); |
1058 | | | 1058 | |
1059 | if (node != NULL) { | | 1059 | if (node != NULL) { |
1060 | sysctl_createv(&sc->sc_log, 0, NULL, NULL, | | 1060 | sysctl_createv(&sc->sc_log, 0, NULL, NULL, |
1061 | CTLFLAG_READWRITE, | | 1061 | CTLFLAG_READWRITE, |
1062 | CTLTYPE_INT, "blk_ms", | | 1062 | CTLTYPE_INT, "blk_ms", |
1063 | SYSCTL_DESCR("blocksize in msec"), | | 1063 | SYSCTL_DESCR("blocksize in msec"), |
1064 | audio_sysctl_blk_ms, 0, (void *)sc, 0, | | 1064 | audio_sysctl_blk_ms, 0, (void *)sc, 0, |
1065 | CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL); | | 1065 | CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL); |
1066 | | | 1066 | |
1067 | sysctl_createv(&sc->sc_log, 0, NULL, NULL, | | 1067 | sysctl_createv(&sc->sc_log, 0, NULL, NULL, |
1068 | CTLFLAG_READWRITE, | | 1068 | CTLFLAG_READWRITE, |
1069 | CTLTYPE_BOOL, "multiuser", | | 1069 | CTLTYPE_BOOL, "multiuser", |
1070 | SYSCTL_DESCR("allow multiple user access"), | | 1070 | SYSCTL_DESCR("allow multiple user access"), |
1071 | audio_sysctl_multiuser, 0, (void *)sc, 0, | | 1071 | audio_sysctl_multiuser, 0, (void *)sc, 0, |
1072 | CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL); | | 1072 | CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL); |
1073 | | | 1073 | |
1074 | #if defined(AUDIO_DEBUG) | | 1074 | #if defined(AUDIO_DEBUG) |
1075 | sysctl_createv(&sc->sc_log, 0, NULL, NULL, | | 1075 | sysctl_createv(&sc->sc_log, 0, NULL, NULL, |
1076 | CTLFLAG_READWRITE, | | 1076 | CTLFLAG_READWRITE, |
1077 | CTLTYPE_INT, "debug", | | 1077 | CTLTYPE_INT, "debug", |
1078 | SYSCTL_DESCR("debug level (0..4)"), | | 1078 | SYSCTL_DESCR("debug level (0..4)"), |
1079 | audio_sysctl_debug, 0, (void *)sc, 0, | | 1079 | audio_sysctl_debug, 0, (void *)sc, 0, |
1080 | CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL); | | 1080 | CTL_HW, node->sysctl_num, CTL_CREATE, CTL_EOL); |
1081 | #endif | | 1081 | #endif |
1082 | } | | 1082 | } |
1083 | | | 1083 | |
1084 | #ifdef AUDIO_PM_IDLE | | 1084 | #ifdef AUDIO_PM_IDLE |
1085 | callout_init(&sc->sc_idle_counter, 0); | | 1085 | callout_init(&sc->sc_idle_counter, 0); |
1086 | callout_setfunc(&sc->sc_idle_counter, audio_idle, self); | | 1086 | callout_setfunc(&sc->sc_idle_counter, audio_idle, self); |
1087 | #endif | | 1087 | #endif |
1088 | | | 1088 | |
1089 | if (!pmf_device_register(self, audio_suspend, audio_resume)) | | 1089 | if (!pmf_device_register(self, audio_suspend, audio_resume)) |
1090 | aprint_error_dev(self, "couldn't establish power handler\n"); | | 1090 | aprint_error_dev(self, "couldn't establish power handler\n"); |
1091 | #ifdef AUDIO_PM_IDLE | | 1091 | #ifdef AUDIO_PM_IDLE |
1092 | if (!device_active_register(self, audio_activity)) | | 1092 | if (!device_active_register(self, audio_activity)) |
1093 | aprint_error_dev(self, "couldn't register activity handler\n"); | | 1093 | aprint_error_dev(self, "couldn't register activity handler\n"); |
1094 | #endif | | 1094 | #endif |
1095 | | | 1095 | |
1096 | if (!pmf_event_register(self, PMFE_AUDIO_VOLUME_DOWN, | | 1096 | if (!pmf_event_register(self, PMFE_AUDIO_VOLUME_DOWN, |
1097 | audio_volume_down, true)) | | 1097 | audio_volume_down, true)) |
1098 | aprint_error_dev(self, "couldn't add volume down handler\n"); | | 1098 | aprint_error_dev(self, "couldn't add volume down handler\n"); |
1099 | if (!pmf_event_register(self, PMFE_AUDIO_VOLUME_UP, | | 1099 | if (!pmf_event_register(self, PMFE_AUDIO_VOLUME_UP, |
1100 | audio_volume_up, true)) | | 1100 | audio_volume_up, true)) |
1101 | aprint_error_dev(self, "couldn't add volume up handler\n"); | | 1101 | aprint_error_dev(self, "couldn't add volume up handler\n"); |
1102 | if (!pmf_event_register(self, PMFE_AUDIO_VOLUME_TOGGLE, | | 1102 | if (!pmf_event_register(self, PMFE_AUDIO_VOLUME_TOGGLE, |
1103 | audio_volume_toggle, true)) | | 1103 | audio_volume_toggle, true)) |
1104 | aprint_error_dev(self, "couldn't add volume toggle handler\n"); | | 1104 | aprint_error_dev(self, "couldn't add volume toggle handler\n"); |
1105 | | | 1105 | |
1106 | #ifdef AUDIO_PM_IDLE | | 1106 | #ifdef AUDIO_PM_IDLE |
1107 | callout_schedule(&sc->sc_idle_counter, audio_idle_timeout * hz); | | 1107 | callout_schedule(&sc->sc_idle_counter, audio_idle_timeout * hz); |
1108 | #endif | | 1108 | #endif |
1109 | | | 1109 | |
1110 | #if defined(AUDIO_DEBUG) | | 1110 | #if defined(AUDIO_DEBUG) |
1111 | audio_mlog_init(); | | 1111 | audio_mlog_init(); |
1112 | #endif | | 1112 | #endif |
1113 | | | 1113 | |
1114 | audiorescan(self, "audio", NULL); | | 1114 | audiorescan(self, NULL, NULL); |
1115 | sc->sc_exlock = 0; | | 1115 | sc->sc_exlock = 0; |
1116 | return; | | 1116 | return; |
1117 | | | 1117 | |
1118 | bad: | | 1118 | bad: |
1119 | /* Clearing hw_if means that device is attached but disabled. */ | | 1119 | /* Clearing hw_if means that device is attached but disabled. */ |
1120 | sc->hw_if = NULL; | | 1120 | sc->hw_if = NULL; |
1121 | sc->sc_exlock = 0; | | 1121 | sc->sc_exlock = 0; |
1122 | aprint_error_dev(sc->sc_dev, "disabled\n"); | | 1122 | aprint_error_dev(sc->sc_dev, "disabled\n"); |
1123 | return; | | 1123 | return; |
1124 | } | | 1124 | } |
1125 | | | 1125 | |
1126 | /* | | 1126 | /* |
1127 | * Initialize hardware mixer. | | 1127 | * Initialize hardware mixer. |
1128 | * This function is called from audioattach(). | | 1128 | * This function is called from audioattach(). |
1129 | */ | | 1129 | */ |
1130 | static void | | 1130 | static void |
1131 | mixer_init(struct audio_softc *sc) | | 1131 | mixer_init(struct audio_softc *sc) |
1132 | { | | 1132 | { |
1133 | mixer_devinfo_t mi; | | 1133 | mixer_devinfo_t mi; |
1134 | int iclass, mclass, oclass, rclass; | | 1134 | int iclass, mclass, oclass, rclass; |
1135 | int record_master_found, record_source_found; | | 1135 | int record_master_found, record_source_found; |
1136 | | | 1136 | |
1137 | iclass = mclass = oclass = rclass = -1; | | 1137 | iclass = mclass = oclass = rclass = -1; |
1138 | sc->sc_inports.index = -1; | | 1138 | sc->sc_inports.index = -1; |
1139 | sc->sc_inports.master = -1; | | 1139 | sc->sc_inports.master = -1; |
1140 | sc->sc_inports.nports = 0; | | 1140 | sc->sc_inports.nports = 0; |
1141 | sc->sc_inports.isenum = false; | | 1141 | sc->sc_inports.isenum = false; |
1142 | sc->sc_inports.allports = 0; | | 1142 | sc->sc_inports.allports = 0; |
1143 | sc->sc_inports.isdual = false; | | 1143 | sc->sc_inports.isdual = false; |
1144 | sc->sc_inports.mixerout = -1; | | 1144 | sc->sc_inports.mixerout = -1; |
1145 | sc->sc_inports.cur_port = -1; | | 1145 | sc->sc_inports.cur_port = -1; |
1146 | sc->sc_outports.index = -1; | | 1146 | sc->sc_outports.index = -1; |
1147 | sc->sc_outports.master = -1; | | 1147 | sc->sc_outports.master = -1; |
1148 | sc->sc_outports.nports = 0; | | 1148 | sc->sc_outports.nports = 0; |
1149 | sc->sc_outports.isenum = false; | | 1149 | sc->sc_outports.isenum = false; |
1150 | sc->sc_outports.allports = 0; | | 1150 | sc->sc_outports.allports = 0; |
1151 | sc->sc_outports.isdual = false; | | 1151 | sc->sc_outports.isdual = false; |
1152 | sc->sc_outports.mixerout = -1; | | 1152 | sc->sc_outports.mixerout = -1; |
1153 | sc->sc_outports.cur_port = -1; | | 1153 | sc->sc_outports.cur_port = -1; |
1154 | sc->sc_monitor_port = -1; | | 1154 | sc->sc_monitor_port = -1; |
1155 | /* | | 1155 | /* |
1156 | * Read through the underlying driver's list, picking out the class | | 1156 | * Read through the underlying driver's list, picking out the class |
1157 | * names from the mixer descriptions. We'll need them to decode the | | 1157 | * names from the mixer descriptions. We'll need them to decode the |
1158 | * mixer descriptions on the next pass through the loop. | | 1158 | * mixer descriptions on the next pass through the loop. |
1159 | */ | | 1159 | */ |
1160 | mutex_enter(sc->sc_lock); | | 1160 | mutex_enter(sc->sc_lock); |
1161 | for(mi.index = 0; ; mi.index++) { | | 1161 | for(mi.index = 0; ; mi.index++) { |
1162 | if (audio_query_devinfo(sc, &mi) != 0) | | 1162 | if (audio_query_devinfo(sc, &mi) != 0) |
1163 | break; | | 1163 | break; |
1164 | /* | | 1164 | /* |
1165 | * The type of AUDIO_MIXER_CLASS merely introduces a class. | | 1165 | * The type of AUDIO_MIXER_CLASS merely introduces a class. |
1166 | * All the other types describe an actual mixer. | | 1166 | * All the other types describe an actual mixer. |
1167 | */ | | 1167 | */ |
1168 | if (mi.type == AUDIO_MIXER_CLASS) { | | 1168 | if (mi.type == AUDIO_MIXER_CLASS) { |
1169 | if (strcmp(mi.label.name, AudioCinputs) == 0) | | 1169 | if (strcmp(mi.label.name, AudioCinputs) == 0) |
1170 | iclass = mi.mixer_class; | | 1170 | iclass = mi.mixer_class; |
1171 | if (strcmp(mi.label.name, AudioCmonitor) == 0) | | 1171 | if (strcmp(mi.label.name, AudioCmonitor) == 0) |
1172 | mclass = mi.mixer_class; | | 1172 | mclass = mi.mixer_class; |
1173 | if (strcmp(mi.label.name, AudioCoutputs) == 0) | | 1173 | if (strcmp(mi.label.name, AudioCoutputs) == 0) |
1174 | oclass = mi.mixer_class; | | 1174 | oclass = mi.mixer_class; |
1175 | if (strcmp(mi.label.name, AudioCrecord) == 0) | | 1175 | if (strcmp(mi.label.name, AudioCrecord) == 0) |
1176 | rclass = mi.mixer_class; | | 1176 | rclass = mi.mixer_class; |
1177 | } | | 1177 | } |
1178 | } | | 1178 | } |
1179 | mutex_exit(sc->sc_lock); | | 1179 | mutex_exit(sc->sc_lock); |
1180 | | | 1180 | |
1181 | /* Allocate save area. Ensure non-zero allocation. */ | | 1181 | /* Allocate save area. Ensure non-zero allocation. */ |
1182 | sc->sc_nmixer_states = mi.index; | | 1182 | sc->sc_nmixer_states = mi.index; |
1183 | sc->sc_mixer_state = kmem_zalloc(sizeof(mixer_ctrl_t) * | | 1183 | sc->sc_mixer_state = kmem_zalloc(sizeof(mixer_ctrl_t) * |
1184 | (sc->sc_nmixer_states + 1), KM_SLEEP); | | 1184 | (sc->sc_nmixer_states + 1), KM_SLEEP); |
1185 | | | 1185 | |
1186 | /* | | 1186 | /* |
1187 | * This is where we assign each control in the "audio" model, to the | | 1187 | * This is where we assign each control in the "audio" model, to the |
1188 | * underlying "mixer" control. We walk through the whole list once, | | 1188 | * underlying "mixer" control. We walk through the whole list once, |
1189 | * assigning likely candidates as we come across them. | | 1189 | * assigning likely candidates as we come across them. |
1190 | */ | | 1190 | */ |
1191 | record_master_found = 0; | | 1191 | record_master_found = 0; |
1192 | record_source_found = 0; | | 1192 | record_source_found = 0; |
1193 | mutex_enter(sc->sc_lock); | | 1193 | mutex_enter(sc->sc_lock); |
1194 | for(mi.index = 0; ; mi.index++) { | | 1194 | for(mi.index = 0; ; mi.index++) { |
1195 | if (audio_query_devinfo(sc, &mi) != 0) | | 1195 | if (audio_query_devinfo(sc, &mi) != 0) |
1196 | break; | | 1196 | break; |
1197 | KASSERT(mi.index < sc->sc_nmixer_states); | | 1197 | KASSERT(mi.index < sc->sc_nmixer_states); |
1198 | if (mi.type == AUDIO_MIXER_CLASS) | | 1198 | if (mi.type == AUDIO_MIXER_CLASS) |
1199 | continue; | | 1199 | continue; |
1200 | if (mi.mixer_class == iclass) { | | 1200 | if (mi.mixer_class == iclass) { |
1201 | /* | | 1201 | /* |
1202 | * AudioCinputs is only a fallback, when we don't | | 1202 | * AudioCinputs is only a fallback, when we don't |
1203 | * find what we're looking for in AudioCrecord, so | | 1203 | * find what we're looking for in AudioCrecord, so |
1204 | * check the flags before accepting one of these. | | 1204 | * check the flags before accepting one of these. |
1205 | */ | | 1205 | */ |
1206 | if (strcmp(mi.label.name, AudioNmaster) == 0 | | 1206 | if (strcmp(mi.label.name, AudioNmaster) == 0 |
1207 | && record_master_found == 0) | | 1207 | && record_master_found == 0) |
1208 | sc->sc_inports.master = mi.index; | | 1208 | sc->sc_inports.master = mi.index; |
1209 | if (strcmp(mi.label.name, AudioNsource) == 0 | | 1209 | if (strcmp(mi.label.name, AudioNsource) == 0 |
1210 | && record_source_found == 0) { | | 1210 | && record_source_found == 0) { |
1211 | if (mi.type == AUDIO_MIXER_ENUM) { | | 1211 | if (mi.type == AUDIO_MIXER_ENUM) { |
1212 | int i; | | 1212 | int i; |
1213 | for(i = 0; i < mi.un.e.num_mem; i++) | | 1213 | for(i = 0; i < mi.un.e.num_mem; i++) |
1214 | if (strcmp(mi.un.e.member[i].label.name, | | 1214 | if (strcmp(mi.un.e.member[i].label.name, |
1215 | AudioNmixerout) == 0) | | 1215 | AudioNmixerout) == 0) |
1216 | sc->sc_inports.mixerout = | | 1216 | sc->sc_inports.mixerout = |
1217 | mi.un.e.member[i].ord; | | 1217 | mi.un.e.member[i].ord; |
1218 | } | | 1218 | } |
1219 | au_setup_ports(sc, &sc->sc_inports, &mi, | | 1219 | au_setup_ports(sc, &sc->sc_inports, &mi, |
1220 | itable); | | 1220 | itable); |
1221 | } | | 1221 | } |
1222 | if (strcmp(mi.label.name, AudioNdac) == 0 && | | 1222 | if (strcmp(mi.label.name, AudioNdac) == 0 && |
1223 | sc->sc_outports.master == -1) | | 1223 | sc->sc_outports.master == -1) |
1224 | sc->sc_outports.master = mi.index; | | 1224 | sc->sc_outports.master = mi.index; |
1225 | } else if (mi.mixer_class == mclass) { | | 1225 | } else if (mi.mixer_class == mclass) { |
1226 | if (strcmp(mi.label.name, AudioNmonitor) == 0) | | 1226 | if (strcmp(mi.label.name, AudioNmonitor) == 0) |
1227 | sc->sc_monitor_port = mi.index; | | 1227 | sc->sc_monitor_port = mi.index; |
1228 | } else if (mi.mixer_class == oclass) { | | 1228 | } else if (mi.mixer_class == oclass) { |
1229 | if (strcmp(mi.label.name, AudioNmaster) == 0) | | 1229 | if (strcmp(mi.label.name, AudioNmaster) == 0) |
1230 | sc->sc_outports.master = mi.index; | | 1230 | sc->sc_outports.master = mi.index; |
1231 | if (strcmp(mi.label.name, AudioNselect) == 0) | | 1231 | if (strcmp(mi.label.name, AudioNselect) == 0) |
1232 | au_setup_ports(sc, &sc->sc_outports, &mi, | | 1232 | au_setup_ports(sc, &sc->sc_outports, &mi, |
1233 | otable); | | 1233 | otable); |
1234 | } else if (mi.mixer_class == rclass) { | | 1234 | } else if (mi.mixer_class == rclass) { |
1235 | /* | | 1235 | /* |
1236 | * These are the preferred mixers for the audio record | | 1236 | * These are the preferred mixers for the audio record |
1237 | * controls, so set the flags here, but don't check. | | 1237 | * controls, so set the flags here, but don't check. |
1238 | */ | | 1238 | */ |
1239 | if (strcmp(mi.label.name, AudioNmaster) == 0) { | | 1239 | if (strcmp(mi.label.name, AudioNmaster) == 0) { |
1240 | sc->sc_inports.master = mi.index; | | 1240 | sc->sc_inports.master = mi.index; |
1241 | record_master_found = 1; | | 1241 | record_master_found = 1; |
1242 | } | | 1242 | } |
1243 | #if 1 /* Deprecated. Use AudioNmaster. */ | | 1243 | #if 1 /* Deprecated. Use AudioNmaster. */ |
1244 | if (strcmp(mi.label.name, AudioNrecord) == 0) { | | 1244 | if (strcmp(mi.label.name, AudioNrecord) == 0) { |
1245 | sc->sc_inports.master = mi.index; | | 1245 | sc->sc_inports.master = mi.index; |
1246 | record_master_found = 1; | | 1246 | record_master_found = 1; |
1247 | } | | 1247 | } |
1248 | if (strcmp(mi.label.name, AudioNvolume) == 0) { | | 1248 | if (strcmp(mi.label.name, AudioNvolume) == 0) { |
1249 | sc->sc_inports.master = mi.index; | | 1249 | sc->sc_inports.master = mi.index; |
1250 | record_master_found = 1; | | 1250 | record_master_found = 1; |
1251 | } | | 1251 | } |
1252 | #endif | | 1252 | #endif |
1253 | if (strcmp(mi.label.name, AudioNsource) == 0) { | | 1253 | if (strcmp(mi.label.name, AudioNsource) == 0) { |
1254 | if (mi.type == AUDIO_MIXER_ENUM) { | | 1254 | if (mi.type == AUDIO_MIXER_ENUM) { |
1255 | int i; | | 1255 | int i; |
1256 | for(i = 0; i < mi.un.e.num_mem; i++) | | 1256 | for(i = 0; i < mi.un.e.num_mem; i++) |
1257 | if (strcmp(mi.un.e.member[i].label.name, | | 1257 | if (strcmp(mi.un.e.member[i].label.name, |
1258 | AudioNmixerout) == 0) | | 1258 | AudioNmixerout) == 0) |
1259 | sc->sc_inports.mixerout = | | 1259 | sc->sc_inports.mixerout = |
1260 | mi.un.e.member[i].ord; | | 1260 | mi.un.e.member[i].ord; |
1261 | } | | 1261 | } |
1262 | au_setup_ports(sc, &sc->sc_inports, &mi, | | 1262 | au_setup_ports(sc, &sc->sc_inports, &mi, |
1263 | itable); | | 1263 | itable); |
1264 | record_source_found = 1; | | 1264 | record_source_found = 1; |
1265 | } | | 1265 | } |
1266 | } | | 1266 | } |
1267 | } | | 1267 | } |
1268 | mutex_exit(sc->sc_lock); | | 1268 | mutex_exit(sc->sc_lock); |
1269 | } | | 1269 | } |
1270 | | | 1270 | |
1271 | static int | | 1271 | static int |
1272 | audioactivate(device_t self, enum devact act) | | 1272 | audioactivate(device_t self, enum devact act) |
1273 | { | | 1273 | { |
1274 | struct audio_softc *sc = device_private(self); | | 1274 | struct audio_softc *sc = device_private(self); |
1275 | | | 1275 | |
1276 | switch (act) { | | 1276 | switch (act) { |
1277 | case DVACT_DEACTIVATE: | | 1277 | case DVACT_DEACTIVATE: |
1278 | mutex_enter(sc->sc_lock); | | 1278 | mutex_enter(sc->sc_lock); |
1279 | sc->sc_dying = true; | | 1279 | sc->sc_dying = true; |
1280 | cv_broadcast(&sc->sc_exlockcv); | | 1280 | cv_broadcast(&sc->sc_exlockcv); |
1281 | mutex_exit(sc->sc_lock); | | 1281 | mutex_exit(sc->sc_lock); |
1282 | return 0; | | 1282 | return 0; |
1283 | default: | | 1283 | default: |
1284 | return EOPNOTSUPP; | | 1284 | return EOPNOTSUPP; |
1285 | } | | 1285 | } |
1286 | } | | 1286 | } |
1287 | | | 1287 | |
1288 | static int | | 1288 | static int |
1289 | audiodetach(device_t self, int flags) | | 1289 | audiodetach(device_t self, int flags) |
1290 | { | | 1290 | { |
1291 | struct audio_softc *sc; | | 1291 | struct audio_softc *sc; |
1292 | struct audio_file *file; | | 1292 | struct audio_file *file; |
1293 | int error; | | 1293 | int error; |
1294 | | | 1294 | |
1295 | sc = device_private(self); | | 1295 | sc = device_private(self); |
1296 | TRACE(2, "flags=%d", flags); | | 1296 | TRACE(2, "flags=%d", flags); |
1297 | | | 1297 | |
1298 | /* device is not initialized */ | | 1298 | /* device is not initialized */ |
1299 | if (sc->hw_if == NULL) | | 1299 | if (sc->hw_if == NULL) |
1300 | return 0; | | 1300 | return 0; |
1301 | | | 1301 | |
1302 | /* Start draining existing accessors of the device. */ | | 1302 | /* Start draining existing accessors of the device. */ |
1303 | error = config_detach_children(self, flags); | | 1303 | error = config_detach_children(self, flags); |
1304 | if (error) | | 1304 | if (error) |
1305 | return error; | | 1305 | return error; |
1306 | | | 1306 | |
1307 | /* | | 1307 | /* |
1308 | * This waits currently running sysctls to finish if exists. | | 1308 | * This waits currently running sysctls to finish if exists. |
1309 | * After this, no more new sysctls will come. | | 1309 | * After this, no more new sysctls will come. |
1310 | */ | | 1310 | */ |
1311 | sysctl_teardown(&sc->sc_log); | | 1311 | sysctl_teardown(&sc->sc_log); |
1312 | | | 1312 | |
1313 | mutex_enter(sc->sc_lock); | | 1313 | mutex_enter(sc->sc_lock); |
1314 | sc->sc_dying = true; | | 1314 | sc->sc_dying = true; |
1315 | cv_broadcast(&sc->sc_exlockcv); | | 1315 | cv_broadcast(&sc->sc_exlockcv); |
1316 | if (sc->sc_pmixer) | | 1316 | if (sc->sc_pmixer) |
1317 | cv_broadcast(&sc->sc_pmixer->outcv); | | 1317 | cv_broadcast(&sc->sc_pmixer->outcv); |
1318 | if (sc->sc_rmixer) | | 1318 | if (sc->sc_rmixer) |
1319 | cv_broadcast(&sc->sc_rmixer->outcv); | | 1319 | cv_broadcast(&sc->sc_rmixer->outcv); |
1320 | | | 1320 | |
1321 | /* Prevent new users */ | | 1321 | /* Prevent new users */ |
1322 | SLIST_FOREACH(file, &sc->sc_files, entry) { | | 1322 | SLIST_FOREACH(file, &sc->sc_files, entry) { |
1323 | atomic_store_relaxed(&file->dying, true); | | 1323 | atomic_store_relaxed(&file->dying, true); |
1324 | } | | 1324 | } |
1325 | | | 1325 | |
1326 | /* | | 1326 | /* |
1327 | * Wait for existing users to drain. | | 1327 | * Wait for existing users to drain. |
1328 | * - pserialize_perform waits for all pserialize_read sections on | | 1328 | * - pserialize_perform waits for all pserialize_read sections on |
1329 | * all CPUs; after this, no more new psref_acquire can happen. | | 1329 | * all CPUs; after this, no more new psref_acquire can happen. |
1330 | * - psref_target_destroy waits for all extant acquired psrefs to | | 1330 | * - psref_target_destroy waits for all extant acquired psrefs to |
1331 | * be psref_released. | | 1331 | * be psref_released. |
1332 | */ | | 1332 | */ |
1333 | pserialize_perform(sc->sc_psz); | | 1333 | pserialize_perform(sc->sc_psz); |
1334 | mutex_exit(sc->sc_lock); | | 1334 | mutex_exit(sc->sc_lock); |
1335 | psref_target_destroy(&sc->sc_psref, audio_psref_class); | | 1335 | psref_target_destroy(&sc->sc_psref, audio_psref_class); |
1336 | | | 1336 | |
1337 | /* | | 1337 | /* |
1338 | * We are now guaranteed that there are no calls to audio fileops | | 1338 | * We are now guaranteed that there are no calls to audio fileops |
1339 | * that hold sc, and any new calls with files that were for sc will | | 1339 | * that hold sc, and any new calls with files that were for sc will |
1340 | * fail. Thus, we now have exclusive access to the softc. | | 1340 | * fail. Thus, we now have exclusive access to the softc. |
1341 | */ | | 1341 | */ |
1342 | sc->sc_exlock = 1; | | 1342 | sc->sc_exlock = 1; |
1343 | | | 1343 | |
1344 | /* | | 1344 | /* |
1345 | * Clean up all open instances. | | 1345 | * Clean up all open instances. |
1346 | * Here, we no longer need any locks to traverse sc_files. | | 1346 | * Here, we no longer need any locks to traverse sc_files. |
1347 | */ | | 1347 | */ |
1348 | while ((file = SLIST_FIRST(&sc->sc_files)) != NULL) { | | 1348 | while ((file = SLIST_FIRST(&sc->sc_files)) != NULL) { |
1349 | audio_unlink(sc, file); | | 1349 | audio_unlink(sc, file); |
1350 | } | | 1350 | } |
1351 | | | 1351 | |
1352 | pmf_event_deregister(self, PMFE_AUDIO_VOLUME_DOWN, | | 1352 | pmf_event_deregister(self, PMFE_AUDIO_VOLUME_DOWN, |
1353 | audio_volume_down, true); | | 1353 | audio_volume_down, true); |
1354 | pmf_event_deregister(self, PMFE_AUDIO_VOLUME_UP, | | 1354 | pmf_event_deregister(self, PMFE_AUDIO_VOLUME_UP, |
1355 | audio_volume_up, true); | | 1355 | audio_volume_up, true); |
1356 | pmf_event_deregister(self, PMFE_AUDIO_VOLUME_TOGGLE, | | 1356 | pmf_event_deregister(self, PMFE_AUDIO_VOLUME_TOGGLE, |
1357 | audio_volume_toggle, true); | | 1357 | audio_volume_toggle, true); |
1358 | | | 1358 | |
1359 | #ifdef AUDIO_PM_IDLE | | 1359 | #ifdef AUDIO_PM_IDLE |
1360 | callout_halt(&sc->sc_idle_counter, sc->sc_lock); | | 1360 | callout_halt(&sc->sc_idle_counter, sc->sc_lock); |
1361 | | | 1361 | |
1362 | device_active_deregister(self, audio_activity); | | 1362 | device_active_deregister(self, audio_activity); |
1363 | #endif | | 1363 | #endif |
1364 | | | 1364 | |
1365 | pmf_device_deregister(self); | | 1365 | pmf_device_deregister(self); |
1366 | | | 1366 | |
1367 | /* Free resources */ | | 1367 | /* Free resources */ |
1368 | if (sc->sc_pmixer) { | | 1368 | if (sc->sc_pmixer) { |
1369 | audio_mixer_destroy(sc, sc->sc_pmixer); | | 1369 | audio_mixer_destroy(sc, sc->sc_pmixer); |
1370 | kmem_free(sc->sc_pmixer, sizeof(*sc->sc_pmixer)); | | 1370 | kmem_free(sc->sc_pmixer, sizeof(*sc->sc_pmixer)); |
1371 | } | | 1371 | } |
1372 | if (sc->sc_rmixer) { | | 1372 | if (sc->sc_rmixer) { |
1373 | audio_mixer_destroy(sc, sc->sc_rmixer); | | 1373 | audio_mixer_destroy(sc, sc->sc_rmixer); |
1374 | kmem_free(sc->sc_rmixer, sizeof(*sc->sc_rmixer)); | | 1374 | kmem_free(sc->sc_rmixer, sizeof(*sc->sc_rmixer)); |
1375 | } | | 1375 | } |
1376 | if (sc->sc_am) | | 1376 | if (sc->sc_am) |
1377 | kern_free(sc->sc_am); | | 1377 | kern_free(sc->sc_am); |
1378 | | | 1378 | |
1379 | seldestroy(&sc->sc_wsel); | | 1379 | seldestroy(&sc->sc_wsel); |
1380 | seldestroy(&sc->sc_rsel); | | 1380 | seldestroy(&sc->sc_rsel); |
1381 | | | 1381 | |
1382 | #ifdef AUDIO_PM_IDLE | | 1382 | #ifdef AUDIO_PM_IDLE |
1383 | callout_destroy(&sc->sc_idle_counter); | | 1383 | callout_destroy(&sc->sc_idle_counter); |
1384 | #endif | | 1384 | #endif |
1385 | | | 1385 | |
1386 | cv_destroy(&sc->sc_exlockcv); | | 1386 | cv_destroy(&sc->sc_exlockcv); |
1387 | | | 1387 | |
1388 | #if defined(AUDIO_DEBUG) | | 1388 | #if defined(AUDIO_DEBUG) |
1389 | audio_mlog_free(); | | 1389 | audio_mlog_free(); |
1390 | #endif | | 1390 | #endif |
1391 | | | 1391 | |
1392 | return 0; | | 1392 | return 0; |
1393 | } | | 1393 | } |
1394 | | | 1394 | |
1395 | static void | | 1395 | static void |
1396 | audiochilddet(device_t self, device_t child) | | 1396 | audiochilddet(device_t self, device_t child) |
1397 | { | | 1397 | { |
1398 | | | 1398 | |
1399 | /* we hold no child references, so do nothing */ | | 1399 | /* we hold no child references, so do nothing */ |
1400 | } | | 1400 | } |
1401 | | | 1401 | |
1402 | static int | | 1402 | static int |
1403 | audiosearch(device_t parent, cfdata_t cf, const int *locs, void *aux) | | 1403 | audiosearch(device_t parent, cfdata_t cf, const int *locs, void *aux) |
1404 | { | | 1404 | { |
1405 | | | 1405 | |
1406 | if (config_match(parent, cf, aux)) | | 1406 | if (config_match(parent, cf, aux)) |
1407 | config_attach_loc(parent, cf, locs, aux, NULL); | | 1407 | config_attach_loc(parent, cf, locs, aux, NULL); |
1408 | | | 1408 | |
1409 | return 0; | | 1409 | return 0; |
1410 | } | | 1410 | } |
1411 | | | 1411 | |
1412 | static int | | 1412 | static int |
1413 | audiorescan(device_t self, const char *ifattr, const int *locators) | | 1413 | audiorescan(device_t self, const char *ifattr, const int *locators) |
1414 | { | | 1414 | { |
1415 | struct audio_softc *sc = device_private(self); | | 1415 | struct audio_softc *sc = device_private(self); |
1416 | | | 1416 | |
1417 | config_search(sc->sc_dev, NULL, | | 1417 | config_search(sc->sc_dev, NULL, |
1418 | CFARG_SUBMATCH, audiosearch, | | 1418 | CFARG_SUBMATCH, audiosearch, |
1419 | CFARG_IATTR, ifattr, | | | |
1420 | CFARG_LOCATORS, locators, | | | |
1421 | CFARG_EOL); | | 1419 | CFARG_EOL); |
1422 | | | 1420 | |
1423 | return 0; | | 1421 | return 0; |
1424 | } | | 1422 | } |
1425 | | | 1423 | |
1426 | /* | | 1424 | /* |
1427 | * Called from hardware driver. This is where the MI audio driver gets | | 1425 | * Called from hardware driver. This is where the MI audio driver gets |
1428 | * probed/attached to the hardware driver. | | 1426 | * probed/attached to the hardware driver. |
1429 | */ | | 1427 | */ |
1430 | device_t | | 1428 | device_t |
1431 | audio_attach_mi(const struct audio_hw_if *ahwp, void *hdlp, device_t dev) | | 1429 | audio_attach_mi(const struct audio_hw_if *ahwp, void *hdlp, device_t dev) |
1432 | { | | 1430 | { |
1433 | struct audio_attach_args arg; | | 1431 | struct audio_attach_args arg; |
1434 | | | 1432 | |
1435 | #ifdef DIAGNOSTIC | | 1433 | #ifdef DIAGNOSTIC |
1436 | if (ahwp == NULL) { | | 1434 | if (ahwp == NULL) { |
1437 | aprint_error("audio_attach_mi: NULL\n"); | | 1435 | aprint_error("audio_attach_mi: NULL\n"); |
1438 | return 0; | | 1436 | return 0; |
1439 | } | | 1437 | } |
1440 | #endif | | 1438 | #endif |
1441 | arg.type = AUDIODEV_TYPE_AUDIO; | | 1439 | arg.type = AUDIODEV_TYPE_AUDIO; |
1442 | arg.hwif = ahwp; | | 1440 | arg.hwif = ahwp; |
1443 | arg.hdl = hdlp; | | 1441 | arg.hdl = hdlp; |
1444 | return config_found(dev, &arg, audioprint, CFARG_EOL); | | 1442 | return config_found(dev, &arg, audioprint, CFARG_EOL); |
1445 | } | | 1443 | } |
1446 | | | 1444 | |
1447 | /* | | 1445 | /* |
1448 | * audio_printf() outputs fmt... with the audio device name and MD device | | 1446 | * audio_printf() outputs fmt... with the audio device name and MD device |
1449 | * name prefixed. If the message is considered to be related to the MD | | 1447 | * name prefixed. If the message is considered to be related to the MD |
1450 | * driver, use this one instead of device_printf(). | | 1448 | * driver, use this one instead of device_printf(). |
1451 | */ | | 1449 | */ |
1452 | static void | | 1450 | static void |
1453 | audio_printf(struct audio_softc *sc, const char *fmt, ...) | | 1451 | audio_printf(struct audio_softc *sc, const char *fmt, ...) |
1454 | { | | 1452 | { |
1455 | va_list ap; | | 1453 | va_list ap; |
1456 | | | 1454 | |
1457 | printf("%s(%s): ", device_xname(sc->sc_dev), device_xname(sc->hw_dev)); | | 1455 | printf("%s(%s): ", device_xname(sc->sc_dev), device_xname(sc->hw_dev)); |
1458 | va_start(ap, fmt); | | 1456 | va_start(ap, fmt); |
1459 | vprintf(fmt, ap); | | 1457 | vprintf(fmt, ap); |
1460 | va_end(ap); | | 1458 | va_end(ap); |
1461 | } | | 1459 | } |
1462 | | | 1460 | |
1463 | /* | | 1461 | /* |
1464 | * Enter critical section and also keep sc_lock. | | 1462 | * Enter critical section and also keep sc_lock. |
1465 | * If successful, returns 0 with sc_lock held. Otherwise returns errno. | | 1463 | * If successful, returns 0 with sc_lock held. Otherwise returns errno. |
1466 | * Must be called without sc_lock held. | | 1464 | * Must be called without sc_lock held. |
1467 | */ | | 1465 | */ |
1468 | static int | | 1466 | static int |
1469 | audio_exlock_mutex_enter(struct audio_softc *sc) | | 1467 | audio_exlock_mutex_enter(struct audio_softc *sc) |
1470 | { | | 1468 | { |
1471 | int error; | | 1469 | int error; |
1472 | | | 1470 | |
1473 | mutex_enter(sc->sc_lock); | | 1471 | mutex_enter(sc->sc_lock); |
1474 | if (sc->sc_dying) { | | 1472 | if (sc->sc_dying) { |
1475 | mutex_exit(sc->sc_lock); | | 1473 | mutex_exit(sc->sc_lock); |
1476 | return EIO; | | 1474 | return EIO; |
1477 | } | | 1475 | } |
1478 | | | 1476 | |
1479 | while (__predict_false(sc->sc_exlock != 0)) { | | 1477 | while (__predict_false(sc->sc_exlock != 0)) { |
1480 | error = cv_wait_sig(&sc->sc_exlockcv, sc->sc_lock); | | 1478 | error = cv_wait_sig(&sc->sc_exlockcv, sc->sc_lock); |
1481 | if (sc->sc_dying) | | 1479 | if (sc->sc_dying) |
1482 | error = EIO; | | 1480 | error = EIO; |
1483 | if (error) { | | 1481 | if (error) { |
1484 | mutex_exit(sc->sc_lock); | | 1482 | mutex_exit(sc->sc_lock); |
1485 | return error; | | 1483 | return error; |
1486 | } | | 1484 | } |
1487 | } | | 1485 | } |
1488 | | | 1486 | |
1489 | /* Acquire */ | | 1487 | /* Acquire */ |
1490 | sc->sc_exlock = 1; | | 1488 | sc->sc_exlock = 1; |
1491 | return 0; | | 1489 | return 0; |
1492 | } | | 1490 | } |
1493 | | | 1491 | |
1494 | /* | | 1492 | /* |
1495 | * Exit critical section and exit sc_lock. | | 1493 | * Exit critical section and exit sc_lock. |
1496 | * Must be called with sc_lock held. | | 1494 | * Must be called with sc_lock held. |
1497 | */ | | 1495 | */ |
1498 | static void | | 1496 | static void |
1499 | audio_exlock_mutex_exit(struct audio_softc *sc) | | 1497 | audio_exlock_mutex_exit(struct audio_softc *sc) |
1500 | { | | 1498 | { |
1501 | | | 1499 | |
1502 | KASSERT(mutex_owned(sc->sc_lock)); | | 1500 | KASSERT(mutex_owned(sc->sc_lock)); |
1503 | | | 1501 | |
1504 | sc->sc_exlock = 0; | | 1502 | sc->sc_exlock = 0; |
1505 | cv_broadcast(&sc->sc_exlockcv); | | 1503 | cv_broadcast(&sc->sc_exlockcv); |
1506 | mutex_exit(sc->sc_lock); | | 1504 | mutex_exit(sc->sc_lock); |
1507 | } | | 1505 | } |
1508 | | | 1506 | |
1509 | /* | | 1507 | /* |
1510 | * Enter critical section. | | 1508 | * Enter critical section. |
1511 | * If successful, it returns 0. Otherwise returns errno. | | 1509 | * If successful, it returns 0. Otherwise returns errno. |
1512 | * Must be called without sc_lock held. | | 1510 | * Must be called without sc_lock held. |
1513 | * This function returns without sc_lock held. | | 1511 | * This function returns without sc_lock held. |
1514 | */ | | 1512 | */ |
1515 | static int | | 1513 | static int |
1516 | audio_exlock_enter(struct audio_softc *sc) | | 1514 | audio_exlock_enter(struct audio_softc *sc) |
1517 | { | | 1515 | { |
1518 | int error; | | 1516 | int error; |
1519 | | | 1517 | |
1520 | error = audio_exlock_mutex_enter(sc); | | 1518 | error = audio_exlock_mutex_enter(sc); |
1521 | if (error) | | 1519 | if (error) |
1522 | return error; | | 1520 | return error; |
1523 | mutex_exit(sc->sc_lock); | | 1521 | mutex_exit(sc->sc_lock); |
1524 | return 0; | | 1522 | return 0; |
1525 | } | | 1523 | } |
1526 | | | 1524 | |
1527 | /* | | 1525 | /* |
1528 | * Exit critical section. | | 1526 | * Exit critical section. |
1529 | * Must be called without sc_lock held. | | 1527 | * Must be called without sc_lock held. |
1530 | */ | | 1528 | */ |
1531 | static void | | 1529 | static void |
1532 | audio_exlock_exit(struct audio_softc *sc) | | 1530 | audio_exlock_exit(struct audio_softc *sc) |
1533 | { | | 1531 | { |
1534 | | | 1532 | |
1535 | mutex_enter(sc->sc_lock); | | 1533 | mutex_enter(sc->sc_lock); |
1536 | audio_exlock_mutex_exit(sc); | | 1534 | audio_exlock_mutex_exit(sc); |
1537 | } | | 1535 | } |
1538 | | | 1536 | |
1539 | /* | | 1537 | /* |
1540 | * Increment reference counter for this sc. | | 1538 | * Increment reference counter for this sc. |
1541 | * This is intended to be used for open. | | 1539 | * This is intended to be used for open. |
1542 | */ | | 1540 | */ |
1543 | void | | 1541 | void |
1544 | audio_sc_acquire_foropen(struct audio_softc *sc, struct psref *refp) | | 1542 | audio_sc_acquire_foropen(struct audio_softc *sc, struct psref *refp) |
1545 | { | | 1543 | { |
1546 | int s; | | 1544 | int s; |
1547 | | | 1545 | |
1548 | /* Block audiodetach while we acquire a reference */ | | 1546 | /* Block audiodetach while we acquire a reference */ |
1549 | s = pserialize_read_enter(); | | 1547 | s = pserialize_read_enter(); |
1550 | | | 1548 | |
1551 | /* | | 1549 | /* |
1552 | * We don't examine sc_dying here. However, all open methods | | 1550 | * We don't examine sc_dying here. However, all open methods |
1553 | * call audio_exlock_enter() right after this, so we can examine | | 1551 | * call audio_exlock_enter() right after this, so we can examine |
1554 | * sc_dying in it. | | 1552 | * sc_dying in it. |
1555 | */ | | 1553 | */ |
1556 | | | 1554 | |
1557 | /* Acquire a reference */ | | 1555 | /* Acquire a reference */ |
1558 | psref_acquire(refp, &sc->sc_psref, audio_psref_class); | | 1556 | psref_acquire(refp, &sc->sc_psref, audio_psref_class); |
1559 | | | 1557 | |
1560 | /* Now sc won't go away until we drop the reference count */ | | 1558 | /* Now sc won't go away until we drop the reference count */ |
1561 | pserialize_read_exit(s); | | 1559 | pserialize_read_exit(s); |
1562 | } | | 1560 | } |
1563 | | | 1561 | |
1564 | /* | | 1562 | /* |
1565 | * Get sc from file, and increment reference counter for this sc. | | 1563 | * Get sc from file, and increment reference counter for this sc. |
1566 | * This is intended to be used for methods other than open. | | 1564 | * This is intended to be used for methods other than open. |
1567 | * If successful, returns sc. Otherwise returns NULL. | | 1565 | * If successful, returns sc. Otherwise returns NULL. |
1568 | */ | | 1566 | */ |
1569 | struct audio_softc * | | 1567 | struct audio_softc * |
1570 | audio_sc_acquire_fromfile(audio_file_t *file, struct psref *refp) | | 1568 | audio_sc_acquire_fromfile(audio_file_t *file, struct psref *refp) |
1571 | { | | 1569 | { |
1572 | int s; | | 1570 | int s; |
1573 | bool dying; | | 1571 | bool dying; |
1574 | | | 1572 | |
1575 | /* Block audiodetach while we acquire a reference */ | | 1573 | /* Block audiodetach while we acquire a reference */ |
1576 | s = pserialize_read_enter(); | | 1574 | s = pserialize_read_enter(); |
1577 | | | 1575 | |
1578 | /* If close or audiodetach already ran, tough -- no more audio */ | | 1576 | /* If close or audiodetach already ran, tough -- no more audio */ |
1579 | dying = atomic_load_relaxed(&file->dying); | | 1577 | dying = atomic_load_relaxed(&file->dying); |
1580 | if (dying) { | | 1578 | if (dying) { |
1581 | pserialize_read_exit(s); | | 1579 | pserialize_read_exit(s); |
1582 | return NULL; | | 1580 | return NULL; |
1583 | } | | 1581 | } |
1584 | | | 1582 | |
1585 | /* Acquire a reference */ | | 1583 | /* Acquire a reference */ |
1586 | psref_acquire(refp, &file->sc->sc_psref, audio_psref_class); | | 1584 | psref_acquire(refp, &file->sc->sc_psref, audio_psref_class); |
1587 | | | 1585 | |
1588 | /* Now sc won't go away until we drop the reference count */ | | 1586 | /* Now sc won't go away until we drop the reference count */ |
1589 | pserialize_read_exit(s); | | 1587 | pserialize_read_exit(s); |
1590 | | | 1588 | |
1591 | return file->sc; | | 1589 | return file->sc; |
1592 | } | | 1590 | } |
1593 | | | 1591 | |
1594 | /* | | 1592 | /* |
1595 | * Decrement reference counter for this sc. | | 1593 | * Decrement reference counter for this sc. |
1596 | */ | | 1594 | */ |
1597 | void | | 1595 | void |
1598 | audio_sc_release(struct audio_softc *sc, struct psref *refp) | | 1596 | audio_sc_release(struct audio_softc *sc, struct psref *refp) |
1599 | { | | 1597 | { |
1600 | | | 1598 | |
1601 | psref_release(refp, &sc->sc_psref, audio_psref_class); | | 1599 | psref_release(refp, &sc->sc_psref, audio_psref_class); |
1602 | } | | 1600 | } |
1603 | | | 1601 | |
1604 | /* | | 1602 | /* |
1605 | * Wait for I/O to complete, releasing sc_lock. | | 1603 | * Wait for I/O to complete, releasing sc_lock. |
1606 | * Must be called with sc_lock held. | | 1604 | * Must be called with sc_lock held. |
1607 | */ | | 1605 | */ |
1608 | static int | | 1606 | static int |
1609 | audio_track_waitio(struct audio_softc *sc, audio_track_t *track) | | 1607 | audio_track_waitio(struct audio_softc *sc, audio_track_t *track) |
1610 | { | | 1608 | { |
1611 | int error; | | 1609 | int error; |
1612 | | | 1610 | |
1613 | KASSERT(track); | | 1611 | KASSERT(track); |
1614 | KASSERT(mutex_owned(sc->sc_lock)); | | 1612 | KASSERT(mutex_owned(sc->sc_lock)); |
1615 | | | 1613 | |
1616 | /* Wait for pending I/O to complete. */ | | 1614 | /* Wait for pending I/O to complete. */ |
1617 | error = cv_timedwait_sig(&track->mixer->outcv, sc->sc_lock, | | 1615 | error = cv_timedwait_sig(&track->mixer->outcv, sc->sc_lock, |
1618 | mstohz(AUDIO_TIMEOUT)); | | 1616 | mstohz(AUDIO_TIMEOUT)); |
1619 | if (sc->sc_suspending) { | | 1617 | if (sc->sc_suspending) { |
1620 | /* If it's about to suspend, ignore timeout error. */ | | 1618 | /* If it's about to suspend, ignore timeout error. */ |
1621 | if (error == EWOULDBLOCK) { | | 1619 | if (error == EWOULDBLOCK) { |
1622 | TRACET(2, track, "timeout (suspending)"); | | 1620 | TRACET(2, track, "timeout (suspending)"); |
1623 | return 0; | | 1621 | return 0; |
1624 | } | | 1622 | } |
1625 | } | | 1623 | } |
1626 | if (sc->sc_dying) { | | 1624 | if (sc->sc_dying) { |
1627 | error = EIO; | | 1625 | error = EIO; |
1628 | } | | 1626 | } |
1629 | if (error) { | | 1627 | if (error) { |
1630 | TRACET(2, track, "cv_timedwait_sig failed %d", error); | | 1628 | TRACET(2, track, "cv_timedwait_sig failed %d", error); |
1631 | if (error == EWOULDBLOCK) | | 1629 | if (error == EWOULDBLOCK) |
1632 | audio_printf(sc, "device timeout\n"); | | 1630 | audio_printf(sc, "device timeout\n"); |
1633 | } else { | | 1631 | } else { |
1634 | TRACET(3, track, "wakeup"); | | 1632 | TRACET(3, track, "wakeup"); |
1635 | } | | 1633 | } |
1636 | return error; | | 1634 | return error; |
1637 | } | | 1635 | } |
1638 | | | 1636 | |
1639 | /* | | 1637 | /* |
1640 | * Try to acquire track lock. | | 1638 | * Try to acquire track lock. |
1641 | * It doesn't block if the track lock is already aquired. | | 1639 | * It doesn't block if the track lock is already aquired. |
1642 | * Returns true if the track lock was acquired, or false if the track | | 1640 | * Returns true if the track lock was acquired, or false if the track |
1643 | * lock was already acquired. | | 1641 | * lock was already acquired. |
1644 | */ | | 1642 | */ |
1645 | static __inline bool | | 1643 | static __inline bool |
1646 | audio_track_lock_tryenter(audio_track_t *track) | | 1644 | audio_track_lock_tryenter(audio_track_t *track) |
1647 | { | | 1645 | { |
1648 | return (atomic_cas_uint(&track->lock, 0, 1) == 0); | | 1646 | return (atomic_cas_uint(&track->lock, 0, 1) == 0); |
1649 | } | | 1647 | } |
1650 | | | 1648 | |
1651 | /* | | 1649 | /* |
1652 | * Acquire track lock. | | 1650 | * Acquire track lock. |
1653 | */ | | 1651 | */ |
1654 | static __inline void | | 1652 | static __inline void |
1655 | audio_track_lock_enter(audio_track_t *track) | | 1653 | audio_track_lock_enter(audio_track_t *track) |
1656 | { | | 1654 | { |
1657 | /* Don't sleep here. */ | | 1655 | /* Don't sleep here. */ |
1658 | while (audio_track_lock_tryenter(track) == false) | | 1656 | while (audio_track_lock_tryenter(track) == false) |
1659 | ; | | 1657 | ; |
1660 | } | | 1658 | } |
1661 | | | 1659 | |
1662 | /* | | 1660 | /* |
1663 | * Release track lock. | | 1661 | * Release track lock. |
1664 | */ | | 1662 | */ |
1665 | static __inline void | | 1663 | static __inline void |
1666 | audio_track_lock_exit(audio_track_t *track) | | 1664 | audio_track_lock_exit(audio_track_t *track) |
1667 | { | | 1665 | { |
1668 | atomic_swap_uint(&track->lock, 0); | | 1666 | atomic_swap_uint(&track->lock, 0); |
1669 | } | | 1667 | } |
1670 | | | 1668 | |
1671 | | | 1669 | |
1672 | static int | | 1670 | static int |
1673 | audioopen(dev_t dev, int flags, int ifmt, struct lwp *l) | | 1671 | audioopen(dev_t dev, int flags, int ifmt, struct lwp *l) |
1674 | { | | 1672 | { |
1675 | struct audio_softc *sc; | | 1673 | struct audio_softc *sc; |
1676 | struct psref sc_ref; | | 1674 | struct psref sc_ref; |
1677 | int bound; | | 1675 | int bound; |
1678 | int error; | | 1676 | int error; |
1679 | | | 1677 | |
1680 | /* Find the device */ | | 1678 | /* Find the device */ |
1681 | sc = device_lookup_private(&audio_cd, AUDIOUNIT(dev)); | | 1679 | sc = device_lookup_private(&audio_cd, AUDIOUNIT(dev)); |
1682 | if (sc == NULL || sc->hw_if == NULL) | | 1680 | if (sc == NULL || sc->hw_if == NULL) |
1683 | return ENXIO; | | 1681 | return ENXIO; |
1684 | | | 1682 | |
1685 | bound = curlwp_bind(); | | 1683 | bound = curlwp_bind(); |
1686 | audio_sc_acquire_foropen(sc, &sc_ref); | | 1684 | audio_sc_acquire_foropen(sc, &sc_ref); |
1687 | | | 1685 | |
1688 | error = audio_exlock_enter(sc); | | 1686 | error = audio_exlock_enter(sc); |
1689 | if (error) | | 1687 | if (error) |
1690 | goto done; | | 1688 | goto done; |
1691 | | | 1689 | |
1692 | device_active(sc->sc_dev, DVA_SYSTEM); | | 1690 | device_active(sc->sc_dev, DVA_SYSTEM); |
1693 | switch (AUDIODEV(dev)) { | | 1691 | switch (AUDIODEV(dev)) { |
1694 | case SOUND_DEVICE: | | 1692 | case SOUND_DEVICE: |
1695 | case AUDIO_DEVICE: | | 1693 | case AUDIO_DEVICE: |
1696 | error = audio_open(dev, sc, flags, ifmt, l, NULL); | | 1694 | error = audio_open(dev, sc, flags, ifmt, l, NULL); |
1697 | break; | | 1695 | break; |
1698 | case AUDIOCTL_DEVICE: | | 1696 | case AUDIOCTL_DEVICE: |
1699 | error = audioctl_open(dev, sc, flags, ifmt, l); | | 1697 | error = audioctl_open(dev, sc, flags, ifmt, l); |
1700 | break; | | 1698 | break; |
1701 | case MIXER_DEVICE: | | 1699 | case MIXER_DEVICE: |
1702 | error = mixer_open(dev, sc, flags, ifmt, l); | | 1700 | error = mixer_open(dev, sc, flags, ifmt, l); |
1703 | break; | | 1701 | break; |
1704 | default: | | 1702 | default: |
1705 | error = ENXIO; | | 1703 | error = ENXIO; |
1706 | break; | | 1704 | break; |
1707 | } | | 1705 | } |
1708 | audio_exlock_exit(sc); | | 1706 | audio_exlock_exit(sc); |
1709 | | | 1707 | |
1710 | done: | | 1708 | done: |
1711 | audio_sc_release(sc, &sc_ref); | | 1709 | audio_sc_release(sc, &sc_ref); |
1712 | curlwp_bindx(bound); | | 1710 | curlwp_bindx(bound); |
1713 | return error; | | 1711 | return error; |
1714 | } | | 1712 | } |
1715 | | | 1713 | |
1716 | static int | | 1714 | static int |
1717 | audioclose(struct file *fp) | | 1715 | audioclose(struct file *fp) |
1718 | { | | 1716 | { |
1719 | struct audio_softc *sc; | | 1717 | struct audio_softc *sc; |
1720 | struct psref sc_ref; | | 1718 | struct psref sc_ref; |
1721 | audio_file_t *file; | | 1719 | audio_file_t *file; |
1722 | int bound; | | 1720 | int bound; |
1723 | int error; | | 1721 | int error; |
1724 | dev_t dev; | | 1722 | dev_t dev; |
1725 | | | 1723 | |
1726 | KASSERT(fp->f_audioctx); | | 1724 | KASSERT(fp->f_audioctx); |
1727 | file = fp->f_audioctx; | | 1725 | file = fp->f_audioctx; |
1728 | dev = file->dev; | | 1726 | dev = file->dev; |
1729 | error = 0; | | 1727 | error = 0; |
1730 | | | 1728 | |
1731 | /* | | 1729 | /* |
1732 | * audioclose() must | | 1730 | * audioclose() must |
1733 | * - unplug track from the trackmixer (and unplug anything from softc), | | 1731 | * - unplug track from the trackmixer (and unplug anything from softc), |
1734 | * if sc exists. | | 1732 | * if sc exists. |
1735 | * - free all memory objects, regardless of sc. | | 1733 | * - free all memory objects, regardless of sc. |
1736 | */ | | 1734 | */ |
1737 | | | 1735 | |
1738 | bound = curlwp_bind(); | | 1736 | bound = curlwp_bind(); |
1739 | sc = audio_sc_acquire_fromfile(file, &sc_ref); | | 1737 | sc = audio_sc_acquire_fromfile(file, &sc_ref); |
1740 | if (sc) { | | 1738 | if (sc) { |
1741 | switch (AUDIODEV(dev)) { | | 1739 | switch (AUDIODEV(dev)) { |
1742 | case SOUND_DEVICE: | | 1740 | case SOUND_DEVICE: |
1743 | case AUDIO_DEVICE: | | 1741 | case AUDIO_DEVICE: |
1744 | error = audio_close(sc, file); | | 1742 | error = audio_close(sc, file); |
1745 | break; | | 1743 | break; |
1746 | case AUDIOCTL_DEVICE: | | 1744 | case AUDIOCTL_DEVICE: |
1747 | error = 0; | | 1745 | error = 0; |
1748 | break; | | 1746 | break; |
1749 | case MIXER_DEVICE: | | 1747 | case MIXER_DEVICE: |
1750 | error = mixer_close(sc, file); | | 1748 | error = mixer_close(sc, file); |
1751 | break; | | 1749 | break; |
1752 | default: | | 1750 | default: |
1753 | error = ENXIO; | | 1751 | error = ENXIO; |
1754 | break; | | 1752 | break; |
1755 | } | | 1753 | } |
1756 | | | 1754 | |
1757 | audio_sc_release(sc, &sc_ref); | | 1755 | audio_sc_release(sc, &sc_ref); |
1758 | } | | 1756 | } |
1759 | curlwp_bindx(bound); | | 1757 | curlwp_bindx(bound); |
1760 | | | 1758 | |
1761 | /* Free memory objects anyway */ | | 1759 | /* Free memory objects anyway */ |
1762 | TRACEF(2, file, "free memory"); | | 1760 | TRACEF(2, file, "free memory"); |
1763 | if (file->ptrack) | | 1761 | if (file->ptrack) |
1764 | audio_track_destroy(file->ptrack); | | 1762 | audio_track_destroy(file->ptrack); |
1765 | if (file->rtrack) | | 1763 | if (file->rtrack) |
1766 | audio_track_destroy(file->rtrack); | | 1764 | audio_track_destroy(file->rtrack); |
1767 | kmem_free(file, sizeof(*file)); | | 1765 | kmem_free(file, sizeof(*file)); |
1768 | fp->f_audioctx = NULL; | | 1766 | fp->f_audioctx = NULL; |
1769 | | | 1767 | |
1770 | return error; | | 1768 | return error; |
1771 | } | | 1769 | } |
1772 | | | 1770 | |
1773 | static int | | 1771 | static int |
1774 | audioread(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred, | | 1772 | audioread(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred, |
1775 | int ioflag) | | 1773 | int ioflag) |
1776 | { | | 1774 | { |
1777 | struct audio_softc *sc; | | 1775 | struct audio_softc *sc; |
1778 | struct psref sc_ref; | | 1776 | struct psref sc_ref; |
1779 | audio_file_t *file; | | 1777 | audio_file_t *file; |
1780 | int bound; | | 1778 | int bound; |
1781 | int error; | | 1779 | int error; |
1782 | dev_t dev; | | 1780 | dev_t dev; |
1783 | | | 1781 | |
1784 | KASSERT(fp->f_audioctx); | | 1782 | KASSERT(fp->f_audioctx); |
1785 | file = fp->f_audioctx; | | 1783 | file = fp->f_audioctx; |
1786 | dev = file->dev; | | 1784 | dev = file->dev; |
1787 | | | 1785 | |
1788 | bound = curlwp_bind(); | | 1786 | bound = curlwp_bind(); |
1789 | sc = audio_sc_acquire_fromfile(file, &sc_ref); | | 1787 | sc = audio_sc_acquire_fromfile(file, &sc_ref); |
1790 | if (sc == NULL) { | | 1788 | if (sc == NULL) { |
1791 | error = EIO; | | 1789 | error = EIO; |
1792 | goto done; | | 1790 | goto done; |
1793 | } | | 1791 | } |
1794 | | | 1792 | |
1795 | if (fp->f_flag & O_NONBLOCK) | | 1793 | if (fp->f_flag & O_NONBLOCK) |
1796 | ioflag |= IO_NDELAY; | | 1794 | ioflag |= IO_NDELAY; |
1797 | | | 1795 | |
1798 | switch (AUDIODEV(dev)) { | | 1796 | switch (AUDIODEV(dev)) { |
1799 | case SOUND_DEVICE: | | 1797 | case SOUND_DEVICE: |
1800 | case AUDIO_DEVICE: | | 1798 | case AUDIO_DEVICE: |
1801 | error = audio_read(sc, uio, ioflag, file); | | 1799 | error = audio_read(sc, uio, ioflag, file); |
1802 | break; | | 1800 | break; |
1803 | case AUDIOCTL_DEVICE: | | 1801 | case AUDIOCTL_DEVICE: |
1804 | case MIXER_DEVICE: | | 1802 | case MIXER_DEVICE: |
1805 | error = ENODEV; | | 1803 | error = ENODEV; |
1806 | break; | | 1804 | break; |
1807 | default: | | 1805 | default: |
1808 | error = ENXIO; | | 1806 | error = ENXIO; |
1809 | break; | | 1807 | break; |
1810 | } | | 1808 | } |
1811 | | | 1809 | |
1812 | audio_sc_release(sc, &sc_ref); | | 1810 | audio_sc_release(sc, &sc_ref); |
1813 | done: | | 1811 | done: |
1814 | curlwp_bindx(bound); | | 1812 | curlwp_bindx(bound); |
1815 | return error; | | 1813 | return error; |
1816 | } | | 1814 | } |
1817 | | | 1815 | |
1818 | static int | | 1816 | static int |
1819 | audiowrite(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred, | | 1817 | audiowrite(struct file *fp, off_t *offp, struct uio *uio, kauth_cred_t cred, |
1820 | int ioflag) | | 1818 | int ioflag) |
1821 | { | | 1819 | { |
1822 | struct audio_softc *sc; | | 1820 | struct audio_softc *sc; |
1823 | struct psref sc_ref; | | 1821 | struct psref sc_ref; |
1824 | audio_file_t *file; | | 1822 | audio_file_t *file; |
1825 | int bound; | | 1823 | int bound; |
1826 | int error; | | 1824 | int error; |
1827 | dev_t dev; | | 1825 | dev_t dev; |
1828 | | | 1826 | |
1829 | KASSERT(fp->f_audioctx); | | 1827 | KASSERT(fp->f_audioctx); |
1830 | file = fp->f_audioctx; | | 1828 | file = fp->f_audioctx; |
1831 | dev = file->dev; | | 1829 | dev = file->dev; |
1832 | | | 1830 | |
1833 | bound = curlwp_bind(); | | 1831 | bound = curlwp_bind(); |
1834 | sc = audio_sc_acquire_fromfile(file, &sc_ref); | | 1832 | sc = audio_sc_acquire_fromfile(file, &sc_ref); |
1835 | if (sc == NULL) { | | 1833 | if (sc == NULL) { |
1836 | error = EIO; | | 1834 | error = EIO; |
1837 | goto done; | | 1835 | goto done; |
1838 | } | | 1836 | } |
1839 | | | 1837 | |
1840 | if (fp->f_flag & O_NONBLOCK) | | 1838 | if (fp->f_flag & O_NONBLOCK) |
1841 | ioflag |= IO_NDELAY; | | 1839 | ioflag |= IO_NDELAY; |
1842 | | | 1840 | |
1843 | switch (AUDIODEV(dev)) { | | 1841 | switch (AUDIODEV(dev)) { |
1844 | case SOUND_DEVICE: | | 1842 | case SOUND_DEVICE: |
1845 | case AUDIO_DEVICE: | | 1843 | case AUDIO_DEVICE: |
1846 | error = audio_write(sc, uio, ioflag, file); | | 1844 | error = audio_write(sc, uio, ioflag, file); |
1847 | break; | | 1845 | break; |
1848 | case AUDIOCTL_DEVICE: | | 1846 | case AUDIOCTL_DEVICE: |
1849 | case MIXER_DEVICE: | | 1847 | case MIXER_DEVICE: |
1850 | error = ENODEV; | | 1848 | error = ENODEV; |
1851 | break; | | 1849 | break; |
1852 | default: | | 1850 | default: |
1853 | error = ENXIO; | | 1851 | error = ENXIO; |
1854 | break; | | 1852 | break; |
1855 | } | | 1853 | } |
1856 | | | 1854 | |
1857 | audio_sc_release(sc, &sc_ref); | | 1855 | audio_sc_release(sc, &sc_ref); |
1858 | done: | | 1856 | done: |
1859 | curlwp_bindx(bound); | | 1857 | curlwp_bindx(bound); |
1860 | return error; | | 1858 | return error; |
1861 | } | | 1859 | } |
1862 | | | 1860 | |
1863 | static int | | 1861 | static int |
1864 | audioioctl(struct file *fp, u_long cmd, void *addr) | | 1862 | audioioctl(struct file *fp, u_long cmd, void *addr) |
1865 | { | | 1863 | { |
1866 | struct audio_softc *sc; | | 1864 | struct audio_softc *sc; |
1867 | struct psref sc_ref; | | 1865 | struct psref sc_ref; |
1868 | audio_file_t *file; | | 1866 | audio_file_t *file; |
1869 | struct lwp *l = curlwp; | | 1867 | struct lwp *l = curlwp; |
1870 | int bound; | | 1868 | int bound; |
1871 | int error; | | 1869 | int error; |
1872 | dev_t dev; | | 1870 | dev_t dev; |
1873 | | | 1871 | |
1874 | KASSERT(fp->f_audioctx); | | 1872 | KASSERT(fp->f_audioctx); |
1875 | file = fp->f_audioctx; | | 1873 | file = fp->f_audioctx; |
1876 | dev = file->dev; | | 1874 | dev = file->dev; |
1877 | | | 1875 | |
1878 | bound = curlwp_bind(); | | 1876 | bound = curlwp_bind(); |
1879 | sc = audio_sc_acquire_fromfile(file, &sc_ref); | | 1877 | sc = audio_sc_acquire_fromfile(file, &sc_ref); |
1880 | if (sc == NULL) { | | 1878 | if (sc == NULL) { |
1881 | error = EIO; | | 1879 | error = EIO; |
1882 | goto done; | | 1880 | goto done; |
1883 | } | | 1881 | } |
1884 | | | 1882 | |
1885 | switch (AUDIODEV(dev)) { | | 1883 | switch (AUDIODEV(dev)) { |
1886 | case SOUND_DEVICE: | | 1884 | case SOUND_DEVICE: |
1887 | case AUDIO_DEVICE: | | 1885 | case AUDIO_DEVICE: |
1888 | case AUDIOCTL_DEVICE: | | 1886 | case AUDIOCTL_DEVICE: |
1889 | mutex_enter(sc->sc_lock); | | 1887 | mutex_enter(sc->sc_lock); |
1890 | device_active(sc->sc_dev, DVA_SYSTEM); | | 1888 | device_active(sc->sc_dev, DVA_SYSTEM); |
1891 | mutex_exit(sc->sc_lock); | | 1889 | mutex_exit(sc->sc_lock); |
1892 | if (IOCGROUP(cmd) == IOCGROUP(AUDIO_MIXER_READ)) | | 1890 | if (IOCGROUP(cmd) == IOCGROUP(AUDIO_MIXER_READ)) |
1893 | error = mixer_ioctl(sc, cmd, addr, fp->f_flag, l); | | 1891 | error = mixer_ioctl(sc, cmd, addr, fp->f_flag, l); |
1894 | else | | 1892 | else |
1895 | error = audio_ioctl(dev, sc, cmd, addr, fp->f_flag, l, | | 1893 | error = audio_ioctl(dev, sc, cmd, addr, fp->f_flag, l, |
1896 | file); | | 1894 | file); |
1897 | break; | | 1895 | break; |
1898 | case MIXER_DEVICE: | | 1896 | case MIXER_DEVICE: |
1899 | error = mixer_ioctl(sc, cmd, addr, fp->f_flag, l); | | 1897 | error = mixer_ioctl(sc, cmd, addr, fp->f_flag, l); |
1900 | break; | | 1898 | break; |
1901 | default: | | 1899 | default: |
1902 | error = ENXIO; | | 1900 | error = ENXIO; |
1903 | break; | | 1901 | break; |
1904 | } | | 1902 | } |
1905 | | | 1903 | |
1906 | audio_sc_release(sc, &sc_ref); | | 1904 | audio_sc_release(sc, &sc_ref); |
1907 | done: | | 1905 | done: |
1908 | curlwp_bindx(bound); | | 1906 | curlwp_bindx(bound); |
1909 | return error; | | 1907 | return error; |
1910 | } | | 1908 | } |
1911 | | | 1909 | |
1912 | static int | | 1910 | static int |
1913 | audiostat(struct file *fp, struct stat *st) | | 1911 | audiostat(struct file *fp, struct stat *st) |
1914 | { | | 1912 | { |
1915 | struct audio_softc *sc; | | 1913 | struct audio_softc *sc; |
1916 | struct psref sc_ref; | | 1914 | struct psref sc_ref; |
1917 | audio_file_t *file; | | 1915 | audio_file_t *file; |
1918 | int bound; | | 1916 | int bound; |
1919 | int error; | | 1917 | int error; |
1920 | | | 1918 | |
1921 | KASSERT(fp->f_audioctx); | | 1919 | KASSERT(fp->f_audioctx); |
1922 | file = fp->f_audioctx; | | 1920 | file = fp->f_audioctx; |
1923 | | | 1921 | |
1924 | bound = curlwp_bind(); | | 1922 | bound = curlwp_bind(); |
1925 | sc = audio_sc_acquire_fromfile(file, &sc_ref); | | 1923 | sc = audio_sc_acquire_fromfile(file, &sc_ref); |
1926 | if (sc == NULL) { | | 1924 | if (sc == NULL) { |
1927 | error = EIO; | | 1925 | error = EIO; |
1928 | goto done; | | 1926 | goto done; |
1929 | } | | 1927 | } |
1930 | | | 1928 | |
1931 | error = 0; | | 1929 | error = 0; |
1932 | memset(st, 0, sizeof(*st)); | | 1930 | memset(st, 0, sizeof(*st)); |
1933 | | | 1931 | |
1934 | st->st_dev = file->dev; | | 1932 | st->st_dev = file->dev; |
1935 | st->st_uid = kauth_cred_geteuid(fp->f_cred); | | 1933 | st->st_uid = kauth_cred_geteuid(fp->f_cred); |
1936 | st->st_gid = kauth_cred_getegid(fp->f_cred); | | 1934 | st->st_gid = kauth_cred_getegid(fp->f_cred); |
1937 | st->st_mode = S_IFCHR; | | 1935 | st->st_mode = S_IFCHR; |
1938 | | | 1936 | |
1939 | audio_sc_release(sc, &sc_ref); | | 1937 | audio_sc_release(sc, &sc_ref); |
1940 | done: | | 1938 | done: |
1941 | curlwp_bindx(bound); | | 1939 | curlwp_bindx(bound); |
1942 | return error; | | 1940 | return error; |
1943 | } | | 1941 | } |
1944 | | | 1942 | |
1945 | static int | | 1943 | static int |
1946 | audiopoll(struct file *fp, int events) | | 1944 | audiopoll(struct file *fp, int events) |
1947 | { | | 1945 | { |
1948 | struct audio_softc *sc; | | 1946 | struct audio_softc *sc; |
1949 | struct psref sc_ref; | | 1947 | struct psref sc_ref; |
1950 | audio_file_t *file; | | 1948 | audio_file_t *file; |
1951 | struct lwp *l = curlwp; | | 1949 | struct lwp *l = curlwp; |
1952 | int bound; | | 1950 | int bound; |
1953 | int revents; | | 1951 | int revents; |
1954 | dev_t dev; | | 1952 | dev_t dev; |
1955 | | | 1953 | |
1956 | KASSERT(fp->f_audioctx); | | 1954 | KASSERT(fp->f_audioctx); |
1957 | file = fp->f_audioctx; | | 1955 | file = fp->f_audioctx; |
1958 | dev = file->dev; | | 1956 | dev = file->dev; |
1959 | | | 1957 | |
1960 | bound = curlwp_bind(); | | 1958 | bound = curlwp_bind(); |
1961 | sc = audio_sc_acquire_fromfile(file, &sc_ref); | | 1959 | sc = audio_sc_acquire_fromfile(file, &sc_ref); |
1962 | if (sc == NULL) { | | 1960 | if (sc == NULL) { |
1963 | revents = POLLERR; | | 1961 | revents = POLLERR; |
1964 | goto done; | | 1962 | goto done; |
1965 | } | | 1963 | } |
1966 | | | 1964 | |
1967 | switch (AUDIODEV(dev)) { | | 1965 | switch (AUDIODEV(dev)) { |
1968 | case SOUND_DEVICE: | | 1966 | case SOUND_DEVICE: |
1969 | case AUDIO_DEVICE: | | 1967 | case AUDIO_DEVICE: |
1970 | revents = audio_poll(sc, events, l, file); | | 1968 | revents = audio_poll(sc, events, l, file); |
1971 | break; | | 1969 | break; |
1972 | case AUDIOCTL_DEVICE: | | 1970 | case AUDIOCTL_DEVICE: |
1973 | case MIXER_DEVICE: | | 1971 | case MIXER_DEVICE: |
1974 | revents = 0; | | 1972 | revents = 0; |
1975 | break; | | 1973 | break; |
1976 | default: | | 1974 | default: |
1977 | revents = POLLERR; | | 1975 | revents = POLLERR; |
1978 | break; | | 1976 | break; |
1979 | } | | 1977 | } |
1980 | | | 1978 | |
1981 | audio_sc_release(sc, &sc_ref); | | 1979 | audio_sc_release(sc, &sc_ref); |
1982 | done: | | 1980 | done: |
1983 | curlwp_bindx(bound); | | 1981 | curlwp_bindx(bound); |
1984 | return revents; | | 1982 | return revents; |
1985 | } | | 1983 | } |
1986 | | | 1984 | |
1987 | static int | | 1985 | static int |
1988 | audiokqfilter(struct file *fp, struct knote *kn) | | 1986 | audiokqfilter(struct file *fp, struct knote *kn) |
1989 | { | | 1987 | { |
1990 | struct audio_softc *sc; | | 1988 | struct audio_softc *sc; |
1991 | struct psref sc_ref; | | 1989 | struct psref sc_ref; |
1992 | audio_file_t *file; | | 1990 | audio_file_t *file; |
1993 | dev_t dev; | | 1991 | dev_t dev; |
1994 | int bound; | | 1992 | int bound; |
1995 | int error; | | 1993 | int error; |
1996 | | | 1994 | |
1997 | KASSERT(fp->f_audioctx); | | 1995 | KASSERT(fp->f_audioctx); |
1998 | file = fp->f_audioctx; | | 1996 | file = fp->f_audioctx; |
1999 | dev = file->dev; | | 1997 | dev = file->dev; |
2000 | | | 1998 | |
2001 | bound = curlwp_bind(); | | 1999 | bound = curlwp_bind(); |
2002 | sc = audio_sc_acquire_fromfile(file, &sc_ref); | | 2000 | sc = audio_sc_acquire_fromfile(file, &sc_ref); |
2003 | if (sc == NULL) { | | 2001 | if (sc == NULL) { |
2004 | error = EIO; | | 2002 | error = EIO; |
2005 | goto done; | | 2003 | goto done; |
2006 | } | | 2004 | } |
2007 | | | 2005 | |
2008 | switch (AUDIODEV(dev)) { | | 2006 | switch (AUDIODEV(dev)) { |
2009 | case SOUND_DEVICE: | | 2007 | case SOUND_DEVICE: |
2010 | case AUDIO_DEVICE: | | 2008 | case AUDIO_DEVICE: |
2011 | error = audio_kqfilter(sc, file, kn); | | 2009 | error = audio_kqfilter(sc, file, kn); |
2012 | break; | | 2010 | break; |
2013 | case AUDIOCTL_DEVICE: | | 2011 | case AUDIOCTL_DEVICE: |
2014 | case MIXER_DEVICE: | | 2012 | case MIXER_DEVICE: |
2015 | error = ENODEV; | | 2013 | error = ENODEV; |
2016 | break; | | 2014 | break; |
2017 | default: | | 2015 | default: |
2018 | error = ENXIO; | | 2016 | error = ENXIO; |
2019 | break; | | 2017 | break; |
2020 | } | | 2018 | } |
2021 | | | 2019 | |
2022 | audio_sc_release(sc, &sc_ref); | | 2020 | audio_sc_release(sc, &sc_ref); |
2023 | done: | | 2021 | done: |
2024 | curlwp_bindx(bound); | | 2022 | curlwp_bindx(bound); |
2025 | return error; | | 2023 | return error; |
2026 | } | | 2024 | } |
2027 | | | 2025 | |
2028 | static int | | 2026 | static int |
2029 | audiommap(struct file *fp, off_t *offp, size_t len, int prot, int *flagsp, | | 2027 | audiommap(struct file *fp, off_t *offp, size_t len, int prot, int *flagsp, |
2030 | int *advicep, struct uvm_object **uobjp, int *maxprotp) | | 2028 | int *advicep, struct uvm_object **uobjp, int *maxprotp) |
2031 | { | | 2029 | { |
2032 | struct audio_softc *sc; | | 2030 | struct audio_softc *sc; |
2033 | struct psref sc_ref; | | 2031 | struct psref sc_ref; |
2034 | audio_file_t *file; | | 2032 | audio_file_t *file; |
2035 | dev_t dev; | | 2033 | dev_t dev; |
2036 | int bound; | | 2034 | int bound; |
2037 | int error; | | 2035 | int error; |
2038 | | | 2036 | |
2039 | KASSERT(fp->f_audioctx); | | 2037 | KASSERT(fp->f_audioctx); |
2040 | file = fp->f_audioctx; | | 2038 | file = fp->f_audioctx; |
2041 | dev = file->dev; | | 2039 | dev = file->dev; |
2042 | | | 2040 | |
2043 | bound = curlwp_bind(); | | 2041 | bound = curlwp_bind(); |
2044 | sc = audio_sc_acquire_fromfile(file, &sc_ref); | | 2042 | sc = audio_sc_acquire_fromfile(file, &sc_ref); |
2045 | if (sc == NULL) { | | 2043 | if (sc == NULL) { |
2046 | error = EIO; | | 2044 | error = EIO; |
2047 | goto done; | | 2045 | goto done; |
2048 | } | | 2046 | } |
2049 | | | 2047 | |
2050 | mutex_enter(sc->sc_lock); | | 2048 | mutex_enter(sc->sc_lock); |
2051 | device_active(sc->sc_dev, DVA_SYSTEM); /* XXXJDM */ | | 2049 | device_active(sc->sc_dev, DVA_SYSTEM); /* XXXJDM */ |
2052 | mutex_exit(sc->sc_lock); | | 2050 | mutex_exit(sc->sc_lock); |
2053 | | | 2051 | |
2054 | switch (AUDIODEV(dev)) { | | 2052 | switch (AUDIODEV(dev)) { |
2055 | case SOUND_DEVICE: | | 2053 | case SOUND_DEVICE: |
2056 | case AUDIO_DEVICE: | | 2054 | case AUDIO_DEVICE: |
2057 | error = audio_mmap(sc, offp, len, prot, flagsp, advicep, | | 2055 | error = audio_mmap(sc, offp, len, prot, flagsp, advicep, |
2058 | uobjp, maxprotp, file); | | 2056 | uobjp, maxprotp, file); |
2059 | break; | | 2057 | break; |
2060 | case AUDIOCTL_DEVICE: | | 2058 | case AUDIOCTL_DEVICE: |
2061 | case MIXER_DEVICE: | | 2059 | case MIXER_DEVICE: |
2062 | default: | | 2060 | default: |
2063 | error = ENOTSUP; | | 2061 | error = ENOTSUP; |
2064 | break; | | 2062 | break; |
2065 | } | | 2063 | } |
2066 | | | 2064 | |
2067 | audio_sc_release(sc, &sc_ref); | | 2065 | audio_sc_release(sc, &sc_ref); |
2068 | done: | | 2066 | done: |
2069 | curlwp_bindx(bound); | | 2067 | curlwp_bindx(bound); |
2070 | return error; | | 2068 | return error; |
2071 | } | | 2069 | } |
2072 | | | 2070 | |
2073 | | | 2071 | |
2074 | /* Exported interfaces for audiobell. */ | | 2072 | /* Exported interfaces for audiobell. */ |
2075 | | | 2073 | |
2076 | /* | | 2074 | /* |
2077 | * Open for audiobell. | | 2075 | * Open for audiobell. |
2078 | * It stores allocated file to *filep. | | 2076 | * It stores allocated file to *filep. |
2079 | * If successful returns 0, otherwise errno. | | 2077 | * If successful returns 0, otherwise errno. |
2080 | */ | | 2078 | */ |
2081 | int | | 2079 | int |
2082 | audiobellopen(dev_t dev, audio_file_t **filep) | | 2080 | audiobellopen(dev_t dev, audio_file_t **filep) |
2083 | { | | 2081 | { |
2084 | struct audio_softc *sc; | | 2082 | struct audio_softc *sc; |
2085 | struct psref sc_ref; | | 2083 | struct psref sc_ref; |
2086 | int bound; | | 2084 | int bound; |
2087 | int error; | | 2085 | int error; |
2088 | | | 2086 | |
2089 | /* Find the device */ | | 2087 | /* Find the device */ |
2090 | sc = device_lookup_private(&audio_cd, AUDIOUNIT(dev)); | | 2088 | sc = device_lookup_private(&audio_cd, AUDIOUNIT(dev)); |
2091 | if (sc == NULL || sc->hw_if == NULL) | | 2089 | if (sc == NULL || sc->hw_if == NULL) |
2092 | return ENXIO; | | 2090 | return ENXIO; |
2093 | | | 2091 | |
2094 | bound = curlwp_bind(); | | 2092 | bound = curlwp_bind(); |
2095 | audio_sc_acquire_foropen(sc, &sc_ref); | | 2093 | audio_sc_acquire_foropen(sc, &sc_ref); |
2096 | | | 2094 | |
2097 | error = audio_exlock_enter(sc); | | 2095 | error = audio_exlock_enter(sc); |
2098 | if (error) | | 2096 | if (error) |
2099 | goto done; | | 2097 | goto done; |
2100 | | | 2098 | |
2101 | device_active(sc->sc_dev, DVA_SYSTEM); | | 2099 | device_active(sc->sc_dev, DVA_SYSTEM); |
2102 | error = audio_open(dev, sc, FWRITE, 0, curlwp, filep); | | 2100 | error = audio_open(dev, sc, FWRITE, 0, curlwp, filep); |
2103 | | | 2101 | |
2104 | audio_exlock_exit(sc); | | 2102 | audio_exlock_exit(sc); |
2105 | done: | | 2103 | done: |
2106 | audio_sc_release(sc, &sc_ref); | | 2104 | audio_sc_release(sc, &sc_ref); |
2107 | curlwp_bindx(bound); | | 2105 | curlwp_bindx(bound); |
2108 | return error; | | 2106 | return error; |
2109 | } | | 2107 | } |
2110 | | | 2108 | |
2111 | /* Close for audiobell */ | | 2109 | /* Close for audiobell */ |
2112 | int | | 2110 | int |
2113 | audiobellclose(audio_file_t *file) | | 2111 | audiobellclose(audio_file_t *file) |
2114 | { | | 2112 | { |
2115 | struct audio_softc *sc; | | 2113 | struct audio_softc *sc; |
2116 | struct psref sc_ref; | | 2114 | struct psref sc_ref; |
2117 | int bound; | | 2115 | int bound; |
2118 | int error; | | 2116 | int error; |
2119 | | | 2117 | |
2120 | error = 0; | | 2118 | error = 0; |
2121 | /* | | 2119 | /* |
2122 | * audiobellclose() must | | 2120 | * audiobellclose() must |
2123 | * - unplug track from the trackmixer if sc exist. | | 2121 | * - unplug track from the trackmixer if sc exist. |
2124 | * - free all memory objects, regardless of sc. | | 2122 | * - free all memory objects, regardless of sc. |
2125 | */ | | 2123 | */ |
2126 | bound = curlwp_bind(); | | 2124 | bound = curlwp_bind(); |
2127 | sc = audio_sc_acquire_fromfile(file, &sc_ref); | | 2125 | sc = audio_sc_acquire_fromfile(file, &sc_ref); |
2128 | if (sc) { | | 2126 | if (sc) { |
2129 | error = audio_close(sc, file); | | 2127 | error = audio_close(sc, file); |
2130 | audio_sc_release(sc, &sc_ref); | | 2128 | audio_sc_release(sc, &sc_ref); |
2131 | } | | 2129 | } |
2132 | curlwp_bindx(bound); | | 2130 | curlwp_bindx(bound); |
2133 | | | 2131 | |
2134 | /* Free memory objects anyway */ | | 2132 | /* Free memory objects anyway */ |
2135 | KASSERT(file->ptrack); | | 2133 | KASSERT(file->ptrack); |
2136 | audio_track_destroy(file->ptrack); | | 2134 | audio_track_destroy(file->ptrack); |
2137 | KASSERT(file->rtrack == NULL); | | 2135 | KASSERT(file->rtrack == NULL); |
2138 | kmem_free(file, sizeof(*file)); | | 2136 | kmem_free(file, sizeof(*file)); |
2139 | return error; | | 2137 | return error; |
2140 | } | | 2138 | } |
2141 | | | 2139 | |
2142 | /* Set sample rate for audiobell */ | | 2140 | /* Set sample rate for audiobell */ |
2143 | int | | 2141 | int |
2144 | audiobellsetrate(audio_file_t *file, u_int sample_rate) | | 2142 | audiobellsetrate(audio_file_t *file, u_int sample_rate) |
2145 | { | | 2143 | { |
2146 | struct audio_softc *sc; | | 2144 | struct audio_softc *sc; |
2147 | struct psref sc_ref; | | 2145 | struct psref sc_ref; |
2148 | struct audio_info ai; | | 2146 | struct audio_info ai; |
2149 | int bound; | | 2147 | int bound; |
2150 | int error; | | 2148 | int error; |
2151 | | | 2149 | |
2152 | bound = curlwp_bind(); | | 2150 | bound = curlwp_bind(); |
2153 | sc = audio_sc_acquire_fromfile(file, &sc_ref); | | 2151 | sc = audio_sc_acquire_fromfile(file, &sc_ref); |
2154 | if (sc == NULL) { | | 2152 | if (sc == NULL) { |
2155 | error = EIO; | | 2153 | error = EIO; |
2156 | goto done1; | | 2154 | goto done1; |
2157 | } | | 2155 | } |
2158 | | | 2156 | |
2159 | AUDIO_INITINFO(&ai); | | 2157 | AUDIO_INITINFO(&ai); |
2160 | ai.play.sample_rate = sample_rate; | | 2158 | ai.play.sample_rate = sample_rate; |
2161 | | | 2159 | |
2162 | error = audio_exlock_enter(sc); | | 2160 | error = audio_exlock_enter(sc); |
2163 | if (error) | | 2161 | if (error) |
2164 | goto done2; | | 2162 | goto done2; |
2165 | error = audio_file_setinfo(sc, file, &ai); | | 2163 | error = audio_file_setinfo(sc, file, &ai); |
2166 | audio_exlock_exit(sc); | | 2164 | audio_exlock_exit(sc); |
2167 | | | 2165 | |
2168 | done2: | | 2166 | done2: |
2169 | audio_sc_release(sc, &sc_ref); | | 2167 | audio_sc_release(sc, &sc_ref); |
2170 | done1: | | 2168 | done1: |
2171 | curlwp_bindx(bound); | | 2169 | curlwp_bindx(bound); |
2172 | return error; | | 2170 | return error; |
2173 | } | | 2171 | } |
2174 | | | 2172 | |
2175 | /* Playback for audiobell */ | | 2173 | /* Playback for audiobell */ |
2176 | int | | 2174 | int |
2177 | audiobellwrite(audio_file_t *file, struct uio *uio) | | 2175 | audiobellwrite(audio_file_t *file, struct uio *uio) |
2178 | { | | 2176 | { |
2179 | struct audio_softc *sc; | | 2177 | struct audio_softc *sc; |
2180 | struct psref sc_ref; | | 2178 | struct psref sc_ref; |
2181 | int bound; | | 2179 | int bound; |
2182 | int error; | | 2180 | int error; |
2183 | | | 2181 | |
2184 | bound = curlwp_bind(); | | 2182 | bound = curlwp_bind(); |
2185 | sc = audio_sc_acquire_fromfile(file, &sc_ref); | | 2183 | sc = audio_sc_acquire_fromfile(file, &sc_ref); |
2186 | if (sc == NULL) { | | 2184 | if (sc == NULL) { |
2187 | error = EIO; | | 2185 | error = EIO; |
2188 | goto done; | | 2186 | goto done; |
2189 | } | | 2187 | } |
2190 | | | 2188 | |
2191 | error = audio_write(sc, uio, 0, file); | | 2189 | error = audio_write(sc, uio, 0, file); |
2192 | | | 2190 | |
2193 | audio_sc_release(sc, &sc_ref); | | 2191 | audio_sc_release(sc, &sc_ref); |
2194 | done: | | 2192 | done: |
2195 | curlwp_bindx(bound); | | 2193 | curlwp_bindx(bound); |
2196 | return error; | | 2194 | return error; |
2197 | } | | 2195 | } |
2198 | | | 2196 | |
2199 | | | 2197 | |
2200 | /* | | 2198 | /* |
2201 | * Audio driver | | 2199 | * Audio driver |
2202 | */ | | 2200 | */ |
2203 | | | 2201 | |
2204 | /* | | 2202 | /* |
2205 | * Must be called with sc_exlock held and without sc_lock held. | | 2203 | * Must be called with sc_exlock held and without sc_lock held. |
2206 | */ | | 2204 | */ |
2207 | int | | 2205 | int |
2208 | audio_open(dev_t dev, struct audio_softc *sc, int flags, int ifmt, | | 2206 | audio_open(dev_t dev, struct audio_softc *sc, int flags, int ifmt, |
2209 | struct lwp *l, audio_file_t **bellfile) | | 2207 | struct lwp *l, audio_file_t **bellfile) |
2210 | { | | 2208 | { |
2211 | struct audio_info ai; | | 2209 | struct audio_info ai; |
2212 | struct file *fp; | | 2210 | struct file *fp; |
2213 | audio_file_t *af; | | 2211 | audio_file_t *af; |
2214 | audio_ring_t *hwbuf; | | 2212 | audio_ring_t *hwbuf; |
2215 | bool fullduplex; | | 2213 | bool fullduplex; |
2216 | bool cred_held; | | 2214 | bool cred_held; |
2217 | bool hw_opened; | | 2215 | bool hw_opened; |
2218 | bool rmixer_started; | | 2216 | bool rmixer_started; |
2219 | bool inserted; | | 2217 | bool inserted; |
2220 | int fd; | | 2218 | int fd; |
2221 | int error; | | 2219 | int error; |
2222 | | | 2220 | |
2223 | KASSERT(sc->sc_exlock); | | 2221 | KASSERT(sc->sc_exlock); |
2224 | | | 2222 | |
2225 | TRACE(1, "%sdev=%s flags=0x%x po=%d ro=%d", | | 2223 | TRACE(1, "%sdev=%s flags=0x%x po=%d ro=%d", |
2226 | (audiodebug >= 3) ? "start " : "", | | 2224 | (audiodebug >= 3) ? "start " : "", |
2227 | ISDEVSOUND(dev) ? "sound" : "audio", | | 2225 | ISDEVSOUND(dev) ? "sound" : "audio", |
2228 | flags, sc->sc_popens, sc->sc_ropens); | | 2226 | flags, sc->sc_popens, sc->sc_ropens); |
2229 | | | 2227 | |
2230 | fp = NULL; | | 2228 | fp = NULL; |
2231 | cred_held = false; | | 2229 | cred_held = false; |
2232 | hw_opened = false; | | 2230 | hw_opened = false; |
2233 | rmixer_started = false; | | 2231 | rmixer_started = false; |
2234 | inserted = false; | | 2232 | inserted = false; |
2235 | | | 2233 | |
2236 | af = kmem_zalloc(sizeof(audio_file_t), KM_SLEEP); | | 2234 | af = kmem_zalloc(sizeof(audio_file_t), KM_SLEEP); |
2237 | af->sc = sc; | | 2235 | af->sc = sc; |
2238 | af->dev = dev; | | 2236 | af->dev = dev; |
2239 | if ((flags & FWRITE) != 0 && audio_can_playback(sc)) | | 2237 | if ((flags & FWRITE) != 0 && audio_can_playback(sc)) |
2240 | af->mode |= AUMODE_PLAY | AUMODE_PLAY_ALL; | | 2238 | af->mode |= AUMODE_PLAY | AUMODE_PLAY_ALL; |
2241 | if ((flags & FREAD) != 0 && audio_can_capture(sc)) | | 2239 | if ((flags & FREAD) != 0 && audio_can_capture(sc)) |
2242 | af->mode |= AUMODE_RECORD; | | 2240 | af->mode |= AUMODE_RECORD; |
2243 | if (af->mode == 0) { | | 2241 | if (af->mode == 0) { |
2244 | error = ENXIO; | | 2242 | error = ENXIO; |
2245 | goto bad; | | 2243 | goto bad; |
2246 | } | | 2244 | } |
2247 | | | 2245 | |
2248 | fullduplex = (sc->sc_props & AUDIO_PROP_FULLDUPLEX); | | 2246 | fullduplex = (sc->sc_props & AUDIO_PROP_FULLDUPLEX); |
2249 | | | 2247 | |
2250 | /* | | 2248 | /* |
2251 | * On half duplex hardware, | | 2249 | * On half duplex hardware, |
2252 | * 1. if mode is (PLAY | REC), let mode PLAY. | | 2250 | * 1. if mode is (PLAY | REC), let mode PLAY. |
2253 | * 2. if mode is PLAY, let mode PLAY if no rec tracks, otherwise error. | | 2251 | * 2. if mode is PLAY, let mode PLAY if no rec tracks, otherwise error. |
2254 | * 3. if mode is REC, let mode REC if no play tracks, otherwise error. | | 2252 | * 3. if mode is REC, let mode REC if no play tracks, otherwise error. |
2255 | */ | | 2253 | */ |
2256 | if (fullduplex == false) { | | 2254 | if (fullduplex == false) { |
2257 | if ((af->mode & AUMODE_PLAY)) { | | 2255 | if ((af->mode & AUMODE_PLAY)) { |
2258 | if (sc->sc_ropens != 0) { | | 2256 | if (sc->sc_ropens != 0) { |
2259 | TRACE(1, "record track already exists"); | | 2257 | TRACE(1, "record track already exists"); |
2260 | error = ENODEV; | | 2258 | error = ENODEV; |
2261 | goto bad; | | 2259 | goto bad; |
2262 | } | | 2260 | } |
2263 | /* Play takes precedence */ | | 2261 | /* Play takes precedence */ |
2264 | af->mode &= ~AUMODE_RECORD; | | 2262 | af->mode &= ~AUMODE_RECORD; |
2265 | } | | 2263 | } |
2266 | if ((af->mode & AUMODE_RECORD)) { | | 2264 | if ((af->mode & AUMODE_RECORD)) { |
2267 | if (sc->sc_popens != 0) { | | 2265 | if (sc->sc_popens != 0) { |
2268 | TRACE(1, "play track already exists"); | | 2266 | TRACE(1, "play track already exists"); |
2269 | error = ENODEV; | | 2267 | error = ENODEV; |
2270 | goto bad; | | 2268 | goto bad; |
2271 | } | | 2269 | } |
2272 | } | | 2270 | } |
2273 | } | | 2271 | } |
2274 | | | 2272 | |
2275 | /* Create tracks */ | | 2273 | /* Create tracks */ |
2276 | if ((af->mode & AUMODE_PLAY)) | | 2274 | if ((af->mode & AUMODE_PLAY)) |
2277 | af->ptrack = audio_track_create(sc, sc->sc_pmixer); | | 2275 | af->ptrack = audio_track_create(sc, sc->sc_pmixer); |
2278 | if ((af->mode & AUMODE_RECORD)) | | 2276 | if ((af->mode & AUMODE_RECORD)) |
2279 | af->rtrack = audio_track_create(sc, sc->sc_rmixer); | | 2277 | af->rtrack = audio_track_create(sc, sc->sc_rmixer); |
2280 | | | 2278 | |
2281 | /* Set parameters */ | | 2279 | /* Set parameters */ |
2282 | AUDIO_INITINFO(&ai); | | 2280 | AUDIO_INITINFO(&ai); |
2283 | if (bellfile) { | | 2281 | if (bellfile) { |
2284 | /* If audiobell, only sample_rate will be set later. */ | | 2282 | /* If audiobell, only sample_rate will be set later. */ |
2285 | ai.play.sample_rate = audio_default.sample_rate; | | 2283 | ai.play.sample_rate = audio_default.sample_rate; |
2286 | ai.play.encoding = AUDIO_ENCODING_SLINEAR_NE; | | 2284 | ai.play.encoding = AUDIO_ENCODING_SLINEAR_NE; |
2287 | ai.play.channels = 1; | | 2285 | ai.play.channels = 1; |
2288 | ai.play.precision = 16; | | 2286 | ai.play.precision = 16; |
2289 | ai.play.pause = 0; | | 2287 | ai.play.pause = 0; |
2290 | } else if (ISDEVAUDIO(dev)) { | | 2288 | } else if (ISDEVAUDIO(dev)) { |
2291 | /* If /dev/audio, initialize everytime. */ | | 2289 | /* If /dev/audio, initialize everytime. */ |
2292 | ai.play.sample_rate = audio_default.sample_rate; | | 2290 | ai.play.sample_rate = audio_default.sample_rate; |
2293 | ai.play.encoding = audio_default.encoding; | | 2291 | ai.play.encoding = audio_default.encoding; |
2294 | ai.play.channels = audio_default.channels; | | 2292 | ai.play.channels = audio_default.channels; |
2295 | ai.play.precision = audio_default.precision; | | 2293 | ai.play.precision = audio_default.precision; |
2296 | ai.play.pause = 0; | | 2294 | ai.play.pause = 0; |
2297 | ai.record.sample_rate = audio_default.sample_rate; | | 2295 | ai.record.sample_rate = audio_default.sample_rate; |
2298 | ai.record.encoding = audio_default.encoding; | | 2296 | ai.record.encoding = audio_default.encoding; |
2299 | ai.record.channels = audio_default.channels; | | 2297 | ai.record.channels = audio_default.channels; |
2300 | ai.record.precision = audio_default.precision; | | 2298 | ai.record.precision = audio_default.precision; |
2301 | ai.record.pause = 0; | | 2299 | ai.record.pause = 0; |
2302 | } else { | | 2300 | } else { |
2303 | /* If /dev/sound, take over the previous parameters. */ | | 2301 | /* If /dev/sound, take over the previous parameters. */ |
2304 | ai.play.sample_rate = sc->sc_sound_pparams.sample_rate; | | 2302 | ai.play.sample_rate = sc->sc_sound_pparams.sample_rate; |
2305 | ai.play.encoding = sc->sc_sound_pparams.encoding; | | 2303 | ai.play.encoding = sc->sc_sound_pparams.encoding; |
2306 | ai.play.channels = sc->sc_sound_pparams.channels; | | 2304 | ai.play.channels = sc->sc_sound_pparams.channels; |
2307 | ai.play.precision = sc->sc_sound_pparams.precision; | | 2305 | ai.play.precision = sc->sc_sound_pparams.precision; |
2308 | ai.play.pause = sc->sc_sound_ppause; | | 2306 | ai.play.pause = sc->sc_sound_ppause; |
2309 | ai.record.sample_rate = sc->sc_sound_rparams.sample_rate; | | 2307 | ai.record.sample_rate = sc->sc_sound_rparams.sample_rate; |
2310 | ai.record.encoding = sc->sc_sound_rparams.encoding; | | 2308 | ai.record.encoding = sc->sc_sound_rparams.encoding; |
2311 | ai.record.channels = sc->sc_sound_rparams.channels; | | 2309 | ai.record.channels = sc->sc_sound_rparams.channels; |
2312 | ai.record.precision = sc->sc_sound_rparams.precision; | | 2310 | ai.record.precision = sc->sc_sound_rparams.precision; |
2313 | ai.record.pause = sc->sc_sound_rpause; | | 2311 | ai.record.pause = sc->sc_sound_rpause; |
2314 | } | | 2312 | } |
2315 | error = audio_file_setinfo(sc, af, &ai); | | 2313 | error = audio_file_setinfo(sc, af, &ai); |
2316 | if (error) | | 2314 | if (error) |
2317 | goto bad; | | 2315 | goto bad; |
2318 | | | 2316 | |
2319 | if (sc->sc_popens + sc->sc_ropens == 0) { | | 2317 | if (sc->sc_popens + sc->sc_ropens == 0) { |
2320 | /* First open */ | | 2318 | /* First open */ |
2321 | | | 2319 | |
2322 | sc->sc_cred = kauth_cred_get(); | | 2320 | sc->sc_cred = kauth_cred_get(); |
2323 | kauth_cred_hold(sc->sc_cred); | | 2321 | kauth_cred_hold(sc->sc_cred); |
2324 | cred_held = true; | | 2322 | cred_held = true; |
2325 | | | 2323 | |
2326 | if (sc->hw_if->open) { | | 2324 | if (sc->hw_if->open) { |
2327 | int hwflags; | | 2325 | int hwflags; |
2328 | | | 2326 | |
2329 | /* | | 2327 | /* |
2330 | * Call hw_if->open() only at first open of | | 2328 | * Call hw_if->open() only at first open of |
2331 | * combination of playback and recording. | | 2329 | * combination of playback and recording. |
2332 | * On full duplex hardware, the flags passed to | | 2330 | * On full duplex hardware, the flags passed to |
2333 | * hw_if->open() is always (FREAD | FWRITE) | | 2331 | * hw_if->open() is always (FREAD | FWRITE) |
2334 | * regardless of this open()'s flags. | | 2332 | * regardless of this open()'s flags. |
2335 | * see also dev/isa/aria.c | | 2333 | * see also dev/isa/aria.c |
2336 | * On half duplex hardware, the flags passed to | | 2334 | * On half duplex hardware, the flags passed to |
2337 | * hw_if->open() is either FREAD or FWRITE. | | 2335 | * hw_if->open() is either FREAD or FWRITE. |
2338 | * see also arch/evbarm/mini2440/audio_mini2440.c | | 2336 | * see also arch/evbarm/mini2440/audio_mini2440.c |
2339 | */ | | 2337 | */ |
2340 | if (fullduplex) { | | 2338 | if (fullduplex) { |
2341 | hwflags = FREAD | FWRITE; | | 2339 | hwflags = FREAD | FWRITE; |
2342 | } else { | | 2340 | } else { |
2343 | /* Construct hwflags from af->mode. */ | | 2341 | /* Construct hwflags from af->mode. */ |
2344 | hwflags = 0; | | 2342 | hwflags = 0; |
2345 | if ((af->mode & AUMODE_PLAY) != 0) | | 2343 | if ((af->mode & AUMODE_PLAY) != 0) |
2346 | hwflags |= FWRITE; | | 2344 | hwflags |= FWRITE; |
2347 | if ((af->mode & AUMODE_RECORD) != 0) | | 2345 | if ((af->mode & AUMODE_RECORD) != 0) |
2348 | hwflags |= FREAD; | | 2346 | hwflags |= FREAD; |
2349 | } | | 2347 | } |
2350 | | | 2348 | |
2351 | mutex_enter(sc->sc_lock); | | 2349 | mutex_enter(sc->sc_lock); |
2352 | mutex_enter(sc->sc_intr_lock); | | 2350 | mutex_enter(sc->sc_intr_lock); |
2353 | error = sc->hw_if->open(sc->hw_hdl, hwflags); | | 2351 | error = sc->hw_if->open(sc->hw_hdl, hwflags); |
2354 | mutex_exit(sc->sc_intr_lock); | | 2352 | mutex_exit(sc->sc_intr_lock); |
2355 | mutex_exit(sc->sc_lock); | | 2353 | mutex_exit(sc->sc_lock); |
2356 | if (error) | | 2354 | if (error) |
2357 | goto bad; | | 2355 | goto bad; |
2358 | } | | 2356 | } |
2359 | /* | | 2357 | /* |
2360 | * Regardless of whether we called hw_if->open (whether | | 2358 | * Regardless of whether we called hw_if->open (whether |
2361 | * hw_if->open exists) or not, we move to the Opened phase | | 2359 | * hw_if->open exists) or not, we move to the Opened phase |
2362 | * here. Therefore from this point, we have to call | | 2360 | * here. Therefore from this point, we have to call |
2363 | * hw_if->close (if exists) whenever abort. | | 2361 | * hw_if->close (if exists) whenever abort. |
2364 | * Note that both of hw_if->{open,close} are optional. | | 2362 | * Note that both of hw_if->{open,close} are optional. |
2365 | */ | | 2363 | */ |
2366 | hw_opened = true; | | 2364 | hw_opened = true; |
2367 | | | 2365 | |
2368 | /* | | 2366 | /* |
2369 | * Set speaker mode when a half duplex. | | 2367 | * Set speaker mode when a half duplex. |
2370 | * XXX I'm not sure this is correct. | | 2368 | * XXX I'm not sure this is correct. |
2371 | */ | | 2369 | */ |
2372 | if (1/*XXX*/) { | | 2370 | if (1/*XXX*/) { |
2373 | if (sc->hw_if->speaker_ctl) { | | 2371 | if (sc->hw_if->speaker_ctl) { |
2374 | int on; | | 2372 | int on; |
2375 | if (af->ptrack) { | | 2373 | if (af->ptrack) { |
2376 | on = 1; | | 2374 | on = 1; |
2377 | } else { | | 2375 | } else { |
2378 | on = 0; | | 2376 | on = 0; |
2379 | } | | 2377 | } |
2380 | mutex_enter(sc->sc_lock); | | 2378 | mutex_enter(sc->sc_lock); |
2381 | mutex_enter(sc->sc_intr_lock); | | 2379 | mutex_enter(sc->sc_intr_lock); |
2382 | error = sc->hw_if->speaker_ctl(sc->hw_hdl, on); | | 2380 | error = sc->hw_if->speaker_ctl(sc->hw_hdl, on); |
2383 | mutex_exit(sc->sc_intr_lock); | | 2381 | mutex_exit(sc->sc_intr_lock); |
2384 | mutex_exit(sc->sc_lock); | | 2382 | mutex_exit(sc->sc_lock); |
2385 | if (error) | | 2383 | if (error) |
2386 | goto bad; | | 2384 | goto bad; |
2387 | } | | 2385 | } |
2388 | } | | 2386 | } |
2389 | } else if (sc->sc_multiuser == false) { | | 2387 | } else if (sc->sc_multiuser == false) { |
2390 | uid_t euid = kauth_cred_geteuid(kauth_cred_get()); | | 2388 | uid_t euid = kauth_cred_geteuid(kauth_cred_get()); |
2391 | if (euid != 0 && euid != kauth_cred_geteuid(sc->sc_cred)) { | | 2389 | if (euid != 0 && euid != kauth_cred_geteuid(sc->sc_cred)) { |
2392 | error = EPERM; | | 2390 | error = EPERM; |
2393 | goto bad; | | 2391 | goto bad; |
2394 | } | | 2392 | } |
2395 | } | | 2393 | } |
2396 | | | 2394 | |
2397 | /* Call init_output if this is the first playback open. */ | | 2395 | /* Call init_output if this is the first playback open. */ |
2398 | if (af->ptrack && sc->sc_popens == 0) { | | 2396 | if (af->ptrack && sc->sc_popens == 0) { |
2399 | if (sc->hw_if->init_output) { | | 2397 | if (sc->hw_if->init_output) { |
2400 | hwbuf = &sc->sc_pmixer->hwbuf; | | 2398 | hwbuf = &sc->sc_pmixer->hwbuf; |
2401 | mutex_enter(sc->sc_lock); | | 2399 | mutex_enter(sc->sc_lock); |
2402 | mutex_enter(sc->sc_intr_lock); | | 2400 | mutex_enter(sc->sc_intr_lock); |
2403 | error = sc->hw_if->init_output(sc->hw_hdl, | | 2401 | error = sc->hw_if->init_output(sc->hw_hdl, |
2404 | hwbuf->mem, | | 2402 | hwbuf->mem, |
2405 | hwbuf->capacity * | | 2403 | hwbuf->capacity * |
2406 | hwbuf->fmt.channels * hwbuf->fmt.stride / NBBY); | | 2404 | hwbuf->fmt.channels * hwbuf->fmt.stride / NBBY); |
2407 | mutex_exit(sc->sc_intr_lock); | | 2405 | mutex_exit(sc->sc_intr_lock); |
2408 | mutex_exit(sc->sc_lock); | | 2406 | mutex_exit(sc->sc_lock); |
2409 | if (error) | | 2407 | if (error) |
2410 | goto bad; | | 2408 | goto bad; |
2411 | } | | 2409 | } |
2412 | } | | 2410 | } |
2413 | /* | | 2411 | /* |
2414 | * Call init_input and start rmixer, if this is the first recording | | 2412 | * Call init_input and start rmixer, if this is the first recording |
2415 | * open. See pause consideration notes. | | 2413 | * open. See pause consideration notes. |
2416 | */ | | 2414 | */ |
2417 | if (af->rtrack && sc->sc_ropens == 0) { | | 2415 | if (af->rtrack && sc->sc_ropens == 0) { |
2418 | if (sc->hw_if->init_input) { | | 2416 | if (sc->hw_if->init_input) { |
2419 | hwbuf = &sc->sc_rmixer->hwbuf; | | 2417 | hwbuf = &sc->sc_rmixer->hwbuf; |