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