X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=sound%2Fpci%2Fintel8x0.c;h=6dc6b7756bd40d968bf8e9ab8505cd825bdda4c2;hb=refs%2Fheads%2Fvserver;hp=0fa7e8a033b038b3f9b50f42d43cc54c02e27c85;hpb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;p=linux-2.6.git diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 0fa7e8a03..6dc6b7756 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -33,13 +33,11 @@ #include #include #include -#include #include #include #include #include #include -#include #include /* for 440MX workaround */ #include @@ -55,7 +53,9 @@ MODULE_SUPPORTED_DEVICE("{{Intel,82801AA-ICH}," "{Intel,82801DB-ICH4}," "{Intel,ICH5}," "{Intel,ICH6}," + "{Intel,ICH7}," "{Intel,6300ESB}," + "{Intel,ESB2}," "{Intel,MX440}," "{SiS,SI7012}," "{NVidia,nForce Audio}," @@ -64,99 +64,38 @@ MODULE_SUPPORTED_DEVICE("{{Intel,82801AA-ICH}," "{AMD,AMD8111}," "{ALI,M5455}}"); -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) -#define SUPPORT_JOYSTICK 1 -#endif -#define SUPPORT_MIDI 1 - -static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ -static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ -static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ -static int ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; -static int ac97_quirk[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = AC97_TUNE_DEFAULT}; -static int buggy_irq[SNDRV_CARDS]; -#ifdef SUPPORT_JOYSTICK -static int joystick[SNDRV_CARDS]; -#endif -#ifdef SUPPORT_MIDI -static int mpu_port[SNDRV_CARDS]; /* disabled */ -#endif -static int boot_devs; +static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ +static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ +static int ac97_clock; +static char *ac97_quirk; +static int buggy_semaphore; +static int buggy_irq = -1; /* auto-check */ +static int xbox; -module_param_array(index, int, boot_devs, 0444); +module_param(index, int, 0444); MODULE_PARM_DESC(index, "Index value for Intel i8x0 soundcard."); -module_param_array(id, charp, boot_devs, 0444); +module_param(id, charp, 0444); MODULE_PARM_DESC(id, "ID string for Intel i8x0 soundcard."); -module_param_array(enable, bool, boot_devs, 0444); -MODULE_PARM_DESC(enable, "Enable Intel i8x0 soundcard."); -module_param_array(ac97_clock, int, boot_devs, 0444); +module_param(ac97_clock, int, 0444); MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (0 = auto-detect)."); -module_param_array(ac97_quirk, int, boot_devs, 0444); +module_param(ac97_quirk, charp, 0444); MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware."); -module_param_array(buggy_irq, bool, boot_devs, 0444); +module_param(buggy_semaphore, bool, 0444); +MODULE_PARM_DESC(buggy_semaphore, "Enable workaround for hardwares with problematic codec semaphores."); +module_param(buggy_irq, bool, 0444); MODULE_PARM_DESC(buggy_irq, "Enable workaround for buggy interrupts on some motherboards."); -#ifdef SUPPORT_JOYSTICK -module_param_array(joystick, bool, boot_devs, 0444); -MODULE_PARM_DESC(joystick, "Enable joystick for Intel i8x0 soundcard."); -#endif -#ifdef SUPPORT_MIDI -module_param_array(mpu_port, int, boot_devs, 0444); -MODULE_PARM_DESC(mpu_port, "MPU401 port # for Intel i8x0 driver."); -#endif +module_param(xbox, bool, 0444); +MODULE_PARM_DESC(xbox, "Set to 1 for Xbox, if you have problems with the AC'97 codec detection."); + +/* just for backward compatibility */ +static int enable; +module_param(enable, bool, 0444); +static int joystick; +module_param(joystick, int, 0444); /* * Direct registers */ - -#ifndef PCI_DEVICE_ID_INTEL_82801 -#define PCI_DEVICE_ID_INTEL_82801 0x2415 -#endif -#ifndef PCI_DEVICE_ID_INTEL_82901 -#define PCI_DEVICE_ID_INTEL_82901 0x2425 -#endif -#ifndef PCI_DEVICE_ID_INTEL_82801BA -#define PCI_DEVICE_ID_INTEL_82801BA 0x2445 -#endif -#ifndef PCI_DEVICE_ID_INTEL_440MX -#define PCI_DEVICE_ID_INTEL_440MX 0x7195 -#endif -#ifndef PCI_DEVICE_ID_INTEL_ICH3 -#define PCI_DEVICE_ID_INTEL_ICH3 0x2485 -#endif -#ifndef PCI_DEVICE_ID_INTEL_ICH4 -#define PCI_DEVICE_ID_INTEL_ICH4 0x24c5 -#endif -#ifndef PCI_DEVICE_ID_INTEL_ICH5 -#define PCI_DEVICE_ID_INTEL_ICH5 0x24d5 -#endif -#ifndef PCI_DEVICE_ID_INTEL_ESB_5 -#define PCI_DEVICE_ID_INTEL_ESB_5 0x25a6 -#endif -#ifndef PCI_DEVICE_ID_INTEL_ICH6_3 -#define PCI_DEVICE_ID_INTEL_ICH6_3 0x266e -#endif -#ifndef PCI_DEVICE_ID_SI_7012 -#define PCI_DEVICE_ID_SI_7012 0x7012 -#endif -#ifndef PCI_DEVICE_ID_NVIDIA_MCP_AUDIO -#define PCI_DEVICE_ID_NVIDIA_MCP_AUDIO 0x01b1 -#endif -#ifndef PCI_DEVICE_ID_NVIDIA_CK804_AUDIO -#define PCI_DEVICE_ID_NVIDIA_CK804_AUDIO 0x0059 -#endif -#ifndef PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO -#define PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO 0x006a -#endif -#ifndef PCI_DEVICE_ID_NVIDIA_CK8_AUDIO -#define PCI_DEVICE_ID_NVIDIA_CK8_AUDIO 0x008a -#endif -#ifndef PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO -#define PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO 0x00da -#endif -#ifndef PCI_DEVICE_ID_NVIDIA_CK8S_AUDIO -#define PCI_DEVICE_ID_NVIDIA_CK8S_AUDIO 0x00ea -#endif - enum { DEVICE_INTEL, DEVICE_INTEL_ICH4, DEVICE_SIS, DEVICE_ALI, DEVICE_NFORCE }; #define ICHREG(x) ICH_REG_##x @@ -239,6 +178,8 @@ DEFINE_REGSET(SP, 0x60); /* SPDIF out */ #define ICH_SAMPLE_CAP 0x00c00000 /* ICH4: sample capability bits (RO) */ #define ICH_SAMPLE_16_20 0x00400000 /* ICH4: 16- and 20-bit samples */ #define ICH_MULTICHAN_CAP 0x00300000 /* ICH4: multi-channel capability bits (RO) */ +#define ICH_SIS_TRI 0x00080000 /* SIS: tertiary resume irq */ +#define ICH_SIS_TCR 0x00040000 /* SIS: tertiary codec ready */ #define ICH_MD3 0x00020000 /* modem power down semaphore */ #define ICH_AD3 0x00010000 /* audio power down semaphore */ #define ICH_RCS 0x00008000 /* read completion status */ @@ -333,7 +274,8 @@ enum { #define ALI_INT_CPRAIS (1<<7) /* command port available */ #define ALI_INT_SPRAIS (1<<5) /* status port available */ #define ALI_INT_GPIO (1<<1) -#define ALI_INT_MASK (ALI_INT_SPDIFOUT|ALI_INT_CODECSPDIFOUT|ALI_INT_MICIN|ALI_INT_PCMOUT|ALI_INT_PCMIN) +#define ALI_INT_MASK (ALI_INT_SPDIFOUT|ALI_INT_CODECSPDIFOUT|\ + ALI_INT_MICIN|ALI_INT_PCMOUT|ALI_INT_PCMIN) #define ICH_ALI_SC_RESET (1<<31) /* master reset */ #define ICH_ALI_SC_AC97_DBL (1<<30) @@ -364,18 +306,40 @@ enum { * */ -enum { ICHD_PCMIN, ICHD_PCMOUT, ICHD_MIC, ICHD_MIC2, ICHD_PCM2IN, ICHD_SPBAR, ICHD_LAST = ICHD_SPBAR }; -enum { NVD_PCMIN, NVD_PCMOUT, NVD_MIC, NVD_SPBAR, NVD_LAST = NVD_SPBAR }; -enum { ALID_PCMIN, ALID_PCMOUT, ALID_MIC, ALID_AC97SPDIFOUT, ALID_SPDIFIN, ALID_SPDIFOUT, ALID_LAST = ALID_SPDIFOUT }; +enum { + ICHD_PCMIN, + ICHD_PCMOUT, + ICHD_MIC, + ICHD_MIC2, + ICHD_PCM2IN, + ICHD_SPBAR, + ICHD_LAST = ICHD_SPBAR +}; +enum { + NVD_PCMIN, + NVD_PCMOUT, + NVD_MIC, + NVD_SPBAR, + NVD_LAST = NVD_SPBAR +}; +enum { + ALID_PCMIN, + ALID_PCMOUT, + ALID_MIC, + ALID_AC97SPDIFOUT, + ALID_SPDIFIN, + ALID_SPDIFOUT, + ALID_LAST = ALID_SPDIFOUT +}; -#define get_ichdev(substream) (ichdev_t *)(substream->runtime->private_data) +#define get_ichdev(substream) (substream->runtime->private_data) -typedef struct { +struct ichdev { unsigned int ichd; /* ich device number */ unsigned long reg_offset; /* offset to bmaddr */ u32 *bdbar; /* CPU address (32bit) */ unsigned int bdbar_addr; /* PCI bus address (32bit) */ - snd_pcm_substream_t *substream; + struct snd_pcm_substream *substream; unsigned int physbuf; /* physical address (32bit) */ unsigned int size; unsigned int fragsize; @@ -395,45 +359,53 @@ typedef struct { unsigned int ali_slot; /* ALI DMA slot */ struct ac97_pcm *pcm; int pcm_open_flag; -} ichdev_t; - -typedef struct _snd_intel8x0 intel8x0_t; + unsigned int page_attr_changed: 1; + unsigned int suspended: 1; +}; -struct _snd_intel8x0 { +struct intel8x0 { unsigned int device_type; int irq; unsigned int mmio; unsigned long addr; - void __iomem * remap_addr; + void __iomem *remap_addr; unsigned int bm_mmio; unsigned long bmaddr; - void __iomem * remap_bmaddr; + void __iomem *remap_bmaddr; struct pci_dev *pci; - snd_card_t *card; + struct snd_card *card; int pcm_devs; - snd_pcm_t *pcm[6]; - ichdev_t ichd[6]; + struct snd_pcm *pcm[6]; + struct ichdev ichd[6]; unsigned multi4: 1, multi6: 1, + dra: 1, smp20bit: 1; unsigned in_ac97_init: 1, in_sdin_init: 1; - unsigned fix_nocache: 1; /* workaround for 440MX */ - unsigned buggy_irq: 1; /* workaround for buggy mobos */ + unsigned in_measurement: 1; /* during ac97 clock measurement */ + unsigned fix_nocache: 1; /* workaround for 440MX */ + unsigned buggy_irq: 1; /* workaround for buggy mobos */ + unsigned xbox: 1; /* workaround for Xbox AC'97 detection */ + unsigned buggy_semaphore: 1; /* workaround for buggy codec semaphore */ - ac97_bus_t *ac97_bus; - ac97_t *ac97[3]; - unsigned int ac97_sdin[3]; + int spdif_idx; /* SPDIF BAR index; *_SPBAR or -1 if use PCMOUT */ + unsigned int sdm_saved; /* SDM reg value */ - snd_rawmidi_t *rmidi; + struct snd_ac97_bus *ac97_bus; + struct snd_ac97 *ac97[3]; + unsigned int ac97_sdin[3]; + unsigned int max_codecs, ncodecs; + unsigned int *codec_bit; + unsigned int codec_isr_bits; + unsigned int codec_ready_bits; spinlock_t reg_lock; - spinlock_t ac97_lock; u32 bdbars_count; struct snd_dma_buffer bdbars; @@ -450,6 +422,8 @@ static struct pci_device_id snd_intel8x0_ids[] = { { 0x8086, 0x24d5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ICH5 */ { 0x8086, 0x25a6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ESB */ { 0x8086, 0x266e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ICH6 */ + { 0x8086, 0x27de, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ICH7 */ + { 0x8086, 0x2698, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ESB2 */ { 0x8086, 0x7195, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 440MX */ { 0x1039, 0x7012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_SIS }, /* SI7012 */ { 0x10de, 0x01b1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* NFORCE */ @@ -459,6 +433,7 @@ static struct pci_device_id snd_intel8x0_ids[] = { { 0x10de, 0x008a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* CK8 */ { 0x10de, 0x00da, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* NFORCE3 */ { 0x10de, 0x00ea, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* CK8S */ + { 0x10de, 0x026b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* MCP51 */ { 0x1022, 0x746d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* AMD8111 */ { 0x1022, 0x7445, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* AMD768 */ { 0x10b9, 0x5455, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALI }, /* Ali5455 */ @@ -471,7 +446,7 @@ MODULE_DEVICE_TABLE(pci, snd_intel8x0_ids); * Lowlevel I/O - busmaster */ -static u8 igetbyte(intel8x0_t *chip, u32 offset) +static u8 igetbyte(struct intel8x0 *chip, u32 offset) { if (chip->bm_mmio) return readb(chip->remap_bmaddr + offset); @@ -479,7 +454,7 @@ static u8 igetbyte(intel8x0_t *chip, u32 offset) return inb(chip->bmaddr + offset); } -static u16 igetword(intel8x0_t *chip, u32 offset) +static u16 igetword(struct intel8x0 *chip, u32 offset) { if (chip->bm_mmio) return readw(chip->remap_bmaddr + offset); @@ -487,7 +462,7 @@ static u16 igetword(intel8x0_t *chip, u32 offset) return inw(chip->bmaddr + offset); } -static u32 igetdword(intel8x0_t *chip, u32 offset) +static u32 igetdword(struct intel8x0 *chip, u32 offset) { if (chip->bm_mmio) return readl(chip->remap_bmaddr + offset); @@ -495,7 +470,7 @@ static u32 igetdword(intel8x0_t *chip, u32 offset) return inl(chip->bmaddr + offset); } -static void iputbyte(intel8x0_t *chip, u32 offset, u8 val) +static void iputbyte(struct intel8x0 *chip, u32 offset, u8 val) { if (chip->bm_mmio) writeb(val, chip->remap_bmaddr + offset); @@ -503,7 +478,7 @@ static void iputbyte(intel8x0_t *chip, u32 offset, u8 val) outb(val, chip->bmaddr + offset); } -static void iputword(intel8x0_t *chip, u32 offset, u16 val) +static void iputword(struct intel8x0 *chip, u32 offset, u16 val) { if (chip->bm_mmio) writew(val, chip->remap_bmaddr + offset); @@ -511,7 +486,7 @@ static void iputword(intel8x0_t *chip, u32 offset, u16 val) outw(val, chip->bmaddr + offset); } -static void iputdword(intel8x0_t *chip, u32 offset, u32 val) +static void iputdword(struct intel8x0 *chip, u32 offset, u32 val) { if (chip->bm_mmio) writel(val, chip->remap_bmaddr + offset); @@ -523,7 +498,7 @@ static void iputdword(intel8x0_t *chip, u32 offset, u32 val) * Lowlevel I/O - AC'97 registers */ -static u16 iagetword(intel8x0_t *chip, u32 offset) +static u16 iagetword(struct intel8x0 *chip, u32 offset) { if (chip->mmio) return readw(chip->remap_addr + offset); @@ -531,7 +506,7 @@ static u16 iagetword(intel8x0_t *chip, u32 offset) return inw(chip->addr + offset); } -static void iaputword(intel8x0_t *chip, u32 offset, u16 val) +static void iaputword(struct intel8x0 *chip, u32 offset, u16 val) { if (chip->mmio) writew(val, chip->remap_addr + offset); @@ -547,19 +522,7 @@ static void iaputword(intel8x0_t *chip, u32 offset, u16 val) * access to AC97 codec via normal i/o (for ICH and SIS7012) */ -/* return the GLOB_STA bit for the corresponding codec */ -static unsigned int get_ich_codec_bit(intel8x0_t *chip, unsigned int codec) -{ - static unsigned int codec_bit[3] = { - ICH_PCR, ICH_SCR, ICH_TCR - }; - snd_assert(codec < 3, return ICH_PCR); - if (chip->device_type == DEVICE_INTEL_ICH4) - codec = chip->ac97_sdin[codec]; - return codec_bit[codec]; -} - -static int snd_intel8x0_codec_semaphore(intel8x0_t *chip, unsigned int codec) +static int snd_intel8x0_codec_semaphore(struct intel8x0 *chip, unsigned int codec) { int time; @@ -568,15 +531,18 @@ static int snd_intel8x0_codec_semaphore(intel8x0_t *chip, unsigned int codec) if (chip->in_sdin_init) { /* we don't know the ready bit assignment at the moment */ /* so we check any */ - codec = ICH_PCR | ICH_SCR | ICH_TCR; + codec = chip->codec_isr_bits; } else { - codec = get_ich_codec_bit(chip, codec); + codec = chip->codec_bit[chip->ac97_sdin[codec]]; } /* codec ready ? */ if ((igetdword(chip, ICHREG(GLOB_STA)) & codec) == 0) return -EIO; + if (chip->buggy_semaphore) + return 0; /* just ignore ... */ + /* Anyone holding a semaphore for 1 msec should be shot... */ time = 100; do { @@ -588,73 +554,70 @@ static int snd_intel8x0_codec_semaphore(intel8x0_t *chip, unsigned int codec) /* access to some forbidden (non existant) ac97 registers will not * reset the semaphore. So even if you don't get the semaphore, still * continue the access. We don't need the semaphore anyway. */ - snd_printk("codec_semaphore: semaphore is not ready [0x%x][0x%x]\n", + snd_printk(KERN_ERR "codec_semaphore: semaphore is not ready [0x%x][0x%x]\n", igetbyte(chip, ICHREG(ACC_SEMA)), igetdword(chip, ICHREG(GLOB_STA))); iagetword(chip, 0); /* clear semaphore flag */ /* I don't care about the semaphore */ return -EBUSY; } -static void snd_intel8x0_codec_write(ac97_t *ac97, +static void snd_intel8x0_codec_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val) { - intel8x0_t *chip = ac97->private_data; + struct intel8x0 *chip = ac97->private_data; - spin_lock(&chip->ac97_lock); if (snd_intel8x0_codec_semaphore(chip, ac97->num) < 0) { if (! chip->in_ac97_init) - snd_printk("codec_write %d: semaphore is not ready for register 0x%x\n", ac97->num, reg); + snd_printk(KERN_ERR "codec_write %d: semaphore is not ready for register 0x%x\n", ac97->num, reg); } iaputword(chip, reg + ac97->num * 0x80, val); - spin_unlock(&chip->ac97_lock); } -static unsigned short snd_intel8x0_codec_read(ac97_t *ac97, +static unsigned short snd_intel8x0_codec_read(struct snd_ac97 *ac97, unsigned short reg) { - intel8x0_t *chip = ac97->private_data; + struct intel8x0 *chip = ac97->private_data; unsigned short res; unsigned int tmp; - spin_lock(&chip->ac97_lock); if (snd_intel8x0_codec_semaphore(chip, ac97->num) < 0) { if (! chip->in_ac97_init) - snd_printk("codec_read %d: semaphore is not ready for register 0x%x\n", ac97->num, reg); + snd_printk(KERN_ERR "codec_read %d: semaphore is not ready for register 0x%x\n", ac97->num, reg); res = 0xffff; } else { res = iagetword(chip, reg + ac97->num * 0x80); if ((tmp = igetdword(chip, ICHREG(GLOB_STA))) & ICH_RCS) { /* reset RCS and preserve other R/WC bits */ - iputdword(chip, ICHREG(GLOB_STA), tmp & ~(ICH_SRI|ICH_PRI|ICH_TRI|ICH_GSCI)); + iputdword(chip, ICHREG(GLOB_STA), tmp & + ~(chip->codec_ready_bits | ICH_GSCI)); if (! chip->in_ac97_init) - snd_printk("codec_read %d: read timeout for register 0x%x\n", ac97->num, reg); + snd_printk(KERN_ERR "codec_read %d: read timeout for register 0x%x\n", ac97->num, reg); res = 0xffff; } } - spin_unlock(&chip->ac97_lock); return res; } -static void snd_intel8x0_codec_read_test(intel8x0_t *chip, unsigned int codec) +static void __devinit snd_intel8x0_codec_read_test(struct intel8x0 *chip, + unsigned int codec) { unsigned int tmp; - spin_lock(&chip->ac97_lock); if (snd_intel8x0_codec_semaphore(chip, codec) >= 0) { iagetword(chip, codec * 0x80); if ((tmp = igetdword(chip, ICHREG(GLOB_STA))) & ICH_RCS) { /* reset RCS and preserve other R/WC bits */ - iputdword(chip, ICHREG(GLOB_STA), tmp & ~(ICH_SRI|ICH_PRI|ICH_TRI|ICH_GSCI)); + iputdword(chip, ICHREG(GLOB_STA), tmp & + ~(chip->codec_ready_bits | ICH_GSCI)); } } - spin_unlock(&chip->ac97_lock); } /* * access to AC97 for Ali5455 */ -static int snd_intel8x0_ali_codec_ready(intel8x0_t *chip, int mask) +static int snd_intel8x0_ali_codec_ready(struct intel8x0 *chip, int mask) { int count = 0; for (count = 0; count < 0x7f; count++) { @@ -662,26 +625,28 @@ static int snd_intel8x0_ali_codec_ready(intel8x0_t *chip, int mask) if (val & mask) return 0; } - snd_printd(KERN_WARNING "intel8x0: AC97 codec ready timeout.\n"); + if (! chip->in_ac97_init) + snd_printd(KERN_WARNING "intel8x0: AC97 codec ready timeout.\n"); return -EBUSY; } -static int snd_intel8x0_ali_codec_semaphore(intel8x0_t *chip) +static int snd_intel8x0_ali_codec_semaphore(struct intel8x0 *chip) { int time = 100; + if (chip->buggy_semaphore) + return 0; /* just ignore ... */ while (time-- && (igetdword(chip, ICHREG(ALI_CAS)) & ALI_CAS_SEM_BUSY)) udelay(1); - if (! time) + if (! time && ! chip->in_ac97_init) snd_printk(KERN_WARNING "ali_codec_semaphore timeout\n"); return snd_intel8x0_ali_codec_ready(chip, ALI_CSPSR_CODEC_READY); } -static unsigned short snd_intel8x0_ali_codec_read(ac97_t *ac97, unsigned short reg) +static unsigned short snd_intel8x0_ali_codec_read(struct snd_ac97 *ac97, unsigned short reg) { - intel8x0_t *chip = ac97->private_data; + struct intel8x0 *chip = ac97->private_data; unsigned short data = 0xffff; - spin_lock(&chip->ac97_lock); if (snd_intel8x0_ali_codec_semaphore(chip)) goto __err; reg |= ALI_CPR_ADDR_READ; @@ -692,32 +657,28 @@ static unsigned short snd_intel8x0_ali_codec_read(ac97_t *ac97, unsigned short r goto __err; data = igetword(chip, ICHREG(ALI_SPR)); __err: - spin_unlock(&chip->ac97_lock); return data; } -static void snd_intel8x0_ali_codec_write(ac97_t *ac97, unsigned short reg, unsigned short val) +static void snd_intel8x0_ali_codec_write(struct snd_ac97 *ac97, unsigned short reg, + unsigned short val) { - intel8x0_t *chip = ac97->private_data; + struct intel8x0 *chip = ac97->private_data; - spin_lock(&chip->ac97_lock); - if (snd_intel8x0_ali_codec_semaphore(chip)) { - spin_unlock(&chip->ac97_lock); + if (snd_intel8x0_ali_codec_semaphore(chip)) return; - } iputword(chip, ICHREG(ALI_CPR), val); if (ac97->num) reg |= ALI_CPR_ADDR_SECONDARY; iputword(chip, ICHREG(ALI_CPR_ADDR), reg); snd_intel8x0_ali_codec_ready(chip, ALI_CSPSR_WRITE_OK); - spin_unlock(&chip->ac97_lock); } /* * DMA I/O */ -static void snd_intel8x0_setup_periods(intel8x0_t *chip, ichdev_t *ichdev) +static void snd_intel8x0_setup_periods(struct intel8x0 *chip, struct ichdev *ichdev) { int idx; u32 *bdbar = ichdev->bdbar; @@ -740,10 +701,15 @@ static void snd_intel8x0_setup_periods(intel8x0_t *chip, ichdev_t *ichdev) ichdev->ack_reload = ichdev->ack = 1; ichdev->fragsize1 = ichdev->fragsize; for (idx = 0; idx < (ICH_REG_LVI_MASK + 1) * 2; idx += 2) { - bdbar[idx + 0] = cpu_to_le32(ichdev->physbuf + (((idx >> 1) * ichdev->fragsize) % ichdev->size)); + bdbar[idx + 0] = cpu_to_le32(ichdev->physbuf + + (((idx >> 1) * ichdev->fragsize) % + ichdev->size)); bdbar[idx + 1] = cpu_to_le32(0x80000000 | /* interrupt on completion */ ichdev->fragsize >> ichdev->pos_shift); - // printk("bdbar[%i] = 0x%x [0x%x]\n", idx + 0, bdbar[idx + 0], bdbar[idx + 1]); +#if 0 + printk("bdbar[%i] = 0x%x [0x%x]\n", + idx + 0, bdbar[idx + 0], bdbar[idx + 1]); +#endif } ichdev->frags = ichdev->size / ichdev->fragsize; } @@ -781,7 +747,7 @@ static void fill_nocache(void *buf, int size, int nocache) * Interrupt handler */ -static inline void snd_intel8x0_update(intel8x0_t *chip, ichdev_t *ichdev) +static inline void snd_intel8x0_update(struct intel8x0 *chip, struct ichdev *ichdev) { unsigned long port = ichdev->reg_offset; int status, civ, i, step; @@ -807,7 +773,8 @@ static inline void snd_intel8x0_update(intel8x0_t *chip, ichdev_t *ichdev) } ichdev->position += step * ichdev->fragsize1; - ichdev->position %= ichdev->size; + if (! chip->in_measurement) + ichdev->position %= ichdev->size; ichdev->lvi += step; ichdev->lvi &= ICH_REG_LVI_MASK; iputbyte(chip, port + ICH_REG_OFF_LVI, ichdev->lvi); @@ -815,7 +782,12 @@ static inline void snd_intel8x0_update(intel8x0_t *chip, ichdev_t *ichdev) ichdev->lvi_frag++; ichdev->lvi_frag %= ichdev->frags; ichdev->bdbar[ichdev->lvi * 2] = cpu_to_le32(ichdev->physbuf + ichdev->lvi_frag * ichdev->fragsize1); - // printk("new: bdbar[%i] = 0x%x [0x%x], prefetch = %i, all = 0x%x, 0x%x\n", ichdev->lvi * 2, ichdev->bdbar[ichdev->lvi * 2], ichdev->bdbar[ichdev->lvi * 2 + 1], inb(ICH_REG_OFF_PIV + port), inl(port + 4), inb(port + ICH_REG_OFF_CR)); +#if 0 + printk("new: bdbar[%i] = 0x%x [0x%x], prefetch = %i, all = 0x%x, 0x%x\n", + ichdev->lvi * 2, ichdev->bdbar[ichdev->lvi * 2], + ichdev->bdbar[ichdev->lvi * 2 + 1], inb(ICH_REG_OFF_PIV + port), + inl(port + 4), inb(port + ICH_REG_OFF_CR)); +#endif if (--ichdev->ack == 0) { ichdev->ack = ichdev->ack_reload; ack = 1; @@ -829,10 +801,10 @@ static inline void snd_intel8x0_update(intel8x0_t *chip, ichdev_t *ichdev) status & (ICH_FIFOE | ICH_BCIS | ICH_LVBCI)); } -static irqreturn_t snd_intel8x0_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t snd_intel8x0_interrupt(int irq, void *dev_id) { - intel8x0_t *chip = dev_id; - ichdev_t *ichdev; + struct intel8x0 *chip = dev_id; + struct ichdev *ichdev; unsigned int status; unsigned int i; @@ -866,20 +838,24 @@ static irqreturn_t snd_intel8x0_interrupt(int irq, void *dev_id, struct pt_regs * PCM part */ -static int snd_intel8x0_pcm_trigger(snd_pcm_substream_t *substream, int cmd) +static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { - intel8x0_t *chip = snd_pcm_substream_chip(substream); - ichdev_t *ichdev = get_ichdev(substream); + struct intel8x0 *chip = snd_pcm_substream_chip(substream); + struct ichdev *ichdev = get_ichdev(substream); unsigned char val = 0; unsigned long port = ichdev->reg_offset; switch (cmd) { - case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: + ichdev->suspended = 0; + /* fallthru */ + case SNDRV_PCM_TRIGGER_START: val = ICH_IOCE | ICH_STARTBM; break; - case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: + ichdev->suspended = 1; + /* fallthru */ + case SNDRV_PCM_TRIGGER_STOP: val = 0; break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: @@ -901,19 +877,23 @@ static int snd_intel8x0_pcm_trigger(snd_pcm_substream_t *substream, int cmd) return 0; } -static int snd_intel8x0_ali_trigger(snd_pcm_substream_t *substream, int cmd) +static int snd_intel8x0_ali_trigger(struct snd_pcm_substream *substream, int cmd) { - intel8x0_t *chip = snd_pcm_substream_chip(substream); - ichdev_t *ichdev = get_ichdev(substream); + struct intel8x0 *chip = snd_pcm_substream_chip(substream); + struct ichdev *ichdev = get_ichdev(substream); unsigned long port = ichdev->reg_offset; - static int fiforeg[] = { ICHREG(ALI_FIFOCR1), ICHREG(ALI_FIFOCR2), ICHREG(ALI_FIFOCR3) }; + static int fiforeg[] = { + ICHREG(ALI_FIFOCR1), ICHREG(ALI_FIFOCR2), ICHREG(ALI_FIFOCR3) + }; unsigned int val, fifo; val = igetdword(chip, ICHREG(ALI_DMACR)); switch (cmd) { + case SNDRV_PCM_TRIGGER_RESUME: + ichdev->suspended = 0; + /* fallthru */ case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - case SNDRV_PCM_TRIGGER_RESUME: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { /* clear FIFO for synchronization of channels */ fifo = igetdword(chip, fiforeg[ichdev->ali_slot / 4]); @@ -923,12 +903,16 @@ static int snd_intel8x0_ali_trigger(snd_pcm_substream_t *substream, int cmd) } iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE); val &= ~(1 << (ichdev->ali_slot + 16)); /* clear PAUSE flag */ - iputdword(chip, ICHREG(ALI_DMACR), val | (1 << ichdev->ali_slot)); /* start DMA */ + /* start DMA */ + iputdword(chip, ICHREG(ALI_DMACR), val | (1 << ichdev->ali_slot)); break; + case SNDRV_PCM_TRIGGER_SUSPEND: + ichdev->suspended = 1; + /* fallthru */ case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - case SNDRV_PCM_TRIGGER_SUSPEND: - iputdword(chip, ICHREG(ALI_DMACR), val | (1 << (ichdev->ali_slot + 16))); /* pause */ + /* pause */ + iputdword(chip, ICHREG(ALI_DMACR), val | (1 << (ichdev->ali_slot + 16))); iputbyte(chip, port + ICH_REG_OFF_CR, 0); while (igetbyte(chip, port + ICH_REG_OFF_CR)) ; @@ -937,7 +921,8 @@ static int snd_intel8x0_ali_trigger(snd_pcm_substream_t *substream, int cmd) /* reset whole DMA things */ iputbyte(chip, port + ICH_REG_OFF_CR, ICH_RESETREGS); /* clear interrupts */ - iputbyte(chip, port + ICH_REG_OFF_SR, igetbyte(chip, port + ICH_REG_OFF_SR) | 0x1e); + iputbyte(chip, port + ICH_REG_OFF_SR, + igetbyte(chip, port + ICH_REG_OFF_SR) | 0x1e); iputdword(chip, ICHREG(ALI_INTERRUPTSR), igetdword(chip, ICHREG(ALI_INTERRUPTSR)) & ichdev->int_sta_mask); break; @@ -947,81 +932,93 @@ static int snd_intel8x0_ali_trigger(snd_pcm_substream_t *substream, int cmd) return 0; } -static int snd_intel8x0_hw_params(snd_pcm_substream_t * substream, - snd_pcm_hw_params_t * hw_params) +static int snd_intel8x0_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) { - intel8x0_t *chip = snd_pcm_substream_chip(substream); - ichdev_t *ichdev = get_ichdev(substream); - snd_pcm_runtime_t *runtime = substream->runtime; - size_t size = params_buffer_bytes(hw_params); + struct intel8x0 *chip = snd_pcm_substream_chip(substream); + struct ichdev *ichdev = get_ichdev(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + int dbl = params_rate(hw_params) > 48000; int err; - if (chip->fix_nocache && runtime->dma_area && runtime->dma_bytes < size) + if (chip->fix_nocache && ichdev->page_attr_changed) { fill_nocache(runtime->dma_area, runtime->dma_bytes, 0); /* clear */ + ichdev->page_attr_changed = 0; + } err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (err < 0) return err; - if (chip->fix_nocache && err > 0) - fill_nocache(runtime->dma_area, runtime->dma_bytes, 1); + if (chip->fix_nocache) { + if (runtime->dma_area && ! ichdev->page_attr_changed) { + fill_nocache(runtime->dma_area, runtime->dma_bytes, 1); + ichdev->page_attr_changed = 1; + } + } if (ichdev->pcm_open_flag) { snd_ac97_pcm_close(ichdev->pcm); ichdev->pcm_open_flag = 0; } err = snd_ac97_pcm_open(ichdev->pcm, params_rate(hw_params), params_channels(hw_params), - ichdev->pcm->r[0].slots); + ichdev->pcm->r[dbl].slots); if (err >= 0) { ichdev->pcm_open_flag = 1; - /* FIXME: hack to enable spdif support */ - if (ichdev->ichd == ICHD_PCMOUT && chip->device_type == DEVICE_SIS) - snd_ac97_set_rate(ichdev->pcm->r[0].codec[0], AC97_SPDIF, params_rate(hw_params)); + /* Force SPDIF setting */ + if (ichdev->ichd == ICHD_PCMOUT && chip->spdif_idx < 0) + snd_ac97_set_rate(ichdev->pcm->r[0].codec[0], AC97_SPDIF, + params_rate(hw_params)); } return err; } -static int snd_intel8x0_hw_free(snd_pcm_substream_t * substream) +static int snd_intel8x0_hw_free(struct snd_pcm_substream *substream) { - intel8x0_t *chip = snd_pcm_substream_chip(substream); - ichdev_t *ichdev = get_ichdev(substream); + struct intel8x0 *chip = snd_pcm_substream_chip(substream); + struct ichdev *ichdev = get_ichdev(substream); if (ichdev->pcm_open_flag) { snd_ac97_pcm_close(ichdev->pcm); ichdev->pcm_open_flag = 0; } - if (chip->fix_nocache && substream->runtime->dma_area) + if (chip->fix_nocache && ichdev->page_attr_changed) { fill_nocache(substream->runtime->dma_area, substream->runtime->dma_bytes, 0); + ichdev->page_attr_changed = 0; + } return snd_pcm_lib_free_pages(substream); } -static void snd_intel8x0_setup_pcm_out(intel8x0_t *chip, - int channels, int sample_bits) +static void snd_intel8x0_setup_pcm_out(struct intel8x0 *chip, + struct snd_pcm_runtime *runtime) { unsigned int cnt; + int dbl = runtime->rate > 48000; + + spin_lock_irq(&chip->reg_lock); switch (chip->device_type) { case DEVICE_ALI: cnt = igetdword(chip, ICHREG(ALI_SCR)); cnt &= ~ICH_ALI_SC_PCM_246_MASK; - if (chip->multi4 && channels == 4) + if (runtime->channels == 4 || dbl) cnt |= ICH_ALI_SC_PCM_4; - else if (chip->multi6 && channels == 6) + else if (runtime->channels == 6) cnt |= ICH_ALI_SC_PCM_6; iputdword(chip, ICHREG(ALI_SCR), cnt); break; case DEVICE_SIS: cnt = igetdword(chip, ICHREG(GLOB_CNT)); cnt &= ~ICH_SIS_PCM_246_MASK; - if (chip->multi4 && channels == 4) + if (runtime->channels == 4 || dbl) cnt |= ICH_SIS_PCM_4; - else if (chip->multi6 && channels == 6) + else if (runtime->channels == 6) cnt |= ICH_SIS_PCM_6; iputdword(chip, ICHREG(GLOB_CNT), cnt); break; default: cnt = igetdword(chip, ICHREG(GLOB_CNT)); cnt &= ~(ICH_PCM_246_MASK | ICH_PCM_20BIT); - if (chip->multi4 && channels == 4) + if (runtime->channels == 4 || dbl) cnt |= ICH_PCM_4; - else if (chip->multi6 && channels == 6) + else if (runtime->channels == 6) cnt |= ICH_PCM_6; if (chip->device_type == DEVICE_NFORCE) { /* reset to 2ch once to keep the 6 channel data in alignment, @@ -1029,45 +1026,44 @@ static void snd_intel8x0_setup_pcm_out(intel8x0_t *chip, */ if (cnt & ICH_PCM_246_MASK) { iputdword(chip, ICHREG(GLOB_CNT), cnt & ~ICH_PCM_246_MASK); + spin_unlock_irq(&chip->reg_lock); msleep(50); /* grrr... */ + spin_lock_irq(&chip->reg_lock); } } else if (chip->device_type == DEVICE_INTEL_ICH4) { - if (sample_bits > 16) + if (runtime->sample_bits > 16) cnt |= ICH_PCM_20BIT; } iputdword(chip, ICHREG(GLOB_CNT), cnt); break; } + spin_unlock_irq(&chip->reg_lock); } -static int snd_intel8x0_pcm_prepare(snd_pcm_substream_t * substream) +static int snd_intel8x0_pcm_prepare(struct snd_pcm_substream *substream) { - intel8x0_t *chip = snd_pcm_substream_chip(substream); - snd_pcm_runtime_t *runtime = substream->runtime; - ichdev_t *ichdev = get_ichdev(substream); + struct intel8x0 *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + struct ichdev *ichdev = get_ichdev(substream); ichdev->physbuf = runtime->dma_addr; ichdev->size = snd_pcm_lib_buffer_bytes(substream); ichdev->fragsize = snd_pcm_lib_period_bytes(substream); - spin_lock_irq(&chip->reg_lock); if (ichdev->ichd == ICHD_PCMOUT) { - snd_intel8x0_setup_pcm_out(chip, runtime->channels, - runtime->sample_bits); - if (chip->device_type == DEVICE_INTEL_ICH4) { + snd_intel8x0_setup_pcm_out(chip, runtime); + if (chip->device_type == DEVICE_INTEL_ICH4) ichdev->pos_shift = (runtime->sample_bits > 16) ? 2 : 1; - } } snd_intel8x0_setup_periods(chip, ichdev); - spin_unlock_irq(&chip->reg_lock); return 0; } -static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(snd_pcm_substream_t * substream) +static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(struct snd_pcm_substream *substream) { - intel8x0_t *chip = snd_pcm_substream_chip(substream); - ichdev_t *ichdev = get_ichdev(substream); + struct intel8x0 *chip = snd_pcm_substream_chip(substream); + struct ichdev *ichdev = get_ichdev(substream); size_t ptr1, ptr; - int civ, timeout = 10; + int civ, timeout = 100; unsigned int position; spin_lock(&chip->reg_lock); @@ -1075,8 +1071,10 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(snd_pcm_substream_t * substrea civ = igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV); ptr1 = igetword(chip, ichdev->reg_offset + ichdev->roff_picb); position = ichdev->position; - if (ptr1 == 0) - udelay(1); + if (ptr1 == 0) { + udelay(10); + continue; + } if (civ == igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV) && ptr1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb)) break; @@ -1090,7 +1088,7 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(snd_pcm_substream_t * substrea return bytes_to_frames(substream->runtime, ptr); } -static snd_pcm_hardware_t snd_intel8x0_stream = +static struct snd_pcm_hardware snd_intel8x0_stream = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | @@ -1115,7 +1113,7 @@ static unsigned int channels4[] = { 2, 4, }; -static snd_pcm_hw_constraint_list_t hw_constraints_channels4 = { +static struct snd_pcm_hw_constraint_list hw_constraints_channels4 = { .count = ARRAY_SIZE(channels4), .list = channels4, .mask = 0, @@ -1125,16 +1123,16 @@ static unsigned int channels6[] = { 2, 4, 6, }; -static snd_pcm_hw_constraint_list_t hw_constraints_channels6 = { +static struct snd_pcm_hw_constraint_list hw_constraints_channels6 = { .count = ARRAY_SIZE(channels6), .list = channels6, .mask = 0, }; -static int snd_intel8x0_pcm_open(snd_pcm_substream_t * substream, ichdev_t *ichdev) +static int snd_intel8x0_pcm_open(struct snd_pcm_substream *substream, struct ichdev *ichdev) { - intel8x0_t *chip = snd_pcm_substream_chip(substream); - snd_pcm_runtime_t *runtime = substream->runtime; + struct intel8x0 *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; int err; ichdev->substream = substream; @@ -1151,10 +1149,10 @@ static int snd_intel8x0_pcm_open(snd_pcm_substream_t * substream, ichdev_t *ichd return 0; } -static int snd_intel8x0_playback_open(snd_pcm_substream_t * substream) +static int snd_intel8x0_playback_open(struct snd_pcm_substream *substream) { - intel8x0_t *chip = snd_pcm_substream_chip(substream); - snd_pcm_runtime_t *runtime = substream->runtime; + struct intel8x0 *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; int err; err = snd_intel8x0_pcm_open(substream, &chip->ichd[ICHD_PCMOUT]); @@ -1163,10 +1161,15 @@ static int snd_intel8x0_playback_open(snd_pcm_substream_t * substream) if (chip->multi6) { runtime->hw.channels_max = 6; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels6); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &hw_constraints_channels6); } else if (chip->multi4) { runtime->hw.channels_max = 4; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels4); + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &hw_constraints_channels4); + } + if (chip->dra) { + snd_ac97_pcm_double_rate_rules(runtime); } if (chip->smp20bit) { runtime->hw.formats |= SNDRV_PCM_FMTBIT_S32_LE; @@ -1175,94 +1178,94 @@ static int snd_intel8x0_playback_open(snd_pcm_substream_t * substream) return 0; } -static int snd_intel8x0_playback_close(snd_pcm_substream_t * substream) +static int snd_intel8x0_playback_close(struct snd_pcm_substream *substream) { - intel8x0_t *chip = snd_pcm_substream_chip(substream); + struct intel8x0 *chip = snd_pcm_substream_chip(substream); chip->ichd[ICHD_PCMOUT].substream = NULL; return 0; } -static int snd_intel8x0_capture_open(snd_pcm_substream_t * substream) +static int snd_intel8x0_capture_open(struct snd_pcm_substream *substream) { - intel8x0_t *chip = snd_pcm_substream_chip(substream); + struct intel8x0 *chip = snd_pcm_substream_chip(substream); return snd_intel8x0_pcm_open(substream, &chip->ichd[ICHD_PCMIN]); } -static int snd_intel8x0_capture_close(snd_pcm_substream_t * substream) +static int snd_intel8x0_capture_close(struct snd_pcm_substream *substream) { - intel8x0_t *chip = snd_pcm_substream_chip(substream); + struct intel8x0 *chip = snd_pcm_substream_chip(substream); chip->ichd[ICHD_PCMIN].substream = NULL; return 0; } -static int snd_intel8x0_mic_open(snd_pcm_substream_t * substream) +static int snd_intel8x0_mic_open(struct snd_pcm_substream *substream) { - intel8x0_t *chip = snd_pcm_substream_chip(substream); + struct intel8x0 *chip = snd_pcm_substream_chip(substream); return snd_intel8x0_pcm_open(substream, &chip->ichd[ICHD_MIC]); } -static int snd_intel8x0_mic_close(snd_pcm_substream_t * substream) +static int snd_intel8x0_mic_close(struct snd_pcm_substream *substream) { - intel8x0_t *chip = snd_pcm_substream_chip(substream); + struct intel8x0 *chip = snd_pcm_substream_chip(substream); chip->ichd[ICHD_MIC].substream = NULL; return 0; } -static int snd_intel8x0_mic2_open(snd_pcm_substream_t * substream) +static int snd_intel8x0_mic2_open(struct snd_pcm_substream *substream) { - intel8x0_t *chip = snd_pcm_substream_chip(substream); + struct intel8x0 *chip = snd_pcm_substream_chip(substream); return snd_intel8x0_pcm_open(substream, &chip->ichd[ICHD_MIC2]); } -static int snd_intel8x0_mic2_close(snd_pcm_substream_t * substream) +static int snd_intel8x0_mic2_close(struct snd_pcm_substream *substream) { - intel8x0_t *chip = snd_pcm_substream_chip(substream); + struct intel8x0 *chip = snd_pcm_substream_chip(substream); chip->ichd[ICHD_MIC2].substream = NULL; return 0; } -static int snd_intel8x0_capture2_open(snd_pcm_substream_t * substream) +static int snd_intel8x0_capture2_open(struct snd_pcm_substream *substream) { - intel8x0_t *chip = snd_pcm_substream_chip(substream); + struct intel8x0 *chip = snd_pcm_substream_chip(substream); return snd_intel8x0_pcm_open(substream, &chip->ichd[ICHD_PCM2IN]); } -static int snd_intel8x0_capture2_close(snd_pcm_substream_t * substream) +static int snd_intel8x0_capture2_close(struct snd_pcm_substream *substream) { - intel8x0_t *chip = snd_pcm_substream_chip(substream); + struct intel8x0 *chip = snd_pcm_substream_chip(substream); chip->ichd[ICHD_PCM2IN].substream = NULL; return 0; } -static int snd_intel8x0_spdif_open(snd_pcm_substream_t * substream) +static int snd_intel8x0_spdif_open(struct snd_pcm_substream *substream) { - intel8x0_t *chip = snd_pcm_substream_chip(substream); + struct intel8x0 *chip = snd_pcm_substream_chip(substream); int idx = chip->device_type == DEVICE_NFORCE ? NVD_SPBAR : ICHD_SPBAR; return snd_intel8x0_pcm_open(substream, &chip->ichd[idx]); } -static int snd_intel8x0_spdif_close(snd_pcm_substream_t * substream) +static int snd_intel8x0_spdif_close(struct snd_pcm_substream *substream) { - intel8x0_t *chip = snd_pcm_substream_chip(substream); + struct intel8x0 *chip = snd_pcm_substream_chip(substream); int idx = chip->device_type == DEVICE_NFORCE ? NVD_SPBAR : ICHD_SPBAR; chip->ichd[idx].substream = NULL; return 0; } -static int snd_intel8x0_ali_ac97spdifout_open(snd_pcm_substream_t * substream) +static int snd_intel8x0_ali_ac97spdifout_open(struct snd_pcm_substream *substream) { - intel8x0_t *chip = snd_pcm_substream_chip(substream); + struct intel8x0 *chip = snd_pcm_substream_chip(substream); unsigned int val; spin_lock_irq(&chip->reg_lock); @@ -1275,9 +1278,9 @@ static int snd_intel8x0_ali_ac97spdifout_open(snd_pcm_substream_t * substream) return snd_intel8x0_pcm_open(substream, &chip->ichd[ALID_AC97SPDIFOUT]); } -static int snd_intel8x0_ali_ac97spdifout_close(snd_pcm_substream_t * substream) +static int snd_intel8x0_ali_ac97spdifout_close(struct snd_pcm_substream *substream) { - intel8x0_t *chip = snd_pcm_substream_chip(substream); + struct intel8x0 *chip = snd_pcm_substream_chip(substream); unsigned int val; chip->ichd[ALID_AC97SPDIFOUT].substream = NULL; @@ -1290,39 +1293,39 @@ static int snd_intel8x0_ali_ac97spdifout_close(snd_pcm_substream_t * substream) return 0; } -static int snd_intel8x0_ali_spdifin_open(snd_pcm_substream_t * substream) +#if 0 // NYI +static int snd_intel8x0_ali_spdifin_open(struct snd_pcm_substream *substream) { - intel8x0_t *chip = snd_pcm_substream_chip(substream); + struct intel8x0 *chip = snd_pcm_substream_chip(substream); return snd_intel8x0_pcm_open(substream, &chip->ichd[ALID_SPDIFIN]); } -static int snd_intel8x0_ali_spdifin_close(snd_pcm_substream_t * substream) +static int snd_intel8x0_ali_spdifin_close(struct snd_pcm_substream *substream) { - intel8x0_t *chip = snd_pcm_substream_chip(substream); + struct intel8x0 *chip = snd_pcm_substream_chip(substream); chip->ichd[ALID_SPDIFIN].substream = NULL; return 0; } -#if 0 // NYI -static int snd_intel8x0_ali_spdifout_open(snd_pcm_substream_t * substream) +static int snd_intel8x0_ali_spdifout_open(struct snd_pcm_substream *substream) { - intel8x0_t *chip = snd_pcm_substream_chip(substream); + struct intel8x0 *chip = snd_pcm_substream_chip(substream); return snd_intel8x0_pcm_open(substream, &chip->ichd[ALID_SPDIFOUT]); } -static int snd_intel8x0_ali_spdifout_close(snd_pcm_substream_t * substream) +static int snd_intel8x0_ali_spdifout_close(struct snd_pcm_substream *substream) { - intel8x0_t *chip = snd_pcm_substream_chip(substream); + struct intel8x0 *chip = snd_pcm_substream_chip(substream); chip->ichd[ALID_SPDIFOUT].substream = NULL; return 0; } #endif -static snd_pcm_ops_t snd_intel8x0_playback_ops = { +static struct snd_pcm_ops snd_intel8x0_playback_ops = { .open = snd_intel8x0_playback_open, .close = snd_intel8x0_playback_close, .ioctl = snd_pcm_lib_ioctl, @@ -1333,7 +1336,7 @@ static snd_pcm_ops_t snd_intel8x0_playback_ops = { .pointer = snd_intel8x0_pcm_pointer, }; -static snd_pcm_ops_t snd_intel8x0_capture_ops = { +static struct snd_pcm_ops snd_intel8x0_capture_ops = { .open = snd_intel8x0_capture_open, .close = snd_intel8x0_capture_close, .ioctl = snd_pcm_lib_ioctl, @@ -1344,7 +1347,7 @@ static snd_pcm_ops_t snd_intel8x0_capture_ops = { .pointer = snd_intel8x0_pcm_pointer, }; -static snd_pcm_ops_t snd_intel8x0_capture_mic_ops = { +static struct snd_pcm_ops snd_intel8x0_capture_mic_ops = { .open = snd_intel8x0_mic_open, .close = snd_intel8x0_mic_close, .ioctl = snd_pcm_lib_ioctl, @@ -1355,7 +1358,7 @@ static snd_pcm_ops_t snd_intel8x0_capture_mic_ops = { .pointer = snd_intel8x0_pcm_pointer, }; -static snd_pcm_ops_t snd_intel8x0_capture_mic2_ops = { +static struct snd_pcm_ops snd_intel8x0_capture_mic2_ops = { .open = snd_intel8x0_mic2_open, .close = snd_intel8x0_mic2_close, .ioctl = snd_pcm_lib_ioctl, @@ -1366,7 +1369,7 @@ static snd_pcm_ops_t snd_intel8x0_capture_mic2_ops = { .pointer = snd_intel8x0_pcm_pointer, }; -static snd_pcm_ops_t snd_intel8x0_capture2_ops = { +static struct snd_pcm_ops snd_intel8x0_capture2_ops = { .open = snd_intel8x0_capture2_open, .close = snd_intel8x0_capture2_close, .ioctl = snd_pcm_lib_ioctl, @@ -1377,7 +1380,7 @@ static snd_pcm_ops_t snd_intel8x0_capture2_ops = { .pointer = snd_intel8x0_pcm_pointer, }; -static snd_pcm_ops_t snd_intel8x0_spdif_ops = { +static struct snd_pcm_ops snd_intel8x0_spdif_ops = { .open = snd_intel8x0_spdif_open, .close = snd_intel8x0_spdif_close, .ioctl = snd_pcm_lib_ioctl, @@ -1388,7 +1391,7 @@ static snd_pcm_ops_t snd_intel8x0_spdif_ops = { .pointer = snd_intel8x0_pcm_pointer, }; -static snd_pcm_ops_t snd_intel8x0_ali_playback_ops = { +static struct snd_pcm_ops snd_intel8x0_ali_playback_ops = { .open = snd_intel8x0_playback_open, .close = snd_intel8x0_playback_close, .ioctl = snd_pcm_lib_ioctl, @@ -1399,7 +1402,7 @@ static snd_pcm_ops_t snd_intel8x0_ali_playback_ops = { .pointer = snd_intel8x0_pcm_pointer, }; -static snd_pcm_ops_t snd_intel8x0_ali_capture_ops = { +static struct snd_pcm_ops snd_intel8x0_ali_capture_ops = { .open = snd_intel8x0_capture_open, .close = snd_intel8x0_capture_close, .ioctl = snd_pcm_lib_ioctl, @@ -1410,7 +1413,7 @@ static snd_pcm_ops_t snd_intel8x0_ali_capture_ops = { .pointer = snd_intel8x0_pcm_pointer, }; -static snd_pcm_ops_t snd_intel8x0_ali_capture_mic_ops = { +static struct snd_pcm_ops snd_intel8x0_ali_capture_mic_ops = { .open = snd_intel8x0_mic_open, .close = snd_intel8x0_mic_close, .ioctl = snd_pcm_lib_ioctl, @@ -1421,7 +1424,7 @@ static snd_pcm_ops_t snd_intel8x0_ali_capture_mic_ops = { .pointer = snd_intel8x0_pcm_pointer, }; -static snd_pcm_ops_t snd_intel8x0_ali_ac97spdifout_ops = { +static struct snd_pcm_ops snd_intel8x0_ali_ac97spdifout_ops = { .open = snd_intel8x0_ali_ac97spdifout_open, .close = snd_intel8x0_ali_ac97spdifout_close, .ioctl = snd_pcm_lib_ioctl, @@ -1432,7 +1435,8 @@ static snd_pcm_ops_t snd_intel8x0_ali_ac97spdifout_ops = { .pointer = snd_intel8x0_pcm_pointer, }; -static snd_pcm_ops_t snd_intel8x0_ali_spdifin_ops = { +#if 0 // NYI +static struct snd_pcm_ops snd_intel8x0_ali_spdifin_ops = { .open = snd_intel8x0_ali_spdifin_open, .close = snd_intel8x0_ali_spdifin_close, .ioctl = snd_pcm_lib_ioctl, @@ -1443,8 +1447,7 @@ static snd_pcm_ops_t snd_intel8x0_ali_spdifin_ops = { .pointer = snd_intel8x0_pcm_pointer, }; -#if 0 // NYI -static snd_pcm_ops_t snd_intel8x0_ali_spdifout_ops = { +static struct snd_pcm_ops snd_intel8x0_ali_spdifout_ops = { .open = snd_intel8x0_ali_spdifout_open, .close = snd_intel8x0_ali_spdifout_close, .ioctl = snd_pcm_lib_ioctl, @@ -1458,16 +1461,17 @@ static snd_pcm_ops_t snd_intel8x0_ali_spdifout_ops = { struct ich_pcm_table { char *suffix; - snd_pcm_ops_t *playback_ops; - snd_pcm_ops_t *capture_ops; + struct snd_pcm_ops *playback_ops; + struct snd_pcm_ops *capture_ops; size_t prealloc_size; size_t prealloc_max_size; int ac97_idx; }; -static int __devinit snd_intel8x0_pcm1(intel8x0_t *chip, int device, struct ich_pcm_table *rec) +static int __devinit snd_intel8x0_pcm1(struct intel8x0 *chip, int device, + struct ich_pcm_table *rec) { - snd_pcm_t *pcm; + struct snd_pcm *pcm; int err; char name[32]; @@ -1494,7 +1498,8 @@ static int __devinit snd_intel8x0_pcm1(intel8x0_t *chip, int device, struct ich_ strcpy(pcm->name, chip->card->shortname); chip->pcm[device] = pcm; - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), rec->prealloc_size, rec->prealloc_max_size); return 0; @@ -1577,7 +1582,7 @@ static struct ich_pcm_table ali_pcms[] __devinitdata = { { .suffix = "IEC958", .playback_ops = &snd_intel8x0_ali_ac97spdifout_ops, - .capture_ops = &snd_intel8x0_ali_spdifin_ops, + /* .capture_ops = &snd_intel8x0_ali_spdifin_ops, */ .prealloc_size = 64 * 1024, .prealloc_max_size = 128 * 1024, .ac97_idx = ALID_AC97SPDIFOUT, @@ -1592,7 +1597,7 @@ static struct ich_pcm_table ali_pcms[] __devinitdata = { #endif }; -static int __devinit snd_intel8x0_pcm(intel8x0_t *chip) +static int __devinit snd_intel8x0_pcm(struct intel8x0 *chip) { int i, tblsize, device, err; struct ich_pcm_table *tbl, *rec; @@ -1639,15 +1644,15 @@ static int __devinit snd_intel8x0_pcm(intel8x0_t *chip) * Mixer part */ -static void snd_intel8x0_mixer_free_ac97_bus(ac97_bus_t *bus) +static void snd_intel8x0_mixer_free_ac97_bus(struct snd_ac97_bus *bus) { - intel8x0_t *chip = bus->private_data; + struct intel8x0 *chip = bus->private_data; chip->ac97_bus = NULL; } -static void snd_intel8x0_mixer_free_ac97(ac97_t *ac97) +static void snd_intel8x0_mixer_free_ac97(struct snd_ac97 *ac97) { - intel8x0_t *chip = ac97->private_data; + struct intel8x0 *chip = ac97->private_data; chip->ac97[ac97->num] = NULL; } @@ -1662,6 +1667,12 @@ static struct ac97_pcm ac97_pcm_defs[] __devinitdata = { (1 << AC97_SLOT_PCM_SLEFT) | (1 << AC97_SLOT_PCM_SRIGHT) | (1 << AC97_SLOT_LFE) + }, + { + .slots = (1 << AC97_SLOT_PCM_LEFT) | + (1 << AC97_SLOT_PCM_RIGHT) | + (1 << AC97_SLOT_PCM_LEFT_0) | + (1 << AC97_SLOT_PCM_RIGHT_0) } } }, @@ -1717,145 +1728,319 @@ static struct ac97_pcm ac97_pcm_defs[] __devinitdata = { static struct ac97_quirk ac97_quirks[] __devinitdata = { { - .vendor = 0x0e11, - .device = 0x00b8, + .subvendor = 0x0e11, + .subdevice = 0x008a, + .name = "Compaq Evo W4000", /* AD1885 */ + .type = AC97_TUNE_HP_ONLY + }, + { + .subvendor = 0x0e11, + .subdevice = 0x00b8, .name = "Compaq Evo D510C", .type = AC97_TUNE_HP_ONLY }, + { + .subvendor = 0x0e11, + .subdevice = 0x0860, + .name = "HP/Compaq nx7010", + .type = AC97_TUNE_MUTE_LED + }, { - .vendor = 0x1014, - .device = 0x1f00, + .subvendor = 0x1014, + .subdevice = 0x1f00, .name = "MS-9128", .type = AC97_TUNE_ALC_JACK }, { - .vendor = 0x1028, - .device = 0x00d8, + .subvendor = 0x1014, + .subdevice = 0x0267, + .name = "IBM NetVista A30p", /* AD1981B */ + .type = AC97_TUNE_HP_ONLY + }, + { + .subvendor = 0x1025, + .subdevice = 0x0083, + .name = "Acer Aspire 3003LCi", + .type = AC97_TUNE_HP_ONLY + }, + { + .subvendor = 0x1028, + .subdevice = 0x00d8, .name = "Dell Precision 530", /* AD1885 */ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x1028, - .device = 0x0126, + .subvendor = 0x1028, + .subdevice = 0x010d, + .name = "Dell", /* which model? AD1885 */ + .type = AC97_TUNE_HP_ONLY + }, + { + .subvendor = 0x1028, + .subdevice = 0x0126, .name = "Dell Optiplex GX260", /* AD1981A */ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x1028, - .device = 0x012d, + .subvendor = 0x1028, + .subdevice = 0x012c, + .name = "Dell Precision 650", /* AD1981A */ + .type = AC97_TUNE_HP_ONLY + }, + { + .subvendor = 0x1028, + .subdevice = 0x012d, .name = "Dell Precision 450", /* AD1981B*/ .type = AC97_TUNE_HP_ONLY }, + { + .subvendor = 0x1028, + .subdevice = 0x0147, + .name = "Dell", /* which model? AD1981B*/ + .type = AC97_TUNE_HP_ONLY + }, + { + .subvendor = 0x1028, + .subdevice = 0x0151, + .name = "Dell Optiplex GX270", /* AD1981B */ + .type = AC97_TUNE_HP_ONLY + }, + { + .subvendor = 0x1028, + .subdevice = 0x014e, + .name = "Dell D800", /* STAC9750/51 */ + .type = AC97_TUNE_HP_ONLY + }, + { + .subvendor = 0x1028, + .subdevice = 0x0163, + .name = "Dell Unknown", /* STAC9750/51 */ + .type = AC97_TUNE_HP_ONLY + }, + { + .subvendor = 0x1028, + .subdevice = 0x0191, + .name = "Dell Inspiron 8600", + .type = AC97_TUNE_HP_ONLY + }, + { + .subvendor = 0x103c, + .subdevice = 0x006d, + .name = "HP zv5000", + .type = AC97_TUNE_MUTE_LED /*AD1981B*/ + }, { /* FIXME: which codec? */ - .vendor = 0x103c, - .device = 0x00c3, - .name = "Hewlett-Packard onboard", + .subvendor = 0x103c, + .subdevice = 0x00c3, + .name = "HP xw6000", + .type = AC97_TUNE_HP_ONLY + }, + { + .subvendor = 0x103c, + .subdevice = 0x088c, + .name = "HP nc8000", + .type = AC97_TUNE_MUTE_LED + }, + { + .subvendor = 0x103c, + .subdevice = 0x0890, + .name = "HP nc6000", + .type = AC97_TUNE_MUTE_LED + }, + { + .subvendor = 0x103c, + .subdevice = 0x0934, + .name = "HP nx8220", + .type = AC97_TUNE_MUTE_LED + }, + { + .subvendor = 0x103c, + .subdevice = 0x129d, + .name = "HP xw8000", .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x103c, - .device = 0x12f1, + .subvendor = 0x103c, + .subdevice = 0x0938, + .name = "HP nc4200", + .type = AC97_TUNE_HP_MUTE_LED + }, + { + .subvendor = 0x103c, + .subdevice = 0x099c, + .name = "HP nx6110/nc6120", + .type = AC97_TUNE_HP_MUTE_LED + }, + { + .subvendor = 0x103c, + .subdevice = 0x0944, + .name = "HP nc6220", + .type = AC97_TUNE_HP_MUTE_LED + }, + { + .subvendor = 0x103c, + .subdevice = 0x0934, + .name = "HP nc8220", + .type = AC97_TUNE_HP_MUTE_LED + }, + { + .subvendor = 0x103c, + .subdevice = 0x12f1, .name = "HP xw8200", /* AD1981B*/ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x103c, - .device = 0x3008, + .subvendor = 0x103c, + .subdevice = 0x12f2, + .name = "HP xw6200", + .type = AC97_TUNE_HP_ONLY + }, + { + .subvendor = 0x103c, + .subdevice = 0x3008, .name = "HP xw4200", /* AD1981B*/ .type = AC97_TUNE_HP_ONLY }, + { + .subvendor = 0x104d, + .subdevice = 0x8197, + .name = "Sony S1XP", + .type = AC97_TUNE_INV_EAPD + }, { - .vendor = 0x1043, - .device = 0x80f3, + .subvendor = 0x1043, + .subdevice = 0x80f3, .name = "ASUS ICH5/AD1985", .type = AC97_TUNE_AD_SHARING }, { - .vendor = 0x10f1, - .device = 0x2665, + .subvendor = 0x10cf, + .subdevice = 0x11c3, + .name = "Fujitsu-Siemens E4010", + .type = AC97_TUNE_HP_ONLY + }, + { + .subvendor = 0x10cf, + .subdevice = 0x1225, + .name = "Fujitsu-Siemens T3010", + .type = AC97_TUNE_HP_ONLY + }, + { + .subvendor = 0x10cf, + .subdevice = 0x1253, + .name = "Fujitsu S6210", /* STAC9750/51 */ + .type = AC97_TUNE_HP_ONLY + }, + { + .subvendor = 0x10cf, + .subdevice = 0x12ec, + .name = "Fujitsu-Siemens 4010", + .type = AC97_TUNE_HP_ONLY + }, + { + .subvendor = 0x10cf, + .subdevice = 0x12f2, + .name = "Fujitsu-Siemens Celsius H320", + .type = AC97_TUNE_SWAP_HP + }, + { + .subvendor = 0x10f1, + .subdevice = 0x2665, .name = "Fujitsu-Siemens Celsius", /* AD1981? */ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x10f1, - .device = 0x2885, + .subvendor = 0x10f1, + .subdevice = 0x2885, .name = "AMD64 Mobo", /* ALC650 */ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x110a, - .device = 0x0056, + .subvendor = 0x10f1, + .subdevice = 0x2895, + .name = "Tyan Thunder K8WE", + .type = AC97_TUNE_HP_ONLY + }, + { + .subvendor = 0x10f7, + .subdevice = 0x834c, + .name = "Panasonic CF-R4", + .type = AC97_TUNE_HP_ONLY, + }, + { + .subvendor = 0x110a, + .subdevice = 0x0056, .name = "Fujitsu-Siemens Scenic", /* AD1981? */ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x11d4, - .device = 0x5375, + .subvendor = 0x11d4, + .subdevice = 0x5375, .name = "ADI AD1985 (discrete)", .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x1462, - .device = 0x5470, + .subvendor = 0x1462, + .subdevice = 0x5470, .name = "MSI P4 ATX 645 Ultra", .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x1734, - .device = 0x0088, + .subvendor = 0x1734, + .subdevice = 0x0088, .name = "Fujitsu-Siemens D1522", /* AD1981 */ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x8086, - .device = 0x2000, + .subvendor = 0x8086, + .subdevice = 0x2000, .mask = 0xfff0, .name = "Intel ICH5/AD1985", .type = AC97_TUNE_AD_SHARING }, { - .vendor = 0x8086, - .device = 0x4000, + .subvendor = 0x8086, + .subdevice = 0x4000, .mask = 0xfff0, .name = "Intel ICH5/AD1985", .type = AC97_TUNE_AD_SHARING }, { - .vendor = 0x8086, - .device = 0x4856, + .subvendor = 0x8086, + .subdevice = 0x4856, .name = "Intel D845WN (82801BA)", .type = AC97_TUNE_SWAP_HP }, { - .vendor = 0x8086, - .device = 0x4d44, + .subvendor = 0x8086, + .subdevice = 0x4d44, .name = "Intel D850EMV2", /* AD1885 */ .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x8086, - .device = 0x4d56, + .subvendor = 0x8086, + .subdevice = 0x4d56, .name = "Intel ICH/AD1885", .type = AC97_TUNE_HP_ONLY }, { - .vendor = 0x8086, - .device = 0x6000, + .subvendor = 0x8086, + .subdevice = 0x6000, .mask = 0xfff0, .name = "Intel ICH5/AD1985", .type = AC97_TUNE_AD_SHARING }, { - .vendor = 0x8086, - .device = 0xe000, + .subvendor = 0x8086, + .subdevice = 0xe000, .mask = 0xfff0, .name = "Intel ICH5/AD1985", .type = AC97_TUNE_AD_SHARING }, #if 0 /* FIXME: this seems wrong on most boards */ { - .vendor = 0x8086, - .device = 0xa000, + .subvendor = 0x8086, + .subdevice = 0xa000, .mask = 0xfff0, .name = "Intel ICH5/AD1985", .type = AC97_TUNE_HP_ONLY @@ -1864,34 +2049,34 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { { } /* terminator */ }; -static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock, int ac97_quirk) +static int __devinit snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock, + const char *quirk_override) { - ac97_bus_t *pbus; - ac97_template_t ac97; + struct snd_ac97_bus *pbus; + struct snd_ac97_template ac97; int err; unsigned int i, codecs; unsigned int glob_sta = 0; - int spdif_idx = -1; /* disabled */ - ac97_bus_ops_t *ops; - static ac97_bus_ops_t standard_bus_ops = { + struct snd_ac97_bus_ops *ops; + static struct snd_ac97_bus_ops standard_bus_ops = { .write = snd_intel8x0_codec_write, .read = snd_intel8x0_codec_read, }; - static ac97_bus_ops_t ali_bus_ops = { + static struct snd_ac97_bus_ops ali_bus_ops = { .write = snd_intel8x0_ali_codec_write, .read = snd_intel8x0_ali_codec_read, }; + chip->spdif_idx = -1; /* use PCMOUT (or disabled) */ switch (chip->device_type) { case DEVICE_NFORCE: - spdif_idx = NVD_SPBAR; + chip->spdif_idx = NVD_SPBAR; break; case DEVICE_ALI: - spdif_idx = ALID_AC97SPDIFOUT; + chip->spdif_idx = ALID_AC97SPDIFOUT; break; - default: - if (chip->device_type == DEVICE_INTEL_ICH4) - spdif_idx = ICHD_SPBAR; + case DEVICE_INTEL_ICH4: + chip->spdif_idx = ICHD_SPBAR; break; }; @@ -1901,26 +2086,29 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock, int ac ac97.private_data = chip; ac97.private_free = snd_intel8x0_mixer_free_ac97; ac97.scaps = AC97_SCAP_SKIP_MODEM; + if (chip->xbox) + ac97.scaps |= AC97_SCAP_DETECT_BY_VENDOR; if (chip->device_type != DEVICE_ALI) { glob_sta = igetdword(chip, ICHREG(GLOB_STA)); ops = &standard_bus_ops; - if (chip->device_type == DEVICE_INTEL_ICH4) { - codecs = 0; - if (glob_sta & ICH_PCR) - codecs++; - if (glob_sta & ICH_SCR) - codecs++; - if (glob_sta & ICH_TCR) - codecs++; - chip->in_sdin_init = 1; - for (i = 0; i < codecs; i++) { - snd_intel8x0_codec_read_test(chip, i); - chip->ac97_sdin[i] = igetbyte(chip, ICHREG(SDM)) & ICH_LDI_MASK; - } - chip->in_sdin_init = 0; - } else { - codecs = glob_sta & ICH_SCR ? 2 : 1; + chip->in_sdin_init = 1; + codecs = 0; + for (i = 0; i < chip->max_codecs; i++) { + if (! (glob_sta & chip->codec_bit[i])) + continue; + if (chip->device_type == DEVICE_INTEL_ICH4) { + snd_intel8x0_codec_read_test(chip, codecs); + chip->ac97_sdin[codecs] = + igetbyte(chip, ICHREG(SDM)) & ICH_LDI_MASK; + snd_assert(chip->ac97_sdin[codecs] < 3, + chip->ac97_sdin[codecs] = 0); + } else + chip->ac97_sdin[codecs] = i; + codecs++; } + chip->in_sdin_init = 0; + if (! codecs) + codecs = 1; } else { ops = &ali_bus_ops; codecs = 1; @@ -1938,13 +2126,15 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock, int ac if ((err = snd_ac97_bus(chip->card, 0, ops, chip, &pbus)) < 0) goto __err; pbus->private_free = snd_intel8x0_mixer_free_ac97_bus; - pbus->shared_type = AC97_SHARED_TYPE_ICH; /* shared with modem driver */ if (ac97_clock >= 8000 && ac97_clock <= 48000) pbus->clock = ac97_clock; /* FIXME: my test board doesn't work well with VRA... */ if (chip->device_type == DEVICE_ALI) pbus->no_vra = 1; + else + pbus->dra = 1; chip->ac97_bus = pbus; + chip->ncodecs = codecs; ac97.pci = chip->pci; for (i = 0; i < codecs; i++) { @@ -1958,7 +2148,7 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock, int ac } } /* tune up the primary codec */ - snd_ac97_tune_hardware(chip->ac97[0], ac97_quirks, ac97_quirk); + snd_ac97_tune_hardware(chip->ac97[0], ac97_quirks, quirk_override); /* enable separate SDINs for ICH4 */ if (chip->device_type == DEVICE_INTEL_ICH4) pbus->isdin = 1; @@ -1966,7 +2156,7 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock, int ac i = ARRAY_SIZE(ac97_pcm_defs); if (chip->device_type != DEVICE_INTEL_ICH4) i -= 2; /* do not allocate PCM2IN and MIC2 */ - if (spdif_idx < 0) + if (chip->spdif_idx < 0) i--; /* do not allocate S/PDIF */ err = snd_ac97_pcm_assign(pbus, i, ac97_pcm_defs); if (err < 0) @@ -1974,8 +2164,8 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock, int ac chip->ichd[ICHD_PCMOUT].pcm = &pbus->pcms[0]; chip->ichd[ICHD_PCMIN].pcm = &pbus->pcms[1]; chip->ichd[ICHD_MIC].pcm = &pbus->pcms[2]; - if (spdif_idx >= 0) - chip->ichd[spdif_idx].pcm = &pbus->pcms[3]; + if (chip->spdif_idx >= 0) + chip->ichd[chip->spdif_idx].pcm = &pbus->pcms[3]; if (chip->device_type == DEVICE_INTEL_ICH4) { chip->ichd[ICHD_PCM2IN].pcm = &pbus->pcms[4]; chip->ichd[ICHD_MIC2].pcm = &pbus->pcms[5]; @@ -2004,13 +2194,24 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock, int ac if (pbus->pcms[0].r[0].slots & (1 << AC97_SLOT_LFE)) chip->multi6 = 1; } + if (pbus->pcms[0].r[1].rslots[0]) { + chip->dra = 1; + } if (chip->device_type == DEVICE_INTEL_ICH4) { if ((igetdword(chip, ICHREG(GLOB_STA)) & ICH_SAMPLE_CAP) == ICH_SAMPLE_16_20) chip->smp20bit = 1; } if (chip->device_type == DEVICE_NFORCE) { /* 48kHz only */ - chip->ichd[spdif_idx].pcm->rates = SNDRV_PCM_RATE_48000; + chip->ichd[chip->spdif_idx].pcm->rates = SNDRV_PCM_RATE_48000; + } + if (chip->device_type == DEVICE_INTEL_ICH4) { + /* use slot 10/11 for SPDIF */ + u32 val; + val = igetdword(chip, ICHREG(GLOB_CNT)) & ~ICH_PCM_SPDIF_MASK; + val |= ICH_PCM_SPDIF_1011; + iputdword(chip, ICHREG(GLOB_CNT), val); + snd_ac97_update_bits(chip->ac97[0], AC97_EXTENDED_STATUS, 0x03 << 4, 0x03 << 4); } chip->in_ac97_init = 0; return 0; @@ -2018,7 +2219,8 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock, int ac __err: /* clear the cold-reset bit for the next chance */ if (chip->device_type != DEVICE_ALI) - iputdword(chip, ICHREG(GLOB_CNT), igetdword(chip, ICHREG(GLOB_CNT)) & ~ICH_AC97COLD); + iputdword(chip, ICHREG(GLOB_CNT), + igetdword(chip, ICHREG(GLOB_CNT)) & ~ICH_AC97COLD); return err; } @@ -2027,24 +2229,19 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock, int ac * */ -static void do_ali_reset(intel8x0_t *chip) +static void do_ali_reset(struct intel8x0 *chip) { iputdword(chip, ICHREG(ALI_SCR), ICH_ALI_SC_RESET); iputdword(chip, ICHREG(ALI_FIFOCR1), 0x83838383); iputdword(chip, ICHREG(ALI_FIFOCR2), 0x83838383); iputdword(chip, ICHREG(ALI_FIFOCR3), 0x83838383); iputdword(chip, ICHREG(ALI_INTERFACECR), - ICH_ALI_IF_MC|ICH_ALI_IF_PI|ICH_ALI_IF_PO); + ICH_ALI_IF_PI|ICH_ALI_IF_PO); iputdword(chip, ICHREG(ALI_INTERRUPTCR), 0x00000000); iputdword(chip, ICHREG(ALI_INTERRUPTSR), 0x00000000); } -#define do_delay(chip) do {\ - set_current_state(TASK_UNINTERRUPTIBLE);\ - schedule_timeout(1);\ -} while (0) - -static int snd_intel8x0_ich_chip_init(intel8x0_t *chip, int probing) +static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing) { unsigned long end_time; unsigned int cnt, status, nstatus; @@ -2060,6 +2257,16 @@ static int snd_intel8x0_ich_chip_init(intel8x0_t *chip, int probing) /* ACLink on, 2 channels */ cnt = igetdword(chip, ICHREG(GLOB_CNT)); cnt &= ~(ICH_ACLINK | ICH_PCM_246_MASK); +#ifdef CONFIG_SND_AC97_POWER_SAVE + /* do cold reset - the full ac97 powerdown may leave the controller + * in a warm state but actually it cannot communicate with the codec. + */ + iputdword(chip, ICHREG(GLOB_CNT), cnt & ~ICH_AC97COLD); + cnt = igetdword(chip, ICHREG(GLOB_CNT)); + udelay(10); + iputdword(chip, ICHREG(GLOB_CNT), cnt | ICH_AC97COLD); + msleep(1); +#else /* finish cold or do warm reset */ cnt |= (cnt & ICH_AC97COLD) == 0 ? ICH_AC97COLD : ICH_AC97WARM; iputdword(chip, ICHREG(GLOB_CNT), cnt); @@ -2067,12 +2274,14 @@ static int snd_intel8x0_ich_chip_init(intel8x0_t *chip, int probing) do { if ((igetdword(chip, ICHREG(GLOB_CNT)) & ICH_AC97WARM) == 0) goto __ok; - do_delay(chip); + schedule_timeout_uninterruptible(1); } while (time_after_eq(end_time, jiffies)); - snd_printk("AC'97 warm reset still in progress? [0x%x]\n", igetdword(chip, ICHREG(GLOB_CNT))); + snd_printk(KERN_ERR "AC'97 warm reset still in progress? [0x%x]\n", + igetdword(chip, ICHREG(GLOB_CNT))); return -EIO; __ok: +#endif if (probing) { /* wait for any codec ready status. * Once it becomes ready it should remain ready @@ -2080,45 +2289,43 @@ static int snd_intel8x0_ich_chip_init(intel8x0_t *chip, int probing) */ end_time = jiffies + HZ; do { - status = igetdword(chip, ICHREG(GLOB_STA)) & (ICH_PCR | ICH_SCR | ICH_TCR); + status = igetdword(chip, ICHREG(GLOB_STA)) & + chip->codec_isr_bits; if (status) break; - do_delay(chip); + schedule_timeout_uninterruptible(1); } while (time_after_eq(end_time, jiffies)); if (! status) { /* no codec is found */ - snd_printk(KERN_ERR "codec_ready: codec is not ready [0x%x]\n", igetdword(chip, ICHREG(GLOB_STA))); + snd_printk(KERN_ERR "codec_ready: codec is not ready [0x%x]\n", + igetdword(chip, ICHREG(GLOB_STA))); return -EIO; } - if (chip->device_type == DEVICE_INTEL_ICH4) - /* ICH4 can have three codecs */ - nstatus = ICH_PCR | ICH_SCR | ICH_TCR; - else - /* others up to two codecs */ - nstatus = ICH_PCR | ICH_SCR; - /* wait for other codecs ready status. */ end_time = jiffies + HZ / 4; - while (status != nstatus && time_after_eq(end_time, jiffies)) { - do_delay(chip); - status |= igetdword(chip, ICHREG(GLOB_STA)) & nstatus; + while (status != chip->codec_isr_bits && + time_after_eq(end_time, jiffies)) { + schedule_timeout_uninterruptible(1); + status |= igetdword(chip, ICHREG(GLOB_STA)) & + chip->codec_isr_bits; } } else { /* resume phase */ int i; status = 0; - for (i = 0; i < 3; i++) + for (i = 0; i < chip->ncodecs; i++) if (chip->ac97[i]) - status |= get_ich_codec_bit(chip, i); + status |= chip->codec_bit[chip->ac97_sdin[i]]; /* wait until all the probed codecs are ready */ end_time = jiffies + HZ; do { - nstatus = igetdword(chip, ICHREG(GLOB_STA)) & (ICH_PCR | ICH_SCR | ICH_TCR); + nstatus = igetdword(chip, ICHREG(GLOB_STA)) & + chip->codec_isr_bits; if (status == nstatus) break; - do_delay(chip); + schedule_timeout_uninterruptible(1); } while (time_after_eq(end_time, jiffies)); } @@ -2136,7 +2343,7 @@ static int snd_intel8x0_ich_chip_init(intel8x0_t *chip, int probing) return 0; } -static int snd_intel8x0_ali_chip_init(intel8x0_t *chip, int probing) +static int snd_intel8x0_ali_chip_init(struct intel8x0 *chip, int probing) { u32 reg; int i = 0; @@ -2152,7 +2359,7 @@ static int snd_intel8x0_ali_chip_init(intel8x0_t *chip, int probing) for (i = 0; i < HZ / 2; i++) { if (! (igetdword(chip, ICHREG(ALI_INTERRUPTSR)) & ALI_INT_GPIO)) goto __ok; - do_delay(chip); + schedule_timeout_uninterruptible(1); } snd_printk(KERN_ERR "AC'97 reset failed.\n"); if (probing) @@ -2164,16 +2371,16 @@ static int snd_intel8x0_ali_chip_init(intel8x0_t *chip, int probing) if (reg & 0x80) /* primary codec */ break; iputdword(chip, ICHREG(ALI_RTSR), reg | 0x80); - do_delay(chip); + schedule_timeout_uninterruptible(1); } do_ali_reset(chip); return 0; } -static int snd_intel8x0_chip_init(intel8x0_t *chip, int probing) +static int snd_intel8x0_chip_init(struct intel8x0 *chip, int probing) { - unsigned int i; + unsigned int i, timeout; int err; if (chip->device_type != DEVICE_ALI) { @@ -2191,13 +2398,23 @@ static int snd_intel8x0_chip_init(intel8x0_t *chip, int probing) /* reset channels */ for (i = 0; i < chip->bdbars_count; i++) iputbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset, ICH_RESETREGS); + for (i = 0; i < chip->bdbars_count; i++) { + timeout = 100000; + while (--timeout != 0) { + if ((igetbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset) & ICH_RESETREGS) == 0) + break; + } + if (timeout == 0) + printk(KERN_ERR "intel8x0: reset of registers failed?\n"); + } /* initialize Buffer Descriptor Lists */ for (i = 0; i < chip->bdbars_count; i++) - iputdword(chip, ICH_REG_OFF_BDBAR + chip->ichd[i].reg_offset, chip->ichd[i].bdbar_addr); + iputdword(chip, ICH_REG_OFF_BDBAR + chip->ichd[i].reg_offset, + chip->ichd[i].bdbar_addr); return 0; } -static int snd_intel8x0_free(intel8x0_t *chip) +static int snd_intel8x0_free(struct intel8x0 *chip) { unsigned int i; @@ -2220,7 +2437,7 @@ static int snd_intel8x0_free(intel8x0_t *chip) synchronize_irq(chip->irq); __hw_end: if (chip->irq >= 0) - free_irq(chip->irq, (void *)chip); + free_irq(chip->irq, chip); if (chip->bdbars.area) { if (chip->fix_nocache) fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 0); @@ -2231,6 +2448,7 @@ static int snd_intel8x0_free(intel8x0_t *chip) if (chip->remap_bmaddr) iounmap(chip->remap_bmaddr); pci_release_regions(chip->pci); + pci_disable_device(chip->pci); kfree(chip); return 0; } @@ -2239,49 +2457,114 @@ static int snd_intel8x0_free(intel8x0_t *chip) /* * power management */ -static int intel8x0_suspend(snd_card_t *card, unsigned int state) +static int intel8x0_suspend(struct pci_dev *pci, pm_message_t state) { - intel8x0_t *chip = card->pm_private_data; + struct snd_card *card = pci_get_drvdata(pci); + struct intel8x0 *chip = card->private_data; int i; + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); for (i = 0; i < chip->pcm_devs; i++) snd_pcm_suspend_all(chip->pcm[i]); - for (i = 0; i < 3; i++) - if (chip->ac97[i]) - snd_ac97_suspend(chip->ac97[i]); - snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); + /* clear nocache */ + if (chip->fix_nocache) { + for (i = 0; i < chip->bdbars_count; i++) { + struct ichdev *ichdev = &chip->ichd[i]; + if (ichdev->substream && ichdev->page_attr_changed) { + struct snd_pcm_runtime *runtime = ichdev->substream->runtime; + if (runtime->dma_area) + fill_nocache(runtime->dma_area, runtime->dma_bytes, 0); + } + } + } + for (i = 0; i < chip->ncodecs; i++) + snd_ac97_suspend(chip->ac97[i]); + if (chip->device_type == DEVICE_INTEL_ICH4) + chip->sdm_saved = igetbyte(chip, ICHREG(SDM)); + + if (chip->irq >= 0) { + synchronize_irq(chip->irq); + free_irq(chip->irq, chip); + chip->irq = -1; + } + pci_disable_device(pci); + pci_save_state(pci); + /* The call below may disable built-in speaker on some laptops + * after S2RAM. So, don't touch it. + */ + /* pci_set_power_state(pci, pci_choose_state(pci, state)); */ return 0; } -static int intel8x0_resume(snd_card_t *card, unsigned int state) +static int intel8x0_resume(struct pci_dev *pci) { - intel8x0_t *chip = card->pm_private_data; + struct snd_card *card = pci_get_drvdata(pci); + struct intel8x0 *chip = card->private_data; int i; - pci_enable_device(chip->pci); - pci_set_master(chip->pci); + pci_set_power_state(pci, PCI_D0); + pci_restore_state(pci); + if (pci_enable_device(pci) < 0) { + printk(KERN_ERR "intel8x0: pci_enable_device failed, " + "disabling device\n"); + snd_card_disconnect(card); + return -EIO; + } + pci_set_master(pci); + if (request_irq(pci->irq, snd_intel8x0_interrupt, + IRQF_SHARED, card->shortname, chip)) { + printk(KERN_ERR "intel8x0: unable to grab IRQ %d, " + "disabling device\n", pci->irq); + snd_card_disconnect(card); + return -EIO; + } + chip->irq = pci->irq; + synchronize_irq(chip->irq); snd_intel8x0_chip_init(chip, 0); + /* re-initialize mixer stuff */ + if (chip->device_type == DEVICE_INTEL_ICH4) { + /* enable separate SDINs for ICH4 */ + iputbyte(chip, ICHREG(SDM), chip->sdm_saved); + /* use slot 10/11 for SPDIF */ + iputdword(chip, ICHREG(GLOB_CNT), + (igetdword(chip, ICHREG(GLOB_CNT)) & ~ICH_PCM_SPDIF_MASK) | + ICH_PCM_SPDIF_1011); + } + /* refill nocache */ if (chip->fix_nocache) fill_nocache(chip->bdbars.area, chip->bdbars.bytes, 1); - for (i = 0; i < 3; i++) - if (chip->ac97[i]) - snd_ac97_resume(chip->ac97[i]); + for (i = 0; i < chip->ncodecs; i++) + snd_ac97_resume(chip->ac97[i]); /* refill nocache */ if (chip->fix_nocache) { for (i = 0; i < chip->bdbars_count; i++) { - ichdev_t *ichdev = &chip->ichd[i]; - if (ichdev->substream) { - snd_pcm_runtime_t *runtime = ichdev->substream->runtime; + struct ichdev *ichdev = &chip->ichd[i]; + if (ichdev->substream && ichdev->page_attr_changed) { + struct snd_pcm_runtime *runtime = ichdev->substream->runtime; if (runtime->dma_area) fill_nocache(runtime->dma_area, runtime->dma_bytes, 1); } } } + /* resume status */ + for (i = 0; i < chip->bdbars_count; i++) { + struct ichdev *ichdev = &chip->ichd[i]; + unsigned long port = ichdev->reg_offset; + if (! ichdev->substream || ! ichdev->suspended) + continue; + if (ichdev->ichd == ICHD_PCMOUT) + snd_intel8x0_setup_pcm_out(chip, ichdev->substream->runtime); + iputdword(chip, port + ICH_REG_OFF_BDBAR, ichdev->bdbar_addr); + iputbyte(chip, port + ICH_REG_OFF_LVI, ichdev->lvi); + iputbyte(chip, port + ICH_REG_OFF_CIV, ichdev->civ); + iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI); + } + snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; } @@ -2289,10 +2572,10 @@ static int intel8x0_resume(snd_card_t *card, unsigned int state) #define INTEL8X0_TESTBUF_SIZE 32768 /* enough large for one shot */ -static void __devinit intel8x0_measure_ac97_clock(intel8x0_t *chip) +static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip) { - snd_pcm_substream_t *subs; - ichdev_t *ichdev; + struct snd_pcm_substream *subs; + struct ichdev *ichdev; unsigned long port; unsigned long pos, t; struct timeval start_time, stop_time; @@ -2302,7 +2585,7 @@ static void __devinit intel8x0_measure_ac97_clock(intel8x0_t *chip) subs = chip->pcm[0]->streams[0].substream; if (! subs || subs->dma_buffer.bytes < INTEL8X0_TESTBUF_SIZE) { - snd_printk("no playback buffer allocated - aborting measure ac97 clock\n"); + snd_printk(KERN_WARNING "no playback buffer allocated - aborting measure ac97 clock\n"); return; } ichdev = &chip->ichd[ICHD_PCMOUT]; @@ -2318,6 +2601,7 @@ static void __devinit intel8x0_measure_ac97_clock(intel8x0_t *chip) snd_intel8x0_setup_periods(chip, ichdev); port = ichdev->reg_offset; spin_lock_irq(&chip->reg_lock); + chip->in_measurement = 1; /* trigger */ if (chip->device_type != DEVICE_ALI) iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE | ICH_STARTBM); @@ -2327,22 +2611,17 @@ static void __devinit intel8x0_measure_ac97_clock(intel8x0_t *chip) } do_gettimeofday(&start_time); spin_unlock_irq(&chip->reg_lock); -#if 0 - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 20); -#else - /* FIXME: schedule() can take too long time and overlap the boundary.. */ - mdelay(50); -#endif + msleep(50); spin_lock_irq(&chip->reg_lock); /* check the position */ pos = ichdev->fragsize1; pos -= igetword(chip, ichdev->reg_offset + ichdev->roff_picb) << ichdev->pos_shift; pos += ichdev->position; + chip->in_measurement = 0; do_gettimeofday(&stop_time); /* stop */ if (chip->device_type == DEVICE_ALI) { - iputdword(chip, ICHREG(ALI_DMACR), 1 << (ichdev->ali_slot + 8)); + iputdword(chip, ICHREG(ALI_DMACR), 1 << (ichdev->ali_slot + 16)); iputbyte(chip, port + ICH_REG_OFF_CR, 0); while (igetbyte(chip, port + ICH_REG_OFF_CR)) ; @@ -2371,12 +2650,14 @@ static void __devinit intel8x0_measure_ac97_clock(intel8x0_t *chip) /* not 48000Hz, tuning the clock.. */ chip->ac97_bus->clock = (chip->ac97_bus->clock * 48000) / pos; printk(KERN_INFO "intel8x0: clocking to %d\n", chip->ac97_bus->clock); + snd_ac97_update_power(chip->ac97[0], AC97_PCM_FRONT_DAC_RATE, 0); } -static void snd_intel8x0_proc_read(snd_info_entry_t * entry, - snd_info_buffer_t * buffer) +#ifdef CONFIG_PROC_FS +static void snd_intel8x0_proc_read(struct snd_info_entry * entry, + struct snd_info_buffer *buffer) { - intel8x0_t *chip = entry->private_data; + struct intel8x0 *chip = entry->private_data; unsigned int tmp; snd_iprintf(buffer, "Intel8x0\n\n"); @@ -2387,29 +2668,40 @@ static void snd_intel8x0_proc_read(snd_info_entry_t * entry, snd_iprintf(buffer, "Global status : 0x%08x\n", tmp); if (chip->device_type == DEVICE_INTEL_ICH4) snd_iprintf(buffer, "SDM : 0x%08x\n", igetdword(chip, ICHREG(SDM))); - snd_iprintf(buffer, "AC'97 codecs ready :%s%s%s%s\n", - tmp & ICH_PCR ? " primary" : "", - tmp & ICH_SCR ? " secondary" : "", - tmp & ICH_TCR ? " tertiary" : "", - (tmp & (ICH_PCR | ICH_SCR | ICH_TCR)) == 0 ? " none" : ""); - if (chip->device_type == DEVICE_INTEL_ICH4) + snd_iprintf(buffer, "AC'97 codecs ready :"); + if (tmp & chip->codec_isr_bits) { + int i; + static const char *codecs[3] = { + "primary", "secondary", "tertiary" + }; + for (i = 0; i < chip->max_codecs; i++) + if (tmp & chip->codec_bit[i]) + snd_iprintf(buffer, " %s", codecs[i]); + } else + snd_iprintf(buffer, " none"); + snd_iprintf(buffer, "\n"); + if (chip->device_type == DEVICE_INTEL_ICH4 || + chip->device_type == DEVICE_SIS) snd_iprintf(buffer, "AC'97 codecs SDIN : %i %i %i\n", chip->ac97_sdin[0], chip->ac97_sdin[1], chip->ac97_sdin[2]); } -static void __devinit snd_intel8x0_proc_init(intel8x0_t * chip) +static void __devinit snd_intel8x0_proc_init(struct intel8x0 * chip) { - snd_info_entry_t *entry; + struct snd_info_entry *entry; if (! snd_card_proc_new(chip->card, "intel8x0", &entry)) - snd_info_set_text_ops(entry, chip, 1024, snd_intel8x0_proc_read); + snd_info_set_text_ops(entry, chip, snd_intel8x0_proc_read); } +#else +#define snd_intel8x0_proc_init(x) +#endif -static int snd_intel8x0_dev_free(snd_device_t *device) +static int snd_intel8x0_dev_free(struct snd_device *device) { - intel8x0_t *chip = device->device_data; + struct intel8x0 *chip = device->device_data; return snd_intel8x0_free(chip); } @@ -2418,17 +2710,24 @@ struct ich_reg_info { unsigned int offset; }; -static int __devinit snd_intel8x0_create(snd_card_t * card, +static unsigned int ich_codec_bits[3] = { + ICH_PCR, ICH_SCR, ICH_TCR +}; +static unsigned int sis_codec_bits[3] = { + ICH_PCR, ICH_SCR, ICH_SIS_TCR +}; + +static int __devinit snd_intel8x0_create(struct snd_card *card, struct pci_dev *pci, unsigned long device_type, - intel8x0_t ** r_intel8x0) + struct intel8x0 ** r_intel8x0) { - intel8x0_t *chip; + struct intel8x0 *chip; int err; unsigned int i; unsigned int int_sta_masks; - ichdev_t *ichdev; - static snd_device_ops_t ops = { + struct ichdev *ichdev; + static struct snd_device_ops ops = { .dev_free = snd_intel8x0_dev_free, }; @@ -2468,28 +2767,30 @@ static int __devinit snd_intel8x0_create(snd_card_t * card, if ((err = pci_enable_device(pci)) < 0) return err; - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); - if (chip == NULL) + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (chip == NULL) { + pci_disable_device(pci); return -ENOMEM; + } spin_lock_init(&chip->reg_lock); - spin_lock_init(&chip->ac97_lock); chip->device_type = device_type; chip->card = card; chip->pci = pci; chip->irq = -1; + /* module parameters */ + chip->buggy_irq = buggy_irq; + chip->buggy_semaphore = buggy_semaphore; + if (xbox) + chip->xbox = 1; + if (pci->vendor == PCI_VENDOR_ID_INTEL && pci->device == PCI_DEVICE_ID_INTEL_440MX) chip->fix_nocache = 1; /* enable workaround */ - /* some Nforce[2] and ICH boards have problems with IRQ handling. - * Needs to return IRQ_HANDLED for unknown irqs. - */ - if (device_type == DEVICE_NFORCE) - chip->buggy_irq = 1; - if ((err = pci_request_regions(pci, card->shortname)) < 0) { kfree(chip); + pci_disable_device(pci); return err; } @@ -2502,9 +2803,10 @@ static int __devinit snd_intel8x0_create(snd_card_t * card, if (pci_resource_flags(pci, 2) & IORESOURCE_MEM) { /* ICH4 and Nforce */ chip->mmio = 1; chip->addr = pci_resource_start(pci, 2); - chip->remap_addr = ioremap_nocache(chip->addr, pci_resource_len(pci, 2)); - if (!chip->remap_addr) { - snd_printk("AC'97 space ioremap problem\n"); + chip->remap_addr = ioremap_nocache(chip->addr, + pci_resource_len(pci, 2)); + if (chip->remap_addr == NULL) { + snd_printk(KERN_ERR "AC'97 space ioremap problem\n"); snd_intel8x0_free(chip); return -EIO; } @@ -2514,9 +2816,10 @@ static int __devinit snd_intel8x0_create(snd_card_t * card, if (pci_resource_flags(pci, 3) & IORESOURCE_MEM) { /* ICH4 */ chip->bm_mmio = 1; chip->bmaddr = pci_resource_start(pci, 3); - chip->remap_bmaddr = ioremap_nocache(chip->bmaddr, pci_resource_len(pci, 3)); - if (!chip->remap_bmaddr) { - snd_printk("Controller space ioremap problem\n"); + chip->remap_bmaddr = ioremap_nocache(chip->bmaddr, + pci_resource_len(pci, 3)); + if (chip->remap_bmaddr == NULL) { + snd_printk(KERN_ERR "Controller space ioremap problem\n"); snd_intel8x0_free(chip); return -EIO; } @@ -2525,15 +2828,6 @@ static int __devinit snd_intel8x0_create(snd_card_t * card, } port_inited: - if (request_irq(pci->irq, snd_intel8x0_interrupt, SA_INTERRUPT|SA_SHIRQ, card->shortname, (void *)chip)) { - snd_printk("unable to grab IRQ %d\n", pci->irq); - snd_intel8x0_free(chip); - return -EBUSY; - } - chip->irq = pci->irq; - pci_set_master(pci); - synchronize_irq(chip->irq); - chip->bdbars_count = bdbars[device_type]; /* initialize offsets */ @@ -2584,20 +2878,55 @@ static int __devinit snd_intel8x0_create(snd_card_t * card, int_sta_masks = 0; for (i = 0; i < chip->bdbars_count; i++) { ichdev = &chip->ichd[i]; - ichdev->bdbar = ((u32 *)chip->bdbars.area) + (i * ICH_MAX_FRAGS * 2); - ichdev->bdbar_addr = chip->bdbars.addr + (i * sizeof(u32) * ICH_MAX_FRAGS * 2); + ichdev->bdbar = ((u32 *)chip->bdbars.area) + + (i * ICH_MAX_FRAGS * 2); + ichdev->bdbar_addr = chip->bdbars.addr + + (i * sizeof(u32) * ICH_MAX_FRAGS * 2); int_sta_masks |= ichdev->int_sta_mask; } - chip->int_sta_reg = device_type == DEVICE_ALI ? ICH_REG_ALI_INTERRUPTSR : ICH_REG_GLOB_STA; + chip->int_sta_reg = device_type == DEVICE_ALI ? + ICH_REG_ALI_INTERRUPTSR : ICH_REG_GLOB_STA; chip->int_sta_mask = int_sta_masks; + /* request irq after initializaing int_sta_mask, etc */ + if (request_irq(pci->irq, snd_intel8x0_interrupt, + IRQF_SHARED, card->shortname, chip)) { + snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); + snd_intel8x0_free(chip); + return -EBUSY; + } + chip->irq = pci->irq; + pci_set_master(pci); + synchronize_irq(chip->irq); + + switch(chip->device_type) { + case DEVICE_INTEL_ICH4: + /* ICH4 can have three codecs */ + chip->max_codecs = 3; + chip->codec_bit = ich_codec_bits; + chip->codec_ready_bits = ICH_PRI | ICH_SRI | ICH_TRI; + break; + case DEVICE_SIS: + /* recent SIS7012 can have three codecs */ + chip->max_codecs = 3; + chip->codec_bit = sis_codec_bits; + chip->codec_ready_bits = ICH_PRI | ICH_SRI | ICH_SIS_TRI; + break; + default: + /* others up to two codecs */ + chip->max_codecs = 2; + chip->codec_bit = ich_codec_bits; + chip->codec_ready_bits = ICH_PRI | ICH_SRI; + break; + } + for (i = 0; i < chip->max_codecs; i++) + chip->codec_isr_bits |= chip->codec_bit[i]; + if ((err = snd_intel8x0_chip_init(chip, 1)) < 0) { snd_intel8x0_free(chip); return err; } - snd_card_set_pm_callback(card, intel8x0_suspend, intel8x0_resume, chip); - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_intel8x0_free(chip); return err; @@ -2613,17 +2942,19 @@ static struct shortname_table { unsigned int id; const char *s; } shortnames[] __devinitdata = { - { PCI_DEVICE_ID_INTEL_82801, "Intel 82801AA-ICH" }, - { PCI_DEVICE_ID_INTEL_82901, "Intel 82901AB-ICH0" }, - { PCI_DEVICE_ID_INTEL_82801BA, "Intel 82801BA-ICH2" }, + { PCI_DEVICE_ID_INTEL_82801AA_5, "Intel 82801AA-ICH" }, + { PCI_DEVICE_ID_INTEL_82801AB_5, "Intel 82901AB-ICH0" }, + { PCI_DEVICE_ID_INTEL_82801BA_4, "Intel 82801BA-ICH2" }, { PCI_DEVICE_ID_INTEL_440MX, "Intel 440MX" }, - { PCI_DEVICE_ID_INTEL_ICH3, "Intel 82801CA-ICH3" }, - { PCI_DEVICE_ID_INTEL_ICH4, "Intel 82801DB-ICH4" }, - { PCI_DEVICE_ID_INTEL_ICH5, "Intel ICH5" }, + { PCI_DEVICE_ID_INTEL_82801CA_5, "Intel 82801CA-ICH3" }, + { PCI_DEVICE_ID_INTEL_82801DB_5, "Intel 82801DB-ICH4" }, + { PCI_DEVICE_ID_INTEL_82801EB_5, "Intel ICH5" }, { PCI_DEVICE_ID_INTEL_ESB_5, "Intel 6300ESB" }, - { PCI_DEVICE_ID_INTEL_ICH6_3, "Intel ICH6" }, + { PCI_DEVICE_ID_INTEL_ICH6_18, "Intel ICH6" }, + { PCI_DEVICE_ID_INTEL_ICH7_20, "Intel ICH7" }, + { PCI_DEVICE_ID_INTEL_ESB2_14, "Intel ESB2" }, { PCI_DEVICE_ID_SI_7012, "SiS SI7012" }, - { PCI_DEVICE_ID_NVIDIA_MCP_AUDIO, "NVidia nForce" }, + { PCI_DEVICE_ID_NVIDIA_MCP1_AUDIO, "NVidia nForce" }, { PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO, "NVidia nForce2" }, { PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO, "NVidia nForce3" }, { PCI_DEVICE_ID_NVIDIA_CK8S_AUDIO, "NVidia CK8S" }, @@ -2639,20 +2970,12 @@ static struct shortname_table { static int __devinit snd_intel8x0_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { - static int dev; - snd_card_t *card; - intel8x0_t *chip; + struct snd_card *card; + struct intel8x0 *chip; int err; struct shortname_table *name; - if (dev >= SNDRV_CARDS) - return -ENODEV; - if (!enable[dev]) { - dev++; - return -ENOENT; - } - - card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); + card = snd_card_new(index, id, THIS_MODULE, 0); if (card == NULL) return -ENOMEM; @@ -2660,6 +2983,9 @@ static int __devinit snd_intel8x0_probe(struct pci_dev *pci, case DEVICE_NFORCE: strcpy(card->driver, "NFORCE"); break; + case DEVICE_INTEL_ICH4: + strcpy(card->driver, "ICH4"); + break; default: strcpy(card->driver, "ICH"); break; @@ -2673,14 +2999,24 @@ static int __devinit snd_intel8x0_probe(struct pci_dev *pci, } } - if ((err = snd_intel8x0_create(card, pci, pci_id->driver_data, &chip)) < 0) { + if (buggy_irq < 0) { + /* some Nforce[2] and ICH boards have problems with IRQ handling. + * Needs to return IRQ_HANDLED for unknown irqs. + */ + if (pci_id->driver_data == DEVICE_NFORCE) + buggy_irq = 1; + else + buggy_irq = 0; + } + + if ((err = snd_intel8x0_create(card, pci, pci_id->driver_data, + &chip)) < 0) { snd_card_free(card); return err; } - if (buggy_irq[dev]) - chip->buggy_irq = 1; + card->private_data = chip; - if ((err = snd_intel8x0_mixer(chip, ac97_clock[dev], ac97_quirk[dev])) < 0) { + if ((err = snd_intel8x0_mixer(chip, ac97_clock, ac97_quirk)) < 0) { snd_card_free(card); return err; } @@ -2689,22 +3025,13 @@ static int __devinit snd_intel8x0_probe(struct pci_dev *pci, return err; } - if (mpu_port[dev] == 0x300 || mpu_port[dev] == 0x330) { - if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_INTEL8X0, - mpu_port[dev], 0, - -1, 0, &chip->rmidi)) < 0) { - printk(KERN_ERR "intel8x0: no UART401 device at 0x%x, skipping.\n", mpu_port[dev]); - mpu_port[dev] = 0; - } - } else - mpu_port[dev] = 0; - snd_intel8x0_proc_init(chip); - sprintf(card->longname, "%s at 0x%lx, irq %i", - card->shortname, chip->addr, chip->irq); + snprintf(card->longname, sizeof(card->longname), + "%s with %s at %#lx, irq %i", card->shortname, + snd_ac97_get_short_name(chip->ac97[0]), chip->addr, chip->irq); - if (! ac97_clock[dev]) + if (! ac97_clock) intel8x0_measure_ac97_clock(chip); if ((err = snd_card_register(card)) < 0) { @@ -2712,7 +3039,6 @@ static int __devinit snd_intel8x0_probe(struct pci_dev *pci, return err; } pci_set_drvdata(pci, card); - dev++; return 0; } @@ -2727,133 +3053,21 @@ static struct pci_driver driver = { .id_table = snd_intel8x0_ids, .probe = snd_intel8x0_probe, .remove = __devexit_p(snd_intel8x0_remove), - SND_PCI_PM_CALLBACKS -}; - - -#if defined(SUPPORT_JOYSTICK) || defined(SUPPORT_MIDI) -/* - * initialize joystick/midi addresses - */ - -#ifdef SUPPORT_JOYSTICK -/* there is only one available device, so we keep it here */ -static struct pci_dev *ich_gameport_pci; -static struct gameport ich_gameport = { .io = 0x200 }; -#endif - -static int __devinit snd_intel8x0_joystick_probe(struct pci_dev *pci, - const struct pci_device_id *id) -{ - u16 val; - static int dev; - if (dev >= SNDRV_CARDS) - return -ENODEV; - if (!enable[dev]) { - dev++; - return -ENOENT; - } - - pci_read_config_word(pci, 0xe6, &val); -#ifdef SUPPORT_JOYSTICK - val &= ~0x100; - if (joystick[dev]) { - if (! request_region(ich_gameport.io, 8, "ICH gameport")) { - printk(KERN_WARNING "intel8x0: cannot grab gameport 0x%x\n", ich_gameport.io); - joystick[dev] = 0; - } else { - ich_gameport_pci = pci; - gameport_register_port(&ich_gameport); - val |= 0x100; - } - } -#endif -#ifdef SUPPORT_MIDI - val &= ~0x20; - if (mpu_port[dev] > 0) { - if (mpu_port[dev] == 0x300 || mpu_port[dev] == 0x330) { - u8 b; - val |= 0x20; - pci_read_config_byte(pci, 0xe2, &b); - if (mpu_port[dev] == 0x300) - b |= 0x08; - else - b &= ~0x08; - pci_write_config_byte(pci, 0xe2, b); - } - } -#endif - pci_write_config_word(pci, 0xe6, val); - return 0; -} - -static void __devexit snd_intel8x0_joystick_remove(struct pci_dev *pci) -{ - u16 val; -#ifdef SUPPORT_JOYSTICK - if (ich_gameport_pci == pci) { - gameport_unregister_port(&ich_gameport); - release_region(ich_gameport.io, 8); - ich_gameport_pci = NULL; - } +#ifdef CONFIG_PM + .suspend = intel8x0_suspend, + .resume = intel8x0_resume, #endif - /* disable joystick and MIDI */ - pci_read_config_word(pci, 0xe6, &val); - val &= ~0x120; - pci_write_config_word(pci, 0xe6, val); -} - -static struct pci_device_id snd_intel8x0_joystick_ids[] = { - { 0x8086, 0x2410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* 82801AA */ - { 0x8086, 0x2420, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* 82901AB */ - { 0x8086, 0x2440, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICH2 */ - { 0x8086, 0x244c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICH2M */ - { 0x8086, 0x248c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICH3 */ - // { 0x8086, 0x7195, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* 440MX */ - // { 0x1039, 0x7012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* SI7012 */ - { 0x10de, 0x01b2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* NFORCE */ - { 0x10de, 0x006b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* NFORCE2 */ - { 0x10de, 0x00db, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* NFORCE3 */ - { 0, } -}; - -static struct pci_driver joystick_driver = { - .name = "Intel ICH Joystick", - .id_table = snd_intel8x0_joystick_ids, - .probe = snd_intel8x0_joystick_probe, - .remove = __devexit_p(snd_intel8x0_joystick_remove), }; -static int have_joystick; -#endif static int __init alsa_card_intel8x0_init(void) { - int err; - - if ((err = pci_module_init(&driver)) < 0) - return err; - -#if defined(SUPPORT_JOYSTICK) || defined(SUPPORT_MIDI) - if (pci_module_init(&joystick_driver) < 0) { - snd_printdd(KERN_INFO "no joystick found\n"); - have_joystick = 0; - } else { - snd_printdd(KERN_INFO "joystick(s) found\n"); - have_joystick = 1; - } -#endif - return 0; - + return pci_register_driver(&driver); } static void __exit alsa_card_intel8x0_exit(void) { pci_unregister_driver(&driver); -#if defined(SUPPORT_JOYSTICK) || defined(SUPPORT_MIDI) - if (have_joystick) - pci_unregister_driver(&joystick_driver); -#endif } module_init(alsa_card_intel8x0_init)