patch-2.4.0-test9 linux/drivers/sound/ac97_codec.c
Next file: linux/drivers/sound/adlib_card.c
Previous file: linux/drivers/sound/Makefile
Back to the patch index
Back to the overall index
- Lines: 308
- Date:
Sun Oct 1 20:20:20 2000
- Orig file:
v2.4.0-test8/linux/drivers/sound/ac97_codec.c
- Orig date:
Tue Aug 29 14:09:15 2000
diff -u --recursive --new-file v2.4.0-test8/linux/drivers/sound/ac97_codec.c linux/drivers/sound/ac97_codec.c
@@ -35,6 +35,7 @@
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/bitops.h>
+#include <linux/delay.h>
#include <linux/ac97_codec.h>
#include <asm/uaccess.h>
@@ -48,6 +49,7 @@
static int ac97_init_mixer(struct ac97_codec *codec);
static int sigmatel_init(struct ac97_codec *codec);
+static int enable_eapd(struct ac97_codec *codec);
#define arraysize(x) (sizeof(x)/sizeof((x)[0]))
@@ -58,11 +60,14 @@
} ac97_codec_ids[] = {
{0x414B4D00, "Asahi Kasei AK4540" , NULL},
{0x41445340, "Analog Devices AD1881" , NULL},
+ {0x41445360, "Analog Devices AD1885" , enable_eapd},
{0x43525900, "Cirrus Logic CS4297" , NULL},
{0x43525903, "Cirrus Logic CS4297" , NULL},
{0x43525913, "Cirrus Logic CS4297A" , NULL},
{0x43525923, "Cirrus Logic CS4298" , NULL},
+ {0x4352592B, "Cirrus Logic CS4294" , NULL},
{0x43525931, "Cirrus Logic CS4299" , NULL},
+ {0x43525934, "Cirrus Logic CS4299" , NULL},
{0x4e534331, "National Semiconductor LM4549" , NULL},
{0x53494c22, "Silicon Laboratory Si3036" , NULL},
{0x53494c23, "Silicon Laboratory Si3038" , NULL},
@@ -71,8 +76,10 @@
{0x83847605, "SigmaTel STAC9704" , NULL},
{0x83847608, "SigmaTel STAC9708" , NULL},
{0x83847609, "SigmaTel STAC9721/23" , sigmatel_init},
+ {0x54524103, "TriTech TR?????" , NULL},
{0x54524106, "TriTech TR28026" , NULL},
{0x54524108, "TriTech TR28028" , NULL},
+ {0x54524123, "TriTech TR?????" , NULL},
{0x574D4C00, "Wolfson WM9704" , NULL},
{0x00000000, NULL, NULL}
};
@@ -119,20 +126,20 @@
unsigned int value;
} mixer_defaults[SOUND_MIXER_NRDEVICES] = {
/* all values 0 -> 100 in bytes */
- {SOUND_MIXER_VOLUME, 0x3232},
- {SOUND_MIXER_BASS, 0x3232},
- {SOUND_MIXER_TREBLE, 0x3232},
- {SOUND_MIXER_PCM, 0x3232},
- {SOUND_MIXER_SPEAKER, 0x3232},
- {SOUND_MIXER_LINE, 0x3232},
- {SOUND_MIXER_MIC, 0x3232},
- {SOUND_MIXER_CD, 0x3232},
- {SOUND_MIXER_ALTPCM, 0x3232},
- {SOUND_MIXER_IGAIN, 0x3232},
- {SOUND_MIXER_LINE1, 0x3232},
- {SOUND_MIXER_PHONEIN, 0x3232},
- {SOUND_MIXER_PHONEOUT, 0x3232},
- {SOUND_MIXER_VIDEO, 0x3232},
+ {SOUND_MIXER_VOLUME, 0x4343},
+ {SOUND_MIXER_BASS, 0x4343},
+ {SOUND_MIXER_TREBLE, 0x4343},
+ {SOUND_MIXER_PCM, 0x4343},
+ {SOUND_MIXER_SPEAKER, 0x4343},
+ {SOUND_MIXER_LINE, 0x4343},
+ {SOUND_MIXER_MIC, 0x4343},
+ {SOUND_MIXER_CD, 0x4343},
+ {SOUND_MIXER_ALTPCM, 0x4343},
+ {SOUND_MIXER_IGAIN, 0x4343},
+ {SOUND_MIXER_LINE1, 0x4343},
+ {SOUND_MIXER_PHONEIN, 0x4343},
+ {SOUND_MIXER_PHONEOUT, 0x4343},
+ {SOUND_MIXER_VIDEO, 0x4343},
{-1,0}
};
@@ -141,20 +148,20 @@
unsigned char offset;
int scale;
} ac97_hw[SOUND_MIXER_NRDEVICES]= {
- [SOUND_MIXER_VOLUME] = {AC97_MASTER_VOL_STEREO,63},
- [SOUND_MIXER_BASS] = {AC97_MASTER_TONE, 15},
- [SOUND_MIXER_TREBLE] = {AC97_MASTER_TONE, 15},
- [SOUND_MIXER_PCM] = {AC97_PCMOUT_VOL, 31},
- [SOUND_MIXER_SPEAKER] = {AC97_PCBEEP_VOL, 15},
- [SOUND_MIXER_LINE] = {AC97_LINEIN_VOL, 31},
- [SOUND_MIXER_MIC] = {AC97_MIC_VOL, 31},
- [SOUND_MIXER_CD] = {AC97_CD_VOL, 31},
- [SOUND_MIXER_ALTPCM] = {AC97_HEADPHONE_VOL, 63},
- [SOUND_MIXER_IGAIN] = {AC97_RECORD_GAIN, 31},
- [SOUND_MIXER_LINE1] = {AC97_AUX_VOL, 31},
- [SOUND_MIXER_PHONEIN] = {AC97_PHONE_VOL, 15},
- [SOUND_MIXER_PHONEOUT] = {AC97_MASTER_VOL_MONO, 63},
- [SOUND_MIXER_VIDEO] = {AC97_VIDEO_VOL, 31},
+ [SOUND_MIXER_VOLUME] = {AC97_MASTER_VOL_STEREO,64},
+ [SOUND_MIXER_BASS] = {AC97_MASTER_TONE, 16},
+ [SOUND_MIXER_TREBLE] = {AC97_MASTER_TONE, 16},
+ [SOUND_MIXER_PCM] = {AC97_PCMOUT_VOL, 32},
+ [SOUND_MIXER_SPEAKER] = {AC97_PCBEEP_VOL, 16},
+ [SOUND_MIXER_LINE] = {AC97_LINEIN_VOL, 32},
+ [SOUND_MIXER_MIC] = {AC97_MIC_VOL, 32},
+ [SOUND_MIXER_CD] = {AC97_CD_VOL, 32},
+ [SOUND_MIXER_ALTPCM] = {AC97_HEADPHONE_VOL, 64},
+ [SOUND_MIXER_IGAIN] = {AC97_RECORD_GAIN, 16},
+ [SOUND_MIXER_LINE1] = {AC97_AUX_VOL, 32},
+ [SOUND_MIXER_PHONEIN] = {AC97_PHONE_VOL, 32},
+ [SOUND_MIXER_PHONEOUT] = {AC97_MASTER_VOL_MONO, 64},
+ [SOUND_MIXER_VIDEO] = {AC97_VIDEO_VOL, 32},
};
/* the following tables allow us to go from OSS <-> ac97 quickly. */
@@ -196,11 +203,14 @@
{
u16 val;
int ret = 0;
+ int scale;
struct ac97_mixer_hw *mh = &ac97_hw[oss_channel];
val = codec->codec_read(codec , mh->offset);
- if (AC97_STEREO_MASK & (1 << oss_channel)) {
+ if (val & AC97_MUTE) {
+ ret = 0;
+ } else if (AC97_STEREO_MASK & (1 << oss_channel)) {
/* nice stereo mixers .. */
int left,right;
@@ -211,8 +221,14 @@
right = (right * 100) / mh->scale;
left = (left * 100) / mh->scale;
} else {
- right = 100 - ((right * 100) / mh->scale);
- left = 100 - ((left * 100) / mh->scale);
+ /* these may have 5 or 6 bit resolution */
+ if(oss_channel == SOUND_MIXER_VOLUME || oss_channel == SOUND_MIXER_ALTPCM)
+ scale = (1 << codec->bit_resolution);
+ else
+ scale = mh->scale;
+
+ right = 100 - ((right * 100) / scale);
+ left = 100 - ((left * 100) / scale);
}
ret = left | (right << 8);
} else if (oss_channel == SOUND_MIXER_SPEAKER) {
@@ -220,7 +236,8 @@
} else if (oss_channel == SOUND_MIXER_PHONEIN) {
ret = 100 - (((val & 0x1f) * 100) / mh->scale);
} else if (oss_channel == SOUND_MIXER_PHONEOUT) {
- ret = 100 - (((val & 0x1f) * 100) / mh->scale);
+ scale = (1 << codec->bit_resolution);
+ ret = 100 - (((val & 0x1f) * 100) / scale);
} else if (oss_channel == SOUND_MIXER_MIC) {
ret = 100 - (((val & 0x1f) * 100) / mh->scale);
/* the low bit is optional in the tone sliders and masking
@@ -247,6 +264,7 @@
unsigned int left, unsigned int right)
{
u16 val = 0;
+ int scale;
struct ac97_mixer_hw *mh = &ac97_hw[oss_channel];
#ifdef DEBUG
@@ -258,31 +276,45 @@
if (AC97_STEREO_MASK & (1 << oss_channel)) {
/* stereo mixers */
- if (oss_channel == SOUND_MIXER_IGAIN) {
- right = (right * mh->scale) / 100;
- left = (left * mh->scale) / 100;
+ if (left == 0 && right == 0) {
+ val = AC97_MUTE;
} else {
- right = ((100 - right) * mh->scale) / 100;
- left = ((100 - left) * mh->scale) / 100;
- }
- val = (left << 8) | right;
+ if (oss_channel == SOUND_MIXER_IGAIN) {
+ right = (right * mh->scale) / 100;
+ left = (left * mh->scale) / 100;
+ } else {
+ /* these may have 5 or 6 bit resolution */
+ if (oss_channel == SOUND_MIXER_VOLUME ||
+ oss_channel == SOUND_MIXER_ALTPCM)
+ scale = (1 << codec->bit_resolution);
+ else
+ scale = mh->scale;
+
+ right = ((100 - right) * scale) / 100;
+ left = ((100 - left) * scale) / 100;
+ }
+ val = (left << 8) | right;
+ }
+ } else if (oss_channel == SOUND_MIXER_BASS) {
+ val = codec->codec_read(codec , mh->offset) & ~0x0f00;
+ val |= ((((100 - left) * mh->scale) / 100) << 8) & 0x0e00;
+ } else if (oss_channel == SOUND_MIXER_TREBLE) {
+ val = codec->codec_read(codec , mh->offset) & ~0x000f;
+ val |= (((100 - left) * mh->scale) / 100) & 0x000e;
+ } else if(left == 0) {
+ val = AC97_MUTE;
} else if (oss_channel == SOUND_MIXER_SPEAKER) {
val = (((100 - left) * mh->scale) / 100) << 1;
} else if (oss_channel == SOUND_MIXER_PHONEIN) {
val = (((100 - left) * mh->scale) / 100);
} else if (oss_channel == SOUND_MIXER_PHONEOUT) {
- val = (((100 - left) * mh->scale) / 100);
+ scale = (1 << codec->bit_resolution);
+ val = (((100 - left) * scale) / 100);
} else if (oss_channel == SOUND_MIXER_MIC) {
val = codec->codec_read(codec , mh->offset) & ~0x801f;
val |= (((100 - left) * mh->scale) / 100);
/* the low bit is optional in the tone sliders and masking
it lets us avoid the 0xf 'bypass'.. */
- } else if (oss_channel == SOUND_MIXER_BASS) {
- val = codec->codec_read(codec , mh->offset) & ~0x0f00;
- val |= ((((100 - left) * mh->scale) / 100) << 8) & 0x0e00;
- } else if (oss_channel == SOUND_MIXER_TREBLE) {
- val = codec->codec_read(codec , mh->offset) & ~0x000f;
- val |= (((100 - left) * mh->scale) / 100) & 0x000e;
}
#ifdef DEBUG
printk(" 0x%04x", val);
@@ -563,7 +595,7 @@
if (codec->codec_wait)
codec->codec_wait(codec);
else
- schedule_timeout(5);
+ udelay(10);
if ((audio = codec->codec_read(codec, AC97_RESET)) & 0x8000) {
printk(KERN_ERR "ac97_codec: %s ac97 codec not present\n",
@@ -582,6 +614,7 @@
id2 = codec->codec_read(codec, AC97_VENDOR_ID2);
for (i = 0; i < arraysize(ac97_codec_ids); i++) {
if (ac97_codec_ids[i].id == ((id1 << 16) | id2)) {
+ codec->type = ac97_codec_ids[i].id;
codec->name = ac97_codec_ids[i].name;
codec->codec_init = ac97_codec_ids[i].init;
break;
@@ -589,8 +622,8 @@
}
if (codec->name == NULL)
codec->name = "Unknown";
- printk(KERN_INFO "ac97_codec: AC97%s codec, id: 0x%04x:0x%04x (%s)\n",
- audio ? " audio" : (modem ? " modem" : ""),
+ printk(KERN_INFO "ac97_codec: AC97 %s codec, vendor id1: 0x%04x, "
+ "id2: 0x%04x (%s)\n", audio ? "Audio" : (modem ? "Modem" : ""),
id1, id2, codec->name);
return ac97_init_mixer(codec);
@@ -612,18 +645,21 @@
if (!(cap & 0x10))
codec->supported_mixers &= ~SOUND_MASK_ALTPCM;
+ /* detect bit resolution */
+ codec->codec_write(codec, AC97_MASTER_VOL_STEREO, 0x2020);
+ if(codec->codec_read(codec, AC97_MASTER_VOL_STEREO) == 0x1f1f)
+ codec->bit_resolution = 5;
+ else
+ codec->bit_resolution = 6;
+
/* generic OSS to AC97 wrapper */
codec->read_mixer = ac97_read_mixer;
codec->write_mixer = ac97_write_mixer;
codec->recmask_io = ac97_recmask_io;
codec->mixer_ioctl = ac97_mixer_ioctl;
- /* initialize volume level */
- codec->codec_write(codec, AC97_MASTER_VOL_STEREO, 0L);
- codec->codec_write(codec, AC97_PCMOUT_VOL, 0L);
-
/* codec specific initialization for 4-6 channel output or secondary codec stuff */
- if (codec->id != 0 && codec->codec_init != NULL) {
+ if (codec->codec_init != NULL) {
codec->codec_init(codec);
}
@@ -642,6 +678,10 @@
static int sigmatel_init(struct ac97_codec * codec)
{
+ /* Only set up secondary codec */
+ if (codec->id == 0)
+ return 1;
+
codec->codec_write(codec, AC97_SURROUND_MASTER, 0L);
/* initialize SigmaTel STAC9721/23 as secondary codec, decoding AC link
@@ -659,6 +699,18 @@
return 1;
}
+
+/*
+ * Bring up an AD1885
+ */
+
+static int enable_eapd(struct ac97_codec * codec)
+{
+ codec->codec_write(codec, AC97_POWER_CONTROL,
+ codec->codec_read(codec, AC97_POWER_CONTROL)|0x8000);
+ return 0;
+}
+
EXPORT_SYMBOL(ac97_read_proc);
EXPORT_SYMBOL(ac97_probe_codec);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)