Annotation of src/lib/libossaudio/ossaudio.c, Revision 1.41
1.41 ! nia 1: /* $NetBSD: ossaudio.c,v 1.40 2020/04/15 15:25:33 nia Exp $ */
1.1 augustss 2:
1.7 augustss 3: /*-
1.1 augustss 4: * Copyright (c) 1997 The NetBSD Foundation, Inc.
5: * All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: *
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
18: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
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
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
26: * POSSIBILITY OF SUCH DAMAGE.
27: */
1.18 lukem 28:
29: #include <sys/cdefs.h>
1.41 ! nia 30: __RCSID("$NetBSD: ossaudio.c,v 1.40 2020/04/15 15:25:33 nia Exp $");
1.1 augustss 31:
32: /*
33: * This is an OSS (Linux) sound API emulator.
34: * It provides the essentials of the API.
35: */
36:
37: /* XXX This file is essentially the same as sys/compat/ossaudio.c.
1.3 augustss 38: * With some preprocessor magic it could be the same file.
1.1 augustss 39: */
40:
41: #include <string.h>
42: #include <sys/types.h>
43: #include <sys/ioctl.h>
44: #include <sys/audioio.h>
45: #include <sys/stat.h>
46: #include <errno.h>
1.29 nat 47: #include <fcntl.h>
48: #include <stdio.h>
49: #include <unistd.h>
1.27 christos 50: #include <stdarg.h>
1.1 augustss 51:
52: #include "soundcard.h"
53: #undef ioctl
54:
55: #define GET_DEV(com) ((com) & 0xff)
56:
1.12 tron 57: #define TO_OSSVOL(x) (((x) * 100 + 127) / 255)
58: #define FROM_OSSVOL(x) ((((x) > 100 ? 100 : (x)) * 255 + 50) / 100)
1.1 augustss 59:
1.38 isaki 60: #define GETPRINFO(info, name) \
61: (((info)->mode == AUMODE_RECORD) \
62: ? (info)->record.name : (info)->play.name)
63:
1.1 augustss 64: static struct audiodevinfo *getdevinfo(int);
65:
1.41 ! nia 66: static void setchannels(int, int, int);
1.1 augustss 67: static void setblocksize(int, struct audio_info *);
68:
69: static int audio_ioctl(int, unsigned long, void *);
70: static int mixer_ioctl(int, unsigned long, void *);
1.27 christos 71: static int opaque_to_enum(struct audiodevinfo *, audio_mixer_name_t *, int);
72: static int enum_to_ord(struct audiodevinfo *, int);
73: static int enum_to_mask(struct audiodevinfo *, int);
1.1 augustss 74:
75: #define INTARG (*(int*)argp)
76:
77: int
1.27 christos 78: _oss_ioctl(int fd, unsigned long com, ...)
1.1 augustss 79: {
1.27 christos 80: va_list ap;
81: void *argp;
82:
83: va_start(ap, com);
84: argp = va_arg(ap, void *);
85: va_end(ap);
86:
1.1 augustss 87: if (IOCGROUP(com) == 'P')
88: return audio_ioctl(fd, com, argp);
89: else if (IOCGROUP(com) == 'M')
90: return mixer_ioctl(fd, com, argp);
91: else
92: return ioctl(fd, com, argp);
93: }
94:
95: static int
96: audio_ioctl(int fd, unsigned long com, void *argp)
97: {
1.8 simonb 98:
1.39 nia 99: struct audio_info tmpinfo, hwfmt;
1.1 augustss 100: struct audio_offset tmpoffs;
101: struct audio_buf_info bufinfo;
102: struct count_info cntinfo;
103: struct audio_encoding tmpenc;
1.29 nat 104: struct oss_sysinfo tmpsysinfo;
105: struct oss_audioinfo *tmpaudioinfo;
106: audio_device_t tmpaudiodev;
107: struct stat tmpstat;
108: dev_t devno;
109: char version[32] = "4.01";
110: char license[16] = "NetBSD";
1.1 augustss 111: u_int u;
1.38 isaki 112: u_int encoding;
113: u_int precision;
1.1 augustss 114: int idat, idata;
115: int retval;
1.29 nat 116: int i;
1.1 augustss 117:
1.20 lukem 118: idat = 0;
119:
1.1 augustss 120: switch (com) {
121: case SNDCTL_DSP_RESET:
122: retval = ioctl(fd, AUDIO_FLUSH, 0);
123: if (retval < 0)
124: return retval;
125: break;
126: case SNDCTL_DSP_SYNC:
127: retval = ioctl(fd, AUDIO_DRAIN, 0);
128: if (retval < 0)
129: return retval;
1.16 mycroft 130: break;
131: case SNDCTL_DSP_POST:
132: /* This call is merely advisory, and may be a nop. */
1.1 augustss 133: break;
134: case SNDCTL_DSP_SPEED:
135: AUDIO_INITINFO(&tmpinfo);
136: tmpinfo.play.sample_rate =
137: tmpinfo.record.sample_rate = INTARG;
1.39 nia 138: /*
139: * The default NetBSD behavior if an unsupported sample rate
140: * is set is to return an error code and keep the rate at the
141: * default of 8000 Hz.
142: *
143: * However, OSS specifies that a sample rate supported by the
144: * hardware is returned if the exact rate could not be set.
145: *
146: * So, if the chosen sample rate is invalid, set and return
147: * the current hardware rate.
148: */
149: if (ioctl(fd, AUDIO_SETINFO, &tmpinfo) < 0) {
150: /* Don't care that SETINFO failed the first time... */
151: errno = 0;
152: retval = ioctl(fd, AUDIO_GETFORMAT, &hwfmt);
153: if (retval < 0)
154: return retval;
155: retval = ioctl(fd, AUDIO_GETINFO, &tmpinfo);
156: if (retval < 0)
157: return retval;
158: tmpinfo.play.sample_rate =
159: tmpinfo.record.sample_rate =
160: (tmpinfo.mode == AUMODE_RECORD) ?
161: hwfmt.record.sample_rate :
162: hwfmt.play.sample_rate;
163: retval = ioctl(fd, AUDIO_SETINFO, &tmpinfo);
164: if (retval < 0)
165: return retval;
166: }
1.10 augustss 167: /* FALLTHRU */
1.1 augustss 168: case SOUND_PCM_READ_RATE:
1.21 joerg 169: retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
1.1 augustss 170: if (retval < 0)
171: return retval;
1.38 isaki 172: INTARG = GETPRINFO(&tmpinfo, sample_rate);
1.1 augustss 173: break;
174: case SNDCTL_DSP_STEREO:
175: AUDIO_INITINFO(&tmpinfo);
176: tmpinfo.play.channels =
177: tmpinfo.record.channels = INTARG ? 2 : 1;
178: (void) ioctl(fd, AUDIO_SETINFO, &tmpinfo);
1.21 joerg 179: retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
1.1 augustss 180: if (retval < 0)
181: return retval;
1.38 isaki 182: INTARG = GETPRINFO(&tmpinfo, channels) - 1;
1.1 augustss 183: break;
184: case SNDCTL_DSP_GETBLKSIZE:
1.21 joerg 185: retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
1.1 augustss 186: if (retval < 0)
187: return retval;
188: setblocksize(fd, &tmpinfo);
189: INTARG = tmpinfo.blocksize;
190: break;
191: case SNDCTL_DSP_SETFMT:
1.4 augustss 192: AUDIO_INITINFO(&tmpinfo);
1.1 augustss 193: switch (INTARG) {
194: case AFMT_MU_LAW:
195: tmpinfo.play.precision =
196: tmpinfo.record.precision = 8;
197: tmpinfo.play.encoding =
198: tmpinfo.record.encoding = AUDIO_ENCODING_ULAW;
199: break;
200: case AFMT_A_LAW:
201: tmpinfo.play.precision =
202: tmpinfo.record.precision = 8;
203: tmpinfo.play.encoding =
204: tmpinfo.record.encoding = AUDIO_ENCODING_ALAW;
205: break;
206: case AFMT_U8:
207: tmpinfo.play.precision =
208: tmpinfo.record.precision = 8;
209: tmpinfo.play.encoding =
210: tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR;
211: break;
212: case AFMT_S8:
213: tmpinfo.play.precision =
214: tmpinfo.record.precision = 8;
215: tmpinfo.play.encoding =
216: tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR;
217: break;
218: case AFMT_S16_LE:
219: tmpinfo.play.precision =
220: tmpinfo.record.precision = 16;
221: tmpinfo.play.encoding =
222: tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_LE;
223: break;
224: case AFMT_S16_BE:
225: tmpinfo.play.precision =
226: tmpinfo.record.precision = 16;
227: tmpinfo.play.encoding =
228: tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_BE;
229: break;
230: case AFMT_U16_LE:
231: tmpinfo.play.precision =
232: tmpinfo.record.precision = 16;
233: tmpinfo.play.encoding =
234: tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR_LE;
235: break;
236: case AFMT_U16_BE:
237: tmpinfo.play.precision =
238: tmpinfo.record.precision = 16;
239: tmpinfo.play.encoding =
240: tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR_BE;
241: break;
1.40 nia 242: /*
243: * XXX: When the kernel supports 24-bit LPCM by default,
244: * the 24-bit formats should be handled properly instead
245: * of falling back to 32 bits.
246: */
1.30 nat 247: case AFMT_S24_LE:
248: case AFMT_S32_LE:
249: tmpinfo.play.precision =
250: tmpinfo.record.precision = 32;
251: tmpinfo.play.encoding =
252: tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_LE;
253: break;
1.40 nia 254: case AFMT_S24_BE:
1.30 nat 255: case AFMT_S32_BE:
256: tmpinfo.play.precision =
257: tmpinfo.record.precision = 32;
258: tmpinfo.play.encoding =
259: tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_BE;
260: break;
1.25 jmcneill 261: case AFMT_AC3:
262: tmpinfo.play.precision =
263: tmpinfo.record.precision = 16;
264: tmpinfo.play.encoding =
265: tmpinfo.record.encoding = AUDIO_ENCODING_AC3;
266: break;
1.1 augustss 267: default:
1.40 nia 268: /*
269: * OSSv4 specifies that if an invalid format is chosen
270: * by an application then a sensible format supported
271: * by the hardware is returned.
272: *
273: * In this case, we pick the current hardware format.
274: */
275: retval = ioctl(fd, AUDIO_GETFORMAT, &hwfmt);
276: if (retval < 0)
277: return retval;
278: retval = ioctl(fd, AUDIO_GETINFO, &tmpinfo);
279: if (retval < 0)
280: return retval;
281: tmpinfo.play.encoding =
282: tmpinfo.record.encoding =
283: (tmpinfo.mode == AUMODE_RECORD) ?
284: hwfmt.record.encoding : hwfmt.play.encoding;
285: tmpinfo.play.precision =
286: tmpinfo.record.precision =
287: (tmpinfo.mode == AUMODE_RECORD) ?
288: hwfmt.record.precision : hwfmt.play.precision ;
289: break;
1.1 augustss 290: }
1.40 nia 291: /*
292: * In the post-kernel-mixer world, assume that any error means
293: * it's fatal rather than an unsupported format being selected.
294: */
295: retval = ioctl(fd, AUDIO_SETINFO, &tmpinfo);
296: if (retval < 0)
297: return retval;
1.10 augustss 298: /* FALLTHRU */
1.1 augustss 299: case SOUND_PCM_READ_BITS:
1.21 joerg 300: retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
1.1 augustss 301: if (retval < 0)
302: return retval;
1.38 isaki 303: encoding = GETPRINFO(&tmpinfo, encoding);
304: precision = GETPRINFO(&tmpinfo, precision);
305: switch (encoding) {
1.1 augustss 306: case AUDIO_ENCODING_ULAW:
307: idat = AFMT_MU_LAW;
308: break;
309: case AUDIO_ENCODING_ALAW:
310: idat = AFMT_A_LAW;
311: break;
312: case AUDIO_ENCODING_SLINEAR_LE:
1.38 isaki 313: if (precision == 32)
1.30 nat 314: idat = AFMT_S32_LE;
1.38 isaki 315: else if (precision == 24)
1.30 nat 316: idat = AFMT_S24_LE;
1.38 isaki 317: else if (precision == 16)
1.1 augustss 318: idat = AFMT_S16_LE;
319: else
320: idat = AFMT_S8;
321: break;
322: case AUDIO_ENCODING_SLINEAR_BE:
1.38 isaki 323: if (precision == 32)
1.30 nat 324: idat = AFMT_S32_BE;
1.38 isaki 325: else if (precision == 24)
1.30 nat 326: idat = AFMT_S24_BE;
1.38 isaki 327: else if (precision == 16)
1.1 augustss 328: idat = AFMT_S16_BE;
329: else
330: idat = AFMT_S8;
331: break;
332: case AUDIO_ENCODING_ULINEAR_LE:
1.38 isaki 333: if (precision == 16)
1.1 augustss 334: idat = AFMT_U16_LE;
335: else
336: idat = AFMT_U8;
337: break;
338: case AUDIO_ENCODING_ULINEAR_BE:
1.38 isaki 339: if (precision == 16)
1.1 augustss 340: idat = AFMT_U16_BE;
341: else
342: idat = AFMT_U8;
343: break;
344: case AUDIO_ENCODING_ADPCM:
345: idat = AFMT_IMA_ADPCM;
346: break;
1.25 jmcneill 347: case AUDIO_ENCODING_AC3:
348: idat = AFMT_AC3;
349: break;
1.1 augustss 350: }
351: INTARG = idat;
352: break;
353: case SNDCTL_DSP_CHANNELS:
1.41 ! nia 354: retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
! 355: if (retval < 0)
! 356: return retval;
! 357: setchannels(fd, tmpinfo.mode, INTARG);
1.10 augustss 358: /* FALLTHRU */
1.1 augustss 359: case SOUND_PCM_READ_CHANNELS:
1.21 joerg 360: retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
1.1 augustss 361: if (retval < 0)
362: return retval;
1.38 isaki 363: INTARG = GETPRINFO(&tmpinfo, channels);
1.1 augustss 364: break;
365: case SOUND_PCM_WRITE_FILTER:
366: case SOUND_PCM_READ_FILTER:
367: errno = EINVAL;
368: return -1; /* XXX unimplemented */
369: case SNDCTL_DSP_SUBDIVIDE:
1.21 joerg 370: retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
1.1 augustss 371: if (retval < 0)
372: return retval;
373: setblocksize(fd, &tmpinfo);
374: idat = INTARG;
375: if (idat == 0)
1.2 augustss 376: idat = tmpinfo.play.buffer_size / tmpinfo.blocksize;
377: idat = (tmpinfo.play.buffer_size / idat) & -4;
1.1 augustss 378: AUDIO_INITINFO(&tmpinfo);
379: tmpinfo.blocksize = idat;
380: retval = ioctl(fd, AUDIO_SETINFO, &tmpinfo);
381: if (retval < 0)
382: return retval;
1.2 augustss 383: INTARG = tmpinfo.play.buffer_size / tmpinfo.blocksize;
1.1 augustss 384: break;
385: case SNDCTL_DSP_SETFRAGMENT:
386: AUDIO_INITINFO(&tmpinfo);
387: idat = INTARG;
388: if ((idat & 0xffff) < 4 || (idat & 0xffff) > 17)
389: return EINVAL;
390: tmpinfo.blocksize = 1 << (idat & 0xffff);
1.11 augustss 391: tmpinfo.hiwat = ((unsigned)idat >> 16) & 0x7fff;
1.1 augustss 392: if (tmpinfo.hiwat == 0) /* 0 means set to max */
393: tmpinfo.hiwat = 65536;
394: (void) ioctl(fd, AUDIO_SETINFO, &tmpinfo);
1.21 joerg 395: retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
1.1 augustss 396: if (retval < 0)
397: return retval;
398: u = tmpinfo.blocksize;
1.6 augustss 399: for(idat = 0; u > 1; idat++, u >>= 1)
1.1 augustss 400: ;
1.5 augustss 401: idat |= (tmpinfo.hiwat & 0x7fff) << 16;
1.1 augustss 402: INTARG = idat;
403: break;
404: case SNDCTL_DSP_GETFMTS:
1.8 simonb 405: for(idat = 0, tmpenc.index = 0;
406: ioctl(fd, AUDIO_GETENC, &tmpenc) == 0;
1.1 augustss 407: tmpenc.index++) {
408: switch(tmpenc.encoding) {
409: case AUDIO_ENCODING_ULAW:
410: idat |= AFMT_MU_LAW;
411: break;
412: case AUDIO_ENCODING_ALAW:
413: idat |= AFMT_A_LAW;
414: break;
415: case AUDIO_ENCODING_SLINEAR:
416: idat |= AFMT_S8;
417: break;
418: case AUDIO_ENCODING_SLINEAR_LE:
1.29 nat 419: if (tmpenc.precision == 32)
420: idat |= AFMT_S32_LE;
421: else if (tmpenc.precision == 24)
422: idat |= AFMT_S24_LE;
423: else if (tmpenc.precision == 16)
1.1 augustss 424: idat |= AFMT_S16_LE;
425: else
426: idat |= AFMT_S8;
427: break;
428: case AUDIO_ENCODING_SLINEAR_BE:
1.29 nat 429: if (tmpenc.precision == 32)
430: idat |= AFMT_S32_BE;
431: else if (tmpenc.precision == 24)
432: idat |= AFMT_S24_BE;
433: else if (tmpenc.precision == 16)
1.1 augustss 434: idat |= AFMT_S16_BE;
435: else
436: idat |= AFMT_S8;
437: break;
438: case AUDIO_ENCODING_ULINEAR:
439: idat |= AFMT_U8;
440: break;
441: case AUDIO_ENCODING_ULINEAR_LE:
442: if (tmpenc.precision == 16)
443: idat |= AFMT_U16_LE;
444: else
445: idat |= AFMT_U8;
446: break;
447: case AUDIO_ENCODING_ULINEAR_BE:
448: if (tmpenc.precision == 16)
449: idat |= AFMT_U16_BE;
450: else
451: idat |= AFMT_U8;
452: break;
453: case AUDIO_ENCODING_ADPCM:
454: idat |= AFMT_IMA_ADPCM;
455: break;
1.25 jmcneill 456: case AUDIO_ENCODING_AC3:
457: idat |= AFMT_AC3;
458: break;
1.1 augustss 459: default:
460: break;
461: }
462: }
463: INTARG = idat;
464: break;
465: case SNDCTL_DSP_GETOSPACE:
1.21 joerg 466: retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
1.14 augustss 467: if (retval < 0)
468: return retval;
469: setblocksize(fd, &tmpinfo);
470: bufinfo.fragsize = tmpinfo.blocksize;
1.35 isaki 471: bufinfo.fragments = tmpinfo.hiwat - (tmpinfo.play.seek
472: + tmpinfo.blocksize - 1) / tmpinfo.blocksize;
1.14 augustss 473: bufinfo.fragstotal = tmpinfo.hiwat;
1.35 isaki 474: bufinfo.bytes = tmpinfo.hiwat * tmpinfo.blocksize
475: - tmpinfo.play.seek;
1.14 augustss 476: *(struct audio_buf_info *)argp = bufinfo;
477: break;
1.1 augustss 478: case SNDCTL_DSP_GETISPACE:
1.21 joerg 479: retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
1.1 augustss 480: if (retval < 0)
481: return retval;
482: setblocksize(fd, &tmpinfo);
483: bufinfo.fragsize = tmpinfo.blocksize;
1.33 nat 484: bufinfo.fragments = tmpinfo.record.seek / tmpinfo.blocksize;
1.36 isaki 485: bufinfo.fragstotal =
486: tmpinfo.record.buffer_size / tmpinfo.blocksize;
487: bufinfo.bytes = tmpinfo.record.seek;
1.1 augustss 488: *(struct audio_buf_info *)argp = bufinfo;
489: break;
490: case SNDCTL_DSP_NONBLOCK:
491: idat = 1;
492: retval = ioctl(fd, FIONBIO, &idat);
493: if (retval < 0)
494: return retval;
495: break;
496: case SNDCTL_DSP_GETCAPS:
1.10 augustss 497: retval = ioctl(fd, AUDIO_GETPROPS, &idata);
1.1 augustss 498: if (retval < 0)
499: return retval;
500: idat = DSP_CAP_TRIGGER; /* pretend we have trigger */
501: if (idata & AUDIO_PROP_FULLDUPLEX)
502: idat |= DSP_CAP_DUPLEX;
503: if (idata & AUDIO_PROP_MMAP)
504: idat |= DSP_CAP_MMAP;
505: INTARG = idat;
506: break;
507: #if 0
508: case SNDCTL_DSP_GETTRIGGER:
1.21 joerg 509: retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
1.1 augustss 510: if (retval < 0)
511: return retval;
512: idat = (tmpinfo.play.pause ? 0 : PCM_ENABLE_OUTPUT) |
513: (tmpinfo.record.pause ? 0 : PCM_ENABLE_INPUT);
514: retval = copyout(&idat, SCARG(uap, data), sizeof idat);
515: if (retval < 0)
516: return retval;
517: break;
518: case SNDCTL_DSP_SETTRIGGER:
519: AUDIO_INITINFO(&tmpinfo);
520: retval = copyin(SCARG(uap, data), &idat, sizeof idat);
521: if (retval < 0)
522: return retval;
523: tmpinfo.play.pause = (idat & PCM_ENABLE_OUTPUT) == 0;
524: tmpinfo.record.pause = (idat & PCM_ENABLE_INPUT) == 0;
1.10 augustss 525: (void) ioctl(fd, AUDIO_SETINFO, &tmpinfo);
1.1 augustss 526: retval = copyout(&idat, SCARG(uap, data), sizeof idat);
527: if (retval < 0)
528: return retval;
529: break;
530: #else
531: case SNDCTL_DSP_GETTRIGGER:
532: case SNDCTL_DSP_SETTRIGGER:
533: /* XXX Do nothing for now. */
534: INTARG = PCM_ENABLE_OUTPUT;
535: break;
536: #endif
537: case SNDCTL_DSP_GETIPTR:
538: retval = ioctl(fd, AUDIO_GETIOFFS, &tmpoffs);
539: if (retval < 0)
540: return retval;
541: cntinfo.bytes = tmpoffs.samples;
542: cntinfo.blocks = tmpoffs.deltablks;
543: cntinfo.ptr = tmpoffs.offset;
544: *(struct count_info *)argp = cntinfo;
545: break;
546: case SNDCTL_DSP_GETOPTR:
547: retval = ioctl(fd, AUDIO_GETOOFFS, &tmpoffs);
548: if (retval < 0)
549: return retval;
550: cntinfo.bytes = tmpoffs.samples;
551: cntinfo.blocks = tmpoffs.deltablks;
552: cntinfo.ptr = tmpoffs.offset;
553: *(struct count_info *)argp = cntinfo;
554: break;
1.29 nat 555: case SNDCTL_SYSINFO:
1.32 maya 556: strlcpy(tmpsysinfo.product, "OSS/NetBSD",
557: sizeof tmpsysinfo.product);
1.31 maya 558: strlcpy(tmpsysinfo.version, version, sizeof tmpsysinfo.version);
559: strlcpy(tmpsysinfo.license, license, sizeof tmpsysinfo.license);
1.29 nat 560: tmpsysinfo.versionnum = SOUND_VERSION;
561: memset(tmpsysinfo.options, 0, 8);
562: tmpsysinfo.numaudios = OSS_MAX_AUDIO_DEVS;
563: tmpsysinfo.numaudioengines = 1;
1.34 mrg 564: memset(tmpsysinfo.openedaudio, 0, sizeof(tmpsysinfo.openedaudio));
1.29 nat 565: tmpsysinfo.numsynths = 1;
566: tmpsysinfo.nummidis = -1;
567: tmpsysinfo.numtimers = -1;
568: tmpsysinfo.nummixers = 1;
569: tmpsysinfo.numcards = 1;
1.34 mrg 570: memset(tmpsysinfo.openedmidi, 0, sizeof(tmpsysinfo.openedmidi));
1.29 nat 571: *(struct oss_sysinfo *)argp = tmpsysinfo;
572: break;
573: case SNDCTL_ENGINEINFO:
574: case SNDCTL_AUDIOINFO:
575: devno = 0;
576: tmpaudioinfo = (struct oss_audioinfo*)argp;
577: if (tmpaudioinfo == NULL)
578: return EINVAL;
579: if (tmpaudioinfo->dev < 0) {
580: fstat(fd, &tmpstat);
581: if ((tmpstat.st_rdev & 0xff00) == 0x2a00)
582: devno = tmpstat.st_rdev & 0xff;
583: if (devno >= 0x80)
584: tmpaudioinfo->dev = devno & 0x7f;
585: }
586: if (tmpaudioinfo->dev < 0)
587: tmpaudioinfo->dev = 0;
588:
589: snprintf(tmpaudioinfo->devnode, OSS_DEVNODE_SIZE,
590: "/dev/audio%d", tmpaudioinfo->dev);
591:
592: retval = ioctl(fd, AUDIO_GETDEV, &tmpaudiodev);
593: if (retval < 0)
594: return retval;
595: retval = ioctl(fd, AUDIO_GETINFO, &tmpinfo);
596: if (retval < 0)
597: return retval;
598: retval = ioctl(fd, AUDIO_GETPROPS, &idata);
599: if (retval < 0)
600: return retval;
601: idat = DSP_CAP_TRIGGER; /* pretend we have trigger */
602: if (idata & AUDIO_PROP_FULLDUPLEX)
603: idat |= DSP_CAP_DUPLEX;
604: if (idata & AUDIO_PROP_MMAP)
605: idat |= DSP_CAP_MMAP;
606: idat = PCM_CAP_INPUT | PCM_CAP_OUTPUT;
1.31 maya 607: strlcpy(tmpaudioinfo->name, tmpaudiodev.name,
608: sizeof tmpaudioinfo->name);
1.29 nat 609: tmpaudioinfo->busy = tmpinfo.play.open;
610: tmpaudioinfo->pid = -1;
611: tmpaudioinfo->caps = idat;
612: ioctl(fd, SNDCTL_DSP_GETFMTS, &tmpaudioinfo->iformats);
613: tmpaudioinfo->oformats = tmpaudioinfo->iformats;
614: tmpaudioinfo->magic = -1;
615: memset(tmpaudioinfo->cmd, 0, 64);
616: tmpaudioinfo->card_number = -1;
617: memset(tmpaudioinfo->song_name, 0, 64);
618: memset(tmpaudioinfo->label, 0, 16);
619: tmpaudioinfo->port_number = tmpinfo.play.port;
620: tmpaudioinfo->mixer_dev = tmpaudioinfo->dev;
621: tmpaudioinfo->legacy_device = -1;
622: tmpaudioinfo->enabled = 1;
623: tmpaudioinfo->flags = -1;
624: tmpaudioinfo->min_rate = tmpinfo.play.sample_rate;
625: tmpaudioinfo->max_rate = tmpinfo.play.sample_rate;
626: tmpaudioinfo->nrates = 2;
627: for (i = 0; i < tmpaudioinfo->nrates; i++)
628: tmpaudioinfo->rates[i] = tmpinfo.play.sample_rate;
629: tmpaudioinfo->min_channels = tmpinfo.play.channels;
630: tmpaudioinfo->max_channels = tmpinfo.play.channels;
631: tmpaudioinfo->binding = -1;
632: tmpaudioinfo->rate_source = -1;
633: memset(tmpaudioinfo->handle, 0, 16);
634: tmpaudioinfo->next_play_engine = 0;
635: tmpaudioinfo->next_rec_engine = 0;
636: argp = tmpaudioinfo;
637: break;
638: case SNDCTL_DSP_GETPLAYVOL:
639: retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
640: if (retval < 0)
641: return retval;
642: *(uint *)argp = tmpinfo.play.gain;
643: break;
644: case SNDCTL_DSP_SETPLAYVOL:
645: retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
646: if (retval < 0)
647: return retval;
648: if (*(uint *)argp > 255)
649: tmpinfo.play.gain = 255;
650: else
651: tmpinfo.play.gain = *(uint *)argp;
652: retval = ioctl(fd, AUDIO_SETINFO, &tmpinfo);
653: if (retval < 0)
654: return retval;
655: break;
656: case SNDCTL_DSP_GETRECVOL:
657: retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
658: if (retval < 0)
659: return retval;
660: *(uint *)argp = tmpinfo.record.gain;
661: break;
662: case SNDCTL_DSP_SETRECVOL:
663: retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
664: if (retval < 0)
665: return retval;
666: if (*(uint *)argp > 255)
667: tmpinfo.record.gain = 255;
668: else
669: tmpinfo.record.gain = *(uint *)argp;
670: retval = ioctl(fd, AUDIO_SETINFO, &tmpinfo);
671: if (retval < 0)
672: return retval;
673: break;
674: case SNDCTL_DSP_SKIP:
675: case SNDCTL_DSP_SILENCE:
676: return EINVAL;
1.17 jdolecek 677: case SNDCTL_DSP_SETDUPLEX:
678: idat = 1;
679: retval = ioctl(fd, AUDIO_SETFD, &idat);
680: if (retval < 0)
681: return retval;
682: break;
1.22 mlelstv 683: case SNDCTL_DSP_GETODELAY:
684: retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
685: if (retval < 0)
686: return retval;
687: idat = tmpinfo.play.seek + tmpinfo.blocksize / 2;
688: INTARG = idat;
689: break;
690: case SNDCTL_DSP_PROFILE:
691: /* This gives just a hint to the driver,
692: * implementing it as a NOP is ok
693: */
694: break;
1.1 augustss 695: case SNDCTL_DSP_MAPINBUF:
696: case SNDCTL_DSP_MAPOUTBUF:
697: case SNDCTL_DSP_SETSYNCRO:
698: errno = EINVAL;
699: return -1; /* XXX unimplemented */
700: default:
701: errno = EINVAL;
702: return -1;
703: }
704:
705: return 0;
706: }
707:
708:
1.11 augustss 709: /* If the NetBSD mixer device should have more than NETBSD_MAXDEVS devices
1.1 augustss 710: * some will not be available to Linux */
1.11 augustss 711: #define NETBSD_MAXDEVS 64
1.1 augustss 712: struct audiodevinfo {
713: int done;
714: dev_t dev;
1.8 simonb 715: int16_t devmap[SOUND_MIXER_NRDEVICES],
1.1 augustss 716: rdevmap[NETBSD_MAXDEVS];
1.11 augustss 717: char names[NETBSD_MAXDEVS][MAX_AUDIO_DEV_LEN];
718: int enum2opaque[NETBSD_MAXDEVS];
1.1 augustss 719: u_long devmask, recmask, stereomask;
1.20 lukem 720: u_long caps;
721: int source;
1.1 augustss 722: };
723:
1.11 augustss 724: static int
725: opaque_to_enum(struct audiodevinfo *di, audio_mixer_name_t *label, int opq)
726: {
727: int i, o;
728:
729: for (i = 0; i < NETBSD_MAXDEVS; i++) {
730: o = di->enum2opaque[i];
731: if (o == opq)
732: break;
733: if (o == -1 && label != NULL &&
734: !strncmp(di->names[i], label->name, sizeof di->names[i])) {
735: di->enum2opaque[i] = opq;
736: break;
737: }
738: }
739: if (i >= NETBSD_MAXDEVS)
740: i = -1;
741: /*printf("opq_to_enum %s %d -> %d\n", label->name, opq, i);*/
742: return (i);
743: }
744:
745: static int
746: enum_to_ord(struct audiodevinfo *di, int enm)
747: {
748: if (enm >= NETBSD_MAXDEVS)
749: return (-1);
750:
751: /*printf("enum_to_ord %d -> %d\n", enm, di->enum2opaque[enm]);*/
752: return (di->enum2opaque[enm]);
753: }
754:
755: static int
756: enum_to_mask(struct audiodevinfo *di, int enm)
757: {
758: int m;
759: if (enm >= NETBSD_MAXDEVS)
760: return (0);
761:
762: m = di->enum2opaque[enm];
763: if (m == -1)
764: m = 0;
765: /*printf("enum_to_mask %d -> %d\n", enm, di->enum2opaque[enm]);*/
766: return (m);
767: }
768:
1.8 simonb 769: /*
1.1 augustss 770: * Collect the audio device information to allow faster
771: * emulation of the Linux mixer ioctls. Cache the information
772: * to eliminate the overhead of repeating all the ioctls needed
773: * to collect the information.
774: */
775: static struct audiodevinfo *
776: getdevinfo(int fd)
777: {
778: mixer_devinfo_t mi;
1.11 augustss 779: int i, j, e;
1.1 augustss 780: static struct {
1.28 christos 781: const char *name;
1.1 augustss 782: int code;
783: } *dp, devs[] = {
784: { AudioNmicrophone, SOUND_MIXER_MIC },
785: { AudioNline, SOUND_MIXER_LINE },
786: { AudioNcd, SOUND_MIXER_CD },
787: { AudioNdac, SOUND_MIXER_PCM },
1.15 kim 788: { AudioNaux, SOUND_MIXER_LINE1 },
1.1 augustss 789: { AudioNrecord, SOUND_MIXER_IMIX },
790: { AudioNmaster, SOUND_MIXER_VOLUME },
791: { AudioNtreble, SOUND_MIXER_TREBLE },
792: { AudioNbass, SOUND_MIXER_BASS },
793: { AudioNspeaker, SOUND_MIXER_SPEAKER },
794: /* { AudioNheadphone, ?? },*/
795: { AudioNoutput, SOUND_MIXER_OGAIN },
796: { AudioNinput, SOUND_MIXER_IGAIN },
797: /* { AudioNmaster, SOUND_MIXER_SPEAKER },*/
798: /* { AudioNstereo, ?? },*/
799: /* { AudioNmono, ?? },*/
800: { AudioNfmsynth, SOUND_MIXER_SYNTH },
801: /* { AudioNwave, SOUND_MIXER_PCM },*/
802: { AudioNmidi, SOUND_MIXER_SYNTH },
803: /* { AudioNmixerout, ?? },*/
804: { 0, -1 }
805: };
1.28 christos 806: static struct audiodevinfo devcache = { .done = 0 };
1.1 augustss 807: struct audiodevinfo *di = &devcache;
808: struct stat sb;
1.27 christos 809: size_t mlen, dlen;
1.1 augustss 810:
811: /* Figure out what device it is so we can check if the
812: * cached data is valid.
813: */
814: if (fstat(fd, &sb) < 0)
815: return 0;
816: if (di->done && di->dev == sb.st_dev)
817: return di;
818:
819: di->done = 1;
820: di->dev = sb.st_dev;
821: di->devmask = 0;
822: di->recmask = 0;
823: di->stereomask = 0;
1.11 augustss 824: di->source = ~0;
1.1 augustss 825: di->caps = 0;
826: for(i = 0; i < SOUND_MIXER_NRDEVICES; i++)
827: di->devmap[i] = -1;
1.11 augustss 828: for(i = 0; i < NETBSD_MAXDEVS; i++) {
1.1 augustss 829: di->rdevmap[i] = -1;
1.11 augustss 830: di->names[i][0] = '\0';
831: di->enum2opaque[i] = -1;
832: }
1.1 augustss 833: for(i = 0; i < NETBSD_MAXDEVS; i++) {
834: mi.index = i;
835: if (ioctl(fd, AUDIO_MIXER_DEVINFO, &mi) < 0)
836: break;
837: switch(mi.type) {
838: case AUDIO_MIXER_VALUE:
1.19 kent 839: for(dp = devs; dp->name; dp++) {
840: if (strcmp(dp->name, mi.label.name) == 0)
1.1 augustss 841: break;
1.19 kent 842: dlen = strlen(dp->name);
843: mlen = strlen(mi.label.name);
844: if (dlen < mlen
845: && mi.label.name[mlen-dlen-1] == '.'
1.27 christos 846: && strcmp(dp->name,
847: mi.label.name + mlen - dlen) == 0)
1.19 kent 848: break;
849: }
1.1 augustss 850: if (dp->code >= 0) {
851: di->devmap[dp->code] = i;
852: di->rdevmap[i] = dp->code;
853: di->devmask |= 1 << dp->code;
854: if (mi.un.v.num_channels == 2)
855: di->stereomask |= 1 << dp->code;
1.31 maya 856: strlcpy(di->names[i], mi.label.name,
1.11 augustss 857: sizeof di->names[i]);
1.1 augustss 858: }
859: break;
1.11 augustss 860: }
861: }
862: for(i = 0; i < NETBSD_MAXDEVS; i++) {
863: mi.index = i;
864: if (ioctl(fd, AUDIO_MIXER_DEVINFO, &mi) < 0)
865: break;
866: if (strcmp(mi.label.name, AudioNsource) != 0)
867: continue;
868: di->source = i;
869: switch(mi.type) {
1.1 augustss 870: case AUDIO_MIXER_ENUM:
1.11 augustss 871: for(j = 0; j < mi.un.e.num_mem; j++) {
872: e = opaque_to_enum(di,
873: &mi.un.e.member[j].label,
874: mi.un.e.member[j].ord);
875: if (e >= 0)
876: di->recmask |= 1 << di->rdevmap[e];
1.1 augustss 877: }
1.11 augustss 878: di->caps = SOUND_CAP_EXCL_INPUT;
1.1 augustss 879: break;
880: case AUDIO_MIXER_SET:
1.11 augustss 881: for(j = 0; j < mi.un.s.num_mem; j++) {
882: e = opaque_to_enum(di,
883: &mi.un.s.member[j].label,
884: mi.un.s.member[j].mask);
885: if (e >= 0)
886: di->recmask |= 1 << di->rdevmap[e];
1.1 augustss 887: }
888: break;
889: }
890: }
891: return di;
892: }
893:
894: int
895: mixer_ioctl(int fd, unsigned long com, void *argp)
1.8 simonb 896: {
1.1 augustss 897: struct audiodevinfo *di;
1.10 augustss 898: struct mixer_info *omi;
899: struct audio_device adev;
1.1 augustss 900: mixer_ctrl_t mc;
1.27 christos 901: u_long idat, n;
1.1 augustss 902: int i;
903: int retval;
1.27 christos 904: int l, r, error, e;
1.1 augustss 905:
1.20 lukem 906: idat = 0;
1.1 augustss 907: di = getdevinfo(fd);
908: if (di == 0)
909: return -1;
910:
911: switch (com) {
1.11 augustss 912: case OSS_GETVERSION:
913: idat = SOUND_VERSION;
914: break;
1.10 augustss 915: case SOUND_MIXER_INFO:
916: case SOUND_OLD_MIXER_INFO:
917: error = ioctl(fd, AUDIO_GETDEV, &adev);
918: if (error)
919: return (error);
920: omi = argp;
921: if (com == SOUND_MIXER_INFO)
922: omi->modify_counter = 1;
1.31 maya 923: strlcpy(omi->id, adev.name, sizeof omi->id);
924: strlcpy(omi->name, adev.name, sizeof omi->name);
1.10 augustss 925: return 0;
1.1 augustss 926: case SOUND_MIXER_READ_RECSRC:
927: if (di->source == -1)
928: return EINVAL;
929: mc.dev = di->source;
930: if (di->caps & SOUND_CAP_EXCL_INPUT) {
931: mc.type = AUDIO_MIXER_ENUM;
932: retval = ioctl(fd, AUDIO_MIXER_READ, &mc);
933: if (retval < 0)
934: return retval;
1.11 augustss 935: e = opaque_to_enum(di, NULL, mc.un.ord);
936: if (e >= 0)
937: idat = 1 << di->rdevmap[e];
1.1 augustss 938: } else {
939: mc.type = AUDIO_MIXER_SET;
940: retval = ioctl(fd, AUDIO_MIXER_READ, &mc);
941: if (retval < 0)
942: return retval;
1.11 augustss 943: e = opaque_to_enum(di, NULL, mc.un.mask);
944: if (e >= 0)
945: idat = 1 << di->rdevmap[e];
1.1 augustss 946: }
947: break;
948: case SOUND_MIXER_READ_DEVMASK:
949: idat = di->devmask;
950: break;
951: case SOUND_MIXER_READ_RECMASK:
952: idat = di->recmask;
953: break;
954: case SOUND_MIXER_READ_STEREODEVS:
955: idat = di->stereomask;
956: break;
957: case SOUND_MIXER_READ_CAPS:
958: idat = di->caps;
959: break;
960: case SOUND_MIXER_WRITE_RECSRC:
961: case SOUND_MIXER_WRITE_R_RECSRC:
962: if (di->source == -1)
963: return EINVAL;
964: mc.dev = di->source;
965: idat = INTARG;
966: if (di->caps & SOUND_CAP_EXCL_INPUT) {
967: mc.type = AUDIO_MIXER_ENUM;
968: for(i = 0; i < SOUND_MIXER_NRDEVICES; i++)
969: if (idat & (1 << i))
970: break;
971: if (i >= SOUND_MIXER_NRDEVICES ||
972: di->devmap[i] == -1)
973: return EINVAL;
1.11 augustss 974: mc.un.ord = enum_to_ord(di, di->devmap[i]);
1.1 augustss 975: } else {
976: mc.type = AUDIO_MIXER_SET;
977: mc.un.mask = 0;
978: for(i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
979: if (idat & (1 << i)) {
980: if (di->devmap[i] == -1)
981: return EINVAL;
1.27 christos 982: mc.un.mask |=
983: enum_to_mask(di, di->devmap[i]);
1.1 augustss 984: }
985: }
986: }
987: return ioctl(fd, AUDIO_MIXER_WRITE, &mc);
988: default:
989: if (MIXER_READ(SOUND_MIXER_FIRST) <= com &&
990: com < MIXER_READ(SOUND_MIXER_NRDEVICES)) {
991: n = GET_DEV(com);
992: if (di->devmap[n] == -1)
993: return EINVAL;
994: mc.dev = di->devmap[n];
995: mc.type = AUDIO_MIXER_VALUE;
996: doread:
1.27 christos 997: mc.un.value.num_channels =
998: di->stereomask & (1 << (u_int)n) ? 2 : 1;
1.1 augustss 999: retval = ioctl(fd, AUDIO_MIXER_READ, &mc);
1000: if (retval < 0)
1001: return retval;
1002: if (mc.type != AUDIO_MIXER_VALUE)
1003: return EINVAL;
1004: if (mc.un.value.num_channels != 2) {
1.27 christos 1005: l = r =
1006: mc.un.value.level[AUDIO_MIXER_LEVEL_MONO];
1.1 augustss 1007: } else {
1008: l = mc.un.value.level[AUDIO_MIXER_LEVEL_LEFT];
1009: r = mc.un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
1010: }
1011: idat = TO_OSSVOL(l) | (TO_OSSVOL(r) << 8);
1012: break;
1013: } else if ((MIXER_WRITE_R(SOUND_MIXER_FIRST) <= com &&
1014: com < MIXER_WRITE_R(SOUND_MIXER_NRDEVICES)) ||
1015: (MIXER_WRITE(SOUND_MIXER_FIRST) <= com &&
1016: com < MIXER_WRITE(SOUND_MIXER_NRDEVICES))) {
1017: n = GET_DEV(com);
1018: if (di->devmap[n] == -1)
1019: return EINVAL;
1020: idat = INTARG;
1.27 christos 1021: l = FROM_OSSVOL((u_int)idat & 0xff);
1.26 christos 1022: r = FROM_OSSVOL(((u_int)idat >> 8) & 0xff);
1.1 augustss 1023: mc.dev = di->devmap[n];
1024: mc.type = AUDIO_MIXER_VALUE;
1.27 christos 1025: if (di->stereomask & (1 << (u_int)n)) {
1.1 augustss 1026: mc.un.value.num_channels = 2;
1027: mc.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
1028: mc.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
1029: } else {
1030: mc.un.value.num_channels = 1;
1.27 christos 1031: mc.un.value.level[AUDIO_MIXER_LEVEL_MONO] =
1032: (l + r) / 2;
1.1 augustss 1033: }
1034: retval = ioctl(fd, AUDIO_MIXER_WRITE, &mc);
1035: if (retval < 0)
1036: return retval;
1037: if (MIXER_WRITE(SOUND_MIXER_FIRST) <= com &&
1038: com < MIXER_WRITE(SOUND_MIXER_NRDEVICES))
1039: return 0;
1040: goto doread;
1041: } else {
1042: errno = EINVAL;
1043: return -1;
1044: }
1045: }
1.27 christos 1046: INTARG = (int)idat;
1.1 augustss 1047: return 0;
1048: }
1049:
1050: /*
1.41 ! nia 1051: * When AUDIO_SETINFO fails to set a channel count, the application's chosen
! 1052: * number is out of range of what the kernel allows.
! 1053: *
! 1054: * When this happens, we use the current hardware settings. This is just in
! 1055: * case an application is abusing SNDCTL_DSP_CHANNELS - OSSv4 always sets and
! 1056: * returns a reasonable value, even if it wasn't what the user requested.
! 1057: *
! 1058: * XXX: If a device is opened for both playback and recording, and supports
! 1059: * fewer channels for recording than playback, applications that do both will
! 1060: * behave very strangely. OSS doesn't allow for reporting separate channel
! 1061: * counts for recording and playback. This could be worked around by always
! 1062: * mixing recorded data up to the same number of channels as is being used
! 1063: * for playback.
! 1064: */
! 1065: static void
! 1066: setchannels(int fd, int mode, int nchannels)
! 1067: {
! 1068: struct audio_info tmpinfo, hwfmt;
! 1069:
! 1070: if (ioctl(fd, AUDIO_GETFORMAT, &hwfmt) < 0) {
! 1071: errno = 0;
! 1072: hwfmt.record.channels = hwfmt.play.channels = 2;
! 1073: }
! 1074:
! 1075: if (mode & AUMODE_PLAY) {
! 1076: AUDIO_INITINFO(&tmpinfo);
! 1077: tmpinfo.play.channels = nchannels;
! 1078: if (ioctl(fd, AUDIO_SETINFO, &tmpinfo) < 0) {
! 1079: errno = 0;
! 1080: AUDIO_INITINFO(&tmpinfo);
! 1081: tmpinfo.play.channels = hwfmt.play.channels;
! 1082: (void)ioctl(fd, AUDIO_SETINFO, &tmpinfo);
! 1083: }
! 1084: }
! 1085:
! 1086: if (mode & AUMODE_RECORD) {
! 1087: AUDIO_INITINFO(&tmpinfo);
! 1088: tmpinfo.record.channels = nchannels;
! 1089: if (ioctl(fd, AUDIO_SETINFO, &tmpinfo) < 0) {
! 1090: errno = 0;
! 1091: AUDIO_INITINFO(&tmpinfo);
! 1092: tmpinfo.record.channels = hwfmt.record.channels;
! 1093: (void)ioctl(fd, AUDIO_SETINFO, &tmpinfo);
! 1094: }
! 1095: }
! 1096: }
! 1097:
! 1098: /*
1.1 augustss 1099: * Check that the blocksize is a power of 2 as OSS wants.
1100: * If not, set it to be.
1101: */
1.8 simonb 1102: static void
1.1 augustss 1103: setblocksize(int fd, struct audio_info *info)
1104: {
1105: struct audio_info set;
1.28 christos 1106: size_t s;
1.1 augustss 1107:
1108: if (info->blocksize & (info->blocksize-1)) {
1109: for(s = 32; s < info->blocksize; s <<= 1)
1110: ;
1111: AUDIO_INITINFO(&set);
1112: set.blocksize = s;
1113: ioctl(fd, AUDIO_SETINFO, &set);
1.21 joerg 1114: ioctl(fd, AUDIO_GETBUFINFO, info);
1.1 augustss 1115: }
1116: }
CVSweb <webmaster@jp.NetBSD.org>