From cb44f623ecc18df464f4850d1a9e4b2b05ce9960 Mon Sep 17 00:00:00 2001 From: Alexander Leidinger Date: Sun, 2 Oct 2005 15:37:40 +0000 Subject: [PATCH] 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 Tested by: multimedia@ --- sys/dev/sound/pcm/ac97.c | 43 ++++++++++++++++++++++++++++++- sys/dev/sound/pcm/ac97.h | 1 + sys/dev/sound/pcm/channel.c | 37 ++++++++++++++++++++++++--- sys/dev/sound/pcm/mixer.c | 50 ++++++++++++++++++++++++++----------- 4 files changed, 112 insertions(+), 19 deletions(-) diff --git a/sys/dev/sound/pcm/ac97.c b/sys/dev/sound/pcm/ac97.c index 9297073eb20..234e38f1ec6 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 e7543983232..8266fb5b762 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 eb5a89e30d8..e6a09a063db 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 e7e3e0ccd42..6b8dac11dd4 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; }