From acd429ac8954b02182438bb7ed56c86e34e78142 Mon Sep 17 00:00:00 2001 From: beveloper Date: Fri, 23 May 2003 20:44:12 +0000 Subject: [PATCH] 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 --- .../kernel/drivers/audio/ac97/ich/ac97.c | 10 ++ .../kernel/drivers/audio/ac97/ich/config.c | 7 +- .../kernel/drivers/audio/ac97/ich/config.h | 10 +- .../kernel/drivers/audio/ac97/ich/hardware.h | 4 +- .../kernel/drivers/audio/ac97/ich/ich.c | 94 +++++++++---------- 5 files changed, 67 insertions(+), 58 deletions(-) diff --git a/src/add-ons/kernel/drivers/audio/ac97/ich/ac97.c b/src/add-ons/kernel/drivers/audio/ac97/ich/ac97.c index cf024251d0..11780fbc03 100644 --- a/src/add-ons/kernel/drivers/audio/ac97/ich/ac97.c +++ b/src/add-ons/kernel/drivers/audio/ac97/ich/ac97.c @@ -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); } diff --git a/src/add-ons/kernel/drivers/audio/ac97/ich/config.c b/src/add-ons/kernel/drivers/audio/ac97/ich/config.c index 145a919974..392af4dee8 100644 --- a/src/add-ons/kernel/drivers/audio/ac97/ich/config.c +++ b/src/add-ons/kernel/drivers/audio/ac97/ich/config.c @@ -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) { diff --git a/src/add-ons/kernel/drivers/audio/ac97/ich/config.h b/src/add-ons/kernel/drivers/audio/ac97/ich/config.h index 4ab94817f2..105fc1ceed 100644 --- a/src/add-ons/kernel/drivers/audio/ac97/ich/config.h +++ b/src/add-ons/kernel/drivers/audio/ac97/ich/config.h @@ -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 diff --git a/src/add-ons/kernel/drivers/audio/ac97/ich/hardware.h b/src/add-ons/kernel/drivers/audio/ac97/ich/hardware.h index e4a8dbefbb..98b56c8161 100644 --- a/src/add-ons/kernel/drivers/audio/ac97/ich/hardware.h +++ b/src/add-ons/kernel/drivers/audio/ac97/ich/hardware.h @@ -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 }; diff --git a/src/add-ons/kernel/drivers/audio/ac97/ich/ich.c b/src/add-ons/kernel/drivers/audio/ac97/ich/ich.c index cd80bd3a78..cd0f2aa9dc 100644 --- a/src/add-ons/kernel/drivers/audio/ac97/ich/ich.c +++ b/src/add-ons/kernel/drivers/audio/ac97/ich/ich.c @@ -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; }