sys/dev/sound/pcm/ac97.c:

* Added codec id for CMI9761.
   * feeder_volume *whitelist* through ac97_fix_volume()

sys/dev/sound/pcm/ac97.h:
   * Added AC97_F_SOFTVOL definition.

sys/dev/sound/pcm/channel.c:
   * Slight changes for chn_setvolume() to conform with OSS.
   * FEEDER_VOLUME is now part of feeder building process.

sys/dev/sound/pcm/mixer.c:
   * General spl* cleanup. It doesn't serve any purpose anymore.
   * Main hook for feeder_volume.

Submitted by:	Ariff Abdullah <skywizard@MyBSD.org.my>
Tested by:	multimedia@
This commit is contained in:
Alexander Leidinger 2005-10-02 15:37:40 +00:00
parent 4406886f5e
commit cb44f623ec
4 changed files with 112 additions and 19 deletions

View file

@ -161,8 +161,11 @@ static struct ac97_codecid ac97codecid[] = {
{ 0x43525940, 0x07, 0, "CS4201", 0 },
{ 0x43525958, 0x07, 0, "CS4205", 0 },
{ 0x43525960, 0x07, 0, "CS4291A", 0 },
{ 0x434d4961, 0x00, 0, "CMI9739", 0 },
{ 0x434d4961, 0x00, 0, "CMI9739", cmi9739_patch },
{ 0x434d4941, 0x00, 0, "CMI9738", 0 },
{ 0x434d4978, 0x00, 0, "CMI9761", 0 },
{ 0x434d4982, 0x00, 0, "CMI9761", 0 },
{ 0x434d4983, 0x00, 0, "CMI9761", 0 },
{ 0x43585421, 0x00, 0, "HSD11246", 0 },
{ 0x43585428, 0x07, 0, "CX20468", 0 },
{ 0x44543000, 0x00, 0, "DT0398", 0 },
@ -197,6 +200,7 @@ static struct ac97_codecid ac97codecid[] = {
{ 0x83847658, 0x00, 0, "STAC9758/59", 0 },
{ 0x83847660, 0x00, 0, "STAC9760/61", 0 }, /* Extrapolated */
{ 0x83847662, 0x00, 0, "STAC9762/63", 0 }, /* Extrapolated */
{ 0x83847666, 0x00, 0, "STAC9766/67", 0 },
{ 0x53494c22, 0x00, 0, "Si3036", 0 },
{ 0x53494c23, 0x00, 0, "Si3038", 0 },
{ 0x54524103, 0x00, 0, "TR28023", 0 }, /* Extrapolated */
@ -538,6 +542,40 @@ 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)
{
@ -643,6 +681,7 @@ ac97_initmixer(struct ac97_info *codec)
}
ac97_fix_auxout(codec);
ac97_fix_tone(codec);
ac97_fix_volume(codec);
if (codec_patch)
codec_patch(codec);
@ -709,6 +748,8 @@ 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))

View file

@ -82,6 +82,7 @@
#define AC97_F_EAPD_INV 0x00000001
#define AC97_F_RDCD_BUG 0x00000002
#define AC97_F_SOFTVOL 0x00000004
#define AC97_DECLARE(name) static DEFINE_CLASS(name, name ## _methods, sizeof(struct kobj))
#define AC97_CREATE(dev, devinfo, cls) ac97_create(dev, devinfo, &cls ## _class)

View file

