ossaudio.c revision 1.14 1 /* $NetBSD: ossaudio.c,v 1.14 1997/07/28 03:51:11 augustss Exp $ */
2 #include <sys/param.h>
3 #include <sys/proc.h>
4 #include <sys/systm.h>
5 #include <sys/file.h>
6 #include <sys/vnode.h>
7 #include <sys/filedesc.h>
8 #include <sys/ioctl.h>
9 #include <sys/mount.h>
10 #include <sys/audioio.h>
11
12 #include <sys/syscallargs.h>
13
14 #include <compat/ossaudio/ossaudio.h>
15 #include <compat/ossaudio/ossaudiovar.h>
16
17 static struct audiodevinfo *getdevinfo __P((struct file *, struct proc *));
18
19 static void setblocksize __P((struct file *, struct audio_info *, struct proc *));
20
21 int
22 oss_ioctl_audio(p, uap, retval)
23 register struct proc *p;
24 register struct oss_sys_ioctl_args /* {
25 syscallarg(int) fd;
26 syscallarg(u_long) com;
27 syscallarg(caddr_t) data;
28 } */ *uap;
29 register_t *retval;
30 {
31 register struct file *fp;
32 register struct filedesc *fdp;
33 u_long com;
34 struct audio_info tmpinfo;
35 struct audio_offset tmpoffs;
36 struct oss_audio_buf_info bufinfo;
37 struct oss_count_info cntinfo;
38 int idat, idata;
39 int error;
40 int (*ioctlf) __P((struct file *, u_long, caddr_t, struct proc *));
41
42 fdp = p->p_fd;
43 if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles ||
44 (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL)
45 return (EBADF);
46
47 if ((fp->f_flag & (FREAD | FWRITE)) == 0)
48 return (EBADF);
49
50 ioctlf = fp->f_ops->fo_ioctl;
51
52 com = SCARG(uap, com);
53 retval[0] = 0;
54
55 switch (com) {
56 case OSS_SNDCTL_DSP_RESET:
57 error = ioctlf(fp, AUDIO_FLUSH, (caddr_t)0, p);
58 if (error)
59 return error;
60 break;
61 case OSS_SNDCTL_DSP_SYNC:
62 case OSS_SNDCTL_DSP_POST:
63 error = ioctlf(fp, AUDIO_DRAIN, (caddr_t)0, p);
64 if (error)
65 return error;
66 break;
67 case OSS_SNDCTL_DSP_SPEED:
68 AUDIO_INITINFO(&tmpinfo);
69 error = copyin(SCARG(uap, data), &idat, sizeof idat);
70 if (error)
71 return error;
72 tmpinfo.play.sample_rate =
73 tmpinfo.record.sample_rate = idat;
74 (void) ioctlf(fp, AUDIO_SETINFO, (caddr_t)&tmpinfo, p);
75 /* fall into ... */
76 case OSS_SOUND_PCM_READ_RATE:
77 error = ioctlf(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p);
78 if (error)
79 return error;
80 idat = tmpinfo.play.sample_rate;
81 error = copyout(&idat, SCARG(uap, data), sizeof idat);
82 if (error)
83 return error;
84 break;
85 case OSS_SNDCTL_DSP_STEREO:
86 AUDIO_INITINFO(&tmpinfo);
87 error = copyin(SCARG(uap, data), &idat, sizeof idat);
88 if (error)
89 return error;
90 tmpinfo.play.channels =
91 tmpinfo.record.channels = idat ? 2 : 1;
92 (void) ioctlf(fp, AUDIO_SETINFO, (caddr_t)&tmpinfo, p);
93 error = ioctlf(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p);
94 if (error)
95 return error;
96 idat = tmpinfo.play.channels - 1;
97 error = copyout(&idat, SCARG(uap, data), sizeof idat);
98 if (error)
99 return error;
100 break;
101 case OSS_SNDCTL_DSP_GETBLKSIZE:
102 error = ioctlf(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p);
103 if (error)
104 return error;
105 setblocksize(fp, &tmpinfo, p);
106 idat = tmpinfo.blocksize;
107 error = copyout(&idat, SCARG(uap, data), sizeof idat);
108 if (error)
109 return error;
110 break;
111 case OSS_SNDCTL_DSP_SETFMT:
112 AUDIO_INITINFO(&tmpinfo);
113 error = copyin(SCARG(uap, data), &idat, sizeof idat);
114 if (error)
115 return error;
116 switch (idat) {
117 case OSS_AFMT_MU_LAW:
118 tmpinfo.play.precision =
119 tmpinfo.record.precision = 8;
120 tmpinfo.play.encoding =
121 tmpinfo.record.encoding = AUDIO_ENCODING_ULAW;
122 break;
123 case OSS_AFMT_A_LAW:
124 tmpinfo.play.precision =
125 tmpinfo.record.precision = 8;
126 tmpinfo.play.encoding =
127 tmpinfo.record.encoding = AUDIO_ENCODING_ALAW;
128 break;
129 case OSS_AFMT_U8:
130 tmpinfo.play.precision =
131 tmpinfo.record.precision = 8;
132 tmpinfo.play.encoding =
133 tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR;
134 break;
135 case OSS_AFMT_S8:
136 tmpinfo.play.precision =
137 tmpinfo.record.precision = 8;
138 tmpinfo.play.encoding =
139 tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR;
140 break;
141 case OSS_AFMT_S16_LE:
142 tmpinfo.play.precision =
143 tmpinfo.record.precision = 16;
144 tmpinfo.play.encoding =
145 tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_LE;
146 break;
147 case OSS_AFMT_S16_BE:
148 tmpinfo.play.precision =
149 tmpinfo.record.precision = 16;
150 tmpinfo.play.encoding =
151 tmpinfo.record.encoding = AUDIO_ENCODING_SLINEAR_BE;
152 break;
153 case OSS_AFMT_U16_LE:
154 tmpinfo.play.precision =
155 tmpinfo.record.precision = 16;
156 tmpinfo.play.encoding =
157 tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR_LE;
158 break;
159 case OSS_AFMT_U16_BE:
160 tmpinfo.play.precision =
161 tmpinfo.record.precision = 16;
162 tmpinfo.play.encoding =
163 tmpinfo.record.encoding = AUDIO_ENCODING_ULINEAR_BE;
164 break;
165 default:
166 return EINVAL;
167 }
168 (void) ioctlf(fp, AUDIO_SETINFO, (caddr_t)&tmpinfo, p);
169 /* fall into ... */
170 case OSS_SOUND_PCM_READ_BITS:
171 error = ioctlf(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p);
172 if (error)
173 return error;
174 switch (tmpinfo.play.encoding) {
175 case AUDIO_ENCODING_ULAW:
176 idat = OSS_AFMT_MU_LAW;
177 break;
178 case AUDIO_ENCODING_ALAW:
179 idat = OSS_AFMT_A_LAW;
180 break;
181 case AUDIO_ENCODING_SLINEAR_LE:
182 if (tmpinfo.play.precision == 16)
183 idat = OSS_AFMT_S16_LE;
184 else
185 idat = OSS_AFMT_S8;
186 break;
187 case AUDIO_ENCODING_SLINEAR_BE:
188 if (tmpinfo.play.precision == 16)
189 idat = OSS_AFMT_S16_BE;
190 else
191 idat = OSS_AFMT_S8;
192 break;
193 case AUDIO_ENCODING_ULINEAR_LE:
194 if (tmpinfo.play.precision == 16)
195 idat = OSS_AFMT_U16_LE;
196 else
197 idat = OSS_AFMT_U8;
198 break;
199 case AUDIO_ENCODING_ULINEAR_BE:
200 if (tmpinfo.play.precision == 16)
201 idat = OSS_AFMT_U16_BE;
202 else
203 idat = OSS_AFMT_U8;
204 break;
205 case AUDIO_ENCODING_ADPCM:
206 idat = OSS_AFMT_IMA_ADPCM;
207 break;
208 }
209 error = copyout(&idat, SCARG(uap, data), sizeof idat);
210 if (error)
211 return error;
212 break;
213 case OSS_SNDCTL_DSP_CHANNELS:
214 AUDIO_INITINFO(&tmpinfo);
215 error = copyin(SCARG(uap, data), &idat, sizeof idat);
216 if (error)
217 return error;
218 tmpinfo.play.channels =
219 tmpinfo.record.channels = idat;
220 (void) ioctlf(fp, AUDIO_SETINFO, (caddr_t)&tmpinfo, p);
221 /* fall into ... */
222 case OSS_SOUND_PCM_READ_CHANNELS:
223 error = ioctlf(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p);
224 if (error)
225 return error;
226 idat = tmpinfo.play.channels;
227 error = copyout(&idat, SCARG(uap, data), sizeof idat);
228 if (error)
229 return error;
230 break;
231 case OSS_SOUND_PCM_WRITE_FILTER:
232 case OSS_SOUND_PCM_READ_FILTER:
233 return EINVAL; /* XXX unimplemented */
234 case OSS_SNDCTL_DSP_SUBDIVIDE:
235 error = copyin(SCARG(uap, data), &idat, sizeof idat);
236 if (error)
237 return error;
238 error = ioctlf(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p);
239 setblocksize(fp, &tmpinfo, p);
240 if (error)
241 return error;
242 if (idat == 0)
243 idat = tmpinfo.buffersize / tmpinfo.blocksize;
244 idat = (tmpinfo.buffersize / idat) & -4;
245 AUDIO_INITINFO(&tmpinfo);
246 tmpinfo.blocksize = idat;
247 error = ioctlf(fp, AUDIO_SETINFO, (caddr_t)&tmpinfo, p);
248 if (error)
249 return error;
250 idat = tmpinfo.buffersize / tmpinfo.blocksize;
251 error = copyout(&idat, SCARG(uap, data), sizeof idat);
252 if (error)
253 return error;
254 break;
255 case OSS_SNDCTL_DSP_SETFRAGMENT:
256 AUDIO_INITINFO(&tmpinfo);
257 error = copyin(SCARG(uap, data), &idat, sizeof idat);
258 if (error)
259 return error;
260 if ((idat & 0xffff) < 4 || (idat & 0xffff) > 17)
261 return EINVAL;
262 tmpinfo.blocksize = 1 << (idat & 0xffff);
263 tmpinfo.hiwat = (idat >> 16) & 0xffff;
264 (void) ioctlf(fp, AUDIO_SETINFO, (caddr_t)&tmpinfo, p);
265 error = ioctlf(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p);
266 if (error)
267 return error;
268 idat = tmpinfo.blocksize;
269 error = copyout(&idat, SCARG(uap, data), sizeof idat);
270 if (error)
271 return error;
272 break;
273 case OSS_SNDCTL_DSP_GETFMTS:
274 idat = OSS_AFMT_MU_LAW | OSS_AFMT_U8 | OSS_AFMT_S16_LE;
275 error = copyout(&idat, SCARG(uap, data), sizeof idat);
276 if (error)
277 return error;
278 break;
279 case OSS_SNDCTL_DSP_GETOSPACE:
280 case OSS_SNDCTL_DSP_GETISPACE:
281 error = ioctlf(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p);
282 if (error)
283 return error;
284 setblocksize(fp, &tmpinfo, p);
285 bufinfo.fragsize = tmpinfo.blocksize;
286 bufinfo.fragments = /* XXX */
287 bufinfo.fragstotal = tmpinfo.buffersize / bufinfo.fragsize;
288 bufinfo.bytes = tmpinfo.buffersize;
289 error = copyout(&bufinfo, SCARG(uap, data), sizeof bufinfo);
290 if (error)
291 return error;
292 break;
293 case OSS_SNDCTL_DSP_NONBLOCK:
294 return EINVAL; /* XXX unimplemented */
295 case OSS_SNDCTL_DSP_GETCAPS:
296 error = ioctlf(fp, AUDIO_GETPROPS, (caddr_t)&idata, p);
297 if (error)
298 return error;
299 idat = OSS_DSP_CAP_TRIGGER; /* pretend we have trigger */
300 if (idata & AUDIO_PROP_FULLDUPLEX)
301 idat |= OSS_DSP_CAP_DUPLEX;
302 if (idata & AUDIO_PROP_MMAP)
303 idat |= OSS_DSP_CAP_MMAP;
304 error = copyout(&idat, SCARG(uap, data), sizeof idat);
305 if (error)
306 return error;
307 break;
308 #if 0
309 case OSS_SNDCTL_DSP_GETTRIGGER:
310 error = ioctlf(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p);
311 if (error)
312 return error;
313 idat = (tmpinfo.play.pause ? 0 : OSS_PCM_ENABLE_OUTPUT) |
314 (tmpinfo.record.pause ? 0 : OSS_PCM_ENABLE_INPUT);
315 error = copyout(&idat, SCARG(uap, data), sizeof idat);
316 if (error)
317 return error;
318 break;
319 case OSS_SNDCTL_DSP_SETTRIGGER:
320 AUDIO_INITINFO(&tmpinfo);
321 error = copyin(SCARG(uap, data), &idat, sizeof idat);
322 if (error)
323 return error;
324 tmpinfo.play.pause = (idat & OSS_PCM_ENABLE_OUTPUT) == 0;
325 tmpinfo.record.pause = (idat & OSS_PCM_ENABLE_INPUT) == 0;
326 (void) ioctlf(fp, AUDIO_SETINFO, (caddr_t)&tmpinfo, p);
327 error = copyout(&idat, SCARG(uap, data), sizeof idat);
328 if (error)
329 return error;
330 break;
331 #else
332 case OSS_SNDCTL_DSP_GETTRIGGER:
333 case OSS_SNDCTL_DSP_SETTRIGGER:
334 /* XXX Do nothing for now. */
335 idat = OSS_PCM_ENABLE_OUTPUT;
336 return copyout(&idat, SCARG(uap, data), sizeof idat);
337 #endif
338 case OSS_SNDCTL_DSP_GETIPTR:
339 error = ioctlf(fp, AUDIO_GETIOFFS, (caddr_t)&tmpoffs, p);
340 if (error)
341 return error;
342 cntinfo.bytes = tmpoffs.samples;
343 cntinfo.blocks = tmpoffs.deltablks;
344 cntinfo.ptr = tmpoffs.offset;
345 error = copyout(&cntinfo, SCARG(uap, data), sizeof cntinfo);
346 if (error)
347 return error;
348 break;
349 case OSS_SNDCTL_DSP_GETOPTR:
350 error = ioctlf(fp, AUDIO_GETOOFFS, (caddr_t)&tmpoffs, p);
351 if (error)
352 return error;
353 cntinfo.bytes = tmpoffs.samples;
354 cntinfo.blocks = tmpoffs.deltablks;
355 cntinfo.ptr = tmpoffs.offset;
356 error = copyout(&cntinfo, SCARG(uap, data), sizeof cntinfo);
357 if (error)
358 return error;
359 break;
360 case OSS_SNDCTL_DSP_MAPINBUF:
361 case OSS_SNDCTL_DSP_MAPOUTBUF:
362 case OSS_SNDCTL_DSP_SETSYNCRO:
363 case OSS_SNDCTL_DSP_SETDUPLEX:
364 case OSS_SNDCTL_DSP_PROFILE:
365 return EINVAL; /* XXX unimplemented */
366 default:
367 return EINVAL;
368 }
369
370 return 0;
371 }
372
373 /* If the NetBSD mixer device should have more than 32 devices
374 * some will not be available to Linux */
375 #define NETBSD_MAXDEVS 32
376 struct audiodevinfo {
377 int done;
378 dev_t dev;
379 int16_t devmap[OSS_SOUND_MIXER_NRDEVICES],
380 rdevmap[NETBSD_MAXDEVS];
381 u_long devmask, recmask, stereomask;
382 u_long caps, source;
383 };
384
385 /*
386 * Collect the audio device information to allow faster
387 * emulation of the Linux mixer ioctls. Cache the information
388 * to eliminate the overhead of repeating all the ioctls needed
389 * to collect the information.
390 */
391 static struct audiodevinfo *
392 getdevinfo(fp, p)
393 struct file *fp;
394 struct proc *p;
395 {
396 mixer_devinfo_t mi;
397 int i;
398 static struct {
399 char *name;
400 int code;
401 } *dp, devs[] = {
402 { AudioNmicrophone, OSS_SOUND_MIXER_MIC },
403 { AudioNline, OSS_SOUND_MIXER_LINE },
404 { AudioNcd, OSS_SOUND_MIXER_CD },
405 { AudioNdac, OSS_SOUND_MIXER_PCM },
406 { AudioNrecord, OSS_SOUND_MIXER_IMIX },
407 { AudioNvolume, OSS_SOUND_MIXER_VOLUME },
408 { AudioNtreble, OSS_SOUND_MIXER_TREBLE },
409 { AudioNbass, OSS_SOUND_MIXER_BASS },
410 { AudioNspeaker, OSS_SOUND_MIXER_SPEAKER },
411 /* { AudioNheadphone, ?? },*/
412 { AudioNoutput, OSS_SOUND_MIXER_OGAIN },
413 { AudioNinput, OSS_SOUND_MIXER_IGAIN },
414 { AudioNmaster, OSS_SOUND_MIXER_SPEAKER },
415 /* { AudioNstereo, ?? },*/
416 /* { AudioNmono, ?? },*/
417 { AudioNfmsynth, OSS_SOUND_MIXER_SYNTH },
418 /* { AudioNwave, OSS_SOUND_MIXER_PCM },*/
419 { AudioNmidi, OSS_SOUND_MIXER_SYNTH },
420 /* { AudioNmixerout, ?? },*/
421 { 0, -1 }
422 };
423 int (*ioctlf) __P((struct file *, u_long, caddr_t, struct proc *)) =
424 fp->f_ops->fo_ioctl;
425 struct vnode *vp;
426 struct vattr va;
427 static struct audiodevinfo devcache = { 0 };
428 struct audiodevinfo *di = &devcache;
429
430 /* Figure out what device it is so we can check if the
431 * cached data is valid.
432 */
433 vp = (struct vnode *)fp->f_data;
434 if (vp->v_type != VCHR)
435 return 0;
436 if (VOP_GETATTR(vp, &va, p->p_ucred, p))
437 return 0;
438 if (di->done && di->dev == va.va_rdev)
439 return di;
440
441 di->done = 1;
442 di->dev = va.va_rdev;
443 di->devmask = 0;
444 di->recmask = 0;
445 di->stereomask = 0;
446 di->source = -1;
447 di->caps = 0;
448 for(i = 0; i < OSS_SOUND_MIXER_NRDEVICES; i++)
449 di->devmap[i] = -1;
450 for(i = 0; i < NETBSD_MAXDEVS; i++)
451 di->rdevmap[i] = -1;
452 for(i = 0; i < NETBSD_MAXDEVS; i++) {
453 mi.index = i;
454 if (ioctlf(fp, AUDIO_MIXER_DEVINFO, (caddr_t)&mi, p) < 0)
455 break;
456 switch(mi.type) {
457 case AUDIO_MIXER_VALUE:
458 for(dp = devs; dp->name; dp++)
459 if (strcmp(dp->name, mi.label.name) == 0)
460 break;
461 if (dp->code >= 0) {
462 di->devmap[dp->code] = i;
463 di->rdevmap[i] = dp->code;
464 di->devmask |= 1 << dp->code;
465 if (mi.un.v.num_channels == 2)
466 di->stereomask |= 1 << dp->code;
467 }
468 break;
469 case AUDIO_MIXER_ENUM:
470 if (strcmp(mi.label.name, AudioNsource) == 0) {
471 int j;
472 di->source = i;
473 for(j = 0; j < mi.un.e.num_mem; j++)
474 di->recmask |= 1 << di->rdevmap[mi.un.e.member[j].ord];
475 di->caps = OSS_SOUND_CAP_EXCL_INPUT;
476 }
477 break;
478 case AUDIO_MIXER_SET:
479 if (strcmp(mi.label.name, AudioNsource) == 0) {
480 int j;
481 di->source = i;
482 for(j = 0; j < mi.un.s.num_mem; j++) {
483 int k, mask = mi.un.s.member[j].mask;
484 if (mask) {
485 for(k = 0; !(mask & 1); mask >>= 1, k++)
486 ;
487 di->recmask |= 1 << di->rdevmap[k];
488 }
489 }
490 }
491 break;
492 }
493 }
494 return di;
495 }
496
497 int
498 oss_ioctl_mixer(p, uap, retval)
499 register struct proc *p;
500 register struct oss_sys_ioctl_args /* {
501 syscallarg(int) fd;
502 syscallarg(u_long) com;
503 syscallarg(caddr_t) data;
504 } */ *uap;
505 register_t *retval;
506 {
507 struct file *fp;
508 struct filedesc *fdp;
509 u_long com;
510 struct audiodevinfo *di;
511 mixer_ctrl_t mc;
512 int idat;
513 int i;
514 int error;
515 int l, r, n;
516 int (*ioctlf) __P((struct file *, u_long, caddr_t, struct proc *));
517
518 fdp = p->p_fd;
519 if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles ||
520 (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL)
521 return (EBADF);
522
523 if ((fp->f_flag & (FREAD | FWRITE)) == 0)
524 return (EBADF);
525
526 com = SCARG(uap, com);
527 retval[0] = 0;
528
529 di = getdevinfo(fp, p);
530 if (di == 0)
531 return EINVAL;
532
533 ioctlf = fp->f_ops->fo_ioctl;
534 switch (com) {
535 case OSS_SOUND_MIXER_READ_RECSRC:
536 if (di->source == -1)
537 return EINVAL;
538 mc.dev = di->source;
539 if (di->caps & OSS_SOUND_CAP_EXCL_INPUT) {
540 mc.type = AUDIO_MIXER_ENUM;
541 error = ioctlf(fp, AUDIO_MIXER_READ, (caddr_t)&mc, p);
542 if (error)
543 return error;
544 idat = 1 << di->rdevmap[mc.un.ord];
545 } else {
546 int k;
547 unsigned int mask;
548 mc.type = AUDIO_MIXER_SET;
549 error = ioctlf(fp, AUDIO_MIXER_READ, (caddr_t)&mc, p);
550 if (error)
551 return error;
552 idat = 0;
553 for(mask = mc.un.mask, k = 0; mask; mask >>= 1, k++)
554 if (mask & 1)
555 idat |= 1 << di->rdevmap[k];
556 }
557 break;
558 case OSS_SOUND_MIXER_READ_DEVMASK:
559 idat = di->devmask;
560 break;
561 case OSS_SOUND_MIXER_READ_RECMASK:
562 idat = di->recmask;
563 break;
564 case OSS_SOUND_MIXER_READ_STEREODEVS:
565 idat = di->stereomask;
566 break;
567 case OSS_SOUND_MIXER_READ_CAPS:
568 idat = di->caps;
569 break;
570 case OSS_SOUND_MIXER_WRITE_RECSRC:
571 if (di->source == -1)
572 return EINVAL;
573 mc.dev = di->source;
574 error = copyin(SCARG(uap, data), &idat, sizeof idat);
575 if (error)
576 return error;
577 if (di->caps & OSS_SOUND_CAP_EXCL_INPUT) {
578 mc.type = AUDIO_MIXER_ENUM;
579 for(i = 0; i < OSS_SOUND_MIXER_NRDEVICES; i++)
580 if (idat & (1 << i))
581 break;
582 if (i >= OSS_SOUND_MIXER_NRDEVICES ||
583 di->devmap[i] == -1)
584 return EINVAL;
585 mc.un.ord = di->devmap[i];
586 } else {
587 mc.type = AUDIO_MIXER_SET;
588 mc.un.mask = 0;
589 for(i = 0; i < OSS_SOUND_MIXER_NRDEVICES; i++) {
590 if (idat & (1 << i)) {
591 if (di->devmap[i] == -1)
592 return EINVAL;
593 mc.un.mask |= 1 << di->devmap[i];
594 }
595 }
596 }
597 return ioctlf(fp, AUDIO_MIXER_WRITE, (caddr_t)&mc, p);
598 default:
599 if (OSS_MIXER_READ(OSS_SOUND_MIXER_FIRST) <= com &&
600 com < OSS_MIXER_READ(OSS_SOUND_MIXER_NRDEVICES)) {
601 n = OSS_GET_DEV(com);
602 if (di->devmap[n] == -1)
603 return EINVAL;
604 mc.dev = di->devmap[n];
605 mc.type = AUDIO_MIXER_VALUE;
606 doread:
607 mc.un.value.num_channels = di->stereomask & (1<<n) ? 2 : 1;
608 error = ioctlf(fp, AUDIO_MIXER_READ, (caddr_t)&mc, p);
609 if (error)
610 return error;
611 if (mc.type != AUDIO_MIXER_VALUE)
612 return EINVAL;
613 if (mc.un.value.num_channels != 2) {
614 l = r = mc.un.value.level[AUDIO_MIXER_LEVEL_MONO];
615 } else {
616 l = mc.un.value.level[AUDIO_MIXER_LEVEL_LEFT];
617 r = mc.un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
618 }
619 l = l * 100 / 255;
620 r = r * 100 / 255;
621 idat = l | (r << 8);
622 break;
623 } else if (OSS_MIXER_WRITE(OSS_SOUND_MIXER_FIRST) <= com &&
624 com < OSS_MIXER_WRITE(OSS_SOUND_MIXER_NRDEVICES)) {
625 n = OSS_GET_DEV(com);
626 if (di->devmap[n] == -1)
627 return EINVAL;
628 error = copyin(SCARG(uap, data), &idat, sizeof idat);
629 if (error)
630 return error;
631 l = (idat & 0xff) * 255 / 100;
632 r = (idat >> 8) * 255 / 100;
633 mc.dev = di->devmap[n];
634 mc.type = AUDIO_MIXER_VALUE;
635 if (di->stereomask & (1<<n)) {
636 mc.un.value.num_channels = 2;
637 mc.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
638 mc.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
639 } else {
640 mc.un.value.num_channels = 1;
641 mc.un.value.level[AUDIO_MIXER_LEVEL_MONO] = (l+r)/2;
642 }
643 error = ioctlf(fp, AUDIO_MIXER_WRITE, (caddr_t)&mc, p);
644 if (error)
645 return error;
646 goto doread;
647 } else
648 return EINVAL;
649 }
650 return copyout(&idat, SCARG(uap, data), sizeof idat);
651 }
652
653 /* XXX hook for sequencer emulation */
654 int
655 oss_ioctl_sequencer(p, uap, retval)
656 register struct proc *p;
657 register struct oss_sys_ioctl_args /* {
658 syscallarg(int) fd;
659 syscallarg(u_long) com;
660 syscallarg(caddr_t) data;
661 } */ *uap;
662 register_t *retval;
663 {
664 register struct file *fp;
665 register struct filedesc *fdp;
666 #if 0
667 u_long com;
668 int idat;
669 int error;
670 #endif
671
672 fdp = p->p_fd;
673 if ((u_int)SCARG(uap, fd) >= fdp->fd_nfiles ||
674 (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL)
675 return (EBADF);
676
677 if ((fp->f_flag & (FREAD | FWRITE)) == 0)
678 return (EBADF);
679
680 #if 0
681 com = SCARG(uap, com);
682 #endif
683 retval[0] = 0;
684
685 return EINVAL;
686 }
687
688 /*
689 * Check that the blocksize is a power of 2 as OSS wants.
690 * If not, set it to be.
691 */
692 static void setblocksize(fp, info, p)
693 struct file *fp;
694 struct audio_info *info;
695 struct proc *p;
696 {
697 struct audio_info set;
698 int s;
699
700 if (info->blocksize & (info->blocksize-1)) {
701 for(s = 32; s < info->blocksize; s <<= 1)
702 ;
703 AUDIO_INITINFO(&set);
704 set.blocksize = s;
705 fp->f_ops->fo_ioctl(fp, AUDIO_SETINFO, (caddr_t)&set, p);
706 fp->f_ops->fo_ioctl(fp, AUDIO_GETINFO, (caddr_t)info, p);
707 }
708 }
709