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