1 /* $NetBSD: ossaudio.c,v 1.26 1998/08/07 00:00:57 augustss Exp $ */ 2 3 /* 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 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the NetBSD 18 * Foundation, Inc. and its contributors. 19 * 4. Neither the name of The NetBSD Foundation nor the names of its 20 * contributors may be used to endorse or promote products derived 21 * from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 25 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 27 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36 #include <sys/param.h> 37 #include <sys/proc.h> 38 #include <sys/systm.h> 39 #include <sys/file.h> 40 #include <sys/vnode.h> 41 #include <sys/filedesc.h> 42 #include <sys/ioctl.h> 43 #include <sys/mount.h> 44 #include <sys/kernel.h> 45 #include <sys/audioio.h> 46 #include <sys/midiio.h> 47 48 #include <sys/syscallargs.h> 49 50 #include <compat/ossaudio/ossaudio.h> 51 #include <compat/ossaudio/ossaudiovar.h> 52 53 #ifdef AUDIO_DEBUG 54 #define DPRINTF(x) if (ossdebug) printf x 55 int ossdebug = 0; 56 #else 57 #define DPRINTF(x) 58 #endif 59 60 #define TO_OSSVOL(x) ((x) * 100 / 255) 61 #define FROM_OSSVOL(x) ((x) * 255 / 100) 62 63 static struct audiodevinfo *getdevinfo __P((struct file *, struct proc *)); 64 65 static void setblocksize __P((struct file *, struct audio_info *, struct proc *)); 66 67 68 int 69 oss_ioctl_audio(p, uap, retval) 70 struct proc *p; 71 struct oss_sys_ioctl_args /* { 72 syscallarg(int) fd; 73 syscallarg(u_long) com; 74 syscallarg(caddr_t) data; 75 } */ *uap; 76 register_t *retval; 77 { 78 struct file *fp; 79 struct filedesc *fdp; 80 u_long com; 81 struct audio_info tmpinfo; 82 struct audio_offset tmpoffs; 83 struct oss_audio_buf_info bufinfo; 84 struct oss_count_info cntinfo; 85 struct audio_encoding tmpenc; 86 u_int u; 87 int idat, idata; 88 int error; 89 int (*ioctlf) __P((struct file *, u_long, caddr_t, struct proc *)); 90 91 fdp = p->p_fd; 92 if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles || 93 (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL) 94 return (EBADF); 95 96 if ((fp->f_flag & (FREAD | FWRITE)) == 0) 97 return (EBADF); 98 99 com = SCARG(uap, com); 100 DPRINTF(("oss_ioctl_audio: com=%08lx\n", com)); 101 102 retval[0] = 0; 103 104 ioctlf = fp->f_ops->fo_ioctl; 105 switch (com) { 106 case OSS_SNDCTL_DSP_RESET: 107 error = ioctlf(fp, AUDIO_FLUSH, (caddr_t)0, p); 108 if (error) 109 return error; 110 break; 111 case OSS_SNDCTL_DSP_SYNC: 112 case OSS_SNDCTL_DSP_POST: 113 error = ioctlf(fp, AUDIO_DRAIN, (caddr_t)0, p); 114 if (error) 115 return error; 116 break; 117 case OSS_SNDCTL_DSP_SPEED: 118 AUDIO_INITINFO(&tmpinfo); 119 error = copyin(SCARG(uap, data), &idat, sizeof idat); 120 if (error) 121 return error; 122 tmpinfo.play.sample_rate = 123 tmpinfo.record.sample_rate = idat; 124 error = ioctlf(fp, AUDIO_SETINFO, (caddr_t)&tmpinfo, p); 125 DPRINTF(("oss_sys_ioctl: SNDCTL_DSP_SPEED %d = %d\n", 126 idat, error)); 127 if (error) 128 return error; 129 /* fall into ... */ 130 case OSS_SOUND_PCM_READ_RATE: 131 error = ioctlf(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p); 132 if (error) 133 return error; 134 idat = tmpinfo.play.sample_rate; 135 error = copyout(&idat, SCARG(uap, data), sizeof idat); 136 if (error) 137 return error; 138 break; 139 case OSS_SNDCTL_DSP_STEREO: 140 AUDIO_INITINFO(&tmpinfo); 141 error = copyin(SCARG(uap, data), &idat, sizeof idat); 142 if (error) 143 return error; 144 tmpinfo.play.channels = 145 tmpinfo.record.channels = idat ? 2 : 1; 146 (void) ioctlf(fp, AUDIO_SETINFO, (caddr_t)&tmpinfo, p); 147 error = ioctlf(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p); 148 if (error) 149 return error; 150 idat = tmpinfo.play.channels - 1; 151 error = copyout(&idat, SCARG(uap, data), sizeof idat); 152 if (error) 153 return error; 154 break; 155 case OSS_SNDCTL_DSP_GETBLKSIZE: 156 error = ioctlf(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p); 157 if (error) 158 return error; 159 setblocksize(fp, &tmpinfo, p); 160 idat = tmpinfo.blocksize; 161 error = copyout(&idat, SCARG(uap, data), sizeof idat); 162 if (error) 163 return error; 164 break; 165 case OSS_SNDCTL_DSP_SETFMT: 166 AUDIO_INITINFO(&tmpinfo); 167 error = copyin(SCARG(uap, data), &idat, sizeof idat); 168 if (error) 169 return error; 170 switch (idat) { 171 case OSS_AFMT_MU_LAW: 172 tmpinfo.play.precision = 173 tmpinfo.record.precision = 8; 174 tmpinfo.play.encoding = 175 tmpinfo.record.encoding = AUDIO_ENCODING_ULAW; 176 break; 177 case OSS_AFMT_A_LAW: 178 tmpinfo.play.precision = 179 tmpinfo.record.precision = 8; 180 tmpinfo.play.encoding = 181 tmpinfo.record.encoding = AUDIO_ENCODING_ALAW; 182 break; 183 case OSS_AFMT_U8: 184 tmpinfo.play.precision = 185 tmpinfo.record.precision = 8; 186 tmpinfo.play.encoding = 187 tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR; 188 break; 189 case OSS_AFMT_S8: 190 tmpinfo.play.precision = 191 tmpinfo.record.precision = 8; 192 tmpinfo.play.encoding = 193 tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR; 194 break; 195 case OSS_AFMT_S16_LE: 196 tmpinfo.play.precision = 197 tmpinfo.record.precision = 16; 198 tmpinfo.play.encoding = 199 tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_LE; 200 break; 201 case OSS_AFMT_S16_BE: 202 tmpinfo.play.precision = 203 tmpinfo.record.precision = 16; 204 tmpinfo.play.encoding = 205 tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_BE; 206 break; 207 case OSS_AFMT_U16_LE: 208 tmpinfo.play.precision = 209 tmpinfo.record.precision = 16; 210 tmpinfo.play.encoding = 211 tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR_LE; 212 break; 213 case OSS_AFMT_U16_BE: 214 tmpinfo.play.precision = 215 tmpinfo.record.precision = 16; 216 tmpinfo.play.encoding = 217 tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR_BE; 218 break; 219 default: 220 return EINVAL; 221 } 222 (void) ioctlf(fp, AUDIO_SETINFO, (caddr_t)&tmpinfo, p); 223 /* fall into ... */ 224 case OSS_SOUND_PCM_READ_BITS: 225 error = ioctlf(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p); 226 if (error) 227 return error; 228 switch (tmpinfo.play.encoding) { 229 case AUDIO_ENCODING_ULAW: 230 idat = OSS_AFMT_MU_LAW; 231 break; 232 case AUDIO_ENCODING_ALAW: 233 idat = OSS_AFMT_A_LAW; 234 break; 235 case AUDIO_ENCODING_SLINEAR_LE: 236 if (tmpinfo.play.precision == 16) 237 idat = OSS_AFMT_S16_LE; 238 else 239 idat = OSS_AFMT_S8; 240 break; 241 case AUDIO_ENCODING_SLINEAR_BE: 242 if (tmpinfo.play.precision == 16) 243 idat = OSS_AFMT_S16_BE; 244 else 245 idat = OSS_AFMT_S8; 246 break; 247 case AUDIO_ENCODING_ULINEAR_LE: 248 if (tmpinfo.play.precision == 16) 249 idat = OSS_AFMT_U16_LE; 250 else 251 idat = OSS_AFMT_U8; 252 break; 253 case AUDIO_ENCODING_ULINEAR_BE: 254 if (tmpinfo.play.precision == 16) 255 idat = OSS_AFMT_U16_BE; 256 else 257 idat = OSS_AFMT_U8; 258 break; 259 case AUDIO_ENCODING_ADPCM: 260 idat = OSS_AFMT_IMA_ADPCM; 261 break; 262 } 263 error = copyout(&idat, SCARG(uap, data), sizeof idat); 264 if (error) 265 return error; 266 break; 267 case OSS_SNDCTL_DSP_CHANNELS: 268 AUDIO_INITINFO(&tmpinfo); 269 error = copyin(SCARG(uap, data), &idat, sizeof idat); 270 if (error) 271 return error; 272 tmpinfo.play.channels = 273 tmpinfo.record.channels = idat; 274 (void) ioctlf(fp, AUDIO_SETINFO, (caddr_t)&tmpinfo, p); 275 /* fall into ... */ 276 case OSS_SOUND_PCM_READ_CHANNELS: 277 error = ioctlf(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p); 278 if (error) 279 return error; 280 idat = tmpinfo.play.channels; 281 error = copyout(&idat, SCARG(uap, data), sizeof idat); 282 if (error) 283 return error; 284 break; 285 case OSS_SOUND_PCM_WRITE_FILTER: 286 case OSS_SOUND_PCM_READ_FILTER: 287 return EINVAL; /* XXX unimplemented */ 288 case OSS_SNDCTL_DSP_SUBDIVIDE: 289 error = copyin(SCARG(uap, data), &idat, sizeof idat); 290 if (error) 291 return error; 292 error = ioctlf(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p); 293 setblocksize(fp, &tmpinfo, p); 294 if (error) 295 return error; 296 if (idat == 0) 297 idat = tmpinfo.play.buffer_size / tmpinfo.blocksize; 298 idat = (tmpinfo.play.buffer_size / idat) & -4; 299 AUDIO_INITINFO(&tmpinfo); 300 tmpinfo.blocksize = idat; 301 error = ioctlf(fp, AUDIO_SETINFO, (caddr_t)&tmpinfo, p); 302 if (error) 303 return error; 304 idat = tmpinfo.play.buffer_size / tmpinfo.blocksize; 305 error = copyout(&idat, SCARG(uap, data), sizeof idat); 306 if (error) 307 return error; 308 break; 309 case OSS_SNDCTL_DSP_SETFRAGMENT: 310 AUDIO_INITINFO(&tmpinfo); 311 error = copyin(SCARG(uap, data), &idat, sizeof idat); 312 if (error) 313 return error; 314 if ((idat & 0xffff) < 4 || (idat & 0xffff) > 17) 315 return EINVAL; 316 tmpinfo.blocksize = 1 << (idat & 0xffff); 317 tmpinfo.hiwat = (idat >> 16) & 0x7fff; 318 DPRINTF(("oss_audio: SETFRAGMENT blksize=%d, hiwat=%d\n", 319 tmpinfo.blocksize, tmpinfo.hiwat)); 320 if (tmpinfo.hiwat == 0) /* 0 means set to max */ 321 tmpinfo.hiwat = 65536; 322 (void) ioctlf(fp, AUDIO_SETINFO, (caddr_t)&tmpinfo, p); 323 error = ioctlf(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p); 324 if (error) 325 return error; 326 u = tmpinfo.blocksize; 327 for(idat = 0; u > 1; idat++, u >>= 1) 328 ; 329 idat |= (tmpinfo.hiwat & 0x7fff) << 16; 330 error = copyout(&idat, SCARG(uap, data), sizeof idat); 331 if (error) 332 return error; 333 break; 334 case OSS_SNDCTL_DSP_GETFMTS: 335 for(idat = 0, tmpenc.index = 0; 336 ioctlf(fp, AUDIO_GETENC, (caddr_t)&tmpenc, p) == 0; 337 tmpenc.index++) { 338 if (tmpenc.flags & AUDIO_ENCODINGFLAG_EMULATED) 339 continue; /* Don't report emulated modes */ 340 switch(tmpenc.encoding) { 341 case AUDIO_ENCODING_ULAW: 342 idat |= OSS_AFMT_MU_LAW; 343 break; 344 case AUDIO_ENCODING_ALAW: 345 idat |= OSS_AFMT_A_LAW; 346 break; 347 case AUDIO_ENCODING_SLINEAR: 348 idat |= OSS_AFMT_S8; 349 break; 350 case AUDIO_ENCODING_SLINEAR_LE: 351 if (tmpenc.precision == 16) 352 idat |= OSS_AFMT_S16_LE; 353 else 354 idat |= OSS_AFMT_S8; 355 break; 356 case AUDIO_ENCODING_SLINEAR_BE: 357 if (tmpenc.precision == 16) 358 idat |= OSS_AFMT_S16_BE; 359 else 360 idat |= OSS_AFMT_S8; 361 break; 362 case AUDIO_ENCODING_ULINEAR: 363 idat |= OSS_AFMT_U8; 364 break; 365 case AUDIO_ENCODING_ULINEAR_LE: 366 if (tmpenc.precision == 16) 367 idat |= OSS_AFMT_U16_LE; 368 else 369 idat |= OSS_AFMT_U8; 370 break; 371 case AUDIO_ENCODING_ULINEAR_BE: 372 if (tmpenc.precision == 16) 373 idat |= OSS_AFMT_U16_BE; 374 else 375 idat |= OSS_AFMT_U8; 376 break; 377 case AUDIO_ENCODING_ADPCM: 378 idat |= OSS_AFMT_IMA_ADPCM; 379 break; 380 default: 381 break; 382 } 383 } 384 DPRINTF(("oss_sys_ioctl: SNDCTL_DSP_GETFMTS = %x\n", idat)); 385 error = copyout(&idat, SCARG(uap, data), sizeof idat); 386 if (error) 387 return error; 388 break; 389 case OSS_SNDCTL_DSP_GETOSPACE: 390 case OSS_SNDCTL_DSP_GETISPACE: 391 error = ioctlf(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p); 392 if (error) 393 return error; 394 setblocksize(fp, &tmpinfo, p); 395 bufinfo.fragsize = tmpinfo.blocksize; 396 bufinfo.fragments = /* XXX */ 397 bufinfo.fragstotal = tmpinfo.play.buffer_size / bufinfo.fragsize; 398 bufinfo.bytes = tmpinfo.play.buffer_size; 399 DPRINTF(("oss_sys_ioctl: SNDCTL_DSP_GETxSPACE = %d %d %d %d\n", 400 bufinfo.fragsize, bufinfo.fragments, 401 bufinfo.fragstotal, bufinfo.bytes)); 402 error = copyout(&bufinfo, SCARG(uap, data), sizeof bufinfo); 403 if (error) 404 return error; 405 break; 406 case OSS_SNDCTL_DSP_NONBLOCK: 407 idat = 1; 408 error = ioctlf(fp, FIONBIO, (caddr_t)&idat, p); 409 if (error) 410 return error; 411 break; 412 case OSS_SNDCTL_DSP_GETCAPS: 413 error = ioctlf(fp, AUDIO_GETPROPS, (caddr_t)&idata, p); 414 if (error) 415 return error; 416 idat = OSS_DSP_CAP_TRIGGER; /* pretend we have trigger */ 417 if (idata & AUDIO_PROP_FULLDUPLEX) 418 idat |= OSS_DSP_CAP_DUPLEX; 419 if (idata & AUDIO_PROP_MMAP) 420 idat |= OSS_DSP_CAP_MMAP; 421 DPRINTF(("oss_sys_ioctl: SNDCTL_DSP_GETCAPS = %x\n", idat)); 422 error = copyout(&idat, SCARG(uap, data), sizeof idat); 423 if (error) 424 return error; 425 break; 426 #if 0 427 case OSS_SNDCTL_DSP_GETTRIGGER: 428 error = ioctlf(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p); 429 if (error) 430 return error; 431 idat = (tmpinfo.play.pause ? 0 : OSS_PCM_ENABLE_OUTPUT) | 432 (tmpinfo.record.pause ? 0 : OSS_PCM_ENABLE_INPUT); 433 error = copyout(&idat, SCARG(uap, data), sizeof idat); 434 if (error) 435 return error; 436 break; 437 case OSS_SNDCTL_DSP_SETTRIGGER: 438 AUDIO_INITINFO(&tmpinfo); 439 error = copyin(SCARG(uap, data), &idat, sizeof idat); 440 if (error) 441 return error; 442 tmpinfo.play.pause = (idat & OSS_PCM_ENABLE_OUTPUT) == 0; 443 tmpinfo.record.pause = (idat & OSS_PCM_ENABLE_INPUT) == 0; 444 (void) ioctlf(fp, AUDIO_SETINFO, (caddr_t)&tmpinfo, p); 445 error = copyout(&idat, SCARG(uap, data), sizeof idat); 446 if (error) 447 return error; 448 break; 449 #else 450 case OSS_SNDCTL_DSP_GETTRIGGER: 451 case OSS_SNDCTL_DSP_SETTRIGGER: 452 /* XXX Do nothing for now. */ 453 idat = OSS_PCM_ENABLE_OUTPUT; 454 return copyout(&idat, SCARG(uap, data), sizeof idat); 455 #endif 456 case OSS_SNDCTL_DSP_GETIPTR: 457 error = ioctlf(fp, AUDIO_GETIOFFS, (caddr_t)&tmpoffs, p); 458 if (error) 459 return error; 460 cntinfo.bytes = tmpoffs.samples; 461 cntinfo.blocks = tmpoffs.deltablks; 462 cntinfo.ptr = tmpoffs.offset; 463 error = copyout(&cntinfo, SCARG(uap, data), sizeof cntinfo); 464 if (error) 465 return error; 466 break; 467 case OSS_SNDCTL_DSP_GETOPTR: 468 error = ioctlf(fp, AUDIO_GETOOFFS, (caddr_t)&tmpoffs, p); 469 if (error) 470 return error; 471 cntinfo.bytes = tmpoffs.samples; 472 cntinfo.blocks = tmpoffs.deltablks; 473 cntinfo.ptr = tmpoffs.offset; 474 error = copyout(&cntinfo, SCARG(uap, data), sizeof cntinfo); 475 if (error) 476 return error; 477 break; 478 case OSS_SNDCTL_DSP_MAPINBUF: 479 case OSS_SNDCTL_DSP_MAPOUTBUF: 480 case OSS_SNDCTL_DSP_SETSYNCRO: 481 case OSS_SNDCTL_DSP_SETDUPLEX: 482 case OSS_SNDCTL_DSP_PROFILE: 483 return EINVAL; /* XXX unimplemented */ 484 default: 485 return EINVAL; 486 } 487 488 return 0; 489 } 490 491 /* If the NetBSD mixer device should have more than 32 devices 492 * some will not be available to Linux */ 493 #define NETBSD_MAXDEVS 64 494 struct audiodevinfo { 495 int done; 496 dev_t dev; 497 int16_t devmap[OSS_SOUND_MIXER_NRDEVICES], 498 rdevmap[NETBSD_MAXDEVS]; 499 u_long devmask, recmask, stereomask; 500 u_long caps, source; 501 }; 502 503 /* 504 * Collect the audio device information to allow faster 505 * emulation of the Linux mixer ioctls. Cache the information 506 * to eliminate the overhead of repeating all the ioctls needed 507 * to collect the information. 508 */ 509 static struct audiodevinfo * 510 getdevinfo(fp, p) 511 struct file *fp; 512 struct proc *p; 513 { 514 mixer_devinfo_t mi; 515 int i; 516 static struct { 517 char *name; 518 int code; 519 } *dp, devs[] = { 520 { AudioNmicrophone, OSS_SOUND_MIXER_MIC }, 521 { AudioNline, OSS_SOUND_MIXER_LINE }, 522 { AudioNcd, OSS_SOUND_MIXER_CD }, 523 { AudioNdac, OSS_SOUND_MIXER_PCM }, 524 { AudioNrecord, OSS_SOUND_MIXER_IMIX }, 525 { AudioNmaster, OSS_SOUND_MIXER_VOLUME }, 526 { AudioNtreble, OSS_SOUND_MIXER_TREBLE }, 527 { AudioNbass, OSS_SOUND_MIXER_BASS }, 528 { AudioNspeaker, OSS_SOUND_MIXER_SPEAKER }, 529 /* { AudioNheadphone, ?? },*/ 530 { AudioNoutput, OSS_SOUND_MIXER_OGAIN }, 531 { AudioNinput, OSS_SOUND_MIXER_IGAIN }, 532 /* { AudioNmaster, OSS_SOUND_MIXER_SPEAKER },*/ 533 /* { AudioNstereo, ?? },*/ 534 /* { AudioNmono, ?? },*/ 535 { AudioNfmsynth, OSS_SOUND_MIXER_SYNTH }, 536 /* { AudioNwave, OSS_SOUND_MIXER_PCM },*/ 537 { AudioNmidi, OSS_SOUND_MIXER_SYNTH }, 538 /* { AudioNmixerout, ?? },*/ 539 { 0, -1 } 540 }; 541 int (*ioctlf) __P((struct file *, u_long, caddr_t, struct proc *)) = 542 fp->f_ops->fo_ioctl; 543 struct vnode *vp; 544 struct vattr va; 545 static struct audiodevinfo devcache = { 0 }; 546 struct audiodevinfo *di = &devcache; 547 548 /* Figure out what device it is so we can check if the 549 * cached data is valid. 550 */ 551 vp = (struct vnode *)fp->f_data; 552 if (vp->v_type != VCHR) 553 return 0; 554 if (VOP_GETATTR(vp, &va, p->p_ucred, p)) 555 return 0; 556 if (di->done && di->dev == va.va_rdev) 557 return di; 558 559 di->done = 1; 560 di->dev = va.va_rdev; 561 di->devmask = 0; 562 di->recmask = 0; 563 di->stereomask = 0; 564 di->source = -1; 565 di->caps = 0; 566 for(i = 0; i < OSS_SOUND_MIXER_NRDEVICES; i++) 567 di->devmap[i] = -1; 568 for(i = 0; i < NETBSD_MAXDEVS; i++) 569 di->rdevmap[i] = -1; 570 for(i = 0; i < NETBSD_MAXDEVS; i++) { 571 mi.index = i; 572 if (ioctlf(fp, AUDIO_MIXER_DEVINFO, (caddr_t)&mi, p) < 0) 573 break; 574 switch(mi.type) { 575 case AUDIO_MIXER_VALUE: 576 for(dp = devs; dp->name; dp++) 577 if (strcmp(dp->name, mi.label.name) == 0) 578 break; 579 if (dp->code >= 0) { 580 di->devmap[dp->code] = i; 581 di->rdevmap[i] = dp->code; 582 di->devmask |= 1 << dp->code; 583 if (mi.un.v.num_channels == 2) 584 di->stereomask |= 1 << dp->code; 585 } 586 break; 587 case AUDIO_MIXER_ENUM: 588 if (strcmp(mi.label.name, AudioNsource) == 0) { 589 int j; 590 di->source = i; 591 for(j = 0; j < mi.un.e.num_mem; j++) 592 di->recmask |= 1 << di->rdevmap[mi.un.e.member[j].ord]; 593 di->caps = OSS_SOUND_CAP_EXCL_INPUT; 594 } 595 break; 596 case AUDIO_MIXER_SET: 597 if (strcmp(mi.label.name, AudioNsource) == 0) { 598 int j; 599 di->source = i; 600 for(j = 0; j < mi.un.s.num_mem; j++) { 601 int k, mask = mi.un.s.member[j].mask; 602 if (mask) { 603 for(k = 0; !(mask & 1); mask >>= 1, k++) 604 ; 605 di->recmask |= 1 << di->rdevmap[k]; 606 } 607 } 608 } 609 break; 610 } 611 } 612 return di; 613 } 614 615 int 616 oss_ioctl_mixer(p, uap, retval) 617 struct proc *p; 618 struct oss_sys_ioctl_args /* { 619 syscallarg(int) fd; 620 syscallarg(u_long) com; 621 syscallarg(caddr_t) data; 622 } */ *uap; 623 register_t *retval; 624 { 625 struct file *fp; 626 struct filedesc *fdp; 627 u_long com; 628 struct audiodevinfo *di; 629 mixer_ctrl_t mc; 630 int idat; 631 int i; 632 int error; 633 int l, r, n; 634 int (*ioctlf) __P((struct file *, u_long, caddr_t, struct proc *)); 635 636 fdp = p->p_fd; 637 if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles || 638 (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL) 639 return (EBADF); 640 641 if ((fp->f_flag & (FREAD | FWRITE)) == 0) 642 return (EBADF); 643 644 com = SCARG(uap, com); 645 DPRINTF(("oss_ioctl_mixer: com=%08lx\n", com)); 646 647 retval[0] = 0; 648 649 di = getdevinfo(fp, p); 650 if (di == 0) 651 return EINVAL; 652 653 ioctlf = fp->f_ops->fo_ioctl; 654 switch (com) { 655 case OSS_SOUND_MIXER_READ_RECSRC: 656 if (di->source == -1) 657 return EINVAL; 658 mc.dev = di->source; 659 if (di->caps & OSS_SOUND_CAP_EXCL_INPUT) { 660 mc.type = AUDIO_MIXER_ENUM; 661 error = ioctlf(fp, AUDIO_MIXER_READ, (caddr_t)&mc, p); 662 if (error) 663 return error; 664 idat = 1 << di->rdevmap[mc.un.ord]; 665 } else { 666 int k; 667 unsigned int mask; 668 mc.type = AUDIO_MIXER_SET; 669 error = ioctlf(fp, AUDIO_MIXER_READ, (caddr_t)&mc, p); 670 if (error) 671 return error; 672 idat = 0; 673 for(mask = mc.un.mask, k = 0; mask; mask >>= 1, k++) 674 if (mask & 1) 675 idat |= 1 << di->rdevmap[k]; 676 } 677 break; 678 case OSS_SOUND_MIXER_READ_DEVMASK: 679 idat = di->devmask; 680 break; 681 case OSS_SOUND_MIXER_READ_RECMASK: 682 idat = di->recmask; 683 break; 684 case OSS_SOUND_MIXER_READ_STEREODEVS: 685 idat = di->stereomask; 686 break; 687 case OSS_SOUND_MIXER_READ_CAPS: 688 idat = di->caps; 689 break; 690 case OSS_SOUND_MIXER_WRITE_RECSRC: 691 case OSS_SOUND_MIXER_WRITE_R_RECSRC: 692 if (di->source == -1) 693 return EINVAL; 694 mc.dev = di->source; 695 error = copyin(SCARG(uap, data), &idat, sizeof idat); 696 if (error) 697 return error; 698 if (di->caps & OSS_SOUND_CAP_EXCL_INPUT) { 699 mc.type = AUDIO_MIXER_ENUM; 700 for(i = 0; i < OSS_SOUND_MIXER_NRDEVICES; i++) 701 if (idat & (1 << i)) 702 break; 703 if (i >= OSS_SOUND_MIXER_NRDEVICES || 704 di->devmap[i] == -1) 705 return EINVAL; 706 mc.un.ord = di->devmap[i]; 707 } else { 708 mc.type = AUDIO_MIXER_SET; 709 mc.un.mask = 0; 710 for(i = 0; i < OSS_SOUND_MIXER_NRDEVICES; i++) { 711 if (idat & (1 << i)) { 712 if (di->devmap[i] == -1) 713 return EINVAL; 714 mc.un.mask |= 1 << di->devmap[i]; 715 } 716 } 717 } 718 return ioctlf(fp, AUDIO_MIXER_WRITE, (caddr_t)&mc, p); 719 default: 720 if (OSS_MIXER_READ(OSS_SOUND_MIXER_FIRST) <= com && 721 com < OSS_MIXER_READ(OSS_SOUND_MIXER_NRDEVICES)) { 722 n = OSS_GET_DEV(com); 723 if (di->devmap[n] == -1) 724 return EINVAL; 725 doread: 726 mc.dev = di->devmap[n]; 727 mc.type = AUDIO_MIXER_VALUE; 728 mc.un.value.num_channels = di->stereomask & (1<<n) ? 2 : 1; 729 error = ioctlf(fp, AUDIO_MIXER_READ, (caddr_t)&mc, p); 730 if (error) 731 return error; 732 if (mc.un.value.num_channels != 2) { 733 l = r = mc.un.value.level[AUDIO_MIXER_LEVEL_MONO]; 734 } else { 735 l = mc.un.value.level[AUDIO_MIXER_LEVEL_LEFT]; 736 r = mc.un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; 737 } 738 idat = TO_OSSVOL(l) | (TO_OSSVOL(r) << 8); 739 DPRINTF(("OSS_MIXER_READ n=%d (dev=%d) l=%d, r=%d, idat=%04x\n", 740 n, di->devmap[n], l, r, idat)); 741 break; 742 } else if ((OSS_MIXER_WRITE_R(OSS_SOUND_MIXER_FIRST) <= com && 743 com < OSS_MIXER_WRITE_R(OSS_SOUND_MIXER_NRDEVICES)) || 744 (OSS_MIXER_WRITE(OSS_SOUND_MIXER_FIRST) <= com && 745 com < OSS_MIXER_WRITE(OSS_SOUND_MIXER_NRDEVICES))) { 746 n = OSS_GET_DEV(com); 747 if (di->devmap[n] == -1) 748 return EINVAL; 749 error = copyin(SCARG(uap, data), &idat, sizeof idat); 750 if (error) 751 return error; 752 l = FROM_OSSVOL( idat & 0xff); 753 r = FROM_OSSVOL((idat >> 8) & 0xff); 754 mc.dev = di->devmap[n]; 755 mc.type = AUDIO_MIXER_VALUE; 756 if (di->stereomask & (1<<n)) { 757 mc.un.value.num_channels = 2; 758 mc.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l; 759 mc.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r; 760 } else { 761 mc.un.value.num_channels = 1; 762 mc.un.value.level[AUDIO_MIXER_LEVEL_MONO] = (l+r)/2; 763 } 764 DPRINTF(("OSS_MIXER_WRITE n=%d (dev=%d) l=%d, r=%d, idat=%04x\n", 765 n, di->devmap[n], l, r, idat)); 766 error = ioctlf(fp, AUDIO_MIXER_WRITE, (caddr_t)&mc, p); 767 if (error) 768 return error; 769 if (OSS_MIXER_WRITE(OSS_SOUND_MIXER_FIRST) <= com && 770 com < OSS_MIXER_WRITE(OSS_SOUND_MIXER_NRDEVICES)) 771 return 0; 772 goto doread; 773 } else { 774 #ifdef AUDIO_DEBUG 775 printf("oss_audio: unknown mixer ioctl %04lx\n", com); 776 #endif 777 return EINVAL; 778 } 779 } 780 return copyout(&idat, SCARG(uap, data), sizeof idat); 781 } 782 783 /* Sequencer emulation */ 784 int 785 oss_ioctl_sequencer(p, uap, retval) 786 struct proc *p; 787 struct oss_sys_ioctl_args /* { 788 syscallarg(int) fd; 789 syscallarg(u_long) com; 790 syscallarg(caddr_t) data; 791 } */ *uap; 792 register_t *retval; 793 { 794 struct file *fp; 795 struct filedesc *fdp; 796 u_long com; 797 int idat, idat1; 798 struct synth_info si; 799 struct oss_synth_info osi; 800 struct oss_seq_event_rec oser; 801 int error; 802 int (*ioctlf) __P((struct file *, u_long, caddr_t, struct proc *)); 803 804 fdp = p->p_fd; 805 if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles || 806 (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL) 807 return (EBADF); 808 809 if ((fp->f_flag & (FREAD | FWRITE)) == 0) 810 return (EBADF); 811 812 com = SCARG(uap, com); 813 DPRINTF(("oss_ioctl_sequencer: com=%08lx\n", com)); 814 815 retval[0] = 0; 816 817 ioctlf = fp->f_ops->fo_ioctl; 818 switch (com) { 819 case OSS_SEQ_RESET: 820 return ioctlf(fp, SEQUENCER_RESET, (caddr_t)&idat, p); 821 case OSS_SEQ_SYNC: 822 return ioctlf(fp, SEQUENCER_SYNC, (caddr_t)&idat, p); 823 case OSS_SYNTH_INFO: 824 error = copyin(SCARG(uap, data), &osi, sizeof osi); 825 if (error) 826 return error; 827 si.device = osi.device; 828 error = ioctlf(fp, SEQUENCER_INFO, (caddr_t)&si, p); 829 if (error) 830 return error; 831 strncpy(osi.name, si.name, sizeof osi.name); 832 osi.device = si.device; 833 switch(si.synth_type) { 834 case SYNTH_TYPE_FM: 835 osi.synth_type = OSS_SYNTH_TYPE_FM; break; 836 case SYNTH_TYPE_SAMPLE: 837 osi.synth_type = OSS_SYNTH_TYPE_SAMPLE; break; 838 case SYNTH_TYPE_MIDI: 839 osi.synth_type = OSS_SYNTH_TYPE_MIDI; break; 840 default: 841 osi.synth_type = 0; break; 842 } 843 switch(si.synth_subtype) { 844 case SYNTH_SUB_FM_TYPE_ADLIB: 845 osi.synth_subtype = OSS_FM_TYPE_ADLIB; break; 846 case SYNTH_SUB_FM_TYPE_OPL3: 847 osi.synth_subtype = OSS_FM_TYPE_OPL3; break; 848 case SYNTH_SUB_MIDI_TYPE_MPU401: 849 osi.synth_subtype = OSS_MIDI_TYPE_MPU401; break; 850 case SYNTH_SUB_SAMPLE_TYPE_BASIC: 851 osi.synth_subtype = OSS_SAMPLE_TYPE_BASIC; break; 852 default: 853 osi.synth_subtype = 0; break; 854 } 855 osi.perc_mode = 0; 856 osi.nr_voices = si.nr_voices; 857 osi.nr_drums = 0; 858 osi.instr_bank_size = si.instr_bank_size; 859 osi.capabilities = 0; 860 if (si.capabilities & SYNTH_CAP_OPL3) 861 osi.capabilities |= OSS_SYNTH_CAP_OPL3; 862 if (si.capabilities & SYNTH_CAP_INPUT) 863 osi.capabilities |= OSS_SYNTH_CAP_INPUT; 864 return copyout(&osi, SCARG(uap, data), sizeof osi); 865 case OSS_SEQ_CTRLRATE: 866 error = copyin(SCARG(uap, data), &idat, sizeof idat); 867 if (error) 868 return error; 869 error = ioctlf(fp, SEQUENCER_CTRLRATE, (caddr_t)&idat, p); 870 if (error) 871 return error; 872 retval[0] = idat; 873 break; 874 case OSS_SEQ_GETOUTCOUNT: 875 error = ioctlf(fp, SEQUENCER_GETOUTCOUNT, (caddr_t)&idat, p); 876 if (error) 877 return error; 878 retval[0] = idat; 879 break; 880 case OSS_SEQ_GETINCOUNT: 881 error = ioctlf(fp, SEQUENCER_GETINCOUNT, (caddr_t)&idat, p); 882 if (error) 883 return error; 884 retval[0] = idat; 885 break; 886 case OSS_SEQ_NRSYNTHS: 887 error = ioctlf(fp, SEQUENCER_NRSYNTHS, (caddr_t)&idat, p); 888 if (error) 889 return error; 890 retval[0] = idat; 891 break; 892 case OSS_SEQ_NRMIDIS: 893 error = ioctlf(fp, SEQUENCER_NRMIDIS, (caddr_t)&idat, p); 894 if (error) 895 return error; 896 retval[0] = idat; 897 break; 898 case OSS_SEQ_THRESHOLD: 899 error = copyin(SCARG(uap, data), &idat, sizeof idat); 900 if (error) 901 return error; 902 return ioctlf(fp, SEQUENCER_THRESHOLD, (caddr_t)&idat, p); 903 case OSS_MEMAVL: 904 error = copyin(SCARG(uap, data), &idat, sizeof idat); 905 if (error) 906 return error; 907 error = ioctlf(fp, SEQUENCER_MEMAVL, (caddr_t)&idat, p); 908 if (error) 909 return error; 910 retval[0] = idat; 911 break; 912 case OSS_SEQ_PANIC: 913 return ioctlf(fp, SEQUENCER_PANIC, (caddr_t)&idat, p); 914 case OSS_SEQ_OUTOFBAND: 915 error = copyin(SCARG(uap, data), &oser, sizeof oser); 916 if (error) 917 return error; 918 error = ioctlf(fp, SEQUENCER_OUTOFBAND, (caddr_t)&oser, p); 919 if (error) 920 return error; 921 break; 922 case OSS_SEQ_GETTIME: 923 error = ioctlf(fp, SEQUENCER_GETTIME, (caddr_t)&idat, p); 924 if (error) 925 return error; 926 retval[0] = idat; 927 break; 928 case OSS_TMR_TIMEBASE: 929 error = copyin(SCARG(uap, data), &idat, sizeof idat); 930 if (error) 931 return error; 932 error = ioctlf(fp, SEQUENCER_TMR_TIMEBASE, (caddr_t)&idat, p); 933 if (error) 934 return error; 935 retval[0] = idat; 936 break; 937 case OSS_TMR_START: 938 return ioctlf(fp, SEQUENCER_TMR_START, (caddr_t)&idat, p); 939 case OSS_TMR_STOP: 940 return ioctlf(fp, SEQUENCER_TMR_STOP, (caddr_t)&idat, p); 941 case OSS_TMR_CONTINUE: 942 return ioctlf(fp, SEQUENCER_TMR_CONTINUE, (caddr_t)&idat, p); 943 case OSS_TMR_TEMPO: 944 error = copyin(SCARG(uap, data), &idat, sizeof idat); 945 if (error) 946 return error; 947 error = ioctlf(fp, SEQUENCER_TMR_TEMPO, (caddr_t)&idat, p); 948 if (error) 949 return error; 950 retval[0] = idat; 951 break; 952 case OSS_TMR_SOURCE: 953 error = copyin(SCARG(uap, data), &idat1, sizeof idat); 954 if (error) 955 return error; 956 idat = 0; 957 if (idat1 & OSS_TMR_INTERNAL) idat |= SEQUENCER_TMR_INTERNAL; 958 error = ioctlf(fp, SEQUENCER_TMR_SOURCE, (caddr_t)&idat, p); 959 if (error) 960 return error; 961 idat1 = idat; 962 if (idat1 & SEQUENCER_TMR_INTERNAL) idat |= OSS_TMR_INTERNAL; 963 retval[0] = idat; 964 break; 965 case OSS_TMR_METRONOME: 966 error = copyin(SCARG(uap, data), &idat, sizeof idat); 967 if (error) 968 return error; 969 return ioctlf(fp, SEQUENCER_TMR_METRONOME, (caddr_t)&idat, p); 970 case OSS_TMR_SELECT: 971 error = copyin(SCARG(uap, data), &idat, sizeof idat); 972 if (error) 973 return error; 974 retval[0] = idat; 975 return ioctlf(fp, SEQUENCER_TMR_SELECT, (caddr_t)&idat, p); 976 default: 977 return EINVAL; 978 } 979 980 return copyout(&idat, SCARG(uap, data), sizeof idat); 981 } 982 983 /* 984 * Check that the blocksize is a power of 2 as OSS wants. 985 * If not, set it to be. 986 */ 987 static void setblocksize(fp, info, p) 988 struct file *fp; 989 struct audio_info *info; 990 struct proc *p; 991 { 992 struct audio_info set; 993 int s; 994 995 if (info->blocksize & (info->blocksize-1)) { 996 for(s = 32; s < info->blocksize; s <<= 1) 997 ; 998 AUDIO_INITINFO(&set); 999 set.blocksize = s; 1000 fp->f_ops->fo_ioctl(fp, AUDIO_SETINFO, (caddr_t)&set, p); 1001 fp->f_ops->fo_ioctl(fp, AUDIO_GETINFO, (caddr_t)info, p); 1002 } 1003 } 1004