Various fixups, especially for the upcomming High Definition Audio
commit. 1) sys/dev/sound/pcm/sound.h sys/dev/sound/pcm/channel.c * Be more specific: SD_F_SOFTVOL -> SD_F_SOFTPCMVOL 2) sys/dev/sound/pcm/mixer.[ch] * Implement mix_setparentchild() mix_setrealdev() mix_getparent() mix_getchild() The purpose of these functions is implement relative volume adjustment, such as to tie two or more mixer device into a single logical device. Usefull for the upcoming HDA driver and few AC97 codec (such as AD1981B) where the master volume "vol" need to be implemented using this logical manner. 3) sys/dev/sound/pcm/ac97_patch.[ch] * Patch for AD1981B codec to enable (automuting) headphone jack sense. 4) sys/dev/sound/pcm/ac97.c * Implement proper logical master volume for AD9181B codec through various mix_set{parentchild,realdev}(). Tie both "ogain" (headphone volume) and "phone" (speaker/lineout) to a logical "vol". 5) sys/dev/sound/pcm/usb/uaudio_pcm.c * ditto, for "vol" -> { "pcm" }. MFC after: 1 month
This commit is contained in:
parent
add92b34d1
commit
7699548f1b
@ -136,7 +136,7 @@ static struct ac97_codecid ac97codecid[] = {
|
||||
{ 0x41445368, 0x00, 0, "AD1888", ad198x_patch },
|
||||
{ 0x41445370, 0x00, 0, "AD1980", ad198x_patch },
|
||||
{ 0x41445372, 0x00, 0, "AD1981A", 0 },
|
||||
{ 0x41445374, 0x00, 0, "AD1981B", 0 },
|
||||
{ 0x41445374, 0x00, 0, "AD1981B", ad1981b_patch },
|
||||
{ 0x41445375, 0x00, 0, "AD1985", ad198x_patch },
|
||||
{ 0x41445378, 0x00, 0, "AD1986", ad198x_patch },
|
||||
{ 0x414b4d00, 0x00, 1, "AK4540", 0 },
|
||||
@ -545,40 +545,6 @@ ac97_fix_tone(struct ac97_info *codec)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ac97_fix_volume(struct ac97_info *codec)
|
||||
{
|
||||
struct snddev_info *d = device_get_softc(codec->dev);
|
||||
|
||||
#if 0
|
||||
/* XXX For the sake of debugging purposes */
|
||||
ac97_wrcd(codec, AC97_MIX_PCM, 0);
|
||||
bzero(&codec->mix[SOUND_MIXER_PCM],
|
||||
sizeof(codec->mix[SOUND_MIXER_PCM]));
|
||||
codec->flags |= AC97_F_SOFTVOL;
|
||||
if (d)
|
||||
d->flags |= SD_F_SOFTVOL;
|
||||
return;
|
||||
#endif
|
||||
switch (codec->id) {
|
||||
case 0x434d4941: /* CMI9738 */
|
||||
case 0x434d4961: /* CMI9739 */
|
||||
case 0x434d4978: /* CMI9761 */
|
||||
case 0x434d4982: /* CMI9761 */
|
||||
case 0x434d4983: /* CMI9761 */
|
||||
ac97_wrcd(codec, AC97_MIX_PCM, 0);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
break;
|
||||
}
|
||||
bzero(&codec->mix[SOUND_MIXER_PCM],
|
||||
sizeof(codec->mix[SOUND_MIXER_PCM]));
|
||||
codec->flags |= AC97_F_SOFTVOL;
|
||||
if (d)
|
||||
d->flags |= SD_F_SOFTVOL;
|
||||
}
|
||||
|
||||
static const char*
|
||||
ac97_hw_desc(u_int32_t id, const char* vname, const char* cname, char* buf)
|
||||
{
|
||||
@ -684,7 +650,6 @@ ac97_initmixer(struct ac97_info *codec)
|
||||
}
|
||||
ac97_fix_auxout(codec);
|
||||
ac97_fix_tone(codec);
|
||||
ac97_fix_volume(codec);
|
||||
if (codec_patch)
|
||||
codec_patch(codec);
|
||||
|
||||
@ -758,8 +723,6 @@ ac97_initmixer(struct ac97_info *codec)
|
||||
if (bootverbose) {
|
||||
if (codec->flags & AC97_F_RDCD_BUG)
|
||||
device_printf(codec->dev, "Buggy AC97 Codec: aggressive ac97_rdcd() workaround enabled\n");
|
||||
if (codec->flags & AC97_F_SOFTVOL)
|
||||
device_printf(codec->dev, "Soft PCM volume\n");
|
||||
device_printf(codec->dev, "Codec features ");
|
||||
for (i = j = 0; i < 10; i++)
|
||||
if (codec->caps & (1 << i))
|
||||
@ -828,14 +791,15 @@ struct ac97_info *
|
||||
ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
|
||||
{
|
||||
struct ac97_info *codec;
|
||||
int eapd_inv;
|
||||
|
||||
codec = (struct ac97_info *)malloc(sizeof *codec, M_AC97, M_NOWAIT);
|
||||
codec = (struct ac97_info *)malloc(sizeof *codec, M_AC97, M_NOWAIT | M_ZERO);
|
||||
if (codec == NULL)
|
||||
return NULL;
|
||||
|
||||
snprintf(codec->name, AC97_NAMELEN, "%s:ac97", device_get_nameunit(dev));
|
||||
codec->lock = snd_mtxcreate(codec->name, "ac97 codec");
|
||||
codec->methods = kobj_create(cls, M_AC97, M_WAITOK);
|
||||
codec->methods = kobj_create(cls, M_AC97, M_WAITOK | M_ZERO);
|
||||
if (codec->methods == NULL) {
|
||||
snd_mtxlock(codec->lock);
|
||||
snd_mtxfree(codec->lock);
|
||||
@ -846,6 +810,11 @@ ac97_create(device_t dev, void *devinfo, kobj_class_t cls)
|
||||
codec->dev = dev;
|
||||
codec->devinfo = devinfo;
|
||||
codec->flags = 0;
|
||||
if (resource_int_value(device_get_name(dev), device_get_unit(dev),
|
||||
"ac97_eapd_inv", &eapd_inv) == 0) {
|
||||
if (eapd_inv != 0)
|
||||
codec->flags |= AC97_F_EAPD_INV;
|
||||
}
|
||||
return codec;
|
||||
}
|
||||
|
||||
@ -877,6 +846,7 @@ static int
|
||||
ac97mix_init(struct snd_mixer *m)
|
||||
{
|
||||
struct ac97_info *codec = mix_getdevinfo(m);
|
||||
struct snddev_info *d;
|
||||
u_int32_t i, mask;
|
||||
|
||||
if (codec == NULL)
|
||||
@ -885,6 +855,46 @@ ac97mix_init(struct snd_mixer *m)
|
||||
if (ac97_initmixer(codec))
|
||||
return -1;
|
||||
|
||||
switch (codec->id) {
|
||||
case 0x41445374: /* AD1981B */
|
||||
mask = 0;
|
||||
if (codec->mix[SOUND_MIXER_OGAIN].enable)
|
||||
mask |= SOUND_MASK_OGAIN;
|
||||
if (codec->mix[SOUND_MIXER_PHONEOUT].enable)
|
||||
mask |= SOUND_MASK_PHONEOUT;
|
||||
/* Tie ogain/phone to master volume */
|
||||
if (codec->mix[SOUND_MIXER_VOLUME].enable)
|
||||
mix_setparentchild(m, SOUND_MIXER_VOLUME, mask);
|
||||
else {
|
||||
mix_setparentchild(m, SOUND_MIXER_VOLUME, mask);
|
||||
mix_setrealdev(m, SOUND_MIXER_VOLUME, SOUND_MIXER_NONE);
|
||||
}
|
||||
break;
|
||||
case 0x434d4941: /* CMI9738 */
|
||||
case 0x434d4961: /* CMI9739 */
|
||||
case 0x434d4978: /* CMI9761 */
|
||||
case 0x434d4982: /* CMI9761 */
|
||||
case 0x434d4983: /* CMI9761 */
|
||||
ac97_wrcd(codec, AC97_MIX_PCM, 0);
|
||||
bzero(&codec->mix[SOUND_MIXER_PCM],
|
||||
sizeof(codec->mix[SOUND_MIXER_PCM]));
|
||||
d = device_get_softc(codec->dev);
|
||||
if (d != NULL)
|
||||
d->flags |= SD_F_SOFTPCMVOL;
|
||||
/* XXX How about master volume ? */
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* XXX For the sake of debugging purposes */
|
||||
mix_setparentchild(m, SOUND_MIXER_VOLUME,
|
||||
SOUND_MASK_PCM | SOUND_MASK_CD);
|
||||
mix_setrealdev(m, SOUND_MIXER_VOLUME, SOUND_MIXER_NONE);
|
||||
ac97_wrcd(codec, AC97_MIX_MASTER, 0);
|
||||
#endif
|
||||
|
||||
mask = 0;
|
||||
for (i = 0; i < 32; i++)
|
||||
mask |= codec->mix[i].enable? 1 << i : 0;
|
||||
|
@ -46,6 +46,12 @@ void ad198x_patch(struct ac97_info* codec)
|
||||
ac97_wrcd(codec, 0x76, ac97_rdcd(codec, 0x76) | 0x0420);
|
||||
}
|
||||
|
||||
void ad1981b_patch(struct ac97_info* codec)
|
||||
{
|
||||
ac97_wrcd(codec, AC97_AD_JACK_SPDIF,
|
||||
ac97_rdcd(codec, AC97_AD_JACK_SPDIF) | 0x0800);
|
||||
}
|
||||
|
||||
void cmi9739_patch(struct ac97_info* codec)
|
||||
{
|
||||
/*
|
||||
|
@ -29,4 +29,5 @@ typedef void (*ac97_patch)(struct ac97_info*);
|
||||
|
||||
void ad1886_patch(struct ac97_info*);
|
||||
void ad198x_patch(struct ac97_info*);
|
||||
void ad1981b_patch(struct ac97_info*);
|
||||
void cmi9739_patch(struct ac97_info*);
|
||||
|
@ -1417,7 +1417,7 @@ chn_buildfeeder(struct pcm_channel *c)
|
||||
c->feederflags &= ~(1 << FEEDER_VOLUME);
|
||||
if (c->direction == PCMDIR_PLAY &&
|
||||
!(c->flags & CHN_F_VIRTUAL) &&
|
||||
c->parentsnddev && (c->parentsnddev->flags & SD_F_SOFTVOL) &&
|
||||
c->parentsnddev && (c->parentsnddev->flags & SD_F_SOFTPCMVOL) &&
|
||||
c->parentsnddev->mixer_dev)
|
||||
c->feederflags |= 1 << FEEDER_VOLUME;
|
||||
flags = c->feederflags;
|
||||
@ -1475,7 +1475,10 @@ chn_buildfeeder(struct pcm_channel *c)
|
||||
sndbuf_setfmt(c->bufhard, hwfmt);
|
||||
|
||||
if ((flags & (1 << FEEDER_VOLUME))) {
|
||||
int vol = 100 | (100 << 8);
|
||||
uint32_t parent = SOUND_MIXER_NONE;
|
||||
int vol, left, right;
|
||||
|
||||
vol = 100 | (100 << 8);
|
||||
|
||||
CHN_UNLOCK(c);
|
||||
/*
|
||||
@ -1485,9 +1488,26 @@ chn_buildfeeder(struct pcm_channel *c)
|
||||
*/
|
||||
if (mixer_ioctl(c->parentsnddev->mixer_dev,
|
||||
MIXER_READ(SOUND_MIXER_PCM), (caddr_t)&vol, -1, NULL) != 0)
|
||||
device_printf(c->dev, "Soft Volume: Failed to read default value\n");
|
||||
device_printf(c->dev, "Soft PCM Volume: Failed to read default value\n");
|
||||
left = vol & 0x7f;
|
||||
right = (vol >> 8) & 0x7f;
|
||||
if (c->parentsnddev != NULL &&
|
||||
c->parentsnddev->mixer_dev != NULL &&
|
||||
c->parentsnddev->mixer_dev->si_drv1 != NULL)
|
||||
parent = mix_getparent(
|
||||
c->parentsnddev->mixer_dev->si_drv1,
|
||||
SOUND_MIXER_PCM);
|
||||
if (parent != SOUND_MIXER_NONE) {
|
||||
vol = 100 | (100 << 8);
|
||||
if (mixer_ioctl(c->parentsnddev->mixer_dev,
|
||||
MIXER_READ(parent),
|
||||
(caddr_t)&vol, -1, NULL) != 0)
|
||||
device_printf(c->dev, "Soft Volume: Failed to read parent default value\n");
|
||||
left = (left * (vol & 0x7f)) / 100;
|
||||
right = (right * ((vol >> 8) & 0x7f)) / 100;
|
||||
}
|
||||
CHN_LOCK(c);
|
||||
chn_setvolume(c, vol & 0x7f, (vol >> 8) & 0x7f);
|
||||
chn_setvolume(c, left, right);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -47,6 +47,9 @@ struct snd_mixer {
|
||||
u_int32_t recdevs;
|
||||
u_int32_t recsrc;
|
||||
u_int16_t level[32];
|
||||
u_int32_t parent[32];
|
||||
u_int32_t child[32];
|
||||
u_int32_t realdev[32];
|
||||
char name[MIXER_NAMELEN];
|
||||
struct mtx *lock;
|
||||
oss_mixer_enuminfo enuminfo;
|
||||
@ -124,48 +127,94 @@ mixer_lookup(char *devname)
|
||||
#endif
|
||||
|
||||
static int
|
||||
mixer_set(struct snd_mixer *mixer, unsigned dev, unsigned lev)
|
||||
mixer_set_softpcmvol(struct snd_mixer *mixer, struct snddev_info *d,
|
||||
unsigned left, unsigned right)
|
||||
{
|
||||
struct snddev_channel *sce;
|
||||
struct pcm_channel *ch;
|
||||
#ifdef USING_MUTEX
|
||||
int locked = (mixer->lock && mtx_owned((struct mtx *)(mixer->lock))) ? 1 : 0;
|
||||
|
||||
if (locked)
|
||||
snd_mtxunlock(mixer->lock);
|
||||
#endif
|
||||
SLIST_FOREACH(sce, &d->channels, link) {
|
||||
ch = sce->channel;
|
||||
CHN_LOCK(ch);
|
||||
if (ch->direction == PCMDIR_PLAY &&
|
||||
(ch->feederflags & (1 << FEEDER_VOLUME)))
|
||||
chn_setvolume(ch, left, right);
|
||||
CHN_UNLOCK(ch);
|
||||
}
|
||||
#ifdef USING_MUTEX
|
||||
if (locked)
|
||||
snd_mtxlock(mixer->lock);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mixer_set(struct snd_mixer *m, unsigned dev, unsigned lev)
|
||||
{
|
||||
struct snddev_info *d;
|
||||
unsigned l, r;
|
||||
int v;
|
||||
unsigned l, r, tl, tr;
|
||||
u_int32_t parent = SOUND_MIXER_NONE, child = 0;
|
||||
u_int32_t realdev;
|
||||
int i;
|
||||
|
||||
if ((dev >= SOUND_MIXER_NRDEVICES) || (0 == (mixer->devs & (1 << dev))))
|
||||
if (m == NULL || dev >= SOUND_MIXER_NRDEVICES ||
|
||||
(0 == (m->devs & (1 << dev))))
|
||||
return -1;
|
||||
|
||||
l = min((lev & 0x00ff), 100);
|
||||
r = min(((lev & 0xff00) >> 8), 100);
|
||||
realdev = m->realdev[dev];
|
||||
|
||||
d = device_get_softc(mixer->dev);
|
||||
if (dev == SOUND_MIXER_PCM && d &&
|
||||
(d->flags & SD_F_SOFTVOL)) {
|
||||
struct snddev_channel *sce;
|
||||
struct pcm_channel *ch;
|
||||
#ifdef USING_MUTEX
|
||||
int locked = (mixer->lock && mtx_owned((struct mtx *)(mixer->lock))) ? 1 : 0;
|
||||
d = device_get_softc(m->dev);
|
||||
if (d == NULL)
|
||||
return -1;
|
||||
|
||||
if (locked)
|
||||
snd_mtxunlock(mixer->lock);
|
||||
#endif
|
||||
SLIST_FOREACH(sce, &d->channels, link) {
|
||||
ch = sce->channel;
|
||||
CHN_LOCK(ch);
|
||||
if (ch->direction == PCMDIR_PLAY &&
|
||||
(ch->feederflags & (1 << FEEDER_VOLUME)))
|
||||
chn_setvolume(ch, l, r);
|
||||
CHN_UNLOCK(ch);
|
||||
/* TODO: recursive handling */
|
||||
parent = m->parent[dev];
|
||||
if (parent >= SOUND_MIXER_NRDEVICES)
|
||||
parent = SOUND_MIXER_NONE;
|
||||
if (parent == SOUND_MIXER_NONE)
|
||||
child = m->child[dev];
|
||||
|
||||
if (parent != SOUND_MIXER_NONE) {
|
||||
tl = (l * (m->level[parent] & 0x00ff)) / 100;
|
||||
tr = (r * ((m->level[parent] & 0xff00) >> 8)) / 100;
|
||||
if (dev == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL))
|
||||
mixer_set_softpcmvol(m, d, tl, tr);
|
||||
else if (realdev != SOUND_MIXER_NONE &&
|
||||
MIXER_SET(m, realdev, tl, tr) < 0)
|
||||
return -1;
|
||||
} else if (child != 0) {
|
||||
for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
|
||||
if (!(child & (1 << i)) || m->parent[i] != dev)
|
||||
continue;
|
||||
realdev = m->realdev[i];
|
||||
tl = (l * (m->level[i] & 0x00ff)) / 100;
|
||||
tr = (r * ((m->level[i] & 0xff00) >> 8)) / 100;
|
||||
if (i == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL))
|
||||
mixer_set_softpcmvol(m, d, tl, tr);
|
||||
else if (realdev != SOUND_MIXER_NONE)
|
||||
MIXER_SET(m, realdev, tl, tr);
|
||||
}
|
||||
#ifdef USING_MUTEX
|
||||
if (locked)
|
||||
snd_mtxlock(mixer->lock);
|
||||
#endif
|
||||
realdev = m->realdev[dev];
|
||||
if (realdev != SOUND_MIXER_NONE &&
|
||||
MIXER_SET(m, realdev, l, r) < 0)
|
||||
return -1;
|
||||
} else {
|
||||
v = MIXER_SET(mixer, dev, l, r);
|
||||
if (v < 0)
|
||||
if (dev == SOUND_MIXER_PCM && (d->flags & SD_F_SOFTPCMVOL))
|
||||
mixer_set_softpcmvol(m, d, l, r);
|
||||
else if (realdev != SOUND_MIXER_NONE &&
|
||||
MIXER_SET(m, realdev, l, r) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
mixer->level[dev] = l | (r << 8);
|
||||
m->level[dev] = l | (r << 8);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -274,8 +323,17 @@ void
|
||||
mix_setdevs(struct snd_mixer *m, u_int32_t v)
|
||||
{
|
||||
struct snddev_info *d = device_get_softc(m->dev);
|
||||
if (d && (d->flags & SD_F_SOFTVOL))
|
||||
int i;
|
||||
|
||||
if (m == NULL)
|
||||
return;
|
||||
if (d != NULL && (d->flags & SD_F_SOFTPCMVOL))
|
||||
v |= SOUND_MASK_PCM;
|
||||
for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
|
||||
if (m->parent[i] < SOUND_MIXER_NRDEVICES)
|
||||
v |= 1 << m->parent[i];
|
||||
v |= m->child[i];
|
||||
}
|
||||
m->devs = v;
|
||||
}
|
||||
|
||||
@ -347,6 +405,54 @@ mix_setrecdevs(struct snd_mixer *m, u_int32_t v)
|
||||
m->recdevs = v;
|
||||
}
|
||||
|
||||
void
|
||||
mix_setparentchild(struct snd_mixer *m, u_int32_t parent, u_int32_t childs)
|
||||
{
|
||||
u_int32_t mask = 0;
|
||||
int i;
|
||||
|
||||
if (m == NULL || parent >= SOUND_MIXER_NRDEVICES)
|
||||
return;
|
||||
for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
|
||||
if (i == parent)
|
||||
continue;
|
||||
if (childs & (1 << i)) {
|
||||
mask |= 1 << i;
|
||||
if (m->parent[i] < SOUND_MIXER_NRDEVICES)
|
||||
m->child[m->parent[i]] &= ~(1 << i);
|
||||
m->parent[i] = parent;
|
||||
m->child[i] = 0;
|
||||
}
|
||||
}
|
||||
mask &= ~(1 << parent);
|
||||
m->child[parent] = mask;
|
||||
}
|
||||
|
||||
void
|
||||
mix_setrealdev(struct snd_mixer *m, u_int32_t dev, u_int32_t realdev)
|
||||
{
|
||||
if (m == NULL || dev >= SOUND_MIXER_NRDEVICES ||
|
||||
!(realdev == SOUND_MIXER_NONE || realdev < SOUND_MIXER_NRDEVICES))
|
||||
return;
|
||||
m->realdev[dev] = realdev;
|
||||
}
|
||||
|
||||
u_int32_t
|
||||
mix_getparent(struct snd_mixer *m, u_int32_t dev)
|
||||
{
|
||||
if (m == NULL || dev >= SOUND_MIXER_NRDEVICES)
|
||||
return SOUND_MIXER_NONE;
|
||||
return m->parent[dev];
|
||||
}
|
||||
|
||||
u_int32_t
|
||||
mix_getchild(struct snd_mixer *m, u_int32_t dev)
|
||||
{
|
||||
if (m == NULL || dev >= SOUND_MIXER_NRDEVICES)
|
||||
return 0;
|
||||
return m->child[dev];
|
||||
}
|
||||
|
||||
u_int32_t
|
||||
mix_getdevs(struct snd_mixer *m)
|
||||
{
|
||||
@ -381,6 +487,11 @@ mixer_init(device_t dev, kobj_class_t cls, void *devinfo)
|
||||
m->devinfo = devinfo;
|
||||
m->busy = 0;
|
||||
m->dev = dev;
|
||||
for (i = 0; i < 32; i++) {
|
||||
m->parent[i] = SOUND_MIXER_NONE;
|
||||
m->child[i] = 0;
|
||||
m->realdev[i] = i;
|
||||
}
|
||||
|
||||
if (MIXER_INIT(m))
|
||||
goto bad;
|
||||
@ -409,6 +520,30 @@ mixer_init(device_t dev, kobj_class_t cls, void *devinfo)
|
||||
|
||||
++mixer_count;
|
||||
|
||||
if (bootverbose) {
|
||||
for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
|
||||
if (!(m->devs & (1 << i)))
|
||||
continue;
|
||||
if (m->realdev[i] != i) {
|
||||
device_printf(dev, "Mixer \"%s\" -> \"%s\":",
|
||||
snd_mixernames[i],
|
||||
(m->realdev[i] < SOUND_MIXER_NRDEVICES) ?
|
||||
snd_mixernames[m->realdev[i]] : "none");
|
||||
} else {
|
||||
device_printf(dev, "Mixer \"%s\":",
|
||||
snd_mixernames[i]);
|
||||
}
|
||||
if (m->parent[i] < SOUND_MIXER_NRDEVICES)
|
||||
printf(" parent=\"%s\"",
|
||||
snd_mixernames[m->parent[i]]);
|
||||
if (m->child[i] != 0)
|
||||
printf(" child=0x%08x", m->child[i]);
|
||||
printf("\n");
|
||||
}
|
||||
if (snddev->flags & SD_F_SOFTPCMVOL)
|
||||
device_printf(dev, "Soft PCM mixer ENABLED\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
bad:
|
||||
|
@ -40,6 +40,10 @@ void mix_setdevs(struct snd_mixer *m, u_int32_t v);
|
||||
void mix_setrecdevs(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);
|
||||
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);
|
||||
u_int32_t mix_getchild(struct snd_mixer *m, u_int32_t dev);
|
||||
void *mix_getdevinfo(struct snd_mixer *m);
|
||||
|
||||
extern int mixer_count;
|
||||
|
@ -136,7 +136,7 @@ nomenclature:
|
||||
|
||||
#define SD_F_SIMPLEX 0x00000001
|
||||
#define SD_F_AUTOVCHAN 0x00000002
|
||||
#define SD_F_SOFTVOL 0x00000004
|
||||
#define SD_F_SOFTPCMVOL 0x00000004
|
||||
#define SD_F_PRIO_RD 0x10000000
|
||||
#define SD_F_PRIO_WR 0x20000000
|
||||
#define SD_F_PRIO_SET (SD_F_PRIO_RD | SD_F_PRIO_WR)
|
||||
|
@ -243,12 +243,20 @@ ua_mixer_init(struct snd_mixer *m)
|
||||
d = device_get_softc(ua->sc_dev);
|
||||
|
||||
mask = uaudio_query_mix_info(pa_dev);
|
||||
if (d && !(mask & SOUND_MIXER_PCM)) {
|
||||
/*
|
||||
* Emulate missing pcm mixer controller
|
||||
* through FEEDER_VOLUME
|
||||
*/
|
||||
d->flags |= SD_F_SOFTVOL;
|
||||
if (d != NULL) {
|
||||
if (!(mask & SOUND_MASK_PCM)) {
|
||||
/*
|
||||
* Emulate missing pcm mixer controller
|
||||
* through FEEDER_VOLUME
|
||||
*/
|
||||
d->flags |= SD_F_SOFTPCMVOL;
|
||||
}
|
||||
if (!(mask & SOUND_MASK_VOLUME)) {
|
||||
mix_setparentchild(m, SOUND_MIXER_VOLUME,
|
||||
SOUND_MASK_PCM);
|
||||
mix_setrealdev(m, SOUND_MIXER_VOLUME,
|
||||
SOUND_MIXER_NONE);
|
||||
}
|
||||
}
|
||||
mix_setdevs(m, mask);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user