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