summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authornetchild <netchild@FreeBSD.org>2005-10-02 15:37:40 +0000
committernetchild <netchild@FreeBSD.org>2005-10-02 15:37:40 +0000
commitf19cdc94c32b0e940041a6482e8bc6a83eaac293 (patch)
treecbb203ee4bf7abe4cc151cba887466cef3b53732 /sys
parent68e320e3c99d605225dc7c472ac1271d915c8a15 (diff)
downloadFreeBSD-src-f19cdc94c32b0e940041a6482e8bc6a83eaac293.zip
FreeBSD-src-f19cdc94c32b0e940041a6482e8bc6a83eaac293.tar.gz
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@
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/sound/pcm/ac97.c43
-rw-r--r--sys/dev/sound/pcm/ac97.h1
-rw-r--r--sys/dev/sound/pcm/channel.c37
-rw-r--r--sys/dev/sound/pcm/mixer.c50
4 files changed, 112 insertions, 19 deletions
diff --git a/sys/dev/sound/pcm/ac97.c b/sys/dev/sound/pcm/ac97.c
index 9297073..234e38f 100644
--- a/sys/dev/sound/pcm/ac97.c
+++ b/sys/dev/sound/pcm/ac97.c
@@ -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))
diff --git a/sys/dev/sound/pcm/ac97.h b/sys/dev/sound/pcm/ac97.h
index e754398..8266fb5 100644
--- a/sys/dev/sound/pcm/ac97.h
+++ b/sys/dev/sound/pcm/ac97.h
@@ -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)
diff --git a/sys/dev/sound/pcm/channel.c b/sys/dev/sound/pcm/channel.c
index eb5a89e..e6a09a0 100644
--- a/sys/dev/sound/pcm/channel.c
+++ b/sys/dev/sound/pcm/channel.c
@@ -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;
}
diff --git a/sys/dev/sound/pcm/mixer.c b/sys/dev/sound/pcm/mixer.c
index e7e3e0c..6b8dac1 100644
--- a/sys/dev/sound/pcm/mixer.c
+++ b/sys/dev/sound/pcm/mixer.c
@@ -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;
}
OpenPOWER on IntegriCloud