Annotation of sys/compat/ossaudio/ossaudio.c, Revision 1.1.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