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