Mon Mar 15 10:58:05 2021 UTC ()
ossv4 mixer API: be extra careful with the inputs to AUDIO_MIXER_READ.

some drivers (not hdaudio(4), but uaudio(4), eap(4), sb(4), various other
old cards) will return error if a AUDIO_MIXER_VALUE is requested and the
number of channels is not specified as input. this is not documented as
well as it should be, unfortunately.


(nia)
diff -r1.65 -r1.66 src/lib/libossaudio/ossaudio.c

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

--- src/lib/libossaudio/Attic/ossaudio.c 2020/12/19 12:55:28 1.65
+++ src/lib/libossaudio/Attic/ossaudio.c 2021/03/15 10:58:05 1.66
@@ -1,1790 +1,1795 @@ @@ -1,1790 +1,1795 @@
1/* $NetBSD: ossaudio.c,v 1.65 2020/12/19 12:55:28 nia Exp $ */ 1/* $NetBSD: ossaudio.c,v 1.66 2021/03/15 10:58:05 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.65 2020/12/19 12:55:28 nia Exp $"); 30__RCSID("$NetBSD: ossaudio.c,v 1.66 2021/03/15 10:58:05 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 getcaps(int, int *); 74static int getcaps(int, int *);
75 75
76static int getvol(u_int, u_char); 76static int getvol(u_int, u_char);
77static void setvol(int, int, bool); 77static void setvol(int, int, bool);
78 78
79static void setchannels(int, int, int); 79static void setchannels(int, int, int);
80static void setblocksize(int, struct audio_info *); 80static void setblocksize(int, struct audio_info *);
81 81
82static int audio_ioctl(int, unsigned long, void *); 82static int audio_ioctl(int, unsigned long, void *);
83static int mixer_oss3_ioctl(int, unsigned long, void *); 83static int mixer_oss3_ioctl(int, unsigned long, void *);
84static int mixer_oss4_ioctl(int, unsigned long, void *); 84static int mixer_oss4_ioctl(int, unsigned long, void *);
85static int global_oss4_ioctl(int, unsigned long, void *); 85static int global_oss4_ioctl(int, unsigned long, void *);
86static int opaque_to_enum(struct audiodevinfo *, audio_mixer_name_t *, int); 86static int opaque_to_enum(struct audiodevinfo *, audio_mixer_name_t *, int);
87static int enum_to_ord(struct audiodevinfo *, int); 87static int enum_to_ord(struct audiodevinfo *, int);
88static int enum_to_mask(struct audiodevinfo *, int); 88static int enum_to_mask(struct audiodevinfo *, int);
89 89
90#define INTARG (*(int*)argp) 90#define INTARG (*(int*)argp)
91 91
92int 92int
93_oss_ioctl(int fd, unsigned long com, ...) 93_oss_ioctl(int fd, unsigned long com, ...)
94{ 94{
95 va_list ap; 95 va_list ap;
96 void *argp; 96 void *argp;
97 97
98 va_start(ap, com); 98 va_start(ap, com);
99 argp = va_arg(ap, void *); 99 argp = va_arg(ap, void *);
100 va_end(ap); 100 va_end(ap);
101 101
102 if (IOCGROUP(com) == 'P') 102 if (IOCGROUP(com) == 'P')
103 return audio_ioctl(fd, com, argp); 103 return audio_ioctl(fd, com, argp);
104 else if (IOCGROUP(com) == 'M') 104 else if (IOCGROUP(com) == 'M')
105 return mixer_oss3_ioctl(fd, com, argp); 105 return mixer_oss3_ioctl(fd, com, argp);
106 else if (IOCGROUP(com) == 'X') 106 else if (IOCGROUP(com) == 'X')
107 return mixer_oss4_ioctl(fd, com, argp); 107 return mixer_oss4_ioctl(fd, com, argp);
108 else if (IOCGROUP(com) == 'Y') 108 else if (IOCGROUP(com) == 'Y')
109 return global_oss4_ioctl(fd, com, argp); 109 return global_oss4_ioctl(fd, com, argp);
110 else 110 else
111 return ioctl(fd, com, argp); 111 return ioctl(fd, com, argp);
112} 112}
113 113
114static int 114static int
115audio_ioctl(int fd, unsigned long com, void *argp) 115audio_ioctl(int fd, unsigned long com, void *argp)
116{ 116{
117 117
118 struct audio_info tmpinfo, hwfmt; 118 struct audio_info tmpinfo, hwfmt;
119 struct audio_offset tmpoffs; 119 struct audio_offset tmpoffs;
120 struct audio_buf_info bufinfo; 120 struct audio_buf_info bufinfo;
121 struct audio_errinfo *tmperrinfo; 121 struct audio_errinfo *tmperrinfo;
122 struct count_info cntinfo; 122 struct count_info cntinfo;
123 struct audio_encoding tmpenc; 123 struct audio_encoding tmpenc;
124 u_int u; 124 u_int u;
125 u_int encoding; 125 u_int encoding;
126 u_int precision; 126 u_int precision;
127 int perrors, rerrors; 127 int perrors, rerrors;
128 static int totalperrors = 0; 128 static int totalperrors = 0;
129 static int totalrerrors = 0; 129 static int totalrerrors = 0;
130 oss_count_t osscount; 130 oss_count_t osscount;
131 int idat; 131 int idat;
132 int retval; 132 int retval;
133 133
134 idat = 0; 134 idat = 0;
135 135
136 switch (com) { 136 switch (com) {
137 case SNDCTL_DSP_RESET: 137 case SNDCTL_DSP_RESET:
138 retval = ioctl(fd, AUDIO_FLUSH, 0); 138 retval = ioctl(fd, AUDIO_FLUSH, 0);
139 if (retval < 0) 139 if (retval < 0)
140 return retval; 140 return retval;
141 break; 141 break;
142 case SNDCTL_DSP_SYNC: 142 case SNDCTL_DSP_SYNC:
143 retval = ioctl(fd, AUDIO_DRAIN, 0); 143 retval = ioctl(fd, AUDIO_DRAIN, 0);
144 if (retval < 0) 144 if (retval < 0)
145 return retval; 145 return retval;
146 break; 146 break;
147 case SNDCTL_DSP_GETERROR: 147 case SNDCTL_DSP_GETERROR:
148 tmperrinfo = (struct audio_errinfo *)argp; 148 tmperrinfo = (struct audio_errinfo *)argp;
149 if (tmperrinfo == NULL) { 149 if (tmperrinfo == NULL) {
150 errno = EINVAL; 150 errno = EINVAL;
151 return -1; 151 return -1;
152 } 152 }
153 memset(tmperrinfo, 0, sizeof(struct audio_errinfo)); 153 memset(tmperrinfo, 0, sizeof(struct audio_errinfo));
154 if ((retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo)) < 0) 154 if ((retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo)) < 0)
155 return retval; 155 return retval;
156 /* 156 /*
157 * OSS requires that we return counters that are relative to 157 * OSS requires that we return counters that are relative to
158 * the last call. We must maintain state here... 158 * the last call. We must maintain state here...
159 */ 159 */
160 if (ioctl(fd, AUDIO_PERROR, &perrors) != -1) { 160 if (ioctl(fd, AUDIO_PERROR, &perrors) != -1) {
161 perrors /= ((tmpinfo.play.precision / NBBY) * 161 perrors /= ((tmpinfo.play.precision / NBBY) *
162 tmpinfo.play.channels); 162 tmpinfo.play.channels);
163 tmperrinfo->play_underruns = 163 tmperrinfo->play_underruns =
164 (perrors / tmpinfo.blocksize) - totalperrors; 164 (perrors / tmpinfo.blocksize) - totalperrors;
165 totalperrors += tmperrinfo->play_underruns; 165 totalperrors += tmperrinfo->play_underruns;
166 } 166 }
167 if (ioctl(fd, AUDIO_RERROR, &rerrors) != -1) { 167 if (ioctl(fd, AUDIO_RERROR, &rerrors) != -1) {
168 rerrors /= ((tmpinfo.record.precision / NBBY) * 168 rerrors /= ((tmpinfo.record.precision / NBBY) *
169 tmpinfo.record.channels); 169 tmpinfo.record.channels);
170 tmperrinfo->rec_overruns = 170 tmperrinfo->rec_overruns =
171 (rerrors / tmpinfo.blocksize) - totalrerrors; 171 (rerrors / tmpinfo.blocksize) - totalrerrors;
172 totalrerrors += tmperrinfo->rec_overruns; 172 totalrerrors += tmperrinfo->rec_overruns;
173 } 173 }
174 break; 174 break;
175 case SNDCTL_DSP_COOKEDMODE: 175 case SNDCTL_DSP_COOKEDMODE:
176 /* 176 /*
177 * NetBSD is always running in "cooked mode" - the kernel 177 * NetBSD is always running in "cooked mode" - the kernel
178 * always performs format conversions. 178 * always performs format conversions.
179 */ 179 */
180 INTARG = 1; 180 INTARG = 1;
181 break; 181 break;
182 case SNDCTL_DSP_POST: 182 case SNDCTL_DSP_POST:
183 /* This call is merely advisory, and may be a nop. */ 183 /* This call is merely advisory, and may be a nop. */
184 break; 184 break;
185 case SNDCTL_DSP_SPEED: 185 case SNDCTL_DSP_SPEED:
186 /* 186 /*
187 * In Solaris, 0 is used a special value to query the 187 * In Solaris, 0 is used a special value to query the
188 * current rate. This seems useful to support. 188 * current rate. This seems useful to support.
189 */ 189 */
190 if (INTARG == 0) { 190 if (INTARG == 0) {
191 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 191 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
192 if (retval < 0) 192 if (retval < 0)
193 return retval; 193 return retval;
194 retval = ioctl(fd, AUDIO_GETFORMAT, &hwfmt); 194 retval = ioctl(fd, AUDIO_GETFORMAT, &hwfmt);
195 if (retval < 0) 195 if (retval < 0)
196 return retval; 196 return retval;
197 INTARG = (tmpinfo.mode == AUMODE_RECORD) ? 197 INTARG = (tmpinfo.mode == AUMODE_RECORD) ?
198 hwfmt.record.sample_rate : 198 hwfmt.record.sample_rate :
199 hwfmt.play.sample_rate; 199 hwfmt.play.sample_rate;
200 } 200 }
201 /* 201 /*
202 * Conform to kernel limits. 202 * Conform to kernel limits.
203 * NetBSD will reject unsupported sample rates, but OSS 203 * NetBSD will reject unsupported sample rates, but OSS
204 * applications need to be able to negotiate a supported one. 204 * applications need to be able to negotiate a supported one.
205 */ 205 */
206 if (INTARG < 1000) 206 if (INTARG < 1000)
207 INTARG = 1000; 207 INTARG = 1000;
208 if (INTARG > 192000) 208 if (INTARG > 192000)
209 INTARG = 192000; 209 INTARG = 192000;
210 AUDIO_INITINFO(&tmpinfo); 210 AUDIO_INITINFO(&tmpinfo);
211 tmpinfo.play.sample_rate = 211 tmpinfo.play.sample_rate =
212 tmpinfo.record.sample_rate = INTARG; 212 tmpinfo.record.sample_rate = INTARG;
213 retval = ioctl(fd, AUDIO_SETINFO, &tmpinfo); 213 retval = ioctl(fd, AUDIO_SETINFO, &tmpinfo);
214 if (retval < 0) 214 if (retval < 0)
215 return retval; 215 return retval;
216 /* FALLTHRU */ 216 /* FALLTHRU */
217 case SOUND_PCM_READ_RATE: 217 case SOUND_PCM_READ_RATE:
218 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 218 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
219 if (retval < 0) 219 if (retval < 0)
220 return retval; 220 return retval;
221 INTARG = GETPRINFO(&tmpinfo, sample_rate); 221 INTARG = GETPRINFO(&tmpinfo, sample_rate);
222 break; 222 break;
223 case SNDCTL_DSP_STEREO: 223 case SNDCTL_DSP_STEREO:
224 AUDIO_INITINFO(&tmpinfo); 224 AUDIO_INITINFO(&tmpinfo);
225 tmpinfo.play.channels = 225 tmpinfo.play.channels =
226 tmpinfo.record.channels = INTARG ? 2 : 1; 226 tmpinfo.record.channels = INTARG ? 2 : 1;
227 (void) ioctl(fd, AUDIO_SETINFO, &tmpinfo); 227 (void) ioctl(fd, AUDIO_SETINFO, &tmpinfo);
228 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 228 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
229 if (retval < 0) 229 if (retval < 0)
230 return retval; 230 return retval;
231 INTARG = GETPRINFO(&tmpinfo, channels) - 1; 231 INTARG = GETPRINFO(&tmpinfo, channels) - 1;
232 break; 232 break;
233 case SNDCTL_DSP_GETBLKSIZE: 233 case SNDCTL_DSP_GETBLKSIZE:
234 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 234 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
235 if (retval < 0) 235 if (retval < 0)
236 return retval; 236 return retval;
237 setblocksize(fd, &tmpinfo); 237 setblocksize(fd, &tmpinfo);
238 INTARG = tmpinfo.blocksize; 238 INTARG = tmpinfo.blocksize;
239 break; 239 break;
240 case SNDCTL_DSP_SETFMT: 240 case SNDCTL_DSP_SETFMT:
241 AUDIO_INITINFO(&tmpinfo); 241 AUDIO_INITINFO(&tmpinfo);
242 switch (INTARG) { 242 switch (INTARG) {
243 case AFMT_MU_LAW: 243 case AFMT_MU_LAW:
244 tmpinfo.play.precision = 244 tmpinfo.play.precision =
245 tmpinfo.record.precision = 8; 245 tmpinfo.record.precision = 8;
246 tmpinfo.play.encoding = 246 tmpinfo.play.encoding =
247 tmpinfo.record.encoding = AUDIO_ENCODING_ULAW; 247 tmpinfo.record.encoding = AUDIO_ENCODING_ULAW;
248 break; 248 break;
249 case AFMT_A_LAW: 249 case AFMT_A_LAW:
250 tmpinfo.play.precision = 250 tmpinfo.play.precision =
251 tmpinfo.record.precision = 8; 251 tmpinfo.record.precision = 8;
252 tmpinfo.play.encoding = 252 tmpinfo.play.encoding =
253 tmpinfo.record.encoding = AUDIO_ENCODING_ALAW; 253 tmpinfo.record.encoding = AUDIO_ENCODING_ALAW;
254 break; 254 break;
255 case AFMT_U8: 255 case AFMT_U8:
256 tmpinfo.play.precision = 256 tmpinfo.play.precision =
257 tmpinfo.record.precision = 8; 257 tmpinfo.record.precision = 8;
258 tmpinfo.play.encoding = 258 tmpinfo.play.encoding =
259 tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR; 259 tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR;
260 break; 260 break;
261 case AFMT_S8: 261 case AFMT_S8:
262 tmpinfo.play.precision = 262 tmpinfo.play.precision =
263 tmpinfo.record.precision = 8; 263 tmpinfo.record.precision = 8;
264 tmpinfo.play.encoding = 264 tmpinfo.play.encoding =
265 tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR; 265 tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR;
266 break; 266 break;
267 case AFMT_S16_LE: 267 case AFMT_S16_LE:
268 tmpinfo.play.precision = 268 tmpinfo.play.precision =
269 tmpinfo.record.precision = 16; 269 tmpinfo.record.precision = 16;
270 tmpinfo.play.encoding = 270 tmpinfo.play.encoding =
271 tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_LE; 271 tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_LE;
272 break; 272 break;
273 case AFMT_S16_BE: 273 case AFMT_S16_BE:
274 tmpinfo.play.precision = 274 tmpinfo.play.precision =
275 tmpinfo.record.precision = 16; 275 tmpinfo.record.precision = 16;
276 tmpinfo.play.encoding = 276 tmpinfo.play.encoding =
277 tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_BE; 277 tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_BE;
278 break; 278 break;
279 case AFMT_U16_LE: 279 case AFMT_U16_LE:
280 tmpinfo.play.precision = 280 tmpinfo.play.precision =
281 tmpinfo.record.precision = 16; 281 tmpinfo.record.precision = 16;
282 tmpinfo.play.encoding = 282 tmpinfo.play.encoding =
283 tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR_LE; 283 tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR_LE;
284 break; 284 break;
285 case AFMT_U16_BE: 285 case AFMT_U16_BE:
286 tmpinfo.play.precision = 286 tmpinfo.play.precision =
287 tmpinfo.record.precision = 16; 287 tmpinfo.record.precision = 16;
288 tmpinfo.play.encoding = 288 tmpinfo.play.encoding =
289 tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR_BE; 289 tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR_BE;
290 break; 290 break;
291 /* 291 /*
292 * XXX: When the kernel supports 24-bit LPCM by default, 292 * XXX: When the kernel supports 24-bit LPCM by default,
293 * the 24-bit formats should be handled properly instead 293 * the 24-bit formats should be handled properly instead
294 * of falling back to 32 bits. 294 * of falling back to 32 bits.
295 */ 295 */
296 case AFMT_S24_LE: 296 case AFMT_S24_LE:
297 case AFMT_S32_LE: 297 case AFMT_S32_LE:
298 tmpinfo.play.precision = 298 tmpinfo.play.precision =
299 tmpinfo.record.precision = 32; 299 tmpinfo.record.precision = 32;
300 tmpinfo.play.encoding = 300 tmpinfo.play.encoding =
301 tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_LE; 301 tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_LE;
302 break; 302 break;
303 case AFMT_S24_BE: 303 case AFMT_S24_BE:
304 case AFMT_S32_BE: 304 case AFMT_S32_BE:
305 tmpinfo.play.precision = 305 tmpinfo.play.precision =
306 tmpinfo.record.precision = 32; 306 tmpinfo.record.precision = 32;
307 tmpinfo.play.encoding = 307 tmpinfo.play.encoding =
308 tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_BE; 308 tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_BE;
309 break; 309 break;
310 case AFMT_AC3: 310 case AFMT_AC3:
311 tmpinfo.play.precision = 311 tmpinfo.play.precision =
312 tmpinfo.record.precision = 16; 312 tmpinfo.record.precision = 16;
313 tmpinfo.play.encoding = 313 tmpinfo.play.encoding =
314 tmpinfo.record.encoding = AUDIO_ENCODING_AC3; 314 tmpinfo.record.encoding = AUDIO_ENCODING_AC3;
315 break; 315 break;
316 default: 316 default:
317 /* 317 /*
318 * OSSv4 specifies that if an invalid format is chosen 318 * OSSv4 specifies that if an invalid format is chosen
319 * by an application then a sensible format supported 319 * by an application then a sensible format supported
320 * by the hardware is returned. 320 * by the hardware is returned.
321 * 321 *
322 * In this case, we pick the current hardware format. 322 * In this case, we pick the current hardware format.
323 */ 323 */
324 retval = ioctl(fd, AUDIO_GETFORMAT, &hwfmt); 324 retval = ioctl(fd, AUDIO_GETFORMAT, &hwfmt);
325 if (retval < 0) 325 if (retval < 0)
326 return retval; 326 return retval;
327 retval = ioctl(fd, AUDIO_GETINFO, &tmpinfo); 327 retval = ioctl(fd, AUDIO_GETINFO, &tmpinfo);
328 if (retval < 0) 328 if (retval < 0)
329 return retval; 329 return retval;
330 tmpinfo.play.encoding = 330 tmpinfo.play.encoding =
331 tmpinfo.record.encoding = 331 tmpinfo.record.encoding =
332 (tmpinfo.mode == AUMODE_RECORD) ? 332 (tmpinfo.mode == AUMODE_RECORD) ?
333 hwfmt.record.encoding : hwfmt.play.encoding; 333 hwfmt.record.encoding : hwfmt.play.encoding;
334 tmpinfo.play.precision = 334 tmpinfo.play.precision =
335 tmpinfo.record.precision = 335 tmpinfo.record.precision =
336 (tmpinfo.mode == AUMODE_RECORD) ? 336 (tmpinfo.mode == AUMODE_RECORD) ?
337 hwfmt.record.precision : hwfmt.play.precision ; 337 hwfmt.record.precision : hwfmt.play.precision ;
338 break; 338 break;
339 } 339 }
340 /* 340 /*
341 * In the post-kernel-mixer world, assume that any error means 341 * In the post-kernel-mixer world, assume that any error means
342 * it's fatal rather than an unsupported format being selected. 342 * it's fatal rather than an unsupported format being selected.
343 */ 343 */
344 retval = ioctl(fd, AUDIO_SETINFO, &tmpinfo); 344 retval = ioctl(fd, AUDIO_SETINFO, &tmpinfo);
345 if (retval < 0) 345 if (retval < 0)
346 return retval; 346 return retval;
347 /* FALLTHRU */ 347 /* FALLTHRU */
348 case SOUND_PCM_READ_BITS: 348 case SOUND_PCM_READ_BITS:
349 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 349 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
350 if (retval < 0) 350 if (retval < 0)
351 return retval; 351 return retval;
352 encoding = GETPRINFO(&tmpinfo, encoding); 352 encoding = GETPRINFO(&tmpinfo, encoding);
353 precision = GETPRINFO(&tmpinfo, precision); 353 precision = GETPRINFO(&tmpinfo, precision);
354 switch (encoding) { 354 switch (encoding) {
355 case AUDIO_ENCODING_ULAW: 355 case AUDIO_ENCODING_ULAW:
356 idat = AFMT_MU_LAW; 356 idat = AFMT_MU_LAW;
357 break; 357 break;
358 case AUDIO_ENCODING_ALAW: 358 case AUDIO_ENCODING_ALAW:
359 idat = AFMT_A_LAW; 359 idat = AFMT_A_LAW;
360 break; 360 break;
361 case AUDIO_ENCODING_SLINEAR_LE: 361 case AUDIO_ENCODING_SLINEAR_LE:
362 if (precision == 32) 362 if (precision == 32)
363 idat = AFMT_S32_LE; 363 idat = AFMT_S32_LE;
364 else if (precision == 24) 364 else if (precision == 24)
365 idat = AFMT_S24_LE; 365 idat = AFMT_S24_LE;
366 else if (precision == 16) 366 else if (precision == 16)
367 idat = AFMT_S16_LE; 367 idat = AFMT_S16_LE;
368 else 368 else
369 idat = AFMT_S8; 369 idat = AFMT_S8;
370 break; 370 break;
371 case AUDIO_ENCODING_SLINEAR_BE: 371 case AUDIO_ENCODING_SLINEAR_BE:
372 if (precision == 32) 372 if (precision == 32)
373 idat = AFMT_S32_BE; 373 idat = AFMT_S32_BE;
374 else if (precision == 24) 374 else if (precision == 24)
375 idat = AFMT_S24_BE; 375 idat = AFMT_S24_BE;
376 else if (precision == 16) 376 else if (precision == 16)
377 idat = AFMT_S16_BE; 377 idat = AFMT_S16_BE;
378 else 378 else
379 idat = AFMT_S8; 379 idat = AFMT_S8;
380 break; 380 break;
381 case AUDIO_ENCODING_ULINEAR_LE: 381 case AUDIO_ENCODING_ULINEAR_LE:
382 if (precision == 16) 382 if (precision == 16)
383 idat = AFMT_U16_LE; 383 idat = AFMT_U16_LE;
384 else 384 else
385 idat = AFMT_U8; 385 idat = AFMT_U8;
386 break; 386 break;
387 case AUDIO_ENCODING_ULINEAR_BE: 387 case AUDIO_ENCODING_ULINEAR_BE:
388 if (precision == 16) 388 if (precision == 16)
389 idat = AFMT_U16_BE; 389 idat = AFMT_U16_BE;
390 else 390 else
391 idat = AFMT_U8; 391 idat = AFMT_U8;
392 break; 392 break;
393 case AUDIO_ENCODING_ADPCM: 393 case AUDIO_ENCODING_ADPCM:
394 idat = AFMT_IMA_ADPCM; 394 idat = AFMT_IMA_ADPCM;
395 break; 395 break;
396 case AUDIO_ENCODING_AC3: 396 case AUDIO_ENCODING_AC3:
397 idat = AFMT_AC3; 397 idat = AFMT_AC3;
398 break; 398 break;
399 } 399 }
400 INTARG = idat; 400 INTARG = idat;
401 break; 401 break;
402 case SNDCTL_DSP_CHANNELS: 402 case SNDCTL_DSP_CHANNELS:
403 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 403 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
404 if (retval < 0) 404 if (retval < 0)
405 return retval; 405 return retval;
406 setchannels(fd, tmpinfo.mode, INTARG); 406 setchannels(fd, tmpinfo.mode, INTARG);
407 /* FALLTHRU */ 407 /* FALLTHRU */
408 case SOUND_PCM_READ_CHANNELS: 408 case SOUND_PCM_READ_CHANNELS:
409 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 409 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
410 if (retval < 0) 410 if (retval < 0)
411 return retval; 411 return retval;
412 INTARG = GETPRINFO(&tmpinfo, channels); 412 INTARG = GETPRINFO(&tmpinfo, channels);
413 break; 413 break;
414 case SOUND_PCM_WRITE_FILTER: 414 case SOUND_PCM_WRITE_FILTER:
415 case SOUND_PCM_READ_FILTER: 415 case SOUND_PCM_READ_FILTER:
416 errno = EINVAL; 416 errno = EINVAL;
417 return -1; /* XXX unimplemented */ 417 return -1; /* XXX unimplemented */
418 case SNDCTL_DSP_SUBDIVIDE: 418 case SNDCTL_DSP_SUBDIVIDE:
419 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 419 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
420 if (retval < 0) 420 if (retval < 0)
421 return retval; 421 return retval;
422 setblocksize(fd, &tmpinfo); 422 setblocksize(fd, &tmpinfo);
423 idat = INTARG; 423 idat = INTARG;
424 if (idat == 0) 424 if (idat == 0)
425 idat = tmpinfo.play.buffer_size / tmpinfo.blocksize; 425 idat = tmpinfo.play.buffer_size / tmpinfo.blocksize;
426 idat = (tmpinfo.play.buffer_size / idat) & -4; 426 idat = (tmpinfo.play.buffer_size / idat) & -4;
427 AUDIO_INITINFO(&tmpinfo); 427 AUDIO_INITINFO(&tmpinfo);
428 tmpinfo.blocksize = idat; 428 tmpinfo.blocksize = idat;
429 retval = ioctl(fd, AUDIO_SETINFO, &tmpinfo); 429 retval = ioctl(fd, AUDIO_SETINFO, &tmpinfo);
430 if (retval < 0) 430 if (retval < 0)
431 return retval; 431 return retval;
432 INTARG = tmpinfo.play.buffer_size / tmpinfo.blocksize; 432 INTARG = tmpinfo.play.buffer_size / tmpinfo.blocksize;
433 break; 433 break;
434 case SNDCTL_DSP_SETFRAGMENT: 434 case SNDCTL_DSP_SETFRAGMENT:
435 AUDIO_INITINFO(&tmpinfo); 435 AUDIO_INITINFO(&tmpinfo);
436 idat = INTARG; 436 idat = INTARG;
437 if ((idat & 0xffff) < 4 || (idat & 0xffff) > 17) { 437 if ((idat & 0xffff) < 4 || (idat & 0xffff) > 17) {
438 errno = EINVAL; 438 errno = EINVAL;
439 return -1; 439 return -1;
440 } 440 }
441 tmpinfo.blocksize = 1 << (idat & 0xffff); 441 tmpinfo.blocksize = 1 << (idat & 0xffff);
442 tmpinfo.hiwat = ((unsigned)idat >> 16) & 0x7fff; 442 tmpinfo.hiwat = ((unsigned)idat >> 16) & 0x7fff;
443 if (tmpinfo.hiwat == 0) /* 0 means set to max */ 443 if (tmpinfo.hiwat == 0) /* 0 means set to max */
444 tmpinfo.hiwat = 65536; 444 tmpinfo.hiwat = 65536;
445 (void) ioctl(fd, AUDIO_SETINFO, &tmpinfo); 445 (void) ioctl(fd, AUDIO_SETINFO, &tmpinfo);
446 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 446 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
447 if (retval < 0) 447 if (retval < 0)
448 return retval; 448 return retval;
449 u = tmpinfo.blocksize; 449 u = tmpinfo.blocksize;
450 for(idat = 0; u > 1; idat++, u >>= 1) 450 for(idat = 0; u > 1; idat++, u >>= 1)
451 ; 451 ;
452 idat |= (tmpinfo.hiwat & 0x7fff) << 16; 452 idat |= (tmpinfo.hiwat & 0x7fff) << 16;
453 INTARG = idat; 453 INTARG = idat;
454 break; 454 break;
455 case SNDCTL_DSP_GETFMTS: 455 case SNDCTL_DSP_GETFMTS:
456 for(idat = 0, tmpenc.index = 0; 456 for(idat = 0, tmpenc.index = 0;
457 ioctl(fd, AUDIO_GETENC, &tmpenc) == 0; 457 ioctl(fd, AUDIO_GETENC, &tmpenc) == 0;
458 tmpenc.index++) { 458 tmpenc.index++) {
459 switch(tmpenc.encoding) { 459 switch(tmpenc.encoding) {
460 case AUDIO_ENCODING_ULAW: 460 case AUDIO_ENCODING_ULAW:
461 idat |= AFMT_MU_LAW; 461 idat |= AFMT_MU_LAW;
462 break; 462 break;
463 case AUDIO_ENCODING_ALAW: 463 case AUDIO_ENCODING_ALAW:
464 idat |= AFMT_A_LAW; 464 idat |= AFMT_A_LAW;
465 break; 465 break;
466 case AUDIO_ENCODING_SLINEAR: 466 case AUDIO_ENCODING_SLINEAR:
467 idat |= AFMT_S8; 467 idat |= AFMT_S8;
468 break; 468 break;
469 case AUDIO_ENCODING_SLINEAR_LE: 469 case AUDIO_ENCODING_SLINEAR_LE:
470 if (tmpenc.precision == 32) 470 if (tmpenc.precision == 32)
471 idat |= AFMT_S32_LE; 471 idat |= AFMT_S32_LE;
472 else if (tmpenc.precision == 24) 472 else if (tmpenc.precision == 24)
473 idat |= AFMT_S24_LE; 473 idat |= AFMT_S24_LE;
474 else if (tmpenc.precision == 16) 474 else if (tmpenc.precision == 16)
475 idat |= AFMT_S16_LE; 475 idat |= AFMT_S16_LE;
476 else 476 else
477 idat |= AFMT_S8; 477 idat |= AFMT_S8;
478 break; 478 break;
479 case AUDIO_ENCODING_SLINEAR_BE: 479 case AUDIO_ENCODING_SLINEAR_BE:
480 if (tmpenc.precision == 32) 480 if (tmpenc.precision == 32)
481 idat |= AFMT_S32_BE; 481 idat |= AFMT_S32_BE;
482 else if (tmpenc.precision == 24) 482 else if (tmpenc.precision == 24)
483 idat |= AFMT_S24_BE; 483 idat |= AFMT_S24_BE;
484 else if (tmpenc.precision == 16) 484 else if (tmpenc.precision == 16)
485 idat |= AFMT_S16_BE; 485 idat |= AFMT_S16_BE;
486 else 486 else
487 idat |= AFMT_S8; 487 idat |= AFMT_S8;
488 break; 488 break;
489 case AUDIO_ENCODING_ULINEAR: 489 case AUDIO_ENCODING_ULINEAR:
490 idat |= AFMT_U8; 490 idat |= AFMT_U8;
491 break; 491 break;
492 case AUDIO_ENCODING_ULINEAR_LE: 492 case AUDIO_ENCODING_ULINEAR_LE:
493 if (tmpenc.precision == 16) 493 if (tmpenc.precision == 16)
494 idat |= AFMT_U16_LE; 494 idat |= AFMT_U16_LE;
495 else 495 else
496 idat |= AFMT_U8; 496 idat |= AFMT_U8;
497 break; 497 break;
498 case AUDIO_ENCODING_ULINEAR_BE: 498 case AUDIO_ENCODING_ULINEAR_BE:
499 if (tmpenc.precision == 16) 499 if (tmpenc.precision == 16)
500 idat |= AFMT_U16_BE; 500 idat |= AFMT_U16_BE;
501 else 501 else
502 idat |= AFMT_U8; 502 idat |= AFMT_U8;
503 break; 503 break;
504 case AUDIO_ENCODING_ADPCM: 504 case AUDIO_ENCODING_ADPCM:
505 idat |= AFMT_IMA_ADPCM; 505 idat |= AFMT_IMA_ADPCM;
506 break; 506 break;
507 case AUDIO_ENCODING_AC3: 507 case AUDIO_ENCODING_AC3:
508 idat |= AFMT_AC3; 508 idat |= AFMT_AC3;
509 break; 509 break;
510 default: 510 default:
511 break; 511 break;
512 } 512 }
513 } 513 }
514 INTARG = idat; 514 INTARG = idat;
515 break; 515 break;
516 case SNDCTL_DSP_GETOSPACE: 516 case SNDCTL_DSP_GETOSPACE:
517 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 517 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
518 if (retval < 0) 518 if (retval < 0)
519 return retval; 519 return retval;
520 setblocksize(fd, &tmpinfo); 520 setblocksize(fd, &tmpinfo);
521 bufinfo.fragsize = tmpinfo.blocksize; 521 bufinfo.fragsize = tmpinfo.blocksize;
522 bufinfo.fragments = tmpinfo.hiwat - (tmpinfo.play.seek 522 bufinfo.fragments = tmpinfo.hiwat - (tmpinfo.play.seek
523 + tmpinfo.blocksize - 1) / tmpinfo.blocksize; 523 + tmpinfo.blocksize - 1) / tmpinfo.blocksize;
524 bufinfo.fragstotal = tmpinfo.hiwat; 524 bufinfo.fragstotal = tmpinfo.hiwat;
525 bufinfo.bytes = tmpinfo.hiwat * tmpinfo.blocksize 525 bufinfo.bytes = tmpinfo.hiwat * tmpinfo.blocksize
526 - tmpinfo.play.seek; 526 - tmpinfo.play.seek;
527 *(struct audio_buf_info *)argp = bufinfo; 527 *(struct audio_buf_info *)argp = bufinfo;
528 break; 528 break;
529 case SNDCTL_DSP_GETISPACE: 529 case SNDCTL_DSP_GETISPACE:
530 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 530 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
531 if (retval < 0) 531 if (retval < 0)
532 return retval; 532 return retval;
533 setblocksize(fd, &tmpinfo); 533 setblocksize(fd, &tmpinfo);
534 bufinfo.fragsize = tmpinfo.blocksize; 534 bufinfo.fragsize = tmpinfo.blocksize;
535 bufinfo.fragments = tmpinfo.record.seek / tmpinfo.blocksize; 535 bufinfo.fragments = tmpinfo.record.seek / tmpinfo.blocksize;
536 bufinfo.fragstotal = 536 bufinfo.fragstotal =
537 tmpinfo.record.buffer_size / tmpinfo.blocksize; 537 tmpinfo.record.buffer_size / tmpinfo.blocksize;
538 bufinfo.bytes = tmpinfo.record.seek; 538 bufinfo.bytes = tmpinfo.record.seek;
539 *(struct audio_buf_info *)argp = bufinfo; 539 *(struct audio_buf_info *)argp = bufinfo;
540 break; 540 break;
541 case SNDCTL_DSP_NONBLOCK: 541 case SNDCTL_DSP_NONBLOCK:
542 idat = 1; 542 idat = 1;
543 retval = ioctl(fd, FIONBIO, &idat); 543 retval = ioctl(fd, FIONBIO, &idat);
544 if (retval < 0) 544 if (retval < 0)
545 return retval; 545 return retval;
546 break; 546 break;
547 case SNDCTL_DSP_GETCAPS: 547 case SNDCTL_DSP_GETCAPS:
548 retval = getcaps(fd, (int *)argp); 548 retval = getcaps(fd, (int *)argp);
549 if (retval < 0) 549 if (retval < 0)
550 return retval; 550 return retval;
551 break; 551 break;
552 case SNDCTL_DSP_SETTRIGGER: 552 case SNDCTL_DSP_SETTRIGGER:
553 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 553 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
554 if (retval < 0) 554 if (retval < 0)
555 return retval; 555 return retval;
556 AUDIO_INITINFO(&tmpinfo); 556 AUDIO_INITINFO(&tmpinfo);
557 if (tmpinfo.mode & AUMODE_PLAY) 557 if (tmpinfo.mode & AUMODE_PLAY)
558 tmpinfo.play.pause = (INTARG & PCM_ENABLE_OUTPUT) == 0; 558 tmpinfo.play.pause = (INTARG & PCM_ENABLE_OUTPUT) == 0;
559 if (tmpinfo.mode & AUMODE_RECORD) 559 if (tmpinfo.mode & AUMODE_RECORD)
560 tmpinfo.record.pause = (INTARG & PCM_ENABLE_INPUT) == 0; 560 tmpinfo.record.pause = (INTARG & PCM_ENABLE_INPUT) == 0;
561 (void)ioctl(fd, AUDIO_SETINFO, &tmpinfo); 561 (void)ioctl(fd, AUDIO_SETINFO, &tmpinfo);
562 /* FALLTHRU */ 562 /* FALLTHRU */
563 case SNDCTL_DSP_GETTRIGGER: 563 case SNDCTL_DSP_GETTRIGGER:
564 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 564 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
565 if (retval < 0) 565 if (retval < 0)
566 return retval; 566 return retval;
567 idat = 0; 567 idat = 0;
568 if ((tmpinfo.mode & AUMODE_PLAY) && !tmpinfo.play.pause) 568 if ((tmpinfo.mode & AUMODE_PLAY) && !tmpinfo.play.pause)
569 idat |= PCM_ENABLE_OUTPUT; 569 idat |= PCM_ENABLE_OUTPUT;
570 if ((tmpinfo.mode & AUMODE_RECORD) && !tmpinfo.record.pause) 570 if ((tmpinfo.mode & AUMODE_RECORD) && !tmpinfo.record.pause)
571 idat |= PCM_ENABLE_INPUT; 571 idat |= PCM_ENABLE_INPUT;
572 INTARG = idat; 572 INTARG = idat;
573 break; 573 break;
574 case SNDCTL_DSP_GETIPTR: 574 case SNDCTL_DSP_GETIPTR:
575 retval = ioctl(fd, AUDIO_GETIOFFS, &tmpoffs); 575 retval = ioctl(fd, AUDIO_GETIOFFS, &tmpoffs);
576 if (retval < 0) 576 if (retval < 0)
577 return retval; 577 return retval;
578 cntinfo.bytes = tmpoffs.samples; 578 cntinfo.bytes = tmpoffs.samples;
579 cntinfo.blocks = tmpoffs.deltablks; 579 cntinfo.blocks = tmpoffs.deltablks;
580 cntinfo.ptr = tmpoffs.offset; 580 cntinfo.ptr = tmpoffs.offset;
581 *(struct count_info *)argp = cntinfo; 581 *(struct count_info *)argp = cntinfo;
582 break; 582 break;
583 case SNDCTL_DSP_CURRENT_IPTR: 583 case SNDCTL_DSP_CURRENT_IPTR:
584 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 584 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
585 if (retval < 0) 585 if (retval < 0)
586 return retval; 586 return retval;
587 /* XXX: 'samples' may wrap */ 587 /* XXX: 'samples' may wrap */
588 memset(osscount.filler, 0, sizeof(osscount.filler)); 588 memset(osscount.filler, 0, sizeof(osscount.filler));
589 osscount.samples = tmpinfo.record.samples / 589 osscount.samples = tmpinfo.record.samples /
590 ((tmpinfo.record.precision / NBBY) * 590 ((tmpinfo.record.precision / NBBY) *
591 tmpinfo.record.channels); 591 tmpinfo.record.channels);
592 osscount.fifo_samples = tmpinfo.record.seek / 592 osscount.fifo_samples = tmpinfo.record.seek /
593 ((tmpinfo.record.precision / NBBY) * 593 ((tmpinfo.record.precision / NBBY) *
594 tmpinfo.record.channels); 594 tmpinfo.record.channels);
595 *(oss_count_t *)argp = osscount; 595 *(oss_count_t *)argp = osscount;
596 break; 596 break;
597 case SNDCTL_DSP_GETOPTR: 597 case SNDCTL_DSP_GETOPTR:
598 retval = ioctl(fd, AUDIO_GETOOFFS, &tmpoffs); 598 retval = ioctl(fd, AUDIO_GETOOFFS, &tmpoffs);
599 if (retval < 0) 599 if (retval < 0)
600 return retval; 600 return retval;
601 cntinfo.bytes = tmpoffs.samples; 601 cntinfo.bytes = tmpoffs.samples;
602 cntinfo.blocks = tmpoffs.deltablks; 602 cntinfo.blocks = tmpoffs.deltablks;
603 cntinfo.ptr = tmpoffs.offset; 603 cntinfo.ptr = tmpoffs.offset;
604 *(struct count_info *)argp = cntinfo; 604 *(struct count_info *)argp = cntinfo;
605 break; 605 break;
606 case SNDCTL_DSP_CURRENT_OPTR: 606 case SNDCTL_DSP_CURRENT_OPTR:
607 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 607 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
608 if (retval < 0) 608 if (retval < 0)
609 return retval; 609 return retval;
610 /* XXX: 'samples' may wrap */ 610 /* XXX: 'samples' may wrap */
611 memset(osscount.filler, 0, sizeof(osscount.filler)); 611 memset(osscount.filler, 0, sizeof(osscount.filler));
612 osscount.samples = tmpinfo.play.samples / 612 osscount.samples = tmpinfo.play.samples /
613 ((tmpinfo.play.precision / NBBY) * 613 ((tmpinfo.play.precision / NBBY) *
614 tmpinfo.play.channels); 614 tmpinfo.play.channels);
615 osscount.fifo_samples = tmpinfo.play.seek / 615 osscount.fifo_samples = tmpinfo.play.seek /
616 ((tmpinfo.play.precision / NBBY) * 616 ((tmpinfo.play.precision / NBBY) *
617 tmpinfo.play.channels); 617 tmpinfo.play.channels);
618 *(oss_count_t *)argp = osscount; 618 *(oss_count_t *)argp = osscount;
619 break; 619 break;
620 case SNDCTL_DSP_SETPLAYVOL: 620 case SNDCTL_DSP_SETPLAYVOL:
621 setvol(fd, INTARG, false); 621 setvol(fd, INTARG, false);
622 /* FALLTHRU */ 622 /* FALLTHRU */
623 case SNDCTL_DSP_GETPLAYVOL: 623 case SNDCTL_DSP_GETPLAYVOL:
624 retval = ioctl(fd, AUDIO_GETINFO, &tmpinfo); 624 retval = ioctl(fd, AUDIO_GETINFO, &tmpinfo);
625 if (retval < 0) 625 if (retval < 0)
626 return retval; 626 return retval;
627 INTARG = getvol(tmpinfo.play.gain, tmpinfo.play.balance); 627 INTARG = getvol(tmpinfo.play.gain, tmpinfo.play.balance);
628 break; 628 break;
629 case SNDCTL_DSP_SETRECVOL: 629 case SNDCTL_DSP_SETRECVOL:
630 setvol(fd, INTARG, true); 630 setvol(fd, INTARG, true);
631 /* FALLTHRU */ 631 /* FALLTHRU */
632 case SNDCTL_DSP_GETRECVOL: 632 case SNDCTL_DSP_GETRECVOL:
633 retval = ioctl(fd, AUDIO_GETINFO, &tmpinfo); 633 retval = ioctl(fd, AUDIO_GETINFO, &tmpinfo);
634 if (retval < 0) 634 if (retval < 0)
635 return retval; 635 return retval;
636 INTARG = getvol(tmpinfo.record.gain, tmpinfo.record.balance); 636 INTARG = getvol(tmpinfo.record.gain, tmpinfo.record.balance);
637 break; 637 break;
638 case SNDCTL_DSP_SKIP: 638 case SNDCTL_DSP_SKIP:
639 case SNDCTL_DSP_SILENCE:  639 case SNDCTL_DSP_SILENCE:
640 errno = EINVAL; 640 errno = EINVAL;
641 return -1; 641 return -1;
642 case SNDCTL_DSP_SETDUPLEX: 642 case SNDCTL_DSP_SETDUPLEX:
643 idat = 1; 643 idat = 1;
644 retval = ioctl(fd, AUDIO_SETFD, &idat); 644 retval = ioctl(fd, AUDIO_SETFD, &idat);
645 if (retval < 0) 645 if (retval < 0)
646 return retval; 646 return retval;
647 break; 647 break;
648 case SNDCTL_DSP_GETODELAY: 648 case SNDCTL_DSP_GETODELAY:
649 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 649 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
650 if (retval < 0) 650 if (retval < 0)
651 return retval; 651 return retval;
652 idat = tmpinfo.play.seek + tmpinfo.blocksize / 2; 652 idat = tmpinfo.play.seek + tmpinfo.blocksize / 2;
653 INTARG = idat; 653 INTARG = idat;
654 break; 654 break;
655 case SNDCTL_DSP_PROFILE: 655 case SNDCTL_DSP_PROFILE:
656 /* This gives just a hint to the driver, 656 /* This gives just a hint to the driver,
657 * implementing it as a NOP is ok 657 * implementing it as a NOP is ok
658 */  658 */
659 break; 659 break;
660 case SNDCTL_DSP_MAPINBUF: 660 case SNDCTL_DSP_MAPINBUF:
661 case SNDCTL_DSP_MAPOUTBUF: 661 case SNDCTL_DSP_MAPOUTBUF:
662 case SNDCTL_DSP_SETSYNCRO: 662 case SNDCTL_DSP_SETSYNCRO:
663 errno = EINVAL; 663 errno = EINVAL;
664 return -1; /* XXX unimplemented */ 664 return -1; /* XXX unimplemented */
665 default: 665 default:
666 errno = EINVAL; 666 errno = EINVAL;
667 return -1; 667 return -1;
668 } 668 }
669 669
670 return 0; 670 return 0;
671} 671}
672 672
673 673
674/* If the NetBSD mixer device should have more than NETBSD_MAXDEVS devices 674/* If the NetBSD mixer device should have more than NETBSD_MAXDEVS devices
675 * some will not be available to OSS applications */ 675 * some will not be available to OSS applications */
676#define NETBSD_MAXDEVS 64 676#define NETBSD_MAXDEVS 64
677struct audiodevinfo { 677struct audiodevinfo {
678 int done; 678 int done;
679 dev_t dev; 679 dev_t dev;
680 int16_t devmap[SOUND_MIXER_NRDEVICES], 680 int16_t devmap[SOUND_MIXER_NRDEVICES],
681 rdevmap[NETBSD_MAXDEVS]; 681 rdevmap[NETBSD_MAXDEVS];
682 char names[NETBSD_MAXDEVS][MAX_AUDIO_DEV_LEN]; 682 char names[NETBSD_MAXDEVS][MAX_AUDIO_DEV_LEN];
683 int enum2opaque[NETBSD_MAXDEVS]; 683 int enum2opaque[NETBSD_MAXDEVS];
684 u_long devmask, recmask, stereomask; 684 u_long devmask, recmask, stereomask;
685 u_long caps; 685 u_long caps;
686 int source; 686 int source;
687}; 687};
688 688
689static int 689static int
690opaque_to_enum(struct audiodevinfo *di, audio_mixer_name_t *label, int opq) 690opaque_to_enum(struct audiodevinfo *di, audio_mixer_name_t *label, int opq)
691{ 691{
692 int i, o; 692 int i, o;
693 693
694 for (i = 0; i < NETBSD_MAXDEVS; i++) { 694 for (i = 0; i < NETBSD_MAXDEVS; i++) {
695 o = di->enum2opaque[i]; 695 o = di->enum2opaque[i];
696 if (o == opq) 696 if (o == opq)
697 break; 697 break;
698 if (o == -1 && label != NULL && 698 if (o == -1 && label != NULL &&
699 !strncmp(di->names[i], label->name, sizeof di->names[i])) { 699 !strncmp(di->names[i], label->name, sizeof di->names[i])) {
700 di->enum2opaque[i] = opq; 700 di->enum2opaque[i] = opq;
701 break; 701 break;
702 } 702 }
703 } 703 }
704 if (i >= NETBSD_MAXDEVS) 704 if (i >= NETBSD_MAXDEVS)
705 i = -1; 705 i = -1;
706 /*printf("opq_to_enum %s %d -> %d\n", label->name, opq, i);*/ 706 /*printf("opq_to_enum %s %d -> %d\n", label->name, opq, i);*/
707 return (i); 707 return (i);
708} 708}
709 709
710static int 710static int
711enum_to_ord(struct audiodevinfo *di, int enm) 711enum_to_ord(struct audiodevinfo *di, int enm)
712{ 712{
713 if (enm >= NETBSD_MAXDEVS) 713 if (enm >= NETBSD_MAXDEVS)
714 return (-1); 714 return (-1);
715 715
716 /*printf("enum_to_ord %d -> %d\n", enm, di->enum2opaque[enm]);*/ 716 /*printf("enum_to_ord %d -> %d\n", enm, di->enum2opaque[enm]);*/
717 return (di->enum2opaque[enm]); 717 return (di->enum2opaque[enm]);
718} 718}
719 719
720static int 720static int
721enum_to_mask(struct audiodevinfo *di, int enm) 721enum_to_mask(struct audiodevinfo *di, int enm)
722{ 722{
723 int m; 723 int m;
724 if (enm >= NETBSD_MAXDEVS) 724 if (enm >= NETBSD_MAXDEVS)
725 return (0); 725 return (0);
726 726
727 m = di->enum2opaque[enm]; 727 m = di->enum2opaque[enm];
728 if (m == -1) 728 if (m == -1)
729 m = 0; 729 m = 0;
730 /*printf("enum_to_mask %d -> %d\n", enm, di->enum2opaque[enm]);*/ 730 /*printf("enum_to_mask %d -> %d\n", enm, di->enum2opaque[enm]);*/
731 return (m); 731 return (m);
732} 732}
733 733
734/* 734/*
735 * Collect the audio device information to allow faster 735 * Collect the audio device information to allow faster
736 * emulation of the OSSv3 mixer ioctls. Cache the information 736 * emulation of the OSSv3 mixer ioctls. Cache the information
737 * to eliminate the overhead of repeating all the ioctls needed 737 * to eliminate the overhead of repeating all the ioctls needed
738 * to collect the information. 738 * to collect the information.
739 */ 739 */
740static struct audiodevinfo * 740static struct audiodevinfo *
741getdevinfo(int fd) 741getdevinfo(int fd)
742{ 742{
743 mixer_devinfo_t mi; 743 mixer_devinfo_t mi;
744 int i, j, e; 744 int i, j, e;
745 static struct { 745 static struct {
746 const char *name; 746 const char *name;
747 int code; 747 int code;
748 } *dp, devs[] = { 748 } *dp, devs[] = {
749 { AudioNmicrophone, SOUND_MIXER_MIC }, 749 { AudioNmicrophone, SOUND_MIXER_MIC },
750 { AudioNline, SOUND_MIXER_LINE }, 750 { AudioNline, SOUND_MIXER_LINE },
751 { AudioNcd, SOUND_MIXER_CD }, 751 { AudioNcd, SOUND_MIXER_CD },
752 { AudioNdac, SOUND_MIXER_PCM }, 752 { AudioNdac, SOUND_MIXER_PCM },
753 { AudioNaux, SOUND_MIXER_LINE1 }, 753 { AudioNaux, SOUND_MIXER_LINE1 },
754 { AudioNrecord, SOUND_MIXER_IMIX }, 754 { AudioNrecord, SOUND_MIXER_IMIX },
755 { AudioNmaster, SOUND_MIXER_VOLUME }, 755 { AudioNmaster, SOUND_MIXER_VOLUME },
756 { AudioNtreble, SOUND_MIXER_TREBLE }, 756 { AudioNtreble, SOUND_MIXER_TREBLE },
757 { AudioNbass, SOUND_MIXER_BASS }, 757 { AudioNbass, SOUND_MIXER_BASS },
758 { AudioNspeaker, SOUND_MIXER_SPEAKER }, 758 { AudioNspeaker, SOUND_MIXER_SPEAKER },
759/* { AudioNheadphone, ?? },*/ 759/* { AudioNheadphone, ?? },*/
760 { AudioNoutput, SOUND_MIXER_OGAIN }, 760 { AudioNoutput, SOUND_MIXER_OGAIN },
761 { AudioNinput, SOUND_MIXER_IGAIN }, 761 { AudioNinput, SOUND_MIXER_IGAIN },
762/* { AudioNmaster, SOUND_MIXER_SPEAKER },*/ 762/* { AudioNmaster, SOUND_MIXER_SPEAKER },*/
763/* { AudioNstereo, ?? },*/ 763/* { AudioNstereo, ?? },*/
764/* { AudioNmono, ?? },*/ 764/* { AudioNmono, ?? },*/
765 { AudioNfmsynth, SOUND_MIXER_SYNTH }, 765 { AudioNfmsynth, SOUND_MIXER_SYNTH },
766/* { AudioNwave, SOUND_MIXER_PCM },*/ 766/* { AudioNwave, SOUND_MIXER_PCM },*/
767 { AudioNmidi, SOUND_MIXER_SYNTH }, 767 { AudioNmidi, SOUND_MIXER_SYNTH },
768/* { AudioNmixerout, ?? },*/ 768/* { AudioNmixerout, ?? },*/
769 { 0, -1 } 769 { 0, -1 }
770 }; 770 };
771 static struct audiodevinfo devcache = { .done = 0 }; 771 static struct audiodevinfo devcache = { .done = 0 };
772 struct audiodevinfo *di = &devcache; 772 struct audiodevinfo *di = &devcache;
773 struct stat sb; 773 struct stat sb;
774 size_t mlen, dlen; 774 size_t mlen, dlen;
775 775
776 /* Figure out what device it is so we can check if the 776 /* Figure out what device it is so we can check if the
777 * cached data is valid. 777 * cached data is valid.
778 */ 778 */
779 if (fstat(fd, &sb) < 0) 779 if (fstat(fd, &sb) < 0)
780 return 0; 780 return 0;
781 if (di->done && di->dev == sb.st_dev) 781 if (di->done && di->dev == sb.st_dev)
782 return di; 782 return di;
783 783
784 di->done = 1; 784 di->done = 1;
785 di->dev = sb.st_dev; 785 di->dev = sb.st_dev;
786 di->devmask = 0; 786 di->devmask = 0;
787 di->recmask = 0; 787 di->recmask = 0;
788 di->stereomask = 0; 788 di->stereomask = 0;
789 di->source = ~0; 789 di->source = ~0;
790 di->caps = 0; 790 di->caps = 0;
791 for(i = 0; i < SOUND_MIXER_NRDEVICES; i++) 791 for(i = 0; i < SOUND_MIXER_NRDEVICES; i++)
792 di->devmap[i] = -1; 792 di->devmap[i] = -1;
793 for(i = 0; i < NETBSD_MAXDEVS; i++) { 793 for(i = 0; i < NETBSD_MAXDEVS; i++) {
794 di->rdevmap[i] = -1; 794 di->rdevmap[i] = -1;
795 di->names[i][0] = '\0'; 795 di->names[i][0] = '\0';
796 di->enum2opaque[i] = -1; 796 di->enum2opaque[i] = -1;
797 } 797 }
798 for(i = 0; i < NETBSD_MAXDEVS; i++) { 798 for(i = 0; i < NETBSD_MAXDEVS; i++) {
799 mi.index = i; 799 mi.index = i;
800 if (ioctl(fd, AUDIO_MIXER_DEVINFO, &mi) < 0) 800 if (ioctl(fd, AUDIO_MIXER_DEVINFO, &mi) < 0)
801 break; 801 break;
802 switch(mi.type) { 802 switch(mi.type) {
803 case AUDIO_MIXER_VALUE: 803 case AUDIO_MIXER_VALUE:
804 for(dp = devs; dp->name; dp++) { 804 for(dp = devs; dp->name; dp++) {
805 if (strcmp(dp->name, mi.label.name) == 0) 805 if (strcmp(dp->name, mi.label.name) == 0)
806 break; 806 break;
807 dlen = strlen(dp->name); 807 dlen = strlen(dp->name);
808 mlen = strlen(mi.label.name); 808 mlen = strlen(mi.label.name);
809 if (dlen < mlen 809 if (dlen < mlen
810 && mi.label.name[mlen-dlen-1] == '.' 810 && mi.label.name[mlen-dlen-1] == '.'
811 && strcmp(dp->name, 811 && strcmp(dp->name,
812 mi.label.name + mlen - dlen) == 0) 812 mi.label.name + mlen - dlen) == 0)
813 break; 813 break;
814 } 814 }
815 if (dp->code >= 0) { 815 if (dp->code >= 0) {
816 di->devmap[dp->code] = i; 816 di->devmap[dp->code] = i;
817 di->rdevmap[i] = dp->code; 817 di->rdevmap[i] = dp->code;
818 di->devmask |= 1 << dp->code; 818 di->devmask |= 1 << dp->code;
819 if (mi.un.v.num_channels == 2) 819 if (mi.un.v.num_channels == 2)
820 di->stereomask |= 1 << dp->code; 820 di->stereomask |= 1 << dp->code;
821 strlcpy(di->names[i], mi.label.name, 821 strlcpy(di->names[i], mi.label.name,
822 sizeof di->names[i]); 822 sizeof di->names[i]);
823 } 823 }
824 break; 824 break;
825 } 825 }
826 } 826 }
827 for(i = 0; i < NETBSD_MAXDEVS; i++) { 827 for(i = 0; i < NETBSD_MAXDEVS; i++) {
828 mi.index = i; 828 mi.index = i;
829 if (ioctl(fd, AUDIO_MIXER_DEVINFO, &mi) < 0) 829 if (ioctl(fd, AUDIO_MIXER_DEVINFO, &mi) < 0)
830 break; 830 break;
831 if (strcmp(mi.label.name, AudioNsource) != 0) 831 if (strcmp(mi.label.name, AudioNsource) != 0)
832 continue; 832 continue;
833 di->source = i; 833 di->source = i;
834 switch(mi.type) { 834 switch(mi.type) {
835 case AUDIO_MIXER_ENUM: 835 case AUDIO_MIXER_ENUM:
836 for(j = 0; j < mi.un.e.num_mem; j++) { 836 for(j = 0; j < mi.un.e.num_mem; j++) {
837 e = opaque_to_enum(di, 837 e = opaque_to_enum(di,
838 &mi.un.e.member[j].label, 838 &mi.un.e.member[j].label,
839 mi.un.e.member[j].ord); 839 mi.un.e.member[j].ord);
840 if (e >= 0) 840 if (e >= 0)
841 di->recmask |= 1 << di->rdevmap[e]; 841 di->recmask |= 1 << di->rdevmap[e];
842 } 842 }
843 di->caps = SOUND_CAP_EXCL_INPUT; 843 di->caps = SOUND_CAP_EXCL_INPUT;
844 break; 844 break;
845 case AUDIO_MIXER_SET: 845 case AUDIO_MIXER_SET:
846 for(j = 0; j < mi.un.s.num_mem; j++) { 846 for(j = 0; j < mi.un.s.num_mem; j++) {
847 e = opaque_to_enum(di, 847 e = opaque_to_enum(di,
848 &mi.un.s.member[j].label, 848 &mi.un.s.member[j].label,
849 mi.un.s.member[j].mask); 849 mi.un.s.member[j].mask);
850 if (e >= 0) 850 if (e >= 0)
851 di->recmask |= 1 << di->rdevmap[e]; 851 di->recmask |= 1 << di->rdevmap[e];
852 } 852 }
853 break; 853 break;
854 } 854 }
855 } 855 }
856 return di; 856 return di;
857} 857}
858 858
859static int 859static int
860mixer_oss3_ioctl(int fd, unsigned long com, void *argp) 860mixer_oss3_ioctl(int fd, unsigned long com, void *argp)
861{ 861{
862 struct audiodevinfo *di; 862 struct audiodevinfo *di;
863 struct mixer_info *omi; 863 struct mixer_info *omi;
864 struct audio_device adev; 864 struct audio_device adev;
865 mixer_ctrl_t mc; 865 mixer_ctrl_t mc;
866 u_long idat, n; 866 u_long idat, n;
867 int i; 867 int i;
868 int retval; 868 int retval;
869 int l, r, error, e; 869 int l, r, error, e;
870 870
871 idat = 0; 871 idat = 0;
872 di = getdevinfo(fd); 872 di = getdevinfo(fd);
873 if (di == 0) 873 if (di == 0)
874 return -1; 874 return -1;
875 875
876 switch (com) { 876 switch (com) {
877 case OSS_GETVERSION: 877 case OSS_GETVERSION:
878 idat = SOUND_VERSION; 878 idat = SOUND_VERSION;
879 break; 879 break;
880 case SOUND_MIXER_INFO: 880 case SOUND_MIXER_INFO:
881 case SOUND_OLD_MIXER_INFO: 881 case SOUND_OLD_MIXER_INFO:
882 error = ioctl(fd, AUDIO_GETDEV, &adev); 882 error = ioctl(fd, AUDIO_GETDEV, &adev);
883 if (error) 883 if (error)
884 return (error); 884 return (error);
885 omi = argp; 885 omi = argp;
886 if (com == SOUND_MIXER_INFO) 886 if (com == SOUND_MIXER_INFO)
887 omi->modify_counter = 1; 887 omi->modify_counter = 1;
888 strlcpy(omi->id, adev.name, sizeof omi->id); 888 strlcpy(omi->id, adev.name, sizeof omi->id);
889 strlcpy(omi->name, adev.name, sizeof omi->name); 889 strlcpy(omi->name, adev.name, sizeof omi->name);
890 return 0; 890 return 0;
891 case SOUND_MIXER_READ_RECSRC: 891 case SOUND_MIXER_READ_RECSRC:
892 if (di->source == -1) { 892 if (di->source == -1) {
893 errno = EINVAL; 893 errno = EINVAL;
894 return -1; 894 return -1;
895 } 895 }
896 mc.dev = di->source; 896 mc.dev = di->source;
897 if (di->caps & SOUND_CAP_EXCL_INPUT) { 897 if (di->caps & SOUND_CAP_EXCL_INPUT) {
898 mc.type = AUDIO_MIXER_ENUM; 898 mc.type = AUDIO_MIXER_ENUM;
899 retval = ioctl(fd, AUDIO_MIXER_READ, &mc); 899 retval = ioctl(fd, AUDIO_MIXER_READ, &mc);
900 if (retval < 0) 900 if (retval < 0)
901 return retval; 901 return retval;
902 e = opaque_to_enum(di, NULL, mc.un.ord); 902 e = opaque_to_enum(di, NULL, mc.un.ord);
903 if (e >= 0) 903 if (e >= 0)
904 idat = 1 << di->rdevmap[e]; 904 idat = 1 << di->rdevmap[e];
905 } else { 905 } else {
906 mc.type = AUDIO_MIXER_SET; 906 mc.type = AUDIO_MIXER_SET;
907 retval = ioctl(fd, AUDIO_MIXER_READ, &mc); 907 retval = ioctl(fd, AUDIO_MIXER_READ, &mc);
908 if (retval < 0) 908 if (retval < 0)
909 return retval; 909 return retval;
910 e = opaque_to_enum(di, NULL, mc.un.mask); 910 e = opaque_to_enum(di, NULL, mc.un.mask);
911 if (e >= 0) 911 if (e >= 0)
912 idat = 1 << di->rdevmap[e]; 912 idat = 1 << di->rdevmap[e];
913 } 913 }
914 break; 914 break;
915 case SOUND_MIXER_READ_DEVMASK: 915 case SOUND_MIXER_READ_DEVMASK:
916 idat = di->devmask; 916 idat = di->devmask;
917 break; 917 break;
918 case SOUND_MIXER_READ_RECMASK: 918 case SOUND_MIXER_READ_RECMASK:
919 idat = di->recmask; 919 idat = di->recmask;
920 break; 920 break;
921 case SOUND_MIXER_READ_STEREODEVS: 921 case SOUND_MIXER_READ_STEREODEVS:
922 idat = di->stereomask; 922 idat = di->stereomask;
923 break; 923 break;
924 case SOUND_MIXER_READ_CAPS: 924 case SOUND_MIXER_READ_CAPS:
925 idat = di->caps; 925 idat = di->caps;
926 break; 926 break;
927 case SOUND_MIXER_WRITE_RECSRC: 927 case SOUND_MIXER_WRITE_RECSRC:
928 case SOUND_MIXER_WRITE_R_RECSRC: 928 case SOUND_MIXER_WRITE_R_RECSRC:
929 if (di->source == -1) { 929 if (di->source == -1) {
930 errno = EINVAL; 930 errno = EINVAL;
931 return -1; 931 return -1;
932 } 932 }
933 mc.dev = di->source; 933 mc.dev = di->source;
934 idat = INTARG; 934 idat = INTARG;
935 if (di->caps & SOUND_CAP_EXCL_INPUT) { 935 if (di->caps & SOUND_CAP_EXCL_INPUT) {
936 mc.type = AUDIO_MIXER_ENUM; 936 mc.type = AUDIO_MIXER_ENUM;
937 for(i = 0; i < SOUND_MIXER_NRDEVICES; i++) 937 for(i = 0; i < SOUND_MIXER_NRDEVICES; i++)
938 if (idat & (1 << i)) 938 if (idat & (1 << i))
939 break; 939 break;
940 if (i >= SOUND_MIXER_NRDEVICES || 940 if (i >= SOUND_MIXER_NRDEVICES ||
941 di->devmap[i] == -1) { 941 di->devmap[i] == -1) {
942 errno = EINVAL; 942 errno = EINVAL;
943 return -1; 943 return -1;
944 } 944 }
945 mc.un.ord = enum_to_ord(di, di->devmap[i]); 945 mc.un.ord = enum_to_ord(di, di->devmap[i]);
946 } else { 946 } else {
947 mc.type = AUDIO_MIXER_SET; 947 mc.type = AUDIO_MIXER_SET;
948 mc.un.mask = 0; 948 mc.un.mask = 0;
949 for(i = 0; i < SOUND_MIXER_NRDEVICES; i++) { 949 for(i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
950 if (idat & (1 << i)) { 950 if (idat & (1 << i)) {
951 if (di->devmap[i] == -1) { 951 if (di->devmap[i] == -1) {
952 errno = EINVAL; 952 errno = EINVAL;
953 return -1; 953 return -1;
954 } 954 }
955 mc.un.mask |= 955 mc.un.mask |=
956 enum_to_mask(di, di->devmap[i]); 956 enum_to_mask(di, di->devmap[i]);
957 } 957 }
958 } 958 }
959 } 959 }
960 return ioctl(fd, AUDIO_MIXER_WRITE, &mc); 960 return ioctl(fd, AUDIO_MIXER_WRITE, &mc);
961 default: 961 default:
962 if (MIXER_READ(SOUND_MIXER_FIRST) <= com && 962 if (MIXER_READ(SOUND_MIXER_FIRST) <= com &&
963 com < MIXER_READ(SOUND_MIXER_NRDEVICES)) { 963 com < MIXER_READ(SOUND_MIXER_NRDEVICES)) {
964 n = GET_DEV(com); 964 n = GET_DEV(com);
965 if (di->devmap[n] == -1) { 965 if (di->devmap[n] == -1) {
966 errno = EINVAL; 966 errno = EINVAL;
967 return -1; 967 return -1;
968 } 968 }
969 mc.dev = di->devmap[n]; 969 mc.dev = di->devmap[n];
970 mc.type = AUDIO_MIXER_VALUE; 970 mc.type = AUDIO_MIXER_VALUE;
971 doread: 971 doread:
972 mc.un.value.num_channels = 972 mc.un.value.num_channels =
973 di->stereomask & (1 << (u_int)n) ? 2 : 1; 973 di->stereomask & (1 << (u_int)n) ? 2 : 1;
974 retval = ioctl(fd, AUDIO_MIXER_READ, &mc); 974 retval = ioctl(fd, AUDIO_MIXER_READ, &mc);
975 if (retval < 0) 975 if (retval < 0)
976 return retval; 976 return retval;
977 if (mc.type != AUDIO_MIXER_VALUE) { 977 if (mc.type != AUDIO_MIXER_VALUE) {
978 errno = EINVAL; 978 errno = EINVAL;
979 return -1; 979 return -1;
980 } 980 }
981 if (mc.un.value.num_channels != 2) { 981 if (mc.un.value.num_channels != 2) {
982 l = r = 982 l = r =
983 mc.un.value.level[AUDIO_MIXER_LEVEL_MONO]; 983 mc.un.value.level[AUDIO_MIXER_LEVEL_MONO];
984 } else { 984 } else {
985 l = mc.un.value.level[AUDIO_MIXER_LEVEL_LEFT]; 985 l = mc.un.value.level[AUDIO_MIXER_LEVEL_LEFT];
986 r = mc.un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; 986 r = mc.un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
987 } 987 }
988 idat = TO_OSSVOL(l) | (TO_OSSVOL(r) << 8); 988 idat = TO_OSSVOL(l) | (TO_OSSVOL(r) << 8);
989 break; 989 break;
990 } else if ((MIXER_WRITE_R(SOUND_MIXER_FIRST) <= com && 990 } else if ((MIXER_WRITE_R(SOUND_MIXER_FIRST) <= com &&
991 com < MIXER_WRITE_R(SOUND_MIXER_NRDEVICES)) || 991 com < MIXER_WRITE_R(SOUND_MIXER_NRDEVICES)) ||
992 (MIXER_WRITE(SOUND_MIXER_FIRST) <= com && 992 (MIXER_WRITE(SOUND_MIXER_FIRST) <= com &&
993 com < MIXER_WRITE(SOUND_MIXER_NRDEVICES))) { 993 com < MIXER_WRITE(SOUND_MIXER_NRDEVICES))) {
994 n = GET_DEV(com); 994 n = GET_DEV(com);
995 if (di->devmap[n] == -1) { 995 if (di->devmap[n] == -1) {
996 errno = EINVAL; 996 errno = EINVAL;
997 return -1; 997 return -1;
998 } 998 }
999 idat = INTARG; 999 idat = INTARG;
1000 l = FROM_OSSVOL((u_int)idat & 0xff); 1000 l = FROM_OSSVOL((u_int)idat & 0xff);
1001 r = FROM_OSSVOL(((u_int)idat >> 8) & 0xff); 1001 r = FROM_OSSVOL(((u_int)idat >> 8) & 0xff);
1002 mc.dev = di->devmap[n]; 1002 mc.dev = di->devmap[n];
1003 mc.type = AUDIO_MIXER_VALUE; 1003 mc.type = AUDIO_MIXER_VALUE;
1004 if (di->stereomask & (1 << (u_int)n)) { 1004 if (di->stereomask & (1 << (u_int)n)) {
1005 mc.un.value.num_channels = 2; 1005 mc.un.value.num_channels = 2;
1006 mc.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l; 1006 mc.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
1007 mc.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r; 1007 mc.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
1008 } else { 1008 } else {
1009 mc.un.value.num_channels = 1; 1009 mc.un.value.num_channels = 1;
1010 mc.un.value.level[AUDIO_MIXER_LEVEL_MONO] = 1010 mc.un.value.level[AUDIO_MIXER_LEVEL_MONO] =
1011 (l + r) / 2; 1011 (l + r) / 2;
1012 } 1012 }
1013 retval = ioctl(fd, AUDIO_MIXER_WRITE, &mc); 1013 retval = ioctl(fd, AUDIO_MIXER_WRITE, &mc);
1014 if (retval < 0) 1014 if (retval < 0)
1015 return retval; 1015 return retval;
1016 if (MIXER_WRITE(SOUND_MIXER_FIRST) <= com && 1016 if (MIXER_WRITE(SOUND_MIXER_FIRST) <= com &&
1017 com < MIXER_WRITE(SOUND_MIXER_NRDEVICES)) 1017 com < MIXER_WRITE(SOUND_MIXER_NRDEVICES))
1018 return 0; 1018 return 0;
1019 goto doread; 1019 goto doread;
1020 } else { 1020 } else {
1021 errno = EINVAL; 1021 errno = EINVAL;
1022 return -1; 1022 return -1;
1023 } 1023 }
1024 } 1024 }
1025 INTARG = (int)idat; 1025 INTARG = (int)idat;
1026 return 0; 1026 return 0;
1027} 1027}
1028 1028
1029static int 1029static int
1030mixer_oss4_ioctl(int fd, unsigned long com, void *argp) 1030mixer_oss4_ioctl(int fd, unsigned long com, void *argp)
1031{ 1031{
1032 oss_audioinfo *tmpai; 1032 oss_audioinfo *tmpai;
1033 oss_card_info *cardinfo; 1033 oss_card_info *cardinfo;
1034 oss_mixext *ext; 1034 oss_mixext *ext;
1035 oss_mixext_root root; 1035 oss_mixext_root root;
1036 oss_mixer_enuminfo *ei; 1036 oss_mixer_enuminfo *ei;
1037 oss_mixer_value *mv; 1037 oss_mixer_value *mv;
1038 oss_mixerinfo *mi; 1038 oss_mixerinfo *mi;
1039 oss_sysinfo sysinfo; 1039 oss_sysinfo sysinfo;
1040 dev_t devno; 1040 dev_t devno;
1041 struct stat tmpstat; 1041 struct stat tmpstat;
1042 struct audio_device dev; 1042 struct audio_device dev;
1043 struct audio_format_query fmtq; 1043 struct audio_format_query fmtq;
1044 struct mixer_devinfo mdi; 1044 struct mixer_devinfo mdi;
1045 struct mixer_ctrl mc; 1045 struct mixer_ctrl mc;
1046 char devname[32]; 1046 char devname[32];
1047 size_t len; 1047 size_t len;
1048 int newfd = -1, tmperrno; 1048 int newfd = -1, tmperrno;
1049 int i, noffs; 1049 int i, noffs;
1050 int retval; 1050 int retval;
1051 1051
1052 /* 1052 /*
1053 * Note: it is difficult to translate the NetBSD concept of a "set" 1053 * Note: it is difficult to translate the NetBSD concept of a "set"
1054 * mixer control type to the OSSv4 API, as far as I can tell. 1054 * mixer control type to the OSSv4 API, as far as I can tell.
1055 * 1055 *
1056 * This means they are treated like enums, i.e. only one entry in the 1056 * This means they are treated like enums, i.e. only one entry in the
1057 * set can be selected at a time. 1057 * set can be selected at a time.
1058 */ 1058 */
1059 1059
1060 switch (com) { 1060 switch (com) {
1061 case SNDCTL_AUDIOINFO: 1061 case SNDCTL_AUDIOINFO:
1062 /* 1062 /*
1063 * SNDCTL_AUDIOINFO_EX is intended for underlying hardware devices 1063 * SNDCTL_AUDIOINFO_EX is intended for underlying hardware devices
1064 * that are to be opened in "exclusive mode" (bypassing the normal 1064 * that are to be opened in "exclusive mode" (bypassing the normal
1065 * kernel mixer for exclusive control). NetBSD does not support 1065 * kernel mixer for exclusive control). NetBSD does not support
1066 * bypassing the kernel mixer, so it's an alias of SNDCTL_AUDIOINFO. 1066 * bypassing the kernel mixer, so it's an alias of SNDCTL_AUDIOINFO.
1067 */ 1067 */
1068 case SNDCTL_AUDIOINFO_EX: 1068 case SNDCTL_AUDIOINFO_EX:
1069 case SNDCTL_ENGINEINFO: 1069 case SNDCTL_ENGINEINFO:
1070 devno = 0; 1070 devno = 0;
1071 tmpai = (struct oss_audioinfo*)argp; 1071 tmpai = (struct oss_audioinfo*)argp;
1072 if (tmpai == NULL) { 1072 if (tmpai == NULL) {
1073 errno = EINVAL; 1073 errno = EINVAL;
1074 return -1; 1074 return -1;
1075 } 1075 }
1076 1076
1077 /* 1077 /*
1078 * If the input device is -1, guess the device related to 1078 * If the input device is -1, guess the device related to
1079 * the open mixer device. 1079 * the open mixer device.
1080 */ 1080 */
1081 if (tmpai->dev < 0) { 1081 if (tmpai->dev < 0) {
1082 fstat(fd, &tmpstat); 1082 fstat(fd, &tmpstat);
1083 if ((tmpstat.st_rdev & 0xff00) == 0x2a00) 1083 if ((tmpstat.st_rdev & 0xff00) == 0x2a00)
1084 devno = tmpstat.st_rdev & 0xff; 1084 devno = tmpstat.st_rdev & 0xff;
1085 if (devno >= 0x80) 1085 if (devno >= 0x80)
1086 tmpai->dev = devno & 0x7f; 1086 tmpai->dev = devno & 0x7f;
1087 } 1087 }
1088 if (tmpai->dev < 0) 1088 if (tmpai->dev < 0)
1089 tmpai->dev = 0; 1089 tmpai->dev = 0;
1090 1090
1091 snprintf(tmpai->devnode, sizeof(tmpai->devnode), 1091 snprintf(tmpai->devnode, sizeof(tmpai->devnode),
1092 "/dev/audio%d", tmpai->dev); 1092 "/dev/audio%d", tmpai->dev);
1093 1093
1094 if ((newfd = open(tmpai->devnode, O_WRONLY)) < 0) { 1094 if ((newfd = open(tmpai->devnode, O_WRONLY)) < 0) {
1095 if ((newfd = open(tmpai->devnode, O_RDONLY)) < 0) { 1095 if ((newfd = open(tmpai->devnode, O_RDONLY)) < 0) {
1096 return newfd; 1096 return newfd;
1097 } 1097 }
1098 } 1098 }
1099 1099
1100 retval = ioctl(newfd, AUDIO_GETDEV, &dev); 1100 retval = ioctl(newfd, AUDIO_GETDEV, &dev);
1101 if (retval < 0) { 1101 if (retval < 0) {
1102 tmperrno = errno; 1102 tmperrno = errno;
1103 close(newfd); 1103 close(newfd);
1104 errno = tmperrno; 1104 errno = tmperrno;
1105 return retval; 1105 return retval;
1106 } 1106 }
1107 if (getcaps(newfd, &tmpai->caps) < 0) { 1107 if (getcaps(newfd, &tmpai->caps) < 0) {
1108 tmperrno = errno; 1108 tmperrno = errno;
1109 close(newfd); 1109 close(newfd);
1110 errno = tmperrno; 1110 errno = tmperrno;
1111 return retval; 1111 return retval;
1112 } 1112 }
1113 snprintf(tmpai->name, sizeof(tmpai->name), 1113 snprintf(tmpai->name, sizeof(tmpai->name),
1114 "%s %s", dev.name, dev.version); 1114 "%s %s", dev.name, dev.version);
1115 tmpai->busy = 0; 1115 tmpai->busy = 0;
1116 tmpai->pid = -1; 1116 tmpai->pid = -1;
1117 ioctl(newfd, SNDCTL_DSP_GETFMTS, &tmpai->iformats); 1117 ioctl(newfd, SNDCTL_DSP_GETFMTS, &tmpai->iformats);
1118 tmpai->oformats = tmpai->iformats; 1118 tmpai->oformats = tmpai->iformats;
1119 tmpai->magic = -1; /* reserved for "internal use" */ 1119 tmpai->magic = -1; /* reserved for "internal use" */
1120 memset(tmpai->cmd, 0, sizeof(tmpai->cmd)); 1120 memset(tmpai->cmd, 0, sizeof(tmpai->cmd));
1121 tmpai->card_number = -1; 1121 tmpai->card_number = -1;
1122 memset(tmpai->song_name, 0, 1122 memset(tmpai->song_name, 0,
1123 sizeof(tmpai->song_name)); 1123 sizeof(tmpai->song_name));
1124 memset(tmpai->label, 0, sizeof(tmpai->label)); 1124 memset(tmpai->label, 0, sizeof(tmpai->label));
1125 tmpai->port_number = 0; 1125 tmpai->port_number = 0;
1126 tmpai->mixer_dev = tmpai->dev; 1126 tmpai->mixer_dev = tmpai->dev;
1127 tmpai->legacy_device = tmpai->dev; 1127 tmpai->legacy_device = tmpai->dev;
1128 tmpai->enabled = 1; 1128 tmpai->enabled = 1;
1129 tmpai->flags = -1; /* reserved for "future versions" */ 1129 tmpai->flags = -1; /* reserved for "future versions" */
1130 tmpai->min_rate = 1000; 1130 tmpai->min_rate = 1000;
1131 tmpai->max_rate = 192000; 1131 tmpai->max_rate = 192000;
1132 tmpai->nrates = 0; 1132 tmpai->nrates = 0;
1133 tmpai->min_channels = 1; 1133 tmpai->min_channels = 1;
1134 tmpai->max_channels = 2; 1134 tmpai->max_channels = 2;
1135 for (fmtq.index = 0; 1135 for (fmtq.index = 0;
1136 ioctl(newfd, AUDIO_QUERYFORMAT, &fmtq) != -1; ++fmtq.index) { 1136 ioctl(newfd, AUDIO_QUERYFORMAT, &fmtq) != -1; ++fmtq.index) {
1137 if (fmtq.fmt.channels > (unsigned)tmpai->max_channels) 1137 if (fmtq.fmt.channels > (unsigned)tmpai->max_channels)
1138 tmpai->max_channels = fmtq.fmt.channels; 1138 tmpai->max_channels = fmtq.fmt.channels;
1139 } 1139 }
1140 tmpai->binding = -1; /* reserved for "future versions" */ 1140 tmpai->binding = -1; /* reserved for "future versions" */
1141 tmpai->rate_source = -1; 1141 tmpai->rate_source = -1;
1142 /* 1142 /*
1143 * 'handle' is supposed to be globally unique. The closest 1143 * 'handle' is supposed to be globally unique. The closest
1144 * we have to that is probably device nodes. 1144 * we have to that is probably device nodes.
1145 */ 1145 */
1146 strlcpy(tmpai->handle, tmpai->devnode, 1146 strlcpy(tmpai->handle, tmpai->devnode,
1147 sizeof(tmpai->handle)); 1147 sizeof(tmpai->handle));
1148 tmpai->next_play_engine = 0; 1148 tmpai->next_play_engine = 0;
1149 tmpai->next_rec_engine = 0; 1149 tmpai->next_rec_engine = 0;
1150 argp = tmpai; 1150 argp = tmpai;
1151 close(newfd); 1151 close(newfd);
1152 break; 1152 break;
1153 case SNDCTL_CARDINFO: 1153 case SNDCTL_CARDINFO:
1154 cardinfo = (oss_card_info *)argp; 1154 cardinfo = (oss_card_info *)argp;
1155 if (cardinfo == NULL) { 1155 if (cardinfo == NULL) {
1156 errno = EINVAL; 1156 errno = EINVAL;
1157 return -1; 1157 return -1;
1158 } 1158 }
1159 if (cardinfo->card != -1) { 1159 if (cardinfo->card != -1) {
1160 snprintf(devname, sizeof(devname), 1160 snprintf(devname, sizeof(devname),
1161 "/dev/audio%d", cardinfo->card); 1161 "/dev/audio%d", cardinfo->card);
1162 newfd = open(devname, O_RDONLY); 1162 newfd = open(devname, O_RDONLY);
1163 if (newfd < 0) 1163 if (newfd < 0)
1164 return newfd; 1164 return newfd;
1165 } else { 1165 } else {
1166 newfd = fd; 1166 newfd = fd;
1167 } 1167 }
1168 retval = ioctl(newfd, AUDIO_GETDEV, &dev); 1168 retval = ioctl(newfd, AUDIO_GETDEV, &dev);
1169 tmperrno = errno; 1169 tmperrno = errno;
1170 if (newfd != fd) 1170 if (newfd != fd)
1171 close(newfd); 1171 close(newfd);
1172 if (retval < 0) { 1172 if (retval < 0) {
1173 errno = tmperrno; 1173 errno = tmperrno;
1174 return retval; 1174 return retval;
1175 } 1175 }
1176 strlcpy(cardinfo->shortname, dev.name, 1176 strlcpy(cardinfo->shortname, dev.name,
1177 sizeof(cardinfo->shortname)); 1177 sizeof(cardinfo->shortname));
1178 snprintf(cardinfo->longname, sizeof(cardinfo->longname), 1178 snprintf(cardinfo->longname, sizeof(cardinfo->longname),
1179 "%s %s %s", dev.name, dev.version, dev.config); 1179 "%s %s %s", dev.name, dev.version, dev.config);
1180 memset(cardinfo->hw_info, 0, sizeof(cardinfo->hw_info)); 1180 memset(cardinfo->hw_info, 0, sizeof(cardinfo->hw_info));
1181 /* 1181 /*
1182 * OSSv4 does not document this ioctl, and claims it should 1182 * OSSv4 does not document this ioctl, and claims it should
1183 * not be used by applications and is provided for "utiltiy 1183 * not be used by applications and is provided for "utiltiy
1184 * programs included in OSS". We follow the Solaris 1184 * programs included in OSS". We follow the Solaris
1185 * implementation (which is documented) and leave these fields 1185 * implementation (which is documented) and leave these fields
1186 * unset. 1186 * unset.
1187 */ 1187 */
1188 cardinfo->flags = 0; 1188 cardinfo->flags = 0;
1189 cardinfo->intr_count = 0; 1189 cardinfo->intr_count = 0;
1190 cardinfo->ack_count = 0; 1190 cardinfo->ack_count = 0;
1191 break; 1191 break;
1192 case SNDCTL_SYSINFO: 1192 case SNDCTL_SYSINFO:
1193 memset(&sysinfo, 0, sizeof(sysinfo)); 1193 memset(&sysinfo, 0, sizeof(sysinfo));
1194 strlcpy(sysinfo.product, 1194 strlcpy(sysinfo.product,
1195 "OSS/NetBSD", sizeof(sysinfo.product)); 1195 "OSS/NetBSD", sizeof(sysinfo.product));
1196 strlcpy(sysinfo.version, 1196 strlcpy(sysinfo.version,
1197 "4.01", sizeof(sysinfo.version)); 1197 "4.01", sizeof(sysinfo.version));
1198 strlcpy(sysinfo.license, 1198 strlcpy(sysinfo.license,
1199 "BSD", sizeof(sysinfo.license)); 1199 "BSD", sizeof(sysinfo.license));
1200 sysinfo.versionnum = SOUND_VERSION; 1200 sysinfo.versionnum = SOUND_VERSION;
1201 sysinfo.numaudios =  1201 sysinfo.numaudios =
1202 sysinfo.numcards = 1202 sysinfo.numcards =
1203 getaudiocount(); 1203 getaudiocount();
1204 sysinfo.numaudioengines = 1; 1204 sysinfo.numaudioengines = 1;
1205 sysinfo.numsynths = 1; 1205 sysinfo.numsynths = 1;
1206 sysinfo.nummidis = -1; 1206 sysinfo.nummidis = -1;
1207 sysinfo.numtimers = -1; 1207 sysinfo.numtimers = -1;
1208 sysinfo.nummixers = getmixercount(); 1208 sysinfo.nummixers = getmixercount();
1209 *(struct oss_sysinfo *)argp = sysinfo; 1209 *(struct oss_sysinfo *)argp = sysinfo;
1210 break; 1210 break;
1211 case SNDCTL_MIXERINFO: 1211 case SNDCTL_MIXERINFO:
1212 mi = (oss_mixerinfo *)argp; 1212 mi = (oss_mixerinfo *)argp;
1213 if (mi == NULL) { 1213 if (mi == NULL) {
1214 errno = EINVAL; 1214 errno = EINVAL;
1215 return -1; 1215 return -1;
1216 } 1216 }
1217 snprintf(devname, sizeof(devname), "/dev/mixer%d", mi->dev); 1217 snprintf(devname, sizeof(devname), "/dev/mixer%d", mi->dev);
1218 if ((newfd = open(devname, O_RDONLY)) < 0) 1218 if ((newfd = open(devname, O_RDONLY)) < 0)
1219 return newfd; 1219 return newfd;
1220 retval = ioctl(newfd, AUDIO_GETDEV, &dev); 1220 retval = ioctl(newfd, AUDIO_GETDEV, &dev);
1221 if (retval < 0) { 1221 if (retval < 0) {
1222 tmperrno = errno; 1222 tmperrno = errno;
1223 close(newfd); 1223 close(newfd);
1224 errno = tmperrno; 1224 errno = tmperrno;
1225 return retval; 1225 return retval;
1226 } 1226 }
1227 strlcpy(mi->id, devname, sizeof(mi->id)); 1227 strlcpy(mi->id, devname, sizeof(mi->id));
1228 snprintf(mi->name, sizeof(mi->name), 1228 snprintf(mi->name, sizeof(mi->name),
1229 "%s %s", dev.name, dev.version); 1229 "%s %s", dev.name, dev.version);
1230 mi->card_number = mi->dev; 1230 mi->card_number = mi->dev;
1231 mi->port_number = 0; 1231 mi->port_number = 0;
1232 mi->magic = 0; 1232 mi->magic = 0;
1233 mi->enabled = 1; 1233 mi->enabled = 1;
1234 mi->caps = 0; 1234 mi->caps = 0;
1235 mi->flags = 0; 1235 mi->flags = 0;
1236 mi->nrext = getmixercontrolcount(newfd) + 1; 1236 mi->nrext = getmixercontrolcount(newfd) + 1;
1237 mi->priority = UCHAR_MAX - mi->dev; 1237 mi->priority = UCHAR_MAX - mi->dev;
1238 strlcpy(mi->devnode, devname, sizeof(mi->devnode)); 1238 strlcpy(mi->devnode, devname, sizeof(mi->devnode));
1239 mi->legacy_device = mi->dev; 1239 mi->legacy_device = mi->dev;
1240 break; 1240 break;
1241 case SNDCTL_MIX_DESCRIPTION: 1241 case SNDCTL_MIX_DESCRIPTION:
1242 /* No description available. */ 1242 /* No description available. */
1243 errno = ENOSYS; 1243 errno = ENOSYS;
1244 return -1; 1244 return -1;
1245 case SNDCTL_MIX_NRMIX: 1245 case SNDCTL_MIX_NRMIX:
1246 INTARG = getmixercount(); 1246 INTARG = getmixercount();
1247 break; 1247 break;
1248 case SNDCTL_MIX_NREXT: 1248 case SNDCTL_MIX_NREXT:
1249 snprintf(devname, sizeof(devname), "/dev/mixer%d", INTARG); 1249 snprintf(devname, sizeof(devname), "/dev/mixer%d", INTARG);
1250 if ((newfd = open(devname, O_RDONLY)) < 0) 1250 if ((newfd = open(devname, O_RDONLY)) < 0)
1251 return newfd; 1251 return newfd;
1252 INTARG = getmixercontrolcount(newfd) + 1; 1252 INTARG = getmixercontrolcount(newfd) + 1;
1253 close(newfd); 1253 close(newfd);
1254 break; 1254 break;
1255 case SNDCTL_MIX_EXTINFO: 1255 case SNDCTL_MIX_EXTINFO:
1256 ext = (oss_mixext *)argp; 1256 ext = (oss_mixext *)argp;
1257 snprintf(devname, sizeof(devname), "/dev/mixer%d", ext->dev); 1257 snprintf(devname, sizeof(devname), "/dev/mixer%d", ext->dev);
1258 if ((newfd = open(devname, O_RDONLY)) < 0) 1258 if ((newfd = open(devname, O_RDONLY)) < 0)
1259 return newfd; 1259 return newfd;
1260 if (ext->ctrl == 0) { 1260 if (ext->ctrl == 0) {
1261 /* 1261 /*
1262 * NetBSD has no concept of a "root mixer control", but 1262 * NetBSD has no concept of a "root mixer control", but
1263 * OSSv4 requires one to work. We fake one at 0 and 1263 * OSSv4 requires one to work. We fake one at 0 and
1264 * simply add 1 to all real control indexes. 1264 * simply add 1 to all real control indexes.
1265 */ 1265 */
1266 retval = ioctl(newfd, AUDIO_GETDEV, &dev); 1266 retval = ioctl(newfd, AUDIO_GETDEV, &dev);
1267 tmperrno = errno; 1267 tmperrno = errno;
1268 close(newfd); 1268 close(newfd);
1269 if (retval < 0) { 1269 if (retval < 0) {
1270 errno = tmperrno; 1270 errno = tmperrno;
1271 return -1; 1271 return -1;
1272 } 1272 }
1273 memset(&root, 0, sizeof(root)); 1273 memset(&root, 0, sizeof(root));
1274 strlcpy(root.id, devname, sizeof(root.id)); 1274 strlcpy(root.id, devname, sizeof(root.id));
1275 snprintf(root.name, sizeof(root.name), 1275 snprintf(root.name, sizeof(root.name),
1276 "%s %s", dev.name, dev.version); 1276 "%s %s", dev.name, dev.version);
1277 strlcpy(ext->id, devname, sizeof(ext->id)); 1277 strlcpy(ext->id, devname, sizeof(ext->id));
1278 snprintf(ext->extname, sizeof(ext->extname), 1278 snprintf(ext->extname, sizeof(ext->extname),
1279 "%s %s", dev.name, dev.version); 1279 "%s %s", dev.name, dev.version);
1280 strlcpy(ext->extname, "root", sizeof(ext->extname)); 1280 strlcpy(ext->extname, "root", sizeof(ext->extname));
1281 ext->type = MIXT_DEVROOT; 1281 ext->type = MIXT_DEVROOT;
1282 ext->minvalue = 0; 1282 ext->minvalue = 0;
1283 ext->maxvalue = 0; 1283 ext->maxvalue = 0;
1284 ext->flags = 0; 1284 ext->flags = 0;
1285 ext->parent = -1; 1285 ext->parent = -1;
1286 ext->control_no = -1; 1286 ext->control_no = -1;
1287 ext->update_counter = 0; 1287 ext->update_counter = 0;
1288 ext->rgbcolor = 0; 1288 ext->rgbcolor = 0;
1289 memcpy(&ext->data, &root, 1289 memcpy(&ext->data, &root,
1290 sizeof(root) > sizeof(ext->data) ? 1290 sizeof(root) > sizeof(ext->data) ?
1291 sizeof(ext->data) : sizeof(root)); 1291 sizeof(ext->data) : sizeof(root));
1292 return 0; 1292 return 0;
1293 } 1293 }
1294 mdi.index = ext->ctrl - 1; 1294 mdi.index = ext->ctrl - 1;
1295 retval = ioctl(newfd, AUDIO_MIXER_DEVINFO, &mdi); 1295 retval = ioctl(newfd, AUDIO_MIXER_DEVINFO, &mdi);
1296 if (retval < 0) { 1296 if (retval < 0) {
1297 tmperrno = errno; 1297 tmperrno = errno;
1298 close(newfd); 1298 close(newfd);
1299 errno = tmperrno; 1299 errno = tmperrno;
1300 return retval; 1300 return retval;
1301 } 1301 }
1302 ext->flags = MIXF_READABLE | MIXF_WRITEABLE | MIXF_POLL; 1302 ext->flags = MIXF_READABLE | MIXF_WRITEABLE | MIXF_POLL;
1303 ext->parent = mdi.mixer_class + 1; 1303 ext->parent = mdi.mixer_class + 1;
1304 strlcpy(ext->id, mdi.label.name, sizeof(ext->id)); 1304 strlcpy(ext->id, mdi.label.name, sizeof(ext->id));
1305 strlcpy(ext->extname, mdi.label.name, sizeof(ext->extname)); 1305 strlcpy(ext->extname, mdi.label.name, sizeof(ext->extname));
1306 len = strlen(ext->extname); 1306 len = strlen(ext->extname);
1307 memset(ext->data, 0, sizeof(ext->data)); 1307 memset(ext->data, 0, sizeof(ext->data));
1308 ext->control_no = -1; 1308 ext->control_no = -1;
1309 ext->update_counter = 0; 1309 ext->update_counter = 0;
1310 ext->rgbcolor = 0; 1310 ext->rgbcolor = 0;
1311 switch (mdi.type) { 1311 switch (mdi.type) {
1312 case AUDIO_MIXER_CLASS: 1312 case AUDIO_MIXER_CLASS:
1313 ext->type = MIXT_GROUP; 1313 ext->type = MIXT_GROUP;
1314 ext->parent = 0; 1314 ext->parent = 0;
1315 ext->minvalue = 0; 1315 ext->minvalue = 0;
1316 ext->maxvalue = 0; 1316 ext->maxvalue = 0;
1317 break; 1317 break;
1318 case AUDIO_MIXER_ENUM: 1318 case AUDIO_MIXER_ENUM:
1319 ext->maxvalue = mdi.un.e.num_mem; 1319 ext->maxvalue = mdi.un.e.num_mem;
1320 ext->minvalue = 0; 1320 ext->minvalue = 0;
1321 for (i = 0; i < mdi.un.e.num_mem; ++i) { 1321 for (i = 0; i < mdi.un.e.num_mem; ++i) {
1322 ext->enum_present[i / 8] |= (1 << (i % 8)); 1322 ext->enum_present[i / 8] |= (1 << (i % 8));
1323 } 1323 }
1324 if (mdi.un.e.num_mem == 2) { 1324 if (mdi.un.e.num_mem == 2) {
1325 if (!strcmp(mdi.un.e.member[0].label.name, AudioNoff) && 1325 if (!strcmp(mdi.un.e.member[0].label.name, AudioNoff) &&
1326 !strcmp(mdi.un.e.member[1].label.name, AudioNon)) { 1326 !strcmp(mdi.un.e.member[1].label.name, AudioNon)) {
1327 ext->type = MIXT_MUTE; 1327 ext->type = MIXT_MUTE;
1328 } else { 1328 } else {
1329 ext->type = MIXT_ENUM; 1329 ext->type = MIXT_ENUM;
1330 } 1330 }
1331 } else { 1331 } else {
1332 ext->type = MIXT_ENUM; 1332 ext->type = MIXT_ENUM;
1333 } 1333 }
1334 break; 1334 break;
1335 case AUDIO_MIXER_SET: 1335 case AUDIO_MIXER_SET:
1336 ext->maxvalue = mdi.un.s.num_mem; 1336 ext->maxvalue = mdi.un.s.num_mem;
1337 ext->minvalue = 0; 1337 ext->minvalue = 0;
1338#ifdef notyet 1338#ifdef notyet
1339 /* 1339 /*
1340 * XXX: This is actually the correct type for "set" 1340 * XXX: This is actually the correct type for "set"
1341 * controls, but it seems no real world software 1341 * controls, but it seems no real world software
1342 * supports it. The only documentation exists in 1342 * supports it. The only documentation exists in
1343 * the OSSv4 headers and describes it as "reserved 1343 * the OSSv4 headers and describes it as "reserved
1344 * for Sun's implementation". 1344 * for Sun's implementation".
1345 */ 1345 */
1346 ext->type = MIXT_ENUM_MULTI; 1346 ext->type = MIXT_ENUM_MULTI;
1347#else 1347#else
1348 ext->type = MIXT_ENUM; 1348 ext->type = MIXT_ENUM;
1349#endif 1349#endif
1350 for (i = 0; i < mdi.un.s.num_mem; ++i) { 1350 for (i = 0; i < mdi.un.s.num_mem; ++i) {
1351 ext->enum_present[i / 8] |= (1 << (i % 8)); 1351 ext->enum_present[i / 8] |= (1 << (i % 8));
1352 } 1352 }
1353 break; 1353 break;
1354 case AUDIO_MIXER_VALUE: 1354 case AUDIO_MIXER_VALUE:
1355 ext->maxvalue = UCHAR_MAX + 1; 1355 ext->maxvalue = UCHAR_MAX + 1;
1356 ext->minvalue = 0; 1356 ext->minvalue = 0;
1357 if (mdi.un.v.num_channels == 2) { 1357 if (mdi.un.v.num_channels == 2) {
1358 ext->type = MIXT_STEREOSLIDER; 1358 ext->type = MIXT_STEREOSLIDER;
1359 } else { 1359 } else {
1360 ext->type = MIXT_MONOSLIDER; 1360 ext->type = MIXT_MONOSLIDER;
1361 } 1361 }
1362 break; 1362 break;
1363 } 1363 }
1364 close(newfd); 1364 close(newfd);
1365 break; 1365 break;
1366 case SNDCTL_MIX_ENUMINFO: 1366 case SNDCTL_MIX_ENUMINFO:
1367 ei = (oss_mixer_enuminfo *)argp; 1367 ei = (oss_mixer_enuminfo *)argp;
1368 if (ei == NULL) { 1368 if (ei == NULL) {
1369 errno = EINVAL; 1369 errno = EINVAL;
1370 return -1; 1370 return -1;
1371 } 1371 }
1372 if (ei->ctrl == 0) { 1372 if (ei->ctrl == 0) {
1373 errno = EINVAL; 1373 errno = EINVAL;
1374 return -1; 1374 return -1;
1375 } 1375 }
1376 snprintf(devname, sizeof(devname), "/dev/mixer%d", ei->dev); 1376 snprintf(devname, sizeof(devname), "/dev/mixer%d", ei->dev);
1377 if ((newfd = open(devname, O_RDONLY)) < 0) 1377 if ((newfd = open(devname, O_RDONLY)) < 0)
1378 return newfd; 1378 return newfd;
1379 mdi.index = ei->ctrl - 1; 1379 mdi.index = ei->ctrl - 1;
1380 retval = ioctl(newfd, AUDIO_MIXER_DEVINFO, &mdi); 1380 retval = ioctl(newfd, AUDIO_MIXER_DEVINFO, &mdi);
1381 tmperrno = errno; 1381 tmperrno = errno;
1382 close(newfd); 1382 close(newfd);
1383 if (retval < 0) { 1383 if (retval < 0) {
1384 errno = tmperrno; 1384 errno = tmperrno;
1385 return retval; 1385 return retval;
1386 } 1386 }
1387 ei->version = 0; 1387 ei->version = 0;
1388 switch (mdi.type) { 1388 switch (mdi.type) {
1389 case AUDIO_MIXER_ENUM: 1389 case AUDIO_MIXER_ENUM:
1390 ei->nvalues = mdi.un.e.num_mem; 1390 ei->nvalues = mdi.un.e.num_mem;
1391 noffs = 0; 1391 noffs = 0;
1392 for (i = 0; i < ei->nvalues; ++i) { 1392 for (i = 0; i < ei->nvalues; ++i) {
1393 ei->strindex[i] = noffs; 1393 ei->strindex[i] = noffs;
1394 len = strlen(mdi.un.e.member[i].label.name) + 1; 1394 len = strlen(mdi.un.e.member[i].label.name) + 1;
1395 if ((noffs + len) >= sizeof(ei->strings)) { 1395 if ((noffs + len) >= sizeof(ei->strings)) {
1396 errno = ENOMEM; 1396 errno = ENOMEM;
1397 return -1; 1397 return -1;
1398 } 1398 }
1399 memcpy(ei->strings + noffs, 1399 memcpy(ei->strings + noffs,
1400 mdi.un.e.member[i].label.name, len); 1400 mdi.un.e.member[i].label.name, len);
1401 noffs += len; 1401 noffs += len;
1402 } 1402 }
1403 break; 1403 break;
1404 case AUDIO_MIXER_SET: 1404 case AUDIO_MIXER_SET:
1405 ei->nvalues = mdi.un.s.num_mem; 1405 ei->nvalues = mdi.un.s.num_mem;
1406 noffs = 0; 1406 noffs = 0;
1407 for (i = 0; i < ei->nvalues; ++i) { 1407 for (i = 0; i < ei->nvalues; ++i) {
1408 ei->strindex[i] = noffs; 1408 ei->strindex[i] = noffs;
1409 len = strlen(mdi.un.s.member[i].label.name) + 1; 1409 len = strlen(mdi.un.s.member[i].label.name) + 1;
1410 if ((noffs + len) >= sizeof(ei->strings)) { 1410 if ((noffs + len) >= sizeof(ei->strings)) {
1411 errno = ENOMEM; 1411 errno = ENOMEM;
1412 return -1; 1412 return -1;
1413 } 1413 }
1414 memcpy(ei->strings + noffs, 1414 memcpy(ei->strings + noffs,
1415 mdi.un.s.member[i].label.name, len); 1415 mdi.un.s.member[i].label.name, len);
1416 noffs += len; 1416 noffs += len;
1417 } 1417 }
1418 break; 1418 break;
1419 default: 1419 default:
1420 errno = EINVAL; 1420 errno = EINVAL;
1421 return -1; 1421 return -1;
1422 } 1422 }
1423 break; 1423 break;
1424 case SNDCTL_MIX_WRITE: 1424 case SNDCTL_MIX_WRITE:
1425 mv = (oss_mixer_value *)argp; 1425 mv = (oss_mixer_value *)argp;
1426 if (mv == NULL) { 1426 if (mv == NULL) {
1427 errno = EINVAL; 1427 errno = EINVAL;
1428 return -1; 1428 return -1;
1429 } 1429 }
1430 if (mv->ctrl == 0) { 1430 if (mv->ctrl == 0) {
1431 errno = EINVAL; 1431 errno = EINVAL;
1432 return -1; 1432 return -1;
1433 } 1433 }
1434 snprintf(devname, sizeof(devname), "/dev/mixer%d", mv->dev); 1434 snprintf(devname, sizeof(devname), "/dev/mixer%d", mv->dev);
1435 if ((newfd = open(devname, O_RDWR)) < 0) 1435 if ((newfd = open(devname, O_RDWR)) < 0)
1436 return newfd; 1436 return newfd;
1437 mdi.index = mc.dev = mv->ctrl - 1; 1437 mdi.index = mc.dev = mv->ctrl - 1;
1438 retval = ioctl(newfd, AUDIO_MIXER_DEVINFO, &mdi); 1438 retval = ioctl(newfd, AUDIO_MIXER_DEVINFO, &mdi);
1439 if (retval < 0) { 1439 if (retval < 0) {
1440 tmperrno = errno; 1440 tmperrno = errno;
1441 close(newfd); 1441 close(newfd);
1442 errno = tmperrno; 1442 errno = tmperrno;
1443 return retval; 1443 return retval;
1444 } 1444 }
 1445 mc.type = mdi.type;
1445 switch (mdi.type) { 1446 switch (mdi.type) {
1446 case AUDIO_MIXER_ENUM: 1447 case AUDIO_MIXER_ENUM:
1447 if (mv->value >= mdi.un.e.num_mem) { 1448 if (mv->value >= mdi.un.e.num_mem) {
1448 close(newfd); 1449 close(newfd);
1449 errno = EINVAL; 1450 errno = EINVAL;
1450 return -1; 1451 return -1;
1451 } 1452 }
1452 mc.un.ord = mdi.un.e.member[mv->value].ord; 1453 mc.un.ord = mdi.un.e.member[mv->value].ord;
1453 break; 1454 break;
1454 case AUDIO_MIXER_SET: 1455 case AUDIO_MIXER_SET:
1455 if (mv->value >= mdi.un.s.num_mem) { 1456 if (mv->value >= mdi.un.s.num_mem) {
1456 close(newfd); 1457 close(newfd);
1457 errno = EINVAL; 1458 errno = EINVAL;
1458 return -1; 1459 return -1;
1459 } 1460 }
1460#ifdef notyet 1461#ifdef notyet
1461 mc.un.mask = 0; 1462 mc.un.mask = 0;
1462 for (i = 0; i < mdi.un.s.num_mem; ++i) { 1463 for (i = 0; i < mdi.un.s.num_mem; ++i) {
1463 if (mv->value & (1 << i)) { 1464 if (mv->value & (1 << i)) {
1464 mc.un.mask |= mdi.un.s.member[mv->value].mask; 1465 mc.un.mask |= mdi.un.s.member[mv->value].mask;
1465 } 1466 }
1466 } 1467 }
1467#else 1468#else
1468 mc.un.mask = mdi.un.s.member[mv->value].mask; 1469 mc.un.mask = mdi.un.s.member[mv->value].mask;
1469#endif 1470#endif
1470 break; 1471 break;
1471 case AUDIO_MIXER_VALUE: 1472 case AUDIO_MIXER_VALUE:
 1473 mc.un.value.num_channels = mdi.un.v.num_channels;
1472 if (mdi.un.v.num_channels != 2) { 1474 if (mdi.un.v.num_channels != 2) {
1473 for (i = 0; i < mdi.un.v.num_channels; ++i) { 1475 for (i = 0; i < mdi.un.v.num_channels; ++i) {
1474 mc.un.value.level[i] = mv->value; 1476 mc.un.value.level[i] = mv->value;
1475 } 1477 }
1476 } else { 1478 } else {
1477 mc.un.value.level[AUDIO_MIXER_LEVEL_LEFT] =  1479 mc.un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
1478 (mv->value >> 0) & 0xFF; 1480 (mv->value >> 0) & 0xFF;
1479 mc.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 1481 mc.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
1480 (mv->value >> 8) & 0xFF; 1482 (mv->value >> 8) & 0xFF;
1481 } 1483 }
1482 break; 1484 break;
1483 } 1485 }
1484 retval = ioctl(newfd, AUDIO_MIXER_WRITE, &mc); 1486 retval = ioctl(newfd, AUDIO_MIXER_WRITE, &mc);
1485 if (retval < 0) { 1487 if (retval < 0) {
1486 tmperrno = errno; 1488 tmperrno = errno;
1487 close(newfd); 1489 close(newfd);
1488 errno = tmperrno; 1490 errno = tmperrno;
1489 return retval; 1491 return retval;
1490 } 1492 }
1491 close(newfd); 1493 close(newfd);
1492 break; 1494 break;
1493 case SNDCTL_MIX_READ: 1495 case SNDCTL_MIX_READ:
1494 mv = (oss_mixer_value *)argp; 1496 mv = (oss_mixer_value *)argp;
1495 if (mv == NULL) { 1497 if (mv == NULL) {
1496 errno = EINVAL; 1498 errno = EINVAL;
1497 return -1; 1499 return -1;
1498 } 1500 }
1499 if (mv->ctrl == 0) { 1501 if (mv->ctrl == 0) {
1500 errno = EINVAL; 1502 errno = EINVAL;
1501 return -1; 1503 return -1;
1502 } 1504 }
1503 snprintf(devname, sizeof(devname), "/dev/mixer%d", mv->dev); 1505 snprintf(devname, sizeof(devname), "/dev/mixer%d", mv->dev);
1504 if ((newfd = open(devname, O_RDWR)) < 0) 1506 if ((newfd = open(devname, O_RDWR)) < 0)
1505 return newfd; 1507 return newfd;
1506 mdi.index = mc.dev = (mv->ctrl - 1); 1508 mdi.index = mc.dev = (mv->ctrl - 1);
1507 retval = ioctl(newfd, AUDIO_MIXER_DEVINFO, &mdi); 1509 retval = ioctl(newfd, AUDIO_MIXER_DEVINFO, &mdi);
1508 if (retval < 0) { 1510 if (retval < 0) {
1509 tmperrno = errno; 1511 tmperrno = errno;
1510 close(newfd); 1512 close(newfd);
1511 errno = tmperrno; 1513 errno = tmperrno;
1512 return retval; 1514 return retval;
1513 } 1515 }
1514 mc.dev = mdi.index; 1516 mc.dev = mdi.index;
 1517 mc.type = mdi.type;
 1518 if (mdi.type == AUDIO_MIXER_VALUE)
 1519 mc.un.value.num_channels = mdi.un.v.num_channels;
1515 retval = ioctl(newfd, AUDIO_MIXER_READ, &mc); 1520 retval = ioctl(newfd, AUDIO_MIXER_READ, &mc);
1516 if (retval < 0) { 1521 if (retval < 0) {
1517 tmperrno = errno; 1522 tmperrno = errno;
1518 close(newfd); 1523 close(newfd);
1519 errno = tmperrno; 1524 errno = tmperrno;
1520 return retval; 1525 return retval;
1521 } 1526 }
1522 close(newfd); 1527 close(newfd);
1523 mv->value = 0; 1528 mv->value = 0;
1524 switch (mdi.type) { 1529 switch (mdi.type) {
1525 case AUDIO_MIXER_ENUM: 1530 case AUDIO_MIXER_ENUM:
1526 for (i = 0; i < mdi.un.e.num_mem; ++i) { 1531 for (i = 0; i < mdi.un.e.num_mem; ++i) {
1527 if (mc.un.ord == mdi.un.e.member[i].ord) { 1532 if (mc.un.ord == mdi.un.e.member[i].ord) {
1528 mv->value = i; 1533 mv->value = i;
1529 break; 1534 break;
1530 } 1535 }
1531 } 1536 }
1532 break; 1537 break;
1533 case AUDIO_MIXER_SET: 1538 case AUDIO_MIXER_SET:
1534 for (i = 0; i < mdi.un.s.num_mem; ++i) { 1539 for (i = 0; i < mdi.un.s.num_mem; ++i) {
1535#ifdef notyet 1540#ifdef notyet
1536 if (mc.un.mask & mdi.un.s.member[i].mask) 1541 if (mc.un.mask & mdi.un.s.member[i].mask)
1537 mv->value |= (1 << i); 1542 mv->value |= (1 << i);
1538#else 1543#else
1539 if (mc.un.mask == mdi.un.s.member[i].mask) { 1544 if (mc.un.mask == mdi.un.s.member[i].mask) {
1540 mv->value = i; 1545 mv->value = i;
1541 break; 1546 break;
1542 } 1547 }
1543#endif 1548#endif
1544 } 1549 }
1545 break; 1550 break;
1546 case AUDIO_MIXER_VALUE: 1551 case AUDIO_MIXER_VALUE:
1547 if (mdi.un.v.num_channels != 2) { 1552 if (mdi.un.v.num_channels != 2) {
1548 mv->value = mc.un.value.level[0]; 1553 mv->value = mc.un.value.level[0];
1549 } else { 1554 } else {
1550 mv->value = \ 1555 mv->value = \
1551 ((mc.un.value.level[1] & 0xFF) << 8) | 1556 ((mc.un.value.level[1] & 0xFF) << 8) |
1552 ((mc.un.value.level[0] & 0xFF) << 0); 1557 ((mc.un.value.level[0] & 0xFF) << 0);
1553 } 1558 }
1554 break; 1559 break;
1555 default: 1560 default:
1556 errno = EINVAL; 1561 errno = EINVAL;
1557 return -1; 1562 return -1;
1558 } 1563 }
1559 break; 1564 break;
1560 default: 1565 default:
1561 errno = EINVAL; 1566 errno = EINVAL;
1562 return -1; 1567 return -1;
1563 } 1568 }
1564 return 0; 1569 return 0;
1565} 1570}
1566 1571
1567static int 1572static int
1568global_oss4_ioctl(int fd, unsigned long com, void *argp) 1573global_oss4_ioctl(int fd, unsigned long com, void *argp)
1569{ 1574{
1570 int retval = 0; 1575 int retval = 0;
1571 1576
1572 switch (com) { 1577 switch (com) {
1573 /* 1578 /*
1574 * These ioctls were added in OSSv4 with the idea that 1579 * These ioctls were added in OSSv4 with the idea that
1575 * applications could apply strings to audio devices to 1580 * applications could apply strings to audio devices to
1576 * display what they are using them for (e.g. with song 1581 * display what they are using them for (e.g. with song
1577 * names) in mixer applications. In practice, the popular 1582 * names) in mixer applications. In practice, the popular
1578 * implementations of the API in FreeBSD and Solaris treat 1583 * implementations of the API in FreeBSD and Solaris treat
1579 * these as a no-op and return EINVAL, and no software in the 1584 * these as a no-op and return EINVAL, and no software in the
1580 * wild seems to use them. 1585 * wild seems to use them.
1581 */ 1586 */
1582 case SNDCTL_SETSONG: 1587 case SNDCTL_SETSONG:
1583 case SNDCTL_GETSONG: 1588 case SNDCTL_GETSONG:
1584 case SNDCTL_SETNAME: 1589 case SNDCTL_SETNAME:
1585 case SNDCTL_SETLABEL: 1590 case SNDCTL_SETLABEL:
1586 case SNDCTL_GETLABEL: 1591 case SNDCTL_GETLABEL:
1587 errno = EINVAL; 1592 errno = EINVAL;
1588 retval = -1; 1593 retval = -1;
1589 break; 1594 break;
1590 default: 1595 default:
1591 errno = EINVAL; 1596 errno = EINVAL;
1592 retval = -1; 1597 retval = -1;
1593 break; 1598 break;
1594 } 1599 }
1595 return retval; 1600 return retval;
1596} 1601}
1597 1602
1598static int 1603static int
1599getcaps(int fd, int *out) 1604getcaps(int fd, int *out)
1600{ 1605{
1601 int props, caps; 1606 int props, caps;
1602 1607
1603 if (ioctl(fd, AUDIO_GETPROPS, &props) < 0) 1608 if (ioctl(fd, AUDIO_GETPROPS, &props) < 0)
1604 return -1; 1609 return -1;
1605 1610
1606 caps = DSP_CAP_TRIGGER; 1611 caps = DSP_CAP_TRIGGER;
1607 1612
1608 if (props & AUDIO_PROP_FULLDUPLEX) 1613 if (props & AUDIO_PROP_FULLDUPLEX)
1609 caps |= DSP_CAP_DUPLEX; 1614 caps |= DSP_CAP_DUPLEX;
1610 if (props & AUDIO_PROP_MMAP) 1615 if (props & AUDIO_PROP_MMAP)
1611 caps |= DSP_CAP_MMAP; 1616 caps |= DSP_CAP_MMAP;
1612 if (props & AUDIO_PROP_CAPTURE) 1617 if (props & AUDIO_PROP_CAPTURE)
1613 caps |= PCM_CAP_INPUT; 1618 caps |= PCM_CAP_INPUT;
1614 if (props & AUDIO_PROP_PLAYBACK) 1619 if (props & AUDIO_PROP_PLAYBACK)
1615 caps |= PCM_CAP_OUTPUT; 1620 caps |= PCM_CAP_OUTPUT;
1616 1621
1617 *out = caps; 1622 *out = caps;
1618 return 0; 1623 return 0;
1619} 1624}
1620 1625
1621static int 1626static int
1622getaudiocount(void) 1627getaudiocount(void)
1623{ 1628{
1624 char devname[32]; 1629 char devname[32];
1625 int ndevs = 0; 1630 int ndevs = 0;
1626 int tmpfd; 1631 int tmpfd;
1627 int tmperrno = errno; 1632 int tmperrno = errno;
1628 1633
1629 do { 1634 do {
1630 snprintf(devname, sizeof(devname), 1635 snprintf(devname, sizeof(devname),
1631 "/dev/audio%d", ndevs); 1636 "/dev/audio%d", ndevs);
1632 if ((tmpfd = open(devname, O_RDONLY)) != -1 || 1637 if ((tmpfd = open(devname, O_RDONLY)) != -1 ||
1633 (tmpfd = open(devname, O_WRONLY)) != -1) { 1638 (tmpfd = open(devname, O_WRONLY)) != -1) {
1634 ndevs++; 1639 ndevs++;
1635 close(tmpfd); 1640 close(tmpfd);
1636 } 1641 }
1637 } while (tmpfd != -1); 1642 } while (tmpfd != -1);
1638 errno = tmperrno; 1643 errno = tmperrno;
1639 return ndevs; 1644 return ndevs;
1640} 1645}
1641 1646
1642static int 1647static int
1643getmixercount(void) 1648getmixercount(void)
1644{ 1649{
1645 char devname[32]; 1650 char devname[32];
1646 int ndevs = 0; 1651 int ndevs = 0;
1647 int tmpfd; 1652 int tmpfd;
1648 int tmperrno = errno; 1653 int tmperrno = errno;
1649 1654
1650 do { 1655 do {
1651 snprintf(devname, sizeof(devname), 1656 snprintf(devname, sizeof(devname),
1652 "/dev/mixer%d", ndevs); 1657 "/dev/mixer%d", ndevs);
1653 if ((tmpfd = open(devname, O_RDONLY)) != -1) { 1658 if ((tmpfd = open(devname, O_RDONLY)) != -1) {
1654 ndevs++; 1659 ndevs++;
1655 close(tmpfd); 1660 close(tmpfd);
1656 } 1661 }
1657 } while (tmpfd != -1); 1662 } while (tmpfd != -1);
1658 errno = tmperrno; 1663 errno = tmperrno;
1659 return ndevs; 1664 return ndevs;
1660} 1665}
1661 1666
1662static int 1667static int
1663getmixercontrolcount(int fd) 1668getmixercontrolcount(int fd)
1664{ 1669{
1665 struct mixer_devinfo mdi; 1670 struct mixer_devinfo mdi;
1666 int ndevs = 0; 1671 int ndevs = 0;
1667 1672
1668 do { 1673 do {
1669 mdi.index = ndevs++; 1674 mdi.index = ndevs++;
1670 } while (ioctl(fd, AUDIO_MIXER_DEVINFO, &mdi) != -1); 1675 } while (ioctl(fd, AUDIO_MIXER_DEVINFO, &mdi) != -1);
1671 1676
1672 return ndevs > 0 ? ndevs - 1 : 0; 1677 return ndevs > 0 ? ndevs - 1 : 0;
1673} 1678}
1674 1679
1675static int 1680static int
1676getvol(u_int gain, u_char balance) 1681getvol(u_int gain, u_char balance)
1677{ 1682{
1678 u_int l, r; 1683 u_int l, r;
1679 1684
1680 if (balance == AUDIO_MID_BALANCE) { 1685 if (balance == AUDIO_MID_BALANCE) {
1681 l = r = gain; 1686 l = r = gain;
1682 } else if (balance < AUDIO_MID_BALANCE) { 1687 } else if (balance < AUDIO_MID_BALANCE) {
1683 l = gain; 1688 l = gain;
1684 r = (balance * gain) / AUDIO_MID_BALANCE; 1689 r = (balance * gain) / AUDIO_MID_BALANCE;
1685 } else { 1690 } else {
1686 r = gain; 1691 r = gain;
1687 l = ((AUDIO_RIGHT_BALANCE - balance) * gain) 1692 l = ((AUDIO_RIGHT_BALANCE - balance) * gain)
1688 / AUDIO_MID_BALANCE; 1693 / AUDIO_MID_BALANCE;
1689 } 1694 }
1690 1695
1691 return TO_OSSVOL(l) | (TO_OSSVOL(r) << 8); 1696 return TO_OSSVOL(l) | (TO_OSSVOL(r) << 8);
1692} 1697}
1693 1698
1694static void 1699static void
1695setvol(int fd, int volume, bool record) 1700setvol(int fd, int volume, bool record)
1696{ 1701{
1697 u_int lgain, rgain; 1702 u_int lgain, rgain;
1698 struct audio_info tmpinfo; 1703 struct audio_info tmpinfo;
1699 struct audio_prinfo *prinfo; 1704 struct audio_prinfo *prinfo;
1700 1705
1701 AUDIO_INITINFO(&tmpinfo); 1706 AUDIO_INITINFO(&tmpinfo);
1702 prinfo = record ? &tmpinfo.record : &tmpinfo.play; 1707 prinfo = record ? &tmpinfo.record : &tmpinfo.play;
1703 1708
1704 lgain = FROM_OSSVOL((volume >> 0) & 0xff); 1709 lgain = FROM_OSSVOL((volume >> 0) & 0xff);
1705 rgain = FROM_OSSVOL((volume >> 8) & 0xff); 1710 rgain = FROM_OSSVOL((volume >> 8) & 0xff);
1706 1711
1707 if (lgain == rgain) { 1712 if (lgain == rgain) {
1708 prinfo->gain = lgain; 1713 prinfo->gain = lgain;
1709 prinfo->balance = AUDIO_MID_BALANCE; 1714 prinfo->balance = AUDIO_MID_BALANCE;
1710 } else if (lgain < rgain) { 1715 } else if (lgain < rgain) {
1711 prinfo->gain = rgain; 1716 prinfo->gain = rgain;
1712 prinfo->balance = AUDIO_RIGHT_BALANCE - 1717 prinfo->balance = AUDIO_RIGHT_BALANCE -
1713 (AUDIO_MID_BALANCE * lgain) / rgain; 1718 (AUDIO_MID_BALANCE * lgain) / rgain;
1714 } else { 1719 } else {
1715 prinfo->gain = lgain; 1720 prinfo->gain = lgain;
1716 prinfo->balance = (AUDIO_MID_BALANCE * rgain) / lgain; 1721 prinfo->balance = (AUDIO_MID_BALANCE * rgain) / lgain;
1717 } 1722 }
1718 1723
1719 (void)ioctl(fd, AUDIO_SETINFO, &tmpinfo); 1724 (void)ioctl(fd, AUDIO_SETINFO, &tmpinfo);
1720} 1725}
1721 1726
1722/* 1727/*
1723 * When AUDIO_SETINFO fails to set a channel count, the application's chosen 1728 * When AUDIO_SETINFO fails to set a channel count, the application's chosen
1724 * number is out of range of what the kernel allows. 1729 * number is out of range of what the kernel allows.
1725 * 1730 *
1726 * When this happens, we use the current hardware settings. This is just in 1731 * When this happens, we use the current hardware settings. This is just in
1727 * case an application is abusing SNDCTL_DSP_CHANNELS - OSSv4 always sets and 1732 * case an application is abusing SNDCTL_DSP_CHANNELS - OSSv4 always sets and
1728 * returns a reasonable value, even if it wasn't what the user requested. 1733 * returns a reasonable value, even if it wasn't what the user requested.
1729 * 1734 *
1730 * Solaris guarantees this behaviour if nchannels = 0. 1735 * Solaris guarantees this behaviour if nchannels = 0.
1731 * 1736 *
1732 * XXX: If a device is opened for both playback and recording, and supports 1737 * XXX: If a device is opened for both playback and recording, and supports
1733 * fewer channels for recording than playback, applications that do both will 1738 * fewer channels for recording than playback, applications that do both will
1734 * behave very strangely. OSS doesn't allow for reporting separate channel 1739 * behave very strangely. OSS doesn't allow for reporting separate channel
1735 * counts for recording and playback. This could be worked around by always 1740 * counts for recording and playback. This could be worked around by always
1736 * mixing recorded data up to the same number of channels as is being used 1741 * mixing recorded data up to the same number of channels as is being used
1737 * for playback. 1742 * for playback.
1738 */ 1743 */
1739static void 1744static void
1740setchannels(int fd, int mode, int nchannels) 1745setchannels(int fd, int mode, int nchannels)
1741{ 1746{
1742 struct audio_info tmpinfo, hwfmt; 1747 struct audio_info tmpinfo, hwfmt;
1743 1748
1744 if (ioctl(fd, AUDIO_GETFORMAT, &hwfmt) < 0) { 1749 if (ioctl(fd, AUDIO_GETFORMAT, &hwfmt) < 0) {
1745 errno = 0; 1750 errno = 0;
1746 hwfmt.record.channels = hwfmt.play.channels = 2; 1751 hwfmt.record.channels = hwfmt.play.channels = 2;
1747 } 1752 }
1748 1753
1749 if (mode & AUMODE_PLAY) { 1754 if (mode & AUMODE_PLAY) {
1750 AUDIO_INITINFO(&tmpinfo); 1755 AUDIO_INITINFO(&tmpinfo);
1751 tmpinfo.play.channels = nchannels; 1756 tmpinfo.play.channels = nchannels;
1752 if (ioctl(fd, AUDIO_SETINFO, &tmpinfo) < 0) { 1757 if (ioctl(fd, AUDIO_SETINFO, &tmpinfo) < 0) {
1753 errno = 0; 1758 errno = 0;
1754 AUDIO_INITINFO(&tmpinfo); 1759 AUDIO_INITINFO(&tmpinfo);
1755 tmpinfo.play.channels = hwfmt.play.channels; 1760 tmpinfo.play.channels = hwfmt.play.channels;
1756 (void)ioctl(fd, AUDIO_SETINFO, &tmpinfo); 1761 (void)ioctl(fd, AUDIO_SETINFO, &tmpinfo);
1757 } 1762 }
1758 } 1763 }
1759 1764
1760 if (mode & AUMODE_RECORD) { 1765 if (mode & AUMODE_RECORD) {
1761 AUDIO_INITINFO(&tmpinfo); 1766 AUDIO_INITINFO(&tmpinfo);
1762 tmpinfo.record.channels = nchannels; 1767 tmpinfo.record.channels = nchannels;
1763 if (ioctl(fd, AUDIO_SETINFO, &tmpinfo) < 0) { 1768 if (ioctl(fd, AUDIO_SETINFO, &tmpinfo) < 0) {
1764 errno = 0; 1769 errno = 0;
1765 AUDIO_INITINFO(&tmpinfo); 1770 AUDIO_INITINFO(&tmpinfo);
1766 tmpinfo.record.channels = hwfmt.record.channels; 1771 tmpinfo.record.channels = hwfmt.record.channels;
1767 (void)ioctl(fd, AUDIO_SETINFO, &tmpinfo); 1772 (void)ioctl(fd, AUDIO_SETINFO, &tmpinfo);
1768 } 1773 }
1769 } 1774 }
1770} 1775}
1771 1776
1772/* 1777/*
1773 * Check that the blocksize is a power of 2 as OSS wants. 1778 * Check that the blocksize is a power of 2 as OSS wants.
1774 * If not, set it to be. 1779 * If not, set it to be.
1775 */ 1780 */
1776static void 1781static void
1777setblocksize(int fd, struct audio_info *info) 1782setblocksize(int fd, struct audio_info *info)
1778{ 1783{
1779 struct audio_info set; 1784 struct audio_info set;
1780 size_t s; 1785 size_t s;
1781 1786
1782 if (info->blocksize & (info->blocksize-1)) { 1787 if (info->blocksize & (info->blocksize-1)) {
1783 for(s = 32; s < info->blocksize; s <<= 1) 1788 for(s = 32; s < info->blocksize; s <<= 1)
1784 ; 1789 ;
1785 AUDIO_INITINFO(&set); 1790 AUDIO_INITINFO(&set);
1786 set.blocksize = s; 1791 set.blocksize = s;
1787 ioctl(fd, AUDIO_SETINFO, &set); 1792 ioctl(fd, AUDIO_SETINFO, &set);
1788 ioctl(fd, AUDIO_GETBUFINFO, info); 1793 ioctl(fd, AUDIO_GETBUFINFO, info);
1789 } 1794 }
1790} 1795}