rewritten AC97 handling
trying to detect real codec rate support for 44100 Hz is now default git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3183 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -29,7 +29,6 @@
|
||||
#include <stdio.h>
|
||||
#include <MediaDefs.h>
|
||||
#include "ac97.h"
|
||||
#include "config.h"
|
||||
|
||||
//#define DEBUG 1
|
||||
|
||||
@@ -76,16 +75,7 @@ const char * stereo_enhancement_technique[] =
|
||||
"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
|
||||
typedef struct
|
||||
{
|
||||
uint32 id;
|
||||
uint32 mask;
|
||||
@@ -93,15 +83,17 @@ typedef struct codec_table_tag
|
||||
const char *info;
|
||||
} codec_table;
|
||||
|
||||
void default_init(void);
|
||||
void ad1886_init(void);
|
||||
void default_init(ac97_dev *dev);
|
||||
void ad1886_init(ac97_dev *dev);
|
||||
|
||||
void default_amp_enable(bool);
|
||||
void cs4299_amp_enable(bool);
|
||||
void default_amp_enable(ac97_dev *dev, bool onoff);
|
||||
void cs4299_amp_enable(ac97_dev *dev, bool onoff);
|
||||
|
||||
codec_ops default_ops = { default_init, default_amp_enable };
|
||||
codec_ops ad1886_ops = { ad1886_init, default_amp_enable };
|
||||
codec_ops cs4299_ops = { default_init, cs4299_amp_enable };
|
||||
bool default_reg_is_valid(ac97_dev *dev, uint8 reg);
|
||||
|
||||
codec_ops default_ops = { default_init, default_amp_enable, default_reg_is_valid };
|
||||
codec_ops ad1886_ops = { ad1886_init, default_amp_enable, default_reg_is_valid };
|
||||
codec_ops cs4299_ops = { default_init, cs4299_amp_enable, default_reg_is_valid };
|
||||
|
||||
codec_table codecs[] =
|
||||
{
|
||||
@@ -186,113 +178,215 @@ find_codec_table(uint32 codecid)
|
||||
return codec;
|
||||
}
|
||||
|
||||
const char *
|
||||
ac97_get_3d_stereo_enhancement()
|
||||
void
|
||||
ac97_attach(ac97_dev **_dev, codec_reg_read reg_read, codec_reg_write reg_write, void *cookie)
|
||||
{
|
||||
uint16 data;
|
||||
data = ich_codec_read(AC97_RESET);
|
||||
data = (data >> 10) & 31;
|
||||
return stereo_enhancement_technique[data];
|
||||
}
|
||||
int reg;
|
||||
ac97_dev *dev;
|
||||
codec_table *codec;
|
||||
|
||||
*_dev = dev = (ac97_dev *) malloc(sizeof(ac97_dev));
|
||||
dev->cookie = cookie;
|
||||
dev->reg_read = reg_read;
|
||||
dev->reg_write = reg_write;
|
||||
dev->codec_id = (reg_read(cookie, AC97_VENDOR_ID1) << 16) | reg_read(cookie, AC97_VENDOR_ID2);
|
||||
codec = find_codec_table(dev->codec_id);
|
||||
dev->codec_info = codec->info;
|
||||
dev->init = codec->ops->init;
|
||||
dev->amp_enable = codec->ops->amp_enable;
|
||||
dev->reg_is_valid = codec->ops->reg_is_valid;
|
||||
dev->clock = 48000; /* default clock on non-broken motherboards */
|
||||
|
||||
const char *
|
||||
ac97_get_vendor_id_description()
|
||||
{
|
||||
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 = '?';
|
||||
LOG(("codec %c%c%c %u\n",f,s,t,id & 0xff));
|
||||
LOG(("info: %s\n",codec->info));
|
||||
return codec->info;
|
||||
}
|
||||
/* setup register cache */
|
||||
for (reg = 0; reg <= 0x7e; reg += 2)
|
||||
dev->reg_cache[reg] = ac97_reg_uncached_read(dev, reg);
|
||||
|
||||
uint32
|
||||
ac97_get_vendor_id()
|
||||
{
|
||||
uint16 data1;
|
||||
uint16 data2;
|
||||
data1 = ich_codec_read(AC97_VENDOR_ID1);
|
||||
data2 = ich_codec_read(AC97_VENDOR_ID2);
|
||||
return (((uint32)data1) << 16) | data2;
|
||||
/* reset the codec */
|
||||
LOG(("codec reset\n"));
|
||||
ac97_reg_uncached_write(dev, AC97_RESET, 0x0000);
|
||||
snooze(50000); // 50 ms
|
||||
|
||||
dev->init(dev);
|
||||
dev->amp_enable(dev, true);
|
||||
|
||||
ac97_reg_update_bits(dev, 0x2a, 1, 1); // enable VRA
|
||||
|
||||
dev->codec_3d_stereo_enhancement = stereo_enhancement_technique[(ac97_reg_cached_read(dev, AC97_RESET) >> 10) & 31];
|
||||
}
|
||||
|
||||
void
|
||||
ac97_amp_enable(bool yesno)
|
||||
ac97_detach(ac97_dev *dev)
|
||||
{
|
||||
codec_table *codec;
|
||||
LOG(("ac97_amp_enable\n"));
|
||||
codec = find_codec_table(ac97_get_vendor_id());
|
||||
codec->ops->amp_enable(yesno);
|
||||
free(dev);
|
||||
}
|
||||
|
||||
void
|
||||
ac97_init()
|
||||
ac97_suspend(ac97_dev *dev)
|
||||
{
|
||||
codec_table *codec;
|
||||
LOG(("ac97_init\n"));
|
||||
codec = find_codec_table(ac97_get_vendor_id());
|
||||
codec->ops->init();
|
||||
dev->amp_enable(dev, false);
|
||||
}
|
||||
|
||||
void default_init(void)
|
||||
void
|
||||
ac97_resume(ac97_dev *dev)
|
||||
{
|
||||
dev->amp_enable(dev, true);
|
||||
}
|
||||
|
||||
void
|
||||
ac97_reg_cached_write(ac97_dev *dev, uint8 reg, uint16 value)
|
||||
{
|
||||
if (!dev->reg_is_valid(dev, reg))
|
||||
return;
|
||||
dev->reg_write(dev->cookie, reg, value);
|
||||
dev->reg_cache[reg] = value;
|
||||
}
|
||||
|
||||
uint16
|
||||
ac97_reg_cached_read(ac97_dev *dev, uint8 reg)
|
||||
{
|
||||
if (!dev->reg_is_valid(dev, reg))
|
||||
return 0;
|
||||
return dev->reg_cache[reg];
|
||||
}
|
||||
|
||||
void
|
||||
ac97_reg_uncached_write(ac97_dev *dev, uint8 reg, uint16 value)
|
||||
{
|
||||
if (!dev->reg_is_valid(dev, reg))
|
||||
return;
|
||||
dev->reg_write(dev->cookie, reg, value);
|
||||
}
|
||||
|
||||
uint16
|
||||
ac97_reg_uncached_read(ac97_dev *dev, uint8 reg)
|
||||
{
|
||||
if (!dev->reg_is_valid(dev, reg))
|
||||
return 0;
|
||||
return dev->reg_read(dev->cookie, reg);
|
||||
}
|
||||
|
||||
bool
|
||||
ac97_reg_update(ac97_dev *dev, uint8 reg, uint16 value)
|
||||
{
|
||||
if (!dev->reg_is_valid(dev, reg))
|
||||
return false;
|
||||
if (ac97_reg_cached_read(dev, reg) == value)
|
||||
return false;
|
||||
ac97_reg_cached_write(dev, reg, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ac97_reg_update_bits(ac97_dev *dev, uint8 reg, uint16 mask, uint16 value)
|
||||
{
|
||||
uint16 old;
|
||||
if (!dev->reg_is_valid(dev, reg))
|
||||
return false;
|
||||
old = ac97_reg_cached_read(dev, reg);
|
||||
value &= mask;
|
||||
value |= (old & ~mask);
|
||||
if (old == value)
|
||||
return false;
|
||||
ac97_reg_cached_write(dev, reg, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ac97_set_rate(ac97_dev *dev, uint8 reg, uint32 rate)
|
||||
{
|
||||
uint32 value;
|
||||
uint32 old;
|
||||
value = (rate * dev->clock) / 48000;
|
||||
LOG(("ac97_set_rate: clock = %d, rate = %d, value = %d\n",dev->clock, rate, value));
|
||||
|
||||
if (value > 0xffff)
|
||||
return false;
|
||||
old = ac97_reg_cached_read(dev, reg);
|
||||
ac97_reg_cached_write(dev, reg, value);
|
||||
if (value != ac97_reg_uncached_read(dev, reg)) {
|
||||
LOG(("ac97_set_rate failed, new rate %d\n", ac97_reg_uncached_read(dev, reg)));
|
||||
ac97_reg_cached_write(dev, reg, old);
|
||||
return false;
|
||||
}
|
||||
LOG(("ac97_set_rate done\n"));
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ac97_set_clock(ac97_dev *dev, uint32 clock)
|
||||
{
|
||||
LOG(("ac97_set_clock: clock = %d\n", clock));
|
||||
dev->clock = clock;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*************************************************
|
||||
*/
|
||||
|
||||
bool
|
||||
default_reg_is_valid(ac97_dev *dev, uint8 reg)
|
||||
{
|
||||
if (reg & 1) return false;
|
||||
if (reg > 0x7e) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void default_init(ac97_dev *dev)
|
||||
{
|
||||
LOG(("default_init\n"));
|
||||
}
|
||||
|
||||
void ad1886_init(void)
|
||||
{
|
||||
LOG(("ad1886_init\n"));
|
||||
|
||||
LOG(("===\n"));
|
||||
LOG(("codecoffset = %d\n",config->codecoffset));
|
||||
LOG(("0x26 = %#04x\n",ich_codec_read(config->codecoffset + 0x26)));
|
||||
LOG(("0x2A = %#04x\n",ich_codec_read(config->codecoffset + 0x2A)));
|
||||
LOG(("0x3A = %#04x\n",ich_codec_read(config->codecoffset + 0x3A)));
|
||||
LOG(("0x72 = %#04x\n",ich_codec_read(config->codecoffset + 0x72)));
|
||||
LOG(("0x74 = %#04x\n",ich_codec_read(config->codecoffset + 0x74)));
|
||||
LOG(("0x76 = %#04x\n",ich_codec_read(config->codecoffset + 0x76)));
|
||||
|
||||
// ich_codec_write(config->codecoffset + 0x72, 0x0010); // enable software jack sense
|
||||
// ich_codec_write(config->codecoffset + 0x72, 0x0110); // disable hardware line muting
|
||||
|
||||
ich_codec_write(config->codecoffset + 0x72, 0x0230);
|
||||
|
||||
LOG(("===\n"));
|
||||
LOG(("0x26 = %#04x\n",ich_codec_read(config->codecoffset + 0x26)));
|
||||
LOG(("0x2A = %#04x\n",ich_codec_read(config->codecoffset + 0x2A)));
|
||||
LOG(("0x3A = %#04x\n",ich_codec_read(config->codecoffset + 0x3A)));
|
||||
LOG(("0x72 = %#04x\n",ich_codec_read(config->codecoffset + 0x72)));
|
||||
LOG(("0x74 = %#04x\n",ich_codec_read(config->codecoffset + 0x74)));
|
||||
LOG(("0x76 = %#04x\n",ich_codec_read(config->codecoffset + 0x76)));
|
||||
|
||||
LOG(("===\n"));
|
||||
}
|
||||
|
||||
void default_amp_enable(bool yesno)
|
||||
void default_amp_enable(ac97_dev *dev, 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", ac97_reg_uncached_read(dev, 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) */
|
||||
ac97_reg_cached_write(dev, AC97_POWERDOWN, ac97_reg_uncached_read(dev, 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)));
|
||||
ac97_reg_cached_write(dev, AC97_POWERDOWN, ac97_reg_uncached_read(dev, AC97_POWERDOWN) | 0x8000); /* switch off */
|
||||
LOG(("powerdown register is = %#04x\n", ac97_reg_uncached_read(dev, AC97_POWERDOWN)));
|
||||
}
|
||||
|
||||
void cs4299_amp_enable(bool yesno)
|
||||
|
||||
|
||||
void ad1886_init(ac97_dev *dev)
|
||||
{
|
||||
LOG(("ad1886_init\n"));
|
||||
|
||||
LOG(("===\n"));
|
||||
LOG(("0x26 = %#04x\n", ac97_reg_uncached_read(dev, 0x26)));
|
||||
LOG(("0x2A = %#04x\n", ac97_reg_uncached_read(dev, 0x2A)));
|
||||
LOG(("0x3A = %#04x\n", ac97_reg_uncached_read(dev, 0x3A)));
|
||||
LOG(("0x72 = %#04x\n", ac97_reg_uncached_read(dev, 0x72)));
|
||||
LOG(("0x74 = %#04x\n", ac97_reg_uncached_read(dev, 0x74)));
|
||||
LOG(("0x76 = %#04x\n", ac97_reg_uncached_read(dev, 0x76)));
|
||||
|
||||
// ich_codec_write(config->codecoffset + 0x72, 0x0010); // enable software jack sense
|
||||
// ich_codec_write(config->codecoffset + 0x72, 0x0110); // disable hardware line muting
|
||||
|
||||
ac97_reg_cached_write(dev, 0x72, 0x0230);
|
||||
|
||||
LOG(("===\n"));
|
||||
LOG(("0x26 = %#04x\n", ac97_reg_uncached_read(dev, 0x26)));
|
||||
LOG(("0x2A = %#04x\n", ac97_reg_uncached_read(dev, 0x2A)));
|
||||
LOG(("0x3A = %#04x\n", ac97_reg_uncached_read(dev, 0x3A)));
|
||||
LOG(("0x72 = %#04x\n", ac97_reg_uncached_read(dev, 0x72)));
|
||||
LOG(("0x74 = %#04x\n", ac97_reg_uncached_read(dev, 0x74)));
|
||||
LOG(("0x76 = %#04x\n", ac97_reg_uncached_read(dev, 0x76)));
|
||||
|
||||
LOG(("===\n"));
|
||||
}
|
||||
|
||||
void cs4299_amp_enable(ac97_dev *dev, bool yesno)
|
||||
{
|
||||
LOG(("cs4299_amp_enable\n"));
|
||||
if (yesno)
|
||||
ich_codec_write(config->codecoffset + 0x68, 0x8004);
|
||||
ac97_reg_cached_write(dev, 0x68, 0x8004);
|
||||
else
|
||||
ich_codec_write(config->codecoffset + 0x68, 0);
|
||||
ac97_reg_cached_write(dev, 0x68, 0);
|
||||
}
|
||||
|
||||
@@ -49,14 +49,63 @@ enum AC97_REGISTER {
|
||||
AC97_3D_CONTROL = 0x22,
|
||||
AC97_PAGING = 0x24,
|
||||
AC97_POWERDOWN = 0x26,
|
||||
AC97_PCM_FRONT_DAC_RATE = 0x2C,
|
||||
AC97_VENDOR_ID1 = 0x7C,
|
||||
AC97_VENDOR_ID2 = 0x7E
|
||||
};
|
||||
|
||||
const char * ac97_get_3d_stereo_enhancement();
|
||||
const char * ac97_get_vendor_id_description();
|
||||
uint32 ac97_get_vendor_id();
|
||||
void ac97_amp_enable(bool yesno);
|
||||
void ac97_init();
|
||||
struct ac97_dev;
|
||||
typedef struct ac97_dev ac97_dev;
|
||||
|
||||
typedef void (* codec_init)(ac97_dev * /*dev*/);
|
||||
typedef void (* codec_amp_enable)(ac97_dev */*dev*/, bool /*onoff*/);
|
||||
typedef bool (* codec_reg_is_valid)(ac97_dev */*dev*/, uint8 /*reg*/);
|
||||
typedef uint16 (* codec_reg_read)(void * /*cookie*/, uint8 /*reg*/);
|
||||
typedef void (* codec_reg_write)(void * /*cookie*/, uint8 /*reg*/, uint16 /*value*/);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
codec_init init;
|
||||
codec_amp_enable amp_enable;
|
||||
codec_reg_is_valid reg_is_valid;
|
||||
} codec_ops;
|
||||
|
||||
struct ac97_dev {
|
||||
uint32 capabilities;
|
||||
uint16 reg_cache[0x7f];
|
||||
|
||||
void * cookie;
|
||||
|
||||
uint32 codec_id;
|
||||
const char * codec_info;
|
||||
const char * codec_3d_stereo_enhancement;
|
||||
|
||||
codec_init init;
|
||||
codec_amp_enable amp_enable;
|
||||
codec_reg_is_valid reg_is_valid;
|
||||
codec_reg_read reg_read;
|
||||
codec_reg_write reg_write;
|
||||
|
||||
uint32 clock;
|
||||
};
|
||||
|
||||
|
||||
void ac97_attach(ac97_dev **dev, codec_reg_read reg_read, codec_reg_write reg_write, void *cookie);
|
||||
void ac97_detach(ac97_dev *dev);
|
||||
void ac97_suspend(ac97_dev *dev);
|
||||
void ac97_resume(ac97_dev *dev);
|
||||
|
||||
void ac97_reg_cached_write(ac97_dev *dev, uint8 reg, uint16 value);
|
||||
uint16 ac97_reg_cached_read(ac97_dev *dev, uint8 reg);
|
||||
void ac97_reg_uncached_write(ac97_dev *dev, uint8 reg, uint16 value);
|
||||
uint16 ac97_reg_uncached_read(ac97_dev *dev, uint8 reg);
|
||||
|
||||
bool ac97_reg_update(ac97_dev *dev, uint8 reg, uint16 value);
|
||||
bool ac97_reg_update_bits(ac97_dev *dev, uint8 reg, uint16 mask, uint16 value);
|
||||
|
||||
bool ac97_set_rate(ac97_dev *dev, uint8 reg, uint32 rate);
|
||||
|
||||
void ac97_set_clock(ac97_dev *dev, uint32 clock);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "debug.h"
|
||||
#include "ich.h"
|
||||
#include "util.h"
|
||||
#include "config.h"
|
||||
|
||||
/*
|
||||
*
|
||||
@@ -105,10 +106,16 @@ static status_t get_description(multi_description *data)
|
||||
memcpy(data->channels,&chans,sizeof(chans));
|
||||
}
|
||||
|
||||
data->output_rates = B_SR_48000;// | B_SR_44100 | B_SR_CVSR;
|
||||
data->input_rates = B_SR_48000;// | B_SR_44100 | B_SR_CVSR;
|
||||
if (ac97_set_rate(config->ac97, AC97_PCM_FRONT_DAC_RATE, 44100)) {
|
||||
data->output_rates = B_SR_44100;
|
||||
data->input_rates = B_SR_44100;
|
||||
data->max_cvsr_rate = 44100;
|
||||
} else {
|
||||
data->output_rates = B_SR_48000;// | B_SR_44100 | B_SR_CVSR;
|
||||
data->input_rates = B_SR_48000;// | B_SR_44100 | B_SR_CVSR;
|
||||
data->max_cvsr_rate = 48000;
|
||||
}
|
||||
data->min_cvsr_rate = 0;
|
||||
data->max_cvsr_rate = 48000;
|
||||
|
||||
data->output_formats = B_FMT_16BIT;
|
||||
data->input_formats = B_FMT_16BIT;
|
||||
@@ -143,11 +150,18 @@ static status_t get_global_format(multi_format_info *data)
|
||||
data->output_latency = 0;
|
||||
data->input_latency = 0;
|
||||
data->timecode_kind = 0;
|
||||
data->input.rate = B_SR_48000;
|
||||
data->input.cvsr = 48000;
|
||||
if (ac97_set_rate(config->ac97, AC97_PCM_FRONT_DAC_RATE, 44100)) {
|
||||
data->input.rate = B_SR_44100;
|
||||
data->input.cvsr = 44100;
|
||||
data->output.rate = B_SR_44100;
|
||||
data->output.cvsr = 44100;
|
||||
} else {
|
||||
data->input.rate = B_SR_48000;
|
||||
data->input.cvsr = 48000;
|
||||
data->output.rate = B_SR_48000;
|
||||
data->output.cvsr = 48000;
|
||||
}
|
||||
data->input.format = B_FMT_16BIT;
|
||||
data->output.rate = B_SR_48000;
|
||||
data->output.cvsr = 48000;
|
||||
data->output.format = B_FMT_16BIT;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
#ifndef _CONFIG_H_
|
||||
#define _CONFIG_H_
|
||||
|
||||
#include "ac97.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *name;
|
||||
@@ -44,6 +46,7 @@ typedef struct
|
||||
area_id area_mmbar; // ich4
|
||||
area_id area_mbbar; // ich4
|
||||
uint32 codecoffset;
|
||||
ac97_dev *ac97;
|
||||
} device_config;
|
||||
|
||||
extern device_config *config;
|
||||
|
||||
@@ -335,6 +335,122 @@ dump_hardware_regs()
|
||||
LOG(("PO ICH_REG_X_CR = %#x\n",ich_reg_read_8(ICH_REG_X_CR + ICH_REG_PO_BASE)));
|
||||
}
|
||||
|
||||
uint16
|
||||
ac97_reg_read(void *cookie, uint8 reg)
|
||||
{
|
||||
return ich_codec_read(config->codecoffset + reg);
|
||||
}
|
||||
|
||||
void
|
||||
ac97_reg_write(void *cookie, uint8 reg, uint16 value)
|
||||
{
|
||||
ich_codec_write(config->codecoffset + reg, value);
|
||||
}
|
||||
|
||||
uint32
|
||||
ich_clock_get()
|
||||
{
|
||||
uint32 civ1, civ2, picb;
|
||||
uint32 startframe;
|
||||
uint32 stopframe;
|
||||
uint32 rate;
|
||||
bigtime_t starttime;
|
||||
bigtime_t stoptime;
|
||||
|
||||
do {
|
||||
civ1 = ich_reg_read_8 (ICH_REG_PO_BASE + ICH_REG_X_CIV);
|
||||
picb = ich_reg_read_16(ICH_REG_PO_BASE + (config->swap_reg ? ICH_REG_X_SR : ICH_REG_X_PICB));
|
||||
civ2 = ich_reg_read_8 (ICH_REG_PO_BASE + ICH_REG_X_CIV);
|
||||
} while (civ1 != civ2);
|
||||
starttime = system_time();
|
||||
startframe = (civ1 * (BUFFER_SIZE / 4));
|
||||
if (picb < (BUFFER_SIZE / 4))
|
||||
startframe += (BUFFER_SIZE / 4) - picb;
|
||||
|
||||
snooze(100000);
|
||||
do {
|
||||
civ1 = ich_reg_read_8 (ICH_REG_PO_BASE + ICH_REG_X_CIV);
|
||||
picb = ich_reg_read_16(ICH_REG_PO_BASE + (config->swap_reg ? ICH_REG_X_SR : ICH_REG_X_PICB));
|
||||
civ2 = ich_reg_read_8 (ICH_REG_PO_BASE + ICH_REG_X_CIV);
|
||||
} while (civ1 != civ2);
|
||||
stoptime = system_time();
|
||||
stopframe = (civ1 * (BUFFER_SIZE / 4));
|
||||
if (picb < (BUFFER_SIZE / 4))
|
||||
stopframe += (BUFFER_SIZE / 4) - picb;
|
||||
|
||||
if (stopframe < startframe)
|
||||
stopframe += ICH_BD_COUNT * (BUFFER_SIZE / 4);
|
||||
|
||||
rate = (1000000LL * (stopframe - startframe)) / (stoptime - starttime);
|
||||
return rate;
|
||||
}
|
||||
|
||||
void
|
||||
ich_clock_calibrate()
|
||||
{
|
||||
int i, j;
|
||||
#define RATES 20
|
||||
uint32 rates[RATES];
|
||||
uint32 rate;
|
||||
|
||||
if (!ac97_set_rate(config->ac97, AC97_PCM_FRONT_DAC_RATE, 48000)) {
|
||||
LOG(("ich_clock_calibrate: can't set default clock rate\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!chan_po->running)
|
||||
start_chan(chan_po);
|
||||
|
||||
for (i = 0; i < RATES; i++)
|
||||
rates[i] = ich_clock_get();
|
||||
|
||||
// for (i = 0; i < RATES; i++)
|
||||
// LOG(("ich_clock_calibrate: rate %ld\n", rates[i]));
|
||||
// LOG(("ich_clock_calibrate: =========\n"));
|
||||
|
||||
for (i = 0; i < RATES; i++) {
|
||||
for (j = 0; j < (RATES - 1); j++) {
|
||||
if (rates[j] > rates[j + 1]) {
|
||||
uint32 temp = rates[j];
|
||||
rates[j] = rates[j + 1];
|
||||
rates[j + 1] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < RATES; i++)
|
||||
LOG(("ich_clock_calibrate: rate %ld\n", rates[i]));
|
||||
|
||||
rate = 0;
|
||||
for (i = 3; i < (RATES - 3); i++)
|
||||
rate += rates[i];
|
||||
rate /= (RATES - 6);
|
||||
|
||||
LOG(("ich_clock_calibrate: finished, rate %ld\n", rate));
|
||||
|
||||
if (rate > (44100 - 300) && rate < (44100 + 300)) {
|
||||
ac97_set_clock(config->ac97, 44100);
|
||||
LOG(("ich_clock_calibrate: setting clock 44100\n"));
|
||||
} else if (rate > (48000 - 300) && rate < (48000 + 300)) {
|
||||
ac97_set_clock(config->ac97, 48000);
|
||||
LOG(("ich_clock_calibrate: setting clock 48000\n"));
|
||||
} else if (rate > (41194 - 300) && rate < (41194 + 300)) {
|
||||
ac97_set_clock(config->ac97, 41194);
|
||||
LOG(("ich_clock_calibrate: setting clock 41194\n"));
|
||||
} else if (rate > (55930 - 300) && rate < (55930 + 300)) {
|
||||
ac97_set_clock(config->ac97, 55930);
|
||||
LOG(("ich_clock_calibrate: setting clock 55930\n"));
|
||||
}
|
||||
|
||||
if ( !ac97_set_rate(config->ac97, AC97_PCM_FRONT_DAC_RATE, 44100)
|
||||
&& !ac97_set_rate(config->ac97, AC97_PCM_FRONT_DAC_RATE, 48000)) {
|
||||
LOG(("ich_clock_calibrate: setting rates doesn't work with clock %d\n", config->ac97->clock));
|
||||
LOG(("ich_clock_calibrate: reset clock\n"));
|
||||
ac97_set_clock(config->ac97, 48000);
|
||||
ac97_set_rate(config->ac97, AC97_PCM_FRONT_DAC_RATE, 48000);
|
||||
}
|
||||
}
|
||||
|
||||
status_t
|
||||
init_driver(void)
|
||||
{
|
||||
@@ -514,18 +630,6 @@ init_driver(void)
|
||||
chan_po->regbase = ICH_REG_PO_BASE;
|
||||
chan_mc->regbase = ICH_REG_MC_BASE;
|
||||
|
||||
/* reset the codec */
|
||||
LOG(("codec reset\n"));
|
||||
ich_codec_write(config->codecoffset + 0x00, 0x0000);
|
||||
snooze(50000); // 50 ms
|
||||
|
||||
ac97_init();
|
||||
ac97_amp_enable(true);
|
||||
|
||||
LOG(("codec vendor id = %#08x\n",ac97_get_vendor_id()));
|
||||
LOG(("codec descripton = %s\n",ac97_get_vendor_id_description()));
|
||||
LOG(("codec 3d enhancement = %s\n",ac97_get_3d_stereo_enhancement()));
|
||||
|
||||
/* reset all channels */
|
||||
reset_chan(chan_pi);
|
||||
reset_chan(chan_po);
|
||||
@@ -535,7 +639,13 @@ init_driver(void)
|
||||
init_chan(chan_pi);
|
||||
init_chan(chan_po);
|
||||
init_chan(chan_mc);
|
||||
|
||||
|
||||
ac97_attach(&config->ac97, ac97_reg_read, ac97_reg_write, NULL);
|
||||
|
||||
LOG(("codec vendor id = %#08x\n", config->ac97->codec_id));
|
||||
LOG(("codec descripton = %s\n", config->ac97->codec_info));
|
||||
LOG(("codec 3d enhancement = %s\n", config->ac97->codec_3d_stereo_enhancement));
|
||||
|
||||
/* first test if interrupts are working, on some Laptops they don't work :-( */
|
||||
if (config->irq != 0 && false == interrupt_test()) {
|
||||
LOG(("interrupt not working, using a kernel thread for polling\n"));
|
||||
@@ -550,41 +660,33 @@ init_driver(void)
|
||||
resume_thread(int_thread_id);
|
||||
}
|
||||
|
||||
LOG(("codec master output = %#04x\n",ich_codec_read(config->codecoffset + 0x02)));
|
||||
LOG(("codec aux output = %#04x\n",ich_codec_read(config->codecoffset + 0x04)));
|
||||
LOG(("codec mono output = %#04x\n",ich_codec_read(config->codecoffset + 0x06)));
|
||||
LOG(("codec pcm output = %#04x\n",ich_codec_read(config->codecoffset + 0x18)));
|
||||
/* calibrate the clock */
|
||||
ich_clock_calibrate();
|
||||
|
||||
LOG(("codec master output = %#04x\n", ac97_reg_uncached_read(config->ac97, 0x02)));
|
||||
LOG(("codec aux output = %#04x\n", ac97_reg_uncached_read(config->ac97, 0x04)));
|
||||
LOG(("codec mono output = %#04x\n", ac97_reg_uncached_read(config->ac97, 0x06)));
|
||||
LOG(("codec cd = %#04x\n", ac97_reg_uncached_read(config->ac97, 0x12)));
|
||||
LOG(("codec pcm = %#04x\n", ac97_reg_uncached_read(config->ac97, 0x18)));
|
||||
|
||||
LOG(("writing codec registers\n"));
|
||||
/* enable master output */
|
||||
ich_codec_write(config->codecoffset + 0x02, 0x0000);
|
||||
ac97_reg_update(config->ac97, 0x02, 0x0000);
|
||||
/* enable aux output */
|
||||
ich_codec_write(config->codecoffset + 0x04, 0x0000);
|
||||
ac97_reg_update(config->ac97, 0x04, 0x0000);
|
||||
/* enable mono output */
|
||||
ich_codec_write(config->codecoffset + 0x06, 0x0000);
|
||||
/* enable pcm output */
|
||||
ich_codec_write(config->codecoffset + 0x18, 0x0404);
|
||||
ac97_reg_update(config->ac97, 0x06, 0x0000);
|
||||
|
||||
/* enable cd */
|
||||
ac97_reg_update(config->ac97, 0x12, 0x0808);
|
||||
/* enable pcm */
|
||||
ac97_reg_update(config->ac97, 0x18, 0x0808);
|
||||
|
||||
LOG(("codec master output = %#04x\n",ich_codec_read(config->codecoffset + 0x02)));
|
||||
LOG(("codec aux output = %#04x\n",ich_codec_read(config->codecoffset + 0x04)));
|
||||
LOG(("codec mono output = %#04x\n",ich_codec_read(config->codecoffset + 0x06)));
|
||||
LOG(("codec pcm output = %#04x\n",ich_codec_read(config->codecoffset + 0x18)));
|
||||
|
||||
#if 0
|
||||
/* enable pcm input */
|
||||
ich_codec_write(config->codecoffset + 0x10, 0x0000);
|
||||
|
||||
/* enable mic input */
|
||||
/* ich_codec_write(config->codecoffset + 0x0E, 0x0000); */
|
||||
|
||||
/* select pcm input record */
|
||||
ich_codec_write(config->codecoffset + 0x1A, 4 | (4 << 8));
|
||||
/* enable PCM record */
|
||||
ich_codec_write(config->codecoffset + 0x1C, 0x0000);
|
||||
|
||||
/* enable mic record */
|
||||
/* ich_codec_write(config->codecoffset + 0x1E, 0x0000); */
|
||||
#endif
|
||||
LOG(("codec master output = %#04x\n", ac97_reg_uncached_read(config->ac97, 0x02)));
|
||||
LOG(("codec aux output = %#04x\n", ac97_reg_uncached_read(config->ac97, 0x04)));
|
||||
LOG(("codec mono output = %#04x\n", ac97_reg_uncached_read(config->ac97, 0x06)));
|
||||
LOG(("codec cd = %#04x\n", ac97_reg_uncached_read(config->ac97, 0x12)));
|
||||
LOG(("codec pcm = %#04x\n", ac97_reg_uncached_read(config->ac97, 0x18)));
|
||||
|
||||
LOG(("init_driver finished!\n"));
|
||||
return B_OK;
|
||||
@@ -611,6 +713,8 @@ uninit_driver(void)
|
||||
|
||||
snooze(50000);
|
||||
|
||||
ac97_detach(config->ac97);
|
||||
|
||||
/* remove the interrupt handler or thread */
|
||||
if (config->irq != 0) {
|
||||
remove_io_interrupt_handler(config->irq,ich_int,0);
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
#define VERSION "Version 1.5, Copyright (c) 2002 Marcus Overhagen, compiled on " ## __DATE__ ## " " ## __TIME__
|
||||
#define DRIVER_NAME "ich_ac97"
|
||||
|
||||
#define BUFFER_SIZE 2048
|
||||
#define BUFFER_SIZE 4096
|
||||
#define BUFFER_COUNT 2
|
||||
#define BUFFER_FRAMES_COUNT (BUFFER_SIZE / 4)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user