aboutsummaryrefslogtreecommitdiff
path: root/sound/pci/intel8x0.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/intel8x0.c')
-rw-r--r--sound/pci/intel8x0.c643
1 files changed, 463 insertions, 180 deletions
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
index c52abd0bf22..c91860e0a28 100644
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -32,7 +32,7 @@
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/slab.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/ac97_codec.h>
@@ -42,6 +42,12 @@
#include <asm/pgtable.h>
#include <asm/cacheflush.h>
+#ifdef CONFIG_KVM_GUEST
+#include <linux/kvm_para.h>
+#else
+#define kvm_para_available() (0)
+#endif
+
MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_DESCRIPTION("Intel 82801AA,82901AB,i810,i820,i830,i840,i845,MX440; SiS 7012; Ali 5455");
MODULE_LICENSE("GPL");
@@ -59,6 +65,12 @@ MODULE_SUPPORTED_DEVICE("{{Intel,82801AA-ICH},"
"{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}}");
@@ -67,30 +79,33 @@ 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 bool buggy_semaphore;
static int buggy_irq = -1; /* auto-check */
-static int xbox;
+static bool xbox;
static int spdif_aclink = -1;
+static int inside_vm = -1;
module_param(index, int, 0444);
MODULE_PARM_DESC(index, "Index value for Intel i8x0 soundcard.");
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);
MODULE_PARM_DESC(buggy_semaphore, "Enable workaround for hardwares with problematic codec semaphores.");
-module_param(buggy_irq, bool, 0444);
+module_param(buggy_irq, bint, 0444);
MODULE_PARM_DESC(buggy_irq, "Enable workaround for buggy interrupts on some motherboards.");
module_param(xbox, bool, 0444);
MODULE_PARM_DESC(xbox, "Set to 1 for Xbox, if you have problems with the AC'97 codec detection.");
module_param(spdif_aclink, int, 0444);
MODULE_PARM_DESC(spdif_aclink, "S/PDIF over AC-link.");
+module_param(inside_vm, bint, 0444);
+MODULE_PARM_DESC(inside_vm, "KVM/Parallels optimization.");
/* just for backward compatibility */
-static int enable;
+static bool enable;
module_param(enable, bool, 0444);
static int joystick;
module_param(joystick, int, 0444);
@@ -155,7 +170,8 @@ DEFINE_REGSET(SP, 0x60); /* SPDIF out */
#define ICH_PCM_SPDIF_69 0x80000000 /* s/pdif pcm on slots 6&9 */
#define ICH_PCM_SPDIF_1011 0xc0000000 /* s/pdif pcm on slots 10&11 */
#define ICH_PCM_20BIT 0x00400000 /* 20-bit samples (ICH4) */
-#define ICH_PCM_246_MASK 0x00300000 /* 6 channels (not all chips) */
+#define ICH_PCM_246_MASK 0x00300000 /* chan mask (not all chips) */
+#define ICH_PCM_8 0x00300000 /* 8 channels (not all chips) */
#define ICH_PCM_6 0x00200000 /* 6 channels (not all chips) */
#define ICH_PCM_4 0x00100000 /* 4 channels (not all chips) */
#define ICH_PCM_2 0x00000000 /* 2 channels (stereo) */
@@ -348,6 +364,7 @@ struct ichdev {
unsigned int fragsize1;
unsigned int position;
unsigned int pos_shift;
+ unsigned int last_pos;
int frags;
int lvi;
int lvi_frag;
@@ -382,6 +399,7 @@ struct intel8x0 {
unsigned multi4: 1,
multi6: 1,
+ multi8 :1,
dra: 1,
smp20bit: 1;
unsigned in_ac97_init: 1,
@@ -391,6 +409,7 @@ struct intel8x0 {
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 */
+ unsigned inside_vm: 1; /* enable VM optimization */
int spdif_idx; /* SPDIF BAR index; *_SPBAR or -1 if use PCMOUT */
unsigned int sdm_saved; /* SDM reg value */
@@ -411,30 +430,30 @@ struct intel8x0 {
u32 int_sta_mask; /* interrupt status mask */
};
-static struct pci_device_id snd_intel8x0_ids[] = {
- { 0x8086, 0x2415, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 82801AA */
- { 0x8086, 0x2425, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 82901AB */
- { 0x8086, 0x2445, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 82801BA */
- { 0x8086, 0x2485, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* ICH3 */
- { 0x8086, 0x24c5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ICH4 */
- { 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 */
- { 0x10de, 0x003a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* MCP04 */
- { 0x10de, 0x006a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* NFORCE2 */
- { 0x10de, 0x0059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* CK804 */
- { 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 */
+static DEFINE_PCI_DEVICE_TABLE(snd_intel8x0_ids) = {
+ { PCI_VDEVICE(INTEL, 0x2415), DEVICE_INTEL }, /* 82801AA */
+ { PCI_VDEVICE(INTEL, 0x2425), DEVICE_INTEL }, /* 82901AB */
+ { PCI_VDEVICE(INTEL, 0x2445), DEVICE_INTEL }, /* 82801BA */
+ { PCI_VDEVICE(INTEL, 0x2485), DEVICE_INTEL }, /* ICH3 */
+ { PCI_VDEVICE(INTEL, 0x24c5), DEVICE_INTEL_ICH4 }, /* ICH4 */
+ { PCI_VDEVICE(INTEL, 0x24d5), DEVICE_INTEL_ICH4 }, /* ICH5 */
+ { PCI_VDEVICE(INTEL, 0x25a6), DEVICE_INTEL_ICH4 }, /* ESB */
+ { PCI_VDEVICE(INTEL, 0x266e), DEVICE_INTEL_ICH4 }, /* ICH6 */
+ { PCI_VDEVICE(INTEL, 0x27de), DEVICE_INTEL_ICH4 }, /* ICH7 */
+ { PCI_VDEVICE(INTEL, 0x2698), DEVICE_INTEL_ICH4 }, /* ESB2 */
+ { PCI_VDEVICE(INTEL, 0x7195), DEVICE_INTEL }, /* 440MX */
+ { PCI_VDEVICE(SI, 0x7012), DEVICE_SIS }, /* SI7012 */
+ { PCI_VDEVICE(NVIDIA, 0x01b1), DEVICE_NFORCE }, /* NFORCE */
+ { PCI_VDEVICE(NVIDIA, 0x003a), DEVICE_NFORCE }, /* MCP04 */
+ { PCI_VDEVICE(NVIDIA, 0x006a), DEVICE_NFORCE }, /* NFORCE2 */
+ { PCI_VDEVICE(NVIDIA, 0x0059), DEVICE_NFORCE }, /* CK804 */
+ { PCI_VDEVICE(NVIDIA, 0x008a), DEVICE_NFORCE }, /* CK8 */
+ { PCI_VDEVICE(NVIDIA, 0x00da), DEVICE_NFORCE }, /* NFORCE3 */
+ { PCI_VDEVICE(NVIDIA, 0x00ea), DEVICE_NFORCE }, /* CK8S */
+ { PCI_VDEVICE(NVIDIA, 0x026b), DEVICE_NFORCE }, /* MCP51 */
+ { PCI_VDEVICE(AMD, 0x746d), DEVICE_INTEL }, /* AMD8111 */
+ { PCI_VDEVICE(AMD, 0x7445), DEVICE_INTEL }, /* AMD768 */
+ { PCI_VDEVICE(AL, 0x5455), DEVICE_ALI }, /* Ali5455 */
{ 0, }
};
@@ -525,10 +544,11 @@ static int snd_intel8x0_codec_semaphore(struct intel8x0 *chip, unsigned int code
udelay(10);
} while (time--);
- /* access to some forbidden (non existant) ac97 registers will not
+ /* access to some forbidden (non existent) 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(KERN_ERR "codec_semaphore: semaphore is not ready [0x%x][0x%x]\n",
+ dev_err(chip->card->dev,
+ "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 */
@@ -543,7 +563,9 @@ static void snd_intel8x0_codec_write(struct snd_ac97 *ac97,
if (snd_intel8x0_codec_semaphore(chip, ac97->num) < 0) {
if (! chip->in_ac97_init)
- snd_printk(KERN_ERR "codec_write %d: semaphore is not ready for register 0x%x\n", ac97->num, reg);
+ dev_err(chip->card->dev,
+ "codec_write %d: semaphore is not ready for register 0x%x\n",
+ ac97->num, reg);
}
iaputword(chip, reg + ac97->num * 0x80, val);
}
@@ -557,7 +579,9 @@ static unsigned short snd_intel8x0_codec_read(struct snd_ac97 *ac97,
if (snd_intel8x0_codec_semaphore(chip, ac97->num) < 0) {
if (! chip->in_ac97_init)
- snd_printk(KERN_ERR "codec_read %d: semaphore is not ready for register 0x%x\n", ac97->num, reg);
+ dev_err(chip->card->dev,
+ "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);
@@ -566,15 +590,17 @@ static unsigned short snd_intel8x0_codec_read(struct snd_ac97 *ac97,
iputdword(chip, ICHREG(GLOB_STA), tmp &
~(chip->codec_ready_bits | ICH_GSCI));
if (! chip->in_ac97_init)
- snd_printk(KERN_ERR "codec_read %d: read timeout for register 0x%x\n", ac97->num, reg);
+ dev_err(chip->card->dev,
+ "codec_read %d: read timeout for register 0x%x\n",
+ ac97->num, reg);
res = 0xffff;
}
}
return res;
}
-static void __devinit snd_intel8x0_codec_read_test(struct intel8x0 *chip,
- unsigned int codec)
+static void snd_intel8x0_codec_read_test(struct intel8x0 *chip,
+ unsigned int codec)
{
unsigned int tmp;
@@ -600,7 +626,7 @@ static int snd_intel8x0_ali_codec_ready(struct intel8x0 *chip, int mask)
return 0;
}
if (! chip->in_ac97_init)
- snd_printd(KERN_WARNING "intel8x0: AC97 codec ready timeout.\n");
+ dev_warn(chip->card->dev, "AC97 codec ready timeout.\n");
return -EBUSY;
}
@@ -609,10 +635,10 @@ 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))
+ 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");
+ dev_warn(chip->card->dev, "ali_codec_semaphore timeout\n");
return snd_intel8x0_ali_codec_ready(chip, ALI_CSPSR_CODEC_READY);
}
@@ -681,7 +707,7 @@ static void snd_intel8x0_setup_periods(struct intel8x0 *chip, struct ichdev *ich
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",
+ dev_dbg(chip->card->dev, "bdbar[%i] = 0x%x [0x%x]\n",
idx + 0, bdbar[idx + 0], bdbar[idx + 1]);
#endif
}
@@ -693,8 +719,10 @@ static void snd_intel8x0_setup_periods(struct intel8x0 *chip, struct ichdev *ich
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);
+ dev_dbg(chip->card->dev,
+ "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);
@@ -705,7 +733,7 @@ static void snd_intel8x0_setup_periods(struct intel8x0 *chip, struct ichdev *ich
* Intel 82443MX running a 100MHz processor system bus has a hardware bug,
* which aborts PCI busmaster for audio transfer. A workaround is to set
* the pages as non-cached. For details, see the errata in
- * http://www.intel.com/design/chipsets/specupdt/245051.htm
+ * http://download.intel.com/design/chipsets/specupdt/24505108.pdf
*/
static void fill_nocache(void *buf, int size, int nocache)
{
@@ -760,7 +788,8 @@ static inline void snd_intel8x0_update(struct intel8x0 *chip, struct ichdev *ich
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",
+ dev_dbg(chip->card->dev,
+ "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));
@@ -827,7 +856,9 @@ static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd
ichdev->suspended = 0;
/* fallthru */
case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
val = ICH_IOCE | ICH_STARTBM;
+ ichdev->last_pos = ichdev->position;
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
ichdev->suspended = 1;
@@ -838,9 +869,6 @@ static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
val = ICH_IOCE;
break;
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- val = ICH_IOCE | ICH_STARTBM;
- break;
default:
return -EINVAL;
}
@@ -997,6 +1025,8 @@ static void snd_intel8x0_setup_pcm_out(struct intel8x0 *chip,
cnt |= ICH_PCM_4;
else if (runtime->channels == 6)
cnt |= ICH_PCM_6;
+ else if (runtime->channels == 8)
+ cnt |= ICH_PCM_8;
if (chip->device_type == DEVICE_NFORCE) {
/* reset to 2ch once to keep the 6 channel data in alignment,
* to start from Front Left always
@@ -1040,7 +1070,7 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(struct snd_pcm_substream *subs
struct intel8x0 *chip = snd_pcm_substream_chip(substream);
struct ichdev *ichdev = get_ichdev(substream);
size_t ptr1, ptr;
- int civ, timeout = 100;
+ int civ, timeout = 10;
unsigned int position;
spin_lock(&chip->reg_lock);
@@ -1052,13 +1082,37 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(struct snd_pcm_substream *subs
udelay(10);
continue;
}
- if (civ == igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV) &&
- ptr1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb))
+ if (civ != igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV))
+ continue;
+
+ /* IO read operation is very expensive inside virtual machine
+ * as it is emulated. The probability that subsequent PICB read
+ * will return different result is high enough to loop till
+ * timeout here.
+ * Same CIV is strict enough condition to be sure that PICB
+ * is valid inside VM on emulated card. */
+ if (chip->inside_vm)
+ break;
+ if (ptr1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb))
break;
} while (timeout--);
- ptr1 <<= ichdev->pos_shift;
- ptr = ichdev->fragsize1 - ptr1;
- ptr += position;
+ ptr = ichdev->last_pos;
+ if (ptr1 != 0) {
+ ptr1 <<= ichdev->pos_shift;
+ ptr = ichdev->fragsize1 - ptr1;
+ ptr += position;
+ if (ptr < ichdev->last_pos) {
+ unsigned int pos_base, last_base;
+ pos_base = position / ichdev->fragsize1;
+ last_base = ichdev->last_pos / ichdev->fragsize1;
+ /* another sanity check; ptr1 can go back to full
+ * before the base position is updated
+ */
+ if (pos_base == last_base)
+ ptr = ichdev->last_pos;
+ }
+ }
+ ichdev->last_pos = ptr;
spin_unlock(&chip->reg_lock);
if (ptr >= ichdev->size)
return 0;
@@ -1106,6 +1160,16 @@ static struct snd_pcm_hw_constraint_list hw_constraints_channels6 = {
.mask = 0,
};
+static unsigned int channels8[] = {
+ 2, 4, 6, 8,
+};
+
+static struct snd_pcm_hw_constraint_list hw_constraints_channels8 = {
+ .count = ARRAY_SIZE(channels8),
+ .list = channels8,
+ .mask = 0,
+};
+
static int snd_intel8x0_pcm_open(struct snd_pcm_substream *substream, struct ichdev *ichdev)
{
struct intel8x0 *chip = snd_pcm_substream_chip(substream);
@@ -1136,7 +1200,12 @@ static int snd_intel8x0_playback_open(struct snd_pcm_substream *substream)
if (err < 0)
return err;
- if (chip->multi6) {
+ if (chip->multi8) {
+ runtime->hw.channels_max = 8;
+ snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ &hw_constraints_channels8);
+ } else if (chip->multi6) {
runtime->hw.channels_max = 6;
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
&hw_constraints_channels6);
@@ -1445,8 +1514,8 @@ struct ich_pcm_table {
int ac97_idx;
};
-static int __devinit snd_intel8x0_pcm1(struct intel8x0 *chip, int device,
- struct ich_pcm_table *rec)
+static int snd_intel8x0_pcm1(struct intel8x0 *chip, int device,
+ struct ich_pcm_table *rec)
{
struct snd_pcm *pcm;
int err;
@@ -1479,10 +1548,29 @@ static int __devinit snd_intel8x0_pcm1(struct intel8x0 *chip, int device,
snd_dma_pci_data(chip->pci),
rec->prealloc_size, rec->prealloc_max_size);
+ if (rec->playback_ops &&
+ rec->playback_ops->open == snd_intel8x0_playback_open) {
+ struct snd_pcm_chmap *chmap;
+ int chs = 2;
+ if (chip->multi8)
+ chs = 8;
+ else if (chip->multi6)
+ chs = 6;
+ else if (chip->multi4)
+ chs = 4;
+ err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ snd_pcm_alt_chmaps, chs, 0,
+ &chmap);
+ if (err < 0)
+ return err;
+ chmap->channel_mask = SND_PCM_CHMAP_MASK_2468;
+ chip->ac97[0]->chmaps[SNDRV_PCM_STREAM_PLAYBACK] = chmap;
+ }
+
return 0;
}
-static struct ich_pcm_table intel_pcms[] __devinitdata = {
+static struct ich_pcm_table intel_pcms[] = {
{
.playback_ops = &snd_intel8x0_playback_ops,
.capture_ops = &snd_intel8x0_capture_ops,
@@ -1519,7 +1607,7 @@ static struct ich_pcm_table intel_pcms[] __devinitdata = {
},
};
-static struct ich_pcm_table nforce_pcms[] __devinitdata = {
+static struct ich_pcm_table nforce_pcms[] = {
{
.playback_ops = &snd_intel8x0_playback_ops,
.capture_ops = &snd_intel8x0_capture_ops,
@@ -1542,7 +1630,7 @@ static struct ich_pcm_table nforce_pcms[] __devinitdata = {
},
};
-static struct ich_pcm_table ali_pcms[] __devinitdata = {
+static struct ich_pcm_table ali_pcms[] = {
{
.playback_ops = &snd_intel8x0_ali_playback_ops,
.capture_ops = &snd_intel8x0_ali_capture_ops,
@@ -1574,7 +1662,7 @@ static struct ich_pcm_table ali_pcms[] __devinitdata = {
#endif
};
-static int __devinit snd_intel8x0_pcm(struct intel8x0 *chip)
+static int snd_intel8x0_pcm(struct intel8x0 *chip)
{
int i, tblsize, device, err;
struct ich_pcm_table *tbl, *rec;
@@ -1637,7 +1725,7 @@ static void snd_intel8x0_mixer_free_ac97(struct snd_ac97 *ac97)
chip->ac97[ac97->num] = NULL;
}
-static struct ac97_pcm ac97_pcm_defs[] __devinitdata = {
+static struct ac97_pcm ac97_pcm_defs[] = {
/* front PCM */
{
.exclusive = 1,
@@ -1707,7 +1795,7 @@ static struct ac97_pcm ac97_pcm_defs[] __devinitdata = {
},
};
-static struct ac97_quirk ac97_quirks[] __devinitdata = {
+static struct ac97_quirk ac97_quirks[] = {
{
.subvendor = 0x0e11,
.subdevice = 0x000e,
@@ -1734,6 +1822,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
},
{
.subvendor = 0x1014,
+ .subdevice = 0x0534,
+ .name = "ThinkPad X31",
+ .type = AC97_TUNE_INV_EAPD
+ },
+ {
+ .subvendor = 0x1014,
.subdevice = 0x1f00,
.name = "MS-9128",
.type = AC97_TUNE_ALC_JACK
@@ -1812,6 +1906,18 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
},
{
.subvendor = 0x1028,
+ .subdevice = 0x016a,
+ .name = "Dell Inspiron 8600", /* STAC9750/51 */
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .subvendor = 0x1028,
+ .subdevice = 0x0182,
+ .name = "Dell Latitude D610", /* STAC9750/51 */
+ .type = AC97_TUNE_HP_ONLY
+ },
+ {
+ .subvendor = 0x1028,
.subdevice = 0x0186,
.name = "Dell Latitude D810", /* cf. Malone #41015 */
.type = AC97_TUNE_HP_MUTE_LED
@@ -1824,6 +1930,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
},
{
.subvendor = 0x1028,
+ .subdevice = 0x0189,
+ .name = "Dell Inspiron 9300",
+ .type = AC97_TUNE_HP_MUTE_LED
+ },
+ {
+ .subvendor = 0x1028,
.subdevice = 0x0191,
.name = "Dell Inspiron 8600",
.type = AC97_TUNE_HP_ONLY
@@ -1854,12 +1966,6 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
},
{
.subvendor = 0x103c,
- .subdevice = 0x0934,
- .name = "HP nx8220",
- .type = AC97_TUNE_MUTE_LED
- },
- {
- .subvendor = 0x103c,
.subdevice = 0x129d,
.name = "HP xw8000",
.type = AC97_TUNE_HP_ONLY
@@ -1908,10 +2014,28 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
},
{
.subvendor = 0x104d,
+ .subdevice = 0x8144,
+ .name = "Sony",
+ .type = AC97_TUNE_INV_EAPD
+ },
+ {
+ .subvendor = 0x104d,
.subdevice = 0x8197,
.name = "Sony S1XP",
.type = AC97_TUNE_INV_EAPD
},
+ {
+ .subvendor = 0x104d,
+ .subdevice = 0x81c0,
+ .name = "Sony VAIO VGN-T350P", /*AD1981B*/
+ .type = AC97_TUNE_INV_EAPD
+ },
+ {
+ .subvendor = 0x104d,
+ .subdevice = 0x81c5,
+ .name = "Sony VAIO VGN-B1VP", /*AD1981B*/
+ .type = AC97_TUNE_INV_EAPD
+ },
{
.subvendor = 0x1043,
.subdevice = 0x80f3,
@@ -1938,6 +2062,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
},
{
.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
@@ -1997,6 +2127,18 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
.type = AC97_TUNE_HP_ONLY
},
{
+ .subvendor = 0x161f,
+ .subdevice = 0x202f,
+ .name = "Gateway M520",
+ .type = AC97_TUNE_INV_EAPD
+ },
+ {
+ .subvendor = 0x161f,
+ .subdevice = 0x203a,
+ .name = "Gateway 4525GZ", /* AD1981B */
+ .type = AC97_TUNE_INV_EAPD
+ },
+ {
.subvendor = 0x1734,
.subdevice = 0x0088,
.name = "Fujitsu-Siemens D1522", /* AD1981 */
@@ -2060,8 +2202,8 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
{ } /* terminator */
};
-static int __devinit snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock,
- const char *quirk_override)
+static int snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock,
+ const char *quirk_override)
{
struct snd_ac97_bus *pbus;
struct snd_ac97_template ac97;
@@ -2090,7 +2232,7 @@ static int __devinit snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock,
case DEVICE_INTEL_ICH4:
chip->spdif_idx = ICHD_SPBAR;
break;
- };
+ }
}
chip->in_ac97_init = 1;
@@ -2113,8 +2255,8 @@ static int __devinit snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock,
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++;
@@ -2154,7 +2296,8 @@ static int __devinit snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock,
ac97.num = i;
if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) {
if (err != -EACCES)
- snd_printk(KERN_ERR "Unable to initialize codec #%d\n", i);
+ dev_err(chip->card->dev,
+ "Unable to initialize codec #%d\n", i);
if (i == 0)
goto __err;
}
@@ -2203,8 +2346,11 @@ static int __devinit snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock,
}
if (pbus->pcms[0].r[0].slots & (1 << AC97_SLOT_PCM_SLEFT)) {
chip->multi4 = 1;
- if (pbus->pcms[0].r[0].slots & (1 << AC97_SLOT_LFE))
+ if (pbus->pcms[0].r[0].slots & (1 << AC97_SLOT_LFE)) {
chip->multi6 = 1;
+ if (chip->ac97[0]->flags & AC97_HAS_8CH)
+ chip->multi8 = 1;
+ }
}
if (pbus->pcms[0].r[1].rslots[0]) {
chip->dra = 1;
@@ -2253,23 +2399,23 @@ static void do_ali_reset(struct intel8x0 *chip)
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.
*/
@@ -2278,22 +2424,58 @@ static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing)
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",
+ dev_err(chip->card->dev, "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
@@ -2309,7 +2491,8 @@ static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing)
} 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",
+ dev_err(chip->card->dev,
+ "codec_ready: codec is not ready [0x%x]\n",
igetdword(chip, ICHREG(GLOB_STA)));
return -EIO;
}
@@ -2373,7 +2556,7 @@ static int snd_intel8x0_ali_chip_init(struct intel8x0 *chip, int probing)
goto __ok;
schedule_timeout_uninterruptible(1);
}
- snd_printk(KERN_ERR "AC'97 reset failed.\n");
+ dev_err(chip->card->dev, "AC'97 reset failed.\n");
if (probing)
return -EIO;
@@ -2417,7 +2600,7 @@ static int snd_intel8x0_chip_init(struct intel8x0 *chip, int probing)
break;
}
if (timeout == 0)
- printk(KERN_ERR "intel8x0: reset of registers failed?\n");
+ dev_err(chip->card->dev, "reset of registers failed?\n");
}
/* initialize Buffer Descriptor Lists */
for (i = 0; i < chip->bdbars_count; i++)
@@ -2446,7 +2629,7 @@ static int snd_intel8x0_free(struct intel8x0 *chip)
pci_write_config_dword(chip->pci, 0x4c, val);
}
/* --- */
- synchronize_irq(chip->irq);
+
__hw_end:
if (chip->irq >= 0)
free_irq(chip->irq, chip);
@@ -2465,13 +2648,14 @@ static int snd_intel8x0_free(struct intel8x0 *chip)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
/*
* power management
*/
-static int intel8x0_suspend(struct pci_dev *pci, pm_message_t state)
+static int intel8x0_suspend(struct device *dev)
{
- struct snd_card *card = pci_get_drvdata(pci);
+ struct pci_dev *pci = to_pci_dev(dev);
+ struct snd_card *card = dev_get_drvdata(dev);
struct intel8x0 *chip = card->private_data;
int i;
@@ -2495,7 +2679,6 @@ static int intel8x0_suspend(struct pci_dev *pci, pm_message_t state)
chip->sdm_saved = igetbyte(chip, ICHREG(SDM));
if (chip->irq >= 0) {
- synchronize_irq(chip->irq);
free_irq(chip->irq, chip);
chip->irq = -1;
}
@@ -2504,30 +2687,30 @@ static int intel8x0_suspend(struct pci_dev *pci, pm_message_t state)
/* 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)); */
+ /* pci_set_power_state(pci, PCI_D3hot); */
return 0;
}
-static int intel8x0_resume(struct pci_dev *pci)
+static int intel8x0_resume(struct device *dev)
{
- struct snd_card *card = pci_get_drvdata(pci);
+ struct pci_dev *pci = to_pci_dev(dev);
+ struct snd_card *card = dev_get_drvdata(dev);
struct intel8x0 *chip = card->private_data;
int i;
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");
+ dev_err(dev, "pci_enable_device failed, disabling device\n");
snd_card_disconnect(card);
return -EIO;
}
pci_set_master(pci);
snd_intel8x0_chip_init(chip, 0);
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);
+ IRQF_SHARED, KBUILD_MODNAME, chip)) {
+ dev_err(dev, "unable to grab IRQ %d, disabling device\n",
+ pci->irq);
snd_card_disconnect(card);
return -EIO;
}
@@ -2580,34 +2763,43 @@ static int intel8x0_resume(struct pci_dev *pci)
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
return 0;
}
-#endif /* CONFIG_PM */
+
+static SIMPLE_DEV_PM_OPS(intel8x0_pm, intel8x0_suspend, intel8x0_resume);
+#define INTEL8X0_PM_OPS &intel8x0_pm
+#else
+#define INTEL8X0_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
#define INTEL8X0_TESTBUF_SIZE 32768 /* enough large for one shot */
-static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip)
+static void intel8x0_measure_ac97_clock(struct intel8x0 *chip)
{
struct snd_pcm_substream *subs;
struct ichdev *ichdev;
unsigned long port;
- unsigned long pos, t;
- struct timeval start_time, stop_time;
+ unsigned long pos, pos1, t;
+ int civ, timeout = 1000, attempt = 1;
+ ktime_t start_time, stop_time;
if (chip->ac97_bus->clock != 48000)
return; /* specified in module option */
+ __again:
subs = chip->pcm[0]->streams[0].substream;
if (! subs || subs->dma_buffer.bytes < INTEL8X0_TESTBUF_SIZE) {
- snd_printk(KERN_WARNING "no playback buffer allocated - aborting measure ac97 clock\n");
+ dev_warn(chip->card->dev,
+ "no playback buffer allocated - aborting measure ac97 clock\n");
return;
}
ichdev = &chip->ichd[ICHD_PCMOUT];
ichdev->physbuf = subs->dma_buffer.addr;
- ichdev->size = chip->ichd[ICHD_PCMOUT].fragsize = INTEL8X0_TESTBUF_SIZE;
+ ichdev->size = ichdev->fragsize = INTEL8X0_TESTBUF_SIZE;
ichdev->substream = NULL; /* don't process interrupts */
/* set rate */
if (snd_ac97_set_rate(chip->ac97[0], AC97_PCM_FRONT_DAC_RATE, 48000) < 0) {
- snd_printk(KERN_ERR "cannot set ac97 rate: clock = %d\n", chip->ac97_bus->clock);
+ dev_err(chip->card->dev, "cannot set ac97 rate: clock = %d\n",
+ chip->ac97_bus->clock);
return;
}
snd_intel8x0_setup_periods(chip, ichdev);
@@ -2621,16 +2813,31 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip)
iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE);
iputdword(chip, ICHREG(ALI_DMACR), 1 << ichdev->ali_slot);
}
- do_gettimeofday(&start_time);
+ start_time = ktime_get();
spin_unlock_irq(&chip->reg_lock);
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;
+ do {
+ civ = igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV);
+ pos1 = igetword(chip, ichdev->reg_offset + ichdev->roff_picb);
+ if (pos1 == 0) {
+ udelay(10);
+ continue;
+ }
+ if (civ == igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV) &&
+ pos1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb))
+ break;
+ } while (timeout--);
+ if (pos1 == 0) { /* oops, this value is not reliable */
+ pos = 0;
+ } else {
+ pos = ichdev->fragsize1;
+ pos -= pos1 << ichdev->pos_shift;
+ pos += ichdev->position;
+ }
chip->in_measurement = 0;
- do_gettimeofday(&stop_time);
+ stop_time = ktime_get();
/* stop */
if (chip->device_type == DEVICE_ALI) {
iputdword(chip, ICHREG(ALI_DMACR), 1 << (ichdev->ali_slot + 16));
@@ -2645,26 +2852,69 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip)
iputbyte(chip, port + ICH_REG_OFF_CR, ICH_RESETREGS);
spin_unlock_irq(&chip->reg_lock);
- t = stop_time.tv_sec - start_time.tv_sec;
- t *= 1000000;
- t += stop_time.tv_usec - start_time.tv_usec;
- printk(KERN_INFO "%s: measured %lu usecs\n", __FUNCTION__, t);
+ if (pos == 0) {
+ dev_err(chip->card->dev,
+ "measure - unreliable DMA position..\n");
+ __retry:
+ if (attempt < 3) {
+ msleep(300);
+ attempt++;
+ goto __again;
+ }
+ goto __end;
+ }
+
+ pos /= 4;
+ t = ktime_us_delta(stop_time, start_time);
+ dev_info(chip->card->dev,
+ "%s: measured %lu usecs (%lu samples)\n", __func__, t, pos);
if (t == 0) {
- snd_printk(KERN_ERR "?? calculation error..\n");
- return;
+ dev_err(chip->card->dev, "?? calculation error..\n");
+ goto __retry;
}
- pos = (pos / 4) * 1000;
+ pos *= 1000;
pos = (pos / t) * 1000 + ((pos % t) * 1000) / t;
- if (pos < 40000 || pos >= 60000)
+ if (pos < 40000 || pos >= 60000) {
/* abnormal value. hw problem? */
- printk(KERN_INFO "intel8x0: measured clock %ld rejected\n", pos);
+ dev_info(chip->card->dev, "measured clock %ld rejected\n", pos);
+ goto __retry;
+ } else if (pos > 40500 && pos < 41500)
+ /* first exception - 41000Hz reference clock */
+ chip->ac97_bus->clock = 41000;
+ else if (pos > 43600 && pos < 44600)
+ /* second exception - 44100HZ reference clock */
+ chip->ac97_bus->clock = 44100;
else if (pos < 47500 || pos > 48500)
/* 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);
+ __end:
+ dev_info(chip->card->dev, "clocking to %d\n", chip->ac97_bus->clock);
snd_ac97_update_power(chip->ac97[0], AC97_PCM_FRONT_DAC_RATE, 0);
}
+static struct snd_pci_quirk intel8x0_clock_list[] = {
+ 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 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;
+ dev_info(chip->card->dev, "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)
@@ -2700,7 +2950,7 @@ static void snd_intel8x0_proc_read(struct snd_info_entry * entry,
chip->ac97_sdin[2]);
}
-static void __devinit snd_intel8x0_proc_init(struct intel8x0 * chip)
+static void snd_intel8x0_proc_init(struct intel8x0 *chip)
{
struct snd_info_entry *entry;
@@ -2729,10 +2979,49 @@ 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,
- struct intel8x0 ** r_intel8x0)
+static int snd_intel8x0_inside_vm(struct pci_dev *pci)
+{
+ int result = inside_vm;
+ char *msg = NULL;
+
+ /* check module parameter first (override detection) */
+ if (result >= 0) {
+ msg = result ? "enable (forced) VM" : "disable (forced) VM";
+ goto fini;
+ }
+
+ /* detect KVM and Parallels virtual environments */
+ result = kvm_para_available();
+#ifdef X86_FEATURE_HYPERVISOR
+ result = result || boot_cpu_has(X86_FEATURE_HYPERVISOR);
+#endif
+ if (!result)
+ goto fini;
+
+ /* check for known (emulated) devices */
+ if (pci->subsystem_vendor == 0x1af4 &&
+ pci->subsystem_device == 0x1100) {
+ /* KVM emulated sound, PCI SSID: 1af4:1100 */
+ msg = "enable KVM";
+ } else if (pci->subsystem_vendor == 0x1ab8) {
+ /* Parallels VM emulated sound, PCI SSID: 1ab8:xxxx */
+ msg = "enable Parallels VM";
+ } else {
+ msg = "disable (unknown or VT-d) VM";
+ result = 0;
+ }
+
+fini:
+ if (msg != NULL)
+ dev_info(&pci->dev, "%s optimization\n", msg);
+
+ return result;
+}
+
+static int snd_intel8x0_create(struct snd_card *card,
+ struct pci_dev *pci,
+ unsigned long device_type,
+ struct intel8x0 **r_intel8x0)
{
struct intel8x0 *chip;
int err;
@@ -2796,6 +3085,8 @@ static int __devinit snd_intel8x0_create(struct snd_card *card,
if (xbox)
chip->xbox = 1;
+ chip->inside_vm = snd_intel8x0_inside_vm(pci);
+
if (pci->vendor == PCI_VENDOR_ID_INTEL &&
pci->device == PCI_DEVICE_ID_INTEL_440MX)
chip->fix_nocache = 1; /* enable workaround */
@@ -2817,7 +3108,7 @@ static int __devinit snd_intel8x0_create(struct snd_card *card,
else
chip->addr = pci_iomap(pci, 0, 0);
if (!chip->addr) {
- snd_printk(KERN_ERR "AC'97 space ioremap problem\n");
+ dev_err(card->dev, "AC'97 space ioremap problem\n");
snd_intel8x0_free(chip);
return -EIO;
}
@@ -2826,7 +3117,7 @@ static int __devinit snd_intel8x0_create(struct snd_card *card,
else
chip->bmaddr = pci_iomap(pci, 1, 0);
if (!chip->bmaddr) {
- snd_printk(KERN_ERR "Controller space ioremap problem\n");
+ dev_err(card->dev, "Controller space ioremap problem\n");
snd_intel8x0_free(chip);
return -EIO;
}
@@ -2871,7 +3162,7 @@ static int __devinit snd_intel8x0_create(struct snd_card *card,
chip->bdbars_count * sizeof(u32) * ICH_MAX_FRAGS * 2,
&chip->bdbars) < 0) {
snd_intel8x0_free(chip);
- snd_printk(KERN_ERR "intel8x0: cannot allocate buffer descriptors\n");
+ dev_err(card->dev, "cannot allocate buffer descriptors\n");
return -ENOMEM;
}
/* tables must be aligned to 8 bytes here, but the kernel pages
@@ -2924,8 +3215,8 @@ static int __devinit snd_intel8x0_create(struct snd_card *card,
/* 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);
+ IRQF_SHARED, KBUILD_MODNAME, chip)) {
+ dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq);
snd_intel8x0_free(chip);
return -EBUSY;
}
@@ -2936,8 +3227,6 @@ static int __devinit snd_intel8x0_create(struct snd_card *card,
return err;
}
- snd_card_set_dev(card, &pci->dev);
-
*r_intel8x0 = chip;
return 0;
}
@@ -2945,7 +3234,7 @@ static int __devinit snd_intel8x0_create(struct snd_card *card,
static struct shortname_table {
unsigned int id;
const char *s;
-} shortnames[] __devinitdata = {
+} shortnames[] = {
{ 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" },
@@ -2971,40 +3260,42 @@ static struct shortname_table {
{ 0, NULL },
};
-static struct snd_pci_quirk spdif_aclink_defaults[] __devinitdata = {
+static struct snd_pci_quirk spdif_aclink_defaults[] = {
SND_PCI_QUIRK(0x147b, 0x1c1a, "ASUS KN8", 1),
{ } /* end */
};
/* look up white/black list for SPDIF over ac-link */
-static int __devinit check_default_spdif_aclink(struct pci_dev *pci)
+static int check_default_spdif_aclink(struct pci_dev *pci)
{
const struct snd_pci_quirk *w;
w = snd_pci_quirk_lookup(pci, spdif_aclink_defaults);
if (w) {
if (w->value)
- snd_printdd(KERN_INFO "intel8x0: Using SPDIF over "
- "AC-Link for %s\n", w->name);
+ dev_dbg(&pci->dev,
+ "Using SPDIF over AC-Link for %s\n",
+ snd_pci_quirk_name(w));
else
- snd_printdd(KERN_INFO "intel8x0: Using integrated "
- "SPDIF DMA for %s\n", w->name);
+ dev_dbg(&pci->dev,
+ "Using integrated SPDIF DMA for %s\n",
+ snd_pci_quirk_name(w));
return w->value;
}
return 0;
}
-static int __devinit snd_intel8x0_probe(struct pci_dev *pci,
- const struct pci_device_id *pci_id)
+static int snd_intel8x0_probe(struct pci_dev *pci,
+ const struct pci_device_id *pci_id)
{
struct snd_card *card;
struct intel8x0 *chip;
int err;
struct shortname_table *name;
- card = snd_card_new(index, id, THIS_MODULE, 0);
- if (card == NULL)
- return -ENOMEM;
+ err = snd_card_new(&pci->dev, index, id, THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
if (spdif_aclink < 0)
spdif_aclink = check_default_spdif_aclink(pci);
@@ -3060,8 +3351,14 @@ static int __devinit snd_intel8x0_probe(struct pci_dev *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);
@@ -3071,33 +3368,19 @@ static int __devinit snd_intel8x0_probe(struct pci_dev *pci,
return 0;
}
-static void __devexit snd_intel8x0_remove(struct pci_dev *pci)
+static void snd_intel8x0_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
- pci_set_drvdata(pci, NULL);
}
-static struct pci_driver driver = {
- .name = "Intel ICH",
+static struct pci_driver intel8x0_driver = {
+ .name = KBUILD_MODNAME,
.id_table = snd_intel8x0_ids,
.probe = snd_intel8x0_probe,
- .remove = __devexit_p(snd_intel8x0_remove),
-#ifdef CONFIG_PM
- .suspend = intel8x0_suspend,
- .resume = intel8x0_resume,
-#endif
+ .remove = snd_intel8x0_remove,
+ .driver = {
+ .pm = INTEL8X0_PM_OPS,
+ },
};
-
-static int __init alsa_card_intel8x0_init(void)
-{
- return pci_register_driver(&driver);
-}
-
-static void __exit alsa_card_intel8x0_exit(void)
-{
- pci_unregister_driver(&driver);
-}
-
-module_init(alsa_card_intel8x0_init)
-module_exit(alsa_card_intel8x0_exit)
+module_pci_driver(intel8x0_driver);