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 ebb892b179..5bb9f7c219 100644 --- a/src/add-ons/kernel/drivers/audio/ac97/ich/ac97.c +++ b/src/add-ons/kernel/drivers/audio/ac97/ich/ac97.c @@ -29,6 +29,7 @@ #include #include #include "ac97.h" +#include "config.h" //#define DEBUG 1 @@ -114,20 +115,20 @@ ac97_amp_enable(bool yesno) { LOG(("using Cirrus enable")); if (yesno) - ich_codec_write(0x68, 0x8004); + ich_codec_write(config->codecoffset + 0x68, 0x8004); else - ich_codec_write(0x68, 0); + ich_codec_write(config->codecoffset + 0x68, 0); break; } default: { - LOG(("powerdown register was = %#04x\n",ich_codec_read(AC97_POWERDOWN))); + LOG(("powerdown register was = %#04x\n",ich_codec_read(config->codecoffset + AC97_POWERDOWN))); if (yesno) - ich_codec_write(AC97_POWERDOWN, ich_codec_read(AC97_POWERDOWN) & ~0x8000); /* switch on (low active) */ + ich_codec_write(config->codecoffset + AC97_POWERDOWN, ich_codec_read(AC97_POWERDOWN) & ~0x8000); /* switch on (low active) */ else - ich_codec_write(AC97_POWERDOWN, ich_codec_read(AC97_POWERDOWN) | 0x8000); /* switch off */ - LOG(("powerdown register is = %#04x\n",ich_codec_read(AC97_POWERDOWN))); + 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; } } @@ -140,7 +141,7 @@ ac97_init() { case 0x41445461: /* Analog Devices AD1886 */ LOG(("using AD1886 init")); - ich_codec_write(0x72, 0x0010); + ich_codec_write(config->codecoffset + 0x72, 0x0010); break; default: break; 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 33e017c593..9446b600af 100644 --- a/src/add-ons/kernel/drivers/audio/ac97/ich/config.c +++ b/src/add-ons/kernel/drivers/audio/ac97/ich/config.c @@ -82,6 +82,7 @@ status_t probe_device(void) config->log_mbbar = 0; config->area_mmbar = -1; config->area_mbbar = -1; + config->codecoffset = 0; result = B_ERROR; cookie = 0; 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 1ef9803921..b3c16d9d88 100644 --- a/src/add-ons/kernel/drivers/audio/ac97/ich/config.h +++ b/src/add-ons/kernel/drivers/audio/ac97/ich/config.h @@ -43,6 +43,7 @@ typedef struct void * log_mbbar; // ich4 area_id area_mmbar; // ich4 area_id area_mbbar; // ich4 + uint32 codecoffset; } device_config; extern device_config *config; 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 3797129317..1f18f523cb 100644 --- a/src/add-ons/kernel/drivers/audio/ac97/ich/hardware.h +++ b/src/add-ons/kernel/drivers/audio/ac97/ich/hardware.h @@ -33,7 +33,8 @@ enum ICH_GLOBAL_REGISTER { ICH_REG_GLOB_CNT = 0x2C, ICH_REG_GLOB_STA = 0x30, - ICH_REG_ACC_SEMA = 0x34 + ICH_REG_ACC_SEMA = 0x34, + ICH_REG_SDM = 0x80 }; enum ICH_X_REGISTER_BASE /* base addresses for the following offsets */ @@ -94,10 +95,10 @@ enum REG_GLOB_STA_BITS STA_PIINT = 0x00000020, /* PCM In Interrupt */ STA_POINT = 0x00000040, /* PCM Out Interrupt */ STA_MINT = 0x00000080, /* Mic In Interrupt */ - STA_PCR = 0x00000100, /* AC_SDIN0 Codec Ready */ - STA_SCR = 0x00000200, /* AC_SDIN1 Codec Ready */ - STA_PRI = 0x00000400, /* AC_SDIN0 Resume Interrupt */ - STA_SRI = 0x00000800, /* AC_SDIN1 Resume Interrupt */ + STA_S0CR = 0x00000100, /* AC_SDIN0 Codec Ready */ + STA_S1CR = 0x00000200, /* AC_SDIN1 Codec Ready */ + STA_S0RI = 0x00000400, /* AC_SDIN0 Resume Interrupt */ + STA_S1RI = 0x00000800, /* AC_SDIN1 Resume Interrupt */ STA_RCS = 0x00008000, /* Read Completition Status */ STA_AD3 = 0x00010000, STA_MD3 = 0x00020000, @@ -107,7 +108,7 @@ enum REG_GLOB_STA_BITS STA_BCS = 0x08000000, /* Bit Clock Stopped */ STA_S2CR = 0x10000000, /* AC_SDIN2 Codec Ready */ STA_S2RI = 0x20000000, /* AC_SDIN2 Resume Interrupt */ - STA_INTMASK = (STA_MIINT | STA_MOINT | STA_PIINT | STA_POINT | STA_MINT | STA_PRI | STA_SRI | STA_M2INT | STA_P2INT | STA_SPINT | STA_S2RI) + STA_INTMASK = (STA_MIINT | STA_MOINT | STA_PIINT | STA_POINT | STA_MINT | STA_S0RI | STA_S1RI | STA_M2INT | STA_P2INT | STA_SPINT | STA_S2RI) }; #define ICH_BD_COUNT 32 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 7ce1acc543..481033890b 100644 --- a/src/add-ons/kernel/drivers/audio/ac97/ich/ich.c +++ b/src/add-ons/kernel/drivers/audio/ac97/ich/ich.c @@ -337,6 +337,7 @@ init_driver(void) { status_t rv; bigtime_t start; + bool s0cr, s1cr, s2cr; LOG_CREATE(); @@ -374,57 +375,87 @@ init_driver(void) LOG(("cold reset failed\n")); } - /* wait until a codec is ready */ + /* detect which codecs are ready */ + s0cr = s1cr = s2cr = false; start = system_time(); - while ((system_time() - start) < 1000000) { + do { rv = ich_reg_read_32(ICH_REG_GLOB_STA); - if ((rv & STA_PCR) != 0) - break; + if (!s0cr && (rv & STA_S0CR)) { + s0cr = true; + LOG(("AC_SDIN0 codec ready after %Ld us\n",(system_time() - start))); + } + if (!s1cr && (rv & STA_S1CR)) { + s1cr = true; + LOG(("AC_SDIN1 codec ready after %Ld us\n",(system_time() - start))); + } + if (!s2cr && (rv & STA_S2CR)) { + s2cr = true; + LOG(("AC_SDIN2 codec ready after %Ld us\n",(system_time() - start))); + } snooze(50000); + } while ((system_time() - start) < 1000000); + + if (!s0cr) { + LOG(("AC_SDIN0 codec not ready\n")); } - if ((rv & STA_PCR)) { - LOG(("primary codec ready after %Ld us\n",(system_time() - start))); - } else { - LOG(("primary codec not ready after %Ld us\n",(system_time() - start))); + if (!s1cr) { + LOG(("AC_SDIN1 codec not ready\n")); } - while ((system_time() - start) < 1000000) { - rv = ich_reg_read_32(ICH_REG_GLOB_STA); - if ((rv & STA_SCR) != 0) - break; - snooze(50000); - } - if ((rv & STA_SCR)) { - LOG(("secondary codec ready after %Ld us\n",(system_time() - start))); - } else { - LOG(("secondary codec not ready after %Ld us\n",(system_time() - start))); - } - while ((system_time() - start) < 1000000) { - rv = ich_reg_read_32(ICH_REG_GLOB_STA); - if ((rv & STA_S2CR) != 0) - break; - snooze(50000); - } - if ((rv & STA_S2CR)) { - LOG(("tertiary codec ready after %Ld us\n",(system_time() - start))); - } else { - LOG(("tertiary codec not ready after %Ld us\n",(system_time() - start))); + if (!s2cr) { + LOG(("AC_SDIN2 codec not ready\n")); } dump_hardware_regs(); - if ((rv & (STA_PCR | STA_SCR | STA_S2CR)) == 0) { + if (!s0cr && !s1cr && !s2cr) { PRINT(("compatible chipset found, but no codec ready!\n")); unmap_io_memory(); return B_ERROR; } - if ((rv & STA_PCR) == 0 && (rv & STA_S2CR) != 0) { - LOG(("using tertiary codec!\n")); - config->nambar += 0x100; - config->log_mmbar += 0x100; /* ICH 4 */ - } else if ((rv & STA_PCR) == 0 && (rv & STA_SCR) != 0) { - LOG(("using secondary codec!\n")); - config->nambar += 0x80; - config->log_mmbar += 0x80; /* ICH 4 */ + + if (config->type & TYPE_ICH4) { + /* we are using a ICH4 chipset, and assume that the codec beeing ready + * is the primary one. + */ + uint8 sdin; + uint16 reset; + uint8 id; + reset = ich_codec_read(0x00); /* access the primary codec */ + if (reset == 0 || reset == 0xFFFF) { + LOG(("primary codec not present\n")); + } //else { + sdin = 0x02 & ich_reg_read_8(ICH_REG_SDM); + id = 0x02 & (ich_codec_read(0x00 + 0x28) >> 14); + LOG(("primary codec id %d is connected to AC_SDIN%d\n", id, sdin)); + //} + reset = ich_codec_read(0x80); /* access the secondary codec */ + if (reset == 0 || reset == 0xFFFF) { + LOG(("secondary codec not present\n")); + } //else { + sdin = 0x02 & ich_reg_read_8(ICH_REG_SDM); + id = 0x02 & (ich_codec_read(0x80 + 0x28) >> 14); + LOG(("secondary codec id %d is connected to AC_SDIN%d\n", id, sdin)); + //} + reset = ich_codec_read(0x100); /* access the tertiary codec */ + if (reset == 0 || reset == 0xFFFF) { + LOG(("tertiary codec not present\n")); + } //else { + sdin = 0x02 & ich_reg_read_8(ICH_REG_SDM); + id = 0x02 & (ich_codec_read(0x100 + 0x28) >> 14); + LOG(("tertiary codec id %d is connected to AC_SDIN%d\n", id, sdin)); + //} + + /* XXX this may be wrong */ + ich_reg_write_8(ICH_REG_SDM, (ich_reg_read_8(ICH_REG_SDM) & 0x0F) | 0x08 | 0x90); + } else { + /* we are using a pre-ICH4 chipset, that has a fixed mapping of + * AC_SDIN0 = primary, AC_SDIN1 = secondary codec. + */ + if (!s0cr && s2cr) { + // is is unknown if this really works, perhaps we should better abort here + LOG(("primary codec doesn't seem to be available, using secondary!\n")); + config->codecoffset = 0x80; + } } dump_hardware_regs(); @@ -480,9 +511,9 @@ init_driver(void) chan_po->regbase = ICH_REG_PO_BASE; chan_mc->regbase = ICH_REG_MC_BASE; - /* reset the (primary?) codec */ + /* reset the codec */ LOG(("codec reset\n")); - ich_codec_write(0x00, 0x0000); + ich_codec_write(config->codecoffset + 0x00, 0x0000); snooze(50000); // 50 ms ac97_init(); @@ -517,24 +548,24 @@ init_driver(void) } /* enable master output */ - ich_codec_write(0x02, 0x0000); + ich_codec_write(config->codecoffset + 0x02, 0x0000); /* enable pcm output */ - ich_codec_write(0x18, 0x0404); + ich_codec_write(config->codecoffset + 0x18, 0x0404); #if 0 /* enable pcm input */ - ich_codec_write(0x10, 0x0000); + ich_codec_write(config->codecoffset + 0x10, 0x0000); /* enable mic input */ - /* ich_codec_write(0x0E, 0x0000); */ + /* ich_codec_write(config->codecoffset + 0x0E, 0x0000); */ /* select pcm input record */ - ich_codec_write(0x1A, 4 | (4 << 8)); + ich_codec_write(config->codecoffset + 0x1A, 4 | (4 << 8)); /* enable PCM record */ - ich_codec_write(0x1C, 0x0000); + ich_codec_write(config->codecoffset + 0x1C, 0x0000); /* enable mic record */ - /* ich_codec_write(0x1E, 0x0000); */ + /* ich_codec_write(config->codecoffset + 0x1E, 0x0000); */ #endif LOG(("init_driver finished!\n")); @@ -615,9 +646,9 @@ int32 ich_int(void *unused) if ((sta & STA_INTMASK) == 0) return B_UNHANDLED_INTERRUPT; - if (sta & (STA_PRI | STA_SRI)) { + if (sta & (STA_S0RI | STA_S1RI | STA_S2RI)) { /* ignore and clear resume interrupt(s) */ - ich_reg_write_32(ICH_REG_GLOB_STA, sta & (STA_PRI | STA_SRI)); + ich_reg_write_32(ICH_REG_GLOB_STA, sta & (STA_S0RI | STA_S1RI | STA_S2RI)); } if (sta & STA_POINT) { // pcm-out diff --git a/src/add-ons/kernel/drivers/audio/ac97/ich/ich.h b/src/add-ons/kernel/drivers/audio/ac97/ich/ich.h index aa08ae2cd2..873be51ddd 100644 --- a/src/add-ons/kernel/drivers/audio/ac97/ich/ich.h +++ b/src/add-ons/kernel/drivers/audio/ac97/ich/ich.h @@ -30,7 +30,7 @@ #include "hardware.h" -#define VERSION "Version 1.3, Copyright (c) 2002 Marcus Overhagen, compiled on " ## __DATE__ ## " " ## __TIME__ +#define VERSION "Version 1.4, Copyright (c) 2002 Marcus Overhagen, compiled on " ## __DATE__ ## " " ## __TIME__ #define DRIVER_NAME "ich_ac97" #define BUFFER_SIZE 2048