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