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