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 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 #ifdef HAVE_KERNEL_OPTION_HEADERS
32 #include "opt_snd.h"
33 #endif
34
35 #include <dev/sound/pcm/sound.h>
36
37 #include "feeder_if.h"
38 #include "mixer_if.h"
39
40 static MALLOC_DEFINE(M_MIXER, "mixer", "mixer");
41
42 static int mixer_bypass = 1;
43 SYSCTL_INT(_hw_snd, OID_AUTO, vpc_mixer_bypass, CTLFLAG_RWTUN,
44 &mixer_bypass, 0,
45 "control channel pcm/rec volume, bypassing real mixer device");
46
47 #define MIXER_NAMELEN 16
48 struct snd_mixer {
49 KOBJ_FIELDS;
50 void *devinfo;
51 int hwvol_mixer;
52 int hwvol_step;
53 int type;
54 device_t dev;
55 u_int32_t devs;
56 u_int32_t mutedevs;
57 u_int32_t recdevs;
58 u_int32_t recsrc;
59 u_int16_t level[32];
60 u_int16_t level_muted[32];
61 u_int8_t parent[32];
62 u_int32_t child[32];
63 u_int8_t realdev[32];
64 char name[MIXER_NAMELEN];
65 struct mtx lock;
66 oss_mixer_enuminfo enuminfo;
67 int modify_counter;
68 };
69
70 static u_int16_t snd_mixerdefaults[SOUND_MIXER_NRDEVICES] = {
71 [SOUND_MIXER_VOLUME] = 75,
72 [SOUND_MIXER_BASS] = 50,
73 [SOUND_MIXER_TREBLE] = 50,
74 [SOUND_MIXER_SYNTH] = 75,
75 [SOUND_MIXER_PCM] = 75,
76 [SOUND_MIXER_SPEAKER] = 75,
77 [SOUND_MIXER_LINE] = 75,
78 [SOUND_MIXER_MIC] = 25,
79 [SOUND_MIXER_CD] = 75,
80 [SOUND_MIXER_IGAIN] = 0,
81 [SOUND_MIXER_LINE1] = 75,
82 [SOUND_MIXER_VIDEO] = 75,
83 [SOUND_MIXER_RECLEV] = 75,
84 [SOUND_MIXER_OGAIN] = 50,
85 [SOUND_MIXER_MONITOR] = 75,
86 };
87
88 static char* snd_mixernames[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
89
90 static d_open_t mixer_open;
91 static d_close_t mixer_close;
92 static d_ioctl_t mixer_ioctl;
93
94 static struct cdevsw mixer_cdevsw = {
95 .d_version = D_VERSION,
96 .d_open = mixer_open,
97 .d_close = mixer_close,
98 .d_ioctl = mixer_ioctl,
99 .d_name = "mixer",
100 };
101
102 static eventhandler_tag mixer_ehtag = NULL;
103
104 static struct cdev *
mixer_get_devt(device_t dev)105 mixer_get_devt(device_t dev)
106 {
107 struct snddev_info *snddev;
108
109 snddev = device_get_softc(dev);
110
111 return snddev->mixer_dev;
112 }
113
114 static int
mixer_lookup(char * devname)115 mixer_lookup(char *devname)
116 {
117 int i;
118
119 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
120 if (strncmp(devname, snd_mixernames[i],
121 strlen(snd_mixernames[i])) == 0)
122 return i;
123 return -1;
124 }
125
126 #define MIXER_SET_UNLOCK(x, y) do { \
127 if ((y) != 0) \
128 mtx_unlock(&(x)->lock); \
129 } while (0)
130
131 #define MIXER_SET_LOCK(x, y) do { \
132 if ((y) != 0) \
133 mtx_lock(&(x)->lock); \
134 } while (0)
135
136 static int
mixer_set_softpcmvol(struct snd_mixer * m,struct snddev_info * d,u_int left,u_int right)137 mixer_set_softpcmvol(struct snd_mixer *m, struct snddev_info *d,
138 u_int left, u_int right)
139 {
140 struct pcm_channel *c;
141 int dropmtx, acquiremtx;
142
143 if (!PCM_REGISTERED(d))
144 return (EINVAL);
145
146 if (mtx_owned(&m->lock))
147 dropmtx = 1;
148 else
149 dropmtx = 0;
150
151 if (!(d->flags & SD_F_MPSAFE) || mtx_owned(&d->lock) != 0)
152 acquiremtx = 0;
153 else
154 acquiremtx = 1;
155
156 /*
157 * Be careful here. If we're coming from cdev ioctl, it is OK to
158 * not doing locking AT ALL (except on individual channel) since
159 * we've been heavily guarded by pcm cv, or if we're still
160 * under Giant influence. Since we also have mix_* calls, we cannot
161 * assume such protection and just do the lock as usuall.
162 */
163 MIXER_SET_UNLOCK(m, dropmtx);
164 MIXER_SET_LOCK(d, acquiremtx);
165
166 CHN_FOREACH(c, d, channels.pcm.busy) {
167 CHN_LOCK(c);
168 if (c->direction == PCMDIR_PLAY &&
169 (c->feederflags & (1 << FEEDER_VOLUME)))
170 chn_setvolume_multi(c, SND_VOL_C_MASTER, left, right,
171 (left + right) >> 1);
172 CHN_UNLOCK(c);
173 }
174
175 MIXER_SET_UNLOCK(d, acquiremtx);
176 MIXER_SET_LOCK(m, dropmtx);
177
178 return (0);
179 }
180
181 static int
mixer_set_eq(struct snd_mixer * m,struct snddev_info * d,u_int dev,u_int level)182 mixer_set_eq(struct snd_mixer *m, struct snddev_info *d,
183 u_int dev, u_int level)
184 {
185 struct pcm_channel *c;
186 struct pcm_feeder *f;
187 int tone, dropmtx, acquiremtx;
188
189 if (dev == SOUND_MIXER_TREBLE)
190 tone = FEEDEQ_TREBLE;
191 else if (dev == SOUND_MIXER_BASS)
192 tone = FEEDEQ_BASS;
193 else
194 return (EINVAL);
195
196 if (!PCM_REGISTERED(d))
197 return (EINVAL);
198
199 if (mtx_owned(&m->lock))
200 dropmtx = 1;
201 else
202 dropmtx = 0;
203
204 if (!(d->flags & SD_F_MPSAFE) || mtx_owned(&d->lock) != 0)
205 acquiremtx = 0;
206 else
207 acquiremtx = 1;
208
209 /*
210 * Be careful here. If we're coming from cdev ioctl, it is OK to
211 * not doing locking AT ALL (except on individual channel) since
212 * we've been heavily guarded by pcm cv, or if we're still
213 * under Giant influence. Since we also have mix_* calls, we cannot
214 * assume such protection and just do the lock as usuall.
215 */
216 MIXER_SET_UNLOCK(m, dropmtx);
217 MIXER_SET_LOCK(d, acquiremtx);
218
219 CHN_FOREACH(c, d, channels.pcm.busy) {
220 CHN_LOCK(c);
221 f = feeder_find(c, FEEDER_EQ);
222 if (f != NULL)
223 (void)FEEDER_SET(f, tone, level);
224 CHN_UNLOCK(c);
225 }
226
227 MIXER_SET_UNLOCK(d, acquiremtx);
228 MIXER_SET_LOCK(m, dropmtx);
229
230 return (0);
231 }
232
233 static int
mixer_set(struct snd_mixer * m,u_int dev,u_int32_t muted,u_int lev)234 mixer_set(struct snd_mixer *m, u_int dev, u_int32_t muted, u_int lev)
235 {
236 struct snddev_info *d;
237 u_int l, r, tl, tr;
238 u_int32_t parent = SOUND_MIXER_NONE, child = 0;
239 u_int32_t realdev;
240 int i, dropmtx;
241
242 if (m == NULL || dev >= SOUND_MIXER_NRDEVICES ||
243 (0 == (m->devs & (1 << dev))))
244 return (-1);
245
246 l = min((lev & 0x00ff), 100);
247 r = min(((lev & 0xff00) >> 8), 100);
248 realdev = m->realdev[dev];
249
250 d = device_get_softc(m->dev);
251 if (d == NULL)
252 return (-1);
253
254 /* It is safe to drop this mutex due to Giant. */
255 if (!(d->flags & SD_F_MPSAFE) && mtx_owned(&m->lock) != 0)
256 dropmtx = 1;
257 else
258 dropmtx = 0;
259
260 /* Allow the volume to be "changed" while muted. */
261 if (muted & (1 << dev)) {
262 m->level_muted[dev] = l | (r << 8);
263 return (0);
264 }
265 MIXER_SET_UNLOCK(m, dropmtx);
266
267 /* TODO: recursive handling */
268 parent = m->parent[dev];
269 if (parent >= SOUND_MIXER_NRDEVICES)
270 parent = SOUND_MIXER_NONE;
271 if (parent == SOUND_MIXER_NONE)
272 child = m->child[dev];
273
274 if (parent != SOUND_MIXER_NONE) {
275 tl = (l * (m->level[parent] & 0x00ff)) / 100;
276 tr = (r * ((m->level[parent] & 0xff00) >> 8)) / 100;
277 if (dev == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL))
278 (void)mixer_set_softpcmvol(m, d, tl, tr);
279 else if (realdev != SOUND_MIXER_NONE &&
280 MIXER_SET(m, realdev, tl, tr) < 0) {
281 MIXER_SET_LOCK(m, dropmtx);
282 return (-1);
283 }
284 } else if (child != 0) {
285 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
286 if (!(child & (1 << i)) || m->parent[i] != dev)
287 continue;
288 realdev = m->realdev[i];
289 tl = (l * (m->level[i] & 0x00ff)) / 100;
290 tr = (r * ((m->level[i] & 0xff00) >> 8)) / 100;
291 if (i == SOUND_MIXER_PCM &&
292 (d->flags & SD_F_SOFTPCMVOL))
293 (void)mixer_set_softpcmvol(m, d, tl, tr);
294 else if (realdev != SOUND_MIXER_NONE)
295 MIXER_SET(m, realdev, tl, tr);
296 }
297 realdev = m->realdev[dev];
298 if (realdev != SOUND_MIXER_NONE &&
299 MIXER_SET(m, realdev, l, r) < 0) {
300 MIXER_SET_LOCK(m, dropmtx);
301 return (-1);
302 }
303 } else {
304 if (dev == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL))
305 (void)mixer_set_softpcmvol(m, d, l, r);
306 else if ((dev == SOUND_MIXER_TREBLE ||
307 dev == SOUND_MIXER_BASS) && (d->flags & SD_F_EQ))
308 (void)mixer_set_eq(m, d, dev, (l + r) >> 1);
309 else if (realdev != SOUND_MIXER_NONE &&
310 MIXER_SET(m, realdev, l, r) < 0) {
311 MIXER_SET_LOCK(m, dropmtx);
312 return (-1);
313 }
314 }
315
316 MIXER_SET_LOCK(m, dropmtx);
317
318 m->level[dev] = l | (r << 8);
319 m->modify_counter++;
320
321 return (0);
322 }
323
324 static int
mixer_get(struct snd_mixer * mixer,int dev)325 mixer_get(struct snd_mixer *mixer, int dev)
326 {
327 if ((dev < SOUND_MIXER_NRDEVICES) && (mixer->devs & (1 << dev))) {
328 if (mixer->mutedevs & (1 << dev))
329 return (mixer->level_muted[dev]);
330 else
331 return (mixer->level[dev]);
332 } else {
333 return (-1);
334 }
335 }
336
337 void
mix_setmutedevs(struct snd_mixer * mixer,u_int32_t mutedevs)338 mix_setmutedevs(struct snd_mixer *mixer, u_int32_t mutedevs)
339 {
340 u_int32_t delta;
341
342 /* Filter out invalid values. */
343 mutedevs &= mixer->devs;
344 delta = (mixer->mutedevs ^ mutedevs) & mixer->devs;
345 mixer->mutedevs = mutedevs;
346
347 for (int i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
348 if (!(delta & (1 << i)))
349 continue;
350 if (mutedevs & (1 << i)) {
351 mixer->level_muted[i] = mixer->level[i];
352 mixer_set(mixer, i, 0, 0);
353 } else {
354 mixer_set(mixer, i, 0, mixer->level_muted[i]);
355 }
356 }
357 }
358
359 static int
mixer_setrecsrc(struct snd_mixer * mixer,u_int32_t src)360 mixer_setrecsrc(struct snd_mixer *mixer, u_int32_t src)
361 {
362 struct snddev_info *d;
363 u_int32_t recsrc;
364 int dropmtx;
365
366 d = device_get_softc(mixer->dev);
367 if (d == NULL)
368 return -1;
369 if (!(d->flags & SD_F_MPSAFE) && mtx_owned(&mixer->lock) != 0)
370 dropmtx = 1;
371 else
372 dropmtx = 0;
373 src &= mixer->recdevs;
374 if (src == 0)
375 src = mixer->recdevs & SOUND_MASK_MIC;
376 if (src == 0)
377 src = mixer->recdevs & SOUND_MASK_MONITOR;
378 if (src == 0)
379 src = mixer->recdevs & SOUND_MASK_LINE;
380 if (src == 0 && mixer->recdevs != 0)
381 src = (1 << (ffs(mixer->recdevs) - 1));
382 /* It is safe to drop this mutex due to Giant. */
383 MIXER_SET_UNLOCK(mixer, dropmtx);
384 recsrc = MIXER_SETRECSRC(mixer, src);
385 MIXER_SET_LOCK(mixer, dropmtx);
386
387 mixer->recsrc = recsrc;
388
389 return 0;
390 }
391
392 static int
mixer_getrecsrc(struct snd_mixer * mixer)393 mixer_getrecsrc(struct snd_mixer *mixer)
394 {
395 return mixer->recsrc;
396 }
397
398 /**
399 * @brief Retrieve the route number of the current recording device
400 *
401 * OSSv4 assigns routing numbers to recording devices, unlike the previous
402 * API which relied on a fixed table of device numbers and names. This
403 * function returns the routing number of the device currently selected
404 * for recording.
405 *
406 * For now, this function is kind of a goofy compatibility stub atop the
407 * existing sound system. (For example, in theory, the old sound system
408 * allows multiple recording devices to be specified via a bitmask.)
409 *
410 * @param m mixer context container thing
411 *
412 * @retval 0 success
413 * @retval EIDRM no recording device found (generally not possible)
414 * @todo Ask about error code
415 */
416 static int
mixer_get_recroute(struct snd_mixer * m,int * route)417 mixer_get_recroute(struct snd_mixer *m, int *route)
418 {
419 int i, cnt;
420
421 cnt = 0;
422
423 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
424 /** @todo can user set a multi-device mask? (== or &?) */
425 if ((1 << i) == m->recsrc)
426 break;
427 if ((1 << i) & m->recdevs)
428 ++cnt;
429 }
430
431 if (i == SOUND_MIXER_NRDEVICES)
432 return EIDRM;
433
434 *route = cnt;
435 return 0;
436 }
437
438 /**
439 * @brief Select a device for recording
440 *
441 * This function sets a recording source based on a recording device's
442 * routing number. Said number is translated to an old school recdev
443 * mask and passed over mixer_setrecsrc.
444 *
445 * @param m mixer context container thing
446 *
447 * @retval 0 success(?)
448 * @retval EINVAL User specified an invalid device number
449 * @retval otherwise error from mixer_setrecsrc
450 */
451 static int
mixer_set_recroute(struct snd_mixer * m,int route)452 mixer_set_recroute(struct snd_mixer *m, int route)
453 {
454 int i, cnt, ret;
455
456 ret = 0;
457 cnt = 0;
458
459 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
460 if ((1 << i) & m->recdevs) {
461 if (route == cnt)
462 break;
463 ++cnt;
464 }
465 }
466
467 if (i == SOUND_MIXER_NRDEVICES)
468 ret = EINVAL;
469 else
470 ret = mixer_setrecsrc(m, (1 << i));
471
472 return ret;
473 }
474
475 void
mix_setdevs(struct snd_mixer * m,u_int32_t v)476 mix_setdevs(struct snd_mixer *m, u_int32_t v)
477 {
478 struct snddev_info *d;
479 int i;
480
481 if (m == NULL)
482 return;
483
484 d = device_get_softc(m->dev);
485 if (d != NULL && (d->flags & SD_F_SOFTPCMVOL))
486 v |= SOUND_MASK_PCM;
487 if (d != NULL && (d->flags & SD_F_EQ))
488 v |= SOUND_MASK_TREBLE | SOUND_MASK_BASS;
489 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
490 if (m->parent[i] < SOUND_MIXER_NRDEVICES)
491 v |= 1 << m->parent[i];
492 v |= m->child[i];
493 }
494 m->devs = v;
495 }
496
497 /**
498 * @brief Record mask of available recording devices
499 *
500 * Calling functions are responsible for defining the mask of available
501 * recording devices. This function records that value in a structure
502 * used by the rest of the mixer code.
503 *
504 * This function also populates a structure used by the SNDCTL_DSP_*RECSRC*
505 * family of ioctls that are part of OSSV4. All recording device labels
506 * are concatenated in ascending order corresponding to their routing
507 * numbers. (Ex: a system might have 0 => 'vol', 1 => 'cd', 2 => 'line',
508 * etc.) For now, these labels are just the standard recording device
509 * names (cd, line1, etc.), but will eventually be fully dynamic and user
510 * controlled.
511 *
512 * @param m mixer device context container thing
513 * @param v mask of recording devices
514 */
515 void
mix_setrecdevs(struct snd_mixer * m,u_int32_t v)516 mix_setrecdevs(struct snd_mixer *m, u_int32_t v)
517 {
518 oss_mixer_enuminfo *ei;
519 char *loc;
520 int i, nvalues, nwrote, nleft, ncopied;
521
522 ei = &m->enuminfo;
523
524 nvalues = 0;
525 nwrote = 0;
526 nleft = sizeof(ei->strings);
527 loc = ei->strings;
528
529 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
530 if ((1 << i) & v) {
531 ei->strindex[nvalues] = nwrote;
532 ncopied = strlcpy(loc, snd_mixernames[i], nleft) + 1;
533 /* strlcpy retval doesn't include terminator */
534
535 nwrote += ncopied;
536 nleft -= ncopied;
537 nvalues++;
538
539 /*
540 * XXX I don't think this should ever be possible.
541 * Even with a move to dynamic device/channel names,
542 * each label is limited to ~16 characters, so that'd
543 * take a LOT to fill this buffer.
544 */
545 if ((nleft <= 0) || (nvalues >= OSS_ENUM_MAXVALUE)) {
546 device_printf(m->dev,
547 "mix_setrecdevs: Not enough room to store device names--please file a bug report.\n");
548 device_printf(m->dev,
549 "mix_setrecdevs: Please include details about your sound hardware, OS version, etc.\n");
550 break;
551 }
552
553 loc = &ei->strings[nwrote];
554 }
555 }
556
557 /*
558 * NB: The SNDCTL_DSP_GET_RECSRC_NAMES ioctl ignores the dev
559 * and ctrl fields.
560 */
561 ei->nvalues = nvalues;
562 m->recdevs = v;
563 }
564
565 void
mix_setparentchild(struct snd_mixer * m,u_int32_t parent,u_int32_t childs)566 mix_setparentchild(struct snd_mixer *m, u_int32_t parent, u_int32_t childs)
567 {
568 u_int32_t mask = 0;
569 int i;
570
571 if (m == NULL || parent >= SOUND_MIXER_NRDEVICES)
572 return;
573 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
574 if (i == parent)
575 continue;
576 if (childs & (1 << i)) {
577 mask |= 1 << i;
578 if (m->parent[i] < SOUND_MIXER_NRDEVICES)
579 m->child[m->parent[i]] &= ~(1 << i);
580 m->parent[i] = parent;
581 m->child[i] = 0;
582 }
583 }
584 mask &= ~(1 << parent);
585 m->child[parent] = mask;
586 }
587
588 void
mix_setrealdev(struct snd_mixer * m,u_int32_t dev,u_int32_t realdev)589 mix_setrealdev(struct snd_mixer *m, u_int32_t dev, u_int32_t realdev)
590 {
591 if (m == NULL || dev >= SOUND_MIXER_NRDEVICES ||
592 !(realdev == SOUND_MIXER_NONE || realdev < SOUND_MIXER_NRDEVICES))
593 return;
594 m->realdev[dev] = realdev;
595 }
596
597 u_int32_t
mix_getparent(struct snd_mixer * m,u_int32_t dev)598 mix_getparent(struct snd_mixer *m, u_int32_t dev)
599 {
600 if (m == NULL || dev >= SOUND_MIXER_NRDEVICES)
601 return SOUND_MIXER_NONE;
602 return m->parent[dev];
603 }
604
605 u_int32_t
mix_getdevs(struct snd_mixer * m)606 mix_getdevs(struct snd_mixer *m)
607 {
608 return m->devs;
609 }
610
611 u_int32_t
mix_getmutedevs(struct snd_mixer * m)612 mix_getmutedevs(struct snd_mixer *m)
613 {
614 return m->mutedevs;
615 }
616
617 u_int32_t
mix_getrecdevs(struct snd_mixer * m)618 mix_getrecdevs(struct snd_mixer *m)
619 {
620 return m->recdevs;
621 }
622
623 void *
mix_getdevinfo(struct snd_mixer * m)624 mix_getdevinfo(struct snd_mixer *m)
625 {
626 return m->devinfo;
627 }
628
629 static struct snd_mixer *
mixer_obj_create(device_t dev,kobj_class_t cls,void * devinfo,int type,const char * desc)630 mixer_obj_create(device_t dev, kobj_class_t cls, void *devinfo,
631 int type, const char *desc)
632 {
633 struct snd_mixer *m;
634 size_t i;
635
636 KASSERT(dev != NULL && cls != NULL && devinfo != NULL,
637 ("%s(): NULL data dev=%p cls=%p devinfo=%p",
638 __func__, dev, cls, devinfo));
639 KASSERT(type == MIXER_TYPE_PRIMARY || type == MIXER_TYPE_SECONDARY,
640 ("invalid mixer type=%d", type));
641
642 m = (struct snd_mixer *)kobj_create(cls, M_MIXER, M_WAITOK | M_ZERO);
643 snprintf(m->name, sizeof(m->name), "%s:mixer",
644 device_get_nameunit(dev));
645 if (desc != NULL) {
646 strlcat(m->name, ":", sizeof(m->name));
647 strlcat(m->name, desc, sizeof(m->name));
648 }
649 mtx_init(&m->lock, m->name, (type == MIXER_TYPE_PRIMARY) ?
650 "primary pcm mixer" : "secondary pcm mixer", MTX_DEF);
651 m->type = type;
652 m->devinfo = devinfo;
653 m->dev = dev;
654 for (i = 0; i < nitems(m->parent); i++) {
655 m->parent[i] = SOUND_MIXER_NONE;
656 m->child[i] = 0;
657 m->realdev[i] = i;
658 }
659
660 if (MIXER_INIT(m)) {
661 mtx_lock(&m->lock);
662 mtx_destroy(&m->lock);
663 kobj_delete((kobj_t)m, M_MIXER);
664 return (NULL);
665 }
666
667 return (m);
668 }
669
670 int
mixer_delete(struct snd_mixer * m)671 mixer_delete(struct snd_mixer *m)
672 {
673 KASSERT(m != NULL, ("NULL snd_mixer"));
674 KASSERT(m->type == MIXER_TYPE_SECONDARY,
675 ("%s(): illegal mixer type=%d", __func__, m->type));
676
677 /* mixer uninit can sleep --hps */
678
679 MIXER_UNINIT(m);
680
681 mtx_destroy(&m->lock);
682 kobj_delete((kobj_t)m, M_MIXER);
683
684 return (0);
685 }
686
687 struct snd_mixer *
mixer_create(device_t dev,kobj_class_t cls,void * devinfo,const char * desc)688 mixer_create(device_t dev, kobj_class_t cls, void *devinfo, const char *desc)
689 {
690 return (mixer_obj_create(dev, cls, devinfo, MIXER_TYPE_SECONDARY, desc));
691 }
692
693 int
mixer_init(device_t dev,kobj_class_t cls,void * devinfo)694 mixer_init(device_t dev, kobj_class_t cls, void *devinfo)
695 {
696 struct snddev_info *snddev;
697 struct snd_mixer *m;
698 u_int16_t v;
699 struct cdev *pdev;
700 const char *name;
701 int i, unit, val;
702
703 snddev = device_get_softc(dev);
704 if (snddev == NULL)
705 return (-1);
706
707 name = device_get_name(dev);
708 unit = device_get_unit(dev);
709 if (resource_int_value(name, unit, "eq", &val) == 0 &&
710 val != 0) {
711 snddev->flags |= SD_F_EQ;
712 if ((val & SD_F_EQ_MASK) == val)
713 snddev->flags |= val;
714 else
715 snddev->flags |= SD_F_EQ_DEFAULT;
716 snddev->eqpreamp = 0;
717 }
718
719 m = mixer_obj_create(dev, cls, devinfo, MIXER_TYPE_PRIMARY, NULL);
720 if (m == NULL)
721 return (-1);
722
723 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
724 v = snd_mixerdefaults[i];
725
726 if (resource_int_value(name, unit, snd_mixernames[i],
727 &val) == 0) {
728 if (val >= 0 && val <= 100) {
729 v = (u_int16_t) val;
730 }
731 }
732
733 mixer_set(m, i, 0, v | (v << 8));
734 }
735
736 mixer_setrecsrc(m, 0); /* Set default input. */
737
738 pdev = make_dev(&mixer_cdevsw, 0, UID_ROOT, GID_WHEEL, 0666, "mixer%d",
739 unit);
740 pdev->si_drv1 = m;
741 snddev->mixer_dev = pdev;
742
743 if (bootverbose) {
744 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
745 if (!(m->devs & (1 << i)))
746 continue;
747 if (m->realdev[i] != i) {
748 device_printf(dev, "Mixer \"%s\" -> \"%s\":",
749 snd_mixernames[i],
750 (m->realdev[i] < SOUND_MIXER_NRDEVICES) ?
751 snd_mixernames[m->realdev[i]] : "none");
752 } else {
753 device_printf(dev, "Mixer \"%s\":",
754 snd_mixernames[i]);
755 }
756 if (m->parent[i] < SOUND_MIXER_NRDEVICES)
757 printf(" parent=\"%s\"",
758 snd_mixernames[m->parent[i]]);
759 if (m->child[i] != 0)
760 printf(" child=0x%08x", m->child[i]);
761 printf("\n");
762 }
763 if (snddev->flags & SD_F_SOFTPCMVOL)
764 device_printf(dev, "Soft PCM mixer ENABLED\n");
765 if (snddev->flags & SD_F_EQ)
766 device_printf(dev, "EQ Treble/Bass ENABLED\n");
767 }
768
769 return (0);
770 }
771
772 int
mixer_uninit(device_t dev)773 mixer_uninit(device_t dev)
774 {
775 int i;
776 struct snddev_info *d;
777 struct snd_mixer *m;
778 struct cdev *pdev;
779
780 d = device_get_softc(dev);
781 pdev = mixer_get_devt(dev);
782 if (d == NULL || pdev == NULL || pdev->si_drv1 == NULL)
783 return EBADF;
784
785 m = pdev->si_drv1;
786 KASSERT(m != NULL, ("NULL snd_mixer"));
787 KASSERT(m->type == MIXER_TYPE_PRIMARY,
788 ("%s(): illegal mixer type=%d", __func__, m->type));
789
790 pdev->si_drv1 = NULL;
791 destroy_dev(pdev);
792
793 mtx_lock(&m->lock);
794
795 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
796 mixer_set(m, i, 0, 0);
797
798 mixer_setrecsrc(m, SOUND_MASK_MIC);
799
800 mtx_unlock(&m->lock);
801
802 /* mixer uninit can sleep --hps */
803
804 MIXER_UNINIT(m);
805
806 mtx_destroy(&m->lock);
807 kobj_delete((kobj_t)m, M_MIXER);
808
809 d->mixer_dev = NULL;
810
811 return 0;
812 }
813
814 int
mixer_reinit(device_t dev)815 mixer_reinit(device_t dev)
816 {
817 struct snd_mixer *m;
818 struct cdev *pdev;
819 int i;
820
821 pdev = mixer_get_devt(dev);
822 m = pdev->si_drv1;
823 mtx_lock(&m->lock);
824
825 i = MIXER_REINIT(m);
826 if (i) {
827 mtx_unlock(&m->lock);
828 return i;
829 }
830
831 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
832 if (m->mutedevs & (1 << i))
833 mixer_set(m, i, 0, 0);
834 else
835 mixer_set(m, i, 0, m->level[i]);
836 }
837
838 mixer_setrecsrc(m, m->recsrc);
839 mtx_unlock(&m->lock);
840
841 return 0;
842 }
843
844 static int
sysctl_hw_snd_hwvol_mixer(SYSCTL_HANDLER_ARGS)845 sysctl_hw_snd_hwvol_mixer(SYSCTL_HANDLER_ARGS)
846 {
847 char devname[32];
848 int error, dev;
849 struct snd_mixer *m;
850
851 m = oidp->oid_arg1;
852 mtx_lock(&m->lock);
853 strlcpy(devname, snd_mixernames[m->hwvol_mixer], sizeof(devname));
854 mtx_unlock(&m->lock);
855 error = sysctl_handle_string(oidp, &devname[0], sizeof(devname), req);
856 mtx_lock(&m->lock);
857 if (error == 0 && req->newptr != NULL) {
858 dev = mixer_lookup(devname);
859 if (dev == -1) {
860 mtx_unlock(&m->lock);
861 return EINVAL;
862 } else {
863 m->hwvol_mixer = dev;
864 }
865 }
866 mtx_unlock(&m->lock);
867 return error;
868 }
869
870 int
mixer_hwvol_init(device_t dev)871 mixer_hwvol_init(device_t dev)
872 {
873 struct snd_mixer *m;
874 struct cdev *pdev;
875
876 pdev = mixer_get_devt(dev);
877 m = pdev->si_drv1;
878
879 m->hwvol_mixer = SOUND_MIXER_VOLUME;
880 m->hwvol_step = 5;
881 SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
882 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
883 OID_AUTO, "hwvol_step", CTLFLAG_RWTUN, &m->hwvol_step, 0, "");
884 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
885 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
886 "hwvol_mixer", CTLTYPE_STRING | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
887 m, 0, sysctl_hw_snd_hwvol_mixer, "A", "");
888 return 0;
889 }
890
891 void
mixer_hwvol_mute_locked(struct snd_mixer * m)892 mixer_hwvol_mute_locked(struct snd_mixer *m)
893 {
894 mix_setmutedevs(m, m->mutedevs ^ (1 << m->hwvol_mixer));
895 }
896
897 void
mixer_hwvol_mute(device_t dev)898 mixer_hwvol_mute(device_t dev)
899 {
900 struct snd_mixer *m;
901 struct cdev *pdev;
902
903 pdev = mixer_get_devt(dev);
904 m = pdev->si_drv1;
905 mtx_lock(&m->lock);
906 mixer_hwvol_mute_locked(m);
907 mtx_unlock(&m->lock);
908 }
909
910 void
mixer_hwvol_step_locked(struct snd_mixer * m,int left_step,int right_step)911 mixer_hwvol_step_locked(struct snd_mixer *m, int left_step, int right_step)
912 {
913 int level, left, right;
914
915 level = mixer_get(m, m->hwvol_mixer);
916
917 if (level != -1) {
918 left = level & 0xff;
919 right = (level >> 8) & 0xff;
920 left += left_step * m->hwvol_step;
921 if (left < 0)
922 left = 0;
923 else if (left > 100)
924 left = 100;
925 right += right_step * m->hwvol_step;
926 if (right < 0)
927 right = 0;
928 else if (right > 100)
929 right = 100;
930
931 mixer_set(m, m->hwvol_mixer, m->mutedevs, left | right << 8);
932 }
933 }
934
935 void
mixer_hwvol_step(device_t dev,int left_step,int right_step)936 mixer_hwvol_step(device_t dev, int left_step, int right_step)
937 {
938 struct snd_mixer *m;
939 struct cdev *pdev;
940
941 pdev = mixer_get_devt(dev);
942 m = pdev->si_drv1;
943 mtx_lock(&m->lock);
944 mixer_hwvol_step_locked(m, left_step, right_step);
945 mtx_unlock(&m->lock);
946 }
947
948 int
mix_set(struct snd_mixer * m,u_int dev,u_int left,u_int right)949 mix_set(struct snd_mixer *m, u_int dev, u_int left, u_int right)
950 {
951 int ret;
952
953 KASSERT(m != NULL, ("NULL snd_mixer"));
954
955 mtx_lock(&m->lock);
956 ret = mixer_set(m, dev, m->mutedevs, left | (right << 8));
957 mtx_unlock(&m->lock);
958
959 return ((ret != 0) ? ENXIO : 0);
960 }
961
962 int
mix_get(struct snd_mixer * m,u_int dev)963 mix_get(struct snd_mixer *m, u_int dev)
964 {
965 int ret;
966
967 KASSERT(m != NULL, ("NULL snd_mixer"));
968
969 mtx_lock(&m->lock);
970 ret = mixer_get(m, dev);
971 mtx_unlock(&m->lock);
972
973 return (ret);
974 }
975
976 int
mix_setrecsrc(struct snd_mixer * m,u_int32_t src)977 mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
978 {
979 int ret;
980
981 KASSERT(m != NULL, ("NULL snd_mixer"));
982
983 mtx_lock(&m->lock);
984 ret = mixer_setrecsrc(m, src);
985 mtx_unlock(&m->lock);
986
987 return ((ret != 0) ? ENXIO : 0);
988 }
989
990 u_int32_t
mix_getrecsrc(struct snd_mixer * m)991 mix_getrecsrc(struct snd_mixer *m)
992 {
993 u_int32_t ret;
994
995 KASSERT(m != NULL, ("NULL snd_mixer"));
996
997 mtx_lock(&m->lock);
998 ret = mixer_getrecsrc(m);
999 mtx_unlock(&m->lock);
1000
1001 return (ret);
1002 }
1003
1004 device_t
mix_get_dev(struct snd_mixer * m)1005 mix_get_dev(struct snd_mixer *m)
1006 {
1007 KASSERT(m != NULL, ("NULL snd_mixer"));
1008
1009 return (m->dev);
1010 }
1011
1012 /* ----------------------------------------------------------------------- */
1013
1014 static int
mixer_open(struct cdev * i_dev,int flags,int mode,struct thread * td)1015 mixer_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
1016 {
1017 struct snddev_info *d;
1018 struct snd_mixer *m;
1019
1020 if (i_dev == NULL || i_dev->si_drv1 == NULL)
1021 return (EBADF);
1022
1023 m = i_dev->si_drv1;
1024 d = device_get_softc(m->dev);
1025 if (!PCM_REGISTERED(d))
1026 return (EBADF);
1027
1028 return (0);
1029 }
1030
1031 static int
mixer_close(struct cdev * i_dev,int flags,int mode,struct thread * td)1032 mixer_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
1033 {
1034 struct snddev_info *d;
1035 struct snd_mixer *m;
1036
1037 if (i_dev == NULL || i_dev->si_drv1 == NULL)
1038 return (EBADF);
1039
1040 m = i_dev->si_drv1;
1041 d = device_get_softc(m->dev);
1042 if (!PCM_REGISTERED(d))
1043 return (EBADF);
1044
1045 return (0);
1046 }
1047
1048 static int
mixer_ioctl_channel(struct cdev * dev,u_long cmd,caddr_t arg,int mode,struct thread * td,int from)1049 mixer_ioctl_channel(struct cdev *dev, u_long cmd, caddr_t arg, int mode,
1050 struct thread *td, int from)
1051 {
1052 struct snddev_info *d;
1053 struct snd_mixer *m;
1054 struct pcm_channel *c, *rdch, *wrch;
1055 pid_t pid;
1056 int j, ret;
1057
1058 if (td == NULL || td->td_proc == NULL)
1059 return (-1);
1060
1061 m = dev->si_drv1;
1062 d = device_get_softc(m->dev);
1063 j = cmd & 0xff;
1064
1065 switch (j) {
1066 case SOUND_MIXER_PCM:
1067 case SOUND_MIXER_RECLEV:
1068 case SOUND_MIXER_DEVMASK:
1069 case SOUND_MIXER_CAPS:
1070 case SOUND_MIXER_STEREODEVS:
1071 break;
1072 default:
1073 return (-1);
1074 break;
1075 }
1076
1077 pid = td->td_proc->p_pid;
1078 rdch = NULL;
1079 wrch = NULL;
1080 c = NULL;
1081 ret = -1;
1082
1083 /*
1084 * This is unfair. Imagine single proc opening multiple
1085 * instances of same direction. What we do right now
1086 * is looking for the first matching proc/pid, and just
1087 * that. Nothing more. Consider it done.
1088 *
1089 * The better approach of controlling specific channel
1090 * pcm or rec volume is by doing mixer ioctl
1091 * (SNDCTL_DSP_[SET|GET][PLAY|REC]VOL / SOUND_MIXER_[PCM|RECLEV]
1092 * on its open fd, rather than cracky mixer bypassing here.
1093 */
1094 CHN_FOREACH(c, d, channels.pcm.opened) {
1095 CHN_LOCK(c);
1096 if (c->pid != pid ||
1097 !(c->feederflags & (1 << FEEDER_VOLUME))) {
1098 CHN_UNLOCK(c);
1099 continue;
1100 }
1101 if (rdch == NULL && c->direction == PCMDIR_REC) {
1102 rdch = c;
1103 if (j == SOUND_MIXER_RECLEV)
1104 goto mixer_ioctl_channel_proc;
1105 } else if (wrch == NULL && c->direction == PCMDIR_PLAY) {
1106 wrch = c;
1107 if (j == SOUND_MIXER_PCM)
1108 goto mixer_ioctl_channel_proc;
1109 }
1110 CHN_UNLOCK(c);
1111 if (rdch != NULL && wrch != NULL)
1112 break;
1113 }
1114
1115 if (rdch == NULL && wrch == NULL)
1116 return (-1);
1117
1118 if ((j == SOUND_MIXER_DEVMASK || j == SOUND_MIXER_CAPS ||
1119 j == SOUND_MIXER_STEREODEVS) &&
1120 (cmd & ~0xff) == MIXER_READ(0)) {
1121 mtx_lock(&m->lock);
1122 *(int *)arg = mix_getdevs(m);
1123 mtx_unlock(&m->lock);
1124 if (rdch != NULL)
1125 *(int *)arg |= SOUND_MASK_RECLEV;
1126 if (wrch != NULL)
1127 *(int *)arg |= SOUND_MASK_PCM;
1128 ret = 0;
1129 }
1130
1131 return (ret);
1132
1133 mixer_ioctl_channel_proc:
1134
1135 KASSERT(c != NULL, ("%s(): NULL channel", __func__));
1136 CHN_LOCKASSERT(c);
1137
1138 if ((cmd & ~0xff) == MIXER_WRITE(0)) {
1139 int left, right, center;
1140
1141 left = *(int *)arg & 0x7f;
1142 right = (*(int *)arg >> 8) & 0x7f;
1143 center = (left + right) >> 1;
1144 chn_setvolume_multi(c, SND_VOL_C_PCM, left, right, center);
1145 } else if ((cmd & ~0xff) == MIXER_READ(0)) {
1146 *(int *)arg = CHN_GETVOLUME(c, SND_VOL_C_PCM, SND_CHN_T_FL);
1147 *(int *)arg |=
1148 CHN_GETVOLUME(c, SND_VOL_C_PCM, SND_CHN_T_FR) << 8;
1149 }
1150
1151 CHN_UNLOCK(c);
1152
1153 return (0);
1154 }
1155
1156 static int
mixer_ioctl(struct cdev * i_dev,u_long cmd,caddr_t arg,int mode,struct thread * td)1157 mixer_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode,
1158 struct thread *td)
1159 {
1160 struct snddev_info *d;
1161 int ret;
1162
1163 if (i_dev == NULL || i_dev->si_drv1 == NULL)
1164 return (EBADF);
1165
1166 d = device_get_softc(((struct snd_mixer *)i_dev->si_drv1)->dev);
1167 if (!PCM_REGISTERED(d))
1168 return (EBADF);
1169
1170 PCM_GIANT_ENTER(d);
1171 PCM_ACQUIRE_QUICK(d);
1172
1173 ret = -1;
1174
1175 if (mixer_bypass != 0 && (d->flags & SD_F_VPC))
1176 ret = mixer_ioctl_channel(i_dev, cmd, arg, mode, td,
1177 MIXER_CMD_CDEV);
1178
1179 if (ret == -1)
1180 ret = mixer_ioctl_cmd(i_dev, cmd, arg, mode, td,
1181 MIXER_CMD_CDEV);
1182
1183 PCM_RELEASE_QUICK(d);
1184 PCM_GIANT_LEAVE(d);
1185
1186 return (ret);
1187 }
1188
1189 static void
mixer_mixerinfo(struct snd_mixer * m,mixer_info * mi)1190 mixer_mixerinfo(struct snd_mixer *m, mixer_info *mi)
1191 {
1192 bzero((void *)mi, sizeof(*mi));
1193 strlcpy(mi->id, m->name, sizeof(mi->id));
1194 strlcpy(mi->name, device_get_desc(m->dev), sizeof(mi->name));
1195 mi->modify_counter = m->modify_counter;
1196 }
1197
1198 /*
1199 * XXX Make sure you can guarantee concurrency safety before calling this
1200 * function, be it through Giant, PCM_*, etc !
1201 */
1202 int
mixer_ioctl_cmd(struct cdev * i_dev,u_long cmd,caddr_t arg,int mode,struct thread * td,int from)1203 mixer_ioctl_cmd(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode,
1204 struct thread *td, int from)
1205 {
1206 struct snd_mixer *m;
1207 int ret = EINVAL, *arg_i = (int *)arg;
1208 int v = -1, j = cmd & 0xff;
1209
1210 /*
1211 * Certain ioctls may be made on any type of device (audio, mixer,
1212 * and MIDI). Handle those special cases here.
1213 */
1214 if (IOCGROUP(cmd) == 'X') {
1215 switch (cmd) {
1216 case SNDCTL_SYSINFO:
1217 sound_oss_sysinfo((oss_sysinfo *)arg);
1218 return (0);
1219 case SNDCTL_CARDINFO:
1220 return (sound_oss_card_info((oss_card_info *)arg));
1221 case SNDCTL_AUDIOINFO:
1222 return (dsp_oss_audioinfo(i_dev, (oss_audioinfo *)arg,
1223 false));
1224 case SNDCTL_AUDIOINFO_EX:
1225 return (dsp_oss_audioinfo(i_dev, (oss_audioinfo *)arg,
1226 true));
1227 case SNDCTL_ENGINEINFO:
1228 return (dsp_oss_engineinfo(i_dev, (oss_audioinfo *)arg));
1229 case SNDCTL_MIXERINFO:
1230 return (mixer_oss_mixerinfo(i_dev, (oss_mixerinfo *)arg));
1231 }
1232 return (EINVAL);
1233 }
1234
1235 m = i_dev->si_drv1;
1236
1237 if (m == NULL)
1238 return (EBADF);
1239
1240 mtx_lock(&m->lock);
1241 switch (cmd) {
1242 case SNDCTL_DSP_GET_RECSRC_NAMES:
1243 bcopy((void *)&m->enuminfo, arg, sizeof(oss_mixer_enuminfo));
1244 ret = 0;
1245 goto done;
1246 case SNDCTL_DSP_GET_RECSRC:
1247 ret = mixer_get_recroute(m, arg_i);
1248 goto done;
1249 case SNDCTL_DSP_SET_RECSRC:
1250 ret = mixer_set_recroute(m, *arg_i);
1251 goto done;
1252 case OSS_GETVERSION:
1253 *arg_i = SOUND_VERSION;
1254 ret = 0;
1255 goto done;
1256 case SOUND_MIXER_INFO:
1257 mixer_mixerinfo(m, (mixer_info *)arg);
1258 ret = 0;
1259 goto done;
1260 }
1261 if ((cmd & ~0xff) == MIXER_WRITE(0)) {
1262 switch (j) {
1263 case SOUND_MIXER_RECSRC:
1264 ret = mixer_setrecsrc(m, *arg_i);
1265 break;
1266 case SOUND_MIXER_MUTE:
1267 mix_setmutedevs(m, *arg_i);
1268 ret = 0;
1269 break;
1270 default:
1271 ret = mixer_set(m, j, m->mutedevs, *arg_i);
1272 break;
1273 }
1274 mtx_unlock(&m->lock);
1275 return ((ret == 0) ? 0 : ENXIO);
1276 }
1277 if ((cmd & ~0xff) == MIXER_READ(0)) {
1278 switch (j) {
1279 case SOUND_MIXER_DEVMASK:
1280 case SOUND_MIXER_CAPS:
1281 case SOUND_MIXER_STEREODEVS:
1282 v = mix_getdevs(m);
1283 break;
1284 case SOUND_MIXER_MUTE:
1285 v = mix_getmutedevs(m);
1286 break;
1287 case SOUND_MIXER_RECMASK:
1288 v = mix_getrecdevs(m);
1289 break;
1290 case SOUND_MIXER_RECSRC:
1291 v = mixer_getrecsrc(m);
1292 break;
1293 default:
1294 v = mixer_get(m, j);
1295 break;
1296 }
1297 *arg_i = v;
1298 mtx_unlock(&m->lock);
1299 return ((v != -1) ? 0 : ENXIO);
1300 }
1301 done:
1302 mtx_unlock(&m->lock);
1303 return (ret);
1304 }
1305
1306 static void
mixer_clone(void * arg,struct ucred * cred,char * name,int namelen,struct cdev ** dev)1307 mixer_clone(void *arg,
1308 struct ucred *cred,
1309 char *name, int namelen, struct cdev **dev)
1310 {
1311 struct snddev_info *d;
1312
1313 if (*dev != NULL)
1314 return;
1315 if (strcmp(name, "mixer") == 0) {
1316 bus_topo_lock();
1317 d = devclass_get_softc(pcm_devclass, snd_unit);
1318 /* See related comment in dsp_clone(). */
1319 if (PCM_REGISTERED(d) && d->mixer_dev != NULL) {
1320 *dev = d->mixer_dev;
1321 dev_ref(*dev);
1322 }
1323 bus_topo_unlock();
1324 }
1325 }
1326
1327 static void
mixer_sysinit(void * p)1328 mixer_sysinit(void *p)
1329 {
1330 if (mixer_ehtag != NULL)
1331 return;
1332 mixer_ehtag = EVENTHANDLER_REGISTER(dev_clone, mixer_clone, 0, 1000);
1333 }
1334
1335 static void
mixer_sysuninit(void * p)1336 mixer_sysuninit(void *p)
1337 {
1338 if (mixer_ehtag == NULL)
1339 return;
1340 EVENTHANDLER_DEREGISTER(dev_clone, mixer_ehtag);
1341 mixer_ehtag = NULL;
1342 }
1343
1344 SYSINIT(mixer_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, mixer_sysinit, NULL);
1345 SYSUNINIT(mixer_sysuninit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, mixer_sysuninit, NULL);
1346
1347 static void
mixer_oss_mixerinfo_unavail(oss_mixerinfo * mi,int unit)1348 mixer_oss_mixerinfo_unavail(oss_mixerinfo *mi, int unit)
1349 {
1350 bzero(mi, sizeof(*mi));
1351 mi->dev = unit;
1352 snprintf(mi->id, sizeof(mi->id), "mixer%d (n/a)", unit);
1353 snprintf(mi->name, sizeof(mi->name), "pcm%d:mixer (unavailable)", unit);
1354 mi->card_number = unit;
1355 mi->legacy_device = unit;
1356 }
1357
1358 /**
1359 * @brief Handler for SNDCTL_MIXERINFO
1360 *
1361 * This function searches for a mixer based on the numeric ID stored
1362 * in oss_miserinfo::dev. If set to -1, then information about the
1363 * current mixer handling the request is provided. Note, however, that
1364 * this ioctl may be made with any sound device (audio, mixer, midi).
1365 *
1366 * @note Caller must not hold any PCM device, channel, or mixer locks.
1367 *
1368 * See http://manuals.opensound.com/developer/SNDCTL_MIXERINFO.html for
1369 * more information.
1370 *
1371 * @param i_dev character device on which the ioctl arrived
1372 * @param arg user argument (oss_mixerinfo *)
1373 *
1374 * @retval EINVAL oss_mixerinfo::dev specified a bad value
1375 * @retval 0 success
1376 */
1377 int
mixer_oss_mixerinfo(struct cdev * i_dev,oss_mixerinfo * mi)1378 mixer_oss_mixerinfo(struct cdev *i_dev, oss_mixerinfo *mi)
1379 {
1380 struct snddev_info *d;
1381 struct snd_mixer *m;
1382 int i;
1383
1384 /*
1385 * If probing the device handling the ioctl, make sure it's a mixer
1386 * device. (This ioctl is valid on audio, mixer, and midi devices.)
1387 */
1388 if (mi->dev == -1 && i_dev->si_devsw != &mixer_cdevsw)
1389 return (EINVAL);
1390
1391 d = NULL;
1392 m = NULL;
1393
1394 /*
1395 * There's a 1:1 relationship between mixers and PCM devices, so
1396 * begin by iterating over PCM devices and search for our mixer.
1397 */
1398 bus_topo_lock();
1399 for (i = 0; pcm_devclass != NULL &&
1400 i < devclass_get_maxunit(pcm_devclass); i++) {
1401 d = devclass_get_softc(pcm_devclass, i);
1402 if (!PCM_REGISTERED(d)) {
1403 if ((mi->dev == -1 && i == snd_unit) || mi->dev == i) {
1404 mixer_oss_mixerinfo_unavail(mi, i);
1405 bus_topo_unlock();
1406 return (0);
1407 } else
1408 continue;
1409 }
1410
1411 /* XXX Need Giant magic entry */
1412
1413 /* See the note in function docblock. */
1414 PCM_UNLOCKASSERT(d);
1415 PCM_LOCK(d);
1416
1417 if (!((d->mixer_dev == i_dev && mi->dev == -1) ||
1418 mi->dev == i)) {
1419 PCM_UNLOCK(d);
1420 continue;
1421 }
1422
1423 if (d->mixer_dev->si_drv1 == NULL) {
1424 mixer_oss_mixerinfo_unavail(mi, i);
1425 PCM_UNLOCK(d);
1426 bus_topo_unlock();
1427 return (0);
1428 }
1429
1430 m = d->mixer_dev->si_drv1;
1431 mtx_lock(&m->lock);
1432
1433 /*
1434 * At this point, the following synchronization stuff
1435 * has happened:
1436 * - a specific PCM device is locked.
1437 * - a specific mixer device has been locked, so be
1438 * sure to unlock when existing.
1439 */
1440 bzero((void *)mi, sizeof(*mi));
1441 mi->dev = i;
1442 snprintf(mi->id, sizeof(mi->id), "mixer%d", i);
1443 strlcpy(mi->name, m->name, sizeof(mi->name));
1444 /**
1445 * Counter is incremented when applications change any of this
1446 * mixer's controls. A change in value indicates that
1447 * persistent mixer applications should update their displays.
1448 */
1449 mi->modify_counter = m->modify_counter;
1450 mi->card_number = i;
1451 /*
1452 * Currently, FreeBSD assumes 1:1 relationship between
1453 * a pcm and mixer devices, so this is hardcoded to 0.
1454 */
1455 mi->port_number = 0;
1456
1457 /**
1458 * @todo Fill in @sa oss_mixerinfo::mixerhandle.
1459 * @note From 4Front: "mixerhandle is an arbitrary
1460 * string that identifies the mixer better than
1461 * the device number (mixerinfo.dev). Device
1462 * numbers may change depending on the order the
1463 * drivers are loaded. However the handle should
1464 * remain the same provided that the sound card
1465 * is not moved to another PCI slot."
1466 */
1467
1468 /**
1469 * @note
1470 * @sa oss_mixerinfo::magic is a reserved field.
1471 *
1472 * @par
1473 * From 4Front: "magic is usually 0. However some
1474 * devices may have dedicated setup utilities and the
1475 * magic field may contain an unique driver specific
1476 * value (managed by [4Front])."
1477 */
1478
1479 mi->enabled = device_is_attached(m->dev) ? 1 : 0;
1480 /**
1481 * The only flag for @sa oss_mixerinfo::caps is
1482 * currently MIXER_CAP_VIRTUAL, which I'm not sure we
1483 * really worry about.
1484 */
1485 /**
1486 * Mixer extensions currently aren't supported, so
1487 * leave @sa oss_mixerinfo::nrext blank for now.
1488 */
1489
1490 /**
1491 * @todo Fill in @sa oss_mixerinfo::priority (requires
1492 * touching drivers?)
1493 * @note The priority field is for mixer applets to
1494 * determine which mixer should be the default, with 0
1495 * being least preferred and 10 being most preferred.
1496 * From 4Front: "OSS drivers like ICH use higher
1497 * values (10) because such chips are known to be used
1498 * only on motherboards. Drivers for high end pro
1499 * devices use 0 because they will never be the
1500 * default mixer. Other devices use values 1 to 9
1501 * depending on the estimated probability of being the
1502 * default device.
1503 */
1504
1505 snprintf(mi->devnode, sizeof(mi->devnode), "/dev/mixer%d", i);
1506 mi->legacy_device = i;
1507
1508 mtx_unlock(&m->lock);
1509
1510 PCM_UNLOCK(d);
1511
1512 bus_topo_unlock();
1513 return (0);
1514 }
1515 bus_topo_unlock();
1516
1517 return (EINVAL);
1518 }
1519
1520 /*
1521 * Allow the sound driver to use the mixer lock to protect its mixer
1522 * data:
1523 */
1524 struct mtx *
mixer_get_lock(struct snd_mixer * m)1525 mixer_get_lock(struct snd_mixer *m)
1526 {
1527 return (&m->lock);
1528 }
1529