]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.0 patches
authorGreg Kroah-Hartman <gregkh@suse.de>
Wed, 2 Nov 2011 16:29:08 +0000 (09:29 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 2 Nov 2011 16:29:08 +0000 (09:29 -0700)
25 files changed:
queue-3.0/asoc-ak4535-fixup-cache-register-table.patch [new file with mode: 0644]
queue-3.0/asoc-ak4642-fixup-cache-register-table.patch [new file with mode: 0644]
queue-3.0/asoc-fix-a-bug-in-wm8962-dsp_a-and-dsp_b-settings.patch [new file with mode: 0644]
queue-3.0/asoc-remove-direct-register-cache-accesses-from-wm8962.patch [new file with mode: 0644]
queue-3.0/asoc-wm8741-fix-setting-interface-format-for-dsp-modes.patch [new file with mode: 0644]
queue-3.0/asoc-wm8940-properly-set-codec-dapm.bias_level.patch [new file with mode: 0644]
queue-3.0/asoc-wm8994-use-snd_soc_dapm_aif_out-for-aif3-capture.patch [new file with mode: 0644]
queue-3.0/carminefb-fix-module-parameters-permissions.patch [new file with mode: 0644]
queue-3.0/ccwgroup-move-attributes-to-attribute-group.patch [new file with mode: 0644]
queue-3.0/dib0700-protect-the-dib0700-buffer-access.patch [new file with mode: 0644]
queue-3.0/dibcom-protect-the-i2c-bufer-access.patch [new file with mode: 0644]
queue-3.0/fb-avoid-possible-deadlock-caused-by-fb_set_suspend.patch [new file with mode: 0644]
queue-3.0/fb-sh-mobile-fix-deadlock-risk-between-lock_fb_info-and-console_lock.patch [new file with mode: 0644]
queue-3.0/io-mapping-ensure-io_mapping_map_atomic-_is_-atomic.patch [new file with mode: 0644]
queue-3.0/iommu-amd-fix-wrong-shift-direction.patch [new file with mode: 0644]
queue-3.0/kvm-s390-check-cpu_id-prior-to-using-it.patch [new file with mode: 0644]
queue-3.0/memory-leak-with-rcu_table_free.patch [new file with mode: 0644]
queue-3.0/proc-self-numa_maps-restore-huge-tag-for-hugetlb-vmas.patch [new file with mode: 0644]
queue-3.0/series
queue-3.0/tuner_xc2028-allow-selection-of-the-frequency-adjustment-code-for-xc3028.patch [new file with mode: 0644]
queue-3.0/user-per-registers-vs.-ptrace-single-stepping.patch [new file with mode: 0644]
queue-3.0/uvcvideo-set-alternate-setting-0-on-resume-if-the-bus-has-been-reset.patch [new file with mode: 0644]
queue-3.0/viafb-improve-pitch-handling.patch [new file with mode: 0644]
queue-3.0/viafb-use-display-information-in-info-not-in-var-for.patch [new file with mode: 0644]
queue-3.0/wmi-properly-cleanup-devices-to-avoid-crashes.patch [new file with mode: 0644]

diff --git a/queue-3.0/asoc-ak4535-fixup-cache-register-table.patch b/queue-3.0/asoc-ak4535-fixup-cache-register-table.patch
new file mode 100644 (file)
index 0000000..e6e71c2
--- /dev/null
@@ -0,0 +1,38 @@
+From 7c04241acbdaf97f1448dcccd27ea0fcd1a57684 Mon Sep 17 00:00:00 2001
+From: Axel Lin <axel.lin@gmail.com>
+Date: Thu, 13 Oct 2011 17:17:06 +0800
+Subject: ASoC: ak4535: fixup cache register table
+
+From: Axel Lin <axel.lin@gmail.com>
+
+commit 7c04241acbdaf97f1448dcccd27ea0fcd1a57684 upstream.
+
+ak4535_reg should be 8bit, but cache table is defined as 16bit.
+
+Signed-off-by: Axel Lin <axel.lin@gmail.com>
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ sound/soc/codecs/ak4535.c |   10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/sound/soc/codecs/ak4535.c
++++ b/sound/soc/codecs/ak4535.c
+@@ -40,11 +40,11 @@ struct ak4535_priv {
+ /*
+  * ak4535 register cache
+  */
+-static const u16 ak4535_reg[AK4535_CACHEREGNUM] = {
+-    0x0000, 0x0080, 0x0000, 0x0003,
+-    0x0002, 0x0000, 0x0011, 0x0001,
+-    0x0000, 0x0040, 0x0036, 0x0010,
+-    0x0000, 0x0000, 0x0057, 0x0000,
++static const u8 ak4535_reg[AK4535_CACHEREGNUM] = {
++      0x00, 0x80, 0x00, 0x03,
++      0x02, 0x00, 0x11, 0x01,
++      0x00, 0x40, 0x36, 0x10,
++      0x00, 0x00, 0x57, 0x00,
+ };
+ /*
diff --git a/queue-3.0/asoc-ak4642-fixup-cache-register-table.patch b/queue-3.0/asoc-ak4642-fixup-cache-register-table.patch
new file mode 100644 (file)
index 0000000..f16bb81
--- /dev/null
@@ -0,0 +1,51 @@
+From 19b115e523208a926813751aac8934cf3fc6085e Mon Sep 17 00:00:00 2001
+From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+Date: Thu, 13 Oct 2011 02:03:54 -0700
+Subject: ASoC: ak4642: fixup cache register table
+
+From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+
+commit 19b115e523208a926813751aac8934cf3fc6085e upstream.
+
+ak4642 register was 8bit, but cache table was defined as 16bit.
+ak4642 doesn't work correctry without this patch.
+
+Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ sound/soc/codecs/ak4642.c |   22 +++++++++++-----------
+ 1 file changed, 11 insertions(+), 11 deletions(-)
+
+--- a/sound/soc/codecs/ak4642.c
++++ b/sound/soc/codecs/ak4642.c
+@@ -162,17 +162,17 @@ struct ak4642_priv {
+ /*
+  * ak4642 register cache
+  */
+-static const u16 ak4642_reg[AK4642_CACHEREGNUM] = {
+-      0x0000, 0x0000, 0x0001, 0x0000,
+-      0x0002, 0x0000, 0x0000, 0x0000,
+-      0x00e1, 0x00e1, 0x0018, 0x0000,
+-      0x00e1, 0x0018, 0x0011, 0x0008,
+-      0x0000, 0x0000, 0x0000, 0x0000,
+-      0x0000, 0x0000, 0x0000, 0x0000,
+-      0x0000, 0x0000, 0x0000, 0x0000,
+-      0x0000, 0x0000, 0x0000, 0x0000,
+-      0x0000, 0x0000, 0x0000, 0x0000,
+-      0x0000,
++static const u8 ak4642_reg[AK4642_CACHEREGNUM] = {
++      0x00, 0x00, 0x01, 0x00,
++      0x02, 0x00, 0x00, 0x00,
++      0xe1, 0xe1, 0x18, 0x00,
++      0xe1, 0x18, 0x11, 0x08,
++      0x00, 0x00, 0x00, 0x00,
++      0x00, 0x00, 0x00, 0x00,
++      0x00, 0x00, 0x00, 0x00,
++      0x00, 0x00, 0x00, 0x00,
++      0x00, 0x00, 0x00, 0x00,
++      0x00,
+ };
+ /*
diff --git a/queue-3.0/asoc-fix-a-bug-in-wm8962-dsp_a-and-dsp_b-settings.patch b/queue-3.0/asoc-fix-a-bug-in-wm8962-dsp_a-and-dsp_b-settings.patch
new file mode 100644 (file)
index 0000000..b248db3
--- /dev/null
@@ -0,0 +1,31 @@
+From fbc7c62a3ff831aef24894b7982cd1adb2b7e070 Mon Sep 17 00:00:00 2001
+From: Susan Gao <sgao@opensource.wolfsonmicro.com>
+Date: Thu, 29 Sep 2011 11:08:18 +0100
+Subject: ASoC: Fix a bug in WM8962 DSP_A and DSP_B settings
+
+From: Susan Gao <sgao@opensource.wolfsonmicro.com>
+
+commit fbc7c62a3ff831aef24894b7982cd1adb2b7e070 upstream.
+
+Signed-off-by: Susan Gao <sgao@opensource.wolfsonmicro.com>
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmico.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ sound/soc/codecs/wm8962.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/sound/soc/codecs/wm8962.c
++++ b/sound/soc/codecs/wm8962.c
+@@ -3028,9 +3028,9 @@ static int wm8962_set_dai_fmt(struct snd
+       int aif0 = 0;
+       switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+-      case SND_SOC_DAIFMT_DSP_A:
+-              aif0 |= WM8962_LRCLK_INV;
+       case SND_SOC_DAIFMT_DSP_B:
++              aif0 |= WM8962_LRCLK_INV | 3;
++      case SND_SOC_DAIFMT_DSP_A:
+               aif0 |= 3;
+               switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
diff --git a/queue-3.0/asoc-remove-direct-register-cache-accesses-from-wm8962.patch b/queue-3.0/asoc-remove-direct-register-cache-accesses-from-wm8962.patch
new file mode 100644 (file)
index 0000000..40e7f00
--- /dev/null
@@ -0,0 +1,72 @@
+From 38f3f31a0a797bdbcc0cdb12553bbecc2f9a91c4 Mon Sep 17 00:00:00 2001
+From: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Date: Fri, 23 Sep 2011 21:26:33 +0100
+Subject: ASoC: Remove direct register cache accesses from WM8962 driver
+
+From: Mark Brown <broonie@opensource.wolfsonmicro.com>
+
+commit 38f3f31a0a797bdbcc0cdb12553bbecc2f9a91c4 upstream.
+
+Also fix return values for speaker switch updates.
+
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ sound/soc/codecs/wm8962.c |   21 +++++++++++----------
+ 1 file changed, 11 insertions(+), 10 deletions(-)
+
+--- a/sound/soc/codecs/wm8962.c
++++ b/sound/soc/codecs/wm8962.c
+@@ -2018,7 +2018,6 @@ static int wm8962_put_spk_sw(struct snd_
+                           struct snd_ctl_elem_value *ucontrol)
+ {
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+-      u16 *reg_cache = codec->reg_cache;
+       int ret;
+       /* Apply the update (if any) */
+@@ -2027,16 +2026,19 @@ static int wm8962_put_spk_sw(struct snd_
+               return 0;
+       /* If the left PGA is enabled hit that VU bit... */
+-      if (reg_cache[WM8962_PWR_MGMT_2] & WM8962_SPKOUTL_PGA_ENA)
+-              return snd_soc_write(codec, WM8962_SPKOUTL_VOLUME,
+-                                   reg_cache[WM8962_SPKOUTL_VOLUME]);
++      ret = snd_soc_read(codec, WM8962_PWR_MGMT_2);
++      if (ret & WM8962_SPKOUTL_PGA_ENA) {
++              snd_soc_write(codec, WM8962_SPKOUTL_VOLUME,
++                            snd_soc_read(codec, WM8962_SPKOUTL_VOLUME));
++              return 1;
++      }
+       /* ...otherwise the right.  The VU is stereo. */
+-      if (reg_cache[WM8962_PWR_MGMT_2] & WM8962_SPKOUTR_PGA_ENA)
+-              return snd_soc_write(codec, WM8962_SPKOUTR_VOLUME,
+-                                   reg_cache[WM8962_SPKOUTR_VOLUME]);
++      if (ret & WM8962_SPKOUTR_PGA_ENA)
++              snd_soc_write(codec, WM8962_SPKOUTR_VOLUME,
++                            snd_soc_read(codec, WM8962_SPKOUTR_VOLUME));
+-      return 0;
++      return 1;
+ }
+ static const char *cap_hpf_mode_text[] = {
+@@ -2336,7 +2338,6 @@ static int out_pga_event(struct snd_soc_
+                        struct snd_kcontrol *kcontrol, int event)
+ {
+       struct snd_soc_codec *codec = w->codec;
+-      u16 *reg_cache = codec->reg_cache;
+       int reg;
+       switch (w->shift) {
+@@ -2359,7 +2360,7 @@ static int out_pga_event(struct snd_soc_
+       switch (event) {
+       case SND_SOC_DAPM_POST_PMU:
+-              return snd_soc_write(codec, reg, reg_cache[reg]);
++              return snd_soc_write(codec, reg, snd_soc_read(codec, reg));
+       default:
+               BUG();
+               return -EINVAL;
diff --git a/queue-3.0/asoc-wm8741-fix-setting-interface-format-for-dsp-modes.patch b/queue-3.0/asoc-wm8741-fix-setting-interface-format-for-dsp-modes.patch
new file mode 100644 (file)
index 0000000..6e8ad36
--- /dev/null
@@ -0,0 +1,48 @@
+From 3a340104fad6ecbea5ad6792a2ea855f0507a6e0 Mon Sep 17 00:00:00 2001
+From: Axel Lin <axel.lin@gmail.com>
+Date: Mon, 17 Oct 2011 20:14:56 +0800
+Subject: ASoC: wm8741: Fix setting interface format for DSP modes
+
+From: Axel Lin <axel.lin@gmail.com>
+
+commit 3a340104fad6ecbea5ad6792a2ea855f0507a6e0 upstream.
+
+According to the datasheet:
+Format Control (05h)
+BITS[3:2]
+        FMT[1:0] Audio data format selection
+                00 = right justified mode
+                01 = left justified mode
+                10 = I2S mode
+                11 = DSP mode
+BIT[4]  LRP Polarity selec for LRCLK/DSP mode select
+                0 = normal LRCLK poalrity/DSP mode A
+                1 = inverted LRCLK poarity/DSP mode B
+
+For SND_SOC_DAIFMT_DSP_A, we should set 0x000C instead of 0x0003.
+For SND_SOC_DAIFMT_DSP_B, we should set 0x001C instead of 0x0013.
+
+Signed-off-by: Axel Lin <axel.lin@gmail.com>
+Acked-by: Liam Girdwood <lrg@ti.com>
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ sound/soc/codecs/wm8741.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/sound/soc/codecs/wm8741.c
++++ b/sound/soc/codecs/wm8741.c
+@@ -337,10 +337,10 @@ static int wm8741_set_dai_fmt(struct snd
+               iface |= 0x0004;
+               break;
+       case SND_SOC_DAIFMT_DSP_A:
+-              iface |= 0x0003;
++              iface |= 0x000C;
+               break;
+       case SND_SOC_DAIFMT_DSP_B:
+-              iface |= 0x0013;
++              iface |= 0x001C;
+               break;
+       default:
+               return -EINVAL;
diff --git a/queue-3.0/asoc-wm8940-properly-set-codec-dapm.bias_level.patch b/queue-3.0/asoc-wm8940-properly-set-codec-dapm.bias_level.patch
new file mode 100644 (file)
index 0000000..fd0d167
--- /dev/null
@@ -0,0 +1,29 @@
+From 5927f94700e860ae27ff24e7f3bc9e4f7b9922eb Mon Sep 17 00:00:00 2001
+From: Axel Lin <axel.lin@gmail.com>
+Date: Wed, 26 Oct 2011 09:53:41 +0800
+Subject: ASoC: wm8940: Properly set codec->dapm.bias_level
+
+From: Axel Lin <axel.lin@gmail.com>
+
+commit 5927f94700e860ae27ff24e7f3bc9e4f7b9922eb upstream.
+
+Reported-by: Chris Paulson-Ellis <chris@edesix.com>
+Signed-off-by: Axel Lin <axel.lin@gmail.com>
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ sound/soc/codecs/wm8940.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/sound/soc/codecs/wm8940.c
++++ b/sound/soc/codecs/wm8940.c
+@@ -472,6 +472,8 @@ static int wm8940_set_bias_level(struct
+               break;
+       }
++      codec->dapm.bias_level = level;
++
+       return ret;
+ }
diff --git a/queue-3.0/asoc-wm8994-use-snd_soc_dapm_aif_out-for-aif3-capture.patch b/queue-3.0/asoc-wm8994-use-snd_soc_dapm_aif_out-for-aif3-capture.patch
new file mode 100644 (file)
index 0000000..2bee0a1
--- /dev/null
@@ -0,0 +1,29 @@
+From 35024f4922f7b271e7529673413889aa3d51c5fc Mon Sep 17 00:00:00 2001
+From: Axel Lin <axel.lin@gmail.com>
+Date: Thu, 20 Oct 2011 12:13:24 +0800
+Subject: ASoC: wm8994: Use SND_SOC_DAPM_AIF_OUT for AIF3 Capture
+
+From: Axel Lin <axel.lin@gmail.com>
+
+commit 35024f4922f7b271e7529673413889aa3d51c5fc upstream.
+
+Signed-off-by: Axel Lin <axel.lin@gmail.com>
+Acked-by: Liam Girdwood <lrg@ti.com>
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ sound/soc/codecs/wm8994.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/sound/soc/codecs/wm8994.c
++++ b/sound/soc/codecs/wm8994.c
+@@ -1266,7 +1266,7 @@ SND_SOC_DAPM_MUX("AIF2DAC Mux", SND_SOC_
+ SND_SOC_DAPM_MUX("AIF2ADC Mux", SND_SOC_NOPM, 0, 0, &aif2adc_mux),
+ SND_SOC_DAPM_AIF_IN("AIF3DACDAT", "AIF3 Playback", 0, SND_SOC_NOPM, 0, 0),
+-SND_SOC_DAPM_AIF_IN("AIF3ADCDAT", "AIF3 Capture", 0, SND_SOC_NOPM, 0, 0),
++SND_SOC_DAPM_AIF_OUT("AIF3ADCDAT", "AIF3 Capture", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_SUPPLY("TOCLK", WM8994_CLOCKING_1, 4, 0, NULL, 0),
diff --git a/queue-3.0/carminefb-fix-module-parameters-permissions.patch b/queue-3.0/carminefb-fix-module-parameters-permissions.patch
new file mode 100644 (file)
index 0000000..46e0331
--- /dev/null
@@ -0,0 +1,61 @@
+From c84c14224bbca6ec60d5851fcc87be0e34df2f44 Mon Sep 17 00:00:00 2001
+From: Jean Delvare <jdelvare@suse.de>
+Date: Fri, 8 Jul 2011 11:04:38 +0200
+Subject: carminefb: Fix module parameters permissions
+
+From: Jean Delvare <jdelvare@suse.de>
+
+commit c84c14224bbca6ec60d5851fcc87be0e34df2f44 upstream.
+
+The third parameter of module_param is supposed to be an octal value.
+The missing leading "0" causes the following:
+
+$ ls -l /sys/module/carminefb/parameters/
+total 0
+-rw-rwxr-- 1 root root 4096 Jul  8 08:55 fb_displays
+-rw-rwxr-- 1 root root 4096 Jul  8 08:55 fb_mode
+-rw-rwxr-- 1 root root 4096 Jul  8 08:55 fb_mode_str
+
+After fixing the perm parameter, we get the expected:
+
+$ ls -l /sys/module/carminefb/parameters/
+total 0
+-r--r--r-- 1 root root 4096 Jul  8 08:56 fb_displays
+-r--r--r-- 1 root root 4096 Jul  8 08:56 fb_mode
+-r--r--r-- 1 root root 4096 Jul  8 08:56 fb_mode_str
+
+Signed-off-by: Jean Delvare <jdelvare@suse.de>
+Cc: Paul Mundt <lethal@linux-sh.org>
+Cc: Sebastian Siewior <bigeasy@linutronix.de>
+Signed-off-by: Paul Mundt <lethal@linux-sh.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/video/carminefb.c |    6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/video/carminefb.c
++++ b/drivers/video/carminefb.c
+@@ -32,11 +32,11 @@
+ #define CARMINEFB_DEFAULT_VIDEO_MODE  1
+ static unsigned int fb_mode = CARMINEFB_DEFAULT_VIDEO_MODE;
+-module_param(fb_mode, uint, 444);
++module_param(fb_mode, uint, 0444);
+ MODULE_PARM_DESC(fb_mode, "Initial video mode as integer.");
+ static char *fb_mode_str;
+-module_param(fb_mode_str, charp, 444);
++module_param(fb_mode_str, charp, 0444);
+ MODULE_PARM_DESC(fb_mode_str, "Initial video mode in characters.");
+ /*
+@@ -46,7 +46,7 @@ MODULE_PARM_DESC(fb_mode_str, "Initial v
+  * 0b010 Display 1
+  */
+ static int fb_displays = CARMINE_USE_DISPLAY0 | CARMINE_USE_DISPLAY1;
+-module_param(fb_displays, int, 444);
++module_param(fb_displays, int, 0444);
+ MODULE_PARM_DESC(fb_displays, "Bit mode, which displays are used");
+ struct carmine_hw {
diff --git a/queue-3.0/ccwgroup-move-attributes-to-attribute-group.patch b/queue-3.0/ccwgroup-move-attributes-to-attribute-group.patch
new file mode 100644 (file)
index 0000000..ad50394
--- /dev/null
@@ -0,0 +1,125 @@
+From dbdf1afcaaabe83dea15a3cb9b9013e73ae3b1ad Mon Sep 17 00:00:00 2001
+From: Sebastian Ott <sebott@linux.vnet.ibm.com>
+Date: Sun, 30 Oct 2011 15:16:52 +0100
+Subject: [S390] ccwgroup: move attributes to attribute group
+
+From: Sebastian Ott <sebott@linux.vnet.ibm.com>
+
+commit dbdf1afcaaabe83dea15a3cb9b9013e73ae3b1ad upstream.
+
+Put sysfs attributes of ccwgroup devices in an attribute group to
+ensure that these attributes are actually present when userspace
+is notified via uevents.
+
+Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/s390/cio/ccwgroup.c |   42 ++++++++++++++++++++++--------------------
+ 1 file changed, 22 insertions(+), 20 deletions(-)
+
+--- a/drivers/s390/cio/ccwgroup.c
++++ b/drivers/s390/cio/ccwgroup.c
+@@ -87,6 +87,12 @@ static void __ccwgroup_remove_cdev_refs(
+       }
+ }
++static ssize_t ccwgroup_online_store(struct device *dev,
++                                   struct device_attribute *attr,
++                                   const char *buf, size_t count);
++static ssize_t ccwgroup_online_show(struct device *dev,
++                                  struct device_attribute *attr,
++                                  char *buf);
+ /*
+  * Provide an 'ungroup' attribute so the user can remove group devices no
+  * longer needed or accidentially created. Saves memory :)
+@@ -134,6 +140,20 @@ out:
+ }
+ static DEVICE_ATTR(ungroup, 0200, NULL, ccwgroup_ungroup_store);
++static DEVICE_ATTR(online, 0644, ccwgroup_online_show, ccwgroup_online_store);
++
++static struct attribute *ccwgroup_attrs[] = {
++      &dev_attr_online.attr,
++      &dev_attr_ungroup.attr,
++      NULL,
++};
++static struct attribute_group ccwgroup_attr_group = {
++      .attrs = ccwgroup_attrs,
++};
++static const struct attribute_group *ccwgroup_attr_groups[] = {
++      &ccwgroup_attr_group,
++      NULL,
++};
+ static void
+ ccwgroup_release (struct device *dev)
+@@ -293,25 +313,17 @@ int ccwgroup_create_from_string(struct d
+       }
+       dev_set_name(&gdev->dev, "%s", dev_name(&gdev->cdev[0]->dev));
+-
++      gdev->dev.groups = ccwgroup_attr_groups;
+       rc = device_add(&gdev->dev);
+       if (rc)
+               goto error;
+       get_device(&gdev->dev);
+-      rc = device_create_file(&gdev->dev, &dev_attr_ungroup);
+-
+-      if (rc) {
+-              device_unregister(&gdev->dev);
+-              goto error;
+-      }
+-
+       rc = __ccwgroup_create_symlinks(gdev);
+       if (!rc) {
+               mutex_unlock(&gdev->reg_mutex);
+               put_device(&gdev->dev);
+               return 0;
+       }
+-      device_remove_file(&gdev->dev, &dev_attr_ungroup);
+       device_unregister(&gdev->dev);
+ error:
+       for (i = 0; i < num_devices; i++)
+@@ -423,7 +435,7 @@ ccwgroup_online_store (struct device *de
+       int ret;
+       if (!dev->driver)
+-              return -ENODEV;
++              return -EINVAL;
+       gdev = to_ccwgroupdev(dev);
+       gdrv = to_ccwgroupdrv(dev->driver);
+@@ -456,8 +468,6 @@ ccwgroup_online_show (struct device *dev
+       return sprintf(buf, online ? "1\n" : "0\n");
+ }
+-static DEVICE_ATTR(online, 0644, ccwgroup_online_show, ccwgroup_online_store);
+-
+ static int
+ ccwgroup_probe (struct device *dev)
+ {
+@@ -469,12 +479,7 @@ ccwgroup_probe (struct device *dev)
+       gdev = to_ccwgroupdev(dev);
+       gdrv = to_ccwgroupdrv(dev->driver);
+-      if ((ret = device_create_file(dev, &dev_attr_online)))
+-              return ret;
+-
+       ret = gdrv->probe ? gdrv->probe(gdev) : -ENODEV;
+-      if (ret)
+-              device_remove_file(dev, &dev_attr_online);
+       return ret;
+ }
+@@ -485,9 +490,6 @@ ccwgroup_remove (struct device *dev)
+       struct ccwgroup_device *gdev;
+       struct ccwgroup_driver *gdrv;
+-      device_remove_file(dev, &dev_attr_online);
+-      device_remove_file(dev, &dev_attr_ungroup);
+-
+       if (!dev->driver)
+               return 0;
diff --git a/queue-3.0/dib0700-protect-the-dib0700-buffer-access.patch b/queue-3.0/dib0700-protect-the-dib0700-buffer-access.patch
new file mode 100644 (file)
index 0000000..71e6fdb
--- /dev/null
@@ -0,0 +1,250 @@
+From bff469f4167fdabfe15294f375577d7eadbaa1bb Mon Sep 17 00:00:00 2001
+From: Olivier Grenie <olivier.grenie@dibcom.fr>
+Date: Mon, 1 Aug 2011 12:45:58 -0300
+Subject: [media] dib0700: protect the dib0700 buffer access
+
+From: Olivier Grenie <olivier.grenie@dibcom.fr>
+
+commit bff469f4167fdabfe15294f375577d7eadbaa1bb upstream.
+
+This patch protects the common buffer access inside the dib0700 in order
+to manage concurrent access. This protection is done using mutex.
+
+Cc: Mauro Carvalho Chehab <mchehab@redhat.com>
+Cc: Florian Mickler <florian@mickler.org>
+Signed-off-by: Javier Marcet <javier@marcet.info>
+Signed-off-by: Olivier Grenie <olivier.grenie@dibcom.fr>
+Signed-off-by: Patrick Boettcher <patrick.boettcher@dibcom.fr>
+[mchehab@redhat.com: dprint requires 3 arguments. Replaced by dib_info]
+Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/media/dvb/dvb-usb/dib0700_core.c |   81 +++++++++++++++++++++++++++----
+ 1 file changed, 72 insertions(+), 9 deletions(-)
+
+--- a/drivers/media/dvb/dvb-usb/dib0700_core.c
++++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
+@@ -30,6 +30,11 @@ int dib0700_get_version(struct dvb_usb_d
+       struct dib0700_state *st = d->priv;
+       int ret;
++      if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
++              deb_info("could not acquire lock");
++              return 0;
++      }
++
+       ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
+                                 REQUEST_GET_VERSION,
+                                 USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
+@@ -46,6 +51,7 @@ int dib0700_get_version(struct dvb_usb_d
+       if (fwtype != NULL)
+               *fwtype     = (st->buf[12] << 24) | (st->buf[13] << 16) |
+                       (st->buf[14] << 8) | st->buf[15];
++      mutex_unlock(&d->usb_mutex);
+       return ret;
+ }
+@@ -108,7 +114,12 @@ int dib0700_ctrl_rd(struct dvb_usb_devic
+ int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val)
+ {
+       struct dib0700_state *st = d->priv;
+-      s16 ret;
++      int ret;
++
++      if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
++              deb_info("could not acquire lock");
++              return 0;
++      }
+       st->buf[0] = REQUEST_SET_GPIO;
+       st->buf[1] = gpio;
+@@ -116,6 +127,7 @@ int dib0700_set_gpio(struct dvb_usb_devi
+       ret = dib0700_ctrl_wr(d, st->buf, 3);
++      mutex_unlock(&d->usb_mutex);
+       return ret;
+ }
+@@ -125,6 +137,11 @@ static int dib0700_set_usb_xfer_len(stru
+       int ret;
+       if (st->fw_version >= 0x10201) {
++              if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
++                      deb_info("could not acquire lock");
++                      return 0;
++              }
++
+               st->buf[0] = REQUEST_SET_USB_XFER_LEN;
+               st->buf[1] = (nb_ts_packets >> 8) & 0xff;
+               st->buf[2] = nb_ts_packets & 0xff;
+@@ -132,6 +149,7 @@ static int dib0700_set_usb_xfer_len(stru
+               deb_info("set the USB xfer len to %i Ts packet\n", nb_ts_packets);
+               ret = dib0700_ctrl_wr(d, st->buf, 3);
++              mutex_unlock(&d->usb_mutex);
+       } else {
+               deb_info("this firmware does not allow to change the USB xfer len\n");
+               ret = -EIO;
+@@ -208,6 +226,10 @@ static int dib0700_i2c_xfer_new(struct i
+               } else {
+                       /* Write request */
++                      if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
++                              deb_info("could not acquire lock");
++                              return 0;
++                      }
+                       st->buf[0] = REQUEST_NEW_I2C_WRITE;
+                       st->buf[1] = msg[i].addr << 1;
+                       st->buf[2] = (en_start << 7) | (en_stop << 6) |
+@@ -227,6 +249,7 @@ static int dib0700_i2c_xfer_new(struct i
+                                                USB_TYPE_VENDOR | USB_DIR_OUT,
+                                                0, 0, st->buf, msg[i].len + 4,
+                                                USB_CTRL_GET_TIMEOUT);
++                      mutex_unlock(&d->usb_mutex);
+                       if (result < 0) {
+                               deb_info("i2c write error (status = %d)\n", result);
+                               break;
+@@ -249,6 +272,10 @@ static int dib0700_i2c_xfer_legacy(struc
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+               return -EAGAIN;
++      if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
++              deb_info("could not acquire lock");
++              return 0;
++      }
+       for (i = 0; i < num; i++) {
+               /* fill in the address */
+@@ -279,6 +306,7 @@ static int dib0700_i2c_xfer_legacy(struc
+                               break;
+               }
+       }
++      mutex_unlock(&d->usb_mutex);
+       mutex_unlock(&d->i2c_mutex);
+       return i;
+@@ -337,7 +365,12 @@ static int dib0700_set_clock(struct dvb_
+       u16 pll_loopdiv, u16 free_div, u16 dsuScaler)
+ {
+       struct dib0700_state *st = d->priv;
+-      s16 ret;
++      int ret;
++
++      if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
++              deb_info("could not acquire lock");
++              return 0;
++      }
+       st->buf[0] = REQUEST_SET_CLOCK;
+       st->buf[1] = (en_pll << 7) | (pll_src << 6) |
+@@ -352,6 +385,7 @@ static int dib0700_set_clock(struct dvb_
+       st->buf[9] =  dsuScaler         & 0xff; /* LSB */
+       ret = dib0700_ctrl_wr(d, st->buf, 10);
++      mutex_unlock(&d->usb_mutex);
+       return ret;
+ }
+@@ -360,10 +394,16 @@ int dib0700_set_i2c_speed(struct dvb_usb
+ {
+       struct dib0700_state *st = d->priv;
+       u16 divider;
++      int ret;
+       if (scl_kHz == 0)
+               return -EINVAL;
++      if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
++              deb_info("could not acquire lock");
++              return 0;
++      }
++
+       st->buf[0] = REQUEST_SET_I2C_PARAM;
+       divider = (u16) (30000 / scl_kHz);
+       st->buf[1] = 0;
+@@ -379,7 +419,11 @@ int dib0700_set_i2c_speed(struct dvb_usb
+       deb_info("setting I2C speed: %04x %04x %04x (%d kHz).",
+               (st->buf[2] << 8) | (st->buf[3]), (st->buf[4] << 8) |
+               st->buf[5], (st->buf[6] << 8) | st->buf[7], scl_kHz);
+-      return dib0700_ctrl_wr(d, st->buf, 8);
++
++      ret = dib0700_ctrl_wr(d, st->buf, 8);
++      mutex_unlock(&d->usb_mutex);
++
++      return ret;
+ }
+@@ -515,6 +559,11 @@ int dib0700_streaming_ctrl(struct dvb_us
+               }
+       }
++      if (mutex_lock_interruptible(&adap->dev->usb_mutex) < 0) {
++              deb_info("could not acquire lock");
++              return 0;
++      }
++
+       st->buf[0] = REQUEST_ENABLE_VIDEO;
+       /* this bit gives a kind of command,
+        * rather than enabling something or not */
+@@ -548,7 +597,10 @@ int dib0700_streaming_ctrl(struct dvb_us
+       deb_info("data for streaming: %x %x\n", st->buf[1], st->buf[2]);
+-      return dib0700_ctrl_wr(adap->dev, st->buf, 4);
++      ret = dib0700_ctrl_wr(adap->dev, st->buf, 4);
++      mutex_unlock(&adap->dev->usb_mutex);
++
++      return ret;
+ }
+ int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type)
+@@ -557,6 +609,11 @@ int dib0700_change_protocol(struct rc_de
+       struct dib0700_state *st = d->priv;
+       int new_proto, ret;
++      if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
++              deb_info("could not acquire lock");
++              return 0;
++      }
++
+       st->buf[0] = REQUEST_SET_RC;
+       st->buf[1] = 0;
+       st->buf[2] = 0;
+@@ -567,23 +624,29 @@ int dib0700_change_protocol(struct rc_de
+       else if (rc_type == RC_TYPE_NEC)
+               new_proto = 0;
+       else if (rc_type == RC_TYPE_RC6) {
+-              if (st->fw_version < 0x10200)
+-                      return -EINVAL;
++              if (st->fw_version < 0x10200) {
++                      ret = -EINVAL;
++                      goto out;
++              }
+               new_proto = 2;
+-      } else
+-              return -EINVAL;
++      } else {
++              ret = -EINVAL;
++              goto out;
++      }
+       st->buf[1] = new_proto;
+       ret = dib0700_ctrl_wr(d, st->buf, 3);
+       if (ret < 0) {
+               err("ir protocol setup failed");
+-              return ret;
++              goto out;
+       }
+       d->props.rc.core.protocol = rc_type;
++out:
++      mutex_unlock(&d->usb_mutex);
+       return ret;
+ }
diff --git a/queue-3.0/dibcom-protect-the-i2c-bufer-access.patch b/queue-3.0/dibcom-protect-the-i2c-bufer-access.patch
new file mode 100644 (file)
index 0000000..540a64f
--- /dev/null
@@ -0,0 +1,1145 @@
+From 79fcce3230b140f7675f8529ee53fe2f9644f902 Mon Sep 17 00:00:00 2001
+From: Patrick Boettcher <Patrick.Boettcher@dibcom.fr>
+Date: Wed, 3 Aug 2011 12:08:21 -0300
+Subject: [media] DiBcom: protect the I2C bufer access
+
+From: Patrick Boettcher <Patrick.Boettcher@dibcom.fr>
+
+commit 79fcce3230b140f7675f8529ee53fe2f9644f902 upstream.
+
+This patch protects the I2C buffer access in order to manage concurrent
+access. This protection is done using mutex.
+Furthermore, for the dib9000, if a pid filtering command is
+received during the tuning, this pid filtering command is delayed to
+avoid any concurrent access issue.
+
+Cc: Mauro Carvalho Chehab <mchehab@redhat.com>
+Cc: Florian Mickler <florian@mickler.org>
+Signed-off-by: Olivier Grenie <olivier.grenie@dibcom.fr>
+Signed-off-by: Patrick Boettcher <Patrick.Boettcher@dibcom.fr>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/media/dvb/frontends/dib0070.c        |   37 ++++--
+ drivers/media/dvb/frontends/dib0090.c        |   70 +++++++++--
+ drivers/media/dvb/frontends/dib7000m.c       |   27 ++++
+ drivers/media/dvb/frontends/dib7000p.c       |   32 ++++-
+ drivers/media/dvb/frontends/dib8000.c        |   72 ++++++++++-
+ drivers/media/dvb/frontends/dib9000.c        |  164 +++++++++++++++++++++++----
+ drivers/media/dvb/frontends/dibx000_common.c |   76 ++++++++++--
+ drivers/media/dvb/frontends/dibx000_common.h |    1 
+ 8 files changed, 412 insertions(+), 67 deletions(-)
+
+--- a/drivers/media/dvb/frontends/dib0070.c
++++ b/drivers/media/dvb/frontends/dib0070.c
+@@ -27,6 +27,7 @@
+ #include <linux/kernel.h>
+ #include <linux/slab.h>
+ #include <linux/i2c.h>
++#include <linux/mutex.h>
+ #include "dvb_frontend.h"
+@@ -78,10 +79,18 @@ struct dib0070_state {
+       struct i2c_msg msg[2];
+       u8 i2c_write_buffer[3];
+       u8 i2c_read_buffer[2];
++      struct mutex i2c_buffer_lock;
+ };
+-static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg)
++static u16 dib0070_read_reg(struct dib0070_state *state, u8 reg)
+ {
++      u16 ret;
++
++      if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++              dprintk("could not acquire lock");
++              return 0;
++      }
++
+       state->i2c_write_buffer[0] = reg;
+       memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
+@@ -96,13 +105,23 @@ static uint16_t dib0070_read_reg(struct
+       if (i2c_transfer(state->i2c, state->msg, 2) != 2) {
+               printk(KERN_WARNING "DiB0070 I2C read failed\n");
+-              return 0;
+-      }
+-      return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++              ret = 0;
++      } else
++              ret = (state->i2c_read_buffer[0] << 8)
++                      | state->i2c_read_buffer[1];
++
++      mutex_unlock(&state->i2c_buffer_lock);
++      return ret;
+ }
+ static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val)
+ {
++      int ret;
++
++      if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++              dprintk("could not acquire lock");
++              return -EINVAL;
++      }
+       state->i2c_write_buffer[0] = reg;
+       state->i2c_write_buffer[1] = val >> 8;
+       state->i2c_write_buffer[2] = val & 0xff;
+@@ -115,9 +134,12 @@ static int dib0070_write_reg(struct dib0
+       if (i2c_transfer(state->i2c, state->msg, 1) != 1) {
+               printk(KERN_WARNING "DiB0070 I2C write failed\n");
+-              return -EREMOTEIO;
+-      }
+-      return 0;
++              ret = -EREMOTEIO;
++      } else
++              ret = 0;
++
++      mutex_unlock(&state->i2c_buffer_lock);
++      return ret;
+ }
+ #define HARD_RESET(state) do { \
+@@ -734,6 +756,7 @@ struct dvb_frontend *dib0070_attach(stru
+       state->cfg = cfg;
+       state->i2c = i2c;
+       state->fe  = fe;
++      mutex_init(&state->i2c_buffer_lock);
+       fe->tuner_priv = state;
+       if (dib0070_reset(fe) != 0)
+--- a/drivers/media/dvb/frontends/dib0090.c
++++ b/drivers/media/dvb/frontends/dib0090.c
+@@ -27,6 +27,7 @@
+ #include <linux/kernel.h>
+ #include <linux/slab.h>
+ #include <linux/i2c.h>
++#include <linux/mutex.h>
+ #include "dvb_frontend.h"
+@@ -196,6 +197,7 @@ struct dib0090_state {
+       struct i2c_msg msg[2];
+       u8 i2c_write_buffer[3];
+       u8 i2c_read_buffer[2];
++      struct mutex i2c_buffer_lock;
+ };
+ struct dib0090_fw_state {
+@@ -208,10 +210,18 @@ struct dib0090_fw_state {
+       struct i2c_msg msg;
+       u8 i2c_write_buffer[2];
+       u8 i2c_read_buffer[2];
++      struct mutex i2c_buffer_lock;
+ };
+ static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg)
+ {
++      u16 ret;
++
++      if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++              dprintk("could not acquire lock");
++              return 0;
++      }
++
+       state->i2c_write_buffer[0] = reg;
+       memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
+@@ -226,14 +236,24 @@ static u16 dib0090_read_reg(struct dib00
+       if (i2c_transfer(state->i2c, state->msg, 2) != 2) {
+               printk(KERN_WARNING "DiB0090 I2C read failed\n");
+-              return 0;
+-      }
++              ret = 0;
++      } else
++              ret = (state->i2c_read_buffer[0] << 8)
++                      | state->i2c_read_buffer[1];
+-      return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++      mutex_unlock(&state->i2c_buffer_lock);
++      return ret;
+ }
+ static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val)
+ {
++      int ret;
++
++      if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++              dprintk("could not acquire lock");
++              return -EINVAL;
++      }
++
+       state->i2c_write_buffer[0] = reg & 0xff;
+       state->i2c_write_buffer[1] = val >> 8;
+       state->i2c_write_buffer[2] = val & 0xff;
+@@ -246,13 +266,23 @@ static int dib0090_write_reg(struct dib0
+       if (i2c_transfer(state->i2c, state->msg, 1) != 1) {
+               printk(KERN_WARNING "DiB0090 I2C write failed\n");
+-              return -EREMOTEIO;
+-      }
+-      return 0;
++              ret = -EREMOTEIO;
++      } else
++              ret = 0;
++
++      mutex_unlock(&state->i2c_buffer_lock);
++      return ret;
+ }
+ static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg)
+ {
++      u16 ret;
++
++      if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++              dprintk("could not acquire lock");
++              return 0;
++      }
++
+       state->i2c_write_buffer[0] = reg;
+       memset(&state->msg, 0, sizeof(struct i2c_msg));
+@@ -262,13 +292,24 @@ static u16 dib0090_fw_read_reg(struct di
+       state->msg.len = 2;
+       if (i2c_transfer(state->i2c, &state->msg, 1) != 1) {
+               printk(KERN_WARNING "DiB0090 I2C read failed\n");
+-              return 0;
+-      }
+-      return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++              ret = 0;
++      } else
++              ret = (state->i2c_read_buffer[0] << 8)
++                      | state->i2c_read_buffer[1];
++
++      mutex_unlock(&state->i2c_buffer_lock);
++      return ret;
+ }
+ static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val)
+ {
++      int ret;
++
++      if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++              dprintk("could not acquire lock");
++              return -EINVAL;
++      }
++
+       state->i2c_write_buffer[0] = val >> 8;
+       state->i2c_write_buffer[1] = val & 0xff;
+@@ -279,9 +320,12 @@ static int dib0090_fw_write_reg(struct d
+       state->msg.len = 2;
+       if (i2c_transfer(state->i2c, &state->msg, 1) != 1) {
+               printk(KERN_WARNING "DiB0090 I2C write failed\n");
+-              return -EREMOTEIO;
+-      }
+-      return 0;
++              ret = -EREMOTEIO;
++      } else
++              ret = 0;
++
++      mutex_unlock(&state->i2c_buffer_lock);
++      return ret;
+ }
+ #define HARD_RESET(state) do {  if (cfg->reset) {  if (cfg->sleep) cfg->sleep(fe, 0); msleep(10);  cfg->reset(fe, 1); msleep(10);  cfg->reset(fe, 0); msleep(10);  }  } while (0)
+@@ -2440,6 +2484,7 @@ struct dvb_frontend *dib0090_register(st
+       st->config = config;
+       st->i2c = i2c;
+       st->fe = fe;
++      mutex_init(&st->i2c_buffer_lock);
+       fe->tuner_priv = st;
+       if (config->wbd == NULL)
+@@ -2471,6 +2516,7 @@ struct dvb_frontend *dib0090_fw_register
+       st->config = config;
+       st->i2c = i2c;
+       st->fe = fe;
++      mutex_init(&st->i2c_buffer_lock);
+       fe->tuner_priv = st;
+       if (dib0090_fw_reset_digital(fe, st->config) != 0)
+--- a/drivers/media/dvb/frontends/dib7000m.c
++++ b/drivers/media/dvb/frontends/dib7000m.c
+@@ -11,6 +11,7 @@
+ #include <linux/kernel.h>
+ #include <linux/slab.h>
+ #include <linux/i2c.h>
++#include <linux/mutex.h>
+ #include "dvb_frontend.h"
+@@ -55,6 +56,7 @@ struct dib7000m_state {
+       struct i2c_msg msg[2];
+       u8 i2c_write_buffer[4];
+       u8 i2c_read_buffer[2];
++      struct mutex i2c_buffer_lock;
+ };
+ enum dib7000m_power_mode {
+@@ -69,6 +71,13 @@ enum dib7000m_power_mode {
+ static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg)
+ {
++      u16 ret;
++
++      if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++              dprintk("could not acquire lock");
++              return 0;
++      }
++
+       state->i2c_write_buffer[0] = (reg >> 8) | 0x80;
+       state->i2c_write_buffer[1] = reg & 0xff;
+@@ -85,11 +94,21 @@ static u16 dib7000m_read_word(struct dib
+       if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
+               dprintk("i2c read error on %d",reg);
+-      return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++      ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++      mutex_unlock(&state->i2c_buffer_lock);
++
++      return ret;
+ }
+ static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val)
+ {
++      int ret;
++
++      if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++              dprintk("could not acquire lock");
++              return -EINVAL;
++      }
++
+       state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+       state->i2c_write_buffer[1] = reg & 0xff;
+       state->i2c_write_buffer[2] = (val >> 8) & 0xff;
+@@ -101,7 +120,10 @@ static int dib7000m_write_word(struct di
+       state->msg[0].buf = state->i2c_write_buffer;
+       state->msg[0].len = 4;
+-      return i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
++      ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ?
++                      -EREMOTEIO : 0);
++      mutex_unlock(&state->i2c_buffer_lock);
++      return ret;
+ }
+ static void dib7000m_write_tab(struct dib7000m_state *state, u16 *buf)
+ {
+@@ -1385,6 +1407,7 @@ struct dvb_frontend * dib7000m_attach(st
+       demod                   = &st->demod;
+       demod->demodulator_priv = st;
+       memcpy(&st->demod.ops, &dib7000m_ops, sizeof(struct dvb_frontend_ops));
++      mutex_init(&st->i2c_buffer_lock);
+       st->timf_default = cfg->bw->timf;
+--- a/drivers/media/dvb/frontends/dib7000p.c
++++ b/drivers/media/dvb/frontends/dib7000p.c
+@@ -10,6 +10,7 @@
+ #include <linux/kernel.h>
+ #include <linux/slab.h>
+ #include <linux/i2c.h>
++#include <linux/mutex.h>
+ #include "dvb_math.h"
+ #include "dvb_frontend.h"
+@@ -68,6 +69,7 @@ struct dib7000p_state {
+       struct i2c_msg msg[2];
+       u8 i2c_write_buffer[4];
+       u8 i2c_read_buffer[2];
++      struct mutex i2c_buffer_lock;
+ };
+ enum dib7000p_power_mode {
+@@ -81,6 +83,13 @@ static int dib7090_set_diversity_in(stru
+ static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
+ {
++      u16 ret;
++
++      if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++              dprintk("could not acquire lock");
++              return 0;
++      }
++
+       state->i2c_write_buffer[0] = reg >> 8;
+       state->i2c_write_buffer[1] = reg & 0xff;
+@@ -97,11 +106,20 @@ static u16 dib7000p_read_word(struct dib
+       if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
+               dprintk("i2c read error on %d", reg);
+-      return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++      ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++      mutex_unlock(&state->i2c_buffer_lock);
++      return ret;
+ }
+ static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
+ {
++      int ret;
++
++      if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++              dprintk("could not acquire lock");
++              return -EINVAL;
++      }
++
+       state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+       state->i2c_write_buffer[1] = reg & 0xff;
+       state->i2c_write_buffer[2] = (val >> 8) & 0xff;
+@@ -113,7 +131,10 @@ static int dib7000p_write_word(struct di
+       state->msg[0].buf = state->i2c_write_buffer;
+       state->msg[0].len = 4;
+-      return i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
++      ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ?
++                      -EREMOTEIO : 0);
++      mutex_unlock(&state->i2c_buffer_lock);
++      return ret;
+ }
+ static void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf)
+@@ -1646,6 +1667,7 @@ int dib7000p_i2c_enumeration(struct i2c_
+               return -ENOMEM;
+       dpst->i2c_adap = i2c;
++      mutex_init(&dpst->i2c_buffer_lock);
+       for (k = no_of_demods - 1; k >= 0; k--) {
+               dpst->cfg = cfg[k];
+@@ -2324,6 +2346,7 @@ struct dvb_frontend *dib7000p_attach(str
+       demod = &st->demod;
+       demod->demodulator_priv = st;
+       memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
++      mutex_init(&st->i2c_buffer_lock);
+       dib7000p_write_word(st, 1287, 0x0003);  /* sram lead in, rdy */
+@@ -2333,8 +2356,9 @@ struct dvb_frontend *dib7000p_attach(str
+       st->version = dib7000p_read_word(st, 897);
+       /* FIXME: make sure the dev.parent field is initialized, or else
+-              request_firmware() will hit an OOPS (this should be moved somewhere
+-              more common) */
++         request_firmware() will hit an OOPS (this should be moved somewhere
++         more common) */
++      st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
+       dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr);
+--- a/drivers/media/dvb/frontends/dib8000.c
++++ b/drivers/media/dvb/frontends/dib8000.c
+@@ -10,6 +10,8 @@
+ #include <linux/kernel.h>
+ #include <linux/slab.h>
+ #include <linux/i2c.h>
++#include <linux/mutex.h>
++
+ #include "dvb_math.h"
+ #include "dvb_frontend.h"
+@@ -37,6 +39,7 @@ struct i2c_device {
+       u8 addr;
+       u8 *i2c_write_buffer;
+       u8 *i2c_read_buffer;
++      struct mutex *i2c_buffer_lock;
+ };
+ struct dib8000_state {
+@@ -77,6 +80,7 @@ struct dib8000_state {
+       struct i2c_msg msg[2];
+       u8 i2c_write_buffer[4];
+       u8 i2c_read_buffer[2];
++      struct mutex i2c_buffer_lock;
+ };
+ enum dib8000_power_mode {
+@@ -86,24 +90,39 @@ enum dib8000_power_mode {
+ static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg)
+ {
++      u16 ret;
+       struct i2c_msg msg[2] = {
+-              {.addr = i2c->addr >> 1, .flags = 0,
+-                      .buf = i2c->i2c_write_buffer, .len = 2},
+-              {.addr = i2c->addr >> 1, .flags = I2C_M_RD,
+-                      .buf = i2c->i2c_read_buffer, .len = 2},
++              {.addr = i2c->addr >> 1, .flags = 0, .len = 2},
++              {.addr = i2c->addr >> 1, .flags = I2C_M_RD, .len = 2},
+       };
++      if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
++              dprintk("could not acquire lock");
++              return 0;
++      }
++
++      msg[0].buf    = i2c->i2c_write_buffer;
+       msg[0].buf[0] = reg >> 8;
+       msg[0].buf[1] = reg & 0xff;
++      msg[1].buf    = i2c->i2c_read_buffer;
+       if (i2c_transfer(i2c->adap, msg, 2) != 2)
+               dprintk("i2c read error on %d", reg);
+-      return (msg[1].buf[0] << 8) | msg[1].buf[1];
++      ret = (msg[1].buf[0] << 8) | msg[1].buf[1];
++      mutex_unlock(i2c->i2c_buffer_lock);
++      return ret;
+ }
+ static u16 dib8000_read_word(struct dib8000_state *state, u16 reg)
+ {
++      u16 ret;
++
++      if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++              dprintk("could not acquire lock");
++              return 0;
++      }
++
+       state->i2c_write_buffer[0] = reg >> 8;
+       state->i2c_write_buffer[1] = reg & 0xff;
+@@ -120,7 +139,10 @@ static u16 dib8000_read_word(struct dib8
+       if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2)
+               dprintk("i2c read error on %d", reg);
+-      return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++      ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++      mutex_unlock(&state->i2c_buffer_lock);
++
++      return ret;
+ }
+ static u32 dib8000_read32(struct dib8000_state *state, u16 reg)
+@@ -135,22 +157,35 @@ static u32 dib8000_read32(struct dib8000
+ static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
+ {
+-      struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0,
+-              .buf = i2c->i2c_write_buffer, .len = 4};
++      struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0, .len = 4};
+       int ret = 0;
++      if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
++              dprintk("could not acquire lock");
++              return -EINVAL;
++      }
++
++      msg.buf    = i2c->i2c_write_buffer;
+       msg.buf[0] = (reg >> 8) & 0xff;
+       msg.buf[1] = reg & 0xff;
+       msg.buf[2] = (val >> 8) & 0xff;
+       msg.buf[3] = val & 0xff;
+       ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
++      mutex_unlock(i2c->i2c_buffer_lock);
+       return ret;
+ }
+ static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val)
+ {
++      int ret;
++
++      if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++              dprintk("could not acquire lock");
++              return -EINVAL;
++      }
++
+       state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+       state->i2c_write_buffer[1] = reg & 0xff;
+       state->i2c_write_buffer[2] = (val >> 8) & 0xff;
+@@ -162,7 +197,11 @@ static int dib8000_write_word(struct dib
+       state->msg[0].buf = state->i2c_write_buffer;
+       state->msg[0].len = 4;
+-      return i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
++      ret = (i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ?
++                      -EREMOTEIO : 0);
++      mutex_unlock(&state->i2c_buffer_lock);
++
++      return ret;
+ }
+ static const s16 coeff_2k_sb_1seg_dqpsk[8] = {
+@@ -2434,8 +2473,15 @@ int dib8000_i2c_enumeration(struct i2c_a
+       if (!client.i2c_read_buffer) {
+               dprintk("%s: not enough memory", __func__);
+               ret = -ENOMEM;
+-              goto error_memory;
++              goto error_memory_read;
++      }
++      client.i2c_buffer_lock = kzalloc(sizeof(struct mutex), GFP_KERNEL);
++      if (!client.i2c_buffer_lock) {
++              dprintk("%s: not enough memory", __func__);
++              ret = -ENOMEM;
++              goto error_memory_lock;
+       }
++      mutex_init(client.i2c_buffer_lock);
+       for (k = no_of_demods - 1; k >= 0; k--) {
+               /* designated i2c address */
+@@ -2476,8 +2522,10 @@ int dib8000_i2c_enumeration(struct i2c_a
+       }
+ error:
++      kfree(client.i2c_buffer_lock);
++error_memory_lock:
+       kfree(client.i2c_read_buffer);
+-error_memory:
++error_memory_read:
+       kfree(client.i2c_write_buffer);
+       return ret;
+@@ -2581,6 +2629,8 @@ struct dvb_frontend *dib8000_attach(stru
+       state->i2c.addr = i2c_addr;
+       state->i2c.i2c_write_buffer = state->i2c_write_buffer;
+       state->i2c.i2c_read_buffer = state->i2c_read_buffer;
++      mutex_init(&state->i2c_buffer_lock);
++      state->i2c.i2c_buffer_lock = &state->i2c_buffer_lock;
+       state->gpio_val = cfg->gpio_val;
+       state->gpio_dir = cfg->gpio_dir;
+--- a/drivers/media/dvb/frontends/dib9000.c
++++ b/drivers/media/dvb/frontends/dib9000.c
+@@ -38,6 +38,15 @@ struct i2c_device {
+ #define DibInitLock(lock) mutex_init(lock)
+ #define DibFreeLock(lock)
++struct dib9000_pid_ctrl {
++#define DIB9000_PID_FILTER_CTRL 0
++#define DIB9000_PID_FILTER      1
++      u8 cmd;
++      u8 id;
++      u16 pid;
++      u8 onoff;
++};
++
+ struct dib9000_state {
+       struct i2c_device i2c;
+@@ -99,6 +108,10 @@ struct dib9000_state {
+       struct i2c_msg msg[2];
+       u8 i2c_write_buffer[255];
+       u8 i2c_read_buffer[255];
++      DIB_LOCK demod_lock;
++      u8 get_frontend_internal;
++      struct dib9000_pid_ctrl pid_ctrl[10];
++      s8 pid_ctrl_index; /* -1: empty list; -2: do not use the list */
+ };
+ static const u32 fe_info[44] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+@@ -1743,19 +1756,56 @@ EXPORT_SYMBOL(dib9000_set_gpio);
+ int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
+ {
+       struct dib9000_state *state = fe->demodulator_priv;
+-      u16 val = dib9000_read_word(state, 294 + 1) & 0xffef;
++      u16 val;
++      int ret;
++
++      if ((state->pid_ctrl_index != -2) && (state->pid_ctrl_index < 9)) {
++              /* postpone the pid filtering cmd */
++              dprintk("pid filter cmd postpone");
++              state->pid_ctrl_index++;
++              state->pid_ctrl[state->pid_ctrl_index].cmd = DIB9000_PID_FILTER_CTRL;
++              state->pid_ctrl[state->pid_ctrl_index].onoff = onoff;
++              return 0;
++      }
++
++      DibAcquireLock(&state->demod_lock);
++
++      val = dib9000_read_word(state, 294 + 1) & 0xffef;
+       val |= (onoff & 0x1) << 4;
+       dprintk("PID filter enabled %d", onoff);
+-      return dib9000_write_word(state, 294 + 1, val);
++      ret = dib9000_write_word(state, 294 + 1, val);
++      DibReleaseLock(&state->demod_lock);
++      return ret;
++
+ }
+ EXPORT_SYMBOL(dib9000_fw_pid_filter_ctrl);
+ int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
+ {
+       struct dib9000_state *state = fe->demodulator_priv;
++      int ret;
++
++      if (state->pid_ctrl_index != -2) {
++              /* postpone the pid filtering cmd */
++              dprintk("pid filter postpone");
++              if (state->pid_ctrl_index < 9) {
++                      state->pid_ctrl_index++;
++                      state->pid_ctrl[state->pid_ctrl_index].cmd = DIB9000_PID_FILTER;
++                      state->pid_ctrl[state->pid_ctrl_index].id = id;
++                      state->pid_ctrl[state->pid_ctrl_index].pid = pid;
++                      state->pid_ctrl[state->pid_ctrl_index].onoff = onoff;
++              } else
++                      dprintk("can not add any more pid ctrl cmd");
++              return 0;
++      }
++
++      DibAcquireLock(&state->demod_lock);
+       dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff);
+-      return dib9000_write_word(state, 300 + 1 + id, onoff ? (1 << 13) | pid : 0);
++      ret = dib9000_write_word(state, 300 + 1 + id,
++                      onoff ? (1 << 13) | pid : 0);
++      DibReleaseLock(&state->demod_lock);
++      return ret;
+ }
+ EXPORT_SYMBOL(dib9000_fw_pid_filter);
+@@ -1778,6 +1828,7 @@ static void dib9000_release(struct dvb_f
+       DibFreeLock(&state->platform.risc.mbx_lock);
+       DibFreeLock(&state->platform.risc.mem_lock);
+       DibFreeLock(&state->platform.risc.mem_mbx_lock);
++      DibFreeLock(&state->demod_lock);
+       dibx000_exit_i2c_master(&st->i2c_master);
+       i2c_del_adapter(&st->tuner_adap);
+@@ -1795,14 +1846,19 @@ static int dib9000_sleep(struct dvb_fron
+ {
+       struct dib9000_state *state = fe->demodulator_priv;
+       u8 index_frontend;
+-      int ret;
++      int ret = 0;
++      DibAcquireLock(&state->demod_lock);
+       for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+               ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]);
+               if (ret < 0)
+-                      return ret;
++                      goto error;
+       }
+-      return dib9000_mbx_send(state, OUT_MSG_FE_SLEEP, NULL, 0);
++      ret = dib9000_mbx_send(state, OUT_MSG_FE_SLEEP, NULL, 0);
++
++error:
++      DibReleaseLock(&state->demod_lock);
++      return ret;
+ }
+ static int dib9000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
+@@ -1816,7 +1872,10 @@ static int dib9000_get_frontend(struct d
+       struct dib9000_state *state = fe->demodulator_priv;
+       u8 index_frontend, sub_index_frontend;
+       fe_status_t stat;
+-      int ret;
++      int ret = 0;
++
++      if (state->get_frontend_internal == 0)
++              DibAcquireLock(&state->demod_lock);
+       for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+               state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
+@@ -1846,14 +1905,15 @@ static int dib9000_get_frontend(struct d
+                                           state->fe[index_frontend]->dtv_property_cache.rolloff;
+                               }
+                       }
+-                      return 0;
++                      ret = 0;
++                      goto return_value;
+               }
+       }
+       /* get the channel from master chip */
+       ret = dib9000_fw_get_channel(fe, fep);
+       if (ret != 0)
+-              return ret;
++              goto return_value;
+       /* synchronize the cache with the other frontends */
+       for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+@@ -1866,8 +1926,12 @@ static int dib9000_get_frontend(struct d
+               state->fe[index_frontend]->dtv_property_cache.code_rate_LP = fe->dtv_property_cache.code_rate_LP;
+               state->fe[index_frontend]->dtv_property_cache.rolloff = fe->dtv_property_cache.rolloff;
+       }
++      ret = 0;
+-      return 0;
++return_value:
++      if (state->get_frontend_internal == 0)
++              DibReleaseLock(&state->demod_lock);
++      return ret;
+ }
+ static int dib9000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
+@@ -1912,6 +1976,10 @@ static int dib9000_set_frontend(struct d
+               dprintk("dib9000: must specify bandwidth ");
+               return 0;
+       }
++
++      state->pid_ctrl_index = -1; /* postpone the pid filtering cmd */
++      DibAcquireLock(&state->demod_lock);
++
+       fe->dtv_property_cache.delivery_system = SYS_DVBT;
+       /* set the master status */
+@@ -1974,13 +2042,18 @@ static int dib9000_set_frontend(struct d
+       /* check the tune result */
+       if (exit_condition == 1) {      /* tune failed */
+               dprintk("tune failed");
++              DibReleaseLock(&state->demod_lock);
++              /* tune failed; put all the pid filtering cmd to junk */
++              state->pid_ctrl_index = -1;
+               return 0;
+       }
+       dprintk("tune success on frontend%i", index_frontend_success);
+       /* synchronize all the channel cache */
++      state->get_frontend_internal = 1;
+       dib9000_get_frontend(state->fe[0], fep);
++      state->get_frontend_internal = 0;
+       /* retune the other frontends with the found channel */
+       channel_status.status = CHANNEL_STATUS_PARAMETERS_SET;
+@@ -2025,6 +2098,28 @@ static int dib9000_set_frontend(struct d
+       /* turn off the diversity for the last frontend */
+       dib9000_fw_set_diversity_in(state->fe[index_frontend - 1], 0);
++      DibReleaseLock(&state->demod_lock);
++      if (state->pid_ctrl_index >= 0) {
++              u8 index_pid_filter_cmd;
++              u8 pid_ctrl_index = state->pid_ctrl_index;
++
++              state->pid_ctrl_index = -2;
++              for (index_pid_filter_cmd = 0;
++                              index_pid_filter_cmd <= pid_ctrl_index;
++                              index_pid_filter_cmd++) {
++                      if (state->pid_ctrl[index_pid_filter_cmd].cmd == DIB9000_PID_FILTER_CTRL)
++                              dib9000_fw_pid_filter_ctrl(state->fe[0],
++                                              state->pid_ctrl[index_pid_filter_cmd].onoff);
++                      else if (state->pid_ctrl[index_pid_filter_cmd].cmd == DIB9000_PID_FILTER)
++                              dib9000_fw_pid_filter(state->fe[0],
++                                              state->pid_ctrl[index_pid_filter_cmd].id,
++                                              state->pid_ctrl[index_pid_filter_cmd].pid,
++                                              state->pid_ctrl[index_pid_filter_cmd].onoff);
++              }
++      }
++      /* do not postpone any more the pid filtering */
++      state->pid_ctrl_index = -2;
++
+       return 0;
+ }
+@@ -2041,6 +2136,7 @@ static int dib9000_read_status(struct dv
+       u8 index_frontend;
+       u16 lock = 0, lock_slave = 0;
++      DibAcquireLock(&state->demod_lock);
+       for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
+               lock_slave |= dib9000_read_lock(state->fe[index_frontend]);
+@@ -2059,6 +2155,8 @@ static int dib9000_read_status(struct dv
+       if ((lock & 0x0008) || (lock_slave & 0x0008))
+               *stat |= FE_HAS_LOCK;
++      DibReleaseLock(&state->demod_lock);
++
+       return 0;
+ }
+@@ -2066,10 +2164,14 @@ static int dib9000_read_ber(struct dvb_f
+ {
+       struct dib9000_state *state = fe->demodulator_priv;
+       u16 *c;
++      int ret = 0;
++      DibAcquireLock(&state->demod_lock);
+       DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+-      if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
+-              return -EIO;
++      if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
++              ret = -EIO;
++              goto error;
++      }
+       dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR,
+                       state->i2c_read_buffer, 16 * 2);
+       DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+@@ -2077,7 +2179,10 @@ static int dib9000_read_ber(struct dvb_f
+       c = (u16 *)state->i2c_read_buffer;
+       *ber = c[10] << 16 | c[11];
+-      return 0;
++
++error:
++      DibReleaseLock(&state->demod_lock);
++      return ret;
+ }
+ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
+@@ -2086,7 +2191,9 @@ static int dib9000_read_signal_strength(
+       u8 index_frontend;
+       u16 *c = (u16 *)state->i2c_read_buffer;
+       u16 val;
++      int ret = 0;
++      DibAcquireLock(&state->demod_lock);
+       *strength = 0;
+       for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+               state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val);
+@@ -2097,8 +2204,10 @@ static int dib9000_read_signal_strength(
+       }
+       DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+-      if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
+-              return -EIO;
++      if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
++              ret = -EIO;
++              goto error;
++      }
+       dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
+       DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+@@ -2107,7 +2216,10 @@ static int dib9000_read_signal_strength(
+               *strength = 65535;
+       else
+               *strength += val;
+-      return 0;
++
++error:
++      DibReleaseLock(&state->demod_lock);
++      return ret;
+ }
+ static u32 dib9000_get_snr(struct dvb_frontend *fe)
+@@ -2151,6 +2263,7 @@ static int dib9000_read_snr(struct dvb_f
+       u8 index_frontend;
+       u32 snr_master;
++      DibAcquireLock(&state->demod_lock);
+       snr_master = dib9000_get_snr(fe);
+       for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
+               snr_master += dib9000_get_snr(state->fe[index_frontend]);
+@@ -2161,6 +2274,8 @@ static int dib9000_read_snr(struct dvb_f
+       } else
+               *snr = 0;
++      DibReleaseLock(&state->demod_lock);
++
+       return 0;
+ }
+@@ -2168,15 +2283,22 @@ static int dib9000_read_unc_blocks(struc
+ {
+       struct dib9000_state *state = fe->demodulator_priv;
+       u16 *c = (u16 *)state->i2c_read_buffer;
++      int ret = 0;
++      DibAcquireLock(&state->demod_lock);
+       DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+-      if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
+-              return -EIO;
++      if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
++              ret = -EIO;
++              goto error;
++      }
+       dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
+       DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+       *unc = c[12];
+-      return 0;
++
++error:
++      DibReleaseLock(&state->demod_lock);
++      return ret;
+ }
+ int dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, u8 first_addr)
+@@ -2322,6 +2444,10 @@ struct dvb_frontend *dib9000_attach(stru
+       DibInitLock(&st->platform.risc.mbx_lock);
+       DibInitLock(&st->platform.risc.mem_lock);
+       DibInitLock(&st->platform.risc.mem_mbx_lock);
++      DibInitLock(&st->demod_lock);
++      st->get_frontend_internal = 0;
++
++      st->pid_ctrl_index = -2;
+       st->fe[0] = fe;
+       fe->demodulator_priv = st;
+--- a/drivers/media/dvb/frontends/dibx000_common.c
++++ b/drivers/media/dvb/frontends/dibx000_common.c
+@@ -1,4 +1,5 @@
+ #include <linux/i2c.h>
++#include <linux/mutex.h>
+ #include "dibx000_common.h"
+@@ -10,6 +11,13 @@ MODULE_PARM_DESC(debug, "turn on debuggi
+ static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val)
+ {
++      int ret;
++
++      if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
++              dprintk("could not acquire lock");
++              return -EINVAL;
++      }
++
+       mst->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+       mst->i2c_write_buffer[1] = reg & 0xff;
+       mst->i2c_write_buffer[2] = (val >> 8) & 0xff;
+@@ -21,11 +29,21 @@ static int dibx000_write_word(struct dib
+       mst->msg[0].buf = mst->i2c_write_buffer;
+       mst->msg[0].len = 4;
+-      return i2c_transfer(mst->i2c_adap, mst->msg, 1) != 1 ? -EREMOTEIO : 0;
++      ret = i2c_transfer(mst->i2c_adap, mst->msg, 1) != 1 ? -EREMOTEIO : 0;
++      mutex_unlock(&mst->i2c_buffer_lock);
++
++      return ret;
+ }
+ static u16 dibx000_read_word(struct dibx000_i2c_master *mst, u16 reg)
+ {
++      u16 ret;
++
++      if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
++              dprintk("could not acquire lock");
++              return 0;
++      }
++
+       mst->i2c_write_buffer[0] = reg >> 8;
+       mst->i2c_write_buffer[1] = reg & 0xff;
+@@ -42,7 +60,10 @@ static u16 dibx000_read_word(struct dibx
+       if (i2c_transfer(mst->i2c_adap, mst->msg, 2) != 2)
+               dprintk("i2c read error on %d", reg);
+-      return (mst->i2c_read_buffer[0] << 8) | mst->i2c_read_buffer[1];
++      ret = (mst->i2c_read_buffer[0] << 8) | mst->i2c_read_buffer[1];
++      mutex_unlock(&mst->i2c_buffer_lock);
++
++      return ret;
+ }
+ static int dibx000_is_i2c_done(struct dibx000_i2c_master *mst)
+@@ -257,6 +278,7 @@ static int dibx000_i2c_gated_gpio67_xfer
+                                       struct i2c_msg msg[], int num)
+ {
+       struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
++      int ret;
+       if (num > 32) {
+               dprintk("%s: too much I2C message to be transmitted (%i).\
+@@ -264,10 +286,15 @@ static int dibx000_i2c_gated_gpio67_xfer
+               return -ENOMEM;
+       }
+-      memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
+-
+       dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_6_7);
++      if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
++              dprintk("could not acquire lock");
++              return -EINVAL;
++      }
++
++      memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
++
+       /* open the gate */
+       dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1);
+       mst->msg[0].addr = mst->i2c_addr;
+@@ -282,7 +309,11 @@ static int dibx000_i2c_gated_gpio67_xfer
+       mst->msg[num + 1].buf = &mst->i2c_write_buffer[4];
+       mst->msg[num + 1].len = 4;
+-      return i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? num : -EIO;
++      ret = (i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ?
++                      num : -EIO);
++
++      mutex_unlock(&mst->i2c_buffer_lock);
++      return ret;
+ }
+ static struct i2c_algorithm dibx000_i2c_gated_gpio67_algo = {
+@@ -294,6 +325,7 @@ static int dibx000_i2c_gated_tuner_xfer(
+                                       struct i2c_msg msg[], int num)
+ {
+       struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
++      int ret;
+       if (num > 32) {
+               dprintk("%s: too much I2C message to be transmitted (%i).\
+@@ -301,10 +333,14 @@ static int dibx000_i2c_gated_tuner_xfer(
+               return -ENOMEM;
+       }
+-      memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
+-
+       dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER);
++      if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
++              dprintk("could not acquire lock");
++              return -EINVAL;
++      }
++      memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
++
+       /* open the gate */
+       dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1);
+       mst->msg[0].addr = mst->i2c_addr;
+@@ -319,7 +355,10 @@ static int dibx000_i2c_gated_tuner_xfer(
+       mst->msg[num + 1].buf = &mst->i2c_write_buffer[4];
+       mst->msg[num + 1].len = 4;
+-      return i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? num : -EIO;
++      ret = (i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ?
++                      num : -EIO);
++      mutex_unlock(&mst->i2c_buffer_lock);
++      return ret;
+ }
+ static struct i2c_algorithm dibx000_i2c_gated_tuner_algo = {
+@@ -390,8 +429,18 @@ static int i2c_adapter_init(struct i2c_a
+ int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev,
+                               struct i2c_adapter *i2c_adap, u8 i2c_addr)
+ {
+-      u8 tx[4];
+-      struct i2c_msg m = {.addr = i2c_addr >> 1,.buf = tx,.len = 4 };
++      int ret;
++
++      mutex_init(&mst->i2c_buffer_lock);
++      if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
++              dprintk("could not acquire lock");
++              return -EINVAL;
++      }
++      memset(mst->msg, 0, sizeof(struct i2c_msg));
++      mst->msg[0].addr = i2c_addr >> 1;
++      mst->msg[0].flags = 0;
++      mst->msg[0].buf = mst->i2c_write_buffer;
++      mst->msg[0].len = 4;
+       mst->device_rev = device_rev;
+       mst->i2c_adap = i2c_adap;
+@@ -431,9 +480,12 @@ int dibx000_init_i2c_master(struct dibx0
+                               "DiBX000: could not initialize the master i2c_adapter\n");
+       /* initialize the i2c-master by closing the gate */
+-      dibx000_i2c_gate_ctrl(mst, tx, 0, 0);
++      dibx000_i2c_gate_ctrl(mst, mst->i2c_write_buffer, 0, 0);
++
++      ret = (i2c_transfer(i2c_adap, mst->msg, 1) == 1);
++      mutex_unlock(&mst->i2c_buffer_lock);
+-      return i2c_transfer(i2c_adap, &m, 1) == 1;
++      return ret;
+ }
+ EXPORT_SYMBOL(dibx000_init_i2c_master);
+--- a/drivers/media/dvb/frontends/dibx000_common.h
++++ b/drivers/media/dvb/frontends/dibx000_common.h
+@@ -33,6 +33,7 @@ struct dibx000_i2c_master {
+       struct i2c_msg msg[34];
+       u8 i2c_write_buffer[8];
+       u8 i2c_read_buffer[2];
++      struct mutex i2c_buffer_lock;
+ };
+ extern int dibx000_init_i2c_master(struct dibx000_i2c_master *mst,
diff --git a/queue-3.0/fb-avoid-possible-deadlock-caused-by-fb_set_suspend.patch b/queue-3.0/fb-avoid-possible-deadlock-caused-by-fb_set_suspend.patch
new file mode 100644 (file)
index 0000000..10d1e3f
--- /dev/null
@@ -0,0 +1,150 @@
+From 9e769ff3f585db8f978f9113be83d36c7e3965dd Mon Sep 17 00:00:00 2001
+From: Herton Ronaldo Krzesinski <herton@mandriva.com.br>
+Date: Fri, 17 Jun 2011 19:02:39 +0000
+Subject: fb: avoid possible deadlock caused by fb_set_suspend
+
+From: Herton Ronaldo Krzesinski <herton@mandriva.com.br>
+
+commit 9e769ff3f585db8f978f9113be83d36c7e3965dd upstream.
+
+A lock ordering issue can cause deadlocks: in framebuffer/console code,
+all needed struct fb_info locks are taken before acquire_console_sem(),
+in places which need to take console semaphore.
+
+But fb_set_suspend is always called with console semaphore held, and
+inside it we call lock_fb_info which gets the fb_info lock, inverse
+locking order of what the rest of the code does. This causes a real
+deadlock issue, when we write to state fb sysfs attribute (which calls
+fb_set_suspend) while a framebuffer is being unregistered by
+remove_conflicting_framebuffers, as can be shown by following show
+blocked state trace on a test program which loads i915 and runs another
+forked processes writing to state attribute:
+
+Test process with semaphore held and trying to get fb_info lock:
+..
+fb-test2      D 0000000000000000     0   237    228 0x00000000
+ ffff8800774f3d68 0000000000000082 00000000000135c0 00000000000135c0
+ ffff880000000000 ffff8800774f3fd8 ffff8800774f3fd8 ffff880076ee4530
+ 00000000000135c0 ffff8800774f3fd8 ffff8800774f2000 00000000000135c0
+Call Trace:
+ [<ffffffff8141287a>] __mutex_lock_slowpath+0x11a/0x1e0
+ [<ffffffff814142f2>] ? _raw_spin_lock_irq+0x22/0x40
+ [<ffffffff814123d3>] mutex_lock+0x23/0x50
+ [<ffffffff8125dfc5>] lock_fb_info+0x25/0x60
+ [<ffffffff8125e3f0>] fb_set_suspend+0x20/0x80
+ [<ffffffff81263e2f>] store_fbstate+0x4f/0x70
+ [<ffffffff812e7f70>] dev_attr_store+0x20/0x30
+ [<ffffffff811c46b4>] sysfs_write_file+0xd4/0x160
+ [<ffffffff81155a26>] vfs_write+0xc6/0x190
+ [<ffffffff81155d51>] sys_write+0x51/0x90
+ [<ffffffff8100c012>] system_call_fastpath+0x16/0x1b
+..
+modprobe process stalled because has the fb_info lock (got inside
+unregister_framebuffer) but waiting for the semaphore held by the
+test process which is waiting to get the fb_info lock:
+..
+modprobe      D 0000000000000000     0   230    218 0x00000000
+ ffff880077a4d618 0000000000000082 0000000000000001 0000000000000001
+ ffff880000000000 ffff880077a4dfd8 ffff880077a4dfd8 ffff8800775a2e20
+ 00000000000135c0 ffff880077a4dfd8 ffff880077a4c000 00000000000135c0
+Call Trace:
+ [<ffffffff81411fe5>] schedule_timeout+0x215/0x310
+ [<ffffffff81058051>] ? get_parent_ip+0x11/0x50
+ [<ffffffff814130dd>] __down+0x6d/0xb0
+ [<ffffffff81089f71>] down+0x41/0x50
+ [<ffffffff810629ac>] acquire_console_sem+0x2c/0x50
+ [<ffffffff812ca53d>] unbind_con_driver+0xad/0x2d0
+ [<ffffffff8126f5f7>] fbcon_event_notify+0x457/0x890
+ [<ffffffff814144ff>] ? _raw_spin_unlock_irqrestore+0x1f/0x50
+ [<ffffffff81058051>] ? get_parent_ip+0x11/0x50
+ [<ffffffff8141836d>] notifier_call_chain+0x4d/0x70
+ [<ffffffff8108a3b8>] __blocking_notifier_call_chain+0x58/0x80
+ [<ffffffff8108a3f6>] blocking_notifier_call_chain+0x16/0x20
+ [<ffffffff8125dabb>] fb_notifier_call_chain+0x1b/0x20
+ [<ffffffff8125e6ac>] unregister_framebuffer+0x7c/0x130
+ [<ffffffff8125e8b3>] remove_conflicting_framebuffers+0x153/0x180
+ [<ffffffff8125eef3>] register_framebuffer+0x93/0x2c0
+ [<ffffffffa0331112>] drm_fb_helper_single_fb_probe+0x252/0x2f0 [drm_kms_helper]
+ [<ffffffffa03314a3>] drm_fb_helper_initial_config+0x2f3/0x6d0 [drm_kms_helper]
+ [<ffffffffa03318dd>] ? drm_fb_helper_single_add_all_connectors+0x5d/0x1c0 [drm_kms_helper]
+ [<ffffffffa037b588>] intel_fbdev_init+0xa8/0x160 [i915]
+ [<ffffffffa0343d74>] i915_driver_load+0x854/0x12b0 [i915]
+ [<ffffffffa02f0e7e>] drm_get_pci_dev+0x19e/0x360 [drm]
+ [<ffffffff8141821d>] ? sub_preempt_count+0x9d/0xd0
+ [<ffffffffa0386f91>] i915_pci_probe+0x15/0x17 [i915]
+ [<ffffffff8124481f>] local_pci_probe+0x5f/0xd0
+ [<ffffffff81244f89>] pci_device_probe+0x119/0x120
+ [<ffffffff812eccaa>] ? driver_sysfs_add+0x7a/0xb0
+ [<ffffffff812ed003>] driver_probe_device+0xa3/0x290
+ [<ffffffff812ed1f0>] ? __driver_attach+0x0/0xb0
+ [<ffffffff812ed29b>] __driver_attach+0xab/0xb0
+ [<ffffffff812ed1f0>] ? __driver_attach+0x0/0xb0
+ [<ffffffff812ebd3e>] bus_for_each_dev+0x5e/0x90
+ [<ffffffff812ecc2e>] driver_attach+0x1e/0x20
+ [<ffffffff812ec6f2>] bus_add_driver+0xe2/0x320
+ [<ffffffffa03aa000>] ? i915_init+0x0/0x96 [i915]
+ [<ffffffff812ed536>] driver_register+0x76/0x140
+ [<ffffffffa03aa000>] ? i915_init+0x0/0x96 [i915]
+ [<ffffffff81245216>] __pci_register_driver+0x56/0xd0
+ [<ffffffffa02f1264>] drm_pci_init+0xe4/0xf0 [drm]
+ [<ffffffffa03aa000>] ? i915_init+0x0/0x96 [i915]
+ [<ffffffffa02e84a8>] drm_init+0x58/0x70 [drm]
+ [<ffffffffa03aa094>] i915_init+0x94/0x96 [i915]
+ [<ffffffff81002194>] do_one_initcall+0x44/0x190
+ [<ffffffff810a066b>] sys_init_module+0xcb/0x210
+ [<ffffffff8100c012>] system_call_fastpath+0x16/0x1b
+..
+
+fb-test2 which reproduces above is available on kernel.org bug #26232.
+To solve this issue, avoid calling lock_fb_info inside fb_set_suspend,
+and move it out to where needed (callers of fb_set_suspend must call
+lock_fb_info before if needed). So far, the only place which needs to
+call lock_fb_info is store_fbstate, all other places which calls
+fb_set_suspend are suspend/resume hooks that should not need the lock as
+they should be run only when processes are already frozen in
+suspend/resume.
+
+References: https://bugzilla.kernel.org/show_bug.cgi?id=26232
+Signed-off-by: Herton Ronaldo Krzesinski <herton@mandriva.com.br>
+Signed-off-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/video/fbmem.c   |    3 ---
+ drivers/video/fbsysfs.c |    3 +++
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+--- a/drivers/video/fbmem.c
++++ b/drivers/video/fbmem.c
+@@ -1738,8 +1738,6 @@ void fb_set_suspend(struct fb_info *info
+ {
+       struct fb_event event;
+-      if (!lock_fb_info(info))
+-              return;
+       event.info = info;
+       if (state) {
+               fb_notifier_call_chain(FB_EVENT_SUSPEND, &event);
+@@ -1748,7 +1746,6 @@ void fb_set_suspend(struct fb_info *info
+               info->state = FBINFO_STATE_RUNNING;
+               fb_notifier_call_chain(FB_EVENT_RESUME, &event);
+       }
+-      unlock_fb_info(info);
+ }
+ /**
+--- a/drivers/video/fbsysfs.c
++++ b/drivers/video/fbsysfs.c
+@@ -399,9 +399,12 @@ static ssize_t store_fbstate(struct devi
+       state = simple_strtoul(buf, &last, 0);
++      if (!lock_fb_info(fb_info))
++              return -ENODEV;
+       console_lock();
+       fb_set_suspend(fb_info, (int)state);
+       console_unlock();
++      unlock_fb_info(fb_info);
+       return count;
+ }
diff --git a/queue-3.0/fb-sh-mobile-fix-deadlock-risk-between-lock_fb_info-and-console_lock.patch b/queue-3.0/fb-sh-mobile-fix-deadlock-risk-between-lock_fb_info-and-console_lock.patch
new file mode 100644 (file)
index 0000000..b93d502
--- /dev/null
@@ -0,0 +1,117 @@
+From 4a47a0e09c504e3ce0ccdb405411aefc5b09deb8 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Bruno=20Pr=C3=A9mont?= <bonbons@linux-vserver.org>
+Date: Fri, 2 Sep 2011 19:24:03 +0200
+Subject: fb: sh-mobile: Fix deadlock risk between lock_fb_info() and console_lock()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: =?UTF-8?q?Bruno=20Pr=C3=A9mont?= <bonbons@linux-vserver.org>
+
+commit 4a47a0e09c504e3ce0ccdb405411aefc5b09deb8 upstream.
+
+Following on Herton's patch "fb: avoid possible deadlock caused by
+fb_set_suspend" which moves lock_fb_info() out of fb_set_suspend()
+to its callers, correct sh-mobile's locking around call to
+fb_set_suspend() and the same sort of deaklocks with console_lock()
+due to order of taking the lock.
+
+console_lock() must be taken while fb_info is already locked and fb_info
+must be locked while calling fb_set_suspend().
+
+Signed-off-by: Bruno Prémont <bonbons@linux-vserver.org>
+Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+Signed-off-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/video/sh_mobile_hdmi.c |   47 ++++++++++++++++++++++-------------------
+ 1 file changed, 26 insertions(+), 21 deletions(-)
+
+--- a/drivers/video/sh_mobile_hdmi.c
++++ b/drivers/video/sh_mobile_hdmi.c
+@@ -1111,6 +1111,7 @@ static long sh_hdmi_clk_configure(struct
+ static void sh_hdmi_edid_work_fn(struct work_struct *work)
+ {
+       struct sh_hdmi *hdmi = container_of(work, struct sh_hdmi, edid_work.work);
++      struct fb_info *info;
+       struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data;
+       struct sh_mobile_lcdc_chan *ch;
+       int ret;
+@@ -1123,8 +1124,9 @@ static void sh_hdmi_edid_work_fn(struct
+       mutex_lock(&hdmi->mutex);
++      info = hdmi->info;
++
+       if (hdmi->hp_state == HDMI_HOTPLUG_CONNECTED) {
+-              struct fb_info *info = hdmi->info;
+               unsigned long parent_rate = 0, hdmi_rate;
+               ret = sh_hdmi_read_edid(hdmi, &hdmi_rate, &parent_rate);
+@@ -1148,42 +1150,45 @@ static void sh_hdmi_edid_work_fn(struct
+               ch = info->par;
+-              console_lock();
++              if (lock_fb_info(info)) {
++                      console_lock();
+-              /* HDMI plug in */
+-              if (!sh_hdmi_must_reconfigure(hdmi) &&
+-                  info->state == FBINFO_STATE_RUNNING) {
+-                      /*
+-                       * First activation with the default monitor - just turn
+-                       * on, if we run a resume here, the logo disappears
+-                       */
+-                      if (lock_fb_info(info)) {
++                      /* HDMI plug in */
++                      if (!sh_hdmi_must_reconfigure(hdmi) &&
++                          info->state == FBINFO_STATE_RUNNING) {
++                              /*
++                               * First activation with the default monitor - just turn
++                               * on, if we run a resume here, the logo disappears
++                               */
+                               info->var.width = hdmi->var.width;
+                               info->var.height = hdmi->var.height;
+                               sh_hdmi_display_on(hdmi, info);
+-                              unlock_fb_info(info);
++                      } else {
++                              /* New monitor or have to wake up */
++                              fb_set_suspend(info, 0);
+                       }
+-              } else {
+-                      /* New monitor or have to wake up */
+-                      fb_set_suspend(info, 0);
+-              }
+-              console_unlock();
++                      console_unlock();
++                      unlock_fb_info(info);
++              }
+       } else {
+               ret = 0;
+-              if (!hdmi->info)
++              if (!info)
+                       goto out;
+               hdmi->monspec.modedb_len = 0;
+               fb_destroy_modedb(hdmi->monspec.modedb);
+               hdmi->monspec.modedb = NULL;
+-              console_lock();
++              if (lock_fb_info(info)) {
++                      console_lock();
+-              /* HDMI disconnect */
+-              fb_set_suspend(hdmi->info, 1);
++                      /* HDMI disconnect */
++                      fb_set_suspend(info, 1);
+-              console_unlock();
++                      console_unlock();
++                      unlock_fb_info(info);
++              }
+       }
+ out:
diff --git a/queue-3.0/io-mapping-ensure-io_mapping_map_atomic-_is_-atomic.patch b/queue-3.0/io-mapping-ensure-io_mapping_map_atomic-_is_-atomic.patch
new file mode 100644 (file)
index 0000000..20bdf97
--- /dev/null
@@ -0,0 +1,55 @@
+From 24dd85ff723f142093f44244764b9b5c152235b8 Mon Sep 17 00:00:00 2001
+From: Daniel Vetter <daniel.vetter@ffwll.ch>
+Date: Wed, 28 Sep 2011 11:57:23 +0200
+Subject: io-mapping: ensure io_mapping_map_atomic _is_ atomic
+
+From: Daniel Vetter <daniel.vetter@ffwll.ch>
+
+commit 24dd85ff723f142093f44244764b9b5c152235b8 upstream.
+
+For the !HAVE_ATOMIC_IOMAP case the stub functions did not call
+pagefault_disable/_enable. The i915 driver relies on the map
+actually being atomic, otherwise it can deadlock with it's own
+pagefault handler in the gtt pwrite fastpath.
+
+This is exercised by gem_mmap_gtt from the intel-gpu-toosl gem
+testsuite.
+
+v2: Chris Wilson noted the lack of an include.
+
+Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=38115
+Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
+Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
+Signed-off-by: Keith Packard <keithp@keithp.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ include/linux/io-mapping.h |    4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/include/linux/io-mapping.h
++++ b/include/linux/io-mapping.h
+@@ -117,6 +117,8 @@ io_mapping_unmap(void __iomem *vaddr)
+ #else
++#include <linux/uaccess.h>
++
+ /* this struct isn't actually defined anywhere */
+ struct io_mapping;
+@@ -138,12 +140,14 @@ static inline void __iomem *
+ io_mapping_map_atomic_wc(struct io_mapping *mapping,
+                        unsigned long offset)
+ {
++      pagefault_disable();
+       return ((char __force __iomem *) mapping) + offset;
+ }
+ static inline void
+ io_mapping_unmap_atomic(void __iomem *vaddr)
+ {
++      pagefault_enable();
+ }
+ /* Non-atomic map/unmap */
diff --git a/queue-3.0/iommu-amd-fix-wrong-shift-direction.patch b/queue-3.0/iommu-amd-fix-wrong-shift-direction.patch
new file mode 100644 (file)
index 0000000..459b2d6
--- /dev/null
@@ -0,0 +1,30 @@
+From fcd0861db1cf4e6ed99f60a815b7b72c2ed36ea4 Mon Sep 17 00:00:00 2001
+From: Joerg Roedel <joerg.roedel@amd.com>
+Date: Tue, 11 Oct 2011 17:41:32 +0200
+Subject: iommu/amd: Fix wrong shift direction
+
+From: Joerg Roedel <joerg.roedel@amd.com>
+
+commit fcd0861db1cf4e6ed99f60a815b7b72c2ed36ea4 upstream.
+
+The shift direction was wrong because the function takes a
+page number and i is the address is the loop.
+
+Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/x86/kernel/amd_iommu.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/arch/x86/kernel/amd_iommu.c
++++ b/arch/x86/kernel/amd_iommu.c
+@@ -1203,7 +1203,7 @@ static int alloc_new_range(struct dma_op
+               if (!pte || !IOMMU_PTE_PRESENT(*pte))
+                       continue;
+-              dma_ops_reserve_addresses(dma_dom, i << PAGE_SHIFT, 1);
++              dma_ops_reserve_addresses(dma_dom, i >> PAGE_SHIFT, 1);
+       }
+       update_domain(&dma_dom->domain);
diff --git a/queue-3.0/kvm-s390-check-cpu_id-prior-to-using-it.patch b/queue-3.0/kvm-s390-check-cpu_id-prior-to-using-it.patch
new file mode 100644 (file)
index 0000000..3a8b1ea
--- /dev/null
@@ -0,0 +1,53 @@
+From 4d47555a80495657161a7e71ec3014ff2021e450 Mon Sep 17 00:00:00 2001
+From: Carsten Otte <cotte@de.ibm.com>
+Date: Tue, 18 Oct 2011 12:27:12 +0200
+Subject: KVM: s390: check cpu_id prior to using it
+
+From: Carsten Otte <cotte@de.ibm.com>
+
+commit 4d47555a80495657161a7e71ec3014ff2021e450 upstream.
+
+We use the cpu id provided by userspace as array index here. Thus we
+clearly need to check it first. Ooops.
+
+Signed-off-by: Carsten Otte <cotte@de.ibm.com>
+Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
+Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/s390/kvm/kvm-s390.c |   14 ++++++++++----
+ 1 file changed, 10 insertions(+), 4 deletions(-)
+
+--- a/arch/s390/kvm/kvm-s390.c
++++ b/arch/s390/kvm/kvm-s390.c
+@@ -301,11 +301,17 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu
+ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
+                                     unsigned int id)
+ {
+-      struct kvm_vcpu *vcpu = kzalloc(sizeof(struct kvm_vcpu), GFP_KERNEL);
+-      int rc = -ENOMEM;
++      struct kvm_vcpu *vcpu;
++      int rc = -EINVAL;
++      if (id >= KVM_MAX_VCPUS)
++              goto out;
++
++      rc = -ENOMEM;
++
++      vcpu = kzalloc(sizeof(struct kvm_vcpu), GFP_KERNEL);
+       if (!vcpu)
+-              goto out_nomem;
++              goto out;
+       vcpu->arch.sie_block = (struct kvm_s390_sie_block *)
+                                       get_zeroed_page(GFP_KERNEL);
+@@ -341,7 +347,7 @@ out_free_sie_block:
+       free_page((unsigned long)(vcpu->arch.sie_block));
+ out_free_cpu:
+       kfree(vcpu);
+-out_nomem:
++out:
+       return ERR_PTR(rc);
+ }
diff --git a/queue-3.0/memory-leak-with-rcu_table_free.patch b/queue-3.0/memory-leak-with-rcu_table_free.patch
new file mode 100644 (file)
index 0000000..f1a6b24
--- /dev/null
@@ -0,0 +1,35 @@
+From e73b7fffe487c315fd1a4fa22282e3362b440a06 Mon Sep 17 00:00:00 2001
+From: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Date: Sun, 30 Oct 2011 15:16:08 +0100
+Subject: [S390] memory leak with RCU_TABLE_FREE
+
+From: Martin Schwidefsky <schwidefsky@de.ibm.com>
+
+commit e73b7fffe487c315fd1a4fa22282e3362b440a06 upstream.
+
+The rcu page table free code uses a couple of bits in the page table
+pointer passed to tlb_remove_table to discern the different page table
+types. __tlb_remove_table extracts the type with an incorrect mask which
+leads to memory leaks. The correct mask is ((FRAG_MASK << 4) | FRAG_MASK).
+
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/s390/mm/pgtable.c |    5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/arch/s390/mm/pgtable.c
++++ b/arch/s390/mm/pgtable.c
+@@ -291,8 +291,9 @@ void page_table_free_rcu(struct mmu_gath
+ void __tlb_remove_table(void *_table)
+ {
+-      void *table = (void *)((unsigned long) _table & PAGE_MASK);
+-      unsigned type = (unsigned long) _table & ~PAGE_MASK;
++      const unsigned long mask = (FRAG_MASK << 4) | FRAG_MASK;
++      void *table = (void *)((unsigned long) _table & ~mask);
++      unsigned type = (unsigned long) _table & mask;
+       if (type)
+               __page_table_free_rcu(table, type);
diff --git a/queue-3.0/proc-self-numa_maps-restore-huge-tag-for-hugetlb-vmas.patch b/queue-3.0/proc-self-numa_maps-restore-huge-tag-for-hugetlb-vmas.patch
new file mode 100644 (file)
index 0000000..50936c4
--- /dev/null
@@ -0,0 +1,41 @@
+From fc360bd9cdcf875639a77f07fafec26699c546f3 Mon Sep 17 00:00:00 2001
+From: Andrew Morton <akpm@linux-foundation.org>
+Date: Mon, 31 Oct 2011 17:06:32 -0700
+Subject: /proc/self/numa_maps: restore "huge" tag for hugetlb vmas
+
+From: Andrew Morton <akpm@linux-foundation.org>
+
+commit fc360bd9cdcf875639a77f07fafec26699c546f3 upstream.
+
+The display of the "huge" tag was accidentally removed in 29ea2f698 ("mm:
+use walk_page_range() instead of custom page table walking code").
+
+Reported-by: Stephen Hemminger <shemminger@vyatta.com>
+Tested-by: Stephen Hemminger <shemminger@vyatta.com>
+Reviewed-by: Stephen Wilson <wilsons@start.ca>
+Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
+Cc: Hugh Dickins <hughd@google.com>
+Acked-by: David Rientjes <rientjes@google.com>
+Cc: Lee Schermerhorn <lee.schermerhorn@hp.com>
+Cc: Alexey Dobriyan <adobriyan@gmail.com>
+Cc: Christoph Lameter <cl@linux-foundation.org>
+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>
+
+---
+ fs/proc/task_mmu.c |    3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/fs/proc/task_mmu.c
++++ b/fs/proc/task_mmu.c
+@@ -1039,6 +1039,9 @@ static int show_numa_map(struct seq_file
+               seq_printf(m, " stack");
+       }
++      if (is_vm_hugetlb_page(vma))
++              seq_printf(m, " huge");
++
+       walk_page_range(vma->vm_start, vma->vm_end, &walk);
+       if (!md->pages)
index 0dd9da09816242cdcc0e571389755729130d0409..da04bef9a4b9ff63199786871b6081e43202fea2 100644 (file)
@@ -96,3 +96,27 @@ nfsd4-fix-open-downgrade-again.patch
 nfsd4-ignore-want-bits-in-open-downgrade.patch
 hppfs-missing-include.patch
 vfs-add-device-tag-to-proc-self-mountstats.patch
+io-mapping-ensure-io_mapping_map_atomic-_is_-atomic.patch
+asoc-wm8940-properly-set-codec-dapm.bias_level.patch
+asoc-wm8741-fix-setting-interface-format-for-dsp-modes.patch
+asoc-ak4642-fixup-cache-register-table.patch
+asoc-ak4535-fixup-cache-register-table.patch
+asoc-wm8994-use-snd_soc_dapm_aif_out-for-aif3-capture.patch
+asoc-remove-direct-register-cache-accesses-from-wm8962.patch
+asoc-fix-a-bug-in-wm8962-dsp_a-and-dsp_b-settings.patch
+kvm-s390-check-cpu_id-prior-to-using-it.patch
+user-per-registers-vs.-ptrace-single-stepping.patch
+memory-leak-with-rcu_table_free.patch
+ccwgroup-move-attributes-to-attribute-group.patch
+wmi-properly-cleanup-devices-to-avoid-crashes.patch
+iommu-amd-fix-wrong-shift-direction.patch
+carminefb-fix-module-parameters-permissions.patch
+fb-avoid-possible-deadlock-caused-by-fb_set_suspend.patch
+fb-sh-mobile-fix-deadlock-risk-between-lock_fb_info-and-console_lock.patch
+viafb-use-display-information-in-info-not-in-var-for.patch
+viafb-improve-pitch-handling.patch
+uvcvideo-set-alternate-setting-0-on-resume-if-the-bus-has-been-reset.patch
+dibcom-protect-the-i2c-bufer-access.patch
+dib0700-protect-the-dib0700-buffer-access.patch
+tuner_xc2028-allow-selection-of-the-frequency-adjustment-code-for-xc3028.patch
+proc-self-numa_maps-restore-huge-tag-for-hugetlb-vmas.patch
diff --git a/queue-3.0/tuner_xc2028-allow-selection-of-the-frequency-adjustment-code-for-xc3028.patch b/queue-3.0/tuner_xc2028-allow-selection-of-the-frequency-adjustment-code-for-xc3028.patch
new file mode 100644 (file)
index 0000000..8026a48
--- /dev/null
@@ -0,0 +1,32 @@
+From 9bed77ee2fb46b74782d0d9d14b92e9d07f3df6e Mon Sep 17 00:00:00 2001
+From: Mauro Carvalho Chehab <mchehab@redhat.com>
+Date: Thu, 28 Jul 2011 16:38:54 -0300
+Subject: [media] tuner_xc2028: Allow selection of the frequency adjustment code for XC3028
+
+From: Mauro Carvalho Chehab <mchehab@redhat.com>
+
+commit 9bed77ee2fb46b74782d0d9d14b92e9d07f3df6e upstream.
+
+This device is not using the proper demod IF. Instead of using the
+IF macro, it is specifying a IF frequency. This doesn't work, as xc3028
+needs to load an specific SCODE for the tuner. In this case, there's
+no IF table for 5 MHz.
+
+Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/media/video/cx23885/cx23885-dvb.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/media/video/cx23885/cx23885-dvb.c
++++ b/drivers/media/video/cx23885/cx23885-dvb.c
+@@ -843,7 +843,7 @@ static int dvb_register(struct cx23885_t
+                       static struct xc2028_ctrl ctl = {
+                               .fname   = XC3028L_DEFAULT_FIRMWARE,
+                               .max_len = 64,
+-                              .demod   = 5000,
++                              .demod   = XC3028_FE_DIBCOM52,
+                               /* This is true for all demods with
+                                       v36 firmware? */
+                               .type    = XC2028_D2633,
diff --git a/queue-3.0/user-per-registers-vs.-ptrace-single-stepping.patch b/queue-3.0/user-per-registers-vs.-ptrace-single-stepping.patch
new file mode 100644 (file)
index 0000000..897ec75
--- /dev/null
@@ -0,0 +1,74 @@
+From a45aff5285871bf7be1781d9462d3fdbb6c913f9 Mon Sep 17 00:00:00 2001
+From: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Date: Sun, 30 Oct 2011 15:16:07 +0100
+Subject: [S390] user per registers vs. ptrace single stepping
+
+From: Martin Schwidefsky <schwidefsky@de.ibm.com>
+
+commit a45aff5285871bf7be1781d9462d3fdbb6c913f9 upstream.
+
+git commit 5e9a2692 "[S390] ptrace cleanup" introduced a regression
+for the case when both a user PER set (e.g. a storage alteration trace) and
+PTRACE_SINGLESTEP are active. The new code will overrule the user PER set
+with a instruction-fetch PER set over the whole address space for ptrace
+single stepping. The inferior process will be stopped after each instruction
+with an instruction fetch event. Any other events that may have occurred
+concurrently are not reported (e.g. storage alteration event) because the
+control bits for them are not set. The solution is to merge the PER control
+bits of the user PER set with the PER_EVENT_IFETCH control bit for
+PTRACE_SINGLESTEP.
+
+Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/s390/kernel/ptrace.c |   28 +++++++++++++++-------------
+ 1 file changed, 15 insertions(+), 13 deletions(-)
+
+--- a/arch/s390/kernel/ptrace.c
++++ b/arch/s390/kernel/ptrace.c
+@@ -47,29 +47,31 @@ enum s390_regset {
+ void update_per_regs(struct task_struct *task)
+ {
+-      static const struct per_regs per_single_step = {
+-              .control = PER_EVENT_IFETCH,
+-              .start = 0,
+-              .end = PSW_ADDR_INSN,
+-      };
+       struct pt_regs *regs = task_pt_regs(task);
+       struct thread_struct *thread = &task->thread;
+-      const struct per_regs *new;
+-      struct per_regs old;
++      struct per_regs old, new;
+-      /* TIF_SINGLE_STEP overrides the user specified PER registers. */
+-      new = test_tsk_thread_flag(task, TIF_SINGLE_STEP) ?
+-              &per_single_step : &thread->per_user;
++      /* Copy user specified PER registers */
++      new.control = thread->per_user.control;
++      new.start = thread->per_user.start;
++      new.end = thread->per_user.end;
++
++      /* merge TIF_SINGLE_STEP into user specified PER registers. */
++      if (test_tsk_thread_flag(task, TIF_SINGLE_STEP)) {
++              new.control |= PER_EVENT_IFETCH;
++              new.start = 0;
++              new.end = PSW_ADDR_INSN;
++      }
+       /* Take care of the PER enablement bit in the PSW. */
+-      if (!(new->control & PER_EVENT_MASK)) {
++      if (!(new.control & PER_EVENT_MASK)) {
+               regs->psw.mask &= ~PSW_MASK_PER;
+               return;
+       }
+       regs->psw.mask |= PSW_MASK_PER;
+       __ctl_store(old, 9, 11);
+-      if (memcmp(new, &old, sizeof(struct per_regs)) != 0)
+-              __ctl_load(*new, 9, 11);
++      if (memcmp(&new, &old, sizeof(struct per_regs)) != 0)
++              __ctl_load(new, 9, 11);
+ }
+ void user_enable_single_step(struct task_struct *task)
diff --git a/queue-3.0/uvcvideo-set-alternate-setting-0-on-resume-if-the-bus-has-been-reset.patch b/queue-3.0/uvcvideo-set-alternate-setting-0-on-resume-if-the-bus-has-been-reset.patch
new file mode 100644 (file)
index 0000000..94c5287
--- /dev/null
@@ -0,0 +1,74 @@
+From d59a7b1dbce8b972ec2dc9fcaaae0bfa23687423 Mon Sep 17 00:00:00 2001
+From: Ming Lei <tom.leiming@gmail.com>
+Date: Sat, 16 Jul 2011 00:51:00 -0300
+Subject: [media] uvcvideo: Set alternate setting 0 on resume if the bus has been reset
+
+From: Ming Lei <tom.leiming@gmail.com>
+
+commit d59a7b1dbce8b972ec2dc9fcaaae0bfa23687423 upstream.
+
+If the bus has been reset on resume, set the alternate setting to 0.
+This should be the default value, but some devices crash or otherwise
+misbehave if they don't receive a SET_INTERFACE request before any other
+video control request.
+
+Microdia's 0c45:6437 camera has been found to require this change or it
+will stop sending video data after resume.
+
+uvc_video.c]
+
+Signed-off-by: Ming Lei <ming.lei@canonical.com>
+Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/media/video/uvc/uvc_driver.c |    2 +-
+ drivers/media/video/uvc/uvc_video.c  |   10 +++++++++-
+ drivers/media/video/uvc/uvcvideo.h   |    2 +-
+ 3 files changed, 11 insertions(+), 3 deletions(-)
+
+--- a/drivers/media/video/uvc/uvc_driver.c
++++ b/drivers/media/video/uvc/uvc_driver.c
+@@ -1960,7 +1960,7 @@ static int __uvc_resume(struct usb_inter
+       list_for_each_entry(stream, &dev->streams, list) {
+               if (stream->intf == intf)
+-                      return uvc_video_resume(stream);
++                      return uvc_video_resume(stream, reset);
+       }
+       uvc_trace(UVC_TRACE_SUSPEND, "Resume: video streaming USB interface "
+--- a/drivers/media/video/uvc/uvc_video.c
++++ b/drivers/media/video/uvc/uvc_video.c
+@@ -1104,10 +1104,18 @@ int uvc_video_suspend(struct uvc_streami
+  * buffers, making sure userspace applications are notified of the problem
+  * instead of waiting forever.
+  */
+-int uvc_video_resume(struct uvc_streaming *stream)
++int uvc_video_resume(struct uvc_streaming *stream, int reset)
+ {
+       int ret;
++      /* If the bus has been reset on resume, set the alternate setting to 0.
++       * This should be the default value, but some devices crash or otherwise
++       * misbehave if they don't receive a SET_INTERFACE request before any
++       * other video control request.
++       */
++      if (reset)
++              usb_set_interface(stream->dev->udev, stream->intfnum, 0);
++
+       stream->frozen = 0;
+       ret = uvc_commit_video(stream, &stream->ctrl);
+--- a/drivers/media/video/uvc/uvcvideo.h
++++ b/drivers/media/video/uvc/uvcvideo.h
+@@ -639,7 +639,7 @@ extern void uvc_mc_cleanup_entity(struct
+ /* Video */
+ extern int uvc_video_init(struct uvc_streaming *stream);
+ extern int uvc_video_suspend(struct uvc_streaming *stream);
+-extern int uvc_video_resume(struct uvc_streaming *stream);
++extern int uvc_video_resume(struct uvc_streaming *stream, int reset);
+ extern int uvc_video_enable(struct uvc_streaming *stream, int enable);
+ extern int uvc_probe_video(struct uvc_streaming *stream,
+               struct uvc_streaming_control *probe);
diff --git a/queue-3.0/viafb-improve-pitch-handling.patch b/queue-3.0/viafb-improve-pitch-handling.patch
new file mode 100644 (file)
index 0000000..5b104db
--- /dev/null
@@ -0,0 +1,62 @@
+From 936a3f770b8de7042d793272f008ef1bb08522e9 Mon Sep 17 00:00:00 2001
+From: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
+Date: Mon, 6 Jun 2011 01:27:34 +0000
+Subject: viafb: improve pitch handling
+
+From: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
+
+commit 936a3f770b8de7042d793272f008ef1bb08522e9 upstream.
+
+This patch adds checks for minimum and maximum pitch size to prevent
+invalid settings which could otherwise crash the machine. Also the
+alignment is done in a slightly more readable way.
+
+Signed-off-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/video/via/via_modesetting.h |    5 +++++
+ drivers/video/via/viafbdev.c        |   11 ++++++++---
+ 2 files changed, 13 insertions(+), 3 deletions(-)
+
+--- a/drivers/video/via/via_modesetting.h
++++ b/drivers/video/via/via_modesetting.h
+@@ -28,6 +28,11 @@
+ #include <linux/types.h>
++
++#define VIA_PITCH_SIZE        (1<<3)
++#define VIA_PITCH_MAX 0x3FF8
++
++
+ void via_set_primary_address(u32 addr);
+ void via_set_secondary_address(u32 addr);
+ void via_set_primary_pitch(u32 pitch);
+--- a/drivers/video/via/viafbdev.c
++++ b/drivers/video/via/viafbdev.c
+@@ -151,7 +151,8 @@ static void viafb_update_fix(struct fb_i
+       info->fix.visual =
+               bpp == 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+-      info->fix.line_length = (info->var.xres_virtual * bpp / 8 + 7) & ~7;
++      info->fix.line_length = ALIGN(info->var.xres_virtual * bpp / 8,
++              VIA_PITCH_SIZE);
+ }
+ static void viafb_setup_fixinfo(struct fb_fix_screeninfo *fix,
+@@ -238,8 +239,12 @@ static int viafb_check_var(struct fb_var
+               depth = 24;
+       viafb_fill_var_color_info(var, depth);
+-      line = (var->xres_virtual * var->bits_per_pixel / 8 + 7) & ~7;
+-      if (line * var->yres_virtual > ppar->memsize)
++      if (var->xres_virtual < var->xres)
++              var->xres_virtual = var->xres;
++
++      line = ALIGN(var->xres_virtual * var->bits_per_pixel / 8,
++              VIA_PITCH_SIZE);
++      if (line > VIA_PITCH_MAX || line * var->yres_virtual > ppar->memsize)
+               return -EINVAL;
+       /* Based on var passed in to calculate the refresh,
diff --git a/queue-3.0/viafb-use-display-information-in-info-not-in-var-for.patch b/queue-3.0/viafb-use-display-information-in-info-not-in-var-for.patch
new file mode 100644 (file)
index 0000000..d3250bb
--- /dev/null
@@ -0,0 +1,37 @@
+From d933990c57b498c092ceef591c7c5d69dbfe9f30 Mon Sep 17 00:00:00 2001
+From: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
+Date: Mon, 23 May 2011 21:39:58 +0000
+Subject: viafb: use display information in info not in var for panning
+
+From: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
+
+commit d933990c57b498c092ceef591c7c5d69dbfe9f30 upstream.
+
+As Laurent pointed out we must not use any information in the passed
+var besides xoffset, yoffset and vmode as otherwise applications
+might abuse it. Also use the aligned fix.line_length and not the
+(possible) unaligned xres_virtual.
+
+Signed-off-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
+Reported-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/video/via/viafbdev.c |    5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/video/via/viafbdev.c
++++ b/drivers/video/via/viafbdev.c
+@@ -348,8 +348,9 @@ static int viafb_pan_display(struct fb_v
+       struct fb_info *info)
+ {
+       struct viafb_par *viapar = info->par;
+-      u32 vram_addr = (var->yoffset * var->xres_virtual + var->xoffset)
+-              * (var->bits_per_pixel / 8) + viapar->vram_addr;
++      u32 vram_addr = viapar->vram_addr
++              + var->yoffset * info->fix.line_length
++              + var->xoffset * info->var.bits_per_pixel / 8;
+       DEBUG_MSG(KERN_DEBUG "viafb_pan_display, address = %d\n", vram_addr);
+       if (!viafb_dual_fb) {
diff --git a/queue-3.0/wmi-properly-cleanup-devices-to-avoid-crashes.patch b/queue-3.0/wmi-properly-cleanup-devices-to-avoid-crashes.patch
new file mode 100644 (file)
index 0000000..9da4cd2
--- /dev/null
@@ -0,0 +1,41 @@
+From 023b9565972a4a5e0f01b9aa32680af6e9b5c388 Mon Sep 17 00:00:00 2001
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Date: Wed, 7 Sep 2011 15:00:02 -0700
+Subject: WMI: properly cleanup devices to avoid crashes
+
+From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+
+commit 023b9565972a4a5e0f01b9aa32680af6e9b5c388 upstream.
+
+We need to remove devices that we destroy from the list, otherwise
+we'll crash if there are more than one "_WDG" methods in DSDT.
+
+This fixes https://bugzilla.kernel.org/show_bug.cgi?id=32052
+
+Tested-by: Ilya Tumaykin <librarian_rus@yahoo.com>
+Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
+Acked-by: Carlos Corbacho <carlos@strangeworlds.co.uk>
+Signed-off-by: Matthew Garrett <mjg@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/platform/x86/wmi.c |    6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+--- a/drivers/platform/x86/wmi.c
++++ b/drivers/platform/x86/wmi.c
+@@ -754,9 +754,13 @@ static void wmi_free_devices(void)
+       struct wmi_block *wblock, *next;
+       /* Delete devices for all the GUIDs */
+-      list_for_each_entry_safe(wblock, next, &wmi_block_list, list)
++      list_for_each_entry_safe(wblock, next, &wmi_block_list, list) {
++              list_del(&wblock->list);
+               if (wblock->dev.class)
+                       device_unregister(&wblock->dev);
++              else
++                      kfree(wblock);
++      }
+ }
+ static bool guid_already_parsed(const char *guid_string)