Changeset View
Changeset View
Standalone View
Standalone View
diff/mixer_kern.diff
- This file was added.
diff --git a/sys/dev/sound/pcm/mixer.c b/sys/dev/sound/pcm/mixer.c | |||||
index 92c5f3d613e..8275d1a2684 100644 | |||||
--- a/sys/dev/sound/pcm/mixer.c | |||||
+++ b/sys/dev/sound/pcm/mixer.c | |||||
@@ -51,16 +51,16 @@ struct snd_mixer { | |||||
KOBJ_FIELDS; | |||||
void *devinfo; | |||||
int busy; | |||||
- int hwvol_muted; | |||||
int hwvol_mixer; | |||||
int hwvol_step; | |||||
int type; | |||||
device_t dev; | |||||
- u_int32_t hwvol_mute_level; | |||||
u_int32_t devs; | |||||
+ u_int32_t mutedevs; | |||||
u_int32_t recdevs; | |||||
u_int32_t recsrc; | |||||
u_int16_t level[32]; | |||||
+ u_int16_t level_muted[32]; | |||||
u_int8_t parent[32]; | |||||
u_int32_t child[32]; | |||||
u_int8_t realdev[32]; | |||||
@@ -244,7 +244,7 @@ mixer_set_eq(struct snd_mixer *m, struct snddev_info *d, | |||||
} | |||||
static int | |||||
-mixer_set(struct snd_mixer *m, u_int dev, u_int lev) | |||||
+mixer_set(struct snd_mixer *m, u_int dev, u_int32_t muted, u_int lev) | |||||
{ | |||||
struct snddev_info *d; | |||||
u_int l, r, tl, tr; | |||||
@@ -254,7 +254,7 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int lev) | |||||
if (m == NULL || dev >= SOUND_MIXER_NRDEVICES || | |||||
(0 == (m->devs & (1 << dev)))) | |||||
- return -1; | |||||
+ return (-1); | |||||
l = min((lev & 0x00ff), 100); | |||||
r = min(((lev & 0xff00) >> 8), 100); | |||||
@@ -262,7 +262,7 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int lev) | |||||
d = device_get_softc(m->dev); | |||||
if (d == NULL) | |||||
- return -1; | |||||
+ return (-1); | |||||
/* It is safe to drop this mutex due to Giant. */ | |||||
if (!(d->flags & SD_F_MPSAFE) && mtx_owned(m->lock) != 0) | |||||
@@ -270,6 +270,11 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int lev) | |||||
else | |||||
dropmtx = 0; | |||||
+ /* Allow the volume to be "changed" while muted. */ | |||||
+ if (muted & (1 << dev)) { | |||||
+ m->level_muted[dev] = l | (r << 8); | |||||
+ return (0); | |||||
+ } | |||||
MIXER_SET_UNLOCK(m, dropmtx); | |||||
/* TODO: recursive handling */ | |||||
@@ -287,7 +292,7 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int lev) | |||||
else if (realdev != SOUND_MIXER_NONE && | |||||
MIXER_SET(m, realdev, tl, tr) < 0) { | |||||
MIXER_SET_LOCK(m, dropmtx); | |||||
- return -1; | |||||
+ return (-1); | |||||
} | |||||
} else if (child != 0) { | |||||
for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { | |||||
@@ -305,8 +310,8 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int lev) | |||||
realdev = m->realdev[dev]; | |||||
if (realdev != SOUND_MIXER_NONE && | |||||
MIXER_SET(m, realdev, l, r) < 0) { | |||||
- MIXER_SET_LOCK(m, dropmtx); | |||||
- return -1; | |||||
+ MIXER_SET_LOCK(m, dropmtx); | |||||
+ return (-1); | |||||
} | |||||
} else { | |||||
if (dev == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL)) | |||||
@@ -317,7 +322,7 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int lev) | |||||
else if (realdev != SOUND_MIXER_NONE && | |||||
MIXER_SET(m, realdev, l, r) < 0) { | |||||
MIXER_SET_LOCK(m, dropmtx); | |||||
- return -1; | |||||
+ return (-1); | |||||
} | |||||
} | |||||
@@ -326,16 +331,43 @@ mixer_set(struct snd_mixer *m, u_int dev, u_int lev) | |||||
m->level[dev] = l | (r << 8); | |||||
m->modify_counter++; | |||||
- return 0; | |||||
+ return (0); | |||||
} | |||||
static int | |||||
mixer_get(struct snd_mixer *mixer, int dev) | |||||
{ | |||||
- if ((dev < SOUND_MIXER_NRDEVICES) && (mixer->devs & (1 << dev))) | |||||
- return mixer->level[dev]; | |||||
- else | |||||
- return -1; | |||||
+ if ((dev < SOUND_MIXER_NRDEVICES) && (mixer->devs & (1 << dev))) { | |||||
+ if (mixer->mutedevs & (1 << dev)) | |||||
+ return (mixer->level_muted[dev]); | |||||
+ else | |||||
+ return (mixer->level[dev]); | |||||
+ } else { | |||||
+ return (-1); | |||||
+ } | |||||
+} | |||||
+ | |||||
+void | |||||
+mix_setmutedevs(struct snd_mixer *mixer, u_int32_t mutedevs) | |||||
+{ | |||||
+ int i; | |||||
+ u_int32_t delta; | |||||
+ | |||||
+ /* Filter out invalid values. */ | |||||
+ mutedevs &= mixer->devs; | |||||
+ delta = (mixer->mutedevs ^ mutedevs) & mixer->devs; | |||||
+ mixer->mutedevs = mutedevs; | |||||
+ | |||||
+ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { | |||||
+ if (!(delta & (1 << i))) | |||||
+ continue; | |||||
+ if (mutedevs & (1 << i)) { | |||||
+ mixer->level_muted[i] = mixer->level[i]; | |||||
+ mixer_set(mixer, i, 0, 0); | |||||
+ } else { | |||||
+ mixer_set(mixer, i, 0, mixer->level_muted[i]); | |||||
+ } | |||||
+ } | |||||
} | |||||
static int | |||||
@@ -598,6 +630,12 @@ mix_getdevs(struct snd_mixer *m) | |||||
return m->devs; | |||||
} | |||||
+u_int32_t | |||||
+mix_getmutedevs(struct snd_mixer *m) | |||||
+{ | |||||
+ return m->mutedevs; | |||||
+} | |||||
+ | |||||
u_int32_t | |||||
mix_getrecdevs(struct snd_mixer *m) | |||||
{ | |||||
@@ -721,7 +759,7 @@ mixer_init(device_t dev, kobj_class_t cls, void *devinfo) | |||||
} | |||||
} | |||||
- mixer_set(m, i, v | (v << 8)); | |||||
+ mixer_set(m, i, 0, v | (v << 8)); | |||||
} | |||||
mixer_setrecsrc(m, 0); /* Set default input. */ | |||||
@@ -799,7 +837,7 @@ mixer_uninit(device_t dev) | |||||
snd_mtxlock(m->lock); | |||||
for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) | |||||
- mixer_set(m, i, 0); | |||||
+ mixer_set(m, i, 0, 0); | |||||
mixer_setrecsrc(m, SOUND_MASK_MIC); | |||||
@@ -836,8 +874,12 @@ mixer_reinit(device_t dev) | |||||
return i; | |||||
} | |||||
- for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) | |||||
- mixer_set(m, i, m->level[i]); | |||||
+ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { | |||||
+ if (m->mutedevs & (1 << i)) | |||||
+ mixer_set(m, i, 0, 0); | |||||
+ else | |||||
+ mixer_set(m, i, 0, m->level[i]); | |||||
+ } | |||||
mixer_setrecsrc(m, m->recsrc); | |||||
snd_mtxunlock(m->lock); | |||||
@@ -863,10 +905,8 @@ sysctl_hw_snd_hwvol_mixer(SYSCTL_HANDLER_ARGS) | |||||
if (dev == -1) { | |||||
snd_mtxunlock(m->lock); | |||||
return EINVAL; | |||||
- } | |||||
- else if (dev != m->hwvol_mixer) { | |||||
+ } else { | |||||
m->hwvol_mixer = dev; | |||||
- m->hwvol_muted = 0; | |||||
} | |||||
} | |||||
snd_mtxunlock(m->lock); | |||||
@@ -897,14 +937,7 @@ mixer_hwvol_init(device_t dev) | |||||
void | |||||
mixer_hwvol_mute_locked(struct snd_mixer *m) | |||||
{ | |||||
- if (m->hwvol_muted) { | |||||
- m->hwvol_muted = 0; | |||||
- mixer_set(m, m->hwvol_mixer, m->hwvol_mute_level); | |||||
- } else { | |||||
- m->hwvol_muted++; | |||||
- m->hwvol_mute_level = mixer_get(m, m->hwvol_mixer); | |||||
- mixer_set(m, m->hwvol_mixer, 0); | |||||
- } | |||||
+ mix_setmutedevs(m, m->mutedevs ^ (1 << m->hwvol_mixer)); | |||||
} | |||||
void | |||||
@@ -925,11 +958,8 @@ mixer_hwvol_step_locked(struct snd_mixer *m, int left_step, int right_step) | |||||
{ | |||||
int level, left, right; | |||||
- if (m->hwvol_muted) { | |||||
- m->hwvol_muted = 0; | |||||
- level = m->hwvol_mute_level; | |||||
- } else | |||||
- level = mixer_get(m, m->hwvol_mixer); | |||||
+ level = mixer_get(m, m->hwvol_mixer); | |||||
+ | |||||
if (level != -1) { | |||||
left = level & 0xff; | |||||
right = (level >> 8) & 0xff; | |||||
@@ -943,7 +973,8 @@ mixer_hwvol_step_locked(struct snd_mixer *m, int left_step, int right_step) | |||||
right = 0; | |||||
else if (right > 100) | |||||
right = 100; | |||||
- mixer_set(m, m->hwvol_mixer, left | right << 8); | |||||
+ | |||||
+ mixer_set(m, m->hwvol_mixer, m->mutedevs, left | right << 8); | |||||
} | |||||
} | |||||
@@ -976,7 +1007,7 @@ mix_set(struct snd_mixer *m, u_int dev, u_int left, u_int right) | |||||
KASSERT(m != NULL, ("NULL snd_mixer")); | |||||
snd_mtxlock(m->lock); | |||||
- ret = mixer_set(m, dev, left | (right << 8)); | |||||
+ ret = mixer_set(m, dev, m->mutedevs, left | (right << 8)); | |||||
snd_mtxunlock(m->lock); | |||||
return ((ret != 0) ? ENXIO : 0); | |||||
@@ -1305,10 +1336,18 @@ mixer_ioctl_cmd(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, | |||||
goto done; | |||||
} | |||||
if ((cmd & ~0xff) == MIXER_WRITE(0)) { | |||||
- if (j == SOUND_MIXER_RECSRC) | |||||
+ switch (j) { | |||||
+ case SOUND_MIXER_RECSRC: | |||||
ret = mixer_setrecsrc(m, *arg_i); | |||||
- else | |||||
- ret = mixer_set(m, j, *arg_i); | |||||
+ break; | |||||
+ case SOUND_MIXER_MUTE: | |||||
+ mix_setmutedevs(m, *arg_i); | |||||
+ ret = 0; | |||||
+ break; | |||||
+ default: | |||||
+ ret = mixer_set(m, j, m->mutedevs, *arg_i); | |||||
+ break; | |||||
+ } | |||||
snd_mtxunlock(m->lock); | |||||
return ((ret == 0) ? 0 : ENXIO); | |||||
} | |||||
@@ -1319,6 +1358,9 @@ mixer_ioctl_cmd(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, | |||||
case SOUND_MIXER_STEREODEVS: | |||||
v = mix_getdevs(m); | |||||
break; | |||||
+ case SOUND_MIXER_MUTE: | |||||
+ v = mix_getmutedevs(m); | |||||
+ break; | |||||
case SOUND_MIXER_RECMASK: | |||||
v = mix_getrecdevs(m); | |||||
break; | |||||
@@ -1327,6 +1369,7 @@ mixer_ioctl_cmd(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, | |||||
break; | |||||
default: | |||||
v = mixer_get(m, j); | |||||
+ break; | |||||
} | |||||
*arg_i = v; | |||||
snd_mtxunlock(m->lock); | |||||
@@ -1555,5 +1598,5 @@ mix_set_locked(struct snd_mixer *m, u_int dev, int left, int right) | |||||
level = (left & 0xFF) | ((right & 0xFF) << 8); | |||||
- return (mixer_set(m, dev, level)); | |||||
+ return (mixer_set(m, dev, m->mutedevs, level)); | |||||
} | |||||
diff --git a/sys/dev/sound/pcm/mixer.h b/sys/dev/sound/pcm/mixer.h | |||||
index 8e11d553a3e..7857609b289 100644 | |||||
--- a/sys/dev/sound/pcm/mixer.h | |||||
+++ b/sys/dev/sound/pcm/mixer.h | |||||
@@ -60,8 +60,10 @@ device_t mix_get_dev(struct snd_mixer *m); | |||||
void mix_setdevs(struct snd_mixer *m, u_int32_t v); | |||||
void mix_setrecdevs(struct snd_mixer *m, u_int32_t v); | |||||
+void mix_setmutedevs(struct snd_mixer *m, u_int32_t v); | |||||
u_int32_t mix_getdevs(struct snd_mixer *m); | |||||
u_int32_t mix_getrecdevs(struct snd_mixer *m); | |||||
+u_int32_t mix_getmutedevs(struct snd_mixer *m); | |||||
void mix_setparentchild(struct snd_mixer *m, u_int32_t parent, u_int32_t childs); | |||||
void mix_setrealdev(struct snd_mixer *m, u_int32_t dev, u_int32_t realdev); | |||||
u_int32_t mix_getparent(struct snd_mixer *m, u_int32_t dev); | |||||
diff --git a/sys/dev/sound/pcm/sound.c b/sys/dev/sound/pcm/sound.c | |||||
index b4be28aeff8..6b1b8bcbc93 100644 | |||||
--- a/sys/dev/sound/pcm/sound.c | |||||
+++ b/sys/dev/sound/pcm/sound.c | |||||
@@ -1012,12 +1012,30 @@ SYSCTL_PROC(_hw_snd, OID_AUTO, clone_gc, CTLTYPE_INT | CTLFLAG_RWTUN, | |||||
"global clone garbage collector"); | |||||
#endif | |||||
+static u_int8_t | |||||
+pcm_mode_init(struct snddev_info *d) | |||||
+{ | |||||
+ u_int8_t mode = 0; | |||||
+ | |||||
+ if (d->playcount > 0) | |||||
+ mode |= PCM_MODE_PLAY; | |||||
+ if (d->reccount > 0) | |||||
+ mode |= PCM_MODE_REC; | |||||
+ if (d->mixer_dev != NULL) | |||||
+ mode |= PCM_MODE_MIXER; | |||||
+ | |||||
+ return (mode); | |||||
+} | |||||
+ | |||||
static void | |||||
pcm_sysinit(device_t dev) | |||||
{ | |||||
struct snddev_info *d = device_get_softc(dev); | |||||
+ u_int8_t mode; | |||||
+ | |||||
+ mode = pcm_mode_init(d); | |||||
- /* XXX: an user should be able to set this with a control tool, the | |||||
+ /* XXX: a user should be able to set this with a control tool, the | |||||
sysadmin then needs min+max sysctls for this */ | |||||
SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), | |||||
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), | |||||
@@ -1027,6 +1045,11 @@ pcm_sysinit(device_t dev) | |||||
"bitperfect", CTLTYPE_INT | CTLFLAG_RWTUN, d, sizeof(d), | |||||
sysctl_dev_pcm_bitperfect, "I", | |||||
"bit-perfect playback/recording (0=disable, 1=enable)"); | |||||
+ SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), | |||||
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), | |||||
+ OID_AUTO, "mode", CTLFLAG_RD, NULL, mode, | |||||
+ "mode (1=mixer, 2=play, 4=rec. The values are OR'ed if more than one" | |||||
+ "mode is supported)"); | |||||
#ifdef SND_DEBUG | |||||
SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), | |||||
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, | |||||
@@ -1130,7 +1153,7 @@ pcm_register(device_t dev, void *devinfo, int numplay, int numrec) | |||||
sysctl_ctx_init(&d->rec_sysctl_ctx); | |||||
d->rec_sysctl_tree = SYSCTL_ADD_NODE(&d->rec_sysctl_ctx, | |||||
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "rec", | |||||
- CTLFLAG_RD, 0, "record channels node"); | |||||
+ CTLFLAG_RD, 0, "recording channels node"); | |||||
if (numplay > 0 || numrec > 0) | |||||
d->flags |= SD_F_AUTOVCHAN; | |||||
diff --git a/sys/dev/sound/pcm/sound.h b/sys/dev/sound/pcm/sound.h | |||||
index d4b3a23e8eb..e9979cf426c 100644 | |||||
--- a/sys/dev/sound/pcm/sound.h | |||||
+++ b/sys/dev/sound/pcm/sound.h | |||||
@@ -411,6 +411,10 @@ struct snddev_info { | |||||
void sound_oss_sysinfo(oss_sysinfo *); | |||||
int sound_oss_card_info(oss_card_info *); | |||||
+#define PCM_MODE_MIXER 0x01 | |||||
+#define PCM_MODE_PLAY 0x02 | |||||
+#define PCM_MODE_REC 0x04 | |||||
+ | |||||
#define PCM_LOCKOWNED(d) mtx_owned((d)->lock) | |||||
#define PCM_LOCK(d) mtx_lock((d)->lock) | |||||
#define PCM_UNLOCK(d) mtx_unlock((d)->lock) |