1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2005-2009 Ariff Abdullah <ariff@FreeBSD.org>
5 * Portions Copyright (c) Ryan Beasley <ryan.beasley@gmail.com> - GSoC 2006
6 * Copyright (c) 1999 Cameron Grant <cg@FreeBSD.org>
7 * All rights reserved.
8 * Copyright (c) 2024-2025 The FreeBSD Foundation
9 *
10 * Portions of this software were developed by Christos Margiolis
11 * <christos@FreeBSD.org> under sponsorship from the FreeBSD Foundation.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #ifdef HAVE_KERNEL_OPTION_HEADERS
36 #include "opt_snd.h"
37 #endif
38
39 #include <dev/sound/pcm/sound.h>
40 #include <dev/sound/pcm/vchan.h>
41 #include <sys/ctype.h>
42 #include <sys/lock.h>
43 #include <sys/rwlock.h>
44 #include <sys/sysent.h>
45
46 #include <vm/vm.h>
47 #include <vm/vm_object.h>
48 #include <vm/vm_page.h>
49 #include <vm/vm_pager.h>
50
51 struct dsp_cdevpriv {
52 struct snddev_info *sc;
53 struct pcm_channel *rdch;
54 struct pcm_channel *wrch;
55 };
56
57 static int dsp_mmap_allow_prot_exec = 0;
58 SYSCTL_INT(_hw_snd, OID_AUTO, compat_linux_mmap, CTLFLAG_RWTUN,
59 &dsp_mmap_allow_prot_exec, 0,
60 "linux mmap compatibility (-1=force disable 0=auto 1=force enable)");
61
62 static int dsp_basename_clone = 1;
63 SYSCTL_INT(_hw_snd, OID_AUTO, basename_clone, CTLFLAG_RWTUN,
64 &dsp_basename_clone, 0,
65 "DSP basename cloning (0: Disable; 1: Enabled)");
66
67 #define DSP_REGISTERED(x) (PCM_REGISTERED(x) && (x)->dsp_dev != NULL)
68
69 #define DSP_F_VALID(x) ((x) & (FREAD | FWRITE))
70 #define DSP_F_DUPLEX(x) (((x) & (FREAD | FWRITE)) == (FREAD | FWRITE))
71 #define DSP_F_SIMPLEX(x) (!DSP_F_DUPLEX(x))
72 #define DSP_F_READ(x) ((x) & FREAD)
73 #define DSP_F_WRITE(x) ((x) & FWRITE)
74
75 #define OLDPCM_IOCTL
76
77 static d_open_t dsp_open;
78 static d_read_t dsp_read;
79 static d_write_t dsp_write;
80 static d_ioctl_t dsp_ioctl;
81 static d_poll_t dsp_poll;
82 static d_mmap_t dsp_mmap;
83 static d_mmap_single_t dsp_mmap_single;
84
85 struct cdevsw dsp_cdevsw = {
86 .d_version = D_VERSION,
87 .d_open = dsp_open,
88 .d_read = dsp_read,
89 .d_write = dsp_write,
90 .d_ioctl = dsp_ioctl,
91 .d_poll = dsp_poll,
92 .d_mmap = dsp_mmap,
93 .d_mmap_single = dsp_mmap_single,
94 .d_name = "dsp",
95 };
96
97 static eventhandler_tag dsp_ehtag = NULL;
98
99 static int dsp_oss_syncgroup(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_syncgroup *group);
100 static int dsp_oss_syncstart(int sg_id);
101 static int dsp_oss_policy(struct pcm_channel *wrch, struct pcm_channel *rdch, int policy);
102 static int dsp_oss_cookedmode(struct pcm_channel *wrch, struct pcm_channel *rdch, int enabled);
103 static int dsp_oss_getchnorder(struct pcm_channel *wrch, struct pcm_channel *rdch, unsigned long long *map);
104 static int dsp_oss_setchnorder(struct pcm_channel *wrch, struct pcm_channel *rdch, unsigned long long *map);
105 static int dsp_oss_getchannelmask(struct pcm_channel *wrch, struct pcm_channel *rdch, int *mask);
106 #ifdef OSSV4_EXPERIMENT
107 static int dsp_oss_getlabel(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_label_t *label);
108 static int dsp_oss_setlabel(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_label_t *label);
109 static int dsp_oss_getsong(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *song);
110 static int dsp_oss_setsong(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *song);
111 static int dsp_oss_setname(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *name);
112 #endif
113
114 int
dsp_make_dev(device_t dev)115 dsp_make_dev(device_t dev)
116 {
117 struct make_dev_args devargs;
118 struct snddev_info *sc;
119 int err, unit;
120
121 sc = device_get_softc(dev);
122 unit = device_get_unit(dev);
123
124 make_dev_args_init(&devargs);
125 devargs.mda_devsw = &dsp_cdevsw;
126 devargs.mda_uid = UID_ROOT;
127 devargs.mda_gid = GID_WHEEL;
128 devargs.mda_mode = 0666;
129 devargs.mda_si_drv1 = sc;
130 err = make_dev_s(&devargs, &sc->dsp_dev, "dsp%d", unit);
131 if (err != 0) {
132 device_printf(dev, "failed to create dsp%d: error %d",
133 unit, err);
134 return (ENXIO);
135 }
136
137 return (0);
138 }
139
140 void
dsp_destroy_dev(device_t dev)141 dsp_destroy_dev(device_t dev)
142 {
143 struct snddev_info *d;
144
145 d = device_get_softc(dev);
146 destroy_dev(d->dsp_dev);
147 }
148
149 static void
dsp_lock_chans(struct dsp_cdevpriv * priv,uint32_t prio)150 dsp_lock_chans(struct dsp_cdevpriv *priv, uint32_t prio)
151 {
152 if (priv->rdch != NULL && DSP_F_READ(prio))
153 CHN_LOCK(priv->rdch);
154 if (priv->wrch != NULL && DSP_F_WRITE(prio))
155 CHN_LOCK(priv->wrch);
156 }
157
158 static void
dsp_unlock_chans(struct dsp_cdevpriv * priv,uint32_t prio)159 dsp_unlock_chans(struct dsp_cdevpriv *priv, uint32_t prio)
160 {
161 if (priv->rdch != NULL && DSP_F_READ(prio))
162 CHN_UNLOCK(priv->rdch);
163 if (priv->wrch != NULL && DSP_F_WRITE(prio))
164 CHN_UNLOCK(priv->wrch);
165 }
166
167 static int
dsp_chn_alloc(struct snddev_info * d,struct pcm_channel ** ch,int direction,int flags,struct thread * td)168 dsp_chn_alloc(struct snddev_info *d, struct pcm_channel **ch, int direction,
169 int flags, struct thread *td)
170 {
171 struct pcm_channel *c;
172 char *comm;
173 pid_t pid;
174 int err;
175 bool vdir_enabled;
176
177 KASSERT(d != NULL && ch != NULL &&
178 (direction == PCMDIR_PLAY || direction == PCMDIR_REC),
179 ("%s(): invalid d=%p ch=%p direction=%d",
180 __func__, d, ch, direction));
181 PCM_BUSYASSERT(d);
182
183 pid = td->td_proc->p_pid;
184 comm = td->td_proc->p_comm;
185
186 vdir_enabled = (direction == PCMDIR_PLAY && d->flags & SD_F_PVCHANS) ||
187 (direction == PCMDIR_REC && d->flags & SD_F_RVCHANS);
188
189 *ch = NULL;
190 CHN_FOREACH(c, d, channels.pcm.primary) {
191 CHN_LOCK(c);
192 if (c->direction != direction) {
193 CHN_UNLOCK(c);
194 continue;
195 }
196 /* Find an available primary channel to use. */
197 if ((c->flags & CHN_F_BUSY) == 0 ||
198 (vdir_enabled && (c->flags & CHN_F_HAS_VCHAN)))
199 break;
200 CHN_UNLOCK(c);
201 }
202 if (c == NULL)
203 return (EBUSY);
204
205 /*
206 * We can have the following cases:
207 * - vchans are enabled, add a new vchan to the primary channel.
208 * - vchans are disabled, use the primary channel directly.
209 */
210 if (vdir_enabled && ((c->flags & CHN_F_BUSY) == 0 ||
211 c->flags & CHN_F_HAS_VCHAN)) {
212 err = vchan_create(c, ch);
213 CHN_UNLOCK(c);
214 if (err != 0)
215 return (err);
216 CHN_LOCK(*ch);
217 } else if ((c->flags & CHN_F_BUSY) == 0) {
218 *ch = c;
219 } else {
220 CHN_UNLOCK(c);
221 return (ENODEV);
222 }
223
224 (*ch)->flags |= CHN_F_BUSY;
225 if (flags & O_NONBLOCK)
226 (*ch)->flags |= CHN_F_NBIO;
227 if (flags & O_EXCL)
228 (*ch)->flags |= CHN_F_EXCLUSIVE;
229 (*ch)->pid = pid;
230 strlcpy((*ch)->comm, (comm != NULL) ? comm : CHN_COMM_UNKNOWN,
231 sizeof((*ch)->comm));
232
233 if ((err = chn_reset(*ch, (*ch)->format, (*ch)->speed)) != 0)
234 return (err);
235 chn_vpc_reset(*ch, SND_VOL_C_PCM, 0);
236
237 CHN_UNLOCK(*ch);
238
239 return (0);
240 }
241
242 static void
dsp_close(void * data)243 dsp_close(void *data)
244 {
245 struct dsp_cdevpriv *priv = data;
246 struct pcm_channel *rdch, *wrch, *parent;
247 struct snddev_info *d;
248 int sg_ids;
249
250 if (priv == NULL)
251 return;
252
253 d = priv->sc;
254 /* At this point pcm_unregister() will destroy all channels anyway. */
255 if (!DSP_REGISTERED(d))
256 goto skip;
257
258 PCM_GIANT_ENTER(d);
259
260 PCM_LOCK(d);
261 PCM_WAIT(d);
262 PCM_ACQUIRE(d);
263
264 rdch = priv->rdch;
265 wrch = priv->wrch;
266
267 if (rdch != NULL)
268 CHN_REMOVE(d, rdch, channels.pcm.opened);
269 if (wrch != NULL)
270 CHN_REMOVE(d, wrch, channels.pcm.opened);
271
272 if (rdch != NULL || wrch != NULL) {
273 PCM_UNLOCK(d);
274 if (rdch != NULL) {
275 /*
276 * The channel itself need not be locked because:
277 * a) Adding a channel to a syncgroup happens only
278 * in dsp_ioctl(), which cannot run concurrently
279 * to dsp_close().
280 * b) The syncmember pointer (sm) is protected by
281 * the global syncgroup list lock.
282 * c) A channel can't just disappear, invalidating
283 * pointers, unless it's closed/dereferenced
284 * first.
285 */
286 PCM_SG_LOCK();
287 sg_ids = chn_syncdestroy(rdch);
288 PCM_SG_UNLOCK();
289 if (sg_ids != 0)
290 free_unr(pcmsg_unrhdr, sg_ids);
291
292 /*
293 * Go through the channel abort/flush path for both
294 * primary and virtual channels to ensure that, in the
295 * case of vchans, the stream is always properly
296 * stopped, and the primary channels do not keep being
297 * interrupted even if all vchans are gone.
298 */
299 CHN_LOCK(rdch);
300 chn_abort(rdch); /* won't sleep */
301 rdch->flags &= ~(CHN_F_RUNNING | CHN_F_MMAP |
302 CHN_F_DEAD | CHN_F_EXCLUSIVE | CHN_F_NBIO);
303 chn_reset(rdch, 0, 0);
304 chn_release(rdch);
305 if (rdch->flags & CHN_F_VIRTUAL) {
306 parent = rdch->parentchannel;
307 CHN_LOCK(parent);
308 CHN_LOCK(rdch);
309 vchan_destroy(rdch);
310 CHN_UNLOCK(parent);
311 }
312 }
313 if (wrch != NULL) {
314 /*
315 * Please see block above.
316 */
317 PCM_SG_LOCK();
318 sg_ids = chn_syncdestroy(wrch);
319 PCM_SG_UNLOCK();
320 if (sg_ids != 0)
321 free_unr(pcmsg_unrhdr, sg_ids);
322
323 CHN_LOCK(wrch);
324 chn_flush(wrch); /* may sleep */
325 wrch->flags &= ~(CHN_F_RUNNING | CHN_F_MMAP |
326 CHN_F_DEAD | CHN_F_EXCLUSIVE | CHN_F_NBIO);
327 chn_reset(wrch, 0, 0);
328 chn_release(wrch);
329 if (wrch->flags & CHN_F_VIRTUAL) {
330 parent = wrch->parentchannel;
331 CHN_LOCK(parent);
332 CHN_LOCK(wrch);
333 vchan_destroy(wrch);
334 CHN_UNLOCK(parent);
335 }
336 }
337 PCM_LOCK(d);
338 }
339
340 PCM_RELEASE(d);
341 PCM_UNLOCK(d);
342
343 PCM_GIANT_LEAVE(d);
344 skip:
345 free(priv, M_DEVBUF);
346 priv = NULL;
347 }
348
349 static int
dsp_open(struct cdev * i_dev,int flags,int mode,struct thread * td)350 dsp_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
351 {
352 struct dsp_cdevpriv *priv;
353 struct pcm_channel *ch;
354 struct snddev_info *d;
355 int error, dir;
356
357 /* Kind of impossible.. */
358 if (i_dev == NULL || td == NULL)
359 return (ENODEV);
360
361 d = i_dev->si_drv1;
362 if (!DSP_REGISTERED(d))
363 return (EBADF);
364
365 if (PCM_CHANCOUNT(d) >= PCM_MAXCHANS)
366 return (ENOMEM);
367
368 priv = malloc(sizeof(*priv), M_DEVBUF, M_WAITOK | M_ZERO);
369 priv->sc = d;
370
371 error = devfs_set_cdevpriv(priv, dsp_close);
372 if (error != 0)
373 return (error);
374
375 PCM_GIANT_ENTER(d);
376
377 /* Lock snddev so nobody else can monkey with it. */
378 PCM_LOCK(d);
379 PCM_WAIT(d);
380
381 error = 0;
382 if (!DSP_F_VALID(flags))
383 error = EINVAL;
384 else if (!DSP_F_DUPLEX(flags) &&
385 ((DSP_F_READ(flags) && d->reccount == 0) ||
386 (DSP_F_WRITE(flags) && d->playcount == 0)))
387 error = ENOTSUP;
388 if (pcm_getflags(d->dev) & SD_F_SIMPLEX) {
389 if (DSP_F_DUPLEX(flags)) {
390 /*
391 * If no channels are opened yet, and we request
392 * DUPLEX, limit to playback only, otherwise open one
393 * channel in a direction that already exists.
394 */
395 if (CHN_EMPTY(d, channels.pcm.opened)) {
396 if (d->playcount > 0)
397 flags &= ~FREAD;
398 else if (d->reccount > 0)
399 flags &= ~FWRITE;
400 } else {
401 ch = CHN_FIRST(d, channels.pcm.opened);
402 if (ch->direction == PCMDIR_PLAY)
403 flags &= ~FREAD;
404 else if (ch->direction == PCMDIR_REC)
405 flags &= ~FWRITE;
406 }
407 } else if (!CHN_EMPTY(d, channels.pcm.opened)) {
408 /*
409 * If we requested SIMPLEX, make sure we do not open a
410 * channel in the opposite direction.
411 */
412 ch = CHN_FIRST(d, channels.pcm.opened);
413 dir = DSP_F_READ(flags) ? PCMDIR_REC : PCMDIR_PLAY;
414 if (ch->direction != dir)
415 error = ENOTSUP;
416 }
417 }
418 if (error != 0) {
419 PCM_UNLOCK(d);
420 PCM_GIANT_EXIT(d);
421 return (error);
422 }
423
424 /*
425 * That is just enough. Acquire and unlock pcm lock so
426 * the other will just have to wait until we finish doing
427 * everything.
428 */
429 PCM_ACQUIRE(d);
430 PCM_UNLOCK(d);
431
432 if (DSP_F_WRITE(flags)) {
433 error = dsp_chn_alloc(d, &priv->wrch, PCMDIR_PLAY, flags, td);
434 if (error != 0) {
435 PCM_RELEASE_QUICK(d);
436 PCM_GIANT_EXIT(d);
437 return (error);
438 }
439 PCM_LOCK(d);
440 CHN_INSERT_HEAD(d, priv->wrch, channels.pcm.opened);
441 PCM_UNLOCK(d);
442 }
443 if (DSP_F_READ(flags)) {
444 error = dsp_chn_alloc(d, &priv->rdch, PCMDIR_REC, flags, td);
445 if (error != 0) {
446 PCM_RELEASE_QUICK(d);
447 PCM_GIANT_EXIT(d);
448 return (error);
449 }
450 PCM_LOCK(d);
451 CHN_INSERT_HEAD(d, priv->rdch, channels.pcm.opened);
452 PCM_UNLOCK(d);
453 }
454
455 PCM_RELEASE_QUICK(d);
456 PCM_GIANT_LEAVE(d);
457
458 return (0);
459 }
460
461 static __inline int
dsp_io_ops(struct dsp_cdevpriv * priv,struct uio * buf)462 dsp_io_ops(struct dsp_cdevpriv *priv, struct uio *buf)
463 {
464 struct snddev_info *d;
465 struct pcm_channel **ch;
466 int (*chn_io)(struct pcm_channel *, struct uio *);
467 int prio, ret;
468 pid_t runpid;
469
470 KASSERT(buf != NULL &&
471 (buf->uio_rw == UIO_READ || buf->uio_rw == UIO_WRITE),
472 ("%s(): io train wreck!", __func__));
473
474 d = priv->sc;
475 if (!DSP_REGISTERED(d))
476 return (EBADF);
477
478 PCM_GIANT_ENTER(d);
479
480 switch (buf->uio_rw) {
481 case UIO_READ:
482 prio = FREAD;
483 ch = &priv->rdch;
484 chn_io = chn_read;
485 break;
486 case UIO_WRITE:
487 prio = FWRITE;
488 ch = &priv->wrch;
489 chn_io = chn_write;
490 break;
491 default:
492 panic("invalid/corrupted uio direction: %d", buf->uio_rw);
493 break;
494 }
495
496 runpid = buf->uio_td->td_proc->p_pid;
497
498 dsp_lock_chans(priv, prio);
499
500 if (*ch == NULL || !((*ch)->flags & CHN_F_BUSY)) {
501 if (priv->rdch != NULL || priv->wrch != NULL)
502 dsp_unlock_chans(priv, prio);
503 PCM_GIANT_EXIT(d);
504 return (EBADF);
505 }
506
507 if (((*ch)->flags & (CHN_F_MMAP | CHN_F_DEAD)) ||
508 (((*ch)->flags & CHN_F_RUNNING) && (*ch)->pid != runpid)) {
509 dsp_unlock_chans(priv, prio);
510 PCM_GIANT_EXIT(d);
511 return (EINVAL);
512 } else if (!((*ch)->flags & CHN_F_RUNNING)) {
513 (*ch)->flags |= CHN_F_RUNNING;
514 (*ch)->pid = runpid;
515 }
516
517 /*
518 * chn_read/write must give up channel lock in order to copy bytes
519 * from/to userland, so up the "in progress" counter to make sure
520 * someone else doesn't come along and muss up the buffer.
521 */
522 ++(*ch)->inprog;
523 ret = chn_io(*ch, buf);
524 --(*ch)->inprog;
525
526 CHN_BROADCAST(&(*ch)->cv);
527
528 dsp_unlock_chans(priv, prio);
529
530 PCM_GIANT_LEAVE(d);
531
532 return (ret);
533 }
534
535 static int
dsp_read(struct cdev * i_dev,struct uio * buf,int flag)536 dsp_read(struct cdev *i_dev, struct uio *buf, int flag)
537 {
538 struct dsp_cdevpriv *priv;
539 int err;
540
541 if ((err = devfs_get_cdevpriv((void **)&priv)) != 0)
542 return (err);
543 return (dsp_io_ops(priv, buf));
544 }
545
546 static int
dsp_write(struct cdev * i_dev,struct uio * buf,int flag)547 dsp_write(struct cdev *i_dev, struct uio *buf, int flag)
548 {
549 struct dsp_cdevpriv *priv;
550 int err;
551
552 if ((err = devfs_get_cdevpriv((void **)&priv)) != 0)
553 return (err);
554 return (dsp_io_ops(priv, buf));
555 }
556
557 static int
dsp_ioctl_channel(struct dsp_cdevpriv * priv,struct pcm_channel * ch,u_long cmd,caddr_t arg)558 dsp_ioctl_channel(struct dsp_cdevpriv *priv, struct pcm_channel *ch,
559 u_long cmd, caddr_t arg)
560 {
561 struct snddev_info *d;
562 struct pcm_channel *rdch, *wrch;
563 int j, left, right, center, mute;
564
565 d = priv->sc;
566 if (!PCM_REGISTERED(d) || !(pcm_getflags(d->dev) & SD_F_VPC))
567 return (-1);
568
569 PCM_UNLOCKASSERT(d);
570
571 j = cmd & 0xff;
572
573 rdch = priv->rdch;
574 wrch = priv->wrch;
575
576 if (ch == NULL) {
577 if (j == SOUND_MIXER_RECLEV && rdch != NULL)
578 ch = rdch;
579 else if (j == SOUND_MIXER_PCM && wrch != NULL)
580 ch = wrch;
581 }
582
583 if (ch == NULL)
584 return (EINVAL);
585
586 CHN_LOCK(ch);
587 if (!(ch->feederflags & (1 << FEEDER_VOLUME))) {
588 CHN_UNLOCK(ch);
589 return (EINVAL);
590 }
591
592 switch (cmd & ~0xff) {
593 case MIXER_WRITE(0):
594 switch (j) {
595 case SOUND_MIXER_MUTE:
596 if (ch->direction == PCMDIR_REC) {
597 chn_setmute_multi(ch, SND_VOL_C_PCM, (*(int *)arg & SOUND_MASK_RECLEV) != 0);
598 } else {
599 chn_setmute_multi(ch, SND_VOL_C_PCM, (*(int *)arg & SOUND_MASK_PCM) != 0);
600 }
601 break;
602 case SOUND_MIXER_PCM:
603 if (ch->direction != PCMDIR_PLAY)
604 break;
605 left = *(int *)arg & 0x7f;
606 right = ((*(int *)arg) >> 8) & 0x7f;
607 center = (left + right) >> 1;
608 chn_setvolume_multi(ch, SND_VOL_C_PCM,
609 left, right, center);
610 break;
611 case SOUND_MIXER_RECLEV:
612 if (ch->direction != PCMDIR_REC)
613 break;
614 left = *(int *)arg & 0x7f;
615 right = ((*(int *)arg) >> 8) & 0x7f;
616 center = (left + right) >> 1;
617 chn_setvolume_multi(ch, SND_VOL_C_PCM,
618 left, right, center);
619 break;
620 default:
621 /* ignore all other mixer writes */
622 break;
623 }
624 break;
625
626 case MIXER_READ(0):
627 switch (j) {
628 case SOUND_MIXER_MUTE:
629 mute = CHN_GETMUTE(ch, SND_VOL_C_PCM, SND_CHN_T_FL) ||
630 CHN_GETMUTE(ch, SND_VOL_C_PCM, SND_CHN_T_FR);
631 if (ch->direction == PCMDIR_REC) {
632 *(int *)arg = mute << SOUND_MIXER_RECLEV;
633 } else {
634 *(int *)arg = mute << SOUND_MIXER_PCM;
635 }
636 break;
637 case SOUND_MIXER_PCM:
638 if (ch->direction != PCMDIR_PLAY)
639 break;
640 *(int *)arg = CHN_GETVOLUME(ch,
641 SND_VOL_C_PCM, SND_CHN_T_FL);
642 *(int *)arg |= CHN_GETVOLUME(ch,
643 SND_VOL_C_PCM, SND_CHN_T_FR) << 8;
644 break;
645 case SOUND_MIXER_RECLEV:
646 if (ch->direction != PCMDIR_REC)
647 break;
648 *(int *)arg = CHN_GETVOLUME(ch,
649 SND_VOL_C_PCM, SND_CHN_T_FL);
650 *(int *)arg |= CHN_GETVOLUME(ch,
651 SND_VOL_C_PCM, SND_CHN_T_FR) << 8;
652 break;
653 case SOUND_MIXER_DEVMASK:
654 case SOUND_MIXER_CAPS:
655 case SOUND_MIXER_STEREODEVS:
656 if (ch->direction == PCMDIR_REC)
657 *(int *)arg = SOUND_MASK_RECLEV;
658 else
659 *(int *)arg = SOUND_MASK_PCM;
660 break;
661 default:
662 *(int *)arg = 0;
663 break;
664 }
665 break;
666
667 default:
668 break;
669 }
670 CHN_UNLOCK(ch);
671 return (0);
672 }
673
674 #ifdef COMPAT_FREEBSD32
675 typedef struct _snd_chan_param32 {
676 uint32_t play_rate;
677 uint32_t rec_rate;
678 uint32_t play_format;
679 uint32_t rec_format;
680 } snd_chan_param32;
681 #define AIOGFMT32 _IOC_NEWTYPE(AIOGFMT, snd_chan_param32)
682 #define AIOSFMT32 _IOC_NEWTYPE(AIOSFMT, snd_chan_param32)
683
684 typedef struct _snd_capabilities32 {
685 uint32_t rate_min, rate_max;
686 uint32_t formats;
687 uint32_t bufsize;
688 uint32_t mixers;
689 uint32_t inputs;
690 uint16_t left, right;
691 } snd_capabilities32;
692 #define AIOGCAP32 _IOC_NEWTYPE(AIOGCAP, snd_capabilities32)
693
694 typedef struct audio_errinfo32
695 {
696 int32_t play_underruns;
697 int32_t rec_overruns;
698 uint32_t play_ptradjust;
699 uint32_t rec_ptradjust;
700 int32_t play_errorcount;
701 int32_t rec_errorcount;
702 int32_t play_lasterror;
703 int32_t rec_lasterror;
704 int32_t play_errorparm;
705 int32_t rec_errorparm;
706 int32_t filler[16];
707 } audio_errinfo32;
708 #define SNDCTL_DSP_GETERROR32 _IOC_NEWTYPE(SNDCTL_DSP_GETERROR, audio_errinfo32)
709 #endif
710
711 static int
dsp_ioctl(struct cdev * i_dev,u_long cmd,caddr_t arg,int mode,struct thread * td)712 dsp_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode,
713 struct thread *td)
714 {
715 struct dsp_cdevpriv *priv;
716 struct pcm_channel *chn, *rdch, *wrch;
717 struct snddev_info *d;
718 u_long xcmd;
719 int *arg_i, ret, tmp, err;
720
721 if ((err = devfs_get_cdevpriv((void **)&priv)) != 0)
722 return (err);
723
724 d = priv->sc;
725 if (!DSP_REGISTERED(d))
726 return (EBADF);
727
728 PCM_GIANT_ENTER(d);
729
730 arg_i = (int *)arg;
731 ret = 0;
732 xcmd = 0;
733 chn = NULL;
734
735 if (IOCGROUP(cmd) == 'M') {
736 if (cmd == OSS_GETVERSION) {
737 *arg_i = SOUND_VERSION;
738 PCM_GIANT_EXIT(d);
739 return (0);
740 }
741 ret = dsp_ioctl_channel(priv, NULL, cmd, arg);
742 if (ret != -1) {
743 PCM_GIANT_EXIT(d);
744 return (ret);
745 }
746
747 if (d->mixer_dev != NULL) {
748 PCM_ACQUIRE_QUICK(d);
749 ret = mixer_ioctl_cmd(d->mixer_dev, cmd, arg, -1, td,
750 MIXER_CMD_DIRECT);
751 PCM_RELEASE_QUICK(d);
752 } else
753 ret = EBADF;
754
755 PCM_GIANT_EXIT(d);
756
757 return (ret);
758 }
759
760 /*
761 * Certain ioctls may be made on any type of device (audio, mixer,
762 * and MIDI). Handle those special cases here.
763 */
764 if (IOCGROUP(cmd) == 'X') {
765 PCM_ACQUIRE_QUICK(d);
766 switch(cmd) {
767 case SNDCTL_SYSINFO:
768 sound_oss_sysinfo((oss_sysinfo *)arg);
769 break;
770 case SNDCTL_CARDINFO:
771 ret = sound_oss_card_info((oss_card_info *)arg);
772 break;
773 case SNDCTL_AUDIOINFO:
774 ret = dsp_oss_audioinfo(i_dev, (oss_audioinfo *)arg,
775 false);
776 break;
777 case SNDCTL_AUDIOINFO_EX:
778 ret = dsp_oss_audioinfo(i_dev, (oss_audioinfo *)arg,
779 true);
780 break;
781 case SNDCTL_ENGINEINFO:
782 ret = dsp_oss_engineinfo(i_dev, (oss_audioinfo *)arg);
783 break;
784 case SNDCTL_MIXERINFO:
785 ret = mixer_oss_mixerinfo(i_dev, (oss_mixerinfo *)arg);
786 break;
787 default:
788 ret = EINVAL;
789 }
790 PCM_RELEASE_QUICK(d);
791 PCM_GIANT_EXIT(d);
792 return (ret);
793 }
794
795 rdch = priv->rdch;
796 wrch = priv->wrch;
797
798 if (wrch != NULL && (wrch->flags & CHN_F_DEAD))
799 wrch = NULL;
800 if (rdch != NULL && (rdch->flags & CHN_F_DEAD))
801 rdch = NULL;
802
803 if (wrch == NULL && rdch == NULL) {
804 PCM_GIANT_EXIT(d);
805 return (EINVAL);
806 }
807
808 switch(cmd) {
809 #ifdef OLDPCM_IOCTL
810 /*
811 * we start with the new ioctl interface.
812 */
813 case AIONWRITE: /* how many bytes can write ? */
814 if (wrch) {
815 CHN_LOCK(wrch);
816 /*
817 if (wrch && wrch->bufhard.dl)
818 while (chn_wrfeed(wrch) == 0);
819 */
820 *arg_i = sndbuf_getfree(wrch->bufsoft);
821 CHN_UNLOCK(wrch);
822 } else {
823 *arg_i = 0;
824 ret = EINVAL;
825 }
826 break;
827
828 case AIOSSIZE: /* set the current blocksize */
829 {
830 struct snd_size *p = (struct snd_size *)arg;
831
832 p->play_size = 0;
833 p->rec_size = 0;
834 PCM_ACQUIRE_QUICK(d);
835 if (wrch) {
836 CHN_LOCK(wrch);
837 chn_setblocksize(wrch, 2, p->play_size);
838 p->play_size = sndbuf_getblksz(wrch->bufsoft);
839 CHN_UNLOCK(wrch);
840 }
841 if (rdch) {
842 CHN_LOCK(rdch);
843 chn_setblocksize(rdch, 2, p->rec_size);
844 p->rec_size = sndbuf_getblksz(rdch->bufsoft);
845 CHN_UNLOCK(rdch);
846 }
847 PCM_RELEASE_QUICK(d);
848 }
849 break;
850 case AIOGSIZE: /* get the current blocksize */
851 {
852 struct snd_size *p = (struct snd_size *)arg;
853
854 if (wrch) {
855 CHN_LOCK(wrch);
856 p->play_size = sndbuf_getblksz(wrch->bufsoft);
857 CHN_UNLOCK(wrch);
858 }
859 if (rdch) {
860 CHN_LOCK(rdch);
861 p->rec_size = sndbuf_getblksz(rdch->bufsoft);
862 CHN_UNLOCK(rdch);
863 }
864 }
865 break;
866
867 case AIOSFMT:
868 case AIOGFMT:
869 #ifdef COMPAT_FREEBSD32
870 case AIOSFMT32:
871 case AIOGFMT32:
872 #endif
873 {
874 snd_chan_param *p = (snd_chan_param *)arg;
875
876 #ifdef COMPAT_FREEBSD32
877 snd_chan_param32 *p32 = (snd_chan_param32 *)arg;
878 snd_chan_param param;
879
880 if (cmd == AIOSFMT32) {
881 p = ¶m;
882 p->play_rate = p32->play_rate;
883 p->rec_rate = p32->rec_rate;
884 p->play_format = p32->play_format;
885 p->rec_format = p32->rec_format;
886 }
887 #endif
888 if (cmd == AIOSFMT &&
889 ((p->play_format != 0 && p->play_rate == 0) ||
890 (p->rec_format != 0 && p->rec_rate == 0))) {
891 ret = EINVAL;
892 break;
893 }
894 PCM_ACQUIRE_QUICK(d);
895 if (wrch) {
896 CHN_LOCK(wrch);
897 if (cmd == AIOSFMT && p->play_format != 0) {
898 chn_setformat(wrch,
899 SND_FORMAT(p->play_format,
900 AFMT_CHANNEL(wrch->format),
901 AFMT_EXTCHANNEL(wrch->format)));
902 chn_setspeed(wrch, p->play_rate);
903 }
904 p->play_rate = wrch->speed;
905 p->play_format = AFMT_ENCODING(wrch->format);
906 CHN_UNLOCK(wrch);
907 } else {
908 p->play_rate = 0;
909 p->play_format = 0;
910 }
911 if (rdch) {
912 CHN_LOCK(rdch);
913 if (cmd == AIOSFMT && p->rec_format != 0) {
914 chn_setformat(rdch,
915 SND_FORMAT(p->rec_format,
916 AFMT_CHANNEL(rdch->format),
917 AFMT_EXTCHANNEL(rdch->format)));
918 chn_setspeed(rdch, p->rec_rate);
919 }
920 p->rec_rate = rdch->speed;
921 p->rec_format = AFMT_ENCODING(rdch->format);
922 CHN_UNLOCK(rdch);
923 } else {
924 p->rec_rate = 0;
925 p->rec_format = 0;
926 }
927 PCM_RELEASE_QUICK(d);
928 #ifdef COMPAT_FREEBSD32
929 if (cmd == AIOSFMT32 || cmd == AIOGFMT32) {
930 p32->play_rate = p->play_rate;
931 p32->rec_rate = p->rec_rate;
932 p32->play_format = p->play_format;
933 p32->rec_format = p->rec_format;
934 }
935 #endif
936 }
937 break;
938
939 case AIOGCAP: /* get capabilities */
940 #ifdef COMPAT_FREEBSD32
941 case AIOGCAP32:
942 #endif
943 {
944 snd_capabilities *p = (snd_capabilities *)arg;
945 struct pcmchan_caps *pcaps = NULL, *rcaps = NULL;
946 struct cdev *pdev;
947 #ifdef COMPAT_FREEBSD32
948 snd_capabilities32 *p32 = (snd_capabilities32 *)arg;
949 snd_capabilities capabilities;
950
951 if (cmd == AIOGCAP32) {
952 p = &capabilities;
953 p->rate_min = p32->rate_min;
954 p->rate_max = p32->rate_max;
955 p->formats = p32->formats;
956 p->bufsize = p32->bufsize;
957 p->mixers = p32->mixers;
958 p->inputs = p32->inputs;
959 p->left = p32->left;
960 p->right = p32->right;
961 }
962 #endif
963 PCM_LOCK(d);
964 if (rdch) {
965 CHN_LOCK(rdch);
966 rcaps = chn_getcaps(rdch);
967 }
968 if (wrch) {
969 CHN_LOCK(wrch);
970 pcaps = chn_getcaps(wrch);
971 }
972 p->rate_min = max(rcaps? rcaps->minspeed : 0,
973 pcaps? pcaps->minspeed : 0);
974 p->rate_max = min(rcaps? rcaps->maxspeed : 1000000,
975 pcaps? pcaps->maxspeed : 1000000);
976 p->bufsize = min(rdch? sndbuf_getsize(rdch->bufsoft) : 1000000,
977 wrch? sndbuf_getsize(wrch->bufsoft) : 1000000);
978 /* XXX bad on sb16 */
979 p->formats = (rdch? chn_getformats(rdch) : 0xffffffff) &
980 (wrch? chn_getformats(wrch) : 0xffffffff);
981 if (rdch && wrch) {
982 p->formats |=
983 (pcm_getflags(d->dev) & SD_F_SIMPLEX) ? 0 :
984 AFMT_FULLDUPLEX;
985 }
986 pdev = d->mixer_dev;
987 p->mixers = 1; /* default: one mixer */
988 p->inputs = pdev->si_drv1? mix_getdevs(pdev->si_drv1) : 0;
989 p->left = p->right = 100;
990 if (wrch)
991 CHN_UNLOCK(wrch);
992 if (rdch)
993 CHN_UNLOCK(rdch);
994 PCM_UNLOCK(d);
995 #ifdef COMPAT_FREEBSD32
996 if (cmd == AIOGCAP32) {
997 p32->rate_min = p->rate_min;
998 p32->rate_max = p->rate_max;
999 p32->formats = p->formats;
1000 p32->bufsize = p->bufsize;
1001 p32->mixers = p->mixers;
1002 p32->inputs = p->inputs;
1003 p32->left = p->left;
1004 p32->right = p->right;
1005 }
1006 #endif
1007 }
1008 break;
1009
1010 case AIOSTOP:
1011 if (*arg_i == AIOSYNC_PLAY && wrch) {
1012 CHN_LOCK(wrch);
1013 *arg_i = chn_abort(wrch);
1014 CHN_UNLOCK(wrch);
1015 } else if (*arg_i == AIOSYNC_CAPTURE && rdch) {
1016 CHN_LOCK(rdch);
1017 *arg_i = chn_abort(rdch);
1018 CHN_UNLOCK(rdch);
1019 } else {
1020 printf("AIOSTOP: bad channel 0x%x\n", *arg_i);
1021 *arg_i = 0;
1022 }
1023 break;
1024
1025 case AIOSYNC:
1026 printf("AIOSYNC chan 0x%03lx pos %lu unimplemented\n",
1027 ((snd_sync_parm *)arg)->chan, ((snd_sync_parm *)arg)->pos);
1028 break;
1029 #endif
1030 /*
1031 * here follow the standard ioctls (filio.h etc.)
1032 */
1033 case FIONREAD: /* get # bytes to read */
1034 if (rdch) {
1035 CHN_LOCK(rdch);
1036 /* if (rdch && rdch->bufhard.dl)
1037 while (chn_rdfeed(rdch) == 0);
1038 */
1039 *arg_i = sndbuf_getready(rdch->bufsoft);
1040 CHN_UNLOCK(rdch);
1041 } else {
1042 *arg_i = 0;
1043 ret = EINVAL;
1044 }
1045 break;
1046
1047 case FIOASYNC: /*set/clear async i/o */
1048 DEB( printf("FIOASYNC\n") ; )
1049 break;
1050
1051 case SNDCTL_DSP_NONBLOCK: /* set non-blocking i/o */
1052 case FIONBIO: /* set/clear non-blocking i/o */
1053 if (rdch) {
1054 CHN_LOCK(rdch);
1055 if (cmd == SNDCTL_DSP_NONBLOCK || *arg_i)
1056 rdch->flags |= CHN_F_NBIO;
1057 else
1058 rdch->flags &= ~CHN_F_NBIO;
1059 CHN_UNLOCK(rdch);
1060 }
1061 if (wrch) {
1062 CHN_LOCK(wrch);
1063 if (cmd == SNDCTL_DSP_NONBLOCK || *arg_i)
1064 wrch->flags |= CHN_F_NBIO;
1065 else
1066 wrch->flags &= ~CHN_F_NBIO;
1067 CHN_UNLOCK(wrch);
1068 }
1069 break;
1070
1071 /*
1072 * Finally, here is the linux-compatible ioctl interface
1073 */
1074 #define THE_REAL_SNDCTL_DSP_GETBLKSIZE _IOWR('P', 4, int)
1075 case THE_REAL_SNDCTL_DSP_GETBLKSIZE:
1076 case SNDCTL_DSP_GETBLKSIZE:
1077 chn = wrch ? wrch : rdch;
1078 if (chn) {
1079 CHN_LOCK(chn);
1080 *arg_i = sndbuf_getblksz(chn->bufsoft);
1081 CHN_UNLOCK(chn);
1082 } else {
1083 *arg_i = 0;
1084 ret = EINVAL;
1085 }
1086 break;
1087
1088 case SNDCTL_DSP_SETBLKSIZE:
1089 RANGE(*arg_i, 16, 65536);
1090 PCM_ACQUIRE_QUICK(d);
1091 if (wrch) {
1092 CHN_LOCK(wrch);
1093 chn_setblocksize(wrch, 2, *arg_i);
1094 CHN_UNLOCK(wrch);
1095 }
1096 if (rdch) {
1097 CHN_LOCK(rdch);
1098 chn_setblocksize(rdch, 2, *arg_i);
1099 CHN_UNLOCK(rdch);
1100 }
1101 PCM_RELEASE_QUICK(d);
1102 break;
1103
1104 case SNDCTL_DSP_RESET:
1105 DEB(printf("dsp reset\n"));
1106 if (wrch) {
1107 CHN_LOCK(wrch);
1108 chn_abort(wrch);
1109 chn_resetbuf(wrch);
1110 CHN_UNLOCK(wrch);
1111 }
1112 if (rdch) {
1113 CHN_LOCK(rdch);
1114 chn_abort(rdch);
1115 chn_resetbuf(rdch);
1116 CHN_UNLOCK(rdch);
1117 }
1118 break;
1119
1120 case SNDCTL_DSP_SYNC:
1121 DEB(printf("dsp sync\n"));
1122 /* chn_sync may sleep */
1123 if (wrch) {
1124 CHN_LOCK(wrch);
1125 chn_sync(wrch, 0);
1126 CHN_UNLOCK(wrch);
1127 }
1128 break;
1129
1130 case SNDCTL_DSP_SPEED:
1131 /* chn_setspeed may sleep */
1132 tmp = 0;
1133 PCM_ACQUIRE_QUICK(d);
1134 if (wrch) {
1135 CHN_LOCK(wrch);
1136 ret = chn_setspeed(wrch, *arg_i);
1137 tmp = wrch->speed;
1138 CHN_UNLOCK(wrch);
1139 }
1140 if (rdch && ret == 0) {
1141 CHN_LOCK(rdch);
1142 ret = chn_setspeed(rdch, *arg_i);
1143 if (tmp == 0)
1144 tmp = rdch->speed;
1145 CHN_UNLOCK(rdch);
1146 }
1147 PCM_RELEASE_QUICK(d);
1148 *arg_i = tmp;
1149 break;
1150
1151 case SOUND_PCM_READ_RATE:
1152 chn = wrch ? wrch : rdch;
1153 if (chn) {
1154 CHN_LOCK(chn);
1155 *arg_i = chn->speed;
1156 CHN_UNLOCK(chn);
1157 } else {
1158 *arg_i = 0;
1159 ret = EINVAL;
1160 }
1161 break;
1162
1163 case SNDCTL_DSP_STEREO:
1164 tmp = -1;
1165 *arg_i = (*arg_i)? 2 : 1;
1166 PCM_ACQUIRE_QUICK(d);
1167 if (wrch) {
1168 CHN_LOCK(wrch);
1169 ret = chn_setformat(wrch,
1170 SND_FORMAT(wrch->format, *arg_i, 0));
1171 tmp = (AFMT_CHANNEL(wrch->format) > 1)? 1 : 0;
1172 CHN_UNLOCK(wrch);
1173 }
1174 if (rdch && ret == 0) {
1175 CHN_LOCK(rdch);
1176 ret = chn_setformat(rdch,
1177 SND_FORMAT(rdch->format, *arg_i, 0));
1178 if (tmp == -1)
1179 tmp = (AFMT_CHANNEL(rdch->format) > 1)? 1 : 0;
1180 CHN_UNLOCK(rdch);
1181 }
1182 PCM_RELEASE_QUICK(d);
1183 *arg_i = tmp;
1184 break;
1185
1186 case SOUND_PCM_WRITE_CHANNELS:
1187 /* case SNDCTL_DSP_CHANNELS: ( == SOUND_PCM_WRITE_CHANNELS) */
1188 if (*arg_i < 0 || *arg_i > AFMT_CHANNEL_MAX) {
1189 *arg_i = 0;
1190 ret = EINVAL;
1191 break;
1192 }
1193 if (*arg_i != 0) {
1194 uint32_t ext = 0;
1195
1196 tmp = 0;
1197 /*
1198 * Map channel number to surround sound formats.
1199 * Devices that need bitperfect mode to operate
1200 * (e.g. more than SND_CHN_MAX channels) are not
1201 * subject to any mapping.
1202 */
1203 if (!(pcm_getflags(d->dev) & SD_F_BITPERFECT)) {
1204 struct pcmchan_matrix *m;
1205
1206 if (*arg_i > SND_CHN_MAX)
1207 *arg_i = SND_CHN_MAX;
1208
1209 m = feeder_matrix_default_channel_map(*arg_i);
1210 if (m != NULL)
1211 ext = m->ext;
1212 }
1213
1214 PCM_ACQUIRE_QUICK(d);
1215 if (wrch) {
1216 CHN_LOCK(wrch);
1217 ret = chn_setformat(wrch,
1218 SND_FORMAT(wrch->format, *arg_i, ext));
1219 tmp = AFMT_CHANNEL(wrch->format);
1220 CHN_UNLOCK(wrch);
1221 }
1222 if (rdch && ret == 0) {
1223 CHN_LOCK(rdch);
1224 ret = chn_setformat(rdch,
1225 SND_FORMAT(rdch->format, *arg_i, ext));
1226 if (tmp == 0)
1227 tmp = AFMT_CHANNEL(rdch->format);
1228 CHN_UNLOCK(rdch);
1229 }
1230 PCM_RELEASE_QUICK(d);
1231 *arg_i = tmp;
1232 } else {
1233 chn = wrch ? wrch : rdch;
1234 CHN_LOCK(chn);
1235 *arg_i = AFMT_CHANNEL(chn->format);
1236 CHN_UNLOCK(chn);
1237 }
1238 break;
1239
1240 case SOUND_PCM_READ_CHANNELS:
1241 chn = wrch ? wrch : rdch;
1242 if (chn) {
1243 CHN_LOCK(chn);
1244 *arg_i = AFMT_CHANNEL(chn->format);
1245 CHN_UNLOCK(chn);
1246 } else {
1247 *arg_i = 0;
1248 ret = EINVAL;
1249 }
1250 break;
1251
1252 case SNDCTL_DSP_GETFMTS: /* returns a mask of supported fmts */
1253 chn = wrch ? wrch : rdch;
1254 if (chn) {
1255 CHN_LOCK(chn);
1256 *arg_i = chn_getformats(chn);
1257 CHN_UNLOCK(chn);
1258 } else {
1259 *arg_i = 0;
1260 ret = EINVAL;
1261 }
1262 break;
1263
1264 case SNDCTL_DSP_SETFMT: /* sets _one_ format */
1265 if (*arg_i != AFMT_QUERY) {
1266 tmp = 0;
1267 PCM_ACQUIRE_QUICK(d);
1268 if (wrch) {
1269 CHN_LOCK(wrch);
1270 ret = chn_setformat(wrch, SND_FORMAT(*arg_i,
1271 AFMT_CHANNEL(wrch->format),
1272 AFMT_EXTCHANNEL(wrch->format)));
1273 tmp = wrch->format;
1274 CHN_UNLOCK(wrch);
1275 }
1276 if (rdch && ret == 0) {
1277 CHN_LOCK(rdch);
1278 ret = chn_setformat(rdch, SND_FORMAT(*arg_i,
1279 AFMT_CHANNEL(rdch->format),
1280 AFMT_EXTCHANNEL(rdch->format)));
1281 if (tmp == 0)
1282 tmp = rdch->format;
1283 CHN_UNLOCK(rdch);
1284 }
1285 PCM_RELEASE_QUICK(d);
1286 *arg_i = AFMT_ENCODING(tmp);
1287 } else {
1288 chn = wrch ? wrch : rdch;
1289 CHN_LOCK(chn);
1290 *arg_i = AFMT_ENCODING(chn->format);
1291 CHN_UNLOCK(chn);
1292 }
1293 break;
1294
1295 case SNDCTL_DSP_SETFRAGMENT:
1296 DEB(printf("SNDCTL_DSP_SETFRAGMENT 0x%08x\n", *(int *)arg));
1297 {
1298 uint32_t fragln = (*arg_i) & 0x0000ffff;
1299 uint32_t maxfrags = ((*arg_i) & 0xffff0000) >> 16;
1300 uint32_t fragsz;
1301 uint32_t r_maxfrags, r_fragsz;
1302
1303 RANGE(fragln, 4, 16);
1304 fragsz = 1 << fragln;
1305
1306 if (maxfrags == 0)
1307 maxfrags = CHN_2NDBUFMAXSIZE / fragsz;
1308 if (maxfrags < 2)
1309 maxfrags = 2;
1310 if (maxfrags * fragsz > CHN_2NDBUFMAXSIZE)
1311 maxfrags = CHN_2NDBUFMAXSIZE / fragsz;
1312
1313 DEB(printf("SNDCTL_DSP_SETFRAGMENT %d frags, %d sz\n", maxfrags, fragsz));
1314 PCM_ACQUIRE_QUICK(d);
1315 if (rdch) {
1316 CHN_LOCK(rdch);
1317 ret = chn_setblocksize(rdch, maxfrags, fragsz);
1318 r_maxfrags = sndbuf_getblkcnt(rdch->bufsoft);
1319 r_fragsz = sndbuf_getblksz(rdch->bufsoft);
1320 CHN_UNLOCK(rdch);
1321 } else {
1322 r_maxfrags = maxfrags;
1323 r_fragsz = fragsz;
1324 }
1325 if (wrch && ret == 0) {
1326 CHN_LOCK(wrch);
1327 ret = chn_setblocksize(wrch, maxfrags, fragsz);
1328 maxfrags = sndbuf_getblkcnt(wrch->bufsoft);
1329 fragsz = sndbuf_getblksz(wrch->bufsoft);
1330 CHN_UNLOCK(wrch);
1331 } else { /* use whatever came from the read channel */
1332 maxfrags = r_maxfrags;
1333 fragsz = r_fragsz;
1334 }
1335 PCM_RELEASE_QUICK(d);
1336
1337 fragln = 0;
1338 while (fragsz > 1) {
1339 fragln++;
1340 fragsz >>= 1;
1341 }
1342 *arg_i = (maxfrags << 16) | fragln;
1343 }
1344 break;
1345
1346 case SNDCTL_DSP_GETISPACE:
1347 /* return the size of data available in the input queue */
1348 {
1349 audio_buf_info *a = (audio_buf_info *)arg;
1350 if (rdch) {
1351 struct snd_dbuf *bs = rdch->bufsoft;
1352
1353 CHN_LOCK(rdch);
1354 a->bytes = sndbuf_getready(bs);
1355 a->fragments = a->bytes / sndbuf_getblksz(bs);
1356 a->fragstotal = sndbuf_getblkcnt(bs);
1357 a->fragsize = sndbuf_getblksz(bs);
1358 CHN_UNLOCK(rdch);
1359 } else
1360 ret = EINVAL;
1361 }
1362 break;
1363
1364 case SNDCTL_DSP_GETOSPACE:
1365 /* return space available in the output queue */
1366 {
1367 audio_buf_info *a = (audio_buf_info *)arg;
1368 if (wrch) {
1369 struct snd_dbuf *bs = wrch->bufsoft;
1370
1371 CHN_LOCK(wrch);
1372 a->bytes = sndbuf_getfree(bs);
1373 a->fragments = a->bytes / sndbuf_getblksz(bs);
1374 a->fragstotal = sndbuf_getblkcnt(bs);
1375 a->fragsize = sndbuf_getblksz(bs);
1376 CHN_UNLOCK(wrch);
1377 } else
1378 ret = EINVAL;
1379 }
1380 break;
1381
1382 case SNDCTL_DSP_GETIPTR:
1383 {
1384 count_info *a = (count_info *)arg;
1385 if (rdch) {
1386 struct snd_dbuf *bs = rdch->bufsoft;
1387
1388 CHN_LOCK(rdch);
1389 a->bytes = sndbuf_gettotal(bs);
1390 a->blocks = sndbuf_getblocks(bs) - rdch->blocks;
1391 a->ptr = sndbuf_getfreeptr(bs);
1392 rdch->blocks = sndbuf_getblocks(bs);
1393 CHN_UNLOCK(rdch);
1394 } else
1395 ret = EINVAL;
1396 }
1397 break;
1398
1399 case SNDCTL_DSP_GETOPTR:
1400 {
1401 count_info *a = (count_info *)arg;
1402 if (wrch) {
1403 struct snd_dbuf *bs = wrch->bufsoft;
1404
1405 CHN_LOCK(wrch);
1406 a->bytes = sndbuf_gettotal(bs);
1407 a->blocks = sndbuf_getblocks(bs) - wrch->blocks;
1408 a->ptr = sndbuf_getreadyptr(bs);
1409 wrch->blocks = sndbuf_getblocks(bs);
1410 CHN_UNLOCK(wrch);
1411 } else
1412 ret = EINVAL;
1413 }
1414 break;
1415
1416 case SNDCTL_DSP_GETCAPS:
1417 PCM_LOCK(d);
1418 *arg_i = PCM_CAP_REALTIME | PCM_CAP_MMAP | PCM_CAP_TRIGGER;
1419 if (rdch && wrch && !(pcm_getflags(d->dev) & SD_F_SIMPLEX))
1420 *arg_i |= PCM_CAP_DUPLEX;
1421 if (rdch && (rdch->flags & CHN_F_VIRTUAL) != 0)
1422 *arg_i |= PCM_CAP_VIRTUAL;
1423 if (wrch && (wrch->flags & CHN_F_VIRTUAL) != 0)
1424 *arg_i |= PCM_CAP_VIRTUAL;
1425 PCM_UNLOCK(d);
1426 break;
1427
1428 case SOUND_PCM_READ_BITS:
1429 chn = wrch ? wrch : rdch;
1430 if (chn) {
1431 CHN_LOCK(chn);
1432 if (chn->format & AFMT_8BIT)
1433 *arg_i = 8;
1434 else if (chn->format & AFMT_16BIT)
1435 *arg_i = 16;
1436 else if (chn->format & AFMT_24BIT)
1437 *arg_i = 24;
1438 else if (chn->format & AFMT_32BIT)
1439 *arg_i = 32;
1440 else
1441 ret = EINVAL;
1442 CHN_UNLOCK(chn);
1443 } else {
1444 *arg_i = 0;
1445 ret = EINVAL;
1446 }
1447 break;
1448
1449 case SNDCTL_DSP_SETTRIGGER:
1450 if (rdch) {
1451 CHN_LOCK(rdch);
1452 rdch->flags &= ~CHN_F_NOTRIGGER;
1453 if (*arg_i & PCM_ENABLE_INPUT)
1454 chn_start(rdch, 1);
1455 else {
1456 chn_abort(rdch);
1457 chn_resetbuf(rdch);
1458 rdch->flags |= CHN_F_NOTRIGGER;
1459 }
1460 CHN_UNLOCK(rdch);
1461 }
1462 if (wrch) {
1463 CHN_LOCK(wrch);
1464 wrch->flags &= ~CHN_F_NOTRIGGER;
1465 if (*arg_i & PCM_ENABLE_OUTPUT)
1466 chn_start(wrch, 1);
1467 else {
1468 chn_abort(wrch);
1469 chn_resetbuf(wrch);
1470 wrch->flags |= CHN_F_NOTRIGGER;
1471 }
1472 CHN_UNLOCK(wrch);
1473 }
1474 break;
1475
1476 case SNDCTL_DSP_GETTRIGGER:
1477 *arg_i = 0;
1478 if (wrch) {
1479 CHN_LOCK(wrch);
1480 if (wrch->flags & CHN_F_TRIGGERED)
1481 *arg_i |= PCM_ENABLE_OUTPUT;
1482 CHN_UNLOCK(wrch);
1483 }
1484 if (rdch) {
1485 CHN_LOCK(rdch);
1486 if (rdch->flags & CHN_F_TRIGGERED)
1487 *arg_i |= PCM_ENABLE_INPUT;
1488 CHN_UNLOCK(rdch);
1489 }
1490 break;
1491
1492 case SNDCTL_DSP_GETODELAY:
1493 if (wrch) {
1494 struct snd_dbuf *bs = wrch->bufsoft;
1495
1496 CHN_LOCK(wrch);
1497 *arg_i = sndbuf_getready(bs);
1498 CHN_UNLOCK(wrch);
1499 } else
1500 ret = EINVAL;
1501 break;
1502
1503 case SNDCTL_DSP_POST:
1504 if (wrch) {
1505 CHN_LOCK(wrch);
1506 wrch->flags &= ~CHN_F_NOTRIGGER;
1507 chn_start(wrch, 1);
1508 CHN_UNLOCK(wrch);
1509 }
1510 break;
1511
1512 case SNDCTL_DSP_SETDUPLEX:
1513 /*
1514 * switch to full-duplex mode if card is in half-duplex
1515 * mode and is able to work in full-duplex mode
1516 */
1517 PCM_LOCK(d);
1518 if (rdch && wrch && (pcm_getflags(d->dev) & SD_F_SIMPLEX))
1519 pcm_setflags(d->dev, pcm_getflags(d->dev)^SD_F_SIMPLEX);
1520 PCM_UNLOCK(d);
1521 break;
1522
1523 /*
1524 * The following four ioctls are simple wrappers around mixer_ioctl
1525 * with no further processing. xcmd is short for "translated
1526 * command".
1527 */
1528 case SNDCTL_DSP_GETRECVOL:
1529 if (xcmd == 0) {
1530 xcmd = SOUND_MIXER_READ_RECLEV;
1531 chn = rdch;
1532 }
1533 /* FALLTHROUGH */
1534 case SNDCTL_DSP_SETRECVOL:
1535 if (xcmd == 0) {
1536 xcmd = SOUND_MIXER_WRITE_RECLEV;
1537 chn = rdch;
1538 }
1539 /* FALLTHROUGH */
1540 case SNDCTL_DSP_GETPLAYVOL:
1541 if (xcmd == 0) {
1542 xcmd = SOUND_MIXER_READ_PCM;
1543 chn = wrch;
1544 }
1545 /* FALLTHROUGH */
1546 case SNDCTL_DSP_SETPLAYVOL:
1547 if (xcmd == 0) {
1548 xcmd = SOUND_MIXER_WRITE_PCM;
1549 chn = wrch;
1550 }
1551
1552 ret = dsp_ioctl_channel(priv, chn, xcmd, arg);
1553 if (ret != -1) {
1554 PCM_GIANT_EXIT(d);
1555 return (ret);
1556 }
1557
1558 if (d->mixer_dev != NULL) {
1559 PCM_ACQUIRE_QUICK(d);
1560 ret = mixer_ioctl_cmd(d->mixer_dev, xcmd, arg, -1, td,
1561 MIXER_CMD_DIRECT);
1562 PCM_RELEASE_QUICK(d);
1563 } else
1564 ret = ENOTSUP;
1565
1566 break;
1567
1568 case SNDCTL_DSP_GET_RECSRC_NAMES:
1569 case SNDCTL_DSP_GET_RECSRC:
1570 case SNDCTL_DSP_SET_RECSRC:
1571 if (d->mixer_dev != NULL) {
1572 PCM_ACQUIRE_QUICK(d);
1573 ret = mixer_ioctl_cmd(d->mixer_dev, cmd, arg, -1, td,
1574 MIXER_CMD_DIRECT);
1575 PCM_RELEASE_QUICK(d);
1576 } else
1577 ret = ENOTSUP;
1578 break;
1579
1580 /*
1581 * The following 3 ioctls aren't very useful at the moment. For
1582 * now, only a single channel is associated with a cdev (/dev/dspN
1583 * instance), so there's only a single output routing to use (i.e.,
1584 * the wrch bound to this cdev).
1585 */
1586 case SNDCTL_DSP_GET_PLAYTGT_NAMES:
1587 {
1588 oss_mixer_enuminfo *ei;
1589 ei = (oss_mixer_enuminfo *)arg;
1590 ei->dev = 0;
1591 ei->ctrl = 0;
1592 ei->version = 0; /* static for now */
1593 ei->strindex[0] = 0;
1594
1595 if (wrch != NULL) {
1596 ei->nvalues = 1;
1597 strlcpy(ei->strings, wrch->name,
1598 sizeof(ei->strings));
1599 } else {
1600 ei->nvalues = 0;
1601 ei->strings[0] = '\0';
1602 }
1603 }
1604 break;
1605 case SNDCTL_DSP_GET_PLAYTGT:
1606 case SNDCTL_DSP_SET_PLAYTGT: /* yes, they are the same for now */
1607 /*
1608 * Re: SET_PLAYTGT
1609 * OSSv4: "The value that was accepted by the device will
1610 * be returned back in the variable pointed by the
1611 * argument."
1612 */
1613 if (wrch != NULL)
1614 *arg_i = 0;
1615 else
1616 ret = EINVAL;
1617 break;
1618
1619 case SNDCTL_DSP_SILENCE:
1620 /*
1621 * Flush the software (pre-feed) buffer, but try to minimize playback
1622 * interruption. (I.e., record unplayed samples with intent to
1623 * restore by SNDCTL_DSP_SKIP.) Intended for application "pause"
1624 * functionality.
1625 */
1626 if (wrch == NULL)
1627 ret = EINVAL;
1628 else {
1629 struct snd_dbuf *bs;
1630 CHN_LOCK(wrch);
1631 while (wrch->inprog != 0)
1632 cv_wait(&wrch->cv, wrch->lock);
1633 bs = wrch->bufsoft;
1634 if ((bs->shadbuf != NULL) && (sndbuf_getready(bs) > 0)) {
1635 bs->sl = sndbuf_getready(bs);
1636 sndbuf_dispose(bs, bs->shadbuf, sndbuf_getready(bs));
1637 sndbuf_fillsilence(bs);
1638 chn_start(wrch, 0);
1639 }
1640 CHN_UNLOCK(wrch);
1641 }
1642 break;
1643
1644 case SNDCTL_DSP_SKIP:
1645 /*
1646 * OSSv4 docs: "This ioctl call discards all unplayed samples in the
1647 * playback buffer by moving the current write position immediately
1648 * before the point where the device is currently reading the samples."
1649 */
1650 if (wrch == NULL)
1651 ret = EINVAL;
1652 else {
1653 struct snd_dbuf *bs;
1654 CHN_LOCK(wrch);
1655 while (wrch->inprog != 0)
1656 cv_wait(&wrch->cv, wrch->lock);
1657 bs = wrch->bufsoft;
1658 if ((bs->shadbuf != NULL) && (bs->sl > 0)) {
1659 sndbuf_softreset(bs);
1660 sndbuf_acquire(bs, bs->shadbuf, bs->sl);
1661 bs->sl = 0;
1662 chn_start(wrch, 0);
1663 }
1664 CHN_UNLOCK(wrch);
1665 }
1666 break;
1667
1668 case SNDCTL_DSP_CURRENT_OPTR:
1669 case SNDCTL_DSP_CURRENT_IPTR:
1670 /**
1671 * @note Changing formats resets the buffer counters, which differs
1672 * from the 4Front drivers. However, I don't expect this to be
1673 * much of a problem.
1674 *
1675 * @note In a test where @c CURRENT_OPTR is called immediately after write
1676 * returns, this driver is about 32K samples behind whereas
1677 * 4Front's is about 8K samples behind. Should determine source
1678 * of discrepancy, even if only out of curiosity.
1679 *
1680 * @todo Actually test SNDCTL_DSP_CURRENT_IPTR.
1681 */
1682 chn = (cmd == SNDCTL_DSP_CURRENT_OPTR) ? wrch : rdch;
1683 if (chn == NULL)
1684 ret = EINVAL;
1685 else {
1686 struct snd_dbuf *bs;
1687 /* int tmp; */
1688
1689 oss_count_t *oc = (oss_count_t *)arg;
1690
1691 CHN_LOCK(chn);
1692 bs = chn->bufsoft;
1693 oc->samples = sndbuf_gettotal(bs) / sndbuf_getalign(bs);
1694 oc->fifo_samples = sndbuf_getready(bs) / sndbuf_getalign(bs);
1695 CHN_UNLOCK(chn);
1696 }
1697 break;
1698
1699 case SNDCTL_DSP_HALT_OUTPUT:
1700 case SNDCTL_DSP_HALT_INPUT:
1701 chn = (cmd == SNDCTL_DSP_HALT_OUTPUT) ? wrch : rdch;
1702 if (chn == NULL)
1703 ret = EINVAL;
1704 else {
1705 CHN_LOCK(chn);
1706 chn_abort(chn);
1707 CHN_UNLOCK(chn);
1708 }
1709 break;
1710
1711 case SNDCTL_DSP_LOW_WATER:
1712 /*
1713 * Set the number of bytes required to attract attention by
1714 * select/poll.
1715 */
1716 if (wrch != NULL) {
1717 CHN_LOCK(wrch);
1718 wrch->lw = (*arg_i > 1) ? *arg_i : 1;
1719 CHN_UNLOCK(wrch);
1720 }
1721 if (rdch != NULL) {
1722 CHN_LOCK(rdch);
1723 rdch->lw = (*arg_i > 1) ? *arg_i : 1;
1724 CHN_UNLOCK(rdch);
1725 }
1726 break;
1727
1728 case SNDCTL_DSP_GETERROR:
1729 #ifdef COMPAT_FREEBSD32
1730 case SNDCTL_DSP_GETERROR32:
1731 #endif
1732 /*
1733 * OSSv4 docs: "All errors and counters will automatically be
1734 * cleared to zeroes after the call so each call will return only
1735 * the errors that occurred after the previous invocation. ... The
1736 * play_underruns and rec_overrun fields are the only useful fields
1737 * returned by OSS 4.0."
1738 */
1739 {
1740 audio_errinfo *ei = (audio_errinfo *)arg;
1741 #ifdef COMPAT_FREEBSD32
1742 audio_errinfo errinfo;
1743 audio_errinfo32 *ei32 = (audio_errinfo32 *)arg;
1744
1745 if (cmd == SNDCTL_DSP_GETERROR32) {
1746 ei = &errinfo;
1747 }
1748 #endif
1749
1750 bzero((void *)ei, sizeof(*ei));
1751
1752 if (wrch != NULL) {
1753 CHN_LOCK(wrch);
1754 ei->play_underruns = wrch->xruns;
1755 wrch->xruns = 0;
1756 CHN_UNLOCK(wrch);
1757 }
1758 if (rdch != NULL) {
1759 CHN_LOCK(rdch);
1760 ei->rec_overruns = rdch->xruns;
1761 rdch->xruns = 0;
1762 CHN_UNLOCK(rdch);
1763 }
1764 #ifdef COMPAT_FREEBSD32
1765 if (cmd == SNDCTL_DSP_GETERROR32) {
1766 bzero((void *)ei32, sizeof(*ei32));
1767 ei32->play_underruns = ei->play_underruns;
1768 ei32->rec_overruns = ei->rec_overruns;
1769 ei32->play_ptradjust = ei->play_ptradjust;
1770 ei32->rec_ptradjust = ei->rec_ptradjust;
1771 ei32->play_errorcount = ei->play_errorcount;
1772 ei32->rec_errorcount = ei->rec_errorcount;
1773 ei32->play_lasterror = ei->play_lasterror;
1774 ei32->rec_lasterror = ei->rec_lasterror;
1775 ei32->play_errorparm = ei->play_errorparm;
1776 ei32->rec_errorparm = ei->rec_errorparm;
1777 }
1778 #endif
1779 }
1780 break;
1781
1782 case SNDCTL_DSP_SYNCGROUP:
1783 PCM_ACQUIRE_QUICK(d);
1784 ret = dsp_oss_syncgroup(wrch, rdch, (oss_syncgroup *)arg);
1785 PCM_RELEASE_QUICK(d);
1786 break;
1787
1788 case SNDCTL_DSP_SYNCSTART:
1789 PCM_ACQUIRE_QUICK(d);
1790 ret = dsp_oss_syncstart(*arg_i);
1791 PCM_RELEASE_QUICK(d);
1792 break;
1793
1794 case SNDCTL_DSP_POLICY:
1795 PCM_ACQUIRE_QUICK(d);
1796 ret = dsp_oss_policy(wrch, rdch, *arg_i);
1797 PCM_RELEASE_QUICK(d);
1798 break;
1799
1800 case SNDCTL_DSP_COOKEDMODE:
1801 PCM_ACQUIRE_QUICK(d);
1802 if (!(pcm_getflags(d->dev) & SD_F_BITPERFECT))
1803 ret = dsp_oss_cookedmode(wrch, rdch, *arg_i);
1804 PCM_RELEASE_QUICK(d);
1805 break;
1806 case SNDCTL_DSP_GET_CHNORDER:
1807 PCM_ACQUIRE_QUICK(d);
1808 ret = dsp_oss_getchnorder(wrch, rdch, (unsigned long long *)arg);
1809 PCM_RELEASE_QUICK(d);
1810 break;
1811 case SNDCTL_DSP_SET_CHNORDER:
1812 PCM_ACQUIRE_QUICK(d);
1813 ret = dsp_oss_setchnorder(wrch, rdch, (unsigned long long *)arg);
1814 PCM_RELEASE_QUICK(d);
1815 break;
1816 case SNDCTL_DSP_GETCHANNELMASK: /* XXX vlc */
1817 PCM_ACQUIRE_QUICK(d);
1818 ret = dsp_oss_getchannelmask(wrch, rdch, (int *)arg);
1819 PCM_RELEASE_QUICK(d);
1820 break;
1821 case SNDCTL_DSP_BIND_CHANNEL: /* XXX what?!? */
1822 ret = EINVAL;
1823 break;
1824 #ifdef OSSV4_EXPERIMENT
1825 /*
1826 * XXX The following ioctls are not yet supported and just return
1827 * EINVAL.
1828 */
1829 case SNDCTL_DSP_GETOPEAKS:
1830 case SNDCTL_DSP_GETIPEAKS:
1831 chn = (cmd == SNDCTL_DSP_GETOPEAKS) ? wrch : rdch;
1832 if (chn == NULL)
1833 ret = EINVAL;
1834 else {
1835 oss_peaks_t *op = (oss_peaks_t *)arg;
1836 int lpeak, rpeak;
1837
1838 CHN_LOCK(chn);
1839 ret = chn_getpeaks(chn, &lpeak, &rpeak);
1840 if (ret == -1)
1841 ret = EINVAL;
1842 else {
1843 (*op)[0] = lpeak;
1844 (*op)[1] = rpeak;
1845 }
1846 CHN_UNLOCK(chn);
1847 }
1848 break;
1849
1850 /*
1851 * XXX Once implemented, revisit this for proper cv protection
1852 * (if necessary).
1853 */
1854 case SNDCTL_GETLABEL:
1855 ret = dsp_oss_getlabel(wrch, rdch, (oss_label_t *)arg);
1856 break;
1857 case SNDCTL_SETLABEL:
1858 ret = dsp_oss_setlabel(wrch, rdch, (oss_label_t *)arg);
1859 break;
1860 case SNDCTL_GETSONG:
1861 ret = dsp_oss_getsong(wrch, rdch, (oss_longname_t *)arg);
1862 break;
1863 case SNDCTL_SETSONG:
1864 ret = dsp_oss_setsong(wrch, rdch, (oss_longname_t *)arg);
1865 break;
1866 case SNDCTL_SETNAME:
1867 ret = dsp_oss_setname(wrch, rdch, (oss_longname_t *)arg);
1868 break;
1869 #endif /* !OSSV4_EXPERIMENT */
1870 case SNDCTL_DSP_MAPINBUF:
1871 case SNDCTL_DSP_MAPOUTBUF:
1872 case SNDCTL_DSP_SETSYNCRO:
1873 /* undocumented */
1874
1875 case SNDCTL_DSP_SUBDIVIDE:
1876 case SOUND_PCM_WRITE_FILTER:
1877 case SOUND_PCM_READ_FILTER:
1878 /* dunno what these do, don't sound important */
1879
1880 default:
1881 DEB(printf("default ioctl fn 0x%08lx fail\n", cmd));
1882 ret = EINVAL;
1883 break;
1884 }
1885
1886 PCM_GIANT_LEAVE(d);
1887
1888 return (ret);
1889 }
1890
1891 static int
dsp_poll(struct cdev * i_dev,int events,struct thread * td)1892 dsp_poll(struct cdev *i_dev, int events, struct thread *td)
1893 {
1894 struct dsp_cdevpriv *priv;
1895 struct snddev_info *d;
1896 struct pcm_channel *wrch, *rdch;
1897 int ret, e, err;
1898
1899 if ((err = devfs_get_cdevpriv((void **)&priv)) != 0)
1900 return (err);
1901 d = priv->sc;
1902 if (!DSP_REGISTERED(d)) {
1903 /* XXX many clients don't understand POLLNVAL */
1904 return (events & (POLLHUP | POLLPRI | POLLIN |
1905 POLLRDNORM | POLLOUT | POLLWRNORM));
1906 }
1907 PCM_GIANT_ENTER(d);
1908
1909 ret = 0;
1910
1911 dsp_lock_chans(priv, FREAD | FWRITE);
1912 wrch = priv->wrch;
1913 rdch = priv->rdch;
1914
1915 if (wrch != NULL && !(wrch->flags & CHN_F_DEAD)) {
1916 e = (events & (POLLOUT | POLLWRNORM));
1917 if (e)
1918 ret |= chn_poll(wrch, e, td);
1919 }
1920
1921 if (rdch != NULL && !(rdch->flags & CHN_F_DEAD)) {
1922 e = (events & (POLLIN | POLLRDNORM));
1923 if (e)
1924 ret |= chn_poll(rdch, e, td);
1925 }
1926
1927 dsp_unlock_chans(priv, FREAD | FWRITE);
1928
1929 PCM_GIANT_LEAVE(d);
1930
1931 return (ret);
1932 }
1933
1934 static int
dsp_mmap(struct cdev * i_dev,vm_ooffset_t offset,vm_paddr_t * paddr,int nprot,vm_memattr_t * memattr)1935 dsp_mmap(struct cdev *i_dev, vm_ooffset_t offset, vm_paddr_t *paddr,
1936 int nprot, vm_memattr_t *memattr)
1937 {
1938
1939 /*
1940 * offset is in range due to checks in dsp_mmap_single().
1941 * XXX memattr is not honored.
1942 */
1943 *paddr = vtophys(offset);
1944 return (0);
1945 }
1946
1947 static int
dsp_mmap_single(struct cdev * i_dev,vm_ooffset_t * offset,vm_size_t size,struct vm_object ** object,int nprot)1948 dsp_mmap_single(struct cdev *i_dev, vm_ooffset_t *offset,
1949 vm_size_t size, struct vm_object **object, int nprot)
1950 {
1951 struct dsp_cdevpriv *priv;
1952 struct snddev_info *d;
1953 struct pcm_channel *wrch, *rdch, *c;
1954 int err;
1955
1956 /*
1957 * Reject PROT_EXEC by default. It just doesn't makes sense.
1958 * Unfortunately, we have to give up this one due to linux_mmap
1959 * changes.
1960 *
1961 * https://lists.freebsd.org/pipermail/freebsd-emulation/2007-June/003698.html
1962 *
1963 */
1964 #ifdef SV_ABI_LINUX
1965 if ((nprot & PROT_EXEC) && (dsp_mmap_allow_prot_exec < 0 ||
1966 (dsp_mmap_allow_prot_exec == 0 &&
1967 SV_CURPROC_ABI() != SV_ABI_LINUX)))
1968 #else
1969 if ((nprot & PROT_EXEC) && dsp_mmap_allow_prot_exec < 1)
1970 #endif
1971 return (EINVAL);
1972
1973 /*
1974 * PROT_READ (alone) selects the input buffer.
1975 * PROT_WRITE (alone) selects the output buffer.
1976 * PROT_WRITE|PROT_READ together select the output buffer.
1977 */
1978 if ((nprot & (PROT_READ | PROT_WRITE)) == 0)
1979 return (EINVAL);
1980
1981 if ((err = devfs_get_cdevpriv((void **)&priv)) != 0)
1982 return (err);
1983 d = priv->sc;
1984 if (!DSP_REGISTERED(d))
1985 return (EINVAL);
1986
1987 PCM_GIANT_ENTER(d);
1988
1989 dsp_lock_chans(priv, FREAD | FWRITE);
1990 wrch = priv->wrch;
1991 rdch = priv->rdch;
1992
1993 c = ((nprot & PROT_WRITE) != 0) ? wrch : rdch;
1994 if (c == NULL || (c->flags & CHN_F_MMAP_INVALID) ||
1995 (*offset + size) > sndbuf_getallocsize(c->bufsoft) ||
1996 (wrch != NULL && (wrch->flags & CHN_F_MMAP_INVALID)) ||
1997 (rdch != NULL && (rdch->flags & CHN_F_MMAP_INVALID))) {
1998 dsp_unlock_chans(priv, FREAD | FWRITE);
1999 PCM_GIANT_EXIT(d);
2000 return (EINVAL);
2001 }
2002
2003 if (wrch != NULL)
2004 wrch->flags |= CHN_F_MMAP;
2005 if (rdch != NULL)
2006 rdch->flags |= CHN_F_MMAP;
2007
2008 *offset = (uintptr_t)sndbuf_getbufofs(c->bufsoft, *offset);
2009 dsp_unlock_chans(priv, FREAD | FWRITE);
2010 *object = vm_pager_allocate(OBJT_DEVICE, i_dev,
2011 size, nprot, *offset, curthread->td_ucred);
2012
2013 PCM_GIANT_LEAVE(d);
2014
2015 if (*object == NULL)
2016 return (EINVAL);
2017 return (0);
2018 }
2019
2020 static const char *dsp_aliases[] = {
2021 "dsp_ac3",
2022 "dsp_mmap",
2023 "dsp_multich",
2024 "dsp_spdifout",
2025 "dsp_spdifin",
2026 };
2027
2028 static void
dsp_clone(void * arg,struct ucred * cred,char * name,int namelen,struct cdev ** dev)2029 dsp_clone(void *arg, struct ucred *cred, char *name, int namelen,
2030 struct cdev **dev)
2031 {
2032 struct snddev_info *d;
2033 size_t i;
2034
2035 if (*dev != NULL)
2036 return;
2037 if (strcmp(name, "dsp") == 0 && dsp_basename_clone)
2038 goto found;
2039 for (i = 0; i < nitems(dsp_aliases); i++) {
2040 if (strcmp(name, dsp_aliases[i]) == 0)
2041 goto found;
2042 }
2043 return;
2044 found:
2045 bus_topo_lock();
2046 d = devclass_get_softc(pcm_devclass, snd_unit);
2047 /*
2048 * If we only have a single soundcard attached and we detach it right
2049 * before entering dsp_clone(), there is a chance pcm_unregister() will
2050 * have returned already, meaning it will have set snd_unit to -1, and
2051 * thus devclass_get_softc() will return NULL here.
2052 */
2053 if (DSP_REGISTERED(d)) {
2054 *dev = d->dsp_dev;
2055 dev_ref(*dev);
2056 }
2057 bus_topo_unlock();
2058 }
2059
2060 static void
dsp_sysinit(void * p)2061 dsp_sysinit(void *p)
2062 {
2063 if (dsp_ehtag != NULL)
2064 return;
2065 dsp_ehtag = EVENTHANDLER_REGISTER(dev_clone, dsp_clone, 0, 1000);
2066 }
2067
2068 static void
dsp_sysuninit(void * p)2069 dsp_sysuninit(void *p)
2070 {
2071 if (dsp_ehtag == NULL)
2072 return;
2073 EVENTHANDLER_DEREGISTER(dev_clone, dsp_ehtag);
2074 dsp_ehtag = NULL;
2075 }
2076
2077 SYSINIT(dsp_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, dsp_sysinit, NULL);
2078 SYSUNINIT(dsp_sysuninit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, dsp_sysuninit, NULL);
2079
2080 static void
dsp_oss_audioinfo_unavail(oss_audioinfo * ai,int unit)2081 dsp_oss_audioinfo_unavail(oss_audioinfo *ai, int unit)
2082 {
2083 bzero(ai, sizeof(*ai));
2084 ai->dev = unit;
2085 snprintf(ai->name, sizeof(ai->name), "pcm%d (unavailable)", unit);
2086 ai->pid = -1;
2087 strlcpy(ai->cmd, CHN_COMM_UNUSED, sizeof(ai->cmd));
2088 ai->card_number = unit;
2089 ai->port_number = unit;
2090 ai->mixer_dev = -1;
2091 ai->legacy_device = unit;
2092 }
2093
2094 /**
2095 * @brief Handler for SNDCTL_AUDIOINFO.
2096 *
2097 * Gathers information about the audio device specified in ai->dev. If
2098 * ai->dev == -1, then this function gathers information about the current
2099 * device. If the call comes in on a non-audio device and ai->dev == -1,
2100 * return EINVAL.
2101 *
2102 * This routine is supposed to go practically straight to the hardware,
2103 * getting capabilities directly from the sound card driver, side-stepping
2104 * the intermediate channel interface.
2105 *
2106 * @note
2107 * Calling threads must not hold any snddev_info or pcm_channel locks.
2108 *
2109 * @param dev device on which the ioctl was issued
2110 * @param ai ioctl request data container
2111 * @param ex flag to distinguish between SNDCTL_AUDIOINFO from
2112 * SNDCTL_AUDIOINFO_EX
2113 *
2114 * @retval 0 success
2115 * @retval EINVAL ai->dev specifies an invalid device
2116 */
2117 int
dsp_oss_audioinfo(struct cdev * i_dev,oss_audioinfo * ai,bool ex)2118 dsp_oss_audioinfo(struct cdev *i_dev, oss_audioinfo *ai, bool ex)
2119 {
2120 struct pcmchan_caps *caps;
2121 struct pcm_channel *ch;
2122 struct snddev_info *d;
2123 uint32_t fmts;
2124 int i, minch, maxch, unit;
2125
2126 /*
2127 * If probing the device that received the ioctl, make sure it's a
2128 * DSP device. (Users may use this ioctl with /dev/mixer and
2129 * /dev/midi.)
2130 */
2131 if (ai->dev == -1 && i_dev->si_devsw != &dsp_cdevsw)
2132 return (EINVAL);
2133
2134 bus_topo_lock();
2135 for (unit = 0; pcm_devclass != NULL &&
2136 unit < devclass_get_maxunit(pcm_devclass); unit++) {
2137 d = devclass_get_softc(pcm_devclass, unit);
2138 if (!PCM_REGISTERED(d)) {
2139 if ((ai->dev == -1 && unit == snd_unit) ||
2140 ai->dev == unit) {
2141 dsp_oss_audioinfo_unavail(ai, unit);
2142 bus_topo_unlock();
2143 return (0);
2144 } else {
2145 d = NULL;
2146 continue;
2147 }
2148 }
2149
2150 PCM_UNLOCKASSERT(d);
2151 PCM_LOCK(d);
2152 if ((ai->dev == -1 && d->dsp_dev == i_dev) ||
2153 (ai->dev == unit)) {
2154 PCM_UNLOCK(d);
2155 break;
2156 } else {
2157 PCM_UNLOCK(d);
2158 d = NULL;
2159 }
2160 }
2161 bus_topo_unlock();
2162
2163 /* Exhausted the search -- nothing is locked, so return. */
2164 if (d == NULL)
2165 return (EINVAL);
2166
2167 /* XXX Need Giant magic entry ??? */
2168
2169 PCM_UNLOCKASSERT(d);
2170 PCM_LOCK(d);
2171
2172 bzero((void *)ai, sizeof(oss_audioinfo));
2173 ai->dev = unit;
2174 strlcpy(ai->name, device_get_desc(d->dev), sizeof(ai->name));
2175 ai->pid = -1;
2176 strlcpy(ai->cmd, CHN_COMM_UNKNOWN, sizeof(ai->cmd));
2177 ai->card_number = unit;
2178 ai->port_number = unit;
2179 ai->mixer_dev = (d->mixer_dev != NULL) ? unit : -1;
2180 ai->legacy_device = unit;
2181 snprintf(ai->devnode, sizeof(ai->devnode), "/dev/dsp%d", unit);
2182 ai->enabled = device_is_attached(d->dev) ? 1 : 0;
2183 ai->next_play_engine = 0;
2184 ai->next_rec_engine = 0;
2185 ai->busy = 0;
2186 ai->caps = PCM_CAP_REALTIME | PCM_CAP_MMAP | PCM_CAP_TRIGGER;
2187 ai->iformats = 0;
2188 ai->oformats = 0;
2189 ai->min_rate = INT_MAX;
2190 ai->max_rate = 0;
2191 ai->min_channels = INT_MAX;
2192 ai->max_channels = 0;
2193
2194 /* Gather global information about the device. */
2195 CHN_FOREACH(ch, d, channels.pcm) {
2196 CHN_UNLOCKASSERT(ch);
2197 CHN_LOCK(ch);
2198
2199 /*
2200 * Skip physical channels if we are servicing SNDCTL_AUDIOINFO,
2201 * or VCHANs if we are servicing SNDCTL_AUDIOINFO_EX.
2202 *
2203 * For SNDCTL_AUDIOINFO do not skip the physical channels if
2204 * there are no VCHANs.
2205 */
2206 if ((ex && (ch->flags & CHN_F_VIRTUAL) != 0) ||
2207 ((!ex && (ch->flags & CHN_F_VIRTUAL) == 0) &&
2208 (d->pvchancount > 0 || d->rvchancount > 0))) {
2209 CHN_UNLOCK(ch);
2210 continue;
2211 }
2212
2213 if ((ch->flags & CHN_F_BUSY) == 0) {
2214 ai->busy |= (ch->direction == PCMDIR_PLAY) ?
2215 OPEN_WRITE : OPEN_READ;
2216 }
2217
2218 ai->caps |=
2219 ((ch->flags & CHN_F_VIRTUAL) ? PCM_CAP_VIRTUAL : 0) |
2220 ((ch->direction == PCMDIR_PLAY) ? PCM_CAP_OUTPUT :
2221 PCM_CAP_INPUT);
2222
2223 caps = chn_getcaps(ch);
2224
2225 minch = INT_MAX;
2226 maxch = 0;
2227 fmts = 0;
2228 for (i = 0; caps->fmtlist[i]; i++) {
2229 fmts |= AFMT_ENCODING(caps->fmtlist[i]);
2230 minch = min(AFMT_CHANNEL(caps->fmtlist[i]), minch);
2231 maxch = max(AFMT_CHANNEL(caps->fmtlist[i]), maxch);
2232 }
2233
2234 if (ch->direction == PCMDIR_PLAY)
2235 ai->oformats |= fmts;
2236 else
2237 ai->iformats |= fmts;
2238
2239 if (ex || (pcm_getflags(d->dev) & SD_F_BITPERFECT)) {
2240 ai->min_rate = min(ai->min_rate, caps->minspeed);
2241 ai->max_rate = max(ai->max_rate, caps->maxspeed);
2242 } else {
2243 ai->min_rate = min(ai->min_rate, feeder_rate_min);
2244 ai->max_rate = max(ai->max_rate, feeder_rate_max);
2245 }
2246 ai->min_channels = min(ai->min_channels, minch);
2247 ai->max_channels = max(ai->max_channels, maxch);
2248
2249 CHN_UNLOCK(ch);
2250 }
2251 if (ai->min_rate == INT_MAX)
2252 ai->min_rate = 0;
2253 if (ai->min_channels == INT_MAX)
2254 ai->min_channels = 0;
2255
2256 PCM_UNLOCK(d);
2257
2258 return (0);
2259 }
2260
2261 static int
dsp_oss_engineinfo_cb(void * data,void * arg)2262 dsp_oss_engineinfo_cb(void *data, void *arg)
2263 {
2264 struct dsp_cdevpriv *priv = data;
2265 struct pcm_channel *ch = arg;
2266
2267 if (DSP_REGISTERED(priv->sc) && (ch == priv->rdch || ch == priv->wrch))
2268 return (1);
2269
2270 return (0);
2271 }
2272
2273 /**
2274 * @brief Handler for SNDCTL_ENGINEINFO
2275 *
2276 * Gathers information about the audio device's engine specified in ai->dev.
2277 * If ai->dev == -1, then this function gathers information about the current
2278 * device. If the call comes in on a non-audio device and ai->dev == -1,
2279 * return EINVAL.
2280 *
2281 * This routine is supposed to go practically straight to the hardware,
2282 * getting capabilities directly from the sound card driver, side-stepping
2283 * the intermediate channel interface.
2284 *
2285 * @note
2286 * Calling threads must not hold any snddev_info or pcm_channel locks.
2287 *
2288 * @param dev device on which the ioctl was issued
2289 * @param ai ioctl request data container
2290 *
2291 * @retval 0 success
2292 * @retval EINVAL ai->dev specifies an invalid device
2293 */
2294 int
dsp_oss_engineinfo(struct cdev * i_dev,oss_audioinfo * ai)2295 dsp_oss_engineinfo(struct cdev *i_dev, oss_audioinfo *ai)
2296 {
2297 struct pcmchan_caps *caps;
2298 struct pcm_channel *ch;
2299 struct snddev_info *d;
2300 uint32_t fmts;
2301 int i, nchan, *rates, minch, maxch, unit;
2302
2303 /*
2304 * If probing the device that received the ioctl, make sure it's a
2305 * DSP device. (Users may use this ioctl with /dev/mixer and
2306 * /dev/midi.)
2307 */
2308 if (ai->dev == -1 && i_dev->si_devsw != &dsp_cdevsw)
2309 return (EINVAL);
2310
2311 ch = NULL;
2312 nchan = 0;
2313
2314 /*
2315 * Search for the requested audio device (channel). Start by
2316 * iterating over pcm devices.
2317 */
2318 bus_topo_lock();
2319 for (unit = 0; pcm_devclass != NULL &&
2320 unit < devclass_get_maxunit(pcm_devclass); unit++) {
2321 d = devclass_get_softc(pcm_devclass, unit);
2322 if (!PCM_REGISTERED(d))
2323 continue;
2324
2325 /* XXX Need Giant magic entry ??? */
2326
2327 /* See the note in function docblock */
2328 PCM_UNLOCKASSERT(d);
2329 PCM_LOCK(d);
2330
2331 CHN_FOREACH(ch, d, channels.pcm) {
2332 CHN_UNLOCKASSERT(ch);
2333 CHN_LOCK(ch);
2334 if ((ai->dev == -1 && devfs_foreach_cdevpriv(
2335 i_dev, dsp_oss_engineinfo_cb, ch) != 0) ||
2336 ai->dev == nchan)
2337 break;
2338 CHN_UNLOCK(ch);
2339 ++nchan;
2340 }
2341
2342 if (ch == NULL) {
2343 PCM_UNLOCK(d);
2344 continue;
2345 }
2346
2347 /*
2348 * At this point, the following synchronization stuff
2349 * has happened:
2350 * - a specific PCM device is locked.
2351 * - a specific audio channel has been locked, so be
2352 * sure to unlock when exiting;
2353 */
2354
2355 caps = chn_getcaps(ch);
2356
2357 /*
2358 * With all handles collected, zero out the user's
2359 * container and begin filling in its fields.
2360 */
2361 bzero((void *)ai, sizeof(oss_audioinfo));
2362
2363 ai->dev = nchan;
2364 strlcpy(ai->name, ch->name, sizeof(ai->name));
2365
2366 if ((ch->flags & CHN_F_BUSY) == 0)
2367 ai->busy = 0;
2368 else
2369 ai->busy = (ch->direction == PCMDIR_PLAY) ? OPEN_WRITE : OPEN_READ;
2370
2371 ai->pid = ch->pid;
2372 strlcpy(ai->cmd, ch->comm, sizeof(ai->cmd));
2373
2374 /*
2375 * These flags stolen from SNDCTL_DSP_GETCAPS handler.
2376 * Note, however, that a single channel operates in
2377 * only one direction, so PCM_CAP_DUPLEX is out.
2378 */
2379 /**
2380 * @todo @c SNDCTL_AUDIOINFO::caps - Make drivers keep
2381 * these in pcmchan::caps?
2382 */
2383 ai->caps = PCM_CAP_REALTIME | PCM_CAP_MMAP | PCM_CAP_TRIGGER |
2384 ((ch->flags & CHN_F_VIRTUAL) ? PCM_CAP_VIRTUAL : 0) |
2385 ((ch->direction == PCMDIR_PLAY) ? PCM_CAP_OUTPUT : PCM_CAP_INPUT);
2386
2387 /*
2388 * Collect formats supported @b natively by the
2389 * device. Also determine min/max channels.
2390 */
2391 minch = INT_MAX;
2392 maxch = 0;
2393 fmts = 0;
2394 for (i = 0; caps->fmtlist[i]; i++) {
2395 fmts |= AFMT_ENCODING(caps->fmtlist[i]);
2396 minch = min(AFMT_CHANNEL(caps->fmtlist[i]), minch);
2397 maxch = max(AFMT_CHANNEL(caps->fmtlist[i]), maxch);
2398 }
2399
2400 if (ch->direction == PCMDIR_PLAY)
2401 ai->oformats = fmts;
2402 else
2403 ai->iformats = fmts;
2404
2405 /**
2406 * @note
2407 * @c magic - OSSv4 docs: "Reserved for internal use
2408 * by OSS."
2409 *
2410 * @par
2411 * @c card_number - OSSv4 docs: "Number of the sound
2412 * card where this device belongs or -1 if this
2413 * information is not available. Applications
2414 * should normally not use this field for any
2415 * purpose."
2416 */
2417 ai->card_number = unit;
2418 /**
2419 * @todo @c song_name - depends first on
2420 * SNDCTL_[GS]ETSONG @todo @c label - depends
2421 * on SNDCTL_[GS]ETLABEL
2422 * @todo @c port_number - routing information?
2423 */
2424 ai->port_number = unit;
2425 ai->mixer_dev = (d->mixer_dev != NULL) ? unit : -1;
2426 /**
2427 * @note
2428 * @c legacy_device - OSSv4 docs: "Obsolete."
2429 */
2430 ai->legacy_device = unit;
2431 snprintf(ai->devnode, sizeof(ai->devnode), "/dev/dsp%d", unit);
2432 ai->enabled = device_is_attached(d->dev) ? 1 : 0;
2433 /**
2434 * @note
2435 * @c flags - OSSv4 docs: "Reserved for future use."
2436 *
2437 * @note
2438 * @c binding - OSSv4 docs: "Reserved for future use."
2439 *
2440 * @todo @c handle - haven't decided how to generate
2441 * this yet; bus, vendor, device IDs?
2442 */
2443
2444 if ((ch->flags & CHN_F_EXCLUSIVE) ||
2445 (pcm_getflags(d->dev) & SD_F_BITPERFECT)) {
2446 ai->min_rate = caps->minspeed;
2447 ai->max_rate = caps->maxspeed;
2448 } else {
2449 ai->min_rate = feeder_rate_min;
2450 ai->max_rate = feeder_rate_max;
2451 }
2452
2453 ai->min_channels = minch;
2454 ai->max_channels = maxch;
2455
2456 ai->nrates = chn_getrates(ch, &rates);
2457 if (ai->nrates > OSS_MAX_SAMPLE_RATES)
2458 ai->nrates = OSS_MAX_SAMPLE_RATES;
2459
2460 for (i = 0; i < ai->nrates; i++)
2461 ai->rates[i] = rates[i];
2462
2463 ai->next_play_engine = 0;
2464 ai->next_rec_engine = 0;
2465
2466 CHN_UNLOCK(ch);
2467 PCM_UNLOCK(d);
2468 bus_topo_unlock();
2469
2470 return (0);
2471 }
2472 bus_topo_unlock();
2473
2474 /* Exhausted the search -- nothing is locked, so return. */
2475 return (EINVAL);
2476 }
2477
2478 /**
2479 * @brief Assigns a PCM channel to a sync group.
2480 *
2481 * Sync groups are used to enable audio operations on multiple devices
2482 * simultaneously. They may be used with any number of devices and may
2483 * span across applications. Devices are added to groups with
2484 * the SNDCTL_DSP_SYNCGROUP ioctl, and operations are triggered with the
2485 * SNDCTL_DSP_SYNCSTART ioctl.
2486 *
2487 * If the @c id field of the @c group parameter is set to zero, then a new
2488 * sync group is created. Otherwise, wrch and rdch (if set) are added to
2489 * the group specified.
2490 *
2491 * @todo As far as memory allocation, should we assume that things are
2492 * okay and allocate with M_WAITOK before acquiring channel locks,
2493 * freeing later if not?
2494 *
2495 * @param wrch output channel associated w/ device (if any)
2496 * @param rdch input channel associated w/ device (if any)
2497 * @param group Sync group parameters
2498 *
2499 * @retval 0 success
2500 * @retval non-zero error to be propagated upstream
2501 */
2502 static int
dsp_oss_syncgroup(struct pcm_channel * wrch,struct pcm_channel * rdch,oss_syncgroup * group)2503 dsp_oss_syncgroup(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_syncgroup *group)
2504 {
2505 struct pcmchan_syncmember *smrd, *smwr;
2506 struct pcmchan_syncgroup *sg;
2507 int ret, sg_ids[3];
2508
2509 smrd = NULL;
2510 smwr = NULL;
2511 sg = NULL;
2512 ret = 0;
2513
2514 /*
2515 * Free_unr() may sleep, so store released syncgroup IDs until after
2516 * all locks are released.
2517 */
2518 sg_ids[0] = sg_ids[1] = sg_ids[2] = 0;
2519
2520 PCM_SG_LOCK();
2521
2522 /*
2523 * - Insert channel(s) into group's member list.
2524 * - Set CHN_F_NOTRIGGER on channel(s).
2525 * - Stop channel(s).
2526 */
2527
2528 /*
2529 * If device's channels are already mapped to a group, unmap them.
2530 */
2531 if (wrch) {
2532 CHN_LOCK(wrch);
2533 sg_ids[0] = chn_syncdestroy(wrch);
2534 }
2535
2536 if (rdch) {
2537 CHN_LOCK(rdch);
2538 sg_ids[1] = chn_syncdestroy(rdch);
2539 }
2540
2541 /*
2542 * Verify that mode matches character device properites.
2543 * - Bail if PCM_ENABLE_OUTPUT && wrch == NULL.
2544 * - Bail if PCM_ENABLE_INPUT && rdch == NULL.
2545 */
2546 if (((wrch == NULL) && (group->mode & PCM_ENABLE_OUTPUT)) ||
2547 ((rdch == NULL) && (group->mode & PCM_ENABLE_INPUT))) {
2548 ret = EINVAL;
2549 goto out;
2550 }
2551
2552 /*
2553 * An id of zero indicates the user wants to create a new
2554 * syncgroup.
2555 */
2556 if (group->id == 0) {
2557 sg = malloc(sizeof(*sg), M_DEVBUF, M_NOWAIT);
2558 if (sg != NULL) {
2559 SLIST_INIT(&sg->members);
2560 sg->id = alloc_unr(pcmsg_unrhdr);
2561
2562 group->id = sg->id;
2563 SLIST_INSERT_HEAD(&snd_pcm_syncgroups, sg, link);
2564 } else
2565 ret = ENOMEM;
2566 } else {
2567 SLIST_FOREACH(sg, &snd_pcm_syncgroups, link) {
2568 if (sg->id == group->id)
2569 break;
2570 }
2571 if (sg == NULL)
2572 ret = EINVAL;
2573 }
2574
2575 /* Couldn't create or find a syncgroup. Fail. */
2576 if (sg == NULL)
2577 goto out;
2578
2579 /*
2580 * Allocate a syncmember, assign it and a channel together, and
2581 * insert into syncgroup.
2582 */
2583 if (group->mode & PCM_ENABLE_INPUT) {
2584 smrd = malloc(sizeof(*smrd), M_DEVBUF, M_NOWAIT);
2585 if (smrd == NULL) {
2586 ret = ENOMEM;
2587 goto out;
2588 }
2589
2590 SLIST_INSERT_HEAD(&sg->members, smrd, link);
2591 smrd->parent = sg;
2592 smrd->ch = rdch;
2593
2594 chn_abort(rdch);
2595 rdch->flags |= CHN_F_NOTRIGGER;
2596 rdch->sm = smrd;
2597 }
2598
2599 if (group->mode & PCM_ENABLE_OUTPUT) {
2600 smwr = malloc(sizeof(*smwr), M_DEVBUF, M_NOWAIT);
2601 if (smwr == NULL) {
2602 ret = ENOMEM;
2603 goto out;
2604 }
2605
2606 SLIST_INSERT_HEAD(&sg->members, smwr, link);
2607 smwr->parent = sg;
2608 smwr->ch = wrch;
2609
2610 chn_abort(wrch);
2611 wrch->flags |= CHN_F_NOTRIGGER;
2612 wrch->sm = smwr;
2613 }
2614
2615 out:
2616 if (ret != 0) {
2617 if (smrd != NULL)
2618 free(smrd, M_DEVBUF);
2619 if ((sg != NULL) && SLIST_EMPTY(&sg->members)) {
2620 sg_ids[2] = sg->id;
2621 SLIST_REMOVE(&snd_pcm_syncgroups, sg, pcmchan_syncgroup, link);
2622 free(sg, M_DEVBUF);
2623 }
2624
2625 if (wrch)
2626 wrch->sm = NULL;
2627 if (rdch)
2628 rdch->sm = NULL;
2629 }
2630
2631 if (wrch)
2632 CHN_UNLOCK(wrch);
2633 if (rdch)
2634 CHN_UNLOCK(rdch);
2635
2636 PCM_SG_UNLOCK();
2637
2638 if (sg_ids[0])
2639 free_unr(pcmsg_unrhdr, sg_ids[0]);
2640 if (sg_ids[1])
2641 free_unr(pcmsg_unrhdr, sg_ids[1]);
2642 if (sg_ids[2])
2643 free_unr(pcmsg_unrhdr, sg_ids[2]);
2644
2645 return (ret);
2646 }
2647
2648 /**
2649 * @brief Launch a sync group into action
2650 *
2651 * Sync groups are established via SNDCTL_DSP_SYNCGROUP. This function
2652 * iterates over all members, triggering them along the way.
2653 *
2654 * @note Caller must not hold any channel locks.
2655 *
2656 * @param sg_id sync group identifier
2657 *
2658 * @retval 0 success
2659 * @retval non-zero error worthy of propagating upstream to user
2660 */
2661 static int
dsp_oss_syncstart(int sg_id)2662 dsp_oss_syncstart(int sg_id)
2663 {
2664 struct pcmchan_syncmember *sm, *sm_tmp;
2665 struct pcmchan_syncgroup *sg;
2666 struct pcm_channel *c;
2667 int ret, needlocks;
2668
2669 /* Get the synclists lock */
2670 PCM_SG_LOCK();
2671
2672 do {
2673 ret = 0;
2674 needlocks = 0;
2675
2676 /* Search for syncgroup by ID */
2677 SLIST_FOREACH(sg, &snd_pcm_syncgroups, link) {
2678 if (sg->id == sg_id)
2679 break;
2680 }
2681
2682 /* Return EINVAL if not found */
2683 if (sg == NULL) {
2684 ret = EINVAL;
2685 break;
2686 }
2687
2688 /* Any removals resulting in an empty group should've handled this */
2689 KASSERT(!SLIST_EMPTY(&sg->members), ("found empty syncgroup"));
2690
2691 /*
2692 * Attempt to lock all member channels - if any are already
2693 * locked, unlock those acquired, sleep for a bit, and try
2694 * again.
2695 */
2696 SLIST_FOREACH(sm, &sg->members, link) {
2697 if (CHN_TRYLOCK(sm->ch) == 0) {
2698 int timo = hz * 5/1000;
2699 if (timo < 1)
2700 timo = 1;
2701
2702 /* Release all locked channels so far, retry */
2703 SLIST_FOREACH(sm_tmp, &sg->members, link) {
2704 /* sm is the member already locked */
2705 if (sm == sm_tmp)
2706 break;
2707 CHN_UNLOCK(sm_tmp->ch);
2708 }
2709
2710 /** @todo Is PRIBIO correct/ */
2711 ret = msleep(sm, &snd_pcm_syncgroups_mtx,
2712 PRIBIO | PCATCH, "pcmsg", timo);
2713 if (ret == EINTR || ret == ERESTART)
2714 break;
2715
2716 needlocks = 1;
2717 ret = 0; /* Assumes ret == EAGAIN... */
2718 }
2719 }
2720 } while (needlocks && ret == 0);
2721
2722 /* Proceed only if no errors encountered. */
2723 if (ret == 0) {
2724 /* Launch channels */
2725 while ((sm = SLIST_FIRST(&sg->members)) != NULL) {
2726 SLIST_REMOVE_HEAD(&sg->members, link);
2727
2728 c = sm->ch;
2729 c->sm = NULL;
2730 chn_start(c, 1);
2731 c->flags &= ~CHN_F_NOTRIGGER;
2732 CHN_UNLOCK(c);
2733
2734 free(sm, M_DEVBUF);
2735 }
2736
2737 SLIST_REMOVE(&snd_pcm_syncgroups, sg, pcmchan_syncgroup, link);
2738 free(sg, M_DEVBUF);
2739 }
2740
2741 PCM_SG_UNLOCK();
2742
2743 /*
2744 * Free_unr() may sleep, so be sure to give up the syncgroup lock
2745 * first.
2746 */
2747 if (ret == 0)
2748 free_unr(pcmsg_unrhdr, sg_id);
2749
2750 return (ret);
2751 }
2752
2753 /**
2754 * @brief Handler for SNDCTL_DSP_POLICY
2755 *
2756 * The SNDCTL_DSP_POLICY ioctl is a simpler interface to control fragment
2757 * size and count like with SNDCTL_DSP_SETFRAGMENT. Instead of the user
2758 * specifying those two parameters, s/he simply selects a number from 0..10
2759 * which corresponds to a buffer size. Smaller numbers request smaller
2760 * buffers with lower latencies (at greater overhead from more frequent
2761 * interrupts), while greater numbers behave in the opposite manner.
2762 *
2763 * The 4Front spec states that a value of 5 should be the default. However,
2764 * this implementation deviates slightly by using a linear scale without
2765 * consulting drivers. I.e., even though drivers may have different default
2766 * buffer sizes, a policy argument of 5 will have the same result across
2767 * all drivers.
2768 *
2769 * See http://manuals.opensound.com/developer/SNDCTL_DSP_POLICY.html for
2770 * more information.
2771 *
2772 * @todo When SNDCTL_DSP_COOKEDMODE is supported, it'll be necessary to
2773 * work with hardware drivers directly.
2774 *
2775 * @note PCM channel arguments must not be locked by caller.
2776 *
2777 * @param wrch Pointer to opened playback channel (optional; may be NULL)
2778 * @param rdch " recording channel (optional; may be NULL)
2779 * @param policy Integer from [0:10]
2780 *
2781 * @retval 0 constant (for now)
2782 */
2783 static int
dsp_oss_policy(struct pcm_channel * wrch,struct pcm_channel * rdch,int policy)2784 dsp_oss_policy(struct pcm_channel *wrch, struct pcm_channel *rdch, int policy)
2785 {
2786 int ret;
2787
2788 if (policy < CHN_POLICY_MIN || policy > CHN_POLICY_MAX)
2789 return (EIO);
2790
2791 /* Default: success */
2792 ret = 0;
2793
2794 if (rdch) {
2795 CHN_LOCK(rdch);
2796 ret = chn_setlatency(rdch, policy);
2797 CHN_UNLOCK(rdch);
2798 }
2799
2800 if (wrch && ret == 0) {
2801 CHN_LOCK(wrch);
2802 ret = chn_setlatency(wrch, policy);
2803 CHN_UNLOCK(wrch);
2804 }
2805
2806 if (ret)
2807 ret = EIO;
2808
2809 return (ret);
2810 }
2811
2812 /**
2813 * @brief Enable or disable "cooked" mode
2814 *
2815 * This is a handler for @c SNDCTL_DSP_COOKEDMODE. When in cooked mode, which
2816 * is the default, the sound system handles rate and format conversions
2817 * automatically (ex: user writing 11025Hz/8 bit/unsigned but card only
2818 * operates with 44100Hz/16bit/signed samples).
2819 *
2820 * Disabling cooked mode is intended for applications wanting to mmap()
2821 * a sound card's buffer space directly, bypassing the FreeBSD 2-stage
2822 * feeder architecture, presumably to gain as much control over audio
2823 * hardware as possible.
2824 *
2825 * See @c http://manuals.opensound.com/developer/SNDCTL_DSP_COOKEDMODE.html
2826 * for more details.
2827 *
2828 * @param wrch playback channel (optional; may be NULL)
2829 * @param rdch recording channel (optional; may be NULL)
2830 * @param enabled 0 = raw mode, 1 = cooked mode
2831 *
2832 * @retval EINVAL Operation not yet supported.
2833 */
2834 static int
dsp_oss_cookedmode(struct pcm_channel * wrch,struct pcm_channel * rdch,int enabled)2835 dsp_oss_cookedmode(struct pcm_channel *wrch, struct pcm_channel *rdch, int enabled)
2836 {
2837
2838 /*
2839 * XXX I just don't get it. Why don't they call it
2840 * "BITPERFECT" ~ SNDCTL_DSP_BITPERFECT !?!?.
2841 * This is just plain so confusing, incoherent,
2842 * <insert any non-printable characters here>.
2843 */
2844 if (!(enabled == 1 || enabled == 0))
2845 return (EINVAL);
2846
2847 /*
2848 * I won't give in. I'm inverting its logic here and now.
2849 * Brag all you want, but "BITPERFECT" should be the better
2850 * term here.
2851 */
2852 enabled ^= 0x00000001;
2853
2854 if (wrch != NULL) {
2855 CHN_LOCK(wrch);
2856 wrch->flags &= ~CHN_F_BITPERFECT;
2857 wrch->flags |= (enabled != 0) ? CHN_F_BITPERFECT : 0x00000000;
2858 CHN_UNLOCK(wrch);
2859 }
2860
2861 if (rdch != NULL) {
2862 CHN_LOCK(rdch);
2863 rdch->flags &= ~CHN_F_BITPERFECT;
2864 rdch->flags |= (enabled != 0) ? CHN_F_BITPERFECT : 0x00000000;
2865 CHN_UNLOCK(rdch);
2866 }
2867
2868 return (0);
2869 }
2870
2871 /**
2872 * @brief Retrieve channel interleaving order
2873 *
2874 * This is the handler for @c SNDCTL_DSP_GET_CHNORDER.
2875 *
2876 * See @c http://manuals.opensound.com/developer/SNDCTL_DSP_GET_CHNORDER.html
2877 * for more details.
2878 *
2879 * @note As the ioctl definition is still under construction, FreeBSD
2880 * does not currently support SNDCTL_DSP_GET_CHNORDER.
2881 *
2882 * @param wrch playback channel (optional; may be NULL)
2883 * @param rdch recording channel (optional; may be NULL)
2884 * @param map channel map (result will be stored there)
2885 *
2886 * @retval EINVAL Operation not yet supported.
2887 */
2888 static int
dsp_oss_getchnorder(struct pcm_channel * wrch,struct pcm_channel * rdch,unsigned long long * map)2889 dsp_oss_getchnorder(struct pcm_channel *wrch, struct pcm_channel *rdch, unsigned long long *map)
2890 {
2891 struct pcm_channel *ch;
2892 int ret;
2893
2894 ch = (wrch != NULL) ? wrch : rdch;
2895 if (ch != NULL) {
2896 CHN_LOCK(ch);
2897 ret = chn_oss_getorder(ch, map);
2898 CHN_UNLOCK(ch);
2899 } else
2900 ret = EINVAL;
2901
2902 return (ret);
2903 }
2904
2905 /**
2906 * @brief Specify channel interleaving order
2907 *
2908 * This is the handler for @c SNDCTL_DSP_SET_CHNORDER.
2909 *
2910 * @note As the ioctl definition is still under construction, FreeBSD
2911 * does not currently support @c SNDCTL_DSP_SET_CHNORDER.
2912 *
2913 * @param wrch playback channel (optional; may be NULL)
2914 * @param rdch recording channel (optional; may be NULL)
2915 * @param map channel map
2916 *
2917 * @retval EINVAL Operation not yet supported.
2918 */
2919 static int
dsp_oss_setchnorder(struct pcm_channel * wrch,struct pcm_channel * rdch,unsigned long long * map)2920 dsp_oss_setchnorder(struct pcm_channel *wrch, struct pcm_channel *rdch, unsigned long long *map)
2921 {
2922 int ret;
2923
2924 ret = 0;
2925
2926 if (wrch != NULL) {
2927 CHN_LOCK(wrch);
2928 ret = chn_oss_setorder(wrch, map);
2929 CHN_UNLOCK(wrch);
2930 }
2931
2932 if (ret == 0 && rdch != NULL) {
2933 CHN_LOCK(rdch);
2934 ret = chn_oss_setorder(rdch, map);
2935 CHN_UNLOCK(rdch);
2936 }
2937
2938 return (ret);
2939 }
2940
2941 static int
dsp_oss_getchannelmask(struct pcm_channel * wrch,struct pcm_channel * rdch,int * mask)2942 dsp_oss_getchannelmask(struct pcm_channel *wrch, struct pcm_channel *rdch,
2943 int *mask)
2944 {
2945 struct pcm_channel *ch;
2946 uint32_t chnmask;
2947 int ret;
2948
2949 chnmask = 0;
2950 ch = (wrch != NULL) ? wrch : rdch;
2951
2952 if (ch != NULL) {
2953 CHN_LOCK(ch);
2954 ret = chn_oss_getmask(ch, &chnmask);
2955 CHN_UNLOCK(ch);
2956 } else
2957 ret = EINVAL;
2958
2959 if (ret == 0)
2960 *mask = chnmask;
2961
2962 return (ret);
2963 }
2964
2965 #ifdef OSSV4_EXPERIMENT
2966 /**
2967 * @brief Retrieve an audio device's label
2968 *
2969 * This is a handler for the @c SNDCTL_GETLABEL ioctl.
2970 *
2971 * See @c http://manuals.opensound.com/developer/SNDCTL_GETLABEL.html
2972 * for more details.
2973 *
2974 * From Hannu@4Front: "For example ossxmix (just like some HW mixer
2975 * consoles) can show variable "labels" for certain controls. By default
2976 * the application name (say quake) is shown as the label but
2977 * applications may change the labels themselves."
2978 *
2979 * @note As the ioctl definition is still under construction, FreeBSD
2980 * does not currently support @c SNDCTL_GETLABEL.
2981 *
2982 * @param wrch playback channel (optional; may be NULL)
2983 * @param rdch recording channel (optional; may be NULL)
2984 * @param label label gets copied here
2985 *
2986 * @retval EINVAL Operation not yet supported.
2987 */
2988 static int
dsp_oss_getlabel(struct pcm_channel * wrch,struct pcm_channel * rdch,oss_label_t * label)2989 dsp_oss_getlabel(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_label_t *label)
2990 {
2991 return (EINVAL);
2992 }
2993
2994 /**
2995 * @brief Specify an audio device's label
2996 *
2997 * This is a handler for the @c SNDCTL_SETLABEL ioctl. Please see the
2998 * comments for @c dsp_oss_getlabel immediately above.
2999 *
3000 * See @c http://manuals.opensound.com/developer/SNDCTL_GETLABEL.html
3001 * for more details.
3002 *
3003 * @note As the ioctl definition is still under construction, FreeBSD
3004 * does not currently support SNDCTL_SETLABEL.
3005 *
3006 * @param wrch playback channel (optional; may be NULL)
3007 * @param rdch recording channel (optional; may be NULL)
3008 * @param label label gets copied from here
3009 *
3010 * @retval EINVAL Operation not yet supported.
3011 */
3012 static int
dsp_oss_setlabel(struct pcm_channel * wrch,struct pcm_channel * rdch,oss_label_t * label)3013 dsp_oss_setlabel(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_label_t *label)
3014 {
3015 return (EINVAL);
3016 }
3017
3018 /**
3019 * @brief Retrieve name of currently played song
3020 *
3021 * This is a handler for the @c SNDCTL_GETSONG ioctl. Audio players could
3022 * tell the system the name of the currently playing song, which would be
3023 * visible in @c /dev/sndstat.
3024 *
3025 * See @c http://manuals.opensound.com/developer/SNDCTL_GETSONG.html
3026 * for more details.
3027 *
3028 * @note As the ioctl definition is still under construction, FreeBSD
3029 * does not currently support SNDCTL_GETSONG.
3030 *
3031 * @param wrch playback channel (optional; may be NULL)
3032 * @param rdch recording channel (optional; may be NULL)
3033 * @param song song name gets copied here
3034 *
3035 * @retval EINVAL Operation not yet supported.
3036 */
3037 static int
dsp_oss_getsong(struct pcm_channel * wrch,struct pcm_channel * rdch,oss_longname_t * song)3038 dsp_oss_getsong(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *song)
3039 {
3040 return (EINVAL);
3041 }
3042
3043 /**
3044 * @brief Retrieve name of currently played song
3045 *
3046 * This is a handler for the @c SNDCTL_SETSONG ioctl. Audio players could
3047 * tell the system the name of the currently playing song, which would be
3048 * visible in @c /dev/sndstat.
3049 *
3050 * See @c http://manuals.opensound.com/developer/SNDCTL_SETSONG.html
3051 * for more details.
3052 *
3053 * @note As the ioctl definition is still under construction, FreeBSD
3054 * does not currently support SNDCTL_SETSONG.
3055 *
3056 * @param wrch playback channel (optional; may be NULL)
3057 * @param rdch recording channel (optional; may be NULL)
3058 * @param song song name gets copied from here
3059 *
3060 * @retval EINVAL Operation not yet supported.
3061 */
3062 static int
dsp_oss_setsong(struct pcm_channel * wrch,struct pcm_channel * rdch,oss_longname_t * song)3063 dsp_oss_setsong(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *song)
3064 {
3065 return (EINVAL);
3066 }
3067
3068 /**
3069 * @brief Rename a device
3070 *
3071 * This is a handler for the @c SNDCTL_SETNAME ioctl.
3072 *
3073 * See @c http://manuals.opensound.com/developer/SNDCTL_SETNAME.html for
3074 * more details.
3075 *
3076 * From Hannu@4Front: "This call is used to change the device name
3077 * reported in /dev/sndstat and ossinfo. So instead of using some generic
3078 * 'OSS loopback audio (MIDI) driver' the device may be given a meaningfull
3079 * name depending on the current context (for example 'OSS virtual wave table
3080 * synth' or 'VoIP link to London')."
3081 *
3082 * @note As the ioctl definition is still under construction, FreeBSD
3083 * does not currently support SNDCTL_SETNAME.
3084 *
3085 * @param wrch playback channel (optional; may be NULL)
3086 * @param rdch recording channel (optional; may be NULL)
3087 * @param name new device name gets copied from here
3088 *
3089 * @retval EINVAL Operation not yet supported.
3090 */
3091 static int
dsp_oss_setname(struct pcm_channel * wrch,struct pcm_channel * rdch,oss_longname_t * name)3092 dsp_oss_setname(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *name)
3093 {
3094 return (EINVAL);
3095 }
3096 #endif /* !OSSV4_EXPERIMENT */
3097