Fixed clock rate calculation (multiple bugs).

Fixed sound stutter after start.
Added generic macros to deal with SIS7012 and Intel differences.
Fixed SIS7012 init (PICB register was written, instead of SR).


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3290 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
beveloper
2003-05-23 20:44:12 +00:00
parent f4949fca43
commit acd429ac89
5 changed files with 67 additions and 58 deletions
@@ -241,6 +241,16 @@ ac97_attach(ac97_dev **_dev, codec_reg_read reg_read, codec_reg_write reg_write,
void
ac97_detach(ac97_dev *dev)
{
/* Mute everything */
ac97_reg_update_bits(dev, AC97_CENTER_LFE_VOLUME, 0x8000, 0x8000);
ac97_reg_update_bits(dev, AC97_SURR_VOLUME, 0x8000, 0x8000);
ac97_reg_update_bits(dev, AC97_MASTER_VOLUME, 0x8000, 0x8000);
ac97_reg_update_bits(dev, AC97_AUX_OUT_VOLUME, 0x8000, 0x8000);
ac97_reg_update_bits(dev, AC97_MONO_VOLUME, 0x8000, 0x8000);
ac97_reg_update_bits(dev, AC97_PCM_OUT_VOLUME, 0x8000, 0x8000);
ac97_reg_update_bits(dev, AC97_CD_VOLUME, 0x8000, 0x8000);
ac97_reg_update_bits(dev, AC97_LINE_IN_VOLUME, 0x8000, 0x8000);
free(dev);
}
@@ -65,9 +65,7 @@ status_t probe_device(void)
config->mmbar = 0;
config->mbbar = 0;
config->irq = 0;
config->sample_size = 2;
config->swap_reg = false;
config->type = 0;
config->type = TYPE_DEFAULT;
config->log_mmbar = 0;
config->log_mbbar = 0;
config->area_mmbar = -1;
@@ -94,8 +92,7 @@ status_t probe_device(void)
config->type = TYPE_ICH4;
} else if (pciinfo->vendor_id == 0x1039 && pciinfo->device_id == 0x7012) { /* verified */
config->name = "SiS SI7012";
config->swap_reg = true;
config->sample_size = 1;
config->type = TYPE_SIS7012;
} else if (pciinfo->vendor_id == 0x10DE && pciinfo->device_id == 0x01B1) {
config->name = "NVIDIA nForce (MCP)";
} else if (pciinfo->vendor_id == 0x10DE && pciinfo->device_id == 0x006A) {
@@ -37,8 +37,6 @@ typedef struct
uint32 nabmbar;
uint32 irq;
uint32 type;
int sample_size;
bool swap_reg;
uint32 mmbar; // ich4
uint32 mbbar; // ich4
void * log_mmbar; // ich4
@@ -56,6 +54,14 @@ extern device_config *config;
status_t probe_device(void);
#define TYPE_DEFAULT 0x00
#define TYPE_ICH4 0x01
#define TYPE_SIS7012 0x02
/* The SIS7012 chipset has SR and PICB registers swapped when compared to Intel */
#define GET_REG_X_PICB(cfg) (((cfg)->type == TYPE_SIS7012) ? _ICH_REG_X_SR : _ICH_REG_X_PICB)
#define GET_REG_X_SR(cfg) (((cfg)->type == TYPE_SIS7012) ? _ICH_REG_X_PICB : _ICH_REG_X_SR)
/* Each 16 bit sample is counted as 1 in SIS7012 chipsets, 2 in all others */
#define GET_HW_SAMPLE_SIZE(cfg) (((cfg)->type == TYPE_SIS7012) ? 1 : 2)
#endif
@@ -49,8 +49,8 @@ enum ICH_X_REGISTER_OFFSETS /* add base address to get the PI, PO or MC reg */
ICH_REG_X_BDBAR = 0x00,
ICH_REG_X_CIV = 0x04,
ICH_REG_X_LVI = 0x05,
ICH_REG_X_SR = 0x06,
ICH_REG_X_PICB = 0x08,
_ICH_REG_X_SR = 0x06, /* use GET_REG_X_SR() macro from config.h */
_ICH_REG_X_PICB = 0x08, /* use GET_REG_X_PICB() macro from config.h */
ICH_REG_X_PIV = 0x0A,
ICH_REG_X_CR = 0x0B
};
+45 -49
View File
@@ -58,6 +58,7 @@ void chan_free_resources(void);
status_t map_io_memory(void);
status_t unmap_io_memory(void);
int32 int_thread(void *data);
void stop_chan(ich_chan *chan);
#if DEBUG > 2
void dump_chan(ich_chan *chan)
@@ -100,7 +101,7 @@ void init_chan(ich_chan *chan)
chan->buffer[i] = ((char *)chan->buffer_log_base) + (i % BUFFER_COUNT) * BUFFER_SIZE;
chan->bd[i] = (ich_bd *) (((char *)chan->bd_log_base) + i * sizeof(ich_bd));
chan->bd[i]->buffer = ((uint32)chan->buffer_phy_base) + (i % BUFFER_COUNT) * BUFFER_SIZE;
chan->bd[i]->length = BUFFER_SIZE / config->sample_size;
chan->bd[i]->length = BUFFER_SIZE / GET_HW_SAMPLE_SIZE(config);
chan->bd[i]->flags = ICH_BDC_FLAG_IOC;
}
@@ -128,7 +129,7 @@ void start_chan(ich_chan *chan)
chan->played_real_time = 0;
// step 1: clear status bits
ich_reg_write_16(chan->regbase + ICH_REG_X_SR, SR_FIFOE | SR_BCIS | SR_LVBCI);
ich_reg_write_16(chan->regbase + GET_REG_X_SR(config), SR_FIFOE | SR_BCIS | SR_LVBCI);
// step 2: prepare buffer transfer
ich_reg_write_8(chan->regbase + ICH_REG_X_LVI, (civ + 28) % ICH_BD_COUNT);
// step 3: enable interrupts & busmaster transfer
@@ -137,6 +138,12 @@ void start_chan(ich_chan *chan)
chan->running = true;
}
void stop_chan(ich_chan *chan)
{
ich_reg_write_8(chan->regbase + ICH_REG_X_CR, ich_reg_read_8(chan->regbase + ICH_REG_X_CR) & ~CR_RPBM);
chan->running = false;
snooze(10000); // 10 ms
}
void reset_chan(ich_chan *chan)
{
@@ -175,7 +182,7 @@ bool interrupt_test(void)
install_io_interrupt_handler(config->irq, ich_test_int, testresult, 0);
// clear status bits
ich_reg_write_16(chan_po->regbase + ICH_REG_X_SR, SR_FIFOE | SR_BCIS | SR_LVBCI);
ich_reg_write_16(chan_po->regbase + GET_REG_X_SR(config), SR_FIFOE | SR_BCIS | SR_LVBCI);
// start transfer of 1 buffer
ich_reg_write_8(chan_po->regbase + ICH_REG_X_LVI, (ich_reg_read_8(chan_po->regbase + ICH_REG_X_LVI) + 1) % ICH_BD_COUNT);
// enable interrupts & busmaster transfer
@@ -322,15 +329,15 @@ dump_hardware_regs()
LOG(("PI ICH_REG_X_BDBAR = %#x\n",ich_reg_read_32(ICH_REG_X_BDBAR + ICH_REG_PI_BASE)));
LOG(("PI ICH_REG_X_CIV = %#x\n",ich_reg_read_8(ICH_REG_X_CIV + ICH_REG_PI_BASE)));
LOG(("PI ICH_REG_X_LVI = %#x\n",ich_reg_read_8(ICH_REG_X_LVI + ICH_REG_PI_BASE)));
LOG(("PI ICH_REG_X_SR = %#x\n",ich_reg_read_16(ICH_REG_X_SR + ICH_REG_PI_BASE)));
LOG(("PI ICH_REG_X_PICB = %#x\n",ich_reg_read_16(ICH_REG_X_PICB + ICH_REG_PI_BASE)));
LOG(("PI REG_X_SR = %#x\n",ich_reg_read_16(GET_REG_X_SR(config) + ICH_REG_PI_BASE)));
LOG(("PI REG_X_PICB = %#x\n",ich_reg_read_16(GET_REG_X_PICB(config) + ICH_REG_PI_BASE)));
LOG(("PI ICH_REG_X_PIV = %#x\n",ich_reg_read_8(ICH_REG_X_PIV + ICH_REG_PI_BASE)));
LOG(("PI ICH_REG_X_CR = %#x\n",ich_reg_read_8(ICH_REG_X_CR + ICH_REG_PI_BASE)));
LOG(("PO ICH_REG_X_BDBAR = %#x\n",ich_reg_read_32(ICH_REG_X_BDBAR + ICH_REG_PO_BASE)));
LOG(("PO ICH_REG_X_CIV = %#x\n",ich_reg_read_8(ICH_REG_X_CIV + ICH_REG_PO_BASE)));
LOG(("PO ICH_REG_X_LVI = %#x\n",ich_reg_read_8(ICH_REG_X_LVI + ICH_REG_PO_BASE)));
LOG(("PO ICH_REG_X_SR = %#x\n",ich_reg_read_16(ICH_REG_X_SR + ICH_REG_PO_BASE)));
LOG(("PO ICH_REG_X_PICB = %#x\n",ich_reg_read_16(ICH_REG_X_PICB + ICH_REG_PO_BASE)));
LOG(("PO REG_X_SR = %#x\n",ich_reg_read_16(GET_REG_X_SR(config) + ICH_REG_PO_BASE)));
LOG(("PO REG_X_PICB = %#x\n",ich_reg_read_16(GET_REG_X_PICB(config) + ICH_REG_PO_BASE)));
LOG(("PO ICH_REG_X_PIV = %#x\n",ich_reg_read_8(ICH_REG_X_PIV + ICH_REG_PO_BASE)));
LOG(("PO ICH_REG_X_CR = %#x\n",ich_reg_read_8(ICH_REG_X_CR + ICH_REG_PO_BASE)));
}
@@ -359,24 +366,31 @@ ich_clock_get()
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));
picb = ich_reg_read_16(ICH_REG_PO_BASE + GET_REG_X_PICB(config));
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))
picb = (picb * GET_HW_SAMPLE_SIZE(config)) / 4; /* convert picb into frames */
if (picb <= (BUFFER_SIZE / 4))
startframe += (BUFFER_SIZE / 4) - picb;
else
LOG(("wrong picb = %d, max %d\n", picb, BUFFER_SIZE / 4));
snooze(100000);
snooze(40000);
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));
picb = ich_reg_read_16(ICH_REG_PO_BASE + GET_REG_X_PICB(config));
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))
picb = (picb * GET_HW_SAMPLE_SIZE(config)) / 4; /* convert picb into frames */
if (picb <= (BUFFER_SIZE / 4))
stopframe += (BUFFER_SIZE / 4) - picb;
else
LOG(("wrong picb = %d, max %d\n", picb, BUFFER_SIZE / 4));
if (stopframe < startframe)
stopframe += ICH_BD_COUNT * (BUFFER_SIZE / 4);
@@ -388,9 +402,6 @@ ich_clock_get()
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)) {
@@ -398,35 +409,18 @@ ich_clock_calibrate()
return;
}
if (!chan_po->running)
start_chan(chan_po);
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;
}
#if DEBUG > 0
{
int i;
for (i = 0; i < 20; i++)
LOG(("ich_clock_calibrate: rate %ld\n", ich_clock_get()));
}
}
#endif
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));
rate = ich_clock_get();
LOG(("ich_clock_calibrate: rate %ld\n", rate));
if (rate > (44100 - 1000) && rate < (44100 + 1000)) {
LOG(("ich_clock_calibrate: setting clock 44100\n"));
@@ -448,6 +442,8 @@ ich_clock_calibrate()
ac97_set_clock(config->ac97, 48000);
ac97_set_rate(config->ac97, AC97_PCM_FRONT_DAC_RATE, 48000);
}
stop_chan(chan_po);
}
status_t
@@ -720,7 +716,7 @@ int32 ich_test_int(void *check)
* pointed to by check to true.
*/
uint32 sta = ich_reg_read_32(ICH_REG_GLOB_STA);
uint16 sr = ich_reg_read_16(chan_po->regbase + (config->swap_reg ? ICH_REG_X_PICB : ICH_REG_X_SR));
uint16 sr = ich_reg_read_16(chan_po->regbase + GET_REG_X_SR(config));
if ((sta & STA_INTMASK) == 0)
return B_UNHANDLED_INTERRUPT;
@@ -729,7 +725,7 @@ int32 ich_test_int(void *check)
*(bool *)check = true; // notify
sr &= SR_FIFOE | SR_BCIS | SR_LVBCI;
ich_reg_write_16(chan_po->regbase + (config->swap_reg ? ICH_REG_X_PICB : ICH_REG_X_SR),sr);
ich_reg_write_16(chan_po->regbase + GET_REG_X_SR(config), sr);
return B_HANDLED_INTERRUPT;
}
@@ -748,7 +744,7 @@ int32 ich_int(void *unused)
}
if (sta & STA_POINT) { // pcm-out
uint16 sr = ich_reg_read_16(chan_po->regbase + (config->swap_reg ? ICH_REG_X_PICB : ICH_REG_X_SR));
uint16 sr = ich_reg_read_16(chan_po->regbase + GET_REG_X_SR(config));
sr &= SR_FIFOE | SR_BCIS | SR_LVBCI;
if (sr & SR_BCIS) { // a buffer completed
@@ -780,11 +776,11 @@ int32 ich_int(void *unused)
release_sem_etc(chan_po->buffer_ready_sem,1,B_DO_NOT_RESCHEDULE);
}
ich_reg_write_16(chan_po->regbase + (config->swap_reg ? ICH_REG_X_PICB : ICH_REG_X_SR),sr);
ich_reg_write_16(chan_po->regbase + GET_REG_X_SR(config), sr);
}
if (sta & STA_PIINT) { // pcm-in
uint16 sr = ich_reg_read_16(chan_pi->regbase + (config->swap_reg ? ICH_REG_X_PICB : ICH_REG_X_SR));
uint16 sr = ich_reg_read_16(chan_pi->regbase + GET_REG_X_SR(config));
sr &= SR_FIFOE | SR_BCIS | SR_LVBCI;
if (sr & SR_BCIS) { // a buffer completed
@@ -816,16 +812,16 @@ int32 ich_int(void *unused)
release_sem_etc(chan_pi->buffer_ready_sem,1,B_DO_NOT_RESCHEDULE);
}
ich_reg_write_16(chan_pi->regbase + (config->swap_reg ? ICH_REG_X_PICB : ICH_REG_X_SR),sr);
ich_reg_write_16(chan_pi->regbase + GET_REG_X_SR(config), sr);
}
if (sta & STA_MINT) { // mic-in
uint16 sr = ich_reg_read_16(chan_mc->regbase + (config->swap_reg ? ICH_REG_X_PICB : ICH_REG_X_SR));
uint16 sr = ich_reg_read_16(chan_mc->regbase + GET_REG_X_SR(config));
sr &= SR_FIFOE | SR_BCIS | SR_LVBCI;
if (sr & SR_BCIS) { // a buffer completed
release_sem_etc(chan_mc->buffer_ready_sem,1,B_DO_NOT_RESCHEDULE);
}
ich_reg_write_16(chan_mc->regbase + (config->swap_reg ? ICH_REG_X_PICB : ICH_REG_X_SR),sr);
ich_reg_write_16(chan_mc->regbase + GET_REG_X_SR(config), sr);
}
return B_HANDLED_INTERRUPT;
}