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