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

View File

@ -38,62 +38,177 @@
#include "debug.h"
#include "io.h"
#define B_UTF8_REGISTERED "\xC2\xAE"
const char * stereo_enhancement_technique[] =
{
"No 3D Stereo Enhancement",
"Analog Devices",
"Creative Technology",
"National Semiconductor",
"Yamaha",
"BBE Sound",
"Crystal Semiconductor",
"Qsound Labs",
"Spatializer Audio Laboratories",
"SRS Labs",
"Platform Tech",
"AKM Semiconductor",
"Aureal",
"Aztech Labs",
"Binaura",
"ESS Technology",
"Harman International",
"Nvidea",
"Philips"
"Texas Instruments",
"VLSI Technology",
"TriTech",
"Realtek",
"Samsung",
"Wolfson Microelectronics",
"Delta Integration",
"SigmaTel",
"KS Waves",
"Rockwell",
"Unknown (29)",
"Unknown (30)",
"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()
{
const char * technique[] = {
"No 3D Stereo Enhancement",
"Analog Devices",
"Creative Technology",
"National Semiconductor",
"Yamaha",
"BBE Sound",
"Crystal Semiconductor",
"Qsound Labs",
"Spatializer Audio Laboratories",
"SRS Labs",
"Platform Tech",
"AKM Semiconductor",
"Aureal",
"Aztech Labs",
"Binaura",
"ESS Technology",
"Harman International",
"Nvidea",
"Philips"
"Texas Instruments",
"VLSI Technology",
"TriTech",
"Realtek",
"Samsung",
"Wolfson Microelectronics",
"Delta Integration",
"SigmaTel",
"KS Waves",
"Rockwell",
"Unknown (29)",
"Unknown (30)",
"Unknown (31)"
};
uint16 data;
data = ich_codec_read(AC97_RESET);
data = (data >> 10) & 31;
return technique[data];
return stereo_enhancement_technique[data];
}
const char *
ac97_get_vendor_id_description()
{
static char desc[10];
uint32 id = ac97_get_vendor_id();
codec_table *codec = find_codec_table(id);
char f = (id >> 24) & 0xff;
char s = (id >> 16) & 0xff;
char t = (id >> 8) & 0xff;
if (f == 0) f = '?';
if (s == 0) s = '?';
if (t == 0) t = '?';
sprintf(desc,"%c%c%c %u",f,s,t,id & 0xff);
return desc;
LOG(("codec %c%c%c %u\n",f,s,t,id & 0xff));
LOG(("info: %s\n",codec->info));
return codec->info;
}
uint32
@ -109,47 +224,52 @@ ac97_get_vendor_id()
void
ac97_amp_enable(bool yesno)
{
switch (ac97_get_vendor_id())
{
case 0x43525931: /* Cirrus Logic CS4299 rev A */
case 0x43525933: /* Cirrus Logic CS4299 rev C */
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:
{
LOG(("powerdown register was = %#04x\n",ich_codec_read(config->codecoffset + AC97_POWERDOWN)));
#if REVERSE_EAMP_POLARITY
yesno = !yesno;
LOG(("using reverse eamp polarity\n"));
#endif
if (yesno)
ich_codec_write(config->codecoffset + AC97_POWERDOWN, ich_codec_read(AC97_POWERDOWN) & ~0x8000); /* switch on (low active) */
else
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)));
break;
}
}
codec_table *codec;
LOG(("ac97_amp_enable\n"));
codec = find_codec_table(ac97_get_vendor_id());
codec->ops->amp_enable(yesno);
}
void
ac97_init()
{
switch (ac97_get_vendor_id())
{
case 0x41445461: /* Analog Devices AD1886 */
LOG(("using AD1886 init"));
ich_codec_write(config->codecoffset + 0x72, 0x0010);
break;
default:
break;
}
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)));
#if REVERSE_EAMP_POLARITY
yesno = !yesno;
LOG(("using reverse eamp polarity\n"));
#endif
if (yesno)
ich_codec_write(config->codecoffset + AC97_POWERDOWN, ich_codec_read(AC97_POWERDOWN) & ~0x8000); /* switch on (low active) */
else
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)));
}
void cirrus_amp_enable(bool yesno)
{
LOG(("cirrus_amp_enable\n"));
if (yesno)
ich_codec_write(config->codecoffset + 0x68, 0x8004);
else
ich_codec_write(config->codecoffset + 0x68, 0);
}