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