1 /* $NetBSD: ossaudio.c,v 1.61 2007/12/20 23:03:03 dsl 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/cdefs.h> 37 __KERNEL_RCSID(0, "$NetBSD: ossaudio.c,v 1.61 2007/12/20 23:03:03 dsl Exp $"); 38 39 #include <sys/param.h> 40 #include <sys/proc.h> 41 #include <sys/systm.h> 42 #include <sys/file.h> 43 #include <sys/vnode.h> 44 #include <sys/filedesc.h> 45 #include <sys/ioctl.h> 46 #include <sys/mount.h> 47 #include <sys/kernel.h> 48 #include <sys/audioio.h> 49 #include <sys/midiio.h> 50 51 #include <sys/syscallargs.h> 52 53 #include <compat/ossaudio/ossaudio.h> 54 #include <compat/ossaudio/ossaudiovar.h> 55 56 #ifdef AUDIO_DEBUG 57 #define DPRINTF(x) if (ossdebug) printf x 58 int ossdebug = 0; 59 #else 60 #define DPRINTF(x) 61 #endif 62 63 #define TO_OSSVOL(x) (((x) * 100 + 127) / 255) 64 #define FROM_OSSVOL(x) ((((x) > 100 ? 100 : (x)) * 255 + 50) / 100) 65 66 static struct audiodevinfo *getdevinfo(struct file *, struct lwp *); 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(struct file *, struct audio_info *, struct lwp *); 72 73 74 int 75 oss_ioctl_audio(struct lwp *l, const struct oss_sys_ioctl_args *uap, register_t *retval) 76 { 77 /* { 78 syscallarg(int) fd; 79 syscallarg(u_long) com; 80 syscallarg(void *) data; 81 } */ 82 struct proc *p = l->l_proc; 83 struct file *fp; 84 struct filedesc *fdp; 85 u_long com; 86 struct audio_info tmpinfo; 87 struct audio_offset tmpoffs; 88 struct oss_audio_buf_info bufinfo; 89 struct oss_count_info cntinfo; 90 struct audio_encoding tmpenc; 91 u_int u; 92 int idat, idata; 93 int error = 0; 94 int (*ioctlf)(struct file *, u_long, void *, struct lwp *); 95 96 fdp = p->p_fd; 97 if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL) 98 return (EBADF); 99 100 FILE_USE(fp); 101 102 if ((fp->f_flag & (FREAD | FWRITE)) == 0) { 103 error = EBADF; 104 goto out; 105 } 106 107 com = SCARG(uap, com); 108 DPRINTF(("oss_ioctl_audio: com=%08lx\n", com)); 109 110 retval[0] = 0; 111 112 ioctlf = fp->f_ops->fo_ioctl; 113 switch (com) { 114 case OSS_SNDCTL_DSP_RESET: 115 error = ioctlf(fp, AUDIO_FLUSH, (void *)0, l); 116 if (error) 117 goto out; 118 break; 119 case OSS_SNDCTL_DSP_SYNC: 120 error = ioctlf(fp, AUDIO_DRAIN, (void *)0, l); 121 if (error) 122 goto out; 123 break; 124 case OSS_SNDCTL_DSP_POST: 125 /* This call is merely advisory, and may be a nop. */ 126 break; 127 case OSS_SNDCTL_DSP_SPEED: 128 AUDIO_INITINFO(&tmpinfo); 129 error = copyin(SCARG(uap, data), &idat, sizeof idat); 130 if (error) 131 goto out; 132 tmpinfo.play.sample_rate = 133 tmpinfo.record.sample_rate = idat; 134 error = ioctlf(fp, AUDIO_SETINFO, (void *)&tmpinfo, l); 135 DPRINTF(("oss_sys_ioctl: SNDCTL_DSP_SPEED %d = %d\n", 136 idat, error)); 137 if (error) 138 goto out; 139 /* fall into ... */ 140 case OSS_SOUND_PCM_READ_RATE: 141 error = ioctlf(fp, AUDIO_GETBUFINFO, (void *)&tmpinfo, l); 142 if (error) 143 goto out; 144 idat = tmpinfo.play.sample_rate; 145 error = copyout(&idat, SCARG(uap, data), sizeof idat); 146 if (error) 147 goto out; 148 break; 149 case OSS_SNDCTL_DSP_STEREO: 150 AUDIO_INITINFO(&tmpinfo); 151 error = copyin(SCARG(uap, data), &idat, sizeof idat); 152 if (error) 153 goto out; 154 tmpinfo.play.channels = 155 tmpinfo.record.channels = idat ? 2 : 1; 156 (void) ioctlf(fp, AUDIO_SETINFO, (void *)&tmpinfo, l); 157 error = ioctlf(fp, AUDIO_GETBUFINFO, (void *)&tmpinfo, l); 158 if (error) 159 goto out; 160 idat = tmpinfo.play.channels - 1; 161 error = copyout(&idat, SCARG(uap, data), sizeof idat); 162 if (error) 163 goto out; 164 break; 165 case OSS_SNDCTL_DSP_GETBLKSIZE: 166 error = ioctlf(fp, AUDIO_GETBUFINFO, (void *)&tmpinfo, l); 167 if (error) 168 goto out; 169 setblocksize(fp, &tmpinfo, l); 170 idat = tmpinfo.blocksize; 171 error = copyout(&idat, SCARG(uap, data), sizeof idat); 172 if (error) 173 goto out; 174 break; 175 case OSS_SNDCTL_DSP_SETFMT: 176 AUDIO_INITINFO(&tmpinfo); 177 error = copyin(SCARG(uap, data), &idat, sizeof idat); 178 if (error) 179 goto out; 180 switch (idat) { 181 case OSS_AFMT_MU_LAW: 182 tmpinfo.play.precision = 183 tmpinfo.record.precision = 8; 184 tmpinfo.play.encoding = 185 tmpinfo.record.encoding = AUDIO_ENCODING_ULAW; 186 break; 187 case OSS_AFMT_A_LAW: 188 tmpinfo.play.precision = 189 tmpinfo.record.precision = 8; 190 tmpinfo.play.encoding = 191 tmpinfo.record.encoding = AUDIO_ENCODING_ALAW; 192 break; 193 case OSS_AFMT_U8: 194 tmpinfo.play.precision = 195 tmpinfo.record.precision = 8; 196 tmpinfo.play.encoding = 197 tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR; 198 break; 199 case OSS_AFMT_S8: 200 tmpinfo.play.precision = 201 tmpinfo.record.precision = 8; 202 tmpinfo.play.encoding = 203 tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR; 204 break; 205 case OSS_AFMT_S16_LE: 206 tmpinfo.play.precision = 207 tmpinfo.record.precision = 16; 208 tmpinfo.play.encoding = 209 tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_LE; 210 break; 211 case OSS_AFMT_S16_BE: 212 tmpinfo.play.precision = 213 tmpinfo.record.precision = 16; 214 tmpinfo.play.encoding = 215 tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_BE; 216 break; 217 case OSS_AFMT_U16_LE: 218 tmpinfo.play.precision = 219 tmpinfo.record.precision = 16; 220 tmpinfo.play.encoding = 221 tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR_LE; 222 break; 223 case OSS_AFMT_U16_BE: 224 tmpinfo.play.precision = 225 tmpinfo.record.precision = 16; 226 tmpinfo.play.encoding = 227 tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR_BE; 228 break; 229 default: 230 error = EINVAL; 231 goto out; 232 } 233 (void) ioctlf(fp, AUDIO_SETINFO, (void *)&tmpinfo, l); 234 /* fall into ... */ 235 case OSS_SOUND_PCM_READ_BITS: 236 error = ioctlf(fp, AUDIO_GETBUFINFO, (void *)&tmpinfo, l); 237 if (error) 238 goto out; 239 switch (tmpinfo.play.encoding) { 240 case AUDIO_ENCODING_ULAW: 241 idat = OSS_AFMT_MU_LAW; 242 break; 243 case AUDIO_ENCODING_ALAW: 244 idat = OSS_AFMT_A_LAW; 245 break; 246 case AUDIO_ENCODING_SLINEAR_LE: 247 if (tmpinfo.play.precision == 16) 248 idat = OSS_AFMT_S16_LE; 249 else 250 idat = OSS_AFMT_S8; 251 break; 252 case AUDIO_ENCODING_SLINEAR_BE: 253 if (tmpinfo.play.precision == 16) 254 idat = OSS_AFMT_S16_BE; 255 else 256 idat = OSS_AFMT_S8; 257 break; 258 case AUDIO_ENCODING_ULINEAR_LE: 259 if (tmpinfo.play.precision == 16) 260 idat = OSS_AFMT_U16_LE; 261 else 262 idat = OSS_AFMT_U8; 263 break; 264 case AUDIO_ENCODING_ULINEAR_BE: 265 if (tmpinfo.play.precision == 16) 266 idat = OSS_AFMT_U16_BE; 267 else 268 idat = OSS_AFMT_U8; 269 break; 270 case AUDIO_ENCODING_ADPCM: 271 idat = OSS_AFMT_IMA_ADPCM; 272 break; 273 } 274 error = copyout(&idat, SCARG(uap, data), sizeof idat); 275 if (error) 276 goto out; 277 break; 278 case OSS_SNDCTL_DSP_CHANNELS: 279 AUDIO_INITINFO(&tmpinfo); 280 error = copyin(SCARG(uap, data), &idat, sizeof idat); 281 if (error) 282 goto out; 283 tmpinfo.play.channels = 284 tmpinfo.record.channels = idat; 285 (void) ioctlf(fp, AUDIO_SETINFO, (void *)&tmpinfo, l); 286 /* fall into ... */ 287 case OSS_SOUND_PCM_READ_CHANNELS: 288 error = ioctlf(fp, AUDIO_GETBUFINFO, (void *)&tmpinfo, l); 289 if (error) 290 goto out; 291 idat = tmpinfo.play.channels; 292 error = copyout(&idat, SCARG(uap, data), sizeof idat); 293 if (error) 294 goto out; 295 break; 296 case OSS_SOUND_PCM_WRITE_FILTER: 297 case OSS_SOUND_PCM_READ_FILTER: 298 error = EINVAL; /* XXX unimplemented */ 299 goto out; 300 case OSS_SNDCTL_DSP_SUBDIVIDE: 301 error = copyin(SCARG(uap, data), &idat, sizeof idat); 302 if (error) 303 goto out; 304 error = ioctlf(fp, AUDIO_GETBUFINFO, (void *)&tmpinfo, l); 305 setblocksize(fp, &tmpinfo, l); 306 if (error) 307 goto out; 308 if (idat == 0) 309 idat = tmpinfo.play.buffer_size / tmpinfo.blocksize; 310 idat = (tmpinfo.play.buffer_size / idat) & -4; 311 AUDIO_INITINFO(&tmpinfo); 312 tmpinfo.blocksize = idat; 313 error = ioctlf(fp, AUDIO_SETINFO, (void *)&tmpinfo, l); 314 if (error) 315 goto out; 316 idat = tmpinfo.play.buffer_size / tmpinfo.blocksize; 317 error = copyout(&idat, SCARG(uap, data), sizeof idat); 318 if (error) 319 goto out; 320 break; 321 case OSS_SNDCTL_DSP_SETFRAGMENT: 322 AUDIO_INITINFO(&tmpinfo); 323 error = copyin(SCARG(uap, data), &idat, sizeof idat); 324 if (error) 325 goto out; 326 if ((idat & 0xffff) < 4 || (idat & 0xffff) > 17) { 327 error = EINVAL; 328 goto out; 329 } 330 tmpinfo.blocksize = 1 << (idat & 0xffff); 331 tmpinfo.hiwat = (idat >> 16) & 0x7fff; 332 DPRINTF(("oss_audio: SETFRAGMENT blksize=%d, hiwat=%d\n", 333 tmpinfo.blocksize, tmpinfo.hiwat)); 334 if (tmpinfo.hiwat == 0) /* 0 means set to max */ 335 tmpinfo.hiwat = 65536; 336 (void) ioctlf(fp, AUDIO_SETINFO, (void *)&tmpinfo, l); 337 error = ioctlf(fp, AUDIO_GETBUFINFO, (void *)&tmpinfo, l); 338 if (error) 339 goto out; 340 u = tmpinfo.blocksize; 341 for(idat = 0; u > 1; idat++, u >>= 1) 342 ; 343 idat |= (tmpinfo.hiwat & 0x7fff) << 16; 344 error = copyout(&idat, SCARG(uap, data), sizeof idat); 345 if (error) 346 goto out; 347 break; 348 case OSS_SNDCTL_DSP_GETFMTS: 349 for(idat = 0, tmpenc.index = 0; 350 ioctlf(fp, AUDIO_GETENC, (void *)&tmpenc, l) == 0; 351 tmpenc.index++) { 352 switch(tmpenc.encoding) { 353 case AUDIO_ENCODING_ULAW: 354 idat |= OSS_AFMT_MU_LAW; 355 break; 356 case AUDIO_ENCODING_ALAW: 357 idat |= OSS_AFMT_A_LAW; 358 break; 359 case AUDIO_ENCODING_SLINEAR: 360 idat |= OSS_AFMT_S8; 361 break; 362 case AUDIO_ENCODING_SLINEAR_LE: 363 if (tmpenc.precision == 16) 364 idat |= OSS_AFMT_S16_LE; 365 else 366 idat |= OSS_AFMT_S8; 367 break; 368 case AUDIO_ENCODING_SLINEAR_BE: 369 if (tmpenc.precision == 16) 370 idat |= OSS_AFMT_S16_BE; 371 else 372 idat |= OSS_AFMT_S8; 373 break; 374 case AUDIO_ENCODING_ULINEAR: 375 idat |= OSS_AFMT_U8; 376 break; 377 case AUDIO_ENCODING_ULINEAR_LE: 378 if (tmpenc.precision == 16) 379 idat |= OSS_AFMT_U16_LE; 380 else 381 idat |= OSS_AFMT_U8; 382 break; 383 case AUDIO_ENCODING_ULINEAR_BE: 384 if (tmpenc.precision == 16) 385 idat |= OSS_AFMT_U16_BE; 386 else 387 idat |= OSS_AFMT_U8; 388 break; 389 case AUDIO_ENCODING_ADPCM: 390 idat |= OSS_AFMT_IMA_ADPCM; 391 break; 392 default: 393 break; 394 } 395 } 396 DPRINTF(("oss_sys_ioctl: SNDCTL_DSP_GETFMTS = %x\n", idat)); 397 error = copyout(&idat, SCARG(uap, data), sizeof idat); 398 if (error) 399 goto out; 400 break; 401 case OSS_SNDCTL_DSP_GETOSPACE: 402 error = ioctlf(fp, AUDIO_GETBUFINFO, (void *)&tmpinfo, l); 403 if (error) 404 goto out; 405 setblocksize(fp, &tmpinfo, l); 406 bufinfo.fragsize = tmpinfo.blocksize; 407 bufinfo.fragments = tmpinfo.hiwat - 408 (tmpinfo.play.seek + tmpinfo.blocksize - 1) / 409 tmpinfo.blocksize; 410 bufinfo.fragstotal = tmpinfo.hiwat; 411 bufinfo.bytes = 412 tmpinfo.hiwat * tmpinfo.blocksize - tmpinfo.play.seek; 413 error = copyout(&bufinfo, SCARG(uap, data), sizeof bufinfo); 414 if (error) 415 goto out; 416 break; 417 case OSS_SNDCTL_DSP_GETISPACE: 418 error = ioctlf(fp, AUDIO_GETBUFINFO, (void *)&tmpinfo, l); 419 if (error) 420 goto out; 421 setblocksize(fp, &tmpinfo, l); 422 bufinfo.fragsize = tmpinfo.blocksize; 423 bufinfo.fragments = tmpinfo.hiwat - 424 (tmpinfo.record.seek + tmpinfo.blocksize - 1) / 425 tmpinfo.blocksize; 426 bufinfo.fragstotal = tmpinfo.hiwat; 427 bufinfo.bytes = 428 tmpinfo.hiwat * tmpinfo.blocksize - tmpinfo.record.seek; 429 DPRINTF(("oss_sys_ioctl: SNDCTL_DSP_GETxSPACE = %d %d %d %d\n", 430 bufinfo.fragsize, bufinfo.fragments, 431 bufinfo.fragstotal, bufinfo.bytes)); 432 error = copyout(&bufinfo, SCARG(uap, data), sizeof bufinfo); 433 if (error) 434 goto out; 435 break; 436 case OSS_SNDCTL_DSP_NONBLOCK: 437 idat = 1; 438 error = ioctlf(fp, FIONBIO, (void *)&idat, l); 439 if (error) 440 goto out; 441 break; 442 case OSS_SNDCTL_DSP_GETCAPS: 443 error = ioctlf(fp, AUDIO_GETPROPS, (void *)&idata, l); 444 if (error) 445 goto out; 446 idat = OSS_DSP_CAP_TRIGGER; /* pretend we have trigger */ 447 if (idata & AUDIO_PROP_FULLDUPLEX) 448 idat |= OSS_DSP_CAP_DUPLEX; 449 if (idata & AUDIO_PROP_MMAP) 450 idat |= OSS_DSP_CAP_MMAP; 451 DPRINTF(("oss_sys_ioctl: SNDCTL_DSP_GETCAPS = %x\n", idat)); 452 error = copyout(&idat, SCARG(uap, data), sizeof idat); 453 if (error) 454 goto out; 455 break; 456 #if 0 457 case OSS_SNDCTL_DSP_GETTRIGGER: 458 error = ioctlf(fp, AUDIO_GETBUFINFO, (void *)&tmpinfo, l); 459 if (error) 460 goto out; 461 idat = (tmpinfo.play.pause ? 0 : OSS_PCM_ENABLE_OUTPUT) | 462 (tmpinfo.record.pause ? 0 : OSS_PCM_ENABLE_INPUT); 463 error = copyout(&idat, SCARG(uap, data), sizeof idat); 464 if (error) 465 goto out; 466 break; 467 case OSS_SNDCTL_DSP_SETTRIGGER: 468 (void) ioctlf(fp, AUDIO_GETBUFINFO, (void *)&tmpinfo, p); 469 error = copyin(SCARG(uap, data), &idat, sizeof idat); 470 if (error) 471 goto out; 472 tmpinfo.play.pause = (idat & OSS_PCM_ENABLE_OUTPUT) == 0; 473 tmpinfo.record.pause = (idat & OSS_PCM_ENABLE_INPUT) == 0; 474 (void) ioctlf(fp, AUDIO_SETINFO, (void *)&tmpinfo, l); 475 error = copyout(&idat, SCARG(uap, data), sizeof idat); 476 if (error) 477 goto out; 478 break; 479 #else 480 case OSS_SNDCTL_DSP_GETTRIGGER: 481 case OSS_SNDCTL_DSP_SETTRIGGER: 482 /* XXX Do nothing for now. */ 483 idat = OSS_PCM_ENABLE_OUTPUT; 484 error = copyout(&idat, SCARG(uap, data), sizeof idat); 485 goto out; 486 #endif 487 case OSS_SNDCTL_DSP_GETIPTR: 488 error = ioctlf(fp, AUDIO_GETIOFFS, (void *)&tmpoffs, l); 489 if (error) 490 goto out; 491 cntinfo.bytes = tmpoffs.samples; 492 cntinfo.blocks = tmpoffs.deltablks; 493 cntinfo.ptr = tmpoffs.offset; 494 error = copyout(&cntinfo, SCARG(uap, data), sizeof cntinfo); 495 if (error) 496 goto out; 497 break; 498 case OSS_SNDCTL_DSP_GETOPTR: 499 error = ioctlf(fp, AUDIO_GETOOFFS, (void *)&tmpoffs, l); 500 if (error) 501 goto out; 502 cntinfo.bytes = tmpoffs.samples; 503 cntinfo.blocks = tmpoffs.deltablks; 504 cntinfo.ptr = tmpoffs.offset; 505 error = copyout(&cntinfo, SCARG(uap, data), sizeof cntinfo); 506 if (error) 507 goto out; 508 break; 509 case OSS_SNDCTL_DSP_SETDUPLEX: 510 idat = 1; 511 error = ioctlf(fp, AUDIO_SETFD, (void *)&idat, l); 512 goto out; 513 case OSS_SNDCTL_DSP_MAPINBUF: 514 case OSS_SNDCTL_DSP_MAPOUTBUF: 515 case OSS_SNDCTL_DSP_SETSYNCRO: 516 error = EINVAL; 517 goto out; 518 case OSS_SNDCTL_DSP_GETODELAY: 519 error = ioctlf(fp, AUDIO_GETBUFINFO, (void *)&tmpinfo, l); 520 if (error) 521 goto out; 522 idat = tmpinfo.play.seek + tmpinfo.blocksize / 2; 523 error = copyout(&idat, SCARG(uap, data), sizeof idat); 524 if (error) 525 goto out; 526 break; 527 case OSS_SNDCTL_DSP_PROFILE: 528 /* This gives just a hint to the driver, 529 * implementing it as a NOP is ok 530 */ 531 break; 532 default: 533 error = EINVAL; 534 goto out; 535 } 536 537 out: 538 FILE_UNUSE(fp, l); 539 return error; 540 } 541 542 /* If the NetBSD mixer device should have more than 32 devices 543 * some will not be available to Linux */ 544 #define NETBSD_MAXDEVS 64 545 struct audiodevinfo { 546 int done; 547 dev_t dev; 548 int16_t devmap[OSS_SOUND_MIXER_NRDEVICES], 549 rdevmap[NETBSD_MAXDEVS]; 550 char names[NETBSD_MAXDEVS][MAX_AUDIO_DEV_LEN]; 551 int enum2opaque[NETBSD_MAXDEVS]; 552 u_long devmask, recmask, stereomask; 553 u_long caps, source; 554 }; 555 556 static int 557 opaque_to_enum(struct audiodevinfo *di, audio_mixer_name_t *label, int opq) 558 { 559 int i, o; 560 561 for (i = 0; i < NETBSD_MAXDEVS; i++) { 562 o = di->enum2opaque[i]; 563 if (o == opq) 564 break; 565 if (o == -1 && label != NULL && 566 !strncmp(di->names[i], label->name, sizeof di->names[i])) { 567 di->enum2opaque[i] = opq; 568 break; 569 } 570 } 571 if (i >= NETBSD_MAXDEVS) 572 i = -1; 573 /*printf("opq_to_enum %s %d -> %d\n", label->name, opq, i);*/ 574 return (i); 575 } 576 577 static int 578 enum_to_ord(struct audiodevinfo *di, int enm) 579 { 580 if (enm >= NETBSD_MAXDEVS) 581 return (-1); 582 583 /*printf("enum_to_ord %d -> %d\n", enm, di->enum2opaque[enm]);*/ 584 return (di->enum2opaque[enm]); 585 } 586 587 static int 588 enum_to_mask(struct audiodevinfo *di, int enm) 589 { 590 int m; 591 if (enm >= NETBSD_MAXDEVS) 592 return (0); 593 594 m = di->enum2opaque[enm]; 595 if (m == -1) 596 m = 0; 597 /*printf("enum_to_mask %d -> %d\n", enm, di->enum2opaque[enm]);*/ 598 return (m); 599 } 600 601 /* 602 * Collect the audio device information to allow faster 603 * emulation of the Linux mixer ioctls. Cache the information 604 * to eliminate the overhead of repeating all the ioctls needed 605 * to collect the information. 606 */ 607 static struct audiodevinfo * 608 getdevinfo(struct file *fp, struct lwp *l) 609 { 610 mixer_devinfo_t mi; 611 int i, j, e; 612 static const struct { 613 const char *name; 614 int code; 615 } *dp, devs[] = { 616 { AudioNmicrophone, OSS_SOUND_MIXER_MIC }, 617 { AudioNline, OSS_SOUND_MIXER_LINE }, 618 { AudioNcd, OSS_SOUND_MIXER_CD }, 619 { AudioNdac, OSS_SOUND_MIXER_PCM }, 620 { AudioNaux, OSS_SOUND_MIXER_LINE1 }, 621 { AudioNrecord, OSS_SOUND_MIXER_IMIX }, 622 { AudioNmaster, OSS_SOUND_MIXER_VOLUME }, 623 { AudioNtreble, OSS_SOUND_MIXER_TREBLE }, 624 { AudioNbass, OSS_SOUND_MIXER_BASS }, 625 { AudioNspeaker, OSS_SOUND_MIXER_SPEAKER }, 626 /* { AudioNheadphone, ?? },*/ 627 { AudioNoutput, OSS_SOUND_MIXER_OGAIN }, 628 { AudioNinput, OSS_SOUND_MIXER_IGAIN }, 629 /* { AudioNmaster, OSS_SOUND_MIXER_SPEAKER },*/ 630 /* { AudioNstereo, ?? },*/ 631 /* { AudioNmono, ?? },*/ 632 { AudioNfmsynth, OSS_SOUND_MIXER_SYNTH }, 633 /* { AudioNwave, OSS_SOUND_MIXER_PCM },*/ 634 { AudioNmidi, OSS_SOUND_MIXER_SYNTH }, 635 /* { AudioNmixerout, ?? },*/ 636 { 0, -1 } 637 }; 638 int (*ioctlf)(struct file *, u_long, void *, struct lwp *) = 639 fp->f_ops->fo_ioctl; 640 struct vnode *vp; 641 struct vattr va; 642 static struct audiodevinfo devcache; 643 struct audiodevinfo *di = &devcache; 644 int mlen, dlen; 645 646 /* 647 * Figure out what device it is so we can check if the 648 * cached data is valid. 649 */ 650 vp = (struct vnode *)fp->f_data; 651 if (vp->v_type != VCHR) 652 return 0; 653 if (VOP_GETATTR(vp, &va, l->l_cred)) 654 return 0; 655 if (di->done && di->dev == va.va_rdev) 656 return di; 657 658 di->done = 1; 659 di->dev = va.va_rdev; 660 di->devmask = 0; 661 di->recmask = 0; 662 di->stereomask = 0; 663 di->source = ~0; 664 di->caps = 0; 665 for(i = 0; i < OSS_SOUND_MIXER_NRDEVICES; i++) 666 di->devmap[i] = -1; 667 for(i = 0; i < NETBSD_MAXDEVS; i++) { 668 di->rdevmap[i] = -1; 669 di->names[i][0] = '\0'; 670 di->enum2opaque[i] = -1; 671 } 672 for(i = 0; i < NETBSD_MAXDEVS; i++) { 673 mi.index = i; 674 if (ioctlf(fp, AUDIO_MIXER_DEVINFO, (void *)&mi, l) < 0) 675 break; 676 switch(mi.type) { 677 case AUDIO_MIXER_VALUE: 678 for(dp = devs; dp->name; dp++) { 679 if (strcmp(dp->name, mi.label.name) == 0) 680 break; 681 dlen = strlen(dp->name); 682 mlen = strlen(mi.label.name); 683 if (dlen < mlen 684 && mi.label.name[mlen-dlen-1] == '.' 685 && strcmp(dp->name, mi.label.name + mlen - dlen) == 0) 686 break; 687 } 688 if (dp->code >= 0) { 689 di->devmap[dp->code] = i; 690 di->rdevmap[i] = dp->code; 691 di->devmask |= 1 << dp->code; 692 if (mi.un.v.num_channels == 2) 693 di->stereomask |= 1 << dp->code; 694 strncpy(di->names[i], mi.label.name, 695 sizeof di->names[i]); 696 } 697 break; 698 } 699 } 700 for(i = 0; i < NETBSD_MAXDEVS; i++) { 701 mi.index = i; 702 if (ioctlf(fp, AUDIO_MIXER_DEVINFO, (void *)&mi, l) < 0) 703 break; 704 if (strcmp(mi.label.name, AudioNsource) != 0) 705 continue; 706 di->source = i; 707 switch(mi.type) { 708 case AUDIO_MIXER_ENUM: 709 for(j = 0; j < mi.un.e.num_mem; j++) { 710 e = opaque_to_enum(di, 711 &mi.un.e.member[j].label, 712 mi.un.e.member[j].ord); 713 if (e >= 0) 714 di->recmask |= 1 << di->rdevmap[e]; 715 } 716 di->caps = OSS_SOUND_CAP_EXCL_INPUT; 717 break; 718 case AUDIO_MIXER_SET: 719 for(j = 0; j < mi.un.s.num_mem; j++) { 720 e = opaque_to_enum(di, 721 &mi.un.s.member[j].label, 722 mi.un.s.member[j].mask); 723 if (e >= 0) 724 di->recmask |= 1 << di->rdevmap[e]; 725 } 726 break; 727 } 728 } 729 return di; 730 } 731 732 int 733 oss_ioctl_mixer(struct lwp *lwp, const struct oss_sys_ioctl_args *uap, register_t *retval) 734 { 735 /* { 736 syscallarg(int) fd; 737 syscallarg(u_long) com; 738 syscallarg(void *) data; 739 } */ 740 struct proc *p = lwp->l_proc; 741 struct file *fp; 742 struct filedesc *fdp; 743 u_long com; 744 struct audiodevinfo *di; 745 mixer_ctrl_t mc; 746 struct oss_mixer_info omi; 747 struct audio_device adev; 748 int idat; 749 int i; 750 int error; 751 int l, r, n, e; 752 int (*ioctlf)(struct file *, u_long, void *, struct lwp *); 753 754 fdp = p->p_fd; 755 if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL) 756 return (EBADF); 757 758 FILE_USE(fp); 759 760 if ((fp->f_flag & (FREAD | FWRITE)) == 0) { 761 error = EBADF; 762 goto out; 763 } 764 765 com = SCARG(uap, com); 766 DPRINTF(("oss_ioctl_mixer: com=%08lx\n", com)); 767 768 retval[0] = 0; 769 770 di = getdevinfo(fp, lwp); 771 if (di == 0) { 772 error = EINVAL; 773 goto out; 774 } 775 776 ioctlf = fp->f_ops->fo_ioctl; 777 switch (com) { 778 case OSS_GET_VERSION: 779 idat = OSS_SOUND_VERSION; 780 break; 781 case OSS_SOUND_MIXER_INFO: 782 case OSS_SOUND_OLD_MIXER_INFO: 783 error = ioctlf(fp, AUDIO_GETDEV, (void *)&adev, lwp); 784 if (error) 785 goto out; 786 omi.modify_counter = 1; 787 strncpy(omi.id, adev.name, sizeof omi.id); 788 strncpy(omi.name, adev.name, sizeof omi.name); 789 error = copyout(&omi, SCARG(uap, data), OSS_IOCTL_SIZE(com)); 790 goto out; 791 case OSS_SOUND_MIXER_READ_RECSRC: 792 if (di->source == -1) { 793 error = EINVAL; 794 goto out; 795 } 796 mc.dev = di->source; 797 if (di->caps & OSS_SOUND_CAP_EXCL_INPUT) { 798 mc.type = AUDIO_MIXER_ENUM; 799 error = ioctlf(fp, AUDIO_MIXER_READ, (void *)&mc, lwp); 800 if (error) 801 goto out; 802 e = opaque_to_enum(di, NULL, mc.un.ord); 803 if (e >= 0) 804 idat = 1 << di->rdevmap[e]; 805 } else { 806 mc.type = AUDIO_MIXER_SET; 807 error = ioctlf(fp, AUDIO_MIXER_READ, (void *)&mc, lwp); 808 if (error) 809 goto out; 810 e = opaque_to_enum(di, NULL, mc.un.mask); 811 if (e >= 0) 812 idat = 1 << di->rdevmap[e]; 813 } 814 break; 815 case OSS_SOUND_MIXER_READ_DEVMASK: 816 idat = di->devmask; 817 break; 818 case OSS_SOUND_MIXER_READ_RECMASK: 819 idat = di->recmask; 820 break; 821 case OSS_SOUND_MIXER_READ_STEREODEVS: 822 idat = di->stereomask; 823 break; 824 case OSS_SOUND_MIXER_READ_CAPS: 825 idat = di->caps; 826 break; 827 case OSS_SOUND_MIXER_WRITE_RECSRC: 828 case OSS_SOUND_MIXER_WRITE_R_RECSRC: 829 if (di->source == -1) { 830 error = EINVAL; 831 goto out; 832 } 833 mc.dev = di->source; 834 error = copyin(SCARG(uap, data), &idat, sizeof idat); 835 if (error) 836 goto out; 837 if (di->caps & OSS_SOUND_CAP_EXCL_INPUT) { 838 mc.type = AUDIO_MIXER_ENUM; 839 for(i = 0; i < OSS_SOUND_MIXER_NRDEVICES; i++) 840 if (idat & (1 << i)) 841 break; 842 if (i >= OSS_SOUND_MIXER_NRDEVICES || 843 di->devmap[i] == -1) { 844 error = EINVAL; 845 goto out; 846 } 847 mc.un.ord = enum_to_ord(di, di->devmap[i]); 848 } else { 849 mc.type = AUDIO_MIXER_SET; 850 mc.un.mask = 0; 851 for(i = 0; i < OSS_SOUND_MIXER_NRDEVICES; i++) { 852 if (idat & (1 << i)) { 853 if (di->devmap[i] == -1) { 854 error = EINVAL; 855 goto out; 856 } 857 mc.un.mask |= enum_to_mask(di, di->devmap[i]); 858 } 859 } 860 } 861 error = ioctlf(fp, AUDIO_MIXER_WRITE, (void *)&mc, lwp); 862 goto out; 863 default: 864 if (OSS_MIXER_READ(OSS_SOUND_MIXER_FIRST) <= com && 865 com < OSS_MIXER_READ(OSS_SOUND_MIXER_NRDEVICES)) { 866 n = OSS_GET_DEV(com); 867 if (di->devmap[n] == -1) { 868 error = EINVAL; 869 goto out; 870 } 871 doread: 872 mc.dev = di->devmap[n]; 873 mc.type = AUDIO_MIXER_VALUE; 874 mc.un.value.num_channels = di->stereomask & (1<<n) ? 2 : 1; 875 error = ioctlf(fp, AUDIO_MIXER_READ, (void *)&mc, lwp); 876 if (error) 877 goto out; 878 if (mc.un.value.num_channels != 2) { 879 l = r = mc.un.value.level[AUDIO_MIXER_LEVEL_MONO]; 880 } else { 881 l = mc.un.value.level[AUDIO_MIXER_LEVEL_LEFT]; 882 r = mc.un.value.level[AUDIO_MIXER_LEVEL_RIGHT]; 883 } 884 idat = TO_OSSVOL(l) | (TO_OSSVOL(r) << 8); 885 DPRINTF(("OSS_MIXER_READ n=%d (dev=%d) l=%d, r=%d, idat=%04x\n", 886 n, di->devmap[n], l, r, idat)); 887 break; 888 } else if ((OSS_MIXER_WRITE_R(OSS_SOUND_MIXER_FIRST) <= com && 889 com < OSS_MIXER_WRITE_R(OSS_SOUND_MIXER_NRDEVICES)) || 890 (OSS_MIXER_WRITE(OSS_SOUND_MIXER_FIRST) <= com && 891 com < OSS_MIXER_WRITE(OSS_SOUND_MIXER_NRDEVICES))) { 892 n = OSS_GET_DEV(com); 893 if (di->devmap[n] == -1) { 894 error = EINVAL; 895 goto out; 896 } 897 error = copyin(SCARG(uap, data), &idat, sizeof idat); 898 if (error) 899 goto out; 900 l = FROM_OSSVOL( idat & 0xff); 901 r = FROM_OSSVOL((idat >> 8) & 0xff); 902 mc.dev = di->devmap[n]; 903 mc.type = AUDIO_MIXER_VALUE; 904 if (di->stereomask & (1<<n)) { 905 mc.un.value.num_channels = 2; 906 mc.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l; 907 mc.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r; 908 } else { 909 mc.un.value.num_channels = 1; 910 mc.un.value.level[AUDIO_MIXER_LEVEL_MONO] = (l+r)/2; 911 } 912 DPRINTF(("OSS_MIXER_WRITE n=%d (dev=%d) l=%d, r=%d, idat=%04x\n", 913 n, di->devmap[n], l, r, idat)); 914 error = ioctlf(fp, AUDIO_MIXER_WRITE, (void *)&mc, lwp); 915 if (error) 916 goto out; 917 if (OSS_MIXER_WRITE(OSS_SOUND_MIXER_FIRST) <= com && 918 com < OSS_MIXER_WRITE(OSS_SOUND_MIXER_NRDEVICES)) { 919 error = 0; 920 goto out; 921 } 922 goto doread; 923 } else { 924 #ifdef AUDIO_DEBUG 925 printf("oss_audio: unknown mixer ioctl %04lx\n", com); 926 #endif 927 error = EINVAL; 928 goto out; 929 } 930 } 931 error = copyout(&idat, SCARG(uap, data), sizeof idat); 932 out: 933 FILE_UNUSE(fp, lwp); 934 return error; 935 } 936 937 /* Sequencer emulation */ 938 int 939 oss_ioctl_sequencer(struct lwp *l, const struct oss_sys_ioctl_args *uap, register_t *retval) 940 { 941 /* { 942 syscallarg(int) fd; 943 syscallarg(u_long) com; 944 syscallarg(void *) data; 945 } */ 946 struct proc *p = l->l_proc; 947 struct file *fp; 948 struct filedesc *fdp; 949 u_long com; 950 int idat, idat1; 951 struct synth_info si; 952 struct oss_synth_info osi; 953 struct oss_seq_event_rec oser; 954 int error; 955 int (*ioctlf)(struct file *, u_long, void *, struct lwp *); 956 957 fdp = p->p_fd; 958 if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL) 959 return (EBADF); 960 961 FILE_USE(fp); 962 963 if ((fp->f_flag & (FREAD | FWRITE)) == 0) { 964 error = EBADF; 965 goto out; 966 } 967 968 com = SCARG(uap, com); 969 DPRINTF(("oss_ioctl_sequencer: com=%08lx\n", com)); 970 971 retval[0] = 0; 972 973 ioctlf = fp->f_ops->fo_ioctl; 974 switch (com) { 975 case OSS_SEQ_RESET: 976 error = ioctlf(fp, SEQUENCER_RESET, (void *)&idat, l); 977 goto out; 978 case OSS_SEQ_SYNC: 979 error = ioctlf(fp, SEQUENCER_SYNC, (void *)&idat, l); 980 goto out; 981 case OSS_SYNTH_INFO: 982 error = copyin(SCARG(uap, data), &osi, sizeof osi); 983 if (error) 984 goto out; 985 si.device = osi.device; 986 error = ioctlf(fp, SEQUENCER_INFO, (void *)&si, l); 987 if (error) 988 goto out; 989 strncpy(osi.name, si.name, sizeof osi.name); 990 osi.device = si.device; 991 switch(si.synth_type) { 992 case SYNTH_TYPE_FM: 993 osi.synth_type = OSS_SYNTH_TYPE_FM; break; 994 case SYNTH_TYPE_SAMPLE: 995 osi.synth_type = OSS_SYNTH_TYPE_SAMPLE; break; 996 case SYNTH_TYPE_MIDI: 997 osi.synth_type = OSS_SYNTH_TYPE_MIDI; break; 998 default: 999 osi.synth_type = 0; break; 1000 } 1001 switch(si.synth_subtype) { 1002 case SYNTH_SUB_FM_TYPE_ADLIB: 1003 osi.synth_subtype = OSS_FM_TYPE_ADLIB; break; 1004 case SYNTH_SUB_FM_TYPE_OPL3: 1005 osi.synth_subtype = OSS_FM_TYPE_OPL3; break; 1006 case SYNTH_SUB_MIDI_TYPE_MPU401: 1007 osi.synth_subtype = OSS_MIDI_TYPE_MPU401; break; 1008 case SYNTH_SUB_SAMPLE_TYPE_BASIC: 1009 osi.synth_subtype = OSS_SAMPLE_TYPE_BASIC; break; 1010 default: 1011 osi.synth_subtype = 0; break; 1012 } 1013 osi.perc_mode = 0; 1014 osi.nr_voices = si.nr_voices; 1015 osi.nr_drums = 0; 1016 osi.instr_bank_size = si.instr_bank_size; 1017 osi.capabilities = 0; 1018 if (si.capabilities & SYNTH_CAP_OPL3) 1019 osi.capabilities |= OSS_SYNTH_CAP_OPL3; 1020 if (si.capabilities & SYNTH_CAP_INPUT) 1021 osi.capabilities |= OSS_SYNTH_CAP_INPUT; 1022 error = copyout(&osi, SCARG(uap, data), sizeof osi); 1023 goto out; 1024 case OSS_SEQ_CTRLRATE: 1025 error = copyin(SCARG(uap, data), &idat, sizeof idat); 1026 if (error) 1027 goto out; 1028 error = ioctlf(fp, SEQUENCER_CTRLRATE, (void *)&idat, l); 1029 if (error) 1030 goto out; 1031 retval[0] = idat; 1032 break; 1033 case OSS_SEQ_GETOUTCOUNT: 1034 error = ioctlf(fp, SEQUENCER_GETOUTCOUNT, (void *)&idat, l); 1035 if (error) 1036 goto out; 1037 retval[0] = idat; 1038 break; 1039 case OSS_SEQ_GETINCOUNT: 1040 error = ioctlf(fp, SEQUENCER_GETINCOUNT, (void *)&idat, l); 1041 if (error) 1042 goto out; 1043 retval[0] = idat; 1044 break; 1045 case OSS_SEQ_NRSYNTHS: 1046 error = ioctlf(fp, SEQUENCER_NRSYNTHS, (void *)&idat, l); 1047 if (error) 1048 goto out; 1049 retval[0] = idat; 1050 break; 1051 case OSS_SEQ_NRMIDIS: 1052 error = ioctlf(fp, SEQUENCER_NRMIDIS, (void *)&idat, l); 1053 if (error) 1054 goto out; 1055 retval[0] = idat; 1056 break; 1057 case OSS_SEQ_THRESHOLD: 1058 error = copyin(SCARG(uap, data), &idat, sizeof idat); 1059 if (error) 1060 goto out; 1061 error = ioctlf(fp, SEQUENCER_THRESHOLD, (void *)&idat, l); 1062 goto out; 1063 case OSS_MEMAVL: 1064 error = copyin(SCARG(uap, data), &idat, sizeof idat); 1065 if (error) 1066 goto out; 1067 error = ioctlf(fp, SEQUENCER_MEMAVL, (void *)&idat, l); 1068 if (error) 1069 goto out; 1070 retval[0] = idat; 1071 break; 1072 case OSS_SEQ_PANIC: 1073 error = ioctlf(fp, SEQUENCER_PANIC, (void *)&idat, l); 1074 goto out; 1075 case OSS_SEQ_OUTOFBAND: 1076 error = copyin(SCARG(uap, data), &oser, sizeof oser); 1077 if (error) 1078 goto out; 1079 error = ioctlf(fp, SEQUENCER_OUTOFBAND, (void *)&oser, l); 1080 if (error) 1081 goto out; 1082 break; 1083 case OSS_SEQ_GETTIME: 1084 error = ioctlf(fp, SEQUENCER_GETTIME, (void *)&idat, l); 1085 if (error) 1086 goto out; 1087 retval[0] = idat; 1088 break; 1089 case OSS_TMR_TIMEBASE: 1090 error = copyin(SCARG(uap, data), &idat, sizeof idat); 1091 if (error) 1092 goto out; 1093 error = ioctlf(fp, SEQUENCER_TMR_TIMEBASE, (void *)&idat, l); 1094 if (error) 1095 goto out; 1096 retval[0] = idat; 1097 break; 1098 case OSS_TMR_START: 1099 error = ioctlf(fp, SEQUENCER_TMR_START, (void *)&idat, l); 1100 goto out; 1101 case OSS_TMR_STOP: 1102 error = ioctlf(fp, SEQUENCER_TMR_STOP, (void *)&idat, l); 1103 goto out; 1104 case OSS_TMR_CONTINUE: 1105 error = ioctlf(fp, SEQUENCER_TMR_CONTINUE, (void *)&idat, l); 1106 goto out; 1107 case OSS_TMR_TEMPO: 1108 error = copyin(SCARG(uap, data), &idat, sizeof idat); 1109 if (error) 1110 goto out; 1111 error = ioctlf(fp, SEQUENCER_TMR_TEMPO, (void *)&idat, l); 1112 if (error) 1113 goto out; 1114 retval[0] = idat; 1115 break; 1116 case OSS_TMR_SOURCE: 1117 error = copyin(SCARG(uap, data), &idat1, sizeof idat); 1118 if (error) 1119 goto out; 1120 idat = 0; 1121 if (idat1 & OSS_TMR_INTERNAL) idat |= SEQUENCER_TMR_INTERNAL; 1122 error = ioctlf(fp, SEQUENCER_TMR_SOURCE, (void *)&idat, l); 1123 if (error) 1124 goto out; 1125 idat1 = idat; 1126 if (idat1 & SEQUENCER_TMR_INTERNAL) idat |= OSS_TMR_INTERNAL; 1127 retval[0] = idat; 1128 break; 1129 case OSS_TMR_METRONOME: 1130 error = copyin(SCARG(uap, data), &idat, sizeof idat); 1131 if (error) 1132 goto out; 1133 error = ioctlf(fp, SEQUENCER_TMR_METRONOME, (void *)&idat, l); 1134 goto out; 1135 case OSS_TMR_SELECT: 1136 error = copyin(SCARG(uap, data), &idat, sizeof idat); 1137 if (error) 1138 goto out; 1139 retval[0] = idat; 1140 error = ioctlf(fp, SEQUENCER_TMR_SELECT, (void *)&idat, l); 1141 goto out; 1142 default: 1143 error = EINVAL; 1144 goto out; 1145 } 1146 1147 error = copyout(&idat, SCARG(uap, data), sizeof idat); 1148 out: 1149 FILE_UNUSE(fp, l); 1150 return error; 1151 } 1152 1153 /* 1154 * Check that the blocksize is a power of 2 as OSS wants. 1155 * If not, set it to be. 1156 */ 1157 static void 1158 setblocksize(struct file *fp, struct audio_info *info, struct lwp *l) 1159 { 1160 struct audio_info set; 1161 int s; 1162 1163 if (info->blocksize & (info->blocksize-1)) { 1164 for(s = 32; s < info->blocksize; s <<= 1) 1165 ; 1166 AUDIO_INITINFO(&set); 1167 set.blocksize = s; 1168 fp->f_ops->fo_ioctl(fp, AUDIO_SETINFO, (void *)&set, l); 1169 fp->f_ops->fo_ioctl(fp, AUDIO_GETBUFINFO, (void *)info, l); 1170 } 1171 } 1172