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);
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);
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 static int
dsp_ioctl(struct cdev * i_dev,u_long cmd,caddr_t arg,int mode,struct thread * td)675 dsp_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode,
676 struct thread *td)
677 {
678 struct dsp_cdevpriv *priv;
679 struct pcm_channel *chn, *rdch, *wrch;
680 struct snddev_info *d;
681 u_long xcmd;
682 int *arg_i, ret, tmp, err;
683
684 if ((err = devfs_get_cdevpriv((void **)&priv)) != 0)
685 return (err);
686
687 d = priv->sc;
688 if (!DSP_REGISTERED(d))
689 return (EBADF);
690
691 PCM_GIANT_ENTER(d);
692
693 arg_i = (int *)arg;
694 ret = 0;
695 xcmd = 0;
696 chn = NULL;
697
698 if (IOCGROUP(cmd) == 'M') {
699 if (cmd == OSS_GETVERSION) {
700 *arg_i = SOUND_VERSION;
701 PCM_GIANT_EXIT(d);
702 return (0);
703 }
704 ret = dsp_ioctl_channel(priv, NULL, cmd, arg);
705 if (ret != -1) {
706 PCM_GIANT_EXIT(d);
707 return (ret);
708 }
709
710 if (d->mixer_dev != NULL) {
711 PCM_ACQUIRE_QUICK(d);
712 ret = mixer_ioctl_cmd(d->mixer_dev, cmd, arg, -1, td,
713 MIXER_CMD_DIRECT);
714 PCM_RELEASE_QUICK(d);
715 } else
716 ret = EBADF;
717
718 PCM_GIANT_EXIT(d);
719
720 return (ret);
721 }
722
723 /*
724 * Certain ioctls may be made on any type of device (audio, mixer,
725 * and MIDI). Handle those special cases here.
726 */
727 if (IOCGROUP(cmd) == 'X') {
728 PCM_ACQUIRE_QUICK(d);
729 switch(cmd) {
730 case SNDCTL_SYSINFO:
731 sound_oss_sysinfo((oss_sysinfo *)arg);
732 break;
733 case SNDCTL_CARDINFO:
734 ret = sound_oss_card_info((oss_card_info *)arg);
735 break;
736 case SNDCTL_AUDIOINFO:
737 ret = dsp_oss_audioinfo(i_dev, (oss_audioinfo *)arg,
738 false);
739 break;
740 case SNDCTL_AUDIOINFO_EX:
741 ret = dsp_oss_audioinfo(i_dev, (oss_audioinfo *)arg,
742 true);
743 break;
744 case SNDCTL_ENGINEINFO:
745 ret = dsp_oss_engineinfo(i_dev, (oss_audioinfo *)arg);
746 break;
747 case SNDCTL_MIXERINFO:
748 ret = mixer_oss_mixerinfo(i_dev, (oss_mixerinfo *)arg);
749 break;
750 default:
751 ret = EINVAL;
752 }
753 PCM_RELEASE_QUICK(d);
754 PCM_GIANT_EXIT(d);
755 return (ret);
756 }
757
758 rdch = priv->rdch;
759 wrch = priv->wrch;
760
761 if (wrch != NULL && (wrch->flags & CHN_F_DEAD))
762 wrch = NULL;
763 if (rdch != NULL && (rdch->flags & CHN_F_DEAD))
764 rdch = NULL;
765
766 if (wrch == NULL && rdch == NULL) {
767 PCM_GIANT_EXIT(d);
768 return (EINVAL);
769 }
770
771 switch(cmd) {
772 #ifdef OLDPCM_IOCTL
773 /*
774 * we start with the new ioctl interface.
775 */
776 case AIONWRITE: /* how many bytes can write ? */
777 if (wrch) {
778 CHN_LOCK(wrch);
779 /*
780 if (wrch && wrch->bufhard.dl)
781 while (chn_wrfeed(wrch) == 0);
782 */
783 *arg_i = sndbuf_getfree(wrch->bufsoft);
784 CHN_UNLOCK(wrch);
785 } else {
786 *arg_i = 0;
787 ret = EINVAL;
788 }
789 break;
790
791 case AIOSSIZE: /* set the current blocksize */
792 {
793 struct snd_size *p = (struct snd_size *)arg;
794
795 p->play_size = 0;
796 p->rec_size = 0;
797 PCM_ACQUIRE_QUICK(d);
798 if (wrch) {
799 CHN_LOCK(wrch);
800 chn_setblocksize(wrch, 2, p->play_size);
801 p->play_size = sndbuf_getblksz(wrch->bufsoft);
802 CHN_UNLOCK(wrch);
803 }
804 if (rdch) {
805 CHN_LOCK(rdch);
806 chn_setblocksize(rdch, 2, p->rec_size);
807 p->rec_size = sndbuf_getblksz(rdch->bufsoft);
808 CHN_UNLOCK(rdch);
809 }
810 PCM_RELEASE_QUICK(d);
811 }
812 break;
813 case AIOGSIZE: /* get the current blocksize */
814 {
815 struct snd_size *p = (struct snd_size *)arg;
816
817 if (wrch) {
818 CHN_LOCK(wrch);
819 p->play_size = sndbuf_getblksz(wrch->bufsoft);
820 CHN_UNLOCK(wrch);
821 }
822 if (rdch) {
823 CHN_LOCK(rdch);
824 p->rec_size = sndbuf_getblksz(rdch->bufsoft);
825 CHN_UNLOCK(rdch);
826 }
827 }
828 break;
829
830 case AIOSFMT:
831 case AIOGFMT:
832 {
833 snd_chan_param *p = (snd_chan_param *)arg;
834
835 if (cmd == AIOSFMT &&
836 ((p->play_format != 0 && p->play_rate == 0) ||
837 (p->rec_format != 0 && p->rec_rate == 0))) {
838 ret = EINVAL;
839 break;
840 }
841 PCM_ACQUIRE_QUICK(d);
842 if (wrch) {
843 CHN_LOCK(wrch);
844 if (cmd == AIOSFMT && p->play_format != 0) {
845 chn_setformat(wrch,
846 SND_FORMAT(p->play_format,
847 AFMT_CHANNEL(wrch->format),
848 AFMT_EXTCHANNEL(wrch->format)));
849 chn_setspeed(wrch, p->play_rate);
850 }
851 p->play_rate = wrch->speed;
852 p->play_format = AFMT_ENCODING(wrch->format);
853 CHN_UNLOCK(wrch);
854 } else {
855 p->play_rate = 0;
856 p->play_format = 0;
857 }
858 if (rdch) {
859 CHN_LOCK(rdch);
860 if (cmd == AIOSFMT && p->rec_format != 0) {
861 chn_setformat(rdch,
862 SND_FORMAT(p->rec_format,
863 AFMT_CHANNEL(rdch->format),
864 AFMT_EXTCHANNEL(rdch->format)));
865 chn_setspeed(rdch, p->rec_rate);
866 }
867 p->rec_rate = rdch->speed;
868 p->rec_format = AFMT_ENCODING(rdch->format);
869 CHN_UNLOCK(rdch);
870 } else {
871 p->rec_rate = 0;
872 p->rec_format = 0;
873 }
874 PCM_RELEASE_QUICK(d);
875 }
876 break;
877
878 case AIOGCAP: /* get capabilities */
879 {
880 snd_capabilities *p = (snd_capabilities *)arg;
881 struct pcmchan_caps *pcaps = NULL, *rcaps = NULL;
882 struct cdev *pdev;
883
884 PCM_LOCK(d);
885 if (rdch) {
886 CHN_LOCK(rdch);
887 rcaps = chn_getcaps(rdch);
888 }
889 if (wrch) {
890 CHN_LOCK(wrch);
891 pcaps = chn_getcaps(wrch);
892 }
893 p->rate_min = max(rcaps? rcaps->minspeed : 0,
894 pcaps? pcaps->minspeed : 0);
895 p->rate_max = min(rcaps? rcaps->maxspeed : 1000000,
896 pcaps? pcaps->maxspeed : 1000000);
897 p->bufsize = min(rdch? sndbuf_getsize(rdch->bufsoft) : 1000000,
898 wrch? sndbuf_getsize(wrch->bufsoft) : 1000000);
899 /* XXX bad on sb16 */
900 p->formats = (rdch? chn_getformats(rdch) : 0xffffffff) &
901 (wrch? chn_getformats(wrch) : 0xffffffff);
902 if (rdch && wrch) {
903 p->formats |=
904 (pcm_getflags(d->dev) & SD_F_SIMPLEX) ? 0 :
905 AFMT_FULLDUPLEX;
906 }
907 pdev = d->mixer_dev;
908 p->mixers = 1; /* default: one mixer */
909 p->inputs = pdev->si_drv1? mix_getdevs(pdev->si_drv1) : 0;
910 p->left = p->right = 100;
911 if (wrch)
912 CHN_UNLOCK(wrch);
913 if (rdch)
914 CHN_UNLOCK(rdch);
915 PCM_UNLOCK(d);
916 }
917 break;
918
919 case AIOSTOP:
920 if (*arg_i == AIOSYNC_PLAY && wrch) {
921 CHN_LOCK(wrch);
922 *arg_i = chn_abort(wrch);
923 CHN_UNLOCK(wrch);
924 } else if (*arg_i == AIOSYNC_CAPTURE && rdch) {
925 CHN_LOCK(rdch);
926 *arg_i = chn_abort(rdch);
927 CHN_UNLOCK(rdch);
928 } else {
929 printf("AIOSTOP: bad channel 0x%x\n", *arg_i);
930 *arg_i = 0;
931 }
932 break;
933
934 case AIOSYNC:
935 printf("AIOSYNC chan 0x%03lx pos %lu unimplemented\n",
936 ((snd_sync_parm *)arg)->chan, ((snd_sync_parm *)arg)->pos);
937 break;
938 #endif
939 /*
940 * here follow the standard ioctls (filio.h etc.)
941 */
942 case FIONREAD: /* get # bytes to read */
943 if (rdch) {
944 CHN_LOCK(rdch);
945 /* if (rdch && rdch->bufhard.dl)
946 while (chn_rdfeed(rdch) == 0);
947 */
948 *arg_i = sndbuf_getready(rdch->bufsoft);
949 CHN_UNLOCK(rdch);
950 } else {
951 *arg_i = 0;
952 ret = EINVAL;
953 }
954 break;
955
956 case FIOASYNC: /*set/clear async i/o */
957 DEB( printf("FIOASYNC\n") ; )
958 break;
959
960 case SNDCTL_DSP_NONBLOCK: /* set non-blocking i/o */
961 case FIONBIO: /* set/clear non-blocking i/o */
962 if (rdch) {
963 CHN_LOCK(rdch);
964 if (cmd == SNDCTL_DSP_NONBLOCK || *arg_i)
965 rdch->flags |= CHN_F_NBIO;
966 else
967 rdch->flags &= ~CHN_F_NBIO;
968 CHN_UNLOCK(rdch);
969 }
970 if (wrch) {
971 CHN_LOCK(wrch);
972 if (cmd == SNDCTL_DSP_NONBLOCK || *arg_i)
973 wrch->flags |= CHN_F_NBIO;
974 else
975 wrch->flags &= ~CHN_F_NBIO;
976 CHN_UNLOCK(wrch);
977 }
978 break;
979
980 /*
981 * Finally, here is the linux-compatible ioctl interface
982 */
983 #define THE_REAL_SNDCTL_DSP_GETBLKSIZE _IOWR('P', 4, int)
984 case THE_REAL_SNDCTL_DSP_GETBLKSIZE:
985 case SNDCTL_DSP_GETBLKSIZE:
986 chn = wrch ? wrch : rdch;
987 if (chn) {
988 CHN_LOCK(chn);
989 *arg_i = sndbuf_getblksz(chn->bufsoft);
990 CHN_UNLOCK(chn);
991 } else {
992 *arg_i = 0;
993 ret = EINVAL;
994 }
995 break;
996
997 case SNDCTL_DSP_SETBLKSIZE:
998 RANGE(*arg_i, 16, 65536);
999 PCM_ACQUIRE_QUICK(d);
1000 if (wrch) {
1001 CHN_LOCK(wrch);
1002 chn_setblocksize(wrch, 2, *arg_i);
1003 CHN_UNLOCK(wrch);
1004 }
1005 if (rdch) {
1006 CHN_LOCK(rdch);
1007 chn_setblocksize(rdch, 2, *arg_i);
1008 CHN_UNLOCK(rdch);
1009 }
1010 PCM_RELEASE_QUICK(d);
1011 break;
1012
1013 case SNDCTL_DSP_RESET:
1014 DEB(printf("dsp reset\n"));
1015 if (wrch) {
1016 CHN_LOCK(wrch);
1017 chn_abort(wrch);
1018 chn_resetbuf(wrch);
1019 CHN_UNLOCK(wrch);
1020 }
1021 if (rdch) {
1022 CHN_LOCK(rdch);
1023 chn_abort(rdch);
1024 chn_resetbuf(rdch);
1025 CHN_UNLOCK(rdch);
1026 }
1027 break;
1028
1029 case SNDCTL_DSP_SYNC:
1030 DEB(printf("dsp sync\n"));
1031 /* chn_sync may sleep */
1032 if (wrch) {
1033 CHN_LOCK(wrch);
1034 chn_sync(wrch, 0);
1035 CHN_UNLOCK(wrch);
1036 }
1037 break;
1038
1039 case SNDCTL_DSP_SPEED:
1040 /* chn_setspeed may sleep */
1041 tmp = 0;
1042 PCM_ACQUIRE_QUICK(d);
1043 if (wrch) {
1044 CHN_LOCK(wrch);
1045 ret = chn_setspeed(wrch, *arg_i);
1046 tmp = wrch->speed;
1047 CHN_UNLOCK(wrch);
1048 }
1049 if (rdch && ret == 0) {
1050 CHN_LOCK(rdch);
1051 ret = chn_setspeed(rdch, *arg_i);
1052 if (tmp == 0)
1053 tmp = rdch->speed;
1054 CHN_UNLOCK(rdch);
1055 }
1056 PCM_RELEASE_QUICK(d);
1057 *arg_i = tmp;
1058 break;
1059
1060 case SOUND_PCM_READ_RATE:
1061 chn = wrch ? wrch : rdch;
1062 if (chn) {
1063 CHN_LOCK(chn);
1064 *arg_i = chn->speed;
1065 CHN_UNLOCK(chn);
1066 } else {
1067 *arg_i = 0;
1068 ret = EINVAL;
1069 }
1070 break;
1071
1072 case SNDCTL_DSP_STEREO:
1073 tmp = -1;
1074 *arg_i = (*arg_i)? 2 : 1;
1075 PCM_ACQUIRE_QUICK(d);
1076 if (wrch) {
1077 CHN_LOCK(wrch);
1078 ret = chn_setformat(wrch,
1079 SND_FORMAT(wrch->format, *arg_i, 0));
1080 tmp = (AFMT_CHANNEL(wrch->format) > 1)? 1 : 0;
1081 CHN_UNLOCK(wrch);
1082 }
1083 if (rdch && ret == 0) {
1084 CHN_LOCK(rdch);
1085 ret = chn_setformat(rdch,
1086 SND_FORMAT(rdch->format, *arg_i, 0));
1087 if (tmp == -1)
1088 tmp = (AFMT_CHANNEL(rdch->format) > 1)? 1 : 0;
1089 CHN_UNLOCK(rdch);
1090 }
1091 PCM_RELEASE_QUICK(d);
1092 *arg_i = tmp;
1093 break;
1094
1095 case SOUND_PCM_WRITE_CHANNELS:
1096 /* case SNDCTL_DSP_CHANNELS: ( == SOUND_PCM_WRITE_CHANNELS) */
1097 if (*arg_i < 0 || *arg_i > AFMT_CHANNEL_MAX) {
1098 *arg_i = 0;
1099 ret = EINVAL;
1100 break;
1101 }
1102 if (*arg_i != 0) {
1103 uint32_t ext = 0;
1104
1105 tmp = 0;
1106 /*
1107 * Map channel number to surround sound formats.
1108 * Devices that need bitperfect mode to operate
1109 * (e.g. more than SND_CHN_MAX channels) are not
1110 * subject to any mapping.
1111 */
1112 if (!(pcm_getflags(d->dev) & SD_F_BITPERFECT)) {
1113 struct pcmchan_matrix *m;
1114
1115 if (*arg_i > SND_CHN_MAX)
1116 *arg_i = SND_CHN_MAX;
1117
1118 m = feeder_matrix_default_channel_map(*arg_i);
1119 if (m != NULL)
1120 ext = m->ext;
1121 }
1122
1123 PCM_ACQUIRE_QUICK(d);
1124 if (wrch) {
1125 CHN_LOCK(wrch);
1126 ret = chn_setformat(wrch,
1127 SND_FORMAT(wrch->format, *arg_i, ext));
1128 tmp = AFMT_CHANNEL(wrch->format);
1129 CHN_UNLOCK(wrch);
1130 }
1131 if (rdch && ret == 0) {
1132 CHN_LOCK(rdch);
1133 ret = chn_setformat(rdch,
1134 SND_FORMAT(rdch->format, *arg_i, ext));
1135 if (tmp == 0)
1136 tmp = AFMT_CHANNEL(rdch->format);
1137 CHN_UNLOCK(rdch);
1138 }
1139 PCM_RELEASE_QUICK(d);
1140 *arg_i = tmp;
1141 } else {
1142 chn = wrch ? wrch : rdch;
1143 CHN_LOCK(chn);
1144 *arg_i = AFMT_CHANNEL(chn->format);
1145 CHN_UNLOCK(chn);
1146 }
1147 break;
1148
1149 case SOUND_PCM_READ_CHANNELS:
1150 chn = wrch ? wrch : rdch;
1151 if (chn) {
1152 CHN_LOCK(chn);
1153 *arg_i = AFMT_CHANNEL(chn->format);
1154 CHN_UNLOCK(chn);
1155 } else {
1156 *arg_i = 0;
1157 ret = EINVAL;
1158 }
1159 break;
1160
1161 case SNDCTL_DSP_GETFMTS: /* returns a mask of supported fmts */
1162 chn = wrch ? wrch : rdch;
1163 if (chn) {
1164 CHN_LOCK(chn);
1165 *arg_i = chn_getformats(chn);
1166 CHN_UNLOCK(chn);
1167 } else {
1168 *arg_i = 0;
1169 ret = EINVAL;
1170 }
1171 break;
1172
1173 case SNDCTL_DSP_SETFMT: /* sets _one_ format */
1174 if (*arg_i != AFMT_QUERY) {
1175 tmp = 0;
1176 PCM_ACQUIRE_QUICK(d);
1177 if (wrch) {
1178 CHN_LOCK(wrch);
1179 ret = chn_setformat(wrch, SND_FORMAT(*arg_i,
1180 AFMT_CHANNEL(wrch->format),
1181 AFMT_EXTCHANNEL(wrch->format)));
1182 tmp = wrch->format;
1183 CHN_UNLOCK(wrch);
1184 }
1185 if (rdch && ret == 0) {
1186 CHN_LOCK(rdch);
1187 ret = chn_setformat(rdch, SND_FORMAT(*arg_i,
1188 AFMT_CHANNEL(rdch->format),
1189 AFMT_EXTCHANNEL(rdch->format)));
1190 if (tmp == 0)
1191 tmp = rdch->format;
1192 CHN_UNLOCK(rdch);
1193 }
1194 PCM_RELEASE_QUICK(d);
1195 *arg_i = AFMT_ENCODING(tmp);
1196 } else {
1197 chn = wrch ? wrch : rdch;
1198 CHN_LOCK(chn);
1199 *arg_i = AFMT_ENCODING(chn->format);
1200 CHN_UNLOCK(chn);
1201 }
1202 break;
1203
1204 case SNDCTL_DSP_SETFRAGMENT:
1205 DEB(printf("SNDCTL_DSP_SETFRAGMENT 0x%08x\n", *(int *)arg));
1206 {
1207 uint32_t fragln = (*arg_i) & 0x0000ffff;
1208 uint32_t maxfrags = ((*arg_i) & 0xffff0000) >> 16;
1209 uint32_t fragsz;
1210 uint32_t r_maxfrags, r_fragsz;
1211
1212 RANGE(fragln, 4, 16);
1213 fragsz = 1 << fragln;
1214
1215 if (maxfrags == 0)
1216 maxfrags = CHN_2NDBUFMAXSIZE / fragsz;
1217 if (maxfrags < 2)
1218 maxfrags = 2;
1219 if (maxfrags * fragsz > CHN_2NDBUFMAXSIZE)
1220 maxfrags = CHN_2NDBUFMAXSIZE / fragsz;
1221
1222 DEB(printf("SNDCTL_DSP_SETFRAGMENT %d frags, %d sz\n", maxfrags, fragsz));
1223 PCM_ACQUIRE_QUICK(d);
1224 if (rdch) {
1225 CHN_LOCK(rdch);
1226 ret = chn_setblocksize(rdch, maxfrags, fragsz);
1227 r_maxfrags = sndbuf_getblkcnt(rdch->bufsoft);
1228 r_fragsz = sndbuf_getblksz(rdch->bufsoft);
1229 CHN_UNLOCK(rdch);
1230 } else {
1231 r_maxfrags = maxfrags;
1232 r_fragsz = fragsz;
1233 }
1234 if (wrch && ret == 0) {
1235 CHN_LOCK(wrch);
1236 ret = chn_setblocksize(wrch, maxfrags, fragsz);
1237 maxfrags = sndbuf_getblkcnt(wrch->bufsoft);
1238 fragsz = sndbuf_getblksz(wrch->bufsoft);
1239 CHN_UNLOCK(wrch);
1240 } else { /* use whatever came from the read channel */
1241 maxfrags = r_maxfrags;
1242 fragsz = r_fragsz;
1243 }
1244 PCM_RELEASE_QUICK(d);
1245
1246 fragln = 0;
1247 while (fragsz > 1) {
1248 fragln++;
1249 fragsz >>= 1;
1250 }
1251 *arg_i = (maxfrags << 16) | fragln;
1252 }
1253 break;
1254
1255 case SNDCTL_DSP_GETISPACE:
1256 /* return the size of data available in the input queue */
1257 {
1258 audio_buf_info *a = (audio_buf_info *)arg;
1259 if (rdch) {
1260 struct snd_dbuf *bs = rdch->bufsoft;
1261
1262 CHN_LOCK(rdch);
1263 a->bytes = sndbuf_getready(bs);
1264 a->fragments = a->bytes / sndbuf_getblksz(bs);
1265 a->fragstotal = sndbuf_getblkcnt(bs);
1266 a->fragsize = sndbuf_getblksz(bs);
1267 CHN_UNLOCK(rdch);
1268 } else
1269 ret = EINVAL;
1270 }
1271 break;
1272
1273 case SNDCTL_DSP_GETOSPACE:
1274 /* return space available in the output queue */
1275 {
1276 audio_buf_info *a = (audio_buf_info *)arg;
1277 if (wrch) {
1278 struct snd_dbuf *bs = wrch->bufsoft;
1279
1280 CHN_LOCK(wrch);
1281 a->bytes = sndbuf_getfree(bs);
1282 a->fragments = a->bytes / sndbuf_getblksz(bs);
1283 a->fragstotal = sndbuf_getblkcnt(bs);
1284 a->fragsize = sndbuf_getblksz(bs);
1285 CHN_UNLOCK(wrch);
1286 } else
1287 ret = EINVAL;
1288 }
1289 break;
1290
1291 case SNDCTL_DSP_GETIPTR:
1292 {
1293 count_info *a = (count_info *)arg;
1294 if (rdch) {
1295 struct snd_dbuf *bs = rdch->bufsoft;
1296
1297 CHN_LOCK(rdch);
1298 a->bytes = sndbuf_gettotal(bs);
1299 a->blocks = sndbuf_getblocks(bs) - rdch->blocks;
1300 a->ptr = sndbuf_getfreeptr(bs);
1301 rdch->blocks = sndbuf_getblocks(bs);
1302 CHN_UNLOCK(rdch);
1303 } else
1304 ret = EINVAL;
1305 }
1306 break;
1307
1308 case SNDCTL_DSP_GETOPTR:
1309 {
1310 count_info *a = (count_info *)arg;
1311 if (wrch) {
1312 struct snd_dbuf *bs = wrch->bufsoft;
1313
1314 CHN_LOCK(wrch);
1315 a->bytes = sndbuf_gettotal(bs);
1316 a->blocks = sndbuf_getblocks(bs) - wrch->blocks;
1317 a->ptr = sndbuf_getreadyptr(bs);
1318 wrch->blocks = sndbuf_getblocks(bs);
1319 CHN_UNLOCK(wrch);
1320 } else
1321 ret = EINVAL;
1322 }
1323 break;
1324
1325 case SNDCTL_DSP_GETCAPS:
1326 PCM_LOCK(d);
1327 *arg_i = PCM_CAP_REALTIME | PCM_CAP_MMAP | PCM_CAP_TRIGGER;
1328 if (rdch && wrch && !(pcm_getflags(d->dev) & SD_F_SIMPLEX))
1329 *arg_i |= PCM_CAP_DUPLEX;
1330 if (rdch && (rdch->flags & CHN_F_VIRTUAL) != 0)
1331 *arg_i |= PCM_CAP_VIRTUAL;
1332 if (wrch && (wrch->flags & CHN_F_VIRTUAL) != 0)
1333 *arg_i |= PCM_CAP_VIRTUAL;
1334 PCM_UNLOCK(d);
1335 break;
1336
1337 case SOUND_PCM_READ_BITS:
1338 chn = wrch ? wrch : rdch;
1339 if (chn) {
1340 CHN_LOCK(chn);
1341 if (chn->format & AFMT_8BIT)
1342 *arg_i = 8;
1343 else if (chn->format & AFMT_16BIT)
1344 *arg_i = 16;
1345 else if (chn->format & AFMT_24BIT)
1346 *arg_i = 24;
1347 else if (chn->format & AFMT_32BIT)
1348 *arg_i = 32;
1349 else
1350 ret = EINVAL;
1351 CHN_UNLOCK(chn);
1352 } else {
1353 *arg_i = 0;
1354 ret = EINVAL;
1355 }
1356 break;
1357
1358 case SNDCTL_DSP_SETTRIGGER:
1359 if (rdch) {
1360 CHN_LOCK(rdch);
1361 rdch->flags &= ~CHN_F_NOTRIGGER;
1362 if (*arg_i & PCM_ENABLE_INPUT)
1363 chn_start(rdch, 1);
1364 else {
1365 chn_abort(rdch);
1366 chn_resetbuf(rdch);
1367 rdch->flags |= CHN_F_NOTRIGGER;
1368 }
1369 CHN_UNLOCK(rdch);
1370 }
1371 if (wrch) {
1372 CHN_LOCK(wrch);
1373 wrch->flags &= ~CHN_F_NOTRIGGER;
1374 if (*arg_i & PCM_ENABLE_OUTPUT)
1375 chn_start(wrch, 1);
1376 else {
1377 chn_abort(wrch);
1378 chn_resetbuf(wrch);
1379 wrch->flags |= CHN_F_NOTRIGGER;
1380 }
1381 CHN_UNLOCK(wrch);
1382 }
1383 break;
1384
1385 case SNDCTL_DSP_GETTRIGGER:
1386 *arg_i = 0;
1387 if (wrch) {
1388 CHN_LOCK(wrch);
1389 if (wrch->flags & CHN_F_TRIGGERED)
1390 *arg_i |= PCM_ENABLE_OUTPUT;
1391 CHN_UNLOCK(wrch);
1392 }
1393 if (rdch) {
1394 CHN_LOCK(rdch);
1395 if (rdch->flags & CHN_F_TRIGGERED)
1396 *arg_i |= PCM_ENABLE_INPUT;
1397 CHN_UNLOCK(rdch);
1398 }
1399 break;
1400
1401 case SNDCTL_DSP_GETODELAY:
1402 if (wrch) {
1403 struct snd_dbuf *bs = wrch->bufsoft;
1404
1405 CHN_LOCK(wrch);
1406 *arg_i = sndbuf_getready(bs);
1407 CHN_UNLOCK(wrch);
1408 } else
1409 ret = EINVAL;
1410 break;
1411
1412 case SNDCTL_DSP_POST:
1413 if (wrch) {
1414 CHN_LOCK(wrch);
1415 wrch->flags &= ~CHN_F_NOTRIGGER;
1416 chn_start(wrch, 1);
1417 CHN_UNLOCK(wrch);
1418 }
1419 break;
1420
1421 case SNDCTL_DSP_SETDUPLEX:
1422 /*
1423 * switch to full-duplex mode if card is in half-duplex
1424 * mode and is able to work in full-duplex mode
1425 */
1426 PCM_LOCK(d);
1427 if (rdch && wrch && (pcm_getflags(d->dev) & SD_F_SIMPLEX))
1428 pcm_setflags(d->dev, pcm_getflags(d->dev)^SD_F_SIMPLEX);
1429 PCM_UNLOCK(d);
1430 break;
1431
1432 /*
1433 * The following four ioctls are simple wrappers around mixer_ioctl
1434 * with no further processing. xcmd is short for "translated
1435 * command".
1436 */
1437 case SNDCTL_DSP_GETRECVOL:
1438 if (xcmd == 0) {
1439 xcmd = SOUND_MIXER_READ_RECLEV;
1440 chn = rdch;
1441 }
1442 /* FALLTHROUGH */
1443 case SNDCTL_DSP_SETRECVOL:
1444 if (xcmd == 0) {
1445 xcmd = SOUND_MIXER_WRITE_RECLEV;
1446 chn = rdch;
1447 }
1448 /* FALLTHROUGH */
1449 case SNDCTL_DSP_GETPLAYVOL:
1450 if (xcmd == 0) {
1451 xcmd = SOUND_MIXER_READ_PCM;
1452 chn = wrch;
1453 }
1454 /* FALLTHROUGH */
1455 case SNDCTL_DSP_SETPLAYVOL:
1456 if (xcmd == 0) {
1457 xcmd = SOUND_MIXER_WRITE_PCM;
1458 chn = wrch;
1459 }
1460
1461 ret = dsp_ioctl_channel(priv, chn, xcmd, arg);
1462 if (ret != -1) {
1463 PCM_GIANT_EXIT(d);
1464 return (ret);
1465 }
1466
1467 if (d->mixer_dev != NULL) {
1468 PCM_ACQUIRE_QUICK(d);
1469 ret = mixer_ioctl_cmd(d->mixer_dev, xcmd, arg, -1, td,
1470 MIXER_CMD_DIRECT);
1471 PCM_RELEASE_QUICK(d);
1472 } else
1473 ret = ENOTSUP;
1474
1475 break;
1476
1477 case SNDCTL_DSP_GET_RECSRC_NAMES:
1478 case SNDCTL_DSP_GET_RECSRC:
1479 case SNDCTL_DSP_SET_RECSRC:
1480 if (d->mixer_dev != NULL) {
1481 PCM_ACQUIRE_QUICK(d);
1482 ret = mixer_ioctl_cmd(d->mixer_dev, cmd, arg, -1, td,
1483 MIXER_CMD_DIRECT);
1484 PCM_RELEASE_QUICK(d);
1485 } else
1486 ret = ENOTSUP;
1487 break;
1488
1489 /*
1490 * The following 3 ioctls aren't very useful at the moment. For
1491 * now, only a single channel is associated with a cdev (/dev/dspN
1492 * instance), so there's only a single output routing to use (i.e.,
1493 * the wrch bound to this cdev).
1494 */
1495 case SNDCTL_DSP_GET_PLAYTGT_NAMES:
1496 {
1497 oss_mixer_enuminfo *ei;
1498 ei = (oss_mixer_enuminfo *)arg;
1499 ei->dev = 0;
1500 ei->ctrl = 0;
1501 ei->version = 0; /* static for now */
1502 ei->strindex[0] = 0;
1503
1504 if (wrch != NULL) {
1505 ei->nvalues = 1;
1506 strlcpy(ei->strings, wrch->name,
1507 sizeof(ei->strings));
1508 } else {
1509 ei->nvalues = 0;
1510 ei->strings[0] = '\0';
1511 }
1512 }
1513 break;
1514 case SNDCTL_DSP_GET_PLAYTGT:
1515 case SNDCTL_DSP_SET_PLAYTGT: /* yes, they are the same for now */
1516 /*
1517 * Re: SET_PLAYTGT
1518 * OSSv4: "The value that was accepted by the device will
1519 * be returned back in the variable pointed by the
1520 * argument."
1521 */
1522 if (wrch != NULL)
1523 *arg_i = 0;
1524 else
1525 ret = EINVAL;
1526 break;
1527
1528 case SNDCTL_DSP_SILENCE:
1529 /*
1530 * Flush the software (pre-feed) buffer, but try to minimize playback
1531 * interruption. (I.e., record unplayed samples with intent to
1532 * restore by SNDCTL_DSP_SKIP.) Intended for application "pause"
1533 * functionality.
1534 */
1535 if (wrch == NULL)
1536 ret = EINVAL;
1537 else {
1538 struct snd_dbuf *bs;
1539 CHN_LOCK(wrch);
1540 while (wrch->inprog != 0)
1541 cv_wait(&wrch->cv, wrch->lock);
1542 bs = wrch->bufsoft;
1543 if ((bs->shadbuf != NULL) && (sndbuf_getready(bs) > 0)) {
1544 bs->sl = sndbuf_getready(bs);
1545 sndbuf_dispose(bs, bs->shadbuf, sndbuf_getready(bs));
1546 sndbuf_fillsilence(bs);
1547 chn_start(wrch, 0);
1548 }
1549 CHN_UNLOCK(wrch);
1550 }
1551 break;
1552
1553 case SNDCTL_DSP_SKIP:
1554 /*
1555 * OSSv4 docs: "This ioctl call discards all unplayed samples in the
1556 * playback buffer by moving the current write position immediately
1557 * before the point where the device is currently reading the samples."
1558 */
1559 if (wrch == NULL)
1560 ret = EINVAL;
1561 else {
1562 struct snd_dbuf *bs;
1563 CHN_LOCK(wrch);
1564 while (wrch->inprog != 0)
1565 cv_wait(&wrch->cv, wrch->lock);
1566 bs = wrch->bufsoft;
1567 if ((bs->shadbuf != NULL) && (bs->sl > 0)) {
1568 sndbuf_softreset(bs);
1569 sndbuf_acquire(bs, bs->shadbuf, bs->sl);
1570 bs->sl = 0;
1571 chn_start(wrch, 0);
1572 }
1573 CHN_UNLOCK(wrch);
1574 }
1575 break;
1576
1577 case SNDCTL_DSP_CURRENT_OPTR:
1578 case SNDCTL_DSP_CURRENT_IPTR:
1579 /**
1580 * @note Changing formats resets the buffer counters, which differs
1581 * from the 4Front drivers. However, I don't expect this to be
1582 * much of a problem.
1583 *
1584 * @note In a test where @c CURRENT_OPTR is called immediately after write
1585 * returns, this driver is about 32K samples behind whereas
1586 * 4Front's is about 8K samples behind. Should determine source
1587 * of discrepancy, even if only out of curiosity.
1588 *
1589 * @todo Actually test SNDCTL_DSP_CURRENT_IPTR.
1590 */
1591 chn = (cmd == SNDCTL_DSP_CURRENT_OPTR) ? wrch : rdch;
1592 if (chn == NULL)
1593 ret = EINVAL;
1594 else {
1595 struct snd_dbuf *bs;
1596 /* int tmp; */
1597
1598 oss_count_t *oc = (oss_count_t *)arg;
1599
1600 CHN_LOCK(chn);
1601 bs = chn->bufsoft;
1602 oc->samples = sndbuf_gettotal(bs) / sndbuf_getalign(bs);
1603 oc->fifo_samples = sndbuf_getready(bs) / sndbuf_getalign(bs);
1604 CHN_UNLOCK(chn);
1605 }
1606 break;
1607
1608 case SNDCTL_DSP_HALT_OUTPUT:
1609 case SNDCTL_DSP_HALT_INPUT:
1610 chn = (cmd == SNDCTL_DSP_HALT_OUTPUT) ? wrch : rdch;
1611 if (chn == NULL)
1612 ret = EINVAL;
1613 else {
1614 CHN_LOCK(chn);
1615 chn_abort(chn);
1616 CHN_UNLOCK(chn);
1617 }
1618 break;
1619
1620 case SNDCTL_DSP_LOW_WATER:
1621 /*
1622 * Set the number of bytes required to attract attention by
1623 * select/poll.
1624 */
1625 if (wrch != NULL) {
1626 CHN_LOCK(wrch);
1627 wrch->lw = (*arg_i > 1) ? *arg_i : 1;
1628 CHN_UNLOCK(wrch);
1629 }
1630 if (rdch != NULL) {
1631 CHN_LOCK(rdch);
1632 rdch->lw = (*arg_i > 1) ? *arg_i : 1;
1633 CHN_UNLOCK(rdch);
1634 }
1635 break;
1636
1637 case SNDCTL_DSP_GETERROR:
1638 /*
1639 * OSSv4 docs: "All errors and counters will automatically be
1640 * cleared to zeroes after the call so each call will return only
1641 * the errors that occurred after the previous invocation. ... The
1642 * play_underruns and rec_overrun fields are the only useful fields
1643 * returned by OSS 4.0."
1644 */
1645 {
1646 audio_errinfo *ei = (audio_errinfo *)arg;
1647
1648 bzero((void *)ei, sizeof(*ei));
1649
1650 if (wrch != NULL) {
1651 CHN_LOCK(wrch);
1652 ei->play_underruns = wrch->xruns;
1653 wrch->xruns = 0;
1654 CHN_UNLOCK(wrch);
1655 }
1656 if (rdch != NULL) {
1657 CHN_LOCK(rdch);
1658 ei->rec_overruns = rdch->xruns;
1659 rdch->xruns = 0;
1660 CHN_UNLOCK(rdch);
1661 }
1662 }
1663 break;
1664
1665 case SNDCTL_DSP_SYNCGROUP:
1666 PCM_ACQUIRE_QUICK(d);
1667 ret = dsp_oss_syncgroup(wrch, rdch, (oss_syncgroup *)arg);
1668 PCM_RELEASE_QUICK(d);
1669 break;
1670
1671 case SNDCTL_DSP_SYNCSTART:
1672 PCM_ACQUIRE_QUICK(d);
1673 ret = dsp_oss_syncstart(*arg_i);
1674 PCM_RELEASE_QUICK(d);
1675 break;
1676
1677 case SNDCTL_DSP_POLICY:
1678 PCM_ACQUIRE_QUICK(d);
1679 ret = dsp_oss_policy(wrch, rdch, *arg_i);
1680 PCM_RELEASE_QUICK(d);
1681 break;
1682
1683 case SNDCTL_DSP_COOKEDMODE:
1684 PCM_ACQUIRE_QUICK(d);
1685 if (!(pcm_getflags(d->dev) & SD_F_BITPERFECT))
1686 ret = dsp_oss_cookedmode(wrch, rdch, *arg_i);
1687 PCM_RELEASE_QUICK(d);
1688 break;
1689 case SNDCTL_DSP_GET_CHNORDER:
1690 PCM_ACQUIRE_QUICK(d);
1691 ret = dsp_oss_getchnorder(wrch, rdch, (unsigned long long *)arg);
1692 PCM_RELEASE_QUICK(d);
1693 break;
1694 case SNDCTL_DSP_SET_CHNORDER:
1695 PCM_ACQUIRE_QUICK(d);
1696 ret = dsp_oss_setchnorder(wrch, rdch, (unsigned long long *)arg);
1697 PCM_RELEASE_QUICK(d);
1698 break;
1699 case SNDCTL_DSP_GETCHANNELMASK: /* XXX vlc */
1700 PCM_ACQUIRE_QUICK(d);
1701 ret = dsp_oss_getchannelmask(wrch, rdch, (int *)arg);
1702 PCM_RELEASE_QUICK(d);
1703 break;
1704 case SNDCTL_DSP_BIND_CHANNEL: /* XXX what?!? */
1705 ret = EINVAL;
1706 break;
1707 #ifdef OSSV4_EXPERIMENT
1708 /*
1709 * XXX The following ioctls are not yet supported and just return
1710 * EINVAL.
1711 */
1712 case SNDCTL_DSP_GETOPEAKS:
1713 case SNDCTL_DSP_GETIPEAKS:
1714 chn = (cmd == SNDCTL_DSP_GETOPEAKS) ? wrch : rdch;
1715 if (chn == NULL)
1716 ret = EINVAL;
1717 else {
1718 oss_peaks_t *op = (oss_peaks_t *)arg;
1719 int lpeak, rpeak;
1720
1721 CHN_LOCK(chn);
1722 ret = chn_getpeaks(chn, &lpeak, &rpeak);
1723 if (ret == -1)
1724 ret = EINVAL;
1725 else {
1726 (*op)[0] = lpeak;
1727 (*op)[1] = rpeak;
1728 }
1729 CHN_UNLOCK(chn);
1730 }
1731 break;
1732
1733 /*
1734 * XXX Once implemented, revisit this for proper cv protection
1735 * (if necessary).
1736 */
1737 case SNDCTL_GETLABEL:
1738 ret = dsp_oss_getlabel(wrch, rdch, (oss_label_t *)arg);
1739 break;
1740 case SNDCTL_SETLABEL:
1741 ret = dsp_oss_setlabel(wrch, rdch, (oss_label_t *)arg);
1742 break;
1743 case SNDCTL_GETSONG:
1744 ret = dsp_oss_getsong(wrch, rdch, (oss_longname_t *)arg);
1745 break;
1746 case SNDCTL_SETSONG:
1747 ret = dsp_oss_setsong(wrch, rdch, (oss_longname_t *)arg);
1748 break;
1749 case SNDCTL_SETNAME:
1750 ret = dsp_oss_setname(wrch, rdch, (oss_longname_t *)arg);
1751 break;
1752 #endif /* !OSSV4_EXPERIMENT */
1753 case SNDCTL_DSP_MAPINBUF:
1754 case SNDCTL_DSP_MAPOUTBUF:
1755 case SNDCTL_DSP_SETSYNCRO:
1756 /* undocumented */
1757
1758 case SNDCTL_DSP_SUBDIVIDE:
1759 case SOUND_PCM_WRITE_FILTER:
1760 case SOUND_PCM_READ_FILTER:
1761 /* dunno what these do, don't sound important */
1762
1763 default:
1764 DEB(printf("default ioctl fn 0x%08lx fail\n", cmd));
1765 ret = EINVAL;
1766 break;
1767 }
1768
1769 PCM_GIANT_LEAVE(d);
1770
1771 return (ret);
1772 }
1773
1774 static int
dsp_poll(struct cdev * i_dev,int events,struct thread * td)1775 dsp_poll(struct cdev *i_dev, int events, struct thread *td)
1776 {
1777 struct dsp_cdevpriv *priv;
1778 struct snddev_info *d;
1779 struct pcm_channel *wrch, *rdch;
1780 int ret, e, err;
1781
1782 if ((err = devfs_get_cdevpriv((void **)&priv)) != 0)
1783 return (err);
1784 d = priv->sc;
1785 if (!DSP_REGISTERED(d)) {
1786 /* XXX many clients don't understand POLLNVAL */
1787 return (events & (POLLHUP | POLLPRI | POLLIN |
1788 POLLRDNORM | POLLOUT | POLLWRNORM));
1789 }
1790 PCM_GIANT_ENTER(d);
1791
1792 ret = 0;
1793
1794 dsp_lock_chans(priv, FREAD | FWRITE);
1795 wrch = priv->wrch;
1796 rdch = priv->rdch;
1797
1798 if (wrch != NULL && !(wrch->flags & CHN_F_DEAD)) {
1799 e = (events & (POLLOUT | POLLWRNORM));
1800 if (e)
1801 ret |= chn_poll(wrch, e, td);
1802 }
1803
1804 if (rdch != NULL && !(rdch->flags & CHN_F_DEAD)) {
1805 e = (events & (POLLIN | POLLRDNORM));
1806 if (e)
1807 ret |= chn_poll(rdch, e, td);
1808 }
1809
1810 dsp_unlock_chans(priv, FREAD | FWRITE);
1811
1812 PCM_GIANT_LEAVE(d);
1813
1814 return (ret);
1815 }
1816
1817 static int
dsp_mmap(struct cdev * i_dev,vm_ooffset_t offset,vm_paddr_t * paddr,int nprot,vm_memattr_t * memattr)1818 dsp_mmap(struct cdev *i_dev, vm_ooffset_t offset, vm_paddr_t *paddr,
1819 int nprot, vm_memattr_t *memattr)
1820 {
1821
1822 /*
1823 * offset is in range due to checks in dsp_mmap_single().
1824 * XXX memattr is not honored.
1825 */
1826 *paddr = vtophys(offset);
1827 return (0);
1828 }
1829
1830 static int
dsp_mmap_single(struct cdev * i_dev,vm_ooffset_t * offset,vm_size_t size,struct vm_object ** object,int nprot)1831 dsp_mmap_single(struct cdev *i_dev, vm_ooffset_t *offset,
1832 vm_size_t size, struct vm_object **object, int nprot)
1833 {
1834 struct dsp_cdevpriv *priv;
1835 struct snddev_info *d;
1836 struct pcm_channel *wrch, *rdch, *c;
1837 int err;
1838
1839 /*
1840 * Reject PROT_EXEC by default. It just doesn't makes sense.
1841 * Unfortunately, we have to give up this one due to linux_mmap
1842 * changes.
1843 *
1844 * https://lists.freebsd.org/pipermail/freebsd-emulation/2007-June/003698.html
1845 *
1846 */
1847 #ifdef SV_ABI_LINUX
1848 if ((nprot & PROT_EXEC) && (dsp_mmap_allow_prot_exec < 0 ||
1849 (dsp_mmap_allow_prot_exec == 0 &&
1850 SV_CURPROC_ABI() != SV_ABI_LINUX)))
1851 #else
1852 if ((nprot & PROT_EXEC) && dsp_mmap_allow_prot_exec < 1)
1853 #endif
1854 return (EINVAL);
1855
1856 /*
1857 * PROT_READ (alone) selects the input buffer.
1858 * PROT_WRITE (alone) selects the output buffer.
1859 * PROT_WRITE|PROT_READ together select the output buffer.
1860 */
1861 if ((nprot & (PROT_READ | PROT_WRITE)) == 0)
1862 return (EINVAL);
1863
1864 if ((err = devfs_get_cdevpriv((void **)&priv)) != 0)
1865 return (err);
1866 d = priv->sc;
1867 if (!DSP_REGISTERED(d))
1868 return (EINVAL);
1869
1870 PCM_GIANT_ENTER(d);
1871
1872 dsp_lock_chans(priv, FREAD | FWRITE);
1873 wrch = priv->wrch;
1874 rdch = priv->rdch;
1875
1876 c = ((nprot & PROT_WRITE) != 0) ? wrch : rdch;
1877 if (c == NULL || (c->flags & CHN_F_MMAP_INVALID) ||
1878 (*offset + size) > sndbuf_getallocsize(c->bufsoft) ||
1879 (wrch != NULL && (wrch->flags & CHN_F_MMAP_INVALID)) ||
1880 (rdch != NULL && (rdch->flags & CHN_F_MMAP_INVALID))) {
1881 dsp_unlock_chans(priv, FREAD | FWRITE);
1882 PCM_GIANT_EXIT(d);
1883 return (EINVAL);
1884 }
1885
1886 if (wrch != NULL)
1887 wrch->flags |= CHN_F_MMAP;
1888 if (rdch != NULL)
1889 rdch->flags |= CHN_F_MMAP;
1890
1891 *offset = (uintptr_t)sndbuf_getbufofs(c->bufsoft, *offset);
1892 dsp_unlock_chans(priv, FREAD | FWRITE);
1893 *object = vm_pager_allocate(OBJT_DEVICE, i_dev,
1894 size, nprot, *offset, curthread->td_ucred);
1895
1896 PCM_GIANT_LEAVE(d);
1897
1898 if (*object == NULL)
1899 return (EINVAL);
1900 return (0);
1901 }
1902
1903 static const char *dsp_aliases[] = {
1904 "dsp_ac3",
1905 "dsp_mmap",
1906 "dsp_multich",
1907 "dsp_spdifout",
1908 "dsp_spdifin",
1909 };
1910
1911 static void
dsp_clone(void * arg,struct ucred * cred,char * name,int namelen,struct cdev ** dev)1912 dsp_clone(void *arg, struct ucred *cred, char *name, int namelen,
1913 struct cdev **dev)
1914 {
1915 struct snddev_info *d;
1916 size_t i;
1917
1918 if (*dev != NULL)
1919 return;
1920 if (strcmp(name, "dsp") == 0 && dsp_basename_clone)
1921 goto found;
1922 for (i = 0; i < nitems(dsp_aliases); i++) {
1923 if (strcmp(name, dsp_aliases[i]) == 0)
1924 goto found;
1925 }
1926 return;
1927 found:
1928 bus_topo_lock();
1929 d = devclass_get_softc(pcm_devclass, snd_unit);
1930 /*
1931 * If we only have a single soundcard attached and we detach it right
1932 * before entering dsp_clone(), there is a chance pcm_unregister() will
1933 * have returned already, meaning it will have set snd_unit to -1, and
1934 * thus devclass_get_softc() will return NULL here.
1935 */
1936 if (DSP_REGISTERED(d)) {
1937 *dev = d->dsp_dev;
1938 dev_ref(*dev);
1939 }
1940 bus_topo_unlock();
1941 }
1942
1943 static void
dsp_sysinit(void * p)1944 dsp_sysinit(void *p)
1945 {
1946 if (dsp_ehtag != NULL)
1947 return;
1948 dsp_ehtag = EVENTHANDLER_REGISTER(dev_clone, dsp_clone, 0, 1000);
1949 }
1950
1951 static void
dsp_sysuninit(void * p)1952 dsp_sysuninit(void *p)
1953 {
1954 if (dsp_ehtag == NULL)
1955 return;
1956 EVENTHANDLER_DEREGISTER(dev_clone, dsp_ehtag);
1957 dsp_ehtag = NULL;
1958 }
1959
1960 SYSINIT(dsp_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, dsp_sysinit, NULL);
1961 SYSUNINIT(dsp_sysuninit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, dsp_sysuninit, NULL);
1962
1963 static void
dsp_oss_audioinfo_unavail(oss_audioinfo * ai,int unit)1964 dsp_oss_audioinfo_unavail(oss_audioinfo *ai, int unit)
1965 {
1966 bzero(ai, sizeof(*ai));
1967 ai->dev = unit;
1968 snprintf(ai->name, sizeof(ai->name), "pcm%d (unavailable)", unit);
1969 ai->pid = -1;
1970 strlcpy(ai->cmd, CHN_COMM_UNUSED, sizeof(ai->cmd));
1971 ai->card_number = unit;
1972 ai->port_number = unit;
1973 ai->mixer_dev = -1;
1974 ai->legacy_device = unit;
1975 }
1976
1977 /**
1978 * @brief Handler for SNDCTL_AUDIOINFO.
1979 *
1980 * Gathers information about the audio device specified in ai->dev. If
1981 * ai->dev == -1, then this function gathers information about the current
1982 * device. If the call comes in on a non-audio device and ai->dev == -1,
1983 * return EINVAL.
1984 *
1985 * This routine is supposed to go practically straight to the hardware,
1986 * getting capabilities directly from the sound card driver, side-stepping
1987 * the intermediate channel interface.
1988 *
1989 * @note
1990 * Calling threads must not hold any snddev_info or pcm_channel locks.
1991 *
1992 * @param dev device on which the ioctl was issued
1993 * @param ai ioctl request data container
1994 * @param ex flag to distinguish between SNDCTL_AUDIOINFO from
1995 * SNDCTL_AUDIOINFO_EX
1996 *
1997 * @retval 0 success
1998 * @retval EINVAL ai->dev specifies an invalid device
1999 */
2000 int
dsp_oss_audioinfo(struct cdev * i_dev,oss_audioinfo * ai,bool ex)2001 dsp_oss_audioinfo(struct cdev *i_dev, oss_audioinfo *ai, bool ex)
2002 {
2003 struct pcmchan_caps *caps;
2004 struct pcm_channel *ch;
2005 struct snddev_info *d;
2006 uint32_t fmts;
2007 int i, minch, maxch, unit;
2008
2009 /*
2010 * If probing the device that received the ioctl, make sure it's a
2011 * DSP device. (Users may use this ioctl with /dev/mixer and
2012 * /dev/midi.)
2013 */
2014 if (ai->dev == -1 && i_dev->si_devsw != &dsp_cdevsw)
2015 return (EINVAL);
2016
2017 bus_topo_lock();
2018 for (unit = 0; pcm_devclass != NULL &&
2019 unit < devclass_get_maxunit(pcm_devclass); unit++) {
2020 d = devclass_get_softc(pcm_devclass, unit);
2021 if (!PCM_REGISTERED(d)) {
2022 if ((ai->dev == -1 && unit == snd_unit) ||
2023 ai->dev == unit) {
2024 dsp_oss_audioinfo_unavail(ai, unit);
2025 bus_topo_unlock();
2026 return (0);
2027 } else {
2028 d = NULL;
2029 continue;
2030 }
2031 }
2032
2033 PCM_UNLOCKASSERT(d);
2034 PCM_LOCK(d);
2035 if ((ai->dev == -1 && d->dsp_dev == i_dev) ||
2036 (ai->dev == unit)) {
2037 PCM_UNLOCK(d);
2038 break;
2039 } else {
2040 PCM_UNLOCK(d);
2041 d = NULL;
2042 }
2043 }
2044 bus_topo_unlock();
2045
2046 /* Exhausted the search -- nothing is locked, so return. */
2047 if (d == NULL)
2048 return (EINVAL);
2049
2050 /* XXX Need Giant magic entry ??? */
2051
2052 PCM_UNLOCKASSERT(d);
2053 PCM_LOCK(d);
2054
2055 bzero((void *)ai, sizeof(oss_audioinfo));
2056 ai->dev = unit;
2057 strlcpy(ai->name, device_get_desc(d->dev), sizeof(ai->name));
2058 ai->pid = -1;
2059 strlcpy(ai->cmd, CHN_COMM_UNKNOWN, sizeof(ai->cmd));
2060 ai->card_number = unit;
2061 ai->port_number = unit;
2062 ai->mixer_dev = (d->mixer_dev != NULL) ? unit : -1;
2063 ai->legacy_device = unit;
2064 snprintf(ai->devnode, sizeof(ai->devnode), "/dev/dsp%d", unit);
2065 ai->enabled = device_is_attached(d->dev) ? 1 : 0;
2066 ai->next_play_engine = 0;
2067 ai->next_rec_engine = 0;
2068 ai->busy = 0;
2069 ai->caps = PCM_CAP_REALTIME | PCM_CAP_MMAP | PCM_CAP_TRIGGER;
2070 ai->iformats = 0;
2071 ai->oformats = 0;
2072 ai->min_rate = INT_MAX;
2073 ai->max_rate = 0;
2074 ai->min_channels = INT_MAX;
2075 ai->max_channels = 0;
2076
2077 /* Gather global information about the device. */
2078 CHN_FOREACH(ch, d, channels.pcm) {
2079 CHN_UNLOCKASSERT(ch);
2080 CHN_LOCK(ch);
2081
2082 /*
2083 * Skip physical channels if we are servicing SNDCTL_AUDIOINFO,
2084 * or VCHANs if we are servicing SNDCTL_AUDIOINFO_EX.
2085 *
2086 * For SNDCTL_AUDIOINFO do not skip the physical channels if
2087 * there are no VCHANs.
2088 */
2089 if ((ex && (ch->flags & CHN_F_VIRTUAL) != 0) ||
2090 ((!ex && (ch->flags & CHN_F_VIRTUAL) == 0) &&
2091 (d->pvchancount > 0 || d->rvchancount > 0))) {
2092 CHN_UNLOCK(ch);
2093 continue;
2094 }
2095
2096 if ((ch->flags & CHN_F_BUSY) == 0) {
2097 ai->busy |= (ch->direction == PCMDIR_PLAY) ?
2098 OPEN_WRITE : OPEN_READ;
2099 }
2100
2101 ai->caps |=
2102 ((ch->flags & CHN_F_VIRTUAL) ? PCM_CAP_VIRTUAL : 0) |
2103 ((ch->direction == PCMDIR_PLAY) ? PCM_CAP_OUTPUT :
2104 PCM_CAP_INPUT);
2105
2106 caps = chn_getcaps(ch);
2107
2108 minch = INT_MAX;
2109 maxch = 0;
2110 fmts = 0;
2111 for (i = 0; caps->fmtlist[i]; i++) {
2112 fmts |= AFMT_ENCODING(caps->fmtlist[i]);
2113 minch = min(AFMT_CHANNEL(caps->fmtlist[i]), minch);
2114 maxch = max(AFMT_CHANNEL(caps->fmtlist[i]), maxch);
2115 }
2116
2117 if (ch->direction == PCMDIR_PLAY)
2118 ai->oformats |= fmts;
2119 else
2120 ai->iformats |= fmts;
2121
2122 if (ex || (pcm_getflags(d->dev) & SD_F_BITPERFECT)) {
2123 ai->min_rate = min(ai->min_rate, caps->minspeed);
2124 ai->max_rate = max(ai->max_rate, caps->maxspeed);
2125 } else {
2126 ai->min_rate = min(ai->min_rate, feeder_rate_min);
2127 ai->max_rate = max(ai->max_rate, feeder_rate_max);
2128 }
2129 ai->min_channels = min(ai->min_channels, minch);
2130 ai->max_channels = max(ai->max_channels, maxch);
2131
2132 CHN_UNLOCK(ch);
2133 }
2134 if (ai->min_rate == INT_MAX)
2135 ai->min_rate = 0;
2136 if (ai->min_channels == INT_MAX)
2137 ai->min_channels = 0;
2138
2139 PCM_UNLOCK(d);
2140
2141 return (0);
2142 }
2143
2144 static int
dsp_oss_engineinfo_cb(void * data,void * arg)2145 dsp_oss_engineinfo_cb(void *data, void *arg)
2146 {
2147 struct dsp_cdevpriv *priv = data;
2148 struct pcm_channel *ch = arg;
2149
2150 if (DSP_REGISTERED(priv->sc) && (ch == priv->rdch || ch == priv->wrch))
2151 return (1);
2152
2153 return (0);
2154 }
2155
2156 /**
2157 * @brief Handler for SNDCTL_ENGINEINFO
2158 *
2159 * Gathers information about the audio device's engine specified in ai->dev.
2160 * If ai->dev == -1, then this function gathers information about the current
2161 * device. If the call comes in on a non-audio device and ai->dev == -1,
2162 * return EINVAL.
2163 *
2164 * This routine is supposed to go practically straight to the hardware,
2165 * getting capabilities directly from the sound card driver, side-stepping
2166 * the intermediate channel interface.
2167 *
2168 * @note
2169 * Calling threads must not hold any snddev_info or pcm_channel locks.
2170 *
2171 * @param dev device on which the ioctl was issued
2172 * @param ai ioctl request data container
2173 *
2174 * @retval 0 success
2175 * @retval EINVAL ai->dev specifies an invalid device
2176 */
2177 int
dsp_oss_engineinfo(struct cdev * i_dev,oss_audioinfo * ai)2178 dsp_oss_engineinfo(struct cdev *i_dev, oss_audioinfo *ai)
2179 {
2180 struct pcmchan_caps *caps;
2181 struct pcm_channel *ch;
2182 struct snddev_info *d;
2183 uint32_t fmts;
2184 int i, nchan, *rates, minch, maxch, unit;
2185
2186 /*
2187 * If probing the device that received the ioctl, make sure it's a
2188 * DSP device. (Users may use this ioctl with /dev/mixer and
2189 * /dev/midi.)
2190 */
2191 if (ai->dev == -1 && i_dev->si_devsw != &dsp_cdevsw)
2192 return (EINVAL);
2193
2194 ch = NULL;
2195 nchan = 0;
2196
2197 /*
2198 * Search for the requested audio device (channel). Start by
2199 * iterating over pcm devices.
2200 */
2201 bus_topo_lock();
2202 for (unit = 0; pcm_devclass != NULL &&
2203 unit < devclass_get_maxunit(pcm_devclass); unit++) {
2204 d = devclass_get_softc(pcm_devclass, unit);
2205 if (!PCM_REGISTERED(d))
2206 continue;
2207
2208 /* XXX Need Giant magic entry ??? */
2209
2210 /* See the note in function docblock */
2211 PCM_UNLOCKASSERT(d);
2212 PCM_LOCK(d);
2213
2214 CHN_FOREACH(ch, d, channels.pcm) {
2215 CHN_UNLOCKASSERT(ch);
2216 CHN_LOCK(ch);
2217 if ((ai->dev == -1 && devfs_foreach_cdevpriv(
2218 i_dev, dsp_oss_engineinfo_cb, ch) != 0) ||
2219 ai->dev == nchan)
2220 break;
2221 CHN_UNLOCK(ch);
2222 ++nchan;
2223 }
2224
2225 if (ch == NULL) {
2226 PCM_UNLOCK(d);
2227 continue;
2228 }
2229
2230 /*
2231 * At this point, the following synchronization stuff
2232 * has happened:
2233 * - a specific PCM device is locked.
2234 * - a specific audio channel has been locked, so be
2235 * sure to unlock when exiting;
2236 */
2237
2238 caps = chn_getcaps(ch);
2239
2240 /*
2241 * With all handles collected, zero out the user's
2242 * container and begin filling in its fields.
2243 */
2244 bzero((void *)ai, sizeof(oss_audioinfo));
2245
2246 ai->dev = nchan;
2247 strlcpy(ai->name, ch->name, sizeof(ai->name));
2248
2249 if ((ch->flags & CHN_F_BUSY) == 0)
2250 ai->busy = 0;
2251 else
2252 ai->busy = (ch->direction == PCMDIR_PLAY) ? OPEN_WRITE : OPEN_READ;
2253
2254 ai->pid = ch->pid;
2255 strlcpy(ai->cmd, ch->comm, sizeof(ai->cmd));
2256
2257 /*
2258 * These flags stolen from SNDCTL_DSP_GETCAPS handler.
2259 * Note, however, that a single channel operates in
2260 * only one direction, so PCM_CAP_DUPLEX is out.
2261 */
2262 /**
2263 * @todo @c SNDCTL_AUDIOINFO::caps - Make drivers keep
2264 * these in pcmchan::caps?
2265 */
2266 ai->caps = PCM_CAP_REALTIME | PCM_CAP_MMAP | PCM_CAP_TRIGGER |
2267 ((ch->flags & CHN_F_VIRTUAL) ? PCM_CAP_VIRTUAL : 0) |
2268 ((ch->direction == PCMDIR_PLAY) ? PCM_CAP_OUTPUT : PCM_CAP_INPUT);
2269
2270 /*
2271 * Collect formats supported @b natively by the
2272 * device. Also determine min/max channels.
2273 */
2274 minch = INT_MAX;
2275 maxch = 0;
2276 fmts = 0;
2277 for (i = 0; caps->fmtlist[i]; i++) {
2278 fmts |= AFMT_ENCODING(caps->fmtlist[i]);
2279 minch = min(AFMT_CHANNEL(caps->fmtlist[i]), minch);
2280 maxch = max(AFMT_CHANNEL(caps->fmtlist[i]), maxch);
2281 }
2282
2283 if (ch->direction == PCMDIR_PLAY)
2284 ai->oformats = fmts;
2285 else
2286 ai->iformats = fmts;
2287
2288 /**
2289 * @note
2290 * @c magic - OSSv4 docs: "Reserved for internal use
2291 * by OSS."
2292 *
2293 * @par
2294 * @c card_number - OSSv4 docs: "Number of the sound
2295 * card where this device belongs or -1 if this
2296 * information is not available. Applications
2297 * should normally not use this field for any
2298 * purpose."
2299 */
2300 ai->card_number = unit;
2301 /**
2302 * @todo @c song_name - depends first on
2303 * SNDCTL_[GS]ETSONG @todo @c label - depends
2304 * on SNDCTL_[GS]ETLABEL
2305 * @todo @c port_number - routing information?
2306 */
2307 ai->port_number = unit;
2308 ai->mixer_dev = (d->mixer_dev != NULL) ? unit : -1;
2309 /**
2310 * @note
2311 * @c legacy_device - OSSv4 docs: "Obsolete."
2312 */
2313 ai->legacy_device = unit;
2314 snprintf(ai->devnode, sizeof(ai->devnode), "/dev/dsp%d", unit);
2315 ai->enabled = device_is_attached(d->dev) ? 1 : 0;
2316 /**
2317 * @note
2318 * @c flags - OSSv4 docs: "Reserved for future use."
2319 *
2320 * @note
2321 * @c binding - OSSv4 docs: "Reserved for future use."
2322 *
2323 * @todo @c handle - haven't decided how to generate
2324 * this yet; bus, vendor, device IDs?
2325 */
2326
2327 if ((ch->flags & CHN_F_EXCLUSIVE) ||
2328 (pcm_getflags(d->dev) & SD_F_BITPERFECT)) {
2329 ai->min_rate = caps->minspeed;
2330 ai->max_rate = caps->maxspeed;
2331 } else {
2332 ai->min_rate = feeder_rate_min;
2333 ai->max_rate = feeder_rate_max;
2334 }
2335
2336 ai->min_channels = minch;
2337 ai->max_channels = maxch;
2338
2339 ai->nrates = chn_getrates(ch, &rates);
2340 if (ai->nrates > OSS_MAX_SAMPLE_RATES)
2341 ai->nrates = OSS_MAX_SAMPLE_RATES;
2342
2343 for (i = 0; i < ai->nrates; i++)
2344 ai->rates[i] = rates[i];
2345
2346 ai->next_play_engine = 0;
2347 ai->next_rec_engine = 0;
2348
2349 CHN_UNLOCK(ch);
2350 PCM_UNLOCK(d);
2351 bus_topo_unlock();
2352
2353 return (0);
2354 }
2355 bus_topo_unlock();
2356
2357 /* Exhausted the search -- nothing is locked, so return. */
2358 return (EINVAL);
2359 }
2360
2361 /**
2362 * @brief Assigns a PCM channel to a sync group.
2363 *
2364 * Sync groups are used to enable audio operations on multiple devices
2365 * simultaneously. They may be used with any number of devices and may
2366 * span across applications. Devices are added to groups with
2367 * the SNDCTL_DSP_SYNCGROUP ioctl, and operations are triggered with the
2368 * SNDCTL_DSP_SYNCSTART ioctl.
2369 *
2370 * If the @c id field of the @c group parameter is set to zero, then a new
2371 * sync group is created. Otherwise, wrch and rdch (if set) are added to
2372 * the group specified.
2373 *
2374 * @todo As far as memory allocation, should we assume that things are
2375 * okay and allocate with M_WAITOK before acquiring channel locks,
2376 * freeing later if not?
2377 *
2378 * @param wrch output channel associated w/ device (if any)
2379 * @param rdch input channel associated w/ device (if any)
2380 * @param group Sync group parameters
2381 *
2382 * @retval 0 success
2383 * @retval non-zero error to be propagated upstream
2384 */
2385 static int
dsp_oss_syncgroup(struct pcm_channel * wrch,struct pcm_channel * rdch,oss_syncgroup * group)2386 dsp_oss_syncgroup(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_syncgroup *group)
2387 {
2388 struct pcmchan_syncmember *smrd, *smwr;
2389 struct pcmchan_syncgroup *sg;
2390 int ret, sg_ids[3];
2391
2392 smrd = NULL;
2393 smwr = NULL;
2394 sg = NULL;
2395 ret = 0;
2396
2397 /*
2398 * Free_unr() may sleep, so store released syncgroup IDs until after
2399 * all locks are released.
2400 */
2401 sg_ids[0] = sg_ids[1] = sg_ids[2] = 0;
2402
2403 PCM_SG_LOCK();
2404
2405 /*
2406 * - Insert channel(s) into group's member list.
2407 * - Set CHN_F_NOTRIGGER on channel(s).
2408 * - Stop channel(s).
2409 */
2410
2411 /*
2412 * If device's channels are already mapped to a group, unmap them.
2413 */
2414 if (wrch) {
2415 CHN_LOCK(wrch);
2416 sg_ids[0] = chn_syncdestroy(wrch);
2417 }
2418
2419 if (rdch) {
2420 CHN_LOCK(rdch);
2421 sg_ids[1] = chn_syncdestroy(rdch);
2422 }
2423
2424 /*
2425 * Verify that mode matches character device properites.
2426 * - Bail if PCM_ENABLE_OUTPUT && wrch == NULL.
2427 * - Bail if PCM_ENABLE_INPUT && rdch == NULL.
2428 */
2429 if (((wrch == NULL) && (group->mode & PCM_ENABLE_OUTPUT)) ||
2430 ((rdch == NULL) && (group->mode & PCM_ENABLE_INPUT))) {
2431 ret = EINVAL;
2432 goto out;
2433 }
2434
2435 /*
2436 * An id of zero indicates the user wants to create a new
2437 * syncgroup.
2438 */
2439 if (group->id == 0) {
2440 sg = malloc(sizeof(*sg), M_DEVBUF, M_NOWAIT);
2441 if (sg != NULL) {
2442 SLIST_INIT(&sg->members);
2443 sg->id = alloc_unr(pcmsg_unrhdr);
2444
2445 group->id = sg->id;
2446 SLIST_INSERT_HEAD(&snd_pcm_syncgroups, sg, link);
2447 } else
2448 ret = ENOMEM;
2449 } else {
2450 SLIST_FOREACH(sg, &snd_pcm_syncgroups, link) {
2451 if (sg->id == group->id)
2452 break;
2453 }
2454 if (sg == NULL)
2455 ret = EINVAL;
2456 }
2457
2458 /* Couldn't create or find a syncgroup. Fail. */
2459 if (sg == NULL)
2460 goto out;
2461
2462 /*
2463 * Allocate a syncmember, assign it and a channel together, and
2464 * insert into syncgroup.
2465 */
2466 if (group->mode & PCM_ENABLE_INPUT) {
2467 smrd = malloc(sizeof(*smrd), M_DEVBUF, M_NOWAIT);
2468 if (smrd == NULL) {
2469 ret = ENOMEM;
2470 goto out;
2471 }
2472
2473 SLIST_INSERT_HEAD(&sg->members, smrd, link);
2474 smrd->parent = sg;
2475 smrd->ch = rdch;
2476
2477 chn_abort(rdch);
2478 rdch->flags |= CHN_F_NOTRIGGER;
2479 rdch->sm = smrd;
2480 }
2481
2482 if (group->mode & PCM_ENABLE_OUTPUT) {
2483 smwr = malloc(sizeof(*smwr), M_DEVBUF, M_NOWAIT);
2484 if (smwr == NULL) {
2485 ret = ENOMEM;
2486 goto out;
2487 }
2488
2489 SLIST_INSERT_HEAD(&sg->members, smwr, link);
2490 smwr->parent = sg;
2491 smwr->ch = wrch;
2492
2493 chn_abort(wrch);
2494 wrch->flags |= CHN_F_NOTRIGGER;
2495 wrch->sm = smwr;
2496 }
2497
2498 out:
2499 if (ret != 0) {
2500 if (smrd != NULL)
2501 free(smrd, M_DEVBUF);
2502 if ((sg != NULL) && SLIST_EMPTY(&sg->members)) {
2503 sg_ids[2] = sg->id;
2504 SLIST_REMOVE(&snd_pcm_syncgroups, sg, pcmchan_syncgroup, link);
2505 free(sg, M_DEVBUF);
2506 }
2507
2508 if (wrch)
2509 wrch->sm = NULL;
2510 if (rdch)
2511 rdch->sm = NULL;
2512 }
2513
2514 if (wrch)
2515 CHN_UNLOCK(wrch);
2516 if (rdch)
2517 CHN_UNLOCK(rdch);
2518
2519 PCM_SG_UNLOCK();
2520
2521 if (sg_ids[0])
2522 free_unr(pcmsg_unrhdr, sg_ids[0]);
2523 if (sg_ids[1])
2524 free_unr(pcmsg_unrhdr, sg_ids[1]);
2525 if (sg_ids[2])
2526 free_unr(pcmsg_unrhdr, sg_ids[2]);
2527
2528 return (ret);
2529 }
2530
2531 /**
2532 * @brief Launch a sync group into action
2533 *
2534 * Sync groups are established via SNDCTL_DSP_SYNCGROUP. This function
2535 * iterates over all members, triggering them along the way.
2536 *
2537 * @note Caller must not hold any channel locks.
2538 *
2539 * @param sg_id sync group identifier
2540 *
2541 * @retval 0 success
2542 * @retval non-zero error worthy of propagating upstream to user
2543 */
2544 static int
dsp_oss_syncstart(int sg_id)2545 dsp_oss_syncstart(int sg_id)
2546 {
2547 struct pcmchan_syncmember *sm, *sm_tmp;
2548 struct pcmchan_syncgroup *sg;
2549 struct pcm_channel *c;
2550 int ret, needlocks;
2551
2552 /* Get the synclists lock */
2553 PCM_SG_LOCK();
2554
2555 do {
2556 ret = 0;
2557 needlocks = 0;
2558
2559 /* Search for syncgroup by ID */
2560 SLIST_FOREACH(sg, &snd_pcm_syncgroups, link) {
2561 if (sg->id == sg_id)
2562 break;
2563 }
2564
2565 /* Return EINVAL if not found */
2566 if (sg == NULL) {
2567 ret = EINVAL;
2568 break;
2569 }
2570
2571 /* Any removals resulting in an empty group should've handled this */
2572 KASSERT(!SLIST_EMPTY(&sg->members), ("found empty syncgroup"));
2573
2574 /*
2575 * Attempt to lock all member channels - if any are already
2576 * locked, unlock those acquired, sleep for a bit, and try
2577 * again.
2578 */
2579 SLIST_FOREACH(sm, &sg->members, link) {
2580 if (CHN_TRYLOCK(sm->ch) == 0) {
2581 int timo = hz * 5/1000;
2582 if (timo < 1)
2583 timo = 1;
2584
2585 /* Release all locked channels so far, retry */
2586 SLIST_FOREACH(sm_tmp, &sg->members, link) {
2587 /* sm is the member already locked */
2588 if (sm == sm_tmp)
2589 break;
2590 CHN_UNLOCK(sm_tmp->ch);
2591 }
2592
2593 /** @todo Is PRIBIO correct/ */
2594 ret = msleep(sm, &snd_pcm_syncgroups_mtx,
2595 PRIBIO | PCATCH, "pcmsg", timo);
2596 if (ret == EINTR || ret == ERESTART)
2597 break;
2598
2599 needlocks = 1;
2600 ret = 0; /* Assumes ret == EAGAIN... */
2601 }
2602 }
2603 } while (needlocks && ret == 0);
2604
2605 /* Proceed only if no errors encountered. */
2606 if (ret == 0) {
2607 /* Launch channels */
2608 while ((sm = SLIST_FIRST(&sg->members)) != NULL) {
2609 SLIST_REMOVE_HEAD(&sg->members, link);
2610
2611 c = sm->ch;
2612 c->sm = NULL;
2613 chn_start(c, 1);
2614 c->flags &= ~CHN_F_NOTRIGGER;
2615 CHN_UNLOCK(c);
2616
2617 free(sm, M_DEVBUF);
2618 }
2619
2620 SLIST_REMOVE(&snd_pcm_syncgroups, sg, pcmchan_syncgroup, link);
2621 free(sg, M_DEVBUF);
2622 }
2623
2624 PCM_SG_UNLOCK();
2625
2626 /*
2627 * Free_unr() may sleep, so be sure to give up the syncgroup lock
2628 * first.
2629 */
2630 if (ret == 0)
2631 free_unr(pcmsg_unrhdr, sg_id);
2632
2633 return (ret);
2634 }
2635
2636 /**
2637 * @brief Handler for SNDCTL_DSP_POLICY
2638 *
2639 * The SNDCTL_DSP_POLICY ioctl is a simpler interface to control fragment
2640 * size and count like with SNDCTL_DSP_SETFRAGMENT. Instead of the user
2641 * specifying those two parameters, s/he simply selects a number from 0..10
2642 * which corresponds to a buffer size. Smaller numbers request smaller
2643 * buffers with lower latencies (at greater overhead from more frequent
2644 * interrupts), while greater numbers behave in the opposite manner.
2645 *
2646 * The 4Front spec states that a value of 5 should be the default. However,
2647 * this implementation deviates slightly by using a linear scale without
2648 * consulting drivers. I.e., even though drivers may have different default
2649 * buffer sizes, a policy argument of 5 will have the same result across
2650 * all drivers.
2651 *
2652 * See http://manuals.opensound.com/developer/SNDCTL_DSP_POLICY.html for
2653 * more information.
2654 *
2655 * @todo When SNDCTL_DSP_COOKEDMODE is supported, it'll be necessary to
2656 * work with hardware drivers directly.
2657 *
2658 * @note PCM channel arguments must not be locked by caller.
2659 *
2660 * @param wrch Pointer to opened playback channel (optional; may be NULL)
2661 * @param rdch " recording channel (optional; may be NULL)
2662 * @param policy Integer from [0:10]
2663 *
2664 * @retval 0 constant (for now)
2665 */
2666 static int
dsp_oss_policy(struct pcm_channel * wrch,struct pcm_channel * rdch,int policy)2667 dsp_oss_policy(struct pcm_channel *wrch, struct pcm_channel *rdch, int policy)
2668 {
2669 int ret;
2670
2671 if (policy < CHN_POLICY_MIN || policy > CHN_POLICY_MAX)
2672 return (EIO);
2673
2674 /* Default: success */
2675 ret = 0;
2676
2677 if (rdch) {
2678 CHN_LOCK(rdch);
2679 ret = chn_setlatency(rdch, policy);
2680 CHN_UNLOCK(rdch);
2681 }
2682
2683 if (wrch && ret == 0) {
2684 CHN_LOCK(wrch);
2685 ret = chn_setlatency(wrch, policy);
2686 CHN_UNLOCK(wrch);
2687 }
2688
2689 if (ret)
2690 ret = EIO;
2691
2692 return (ret);
2693 }
2694
2695 /**
2696 * @brief Enable or disable "cooked" mode
2697 *
2698 * This is a handler for @c SNDCTL_DSP_COOKEDMODE. When in cooked mode, which
2699 * is the default, the sound system handles rate and format conversions
2700 * automatically (ex: user writing 11025Hz/8 bit/unsigned but card only
2701 * operates with 44100Hz/16bit/signed samples).
2702 *
2703 * Disabling cooked mode is intended for applications wanting to mmap()
2704 * a sound card's buffer space directly, bypassing the FreeBSD 2-stage
2705 * feeder architecture, presumably to gain as much control over audio
2706 * hardware as possible.
2707 *
2708 * See @c http://manuals.opensound.com/developer/SNDCTL_DSP_COOKEDMODE.html
2709 * for more details.
2710 *
2711 * @param wrch playback channel (optional; may be NULL)
2712 * @param rdch recording channel (optional; may be NULL)
2713 * @param enabled 0 = raw mode, 1 = cooked mode
2714 *
2715 * @retval EINVAL Operation not yet supported.
2716 */
2717 static int
dsp_oss_cookedmode(struct pcm_channel * wrch,struct pcm_channel * rdch,int enabled)2718 dsp_oss_cookedmode(struct pcm_channel *wrch, struct pcm_channel *rdch, int enabled)
2719 {
2720
2721 /*
2722 * XXX I just don't get it. Why don't they call it
2723 * "BITPERFECT" ~ SNDCTL_DSP_BITPERFECT !?!?.
2724 * This is just plain so confusing, incoherent,
2725 * <insert any non-printable characters here>.
2726 */
2727 if (!(enabled == 1 || enabled == 0))
2728 return (EINVAL);
2729
2730 /*
2731 * I won't give in. I'm inverting its logic here and now.
2732 * Brag all you want, but "BITPERFECT" should be the better
2733 * term here.
2734 */
2735 enabled ^= 0x00000001;
2736
2737 if (wrch != NULL) {
2738 CHN_LOCK(wrch);
2739 wrch->flags &= ~CHN_F_BITPERFECT;
2740 wrch->flags |= (enabled != 0) ? CHN_F_BITPERFECT : 0x00000000;
2741 CHN_UNLOCK(wrch);
2742 }
2743
2744 if (rdch != NULL) {
2745 CHN_LOCK(rdch);
2746 rdch->flags &= ~CHN_F_BITPERFECT;
2747 rdch->flags |= (enabled != 0) ? CHN_F_BITPERFECT : 0x00000000;
2748 CHN_UNLOCK(rdch);
2749 }
2750
2751 return (0);
2752 }
2753
2754 /**
2755 * @brief Retrieve channel interleaving order
2756 *
2757 * This is the handler for @c SNDCTL_DSP_GET_CHNORDER.
2758 *
2759 * See @c http://manuals.opensound.com/developer/SNDCTL_DSP_GET_CHNORDER.html
2760 * for more details.
2761 *
2762 * @note As the ioctl definition is still under construction, FreeBSD
2763 * does not currently support SNDCTL_DSP_GET_CHNORDER.
2764 *
2765 * @param wrch playback channel (optional; may be NULL)
2766 * @param rdch recording channel (optional; may be NULL)
2767 * @param map channel map (result will be stored there)
2768 *
2769 * @retval EINVAL Operation not yet supported.
2770 */
2771 static int
dsp_oss_getchnorder(struct pcm_channel * wrch,struct pcm_channel * rdch,unsigned long long * map)2772 dsp_oss_getchnorder(struct pcm_channel *wrch, struct pcm_channel *rdch, unsigned long long *map)
2773 {
2774 struct pcm_channel *ch;
2775 int ret;
2776
2777 ch = (wrch != NULL) ? wrch : rdch;
2778 if (ch != NULL) {
2779 CHN_LOCK(ch);
2780 ret = chn_oss_getorder(ch, map);
2781 CHN_UNLOCK(ch);
2782 } else
2783 ret = EINVAL;
2784
2785 return (ret);
2786 }
2787
2788 /**
2789 * @brief Specify channel interleaving order
2790 *
2791 * This is the handler for @c SNDCTL_DSP_SET_CHNORDER.
2792 *
2793 * @note As the ioctl definition is still under construction, FreeBSD
2794 * does not currently support @c SNDCTL_DSP_SET_CHNORDER.
2795 *
2796 * @param wrch playback channel (optional; may be NULL)
2797 * @param rdch recording channel (optional; may be NULL)
2798 * @param map channel map
2799 *
2800 * @retval EINVAL Operation not yet supported.
2801 */
2802 static int
dsp_oss_setchnorder(struct pcm_channel * wrch,struct pcm_channel * rdch,unsigned long long * map)2803 dsp_oss_setchnorder(struct pcm_channel *wrch, struct pcm_channel *rdch, unsigned long long *map)
2804 {
2805 int ret;
2806
2807 ret = 0;
2808
2809 if (wrch != NULL) {
2810 CHN_LOCK(wrch);
2811 ret = chn_oss_setorder(wrch, map);
2812 CHN_UNLOCK(wrch);
2813 }
2814
2815 if (ret == 0 && rdch != NULL) {
2816 CHN_LOCK(rdch);
2817 ret = chn_oss_setorder(rdch, map);
2818 CHN_UNLOCK(rdch);
2819 }
2820
2821 return (ret);
2822 }
2823
2824 static int
dsp_oss_getchannelmask(struct pcm_channel * wrch,struct pcm_channel * rdch,int * mask)2825 dsp_oss_getchannelmask(struct pcm_channel *wrch, struct pcm_channel *rdch,
2826 int *mask)
2827 {
2828 struct pcm_channel *ch;
2829 uint32_t chnmask;
2830 int ret;
2831
2832 chnmask = 0;
2833 ch = (wrch != NULL) ? wrch : rdch;
2834
2835 if (ch != NULL) {
2836 CHN_LOCK(ch);
2837 ret = chn_oss_getmask(ch, &chnmask);
2838 CHN_UNLOCK(ch);
2839 } else
2840 ret = EINVAL;
2841
2842 if (ret == 0)
2843 *mask = chnmask;
2844
2845 return (ret);
2846 }
2847
2848 #ifdef OSSV4_EXPERIMENT
2849 /**
2850 * @brief Retrieve an audio device's label
2851 *
2852 * This is a handler for the @c SNDCTL_GETLABEL ioctl.
2853 *
2854 * See @c http://manuals.opensound.com/developer/SNDCTL_GETLABEL.html
2855 * for more details.
2856 *
2857 * From Hannu@4Front: "For example ossxmix (just like some HW mixer
2858 * consoles) can show variable "labels" for certain controls. By default
2859 * the application name (say quake) is shown as the label but
2860 * applications may change the labels themselves."
2861 *
2862 * @note As the ioctl definition is still under construction, FreeBSD
2863 * does not currently support @c SNDCTL_GETLABEL.
2864 *
2865 * @param wrch playback channel (optional; may be NULL)
2866 * @param rdch recording channel (optional; may be NULL)
2867 * @param label label gets copied here
2868 *
2869 * @retval EINVAL Operation not yet supported.
2870 */
2871 static int
dsp_oss_getlabel(struct pcm_channel * wrch,struct pcm_channel * rdch,oss_label_t * label)2872 dsp_oss_getlabel(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_label_t *label)
2873 {
2874 return (EINVAL);
2875 }
2876
2877 /**
2878 * @brief Specify an audio device's label
2879 *
2880 * This is a handler for the @c SNDCTL_SETLABEL ioctl. Please see the
2881 * comments for @c dsp_oss_getlabel immediately above.
2882 *
2883 * See @c http://manuals.opensound.com/developer/SNDCTL_GETLABEL.html
2884 * for more details.
2885 *
2886 * @note As the ioctl definition is still under construction, FreeBSD
2887 * does not currently support SNDCTL_SETLABEL.
2888 *
2889 * @param wrch playback channel (optional; may be NULL)
2890 * @param rdch recording channel (optional; may be NULL)
2891 * @param label label gets copied from here
2892 *
2893 * @retval EINVAL Operation not yet supported.
2894 */
2895 static int
dsp_oss_setlabel(struct pcm_channel * wrch,struct pcm_channel * rdch,oss_label_t * label)2896 dsp_oss_setlabel(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_label_t *label)
2897 {
2898 return (EINVAL);
2899 }
2900
2901 /**
2902 * @brief Retrieve name of currently played song
2903 *
2904 * This is a handler for the @c SNDCTL_GETSONG ioctl. Audio players could
2905 * tell the system the name of the currently playing song, which would be
2906 * visible in @c /dev/sndstat.
2907 *
2908 * See @c http://manuals.opensound.com/developer/SNDCTL_GETSONG.html
2909 * for more details.
2910 *
2911 * @note As the ioctl definition is still under construction, FreeBSD
2912 * does not currently support SNDCTL_GETSONG.
2913 *
2914 * @param wrch playback channel (optional; may be NULL)
2915 * @param rdch recording channel (optional; may be NULL)
2916 * @param song song name gets copied here
2917 *
2918 * @retval EINVAL Operation not yet supported.
2919 */
2920 static int
dsp_oss_getsong(struct pcm_channel * wrch,struct pcm_channel * rdch,oss_longname_t * song)2921 dsp_oss_getsong(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *song)
2922 {
2923 return (EINVAL);
2924 }
2925
2926 /**
2927 * @brief Retrieve name of currently played song
2928 *
2929 * This is a handler for the @c SNDCTL_SETSONG ioctl. Audio players could
2930 * tell the system the name of the currently playing song, which would be
2931 * visible in @c /dev/sndstat.
2932 *
2933 * See @c http://manuals.opensound.com/developer/SNDCTL_SETSONG.html
2934 * for more details.
2935 *
2936 * @note As the ioctl definition is still under construction, FreeBSD
2937 * does not currently support SNDCTL_SETSONG.
2938 *
2939 * @param wrch playback channel (optional; may be NULL)
2940 * @param rdch recording channel (optional; may be NULL)
2941 * @param song song name gets copied from here
2942 *
2943 * @retval EINVAL Operation not yet supported.
2944 */
2945 static int
dsp_oss_setsong(struct pcm_channel * wrch,struct pcm_channel * rdch,oss_longname_t * song)2946 dsp_oss_setsong(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *song)
2947 {
2948 return (EINVAL);
2949 }
2950
2951 /**
2952 * @brief Rename a device
2953 *
2954 * This is a handler for the @c SNDCTL_SETNAME ioctl.
2955 *
2956 * See @c http://manuals.opensound.com/developer/SNDCTL_SETNAME.html for
2957 * more details.
2958 *
2959 * From Hannu@4Front: "This call is used to change the device name
2960 * reported in /dev/sndstat and ossinfo. So instead of using some generic
2961 * 'OSS loopback audio (MIDI) driver' the device may be given a meaningfull
2962 * name depending on the current context (for example 'OSS virtual wave table
2963 * synth' or 'VoIP link to London')."
2964 *
2965 * @note As the ioctl definition is still under construction, FreeBSD
2966 * does not currently support SNDCTL_SETNAME.
2967 *
2968 * @param wrch playback channel (optional; may be NULL)
2969 * @param rdch recording channel (optional; may be NULL)
2970 * @param name new device name gets copied from here
2971 *
2972 * @retval EINVAL Operation not yet supported.
2973 */
2974 static int
dsp_oss_setname(struct pcm_channel * wrch,struct pcm_channel * rdch,oss_longname_t * name)2975 dsp_oss_setname(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *name)
2976 {
2977 return (EINVAL);
2978 }
2979 #endif /* !OSSV4_EXPERIMENT */
2980