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