aboutsummaryrefslogtreecommitdiff
path: root/sound/pci/hda
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda')
-rw-r--r--sound/pci/hda/hda_codec.c6
-rw-r--r--sound/pci/hda/hda_intel.c39
-rw-r--r--sound/pci/hda/patch_conexant.c21
-rw-r--r--sound/pci/hda/patch_realtek.c5
-rw-r--r--sound/pci/hda/patch_sigmatel.c27
5 files changed, 72 insertions, 26 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index a4e5e595211..fd6e6f337d1 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -2250,7 +2250,11 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid,
err = bus->ops.command(bus, res);
if (!err) {
struct hda_cache_head *c;
- u32 key = build_cmd_cache_key(nid, verb);
+ u32 key;
+ /* parm may contain the verb stuff for get/set amp */
+ verb = verb | (parm >> 8);
+ parm &= 0xff;
+ key = build_cmd_cache_key(nid, verb);
c = get_alloc_hash(&codec->cmd_cache, key);
if (c)
c->val = parm;
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 7ba8db5d4c4..bc882f8f163 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -312,6 +312,9 @@ struct azx_dev {
unsigned int period_bytes; /* size of the period in bytes */
unsigned int frags; /* number for period in the play buffer */
unsigned int fifo_size; /* FIFO size */
+ unsigned int start_flag: 1; /* stream full start flag */
+ unsigned long start_jiffies; /* start + minimum jiffies */
+ unsigned long min_jiffies; /* minimum jiffies before position is valid */
void __iomem *sd_addr; /* stream descriptor pointer */
@@ -330,7 +333,6 @@ struct azx_dev {
unsigned int opened :1;
unsigned int running :1;
unsigned int irq_pending :1;
- unsigned int irq_ignore :1;
/*
* For VIA:
* A flag to ensure DMA position is 0
@@ -975,7 +977,7 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
struct azx *chip = dev_id;
struct azx_dev *azx_dev;
u32 status;
- int i;
+ int i, ok;
spin_lock(&chip->reg_lock);
@@ -991,18 +993,14 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK);
if (!azx_dev->substream || !azx_dev->running)
continue;
- /* ignore the first dummy IRQ (due to pos_adj) */
- if (azx_dev->irq_ignore) {
- azx_dev->irq_ignore = 0;
- continue;
- }
/* check whether this IRQ is really acceptable */
- if (azx_position_ok(chip, azx_dev)) {
+ ok = azx_position_ok(chip, azx_dev);
+ if (ok == 1) {
azx_dev->irq_pending = 0;
spin_unlock(&chip->reg_lock);
snd_pcm_period_elapsed(azx_dev->substream);
spin_lock(&chip->reg_lock);
- } else if (chip->bus && chip->bus->workq) {
+ } else if (ok == 0 && chip->bus && chip->bus->workq) {
/* bogus IRQ, process it later */
azx_dev->irq_pending = 1;
queue_work(chip->bus->workq,
@@ -1088,7 +1086,6 @@ static int azx_setup_periods(struct azx *chip,
bdl = (u32 *)azx_dev->bdl.area;
ofs = 0;
azx_dev->frags = 0;
- azx_dev->irq_ignore = 0;
pos_adj = bdl_pos_adj[chip->dev_index];
if (pos_adj > 0) {
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -1109,7 +1106,6 @@ static int azx_setup_periods(struct azx *chip,
&bdl, ofs, pos_adj, 1);
if (ofs < 0)
goto error;
- azx_dev->irq_ignore = 1;
}
} else
pos_adj = 0;
@@ -1155,6 +1151,9 @@ static void azx_stream_reset(struct azx *chip, struct azx_dev *azx_dev)
while (((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) &&
--timeout)
;
+
+ /* reset first position - may not be synced with hw at this time */
+ *azx_dev->posbuf = 0;
}
/*
@@ -1409,7 +1408,6 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
snd_pcm_set_sync(substream);
mutex_unlock(&chip->open_mutex);
- azx_stream_reset(chip, azx_dev);
return 0;
}
@@ -1474,6 +1472,7 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
unsigned int bufsize, period_bytes, format_val;
int err;
+ azx_stream_reset(chip, azx_dev);
format_val = snd_hda_calc_stream_format(runtime->rate,
runtime->channels,
runtime->format,
@@ -1502,6 +1501,8 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
return err;
}
+ azx_dev->min_jiffies = (runtime->period_size * HZ) /
+ (runtime->rate * 2);
azx_setup_controller(chip, azx_dev);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1;
@@ -1518,13 +1519,14 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
struct azx *chip = apcm->chip;
struct azx_dev *azx_dev;
struct snd_pcm_substream *s;
- int start, nsync = 0, sbits = 0;
+ int rstart = 0, start, nsync = 0, sbits = 0;
int nwait, timeout;
switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ rstart = 1;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_START:
start = 1;
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
@@ -1554,6 +1556,10 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
if (s->pcm->card != substream->pcm->card)
continue;
azx_dev = get_azx_dev(s);
+ if (rstart) {
+ azx_dev->start_flag = 1;
+ azx_dev->start_jiffies = jiffies + azx_dev->min_jiffies;
+ }
if (start)
azx_stream_start(chip, azx_dev);
else
@@ -1703,6 +1709,11 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
{
unsigned int pos;
+ if (azx_dev->start_flag &&
+ time_before_eq(jiffies, azx_dev->start_jiffies))
+ return -1; /* bogus (too early) interrupt */
+ azx_dev->start_flag = 0;
+
pos = azx_get_position(chip, azx_dev);
if (chip->position_fix == POS_FIX_AUTO) {
if (!pos) {
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 1f2ad76ca94..56ce19e68cb 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -350,12 +350,20 @@ static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol,
}
#ifdef CONFIG_SND_JACK
+static void conexant_free_jack_priv(struct snd_jack *jack)
+{
+ struct conexant_jack *jacks = jack->private_data;
+ jacks->nid = 0;
+ jacks->jack = NULL;
+}
+
static int conexant_add_jack(struct hda_codec *codec,
hda_nid_t nid, int type)
{
struct conexant_spec *spec;
struct conexant_jack *jack;
const char *name;
+ int err;
spec = codec->spec;
snd_array_init(&spec->jacks, sizeof(*jack), 32);
@@ -368,7 +376,12 @@ static int conexant_add_jack(struct hda_codec *codec,
jack->nid = nid;
jack->type = type;
- return snd_jack_new(codec->bus->card, name, type, &jack->jack);
+ err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
+ if (err < 0)
+ return err;
+ jack->jack->private_data = jack;
+ jack->jack->private_free = conexant_free_jack_priv;
+ return 0;
}
static void conexant_report_jack(struct hda_codec *codec, hda_nid_t nid)
@@ -455,8 +468,10 @@ static void conexant_free(struct hda_codec *codec)
if (spec->jacks.list) {
struct conexant_jack *jacks = spec->jacks.list;
int i;
- for (i = 0; i < spec->jacks.used; i++)
- snd_device_free(codec->bus->card, &jacks[i].jack);
+ for (i = 0; i < spec->jacks.used; i++, jacks++) {
+ if (jacks->jack)
+ snd_device_free(codec->bus->card, jacks->jack);
+ }
snd_array_free(&spec->jacks);
}
#endif
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index f35e58a2d92..6ed787eedd0 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -8742,10 +8742,9 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD),
SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch),
SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION),
- SND_PCI_QUIRK(0x1734, 0x1107, "FSC AMILO Xi2550",
+ SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx",
ALC883_FUJITSU_PI2515),
- SND_PCI_QUIRK(0x1734, 0x1108, "Fujitsu AMILO Pi2515", ALC883_FUJITSU_PI2515),
- SND_PCI_QUIRK(0x1734, 0x113d, "Fujitsu AMILO Xa3530",
+ SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1130, "Fujitsu AMILO Xa35xx",
ALC888_FUJITSU_XA3530),
SND_PCI_QUIRK(0x17aa, 0x101e, "Lenovo 101e", ALC883_LENOVO_101E_2ch),
SND_PCI_QUIRK(0x17aa, 0x2085, "Lenovo NB0763", ALC883_LENOVO_NB0763),
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 61996a2f45d..ce30b459aee 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -3851,6 +3851,15 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
}
+#ifdef CONFIG_SND_JACK
+static void stac92xx_free_jack_priv(struct snd_jack *jack)
+{
+ struct sigmatel_jack *jacks = jack->private_data;
+ jacks->nid = 0;
+ jacks->jack = NULL;
+}
+#endif
+
static int stac92xx_add_jack(struct hda_codec *codec,
hda_nid_t nid, int type)
{
@@ -3860,6 +3869,7 @@ static int stac92xx_add_jack(struct hda_codec *codec,
int def_conf = snd_hda_codec_get_pincfg(codec, nid);
int connectivity = get_defcfg_connect(def_conf);
char name[32];
+ int err;
if (connectivity && connectivity != AC_JACK_PORT_FIXED)
return 0;
@@ -3876,10 +3886,15 @@ static int stac92xx_add_jack(struct hda_codec *codec,
snd_hda_get_jack_connectivity(def_conf),
snd_hda_get_jack_location(def_conf));
- return snd_jack_new(codec->bus->card, name, type, &jack->jack);
-#else
- return 0;
+ err = snd_jack_new(codec->bus->card, name, type, &jack->jack);
+ if (err < 0) {
+ jack->nid = 0;
+ return err;
+ }
+ jack->jack->private_data = jack;
+ jack->jack->private_free = stac92xx_free_jack_priv;
#endif
+ return 0;
}
static int stac_add_event(struct sigmatel_spec *spec, hda_nid_t nid,
@@ -4138,8 +4153,10 @@ static void stac92xx_free_jacks(struct hda_codec *codec)
if (!codec->bus->shutdown && spec->jacks.list) {
struct sigmatel_jack *jacks = spec->jacks.list;
int i;
- for (i = 0; i < spec->jacks.used; i++)
- snd_device_free(codec->bus->card, &jacks[i].jack);
+ for (i = 0; i < spec->jacks.used; i++, jacks++) {
+ if (jacks->jack)
+ snd_device_free(codec->bus->card, jacks->jack);
+ }
}
snd_array_free(&spec->jacks);
#endif