Tue Nov 3 08:24:33 2020 UTC ()
ossaudio(3): return correctly initialized return value in unlikely
error case. pointed out by tnn.


(nia)
diff -r1.59 -r1.60 src/lib/libossaudio/ossaudio.c

cvs diff -r1.59 -r1.60 src/lib/libossaudio/Attic/ossaudio.c (switch to unified diff)

--- src/lib/libossaudio/Attic/ossaudio.c 2020/10/30 21:44:49 1.59
+++ src/lib/libossaudio/Attic/ossaudio.c 2020/11/03 08:24:33 1.60
@@ -1,1191 +1,1191 @@ @@ -1,1191 +1,1191 @@
1/* $NetBSD: ossaudio.c,v 1.59 2020/10/30 21:44:49 nia Exp $ */ 1/* $NetBSD: ossaudio.c,v 1.60 2020/11/03 08:24:33 nia Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 1997, 2020 The NetBSD Foundation, Inc. 4 * Copyright (c) 1997, 2020 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__RCSID("$NetBSD: ossaudio.c,v 1.59 2020/10/30 21:44:49 nia Exp $"); 30__RCSID("$NetBSD: ossaudio.c,v 1.60 2020/11/03 08:24:33 nia Exp $");
31 31
32/* 32/*
33 * This is an Open Sound System compatibility layer, which provides 33 * This is an Open Sound System compatibility layer, which provides
34 * fairly complete ioctl emulation for OSSv3 and some of OSSv4. 34 * fairly complete ioctl emulation for OSSv3 and some of OSSv4.
35 * 35 *
36 * The canonical OSS specification is available at 36 * The canonical OSS specification is available at
37 * http://manuals.opensound.com/developer/ 37 * http://manuals.opensound.com/developer/
38 *  38 *
39 * This file is similar to sys/compat/ossaudio.c with additional OSSv4 39 * This file is similar to sys/compat/ossaudio.c with additional OSSv4
40 * compatibility. 40 * compatibility.
41 */ 41 */
42 42
43#include <string.h> 43#include <string.h>
44#include <sys/types.h> 44#include <sys/types.h>
45#include <sys/ioctl.h> 45#include <sys/ioctl.h>
46#include <sys/audioio.h> 46#include <sys/audioio.h>
47#include <sys/stat.h> 47#include <sys/stat.h>
48#include <errno.h> 48#include <errno.h>
49#include <fcntl.h> 49#include <fcntl.h>
50#include <stdio.h> 50#include <stdio.h>
51#include <unistd.h> 51#include <unistd.h>
52#include <limits.h> 52#include <limits.h>
53#include <stdarg.h> 53#include <stdarg.h>
54#include <stdbool.h> 54#include <stdbool.h>
55 55
56#include "soundcard.h" 56#include "soundcard.h"
57#undef ioctl 57#undef ioctl
58 58
59#define GET_DEV(com) ((com) & 0xff) 59#define GET_DEV(com) ((com) & 0xff)
60 60
61#define TO_OSSVOL(x) (((x) * 100 + 127) / 255) 61#define TO_OSSVOL(x) (((x) * 100 + 127) / 255)
62#define FROM_OSSVOL(x) ((((x) > 100 ? 100 : (x)) * 255 + 50) / 100) 62#define FROM_OSSVOL(x) ((((x) > 100 ? 100 : (x)) * 255 + 50) / 100)
63 63
64#define GETPRINFO(info, name) \ 64#define GETPRINFO(info, name) \
65 (((info)->mode == AUMODE_RECORD) \ 65 (((info)->mode == AUMODE_RECORD) \
66 ? (info)->record.name : (info)->play.name) 66 ? (info)->record.name : (info)->play.name)
67 67
68static struct audiodevinfo *getdevinfo(int); 68static struct audiodevinfo *getdevinfo(int);
69 69
70static int getaudiocount(void); 70static int getaudiocount(void);
71static int getmixercount(void); 71static int getmixercount(void);
72static int getmixercontrolcount(int); 72static int getmixercontrolcount(int);
73 73
74static int getvol(u_int, u_char); 74static int getvol(u_int, u_char);
75static void setvol(int, int, bool); 75static void setvol(int, int, bool);
76 76
77static void setchannels(int, int, int); 77static void setchannels(int, int, int);
78static void setblocksize(int, struct audio_info *); 78static void setblocksize(int, struct audio_info *);
79 79
80static int audio_ioctl(int, unsigned long, void *); 80static int audio_ioctl(int, unsigned long, void *);
81static int mixer_oss3_ioctl(int, unsigned long, void *); 81static int mixer_oss3_ioctl(int, unsigned long, void *);
82static int mixer_oss4_ioctl(int, unsigned long, void *); 82static int mixer_oss4_ioctl(int, unsigned long, void *);
83static int global_oss4_ioctl(int, unsigned long, void *); 83static int global_oss4_ioctl(int, unsigned long, void *);
84static int opaque_to_enum(struct audiodevinfo *, audio_mixer_name_t *, int); 84static int opaque_to_enum(struct audiodevinfo *, audio_mixer_name_t *, int);
85static int enum_to_ord(struct audiodevinfo *, int); 85static int enum_to_ord(struct audiodevinfo *, int);
86static int enum_to_mask(struct audiodevinfo *, int); 86static int enum_to_mask(struct audiodevinfo *, int);
87 87
88#define INTARG (*(int*)argp) 88#define INTARG (*(int*)argp)
89 89
90int 90int
91_oss_ioctl(int fd, unsigned long com, ...) 91_oss_ioctl(int fd, unsigned long com, ...)
92{ 92{
93 va_list ap; 93 va_list ap;
94 void *argp; 94 void *argp;
95 95
96 va_start(ap, com); 96 va_start(ap, com);
97 argp = va_arg(ap, void *); 97 argp = va_arg(ap, void *);
98 va_end(ap); 98 va_end(ap);
99 99
100 if (IOCGROUP(com) == 'P') 100 if (IOCGROUP(com) == 'P')
101 return audio_ioctl(fd, com, argp); 101 return audio_ioctl(fd, com, argp);
102 else if (IOCGROUP(com) == 'M') 102 else if (IOCGROUP(com) == 'M')
103 return mixer_oss3_ioctl(fd, com, argp); 103 return mixer_oss3_ioctl(fd, com, argp);
104 else if (IOCGROUP(com) == 'X') 104 else if (IOCGROUP(com) == 'X')
105 return mixer_oss4_ioctl(fd, com, argp); 105 return mixer_oss4_ioctl(fd, com, argp);
106 else if (IOCGROUP(com) == 'Y') 106 else if (IOCGROUP(com) == 'Y')
107 return global_oss4_ioctl(fd, com, argp); 107 return global_oss4_ioctl(fd, com, argp);
108 else 108 else
109 return ioctl(fd, com, argp); 109 return ioctl(fd, com, argp);
110} 110}
111 111
112static int 112static int
113audio_ioctl(int fd, unsigned long com, void *argp) 113audio_ioctl(int fd, unsigned long com, void *argp)
114{ 114{
115 115
116 struct audio_info tmpinfo, hwfmt; 116 struct audio_info tmpinfo, hwfmt;
117 struct audio_offset tmpoffs; 117 struct audio_offset tmpoffs;
118 struct audio_buf_info bufinfo; 118 struct audio_buf_info bufinfo;
119 struct audio_errinfo *tmperrinfo; 119 struct audio_errinfo *tmperrinfo;
120 struct count_info cntinfo; 120 struct count_info cntinfo;
121 struct audio_encoding tmpenc; 121 struct audio_encoding tmpenc;
122 u_int u; 122 u_int u;
123 u_int encoding; 123 u_int encoding;
124 u_int precision; 124 u_int precision;
125 int perrors, rerrors; 125 int perrors, rerrors;
126 static int totalperrors = 0; 126 static int totalperrors = 0;
127 static int totalrerrors = 0; 127 static int totalrerrors = 0;
128 oss_count_t osscount; 128 oss_count_t osscount;
129 int idat, idata; 129 int idat, idata;
130 int retval; 130 int retval;
131 131
132 idat = 0; 132 idat = 0;
133 133
134 switch (com) { 134 switch (com) {
135 case SNDCTL_DSP_RESET: 135 case SNDCTL_DSP_RESET:
136 retval = ioctl(fd, AUDIO_FLUSH, 0); 136 retval = ioctl(fd, AUDIO_FLUSH, 0);
137 if (retval < 0) 137 if (retval < 0)
138 return retval; 138 return retval;
139 break; 139 break;
140 case SNDCTL_DSP_SYNC: 140 case SNDCTL_DSP_SYNC:
141 retval = ioctl(fd, AUDIO_DRAIN, 0); 141 retval = ioctl(fd, AUDIO_DRAIN, 0);
142 if (retval < 0) 142 if (retval < 0)
143 return retval; 143 return retval;
144 break; 144 break;
145 case SNDCTL_DSP_GETERROR: 145 case SNDCTL_DSP_GETERROR:
146 tmperrinfo = (struct audio_errinfo *)argp; 146 tmperrinfo = (struct audio_errinfo *)argp;
147 if (tmperrinfo == NULL) 147 if (tmperrinfo == NULL)
148 return EINVAL; 148 return EINVAL;
149 memset(tmperrinfo, 0, sizeof(struct audio_errinfo)); 149 memset(tmperrinfo, 0, sizeof(struct audio_errinfo));
150 if ((retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo)) < 0) 150 if ((retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo)) < 0)
151 return retval; 151 return retval;
152 /* 152 /*
153 * OSS requires that we return counters that are relative to 153 * OSS requires that we return counters that are relative to
154 * the last call. We must maintain state here... 154 * the last call. We must maintain state here...
155 */ 155 */
156 if (ioctl(fd, AUDIO_PERROR, &perrors) != -1) { 156 if (ioctl(fd, AUDIO_PERROR, &perrors) != -1) {
157 perrors /= ((tmpinfo.play.precision / NBBY) * 157 perrors /= ((tmpinfo.play.precision / NBBY) *
158 tmpinfo.play.channels); 158 tmpinfo.play.channels);
159 tmperrinfo->play_underruns = 159 tmperrinfo->play_underruns =
160 (perrors / tmpinfo.blocksize) - totalperrors; 160 (perrors / tmpinfo.blocksize) - totalperrors;
161 totalperrors += tmperrinfo->play_underruns; 161 totalperrors += tmperrinfo->play_underruns;
162 } 162 }
163 if (ioctl(fd, AUDIO_RERROR, &rerrors) != -1) { 163 if (ioctl(fd, AUDIO_RERROR, &rerrors) != -1) {
164 rerrors /= ((tmpinfo.record.precision / NBBY) * 164 rerrors /= ((tmpinfo.record.precision / NBBY) *
165 tmpinfo.record.channels); 165 tmpinfo.record.channels);
166 tmperrinfo->rec_overruns = 166 tmperrinfo->rec_overruns =
167 (rerrors / tmpinfo.blocksize) - totalrerrors; 167 (rerrors / tmpinfo.blocksize) - totalrerrors;
168 totalrerrors += tmperrinfo->rec_overruns; 168 totalrerrors += tmperrinfo->rec_overruns;
169 } 169 }
170 break; 170 break;
171 case SNDCTL_DSP_COOKEDMODE: 171 case SNDCTL_DSP_COOKEDMODE:
172 /* 172 /*
173 * NetBSD is always running in "cooked mode" - the kernel 173 * NetBSD is always running in "cooked mode" - the kernel
174 * always performs format conversions. 174 * always performs format conversions.
175 */ 175 */
176 INTARG = 1; 176 INTARG = 1;
177 break; 177 break;
178 case SNDCTL_DSP_POST: 178 case SNDCTL_DSP_POST:
179 /* This call is merely advisory, and may be a nop. */ 179 /* This call is merely advisory, and may be a nop. */
180 break; 180 break;
181 case SNDCTL_DSP_SPEED: 181 case SNDCTL_DSP_SPEED:
182 AUDIO_INITINFO(&tmpinfo); 182 AUDIO_INITINFO(&tmpinfo);
183 /* Conform to kernel limits. */ 183 /* Conform to kernel limits. */
184 if (INTARG < 1000) 184 if (INTARG < 1000)
185 INTARG = 1000; 185 INTARG = 1000;
186 if (INTARG > 192000) 186 if (INTARG > 192000)
187 INTARG = 192000; 187 INTARG = 192000;
188 tmpinfo.play.sample_rate = 188 tmpinfo.play.sample_rate =
189 tmpinfo.record.sample_rate = INTARG; 189 tmpinfo.record.sample_rate = INTARG;
190 if (ioctl(fd, AUDIO_SETINFO, &tmpinfo) < 0) { 190 retval = ioctl(fd, AUDIO_SETINFO, &tmpinfo);
 191 if (retval < 0)
191 return retval; 192 return retval;
192 } 
193 /* FALLTHRU */ 193 /* FALLTHRU */
194 case SOUND_PCM_READ_RATE: 194 case SOUND_PCM_READ_RATE:
195 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 195 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
196 if (retval < 0) 196 if (retval < 0)
197 return retval; 197 return retval;
198 INTARG = GETPRINFO(&tmpinfo, sample_rate); 198 INTARG = GETPRINFO(&tmpinfo, sample_rate);
199 break; 199 break;
200 case SNDCTL_DSP_STEREO: 200 case SNDCTL_DSP_STEREO:
201 AUDIO_INITINFO(&tmpinfo); 201 AUDIO_INITINFO(&tmpinfo);
202 tmpinfo.play.channels = 202 tmpinfo.play.channels =
203 tmpinfo.record.channels = INTARG ? 2 : 1; 203 tmpinfo.record.channels = INTARG ? 2 : 1;
204 (void) ioctl(fd, AUDIO_SETINFO, &tmpinfo); 204 (void) ioctl(fd, AUDIO_SETINFO, &tmpinfo);
205 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 205 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
206 if (retval < 0) 206 if (retval < 0)
207 return retval; 207 return retval;
208 INTARG = GETPRINFO(&tmpinfo, channels) - 1; 208 INTARG = GETPRINFO(&tmpinfo, channels) - 1;
209 break; 209 break;
210 case SNDCTL_DSP_GETBLKSIZE: 210 case SNDCTL_DSP_GETBLKSIZE:
211 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 211 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
212 if (retval < 0) 212 if (retval < 0)
213 return retval; 213 return retval;
214 setblocksize(fd, &tmpinfo); 214 setblocksize(fd, &tmpinfo);
215 INTARG = tmpinfo.blocksize; 215 INTARG = tmpinfo.blocksize;
216 break; 216 break;
217 case SNDCTL_DSP_SETFMT: 217 case SNDCTL_DSP_SETFMT:
218 AUDIO_INITINFO(&tmpinfo); 218 AUDIO_INITINFO(&tmpinfo);
219 switch (INTARG) { 219 switch (INTARG) {
220 case AFMT_MU_LAW: 220 case AFMT_MU_LAW:
221 tmpinfo.play.precision = 221 tmpinfo.play.precision =
222 tmpinfo.record.precision = 8; 222 tmpinfo.record.precision = 8;
223 tmpinfo.play.encoding = 223 tmpinfo.play.encoding =
224 tmpinfo.record.encoding = AUDIO_ENCODING_ULAW; 224 tmpinfo.record.encoding = AUDIO_ENCODING_ULAW;
225 break; 225 break;
226 case AFMT_A_LAW: 226 case AFMT_A_LAW:
227 tmpinfo.play.precision = 227 tmpinfo.play.precision =
228 tmpinfo.record.precision = 8; 228 tmpinfo.record.precision = 8;
229 tmpinfo.play.encoding = 229 tmpinfo.play.encoding =
230 tmpinfo.record.encoding = AUDIO_ENCODING_ALAW; 230 tmpinfo.record.encoding = AUDIO_ENCODING_ALAW;
231 break; 231 break;
232 case AFMT_U8: 232 case AFMT_U8:
233 tmpinfo.play.precision = 233 tmpinfo.play.precision =
234 tmpinfo.record.precision = 8; 234 tmpinfo.record.precision = 8;
235 tmpinfo.play.encoding = 235 tmpinfo.play.encoding =
236 tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR; 236 tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR;
237 break; 237 break;
238 case AFMT_S8: 238 case AFMT_S8:
239 tmpinfo.play.precision = 239 tmpinfo.play.precision =
240 tmpinfo.record.precision = 8; 240 tmpinfo.record.precision = 8;
241 tmpinfo.play.encoding = 241 tmpinfo.play.encoding =
242 tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR; 242 tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR;
243 break; 243 break;
244 case AFMT_S16_LE: 244 case AFMT_S16_LE:
245 tmpinfo.play.precision = 245 tmpinfo.play.precision =
246 tmpinfo.record.precision = 16; 246 tmpinfo.record.precision = 16;
247 tmpinfo.play.encoding = 247 tmpinfo.play.encoding =
248 tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_LE; 248 tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_LE;
249 break; 249 break;
250 case AFMT_S16_BE: 250 case AFMT_S16_BE:
251 tmpinfo.play.precision = 251 tmpinfo.play.precision =
252 tmpinfo.record.precision = 16; 252 tmpinfo.record.precision = 16;
253 tmpinfo.play.encoding = 253 tmpinfo.play.encoding =
254 tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_BE; 254 tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_BE;
255 break; 255 break;
256 case AFMT_U16_LE: 256 case AFMT_U16_LE:
257 tmpinfo.play.precision = 257 tmpinfo.play.precision =
258 tmpinfo.record.precision = 16; 258 tmpinfo.record.precision = 16;
259 tmpinfo.play.encoding = 259 tmpinfo.play.encoding =
260 tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR_LE; 260 tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR_LE;
261 break; 261 break;
262 case AFMT_U16_BE: 262 case AFMT_U16_BE:
263 tmpinfo.play.precision = 263 tmpinfo.play.precision =
264 tmpinfo.record.precision = 16; 264 tmpinfo.record.precision = 16;
265 tmpinfo.play.encoding = 265 tmpinfo.play.encoding =
266 tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR_BE; 266 tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR_BE;
267 break; 267 break;
268 /* 268 /*
269 * XXX: When the kernel supports 24-bit LPCM by default, 269 * XXX: When the kernel supports 24-bit LPCM by default,
270 * the 24-bit formats should be handled properly instead 270 * the 24-bit formats should be handled properly instead
271 * of falling back to 32 bits. 271 * of falling back to 32 bits.
272 */ 272 */
273 case AFMT_S24_LE: 273 case AFMT_S24_LE:
274 case AFMT_S32_LE: 274 case AFMT_S32_LE:
275 tmpinfo.play.precision = 275 tmpinfo.play.precision =
276 tmpinfo.record.precision = 32; 276 tmpinfo.record.precision = 32;
277 tmpinfo.play.encoding = 277 tmpinfo.play.encoding =
278 tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_LE; 278 tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_LE;
279 break; 279 break;
280 case AFMT_S24_BE: 280 case AFMT_S24_BE:
281 case AFMT_S32_BE: 281 case AFMT_S32_BE:
282 tmpinfo.play.precision = 282 tmpinfo.play.precision =
283 tmpinfo.record.precision = 32; 283 tmpinfo.record.precision = 32;
284 tmpinfo.play.encoding = 284 tmpinfo.play.encoding =
285 tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_BE; 285 tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_BE;
286 break; 286 break;
287 case AFMT_AC3: 287 case AFMT_AC3:
288 tmpinfo.play.precision = 288 tmpinfo.play.precision =
289 tmpinfo.record.precision = 16; 289 tmpinfo.record.precision = 16;
290 tmpinfo.play.encoding = 290 tmpinfo.play.encoding =
291 tmpinfo.record.encoding = AUDIO_ENCODING_AC3; 291 tmpinfo.record.encoding = AUDIO_ENCODING_AC3;
292 break; 292 break;
293 default: 293 default:
294 /* 294 /*
295 * OSSv4 specifies that if an invalid format is chosen 295 * OSSv4 specifies that if an invalid format is chosen
296 * by an application then a sensible format supported 296 * by an application then a sensible format supported
297 * by the hardware is returned. 297 * by the hardware is returned.
298 * 298 *
299 * In this case, we pick the current hardware format. 299 * In this case, we pick the current hardware format.
300 */ 300 */
301 retval = ioctl(fd, AUDIO_GETFORMAT, &hwfmt); 301 retval = ioctl(fd, AUDIO_GETFORMAT, &hwfmt);
302 if (retval < 0) 302 if (retval < 0)
303 return retval; 303 return retval;
304 retval = ioctl(fd, AUDIO_GETINFO, &tmpinfo); 304 retval = ioctl(fd, AUDIO_GETINFO, &tmpinfo);
305 if (retval < 0) 305 if (retval < 0)
306 return retval; 306 return retval;
307 tmpinfo.play.encoding = 307 tmpinfo.play.encoding =
308 tmpinfo.record.encoding = 308 tmpinfo.record.encoding =
309 (tmpinfo.mode == AUMODE_RECORD) ? 309 (tmpinfo.mode == AUMODE_RECORD) ?
310 hwfmt.record.encoding : hwfmt.play.encoding; 310 hwfmt.record.encoding : hwfmt.play.encoding;
311 tmpinfo.play.precision = 311 tmpinfo.play.precision =
312 tmpinfo.record.precision = 312 tmpinfo.record.precision =
313 (tmpinfo.mode == AUMODE_RECORD) ? 313 (tmpinfo.mode == AUMODE_RECORD) ?
314 hwfmt.record.precision : hwfmt.play.precision ; 314 hwfmt.record.precision : hwfmt.play.precision ;
315 break; 315 break;
316 } 316 }
317 /* 317 /*
318 * In the post-kernel-mixer world, assume that any error means 318 * In the post-kernel-mixer world, assume that any error means
319 * it's fatal rather than an unsupported format being selected. 319 * it's fatal rather than an unsupported format being selected.
320 */ 320 */
321 retval = ioctl(fd, AUDIO_SETINFO, &tmpinfo); 321 retval = ioctl(fd, AUDIO_SETINFO, &tmpinfo);
322 if (retval < 0) 322 if (retval < 0)
323 return retval; 323 return retval;
324 /* FALLTHRU */ 324 /* FALLTHRU */
325 case SOUND_PCM_READ_BITS: 325 case SOUND_PCM_READ_BITS:
326 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 326 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
327 if (retval < 0) 327 if (retval < 0)
328 return retval; 328 return retval;
329 encoding = GETPRINFO(&tmpinfo, encoding); 329 encoding = GETPRINFO(&tmpinfo, encoding);
330 precision = GETPRINFO(&tmpinfo, precision); 330 precision = GETPRINFO(&tmpinfo, precision);
331 switch (encoding) { 331 switch (encoding) {
332 case AUDIO_ENCODING_ULAW: 332 case AUDIO_ENCODING_ULAW:
333 idat = AFMT_MU_LAW; 333 idat = AFMT_MU_LAW;
334 break; 334 break;
335 case AUDIO_ENCODING_ALAW: 335 case AUDIO_ENCODING_ALAW:
336 idat = AFMT_A_LAW; 336 idat = AFMT_A_LAW;
337 break; 337 break;
338 case AUDIO_ENCODING_SLINEAR_LE: 338 case AUDIO_ENCODING_SLINEAR_LE:
339 if (precision == 32) 339 if (precision == 32)
340 idat = AFMT_S32_LE; 340 idat = AFMT_S32_LE;
341 else if (precision == 24) 341 else if (precision == 24)
342 idat = AFMT_S24_LE; 342 idat = AFMT_S24_LE;
343 else if (precision == 16) 343 else if (precision == 16)
344 idat = AFMT_S16_LE; 344 idat = AFMT_S16_LE;
345 else 345 else
346 idat = AFMT_S8; 346 idat = AFMT_S8;
347 break; 347 break;
348 case AUDIO_ENCODING_SLINEAR_BE: 348 case AUDIO_ENCODING_SLINEAR_BE:
349 if (precision == 32) 349 if (precision == 32)
350 idat = AFMT_S32_BE; 350 idat = AFMT_S32_BE;
351 else if (precision == 24) 351 else if (precision == 24)
352 idat = AFMT_S24_BE; 352 idat = AFMT_S24_BE;
353 else if (precision == 16) 353 else if (precision == 16)
354 idat = AFMT_S16_BE; 354 idat = AFMT_S16_BE;
355 else 355 else
356 idat = AFMT_S8; 356 idat = AFMT_S8;
357 break; 357 break;
358 case AUDIO_ENCODING_ULINEAR_LE: 358 case AUDIO_ENCODING_ULINEAR_LE:
359 if (precision == 16) 359 if (precision == 16)
360 idat = AFMT_U16_LE; 360 idat = AFMT_U16_LE;
361 else 361 else
362 idat = AFMT_U8; 362 idat = AFMT_U8;
363 break; 363 break;
364 case AUDIO_ENCODING_ULINEAR_BE: 364 case AUDIO_ENCODING_ULINEAR_BE:
365 if (precision == 16) 365 if (precision == 16)
366 idat = AFMT_U16_BE; 366 idat = AFMT_U16_BE;
367 else 367 else
368 idat = AFMT_U8; 368 idat = AFMT_U8;
369 break; 369 break;
370 case AUDIO_ENCODING_ADPCM: 370 case AUDIO_ENCODING_ADPCM:
371 idat = AFMT_IMA_ADPCM; 371 idat = AFMT_IMA_ADPCM;
372 break; 372 break;
373 case AUDIO_ENCODING_AC3: 373 case AUDIO_ENCODING_AC3:
374 idat = AFMT_AC3; 374 idat = AFMT_AC3;
375 break; 375 break;
376 } 376 }
377 INTARG = idat; 377 INTARG = idat;
378 break; 378 break;
379 case SNDCTL_DSP_CHANNELS: 379 case SNDCTL_DSP_CHANNELS:
380 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 380 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
381 if (retval < 0) 381 if (retval < 0)
382 return retval; 382 return retval;
383 setchannels(fd, tmpinfo.mode, INTARG); 383 setchannels(fd, tmpinfo.mode, INTARG);
384 /* FALLTHRU */ 384 /* FALLTHRU */
385 case SOUND_PCM_READ_CHANNELS: 385 case SOUND_PCM_READ_CHANNELS:
386 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 386 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
387 if (retval < 0) 387 if (retval < 0)
388 return retval; 388 return retval;
389 INTARG = GETPRINFO(&tmpinfo, channels); 389 INTARG = GETPRINFO(&tmpinfo, channels);
390 break; 390 break;
391 case SOUND_PCM_WRITE_FILTER: 391 case SOUND_PCM_WRITE_FILTER:
392 case SOUND_PCM_READ_FILTER: 392 case SOUND_PCM_READ_FILTER:
393 errno = EINVAL; 393 errno = EINVAL;
394 return -1; /* XXX unimplemented */ 394 return -1; /* XXX unimplemented */
395 case SNDCTL_DSP_SUBDIVIDE: 395 case SNDCTL_DSP_SUBDIVIDE:
396 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 396 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
397 if (retval < 0) 397 if (retval < 0)
398 return retval; 398 return retval;
399 setblocksize(fd, &tmpinfo); 399 setblocksize(fd, &tmpinfo);
400 idat = INTARG; 400 idat = INTARG;
401 if (idat == 0) 401 if (idat == 0)
402 idat = tmpinfo.play.buffer_size / tmpinfo.blocksize; 402 idat = tmpinfo.play.buffer_size / tmpinfo.blocksize;
403 idat = (tmpinfo.play.buffer_size / idat) & -4; 403 idat = (tmpinfo.play.buffer_size / idat) & -4;
404 AUDIO_INITINFO(&tmpinfo); 404 AUDIO_INITINFO(&tmpinfo);
405 tmpinfo.blocksize = idat; 405 tmpinfo.blocksize = idat;
406 retval = ioctl(fd, AUDIO_SETINFO, &tmpinfo); 406 retval = ioctl(fd, AUDIO_SETINFO, &tmpinfo);
407 if (retval < 0) 407 if (retval < 0)
408 return retval; 408 return retval;
409 INTARG = tmpinfo.play.buffer_size / tmpinfo.blocksize; 409 INTARG = tmpinfo.play.buffer_size / tmpinfo.blocksize;
410 break; 410 break;
411 case SNDCTL_DSP_SETFRAGMENT: 411 case SNDCTL_DSP_SETFRAGMENT:
412 AUDIO_INITINFO(&tmpinfo); 412 AUDIO_INITINFO(&tmpinfo);
413 idat = INTARG; 413 idat = INTARG;
414 if ((idat & 0xffff) < 4 || (idat & 0xffff) > 17) 414 if ((idat & 0xffff) < 4 || (idat & 0xffff) > 17)
415 return EINVAL; 415 return EINVAL;
416 tmpinfo.blocksize = 1 << (idat & 0xffff); 416 tmpinfo.blocksize = 1 << (idat & 0xffff);
417 tmpinfo.hiwat = ((unsigned)idat >> 16) & 0x7fff; 417 tmpinfo.hiwat = ((unsigned)idat >> 16) & 0x7fff;
418 if (tmpinfo.hiwat == 0) /* 0 means set to max */ 418 if (tmpinfo.hiwat == 0) /* 0 means set to max */
419 tmpinfo.hiwat = 65536; 419 tmpinfo.hiwat = 65536;
420 (void) ioctl(fd, AUDIO_SETINFO, &tmpinfo); 420 (void) ioctl(fd, AUDIO_SETINFO, &tmpinfo);
421 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 421 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
422 if (retval < 0) 422 if (retval < 0)
423 return retval; 423 return retval;
424 u = tmpinfo.blocksize; 424 u = tmpinfo.blocksize;
425 for(idat = 0; u > 1; idat++, u >>= 1) 425 for(idat = 0; u > 1; idat++, u >>= 1)
426 ; 426 ;
427 idat |= (tmpinfo.hiwat & 0x7fff) << 16; 427 idat |= (tmpinfo.hiwat & 0x7fff) << 16;
428 INTARG = idat; 428 INTARG = idat;
429 break; 429 break;
430 case SNDCTL_DSP_GETFMTS: 430 case SNDCTL_DSP_GETFMTS:
431 for(idat = 0, tmpenc.index = 0; 431 for(idat = 0, tmpenc.index = 0;
432 ioctl(fd, AUDIO_GETENC, &tmpenc) == 0; 432 ioctl(fd, AUDIO_GETENC, &tmpenc) == 0;
433 tmpenc.index++) { 433 tmpenc.index++) {
434 switch(tmpenc.encoding) { 434 switch(tmpenc.encoding) {
435 case AUDIO_ENCODING_ULAW: 435 case AUDIO_ENCODING_ULAW:
436 idat |= AFMT_MU_LAW; 436 idat |= AFMT_MU_LAW;
437 break; 437 break;
438 case AUDIO_ENCODING_ALAW: 438 case AUDIO_ENCODING_ALAW:
439 idat |= AFMT_A_LAW; 439 idat |= AFMT_A_LAW;
440 break; 440 break;
441 case AUDIO_ENCODING_SLINEAR: 441 case AUDIO_ENCODING_SLINEAR:
442 idat |= AFMT_S8; 442 idat |= AFMT_S8;
443 break; 443 break;
444 case AUDIO_ENCODING_SLINEAR_LE: 444 case AUDIO_ENCODING_SLINEAR_LE:
445 if (tmpenc.precision == 32) 445 if (tmpenc.precision == 32)
446 idat |= AFMT_S32_LE; 446 idat |= AFMT_S32_LE;
447 else if (tmpenc.precision == 24) 447 else if (tmpenc.precision == 24)
448 idat |= AFMT_S24_LE; 448 idat |= AFMT_S24_LE;
449 else if (tmpenc.precision == 16) 449 else if (tmpenc.precision == 16)
450 idat |= AFMT_S16_LE; 450 idat |= AFMT_S16_LE;
451 else 451 else
452 idat |= AFMT_S8; 452 idat |= AFMT_S8;
453 break; 453 break;
454 case AUDIO_ENCODING_SLINEAR_BE: 454 case AUDIO_ENCODING_SLINEAR_BE:
455 if (tmpenc.precision == 32) 455 if (tmpenc.precision == 32)
456 idat |= AFMT_S32_BE; 456 idat |= AFMT_S32_BE;
457 else if (tmpenc.precision == 24) 457 else if (tmpenc.precision == 24)
458 idat |= AFMT_S24_BE; 458 idat |= AFMT_S24_BE;
459 else if (tmpenc.precision == 16) 459 else if (tmpenc.precision == 16)
460 idat |= AFMT_S16_BE; 460 idat |= AFMT_S16_BE;
461 else 461 else
462 idat |= AFMT_S8; 462 idat |= AFMT_S8;
463 break; 463 break;
464 case AUDIO_ENCODING_ULINEAR: 464 case AUDIO_ENCODING_ULINEAR:
465 idat |= AFMT_U8; 465 idat |= AFMT_U8;
466 break; 466 break;
467 case AUDIO_ENCODING_ULINEAR_LE: 467 case AUDIO_ENCODING_ULINEAR_LE:
468 if (tmpenc.precision == 16) 468 if (tmpenc.precision == 16)
469 idat |= AFMT_U16_LE; 469 idat |= AFMT_U16_LE;
470 else 470 else
471 idat |= AFMT_U8; 471 idat |= AFMT_U8;
472 break; 472 break;
473 case AUDIO_ENCODING_ULINEAR_BE: 473 case AUDIO_ENCODING_ULINEAR_BE:
474 if (tmpenc.precision == 16) 474 if (tmpenc.precision == 16)
475 idat |= AFMT_U16_BE; 475 idat |= AFMT_U16_BE;
476 else 476 else
477 idat |= AFMT_U8; 477 idat |= AFMT_U8;
478 break; 478 break;
479 case AUDIO_ENCODING_ADPCM: 479 case AUDIO_ENCODING_ADPCM:
480 idat |= AFMT_IMA_ADPCM; 480 idat |= AFMT_IMA_ADPCM;
481 break; 481 break;
482 case AUDIO_ENCODING_AC3: 482 case AUDIO_ENCODING_AC3:
483 idat |= AFMT_AC3; 483 idat |= AFMT_AC3;
484 break; 484 break;
485 default: 485 default:
486 break; 486 break;
487 } 487 }
488 } 488 }
489 INTARG = idat; 489 INTARG = idat;
490 break; 490 break;
491 case SNDCTL_DSP_GETOSPACE: 491 case SNDCTL_DSP_GETOSPACE:
492 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 492 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
493 if (retval < 0) 493 if (retval < 0)
494 return retval; 494 return retval;
495 setblocksize(fd, &tmpinfo); 495 setblocksize(fd, &tmpinfo);
496 bufinfo.fragsize = tmpinfo.blocksize; 496 bufinfo.fragsize = tmpinfo.blocksize;
497 bufinfo.fragments = tmpinfo.hiwat - (tmpinfo.play.seek 497 bufinfo.fragments = tmpinfo.hiwat - (tmpinfo.play.seek
498 + tmpinfo.blocksize - 1) / tmpinfo.blocksize; 498 + tmpinfo.blocksize - 1) / tmpinfo.blocksize;
499 bufinfo.fragstotal = tmpinfo.hiwat; 499 bufinfo.fragstotal = tmpinfo.hiwat;
500 bufinfo.bytes = tmpinfo.hiwat * tmpinfo.blocksize 500 bufinfo.bytes = tmpinfo.hiwat * tmpinfo.blocksize
501 - tmpinfo.play.seek; 501 - tmpinfo.play.seek;
502 *(struct audio_buf_info *)argp = bufinfo; 502 *(struct audio_buf_info *)argp = bufinfo;
503 break; 503 break;
504 case SNDCTL_DSP_GETISPACE: 504 case SNDCTL_DSP_GETISPACE:
505 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 505 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
506 if (retval < 0) 506 if (retval < 0)
507 return retval; 507 return retval;
508 setblocksize(fd, &tmpinfo); 508 setblocksize(fd, &tmpinfo);
509 bufinfo.fragsize = tmpinfo.blocksize; 509 bufinfo.fragsize = tmpinfo.blocksize;
510 bufinfo.fragments = tmpinfo.record.seek / tmpinfo.blocksize; 510 bufinfo.fragments = tmpinfo.record.seek / tmpinfo.blocksize;
511 bufinfo.fragstotal = 511 bufinfo.fragstotal =
512 tmpinfo.record.buffer_size / tmpinfo.blocksize; 512 tmpinfo.record.buffer_size / tmpinfo.blocksize;
513 bufinfo.bytes = tmpinfo.record.seek; 513 bufinfo.bytes = tmpinfo.record.seek;
514 *(struct audio_buf_info *)argp = bufinfo; 514 *(struct audio_buf_info *)argp = bufinfo;
515 break; 515 break;
516 case SNDCTL_DSP_NONBLOCK: 516 case SNDCTL_DSP_NONBLOCK:
517 idat = 1; 517 idat = 1;
518 retval = ioctl(fd, FIONBIO, &idat); 518 retval = ioctl(fd, FIONBIO, &idat);
519 if (retval < 0) 519 if (retval < 0)
520 return retval; 520 return retval;
521 break; 521 break;
522 case SNDCTL_DSP_GETCAPS: 522 case SNDCTL_DSP_GETCAPS:
523 retval = ioctl(fd, AUDIO_GETPROPS, &idata); 523 retval = ioctl(fd, AUDIO_GETPROPS, &idata);
524 if (retval < 0) 524 if (retval < 0)
525 return retval; 525 return retval;
526 idat = DSP_CAP_TRIGGER; 526 idat = DSP_CAP_TRIGGER;
527 if (idata & AUDIO_PROP_FULLDUPLEX) 527 if (idata & AUDIO_PROP_FULLDUPLEX)
528 idat |= DSP_CAP_DUPLEX; 528 idat |= DSP_CAP_DUPLEX;
529 if (idata & AUDIO_PROP_MMAP) 529 if (idata & AUDIO_PROP_MMAP)
530 idat |= DSP_CAP_MMAP; 530 idat |= DSP_CAP_MMAP;
531 INTARG = idat; 531 INTARG = idat;
532 break; 532 break;
533 case SNDCTL_DSP_SETTRIGGER: 533 case SNDCTL_DSP_SETTRIGGER:
534 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 534 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
535 if (retval < 0) 535 if (retval < 0)
536 return retval; 536 return retval;
537 AUDIO_INITINFO(&tmpinfo); 537 AUDIO_INITINFO(&tmpinfo);
538 if (tmpinfo.mode & AUMODE_PLAY) 538 if (tmpinfo.mode & AUMODE_PLAY)
539 tmpinfo.play.pause = (INTARG & PCM_ENABLE_OUTPUT) == 0; 539 tmpinfo.play.pause = (INTARG & PCM_ENABLE_OUTPUT) == 0;
540 if (tmpinfo.mode & AUMODE_RECORD) 540 if (tmpinfo.mode & AUMODE_RECORD)
541 tmpinfo.record.pause = (INTARG & PCM_ENABLE_INPUT) == 0; 541 tmpinfo.record.pause = (INTARG & PCM_ENABLE_INPUT) == 0;
542 (void)ioctl(fd, AUDIO_SETINFO, &tmpinfo); 542 (void)ioctl(fd, AUDIO_SETINFO, &tmpinfo);
543 /* FALLTHRU */ 543 /* FALLTHRU */
544 case SNDCTL_DSP_GETTRIGGER: 544 case SNDCTL_DSP_GETTRIGGER:
545 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 545 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
546 if (retval < 0) 546 if (retval < 0)
547 return retval; 547 return retval;
548 idat = 0; 548 idat = 0;
549 if ((tmpinfo.mode & AUMODE_PLAY) && !tmpinfo.play.pause) 549 if ((tmpinfo.mode & AUMODE_PLAY) && !tmpinfo.play.pause)
550 idat |= PCM_ENABLE_OUTPUT; 550 idat |= PCM_ENABLE_OUTPUT;
551 if ((tmpinfo.mode & AUMODE_RECORD) && !tmpinfo.record.pause) 551 if ((tmpinfo.mode & AUMODE_RECORD) && !tmpinfo.record.pause)
552 idat |= PCM_ENABLE_INPUT; 552 idat |= PCM_ENABLE_INPUT;
553 INTARG = idat; 553 INTARG = idat;
554 break; 554 break;
555 case SNDCTL_DSP_GETIPTR: 555 case SNDCTL_DSP_GETIPTR:
556 retval = ioctl(fd, AUDIO_GETIOFFS, &tmpoffs); 556 retval = ioctl(fd, AUDIO_GETIOFFS, &tmpoffs);
557 if (retval < 0) 557 if (retval < 0)
558 return retval; 558 return retval;
559 cntinfo.bytes = tmpoffs.samples; 559 cntinfo.bytes = tmpoffs.samples;
560 cntinfo.blocks = tmpoffs.deltablks; 560 cntinfo.blocks = tmpoffs.deltablks;
561 cntinfo.ptr = tmpoffs.offset; 561 cntinfo.ptr = tmpoffs.offset;
562 *(struct count_info *)argp = cntinfo; 562 *(struct count_info *)argp = cntinfo;
563 break; 563 break;
564 case SNDCTL_DSP_CURRENT_IPTR: 564 case SNDCTL_DSP_CURRENT_IPTR:
565 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 565 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
566 if (retval < 0) 566 if (retval < 0)
567 return retval; 567 return retval;
568 /* XXX: 'samples' may wrap */ 568 /* XXX: 'samples' may wrap */
569 memset(osscount.filler, 0, sizeof(osscount.filler)); 569 memset(osscount.filler, 0, sizeof(osscount.filler));
570 osscount.samples = tmpinfo.record.samples / 570 osscount.samples = tmpinfo.record.samples /
571 ((tmpinfo.record.precision / NBBY) * 571 ((tmpinfo.record.precision / NBBY) *
572 tmpinfo.record.channels); 572 tmpinfo.record.channels);
573 osscount.fifo_samples = tmpinfo.record.seek / 573 osscount.fifo_samples = tmpinfo.record.seek /
574 ((tmpinfo.record.precision / NBBY) * 574 ((tmpinfo.record.precision / NBBY) *
575 tmpinfo.record.channels); 575 tmpinfo.record.channels);
576 *(oss_count_t *)argp = osscount; 576 *(oss_count_t *)argp = osscount;
577 break; 577 break;
578 case SNDCTL_DSP_GETOPTR: 578 case SNDCTL_DSP_GETOPTR:
579 retval = ioctl(fd, AUDIO_GETOOFFS, &tmpoffs); 579 retval = ioctl(fd, AUDIO_GETOOFFS, &tmpoffs);
580 if (retval < 0) 580 if (retval < 0)
581 return retval; 581 return retval;
582 cntinfo.bytes = tmpoffs.samples; 582 cntinfo.bytes = tmpoffs.samples;
583 cntinfo.blocks = tmpoffs.deltablks; 583 cntinfo.blocks = tmpoffs.deltablks;
584 cntinfo.ptr = tmpoffs.offset; 584 cntinfo.ptr = tmpoffs.offset;
585 *(struct count_info *)argp = cntinfo; 585 *(struct count_info *)argp = cntinfo;
586 break; 586 break;
587 case SNDCTL_DSP_CURRENT_OPTR: 587 case SNDCTL_DSP_CURRENT_OPTR:
588 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 588 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
589 if (retval < 0) 589 if (retval < 0)
590 return retval; 590 return retval;
591 /* XXX: 'samples' may wrap */ 591 /* XXX: 'samples' may wrap */
592 memset(osscount.filler, 0, sizeof(osscount.filler)); 592 memset(osscount.filler, 0, sizeof(osscount.filler));
593 osscount.samples = tmpinfo.play.samples / 593 osscount.samples = tmpinfo.play.samples /
594 ((tmpinfo.play.precision / NBBY) * 594 ((tmpinfo.play.precision / NBBY) *
595 tmpinfo.play.channels); 595 tmpinfo.play.channels);
596 osscount.fifo_samples = tmpinfo.play.seek / 596 osscount.fifo_samples = tmpinfo.play.seek /
597 ((tmpinfo.play.precision / NBBY) * 597 ((tmpinfo.play.precision / NBBY) *
598 tmpinfo.play.channels); 598 tmpinfo.play.channels);
599 *(oss_count_t *)argp = osscount; 599 *(oss_count_t *)argp = osscount;
600 break; 600 break;
601 case SNDCTL_DSP_SETPLAYVOL: 601 case SNDCTL_DSP_SETPLAYVOL:
602 setvol(fd, INTARG, false); 602 setvol(fd, INTARG, false);
603 /* FALLTHRU */ 603 /* FALLTHRU */
604 case SNDCTL_DSP_GETPLAYVOL: 604 case SNDCTL_DSP_GETPLAYVOL:
605 retval = ioctl(fd, AUDIO_GETINFO, &tmpinfo); 605 retval = ioctl(fd, AUDIO_GETINFO, &tmpinfo);
606 if (retval < 0) 606 if (retval < 0)
607 return retval; 607 return retval;
608 INTARG = getvol(tmpinfo.play.gain, tmpinfo.play.balance); 608 INTARG = getvol(tmpinfo.play.gain, tmpinfo.play.balance);
609 break; 609 break;
610 case SNDCTL_DSP_SETRECVOL: 610 case SNDCTL_DSP_SETRECVOL:
611 setvol(fd, INTARG, true); 611 setvol(fd, INTARG, true);
612 /* FALLTHRU */ 612 /* FALLTHRU */
613 case SNDCTL_DSP_GETRECVOL: 613 case SNDCTL_DSP_GETRECVOL:
614 retval = ioctl(fd, AUDIO_GETINFO, &tmpinfo); 614 retval = ioctl(fd, AUDIO_GETINFO, &tmpinfo);
615 if (retval < 0) 615 if (retval < 0)
616 return retval; 616 return retval;
617 INTARG = getvol(tmpinfo.record.gain, tmpinfo.record.balance); 617 INTARG = getvol(tmpinfo.record.gain, tmpinfo.record.balance);
618 break; 618 break;
619 case SNDCTL_DSP_SKIP: 619 case SNDCTL_DSP_SKIP:
620 case SNDCTL_DSP_SILENCE: 620 case SNDCTL_DSP_SILENCE:
621 return EINVAL; 621 return EINVAL;
622 case SNDCTL_DSP_SETDUPLEX: 622 case SNDCTL_DSP_SETDUPLEX:
623 idat = 1; 623 idat = 1;
624 retval = ioctl(fd, AUDIO_SETFD, &idat); 624 retval = ioctl(fd, AUDIO_SETFD, &idat);
625 if (retval < 0) 625 if (retval < 0)
626 return retval; 626 return retval;
627 break; 627 break;
628 case SNDCTL_DSP_GETODELAY: 628 case SNDCTL_DSP_GETODELAY:
629 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 629 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
630 if (retval < 0) 630 if (retval < 0)
631 return retval; 631 return retval;
632 idat = tmpinfo.play.seek + tmpinfo.blocksize / 2; 632 idat = tmpinfo.play.seek + tmpinfo.blocksize / 2;
633 INTARG = idat; 633 INTARG = idat;
634 break; 634 break;
635 case SNDCTL_DSP_PROFILE: 635 case SNDCTL_DSP_PROFILE:
636 /* This gives just a hint to the driver, 636 /* This gives just a hint to the driver,
637 * implementing it as a NOP is ok 637 * implementing it as a NOP is ok
638 */  638 */
639 break; 639 break;
640 case SNDCTL_DSP_MAPINBUF: 640 case SNDCTL_DSP_MAPINBUF:
641 case SNDCTL_DSP_MAPOUTBUF: 641 case SNDCTL_DSP_MAPOUTBUF:
642 case SNDCTL_DSP_SETSYNCRO: 642 case SNDCTL_DSP_SETSYNCRO:
643 errno = EINVAL; 643 errno = EINVAL;
644 return -1; /* XXX unimplemented */ 644 return -1; /* XXX unimplemented */
645 default: 645 default:
646 errno = EINVAL; 646 errno = EINVAL;
647 return -1; 647 return -1;
648 } 648 }
649 649
650 return 0; 650 return 0;
651} 651}
652 652
653 653
654/* If the NetBSD mixer device should have more than NETBSD_MAXDEVS devices 654/* If the NetBSD mixer device should have more than NETBSD_MAXDEVS devices
655 * some will not be available to OSS applications */ 655 * some will not be available to OSS applications */
656#define NETBSD_MAXDEVS 64 656#define NETBSD_MAXDEVS 64
657struct audiodevinfo { 657struct audiodevinfo {
658 int done; 658 int done;
659 dev_t dev; 659 dev_t dev;
660 int16_t devmap[SOUND_MIXER_NRDEVICES], 660 int16_t devmap[SOUND_MIXER_NRDEVICES],
661 rdevmap[NETBSD_MAXDEVS]; 661 rdevmap[NETBSD_MAXDEVS];
662 char names[NETBSD_MAXDEVS][MAX_AUDIO_DEV_LEN]; 662 char names[NETBSD_MAXDEVS][MAX_AUDIO_DEV_LEN];
663 int enum2opaque[NETBSD_MAXDEVS]; 663 int enum2opaque[NETBSD_MAXDEVS];
664 u_long devmask, recmask, stereomask; 664 u_long devmask, recmask, stereomask;
665 u_long caps; 665 u_long caps;
666 int source; 666 int source;
667}; 667};
668 668
669static int 669static int
670opaque_to_enum(struct audiodevinfo *di, audio_mixer_name_t *label, int opq) 670opaque_to_enum(struct audiodevinfo *di, audio_mixer_name_t *label, int opq)
671{ 671{
672 int i, o; 672 int i, o;
673 673
674 for (i = 0; i < NETBSD_MAXDEVS; i++) { 674 for (i = 0; i < NETBSD_MAXDEVS; i++) {
675 o = di->enum2opaque[i]; 675 o = di->enum2opaque[i];
676 if (o == opq) 676 if (o == opq)
677 break; 677 break;
678 if (o == -1 && label != NULL && 678 if (o == -1 && label != NULL &&
679 !strncmp(di->names[i], label->name, sizeof di->names[i])) { 679 !strncmp(di->names[i], label->name, sizeof di->names[i])) {
680 di->enum2opaque[i] = opq; 680 di->enum2opaque[i] = opq;
681 break; 681 break;
682 } 682 }
683 } 683 }
684 if (i >= NETBSD_MAXDEVS) 684 if (i >= NETBSD_MAXDEVS)
685 i = -1; 685 i = -1;
686 /*printf("opq_to_enum %s %d -> %d\n", label->name, opq, i);*/ 686 /*printf("opq_to_enum %s %d -> %d\n", label->name, opq, i);*/
687 return (i); 687 return (i);
688} 688}
689 689
690static int 690static int
691enum_to_ord(struct audiodevinfo *di, int enm) 691enum_to_ord(struct audiodevinfo *di, int enm)
692{ 692{
693 if (enm >= NETBSD_MAXDEVS) 693 if (enm >= NETBSD_MAXDEVS)
694 return (-1); 694 return (-1);
695 695
696 /*printf("enum_to_ord %d -> %d\n", enm, di->enum2opaque[enm]);*/ 696 /*printf("enum_to_ord %d -> %d\n", enm, di->enum2opaque[enm]);*/
697 return (di->enum2opaque[enm]); 697 return (di->enum2opaque[enm]);
698} 698}
699 699
700static int 700static int
701enum_to_mask(struct audiodevinfo *di, int enm) 701enum_to_mask(struct audiodevinfo *di, int enm)
702{ 702{
703 int m; 703 int m;
704 if (enm >= NETBSD_MAXDEVS) 704 if (enm >= NETBSD_MAXDEVS)
705 return (0); 705 return (0);
706 706
707 m = di->enum2opaque[enm]; 707 m = di->enum2opaque[enm];
708 if (m == -1) 708 if (m == -1)
709 m = 0; 709 m = 0;
710 /*printf("enum_to_mask %d -> %d\n", enm, di->enum2opaque[enm]);*/ 710 /*printf("enum_to_mask %d -> %d\n", enm, di->enum2opaque[enm]);*/
711 return (m); 711 return (m);
712} 712}
713 713
714/* 714/*
715 * Collect the audio device information to allow faster 715 * Collect the audio device information to allow faster
716 * emulation of the OSSv3 mixer ioctls. Cache the information 716 * emulation of the OSSv3 mixer ioctls. Cache the information
717 * to eliminate the overhead of repeating all the ioctls needed 717 * to eliminate the overhead of repeating all the ioctls needed
718 * to collect the information. 718 * to collect the information.
719 */ 719 */
720static struct audiodevinfo * 720static struct audiodevinfo *
721getdevinfo(int fd) 721getdevinfo(int fd)
722{ 722{
723 mixer_devinfo_t mi; 723 mixer_devinfo_t mi;
724 int i, j, e; 724 int i, j, e;
725 static struct { 725 static struct {
726 const char *name; 726 const char *name;
727 int code; 727 int code;
728 } *dp, devs[] = { 728 } *dp, devs[] = {
729 { AudioNmicrophone, SOUND_MIXER_MIC }, 729 { AudioNmicrophone, SOUND_MIXER_MIC },
730 { AudioNline, SOUND_MIXER_LINE }, 730 { AudioNline, SOUND_MIXER_LINE },
731 { AudioNcd, SOUND_MIXER_CD }, 731 { AudioNcd, SOUND_MIXER_CD },
732 { AudioNdac, SOUND_MIXER_PCM }, 732 { AudioNdac, SOUND_MIXER_PCM },
733 { AudioNaux, SOUND_MIXER_LINE1 }, 733 { AudioNaux, SOUND_MIXER_LINE1 },
734 { AudioNrecord, SOUND_MIXER_IMIX }, 734 { AudioNrecord, SOUND_MIXER_IMIX },
735 { AudioNmaster, SOUND_MIXER_VOLUME }, 735 { AudioNmaster, SOUND_MIXER_VOLUME },
736 { AudioNtreble, SOUND_MIXER_TREBLE }, 736 { AudioNtreble, SOUND_MIXER_TREBLE },
737 { AudioNbass, SOUND_MIXER_BASS }, 737 { AudioNbass, SOUND_MIXER_BASS },
738 { AudioNspeaker, SOUND_MIXER_SPEAKER }, 738 { AudioNspeaker, SOUND_MIXER_SPEAKER },
739/* { AudioNheadphone, ?? },*/ 739/* { AudioNheadphone, ?? },*/
740 { AudioNoutput, SOUND_MIXER_OGAIN }, 740 { AudioNoutput, SOUND_MIXER_OGAIN },
741 { AudioNinput, SOUND_MIXER_IGAIN }, 741 { AudioNinput, SOUND_MIXER_IGAIN },
742/* { AudioNmaster, SOUND_MIXER_SPEAKER },*/ 742/* { AudioNmaster, SOUND_MIXER_SPEAKER },*/
743/* { AudioNstereo, ?? },*/ 743/* { AudioNstereo, ?? },*/
744/* { AudioNmono, ?? },*/ 744/* { AudioNmono, ?? },*/
745 { AudioNfmsynth, SOUND_MIXER_SYNTH }, 745 { AudioNfmsynth, SOUND_MIXER_SYNTH },
746/* { AudioNwave, SOUND_MIXER_PCM },*/ 746/* { AudioNwave, SOUND_MIXER_PCM },*/
747 { AudioNmidi, SOUND_MIXER_SYNTH }, 747 { AudioNmidi, SOUND_MIXER_SYNTH },
748/* { AudioNmixerout, ?? },*/ 748/* { AudioNmixerout, ?? },*/
749 { 0, -1 } 749 { 0, -1 }
750 }; 750 };
751 static struct audiodevinfo devcache = { .done = 0 }; 751 static struct audiodevinfo devcache = { .done = 0 };
752 struct audiodevinfo *di = &devcache; 752 struct audiodevinfo *di = &devcache;
753 struct stat sb; 753 struct stat sb;
754 size_t mlen, dlen; 754 size_t mlen, dlen;
755 755
756 /* Figure out what device it is so we can check if the 756 /* Figure out what device it is so we can check if the
757 * cached data is valid. 757 * cached data is valid.
758 */ 758 */
759 if (fstat(fd, &sb) < 0) 759 if (fstat(fd, &sb) < 0)
760 return 0; 760 return 0;
761 if (di->done && di->dev == sb.st_dev) 761 if (di->done && di->dev == sb.st_dev)
762 return di; 762 return di;
763 763
764 di->done = 1; 764 di->done = 1;
765 di->dev = sb.st_dev; 765 di->dev = sb.st_dev;
766 di->devmask = 0; 766 di->devmask = 0;
767 di->recmask = 0; 767 di->recmask = 0;
768 di->stereomask = 0; 768 di->stereomask = 0;
769 di->source = ~0; 769 di->source = ~0;
770 di->caps = 0; 770 di->caps = 0;
771 for(i = 0; i < SOUND_MIXER_NRDEVICES; i++) 771 for(i = 0; i < SOUND_MIXER_NRDEVICES; i++)
772 di->devmap[i] = -1; 772 di->devmap[i] = -1;
773 for(i = 0; i < NETBSD_MAXDEVS; i++) { 773 for(i = 0; i < NETBSD_MAXDEVS; i++) {
774 di->rdevmap[i] = -1; 774 di->rdevmap[i] = -1;
775 di->names[i][0] = '\0'; 775 di->names[i][0] = '\0';
776 di->enum2opaque[i] = -1; 776 di->enum2opaque[i] = -1;
777 } 777 }
778 for(i = 0; i < NETBSD_MAXDEVS; i++) { 778 for(i = 0; i < NETBSD_MAXDEVS; i++) {
779 mi.index = i; 779 mi.index = i;
780 if (ioctl(fd, AUDIO_MIXER_DEVINFO, &mi) < 0) 780 if (ioctl(fd, AUDIO_MIXER_DEVINFO, &mi) < 0)
781 break; 781 break;
782 switch(mi.type) { 782 switch(mi.type) {
783 case AUDIO_MIXER_VALUE: 783 case AUDIO_MIXER_VALUE:
784 for(dp = devs; dp->name; dp++) { 784 for(dp = devs; dp->name; dp++) {
785 if (strcmp(dp->name, mi.label.name) == 0) 785 if (strcmp(dp->name, mi.label.name) == 0)
786 break; 786 break;
787 dlen = strlen(dp->name); 787 dlen = strlen(dp->name);
788 mlen = strlen(mi.label.name); 788 mlen = strlen(mi.label.name);
789 if (dlen < mlen 789 if (dlen < mlen
790 && mi.label.name[mlen-dlen-1] == '.' 790 && mi.label.name[mlen-dlen-1] == '.'
791 && strcmp(dp->name, 791 && strcmp(dp->name,
792 mi.label.name + mlen - dlen) == 0) 792 mi.label.name + mlen - dlen) == 0)
793 break; 793 break;
794 } 794 }
795 if (dp->code >= 0) { 795 if (dp->code >= 0) {
796 di->devmap[dp->code] = i; 796 di->devmap[dp->code] = i;
797 di->rdevmap[i] = dp->code; 797 di->rdevmap[i] = dp->code;
798 di->devmask |= 1 << dp->code; 798 di->devmask |= 1 << dp->code;
799 if (mi.un.v.num_channels == 2) 799 if (mi.un.v.num_channels == 2)
800 di->stereomask |= 1 << dp->code; 800 di->stereomask |= 1 << dp->code;
801 strlcpy(di->names[i], mi.label.name, 801 strlcpy(di->names[i], mi.label.name,
802 sizeof di->names[i]); 802 sizeof di->names[i]);
803 } 803 }
804 break; 804 break;
805 } 805 }
806 } 806 }
807 for(i = 0; i < NETBSD_MAXDEVS; i++) { 807 for(i = 0; i < NETBSD_MAXDEVS; i++) {
808 mi.index = i; 808 mi.index = i;
809 if (ioctl(fd, AUDIO_MIXER_DEVINFO, &mi) < 0) 809 if (ioctl(fd, AUDIO_MIXER_DEVINFO, &mi) < 0)
810 break; 810 break;
811 if (strcmp(mi.label.name, AudioNsource) != 0) 811 if (strcmp(mi.label.name, AudioNsource) != 0)
812 continue; 812 continue;
813 di->source = i; 813 di->source = i;
814 switch(mi.type) { 814 switch(mi.type) {
815 case AUDIO_MIXER_ENUM: 815 case AUDIO_MIXER_ENUM:
816 for(j = 0; j < mi.un.e.num_mem; j++) { 816 for(j = 0; j < mi.un.e.num_mem; j++) {
817 e = opaque_to_enum(di, 817 e = opaque_to_enum(di,
818 &mi.un.e.member[j].label, 818 &mi.un.e.member[j].label,
819 mi.un.e.member[j].ord); 819 mi.un.e.member[j].ord);
820 if (e >= 0) 820 if (e >= 0)
821 di->recmask |= 1 << di->rdevmap[e]; 821 di->recmask |= 1 << di->rdevmap[e];
822 } 822 }
823 di->caps = SOUND_CAP_EXCL_INPUT; 823 di->caps = SOUND_CAP_EXCL_INPUT;
824 break; 824 break;
825 case AUDIO_MIXER_SET: 825 case AUDIO_MIXER_SET:
826 for(j = 0; j < mi.un.s.num_mem; j++) { 826 for(j = 0; j < mi.un.s.num_mem; j++) {
827 e = opaque_to_enum(di, 827 e = opaque_to_enum(di,
828 &mi.un.s.member[j].label, 828 &mi.un.s.member[j].label,
829 mi.un.s.member[j].mask); 829 mi.un.s.member[j].mask);
830 if (e >= 0) 830 if (e >= 0)
831 di->recmask |= 1 << di->rdevmap[e]; 831 di->recmask |= 1 << di->rdevmap[e];
832 } 832 }
833 break; 833 break;
834 } 834 }
835 } 835 }
836 return di; 836 return di;
837} 837}
838 838
839static int 839static int
840mixer_oss3_ioctl(int fd, unsigned long com, void *argp) 840mixer_oss3_ioctl(int fd, unsigned long com, void *argp)
841{ 841{
842 struct audiodevinfo *di; 842 struct audiodevinfo *di;
843 struct mixer_info *omi; 843 struct mixer_info *omi;
844 struct audio_device adev; 844 struct audio_device adev;
845 mixer_ctrl_t mc; 845 mixer_ctrl_t mc;
846 u_long idat, n; 846 u_long idat, n;
847 int i; 847 int i;
848 int retval; 848 int retval;
849 int l, r, error, e; 849 int l, r, error, e;
850 850
851 idat = 0; 851 idat = 0;
852 di = getdevinfo(fd); 852 di = getdevinfo(fd);
853 if (di == 0) 853 if (di == 0)
854 return -1; 854 return -1;
855 855
856 switch (com) { 856 switch (com) {
857 case OSS_GETVERSION: 857 case OSS_GETVERSION:
858 idat = SOUND_VERSION; 858 idat = SOUND_VERSION;
859 break; 859 break;
860 case SOUND_MIXER_INFO: 860 case SOUND_MIXER_INFO:
861 case SOUND_OLD_MIXER_INFO: 861 case SOUND_OLD_MIXER_INFO:
862 error = ioctl(fd, AUDIO_GETDEV, &adev); 862 error = ioctl(fd, AUDIO_GETDEV, &adev);
863 if (error) 863 if (error)
864 return (error); 864 return (error);
865 omi = argp; 865 omi = argp;
866 if (com == SOUND_MIXER_INFO) 866 if (com == SOUND_MIXER_INFO)
867 omi->modify_counter = 1; 867 omi->modify_counter = 1;
868 strlcpy(omi->id, adev.name, sizeof omi->id); 868 strlcpy(omi->id, adev.name, sizeof omi->id);
869 strlcpy(omi->name, adev.name, sizeof omi->name); 869 strlcpy(omi->name, adev.name, sizeof omi->name);
870 return 0; 870 return 0;
871 case SOUND_MIXER_READ_RECSRC: 871 case SOUND_MIXER_READ_RECSRC:
872 if (di->source == -1) 872 if (di->source == -1)
873 return EINVAL; 873 return EINVAL;
874 mc.dev = di->source; 874 mc.dev = di->source;
875 if (di->caps & SOUND_CAP_EXCL_INPUT) { 875 if (di->caps & SOUND_CAP_EXCL_INPUT) {
876 mc.type = AUDIO_MIXER_ENUM; 876 mc.type = AUDIO_MIXER_ENUM;
877 retval = ioctl(fd, AUDIO_MIXER_READ, &mc); 877 retval = ioctl(fd, AUDIO_MIXER_READ, &mc);
878 if (retval < 0) 878 if (retval < 0)
879 return retval; 879 return retval;
880 e = opaque_to_enum(di, NULL, mc.un.ord); 880 e = opaque_to_enum(di, NULL, mc.un.ord);
881 if (e >= 0) 881 if (e >= 0)
882 idat = 1 << di->rdevmap[e]; 882 idat = 1 << di->rdevmap[e];
883 } else { 883 } else {
884 mc.type = AUDIO_MIXER_SET; 884 mc.type = AUDIO_MIXER_SET;
885 retval = ioctl(fd, AUDIO_MIXER_READ, &mc); 885 retval = ioctl(fd, AUDIO_MIXER_READ, &mc);
886 if (retval < 0) 886 if (retval < 0)
887 return retval; 887 return retval;
888 e = opaque_to_enum(di, NULL, mc.un.mask); 888 e = opaque_to_enum(di, NULL, mc.un.mask);
889 if (e >= 0) 889 if (e >= 0)
890 idat = 1 << di->rdevmap[e]; 890 idat = 1 << di->rdevmap[e];
891 } 891 }
892 break; 892 break;
893 case SOUND_MIXER_READ_DEVMASK: 893 case SOUND_MIXER_READ_DEVMASK:
894 idat = di->devmask; 894 idat = di->devmask;
895 break; 895 break;
896 case SOUND_MIXER_READ_RECMASK: 896 case SOUND_MIXER_READ_RECMASK:
897 idat = di->recmask; 897 idat = di->recmask;
898 break; 898 break;
899 case SOUND_MIXER_READ_STEREODEVS: 899 case SOUND_MIXER_READ_STEREODEVS:
900 idat = di->stereomask; 900 idat = di->stereomask;
901 break; 901 break;
902 case SOUND_MIXER_READ_CAPS: 902 case SOUND_MIXER_READ_CAPS:
903 idat = di->caps; 903 idat = di->caps;
904 break; 904 break;
905 case SOUND_MIXER_WRITE_RECSRC: 905 case SOUND_MIXER_WRITE_RECSRC:
906 case SOUND_MIXER_WRITE_R_RECSRC: 906 case SOUND_MIXER_WRITE_R_RECSRC:
907 if (di->source == -1) 907 if (di->source == -1)
908 return EINVAL; 908 return EINVAL;
909 mc.dev = di->source; 909 mc.dev = di->source;
910 idat = INTARG; 910 idat = INTARG;
911 if (di->caps & SOUND_CAP_EXCL_INPUT) { 911 if (di->caps & SOUND_CAP_EXCL_INPUT) {
912 mc.type = AUDIO_MIXER_ENUM; 912 mc.type = AUDIO_MIXER_ENUM;
913 for(i = 0; i < SOUND_MIXER_NRDEVICES; i++) 913 for(i = 0; i < SOUND_MIXER_NRDEVICES; i++)
914 if (idat & (1 << i)) 914 if (idat & (1 << i))
915 break; 915 break;
916 if (i >= SOUND_MIXER_NRDEVICES || 916 if (i >= SOUND_MIXER_NRDEVICES ||
917 di->devmap[i] == -1) 917 di->devmap[i] == -1)
918 return EINVAL; 918 return EINVAL;
919 mc.un.ord = enum_to_ord(di, di->devmap[i]); 919 mc.un.ord = enum_to_ord(di, di->devmap[i]);
920 } else { 920 } else {
921 mc.type = AUDIO_MIXER_SET; 921 mc.type = AUDIO_MIXER_SET;
922 mc.un.mask = 0; 922 mc.un.mask = 0;
923 for(i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 923 for(i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
924 if (idat & (1 << i)) { 924 if (idat & (1 << i)) {
925 if (di->devmap[i] == -1) 925 if (di->devmap[i] == -1)
926 return EINVAL; 926 return EINVAL;
927 mc.un.mask |= 927 mc.un.mask |=
928 enum_to_mask(di, di->devmap[i]); 928 enum_to_mask(di, di->devmap[i]);
929 } 929 }
930 } 930 }
931 } 931 }
932 return ioctl(fd, AUDIO_MIXER_WRITE, &mc); 932 return ioctl(fd, AUDIO_MIXER_WRITE, &mc);
933 default: 933 default:
934 if (MIXER_READ(SOUND_MIXER_FIRST) <= com && 934 if (MIXER_READ(SOUND_MIXER_FIRST) <= com &&
935 com < MIXER_READ(SOUND_MIXER_NRDEVICES)) { 935 com < MIXER_READ(SOUND_MIXER_NRDEVICES)) {
936 n = GET_DEV(com); 936 n = GET_DEV(com);
937 if (di->devmap[n] == -1) 937 if (di->devmap[n] == -1)
938 return EINVAL; 938 return EINVAL;
939 mc.dev = di->devmap[n]; 939 mc.dev = di->devmap[n];
940 mc.type = AUDIO_MIXER_VALUE; 940 mc.type = AUDIO_MIXER_VALUE;
941 doread: 941 doread:
942 mc.un.value.num_channels = 942 mc.un.value.num_channels =
943 di->stereomask & (1 << (u_int)n) ? 2 : 1; 943 di->stereomask & (1 << (u_int)n) ? 2 : 1;
944 retval = ioctl(fd, AUDIO_MIXER_READ, &mc); 944 retval = ioctl(fd, AUDIO_MIXER_READ, &mc);
945 if (retval < 0) 945 if (retval < 0)
946 return retval; 946 return retval;
947 if (mc.type != AUDIO_MIXER_VALUE) 947 if (mc.type != AUDIO_MIXER_VALUE)
948 return EINVAL; 948 return EINVAL;
949 if (mc.un.value.num_channels != 2) { 949 if (mc.un.value.num_channels != 2) {
950 l = r = 950 l = r =
951 mc.un.value.level[AUDIO_MIXER_LEVEL_MONO]; 951 mc.un.value.level[AUDIO_MIXER_LEVEL_MONO];
952 } else { 952 } else {
953 l = mc.un.value.level[AUDIO_MIXER_LEVEL_LEFT]; 953 l = mc.un.value.level[AUDIO_MIXER_LEVEL_LEFT];
954 r = mc.un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; 954 r = mc.un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
955 } 955 }
956 idat = TO_OSSVOL(l) | (TO_OSSVOL(r) << 8); 956 idat = TO_OSSVOL(l) | (TO_OSSVOL(r) << 8);
957 break; 957 break;
958 } else if ((MIXER_WRITE_R(SOUND_MIXER_FIRST) <= com && 958 } else if ((MIXER_WRITE_R(SOUND_MIXER_FIRST) <= com &&
959 com < MIXER_WRITE_R(SOUND_MIXER_NRDEVICES)) || 959 com < MIXER_WRITE_R(SOUND_MIXER_NRDEVICES)) ||
960 (MIXER_WRITE(SOUND_MIXER_FIRST) <= com && 960 (MIXER_WRITE(SOUND_MIXER_FIRST) <= com &&
961 com < MIXER_WRITE(SOUND_MIXER_NRDEVICES))) { 961 com < MIXER_WRITE(SOUND_MIXER_NRDEVICES))) {
962 n = GET_DEV(com); 962 n = GET_DEV(com);
963 if (di->devmap[n] == -1) 963 if (di->devmap[n] == -1)
964 return EINVAL; 964 return EINVAL;
965 idat = INTARG; 965 idat = INTARG;
966 l = FROM_OSSVOL((u_int)idat & 0xff); 966 l = FROM_OSSVOL((u_int)idat & 0xff);
967 r = FROM_OSSVOL(((u_int)idat >> 8) & 0xff); 967 r = FROM_OSSVOL(((u_int)idat >> 8) & 0xff);
968 mc.dev = di->devmap[n]; 968 mc.dev = di->devmap[n];
969 mc.type = AUDIO_MIXER_VALUE; 969 mc.type = AUDIO_MIXER_VALUE;
970 if (di->stereomask & (1 << (u_int)n)) { 970 if (di->stereomask & (1 << (u_int)n)) {
971 mc.un.value.num_channels = 2; 971 mc.un.value.num_channels = 2;
972 mc.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l; 972 mc.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
973 mc.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r; 973 mc.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
974 } else { 974 } else {
975 mc.un.value.num_channels = 1; 975 mc.un.value.num_channels = 1;
976 mc.un.value.level[AUDIO_MIXER_LEVEL_MONO] = 976 mc.un.value.level[AUDIO_MIXER_LEVEL_MONO] =
977 (l + r) / 2; 977 (l + r) / 2;
978 } 978 }
979 retval = ioctl(fd, AUDIO_MIXER_WRITE, &mc); 979 retval = ioctl(fd, AUDIO_MIXER_WRITE, &mc);
980 if (retval < 0) 980 if (retval < 0)
981 return retval; 981 return retval;
982 if (MIXER_WRITE(SOUND_MIXER_FIRST) <= com && 982 if (MIXER_WRITE(SOUND_MIXER_FIRST) <= com &&
983 com < MIXER_WRITE(SOUND_MIXER_NRDEVICES)) 983 com < MIXER_WRITE(SOUND_MIXER_NRDEVICES))
984 return 0; 984 return 0;
985 goto doread; 985 goto doread;
986 } else { 986 } else {
987 errno = EINVAL; 987 errno = EINVAL;
988 return -1; 988 return -1;
989 } 989 }
990 } 990 }
991 INTARG = (int)idat; 991 INTARG = (int)idat;
992 return 0; 992 return 0;
993} 993}
994 994
995static int 995static int
996mixer_oss4_ioctl(int fd, unsigned long com, void *argp) 996mixer_oss4_ioctl(int fd, unsigned long com, void *argp)
997{ 997{
998 oss_audioinfo *tmpai; 998 oss_audioinfo *tmpai;
999 oss_card_info *cardinfo; 999 oss_card_info *cardinfo;
1000 oss_mixext *ext; 1000 oss_mixext *ext;
1001 oss_mixext_root root; 1001 oss_mixext_root root;
1002 oss_mixer_enuminfo *ei; 1002 oss_mixer_enuminfo *ei;
1003 oss_mixer_value *mv; 1003 oss_mixer_value *mv;
1004 oss_mixerinfo *mi; 1004 oss_mixerinfo *mi;
1005 oss_sysinfo sysinfo; 1005 oss_sysinfo sysinfo;
1006 dev_t devno; 1006 dev_t devno;
1007 struct stat tmpstat; 1007 struct stat tmpstat;
1008 struct audio_device dev; 1008 struct audio_device dev;
1009 struct audio_format_query fmtq; 1009 struct audio_format_query fmtq;
1010 struct mixer_devinfo mdi; 1010 struct mixer_devinfo mdi;
1011 struct mixer_ctrl mc; 1011 struct mixer_ctrl mc;
1012 char devname[32]; 1012 char devname[32];
1013 size_t len; 1013 size_t len;
1014 int newfd = -1, tmperrno; 1014 int newfd = -1, tmperrno;
1015 int i, noffs; 1015 int i, noffs;
1016 int retval; 1016 int retval;
1017 int props, caps; 1017 int props, caps;
1018 1018
1019 /* 1019 /*
1020 * Note: it is difficult to translate the NetBSD concept of a "set" 1020 * Note: it is difficult to translate the NetBSD concept of a "set"
1021 * mixer control type to the OSSv4 API, as far as I can tell. 1021 * mixer control type to the OSSv4 API, as far as I can tell.
1022 * 1022 *
1023 * This means they are treated like enums, i.e. only one entry in the 1023 * This means they are treated like enums, i.e. only one entry in the
1024 * set can be selected at a time. 1024 * set can be selected at a time.
1025 */ 1025 */
1026 1026
1027 switch (com) { 1027 switch (com) {
1028 case SNDCTL_AUDIOINFO: 1028 case SNDCTL_AUDIOINFO:
1029 /* 1029 /*
1030 * SNDCTL_AUDIOINFO_EX is intended for underlying hardware devices 1030 * SNDCTL_AUDIOINFO_EX is intended for underlying hardware devices
1031 * that are to be opened in "exclusive mode" (bypassing the normal 1031 * that are to be opened in "exclusive mode" (bypassing the normal
1032 * kernel mixer for exclusive control). NetBSD does not support 1032 * kernel mixer for exclusive control). NetBSD does not support
1033 * bypassing the kernel mixer, so it's an alias of SNDCTL_AUDIOINFO. 1033 * bypassing the kernel mixer, so it's an alias of SNDCTL_AUDIOINFO.
1034 */ 1034 */
1035 case SNDCTL_AUDIOINFO_EX: 1035 case SNDCTL_AUDIOINFO_EX:
1036 case SNDCTL_ENGINEINFO: 1036 case SNDCTL_ENGINEINFO:
1037 devno = 0; 1037 devno = 0;
1038 tmpai = (struct oss_audioinfo*)argp; 1038 tmpai = (struct oss_audioinfo*)argp;
1039 if (tmpai == NULL) { 1039 if (tmpai == NULL) {
1040 errno = EINVAL; 1040 errno = EINVAL;
1041 return -1; 1041 return -1;
1042 } 1042 }
1043 1043
1044 /* 1044 /*
1045 * If the input device is -1, guess the device related to 1045 * If the input device is -1, guess the device related to
1046 * the open mixer device. 1046 * the open mixer device.
1047 */ 1047 */
1048 if (tmpai->dev < 0) { 1048 if (tmpai->dev < 0) {
1049 fstat(fd, &tmpstat); 1049 fstat(fd, &tmpstat);
1050 if ((tmpstat.st_rdev & 0xff00) == 0x2a00) 1050 if ((tmpstat.st_rdev & 0xff00) == 0x2a00)
1051 devno = tmpstat.st_rdev & 0xff; 1051 devno = tmpstat.st_rdev & 0xff;
1052 if (devno >= 0x80) 1052 if (devno >= 0x80)
1053 tmpai->dev = devno & 0x7f; 1053 tmpai->dev = devno & 0x7f;
1054 } 1054 }
1055 if (tmpai->dev < 0) 1055 if (tmpai->dev < 0)
1056 tmpai->dev = 0; 1056 tmpai->dev = 0;
1057 1057
1058 snprintf(tmpai->devnode, sizeof(tmpai->devnode), 1058 snprintf(tmpai->devnode, sizeof(tmpai->devnode),
1059 "/dev/audio%d", tmpai->dev); 1059 "/dev/audio%d", tmpai->dev);
1060 1060
1061 if ((newfd = open(tmpai->devnode, O_WRONLY)) < 0) { 1061 if ((newfd = open(tmpai->devnode, O_WRONLY)) < 0) {
1062 if ((newfd = open(tmpai->devnode, O_RDONLY)) < 0) { 1062 if ((newfd = open(tmpai->devnode, O_RDONLY)) < 0) {
1063 return newfd; 1063 return newfd;
1064 } 1064 }
1065 } 1065 }
1066 1066
1067 retval = ioctl(newfd, AUDIO_GETDEV, &dev); 1067 retval = ioctl(newfd, AUDIO_GETDEV, &dev);
1068 if (retval < 0) { 1068 if (retval < 0) {
1069 tmperrno = errno; 1069 tmperrno = errno;
1070 close(newfd); 1070 close(newfd);
1071 errno = tmperrno; 1071 errno = tmperrno;
1072 return retval; 1072 return retval;
1073 } 1073 }
1074 retval = ioctl(newfd, AUDIO_GETPROPS, &props); 1074 retval = ioctl(newfd, AUDIO_GETPROPS, &props);
1075 if (retval < 0) { 1075 if (retval < 0) {
1076 tmperrno = errno; 1076 tmperrno = errno;
1077 close(newfd); 1077 close(newfd);
1078 errno = tmperrno; 1078 errno = tmperrno;
1079 return retval; 1079 return retval;
1080 } 1080 }
1081 caps = DSP_CAP_TRIGGER; 1081 caps = DSP_CAP_TRIGGER;
1082 if (props & AUDIO_PROP_FULLDUPLEX) 1082 if (props & AUDIO_PROP_FULLDUPLEX)
1083 caps |= DSP_CAP_DUPLEX; 1083 caps |= DSP_CAP_DUPLEX;
1084 if (props & AUDIO_PROP_MMAP) 1084 if (props & AUDIO_PROP_MMAP)
1085 caps |= DSP_CAP_MMAP; 1085 caps |= DSP_CAP_MMAP;
1086 if (props & AUDIO_PROP_CAPTURE) 1086 if (props & AUDIO_PROP_CAPTURE)
1087 caps |= PCM_CAP_INPUT; 1087 caps |= PCM_CAP_INPUT;
1088 if (props & AUDIO_PROP_PLAYBACK) 1088 if (props & AUDIO_PROP_PLAYBACK)
1089 caps |= PCM_CAP_OUTPUT; 1089 caps |= PCM_CAP_OUTPUT;
1090 snprintf(tmpai->name, sizeof(tmpai->name), 1090 snprintf(tmpai->name, sizeof(tmpai->name),
1091 "%s %s", dev.name, dev.version); 1091 "%s %s", dev.name, dev.version);
1092 tmpai->busy = 0; 1092 tmpai->busy = 0;
1093 tmpai->pid = -1; 1093 tmpai->pid = -1;
1094 tmpai->caps = caps; 1094 tmpai->caps = caps;
1095 ioctl(newfd, SNDCTL_DSP_GETFMTS, &tmpai->iformats); 1095 ioctl(newfd, SNDCTL_DSP_GETFMTS, &tmpai->iformats);
1096 tmpai->oformats = tmpai->iformats; 1096 tmpai->oformats = tmpai->iformats;
1097 tmpai->magic = -1; /* reserved for "internal use" */ 1097 tmpai->magic = -1; /* reserved for "internal use" */
1098 memset(tmpai->cmd, 0, sizeof(tmpai->cmd)); 1098 memset(tmpai->cmd, 0, sizeof(tmpai->cmd));
1099 tmpai->card_number = -1; 1099 tmpai->card_number = -1;
1100 memset(tmpai->song_name, 0, 1100 memset(tmpai->song_name, 0,
1101 sizeof(tmpai->song_name)); 1101 sizeof(tmpai->song_name));
1102 memset(tmpai->label, 0, sizeof(tmpai->label)); 1102 memset(tmpai->label, 0, sizeof(tmpai->label));
1103 tmpai->port_number = 0; 1103 tmpai->port_number = 0;
1104 tmpai->mixer_dev = tmpai->dev; 1104 tmpai->mixer_dev = tmpai->dev;
1105 tmpai->legacy_device = tmpai->dev; 1105 tmpai->legacy_device = tmpai->dev;
1106 tmpai->enabled = 1; 1106 tmpai->enabled = 1;
1107 tmpai->flags = -1; /* reserved for "future versions" */ 1107 tmpai->flags = -1; /* reserved for "future versions" */
1108 tmpai->min_rate = 1000; 1108 tmpai->min_rate = 1000;
1109 tmpai->max_rate = 192000; 1109 tmpai->max_rate = 192000;
1110 tmpai->nrates = 0; 1110 tmpai->nrates = 0;
1111 tmpai->min_channels = 1; 1111 tmpai->min_channels = 1;
1112 tmpai->max_channels = 2; 1112 tmpai->max_channels = 2;
1113 for (fmtq.index = 0; 1113 for (fmtq.index = 0;
1114 ioctl(newfd, AUDIO_QUERYFORMAT, &fmtq) != -1; ++fmtq.index) { 1114 ioctl(newfd, AUDIO_QUERYFORMAT, &fmtq) != -1; ++fmtq.index) {
1115 if (fmtq.fmt.channels > (unsigned)tmpai->max_channels) 1115 if (fmtq.fmt.channels > (unsigned)tmpai->max_channels)
1116 tmpai->max_channels = fmtq.fmt.channels; 1116 tmpai->max_channels = fmtq.fmt.channels;
1117 } 1117 }
1118 tmpai->binding = -1; /* reserved for "future versions" */ 1118 tmpai->binding = -1; /* reserved for "future versions" */
1119 tmpai->rate_source = -1; 1119 tmpai->rate_source = -1;
1120 /* 1120 /*
1121 * 'handle' is supposed to be globally unique. The closest 1121 * 'handle' is supposed to be globally unique. The closest
1122 * we have to that is probably device nodes. 1122 * we have to that is probably device nodes.
1123 */ 1123 */
1124 strlcpy(tmpai->handle, tmpai->devnode, 1124 strlcpy(tmpai->handle, tmpai->devnode,
1125 sizeof(tmpai->handle)); 1125 sizeof(tmpai->handle));
1126 tmpai->next_play_engine = 0; 1126 tmpai->next_play_engine = 0;
1127 tmpai->next_rec_engine = 0; 1127 tmpai->next_rec_engine = 0;
1128 argp = tmpai; 1128 argp = tmpai;
1129 close(newfd); 1129 close(newfd);
1130 break; 1130 break;
1131 case SNDCTL_CARDINFO: 1131 case SNDCTL_CARDINFO:
1132 cardinfo = (oss_card_info *)argp; 1132 cardinfo = (oss_card_info *)argp;
1133 if (cardinfo == NULL) 1133 if (cardinfo == NULL)
1134 return EINVAL; 1134 return EINVAL;
1135 if (cardinfo->card != -1) { 1135 if (cardinfo->card != -1) {
1136 snprintf(devname, sizeof(devname), 1136 snprintf(devname, sizeof(devname),
1137 "/dev/audio%d", cardinfo->card); 1137 "/dev/audio%d", cardinfo->card);
1138 newfd = open(devname, O_RDONLY); 1138 newfd = open(devname, O_RDONLY);
1139 if (newfd < 0) 1139 if (newfd < 0)
1140 return newfd; 1140 return newfd;
1141 } else { 1141 } else {
1142 newfd = fd; 1142 newfd = fd;
1143 } 1143 }
1144 retval = ioctl(newfd, AUDIO_GETDEV, &dev); 1144 retval = ioctl(newfd, AUDIO_GETDEV, &dev);
1145 tmperrno = errno; 1145 tmperrno = errno;
1146 if (newfd != fd) 1146 if (newfd != fd)
1147 close(newfd); 1147 close(newfd);
1148 if (retval < 0) { 1148 if (retval < 0) {
1149 errno = tmperrno; 1149 errno = tmperrno;
1150 return retval; 1150 return retval;
1151 } 1151 }
1152 strlcpy(cardinfo->shortname, dev.name, 1152 strlcpy(cardinfo->shortname, dev.name,
1153 sizeof(cardinfo->shortname)); 1153 sizeof(cardinfo->shortname));
1154 snprintf(cardinfo->longname, sizeof(cardinfo->longname), 1154 snprintf(cardinfo->longname, sizeof(cardinfo->longname),
1155 "%s %s %s", dev.name, dev.version, dev.config); 1155 "%s %s %s", dev.name, dev.version, dev.config);
1156 memset(cardinfo->hw_info, 0, sizeof(cardinfo->hw_info)); 1156 memset(cardinfo->hw_info, 0, sizeof(cardinfo->hw_info));
1157 /* 1157 /*
1158 * OSSv4 does not document this ioctl, and claims it should 1158 * OSSv4 does not document this ioctl, and claims it should
1159 * not be used by applications and is provided for "utiltiy 1159 * not be used by applications and is provided for "utiltiy
1160 * programs included in OSS". We follow the Solaris 1160 * programs included in OSS". We follow the Solaris
1161 * implementation (which is documented) and leave these fields 1161 * implementation (which is documented) and leave these fields
1162 * unset. 1162 * unset.
1163 */ 1163 */
1164 cardinfo->flags = 0; 1164 cardinfo->flags = 0;
1165 cardinfo->intr_count = 0; 1165 cardinfo->intr_count = 0;
1166 cardinfo->ack_count = 0; 1166 cardinfo->ack_count = 0;
1167 break; 1167 break;
1168 case SNDCTL_SYSINFO: 1168 case SNDCTL_SYSINFO:
1169 memset(&sysinfo, 0, sizeof(sysinfo)); 1169 memset(&sysinfo, 0, sizeof(sysinfo));
1170 strlcpy(sysinfo.product, 1170 strlcpy(sysinfo.product,
1171 "OSS/NetBSD", sizeof(sysinfo.product)); 1171 "OSS/NetBSD", sizeof(sysinfo.product));
1172 strlcpy(sysinfo.version, 1172 strlcpy(sysinfo.version,
1173 "4.01", sizeof(sysinfo.version)); 1173 "4.01", sizeof(sysinfo.version));
1174 strlcpy(sysinfo.license, 1174 strlcpy(sysinfo.license,
1175 "BSD", sizeof(sysinfo.license)); 1175 "BSD", sizeof(sysinfo.license));
1176 sysinfo.versionnum = SOUND_VERSION; 1176 sysinfo.versionnum = SOUND_VERSION;
1177 sysinfo.numaudios =  1177 sysinfo.numaudios =
1178 sysinfo.numcards = 1178 sysinfo.numcards =
1179 getaudiocount(); 1179 getaudiocount();
1180 sysinfo.numaudioengines = 1; 1180 sysinfo.numaudioengines = 1;
1181 sysinfo.numsynths = 1; 1181 sysinfo.numsynths = 1;
1182 sysinfo.nummidis = -1; 1182 sysinfo.nummidis = -1;
1183 sysinfo.numtimers = -1; 1183 sysinfo.numtimers = -1;
1184 sysinfo.nummixers = getmixercount(); 1184 sysinfo.nummixers = getmixercount();
1185 *(struct oss_sysinfo *)argp = sysinfo; 1185 *(struct oss_sysinfo *)argp = sysinfo;
1186 break; 1186 break;
1187 case SNDCTL_MIXERINFO: 1187 case SNDCTL_MIXERINFO:
1188 mi = (oss_mixerinfo *)argp; 1188 mi = (oss_mixerinfo *)argp;
1189 if (mi == NULL) { 1189 if (mi == NULL) {
1190 errno = EINVAL; 1190 errno = EINVAL;
1191 return -1; 1191 return -1;