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