--- /dev/null
+From 56385a12d9bb9e173751f74b6c430742018cafc0 Mon Sep 17 00:00:00 2001
+From: Jaroslav Kysela <perex@perex.cz>
+Date: Wed, 18 Aug 2010 14:08:17 +0200
+Subject: ALSA: emu10k1 - delay the PCM interrupts (add pcm_irq_delay parameter)
+
+From: Jaroslav Kysela <perex@perex.cz>
+
+commit 56385a12d9bb9e173751f74b6c430742018cafc0 upstream.
+
+With some hardware combinations, the PCM interrupts are acknowledged
+before the period boundary from the emu10k1 chip. The midlevel PCM code
+gets confused and the playback stream is interrupted.
+
+It seems that the interrupt processing shift by 2 samples is enough
+to fix this issue. This default value does not harm other,
+non-affected hardware.
+
+More information: Kernel bugzilla bug#16300
+
+[A copmile warning fixed by tiwai]
+
+Signed-off-by: Jaroslav Kysela <perex@perex.cz>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ include/sound/emu10k1.h | 1 +
+ sound/core/pcm_native.c | 4 ++++
+ sound/pci/emu10k1/emu10k1.c | 4 ++++
+ sound/pci/emu10k1/emupcm.c | 30 ++++++++++++++++++++++++++----
+ sound/pci/emu10k1/memory.c | 4 +++-
+ 5 files changed, 38 insertions(+), 5 deletions(-)
+
+--- a/include/sound/emu10k1.h
++++ b/include/sound/emu10k1.h
+@@ -1707,6 +1707,7 @@ struct snd_emu10k1 {
+ unsigned int card_type; /* EMU10K1_CARD_* */
+ unsigned int ecard_ctrl; /* ecard control bits */
+ unsigned long dma_mask; /* PCI DMA mask */
++ unsigned int delay_pcm_irq; /* in samples */
+ int max_cache_pages; /* max memory size / PAGE_SIZE */
+ struct snd_dma_buffer silent_page; /* silent page */
+ struct snd_dma_buffer ptb_pages; /* page table pages */
+--- a/sound/core/pcm_native.c
++++ b/sound/core/pcm_native.c
+@@ -972,6 +972,10 @@ static int snd_pcm_do_pause(struct snd_p
+ {
+ if (substream->runtime->trigger_master != substream)
+ return 0;
++ /* some drivers might use hw_ptr to recover from the pause -
++ update the hw_ptr now */
++ if (push)
++ snd_pcm_update_hw_ptr(substream);
+ /* The jiffies check in snd_pcm_update_hw_ptr*() is done by
+ * a delta betwen the current jiffies, this gives a large enough
+ * delta, effectively to skip the check once.
+--- a/sound/pci/emu10k1/emu10k1.c
++++ b/sound/pci/emu10k1/emu10k1.c
+@@ -52,6 +52,7 @@ static int max_synth_voices[SNDRV_CARDS]
+ static int max_buffer_size[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 128};
+ static int enable_ir[SNDRV_CARDS];
+ static uint subsystem[SNDRV_CARDS]; /* Force card subsystem model */
++static uint delay_pcm_irq[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
+
+ module_param_array(index, int, NULL, 0444);
+ MODULE_PARM_DESC(index, "Index value for the EMU10K1 soundcard.");
+@@ -73,6 +74,8 @@ module_param_array(enable_ir, bool, NULL
+ MODULE_PARM_DESC(enable_ir, "Enable IR.");
+ module_param_array(subsystem, uint, NULL, 0444);
+ MODULE_PARM_DESC(subsystem, "Force card subsystem model.");
++module_param_array(delay_pcm_irq, uint, NULL, 0444);
++MODULE_PARM_DESC(delay_pcm_irq, "Delay PCM interrupt by specified number of samples (default 0).");
+ /*
+ * Class 0401: 1102:0008 (rev 00) Subsystem: 1102:1001 -> Audigy2 Value Model:SB0400
+ */
+@@ -127,6 +130,7 @@ static int __devinit snd_card_emu10k1_pr
+ &emu)) < 0)
+ goto error;
+ card->private_data = emu;
++ emu->delay_pcm_irq = delay_pcm_irq[dev] & 0x1f;
+ if ((err = snd_emu10k1_pcm(emu, 0, NULL)) < 0)
+ goto error;
+ if ((err = snd_emu10k1_pcm_mic(emu, 1, NULL)) < 0)
+--- a/sound/pci/emu10k1/emupcm.c
++++ b/sound/pci/emu10k1/emupcm.c
+@@ -332,7 +332,7 @@ static void snd_emu10k1_pcm_init_voice(s
+ evoice->epcm->ccca_start_addr = start_addr + ccis;
+ if (extra) {
+ start_addr += ccis;
+- end_addr += ccis;
++ end_addr += ccis + emu->delay_pcm_irq;
+ }
+ if (stereo && !extra) {
+ snd_emu10k1_ptr_write(emu, CPF, voice, CPF_STEREO_MASK);
+@@ -360,7 +360,9 @@ static void snd_emu10k1_pcm_init_voice(s
+ /* Assumption that PT is already 0 so no harm overwriting */
+ snd_emu10k1_ptr_write(emu, PTRX, voice, (send_amount[0] << 8) | send_amount[1]);
+ snd_emu10k1_ptr_write(emu, DSL, voice, end_addr | (send_amount[3] << 24));
+- snd_emu10k1_ptr_write(emu, PSST, voice, start_addr | (send_amount[2] << 24));
++ snd_emu10k1_ptr_write(emu, PSST, voice,
++ (start_addr + (extra ? emu->delay_pcm_irq : 0)) |
++ (send_amount[2] << 24));
+ if (emu->card_capabilities->emu_model)
+ pitch_target = PITCH_48000; /* Disable interpolators on emu1010 card */
+ else
+@@ -732,6 +734,23 @@ static void snd_emu10k1_playback_stop_vo
+ snd_emu10k1_ptr_write(emu, IP, voice, 0);
+ }
+
++static inline void snd_emu10k1_playback_mangle_extra(struct snd_emu10k1 *emu,
++ struct snd_emu10k1_pcm *epcm,
++ struct snd_pcm_substream *substream,
++ struct snd_pcm_runtime *runtime)
++{
++ unsigned int ptr, period_pos;
++
++ /* try to sychronize the current position for the interrupt
++ source voice */
++ period_pos = runtime->status->hw_ptr - runtime->hw_ptr_interrupt;
++ period_pos %= runtime->period_size;
++ ptr = snd_emu10k1_ptr_read(emu, CCCA, epcm->extra->number);
++ ptr &= ~0x00ffffff;
++ ptr |= epcm->ccca_start_addr + period_pos;
++ snd_emu10k1_ptr_write(emu, CCCA, epcm->extra->number, ptr);
++}
++
+ static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream,
+ int cmd)
+ {
+@@ -753,6 +772,8 @@ static int snd_emu10k1_playback_trigger(
+ /* follow thru */
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ case SNDRV_PCM_TRIGGER_RESUME:
++ if (cmd == SNDRV_PCM_TRIGGER_PAUSE_RELEASE)
++ snd_emu10k1_playback_mangle_extra(emu, epcm, substream, runtime);
+ mix = &emu->pcm_mixer[substream->number];
+ snd_emu10k1_playback_prepare_voice(emu, epcm->voices[0], 1, 0, mix);
+ snd_emu10k1_playback_prepare_voice(emu, epcm->voices[1], 0, 0, mix);
+@@ -869,8 +890,9 @@ static snd_pcm_uframes_t snd_emu10k1_pla
+ #endif
+ /*
+ printk(KERN_DEBUG
+- "ptr = 0x%x, buffer_size = 0x%x, period_size = 0x%x\n",
+- ptr, runtime->buffer_size, runtime->period_size);
++ "ptr = 0x%lx, buffer_size = 0x%lx, period_size = 0x%lx\n",
++ (long)ptr, (long)runtime->buffer_size,
++ (long)runtime->period_size);
+ */
+ return ptr;
+ }
+--- a/sound/pci/emu10k1/memory.c
++++ b/sound/pci/emu10k1/memory.c
+@@ -309,8 +309,10 @@ snd_emu10k1_alloc_pages(struct snd_emu10
+ if (snd_BUG_ON(!hdr))
+ return NULL;
+
++ idx = runtime->period_size >= runtime->buffer_size ?
++ (emu->delay_pcm_irq * 2) : 0;
+ mutex_lock(&hdr->block_mutex);
+- blk = search_empty(emu, runtime->dma_bytes);
++ blk = search_empty(emu, runtime->dma_bytes + idx);
+ if (blk == NULL) {
+ mutex_unlock(&hdr->block_mutex);
+ return NULL;
--- /dev/null
+From 4f0ed9a51bc8ef16c2589112fdb110479e4b0df1 Mon Sep 17 00:00:00 2001
+From: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Date: Fri, 6 Aug 2010 17:57:12 +0100
+Subject: ASoC: Fix inverted mute controls for WM8580
+
+From: Mark Brown <broonie@opensource.wolfsonmicro.com>
+
+commit 4f0ed9a51bc8ef16c2589112fdb110479e4b0df1 upstream.
+
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ sound/soc/codecs/wm8580.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/sound/soc/codecs/wm8580.c
++++ b/sound/soc/codecs/wm8580.c
+@@ -268,9 +268,9 @@ SOC_DOUBLE("DAC2 Invert Switch", WM8580_
+ SOC_DOUBLE("DAC3 Invert Switch", WM8580_DAC_CONTROL4, 4, 5, 1, 0),
+
+ SOC_SINGLE("DAC ZC Switch", WM8580_DAC_CONTROL5, 5, 1, 0),
+-SOC_SINGLE("DAC1 Switch", WM8580_DAC_CONTROL5, 0, 1, 0),
+-SOC_SINGLE("DAC2 Switch", WM8580_DAC_CONTROL5, 1, 1, 0),
+-SOC_SINGLE("DAC3 Switch", WM8580_DAC_CONTROL5, 2, 1, 0),
++SOC_SINGLE("DAC1 Switch", WM8580_DAC_CONTROL5, 0, 1, 1),
++SOC_SINGLE("DAC2 Switch", WM8580_DAC_CONTROL5, 1, 1, 1),
++SOC_SINGLE("DAC3 Switch", WM8580_DAC_CONTROL5, 2, 1, 1),
+
+ SOC_DOUBLE("ADC Mute Switch", WM8580_ADC_CONTROL1, 0, 1, 1, 0),
+ SOC_SINGLE("ADC High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0),
--- /dev/null
+From d862b13bc8cbab9692fbe0ef44c40d0488b81af1 Mon Sep 17 00:00:00 2001
+From: Maxim Levitsky <maximlevitsky@gmail.com>
+Date: Wed, 11 Aug 2010 14:17:52 -0700
+Subject: memstick: fix hangs on unexpected device removal in mspro_blk
+
+From: Maxim Levitsky <maximlevitsky@gmail.com>
+
+commit d862b13bc8cbab9692fbe0ef44c40d0488b81af1 upstream.
+
+mspro_block_remove() is called from detect thread that first calls the
+mspro_block_stop(), which stops the request queue. If we call
+del_gendisk() with the queue stopped we get a deadlock.
+
+Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com>
+Cc: Alex Dubov <oakad@yahoo.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/memstick/core/mspro_block.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/memstick/core/mspro_block.c
++++ b/drivers/memstick/core/mspro_block.c
+@@ -1330,13 +1330,14 @@ static void mspro_block_remove(struct me
+ struct mspro_block_data *msb = memstick_get_drvdata(card);
+ unsigned long flags;
+
+- del_gendisk(msb->disk);
+- dev_dbg(&card->dev, "mspro block remove\n");
+ spin_lock_irqsave(&msb->q_lock, flags);
+ msb->eject = 1;
+ blk_start_queue(msb->queue);
+ spin_unlock_irqrestore(&msb->q_lock, flags);
+
++ del_gendisk(msb->disk);
++ dev_dbg(&card->dev, "mspro block remove\n");
++
+ blk_cleanup_queue(msb->queue);
+ msb->queue = NULL;
+