Wed Apr 15 16:39:06 2020 UTC ()
ossaudio: If the user's channel count is rejected, use the hardware count


(nia)
diff -r1.40 -r1.41 src/lib/libossaudio/ossaudio.c
diff -r1.80 -r1.81 src/sys/compat/ossaudio/ossaudio.c

cvs diff -r1.40 -r1.41 src/lib/libossaudio/Attic/ossaudio.c (expand / switch to unified diff)

--- src/lib/libossaudio/Attic/ossaudio.c 2020/04/15 15:25:33 1.40
+++ src/lib/libossaudio/Attic/ossaudio.c 2020/04/15 16:39:06 1.41
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: ossaudio.c,v 1.40 2020/04/15 15:25:33 nia Exp $ */ 1/* $NetBSD: ossaudio.c,v 1.41 2020/04/15 16:39:06 nia Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 1997 The NetBSD Foundation, Inc. 4 * Copyright (c) 1997 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.
@@ -17,27 +17,27 @@ @@ -17,27 +17,27 @@
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.40 2020/04/15 15:25:33 nia Exp $"); 30__RCSID("$NetBSD: ossaudio.c,v 1.41 2020/04/15 16:39:06 nia Exp $");
31 31
32/* 32/*
33 * This is an OSS (Linux) sound API emulator. 33 * This is an OSS (Linux) sound API emulator.
34 * It provides the essentials of the API. 34 * It provides the essentials of the API.
35 */ 35 */
36 36
37/* XXX This file is essentially the same as sys/compat/ossaudio.c. 37/* XXX This file is essentially the same as sys/compat/ossaudio.c.
38 * With some preprocessor magic it could be the same file. 38 * With some preprocessor magic it could be the same file.
39 */ 39 */
40 40
41#include <string.h> 41#include <string.h>
42#include <sys/types.h> 42#include <sys/types.h>
43#include <sys/ioctl.h> 43#include <sys/ioctl.h>
@@ -53,26 +53,27 @@ __RCSID("$NetBSD: ossaudio.c,v 1.40 2020 @@ -53,26 +53,27 @@ __RCSID("$NetBSD: ossaudio.c,v 1.40 2020
53#undef ioctl 53#undef ioctl
54 54
55#define GET_DEV(com) ((com) & 0xff) 55#define GET_DEV(com) ((com) & 0xff)
56 56
57#define TO_OSSVOL(x) (((x) * 100 + 127) / 255) 57#define TO_OSSVOL(x) (((x) * 100 + 127) / 255)
58#define FROM_OSSVOL(x) ((((x) > 100 ? 100 : (x)) * 255 + 50) / 100) 58#define FROM_OSSVOL(x) ((((x) > 100 ? 100 : (x)) * 255 + 50) / 100)
59 59
60#define GETPRINFO(info, name) \ 60#define GETPRINFO(info, name) \
61 (((info)->mode == AUMODE_RECORD) \ 61 (((info)->mode == AUMODE_RECORD) \
62 ? (info)->record.name : (info)->play.name) 62 ? (info)->record.name : (info)->play.name)
63 63
64static struct audiodevinfo *getdevinfo(int); 64static struct audiodevinfo *getdevinfo(int);
65 65
 66static void setchannels(int, int, int);
66static void setblocksize(int, struct audio_info *); 67static void setblocksize(int, struct audio_info *);
67 68
68static int audio_ioctl(int, unsigned long, void *); 69static int audio_ioctl(int, unsigned long, void *);
69static int mixer_ioctl(int, unsigned long, void *); 70static int mixer_ioctl(int, unsigned long, void *);
70static int opaque_to_enum(struct audiodevinfo *, audio_mixer_name_t *, int); 71static int opaque_to_enum(struct audiodevinfo *, audio_mixer_name_t *, int);
71static int enum_to_ord(struct audiodevinfo *, int); 72static int enum_to_ord(struct audiodevinfo *, int);
72static int enum_to_mask(struct audiodevinfo *, int); 73static int enum_to_mask(struct audiodevinfo *, int);
73 74
74#define INTARG (*(int*)argp) 75#define INTARG (*(int*)argp)
75 76
76int 77int
77_oss_ioctl(int fd, unsigned long com, ...) 78_oss_ioctl(int fd, unsigned long com, ...)
78{ 79{
@@ -340,32 +341,30 @@ audio_ioctl(int fd, unsigned long com, v @@ -340,32 +341,30 @@ audio_ioctl(int fd, unsigned long com, v
340 else 341 else
341 idat = AFMT_U8; 342 idat = AFMT_U8;
342 break; 343 break;
343 case AUDIO_ENCODING_ADPCM: 344 case AUDIO_ENCODING_ADPCM:
344 idat = AFMT_IMA_ADPCM; 345 idat = AFMT_IMA_ADPCM;
345 break; 346 break;
346 case AUDIO_ENCODING_AC3: 347 case AUDIO_ENCODING_AC3:
347 idat = AFMT_AC3; 348 idat = AFMT_AC3;
348 break; 349 break;
349 } 350 }
350 INTARG = idat; 351 INTARG = idat;
351 break; 352 break;
352 case SNDCTL_DSP_CHANNELS: 353 case SNDCTL_DSP_CHANNELS:
353 AUDIO_INITINFO(&tmpinfo); 354 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
354 tmpinfo.play.channels = INTARG; 355 if (retval < 0)
355 (void) ioctl(fd, AUDIO_SETINFO, &tmpinfo); 356 return retval;
356 AUDIO_INITINFO(&tmpinfo); 357 setchannels(fd, tmpinfo.mode, INTARG);
357 tmpinfo.record.channels = INTARG; 
358 (void) ioctl(fd, AUDIO_SETINFO, &tmpinfo); 
359 /* FALLTHRU */ 358 /* FALLTHRU */
360 case SOUND_PCM_READ_CHANNELS: 359 case SOUND_PCM_READ_CHANNELS:
361 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 360 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
362 if (retval < 0) 361 if (retval < 0)
363 return retval; 362 return retval;
364 INTARG = GETPRINFO(&tmpinfo, channels); 363 INTARG = GETPRINFO(&tmpinfo, channels);
365 break; 364 break;
366 case SOUND_PCM_WRITE_FILTER: 365 case SOUND_PCM_WRITE_FILTER:
367 case SOUND_PCM_READ_FILTER: 366 case SOUND_PCM_READ_FILTER:
368 errno = EINVAL; 367 errno = EINVAL;
369 return -1; /* XXX unimplemented */ 368 return -1; /* XXX unimplemented */
370 case SNDCTL_DSP_SUBDIVIDE: 369 case SNDCTL_DSP_SUBDIVIDE:
371 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo); 370 retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
@@ -1039,26 +1038,74 @@ mixer_ioctl(int fd, unsigned long com, v @@ -1039,26 +1038,74 @@ mixer_ioctl(int fd, unsigned long com, v
1039 com < MIXER_WRITE(SOUND_MIXER_NRDEVICES)) 1038 com < MIXER_WRITE(SOUND_MIXER_NRDEVICES))
1040 return 0; 1039 return 0;
1041 goto doread; 1040 goto doread;
1042 } else { 1041 } else {
1043 errno = EINVAL; 1042 errno = EINVAL;
1044 return -1; 1043 return -1;
1045 } 1044 }
1046 } 1045 }
1047 INTARG = (int)idat; 1046 INTARG = (int)idat;
1048 return 0; 1047 return 0;
1049} 1048}
1050 1049
1051/* 1050/*
 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 */
 1065static void
 1066setchannels(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/*
1052 * Check that the blocksize is a power of 2 as OSS wants. 1099 * Check that the blocksize is a power of 2 as OSS wants.
1053 * If not, set it to be. 1100 * If not, set it to be.
1054 */ 1101 */
1055static void 1102static void
1056setblocksize(int fd, struct audio_info *info) 1103setblocksize(int fd, struct audio_info *info)
1057{ 1104{
1058 struct audio_info set; 1105 struct audio_info set;
1059 size_t s; 1106 size_t s;
1060 1107
1061 if (info->blocksize & (info->blocksize-1)) { 1108 if (info->blocksize & (info->blocksize-1)) {
1062 for(s = 32; s < info->blocksize; s <<= 1) 1109 for(s = 32; s < info->blocksize; s <<= 1)
1063 ; 1110 ;
1064 AUDIO_INITINFO(&set); 1111 AUDIO_INITINFO(&set);

cvs diff -r1.80 -r1.81 src/sys/compat/ossaudio/ossaudio.c (expand / switch to unified diff)

--- src/sys/compat/ossaudio/ossaudio.c 2020/04/15 15:25:33 1.80
+++ src/sys/compat/ossaudio/ossaudio.c 2020/04/15 16:39:06 1.81
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: ossaudio.c,v 1.80 2020/04/15 15:25:33 nia Exp $ */ 1/* $NetBSD: ossaudio.c,v 1.81 2020/04/15 16:39:06 nia Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 1997, 2008 The NetBSD Foundation, Inc. 4 * Copyright (c) 1997, 2008 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
@@ -17,27 +17,27 @@ @@ -17,27 +17,27 @@
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE. 26 * POSSIBILITY OF SUCH DAMAGE.
27 */ 27 */
28 28
29#include <sys/cdefs.h> 29#include <sys/cdefs.h>
30__KERNEL_RCSID(0, "$NetBSD: ossaudio.c,v 1.80 2020/04/15 15:25:33 nia Exp $"); 30__KERNEL_RCSID(0, "$NetBSD: ossaudio.c,v 1.81 2020/04/15 16:39:06 nia Exp $");
31 31
32#include <sys/param.h> 32#include <sys/param.h>
33#include <sys/proc.h> 33#include <sys/proc.h>
34#include <sys/systm.h> 34#include <sys/systm.h>
35#include <sys/file.h> 35#include <sys/file.h>
36#include <sys/vnode.h> 36#include <sys/vnode.h>
37#include <sys/filedesc.h> 37#include <sys/filedesc.h>
38#include <sys/ioctl.h> 38#include <sys/ioctl.h>
39#include <sys/mount.h> 39#include <sys/mount.h>
40#include <sys/kernel.h> 40#include <sys/kernel.h>
41#include <sys/audioio.h> 41#include <sys/audioio.h>
42#include <sys/midiio.h> 42#include <sys/midiio.h>
43#include <sys/kauth.h> 43#include <sys/kauth.h>
@@ -58,26 +58,27 @@ int ossdebug = 0; @@ -58,26 +58,27 @@ int ossdebug = 0;
58 58
59#define TO_OSSVOL(x) (((x) * 100 + 127) / 255) 59#define TO_OSSVOL(x) (((x) * 100 + 127) / 255)
60#define FROM_OSSVOL(x) ((((x) > 100 ? 100 : (x)) * 255 + 50) / 100) 60#define FROM_OSSVOL(x) ((((x) > 100 ? 100 : (x)) * 255 + 50) / 100)
61 61
62#define GETPRINFO(info, name) \ 62#define GETPRINFO(info, name) \
63 (((info)->mode == AUMODE_RECORD) \ 63 (((info)->mode == AUMODE_RECORD) \
64 ? (info)->record.name : (info)->play.name) 64 ? (info)->record.name : (info)->play.name)
65 65
66static struct audiodevinfo *getdevinfo(file_t *); 66static struct audiodevinfo *getdevinfo(file_t *);
67static int opaque_to_enum(struct audiodevinfo *di, audio_mixer_name_t *label, int opq); 67static int opaque_to_enum(struct audiodevinfo *di, audio_mixer_name_t *label, int opq);
68static int enum_to_ord(struct audiodevinfo *di, int enm); 68static int enum_to_ord(struct audiodevinfo *di, int enm);
69static int enum_to_mask(struct audiodevinfo *di, int enm); 69static int enum_to_mask(struct audiodevinfo *di, int enm);
70 70
 71static void setchannels(file_t *, int, int);
71static void setblocksize(file_t *, struct audio_info *); 72static void setblocksize(file_t *, struct audio_info *);
72 73
73#ifdef AUDIO_DEBUG 74#ifdef AUDIO_DEBUG
74static const char * 75static const char *
75compat_ossaudio_getcmd(u_long cmd) 76compat_ossaudio_getcmd(u_long cmd)
76{ 77{
77 static char buf[64]; 78 static char buf[64];
78 switch (cmd) { 79 switch (cmd) {
79#define _DO(_a) \ 80#define _DO(_a) \
80 case _a: \ 81 case _a: \
81 return # _a; 82 return # _a;
82_DO(OSS_SNDCTL_DSP_RESET) 83_DO(OSS_SNDCTL_DSP_RESET)
83_DO(OSS_SNDCTL_DSP_SYNC) 84_DO(OSS_SNDCTL_DSP_SYNC)
@@ -477,35 +478,33 @@ oss_ioctl_audio(struct lwp *l, const str @@ -477,35 +478,33 @@ oss_ioctl_audio(struct lwp *l, const str
477 DPRINTF(("%s: SOUND_PCM_READ_BITS %d = %d\n", 478 DPRINTF(("%s: SOUND_PCM_READ_BITS %d = %d\n",
478 __func__, idat, error)); 479 __func__, idat, error));
479 goto out; 480 goto out;
480 } 481 }
481 break; 482 break;
482 case OSS_SNDCTL_DSP_CHANNELS: 483 case OSS_SNDCTL_DSP_CHANNELS:
483 AUDIO_INITINFO(&tmpinfo); 484 AUDIO_INITINFO(&tmpinfo);
484 error = copyin(SCARG(uap, data), &idat, sizeof idat); 485 error = copyin(SCARG(uap, data), &idat, sizeof idat);
485 if (error) { 486 if (error) {
486 DPRINTF(("%s: SNDCTL_DSP_CHANNELS %d\n", 487 DPRINTF(("%s: SNDCTL_DSP_CHANNELS %d\n",
487 __func__, error)); 488 __func__, error));
488 goto out; 489 goto out;
489 } 490 }
490 tmpinfo.play.channels = 491 error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo);
491 tmpinfo.record.channels = idat; 
492 DPRINTF(("%s: SNDCTL_DSP_CHANNELS > %d\n", __func__, idat)); 
493 error = ioctlf(fp, AUDIO_SETINFO, &tmpinfo); 
494 if (error) { 492 if (error) {
495 DPRINTF(("%s: AUDIO_SETINFO %d\n", 493 DPRINTF(("%s: AUDIO_GETBUFINFO %d\n",
496 __func__, error)); 494 __func__, error));
497 goto out; 495 goto out;
498 } 496 }
 497 setchannels(fp, tmpinfo.mode, idat);
499 /* FALLTHROUGH */ 498 /* FALLTHROUGH */
500 case OSS_SOUND_PCM_READ_CHANNELS: 499 case OSS_SOUND_PCM_READ_CHANNELS:
501 error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo); 500 error = ioctlf(fp, AUDIO_GETBUFINFO, &tmpinfo);
502 if (error) { 501 if (error) {
503 DPRINTF(("%s: AUDIO_GETBUFINFO %d\n", 502 DPRINTF(("%s: AUDIO_GETBUFINFO %d\n",
504 __func__, error)); 503 __func__, error));
505 goto out; 504 goto out;
506 } 505 }
507 idat = GETPRINFO(&tmpinfo, channels); 506 idat = GETPRINFO(&tmpinfo, channels);
508 DPRINTF(("%s: SOUND_PCM_READ_CHANNELS < %d\n", __func__, idat)); 507 DPRINTF(("%s: SOUND_PCM_READ_CHANNELS < %d\n", __func__, idat));
509 error = copyout(&idat, SCARG(uap, data), sizeof idat); 508 error = copyout(&idat, SCARG(uap, data), sizeof idat);
510 if (error) { 509 if (error) {
511 DPRINTF(("%s: SOUND_PCM_READ_CHANNELS %d = %d\n", 510 DPRINTF(("%s: SOUND_PCM_READ_CHANNELS %d = %d\n",
@@ -1522,26 +1521,74 @@ oss_ioctl_sequencer(struct lwp *l, const @@ -1522,26 +1521,74 @@ oss_ioctl_sequencer(struct lwp *l, const
1522 DPRINTF(("%s: Unknown sequencer command 0x%lx\n", __func__, 1521 DPRINTF(("%s: Unknown sequencer command 0x%lx\n", __func__,
1523 com)); 1522 com));
1524 error = EINVAL; 1523 error = EINVAL;
1525 goto out; 1524 goto out;
1526 } 1525 }
1527 1526
1528 error = copyout(&idat, SCARG(uap, data), sizeof idat); 1527 error = copyout(&idat, SCARG(uap, data), sizeof idat);
1529 out: 1528 out:
1530 fd_putfile(SCARG(uap, fd)); 1529 fd_putfile(SCARG(uap, fd));
1531 return error; 1530 return error;
1532} 1531}
1533 1532
1534/* 1533/*
 1534 * When AUDIO_SETINFO fails to set a channel count, the application's chosen
 1535 * number is out of range of what the kernel allows.
 1536 *
 1537 * When this happens, we use the current hardware settings. This is just in
 1538 * case an application is abusing SNDCTL_DSP_CHANNELS - OSSv4 always sets and
 1539 * returns a reasonable value, even if it wasn't what the user requested.
 1540 *
 1541 * XXX: If a device is opened for both playback and recording, and supports
 1542 * fewer channels for recording than playback, applications that do both will
 1543 * behave very strangely. OSS doesn't allow for reporting separate channel
 1544 * counts for recording and playback. This could be worked around by always
 1545 * mixing recorded data up to the same number of channels as is being used
 1546 * for playback.
 1547 */
 1548static void
 1549setchannels(file_t *fp, int mode, int nchannels)
 1550{
 1551 struct audio_info tmpinfo, hwfmt;
 1552 int (*ioctlf)(file_t *, u_long, void *);
 1553
 1554 ioctlf = fp->f_ops->fo_ioctl;
 1555
 1556 if (ioctlf(fp, AUDIO_GETFORMAT, &hwfmt) < 0) {
 1557 hwfmt.record.channels = hwfmt.play.channels = 2;
 1558 }
 1559
 1560 if (mode & AUMODE_PLAY) {
 1561 AUDIO_INITINFO(&tmpinfo);
 1562 tmpinfo.play.channels = nchannels;
 1563 if (ioctlf(fp, AUDIO_SETINFO, &tmpinfo) < 0) {
 1564 AUDIO_INITINFO(&tmpinfo);
 1565 tmpinfo.play.channels = hwfmt.play.channels;
 1566 (void)ioctlf(fp, AUDIO_SETINFO, &tmpinfo);
 1567 }
 1568 }
 1569
 1570 if (mode & AUMODE_RECORD) {
 1571 AUDIO_INITINFO(&tmpinfo);
 1572 tmpinfo.record.channels = nchannels;
 1573 if (ioctlf(fp, AUDIO_SETINFO, &tmpinfo) < 0) {
 1574 AUDIO_INITINFO(&tmpinfo);
 1575 tmpinfo.record.channels = hwfmt.record.channels;
 1576 (void)ioctlf(fp, AUDIO_SETINFO, &tmpinfo);
 1577 }
 1578 }
 1579}
 1580
 1581/*
1535 * Check that the blocksize is a power of 2 as OSS wants. 1582 * Check that the blocksize is a power of 2 as OSS wants.
1536 * If not, set it to be. 1583 * If not, set it to be.
1537 */ 1584 */
1538static void 1585static void
1539setblocksize(file_t *fp, struct audio_info *info) 1586setblocksize(file_t *fp, struct audio_info *info)
1540{ 1587{
1541 struct audio_info set; 1588 struct audio_info set;
1542 u_int s; 1589 u_int s;
1543 1590
1544 if (info->blocksize & (info->blocksize - 1)) { 1591 if (info->blocksize & (info->blocksize - 1)) {
1545 for(s = 32; s < info->blocksize; s <<= 1) 1592 for(s = 32; s < info->blocksize; s <<= 1)
1546 continue; 1593 continue;
1547 AUDIO_INITINFO(&set); 1594 AUDIO_INITINFO(&set);