| @@ -1,1599 +1,1580 @@ | | | @@ -1,1599 +1,1580 @@ |
1 | /* $NetBSD: ossaudio.c,v 1.81 2020/04/15 16:39:06 nia Exp $ */ | | 1 | /* $NetBSD: ossaudio.c,v 1.82 2020/04/19 13:44:51 nia Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (c) 1997, 2008 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 1997, 2008 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
15 | * | | 15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | | 16 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
17 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 17 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | | 18 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
19 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 19 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
20 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 20 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | 23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | | 25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
26 | * POSSIBILITY OF SUCH DAMAGE. | | 26 | * POSSIBILITY OF SUCH DAMAGE. |
27 | */ | | 27 | */ |
28 | | | 28 | |
29 | #include <sys/cdefs.h> | | 29 | #include <sys/cdefs.h> |
30 | __KERNEL_RCSID(0, "$NetBSD: ossaudio.c,v 1.81 2020/04/15 16:39:06 nia Exp $"); | | 30 | __KERNEL_RCSID(0, "$NetBSD: ossaudio.c,v 1.82 2020/04/19 13:44:51 nia Exp $"); |
31 | | | 31 | |
32 | #include <sys/param.h> | | 32 | #include <sys/param.h> |
33 | #include <sys/proc.h> | | 33 | #include <sys/proc.h> |
34 | #include <sys/systm.h> | | 34 | #include <sys/systm.h> |
35 | #include <sys/file.h> | | 35 | #include <sys/file.h> |
36 | #include <sys/vnode.h> | | 36 | #include <sys/vnode.h> |
37 | #include <sys/filedesc.h> | | 37 | #include <sys/filedesc.h> |
38 | #include <sys/ioctl.h> | | 38 | #include <sys/ioctl.h> |
39 | #include <sys/mount.h> | | 39 | #include <sys/mount.h> |
40 | #include <sys/kernel.h> | | 40 | #include <sys/kernel.h> |
41 | #include <sys/audioio.h> | | 41 | #include <sys/audioio.h> |
42 | #include <sys/midiio.h> | | 42 | #include <sys/midiio.h> |
43 | #include <sys/kauth.h> | | 43 | #include <sys/kauth.h> |
44 | #include <sys/syscallargs.h> | | 44 | #include <sys/syscallargs.h> |
45 | #include <sys/module.h> | | 45 | #include <sys/module.h> |
46 | | | 46 | |
47 | #include <compat/ossaudio/ossaudio.h> | | 47 | #include <compat/ossaudio/ossaudio.h> |
48 | #include <compat/ossaudio/ossaudiovar.h> | | 48 | #include <compat/ossaudio/ossaudiovar.h> |
49 | | | 49 | |
50 | MODULE(MODULE_CLASS_EXEC, compat_ossaudio, NULL); | | 50 | MODULE(MODULE_CLASS_EXEC, compat_ossaudio, NULL); |
51 | | | 51 | |
52 | #ifdef AUDIO_DEBUG | | 52 | #ifdef AUDIO_DEBUG |
53 | #define DPRINTF(x) if (ossdebug) printf x | | 53 | #define DPRINTF(x) if (ossdebug) printf x |
54 | int ossdebug = 0; | | 54 | int ossdebug = 0; |
55 | #else | | 55 | #else |
56 | #define DPRINTF(x) | | 56 | #define DPRINTF(x) |
57 | #endif | | 57 | #endif |
58 | | | 58 | |
59 | #define TO_OSSVOL(x) (((x) * 100 + 127) / 255) | | 59 | #define TO_OSSVOL(x) (((x) * 100 + 127) / 255) |
60 | #define FROM_OSSVOL(x) ((((x) > 100 ? 100 : (x)) * 255 + 50) / 100) | | 60 | #define FROM_OSSVOL(x) ((((x) > 100 ? 100 : (x)) * 255 + 50) / 100) |
61 | | | 61 | |
62 | #define GETPRINFO(info, name) \ | | 62 | #define GETPRINFO(info, name) \ |
63 | (((info)->mode == AUMODE_RECORD) \ | | 63 | (((info)->mode == AUMODE_RECORD) \ |
64 | ? (info)->record.name : (info)->play.name) | | 64 | ? (info)->record.name : (info)->play.name) |
65 | | | 65 | |
66 | static struct audiodevinfo *getdevinfo(file_t *); | | 66 | static struct audiodevinfo *getdevinfo(file_t *); |
67 | static int opaque_to_enum(struct audiodevinfo *di, audio_mixer_name_t *label, int opq); | | 67 | static int opaque_to_enum(struct audiodevinfo *di, audio_mixer_name_t *label, int opq); |
68 | static int enum_to_ord(struct audiodevinfo *di, int enm); | | 68 | static int enum_to_ord(struct audiodevinfo *di, int enm); |
69 | static int enum_to_mask(struct audiodevinfo *di, int enm); | | 69 | static int enum_to_mask(struct audiodevinfo *di, int enm); |
70 | | | 70 | |
71 | static void setchannels(file_t *, int, int); | | 71 | static void setchannels(file_t *, int, int); |
72 | static void setblocksize(file_t *, struct audio_info *); | | 72 | static void setblocksize(file_t *, struct audio_info *); |
73 | | | 73 | |
74 | #ifdef AUDIO_DEBUG | | 74 | #ifdef AUDIO_DEBUG |
75 | static const char * | | 75 | static const char * |
76 | compat_ossaudio_getcmd(u_long cmd) | | 76 | compat_ossaudio_getcmd(u_long cmd) |
77 | { | | 77 | { |
78 | static char buf[64]; | | 78 | static char buf[64]; |
79 | switch (cmd) { | | 79 | switch (cmd) { |
80 | #define _DO(_a) \ | | 80 | #define _DO(_a) \ |
81 | case _a: \ | | 81 | case _a: \ |
82 | return # _a; | | 82 | return # _a; |
83 | _DO(OSS_SNDCTL_DSP_RESET) | | 83 | _DO(OSS_SNDCTL_DSP_RESET) |
84 | _DO(OSS_SNDCTL_DSP_SYNC) | | 84 | _DO(OSS_SNDCTL_DSP_SYNC) |
85 | _DO(OSS_SNDCTL_DSP_SPEED) | | 85 | _DO(OSS_SNDCTL_DSP_SPEED) |
86 | _DO(OSS_SOUND_PCM_READ_RATE) | | 86 | _DO(OSS_SOUND_PCM_READ_RATE) |
87 | _DO(OSS_SNDCTL_DSP_STEREO) | | 87 | _DO(OSS_SNDCTL_DSP_STEREO) |
88 | _DO(OSS_SNDCTL_DSP_GETBLKSIZE) | | 88 | _DO(OSS_SNDCTL_DSP_GETBLKSIZE) |
89 | _DO(OSS_SNDCTL_DSP_SETFMT) | | 89 | _DO(OSS_SNDCTL_DSP_SETFMT) |
90 | _DO(OSS_SOUND_PCM_READ_BITS) | | 90 | _DO(OSS_SOUND_PCM_READ_BITS) |
91 | _DO(OSS_SNDCTL_DSP_CHANNELS) | | 91 | _DO(OSS_SNDCTL_DSP_CHANNELS) |
92 | _DO(OSS_SOUND_PCM_READ_CHANNELS) | | 92 | _DO(OSS_SOUND_PCM_READ_CHANNELS) |
93 | _DO(OSS_SOUND_PCM_WRITE_FILTER) | | 93 | _DO(OSS_SOUND_PCM_WRITE_FILTER) |
94 | _DO(OSS_SOUND_PCM_READ_FILTER) | | 94 | _DO(OSS_SOUND_PCM_READ_FILTER) |
95 | _DO(OSS_SNDCTL_DSP_POST) | | 95 | _DO(OSS_SNDCTL_DSP_POST) |
96 | _DO(OSS_SNDCTL_DSP_SUBDIVIDE) | | 96 | _DO(OSS_SNDCTL_DSP_SUBDIVIDE) |
97 | _DO(OSS_SNDCTL_DSP_SETFRAGMENT) | | 97 | _DO(OSS_SNDCTL_DSP_SETFRAGMENT) |
98 | _DO(OSS_SNDCTL_DSP_GETFMTS) | | 98 | _DO(OSS_SNDCTL_DSP_GETFMTS) |
99 | _DO(OSS_SNDCTL_DSP_GETOSPACE) | | 99 | _DO(OSS_SNDCTL_DSP_GETOSPACE) |
100 | _DO(OSS_SNDCTL_DSP_GETISPACE) | | 100 | _DO(OSS_SNDCTL_DSP_GETISPACE) |
101 | _DO(OSS_SNDCTL_DSP_NONBLOCK) | | 101 | _DO(OSS_SNDCTL_DSP_NONBLOCK) |
102 | _DO(OSS_SNDCTL_DSP_GETCAPS) | | 102 | _DO(OSS_SNDCTL_DSP_GETCAPS) |
103 | _DO(OSS_SNDCTL_DSP_GETTRIGGER) | | 103 | _DO(OSS_SNDCTL_DSP_GETTRIGGER) |
104 | _DO(OSS_SNDCTL_DSP_SETTRIGGER) | | 104 | _DO(OSS_SNDCTL_DSP_SETTRIGGER) |
105 | _DO(OSS_SNDCTL_DSP_GETIPTR) | | 105 | _DO(OSS_SNDCTL_DSP_GETIPTR) |
106 | _DO(OSS_SNDCTL_DSP_GETOPTR) | | 106 | _DO(OSS_SNDCTL_DSP_GETOPTR) |
107 | _DO(OSS_SNDCTL_DSP_MAPINBUF) | | 107 | _DO(OSS_SNDCTL_DSP_MAPINBUF) |
108 | _DO(OSS_SNDCTL_DSP_MAPOUTBUF) | | 108 | _DO(OSS_SNDCTL_DSP_MAPOUTBUF) |
109 | _DO(OSS_SNDCTL_DSP_SETSYNCRO) | | 109 | _DO(OSS_SNDCTL_DSP_SETSYNCRO) |
110 | _DO(OSS_SNDCTL_DSP_SETDUPLEX) | | 110 | _DO(OSS_SNDCTL_DSP_SETDUPLEX) |
111 | _DO(OSS_SNDCTL_DSP_GETODELAY) | | 111 | _DO(OSS_SNDCTL_DSP_GETODELAY) |
112 | _DO(OSS_SNDCTL_DSP_PROFILE) | | 112 | _DO(OSS_SNDCTL_DSP_PROFILE) |
113 | _DO(OSS_SOUND_MIXER_INFO) | | 113 | _DO(OSS_SOUND_MIXER_INFO) |
114 | _DO(OSS_SOUND_OLD_MIXER_INFO) | | 114 | _DO(OSS_SOUND_OLD_MIXER_INFO) |
115 | _DO(OSS_GET_VERSION) | | 115 | _DO(OSS_GET_VERSION) |
116 | _DO(OSS_SEQ_RESET) | | 116 | _DO(OSS_SEQ_RESET) |
117 | _DO(OSS_SEQ_SYNC) | | 117 | _DO(OSS_SEQ_SYNC) |
118 | _DO(OSS_SYNTH_INFO) | | 118 | _DO(OSS_SYNTH_INFO) |
119 | _DO(OSS_SEQ_CTRLRATE) | | 119 | _DO(OSS_SEQ_CTRLRATE) |
120 | _DO(OSS_SEQ_GETOUTCOUNT) | | 120 | _DO(OSS_SEQ_GETOUTCOUNT) |
121 | _DO(OSS_SEQ_GETINCOUNT) | | 121 | _DO(OSS_SEQ_GETINCOUNT) |
122 | _DO(OSS_SEQ_PERCMODE) | | 122 | _DO(OSS_SEQ_PERCMODE) |
123 | _DO(OSS_SEQ_TESTMIDI) | | 123 | _DO(OSS_SEQ_TESTMIDI) |
124 | _DO(OSS_SEQ_RESETSAMPLES) | | 124 | _DO(OSS_SEQ_RESETSAMPLES) |
125 | _DO(OSS_SEQ_NRSYNTHS) | | 125 | _DO(OSS_SEQ_NRSYNTHS) |
126 | _DO(OSS_SEQ_NRMIDIS) | | 126 | _DO(OSS_SEQ_NRMIDIS) |
127 | #ifdef notyet | | 127 | #ifdef notyet |
128 | _DO(OSS_MIDI_INFO) | | 128 | _DO(OSS_MIDI_INFO) |
129 | #endif | | 129 | #endif |
130 | _DO(OSS_SEQ_THRESHOLD) | | 130 | _DO(OSS_SEQ_THRESHOLD) |
131 | _DO(OSS_MEMAVL) | | 131 | _DO(OSS_MEMAVL) |
132 | _DO(OSS_FM_4OP_ENABLE) | | 132 | _DO(OSS_FM_4OP_ENABLE) |
133 | _DO(OSS_SEQ_PANIC) | | 133 | _DO(OSS_SEQ_PANIC) |
134 | _DO(OSS_SEQ_OUTOFBAND) | | 134 | _DO(OSS_SEQ_OUTOFBAND) |
135 | _DO(OSS_SEQ_GETTIME) | | 135 | _DO(OSS_SEQ_GETTIME) |
136 | _DO(OSS_ID) | | 136 | _DO(OSS_ID) |
137 | _DO(OSS_CONTROL) | | 137 | _DO(OSS_CONTROL) |
138 | _DO(OSS_REMOVESAMPLE) | | 138 | _DO(OSS_REMOVESAMPLE) |
139 | _DO(OSS_TMR_TIMEBASE) | | 139 | _DO(OSS_TMR_TIMEBASE) |
140 | _DO(OSS_TMR_START) | | 140 | _DO(OSS_TMR_START) |
141 | _DO(OSS_TMR_STOP) | | 141 | _DO(OSS_TMR_STOP) |
142 | _DO(OSS_TMR_CONTINUE) | | 142 | _DO(OSS_TMR_CONTINUE) |
143 | _DO(OSS_TMR_TEMPO) | | 143 | _DO(OSS_TMR_TEMPO) |
144 | _DO(OSS_TMR_SOURCE) | | 144 | _DO(OSS_TMR_SOURCE) |
145 | _DO(OSS_TMR_METRONOME) | | 145 | _DO(OSS_TMR_METRONOME) |
146 | _DO(OSS_TMR_SELECT) | | 146 | _DO(OSS_TMR_SELECT) |
147 | #undef _DO | | 147 | #undef _DO |
148 | default: | | 148 | default: |
149 | (void)snprintf(buf, sizeof(buf), "*0x%lx*", cmd); | | 149 | (void)snprintf(buf, sizeof(buf), "*0x%lx*", cmd); |
150 | return buf; | | 150 | return buf; |
151 | } | | 151 | } |
152 | } | | 152 | } |
153 | #endif | | 153 | #endif |
154 | | | 154 | |
155 | | | 155 | |
156 | static int | | 156 | static int |
157 | compat_ossaudio_modcmd(modcmd_t cmd, void *arg) | | 157 | compat_ossaudio_modcmd(modcmd_t cmd, void *arg) |
158 | { | | 158 | { |
159 | | | 159 | |
160 | switch (cmd) { | | 160 | switch (cmd) { |
161 | case MODULE_CMD_INIT: | | 161 | case MODULE_CMD_INIT: |
162 | case MODULE_CMD_FINI: | | 162 | case MODULE_CMD_FINI: |
163 | return 0; | | 163 | return 0; |
164 | default: | | 164 | default: |
165 | return ENOTTY; | | 165 | return ENOTTY; |
166 | } | | 166 | } |
167 | } | | 167 | } |
168 | | | 168 | |
169 | int | | 169 | int |
170 | oss_ioctl_audio(struct lwp *l, const struct oss_sys_ioctl_args *uap, register_t *retval) | | 170 | oss_ioctl_audio(struct lwp *l, const struct oss_sys_ioctl_args *uap, register_t *retval) |
171 | { | | 171 | { |
172 | /* { | | 172 | /* { |
173 | syscallarg(int) fd; | | 173 | syscallarg(int) fd; |
174 | syscallarg(u_long) com; | | 174 | syscallarg(u_long) com; |
175 | syscallarg(void *) data; | | 175 | syscallarg(void *) data; |
176 | } */ | | 176 | } */ |
177 | file_t *fp; | | 177 | file_t *fp; |
178 | u_long com; | | 178 | u_long com; |
179 | struct audio_info tmpinfo, hwfmt; | | 179 | struct audio_info tmpinfo, hwfmt; |
180 | struct audio_offset tmpoffs; | | 180 | struct audio_offset tmpoffs; |
181 | struct oss_audio_buf_info bufinfo; | | 181 | struct oss_audio_buf_info bufinfo; |
182 | struct oss_count_info cntinfo; | | 182 | struct oss_count_info cntinfo; |
183 | struct audio_encoding tmpenc; | | 183 | struct audio_encoding tmpenc; |
184 | u_int u; | | 184 | u_int u; |
185 | u_int encoding; | | 185 | u_int encoding; |
186 | u_int precision; | | 186 | u_int precision; |
187 | int idat, idata; | | 187 | int idat, idata; |
188 | int error = 0; | | 188 | int error = 0; |
189 | int (*ioctlf)(file_t *, u_long, void *); | | 189 | int (*ioctlf)(file_t *, u_long, void *); |
190 | | | 190 | |
191 | if ((fp = fd_getfile(SCARG(uap, fd))) == NULL) | | 191 | if ((fp = fd_getfile(SCARG(uap, fd))) == NULL) |
192 | return (EBADF); | | 192 | return (EBADF); |
193 | | | 193 | |
194 | if ((fp->f_flag & (FREAD | FWRITE)) == 0) { | | 194 | if ((fp->f_flag & (FREAD | FWRITE)) == 0) { |
195 | error = EBADF; | | 195 | error = EBADF; |
196 | goto out; | | 196 | goto out; |
197 | } | | 197 | } |
198 | | | 198 | |
199 | com = SCARG(uap, com); | | 199 | com = SCARG(uap, com); |
200 | DPRINTF(("%s: com=%s\n", __func__, compat_ossaudio_getcmd(com))); | | 200 | DPRINTF(("%s: com=%s\n", __func__, compat_ossaudio_getcmd(com))); |
201 | | | 201 | |
202 | retval[0] = 0; | | 202 | retval[0] = 0; |
203 | | | 203 | |
204 | ioctlf = fp->f_ops->fo_ioctl; | | 204 | ioctlf = fp->f_ops->fo_ioctl; |
205 | switch (com) { | | 205 | switch (com) { |
206 | case OSS_SNDCTL_DSP_RESET: | | 206 | case OSS_SNDCTL_DSP_RESET: |
207 | error = ioctlf(fp, AUDIO_FLUSH, NULL); | | 207 | error = ioctlf(fp, AUDIO_FLUSH, NULL); |
208 | if (error) { | | 208 | if (error) { |
209 | DPRINTF(("%s: AUDIO_FLUSH %d\n", __func__, error)); | | 209 | DPRINTF(("%s: AUDIO_FLUSH %d\n", __func__, error)); |
210 | goto out; | | 210 | goto out; |
211 | } | | 211 | } |
212 | break; | | 212 | break; |
213 | case OSS_SNDCTL_DSP_SYNC: | | 213 | case OSS_SNDCTL_DSP_SYNC: |
214 | error = ioctlf(fp, AUDIO_DRAIN, NULL); | | 214 | error = ioctlf(fp, AUDIO_DRAIN, NULL); |
215 | if (error) { | | 215 | if (error) { |
216 | DPRINTF(("%s: AUDIO_DRAIN %d\n", __func__, error)); | | 216 | DPRINTF(("%s: AUDIO_DRAIN %d\n", __func__, error)); |
217 | goto out; | | 217 | goto out; |
218 | } | | 218 | } |
219 | break; | | 219 | break; |
220 | case OSS_SNDCTL_DSP_POST: | | 220 | case OSS_SNDCTL_DSP_POST: |
221 | /* This call is merely advisory, and may be a nop. */ | | 221 | /* This call is merely advisory, and may be a nop. */ |
222 | break; | | 222 | break; |
223 | case OSS_SNDCTL_DSP_SPEED: | | 223 | case OSS_SNDCTL_DSP_SPEED: |
224 | AUDIO_INITINFO(&tmpinfo); | | 224 | AUDIO_INITINFO(&tmpinfo); |
225 | error = copyin(SCARG(uap, data), &idat, sizeof idat); | | 225 | error = copyin(SCARG(uap, data), &idat, sizeof idat); |
226 | if (error) { | | 226 | if (error) { |
227 | DPRINTF(("%s: SNDCTL_DSP_SPEED %d\n", | | 227 | DPRINTF(("%s: SNDCTL_DSP_SPEED %d\n", |
228 | __func__, error)); | | 228 | __func__, error)); |
229 | goto out; | | 229 | goto out; |
230 | } | | 230 | } |
231 | tmpinfo.play.sample_rate = | | 231 | tmpinfo.play.sample_rate = |
232 | tmpinfo.record.sample_rate = idat; | | 232 | tmpinfo.record.sample_rate = idat; |
233 | DPRINTF(("%s: SNDCTL_DSP_SPEED > %d\n", __func__, idat)); | | 233 | DPRINTF(("%s: SNDCTL_DSP_SPEED > %d\n", __func__, idat)); |
234 | /* | | 234 | /* |
235 | * The default NetBSD behavior if an unsupported sample rate | | 235 | * The default NetBSD behavior if an unsupported sample rate |
236 | * is set is to return an error code and keep the rate at the | | 236 | * is set is to return an error code and keep the rate at the |
237 | * default of 8000 Hz. | | 237 | * default of 8000 Hz. |
238 | * | | 238 | * |
239 | * However, the OSS expectation is a sample rate supported by | | 239 | * However, the OSS expectation is a sample rate supported by |
240 | * the hardware is returned if the exact rate could not be set. | | 240 | * the hardware is returned if the exact rate could not be set. |
241 | * | | 241 | * |
242 | * So, if the chosen sample rate is invalid, set and return | | 242 | * So, if the chosen sample rate is invalid, set and return |
243 | * the current hardware rate. | | 243 | * the current hardware rate. |
244 | */ | | 244 | */ |
245 | if (ioctlf(fp, AUDIO_SETINFO, &tmpinfo) != 0) { | | 245 | if (ioctlf(fp, AUDIO_SETINFO, &tmpinfo) != 0) { |
246 | error = ioctlf(fp, AUDIO_GETFORMAT, &hwfmt); | | 246 | error = ioctlf(fp, AUDIO_GETFORMAT, &hwfmt); |
247 | if (error) { | | 247 | if (error) { |
248 | DPRINTF(("%s: AUDIO_GETFORMAT %d\n", | | 248 | DPRINTF(("%s: AUDIO_GETFORMAT %d\n", |
249 | __func__, error)); | | 249 | __func__, error)); |
250 | goto out; | | 250 | goto out; |
251 | } | | 251 | } |
252 | error = ioctlf(fp, AUDIO_GETINFO, &tmpinfo); | | 252 | error = ioctlf(fp, AUDIO_GETINFO, &tmpinfo); |
253 | if (error) { | | 253 | if (error) { |
254 | DPRINTF(("%s: AUDIO_GETINFO %d\n", | | 254 | DPRINTF(("%s: AUDIO_GETINFO %d\n", |
255 | __func__, error)); | | 255 | __func__, error)); |
256 | goto out; | | 256 | goto out; |
257 | } | | 257 | } |
258 | tmpinfo.play.sample_rate = | | 258 | tmpinfo.play.sample_rate = |
259 | tmpinfo.record.sample_rate = | | 259 | tmpinfo.record.sample_rate = |
260 | (tmpinfo.mode == AUMODE_RECORD) ? | | 260 | (tmpinfo.mode == AUMODE_RECORD) ? |
261 | hwfmt.record.sample_rate : | | 261 | hwfmt.record.sample_rate : |
262 | hwfmt.play.sample_rate; | | 262 | hwfmt.play.sample_rate; |
263 | error = ioctlf(fp, AUDIO_SETINFO, &tmpinfo); | | 263 | error = ioctlf(fp, AUDIO_SETINFO, &tmpinfo); |
264 | if (error) { | | 264 | if (error) { |
265 | DPRINTF(("%s: SNDCTL_DSP_SPEED %d = %d\n", | | 265 | DPRINTF(("%s: SNDCTL_DSP_SPEED %d = %d\n", |
266 | __func__, idat, error)); | | 266 | __func__, idat, error)); |
267 | goto out; | | 267 | goto out; |
268 | } | | 268 | } |
269 | } | | 269 | } |
270 | /* FALLTHROUGH */ | | 270 | /* FALLTHROUGH */ |
271 | case OSS_SOUND_PCM_READ_RATE: | | 271 | case OSS_SOUND_PCM_READ_RATE: |
272 | error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo); | | 272 | error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo); |
273 | if (error) { | | 273 | if (error) { |
274 | DPRINTF(("%s: AUDIO_GETBUFINFO %d\n", | | 274 | DPRINTF(("%s: AUDIO_GETBUFINFO %d\n", |
275 | __func__, error)); | | 275 | __func__, error)); |
276 | goto out; | | 276 | goto out; |
277 | } | | 277 | } |
278 | idat = GETPRINFO(&tmpinfo, sample_rate); | | 278 | idat = GETPRINFO(&tmpinfo, sample_rate); |
279 | DPRINTF(("%s: SNDCTL_PCM_READ_RATE < %d\n", __func__, idat)); | | 279 | DPRINTF(("%s: SNDCTL_PCM_READ_RATE < %d\n", __func__, idat)); |
280 | error = copyout(&idat, SCARG(uap, data), sizeof idat); | | 280 | error = copyout(&idat, SCARG(uap, data), sizeof idat); |
281 | if (error) { | | 281 | if (error) { |
282 | DPRINTF(("%s: SOUND_PCM_READ_RATE %d = %d\n", | | 282 | DPRINTF(("%s: SOUND_PCM_READ_RATE %d = %d\n", |
283 | __func__, idat, error)); | | 283 | __func__, idat, error)); |
284 | goto out; | | 284 | goto out; |
285 | } | | 285 | } |
286 | break; | | 286 | break; |
287 | case OSS_SNDCTL_DSP_STEREO: | | 287 | case OSS_SNDCTL_DSP_STEREO: |
288 | AUDIO_INITINFO(&tmpinfo); | | 288 | AUDIO_INITINFO(&tmpinfo); |
289 | error = copyin(SCARG(uap, data), &idat, sizeof idat); | | 289 | error = copyin(SCARG(uap, data), &idat, sizeof idat); |
290 | if (error) { | | 290 | if (error) { |
291 | DPRINTF(("%s: SNDCTL_DSP_STEREO %d\n", | | 291 | DPRINTF(("%s: SNDCTL_DSP_STEREO %d\n", |
292 | __func__, error)); | | 292 | __func__, error)); |
293 | goto out; | | 293 | goto out; |
294 | } | | 294 | } |
295 | tmpinfo.play.channels = | | 295 | tmpinfo.play.channels = |
296 | tmpinfo.record.channels = idat ? 2 : 1; | | 296 | tmpinfo.record.channels = idat ? 2 : 1; |
297 | error = ioctlf(fp, AUDIO_SETINFO, &tmpinfo); | | 297 | error = ioctlf(fp, AUDIO_SETINFO, &tmpinfo); |
298 | if (error) { | | 298 | if (error) { |
299 | DPRINTF(("%s: AUDIO_SETINFO %d\n", | | 299 | DPRINTF(("%s: AUDIO_SETINFO %d\n", |
300 | __func__, error)); | | 300 | __func__, error)); |
301 | goto out; | | 301 | goto out; |
302 | } | | 302 | } |
303 | error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo); | | 303 | error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo); |
304 | if (error) { | | 304 | if (error) { |
305 | DPRINTF(("%s: AUDIO_GETBUFINFO %d\n", | | 305 | DPRINTF(("%s: AUDIO_GETBUFINFO %d\n", |
306 | __func__, error)); | | 306 | __func__, error)); |
307 | goto out; | | 307 | goto out; |
308 | } | | 308 | } |
309 | idat = GETPRINFO(&tmpinfo, channels) - 1; | | 309 | idat = GETPRINFO(&tmpinfo, channels) - 1; |
310 | error = copyout(&idat, SCARG(uap, data), sizeof idat); | | 310 | error = copyout(&idat, SCARG(uap, data), sizeof idat); |
311 | if (error) { | | 311 | if (error) { |
312 | DPRINTF(("%s: SNDCTL_DSP_STEREO %d = %d\n", | | 312 | DPRINTF(("%s: SNDCTL_DSP_STEREO %d = %d\n", |
313 | __func__, idat, error)); | | 313 | __func__, idat, error)); |
314 | goto out; | | 314 | goto out; |
315 | } | | 315 | } |
316 | break; | | 316 | break; |
317 | case OSS_SNDCTL_DSP_GETBLKSIZE: | | 317 | case OSS_SNDCTL_DSP_GETBLKSIZE: |
318 | error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo); | | 318 | error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo); |
319 | if (error) { | | 319 | if (error) { |
320 | DPRINTF(("%s: AUDIO_GETBUFINFO %d\n", | | 320 | DPRINTF(("%s: AUDIO_GETBUFINFO %d\n", |
321 | __func__, error)); | | 321 | __func__, error)); |
322 | goto out; | | 322 | goto out; |
323 | } | | 323 | } |
324 | setblocksize(fp, &tmpinfo); | | 324 | setblocksize(fp, &tmpinfo); |
325 | idat = tmpinfo.blocksize; | | 325 | idat = tmpinfo.blocksize; |
326 | DPRINTF(("%s: SNDCTL_DSP_GETBLKSIZE < %d\n", | | 326 | DPRINTF(("%s: SNDCTL_DSP_GETBLKSIZE < %d\n", |
327 | __func__, idat)); | | 327 | __func__, idat)); |
328 | error = copyout(&idat, SCARG(uap, data), sizeof idat); | | 328 | error = copyout(&idat, SCARG(uap, data), sizeof idat); |
329 | if (error) { | | 329 | if (error) { |
330 | DPRINTF(("%s: SNDCTL_DSP_GETBLKSIZE %d = %d\n", | | 330 | DPRINTF(("%s: SNDCTL_DSP_GETBLKSIZE %d = %d\n", |
331 | __func__, idat, error)); | | 331 | __func__, idat, error)); |
332 | goto out; | | 332 | goto out; |
333 | } | | 333 | } |
334 | break; | | 334 | break; |
335 | case OSS_SNDCTL_DSP_SETFMT: | | 335 | case OSS_SNDCTL_DSP_SETFMT: |
336 | AUDIO_INITINFO(&tmpinfo); | | 336 | AUDIO_INITINFO(&tmpinfo); |
337 | error = copyin(SCARG(uap, data), &idat, sizeof idat); | | 337 | error = copyin(SCARG(uap, data), &idat, sizeof idat); |
338 | if (error) { | | 338 | if (error) { |
339 | DPRINTF(("%s: SNDCTL_DSP_SETFMT %d\n", | | 339 | DPRINTF(("%s: SNDCTL_DSP_SETFMT %d\n", |
340 | __func__, error)); | | 340 | __func__, error)); |
341 | goto out; | | 341 | goto out; |
342 | } | | 342 | } |
343 | switch (idat) { | | 343 | switch (idat) { |
344 | case OSS_AFMT_MU_LAW: | | 344 | case OSS_AFMT_MU_LAW: |
345 | tmpinfo.play.precision = | | 345 | tmpinfo.play.precision = |
346 | tmpinfo.record.precision = 8; | | 346 | tmpinfo.record.precision = 8; |
347 | tmpinfo.play.encoding = | | 347 | tmpinfo.play.encoding = |
348 | tmpinfo.record.encoding = AUDIO_ENCODING_ULAW; | | 348 | tmpinfo.record.encoding = AUDIO_ENCODING_ULAW; |
349 | break; | | 349 | break; |
350 | case OSS_AFMT_A_LAW: | | 350 | case OSS_AFMT_A_LAW: |
351 | tmpinfo.play.precision = | | 351 | tmpinfo.play.precision = |
352 | tmpinfo.record.precision = 8; | | 352 | tmpinfo.record.precision = 8; |
353 | tmpinfo.play.encoding = | | 353 | tmpinfo.play.encoding = |
354 | tmpinfo.record.encoding = AUDIO_ENCODING_ALAW; | | 354 | tmpinfo.record.encoding = AUDIO_ENCODING_ALAW; |
355 | break; | | 355 | break; |
356 | case OSS_AFMT_U8: | | 356 | case OSS_AFMT_U8: |
357 | tmpinfo.play.precision = | | 357 | tmpinfo.play.precision = |
358 | tmpinfo.record.precision = 8; | | 358 | tmpinfo.record.precision = 8; |
359 | tmpinfo.play.encoding = | | 359 | tmpinfo.play.encoding = |
360 | tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR; | | 360 | tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR; |
361 | break; | | 361 | break; |
362 | case OSS_AFMT_S8: | | 362 | case OSS_AFMT_S8: |
363 | tmpinfo.play.precision = | | 363 | tmpinfo.play.precision = |
364 | tmpinfo.record.precision = 8; | | 364 | tmpinfo.record.precision = 8; |
365 | tmpinfo.play.encoding = | | 365 | tmpinfo.play.encoding = |
366 | tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR; | | 366 | tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR; |
367 | break; | | 367 | break; |
368 | case OSS_AFMT_S16_LE: | | 368 | case OSS_AFMT_S16_LE: |
369 | tmpinfo.play.precision = | | 369 | tmpinfo.play.precision = |
370 | tmpinfo.record.precision = 16; | | 370 | tmpinfo.record.precision = 16; |
371 | tmpinfo.play.encoding = | | 371 | tmpinfo.play.encoding = |
372 | tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_LE; | | 372 | tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_LE; |
373 | break; | | 373 | break; |
374 | case OSS_AFMT_S16_BE: | | 374 | case OSS_AFMT_S16_BE: |
375 | tmpinfo.play.precision = | | 375 | tmpinfo.play.precision = |
376 | tmpinfo.record.precision = 16; | | 376 | tmpinfo.record.precision = 16; |
377 | tmpinfo.play.encoding = | | 377 | tmpinfo.play.encoding = |
378 | tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_BE; | | 378 | tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_BE; |
379 | break; | | 379 | break; |
380 | case OSS_AFMT_U16_LE: | | 380 | case OSS_AFMT_U16_LE: |
381 | tmpinfo.play.precision = | | 381 | tmpinfo.play.precision = |
382 | tmpinfo.record.precision = 16; | | 382 | tmpinfo.record.precision = 16; |
383 | tmpinfo.play.encoding = | | 383 | tmpinfo.play.encoding = |
384 | tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR_LE; | | 384 | tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR_LE; |
385 | break; | | 385 | break; |
386 | case OSS_AFMT_U16_BE: | | 386 | case OSS_AFMT_U16_BE: |
387 | tmpinfo.play.precision = | | 387 | tmpinfo.play.precision = |
388 | tmpinfo.record.precision = 16; | | 388 | tmpinfo.record.precision = 16; |
389 | tmpinfo.play.encoding = | | 389 | tmpinfo.play.encoding = |
390 | tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR_BE; | | 390 | tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR_BE; |
391 | break; | | 391 | break; |
392 | case OSS_AFMT_AC3: | | 392 | case OSS_AFMT_AC3: |
393 | tmpinfo.play.precision = | | 393 | tmpinfo.play.precision = |
394 | tmpinfo.record.precision = 16; | | 394 | tmpinfo.record.precision = 16; |
395 | tmpinfo.play.encoding = | | 395 | tmpinfo.play.encoding = |
396 | tmpinfo.record.encoding = AUDIO_ENCODING_AC3; | | 396 | tmpinfo.record.encoding = AUDIO_ENCODING_AC3; |
397 | break; | | 397 | break; |
398 | default: | | 398 | default: |
399 | /* | | 399 | /* |
400 | * OSSv4 specifies that if an invalid format is chosen | | 400 | * OSSv4 specifies that if an invalid format is chosen |
401 | * by an application then a sensible format supported | | 401 | * by an application then a sensible format supported |
402 | * by the hardware is returned. | | 402 | * by the hardware is returned. |
403 | * | | 403 | * |
404 | * In this case, we pick S16LE since it's reasonably | | 404 | * In this case, we pick S16LE since it's reasonably |
405 | * assumed to be supported by applications. | | 405 | * assumed to be supported by applications. |
406 | */ | | 406 | */ |
407 | tmpinfo.play.precision = | | 407 | tmpinfo.play.precision = |
408 | tmpinfo.record.precision = 16; | | 408 | tmpinfo.record.precision = 16; |
409 | tmpinfo.play.encoding = | | 409 | tmpinfo.play.encoding = |
410 | tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_LE; | | 410 | tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_LE; |
411 | break; | | 411 | break; |
412 | } | | 412 | } |
413 | DPRINTF(("%s: SNDCTL_DSP_SETFMT > 0x%x\n", | | 413 | DPRINTF(("%s: SNDCTL_DSP_SETFMT > 0x%x\n", |
414 | __func__, idat)); | | 414 | __func__, idat)); |
415 | error = ioctlf(fp, AUDIO_SETINFO, &tmpinfo); | | 415 | error = ioctlf(fp, AUDIO_SETINFO, &tmpinfo); |
416 | if (error) { | | 416 | if (error) { |
417 | DPRINTF(("%s: AUDIO_SETINFO %d\n", | | 417 | DPRINTF(("%s: AUDIO_SETINFO %d\n", |
418 | __func__, error)); | | 418 | __func__, error)); |
419 | goto out; | | 419 | goto out; |
420 | } | | 420 | } |
421 | /* FALLTHROUGH */ | | 421 | /* FALLTHROUGH */ |
422 | case OSS_SOUND_PCM_READ_BITS: | | 422 | case OSS_SOUND_PCM_READ_BITS: |
423 | error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo); | | 423 | error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo); |
424 | if (error) { | | 424 | if (error) { |
425 | DPRINTF(("%s: AUDIO_GETBUFINFO %d\n", | | 425 | DPRINTF(("%s: AUDIO_GETBUFINFO %d\n", |
426 | __func__, error)); | | 426 | __func__, error)); |
427 | goto out; | | 427 | goto out; |
428 | } | | 428 | } |
429 | encoding = GETPRINFO(&tmpinfo, encoding); | | 429 | encoding = GETPRINFO(&tmpinfo, encoding); |
430 | precision = GETPRINFO(&tmpinfo, precision); | | 430 | precision = GETPRINFO(&tmpinfo, precision); |
431 | switch (encoding) { | | 431 | switch (encoding) { |
432 | case AUDIO_ENCODING_ULAW: | | 432 | case AUDIO_ENCODING_ULAW: |
433 | idat = OSS_AFMT_MU_LAW; | | 433 | idat = OSS_AFMT_MU_LAW; |
434 | break; | | 434 | break; |
435 | case AUDIO_ENCODING_ALAW: | | 435 | case AUDIO_ENCODING_ALAW: |
436 | idat = OSS_AFMT_A_LAW; | | 436 | idat = OSS_AFMT_A_LAW; |
437 | break; | | 437 | break; |
438 | case AUDIO_ENCODING_SLINEAR_LE: | | 438 | case AUDIO_ENCODING_SLINEAR_LE: |
439 | if (precision == 16) | | 439 | if (precision == 16) |
440 | idat = OSS_AFMT_S16_LE; | | 440 | idat = OSS_AFMT_S16_LE; |
441 | else | | 441 | else |
442 | idat = OSS_AFMT_S8; | | 442 | idat = OSS_AFMT_S8; |
443 | break; | | 443 | break; |
444 | case AUDIO_ENCODING_SLINEAR_BE: | | 444 | case AUDIO_ENCODING_SLINEAR_BE: |
445 | if (precision == 16) | | 445 | if (precision == 16) |
446 | idat = OSS_AFMT_S16_BE; | | 446 | idat = OSS_AFMT_S16_BE; |
447 | else | | 447 | else |
448 | idat = OSS_AFMT_S8; | | 448 | idat = OSS_AFMT_S8; |
449 | break; | | 449 | break; |
450 | case AUDIO_ENCODING_ULINEAR_LE: | | 450 | case AUDIO_ENCODING_ULINEAR_LE: |
451 | if (precision == 16) | | 451 | if (precision == 16) |
452 | idat = OSS_AFMT_U16_LE; | | 452 | idat = OSS_AFMT_U16_LE; |
453 | else | | 453 | else |
454 | idat = OSS_AFMT_U8; | | 454 | idat = OSS_AFMT_U8; |
455 | break; | | 455 | break; |
456 | case AUDIO_ENCODING_ULINEAR_BE: | | 456 | case AUDIO_ENCODING_ULINEAR_BE: |
457 | if (precision == 16) | | 457 | if (precision == 16) |
458 | idat = OSS_AFMT_U16_BE; | | 458 | idat = OSS_AFMT_U16_BE; |
459 | else | | 459 | else |
460 | idat = OSS_AFMT_U8; | | 460 | idat = OSS_AFMT_U8; |
461 | break; | | 461 | break; |
462 | case AUDIO_ENCODING_ADPCM: | | 462 | case AUDIO_ENCODING_ADPCM: |
463 | idat = OSS_AFMT_IMA_ADPCM; | | 463 | idat = OSS_AFMT_IMA_ADPCM; |
464 | break; | | 464 | break; |
465 | case AUDIO_ENCODING_AC3: | | 465 | case AUDIO_ENCODING_AC3: |
466 | idat = OSS_AFMT_AC3; | | 466 | idat = OSS_AFMT_AC3; |
467 | break; | | 467 | break; |
468 | default: | | 468 | default: |
469 | DPRINTF(("%s: SOUND_PCM_READ_BITS bad encoding %d\n", | | 469 | DPRINTF(("%s: SOUND_PCM_READ_BITS bad encoding %d\n", |
470 | __func__, tmpinfo.play.encoding)); | | 470 | __func__, tmpinfo.play.encoding)); |
471 | error = EINVAL; | | 471 | error = EINVAL; |
472 | goto out; | | 472 | goto out; |
473 | } | | 473 | } |
474 | DPRINTF(("%s: SOUND_PCM_READ_BITS < 0x%x\n", | | 474 | DPRINTF(("%s: SOUND_PCM_READ_BITS < 0x%x\n", |
475 | __func__, idat)); | | 475 | __func__, idat)); |
476 | error = copyout(&idat, SCARG(uap, data), sizeof idat); | | 476 | error = copyout(&idat, SCARG(uap, data), sizeof idat); |
477 | if (error) { | | 477 | if (error) { |
478 | DPRINTF(("%s: SOUND_PCM_READ_BITS %d = %d\n", | | 478 | DPRINTF(("%s: SOUND_PCM_READ_BITS %d = %d\n", |
479 | __func__, idat, error)); | | 479 | __func__, idat, error)); |
480 | goto out; | | 480 | goto out; |
481 | } | | 481 | } |
482 | break; | | 482 | break; |
483 | case OSS_SNDCTL_DSP_CHANNELS: | | 483 | case OSS_SNDCTL_DSP_CHANNELS: |
484 | AUDIO_INITINFO(&tmpinfo); | | 484 | AUDIO_INITINFO(&tmpinfo); |
485 | error = copyin(SCARG(uap, data), &idat, sizeof idat); | | 485 | error = copyin(SCARG(uap, data), &idat, sizeof idat); |
486 | if (error) { | | 486 | if (error) { |
487 | DPRINTF(("%s: SNDCTL_DSP_CHANNELS %d\n", | | 487 | DPRINTF(("%s: SNDCTL_DSP_CHANNELS %d\n", |
488 | __func__, error)); | | 488 | __func__, error)); |
489 | goto out; | | 489 | goto out; |
490 | } | | 490 | } |
491 | error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo); | | 491 | error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo); |
492 | if (error) { | | 492 | if (error) { |
493 | DPRINTF(("%s: AUDIO_GETBUFINFO %d\n", | | 493 | DPRINTF(("%s: AUDIO_GETBUFINFO %d\n", |
494 | __func__, error)); | | 494 | __func__, error)); |
495 | goto out; | | 495 | goto out; |
496 | } | | 496 | } |
497 | setchannels(fp, tmpinfo.mode, idat); | | 497 | setchannels(fp, tmpinfo.mode, idat); |
498 | /* FALLTHROUGH */ | | 498 | /* FALLTHROUGH */ |
499 | case OSS_SOUND_PCM_READ_CHANNELS: | | 499 | case OSS_SOUND_PCM_READ_CHANNELS: |
500 | error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo); | | 500 | error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo); |
501 | if (error) { | | 501 | if (error) { |
502 | DPRINTF(("%s: AUDIO_GETBUFINFO %d\n", | | 502 | DPRINTF(("%s: AUDIO_GETBUFINFO %d\n", |
503 | __func__, error)); | | 503 | __func__, error)); |
504 | goto out; | | 504 | goto out; |
505 | } | | 505 | } |
506 | idat = GETPRINFO(&tmpinfo, channels); | | 506 | idat = GETPRINFO(&tmpinfo, channels); |
507 | DPRINTF(("%s: SOUND_PCM_READ_CHANNELS < %d\n", __func__, idat)); | | 507 | DPRINTF(("%s: SOUND_PCM_READ_CHANNELS < %d\n", __func__, idat)); |
508 | error = copyout(&idat, SCARG(uap, data), sizeof idat); | | 508 | error = copyout(&idat, SCARG(uap, data), sizeof idat); |
509 | if (error) { | | 509 | if (error) { |
510 | DPRINTF(("%s: SOUND_PCM_READ_CHANNELS %d = %d\n", | | 510 | DPRINTF(("%s: SOUND_PCM_READ_CHANNELS %d = %d\n", |
511 | __func__, idat, error)); | | 511 | __func__, idat, error)); |
512 | goto out; | | 512 | goto out; |
513 | } | | 513 | } |
514 | break; | | 514 | break; |
515 | case OSS_SOUND_PCM_WRITE_FILTER: | | 515 | case OSS_SOUND_PCM_WRITE_FILTER: |
516 | case OSS_SOUND_PCM_READ_FILTER: | | 516 | case OSS_SOUND_PCM_READ_FILTER: |
517 | error = EINVAL; /* XXX unimplemented */ | | 517 | error = EINVAL; /* XXX unimplemented */ |
518 | DPRINTF(("%s: SOUND_PCM_{READ,WRITE}_FILTER filter\n", | | 518 | DPRINTF(("%s: SOUND_PCM_{READ,WRITE}_FILTER filter\n", |
519 | __func__)); | | 519 | __func__)); |
520 | goto out; | | 520 | goto out; |
521 | case OSS_SNDCTL_DSP_SUBDIVIDE: | | 521 | case OSS_SNDCTL_DSP_SUBDIVIDE: |
522 | error = copyin(SCARG(uap, data), &idat, sizeof idat); | | 522 | error = copyin(SCARG(uap, data), &idat, sizeof idat); |
523 | if (error) { | | 523 | if (error) { |
524 | DPRINTF(("%s: SNDCTL_DSP_SUBDIVIDE %d\n", | | 524 | DPRINTF(("%s: SNDCTL_DSP_SUBDIVIDE %d\n", |
525 | __func__, error)); | | 525 | __func__, error)); |
526 | goto out; | | 526 | goto out; |
527 | } | | 527 | } |
528 | error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo); | | 528 | error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo); |
529 | if (error) { | | 529 | if (error) { |
530 | DPRINTF(("%s: AUDIO_GETBUFINFO %d\n", | | 530 | DPRINTF(("%s: AUDIO_GETBUFINFO %d\n", |
531 | __func__, error)); | | 531 | __func__, error)); |
532 | goto out; | | 532 | goto out; |
533 | } | | 533 | } |
534 | setblocksize(fp, &tmpinfo); | | 534 | setblocksize(fp, &tmpinfo); |
535 | if (idat == 0) | | 535 | if (idat == 0) |
536 | idat = tmpinfo.play.buffer_size / tmpinfo.blocksize; | | 536 | idat = tmpinfo.play.buffer_size / tmpinfo.blocksize; |
537 | idat = (tmpinfo.play.buffer_size / idat) & -4; | | 537 | idat = (tmpinfo.play.buffer_size / idat) & -4; |
538 | AUDIO_INITINFO(&tmpinfo); | | 538 | AUDIO_INITINFO(&tmpinfo); |
539 | tmpinfo.blocksize = idat; | | 539 | tmpinfo.blocksize = idat; |
540 | error = ioctlf(fp, AUDIO_SETINFO, &tmpinfo); | | 540 | error = ioctlf(fp, AUDIO_SETINFO, &tmpinfo); |
541 | if (error) { | | 541 | if (error) { |
542 | DPRINTF(("%s: AUDIO_SETINFO %d\n", | | 542 | DPRINTF(("%s: AUDIO_SETINFO %d\n", |
543 | __func__, error)); | | 543 | __func__, error)); |
544 | goto out; | | 544 | goto out; |
545 | } | | 545 | } |
546 | idat = tmpinfo.play.buffer_size / tmpinfo.blocksize; | | 546 | idat = tmpinfo.play.buffer_size / tmpinfo.blocksize; |
547 | error = copyout(&idat, SCARG(uap, data), sizeof idat); | | 547 | error = copyout(&idat, SCARG(uap, data), sizeof idat); |
548 | if (error) { | | 548 | if (error) { |
549 | DPRINTF(("%s: SNDCTL_DSP_SUBDIVIDE %d = %d\n", | | 549 | DPRINTF(("%s: SNDCTL_DSP_SUBDIVIDE %d = %d\n", |
550 | __func__, idat, error)); | | 550 | __func__, idat, error)); |
551 | goto out; | | 551 | goto out; |
552 | } | | 552 | } |
553 | break; | | 553 | break; |
554 | case OSS_SNDCTL_DSP_SETFRAGMENT: | | 554 | case OSS_SNDCTL_DSP_SETFRAGMENT: |
555 | AUDIO_INITINFO(&tmpinfo); | | 555 | AUDIO_INITINFO(&tmpinfo); |
556 | error = copyin(SCARG(uap, data), &idat, sizeof idat); | | 556 | error = copyin(SCARG(uap, data), &idat, sizeof idat); |
557 | if (error) { | | 557 | if (error) { |
558 | DPRINTF(("%s: SNDCTL_DSP_SETFRAGMENT %d\n", | | 558 | DPRINTF(("%s: SNDCTL_DSP_SETFRAGMENT %d\n", |
559 | __func__, error)); | | 559 | __func__, error)); |
560 | goto out; | | 560 | goto out; |
561 | } | | 561 | } |
562 | if ((idat & 0xffff) < 4 || (idat & 0xffff) > 17) { | | 562 | if ((idat & 0xffff) < 4 || (idat & 0xffff) > 17) { |
563 | DPRINTF(("%s: SNDCTL_DSP_SETFRAGMENT bad ival%d\n", | | 563 | DPRINTF(("%s: SNDCTL_DSP_SETFRAGMENT bad ival%d\n", |
564 | __func__, idat)); | | 564 | __func__, idat)); |
565 | error = EINVAL; | | 565 | error = EINVAL; |
566 | goto out; | | 566 | goto out; |
567 | } | | 567 | } |
568 | tmpinfo.blocksize = 1 << (idat & 0xffff); | | 568 | tmpinfo.blocksize = 1 << (idat & 0xffff); |
569 | tmpinfo.hiwat = (idat >> 16) & 0x7fff; | | 569 | tmpinfo.hiwat = (idat >> 16) & 0x7fff; |
570 | DPRINTF(("%s: SNDCTL_DSP_SETFRAGMENT blksize=%d, " | | 570 | DPRINTF(("%s: SNDCTL_DSP_SETFRAGMENT blksize=%d, " |
571 | "hiwat=%d\n", __func__, tmpinfo.blocksize, tmpinfo.hiwat)); | | 571 | "hiwat=%d\n", __func__, tmpinfo.blocksize, tmpinfo.hiwat)); |
572 | if (tmpinfo.hiwat == 0) /* 0 means set to max */ | | 572 | if (tmpinfo.hiwat == 0) /* 0 means set to max */ |
573 | tmpinfo.hiwat = 65536; | | 573 | tmpinfo.hiwat = 65536; |
574 | error = ioctlf(fp, AUDIO_SETINFO, &tmpinfo); | | 574 | error = ioctlf(fp, AUDIO_SETINFO, &tmpinfo); |
575 | if (error) { | | 575 | if (error) { |
576 | DPRINTF(("%s: AUDIO_SETINFO %d\n", | | 576 | DPRINTF(("%s: AUDIO_SETINFO %d\n", |
577 | __func__, error)); | | 577 | __func__, error)); |
578 | goto out; | | 578 | goto out; |
579 | } | | 579 | } |
580 | error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo); | | 580 | error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo); |
581 | if (error) { | | 581 | if (error) { |
582 | DPRINTF(("%s: AUDIO_GETBUFINFO %d\n", | | 582 | DPRINTF(("%s: AUDIO_GETBUFINFO %d\n", |
583 | __func__, error)); | | 583 | __func__, error)); |
584 | goto out; | | 584 | goto out; |
585 | } | | 585 | } |
586 | u = tmpinfo.blocksize; | | 586 | u = tmpinfo.blocksize; |
587 | for(idat = 0; u > 1; idat++, u >>= 1) | | 587 | for(idat = 0; u > 1; idat++, u >>= 1) |
588 | ; | | 588 | ; |
589 | idat |= (tmpinfo.hiwat & 0x7fff) << 16; | | 589 | idat |= (tmpinfo.hiwat & 0x7fff) << 16; |
590 | error = copyout(&idat, SCARG(uap, data), sizeof idat); | | 590 | error = copyout(&idat, SCARG(uap, data), sizeof idat); |
591 | if (error) { | | 591 | if (error) { |
592 | DPRINTF(("%s: SNDCTL_DSP_SETFRAGMENT %d = %d\n", | | 592 | DPRINTF(("%s: SNDCTL_DSP_SETFRAGMENT %d = %d\n", |
593 | __func__, idat, error)); | | 593 | __func__, idat, error)); |
594 | goto out; | | 594 | goto out; |
595 | } | | 595 | } |
596 | break; | | 596 | break; |
597 | case OSS_SNDCTL_DSP_GETFMTS: | | 597 | case OSS_SNDCTL_DSP_GETFMTS: |
598 | for (idat = 0, tmpenc.index = 0; | | 598 | for (idat = 0, tmpenc.index = 0; |
599 | ioctlf(fp, AUDIO_GETENC, &tmpenc) == 0; | | 599 | ioctlf(fp, AUDIO_GETENC, &tmpenc) == 0; |
600 | tmpenc.index++) { | | 600 | tmpenc.index++) { |
601 | switch(tmpenc.encoding) { | | 601 | switch(tmpenc.encoding) { |
602 | case AUDIO_ENCODING_ULAW: | | 602 | case AUDIO_ENCODING_ULAW: |
603 | idat |= OSS_AFMT_MU_LAW; | | 603 | idat |= OSS_AFMT_MU_LAW; |
604 | break; | | 604 | break; |
605 | case AUDIO_ENCODING_ALAW: | | 605 | case AUDIO_ENCODING_ALAW: |
606 | idat |= OSS_AFMT_A_LAW; | | 606 | idat |= OSS_AFMT_A_LAW; |
607 | break; | | 607 | break; |
608 | case AUDIO_ENCODING_SLINEAR: | | 608 | case AUDIO_ENCODING_SLINEAR: |
609 | idat |= OSS_AFMT_S8; | | 609 | idat |= OSS_AFMT_S8; |
610 | break; | | 610 | break; |
611 | case AUDIO_ENCODING_SLINEAR_LE: | | 611 | case AUDIO_ENCODING_SLINEAR_LE: |
612 | if (tmpenc.precision == 16) | | 612 | if (tmpenc.precision == 16) |
613 | idat |= OSS_AFMT_S16_LE; | | 613 | idat |= OSS_AFMT_S16_LE; |
614 | else | | 614 | else |
615 | idat |= OSS_AFMT_S8; | | 615 | idat |= OSS_AFMT_S8; |
616 | break; | | 616 | break; |
617 | case AUDIO_ENCODING_SLINEAR_BE: | | 617 | case AUDIO_ENCODING_SLINEAR_BE: |
618 | if (tmpenc.precision == 16) | | 618 | if (tmpenc.precision == 16) |
619 | idat |= OSS_AFMT_S16_BE; | | 619 | idat |= OSS_AFMT_S16_BE; |
620 | else | | 620 | else |
621 | idat |= OSS_AFMT_S8; | | 621 | idat |= OSS_AFMT_S8; |
622 | break; | | 622 | break; |
623 | case AUDIO_ENCODING_ULINEAR: | | 623 | case AUDIO_ENCODING_ULINEAR: |
624 | idat |= OSS_AFMT_U8; | | 624 | idat |= OSS_AFMT_U8; |
625 | break; | | 625 | break; |
626 | case AUDIO_ENCODING_ULINEAR_LE: | | 626 | case AUDIO_ENCODING_ULINEAR_LE: |
627 | if (tmpenc.precision == 16) | | 627 | if (tmpenc.precision == 16) |
628 | idat |= OSS_AFMT_U16_LE; | | 628 | idat |= OSS_AFMT_U16_LE; |
629 | else | | 629 | else |
630 | idat |= OSS_AFMT_U8; | | 630 | idat |= OSS_AFMT_U8; |
631 | break; | | 631 | break; |
632 | case AUDIO_ENCODING_ULINEAR_BE: | | 632 | case AUDIO_ENCODING_ULINEAR_BE: |
633 | if (tmpenc.precision == 16) | | 633 | if (tmpenc.precision == 16) |
634 | idat |= OSS_AFMT_U16_BE; | | 634 | idat |= OSS_AFMT_U16_BE; |
635 | else | | 635 | else |
636 | idat |= OSS_AFMT_U8; | | 636 | idat |= OSS_AFMT_U8; |
637 | break; | | 637 | break; |
638 | case AUDIO_ENCODING_ADPCM: | | 638 | case AUDIO_ENCODING_ADPCM: |
639 | idat |= OSS_AFMT_IMA_ADPCM; | | 639 | idat |= OSS_AFMT_IMA_ADPCM; |
640 | break; | | 640 | break; |
641 | case AUDIO_ENCODING_AC3: | | 641 | case AUDIO_ENCODING_AC3: |
642 | idat |= OSS_AFMT_AC3; | | 642 | idat |= OSS_AFMT_AC3; |
643 | break; | | 643 | break; |
644 | default: | | 644 | default: |
645 | DPRINTF(("%s: SNDCTL_DSP_GETFMTS unknown %d\n", | | 645 | DPRINTF(("%s: SNDCTL_DSP_GETFMTS unknown %d\n", |
646 | __func__, tmpenc.encoding)); | | 646 | __func__, tmpenc.encoding)); |
647 | break; | | 647 | break; |
648 | } | | 648 | } |
649 | } | | 649 | } |
650 | DPRINTF(("%s: SNDCTL_DSP_GETFMTS < 0x%x\n", | | 650 | DPRINTF(("%s: SNDCTL_DSP_GETFMTS < 0x%x\n", |
651 | __func__, idat)); | | 651 | __func__, idat)); |
652 | error = copyout(&idat, SCARG(uap, data), sizeof idat); | | 652 | error = copyout(&idat, SCARG(uap, data), sizeof idat); |
653 | if (error) { | | 653 | if (error) { |
654 | DPRINTF(("%s: SNDCTL_DSP_GETFMTS = %x = %d\n", | | 654 | DPRINTF(("%s: SNDCTL_DSP_GETFMTS = %x = %d\n", |
655 | __func__, idat, error)); | | 655 | __func__, idat, error)); |
656 | goto out; | | 656 | goto out; |
657 | } | | 657 | } |
658 | break; | | 658 | break; |
659 | case OSS_SNDCTL_DSP_GETOSPACE: | | 659 | case OSS_SNDCTL_DSP_GETOSPACE: |
660 | error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo); | | 660 | error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo); |
661 | if (error) { | | 661 | if (error) { |
662 | DPRINTF(("%s: AUDIO_GETBUFINFO %d\n", | | 662 | DPRINTF(("%s: AUDIO_GETBUFINFO %d\n", |
663 | __func__, error)); | | 663 | __func__, error)); |
664 | goto out; | | 664 | goto out; |
665 | } | | 665 | } |
666 | setblocksize(fp, &tmpinfo); | | 666 | setblocksize(fp, &tmpinfo); |
667 | bufinfo.fragsize = tmpinfo.blocksize; | | 667 | bufinfo.fragsize = tmpinfo.blocksize; |
668 | bufinfo.fragments = tmpinfo.hiwat - | | 668 | bufinfo.fragments = tmpinfo.hiwat - |
669 | (tmpinfo.play.seek + tmpinfo.blocksize - 1) / | | 669 | (tmpinfo.play.seek + tmpinfo.blocksize - 1) / |
670 | tmpinfo.blocksize; | | 670 | tmpinfo.blocksize; |
671 | bufinfo.fragstotal = tmpinfo.hiwat; | | 671 | bufinfo.fragstotal = tmpinfo.hiwat; |
672 | bufinfo.bytes = | | 672 | bufinfo.bytes = |
673 | tmpinfo.hiwat * tmpinfo.blocksize - tmpinfo.play.seek; | | 673 | tmpinfo.hiwat * tmpinfo.blocksize - tmpinfo.play.seek; |
674 | error = copyout(&bufinfo, SCARG(uap, data), sizeof bufinfo); | | 674 | error = copyout(&bufinfo, SCARG(uap, data), sizeof bufinfo); |
675 | if (error) { | | 675 | if (error) { |
676 | DPRINTF(("%s: SNDCTL_DSP_GETOSPACE = %d\n", | | 676 | DPRINTF(("%s: SNDCTL_DSP_GETOSPACE = %d\n", |
677 | __func__, error)); | | 677 | __func__, error)); |
678 | goto out; | | 678 | goto out; |
679 | } | | 679 | } |
680 | break; | | 680 | break; |
681 | case OSS_SNDCTL_DSP_GETISPACE: | | 681 | case OSS_SNDCTL_DSP_GETISPACE: |
682 | error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo); | | 682 | error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo); |
683 | if (error) { | | 683 | if (error) { |
684 | DPRINTF(("%s: AUDIO_GETBUFINFO %d\n", | | 684 | DPRINTF(("%s: AUDIO_GETBUFINFO %d\n", |
685 | __func__, error)); | | 685 | __func__, error)); |
686 | goto out; | | 686 | goto out; |
687 | } | | 687 | } |
688 | setblocksize(fp, &tmpinfo); | | 688 | setblocksize(fp, &tmpinfo); |
689 | bufinfo.fragsize = tmpinfo.blocksize; | | 689 | bufinfo.fragsize = tmpinfo.blocksize; |
690 | bufinfo.fragments = tmpinfo.record.seek / tmpinfo.blocksize; | | 690 | bufinfo.fragments = tmpinfo.record.seek / tmpinfo.blocksize; |
691 | bufinfo.fragstotal = | | 691 | bufinfo.fragstotal = |
692 | tmpinfo.record.buffer_size / tmpinfo.blocksize; | | 692 | tmpinfo.record.buffer_size / tmpinfo.blocksize; |
693 | bufinfo.bytes = tmpinfo.record.seek; | | 693 | bufinfo.bytes = tmpinfo.record.seek; |
694 | error = copyout(&bufinfo, SCARG(uap, data), sizeof bufinfo); | | 694 | error = copyout(&bufinfo, SCARG(uap, data), sizeof bufinfo); |
695 | if (error) { | | 695 | if (error) { |
696 | DPRINTF(("%s: SNDCTL_DSP_GETISPACE %d %d %d %d = %d\n", | | 696 | DPRINTF(("%s: SNDCTL_DSP_GETISPACE %d %d %d %d = %d\n", |
697 | __func__, bufinfo.fragsize, bufinfo.fragments, | | 697 | __func__, bufinfo.fragsize, bufinfo.fragments, |
698 | bufinfo.fragstotal, bufinfo.bytes, error)); | | 698 | bufinfo.fragstotal, bufinfo.bytes, error)); |
699 | goto out; | | 699 | goto out; |
700 | } | | 700 | } |
701 | break; | | 701 | break; |
702 | case OSS_SNDCTL_DSP_NONBLOCK: | | 702 | case OSS_SNDCTL_DSP_NONBLOCK: |
703 | idat = 1; | | 703 | idat = 1; |
704 | error = ioctlf(fp, FIONBIO, &idat); | | 704 | error = ioctlf(fp, FIONBIO, &idat); |
705 | if (error) { | | 705 | if (error) { |
706 | DPRINTF(("%s: FIONBIO %d\n", | | 706 | DPRINTF(("%s: FIONBIO %d\n", |
707 | __func__, error)); | | 707 | __func__, error)); |
708 | goto out; | | 708 | goto out; |
709 | } | | 709 | } |
710 | break; | | 710 | break; |
711 | case OSS_SNDCTL_DSP_GETCAPS: | | 711 | case OSS_SNDCTL_DSP_GETCAPS: |
712 | error = ioctlf(fp, AUDIO_GETPROPS, &idata); | | 712 | error = ioctlf(fp, AUDIO_GETPROPS, &idata); |
713 | if (error) { | | 713 | if (error) { |
714 | DPRINTF(("%s: AUDIO_GETPROPS %d\n", | | 714 | DPRINTF(("%s: AUDIO_GETPROPS %d\n", |
715 | __func__, error)); | | 715 | __func__, error)); |
716 | goto out; | | 716 | goto out; |
717 | } | | 717 | } |
718 | idat = OSS_DSP_CAP_TRIGGER; /* pretend we have trigger */ | | 718 | idat = OSS_DSP_CAP_TRIGGER; |
719 | if (idata & AUDIO_PROP_FULLDUPLEX) | | 719 | if (idata & AUDIO_PROP_FULLDUPLEX) |
720 | idat |= OSS_DSP_CAP_DUPLEX; | | 720 | idat |= OSS_DSP_CAP_DUPLEX; |
721 | if (idata & AUDIO_PROP_MMAP) | | 721 | if (idata & AUDIO_PROP_MMAP) |
722 | idat |= OSS_DSP_CAP_MMAP; | | 722 | idat |= OSS_DSP_CAP_MMAP; |
723 | DPRINTF(("%s: SNDCL_DSP_GETCAPS %s duplex, %smmap\n", | | 723 | DPRINTF(("%s: SNDCL_DSP_GETCAPS %s duplex, %smmap\n", |
724 | __func__, (idat & OSS_DSP_CAP_DUPLEX) ? "full" : "half", | | 724 | __func__, (idat & OSS_DSP_CAP_DUPLEX) ? "full" : "half", |
725 | (idat & OSS_DSP_CAP_MMAP) ? "" : "no ")); | | 725 | (idat & OSS_DSP_CAP_MMAP) ? "" : "no ")); |
726 | error = copyout(&idat, SCARG(uap, data), sizeof idat); | | 726 | error = copyout(&idat, SCARG(uap, data), sizeof idat); |
727 | if (error) { | | 727 | if (error) { |
728 | DPRINTF(("%s: SNDCTL_DSP_GETCAPS %x = %d\n", __func__, | | 728 | DPRINTF(("%s: SNDCTL_DSP_GETCAPS %x = %d\n", __func__, |
729 | idat, error)); | | 729 | idat, error)); |
730 | goto out; | | 730 | goto out; |
731 | } | | 731 | } |
732 | break; | | 732 | break; |
733 | #if 0 | | | |
734 | case OSS_SNDCTL_DSP_GETTRIGGER: | | | |
735 | error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo); | | | |
736 | if (error) { | | | |
737 | DPRINTF(("%s: AUDIO_GETBUFINFO %d\n", | | | |
738 | __func__, error)); | | | |
739 | goto out; | | | |
740 | } | | | |
741 | idat = (tmpinfo.play.pause ? 0 : OSS_PCM_ENABLE_OUTPUT) | | | | |
742 | (tmpinfo.record.pause ? 0 : OSS_PCM_ENABLE_INPUT); | | | |
743 | error = copyout(&idat, SCARG(uap, data), sizeof idat); | | | |
744 | if (error) { | | | |
745 | DPRINTF(("%s: SNDCTL_DSP_SETRIGGER %x = %d\n", | | | |
746 | __func__, idat, error)); | | | |
747 | goto out; | | | |
748 | } | | | |
749 | break; | | | |
750 | case OSS_SNDCTL_DSP_SETTRIGGER: | | 733 | case OSS_SNDCTL_DSP_SETTRIGGER: |
751 | error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo, p); | | 734 | error = copyin(SCARG(uap, data), &idat, sizeof idat); |
752 | if (error) { | | 735 | if (error) { |
753 | DPRINTF(("%s: AUDIO_GETBUFINFO %d\n", | | 736 | DPRINTF(("%s: SNDCTL_DSP_SETTRIGGER: %d\n", |
754 | __func__, error)); | | 737 | __func__, error)); |
755 | goto out; | | 738 | goto out; |
756 | } | | 739 | } |
757 | error = copyin(SCARG(uap, data), &idat, sizeof idat); | | 740 | error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo); |
758 | if (error) { | | 741 | if (error) { |
759 | DPRINTF(("%s: AUDIO_GETBUFINFO %d\n", | | 742 | DPRINTF(("%s: AUDIO_GETBUFINFO %d\n", |
760 | __func__, error)); | | 743 | __func__, error)); |
761 | goto out; | | 744 | goto out; |
762 | } | | 745 | } |
763 | tmpinfo.play.pause = (idat & OSS_PCM_ENABLE_OUTPUT) == 0; | | 746 | AUDIO_INITINFO(&tmpinfo); |
764 | tmpinfo.record.pause = (idat & OSS_PCM_ENABLE_INPUT) == 0; | | 747 | if (tmpinfo.mode & AUMODE_PLAY) |
765 | error = ioctlf(fp, AUDIO_SETINFO, &tmpinfo); | | 748 | tmpinfo.play.pause = (idat & OSS_PCM_ENABLE_OUTPUT) == 0; |
| | | 749 | if (tmpinfo.mode & AUMODE_RECORD) |
| | | 750 | tmpinfo.record.pause = (idat & OSS_PCM_ENABLE_INPUT) == 0; |
| | | 751 | (void)ioctlf(fp, AUDIO_SETINFO, &tmpinfo); |
| | | 752 | /* FALLTHRU */ |
| | | 753 | case OSS_SNDCTL_DSP_GETTRIGGER: |
| | | 754 | error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo); |
766 | if (error) { | | 755 | if (error) { |
767 | DPRINTF(("%s: AUDIO_SETINFO %d\n", | | 756 | DPRINTF(("%s: AUDIO_GETBUFINFO %d\n", |
768 | __func__, error)); | | 757 | __func__, error)); |
769 | goto out; | | 758 | goto out; |
770 | } | | 759 | } |
| | | 760 | idat = 0; |
| | | 761 | if ((tmpinfo.mode & AUMODE_PLAY) && !tmpinfo.play.pause) |
| | | 762 | idat |= OSS_PCM_ENABLE_OUTPUT; |
| | | 763 | if ((tmpinfo.mode & AUMODE_RECORD) && !tmpinfo.record.pause) |
| | | 764 | idat |= OSS_PCM_ENABLE_INPUT; |
771 | error = copyout(&idat, SCARG(uap, data), sizeof idat); | | 765 | error = copyout(&idat, SCARG(uap, data), sizeof idat); |
772 | if (error) { | | 766 | if (error) { |
773 | DPRINTF(("%s: SNDCTL_DSP_SETRIGGER %x = %d\n", | | 767 | DPRINTF(("%s: SNDCTL_DSP_GETTRIGGER = %x = %d\n", |
774 | __func__, idat, error)); | | | |
775 | goto out; | | | |
776 | } | | | |
777 | break; | | | |
778 | #else | | | |
779 | case OSS_SNDCTL_DSP_GETTRIGGER: | | | |
780 | case OSS_SNDCTL_DSP_SETTRIGGER: | | | |
781 | /* XXX Do nothing for now. */ | | | |
782 | idat = OSS_PCM_ENABLE_OUTPUT; | | | |
783 | error = copyout(&idat, SCARG(uap, data), sizeof idat); | | | |
784 | if (error) { | | | |
785 | DPRINTF(("%s: SNDCTL_DSP_{GET,SET}RIGGER %x = %d\n", | | | |
786 | __func__, idat, error)); | | 768 | __func__, idat, error)); |
787 | goto out; | | 769 | goto out; |
788 | } | | 770 | } |
789 | break; | | 771 | break; |
790 | #endif | | | |
791 | case OSS_SNDCTL_DSP_GETIPTR: | | 772 | case OSS_SNDCTL_DSP_GETIPTR: |
792 | error = ioctlf(fp, AUDIO_GETIOFFS, &tmpoffs); | | 773 | error = ioctlf(fp, AUDIO_GETIOFFS, &tmpoffs); |
793 | if (error) { | | 774 | if (error) { |
794 | DPRINTF(("%s: AUDIO_GETIOFFS %d\n", | | 775 | DPRINTF(("%s: AUDIO_GETIOFFS %d\n", |
795 | __func__, error)); | | 776 | __func__, error)); |
796 | goto out; | | 777 | goto out; |
797 | } | | 778 | } |
798 | cntinfo.bytes = tmpoffs.samples; | | 779 | cntinfo.bytes = tmpoffs.samples; |
799 | cntinfo.blocks = tmpoffs.deltablks; | | 780 | cntinfo.blocks = tmpoffs.deltablks; |
800 | cntinfo.ptr = tmpoffs.offset; | | 781 | cntinfo.ptr = tmpoffs.offset; |
801 | error = copyout(&cntinfo, SCARG(uap, data), sizeof cntinfo); | | 782 | error = copyout(&cntinfo, SCARG(uap, data), sizeof cntinfo); |
802 | if (error) { | | 783 | if (error) { |
803 | DPRINTF(("%s: SNDCTL_DSP_GETIPTR %d\n", | | 784 | DPRINTF(("%s: SNDCTL_DSP_GETIPTR %d\n", |
804 | __func__, error)); | | 785 | __func__, error)); |
805 | goto out; | | 786 | goto out; |
806 | } | | 787 | } |
807 | break; | | 788 | break; |
808 | case OSS_SNDCTL_DSP_GETOPTR: | | 789 | case OSS_SNDCTL_DSP_GETOPTR: |
809 | error = ioctlf(fp, AUDIO_GETOOFFS, &tmpoffs); | | 790 | error = ioctlf(fp, AUDIO_GETOOFFS, &tmpoffs); |
810 | if (error) { | | 791 | if (error) { |
811 | DPRINTF(("%s: AUDIO_GETOOFFS %d\n", | | 792 | DPRINTF(("%s: AUDIO_GETOOFFS %d\n", |
812 | __func__, error)); | | 793 | __func__, error)); |
813 | goto out; | | 794 | goto out; |
814 | } | | 795 | } |
815 | cntinfo.bytes = tmpoffs.samples; | | 796 | cntinfo.bytes = tmpoffs.samples; |
816 | cntinfo.blocks = tmpoffs.deltablks; | | 797 | cntinfo.blocks = tmpoffs.deltablks; |
817 | cntinfo.ptr = tmpoffs.offset; | | 798 | cntinfo.ptr = tmpoffs.offset; |
818 | error = copyout(&cntinfo, SCARG(uap, data), sizeof cntinfo); | | 799 | error = copyout(&cntinfo, SCARG(uap, data), sizeof cntinfo); |
819 | if (error) { | | 800 | if (error) { |
820 | DPRINTF(("%s: SNDCTL_DSP_GETOPTR %d\n", | | 801 | DPRINTF(("%s: SNDCTL_DSP_GETOPTR %d\n", |
821 | __func__, error)); | | 802 | __func__, error)); |
822 | goto out; | | 803 | goto out; |
823 | } | | 804 | } |
824 | break; | | 805 | break; |
825 | case OSS_SNDCTL_DSP_SETDUPLEX: | | 806 | case OSS_SNDCTL_DSP_SETDUPLEX: |
826 | idat = 1; | | 807 | idat = 1; |
827 | error = ioctlf(fp, AUDIO_SETFD, &idat); | | 808 | error = ioctlf(fp, AUDIO_SETFD, &idat); |
828 | if (error) { | | 809 | if (error) { |
829 | DPRINTF(("%s: AUDIO_SETFD %d = %d\n", | | 810 | DPRINTF(("%s: AUDIO_SETFD %d = %d\n", |
830 | __func__, idat, error)); | | 811 | __func__, idat, error)); |
831 | goto out; | | 812 | goto out; |
832 | } | | 813 | } |
833 | break; | | 814 | break; |
834 | case OSS_SNDCTL_DSP_MAPINBUF: | | 815 | case OSS_SNDCTL_DSP_MAPINBUF: |
835 | DPRINTF(("%s: Unimplemented SNDCTL_DSP_MAPINBUF\n", | | 816 | DPRINTF(("%s: Unimplemented SNDCTL_DSP_MAPINBUF\n", |
836 | __func__)); | | 817 | __func__)); |
837 | error = EINVAL; | | 818 | error = EINVAL; |
838 | goto out; | | 819 | goto out; |
839 | case OSS_SNDCTL_DSP_MAPOUTBUF: | | 820 | case OSS_SNDCTL_DSP_MAPOUTBUF: |
840 | DPRINTF(("%s: Unimplemented SNDCTL_DSP_MAPOUTBUF\n", | | 821 | DPRINTF(("%s: Unimplemented SNDCTL_DSP_MAPOUTBUF\n", |
841 | __func__)); | | 822 | __func__)); |
842 | error = EINVAL; | | 823 | error = EINVAL; |
843 | goto out; | | 824 | goto out; |
844 | case OSS_SNDCTL_DSP_SETSYNCRO: | | 825 | case OSS_SNDCTL_DSP_SETSYNCRO: |
845 | DPRINTF(("%s: Unimplemented SNDCTL_DSP_GETSYNCHRO\n", | | 826 | DPRINTF(("%s: Unimplemented SNDCTL_DSP_GETSYNCHRO\n", |
846 | __func__)); | | 827 | __func__)); |
847 | error = EINVAL; | | 828 | error = EINVAL; |
848 | goto out; | | 829 | goto out; |
849 | case OSS_SNDCTL_DSP_GETODELAY: | | 830 | case OSS_SNDCTL_DSP_GETODELAY: |
850 | error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo); | | 831 | error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo); |
851 | if (error) { | | 832 | if (error) { |
852 | DPRINTF(("%s: AUDIO_GETBUFINFO %d\n", | | 833 | DPRINTF(("%s: AUDIO_GETBUFINFO %d\n", |
853 | __func__, error)); | | 834 | __func__, error)); |
854 | goto out; | | 835 | goto out; |
855 | } | | 836 | } |
856 | idat = tmpinfo.play.seek + tmpinfo.blocksize / 2; | | 837 | idat = tmpinfo.play.seek + tmpinfo.blocksize / 2; |
857 | error = copyout(&idat, SCARG(uap, data), sizeof idat); | | 838 | error = copyout(&idat, SCARG(uap, data), sizeof idat); |
858 | if (error) { | | 839 | if (error) { |
859 | DPRINTF(("%s: SNDCTL_DSP_GETODELAY %d\n", | | 840 | DPRINTF(("%s: SNDCTL_DSP_GETODELAY %d\n", |
860 | __func__, error)); | | 841 | __func__, error)); |
861 | goto out; | | 842 | goto out; |
862 | } | | 843 | } |
863 | break; | | 844 | break; |
864 | case OSS_SNDCTL_DSP_PROFILE: | | 845 | case OSS_SNDCTL_DSP_PROFILE: |
865 | /* This gives just a hint to the driver, | | 846 | /* This gives just a hint to the driver, |
866 | * implementing it as a NOP is ok | | 847 | * implementing it as a NOP is ok |
867 | */ | | 848 | */ |
868 | DPRINTF(("%s: SNDCTL_DSP_PROFILE\n", __func__)); | | 849 | DPRINTF(("%s: SNDCTL_DSP_PROFILE\n", __func__)); |
869 | break; | | 850 | break; |
870 | default: | | 851 | default: |
871 | DPRINTF(("%s: Unimplemented 0x%lx\n", __func__, com)); | | 852 | DPRINTF(("%s: Unimplemented 0x%lx\n", __func__, com)); |
872 | error = EINVAL; | | 853 | error = EINVAL; |
873 | goto out; | | 854 | goto out; |
874 | } | | 855 | } |
875 | | | 856 | |
876 | out: | | 857 | out: |
877 | fd_putfile(SCARG(uap, fd)); | | 858 | fd_putfile(SCARG(uap, fd)); |
878 | return error; | | 859 | return error; |
879 | } | | 860 | } |
880 | | | 861 | |
881 | /* If the NetBSD mixer device should have more than 32 devices | | 862 | /* If the NetBSD mixer device should have more than 32 devices |
882 | * some will not be available to Linux */ | | 863 | * some will not be available to Linux */ |
883 | #define NETBSD_MAXDEVS 64 | | 864 | #define NETBSD_MAXDEVS 64 |
884 | struct audiodevinfo { | | 865 | struct audiodevinfo { |
885 | int done; | | 866 | int done; |
886 | dev_t dev; | | 867 | dev_t dev; |
887 | int16_t devmap[OSS_SOUND_MIXER_NRDEVICES], | | 868 | int16_t devmap[OSS_SOUND_MIXER_NRDEVICES], |
888 | rdevmap[NETBSD_MAXDEVS]; | | 869 | rdevmap[NETBSD_MAXDEVS]; |
889 | char names[NETBSD_MAXDEVS][MAX_AUDIO_DEV_LEN]; | | 870 | char names[NETBSD_MAXDEVS][MAX_AUDIO_DEV_LEN]; |
890 | int enum2opaque[NETBSD_MAXDEVS]; | | 871 | int enum2opaque[NETBSD_MAXDEVS]; |
891 | u_long devmask, recmask, stereomask; | | 872 | u_long devmask, recmask, stereomask; |
892 | u_long caps, source; | | 873 | u_long caps, source; |
893 | }; | | 874 | }; |
894 | | | 875 | |
895 | static int | | 876 | static int |
896 | opaque_to_enum(struct audiodevinfo *di, audio_mixer_name_t *label, int opq) | | 877 | opaque_to_enum(struct audiodevinfo *di, audio_mixer_name_t *label, int opq) |
897 | { | | 878 | { |
898 | int i, o; | | 879 | int i, o; |
899 | | | 880 | |
900 | for (i = 0; i < NETBSD_MAXDEVS; i++) { | | 881 | for (i = 0; i < NETBSD_MAXDEVS; i++) { |
901 | o = di->enum2opaque[i]; | | 882 | o = di->enum2opaque[i]; |
902 | if (o == opq) | | 883 | if (o == opq) |
903 | break; | | 884 | break; |
904 | if (o == -1 && label != NULL && | | 885 | if (o == -1 && label != NULL && |
905 | !strncmp(di->names[i], label->name, sizeof di->names[i])) { | | 886 | !strncmp(di->names[i], label->name, sizeof di->names[i])) { |
906 | di->enum2opaque[i] = opq; | | 887 | di->enum2opaque[i] = opq; |
907 | break; | | 888 | break; |
908 | } | | 889 | } |
909 | } | | 890 | } |
910 | if (i >= NETBSD_MAXDEVS) | | 891 | if (i >= NETBSD_MAXDEVS) |
911 | i = -1; | | 892 | i = -1; |
912 | /*printf("opq_to_enum %s %d -> %d\n", label->name, opq, i);*/ | | 893 | /*printf("opq_to_enum %s %d -> %d\n", label->name, opq, i);*/ |
913 | return (i); | | 894 | return (i); |
914 | } | | 895 | } |
915 | | | 896 | |
916 | static int | | 897 | static int |
917 | enum_to_ord(struct audiodevinfo *di, int enm) | | 898 | enum_to_ord(struct audiodevinfo *di, int enm) |
918 | { | | 899 | { |
919 | if (enm >= NETBSD_MAXDEVS) | | 900 | if (enm >= NETBSD_MAXDEVS) |
920 | return (-1); | | 901 | return (-1); |
921 | | | 902 | |
922 | /*printf("enum_to_ord %d -> %d\n", enm, di->enum2opaque[enm]);*/ | | 903 | /*printf("enum_to_ord %d -> %d\n", enm, di->enum2opaque[enm]);*/ |
923 | return (di->enum2opaque[enm]); | | 904 | return (di->enum2opaque[enm]); |
924 | } | | 905 | } |
925 | | | 906 | |
926 | static int | | 907 | static int |
927 | enum_to_mask(struct audiodevinfo *di, int enm) | | 908 | enum_to_mask(struct audiodevinfo *di, int enm) |
928 | { | | 909 | { |
929 | int m; | | 910 | int m; |
930 | if (enm >= NETBSD_MAXDEVS) | | 911 | if (enm >= NETBSD_MAXDEVS) |
931 | return (0); | | 912 | return (0); |
932 | | | 913 | |
933 | m = di->enum2opaque[enm]; | | 914 | m = di->enum2opaque[enm]; |
934 | if (m == -1) | | 915 | if (m == -1) |
935 | m = 0; | | 916 | m = 0; |
936 | /*printf("enum_to_mask %d -> %d\n", enm, di->enum2opaque[enm]);*/ | | 917 | /*printf("enum_to_mask %d -> %d\n", enm, di->enum2opaque[enm]);*/ |
937 | return (m); | | 918 | return (m); |
938 | } | | 919 | } |
939 | | | 920 | |
940 | /* | | 921 | /* |
941 | * Collect the audio device information to allow faster | | 922 | * Collect the audio device information to allow faster |
942 | * emulation of the Linux mixer ioctls. Cache the information | | 923 | * emulation of the Linux mixer ioctls. Cache the information |
943 | * to eliminate the overhead of repeating all the ioctls needed | | 924 | * to eliminate the overhead of repeating all the ioctls needed |
944 | * to collect the information. | | 925 | * to collect the information. |
945 | */ | | 926 | */ |
946 | static struct audiodevinfo * | | 927 | static struct audiodevinfo * |
947 | getdevinfo(file_t *fp) | | 928 | getdevinfo(file_t *fp) |
948 | { | | 929 | { |
949 | mixer_devinfo_t mi; | | 930 | mixer_devinfo_t mi; |
950 | int i, j, e; | | 931 | int i, j, e; |
951 | static const struct { | | 932 | static const struct { |
952 | const char *name; | | 933 | const char *name; |
953 | int code; | | 934 | int code; |
954 | } *dp, devs[] = { | | 935 | } *dp, devs[] = { |
955 | { AudioNmicrophone, OSS_SOUND_MIXER_MIC }, | | 936 | { AudioNmicrophone, OSS_SOUND_MIXER_MIC }, |
956 | { AudioNline, OSS_SOUND_MIXER_LINE }, | | 937 | { AudioNline, OSS_SOUND_MIXER_LINE }, |
957 | { AudioNcd, OSS_SOUND_MIXER_CD }, | | 938 | { AudioNcd, OSS_SOUND_MIXER_CD }, |
958 | { AudioNdac, OSS_SOUND_MIXER_PCM }, | | 939 | { AudioNdac, OSS_SOUND_MIXER_PCM }, |
959 | { AudioNaux, OSS_SOUND_MIXER_LINE1 }, | | 940 | { AudioNaux, OSS_SOUND_MIXER_LINE1 }, |
960 | { AudioNrecord, OSS_SOUND_MIXER_IMIX }, | | 941 | { AudioNrecord, OSS_SOUND_MIXER_IMIX }, |
961 | { AudioNmaster, OSS_SOUND_MIXER_VOLUME }, | | 942 | { AudioNmaster, OSS_SOUND_MIXER_VOLUME }, |
962 | { AudioNtreble, OSS_SOUND_MIXER_TREBLE }, | | 943 | { AudioNtreble, OSS_SOUND_MIXER_TREBLE }, |
963 | { AudioNbass, OSS_SOUND_MIXER_BASS }, | | 944 | { AudioNbass, OSS_SOUND_MIXER_BASS }, |
964 | { AudioNspeaker, OSS_SOUND_MIXER_SPEAKER }, | | 945 | { AudioNspeaker, OSS_SOUND_MIXER_SPEAKER }, |
965 | /* { AudioNheadphone, ?? },*/ | | 946 | /* { AudioNheadphone, ?? },*/ |
966 | { AudioNoutput, OSS_SOUND_MIXER_OGAIN }, | | 947 | { AudioNoutput, OSS_SOUND_MIXER_OGAIN }, |
967 | { AudioNinput, OSS_SOUND_MIXER_IGAIN }, | | 948 | { AudioNinput, OSS_SOUND_MIXER_IGAIN }, |
968 | /* { AudioNmaster, OSS_SOUND_MIXER_SPEAKER },*/ | | 949 | /* { AudioNmaster, OSS_SOUND_MIXER_SPEAKER },*/ |
969 | /* { AudioNstereo, ?? },*/ | | 950 | /* { AudioNstereo, ?? },*/ |
970 | /* { AudioNmono, ?? },*/ | | 951 | /* { AudioNmono, ?? },*/ |
971 | { AudioNfmsynth, OSS_SOUND_MIXER_SYNTH }, | | 952 | { AudioNfmsynth, OSS_SOUND_MIXER_SYNTH }, |
972 | /* { AudioNwave, OSS_SOUND_MIXER_PCM },*/ | | 953 | /* { AudioNwave, OSS_SOUND_MIXER_PCM },*/ |
973 | { AudioNmidi, OSS_SOUND_MIXER_SYNTH }, | | 954 | { AudioNmidi, OSS_SOUND_MIXER_SYNTH }, |
974 | /* { AudioNmixerout, ?? },*/ | | 955 | /* { AudioNmixerout, ?? },*/ |
975 | { 0, -1 } | | 956 | { 0, -1 } |
976 | }; | | 957 | }; |
977 | int (*ioctlf)(file_t *, u_long, void *) = fp->f_ops->fo_ioctl; | | 958 | int (*ioctlf)(file_t *, u_long, void *) = fp->f_ops->fo_ioctl; |
978 | struct vnode *vp; | | 959 | struct vnode *vp; |
979 | struct vattr va; | | 960 | struct vattr va; |
980 | static struct audiodevinfo devcache; | | 961 | static struct audiodevinfo devcache; |
981 | struct audiodevinfo *di = &devcache; | | 962 | struct audiodevinfo *di = &devcache; |
982 | int error, mlen, dlen; | | 963 | int error, mlen, dlen; |
983 | | | 964 | |
984 | /* | | 965 | /* |
985 | * Figure out what device it is so we can check if the | | 966 | * Figure out what device it is so we can check if the |
986 | * cached data is valid. | | 967 | * cached data is valid. |
987 | */ | | 968 | */ |
988 | vp = fp->f_vnode; | | 969 | vp = fp->f_vnode; |
989 | if (vp->v_type != VCHR) | | 970 | if (vp->v_type != VCHR) |
990 | return 0; | | 971 | return 0; |
991 | vn_lock(vp, LK_SHARED | LK_RETRY); | | 972 | vn_lock(vp, LK_SHARED | LK_RETRY); |
992 | error = VOP_GETATTR(vp, &va, kauth_cred_get()); | | 973 | error = VOP_GETATTR(vp, &va, kauth_cred_get()); |
993 | VOP_UNLOCK(vp); | | 974 | VOP_UNLOCK(vp); |
994 | if (error) | | 975 | if (error) |
995 | return 0; | | 976 | return 0; |
996 | if (di->done && di->dev == va.va_rdev) | | 977 | if (di->done && di->dev == va.va_rdev) |
997 | return di; | | 978 | return di; |
998 | | | 979 | |
999 | di->done = 1; | | 980 | di->done = 1; |
1000 | di->dev = va.va_rdev; | | 981 | di->dev = va.va_rdev; |
1001 | di->devmask = 0; | | 982 | di->devmask = 0; |
1002 | di->recmask = 0; | | 983 | di->recmask = 0; |
1003 | di->stereomask = 0; | | 984 | di->stereomask = 0; |
1004 | di->source = ~0; | | 985 | di->source = ~0; |
1005 | di->caps = 0; | | 986 | di->caps = 0; |
1006 | for(i = 0; i < OSS_SOUND_MIXER_NRDEVICES; i++) | | 987 | for(i = 0; i < OSS_SOUND_MIXER_NRDEVICES; i++) |
1007 | di->devmap[i] = -1; | | 988 | di->devmap[i] = -1; |
1008 | for(i = 0; i < NETBSD_MAXDEVS; i++) { | | 989 | for(i = 0; i < NETBSD_MAXDEVS; i++) { |
1009 | di->rdevmap[i] = -1; | | 990 | di->rdevmap[i] = -1; |
1010 | di->names[i][0] = '\0'; | | 991 | di->names[i][0] = '\0'; |
1011 | di->enum2opaque[i] = -1; | | 992 | di->enum2opaque[i] = -1; |
1012 | } | | 993 | } |
1013 | for(i = 0; i < NETBSD_MAXDEVS; i++) { | | 994 | for(i = 0; i < NETBSD_MAXDEVS; i++) { |
1014 | mi.index = i; | | 995 | mi.index = i; |
1015 | if (ioctlf(fp, AUDIO_MIXER_DEVINFO, &mi) != 0) | | 996 | if (ioctlf(fp, AUDIO_MIXER_DEVINFO, &mi) != 0) |
1016 | break; | | 997 | break; |
1017 | switch(mi.type) { | | 998 | switch(mi.type) { |
1018 | case AUDIO_MIXER_VALUE: | | 999 | case AUDIO_MIXER_VALUE: |
1019 | for(dp = devs; dp->name; dp++) { | | 1000 | for(dp = devs; dp->name; dp++) { |
1020 | if (strcmp(dp->name, mi.label.name) == 0) | | 1001 | if (strcmp(dp->name, mi.label.name) == 0) |
1021 | break; | | 1002 | break; |
1022 | dlen = strlen(dp->name); | | 1003 | dlen = strlen(dp->name); |
1023 | mlen = strlen(mi.label.name); | | 1004 | mlen = strlen(mi.label.name); |
1024 | if (dlen < mlen | | 1005 | if (dlen < mlen |
1025 | && mi.label.name[mlen-dlen-1] == '.' | | 1006 | && mi.label.name[mlen-dlen-1] == '.' |
1026 | && strcmp(dp->name, mi.label.name + mlen - dlen) == 0) | | 1007 | && strcmp(dp->name, mi.label.name + mlen - dlen) == 0) |
1027 | break; | | 1008 | break; |
1028 | } | | 1009 | } |
1029 | if (dp->code >= 0) { | | 1010 | if (dp->code >= 0) { |
1030 | di->devmap[dp->code] = i; | | 1011 | di->devmap[dp->code] = i; |
1031 | di->rdevmap[i] = dp->code; | | 1012 | di->rdevmap[i] = dp->code; |
1032 | di->devmask |= 1 << dp->code; | | 1013 | di->devmask |= 1 << dp->code; |
1033 | if (mi.un.v.num_channels == 2) | | 1014 | if (mi.un.v.num_channels == 2) |
1034 | di->stereomask |= 1 << dp->code; | | 1015 | di->stereomask |= 1 << dp->code; |
1035 | strncpy(di->names[i], mi.label.name, | | 1016 | strncpy(di->names[i], mi.label.name, |
1036 | sizeof di->names[i]); | | 1017 | sizeof di->names[i]); |
1037 | } | | 1018 | } |
1038 | break; | | 1019 | break; |
1039 | } | | 1020 | } |
1040 | } | | 1021 | } |
1041 | for(i = 0; i < NETBSD_MAXDEVS; i++) { | | 1022 | for(i = 0; i < NETBSD_MAXDEVS; i++) { |
1042 | mi.index = i; | | 1023 | mi.index = i; |
1043 | if (ioctlf(fp, AUDIO_MIXER_DEVINFO, &mi) != 0) | | 1024 | if (ioctlf(fp, AUDIO_MIXER_DEVINFO, &mi) != 0) |
1044 | break; | | 1025 | break; |
1045 | if (strcmp(mi.label.name, AudioNsource) != 0) | | 1026 | if (strcmp(mi.label.name, AudioNsource) != 0) |
1046 | continue; | | 1027 | continue; |
1047 | di->source = i; | | 1028 | di->source = i; |
1048 | switch(mi.type) { | | 1029 | switch(mi.type) { |
1049 | case AUDIO_MIXER_ENUM: | | 1030 | case AUDIO_MIXER_ENUM: |
1050 | for(j = 0; j < mi.un.e.num_mem; j++) { | | 1031 | for(j = 0; j < mi.un.e.num_mem; j++) { |
1051 | e = opaque_to_enum(di, | | 1032 | e = opaque_to_enum(di, |
1052 | &mi.un.e.member[j].label, | | 1033 | &mi.un.e.member[j].label, |
1053 | mi.un.e.member[j].ord); | | 1034 | mi.un.e.member[j].ord); |
1054 | if (e >= 0) | | 1035 | if (e >= 0) |
1055 | di->recmask |= 1 << di->rdevmap[e]; | | 1036 | di->recmask |= 1 << di->rdevmap[e]; |
1056 | } | | 1037 | } |
1057 | di->caps = OSS_SOUND_CAP_EXCL_INPUT; | | 1038 | di->caps = OSS_SOUND_CAP_EXCL_INPUT; |
1058 | break; | | 1039 | break; |
1059 | case AUDIO_MIXER_SET: | | 1040 | case AUDIO_MIXER_SET: |
1060 | for(j = 0; j < mi.un.s.num_mem; j++) { | | 1041 | for(j = 0; j < mi.un.s.num_mem; j++) { |
1061 | e = opaque_to_enum(di, | | 1042 | e = opaque_to_enum(di, |
1062 | &mi.un.s.member[j].label, | | 1043 | &mi.un.s.member[j].label, |
1063 | mi.un.s.member[j].mask); | | 1044 | mi.un.s.member[j].mask); |
1064 | if (e >= 0) | | 1045 | if (e >= 0) |
1065 | di->recmask |= 1 << di->rdevmap[e]; | | 1046 | di->recmask |= 1 << di->rdevmap[e]; |
1066 | } | | 1047 | } |
1067 | break; | | 1048 | break; |
1068 | } | | 1049 | } |
1069 | } | | 1050 | } |
1070 | return di; | | 1051 | return di; |
1071 | } | | 1052 | } |
1072 | | | 1053 | |
1073 | int | | 1054 | int |
1074 | oss_ioctl_mixer(struct lwp *lwp, const struct oss_sys_ioctl_args *uap, register_t *retval) | | 1055 | oss_ioctl_mixer(struct lwp *lwp, const struct oss_sys_ioctl_args *uap, register_t *retval) |
1075 | { | | 1056 | { |
1076 | /* { | | 1057 | /* { |
1077 | syscallarg(int) fd; | | 1058 | syscallarg(int) fd; |
1078 | syscallarg(u_long) com; | | 1059 | syscallarg(u_long) com; |
1079 | syscallarg(void *) data; | | 1060 | syscallarg(void *) data; |
1080 | } */ | | 1061 | } */ |
1081 | file_t *fp; | | 1062 | file_t *fp; |
1082 | u_long com; | | 1063 | u_long com; |
1083 | struct audiodevinfo *di; | | 1064 | struct audiodevinfo *di; |
1084 | mixer_ctrl_t mc; | | 1065 | mixer_ctrl_t mc; |
1085 | struct oss_mixer_info omi; | | 1066 | struct oss_mixer_info omi; |
1086 | struct audio_device adev; | | 1067 | struct audio_device adev; |
1087 | int idat; | | 1068 | int idat; |
1088 | int i; | | 1069 | int i; |
1089 | int error; | | 1070 | int error; |
1090 | int l, r, n, e; | | 1071 | int l, r, n, e; |
1091 | int (*ioctlf)(file_t *, u_long, void *); | | 1072 | int (*ioctlf)(file_t *, u_long, void *); |
1092 | | | 1073 | |
1093 | if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) | | 1074 | if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) |
1094 | return error; | | 1075 | return error; |
1095 | | | 1076 | |
1096 | if ((fp->f_flag & (FREAD | FWRITE)) == 0) { | | 1077 | if ((fp->f_flag & (FREAD | FWRITE)) == 0) { |
1097 | error = EBADF; | | 1078 | error = EBADF; |
1098 | goto out; | | 1079 | goto out; |
1099 | } | | 1080 | } |
1100 | | | 1081 | |
1101 | com = SCARG(uap, com); | | 1082 | com = SCARG(uap, com); |
1102 | DPRINTF(("%s: com=%s\n", __func__, compat_ossaudio_getcmd(com))); | | 1083 | DPRINTF(("%s: com=%s\n", __func__, compat_ossaudio_getcmd(com))); |
1103 | | | 1084 | |
1104 | retval[0] = 0; | | 1085 | retval[0] = 0; |
1105 | | | 1086 | |
1106 | di = getdevinfo(fp); | | 1087 | di = getdevinfo(fp); |
1107 | if (di == 0) { | | 1088 | if (di == 0) { |
1108 | error = EINVAL; | | 1089 | error = EINVAL; |
1109 | goto out; | | 1090 | goto out; |
1110 | } | | 1091 | } |
1111 | | | 1092 | |
1112 | ioctlf = fp->f_ops->fo_ioctl; | | 1093 | ioctlf = fp->f_ops->fo_ioctl; |
1113 | switch (com) { | | 1094 | switch (com) { |
1114 | case OSS_GET_VERSION: | | 1095 | case OSS_GET_VERSION: |
1115 | idat = OSS_SOUND_VERSION; | | 1096 | idat = OSS_SOUND_VERSION; |
1116 | break; | | 1097 | break; |
1117 | case OSS_SOUND_MIXER_INFO: | | 1098 | case OSS_SOUND_MIXER_INFO: |
1118 | case OSS_SOUND_OLD_MIXER_INFO: | | 1099 | case OSS_SOUND_OLD_MIXER_INFO: |
1119 | error = ioctlf(fp, AUDIO_GETDEV, &adev); | | 1100 | error = ioctlf(fp, AUDIO_GETDEV, &adev); |
1120 | if (error) { | | 1101 | if (error) { |
1121 | DPRINTF(("%s: AUDIO_GETDEV %d\n", | | 1102 | DPRINTF(("%s: AUDIO_GETDEV %d\n", |
1122 | __func__, error)); | | 1103 | __func__, error)); |
1123 | goto out; | | 1104 | goto out; |
1124 | } | | 1105 | } |
1125 | omi.modify_counter = 1; | | 1106 | omi.modify_counter = 1; |
1126 | strncpy(omi.id, adev.name, sizeof omi.id); | | 1107 | strncpy(omi.id, adev.name, sizeof omi.id); |
1127 | strncpy(omi.name, adev.name, sizeof omi.name); | | 1108 | strncpy(omi.name, adev.name, sizeof omi.name); |
1128 | error = copyout(&omi, SCARG(uap, data), OSS_IOCTL_SIZE(com)); | | 1109 | error = copyout(&omi, SCARG(uap, data), OSS_IOCTL_SIZE(com)); |
1129 | if (error) { | | 1110 | if (error) { |
1130 | DPRINTF(("%s: OSS_SOUND_MIXER_INFO %d\n", | | 1111 | DPRINTF(("%s: OSS_SOUND_MIXER_INFO %d\n", |
1131 | __func__, error)); | | 1112 | __func__, error)); |
1132 | goto out; | | 1113 | goto out; |
1133 | } | | 1114 | } |
1134 | break; | | 1115 | break; |
1135 | case OSS_SOUND_MIXER_READ_RECSRC: | | 1116 | case OSS_SOUND_MIXER_READ_RECSRC: |
1136 | if (di->source == (u_long)-1) { | | 1117 | if (di->source == (u_long)-1) { |
1137 | DPRINTF(("%s: OSS_SOUND_MIXER_READ_RECSRC bad source\n", | | 1118 | DPRINTF(("%s: OSS_SOUND_MIXER_READ_RECSRC bad source\n", |
1138 | __func__)); | | 1119 | __func__)); |
1139 | error = EINVAL; | | 1120 | error = EINVAL; |
1140 | goto out; | | 1121 | goto out; |
1141 | } | | 1122 | } |
1142 | mc.dev = di->source; | | 1123 | mc.dev = di->source; |
1143 | if (di->caps & OSS_SOUND_CAP_EXCL_INPUT) { | | 1124 | if (di->caps & OSS_SOUND_CAP_EXCL_INPUT) { |
1144 | mc.type = AUDIO_MIXER_ENUM; | | 1125 | mc.type = AUDIO_MIXER_ENUM; |
1145 | error = ioctlf(fp, AUDIO_MIXER_READ, &mc); | | 1126 | error = ioctlf(fp, AUDIO_MIXER_READ, &mc); |
1146 | if (error) { | | 1127 | if (error) { |
1147 | DPRINTF(("%s: AUDIO_MIXER_READ %d\n", | | 1128 | DPRINTF(("%s: AUDIO_MIXER_READ %d\n", |
1148 | __func__, error)); | | 1129 | __func__, error)); |
1149 | goto out; | | 1130 | goto out; |
1150 | } | | 1131 | } |
1151 | e = opaque_to_enum(di, NULL, mc.un.ord); | | 1132 | e = opaque_to_enum(di, NULL, mc.un.ord); |
1152 | if (e >= 0) | | 1133 | if (e >= 0) |
1153 | idat = 1 << di->rdevmap[e]; | | 1134 | idat = 1 << di->rdevmap[e]; |
1154 | } else { | | 1135 | } else { |
1155 | mc.type = AUDIO_MIXER_SET; | | 1136 | mc.type = AUDIO_MIXER_SET; |
1156 | error = ioctlf(fp, AUDIO_MIXER_READ, &mc); | | 1137 | error = ioctlf(fp, AUDIO_MIXER_READ, &mc); |
1157 | if (error) { | | 1138 | if (error) { |
1158 | DPRINTF(("%s: AUDIO_MIXER_READ %d\n", | | 1139 | DPRINTF(("%s: AUDIO_MIXER_READ %d\n", |
1159 | __func__, error)); | | 1140 | __func__, error)); |
1160 | goto out; | | 1141 | goto out; |
1161 | } | | 1142 | } |
1162 | e = opaque_to_enum(di, NULL, mc.un.mask); | | 1143 | e = opaque_to_enum(di, NULL, mc.un.mask); |
1163 | if (e >= 0) | | 1144 | if (e >= 0) |
1164 | idat = 1 << di->rdevmap[e]; | | 1145 | idat = 1 << di->rdevmap[e]; |
1165 | } | | 1146 | } |
1166 | break; | | 1147 | break; |
1167 | case OSS_SOUND_MIXER_READ_DEVMASK: | | 1148 | case OSS_SOUND_MIXER_READ_DEVMASK: |
1168 | idat = di->devmask; | | 1149 | idat = di->devmask; |
1169 | break; | | 1150 | break; |
1170 | case OSS_SOUND_MIXER_READ_RECMASK: | | 1151 | case OSS_SOUND_MIXER_READ_RECMASK: |
1171 | idat = di->recmask; | | 1152 | idat = di->recmask; |
1172 | break; | | 1153 | break; |
1173 | case OSS_SOUND_MIXER_READ_STEREODEVS: | | 1154 | case OSS_SOUND_MIXER_READ_STEREODEVS: |
1174 | idat = di->stereomask; | | 1155 | idat = di->stereomask; |
1175 | break; | | 1156 | break; |
1176 | case OSS_SOUND_MIXER_READ_CAPS: | | 1157 | case OSS_SOUND_MIXER_READ_CAPS: |
1177 | idat = di->caps; | | 1158 | idat = di->caps; |
1178 | break; | | 1159 | break; |
1179 | case OSS_SOUND_MIXER_WRITE_RECSRC: | | 1160 | case OSS_SOUND_MIXER_WRITE_RECSRC: |
1180 | case OSS_SOUND_MIXER_WRITE_R_RECSRC: | | 1161 | case OSS_SOUND_MIXER_WRITE_R_RECSRC: |
1181 | if (di->source == (u_long)-1) { | | 1162 | if (di->source == (u_long)-1) { |
1182 | DPRINTF(("%s: OSS_SOUND_MIXER_WRITE_RECSRC bad " | | 1163 | DPRINTF(("%s: OSS_SOUND_MIXER_WRITE_RECSRC bad " |
1183 | "source\n", __func__)); | | 1164 | "source\n", __func__)); |
1184 | error = EINVAL; | | 1165 | error = EINVAL; |
1185 | goto out; | | 1166 | goto out; |
1186 | } | | 1167 | } |
1187 | mc.dev = di->source; | | 1168 | mc.dev = di->source; |
1188 | error = copyin(SCARG(uap, data), &idat, sizeof idat); | | 1169 | error = copyin(SCARG(uap, data), &idat, sizeof idat); |
1189 | if (error) { | | 1170 | if (error) { |
1190 | DPRINTF(("%s: OSS_SOUND_MIXER_WRITE_RECSRC %d\n", | | 1171 | DPRINTF(("%s: OSS_SOUND_MIXER_WRITE_RECSRC %d\n", |
1191 | __func__, error)); | | 1172 | __func__, error)); |
1192 | goto out; | | 1173 | goto out; |
1193 | } | | 1174 | } |
1194 | if (di->caps & OSS_SOUND_CAP_EXCL_INPUT) { | | 1175 | if (di->caps & OSS_SOUND_CAP_EXCL_INPUT) { |
1195 | mc.type = AUDIO_MIXER_ENUM; | | 1176 | mc.type = AUDIO_MIXER_ENUM; |
1196 | for(i = 0; i < OSS_SOUND_MIXER_NRDEVICES; i++) | | 1177 | for(i = 0; i < OSS_SOUND_MIXER_NRDEVICES; i++) |
1197 | if (idat & (1 << i)) | | 1178 | if (idat & (1 << i)) |
1198 | break; | | 1179 | break; |
1199 | if (i >= OSS_SOUND_MIXER_NRDEVICES || | | 1180 | if (i >= OSS_SOUND_MIXER_NRDEVICES || |
1200 | di->devmap[i] == -1) { | | 1181 | di->devmap[i] == -1) { |
1201 | error = EINVAL; | | 1182 | error = EINVAL; |
1202 | DPRINTF(("%s: OSS_SOUND_MIXER_WRITE_RECSRC " | | 1183 | DPRINTF(("%s: OSS_SOUND_MIXER_WRITE_RECSRC " |
1203 | "bad index %d\n", __func__, i)); | | 1184 | "bad index %d\n", __func__, i)); |
1204 | goto out; | | 1185 | goto out; |
1205 | } | | 1186 | } |
1206 | mc.un.ord = enum_to_ord(di, di->devmap[i]); | | 1187 | mc.un.ord = enum_to_ord(di, di->devmap[i]); |
1207 | } else { | | 1188 | } else { |
1208 | mc.type = AUDIO_MIXER_SET; | | 1189 | mc.type = AUDIO_MIXER_SET; |
1209 | mc.un.mask = 0; | | 1190 | mc.un.mask = 0; |
1210 | for(i = 0; i < OSS_SOUND_MIXER_NRDEVICES; i++) { | | 1191 | for(i = 0; i < OSS_SOUND_MIXER_NRDEVICES; i++) { |
1211 | if (idat & (1 << i)) { | | 1192 | if (idat & (1 << i)) { |
1212 | if (di->devmap[i] == -1) { | | 1193 | if (di->devmap[i] == -1) { |
1213 | DPRINTF(("%s: OSS_SOUND_MIXER_" | | 1194 | DPRINTF(("%s: OSS_SOUND_MIXER_" |
1214 | "WRITE_RECSRC bad devmap " | | 1195 | "WRITE_RECSRC bad devmap " |
1215 | "%d\n", __func__, i)); | | 1196 | "%d\n", __func__, i)); |
1216 | error = EINVAL; | | 1197 | error = EINVAL; |
1217 | goto out; | | 1198 | goto out; |
1218 | } | | 1199 | } |
1219 | mc.un.mask |= enum_to_mask(di, | | 1200 | mc.un.mask |= enum_to_mask(di, |
1220 | di->devmap[i]); | | 1201 | di->devmap[i]); |
1221 | } | | 1202 | } |
1222 | } | | 1203 | } |
1223 | } | | 1204 | } |
1224 | error = ioctlf(fp, AUDIO_MIXER_WRITE, &mc); | | 1205 | error = ioctlf(fp, AUDIO_MIXER_WRITE, &mc); |
1225 | if (error) { | | 1206 | if (error) { |
1226 | DPRINTF(("%s: AUDIO_MIXER_WRITE %d\n", | | 1207 | DPRINTF(("%s: AUDIO_MIXER_WRITE %d\n", |
1227 | __func__, error)); | | 1208 | __func__, error)); |
1228 | goto out; | | 1209 | goto out; |
1229 | } | | 1210 | } |
1230 | goto out; | | 1211 | goto out; |
1231 | default: | | 1212 | default: |
1232 | if (OSS_MIXER_READ(OSS_SOUND_MIXER_FIRST) <= com && | | 1213 | if (OSS_MIXER_READ(OSS_SOUND_MIXER_FIRST) <= com && |
1233 | com < OSS_MIXER_READ(OSS_SOUND_MIXER_NRDEVICES)) { | | 1214 | com < OSS_MIXER_READ(OSS_SOUND_MIXER_NRDEVICES)) { |
1234 | n = OSS_GET_DEV(com); | | 1215 | n = OSS_GET_DEV(com); |
1235 | if (di->devmap[n] == -1) { | | 1216 | if (di->devmap[n] == -1) { |
1236 | DPRINTF(("%s: 0x%lx bad devmap %d\n", | | 1217 | DPRINTF(("%s: 0x%lx bad devmap %d\n", |
1237 | __func__, com, n)); | | 1218 | __func__, com, n)); |
1238 | error = EINVAL; | | 1219 | error = EINVAL; |
1239 | goto out; | | 1220 | goto out; |
1240 | } | | 1221 | } |
1241 | doread: | | 1222 | doread: |
1242 | mc.dev = di->devmap[n]; | | 1223 | mc.dev = di->devmap[n]; |
1243 | mc.type = AUDIO_MIXER_VALUE; | | 1224 | mc.type = AUDIO_MIXER_VALUE; |
1244 | mc.un.value.num_channels = di->stereomask & | | 1225 | mc.un.value.num_channels = di->stereomask & |
1245 | (1 << n) ? 2 : 1; | | 1226 | (1 << n) ? 2 : 1; |
1246 | error = ioctlf(fp, AUDIO_MIXER_READ, &mc); | | 1227 | error = ioctlf(fp, AUDIO_MIXER_READ, &mc); |
1247 | if (error) { | | 1228 | if (error) { |
1248 | DPRINTF(("%s: AUDIO_MIXER_READ %d\n", | | 1229 | DPRINTF(("%s: AUDIO_MIXER_READ %d\n", |
1249 | __func__, error)); | | 1230 | __func__, error)); |
1250 | goto out; | | 1231 | goto out; |
1251 | } | | 1232 | } |
1252 | if (mc.un.value.num_channels != 2) { | | 1233 | if (mc.un.value.num_channels != 2) { |
1253 | l = r = | | 1234 | l = r = |
1254 | mc.un.value.level[AUDIO_MIXER_LEVEL_MONO]; | | 1235 | mc.un.value.level[AUDIO_MIXER_LEVEL_MONO]; |
1255 | } else { | | 1236 | } else { |
1256 | l = mc.un.value.level[AUDIO_MIXER_LEVEL_LEFT]; | | 1237 | l = mc.un.value.level[AUDIO_MIXER_LEVEL_LEFT]; |
1257 | r = mc.un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; | | 1238 | r = mc.un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; |
1258 | } | | 1239 | } |
1259 | idat = TO_OSSVOL(l) | (TO_OSSVOL(r) << 8); | | 1240 | idat = TO_OSSVOL(l) | (TO_OSSVOL(r) << 8); |
1260 | DPRINTF(("%s: n=%d (dev=%d) l=%d, r=%d, idat=%04x\n", | | 1241 | DPRINTF(("%s: n=%d (dev=%d) l=%d, r=%d, idat=%04x\n", |
1261 | __func__, n, di->devmap[n], l, r, idat)); | | 1242 | __func__, n, di->devmap[n], l, r, idat)); |
1262 | break; | | 1243 | break; |
1263 | } else if ((OSS_MIXER_WRITE_R(OSS_SOUND_MIXER_FIRST) <= com && | | 1244 | } else if ((OSS_MIXER_WRITE_R(OSS_SOUND_MIXER_FIRST) <= com && |
1264 | com < OSS_MIXER_WRITE_R(OSS_SOUND_MIXER_NRDEVICES)) || | | 1245 | com < OSS_MIXER_WRITE_R(OSS_SOUND_MIXER_NRDEVICES)) || |
1265 | (OSS_MIXER_WRITE(OSS_SOUND_MIXER_FIRST) <= com && | | 1246 | (OSS_MIXER_WRITE(OSS_SOUND_MIXER_FIRST) <= com && |
1266 | com < OSS_MIXER_WRITE(OSS_SOUND_MIXER_NRDEVICES))) { | | 1247 | com < OSS_MIXER_WRITE(OSS_SOUND_MIXER_NRDEVICES))) { |
1267 | n = OSS_GET_DEV(com); | | 1248 | n = OSS_GET_DEV(com); |
1268 | if (di->devmap[n] == -1) { | | 1249 | if (di->devmap[n] == -1) { |
1269 | DPRINTF(("%s: 0x%lx bad devmap %d\n", | | 1250 | DPRINTF(("%s: 0x%lx bad devmap %d\n", |
1270 | __func__, com, n)); | | 1251 | __func__, com, n)); |
1271 | error = EINVAL; | | 1252 | error = EINVAL; |
1272 | goto out; | | 1253 | goto out; |
1273 | } | | 1254 | } |
1274 | error = copyin(SCARG(uap, data), &idat, sizeof idat); | | 1255 | error = copyin(SCARG(uap, data), &idat, sizeof idat); |
1275 | if (error) { | | 1256 | if (error) { |
1276 | DPRINTF(("%s: 0x%lx error %d\n", | | 1257 | DPRINTF(("%s: 0x%lx error %d\n", |
1277 | __func__, com, error)); | | 1258 | __func__, com, error)); |
1278 | goto out; | | 1259 | goto out; |
1279 | } | | 1260 | } |
1280 | l = FROM_OSSVOL( idat & 0xff); | | 1261 | l = FROM_OSSVOL( idat & 0xff); |
1281 | r = FROM_OSSVOL((idat >> 8) & 0xff); | | 1262 | r = FROM_OSSVOL((idat >> 8) & 0xff); |
1282 | mc.dev = di->devmap[n]; | | 1263 | mc.dev = di->devmap[n]; |
1283 | mc.type = AUDIO_MIXER_VALUE; | | 1264 | mc.type = AUDIO_MIXER_VALUE; |
1284 | if (di->stereomask & (1 << n)) { | | 1265 | if (di->stereomask & (1 << n)) { |
1285 | mc.un.value.num_channels = 2; | | 1266 | mc.un.value.num_channels = 2; |
1286 | mc.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l; | | 1267 | mc.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l; |
1287 | mc.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r; | | 1268 | mc.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r; |
1288 | } else { | | 1269 | } else { |
1289 | mc.un.value.num_channels = 1; | | 1270 | mc.un.value.num_channels = 1; |
1290 | mc.un.value.level[AUDIO_MIXER_LEVEL_MONO] = | | 1271 | mc.un.value.level[AUDIO_MIXER_LEVEL_MONO] = |
1291 | (l + r) / 2; | | 1272 | (l + r) / 2; |
1292 | } | | 1273 | } |
1293 | DPRINTF(("%s: n=%d (dev=%d) l=%d, r=%d, idat=%04x\n", | | 1274 | DPRINTF(("%s: n=%d (dev=%d) l=%d, r=%d, idat=%04x\n", |
1294 | __func__, n, di->devmap[n], l, r, idat)); | | 1275 | __func__, n, di->devmap[n], l, r, idat)); |
1295 | error = ioctlf(fp, AUDIO_MIXER_WRITE, &mc); | | 1276 | error = ioctlf(fp, AUDIO_MIXER_WRITE, &mc); |
1296 | if (error) { | | 1277 | if (error) { |
1297 | DPRINTF(("%s: AUDIO_MIXER_WRITE %d\n", | | 1278 | DPRINTF(("%s: AUDIO_MIXER_WRITE %d\n", |
1298 | __func__, error)); | | 1279 | __func__, error)); |
1299 | goto out; | | 1280 | goto out; |
1300 | } | | 1281 | } |
1301 | if (OSS_MIXER_WRITE(OSS_SOUND_MIXER_FIRST) <= com && | | 1282 | if (OSS_MIXER_WRITE(OSS_SOUND_MIXER_FIRST) <= com && |
1302 | com < OSS_MIXER_WRITE(OSS_SOUND_MIXER_NRDEVICES)) { | | 1283 | com < OSS_MIXER_WRITE(OSS_SOUND_MIXER_NRDEVICES)) { |
1303 | error = 0; | | 1284 | error = 0; |
1304 | goto out; | | 1285 | goto out; |
1305 | } | | 1286 | } |
1306 | goto doread; | | 1287 | goto doread; |
1307 | } else { | | 1288 | } else { |
1308 | DPRINTF(("%s: Unknown mixer ioctl 0x%lx\n", __func__, | | 1289 | DPRINTF(("%s: Unknown mixer ioctl 0x%lx\n", __func__, |
1309 | com)); | | 1290 | com)); |
1310 | error = EINVAL; | | 1291 | error = EINVAL; |
1311 | goto out; | | 1292 | goto out; |
1312 | } | | 1293 | } |
1313 | } | | 1294 | } |
1314 | error = copyout(&idat, SCARG(uap, data), sizeof idat); | | 1295 | error = copyout(&idat, SCARG(uap, data), sizeof idat); |
1315 | out: | | 1296 | out: |
1316 | fd_putfile(SCARG(uap, fd)); | | 1297 | fd_putfile(SCARG(uap, fd)); |
1317 | return error; | | 1298 | return error; |
1318 | } | | 1299 | } |
1319 | | | 1300 | |
1320 | /* Sequencer emulation */ | | 1301 | /* Sequencer emulation */ |
1321 | int | | 1302 | int |
1322 | oss_ioctl_sequencer(struct lwp *l, const struct oss_sys_ioctl_args *uap, register_t *retval) | | 1303 | oss_ioctl_sequencer(struct lwp *l, const struct oss_sys_ioctl_args *uap, register_t *retval) |
1323 | { | | 1304 | { |
1324 | /* { | | 1305 | /* { |
1325 | syscallarg(int) fd; | | 1306 | syscallarg(int) fd; |
1326 | syscallarg(u_long) com; | | 1307 | syscallarg(u_long) com; |
1327 | syscallarg(void *) data; | | 1308 | syscallarg(void *) data; |
1328 | } */ | | 1309 | } */ |
1329 | file_t *fp; | | 1310 | file_t *fp; |
1330 | u_long com; | | 1311 | u_long com; |
1331 | int idat, idat1; | | 1312 | int idat, idat1; |
1332 | struct synth_info si; | | 1313 | struct synth_info si; |
1333 | struct oss_synth_info osi; | | 1314 | struct oss_synth_info osi; |
1334 | struct oss_seq_event_rec oser; | | 1315 | struct oss_seq_event_rec oser; |
1335 | int error; | | 1316 | int error; |
1336 | int (*ioctlf)(file_t *, u_long, void *); | | 1317 | int (*ioctlf)(file_t *, u_long, void *); |
1337 | | | 1318 | |
1338 | if ((fp = fd_getfile(SCARG(uap, fd))) == NULL) | | 1319 | if ((fp = fd_getfile(SCARG(uap, fd))) == NULL) |
1339 | return (EBADF); | | 1320 | return (EBADF); |
1340 | | | 1321 | |
1341 | if ((fp->f_flag & (FREAD | FWRITE)) == 0) { | | 1322 | if ((fp->f_flag & (FREAD | FWRITE)) == 0) { |
1342 | error = EBADF; | | 1323 | error = EBADF; |
1343 | goto out; | | 1324 | goto out; |
1344 | } | | 1325 | } |
1345 | | | 1326 | |
1346 | com = SCARG(uap, com); | | 1327 | com = SCARG(uap, com); |
1347 | DPRINTF(("%s: com=%s\n", __func__, compat_ossaudio_getcmd(com))); | | 1328 | DPRINTF(("%s: com=%s\n", __func__, compat_ossaudio_getcmd(com))); |
1348 | | | 1329 | |
1349 | retval[0] = 0; | | 1330 | retval[0] = 0; |
1350 | | | 1331 | |
1351 | ioctlf = fp->f_ops->fo_ioctl; | | 1332 | ioctlf = fp->f_ops->fo_ioctl; |
1352 | switch (com) { | | 1333 | switch (com) { |
1353 | case OSS_SEQ_RESET: | | 1334 | case OSS_SEQ_RESET: |
1354 | error = ioctlf(fp, SEQUENCER_RESET, &idat); | | 1335 | error = ioctlf(fp, SEQUENCER_RESET, &idat); |
1355 | goto out; | | 1336 | goto out; |
1356 | case OSS_SEQ_SYNC: | | 1337 | case OSS_SEQ_SYNC: |
1357 | error = ioctlf(fp, SEQUENCER_SYNC, &idat); | | 1338 | error = ioctlf(fp, SEQUENCER_SYNC, &idat); |
1358 | goto out; | | 1339 | goto out; |
1359 | case OSS_SYNTH_INFO: | | 1340 | case OSS_SYNTH_INFO: |
1360 | error = copyin(SCARG(uap, data), &osi, sizeof osi); | | 1341 | error = copyin(SCARG(uap, data), &osi, sizeof osi); |
1361 | if (error) | | 1342 | if (error) |
1362 | goto out; | | 1343 | goto out; |
1363 | si.device = osi.device; | | 1344 | si.device = osi.device; |
1364 | error = ioctlf(fp, SEQUENCER_INFO, &si); | | 1345 | error = ioctlf(fp, SEQUENCER_INFO, &si); |
1365 | if (error) | | 1346 | if (error) |
1366 | goto out; | | 1347 | goto out; |
1367 | strncpy(osi.name, si.name, sizeof osi.name); | | 1348 | strncpy(osi.name, si.name, sizeof osi.name); |
1368 | osi.device = si.device; | | 1349 | osi.device = si.device; |
1369 | switch(si.synth_type) { | | 1350 | switch(si.synth_type) { |
1370 | case SYNTH_TYPE_FM: | | 1351 | case SYNTH_TYPE_FM: |
1371 | osi.synth_type = OSS_SYNTH_TYPE_FM; break; | | 1352 | osi.synth_type = OSS_SYNTH_TYPE_FM; break; |
1372 | case SYNTH_TYPE_SAMPLE: | | 1353 | case SYNTH_TYPE_SAMPLE: |
1373 | osi.synth_type = OSS_SYNTH_TYPE_SAMPLE; break; | | 1354 | osi.synth_type = OSS_SYNTH_TYPE_SAMPLE; break; |
1374 | case SYNTH_TYPE_MIDI: | | 1355 | case SYNTH_TYPE_MIDI: |
1375 | osi.synth_type = OSS_SYNTH_TYPE_MIDI; break; | | 1356 | osi.synth_type = OSS_SYNTH_TYPE_MIDI; break; |
1376 | default: | | 1357 | default: |
1377 | osi.synth_type = 0; break; | | 1358 | osi.synth_type = 0; break; |
1378 | } | | 1359 | } |
1379 | switch(si.synth_subtype) { | | 1360 | switch(si.synth_subtype) { |
1380 | case SYNTH_SUB_FM_TYPE_ADLIB: | | 1361 | case SYNTH_SUB_FM_TYPE_ADLIB: |
1381 | osi.synth_subtype = OSS_FM_TYPE_ADLIB; break; | | 1362 | osi.synth_subtype = OSS_FM_TYPE_ADLIB; break; |
1382 | case SYNTH_SUB_FM_TYPE_OPL3: | | 1363 | case SYNTH_SUB_FM_TYPE_OPL3: |
1383 | osi.synth_subtype = OSS_FM_TYPE_OPL3; break; | | 1364 | osi.synth_subtype = OSS_FM_TYPE_OPL3; break; |
1384 | case SYNTH_SUB_MIDI_TYPE_MPU401: | | 1365 | case SYNTH_SUB_MIDI_TYPE_MPU401: |
1385 | osi.synth_subtype = OSS_MIDI_TYPE_MPU401; break; | | 1366 | osi.synth_subtype = OSS_MIDI_TYPE_MPU401; break; |
1386 | case SYNTH_SUB_SAMPLE_TYPE_BASIC: | | 1367 | case SYNTH_SUB_SAMPLE_TYPE_BASIC: |
1387 | osi.synth_subtype = OSS_SAMPLE_TYPE_BASIC; break; | | 1368 | osi.synth_subtype = OSS_SAMPLE_TYPE_BASIC; break; |
1388 | default: | | 1369 | default: |
1389 | osi.synth_subtype = 0; break; | | 1370 | osi.synth_subtype = 0; break; |
1390 | } | | 1371 | } |
1391 | osi.perc_mode = 0; | | 1372 | osi.perc_mode = 0; |
1392 | osi.nr_voices = si.nr_voices; | | 1373 | osi.nr_voices = si.nr_voices; |
1393 | osi.nr_drums = 0; | | 1374 | osi.nr_drums = 0; |
1394 | osi.instr_bank_size = si.instr_bank_size; | | 1375 | osi.instr_bank_size = si.instr_bank_size; |
1395 | osi.capabilities = 0; | | 1376 | osi.capabilities = 0; |
1396 | if (si.capabilities & SYNTH_CAP_OPL3) | | 1377 | if (si.capabilities & SYNTH_CAP_OPL3) |
1397 | osi.capabilities |= OSS_SYNTH_CAP_OPL3; | | 1378 | osi.capabilities |= OSS_SYNTH_CAP_OPL3; |
1398 | if (si.capabilities & SYNTH_CAP_INPUT) | | 1379 | if (si.capabilities & SYNTH_CAP_INPUT) |
1399 | osi.capabilities |= OSS_SYNTH_CAP_INPUT; | | 1380 | osi.capabilities |= OSS_SYNTH_CAP_INPUT; |
1400 | error = copyout(&osi, SCARG(uap, data), sizeof osi); | | 1381 | error = copyout(&osi, SCARG(uap, data), sizeof osi); |
1401 | goto out; | | 1382 | goto out; |
1402 | case OSS_SEQ_CTRLRATE: | | 1383 | case OSS_SEQ_CTRLRATE: |
1403 | error = copyin(SCARG(uap, data), &idat, sizeof idat); | | 1384 | error = copyin(SCARG(uap, data), &idat, sizeof idat); |
1404 | if (error) | | 1385 | if (error) |
1405 | goto out; | | 1386 | goto out; |
1406 | error = ioctlf(fp, SEQUENCER_CTRLRATE, &idat); | | 1387 | error = ioctlf(fp, SEQUENCER_CTRLRATE, &idat); |
1407 | if (error) | | 1388 | if (error) |
1408 | goto out; | | 1389 | goto out; |
1409 | retval[0] = idat; | | 1390 | retval[0] = idat; |
1410 | break; | | 1391 | break; |
1411 | case OSS_SEQ_GETOUTCOUNT: | | 1392 | case OSS_SEQ_GETOUTCOUNT: |
1412 | error = ioctlf(fp, SEQUENCER_GETOUTCOUNT, &idat); | | 1393 | error = ioctlf(fp, SEQUENCER_GETOUTCOUNT, &idat); |
1413 | if (error) | | 1394 | if (error) |
1414 | goto out; | | 1395 | goto out; |
1415 | retval[0] = idat; | | 1396 | retval[0] = idat; |
1416 | break; | | 1397 | break; |
1417 | case OSS_SEQ_GETINCOUNT: | | 1398 | case OSS_SEQ_GETINCOUNT: |
1418 | error = ioctlf(fp, SEQUENCER_GETINCOUNT, &idat); | | 1399 | error = ioctlf(fp, SEQUENCER_GETINCOUNT, &idat); |
1419 | if (error) | | 1400 | if (error) |
1420 | goto out; | | 1401 | goto out; |
1421 | retval[0] = idat; | | 1402 | retval[0] = idat; |
1422 | break; | | 1403 | break; |
1423 | case OSS_SEQ_NRSYNTHS: | | 1404 | case OSS_SEQ_NRSYNTHS: |
1424 | error = ioctlf(fp, SEQUENCER_NRSYNTHS, &idat); | | 1405 | error = ioctlf(fp, SEQUENCER_NRSYNTHS, &idat); |
1425 | if (error) | | 1406 | if (error) |
1426 | goto out; | | 1407 | goto out; |
1427 | retval[0] = idat; | | 1408 | retval[0] = idat; |
1428 | break; | | 1409 | break; |
1429 | case OSS_SEQ_NRMIDIS: | | 1410 | case OSS_SEQ_NRMIDIS: |
1430 | error = ioctlf(fp, SEQUENCER_NRMIDIS, &idat); | | 1411 | error = ioctlf(fp, SEQUENCER_NRMIDIS, &idat); |
1431 | if (error) | | 1412 | if (error) |
1432 | goto out; | | 1413 | goto out; |
1433 | retval[0] = idat; | | 1414 | retval[0] = idat; |
1434 | break; | | 1415 | break; |
1435 | case OSS_SEQ_THRESHOLD: | | 1416 | case OSS_SEQ_THRESHOLD: |
1436 | error = copyin(SCARG(uap, data), &idat, sizeof idat); | | 1417 | error = copyin(SCARG(uap, data), &idat, sizeof idat); |
1437 | if (error) | | 1418 | if (error) |
1438 | goto out; | | 1419 | goto out; |
1439 | error = ioctlf(fp, SEQUENCER_THRESHOLD, &idat); | | 1420 | error = ioctlf(fp, SEQUENCER_THRESHOLD, &idat); |
1440 | goto out; | | 1421 | goto out; |
1441 | case OSS_MEMAVL: | | 1422 | case OSS_MEMAVL: |
1442 | error = copyin(SCARG(uap, data), &idat, sizeof idat); | | 1423 | error = copyin(SCARG(uap, data), &idat, sizeof idat); |
1443 | if (error) | | 1424 | if (error) |
1444 | goto out; | | 1425 | goto out; |
1445 | error = ioctlf(fp, SEQUENCER_MEMAVL, &idat); | | 1426 | error = ioctlf(fp, SEQUENCER_MEMAVL, &idat); |
1446 | if (error) | | 1427 | if (error) |
1447 | goto out; | | 1428 | goto out; |
1448 | retval[0] = idat; | | 1429 | retval[0] = idat; |
1449 | break; | | 1430 | break; |
1450 | case OSS_SEQ_PANIC: | | 1431 | case OSS_SEQ_PANIC: |
1451 | error = ioctlf(fp, SEQUENCER_PANIC, &idat); | | 1432 | error = ioctlf(fp, SEQUENCER_PANIC, &idat); |
1452 | goto out; | | 1433 | goto out; |
1453 | case OSS_SEQ_OUTOFBAND: | | 1434 | case OSS_SEQ_OUTOFBAND: |
1454 | error = copyin(SCARG(uap, data), &oser, sizeof oser); | | 1435 | error = copyin(SCARG(uap, data), &oser, sizeof oser); |
1455 | if (error) | | 1436 | if (error) |
1456 | goto out; | | 1437 | goto out; |
1457 | error = ioctlf(fp, SEQUENCER_OUTOFBAND, &oser); | | 1438 | error = ioctlf(fp, SEQUENCER_OUTOFBAND, &oser); |
1458 | if (error) | | 1439 | if (error) |
1459 | goto out; | | 1440 | goto out; |
1460 | break; | | 1441 | break; |
1461 | case OSS_SEQ_GETTIME: | | 1442 | case OSS_SEQ_GETTIME: |
1462 | error = ioctlf(fp, SEQUENCER_GETTIME, &idat); | | 1443 | error = ioctlf(fp, SEQUENCER_GETTIME, &idat); |
1463 | if (error) | | 1444 | if (error) |
1464 | goto out; | | 1445 | goto out; |
1465 | retval[0] = idat; | | 1446 | retval[0] = idat; |
1466 | break; | | 1447 | break; |
1467 | case OSS_TMR_TIMEBASE: | | 1448 | case OSS_TMR_TIMEBASE: |
1468 | error = copyin(SCARG(uap, data), &idat, sizeof idat); | | 1449 | error = copyin(SCARG(uap, data), &idat, sizeof idat); |
1469 | if (error) | | 1450 | if (error) |
1470 | goto out; | | 1451 | goto out; |
1471 | error = ioctlf(fp, SEQUENCER_TMR_TIMEBASE, &idat); | | 1452 | error = ioctlf(fp, SEQUENCER_TMR_TIMEBASE, &idat); |
1472 | if (error) | | 1453 | if (error) |
1473 | goto out; | | 1454 | goto out; |
1474 | retval[0] = idat; | | 1455 | retval[0] = idat; |
1475 | break; | | 1456 | break; |
1476 | case OSS_TMR_START: | | 1457 | case OSS_TMR_START: |
1477 | error = ioctlf(fp, SEQUENCER_TMR_START, &idat); | | 1458 | error = ioctlf(fp, SEQUENCER_TMR_START, &idat); |
1478 | goto out; | | 1459 | goto out; |
1479 | case OSS_TMR_STOP: | | 1460 | case OSS_TMR_STOP: |
1480 | error = ioctlf(fp, SEQUENCER_TMR_STOP, &idat); | | 1461 | error = ioctlf(fp, SEQUENCER_TMR_STOP, &idat); |
1481 | goto out; | | 1462 | goto out; |
1482 | case OSS_TMR_CONTINUE: | | 1463 | case OSS_TMR_CONTINUE: |
1483 | error = ioctlf(fp, SEQUENCER_TMR_CONTINUE, &idat); | | 1464 | error = ioctlf(fp, SEQUENCER_TMR_CONTINUE, &idat); |
1484 | goto out; | | 1465 | goto out; |
1485 | case OSS_TMR_TEMPO: | | 1466 | case OSS_TMR_TEMPO: |
1486 | error = copyin(SCARG(uap, data), &idat, sizeof idat); | | 1467 | error = copyin(SCARG(uap, data), &idat, sizeof idat); |
1487 | if (error) | | 1468 | if (error) |
1488 | goto out; | | 1469 | goto out; |
1489 | error = ioctlf(fp, SEQUENCER_TMR_TEMPO, &idat); | | 1470 | error = ioctlf(fp, SEQUENCER_TMR_TEMPO, &idat); |
1490 | if (error) | | 1471 | if (error) |
1491 | goto out; | | 1472 | goto out; |
1492 | retval[0] = idat; | | 1473 | retval[0] = idat; |
1493 | break; | | 1474 | break; |
1494 | case OSS_TMR_SOURCE: | | 1475 | case OSS_TMR_SOURCE: |
1495 | error = copyin(SCARG(uap, data), &idat1, sizeof idat); | | 1476 | error = copyin(SCARG(uap, data), &idat1, sizeof idat); |
1496 | if (error) | | 1477 | if (error) |
1497 | goto out; | | 1478 | goto out; |
1498 | idat = 0; | | 1479 | idat = 0; |
1499 | if (idat1 & OSS_TMR_INTERNAL) idat |= SEQUENCER_TMR_INTERNAL; | | 1480 | if (idat1 & OSS_TMR_INTERNAL) idat |= SEQUENCER_TMR_INTERNAL; |
1500 | error = ioctlf(fp, SEQUENCER_TMR_SOURCE, &idat); | | 1481 | error = ioctlf(fp, SEQUENCER_TMR_SOURCE, &idat); |
1501 | if (error) | | 1482 | if (error) |
1502 | goto out; | | 1483 | goto out; |
1503 | idat1 = idat; | | 1484 | idat1 = idat; |
1504 | if (idat1 & SEQUENCER_TMR_INTERNAL) idat |= OSS_TMR_INTERNAL; | | 1485 | if (idat1 & SEQUENCER_TMR_INTERNAL) idat |= OSS_TMR_INTERNAL; |
1505 | retval[0] = idat; | | 1486 | retval[0] = idat; |
1506 | break; | | 1487 | break; |
1507 | case OSS_TMR_METRONOME: | | 1488 | case OSS_TMR_METRONOME: |
1508 | error = copyin(SCARG(uap, data), &idat, sizeof idat); | | 1489 | error = copyin(SCARG(uap, data), &idat, sizeof idat); |
1509 | if (error) | | 1490 | if (error) |
1510 | goto out; | | 1491 | goto out; |
1511 | error = ioctlf(fp, SEQUENCER_TMR_METRONOME, &idat); | | 1492 | error = ioctlf(fp, SEQUENCER_TMR_METRONOME, &idat); |
1512 | goto out; | | 1493 | goto out; |
1513 | case OSS_TMR_SELECT: | | 1494 | case OSS_TMR_SELECT: |
1514 | error = copyin(SCARG(uap, data), &idat, sizeof idat); | | 1495 | error = copyin(SCARG(uap, data), &idat, sizeof idat); |
1515 | if (error) | | 1496 | if (error) |
1516 | goto out; | | 1497 | goto out; |
1517 | retval[0] = idat; | | 1498 | retval[0] = idat; |
1518 | error = ioctlf(fp, SEQUENCER_TMR_SELECT, &idat); | | 1499 | error = ioctlf(fp, SEQUENCER_TMR_SELECT, &idat); |
1519 | goto out; | | 1500 | goto out; |
1520 | default: | | 1501 | default: |
1521 | DPRINTF(("%s: Unknown sequencer command 0x%lx\n", __func__, | | 1502 | DPRINTF(("%s: Unknown sequencer command 0x%lx\n", __func__, |
1522 | com)); | | 1503 | com)); |
1523 | error = EINVAL; | | 1504 | error = EINVAL; |
1524 | goto out; | | 1505 | goto out; |
1525 | } | | 1506 | } |
1526 | | | 1507 | |
1527 | error = copyout(&idat, SCARG(uap, data), sizeof idat); | | 1508 | error = copyout(&idat, SCARG(uap, data), sizeof idat); |
1528 | out: | | 1509 | out: |
1529 | fd_putfile(SCARG(uap, fd)); | | 1510 | fd_putfile(SCARG(uap, fd)); |
1530 | return error; | | 1511 | return error; |
1531 | } | | 1512 | } |
1532 | | | 1513 | |
1533 | /* | | 1514 | /* |
1534 | * When AUDIO_SETINFO fails to set a channel count, the application's chosen | | 1515 | * When AUDIO_SETINFO fails to set a channel count, the application's chosen |
1535 | * number is out of range of what the kernel allows. | | 1516 | * number is out of range of what the kernel allows. |
1536 | * | | 1517 | * |
1537 | * When this happens, we use the current hardware settings. This is just in | | 1518 | * When this happens, we use the current hardware settings. This is just in |
1538 | * case an application is abusing SNDCTL_DSP_CHANNELS - OSSv4 always sets and | | 1519 | * case an application is abusing SNDCTL_DSP_CHANNELS - OSSv4 always sets and |
1539 | * returns a reasonable value, even if it wasn't what the user requested. | | 1520 | * returns a reasonable value, even if it wasn't what the user requested. |
1540 | * | | 1521 | * |
1541 | * XXX: If a device is opened for both playback and recording, and supports | | 1522 | * XXX: If a device is opened for both playback and recording, and supports |
1542 | * fewer channels for recording than playback, applications that do both will | | 1523 | * fewer channels for recording than playback, applications that do both will |
1543 | * behave very strangely. OSS doesn't allow for reporting separate channel | | 1524 | * behave very strangely. OSS doesn't allow for reporting separate channel |
1544 | * counts for recording and playback. This could be worked around by always | | 1525 | * counts for recording and playback. This could be worked around by always |
1545 | * mixing recorded data up to the same number of channels as is being used | | 1526 | * mixing recorded data up to the same number of channels as is being used |
1546 | * for playback. | | 1527 | * for playback. |
1547 | */ | | 1528 | */ |
1548 | static void | | 1529 | static void |
1549 | setchannels(file_t *fp, int mode, int nchannels) | | 1530 | setchannels(file_t *fp, int mode, int nchannels) |
1550 | { | | 1531 | { |
1551 | struct audio_info tmpinfo, hwfmt; | | 1532 | struct audio_info tmpinfo, hwfmt; |
1552 | int (*ioctlf)(file_t *, u_long, void *); | | 1533 | int (*ioctlf)(file_t *, u_long, void *); |
1553 | | | 1534 | |
1554 | ioctlf = fp->f_ops->fo_ioctl; | | 1535 | ioctlf = fp->f_ops->fo_ioctl; |
1555 | | | 1536 | |
1556 | if (ioctlf(fp, AUDIO_GETFORMAT, &hwfmt) < 0) { | | 1537 | if (ioctlf(fp, AUDIO_GETFORMAT, &hwfmt) < 0) { |
1557 | hwfmt.record.channels = hwfmt.play.channels = 2; | | 1538 | hwfmt.record.channels = hwfmt.play.channels = 2; |
1558 | } | | 1539 | } |
1559 | | | 1540 | |
1560 | if (mode & AUMODE_PLAY) { | | 1541 | if (mode & AUMODE_PLAY) { |
1561 | AUDIO_INITINFO(&tmpinfo); | | 1542 | AUDIO_INITINFO(&tmpinfo); |
1562 | tmpinfo.play.channels = nchannels; | | 1543 | tmpinfo.play.channels = nchannels; |
1563 | if (ioctlf(fp, AUDIO_SETINFO, &tmpinfo) < 0) { | | 1544 | if (ioctlf(fp, AUDIO_SETINFO, &tmpinfo) < 0) { |
1564 | AUDIO_INITINFO(&tmpinfo); | | 1545 | AUDIO_INITINFO(&tmpinfo); |
1565 | tmpinfo.play.channels = hwfmt.play.channels; | | 1546 | tmpinfo.play.channels = hwfmt.play.channels; |
1566 | (void)ioctlf(fp, AUDIO_SETINFO, &tmpinfo); | | 1547 | (void)ioctlf(fp, AUDIO_SETINFO, &tmpinfo); |
1567 | } | | 1548 | } |
1568 | } | | 1549 | } |
1569 | | | 1550 | |
1570 | if (mode & AUMODE_RECORD) { | | 1551 | if (mode & AUMODE_RECORD) { |
1571 | AUDIO_INITINFO(&tmpinfo); | | 1552 | AUDIO_INITINFO(&tmpinfo); |
1572 | tmpinfo.record.channels = nchannels; | | 1553 | tmpinfo.record.channels = nchannels; |
1573 | if (ioctlf(fp, AUDIO_SETINFO, &tmpinfo) < 0) { | | 1554 | if (ioctlf(fp, AUDIO_SETINFO, &tmpinfo) < 0) { |
1574 | AUDIO_INITINFO(&tmpinfo); | | 1555 | AUDIO_INITINFO(&tmpinfo); |
1575 | tmpinfo.record.channels = hwfmt.record.channels; | | 1556 | tmpinfo.record.channels = hwfmt.record.channels; |
1576 | (void)ioctlf(fp, AUDIO_SETINFO, &tmpinfo); | | 1557 | (void)ioctlf(fp, AUDIO_SETINFO, &tmpinfo); |
1577 | } | | 1558 | } |
1578 | } | | 1559 | } |
1579 | } | | 1560 | } |
1580 | | | 1561 | |
1581 | /* | | 1562 | /* |
1582 | * Check that the blocksize is a power of 2 as OSS wants. | | 1563 | * Check that the blocksize is a power of 2 as OSS wants. |
1583 | * If not, set it to be. | | 1564 | * If not, set it to be. |
1584 | */ | | 1565 | */ |
1585 | static void | | 1566 | static void |
1586 | setblocksize(file_t *fp, struct audio_info *info) | | 1567 | setblocksize(file_t *fp, struct audio_info *info) |
1587 | { | | 1568 | { |
1588 | struct audio_info set; | | 1569 | struct audio_info set; |
1589 | u_int s; | | 1570 | u_int s; |
1590 | | | 1571 | |
1591 | if (info->blocksize & (info->blocksize - 1)) { | | 1572 | if (info->blocksize & (info->blocksize - 1)) { |
1592 | for(s = 32; s < info->blocksize; s <<= 1) | | 1573 | for(s = 32; s < info->blocksize; s <<= 1) |
1593 | continue; | | 1574 | continue; |
1594 | AUDIO_INITINFO(&set); | | 1575 | AUDIO_INITINFO(&set); |
1595 | set.blocksize = s; | | 1576 | set.blocksize = s; |
1596 | fp->f_ops->fo_ioctl(fp, AUDIO_SETINFO, &set); | | 1577 | fp->f_ops->fo_ioctl(fp, AUDIO_SETINFO, &set); |
1597 | fp->f_ops->fo_ioctl(fp, AUDIO_GETBUFINFO, info); | | 1578 | fp->f_ops->fo_ioctl(fp, AUDIO_GETBUFINFO, info); |
1598 | } | | 1579 | } |
1599 | } | | 1580 | } |