"{SiS,SI7012},"
"{NVidia,nForce Audio},"
"{NVidia,nForce2 Audio},"
+ "{NVidia,nForce3 Audio},"
+ "{NVidia,MCP04},"
+ "{NVidia,MCP501},"
+ "{NVidia,CK804},"
+ "{NVidia,CK8},"
+ "{NVidia,CK8S},"
"{AMD,AMD768},"
"{AMD,AMD8111},"
"{ALI,M5455}}");
module_param(id, charp, 0444);
MODULE_PARM_DESC(id, "ID string for Intel i8x0 soundcard.");
module_param(ac97_clock, int, 0444);
-MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (0 = auto-detect).");
+MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (0 = whitelist + auto-detect, 1 = force autodetect).");
module_param(ac97_quirk, charp, 0444);
MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware.");
module_param(buggy_semaphore, bool, 0444);
int time = 100;
if (chip->buggy_semaphore)
return 0; /* just ignore ... */
- while (time-- && (igetdword(chip, ICHREG(ALI_CAS)) & ALI_CAS_SEM_BUSY))
+ while (--time && (igetdword(chip, ICHREG(ALI_CAS)) & ALI_CAS_SEM_BUSY))
udelay(1);
if (! time && ! chip->in_ac97_init)
snd_printk(KERN_WARNING "ali_codec_semaphore timeout\n");
bdbar[idx + 1] = cpu_to_le32(0x80000000 | /* interrupt on completion */
ichdev->fragsize >> ichdev->pos_shift);
#if 0
- printk("bdbar[%i] = 0x%x [0x%x]\n",
+ printk(KERN_DEBUG "bdbar[%i] = 0x%x [0x%x]\n",
idx + 0, bdbar[idx + 0], bdbar[idx + 1]);
#endif
}
ichdev->lvi_frag = ICH_REG_LVI_MASK % ichdev->frags;
ichdev->position = 0;
#if 0
- printk("lvi_frag = %i, frags = %i, period_size = 0x%x, period_size1 = 0x%x\n",
- ichdev->lvi_frag, ichdev->frags, ichdev->fragsize, ichdev->fragsize1);
+ printk(KERN_DEBUG "lvi_frag = %i, frags = %i, period_size = 0x%x, "
+ "period_size1 = 0x%x\n",
+ ichdev->lvi_frag, ichdev->frags, ichdev->fragsize,
+ ichdev->fragsize1);
#endif
/* clear interrupts */
iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI);
ichdev->lvi_frag %= ichdev->frags;
ichdev->bdbar[ichdev->lvi * 2] = cpu_to_le32(ichdev->physbuf + ichdev->lvi_frag * ichdev->fragsize1);
#if 0
- printk("new: bdbar[%i] = 0x%x [0x%x], prefetch = %i, all = 0x%x, 0x%x\n",
+ printk(KERN_DEBUG "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));
},
{
.subvendor = 0x10cf,
+ .subdevice = 0x127d,
+ .name = "Fujitsu Lifebook P7010",
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .subvendor = 0x10cf,
.subdevice = 0x127e,
.name = "Fujitsu Lifebook C1211D",
.type = AC97_TUNE_HP_ONLY
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);
+ if (snd_BUG_ON(chip->ac97_sdin[codecs] >= 3))
+ chip->ac97_sdin[codecs] = 0;
} else
chip->ac97_sdin[codecs] = i;
codecs++;
iputdword(chip, ICHREG(ALI_INTERRUPTSR), 0x00000000);
}
-static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing)
-{
- unsigned long end_time;
- unsigned int cnt, status, nstatus;
-
- /* put logic to right state */
- /* first clear status bits */
- status = ICH_RCS | ICH_MCINT | ICH_POINT | ICH_PIINT;
- if (chip->device_type == DEVICE_NFORCE)
- status |= ICH_NVSPINT;
- cnt = igetdword(chip, ICHREG(GLOB_STA));
- iputdword(chip, ICHREG(GLOB_STA), cnt & status);
+#ifdef CONFIG_SND_AC97_POWER_SAVE
+static struct snd_pci_quirk ich_chip_reset_mode[] = {
+ SND_PCI_QUIRK(0x1014, 0x051f, "Thinkpad R32", 1),
+ { } /* end */
+};
+static int snd_intel8x0_ich_chip_cold_reset(struct intel8x0 *chip)
+{
+ unsigned int cnt;
/* ACLink on, 2 channels */
+
+ if (snd_pci_quirk_lookup(chip->pci, ich_chip_reset_mode))
+ return -EIO;
+
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.
*/
udelay(10);
iputdword(chip, ICHREG(GLOB_CNT), cnt | ICH_AC97COLD);
msleep(1);
+ return 0;
+}
+#define snd_intel8x0_ich_chip_can_cold_reset(chip) \
+ (!snd_pci_quirk_lookup(chip->pci, ich_chip_reset_mode))
#else
+#define snd_intel8x0_ich_chip_cold_reset(chip) 0
+#define snd_intel8x0_ich_chip_can_cold_reset(chip) (0)
+#endif
+
+static int snd_intel8x0_ich_chip_reset(struct intel8x0 *chip)
+{
+ unsigned long end_time;
+ unsigned int cnt;
+ /* ACLink on, 2 channels */
+ cnt = igetdword(chip, ICHREG(GLOB_CNT));
+ cnt &= ~(ICH_ACLINK | ICH_PCM_246_MASK);
/* finish cold or do warm reset */
cnt |= (cnt & ICH_AC97COLD) == 0 ? ICH_AC97COLD : ICH_AC97WARM;
iputdword(chip, ICHREG(GLOB_CNT), cnt);
end_time = (jiffies + (HZ / 4)) + 1;
do {
if ((igetdword(chip, ICHREG(GLOB_CNT)) & ICH_AC97WARM) == 0)
- goto __ok;
+ return 0;
schedule_timeout_uninterruptible(1);
} while (time_after_eq(end_time, jiffies));
snd_printk(KERN_ERR "AC'97 warm reset still in progress? [0x%x]\n",
igetdword(chip, ICHREG(GLOB_CNT)));
return -EIO;
+}
+
+static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing)
+{
+ unsigned long end_time;
+ unsigned int status, nstatus;
+ unsigned int cnt;
+ int err;
+
+ /* put logic to right state */
+ /* first clear status bits */
+ status = ICH_RCS | ICH_MCINT | ICH_POINT | ICH_PIINT;
+ if (chip->device_type == DEVICE_NFORCE)
+ status |= ICH_NVSPINT;
+ cnt = igetdword(chip, ICHREG(GLOB_STA));
+ iputdword(chip, ICHREG(GLOB_STA), cnt & status);
+
+ if (snd_intel8x0_ich_chip_can_cold_reset(chip))
+ err = snd_intel8x0_ich_chip_cold_reset(chip);
+ else
+ err = snd_intel8x0_ich_chip_reset(chip);
+ if (err < 0)
+ return err;
- __ok:
-#endif
if (probing) {
/* wait for any codec ready status.
* Once it becomes ready it should remain ready
pci_write_config_dword(chip->pci, 0x4c, val);
}
/* --- */
- synchronize_irq(chip->irq);
+
__hw_end:
if (chip->irq >= 0)
free_irq(chip->irq, chip);
chip->sdm_saved = igetbyte(chip, ICHREG(SDM));
if (chip->irq >= 0) {
- synchronize_irq(chip->irq);
free_irq(chip->irq, chip);
chip->irq = -1;
}
snd_ac97_update_power(chip->ac97[0], AC97_PCM_FRONT_DAC_RATE, 0);
}
+static struct snd_pci_quirk intel8x0_clock_list[] __devinitdata = {
+ SND_PCI_QUIRK(0x0e11, 0x008a, "AD1885", 41000),
+ SND_PCI_QUIRK(0x1028, 0x00be, "AD1885", 44100),
+ SND_PCI_QUIRK(0x1028, 0x0177, "AD1980", 48000),
+ SND_PCI_QUIRK(0x1028, 0x01ad, "AD1981B", 48000),
+ SND_PCI_QUIRK(0x1043, 0x80f3, "AD1985", 48000),
+ { } /* terminator */
+};
+
+static int __devinit intel8x0_in_clock_list(struct intel8x0 *chip)
+{
+ struct pci_dev *pci = chip->pci;
+ const struct snd_pci_quirk *wl;
+
+ wl = snd_pci_quirk_lookup(pci, intel8x0_clock_list);
+ if (!wl)
+ return 0;
+ printk(KERN_INFO "intel8x0: white list rate for %04x:%04x is %i\n",
+ pci->subsystem_vendor, pci->subsystem_device, wl->value);
+ chip->ac97_bus->clock = wl->value;
+ return 1;
+}
+
#ifdef CONFIG_PROC_FS
static void snd_intel8x0_proc_read(struct snd_info_entry * entry,
struct snd_info_buffer *buffer)
int err;
struct shortname_table *name;
- card = snd_card_new(index, id, THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
if (spdif_aclink < 0)
spdif_aclink = check_default_spdif_aclink(pci);
"%s with %s at irq %i", card->shortname,
snd_ac97_get_short_name(chip->ac97[0]), chip->irq);
- if (! ac97_clock)
- intel8x0_measure_ac97_clock(chip);
+ if (ac97_clock == 0 || ac97_clock == 1) {
+ if (ac97_clock == 0) {
+ if (intel8x0_in_clock_list(chip) == 0)
+ intel8x0_measure_ac97_clock(chip);
+ } else {
+ intel8x0_measure_ac97_clock(chip);
+ }
+ }
if ((err = snd_card_register(card)) < 0) {
snd_card_free(card);