better codec detection and allow codec specific functions

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@950 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
beveloper
2002-09-01 21:23:57 +00:00
parent b4be4c38fa
commit 0170038a31
+157 -37
View File
@@ -38,10 +38,10 @@
#include "debug.h" #include "debug.h"
#include "io.h" #include "io.h"
const char * #define B_UTF8_REGISTERED "\xC2\xAE"
ac97_get_3d_stereo_enhancement()
const char * stereo_enhancement_technique[] =
{ {
const char * technique[] = {
"No 3D Stereo Enhancement", "No 3D Stereo Enhancement",
"Analog Devices", "Analog Devices",
"Creative Technology", "Creative Technology",
@@ -74,26 +74,141 @@ ac97_get_3d_stereo_enhancement()
"Unknown (29)", "Unknown (29)",
"Unknown (30)", "Unknown (30)",
"Unknown (31)" "Unknown (31)"
}; };
typedef void (* codec_init)(void);
typedef void (* codec_amp_enable)(bool);
typedef struct codec_ops_tag
{
codec_init init;
codec_amp_enable amp_enable;
} codec_ops;
typedef struct codec_table_tag
{
uint32 id;
uint32 mask;
codec_ops *ops;
const char *info;
} codec_table;
void default_init(void);
void ad1886_init(void);
void default_amp_enable(bool);
void cirrus_amp_enable(bool);
codec_ops default_ops = { default_init, default_amp_enable };
codec_ops ad1868_ops = { ad1886_init, default_amp_enable };
codec_ops cirrus_ops = { default_init, cirrus_amp_enable };
codec_table codecs[] =
{
/* Vendor ID and description imported from FreeBSD src/sys/dev/sound/pcm/ac97.c */
{ 0x414b4d00, 0xffffffff, &default_ops, "Asahi Kasei AK4540" },
{ 0x414b4d01, 0xffffffff, &default_ops, "Asahi Kasei AK4542" },
{ 0x414b4d02, 0xffffffff, &default_ops, "Asahi Kasei AK4543" },
{ 0x43525900, 0xffffffff, &default_ops, "Cirrus Logic CS4297" },
{ 0x43525903, 0xffffffff, &default_ops, "Cirrus Logic CS4297" },
{ 0x43525913, 0xffffffff, &default_ops, "Cirrus Logic CS4297A" },
{ 0x43525914, 0xffffffff, &default_ops, "Cirrus Logic CS4297B" },
{ 0x43525923, 0xffffffff, &default_ops, "Cirrus Logic CS4294C" },
{ 0x4352592b, 0xffffffff, &default_ops, "Cirrus Logic CS4298C" },
{ 0x43525931, 0xffffffff, &cirrus_ops, "Cirrus Logic CS4299A" },
{ 0x43525933, 0xffffffff, &cirrus_ops, "Cirrus Logic CS4299C" },
{ 0x43525934, 0xffffffff, &cirrus_ops, "Cirrus Logic CS4299D" },
{ 0x43525941, 0xffffffff, &default_ops, "Cirrus Logic CS4201A" },
{ 0x43525951, 0xffffffff, &default_ops, "Cirrus Logic CS4205A" },
{ 0x43525961, 0xffffffff, &default_ops, "Cirrus Logic CS4291A" },
{ 0x45838308, 0xffffffff, &default_ops, "ESS Technology ES1921" },
{ 0x49434511, 0xffffffff, &default_ops, "ICEnsemble ICE1232" },
{ 0x4e534331, 0xffffffff, &default_ops, "National Semiconductor LM4549" },
{ 0x83847600, 0xffffffff, &default_ops, "SigmaTel STAC9700/9783/9784" },
{ 0x83847604, 0xffffffff, &default_ops, "SigmaTel STAC9701/9703/9704/9705" },
{ 0x83847605, 0xffffffff, &default_ops, "SigmaTel STAC9704" },
{ 0x83847608, 0xffffffff, &default_ops, "SigmaTel STAC9708/9711" },
{ 0x83847609, 0xffffffff, &default_ops, "SigmaTel STAC9721/9723" },
{ 0x83847644, 0xffffffff, &default_ops, "SigmaTel STAC9744" },
{ 0x83847656, 0xffffffff, &default_ops, "SigmaTel STAC9756/9757" },
{ 0x53494c22, 0xffffffff, &default_ops, "Silicon Laboratory Si3036" },
{ 0x53494c23, 0xffffffff, &default_ops, "Silicon Laboratory Si3038" },
{ 0x54524103, 0xffffffff, &default_ops, "TriTech TR?????" },
{ 0x54524106, 0xffffffff, &default_ops, "TriTech TR28026" },
{ 0x54524108, 0xffffffff, &default_ops, "TriTech TR28028" },
{ 0x54524123, 0xffffffff, &default_ops, "TriTech TR28602" },
{ 0x574d4c00, 0xffffffff, &default_ops, "Wolfson WM9701A" },
{ 0x574d4c03, 0xffffffff, &default_ops, "Wolfson WM9703/9704" },
{ 0x574d4c04, 0xffffffff, &default_ops, "Wolfson WM9704 (quad)" },
/* Assembled from datasheets: */
{ 0x41445303, 0xffffffff, &default_ops, "Analog Devices AD1819B SoundPort"B_UTF8_REGISTERED },
{ 0x41445340, 0xffffffff, &default_ops, "Analog Devices AD1881 SoundMAX"B_UTF8_REGISTERED },
{ 0x41445348, 0xffffffff, &default_ops, "Analog Devices AD1881A SoundMAX"B_UTF8_REGISTERED },
{ 0x41445360, 0xffffffff, &default_ops, "Analog Devices AD1885 SoundMAX"B_UTF8_REGISTERED },
{ 0x41445361, 0xffffffff, &ad1868_ops, "Analog Devices AD1886 SoundMAX"B_UTF8_REGISTERED },
{ 0x41445362, 0xffffffff, &default_ops, "Analog Devices AD1887 SoundMAX"B_UTF8_REGISTERED },
{ 0x41445363, 0xffffffff, &default_ops, "Analog Devices AD1886A SoundMAX"B_UTF8_REGISTERED },
{ 0x41445371, 0xffffffff, &default_ops, "Analog Devices AD1981A SoundMAX"B_UTF8_REGISTERED },
{ 0x41445372, 0xffffffff, &default_ops, "Analog Devices AD1981A SoundMAX"B_UTF8_REGISTERED },
{ 0x414c4320, 0xfffffff0, &default_ops, "Avance Logic (Realtek) ALC100/ALC100P, RL5383/RL5522" },
{ 0x414c4730, 0xffffffff, &default_ops, "Avance Logic (Realtek) ALC101" },
#if 0
{ 0x414c4710, 0xffffffff, &default_ops, "Avance Logic (Realtek) ALC200/ALC200A" }, /* datasheet says id2 = 4710 */
{ 0x414c4710, 0xffffffff, &default_ops, "Avance Logic (Realtek) ALC201/ALC201A" }, /* 4710 or 4720 */
{ 0x414c4720, 0xffffffff, &default_ops, "Avance Logic (Realtek) ALC650" }, /* datasheet says id2 = 4720 */
#else
{ 0x414c4710, 0xffffffff, &default_ops, "Avance Logic (Realtek) ALC200/ALC200A or ALC201/ALC201A" },
{ 0x414c4720, 0xffffffff, &default_ops, "Avance Logic (Realtek) ALC650 or ALC201/ALC201A" },
#endif
{ 0x414c4740, 0xffffffff, &default_ops, "Avance Logic (Realtek) ALC202/ALC202A" },
/* Vendors only: */
{ 0x41445300, 0xffffff00, &default_ops, "Analog Devices" },
{ 0x414b4d00, 0xffffff00, &default_ops, "Asahi Kasei" },
{ 0x414c4700, 0xffffff00, &default_ops, "Avance Logic (Realtek)" },
{ 0x43525900, 0xffffff00, &default_ops, "Cirrus Logic" },
{ 0x45838300, 0xffffff00, &default_ops, "ESS Technology" },
{ 0x49434500, 0xffffff00, &default_ops, "ICEnsemble" },
{ 0x4e534300, 0xffffff00, &default_ops, "National Semiconductor" },
{ 0x83847600, 0xffffff00, &default_ops, "SigmaTel" },
{ 0x53494c00, 0xffffff00, &default_ops, "Silicon Laboratory" },
{ 0x54524100, 0xffffff00, &default_ops, "TriTech" },
{ 0x574d4c00, 0xffffff00, &default_ops, "Wolfson" },
{ 0x00000000, 0x00000000, &default_ops, "Unknown" } /* must be last one, matches every codec */
};
codec_table *
find_codec_table(uint32 codecid)
{
codec_table *codec;
for (codec = codecs; codec->id; codec++)
if ((codec->id & codec->mask) == (codecid & codec->mask))
break;
return codec;
}
const char *
ac97_get_3d_stereo_enhancement()
{
uint16 data; uint16 data;
data = ich_codec_read(AC97_RESET); data = ich_codec_read(AC97_RESET);
data = (data >> 10) & 31; data = (data >> 10) & 31;
return technique[data]; return stereo_enhancement_technique[data];
} }
const char * const char *
ac97_get_vendor_id_description() ac97_get_vendor_id_description()
{ {
static char desc[10];
uint32 id = ac97_get_vendor_id(); uint32 id = ac97_get_vendor_id();
codec_table *codec = find_codec_table(id);
char f = (id >> 24) & 0xff; char f = (id >> 24) & 0xff;
char s = (id >> 16) & 0xff; char s = (id >> 16) & 0xff;
char t = (id >> 8) & 0xff; char t = (id >> 8) & 0xff;
if (f == 0) f = '?'; if (f == 0) f = '?';
if (s == 0) s = '?'; if (s == 0) s = '?';
if (t == 0) t = '?'; if (t == 0) t = '?';
sprintf(desc,"%c%c%c %u",f,s,t,id & 0xff); LOG(("codec %c%c%c %u\n",f,s,t,id & 0xff));
return desc; LOG(("info: %s\n",codec->info));
return codec->info;
} }
uint32 uint32
@@ -109,22 +224,35 @@ ac97_get_vendor_id()
void void
ac97_amp_enable(bool yesno) ac97_amp_enable(bool yesno)
{ {
switch (ac97_get_vendor_id()) codec_table *codec;
{ LOG(("ac97_amp_enable\n"));
case 0x43525931: /* Cirrus Logic CS4299 rev A */ codec = find_codec_table(ac97_get_vendor_id());
case 0x43525933: /* Cirrus Logic CS4299 rev C */ codec->ops->amp_enable(yesno);
case 0x43525934: /* Cirrus Logic CS4299 rev D */ }
{
LOG(("using Cirrus enable"));
if (yesno)
ich_codec_write(config->codecoffset + 0x68, 0x8004);
else
ich_codec_write(config->codecoffset + 0x68, 0);
break;
}
default: void
{ ac97_init()
{
codec_table *codec;
LOG(("ac97_init\n"));
codec = find_codec_table(ac97_get_vendor_id());
codec->ops->init();
}
void default_init(void)
{
LOG(("default_init\n"));
}
void ad1886_init(void)
{
LOG(("ad1886_init\n"));
ich_codec_write(config->codecoffset + 0x72, 0x0010);
}
void default_amp_enable(bool yesno)
{
LOG(("default_amp_enable\n"));
LOG(("powerdown register was = %#04x\n",ich_codec_read(config->codecoffset + AC97_POWERDOWN))); LOG(("powerdown register was = %#04x\n",ich_codec_read(config->codecoffset + AC97_POWERDOWN)));
#if REVERSE_EAMP_POLARITY #if REVERSE_EAMP_POLARITY
yesno = !yesno; yesno = !yesno;
@@ -135,21 +263,13 @@ ac97_amp_enable(bool yesno)
else else
ich_codec_write(config->codecoffset + AC97_POWERDOWN, ich_codec_read(AC97_POWERDOWN) | 0x8000); /* switch off */ ich_codec_write(config->codecoffset + AC97_POWERDOWN, ich_codec_read(AC97_POWERDOWN) | 0x8000); /* switch off */
LOG(("powerdown register is = %#04x\n",ich_codec_read(config->codecoffset + AC97_POWERDOWN))); LOG(("powerdown register is = %#04x\n",ich_codec_read(config->codecoffset + AC97_POWERDOWN)));
break;
}
}
} }
void void cirrus_amp_enable(bool yesno)
ac97_init()
{ {
switch (ac97_get_vendor_id()) LOG(("cirrus_amp_enable\n"));
{ if (yesno)
case 0x41445461: /* Analog Devices AD1886 */ ich_codec_write(config->codecoffset + 0x68, 0x8004);
LOG(("using AD1886 init")); else
ich_codec_write(config->codecoffset + 0x72, 0x0010); ich_codec_write(config->codecoffset + 0x68, 0);
break;
default:
break;
}
} }