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