--- /dev/null
+From stable-bounces@linux.kernel.org Mon Oct 9 21:17:18 2006
+Date: Mon, 09 Oct 2006 21:16:11 -0700 (PDT)
+Message-Id: <20061009.211611.118971931.davem@davemloft.net>
+To: stable@kernel.org
+From: David Miller <davem@davemloft.net>
+Subject: NET_SCHED: Fix fallout from dev->qdisc RCU change
+
+From: Patrick McHardy <kaber@trash.net>
+
+The move of qdisc destruction to a rcu callback broke locking in the
+entire qdisc layer by invalidating previously valid assumptions about
+the context in which changes to the qdisc tree occur.
+
+The two assumptions were:
+
+- since changes only happen in process context, read_lock doesn't need
+ bottem half protection. Now invalid since destruction of inner qdiscs,
+ classifiers, actions and estimators happens in the RCU callback unless
+ they're manually deleted, resulting in dead-locks when read_lock in
+ process context is interrupted by write_lock_bh in bottem half context.
+
+- since changes only happen under the RTNL, no additional locking is
+ necessary for data not used during packet processing (f.e. u32_list).
+ Again, since destruction now happens in the RCU callback, this assumption
+ is not valid anymore, causing races while using this data, which can
+ result in corruption or use-after-free.
+
+Instead of "fixing" this by disabling bottem halfs everywhere and adding
+new locks/refcounting, this patch makes these assumptions valid again by
+moving destruction back to process context. Since only the dev->qdisc
+pointer is protected by RCU, but ->enqueue and the qdisc tree are still
+protected by dev->qdisc_lock, destruction of the tree can be performed
+immediately and only the final free needs to happen in the rcu callback
+to make sure dev_queue_xmit doesn't access already freed memory.
+
+Signed-off-by: Patrick McHardy <kaber@trash.net>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ net/core/dev.c | 14 +++++-----
+ net/sched/cls_api.c | 4 +-
+ net/sched/sch_api.c | 16 +++++------
+ net/sched/sch_generic.c | 66 +++++++++++++++---------------------------------
+ 4 files changed, 39 insertions(+), 61 deletions(-)
+
+--- linux-2.6.18.orig/net/core/dev.c
++++ linux-2.6.18/net/core/dev.c
+@@ -1478,14 +1478,16 @@ gso:
+ if (q->enqueue) {
+ /* Grab device queue */
+ spin_lock(&dev->queue_lock);
++ q = dev->qdisc;
++ if (q->enqueue) {
++ rc = q->enqueue(skb, q);
++ qdisc_run(dev);
++ spin_unlock(&dev->queue_lock);
+
+- rc = q->enqueue(skb, q);
+-
+- qdisc_run(dev);
+-
++ rc = rc == NET_XMIT_BYPASS ? NET_XMIT_SUCCESS : rc;
++ goto out;
++ }
+ spin_unlock(&dev->queue_lock);
+- rc = rc == NET_XMIT_BYPASS ? NET_XMIT_SUCCESS : rc;
+- goto out;
+ }
+
+ /* The device has no queue. Common case for software devices:
+--- linux-2.6.18.orig/net/sched/cls_api.c
++++ linux-2.6.18/net/sched/cls_api.c
+@@ -401,7 +401,7 @@ static int tc_dump_tfilter(struct sk_buf
+ if ((dev = dev_get_by_index(tcm->tcm_ifindex)) == NULL)
+ return skb->len;
+
+- read_lock_bh(&qdisc_tree_lock);
++ read_lock(&qdisc_tree_lock);
+ if (!tcm->tcm_parent)
+ q = dev->qdisc_sleeping;
+ else
+@@ -458,7 +458,7 @@ errout:
+ if (cl)
+ cops->put(q, cl);
+ out:
+- read_unlock_bh(&qdisc_tree_lock);
++ read_unlock(&qdisc_tree_lock);
+ dev_put(dev);
+ return skb->len;
+ }
+--- linux-2.6.18.orig/net/sched/sch_api.c
++++ linux-2.6.18/net/sched/sch_api.c
+@@ -195,14 +195,14 @@ struct Qdisc *qdisc_lookup(struct net_de
+ {
+ struct Qdisc *q;
+
+- read_lock_bh(&qdisc_tree_lock);
++ read_lock(&qdisc_tree_lock);
+ list_for_each_entry(q, &dev->qdisc_list, list) {
+ if (q->handle == handle) {
+- read_unlock_bh(&qdisc_tree_lock);
++ read_unlock(&qdisc_tree_lock);
+ return q;
+ }
+ }
+- read_unlock_bh(&qdisc_tree_lock);
++ read_unlock(&qdisc_tree_lock);
+ return NULL;
+ }
+
+@@ -837,7 +837,7 @@ static int tc_dump_qdisc(struct sk_buff
+ continue;
+ if (idx > s_idx)
+ s_q_idx = 0;
+- read_lock_bh(&qdisc_tree_lock);
++ read_lock(&qdisc_tree_lock);
+ q_idx = 0;
+ list_for_each_entry(q, &dev->qdisc_list, list) {
+ if (q_idx < s_q_idx) {
+@@ -846,12 +846,12 @@ static int tc_dump_qdisc(struct sk_buff
+ }
+ if (tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).pid,
+ cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0) {
+- read_unlock_bh(&qdisc_tree_lock);
++ read_unlock(&qdisc_tree_lock);
+ goto done;
+ }
+ q_idx++;
+ }
+- read_unlock_bh(&qdisc_tree_lock);
++ read_unlock(&qdisc_tree_lock);
+ }
+
+ done:
+@@ -1074,7 +1074,7 @@ static int tc_dump_tclass(struct sk_buff
+ s_t = cb->args[0];
+ t = 0;
+
+- read_lock_bh(&qdisc_tree_lock);
++ read_lock(&qdisc_tree_lock);
+ list_for_each_entry(q, &dev->qdisc_list, list) {
+ if (t < s_t || !q->ops->cl_ops ||
+ (tcm->tcm_parent &&
+@@ -1096,7 +1096,7 @@ static int tc_dump_tclass(struct sk_buff
+ break;
+ t++;
+ }
+- read_unlock_bh(&qdisc_tree_lock);
++ read_unlock(&qdisc_tree_lock);
+
+ cb->args[0] = t;
+
+--- linux-2.6.18.orig/net/sched/sch_generic.c
++++ linux-2.6.18/net/sched/sch_generic.c
+@@ -45,11 +45,10 @@
+ The idea is the following:
+ - enqueue, dequeue are serialized via top level device
+ spinlock dev->queue_lock.
+- - tree walking is protected by read_lock_bh(qdisc_tree_lock)
++ - tree walking is protected by read_lock(qdisc_tree_lock)
+ and this lock is used only in process context.
+- - updates to tree are made under rtnl semaphore or
+- from softirq context (__qdisc_destroy rcu-callback)
+- hence this lock needs local bh disabling.
++ - updates to tree are made only under rtnl semaphore,
++ hence this lock may be made without local bh disabling.
+
+ qdisc_tree_lock must be grabbed BEFORE dev->queue_lock!
+ */
+@@ -57,14 +56,14 @@ DEFINE_RWLOCK(qdisc_tree_lock);
+
+ void qdisc_lock_tree(struct net_device *dev)
+ {
+- write_lock_bh(&qdisc_tree_lock);
++ write_lock(&qdisc_tree_lock);
+ spin_lock_bh(&dev->queue_lock);
+ }
+
+ void qdisc_unlock_tree(struct net_device *dev)
+ {
+ spin_unlock_bh(&dev->queue_lock);
+- write_unlock_bh(&qdisc_tree_lock);
++ write_unlock(&qdisc_tree_lock);
+ }
+
+ /*
+@@ -483,20 +482,6 @@ void qdisc_reset(struct Qdisc *qdisc)
+ static void __qdisc_destroy(struct rcu_head *head)
+ {
+ struct Qdisc *qdisc = container_of(head, struct Qdisc, q_rcu);
+- struct Qdisc_ops *ops = qdisc->ops;
+-
+-#ifdef CONFIG_NET_ESTIMATOR
+- gen_kill_estimator(&qdisc->bstats, &qdisc->rate_est);
+-#endif
+- write_lock(&qdisc_tree_lock);
+- if (ops->reset)
+- ops->reset(qdisc);
+- if (ops->destroy)
+- ops->destroy(qdisc);
+- write_unlock(&qdisc_tree_lock);
+- module_put(ops->owner);
+-
+- dev_put(qdisc->dev);
+ kfree((char *) qdisc - qdisc->padded);
+ }
+
+@@ -504,32 +489,23 @@ static void __qdisc_destroy(struct rcu_h
+
+ void qdisc_destroy(struct Qdisc *qdisc)
+ {
+- struct list_head cql = LIST_HEAD_INIT(cql);
+- struct Qdisc *cq, *q, *n;
++ struct Qdisc_ops *ops = qdisc->ops;
+
+ if (qdisc->flags & TCQ_F_BUILTIN ||
+- !atomic_dec_and_test(&qdisc->refcnt))
++ !atomic_dec_and_test(&qdisc->refcnt))
+ return;
+
+- if (!list_empty(&qdisc->list)) {
+- if (qdisc->ops->cl_ops == NULL)
+- list_del(&qdisc->list);
+- else
+- list_move(&qdisc->list, &cql);
+- }
+-
+- /* unlink inner qdiscs from dev->qdisc_list immediately */
+- list_for_each_entry(cq, &cql, list)
+- list_for_each_entry_safe(q, n, &qdisc->dev->qdisc_list, list)
+- if (TC_H_MAJ(q->parent) == TC_H_MAJ(cq->handle)) {
+- if (q->ops->cl_ops == NULL)
+- list_del_init(&q->list);
+- else
+- list_move_tail(&q->list, &cql);
+- }
+- list_for_each_entry_safe(cq, n, &cql, list)
+- list_del_init(&cq->list);
++ list_del(&qdisc->list);
++#ifdef CONFIG_NET_ESTIMATOR
++ gen_kill_estimator(&qdisc->bstats, &qdisc->rate_est);
++#endif
++ if (ops->reset)
++ ops->reset(qdisc);
++ if (ops->destroy)
++ ops->destroy(qdisc);
+
++ module_put(ops->owner);
++ dev_put(qdisc->dev);
+ call_rcu(&qdisc->q_rcu, __qdisc_destroy);
+ }
+
+@@ -549,15 +525,15 @@ void dev_activate(struct net_device *dev
+ printk(KERN_INFO "%s: activation failed\n", dev->name);
+ return;
+ }
+- write_lock_bh(&qdisc_tree_lock);
++ write_lock(&qdisc_tree_lock);
+ list_add_tail(&qdisc->list, &dev->qdisc_list);
+- write_unlock_bh(&qdisc_tree_lock);
++ write_unlock(&qdisc_tree_lock);
+ } else {
+ qdisc = &noqueue_qdisc;
+ }
+- write_lock_bh(&qdisc_tree_lock);
++ write_lock(&qdisc_tree_lock);
+ dev->qdisc_sleeping = qdisc;
+- write_unlock_bh(&qdisc_tree_lock);
++ write_unlock(&qdisc_tree_lock);
+ }
+
+ if (!netif_carrier_ok(dev))
--- /dev/null
+net_sched-fix-fallout-from-dev-qdisc-rcu-change.patch
+uml-allow-using-again-x86-x86_64-crypto-code.patch
+uml-use-defconfig_list-to-avoid-reading-host-s-config.patch
+uml-fix-uml-build-failure.patch
+video-fix-msp343xg-handling-regression.patch
+video-cx24123-fix-pll-divisor-setup.patch
+video-pvrusb2-solve-mutex-deadlock.patch
+video-pvrusb2-improve-24xxx-config-option-description.patch
+video-pvrusb2-suppress-compiler-warning.patch
+video-pvrusb2-limit-hor-res-for-24xxx-devices.patch
+zd1211rw-zd1211b-asic-fwt-not-jointly-decoder.patch
--- /dev/null
+From stable-bounces@linux.kernel.org Thu Oct 5 14:10:24 2006
+From: "Paolo 'Blaisorblade' Giarrusso" <blaisorblade@yahoo.it>
+To: stable@kernel.org
+Date: Thu, 5 Oct 2006 21:34:28 +0200
+Message-Id: <11600768683307-git-send-email-blaisorblade@yahoo.it>
+Cc: Jeff Dike <jdike@addtoit.com>,
+ "Paolo 'Blaisorblade' Giarrusso" <blaisorblade@yahoo.it>,
+ <user-mode-linux-devel@lists.sourceforge.net>
+Subject: uml: allow using again x86/x86_64 crypto code
+
+From: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
+
+Enable compilation of x86_64 crypto code;, and add the needed constant
+to make the code compile again (that macro was added to i386 asm-offsets
+between 2.6.17 and 2.6.18, in 6c2bb98bc33ae33c7a33a133a4cd5a06395fece5).
+
+Signed-off-by: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
+Acked-by: Jeff Dike <jdike@addtoit.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/um/Makefile-x86_64 | 2 +-
+ arch/um/include/common-offsets.h | 1 +
+ arch/um/include/sysdep-i386/kernel-offsets.h | 1 +
+ arch/um/include/sysdep-x86_64/kernel-offsets.h | 1 +
+ 4 files changed, 4 insertions(+), 1 deletion(-)
+
+--- linux-2.6.18.orig/arch/um/Makefile-x86_64
++++ linux-2.6.18/arch/um/Makefile-x86_64
+@@ -1,7 +1,7 @@
+ # Copyright 2003 - 2004 Pathscale, Inc
+ # Released under the GPL
+
+-core-y += arch/um/sys-x86_64/
++core-y += arch/um/sys-x86_64/ arch/x86_64/crypto/
+ START := 0x60000000
+
+ #We #undef __x86_64__ for kernelspace, not for userspace where
+--- linux-2.6.18.orig/arch/um/include/common-offsets.h
++++ linux-2.6.18/arch/um/include/common-offsets.h
+@@ -15,3 +15,4 @@ DEFINE_STR(UM_KERN_DEBUG, KERN_DEBUG);
+ DEFINE(UM_ELF_CLASS, ELF_CLASS);
+ DEFINE(UM_ELFCLASS32, ELFCLASS32);
+ DEFINE(UM_ELFCLASS64, ELFCLASS64);
++DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx));
+--- linux-2.6.18.orig/arch/um/include/sysdep-i386/kernel-offsets.h
++++ linux-2.6.18/arch/um/include/sysdep-i386/kernel-offsets.h
+@@ -1,6 +1,7 @@
+ #include <linux/stddef.h>
+ #include <linux/sched.h>
+ #include <linux/elf.h>
++#include <linux/crypto.h>
+ #include <asm/mman.h>
+
+ #define DEFINE(sym, val) \
+--- linux-2.6.18.orig/arch/um/include/sysdep-x86_64/kernel-offsets.h
++++ linux-2.6.18/arch/um/include/sysdep-x86_64/kernel-offsets.h
+@@ -2,6 +2,7 @@
+ #include <linux/sched.h>
+ #include <linux/time.h>
+ #include <linux/elf.h>
++#include <linux/crypto.h>
+ #include <asm/page.h>
+ #include <asm/mman.h>
+
--- /dev/null
+From stable-bounces@linux.kernel.org Thu Oct 5 11:28:24 2006
+Date: Thu, 5 Oct 2006 20:27:32 +0200
+From: Mattia Dongili <malattia@linux.it>
+To: stable@kernel.org
+Message-ID: <20061005182732.GB17561@inferi.kami.home>
+Content-Disposition: inline
+Cc: Jeff Dike <jdike@addtoit.com>, Paolo Giarrusso <blaisorblade@yahoo.it>
+Subject: UML: Fix UML build failure
+
+From: Jeff Dike <jdike@addtoit.com>
+
+don't know if the following is already queued, it fixes an ARCH=um build
+failure, evidence here:
+http://marc.theaimsgroup.com/?l=linux-kernel&m=115875912525137&w=2
+and following thread.
+Cc-ing uml maintainers and I hope I didn't follow too many
+Submitting-patches rules...
+
+The patch is taken from:
+http://user-mode-linux.sourceforge.net/work/current/2.6/2.6.18/patches/no-syscallx
+
+Since the syscallx macros seem to be under threat, this patch stops
+using them, using syscall instead.
+
+Acked-by: Jeff Dike <jdike@addtoit.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+
+---
+ arch/um/os-Linux/process.c | 4 +---
+ arch/um/os-Linux/sys-i386/tls.c | 4 +---
+ arch/um/os-Linux/tls.c | 7 ++-----
+ 3 files changed, 4 insertions(+), 11 deletions(-)
+
+--- linux-2.6.18.orig/arch/um/os-Linux/process.c
++++ linux-2.6.18/arch/um/os-Linux/process.c
+@@ -141,11 +141,9 @@ void os_usr1_process(int pid)
+ * syscalls, and also breaks with clone(), which does not unshare the TLS.
+ */
+
+-inline _syscall0(pid_t, getpid)
+-
+ int os_getpid(void)
+ {
+- return(getpid());
++ return syscall(__NR_getpid);
+ }
+
+ int os_getpgrp(void)
+--- linux-2.6.18.orig/arch/um/os-Linux/sys-i386/tls.c
++++ linux-2.6.18/arch/um/os-Linux/sys-i386/tls.c
+@@ -3,8 +3,6 @@
+ #include "sysdep/tls.h"
+ #include "user_util.h"
+
+-static _syscall1(int, get_thread_area, user_desc_t *, u_info);
+-
+ /* Checks whether host supports TLS, and sets *tls_min according to the value
+ * valid on the host.
+ * i386 host have it == 6; x86_64 host have it == 12, for i386 emulation. */
+@@ -17,7 +15,7 @@ void check_host_supports_tls(int *suppor
+ user_desc_t info;
+ info.entry_number = val[i];
+
+- if (get_thread_area(&info) == 0) {
++ if(syscall(__NR_get_thread_area, &info) == 0){
+ *tls_min = val[i];
+ *supports_tls = 1;
+ return;
+--- linux-2.6.18.orig/arch/um/os-Linux/tls.c
++++ linux-2.6.18/arch/um/os-Linux/tls.c
+@@ -48,14 +48,11 @@ int os_get_thread_area(user_desc_t *info
+ #ifdef UML_CONFIG_MODE_TT
+ #include "linux/unistd.h"
+
+-static _syscall1(int, get_thread_area, user_desc_t *, u_info);
+-static _syscall1(int, set_thread_area, user_desc_t *, u_info);
+-
+ int do_set_thread_area_tt(user_desc_t *info)
+ {
+ int ret;
+
+- ret = set_thread_area(info);
++ ret = syscall(__NR_set_thread_area, info);
+ if (ret < 0) {
+ ret = -errno;
+ }
+@@ -66,7 +63,7 @@ int do_get_thread_area_tt(user_desc_t *i
+ {
+ int ret;
+
+- ret = get_thread_area(info);
++ ret = syscall(__NR_get_thread_area, info);
+ if (ret < 0) {
+ ret = -errno;
+ }
--- /dev/null
+From stable-bounces@linux.kernel.org Thu Oct 5 14:10:16 2006
+From: "Paolo 'Blaisorblade' Giarrusso" <blaisorblade@yahoo.it>
+To: stable@kernel.org
+Date: Thu, 5 Oct 2006 22:01:47 +0200
+Message-Id: <11600785071661-git-send-email-blaisorblade@yahoo.it>
+Cc: Jeff Dike <jdike@addtoit.com>,
+ "Paolo 'Blaisorblade' Giarrusso" <blaisorblade@yahoo.it>,
+ <user-mode-linux-devel@lists.sourceforge.net>
+Subject: uml: use DEFCONFIG_LIST to avoid reading host's config
+
+From: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
+
+This should make sure that, for UML, host's configuration files are not
+considered, which avoids various pains to the user. Our dependency are such that
+the obtained Kconfig will be valid and will lead to successful compilation -
+however they cannot prevent an user from disabling any boot device, and if an
+option is not set in the read .config (say /boot/config-XXX), with make
+menuconfig ARCH=um, it is not set. This always disables UBD and all console I/O
+channels, which leads to non-working UML kernels, so this bothers users -
+especially now, since it will happen on almost every machine
+(/boot/config-`uname -r` exists almost on every machine). It can be workarounded
+with make defconfig ARCH=um, but it is non-obvious and can be avoided, so please
+_do_ merge this patch.
+
+Signed-off-by: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
+Acked-by: Jeff Dike <jdike@addtoit.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ arch/um/Kconfig | 5 +++++
+ init/Kconfig | 1 +
+ 2 files changed, 6 insertions(+)
+
+--- linux-2.6.18.orig/arch/um/Kconfig
++++ linux-2.6.18/arch/um/Kconfig
+@@ -1,3 +1,8 @@
++config DEFCONFIG_LIST
++ string
++ option defconfig_list
++ default "arch/$ARCH/defconfig"
++
+ # UML uses the generic IRQ sugsystem
+ config GENERIC_HARDIRQS
+ bool
+--- linux-2.6.18.orig/init/Kconfig
++++ linux-2.6.18/init/Kconfig
+@@ -1,5 +1,6 @@
+ config DEFCONFIG_LIST
+ string
++ depends on !UML
+ option defconfig_list
+ default "/lib/modules/$UNAME_RELEASE/.config"
+ default "/etc/kernel-config"
--- /dev/null
+From stable-bounces@linux.kernel.org Sun Oct 8 11:43:11 2006
+Message-ID: <45294667.9030503@linuxtv.org>
+Date: Sun, 08 Oct 2006 14:41:43 -0400
+From: Michael Krufky <mkrufky@linuxtv.org>
+To: stable@kernel.org
+Cc: v4l-dvb maintainer list <v4l-dvb-maintainer@linuxtv.org>,
+ Yeasah Pell <yeasah@schwide.net>, linux-kernel@vger.kernel.org,
+ Steven Toth <stoth@hauppauge.com>
+Subject: Video: cx24123: fix PLL divisor setup
+
+From: Yeasah Pell <yeasah@schwide.net>
+
+The cx24109 datasheet says: "NOTE: if A=0, then N=N+1"
+
+The current code is the result of a misinterpretation of the datasheet to
+mean exactly the opposite of the requirement -- The actual value of N is 1
+greater than the value written when A is 0, so 1 needs to be *subtracted*
+from it to compensate.
+
+Signed-off-by: Yeasah Pell <yeasah@schwide.net>
+Signed-off-by: Steven Toth <stoth@hauppauge.com>
+Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/media/dvb/frontends/cx24123.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- linux-2.6.18.orig/drivers/media/dvb/frontends/cx24123.c
++++ linux-2.6.18/drivers/media/dvb/frontends/cx24123.c
+@@ -549,8 +549,8 @@ static int cx24123_pll_calculate(struct
+ ndiv = ( ((p->frequency * vco_div * 10) / (2 * XTAL / 1000)) / 32) & 0x1ff;
+ adiv = ( ((p->frequency * vco_div * 10) / (2 * XTAL / 1000)) % 32) & 0x1f;
+
+- if (adiv == 0)
+- ndiv++;
++ if (adiv == 0 && ndiv > 0)
++ ndiv--;
+
+ /* control bits 11, refdiv 11, charge pump polarity 1, charge pump current, ndiv, adiv */
+ state->pllarg = (3 << 19) | (3 << 17) | (1 << 16) | (pump << 14) | (ndiv << 5) | adiv;
--- /dev/null
+From stable-bounces@linux.kernel.org Sun Oct 8 11:42:36 2006
+Message-ID: <45294666.3040204@linuxtv.org>
+Date: Sun, 08 Oct 2006 14:41:42 -0400
+From: Michael Krufky <mkrufky@linuxtv.org>
+To: stable@kernel.org
+Cc: v4l-dvb maintainer list <v4l-dvb-maintainer@linuxtv.org>,
+ Hans Verkuil <hverkuil@xs4all.nl>,
+ Linux and Kernel Video <video4linux-list@redhat.com>,
+ linux-kernel@vger.kernel.org
+Subject: Video: Fix msp343xG handling regression
+
+From: Hans Verkuil <hverkuil@xs4all.nl>
+
+The msp3430G and msp3435G models cannot do Automatic Standard Detection,
+so these should be forced to BTSC. These chips are early production
+versions for the msp34xxG series and are quite rare.
+
+The workaround for kernel 2.6.18 is to use 'standard=32' as msp3400 module
+option.
+
+Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
+Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/media/video/msp3400-driver.c | 2 ++
+ drivers/media/video/msp3400-driver.h | 1 +
+ drivers/media/video/msp3400-kthreads.c | 5 +++--
+ 3 files changed, 6 insertions(+), 2 deletions(-)
+
+--- linux-2.6.18.orig/drivers/media/video/msp3400-driver.c
++++ linux-2.6.18/drivers/media/video/msp3400-driver.c
+@@ -904,6 +904,8 @@ static int msp_attach(struct i2c_adapter
+ state->has_virtual_dolby_surround = msp_revision == 'G' && msp_prod_lo == 1;
+ /* Has Virtual Dolby Surround & Dolby Pro Logic: only in msp34x2 */
+ state->has_dolby_pro_logic = msp_revision == 'G' && msp_prod_lo == 2;
++ /* The msp343xG supports BTSC only and cannot do Automatic Standard Detection. */
++ state->force_btsc = msp_family == 3 && msp_revision == 'G' && msp_prod_hi == 3;
+
+ state->opmode = opmode;
+ if (state->opmode == OPMODE_AUTO) {
+--- linux-2.6.18.orig/drivers/media/video/msp3400-driver.h
++++ linux-2.6.18/drivers/media/video/msp3400-driver.h
+@@ -64,6 +64,7 @@ struct msp_state {
+ u8 has_sound_processing;
+ u8 has_virtual_dolby_surround;
+ u8 has_dolby_pro_logic;
++ u8 force_btsc;
+
+ int radio;
+ int opmode;
+--- linux-2.6.18.orig/drivers/media/video/msp3400-kthreads.c
++++ linux-2.6.18/drivers/media/video/msp3400-kthreads.c
+@@ -960,9 +960,10 @@ int msp34xxg_thread(void *data)
+
+ /* setup the chip*/
+ msp34xxg_reset(client);
+- state->std = state->radio ? 0x40 : msp_standard;
+- /* start autodetect */
++ state->std = state->radio ? 0x40 :
++ (state->force_btsc && msp_standard == 1) ? 32 : msp_standard;
+ msp_write_dem(client, 0x20, state->std);
++ /* start autodetect */
+ if (state->std != 1)
+ goto unmute;
+
--- /dev/null
+From stable-bounces@linux.kernel.org Sun Oct 8 11:43:20 2006
+Message-ID: <45294683.8040508@linuxtv.org>
+Date: Sun, 08 Oct 2006 14:42:11 -0400
+From: Michael Krufky <mkrufky@linuxtv.org>
+To: stable@kernel.org
+Cc: v4l-dvb maintainer list <v4l-dvb-maintainer@linuxtv.org>,
+ Mike Isely <isely@pobox.com>, linux-kernel@vger.kernel.org
+Subject: Video: pvrusb2: improve 24XXX config option description
+
+From: Mike Isely <isely@pobox.com>
+
+The CONFIG_VIDEO_PVRUSB2_24XXX is not nearly as "experimental" as the
+description suggests. So refine the description to better match reality.
+
+Signed-off-by: Mike Isely <isely@pobox.com>
+Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/media/video/pvrusb2/Kconfig | 9 ++-------
+ 1 file changed, 2 insertions(+), 7 deletions(-)
+
+--- linux-2.6.18.orig/drivers/media/video/pvrusb2/Kconfig
++++ linux-2.6.18/drivers/media/video/pvrusb2/Kconfig
+@@ -25,14 +25,9 @@ config VIDEO_PVRUSB2_24XXX
+ form "24xxx" (leading prefix of "24" followed by 3 digits).
+ To see if you may need this option, examine the white
+ sticker on the underside of your device. Enabling this
+- option will not harm support for older devices, however it
+- is a separate option because of the experimental nature of
+- this new feature.
++ option will not harm support for older devices.
+
+- If you are in doubt, say N.
+-
+- Note: This feature is _very_ experimental. You have been
+- warned.
++ If you are in doubt, say Y.
+
+ config VIDEO_PVRUSB2_SYSFS
+ bool "pvrusb2 sysfs support (EXPERIMENTAL)"
--- /dev/null
+From stable-bounces@linux.kernel.org Sun Oct 8 12:11:06 2006
+Message-ID: <45294689.80706@linuxtv.org>
+Date: Sun, 08 Oct 2006 14:42:17 -0400
+From: Michael Krufky <mkrufky@linuxtv.org>
+To: stable@kernel.org
+Cc: v4l-dvb maintainer list <v4l-dvb-maintainer@linuxtv.org>,
+ Mike Isely <isely@pobox.com>, linux-kernel@vger.kernel.org
+Subject: Video: pvrusb2: Limit hor res for 24xxx devices
+
+From: Mike Isely <isely@pobox.com>
+
+Currently it is not understood how to properly control the horizontal
+capture resolution on 24xxx devices. The pvrusb2 driver is doing
+everything it should (pass resolution paramter(s) to cx2341x and
+cx25840 modules) but for some reason the result is corrupted video if
+any resolution other than 720 is used. This patch causes the driver
+to only permit a horizontal resolution of 720 to be used on 24xxx
+devices. Even if the app requests something else, the driver will
+force the resolution back to 720. This patch still allows full
+control of the resolution for 29xxx devices.
+
+Signed-off-by: Mike Isely <isely@pobox.com>
+Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/media/video/pvrusb2/pvrusb2-ctrl.c | 21 +++++++++---
+ drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h | 2 +
+ drivers/media/video/pvrusb2/pvrusb2-hdw.c | 30 ++++++++++++++++++
+ drivers/media/video/pvrusb2/pvrusb2-v4l2.c | 34 +++++++++++----------
+ 4 files changed, 65 insertions(+), 22 deletions(-)
+
+--- linux-2.6.18.orig/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
++++ linux-2.6.18/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
+@@ -43,12 +43,17 @@ int pvr2_ctrl_set_mask_value(struct pvr2
+ if (cptr->info->type == pvr2_ctl_bitmask) {
+ mask &= cptr->info->def.type_bitmask.valid_bits;
+ } else if (cptr->info->type == pvr2_ctl_int) {
+- if (val < cptr->info->def.type_int.min_value) {
+- break;
++ int lim;
++ lim = cptr->info->def.type_int.min_value;
++ if (cptr->info->get_min_value) {
++ cptr->info->get_min_value(cptr,&lim);
+ }
+- if (val > cptr->info->def.type_int.max_value) {
+- break;
++ if (val < lim) break;
++ lim = cptr->info->def.type_int.max_value;
++ if (cptr->info->get_max_value) {
++ cptr->info->get_max_value(cptr,&lim);
+ }
++ if (val > lim) break;
+ } else if (cptr->info->type == pvr2_ctl_enum) {
+ if (val >= cptr->info->def.type_enum.count) {
+ break;
+@@ -91,7 +96,9 @@ int pvr2_ctrl_get_max(struct pvr2_ctrl *
+ int ret = 0;
+ if (!cptr) return 0;
+ LOCK_TAKE(cptr->hdw->big_lock); do {
+- if (cptr->info->type == pvr2_ctl_int) {
++ if (cptr->info->get_max_value) {
++ cptr->info->get_max_value(cptr,&ret);
++ } else if (cptr->info->type == pvr2_ctl_int) {
+ ret = cptr->info->def.type_int.max_value;
+ }
+ } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+@@ -105,7 +112,9 @@ int pvr2_ctrl_get_min(struct pvr2_ctrl *
+ int ret = 0;
+ if (!cptr) return 0;
+ LOCK_TAKE(cptr->hdw->big_lock); do {
+- if (cptr->info->type == pvr2_ctl_int) {
++ if (cptr->info->get_min_value) {
++ cptr->info->get_min_value(cptr,&ret);
++ } else if (cptr->info->type == pvr2_ctl_int) {
+ ret = cptr->info->def.type_int.min_value;
+ }
+ } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+--- linux-2.6.18.orig/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
++++ linux-2.6.18/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+@@ -107,6 +107,8 @@ struct pvr2_ctl_info {
+
+ /* Control's implementation */
+ pvr2_ctlf_get_value get_value; /* Get its value */
++ pvr2_ctlf_get_value get_min_value; /* Get minimum allowed value */
++ pvr2_ctlf_get_value get_max_value; /* Get maximum allowed value */
+ pvr2_ctlf_set_value set_value; /* Set its value */
+ pvr2_ctlf_val_to_sym val_to_sym; /* Custom convert value->symbol */
+ pvr2_ctlf_sym_to_val sym_to_val; /* Custom convert symbol->value */
+--- linux-2.6.18.orig/drivers/media/video/pvrusb2/pvrusb2-hdw.c
++++ linux-2.6.18/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+@@ -362,6 +362,30 @@ static int ctrl_freq_set(struct pvr2_ctr
+ return 0;
+ }
+
++#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
++static int ctrl_hres_max_get(struct pvr2_ctrl *cptr,int *vp)
++{
++ /* If we're dealing with a 24xxx device, force the horizontal
++ maximum to be 720 no matter what, since we can't get the device
++ to work properly with any other value. Otherwise just return
++ the normal value. */
++ *vp = cptr->info->def.type_int.max_value;
++ if (cptr->hdw->hdw_type == PVR2_HDW_TYPE_24XXX) *vp = 720;
++ return 0;
++}
++
++static int ctrl_hres_min_get(struct pvr2_ctrl *cptr,int *vp)
++{
++ /* If we're dealing with a 24xxx device, force the horizontal
++ minimum to be 720 no matter what, since we can't get the device
++ to work properly with any other value. Otherwise just return
++ the normal value. */
++ *vp = cptr->info->def.type_int.min_value;
++ if (cptr->hdw->hdw_type == PVR2_HDW_TYPE_24XXX) *vp = 720;
++ return 0;
++}
++#endif
++
+ static int ctrl_cx2341x_is_dirty(struct pvr2_ctrl *cptr)
+ {
+ return cptr->hdw->enc_stale != 0;
+@@ -720,6 +744,12 @@ static const struct pvr2_ctl_info contro
+ .default_value = 720,
+ DEFREF(res_hor),
+ DEFINT(320,720),
++#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
++ /* Hook in check for clamp on horizontal resolution in
++ order to avoid unsolved problem involving cx25840. */
++ .get_max_value = ctrl_hres_max_get,
++ .get_min_value = ctrl_hres_min_get,
++#endif
+ },{
+ .desc = "Vertical capture resolution",
+ .name = "resolution_ver",
+--- linux-2.6.18.orig/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
++++ linux-2.6.18/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+@@ -456,18 +456,26 @@ static int pvr2_v4l2_do_ioctl(struct ino
+ ret = 0;
+ switch(vf->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
++ int lmin,lmax;
++ struct pvr2_ctrl *hcp,*vcp;
+ int h = vf->fmt.pix.height;
+ int w = vf->fmt.pix.width;
++ hcp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_HRES);
++ vcp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_VRES);
+
+- if (h < 200) {
+- h = 200;
+- } else if (h > 625) {
+- h = 625;
++ lmin = pvr2_ctrl_get_min(hcp);
++ lmax = pvr2_ctrl_get_max(hcp);
++ if (w < lmin) {
++ w = lmin;
++ } else if (w > lmax) {
++ w = lmax;
+ }
+- if (w < 320) {
+- w = 320;
+- } else if (w > 720) {
+- w = 720;
++ lmin = pvr2_ctrl_get_min(vcp);
++ lmax = pvr2_ctrl_get_max(vcp);
++ if (h < lmin) {
++ h = lmin;
++ } else if (h > lmax) {
++ h = lmax;
+ }
+
+ memcpy(vf, &pvr_format[PVR_FORMAT_PIX],
+@@ -476,14 +484,8 @@ static int pvr2_v4l2_do_ioctl(struct ino
+ vf->fmt.pix.height = h;
+
+ if (cmd == VIDIOC_S_FMT) {
+- pvr2_ctrl_set_value(
+- pvr2_hdw_get_ctrl_by_id(hdw,
+- PVR2_CID_HRES),
+- vf->fmt.pix.width);
+- pvr2_ctrl_set_value(
+- pvr2_hdw_get_ctrl_by_id(hdw,
+- PVR2_CID_VRES),
+- vf->fmt.pix.height);
++ pvr2_ctrl_set_value(hcp,vf->fmt.pix.width);
++ pvr2_ctrl_set_value(vcp,vf->fmt.pix.height);
+ }
+ } break;
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
--- /dev/null
+From stable-bounces@linux.kernel.org Sun Oct 8 11:43:20 2006
+Message-ID: <45294680.5010205@linuxtv.org>
+Date: Sun, 08 Oct 2006 14:42:08 -0400
+From: Michael Krufky <mkrufky@linuxtv.org>
+To: stable@kernel.org
+Cc: v4l-dvb maintainer list <v4l-dvb-maintainer@linuxtv.org>,
+ Mike Isely <isely@pobox.com>, linux-kernel@vger.kernel.org
+Subject: Video: pvrusb2: Solve mutex deadlock
+
+From: Mike Isely <isely@pobox.com>
+
+There is a mutex ordering problem between the pvrusb2 driver and the
+v4l core. Two different pathways take mutexes in opposing orders and
+this (under rare circumstances) can cause a deadlock. The two mutexes
+in question are videodev_lock in the v4l core and device_lock inside
+the pvrusb2 driver. The device_lock instance in the driver protects a
+private global array of context pointers which had been implemented in
+advance of v4l core changes which eliminate the video_set_drvdata()
+and video_get_drvdata() functions.
+
+This patch restores the use of video_get_drvdata() and
+video_set_drvdata(), eliminating the need for the array and the mutex.
+(This is actually a patch to restore the previous implementation.) We
+can do this for 2.6.18 since those functions are in fact still
+present. A better (and larger) solution will be done for later
+kernels.
+
+Signed-off-by: Mike Isely <isely@pobox.com>
+Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
++++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+@@ -22,6 +22,7 @@
+
+ #include <linux/kernel.h>
+ #include <linux/version.h>
++#include <linux/videodev.h>
+ #include "pvrusb2-context.h"
+ #include "pvrusb2-hdw.h"
+ #include "pvrusb2.h"
+@@ -35,21 +36,11 @@ struct pvr2_v4l2_dev;
+ struct pvr2_v4l2_fh;
+ struct pvr2_v4l2;
+
+-/* V4L no longer provide the ability to set / get a private context pointer
+- (i.e. video_get_drvdata / video_set_drvdata), which means we have to
+- concoct our own context locating mechanism. Supposedly this is intended
+- to simplify driver implementation. It's not clear to me how that can
+- possibly be true. Our solution here is to maintain a lookup table of
+- our context instances, indexed by the minor device number of the V4L
+- device. See pvr2_v4l2_open() for some implications of this approach. */
+-static struct pvr2_v4l2_dev *devices[256];
+-static DEFINE_MUTEX(device_lock);
+
+ struct pvr2_v4l2_dev {
+ struct pvr2_v4l2 *v4lp;
+ struct video_device *vdev;
+ struct pvr2_context_stream *stream;
+- int ctxt_idx;
+ enum pvr2_config config;
+ };
+
+@@ -703,12 +694,6 @@ static void pvr2_v4l2_dev_destroy(struct
+ {
+ printk(KERN_INFO "pvrusb2: unregistering device video%d [%s]\n",
+ dip->vdev->minor,pvr2_config_get_name(dip->config));
+- if (dip->ctxt_idx >= 0) {
+- mutex_lock(&device_lock);
+- devices[dip->ctxt_idx] = NULL;
+- dip->ctxt_idx = -1;
+- mutex_unlock(&device_lock);
+- }
+ video_unregister_device(dip->vdev);
+ }
+
+@@ -800,33 +785,10 @@ static int pvr2_v4l2_open(struct inode *
+ struct pvr2_v4l2 *vp;
+ struct pvr2_hdw *hdw;
+
+- mutex_lock(&device_lock);
+- /* MCI 7-Jun-2006 Even though we're just doing what amounts to an
+- atomic read of the device mapping array here, we still need the
+- mutex. The problem is that there is a tiny race possible when
+- we register the device. We can't update the device mapping
+- array until after the device has been registered, owing to the
+- fact that we can't know the minor device number until after the
+- registration succeeds. And if another thread tries to open the
+- device in the window of time after registration but before the
+- map is updated, then it will get back an erroneous null pointer
+- and the open will result in a spurious failure. The only way to
+- prevent that is to (a) be inside the mutex here before we access
+- the array, and (b) cover the entire registration process later
+- on with this same mutex. Thus if we get inside the mutex here,
+- then we can be assured that the registration process actually
+- completed correctly. This is an unhappy complication from the
+- use of global data in a driver that lives in a preemptible
+- environment. It sure would be nice if the video device itself
+- had a means for storing and retrieving a local context pointer.
+- Oh wait. It did. But now it's gone. Silly me. */
+ {
+- unsigned int midx = iminor(file->f_dentry->d_inode);
+- if (midx < sizeof(devices)/sizeof(devices[0])) {
+- dip = devices[midx];
+- }
++ struct video_device *vdev = video_devdata(file);
++ dip = (struct pvr2_v4l2_dev *)video_get_drvdata(vdev);
+ }
+- mutex_unlock(&device_lock);
+
+ if (!dip) return -ENODEV; /* Should be impossible but I'm paranoid */
+
+@@ -1066,7 +1028,7 @@ static void pvr2_v4l2_dev_init(struct pv
+
+ memcpy(dip->vdev,&vdev_template,sizeof(vdev_template));
+ dip->vdev->release = video_device_release;
+- mutex_lock(&device_lock);
++ video_set_drvdata(dip->vdev,dip);
+
+ mindevnum = -1;
+ unit_number = pvr2_hdw_get_unit_number(vp->channel.mc_head->hdw);
+@@ -1081,12 +1043,6 @@ static void pvr2_v4l2_dev_init(struct pv
+ dip->vdev->minor,pvr2_config_get_name(dip->config));
+ }
+
+- if ((dip->vdev->minor < sizeof(devices)/sizeof(devices[0])) &&
+- (devices[dip->vdev->minor] == NULL)) {
+- dip->ctxt_idx = dip->vdev->minor;
+- devices[dip->ctxt_idx] = dip;
+- }
+- mutex_unlock(&device_lock);
+
+ pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,
+ dip->vdev->minor);
+@@ -1100,7 +1056,6 @@ struct pvr2_v4l2 *pvr2_v4l2_create(struc
+ vp = kmalloc(sizeof(*vp),GFP_KERNEL);
+ if (!vp) return vp;
+ memset(vp,0,sizeof(*vp));
+- vp->video_dev.ctxt_idx = -1;
+ pvr2_channel_init(&vp->channel,mnp);
+ pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_v4l2 id=%p",vp);
+
+
+_______________________________________________
+stable mailing list
+stable@linux.kernel.org
+http://linux.kernel.org/mailman/listinfo/stable
+
--- /dev/null
+From stable-bounces@linux.kernel.org Sun Oct 8 11:43:20 2006
+Message-ID: <45294686.6050003@linuxtv.org>
+Date: Sun, 08 Oct 2006 14:42:14 -0400
+From: Michael Krufky <mkrufky@linuxtv.org>
+To: stable@kernel.org
+Cc: v4l-dvb maintainer list <v4l-dvb-maintainer@linuxtv.org>,
+ Mike Isely <isely@pobox.com>, linux-kernel@vger.kernel.org
+Subject: Video: pvrusb2: Suppress compiler warning
+
+From: Mike Isely <isely@pobox.com>
+
+The pvrusb2 driver needs to call video_devdata() in order to correctly
+transform a file pointer into a video_device pointer. Unfortunately
+the prototype for this function has been marked V4L1-only and there's
+no official substitute that I can find for V4L2. Adding to the
+mystery is that the implementation for this function exists whether or
+not V4L1 compatibility has been selected. The upshot of all this is
+that we get a compilation warning here about a missing prototype but
+the code links OK. This fix solves the warning by copying the
+prototype into the source file that is using it. Yes this is a hack,
+but it's a safe one for 2.6.18 (any alternative would be much more
+intrusive). A better solution should be forthcoming for the next
+kernel.
+
+Signed-off-by: Mike Isely <isely@pobox.com>
+Signed-off-by: Michael Krufky <mkrufky@linuxtv.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/media/video/pvrusb2/pvrusb2-v4l2.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- linux-2.6.18.orig/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
++++ linux-2.6.18/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+@@ -32,6 +32,12 @@
+ #include <linux/videodev2.h>
+ #include <media/v4l2-common.h>
+
++/* Mike Isely <isely@pobox.com> 23-Sep-2006 - This function is prototyped
++ * only for V4L1 but is implemented regardless of the V4L1 compatibility
++ * option state. V4L2 has no replacement for this and we need it. For now
++ * copy the prototype here so we can avoid the compiler warning. */
++extern struct video_device* video_devdata(struct file*);
++
+ struct pvr2_v4l2_dev;
+ struct pvr2_v4l2_fh;
+ struct pvr2_v4l2;
--- /dev/null
+From stable-bounces@linux.kernel.org Mon Oct 9 08:06:59 2006
+From: Daniel Drake <dsd@gentoo.org>
+To: stable@kernel.org
+Message-Id: <20061009150616.878027B40A0@zog.reactivated.net>
+Date: Mon, 9 Oct 2006 16:06:16 +0100 (BST)
+Subject: zd1211rw: ZD1211B ASIC/FWT, not jointly decoder
+
+From: Daniel Drake <dsd@gentoo.org>
+
+The vendor driver chooses this value based on an ifndef ASIC,
+and ASIC is never defined.
+
+Signed-off-by: Daniel Drake <dsd@gentoo.org>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ drivers/net/wireless/zd1211rw/zd_chip.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- linux-2.6.18.orig/drivers/net/wireless/zd1211rw/zd_chip.c
++++ linux-2.6.18/drivers/net/wireless/zd1211rw/zd_chip.c
+@@ -717,7 +717,7 @@ static int zd1211b_hw_reset_phy(struct z
+ { CR21, 0x0e }, { CR22, 0x23 }, { CR23, 0x90 },
+ { CR24, 0x14 }, { CR25, 0x40 }, { CR26, 0x10 },
+ { CR27, 0x10 }, { CR28, 0x7f }, { CR29, 0x80 },
+- { CR30, 0x49 }, /* jointly decoder, no ASIC */
++ { CR30, 0x4b }, /* ASIC/FWT, no jointly decoder */
+ { CR31, 0x60 }, { CR32, 0x43 }, { CR33, 0x08 },
+ { CR34, 0x06 }, { CR35, 0x0a }, { CR36, 0x00 },
+ { CR37, 0x00 }, { CR38, 0x38 }, { CR39, 0x0c },