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