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