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