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) 2026 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
41 #include "feeder_if.h"
42 #include "mixer_if.h"
43
44 static uint16_t snd_mixerdefaults[SOUND_MIXER_NRDEVICES] = {
45 [SOUND_MIXER_VOLUME] = 75,
46 [SOUND_MIXER_BASS] = 50,
47 [SOUND_MIXER_TREBLE] = 50,
48 [SOUND_MIXER_SYNTH] = 75,
49 [SOUND_MIXER_PCM] = 75,
50 [SOUND_MIXER_SPEAKER] = 75,
51 [SOUND_MIXER_LINE] = 75,
52 [SOUND_MIXER_MIC] = 25,
53 [SOUND_MIXER_CD] = 75,
54 [SOUND_MIXER_IGAIN] = 0,
55 [SOUND_MIXER_LINE1] = 75,
56 [SOUND_MIXER_VIDEO] = 75,
57 [SOUND_MIXER_RECLEV] = 75,
58 [SOUND_MIXER_OGAIN] = 50,
59 [SOUND_MIXER_MONITOR] = 75,
60 };
61
62 static char* snd_mixernames[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
63
64 static d_open_t mixer_open;
65 static d_close_t mixer_close;
66 static d_ioctl_t mixer_ioctl;
67
68 static struct cdevsw mixer_cdevsw = {
69 .d_version = D_VERSION,
70 .d_open = mixer_open,
71 .d_close = mixer_close,
72 .d_ioctl = mixer_ioctl,
73 .d_name = "mixer",
74 };
75
76 static eventhandler_tag mixer_ehtag = NULL;
77
78 static struct snd_mixer *
mixer_get_devt(device_t dev)79 mixer_get_devt(device_t dev)
80 {
81 struct snddev_info *snddev;
82
83 snddev = device_get_softc(dev);
84
85 return (snddev->mixer);
86 }
87
88 static int
mixer_lookup(char * devname)89 mixer_lookup(char *devname)
90 {
91 int i;
92
93 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
94 if (strncmp(devname, snd_mixernames[i],
95 strlen(snd_mixernames[i])) == 0)
96 return i;
97 return -1;
98 }
99
100 static int
mixer_set_softpcmvol(struct snd_mixer * m,struct snddev_info * d,unsigned int left,unsigned int right)101 mixer_set_softpcmvol(struct snd_mixer *m, struct snddev_info *d,
102 unsigned int left, unsigned int right)
103 {
104 struct pcm_channel *c;
105
106 if (!PCM_REGISTERED(d))
107 return (EINVAL);
108
109 CHN_FOREACH(c, d, channels.pcm.busy) {
110 CHN_LOCK(c);
111 if (c->direction == PCMDIR_PLAY &&
112 (c->feederflags & (1 << FEEDER_VOLUME)))
113 chn_setvolume_multi(c, SND_VOL_C_MASTER, left, right,
114 (left + right) >> 1);
115 CHN_UNLOCK(c);
116 }
117
118 return (0);
119 }
120
121 static int
mixer_set_eq(struct snd_mixer * m,struct snddev_info * d,unsigned int dev,unsigned int level)122 mixer_set_eq(struct snd_mixer *m, struct snddev_info *d,
123 unsigned int dev, unsigned int level)
124 {
125 struct pcm_channel *c;
126 struct pcm_feeder *f;
127 int tone;
128
129 if (dev == SOUND_MIXER_TREBLE)
130 tone = FEEDEQ_TREBLE;
131 else if (dev == SOUND_MIXER_BASS)
132 tone = FEEDEQ_BASS;
133 else
134 return (EINVAL);
135
136 if (!PCM_REGISTERED(d))
137 return (EINVAL);
138
139 CHN_FOREACH(c, d, channels.pcm.busy) {
140 CHN_LOCK(c);
141 f = feeder_find(c, FEEDER_EQ);
142 if (f != NULL)
143 (void)FEEDER_SET(f, tone, level);
144 CHN_UNLOCK(c);
145 }
146
147 return (0);
148 }
149
150 static int
mixer_set(struct snd_mixer * m,unsigned int dev,uint32_t muted,unsigned int lev)151 mixer_set(struct snd_mixer *m, unsigned int dev, uint32_t muted, unsigned int lev)
152 {
153 struct snddev_info *d;
154 unsigned int l, r, tl, tr;
155 uint32_t parent = SOUND_MIXER_NONE, child = 0;
156 uint32_t realdev;
157 int i;
158
159 if (m == NULL || dev >= SOUND_MIXER_NRDEVICES ||
160 (0 == (m->devs & (1 << dev))))
161 return (EINVAL);
162
163 l = min((lev & 0x00ff), 100);
164 r = min(((lev & 0xff00) >> 8), 100);
165 realdev = m->realdev[dev];
166
167 d = device_get_softc(m->dev);
168 if (d == NULL)
169 return (ENXIO);
170
171 /* Allow the volume to be "changed" while muted. */
172 if (muted & (1 << dev)) {
173 m->level_muted[dev] = l | (r << 8);
174 return (0);
175 }
176
177 /* TODO: recursive handling */
178 parent = m->parent[dev];
179 if (parent >= SOUND_MIXER_NRDEVICES)
180 parent = SOUND_MIXER_NONE;
181 if (parent == SOUND_MIXER_NONE)
182 child = m->child[dev];
183
184 if (parent != SOUND_MIXER_NONE) {
185 tl = (l * (m->level[parent] & 0x00ff)) / 100;
186 tr = (r * ((m->level[parent] & 0xff00) >> 8)) / 100;
187 if (dev == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL))
188 (void)mixer_set_softpcmvol(m, d, tl, tr);
189 else if (realdev != SOUND_MIXER_NONE &&
190 MIXER_SET(m, realdev, tl, tr) < 0)
191 return (EINVAL);
192 } else if (child != 0) {
193 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
194 if (!(child & (1 << i)) || m->parent[i] != dev)
195 continue;
196 realdev = m->realdev[i];
197 tl = (l * (m->level[i] & 0x00ff)) / 100;
198 tr = (r * ((m->level[i] & 0xff00) >> 8)) / 100;
199 if (i == SOUND_MIXER_PCM &&
200 (d->flags & SD_F_SOFTPCMVOL))
201 (void)mixer_set_softpcmvol(m, d, tl, tr);
202 else if (realdev != SOUND_MIXER_NONE)
203 MIXER_SET(m, realdev, tl, tr);
204 }
205 realdev = m->realdev[dev];
206 if (realdev != SOUND_MIXER_NONE &&
207 MIXER_SET(m, realdev, l, r) < 0)
208 return (EINVAL);
209 } else {
210 if (dev == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL))
211 (void)mixer_set_softpcmvol(m, d, l, r);
212 else if ((dev == SOUND_MIXER_TREBLE ||
213 dev == SOUND_MIXER_BASS) && (d->flags & SD_F_EQ))
214 (void)mixer_set_eq(m, d, dev, (l + r) >> 1);
215 else if (realdev != SOUND_MIXER_NONE &&
216 MIXER_SET(m, realdev, l, r) < 0)
217 return (EINVAL);
218 }
219
220 m->level[dev] = l | (r << 8);
221 m->modify_counter++;
222
223 return (0);
224 }
225
226 static int
mixer_get(struct snd_mixer * mixer,int dev)227 mixer_get(struct snd_mixer *mixer, int dev)
228 {
229 if ((dev < SOUND_MIXER_NRDEVICES) && (mixer->devs & (1 << dev))) {
230 if (mixer->mutedevs & (1 << dev))
231 return (mixer->level_muted[dev]);
232 else
233 return (mixer->level[dev]);
234 } else {
235 return (-1);
236 }
237 }
238
239 void
mix_setmutedevs(struct snd_mixer * mixer,uint32_t mutedevs)240 mix_setmutedevs(struct snd_mixer *mixer, uint32_t mutedevs)
241 {
242 uint32_t delta;
243
244 /* Filter out invalid values. */
245 mutedevs &= mixer->devs;
246 delta = (mixer->mutedevs ^ mutedevs) & mixer->devs;
247 mixer->mutedevs = mutedevs;
248
249 for (int i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
250 if (!(delta & (1 << i)))
251 continue;
252 if (mutedevs & (1 << i)) {
253 mixer->level_muted[i] = mixer->level[i];
254 mixer_set(mixer, i, 0, 0);
255 } else {
256 mixer_set(mixer, i, 0, mixer->level_muted[i]);
257 }
258 }
259 }
260
261 static int
mixer_setrecsrc(struct snd_mixer * mixer,uint32_t src)262 mixer_setrecsrc(struct snd_mixer *mixer, uint32_t src)
263 {
264 struct snddev_info *d;
265 uint32_t recsrc;
266
267 d = device_get_softc(mixer->dev);
268 if (d == NULL)
269 return (ENXIO);
270 src &= mixer->recdevs;
271 if (src == 0)
272 src = mixer->recdevs & SOUND_MASK_MIC;
273 if (src == 0)
274 src = mixer->recdevs & SOUND_MASK_MONITOR;
275 if (src == 0)
276 src = mixer->recdevs & SOUND_MASK_LINE;
277 if (src == 0 && mixer->recdevs != 0)
278 src = (1 << (ffs(mixer->recdevs) - 1));
279 recsrc = MIXER_SETRECSRC(mixer, src);
280
281 mixer->recsrc = recsrc;
282
283 return (0);
284 }
285
286 static int
mixer_getrecsrc(struct snd_mixer * mixer)287 mixer_getrecsrc(struct snd_mixer *mixer)
288 {
289 return mixer->recsrc;
290 }
291
292 /**
293 * @brief Retrieve the route number of the current recording device
294 *
295 * OSSv4 assigns routing numbers to recording devices, unlike the previous
296 * API which relied on a fixed table of device numbers and names. This
297 * function returns the routing number of the device currently selected
298 * for recording.
299 *
300 * For now, this function is kind of a goofy compatibility stub atop the
301 * existing sound system. (For example, in theory, the old sound system
302 * allows multiple recording devices to be specified via a bitmask.)
303 *
304 * @param m mixer context container thing
305 *
306 * @retval 0 success
307 * @retval EIDRM no recording device found (generally not possible)
308 * @todo Ask about error code
309 */
310 static int
mixer_get_recroute(struct snd_mixer * m,int * route)311 mixer_get_recroute(struct snd_mixer *m, int *route)
312 {
313 int i, cnt;
314
315 cnt = 0;
316
317 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
318 /** @todo can user set a multi-device mask? (== or &?) */
319 if ((1 << i) == m->recsrc)
320 break;
321 if ((1 << i) & m->recdevs)
322 ++cnt;
323 }
324
325 if (i == SOUND_MIXER_NRDEVICES)
326 return EIDRM;
327
328 *route = cnt;
329 return 0;
330 }
331
332 /**
333 * @brief Select a device for recording
334 *
335 * This function sets a recording source based on a recording device's
336 * routing number. Said number is translated to an old school recdev
337 * mask and passed over mixer_setrecsrc.
338 *
339 * @param m mixer context container thing
340 *
341 * @retval 0 success(?)
342 * @retval EINVAL User specified an invalid device number
343 * @retval otherwise error from mixer_setrecsrc
344 */
345 static int
mixer_set_recroute(struct snd_mixer * m,int route)346 mixer_set_recroute(struct snd_mixer *m, int route)
347 {
348 int i, cnt, ret;
349
350 ret = 0;
351 cnt = 0;
352
353 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
354 if ((1 << i) & m->recdevs) {
355 if (route == cnt)
356 break;
357 ++cnt;
358 }
359 }
360
361 if (i == SOUND_MIXER_NRDEVICES)
362 ret = EINVAL;
363 else
364 ret = mixer_setrecsrc(m, (1 << i));
365
366 return ret;
367 }
368
369 void
mix_setdevs(struct snd_mixer * m,uint32_t v)370 mix_setdevs(struct snd_mixer *m, uint32_t v)
371 {
372 struct snddev_info *d;
373 int i;
374
375 if (m == NULL)
376 return;
377
378 d = device_get_softc(m->dev);
379 if (d != NULL && (d->flags & SD_F_SOFTPCMVOL))
380 v |= SOUND_MASK_PCM;
381 v |= SOUND_MASK_TREBLE | SOUND_MASK_BASS;
382 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
383 if (m->parent[i] < SOUND_MIXER_NRDEVICES)
384 v |= 1 << m->parent[i];
385 v |= m->child[i];
386 }
387 m->devs = v;
388 }
389
390 /**
391 * @brief Record mask of available recording devices
392 *
393 * Calling functions are responsible for defining the mask of available
394 * recording devices. This function records that value in a structure
395 * used by the rest of the mixer code.
396 *
397 * @param m mixer device context container thing
398 * @param v mask of recording devices
399 */
400 void
mix_setrecdevs(struct snd_mixer * m,uint32_t v)401 mix_setrecdevs(struct snd_mixer *m, uint32_t v)
402 {
403 m->recdevs = v;
404 }
405
406 void
mix_setparentchild(struct snd_mixer * m,uint32_t parent,uint32_t childs)407 mix_setparentchild(struct snd_mixer *m, uint32_t parent, uint32_t childs)
408 {
409 uint32_t mask = 0;
410 int i;
411
412 if (m == NULL || parent >= SOUND_MIXER_NRDEVICES)
413 return;
414 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
415 if (i == parent)
416 continue;
417 if (childs & (1 << i)) {
418 mask |= 1 << i;
419 if (m->parent[i] < SOUND_MIXER_NRDEVICES)
420 m->child[m->parent[i]] &= ~(1 << i);
421 m->parent[i] = parent;
422 m->child[i] = 0;
423 }
424 }
425 mask &= ~(1 << parent);
426 m->child[parent] = mask;
427 }
428
429 void
mix_setrealdev(struct snd_mixer * m,uint32_t dev,uint32_t realdev)430 mix_setrealdev(struct snd_mixer *m, uint32_t dev, uint32_t realdev)
431 {
432 if (m == NULL || dev >= SOUND_MIXER_NRDEVICES ||
433 !(realdev == SOUND_MIXER_NONE || realdev < SOUND_MIXER_NRDEVICES))
434 return;
435 m->realdev[dev] = realdev;
436 }
437
438 uint32_t
mix_getparent(struct snd_mixer * m,uint32_t dev)439 mix_getparent(struct snd_mixer *m, uint32_t dev)
440 {
441 if (m == NULL || dev >= SOUND_MIXER_NRDEVICES)
442 return SOUND_MIXER_NONE;
443 return m->parent[dev];
444 }
445
446 uint32_t
mix_getdevs(struct snd_mixer * m)447 mix_getdevs(struct snd_mixer *m)
448 {
449 return m->devs;
450 }
451
452 uint32_t
mix_getmutedevs(struct snd_mixer * m)453 mix_getmutedevs(struct snd_mixer *m)
454 {
455 return m->mutedevs;
456 }
457
458 uint32_t
mix_getrecdevs(struct snd_mixer * m)459 mix_getrecdevs(struct snd_mixer *m)
460 {
461 return m->recdevs;
462 }
463
464 void *
mix_getdevinfo(struct snd_mixer * m)465 mix_getdevinfo(struct snd_mixer *m)
466 {
467 return m->devinfo;
468 }
469
470 static struct snd_mixer *
mixer_obj_create(device_t dev,kobj_class_t cls,void * devinfo,int type,const char * desc)471 mixer_obj_create(device_t dev, kobj_class_t cls, void *devinfo,
472 int type, const char *desc)
473 {
474 struct snddev_info *d;
475 struct snd_mixer *m;
476 size_t i;
477
478 KASSERT(dev != NULL && cls != NULL && devinfo != NULL,
479 ("%s(): NULL data dev=%p cls=%p devinfo=%p",
480 __func__, dev, cls, devinfo));
481 KASSERT(type == MIXER_TYPE_PRIMARY || type == MIXER_TYPE_SECONDARY,
482 ("invalid mixer type=%d", type));
483
484 m = (struct snd_mixer *)kobj_create(cls, M_DEVBUF, M_WAITOK | M_ZERO);
485 snprintf(m->name, sizeof(m->name), "%s:mixer",
486 device_get_nameunit(dev));
487 if (desc != NULL) {
488 strlcat(m->name, ":", sizeof(m->name));
489 strlcat(m->name, desc, sizeof(m->name));
490 }
491
492 d = device_get_softc(dev);
493 if (type == MIXER_TYPE_PRIMARY)
494 m->lock = &d->lock;
495 else {
496 mtx_init(&m->priv_lock, m->name, "secondary pcm mixer", MTX_DEF);
497 m->lock = &m->priv_lock;
498 }
499 m->type = type;
500 m->devinfo = devinfo;
501 m->dev = dev;
502 for (i = 0; i < nitems(m->parent); i++) {
503 m->parent[i] = SOUND_MIXER_NONE;
504 m->child[i] = 0;
505 m->realdev[i] = i;
506 }
507
508 if (MIXER_INIT(m)) {
509 if (type == MIXER_TYPE_SECONDARY)
510 mtx_destroy(m->lock);
511 kobj_delete((kobj_t)m, M_DEVBUF);
512 return (NULL);
513 }
514
515 return (m);
516 }
517
518 int
mixer_delete(struct snd_mixer * m)519 mixer_delete(struct snd_mixer *m)
520 {
521 KASSERT(m != NULL, ("NULL snd_mixer"));
522
523 /* mixer uninit can sleep --hps */
524
525 MIXER_UNINIT(m);
526
527 if (m->type == MIXER_TYPE_SECONDARY)
528 mtx_destroy(m->lock);
529 kobj_delete((kobj_t)m, M_DEVBUF);
530
531 return (0);
532 }
533
534 struct snd_mixer *
mixer_create(device_t dev,kobj_class_t cls,void * devinfo,const char * desc)535 mixer_create(device_t dev, kobj_class_t cls, void *devinfo, const char *desc)
536 {
537 return (mixer_obj_create(dev, cls, devinfo, MIXER_TYPE_SECONDARY, desc));
538 }
539
540 int
mixer_init(device_t dev,kobj_class_t cls,void * devinfo)541 mixer_init(device_t dev, kobj_class_t cls, void *devinfo)
542 {
543 struct snddev_info *snddev;
544 struct snd_mixer *m;
545 uint16_t v;
546 const char *name;
547 int i, unit, val;
548
549 snddev = device_get_softc(dev);
550 if (snddev == NULL)
551 return (-1);
552
553 name = device_get_name(dev);
554 unit = device_get_unit(dev);
555
556 m = mixer_obj_create(dev, cls, devinfo, MIXER_TYPE_PRIMARY, NULL);
557 if (m == NULL)
558 return (-1);
559
560 /* There is no need to lock here, but do it for consistency. */
561 mtx_lock(m->lock);
562
563 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
564 v = snd_mixerdefaults[i];
565
566 if (resource_int_value(name, unit, snd_mixernames[i],
567 &val) == 0) {
568 if (val >= 0 && val <= 100) {
569 v = (uint16_t) val;
570 }
571 }
572
573 mixer_set(m, i, 0, v | (v << 8));
574 }
575
576 mixer_setrecsrc(m, 0); /* Set default input. */
577
578 mtx_unlock(m->lock);
579
580 snddev->mixer = m;
581
582 if (bootverbose) {
583 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
584 if (!(m->devs & (1 << i)))
585 continue;
586 if (m->realdev[i] != i) {
587 device_printf(dev, "Mixer \"%s\" -> \"%s\":",
588 snd_mixernames[i],
589 (m->realdev[i] < SOUND_MIXER_NRDEVICES) ?
590 snd_mixernames[m->realdev[i]] : "none");
591 } else {
592 device_printf(dev, "Mixer \"%s\":",
593 snd_mixernames[i]);
594 }
595 if (m->parent[i] < SOUND_MIXER_NRDEVICES)
596 printf(" parent=\"%s\"",
597 snd_mixernames[m->parent[i]]);
598 if (m->child[i] != 0)
599 printf(" child=0x%08x", m->child[i]);
600 printf("\n");
601 }
602 if (snddev->flags & SD_F_SOFTPCMVOL)
603 device_printf(dev, "Soft PCM mixer ENABLED\n");
604 device_printf(dev, "EQ Treble/Bass ENABLED\n");
605 }
606
607 return (0);
608 }
609
610 int
mixer_uninit(device_t dev)611 mixer_uninit(device_t dev)
612 {
613 int i;
614 struct snd_mixer *m;
615
616 m = mixer_get_devt(dev);
617
618 KASSERT(m != NULL, ("NULL snd_mixer"));
619 KASSERT(m->type == MIXER_TYPE_PRIMARY,
620 ("%s(): illegal mixer type=%d", __func__, m->type));
621
622 /*
623 * snd_uaudio(4) in particular can call mixer_uninit() directly if
624 * attach failed prior to pcm_register(), in which case the cdev will
625 * not have been created. Do not call destroy_dev() unconditionally.
626 */
627 if (MIXER_REGISTERED(m))
628 destroy_dev(m->cdev);
629
630 mtx_lock(m->lock);
631
632 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
633 mixer_set(m, i, 0, 0);
634
635 mtx_unlock(m->lock);
636
637 /* mixer uninit can sleep --hps */
638
639 mixer_delete(m);
640
641 return 0;
642 }
643
644 int
mixer_reinit(device_t dev)645 mixer_reinit(device_t dev)
646 {
647 struct snd_mixer *m;
648 int i;
649
650 m = mixer_get_devt(dev);
651 mtx_lock(m->lock);
652
653 i = MIXER_REINIT(m);
654 if (i) {
655 mtx_unlock(m->lock);
656 return i;
657 }
658
659 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
660 if (m->mutedevs & (1 << i))
661 mixer_set(m, i, 0, 0);
662 else
663 mixer_set(m, i, 0, m->level[i]);
664 }
665
666 mixer_setrecsrc(m, m->recsrc);
667 mtx_unlock(m->lock);
668
669 return 0;
670 }
671
672 int
mixer_make_dev(device_t dev)673 mixer_make_dev(device_t dev)
674 {
675 struct make_dev_args devargs;
676 struct snddev_info *sc;
677 int err, unit;
678
679 sc = device_get_softc(dev);
680 unit = device_get_unit(dev);
681
682 make_dev_args_init(&devargs);
683 devargs.mda_devsw = &mixer_cdevsw;
684 devargs.mda_uid = UID_ROOT;
685 devargs.mda_gid = GID_AUDIO;
686 devargs.mda_mode = 0660;
687 devargs.mda_si_drv1 = sc->mixer;
688 err = make_dev_s(&devargs, &sc->mixer->cdev, "mixer%d", unit);
689 if (err != 0) {
690 device_printf(dev, "failed to create mixer%d: error %d\n",
691 unit, err);
692 return (err);
693 }
694
695 return (0);
696 }
697
698 static int
sysctl_hw_snd_hwvol_mixer(SYSCTL_HANDLER_ARGS)699 sysctl_hw_snd_hwvol_mixer(SYSCTL_HANDLER_ARGS)
700 {
701 char devname[32];
702 int error, dev;
703 struct snd_mixer *m;
704
705 m = oidp->oid_arg1;
706 strlcpy(devname, snd_mixernames[m->hwvol_mixer], sizeof(devname));
707 error = sysctl_handle_string(oidp, &devname[0], sizeof(devname), req);
708 if (error == 0 && req->newptr != NULL) {
709 if ((dev = mixer_lookup(devname)) == -1)
710 return (EINVAL);
711 mtx_lock(m->lock);
712 m->hwvol_mixer = dev;
713 mtx_unlock(m->lock);
714 }
715 return (error);
716 }
717
718 int
mixer_hwvol_init(device_t dev)719 mixer_hwvol_init(device_t dev)
720 {
721 struct snd_mixer *m;
722
723 m = mixer_get_devt(dev);
724
725 m->hwvol_mixer = SOUND_MIXER_VOLUME;
726 m->hwvol_step = 5;
727 SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
728 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
729 OID_AUTO, "hwvol_step", CTLFLAG_RWTUN, &m->hwvol_step, 0, "");
730 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
731 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
732 "hwvol_mixer", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
733 m, 0, sysctl_hw_snd_hwvol_mixer, "A", "");
734 return 0;
735 }
736
737 void
mixer_hwvol_mute(device_t dev)738 mixer_hwvol_mute(device_t dev)
739 {
740 struct snd_mixer *m;
741
742 m = mixer_get_devt(dev);
743 mtx_lock(m->lock);
744 mix_setmutedevs(m, m->mutedevs ^ (1 << m->hwvol_mixer));
745 mtx_unlock(m->lock);
746 }
747
748 void
mixer_hwvol_step(device_t dev,int left_step,int right_step)749 mixer_hwvol_step(device_t dev, int left_step, int right_step)
750 {
751 struct snd_mixer *m;
752 int level, left, right;
753
754 m = mixer_get_devt(dev);
755 mtx_lock(m->lock);
756 level = mixer_get(m, m->hwvol_mixer);
757 if (level != -1) {
758 left = level & 0xff;
759 right = (level >> 8) & 0xff;
760 left += left_step * m->hwvol_step;
761 if (left < 0)
762 left = 0;
763 else if (left > 100)
764 left = 100;
765 right += right_step * m->hwvol_step;
766 if (right < 0)
767 right = 0;
768 else if (right > 100)
769 right = 100;
770
771 mixer_set(m, m->hwvol_mixer, m->mutedevs, left | right << 8);
772 }
773 mtx_unlock(m->lock);
774 }
775
776 int
mix_set(struct snd_mixer * m,unsigned int dev,unsigned int left,unsigned int right)777 mix_set(struct snd_mixer *m, unsigned int dev, unsigned int left, unsigned int right)
778 {
779 int ret;
780
781 KASSERT(m != NULL, ("NULL snd_mixer"));
782
783 mtx_lock(m->lock);
784 ret = mixer_set(m, dev, m->mutedevs, left | (right << 8));
785 mtx_unlock(m->lock);
786
787 return (ret);
788 }
789
790 int
mix_get(struct snd_mixer * m,unsigned int dev)791 mix_get(struct snd_mixer *m, unsigned int dev)
792 {
793 int ret;
794
795 KASSERT(m != NULL, ("NULL snd_mixer"));
796
797 mtx_lock(m->lock);
798 ret = mixer_get(m, dev);
799 mtx_unlock(m->lock);
800
801 return (ret);
802 }
803
804 int
mix_setrecsrc(struct snd_mixer * m,uint32_t src)805 mix_setrecsrc(struct snd_mixer *m, uint32_t src)
806 {
807 int ret;
808
809 KASSERT(m != NULL, ("NULL snd_mixer"));
810
811 mtx_lock(m->lock);
812 ret = mixer_setrecsrc(m, src);
813 mtx_unlock(m->lock);
814
815 return (ret);
816 }
817
818 uint32_t
mix_getrecsrc(struct snd_mixer * m)819 mix_getrecsrc(struct snd_mixer *m)
820 {
821 uint32_t ret;
822
823 KASSERT(m != NULL, ("NULL snd_mixer"));
824
825 mtx_lock(m->lock);
826 ret = mixer_getrecsrc(m);
827 mtx_unlock(m->lock);
828
829 return (ret);
830 }
831
832 device_t
mix_get_dev(struct snd_mixer * m)833 mix_get_dev(struct snd_mixer *m)
834 {
835 KASSERT(m != NULL, ("NULL snd_mixer"));
836
837 return (m->dev);
838 }
839
840 /* ----------------------------------------------------------------------- */
841
842 static int
mixer_open(struct cdev * i_dev,int flags,int mode,struct thread * td)843 mixer_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
844 {
845 struct snddev_info *d;
846 struct snd_mixer *m;
847
848 m = i_dev->si_drv1;
849 if (m == NULL)
850 return (EBADF);
851 d = device_get_softc(m->dev);
852 if (!PCM_REGISTERED(d))
853 return (EBADF);
854
855 return (0);
856 }
857
858 static int
mixer_close(struct cdev * i_dev,int flags,int mode,struct thread * td)859 mixer_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
860 {
861 struct snddev_info *d;
862 struct snd_mixer *m;
863
864 m = i_dev->si_drv1;
865 if (m == NULL)
866 return (EBADF);
867 d = device_get_softc(m->dev);
868 if (!PCM_REGISTERED(d))
869 return (EBADF);
870
871 return (0);
872 }
873
874 static int
mixer_ioctl(struct cdev * i_dev,unsigned long cmd,caddr_t arg,int mode,struct thread * td)875 mixer_ioctl(struct cdev *i_dev, unsigned long cmd, caddr_t arg, int mode,
876 struct thread *td)
877 {
878 struct snddev_info *d;
879 struct snd_mixer *m;
880 int ret;
881
882 m = i_dev->si_drv1;
883 if (m == NULL)
884 return (EBADF);
885 d = device_get_softc(m->dev);
886 if (!PCM_REGISTERED(d))
887 return (EBADF);
888
889 PCM_GIANT_ENTER(d);
890 PCM_ACQUIRE_QUICK(d);
891
892 ret = mixer_ioctl_cmd(i_dev, cmd, arg, mode, td);
893
894 PCM_RELEASE_QUICK(d);
895 PCM_GIANT_LEAVE(d);
896
897 return (ret);
898 }
899
900 static void
mixer_mixerinfo(struct snd_mixer * m,mixer_info * mi)901 mixer_mixerinfo(struct snd_mixer *m, mixer_info *mi)
902 {
903 bzero((void *)mi, sizeof(*mi));
904 strlcpy(mi->id, m->name, sizeof(mi->id));
905 strlcpy(mi->name, device_get_desc(m->dev), sizeof(mi->name));
906 mi->modify_counter = m->modify_counter;
907 }
908
909 int
mixer_ioctl_cmd(struct cdev * i_dev,unsigned long cmd,caddr_t arg,int mode,struct thread * td)910 mixer_ioctl_cmd(struct cdev *i_dev, unsigned long cmd, caddr_t arg, int mode,
911 struct thread *td)
912 {
913 struct snd_mixer *m;
914 int ret = EINVAL, *arg_i = (int *)arg;
915 int v = -1, j = cmd & 0xff;
916
917 /*
918 * Certain ioctls may be made on any type of device (audio, mixer,
919 * and MIDI). Handle those special cases here.
920 */
921 if (IOCGROUP(cmd) == 'X') {
922 switch (cmd) {
923 case SNDCTL_SYSINFO:
924 sound_oss_sysinfo((oss_sysinfo *)arg);
925 return (0);
926 case SNDCTL_CARDINFO:
927 return (sound_oss_card_info((oss_card_info *)arg));
928 case SNDCTL_AUDIOINFO:
929 return (dsp_oss_audioinfo(i_dev, (oss_audioinfo *)arg,
930 false));
931 case SNDCTL_AUDIOINFO_EX:
932 return (dsp_oss_audioinfo(i_dev, (oss_audioinfo *)arg,
933 true));
934 case SNDCTL_ENGINEINFO:
935 return (dsp_oss_engineinfo(i_dev, (oss_audioinfo *)arg));
936 case SNDCTL_MIXERINFO:
937 return (mixer_oss_mixerinfo(i_dev, (oss_mixerinfo *)arg));
938 }
939 return (EINVAL);
940 }
941
942 m = i_dev->si_drv1;
943
944 if (m == NULL)
945 return (EBADF);
946
947 mtx_lock(m->lock);
948 switch (cmd) {
949 case SNDCTL_DSP_GET_RECSRC_NAMES: {
950 oss_mixer_enuminfo *ei = (oss_mixer_enuminfo *)arg;
951 char *loc;
952 int i, nvalues, nwrote, nleft, ncopied;
953
954 nvalues = 0;
955 nwrote = 0;
956 nleft = sizeof(ei->strings);
957 loc = ei->strings;
958
959 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
960 if (!((1 << i) & m->recdevs))
961 continue;
962 ei->strindex[nvalues] = nwrote;
963 ncopied = strlcpy(loc, snd_mixernames[i], nleft) + 1;
964 nwrote += ncopied;
965 nleft -= ncopied;
966 nvalues++;
967 loc = &ei->strings[nwrote];
968 }
969 ei->nvalues = nvalues;
970
971 ret = 0;
972 goto done;
973 }
974 case SNDCTL_DSP_GET_RECSRC:
975 ret = mixer_get_recroute(m, arg_i);
976 goto done;
977 case SNDCTL_DSP_SET_RECSRC:
978 ret = mixer_set_recroute(m, *arg_i);
979 goto done;
980 case OSS_GETVERSION:
981 *arg_i = SOUND_VERSION;
982 ret = 0;
983 goto done;
984 case SOUND_MIXER_INFO:
985 mixer_mixerinfo(m, (mixer_info *)arg);
986 ret = 0;
987 goto done;
988 }
989 if ((cmd & ~0xff) == MIXER_WRITE(0)) {
990 switch (j) {
991 case SOUND_MIXER_RECSRC:
992 ret = mixer_setrecsrc(m, *arg_i);
993 break;
994 case SOUND_MIXER_MUTE:
995 mix_setmutedevs(m, *arg_i);
996 ret = 0;
997 break;
998 default:
999 ret = mixer_set(m, j, m->mutedevs, *arg_i);
1000 break;
1001 }
1002 mtx_unlock(m->lock);
1003 return (ret);
1004 }
1005 if ((cmd & ~0xff) == MIXER_READ(0)) {
1006 switch (j) {
1007 case SOUND_MIXER_DEVMASK:
1008 case SOUND_MIXER_CAPS:
1009 case SOUND_MIXER_STEREODEVS:
1010 v = mix_getdevs(m);
1011 break;
1012 case SOUND_MIXER_MUTE:
1013 v = mix_getmutedevs(m);
1014 break;
1015 case SOUND_MIXER_RECMASK:
1016 v = mix_getrecdevs(m);
1017 break;
1018 case SOUND_MIXER_RECSRC:
1019 v = mixer_getrecsrc(m);
1020 break;
1021 default:
1022 v = mixer_get(m, j);
1023 break;
1024 }
1025 *arg_i = v;
1026 mtx_unlock(m->lock);
1027 return ((v != -1) ? 0 : ENXIO);
1028 }
1029 done:
1030 mtx_unlock(m->lock);
1031 return (ret);
1032 }
1033
1034 static void
mixer_clone(void * arg,struct ucred * cred,char * name,int namelen,struct cdev ** dev)1035 mixer_clone(void *arg,
1036 struct ucred *cred,
1037 char *name, int namelen, struct cdev **dev)
1038 {
1039 struct snddev_info *d;
1040
1041 if (*dev != NULL)
1042 return;
1043 if (strcmp(name, "mixer") == 0) {
1044 bus_topo_lock();
1045 d = devclass_get_softc(pcm_devclass, snd_unit);
1046 /* See related comment in dsp_clone(). */
1047 if (PCM_REGISTERED(d) && MIXER_REGISTERED(d->mixer)) {
1048 *dev = d->mixer->cdev;
1049 dev_ref(*dev);
1050 }
1051 bus_topo_unlock();
1052 }
1053 }
1054
1055 static void
mixer_sysinit(void * p)1056 mixer_sysinit(void *p)
1057 {
1058 if (mixer_ehtag != NULL)
1059 return;
1060 mixer_ehtag = EVENTHANDLER_REGISTER(dev_clone, mixer_clone, 0, 1000);
1061 }
1062
1063 static void
mixer_sysuninit(void * p)1064 mixer_sysuninit(void *p)
1065 {
1066 if (mixer_ehtag == NULL)
1067 return;
1068 EVENTHANDLER_DEREGISTER(dev_clone, mixer_ehtag);
1069 mixer_ehtag = NULL;
1070 }
1071
1072 SYSINIT(mixer_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, mixer_sysinit, NULL);
1073 SYSUNINIT(mixer_sysuninit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, mixer_sysuninit, NULL);
1074
1075 static void
mixer_oss_mixerinfo_unavail(oss_mixerinfo * mi,int unit)1076 mixer_oss_mixerinfo_unavail(oss_mixerinfo *mi, int unit)
1077 {
1078 bzero(mi, sizeof(*mi));
1079 mi->dev = unit;
1080 snprintf(mi->id, sizeof(mi->id), "mixer%d (n/a)", unit);
1081 snprintf(mi->name, sizeof(mi->name), "pcm%d:mixer (unavailable)", unit);
1082 mi->card_number = unit;
1083 mi->legacy_device = unit;
1084 }
1085
1086 /**
1087 * @brief Handler for SNDCTL_MIXERINFO
1088 *
1089 * This function searches for a mixer based on the numeric ID stored
1090 * in oss_miserinfo::dev. If set to -1, then information about the
1091 * current mixer handling the request is provided. Note, however, that
1092 * this ioctl may be made with any sound device (audio, mixer, midi).
1093 *
1094 * @note Caller must not hold any PCM device, channel, or mixer locks.
1095 *
1096 * See http://manuals.opensound.com/developer/SNDCTL_MIXERINFO.html for
1097 * more information.
1098 *
1099 * @param i_dev character device on which the ioctl arrived
1100 * @param arg user argument (oss_mixerinfo *)
1101 *
1102 * @retval EINVAL oss_mixerinfo::dev specified a bad value
1103 * @retval 0 success
1104 */
1105 int
mixer_oss_mixerinfo(struct cdev * i_dev,oss_mixerinfo * mi)1106 mixer_oss_mixerinfo(struct cdev *i_dev, oss_mixerinfo *mi)
1107 {
1108 struct snddev_info *d;
1109 struct snd_mixer *m;
1110 int i;
1111
1112 /*
1113 * If probing the device handling the ioctl, make sure it's a mixer
1114 * device. (This ioctl is valid on audio, mixer, and midi devices.)
1115 */
1116 if (mi->dev == -1 && i_dev->si_devsw != &mixer_cdevsw)
1117 return (EINVAL);
1118
1119 d = NULL;
1120 m = NULL;
1121
1122 /*
1123 * There's a 1:1 relationship between mixers and PCM devices, so
1124 * begin by iterating over PCM devices and search for our mixer.
1125 */
1126 bus_topo_lock();
1127 for (i = 0; pcm_devclass != NULL &&
1128 i < devclass_get_maxunit(pcm_devclass); i++) {
1129 d = devclass_get_softc(pcm_devclass, i);
1130 if (!PCM_REGISTERED(d)) {
1131 if ((mi->dev == -1 && i == snd_unit) || mi->dev == i) {
1132 mixer_oss_mixerinfo_unavail(mi, i);
1133 bus_topo_unlock();
1134 return (0);
1135 } else
1136 continue;
1137 }
1138
1139 /* XXX Need Giant magic entry */
1140
1141 /* See the note in function docblock. */
1142 PCM_UNLOCKASSERT(d);
1143 PCM_LOCK(d);
1144
1145 if (!MIXER_REGISTERED(d->mixer)) {
1146 if (mi->dev == i) {
1147 mixer_oss_mixerinfo_unavail(mi, i);
1148 PCM_UNLOCK(d);
1149 bus_topo_unlock();
1150 return (0);
1151 }
1152 PCM_UNLOCK(d);
1153 continue;
1154 }
1155
1156 if (!((d->mixer->cdev == i_dev && mi->dev == -1) ||
1157 mi->dev == i)) {
1158 PCM_UNLOCK(d);
1159 continue;
1160 }
1161
1162 m = d->mixer;
1163
1164 /*
1165 * At this point, the following synchronization stuff
1166 * has happened:
1167 * - a specific PCM device is locked.
1168 * - a specific mixer device has been locked, so be
1169 * sure to unlock when existing.
1170 */
1171 bzero((void *)mi, sizeof(*mi));
1172 mi->dev = i;
1173 snprintf(mi->id, sizeof(mi->id), "mixer%d", i);
1174 strlcpy(mi->name, m->name, sizeof(mi->name));
1175 /**
1176 * Counter is incremented when applications change any of this
1177 * mixer's controls. A change in value indicates that
1178 * persistent mixer applications should update their displays.
1179 */
1180 mi->modify_counter = m->modify_counter;
1181 mi->card_number = i;
1182 /*
1183 * Currently, FreeBSD assumes 1:1 relationship between
1184 * a pcm and mixer devices, so this is hardcoded to 0.
1185 */
1186 mi->port_number = 0;
1187
1188 /**
1189 * @todo Fill in @sa oss_mixerinfo::mixerhandle.
1190 * @note From 4Front: "mixerhandle is an arbitrary
1191 * string that identifies the mixer better than
1192 * the device number (mixerinfo.dev). Device
1193 * numbers may change depending on the order the
1194 * drivers are loaded. However the handle should
1195 * remain the same provided that the sound card
1196 * is not moved to another PCI slot."
1197 */
1198
1199 /**
1200 * @note
1201 * @sa oss_mixerinfo::magic is a reserved field.
1202 *
1203 * @par
1204 * From 4Front: "magic is usually 0. However some
1205 * devices may have dedicated setup utilities and the
1206 * magic field may contain an unique driver specific
1207 * value (managed by [4Front])."
1208 */
1209
1210 mi->enabled = device_is_attached(m->dev) ? 1 : 0;
1211 /**
1212 * The only flag for @sa oss_mixerinfo::caps is
1213 * currently MIXER_CAP_VIRTUAL, which I'm not sure we
1214 * really worry about.
1215 */
1216 /**
1217 * Mixer extensions currently aren't supported, so
1218 * leave @sa oss_mixerinfo::nrext blank for now.
1219 */
1220
1221 /**
1222 * @todo Fill in @sa oss_mixerinfo::priority (requires
1223 * touching drivers?)
1224 * @note The priority field is for mixer applets to
1225 * determine which mixer should be the default, with 0
1226 * being least preferred and 10 being most preferred.
1227 * From 4Front: "OSS drivers like ICH use higher
1228 * values (10) because such chips are known to be used
1229 * only on motherboards. Drivers for high end pro
1230 * devices use 0 because they will never be the
1231 * default mixer. Other devices use values 1 to 9
1232 * depending on the estimated probability of being the
1233 * default device.
1234 */
1235
1236 snprintf(mi->devnode, sizeof(mi->devnode), "/dev/mixer%d", i);
1237 mi->legacy_device = i;
1238
1239 PCM_UNLOCK(d);
1240
1241 bus_topo_unlock();
1242 return (0);
1243 }
1244 bus_topo_unlock();
1245
1246 return (EINVAL);
1247 }
1248