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; }