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