@ -165,7 +165,7 @@ chn_sleep(struct pcm_channel *c, char *str, int timeout)
/*
* chn_dmaupdate() tracks the status of a dma transfer,
* updating pointers. It must be called at spltty().
* updating pointers.
*/
static unsigned int
@ -394,7 +394,6 @@ chn_rddump(struct pcm_channel *c, unsigned int cnt)
/*
* Feed new data from the read buffer. Can be called in the bottom half.
* Hence must be called at spltty.
*/
int
chn_rdfeed(struct pcm_channel *c)
@ -785,8 +784,10 @@ chn_reset(struct pcm_channel *c, u_int32_t fmt)
r = chn_setformat(c, fmt);
if (r == 0)
r = chn_setspeed(c, hwspd);
#if 0
if (r == 0)
r = chn_setvolume(c, 100, 100);
#endif
}
if (r == 0)
r = chn_setblocksize(c, 0, 0);
@ -926,7 +927,15 @@ chn_setvolume(struct pcm_channel *c, int left, int right)
{
CHN_LOCKASSERT(c);
/* should add a feeder for volume changing if channel returns -1 */
c->volume = (left << 8) | right;
if (left > 100)
left = 100;
if (left < 0)
left = 0;
if (right > 100)
right = 100;
if (right < 0)
right = 0;
c->volume = left | (right << 8);
return 0;
}
@ -1303,6 +1312,12 @@ chn_buildfeeder(struct pcm_channel *c)
return err;
}
}
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->mixer_dev)
c->feederflags |= 1 << FEEDER_VOLUME;
flags = c->feederflags;
fmtlist = chn_getcaps(c)->fmtlist;
@ -1367,6 +1382,22 @@ chn_buildfeeder(struct pcm_channel *c)
sndbuf_setfmt(c->bufhard, hwfmt);
if ((flags & (1 << FEEDER_VOLUME))) {
int vol = 100 | (100 << 8);
CHN_UNLOCK(c);
/*
* XXX This is ugly! The way mixer subs being so secretive
* about its own internals force us to use this silly
* monkey trick.
*/
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");
CHN_LOCK(c);
chn_setvolume(c, vol & 0x7f, (vol >> 8) & 0x7f);
}
return 0;
}

View file

@ -41,6 +41,7 @@ struct snd_mixer {
int hwvol_muted;
int hwvol_mixer;
int hwvol_step;
device_t dev;
u_int32_t hwvol_mute_level;
u_int32_t devs;
u_int32_t recdevs;
@ -112,6 +113,7 @@ mixer_lookup(char *devname)
static int
mixer_set(struct snd_mixer *mixer, unsigned dev, unsigned lev)
{
struct snddev_info *d;
unsigned l, r;
int v;
@ -121,9 +123,34 @@ mixer_set(struct snd_mixer *mixer, unsigned dev, unsigned lev)
l = min((lev & 0x00ff), 100);
r = min(((lev & 0xff00) >> 8), 100);
v = MIXER_SET(mixer, dev, l, r);
if (v < 0)
return -1;
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;
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);
}
#ifdef USING_MUTEX
if (locked)
snd_mtxlock(mixer->lock);
#endif
} else {
v = MIXER_SET(mixer, dev, l, r);
if (v < 0)
return -1;
}
mixer->level[dev] = l | (r << 8);
return 0;
@ -156,6 +183,9 @@ mixer_getrecsrc(struct snd_mixer *mixer)
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))
v |= SOUND_MASK_PCM;
m->devs = v;
}
@ -198,6 +228,7 @@ mixer_init(device_t dev, kobj_class_t cls, void *devinfo)
m->type = cls->name;
m->devinfo = devinfo;
m->busy = 0;
m->dev = dev;
if (MIXER_INIT(m))
goto bad;
@ -397,16 +428,13 @@ static int
mixer_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
{
struct snd_mixer *m;
intrmask_t s;
m = i_dev->si_drv1;
s = spltty();
snd_mtxlock(m->lock);
m->busy++;
snd_mtxunlock(m->lock);
splx(s);
return 0;
}
@ -414,21 +442,17 @@ static int
mixer_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
{
struct snd_mixer *m;
intrmask_t s;
m = i_dev->si_drv1;
s = spltty();
snd_mtxlock(m->lock);
if (!m->busy) {
snd_mtxunlock(m->lock);
splx(s);
return EBADF;
}
m->busy--;
snd_mtxunlock(m->lock);
splx(s);
return 0;
}
@ -436,15 +460,13 @@ int
mixer_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td)
{
struct snd_mixer *m;
intrmask_t s;
int ret, *arg_i = (int *)arg;
int v = -1, j = cmd & 0xff;
m = i_dev->si_drv1;
if (!m->busy)
if (mode != -1 && !m->busy)
return EBADF;
s = spltty();
snd_mtxlock(m->lock);
if ((cmd & MIXER_WRITE(0)) == MIXER_WRITE(0)) {
if (j == SOUND_MIXER_RECSRC)
@ -452,7 +474,6 @@ mixer_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struct thread
else
ret = mixer_set(m, j, *arg_i);
snd_mtxunlock(m->lock);
splx(s);
return (ret == 0)? 0 : ENXIO;
}
@ -480,7 +501,6 @@ mixer_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struct thread
return (v != -1)? 0 : ENXIO;
}
snd_mtxunlock(m->lock);
splx(s);
return ENXIO;
}